From cb51e03587f0079665dca9048f522bb264a41a10 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 13 Oct 2018 01:36:26 +0100 Subject: [PATCH 001/127] Add Sprout support to TransactionBuilder --- src/gtest/test_transaction_builder.cpp | 158 ++++++++++ src/transaction_builder.cpp | 396 ++++++++++++++++++++++++- src/transaction_builder.h | 43 ++- 3 files changed, 589 insertions(+), 8 deletions(-) diff --git a/src/gtest/test_transaction_builder.cpp b/src/gtest/test_transaction_builder.cpp index 72aab05f717..f6aecb88f0b 100644 --- a/src/gtest/test_transaction_builder.cpp +++ b/src/gtest/test_transaction_builder.cpp @@ -12,6 +12,67 @@ #include #include +extern ZCJoinSplit* params; + +// Fake an empty view +class TransactionBuilderCoinsViewDB : public CCoinsView { +public: + std::map sproutTrees; + + TransactionBuilderCoinsViewDB() {} + + bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { + auto it = sproutTrees.find(rt); + if (it != sproutTrees.end()) { + tree = it->second; + return true; + } else { + return false; + } + } + + bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { + return false; + } + + bool GetNullifier(const uint256 &nf, ShieldedType type) const { + return false; + } + + bool GetCoins(const uint256 &txid, CCoins &coins) const { + return false; + } + + bool HaveCoins(const uint256 &txid) const { + return false; + } + + uint256 GetBestBlock() const { + uint256 a; + return a; + } + + uint256 GetBestAnchor(ShieldedType type) const { + uint256 a; + return a; + } + + bool BatchWrite(CCoinsMap &mapCoins, + const uint256 &hashBlock, + const uint256 &hashSproutAnchor, + const uint256 &hashSaplingAnchor, + CAnchorsSproutMap &mapSproutAnchors, + CAnchorsSaplingMap &mapSaplingAnchors, + CNullifiersMap &mapSproutNullifiers, + CNullifiersMap saplingNullifiersMap) { + return false; + } + + bool GetStats(CCoinsStats &stats) const { + return false; + } +}; + TEST(TransactionBuilder, Invoke) { auto consensusParams = RegtestActivateSapling(); @@ -30,6 +91,10 @@ TEST(TransactionBuilder, Invoke) libzcash::diversifier_t d = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; auto pk = *ivk.address(d); + auto sproutSk = libzcash::SproutSpendingKey::random(); + ZCNoteDecryption sproutDecryptor(sproutSk.receiving_key()); + auto sproutAddr = sproutSk.address(); + // Create a shielding transaction from transparent to Sapling // 0.0005 t-ZEC in, 0.0004 z-ZEC out, 0.0001 t-ZEC fee auto builder1 = TransactionBuilder(consensusParams, 1, &keystore); @@ -81,10 +146,103 @@ TEST(TransactionBuilder, Invoke) EXPECT_TRUE(ContextualCheckTransaction(tx2, state, 3, 0)); EXPECT_EQ(state.GetRejectReason(), ""); + // Create a Sapling-to-Sprout transaction (reusing the note from above) + // - 0.0004 Sapling-ZEC in - 0.00025 Sprout-ZEC out + // - 0.00005 Sapling-ZEC change + // - 0.0001 t-ZEC fee + auto builder3 = TransactionBuilder(consensusParams, 2, nullptr, params); + builder3.AddSaplingSpend(expsk, note, anchor, witness); + builder3.AddSproutOutput(sproutAddr, 25000); + auto tx3 = builder3.Build().GetTxOrThrow(); + + EXPECT_EQ(tx3.vin.size(), 0); + EXPECT_EQ(tx3.vout.size(), 0); + EXPECT_EQ(tx3.vjoinsplit.size(), 1); + EXPECT_EQ(tx3.vjoinsplit[0].vpub_old, 25000); + EXPECT_EQ(tx3.vjoinsplit[0].vpub_new, 0); + EXPECT_EQ(tx3.vShieldedSpend.size(), 1); + EXPECT_EQ(tx3.vShieldedOutput.size(), 1); + EXPECT_EQ(tx3.valueBalance, 35000); + + EXPECT_TRUE(ContextualCheckTransaction(tx3, state, 3, 0)); + EXPECT_EQ(state.GetRejectReason(), ""); + + // Prepare to spend the Sprout note that was just created + SproutMerkleTree sproutTree; + libzcash::SproutNote sproutNote; + SproutWitness sproutWitness; + for (int i = 0; i < ZC_NUM_JS_OUTPUTS; i++) { + sproutTree.append(tx3.vjoinsplit[0].commitments[i]); + + auto hSig = tx3.vjoinsplit[0].h_sig(*params, tx3.joinSplitPubKey); + try { + auto pt = libzcash::SproutNotePlaintext::decrypt( + sproutDecryptor, + tx3.vjoinsplit[0].ciphertexts[i], + tx3.vjoinsplit[0].ephemeralKey, + hSig, + (unsigned char)i); + sproutNote = pt.note(sproutAddr); + sproutWitness = sproutTree.witness(); + break; + } catch (const std::exception& e) { + // One of the outputs must be ours + assert(i + 1 < ZC_NUM_JS_OUTPUTS); + } + } + + // Fake a view with the Sprout note in it + auto rt = sproutTree.root(); + TransactionBuilderCoinsViewDB fakeDB; + fakeDB.sproutTrees.insert(std::pair(rt, sproutTree)); + CCoinsViewCache view(&fakeDB); + + // Create a Sprout-to-[Sprout-and-Sapling] transaction + // - 0.00025 Sprout-ZEC in - 0.00006 Sprout-ZEC out + // - 0.00004 Sprout-ZEC out + // - 0.00005 Sprout-ZEC change + // - 0.00005 Sapling-ZEC out + // - 0.00005 t-ZEC fee + auto builder4 = TransactionBuilder(consensusParams, 2, nullptr, params, &view); + builder4.SetFee(5000); + builder4.AddSproutInput(sproutSk, sproutNote, sproutWitness); + builder4.AddSproutOutput(sproutAddr, 6000); + builder4.AddSproutOutput(sproutAddr, 4000); + builder4.AddSaplingOutput(fvk.ovk, pk, 5000); + auto tx4 = builder4.Build().GetTxOrThrow(); + + EXPECT_EQ(tx4.vin.size(), 0); + EXPECT_EQ(tx4.vout.size(), 0); + // TODO: This should be doable in two JoinSplits. + // There's an inefficiency in the implementation. + EXPECT_EQ(tx4.vjoinsplit.size(), 3); + EXPECT_EQ(tx4.vjoinsplit[0].vpub_old, 0); + EXPECT_EQ(tx4.vjoinsplit[0].vpub_new, 0); + EXPECT_EQ(tx4.vjoinsplit[1].vpub_old, 0); + EXPECT_EQ(tx4.vjoinsplit[1].vpub_new, 0); + EXPECT_EQ(tx4.vjoinsplit[2].vpub_old, 0); + EXPECT_EQ(tx4.vjoinsplit[2].vpub_new, 10000); + EXPECT_EQ(tx4.vShieldedSpend.size(), 0); + EXPECT_EQ(tx4.vShieldedOutput.size(), 1); + EXPECT_EQ(tx4.valueBalance, -5000); + + EXPECT_TRUE(ContextualCheckTransaction(tx4, state, 4, 0)); + EXPECT_EQ(state.GetRejectReason(), ""); + // Revert to default RegtestDeactivateSapling(); } +TEST(TransactionBuilder, ThrowsOnSproutOutputWithoutParams) +{ + auto consensusParams = Params().GetConsensus(); + auto sk = libzcash::SproutSpendingKey::random(); + auto addr = sk.address(); + + auto builder = TransactionBuilder(consensusParams, 1); + ASSERT_THROW(builder.AddSproutOutput(addr, 10), std::runtime_error); +} + TEST(TransactionBuilder, ThrowsOnTransparentInputWithoutKeyStore) { SelectParams(CBaseChainParams::REGTEST); diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp index c90ac968076..d8743cee4e0 100644 --- a/src/transaction_builder.cpp +++ b/src/transaction_builder.cpp @@ -8,6 +8,7 @@ #include "pubkey.h" #include "rpc/protocol.h" #include "script/sign.h" +#include "utilmoneystr.h" #include #include @@ -49,7 +50,16 @@ std::string TransactionBuilderResult::GetError() { TransactionBuilder::TransactionBuilder( const Consensus::Params& consensusParams, int nHeight, - CKeyStore* keystore) : consensusParams(consensusParams), nHeight(nHeight), keystore(keystore) + CKeyStore* keystore, + ZCJoinSplit* sproutParams, + CCoinsViewCache* coinsView, + CCriticalSection* cs_coinsView) : + consensusParams(consensusParams), + nHeight(nHeight), + keystore(keystore), + sproutParams(sproutParams), + coinsView(coinsView), + cs_coinsView(cs_coinsView) { mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight); } @@ -90,6 +100,39 @@ void TransactionBuilder::AddSaplingOutput( mtx.valueBalance -= value; } +void TransactionBuilder::AddSproutInput( + libzcash::SproutSpendingKey sk, + libzcash::SproutNote note, + SproutWitness witness) +{ + if (sproutParams == nullptr) { + throw std::runtime_error("Cannot add Sprout inputs to a TransactionBuilder without Sprout params"); + } + + // Consistency check: all anchors must equal the first one + if (!jsInputs.empty()) { + if (jsInputs[0].witness.root() != witness.root()) { + throw JSONRPCError(RPC_WALLET_ERROR, "Anchor does not match previously-added Sprout spends."); + } + } + + jsInputs.emplace_back(witness, note, sk); +} + +void TransactionBuilder::AddSproutOutput( + libzcash::SproutPaymentAddress to, + CAmount value, + std::array memo) +{ + if (sproutParams == nullptr) { + throw std::runtime_error("Cannot add Sprout outputs to a TransactionBuilder without Sprout params"); + } + + libzcash::JSOutput jsOutput(to, value); + jsOutput.memo = memo; + jsOutputs.push_back(jsOutput); +} + void TransactionBuilder::AddTransparentInput(COutPoint utxo, CScript scriptPubKey, CAmount value) { if (keystore == nullptr) { @@ -118,7 +161,15 @@ void TransactionBuilder::SetFee(CAmount fee) void TransactionBuilder::SendChangeTo(libzcash::SaplingPaymentAddress changeAddr, uint256 ovk) { - zChangeAddr = std::make_pair(ovk, changeAddr); + saplingChangeAddr = std::make_pair(ovk, changeAddr); + sproutChangeAddr = boost::none; + tChangeAddr = boost::none; +} + +void TransactionBuilder::SendChangeTo(libzcash::SproutPaymentAddress changeAddr) +{ + sproutChangeAddr = changeAddr; + saplingChangeAddr = boost::none; tChangeAddr = boost::none; } @@ -129,7 +180,8 @@ void TransactionBuilder::SendChangeTo(CTxDestination& changeAddr) } tChangeAddr = changeAddr; - zChangeAddr = boost::none; + saplingChangeAddr = boost::none; + sproutChangeAddr = boost::none; } TransactionBuilderResult TransactionBuilder::Build() @@ -140,6 +192,12 @@ TransactionBuilderResult TransactionBuilder::Build() // Valid change CAmount change = mtx.valueBalance - fee; + for (auto jsInput : jsInputs) { + change += jsInput.note.value(); + } + for (auto jsOutput : jsOutputs) { + change -= jsOutput.value; + } for (auto tIn : tIns) { change += tIn.value; } @@ -156,9 +214,12 @@ TransactionBuilderResult TransactionBuilder::Build() if (change > 0) { // Send change to the specified change address. If no change address - // was set, send change to the first Sapling address given as input. - if (zChangeAddr) { - AddSaplingOutput(zChangeAddr->first, zChangeAddr->second, change); + // was set, send change to the first Sapling address given as input, + // or the first Sprout address given as input. + if (saplingChangeAddr) { + AddSaplingOutput(saplingChangeAddr->first, saplingChangeAddr->second, change); + } else if (sproutChangeAddr) { + AddSproutOutput(sproutChangeAddr.get(), change); } else if (tChangeAddr) { // tChangeAddr has already been validated. AddTransparentOutput(tChangeAddr.value(), change); @@ -167,6 +228,9 @@ TransactionBuilderResult TransactionBuilder::Build() auto note = spends[0].note; libzcash::SaplingPaymentAddress changeAddr(note.d, note.pk_d); AddSaplingOutput(fvk.ovk, changeAddr, change); + } else if (!jsInputs.empty()) { + auto changeAddr = jsInputs[0].key.address(); + AddSproutOutput(changeAddr, change); } else { return TransactionBuilderResult("Could not determine change address"); } @@ -260,6 +324,22 @@ TransactionBuilderResult TransactionBuilder::Build() mtx.vShieldedOutput.push_back(odesc); } + // + // Sprout JoinSplits + // + + unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES]; + crypto_sign_keypair(mtx.joinSplitPubKey.begin(), joinSplitPrivKey); + + // Create Sprout JSDescriptions + if (!jsInputs.empty() || !jsOutputs.empty()) { + auto result = CreateJSDescriptions(); + if (result) { + librustzcash_sapling_proving_ctx_free(ctx); + return result.get(); + } + } + // // Signatures // @@ -292,6 +372,24 @@ TransactionBuilderResult TransactionBuilder::Build() librustzcash_sapling_proving_ctx_free(ctx); + // Create Sprout joinSplitSig + if (crypto_sign_detached( + mtx.joinSplitSig.data(), NULL, + dataToBeSigned.begin(), 32, + joinSplitPrivKey) != 0) + { + return TransactionBuilderResult("Failed to create Sprout joinSplitSig"); + } + + // Sanity check Sprout joinSplitSig + if (crypto_sign_verify_detached( + mtx.joinSplitSig.data(), + dataToBeSigned.begin(), 32, + mtx.joinSplitPubKey.begin()) != 0) + { + return TransactionBuilderResult("Sprout joinSplitSig sanity check failed"); + } + // Transparent signatures CTransaction txNewConst(mtx); for (int nIn = 0; nIn < mtx.vin.size(); nIn++) { @@ -311,3 +409,289 @@ TransactionBuilderResult TransactionBuilder::Build() return TransactionBuilderResult(CTransaction(mtx)); } + +boost::optional TransactionBuilder::CreateJSDescriptions() +{ + // Copy jsInputs and jsOutputs to more flexible containers + std::deque jsInputsDeque; + for (auto jsInput : jsInputs) { + jsInputsDeque.push_back(jsInput); + } + std::deque jsOutputsDeque; + for (auto jsOutput : jsOutputs) { + jsOutputsDeque.push_back(jsOutput); + } + + // If we have no Sprout shielded inputs, then we do the simpler more-leaky + // process where we just create outputs directly. We save the chaining logic, + // at the expense of leaking the sums of pairs of output values in vpub_old. + if (jsInputs.empty()) { + // Create joinsplits, where each output represents a zaddr recipient. + while (jsOutputsDeque.size() > 0) { + // Default array entries are dummy inputs and outputs + std::array vjsin; + std::array vjsout; + uint64_t vpub_old = 0; + + for (int n = 0; n < ZC_NUM_JS_OUTPUTS && jsOutputsDeque.size() > 0; n++) { + vjsout[n] = jsOutputsDeque.front(); + jsOutputsDeque.pop_front(); + + // Funds are removed from the value pool and enter the private pool + vpub_old += vjsout[n].value; + } + + std::array inputMap; + std::array outputMap; + CreateJSDescription(vpub_old, 0, vjsin, vjsout, inputMap, outputMap); + } + return boost::none; + } + + // At this point, we are guaranteed to have at least one input note. + // Use address of first input note as the temporary change address. + auto changeKey = jsInputsDeque.front().key; + auto changeAddress = changeKey.address(); + + CAmount jsChange = 0; // this is updated after each joinsplit + int changeOutputIndex = -1; // this is updated after each joinsplit if jsChange > 0 + bool vpubOldProcessed = false; // updated when vpub_old for taddr inputs is set in first joinsplit + bool vpubNewProcessed = false; // updated when vpub_new for miner fee and taddr outputs is set in last joinsplit + + CAmount valueOut = 0; + for (auto jsInput : jsInputs) { + valueOut += jsInput.note.value(); + } + for (auto jsOutput : jsOutputs) { + valueOut -= jsOutput.value; + } + CAmount vpubOldTarget = valueOut < 0 ? -valueOut : 0; + CAmount vpubNewTarget = valueOut > 0 ? valueOut : 0; + + // Keep track of treestate within this transaction + boost::unordered_map intermediates; + std::vector previousCommitments; + + while (!vpubNewProcessed) { + // Default array entries are dummy inputs and outputs + std::array vjsin; + std::array vjsout; + uint64_t vpub_old = 0; + uint64_t vpub_new = 0; + + // Set vpub_old in the first joinsplit + if (!vpubOldProcessed) { + vpub_old += vpubOldTarget; // funds flowing from public pool + vpubOldProcessed = true; + } + + CAmount jsInputValue = 0; + uint256 jsAnchor; + + JSDescription prevJoinSplit; + + // Keep track of previous JoinSplit and its commitments + if (mtx.vjoinsplit.size() > 0) { + prevJoinSplit = mtx.vjoinsplit.back(); + } + + // If there is no change, the chain has terminated so we can reset the tracked treestate. + if (jsChange == 0 && mtx.vjoinsplit.size() > 0) { + intermediates.clear(); + previousCommitments.clear(); + } + + // + // Consume change as the first input of the JoinSplit. + // + if (jsChange > 0) { + // Update tree state with previous joinsplit + SproutMerkleTree tree; + { + LOCK(cs_coinsView); + auto it = intermediates.find(prevJoinSplit.anchor); + if (it != intermediates.end()) { + tree = it->second; + } else if (!coinsView->GetSproutAnchorAt(prevJoinSplit.anchor, tree)) { + return TransactionBuilderResult("Could not find previous JoinSplit anchor"); + } + } + + assert(changeOutputIndex != -1); + assert(changeOutputIndex < prevJoinSplit.commitments.size()); + boost::optional changeWitness; + int n = 0; + for (const uint256& commitment : prevJoinSplit.commitments) { + tree.append(commitment); + previousCommitments.push_back(commitment); + if (!changeWitness && changeOutputIndex == n++) { + changeWitness = tree.witness(); + } else if (changeWitness) { + changeWitness.get().append(commitment); + } + } + assert(changeWitness.has_value()); + jsAnchor = tree.root(); + intermediates.insert(std::make_pair(tree.root(), tree)); // chained js are interstitial (found in between block boundaries) + + // Decrypt the change note's ciphertext to retrieve some data we need + ZCNoteDecryption decryptor(changeKey.receiving_key()); + auto hSig = prevJoinSplit.h_sig(*sproutParams, mtx.joinSplitPubKey); + try { + auto plaintext = libzcash::SproutNotePlaintext::decrypt( + decryptor, + prevJoinSplit.ciphertexts[changeOutputIndex], + prevJoinSplit.ephemeralKey, + hSig, + (unsigned char)changeOutputIndex); + + auto note = plaintext.note(changeAddress); + vjsin[0] = libzcash::JSInput(changeWitness.get(), note, changeKey); + + jsInputValue += plaintext.value(); + + LogPrint("zrpcunsafe", "spending change (amount=%s)\n", FormatMoney(plaintext.value())); + + } catch (const std::exception& e) { + return TransactionBuilderResult("Error decrypting output note of previous JoinSplit"); + } + } + + // + // Consume spendable non-change notes + // + for (int n = (jsChange > 0) ? 1 : 0; n < ZC_NUM_JS_INPUTS && jsInputsDeque.size() > 0; n++) { + auto jsInput = jsInputsDeque.front(); + jsInputsDeque.pop_front(); + + // Add history of previous commitments to witness + if (jsChange > 0) { + for (const uint256& commitment : previousCommitments) { + jsInput.witness.append(commitment); + } + if (jsAnchor != jsInput.witness.root()) { + return TransactionBuilderResult("Witness for spendable note does not have same anchor as change input"); + } + } + + // The jsAnchor is null if this JoinSplit is at the start of a new chain + if (jsAnchor.IsNull()) { + jsAnchor = jsInput.witness.root(); + } + + jsInputValue += jsInput.note.value(); + vjsin[n] = jsInput; + } + + // Find recipient to transfer funds to + libzcash::JSOutput recipient; + if (jsOutputsDeque.size() > 0) { + recipient = jsOutputsDeque.front(); + jsOutputsDeque.pop_front(); + } + // `recipient` is now either a valid recipient, or a dummy output with value = 0 + + // Reset change + jsChange = 0; + CAmount outAmount = recipient.value; + + // Set vpub_new in the last joinsplit (when there are no more notes to spend or zaddr outputs to satisfy) + if (jsOutputsDeque.empty() && jsInputsDeque.empty()) { + assert(!vpubNewProcessed); + if (jsInputValue < vpubNewTarget) { + return TransactionBuilderResult( + strprintf("Insufficient funds for vpub_new %s", FormatMoney(vpubNewTarget)) + ); + } + outAmount += vpubNewTarget; + vpub_new += vpubNewTarget; // funds flowing back to public pool + vpubNewProcessed = true; + jsChange = jsInputValue - outAmount; + assert(jsChange >= 0); + } else { + // This is not the last joinsplit, so compute change and any amount still due to the recipient + if (jsInputValue > outAmount) { + jsChange = jsInputValue - outAmount; + } else if (outAmount > jsInputValue) { + // Any amount due is owed to the recipient. Let the miners fee get paid first. + CAmount due = outAmount - jsInputValue; + libzcash::JSOutput recipientDue(recipient.addr, due); + recipientDue.memo = recipient.memo; + jsOutputsDeque.push_front(recipientDue); + + // reduce the amount being sent right now to the value of all inputs + recipient.value = jsInputValue; + } + } + + // create output for recipient + assert(ZC_NUM_JS_OUTPUTS == 2); // If this changes, the logic here will need to be adjusted + vjsout[0] = recipient; + + // create output for any change + if (jsChange > 0) { + vjsout[1] = libzcash::JSOutput(changeAddress, jsChange); + + LogPrint("zrpcunsafe", "generating note for change (amount=%s)\n", FormatMoney(jsChange)); + } + + std::array inputMap; + std::array outputMap; + CreateJSDescription(vpub_old, vpub_new, vjsin, vjsout, inputMap, outputMap); + + if (jsChange > 0) { + changeOutputIndex = -1; + for (size_t i = 0; i < outputMap.size(); i++) { + if (outputMap[i] == 1) { + changeOutputIndex = i; + } + } + assert(changeOutputIndex != -1); + } + } + + return boost::none; +} + +void TransactionBuilder::CreateJSDescription( + uint64_t vpub_old, + uint64_t vpub_new, + std::array vjsin, + std::array vjsout, + std::array& inputMap, + std::array& outputMap) +{ + LogPrint("zrpcunsafe", "%s: creating joinsplit at index %d (vpub_old=%s, vpub_new=%s, in[0]=%s, in[1]=%s, out[0]=%s, out[1]=%s)\n", + mtx.vjoinsplit.size(), + FormatMoney(vpub_old), FormatMoney(vpub_new), + FormatMoney(vjsin[0].note.value()), FormatMoney(vjsin[1].note.value()), + FormatMoney(vjsout[0].value), FormatMoney(vjsout[1].value)); + + uint256 esk; // payment disclosure - secret + + // Generate the proof, this can take over a minute. + JSDescription jsdesc = JSDescription::Randomized( + mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION), + *sproutParams, + mtx.joinSplitPubKey, + vjsin[0].witness.root(), + vjsin, + vjsout, + inputMap, + outputMap, + vpub_old, + vpub_new, + true, //!this->testmode, + &esk); // parameter expects pointer to esk, so pass in address + + { + auto verifier = libzcash::ProofVerifier::Strict(); + if (!jsdesc.Verify(*sproutParams, verifier, mtx.joinSplitPubKey)) { + throw std::runtime_error("error verifying joinsplit"); + } + } + + mtx.vjoinsplit.push_back(jsdesc); + + // TODO: Sprout payment disclosure +} diff --git a/src/transaction_builder.h b/src/transaction_builder.h index 592f4f64db2..43946f498ed 100644 --- a/src/transaction_builder.h +++ b/src/transaction_builder.h @@ -5,6 +5,7 @@ #ifndef TRANSACTION_BUILDER_H #define TRANSACTION_BUILDER_H +#include "coins.h" #include "consensus/params.h" #include "keystore.h" #include "primitives/transaction.h" @@ -13,6 +14,7 @@ #include "uint256.h" #include "zcash/Address.hpp" #include "zcash/IncrementalMerkleTree.hpp" +#include "zcash/JoinSplit.hpp" #include "zcash/Note.hpp" #include "zcash/NoteEncryption.hpp" @@ -72,19 +74,31 @@ class TransactionBuilder Consensus::Params consensusParams; int nHeight; const CKeyStore* keystore; + ZCJoinSplit* sproutParams; + const CCoinsViewCache* coinsView; + CCriticalSection* cs_coinsView; CMutableTransaction mtx; CAmount fee = 10000; std::vector spends; std::vector outputs; + std::vector jsInputs; + std::vector jsOutputs; std::vector tIns; - boost::optional> zChangeAddr; + boost::optional> saplingChangeAddr; + boost::optional sproutChangeAddr; boost::optional tChangeAddr; public: TransactionBuilder() {} - TransactionBuilder(const Consensus::Params& consensusParams, int nHeight, CKeyStore* keyStore = nullptr); + TransactionBuilder( + const Consensus::Params& consensusParams, + int nHeight, + CKeyStore* keyStore = nullptr, + ZCJoinSplit* sproutParams = nullptr, + CCoinsViewCache* coinsView = nullptr, + CCriticalSection* cs_coinsView = nullptr); void SetFee(CAmount fee); @@ -102,6 +116,18 @@ class TransactionBuilder CAmount value, std::array memo = {{0xF6}}); + // Throws if the anchor does not match the anchor used by + // previously-added Sprout inputs. + void AddSproutInput( + libzcash::SproutSpendingKey sk, + libzcash::SproutNote note, + SproutWitness witness); + + void AddSproutOutput( + libzcash::SproutPaymentAddress to, + CAmount value, + std::array memo = {{0xF6}}); + // Assumes that the value correctly corresponds to the provided UTXO. void AddTransparentInput(COutPoint utxo, CScript scriptPubKey, CAmount value); @@ -109,9 +135,22 @@ class TransactionBuilder void SendChangeTo(libzcash::SaplingPaymentAddress changeAddr, uint256 ovk); + void SendChangeTo(libzcash::SproutPaymentAddress); + void SendChangeTo(CTxDestination& changeAddr); TransactionBuilderResult Build(); + +private: + boost::optional CreateJSDescriptions(); + + void CreateJSDescription( + uint64_t vpub_old, + uint64_t vpub_new, + std::array vjsin, + std::array vjsout, + std::array& inputMap, + std::array& outputMap); }; #endif /* TRANSACTION_BUILDER_H */ From 9e8729113cc94a3f4cb6ad8472c329aa29c5becd Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 26 Feb 2019 15:09:55 -0700 Subject: [PATCH 002/127] Split test in to multiple parts --- src/gtest/test_transaction_builder.cpp | 212 +++++++++++++------------ 1 file changed, 114 insertions(+), 98 deletions(-) diff --git a/src/gtest/test_transaction_builder.cpp b/src/gtest/test_transaction_builder.cpp index f6aecb88f0b..6676ef21eec 100644 --- a/src/gtest/test_transaction_builder.cpp +++ b/src/gtest/test_transaction_builder.cpp @@ -73,7 +73,7 @@ class TransactionBuilderCoinsViewDB : public CCoinsView { } }; -TEST(TransactionBuilder, Invoke) +TEST(TransactionBuilder, TransparentToSapling) { auto consensusParams = RegtestActivateSapling(); @@ -91,106 +91,121 @@ TEST(TransactionBuilder, Invoke) libzcash::diversifier_t d = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; auto pk = *ivk.address(d); - auto sproutSk = libzcash::SproutSpendingKey::random(); - ZCNoteDecryption sproutDecryptor(sproutSk.receiving_key()); - auto sproutAddr = sproutSk.address(); - // Create a shielding transaction from transparent to Sapling // 0.0005 t-ZEC in, 0.0004 z-ZEC out, 0.0001 t-ZEC fee - auto builder1 = TransactionBuilder(consensusParams, 1, &keystore); - builder1.AddTransparentInput(COutPoint(), scriptPubKey, 50000); - builder1.AddSaplingOutput(fvk_from.ovk, pk, 40000, {}); - auto tx1 = builder1.Build().GetTxOrThrow(); - - EXPECT_EQ(tx1.vin.size(), 1); - EXPECT_EQ(tx1.vout.size(), 0); - EXPECT_EQ(tx1.vjoinsplit.size(), 0); - EXPECT_EQ(tx1.vShieldedSpend.size(), 0); - EXPECT_EQ(tx1.vShieldedOutput.size(), 1); - EXPECT_EQ(tx1.valueBalance, -40000); + auto builder = TransactionBuilder(consensusParams, 1, &keystore); + builder.AddTransparentInput(COutPoint(), scriptPubKey, 50000); + builder.AddSaplingOutput(fvk_from.ovk, pk, 40000, {}); + auto tx = builder.Build().GetTxOrThrow(); + + EXPECT_EQ(tx.vin.size(), 1); + EXPECT_EQ(tx.vout.size(), 0); + EXPECT_EQ(tx.vjoinsplit.size(), 0); + EXPECT_EQ(tx.vShieldedSpend.size(), 0); + EXPECT_EQ(tx.vShieldedOutput.size(), 1); + EXPECT_EQ(tx.valueBalance, -40000); CValidationState state; - EXPECT_TRUE(ContextualCheckTransaction(tx1, state, 2, 0)); + EXPECT_TRUE(ContextualCheckTransaction(tx, state, 2, 0)); EXPECT_EQ(state.GetRejectReason(), ""); - // Prepare to spend the note that was just created - auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt( - tx1.vShieldedOutput[0].encCiphertext, ivk, tx1.vShieldedOutput[0].ephemeralKey, tx1.vShieldedOutput[0].cm); - ASSERT_EQ(static_cast(maybe_pt), true); - auto maybe_note = maybe_pt.get().note(ivk); - ASSERT_EQ(static_cast(maybe_note), true); - auto note = maybe_note.get(); - SaplingMerkleTree tree; - tree.append(tx1.vShieldedOutput[0].cm); - auto anchor = tree.root(); - auto witness = tree.witness(); + // Revert to default + RegtestDeactivateSapling(); +} + +TEST(TransactionBuilder, SaplingToSapling) { + auto consensusParams = RegtestActivateSapling(); + + auto sk = libzcash::SaplingSpendingKey::random(); + auto expsk = sk.expanded_spending_key(); + auto fvk = sk.full_viewing_key(); + auto pa = sk.default_address(); + auto testNote = GetTestSaplingNote(pa, 40000); + // Create a Sapling-only transaction // 0.0004 z-ZEC in, 0.00025 z-ZEC out, 0.0001 t-ZEC fee, 0.00005 z-ZEC change - auto builder2 = TransactionBuilder(consensusParams, 2); - builder2.AddSaplingSpend(expsk, note, anchor, witness); + auto builder = TransactionBuilder(consensusParams, 2); + builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); + // Check that trying to add a different anchor fails // TODO: the following check can be split out in to another test - ASSERT_THROW(builder2.AddSaplingSpend(expsk, note, uint256(), witness), UniValue); + ASSERT_THROW(builder.AddSaplingSpend(expsk, testNote.note, uint256(), testNote.tree.witness()), UniValue); - builder2.AddSaplingOutput(fvk.ovk, pk, 25000, {}); - auto tx2 = builder2.Build().GetTxOrThrow(); + builder.AddSaplingOutput(fvk.ovk, pa, 25000, {}); + auto tx = builder.Build().GetTxOrThrow(); - EXPECT_EQ(tx2.vin.size(), 0); - EXPECT_EQ(tx2.vout.size(), 0); - EXPECT_EQ(tx2.vjoinsplit.size(), 0); - EXPECT_EQ(tx2.vShieldedSpend.size(), 1); - EXPECT_EQ(tx2.vShieldedOutput.size(), 2); - EXPECT_EQ(tx2.valueBalance, 10000); + EXPECT_EQ(tx.vin.size(), 0); + EXPECT_EQ(tx.vout.size(), 0); + EXPECT_EQ(tx.vjoinsplit.size(), 0); + EXPECT_EQ(tx.vShieldedSpend.size(), 1); + EXPECT_EQ(tx.vShieldedOutput.size(), 2); + EXPECT_EQ(tx.valueBalance, 10000); - EXPECT_TRUE(ContextualCheckTransaction(tx2, state, 3, 0)); + CValidationState state; + EXPECT_TRUE(ContextualCheckTransaction(tx, state, 3, 0)); EXPECT_EQ(state.GetRejectReason(), ""); + // Revert to default + RegtestDeactivateSapling(); +} + +TEST(TransactionBuilder, SaplingToSprout) { + auto consensusParams = RegtestActivateSapling(); + + auto sk = libzcash::SaplingSpendingKey::random(); + auto expsk = sk.expanded_spending_key(); + auto pa = sk.default_address(); + + auto testNote = GetTestSaplingNote(pa, 40000); + + auto sproutSk = libzcash::SproutSpendingKey::random(); + auto sproutAddr = sproutSk.address(); + // Create a Sapling-to-Sprout transaction (reusing the note from above) // - 0.0004 Sapling-ZEC in - 0.00025 Sprout-ZEC out // - 0.00005 Sapling-ZEC change // - 0.0001 t-ZEC fee - auto builder3 = TransactionBuilder(consensusParams, 2, nullptr, params); - builder3.AddSaplingSpend(expsk, note, anchor, witness); - builder3.AddSproutOutput(sproutAddr, 25000); - auto tx3 = builder3.Build().GetTxOrThrow(); - - EXPECT_EQ(tx3.vin.size(), 0); - EXPECT_EQ(tx3.vout.size(), 0); - EXPECT_EQ(tx3.vjoinsplit.size(), 1); - EXPECT_EQ(tx3.vjoinsplit[0].vpub_old, 25000); - EXPECT_EQ(tx3.vjoinsplit[0].vpub_new, 0); - EXPECT_EQ(tx3.vShieldedSpend.size(), 1); - EXPECT_EQ(tx3.vShieldedOutput.size(), 1); - EXPECT_EQ(tx3.valueBalance, 35000); - - EXPECT_TRUE(ContextualCheckTransaction(tx3, state, 3, 0)); + auto builder = TransactionBuilder(consensusParams, 2, nullptr, params); + builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); + builder.AddSproutOutput(sproutAddr, 25000); + auto tx = builder.Build().GetTxOrThrow(); + + EXPECT_EQ(tx.vin.size(), 0); + EXPECT_EQ(tx.vout.size(), 0); + EXPECT_EQ(tx.vjoinsplit.size(), 1); + EXPECT_EQ(tx.vjoinsplit[0].vpub_old, 25000); + EXPECT_EQ(tx.vjoinsplit[0].vpub_new, 0); + EXPECT_EQ(tx.vShieldedSpend.size(), 1); + EXPECT_EQ(tx.vShieldedOutput.size(), 1); + EXPECT_EQ(tx.valueBalance, 35000); + + CValidationState state; + EXPECT_TRUE(ContextualCheckTransaction(tx, state, 3, 0)); EXPECT_EQ(state.GetRejectReason(), ""); - // Prepare to spend the Sprout note that was just created + // Revert to default + RegtestDeactivateSapling(); +} + +TEST(TransactionBuilder, SproutToSproutAndSapling) { + auto consensusParams = RegtestActivateSapling(); + + auto sk = libzcash::SaplingSpendingKey::random(); + auto fvk = sk.full_viewing_key(); + auto pa = sk.default_address(); + + auto sproutSk = libzcash::SproutSpendingKey::random(); + auto sproutAddr = sproutSk.address(); + + auto wtx = GetValidSproutReceive(*params, sproutSk, 25000, true); + auto sproutNote = GetSproutNote(*params, sproutSk, wtx, 0, 1); + SproutMerkleTree sproutTree; - libzcash::SproutNote sproutNote; - SproutWitness sproutWitness; for (int i = 0; i < ZC_NUM_JS_OUTPUTS; i++) { - sproutTree.append(tx3.vjoinsplit[0].commitments[i]); - - auto hSig = tx3.vjoinsplit[0].h_sig(*params, tx3.joinSplitPubKey); - try { - auto pt = libzcash::SproutNotePlaintext::decrypt( - sproutDecryptor, - tx3.vjoinsplit[0].ciphertexts[i], - tx3.vjoinsplit[0].ephemeralKey, - hSig, - (unsigned char)i); - sproutNote = pt.note(sproutAddr); - sproutWitness = sproutTree.witness(); - break; - } catch (const std::exception& e) { - // One of the outputs must be ours - assert(i + 1 < ZC_NUM_JS_OUTPUTS); - } + sproutTree.append(wtx.vjoinsplit[0].commitments[i]); } - + SproutWitness sproutWitness = sproutTree.witness(); // Fake a view with the Sprout note in it auto rt = sproutTree.root(); TransactionBuilderCoinsViewDB fakeDB; @@ -203,30 +218,31 @@ TEST(TransactionBuilder, Invoke) // - 0.00005 Sprout-ZEC change // - 0.00005 Sapling-ZEC out // - 0.00005 t-ZEC fee - auto builder4 = TransactionBuilder(consensusParams, 2, nullptr, params, &view); - builder4.SetFee(5000); - builder4.AddSproutInput(sproutSk, sproutNote, sproutWitness); - builder4.AddSproutOutput(sproutAddr, 6000); - builder4.AddSproutOutput(sproutAddr, 4000); - builder4.AddSaplingOutput(fvk.ovk, pk, 5000); - auto tx4 = builder4.Build().GetTxOrThrow(); - - EXPECT_EQ(tx4.vin.size(), 0); - EXPECT_EQ(tx4.vout.size(), 0); + auto builder = TransactionBuilder(consensusParams, 2, nullptr, params, &view); + builder.SetFee(5000); + builder.AddSproutInput(sproutSk, sproutNote, sproutWitness); + builder.AddSproutOutput(sproutAddr, 6000); + builder.AddSproutOutput(sproutAddr, 4000); + builder.AddSaplingOutput(fvk.ovk, pa, 5000); + auto tx = builder.Build().GetTxOrThrow(); + + EXPECT_EQ(tx.vin.size(), 0); + EXPECT_EQ(tx.vout.size(), 0); // TODO: This should be doable in two JoinSplits. // There's an inefficiency in the implementation. - EXPECT_EQ(tx4.vjoinsplit.size(), 3); - EXPECT_EQ(tx4.vjoinsplit[0].vpub_old, 0); - EXPECT_EQ(tx4.vjoinsplit[0].vpub_new, 0); - EXPECT_EQ(tx4.vjoinsplit[1].vpub_old, 0); - EXPECT_EQ(tx4.vjoinsplit[1].vpub_new, 0); - EXPECT_EQ(tx4.vjoinsplit[2].vpub_old, 0); - EXPECT_EQ(tx4.vjoinsplit[2].vpub_new, 10000); - EXPECT_EQ(tx4.vShieldedSpend.size(), 0); - EXPECT_EQ(tx4.vShieldedOutput.size(), 1); - EXPECT_EQ(tx4.valueBalance, -5000); - - EXPECT_TRUE(ContextualCheckTransaction(tx4, state, 4, 0)); + EXPECT_EQ(tx.vjoinsplit.size(), 3); + EXPECT_EQ(tx.vjoinsplit[0].vpub_old, 0); + EXPECT_EQ(tx.vjoinsplit[0].vpub_new, 0); + EXPECT_EQ(tx.vjoinsplit[1].vpub_old, 0); + EXPECT_EQ(tx.vjoinsplit[1].vpub_new, 0); + EXPECT_EQ(tx.vjoinsplit[2].vpub_old, 0); + EXPECT_EQ(tx.vjoinsplit[2].vpub_new, 10000); + EXPECT_EQ(tx.vShieldedSpend.size(), 0); + EXPECT_EQ(tx.vShieldedOutput.size(), 1); + EXPECT_EQ(tx.valueBalance, -5000); + + CValidationState state; + EXPECT_TRUE(ContextualCheckTransaction(tx, state, 4, 0)); EXPECT_EQ(state.GetRejectReason(), ""); // Revert to default From 6281cc32b7ed349ad2de9be4584406ef05171e8e Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Thu, 28 Feb 2019 11:19:36 -0700 Subject: [PATCH 003/127] Use a custom error type if creating joinsplit descriptions fails --- src/transaction_builder.cpp | 37 ++++++++++++++++++++++++------------- src/transaction_builder.h | 2 +- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp index d8743cee4e0..a2e515834d4 100644 --- a/src/transaction_builder.cpp +++ b/src/transaction_builder.cpp @@ -64,6 +64,17 @@ TransactionBuilder::TransactionBuilder( mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight); } +// This exception is thrown in certain scenarios when building JoinSplits fails. +struct JSDException : public std::exception +{ + JSDException (const std::string msg_) : msg(msg_) {} + + const char* what() { return msg.c_str(); } + +private: + std::string msg; +}; + void TransactionBuilder::AddSaplingSpend( libzcash::SaplingExpandedSpendingKey expsk, libzcash::SaplingNote note, @@ -333,10 +344,14 @@ TransactionBuilderResult TransactionBuilder::Build() // Create Sprout JSDescriptions if (!jsInputs.empty() || !jsOutputs.empty()) { - auto result = CreateJSDescriptions(); - if (result) { + try { + CreateJSDescriptions(); + } catch (JSDException e) { + librustzcash_sapling_proving_ctx_free(ctx); + return TransactionBuilderResult(e.what()); + } catch (std::runtime_error e) { librustzcash_sapling_proving_ctx_free(ctx); - return result.get(); + throw e; } } @@ -410,7 +425,7 @@ TransactionBuilderResult TransactionBuilder::Build() return TransactionBuilderResult(CTransaction(mtx)); } -boost::optional TransactionBuilder::CreateJSDescriptions() +void TransactionBuilder::CreateJSDescriptions() { // Copy jsInputs and jsOutputs to more flexible containers std::deque jsInputsDeque; @@ -445,7 +460,7 @@ boost::optional TransactionBuilder::CreateJSDescriptio std::array outputMap; CreateJSDescription(vpub_old, 0, vjsin, vjsout, inputMap, outputMap); } - return boost::none; + return; } // At this point, we are guaranteed to have at least one input note. @@ -513,7 +528,7 @@ boost::optional TransactionBuilder::CreateJSDescriptio if (it != intermediates.end()) { tree = it->second; } else if (!coinsView->GetSproutAnchorAt(prevJoinSplit.anchor, tree)) { - return TransactionBuilderResult("Could not find previous JoinSplit anchor"); + throw JSDException("Could not find previous JoinSplit anchor"); } } @@ -553,7 +568,7 @@ boost::optional TransactionBuilder::CreateJSDescriptio LogPrint("zrpcunsafe", "spending change (amount=%s)\n", FormatMoney(plaintext.value())); } catch (const std::exception& e) { - return TransactionBuilderResult("Error decrypting output note of previous JoinSplit"); + throw JSDException("Error decrypting output note of previous JoinSplit"); } } @@ -570,7 +585,7 @@ boost::optional TransactionBuilder::CreateJSDescriptio jsInput.witness.append(commitment); } if (jsAnchor != jsInput.witness.root()) { - return TransactionBuilderResult("Witness for spendable note does not have same anchor as change input"); + throw JSDException("Witness for spendable note does not have same anchor as change input"); } } @@ -599,9 +614,7 @@ boost::optional TransactionBuilder::CreateJSDescriptio if (jsOutputsDeque.empty() && jsInputsDeque.empty()) { assert(!vpubNewProcessed); if (jsInputValue < vpubNewTarget) { - return TransactionBuilderResult( - strprintf("Insufficient funds for vpub_new %s", FormatMoney(vpubNewTarget)) - ); + throw JSDException(strprintf("Insufficient funds for vpub_new %s", FormatMoney(vpubNewTarget))); } outAmount += vpubNewTarget; vpub_new += vpubNewTarget; // funds flowing back to public pool @@ -649,8 +662,6 @@ boost::optional TransactionBuilder::CreateJSDescriptio assert(changeOutputIndex != -1); } } - - return boost::none; } void TransactionBuilder::CreateJSDescription( diff --git a/src/transaction_builder.h b/src/transaction_builder.h index 43946f498ed..ee3c4e7ae45 100644 --- a/src/transaction_builder.h +++ b/src/transaction_builder.h @@ -142,7 +142,7 @@ class TransactionBuilder TransactionBuilderResult Build(); private: - boost::optional CreateJSDescriptions(); + void CreateJSDescriptions(); void CreateJSDescription( uint64_t vpub_old, From 74de4ddc465d76e58cef98a38168aa20d4312f8d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 24 Jun 2018 16:03:43 -0400 Subject: [PATCH 004/127] depends: Use full path to cargo binary The native binaries generated in the depends system are available on the path, but system binaries are still visible. This change ensures we use cargo from the depends system rather than whatever might be installed locally. --- depends/packages/librustzcash.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/packages/librustzcash.mk b/depends/packages/librustzcash.mk index a47c757de80..0d2fc3dd24b 100644 --- a/depends/packages/librustzcash.mk +++ b/depends/packages/librustzcash.mk @@ -27,7 +27,7 @@ define $(package)_preprocess_cmds endef define $(package)_build_cmds - cargo build --package librustzcash $($(package)_build_opts) + $(host_prefix)/native/bin/cargo build --package librustzcash $($(package)_build_opts) endef define $(package)_stage_cmds From d7ab9545116f4cf20ba9c803d8a253f639d83546 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 25 Jun 2018 13:43:46 -0400 Subject: [PATCH 005/127] depends: Generalise the rust package cross-compilation functions --- depends/funcs.mk | 4 ++-- depends/packages/librustzcash.mk | 8 +++++++- depends/packages/rust.mk | 22 +++++++++++++++------- depends/patches/librustzcash/cargo.config | 3 --- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/depends/funcs.mk b/depends/funcs.mk index 3d89de8a703..f17b246a4c8 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -59,8 +59,8 @@ $(eval $(1)_build_id:=$(shell echo -n "$($(1)_build_id_long)" | $(build_SHA256SU final_build_id_long+=$($(package)_build_id_long) #override platform specific files and hashes -$(eval $(1)_file_name=$(if $($(1)_file_name_$(host_os)),$($(1)_file_name_$(host_os)),$($(1)_file_name))) -$(eval $(1)_sha256_hash=$(if $($(1)_sha256_hash_$(host_os)),$($(1)_sha256_hash_$(host_os)),$($(1)_sha256_hash))) +$(eval $(1)_file_name=$(if $($(1)_exact_file_name),$($(1)_exact_file_name),$(if $($(1)_file_name_$(host_os)),$($(1)_file_name_$(host_os)),$($(1)_file_name)))) +$(eval $(1)_sha256_hash=$(if $($(1)_exact_sha256_hash),$($(1)_exact_sha256_hash),$(if $($(1)_sha256_hash_$(host_os)),$($(1)_sha256_hash_$(host_os)),$($(1)_sha256_hash)))) #compute package-specific paths $(1)_build_subdir?=. diff --git a/depends/packages/librustzcash.mk b/depends/packages/librustzcash.mk index 0d2fc3dd24b..9bc8ee543ec 100644 --- a/depends/packages/librustzcash.mk +++ b/depends/packages/librustzcash.mk @@ -8,15 +8,21 @@ $(package)_git_commit=06da3b9ac8f278e5d4ae13088cf0a4c03d2c13f5 $(package)_dependencies=rust $(rust_crates) $(package)_patches=cargo.config 0001-Start-using-cargo-clippy-for-CI.patch remove-dev-dependencies.diff +$(package)_rust_target=$(if $(rust_rust_target_$(canonical_host)),$(rust_rust_target_$(canonical_host)),$(canonical_host)) + ifeq ($(host_os),mingw32) $(package)_library_file=target/x86_64-pc-windows-gnu/release/rustzcash.lib +else ifneq ($(canonical_host),$(build)) +$(package)_library_file=target/$($(package)_rust_target)/release/librustzcash.a else $(package)_library_file=target/release/librustzcash.a endif define $(package)_set_vars $(package)_build_opts=--frozen --release -$(package)_build_opts_mingw32=--target=x86_64-pc-windows-gnu +ifneq ($(canonical_host),$(build)) +$(package)_build_opts+=--target=$($(package)_rust_target) +endif endef define $(package)_preprocess_cmds diff --git a/depends/packages/rust.mk b/depends/packages/rust.mk index 18d5b131647..b8227ff93aa 100644 --- a/depends/packages/rust.mk +++ b/depends/packages/rust.mk @@ -5,12 +5,20 @@ $(package)_file_name_linux=rust-$($(package)_version)-x86_64-unknown-linux-gnu.t $(package)_sha256_hash_linux=e024698320d76b74daf0e6e71be3681a1e7923122e3ebd03673fcac3ecc23810 $(package)_file_name_darwin=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz $(package)_sha256_hash_darwin=f0dfba507192f9b5c330b5984ba71d57d434475f3d62bd44a39201e36fa76304 -$(package)_file_name_mingw32=rust-$($(package)_version)-x86_64-pc-windows-gnu.tar.gz -$(package)_sha256_hash_mingw32=358e1435347c67dbf33aa9cad6fe501a833d6633ed5d5aa1863d5dffa0349be9 -ifeq ($(host_os),mingw32) +# Mapping from GCC canonical hosts to Rust targets +# If a mapping is not present, we assume they are identical +$(package)_rust_target_x86_64-w64-mingw32=x86_64-pc-windows-gnu + +# Mapping from Rust targets to SHA-256 hashes +$(package)_rust_std_sha256_hash_x86_64-pc-windows-gnu=cad5f1454d591c13eeb3657f1c9dbfeb30e648f59680bd0765b94c63e7afc49e + +ifneq ($(canonical_host),$(build)) +$(package)_rust_target=$(if $($(package)_rust_target_$(canonical_host)),$($(package)_rust_target_$(canonical_host)),$(canonical_host)) +$(package)_exact_file_name=rust-std-$($(package)_version)-$($(package)_rust_target).tar.gz +$(package)_exact_sha256_hash=$($(package)_rust_std_sha256_hash_$($(package)_rust_target)) $(package)_build_subdir=buildos -$(package)_extra_sources = $($(package)_file_name_$(build_os)) +$(package)_extra_sources=$($(package)_file_name_$(build_os)) define $(package)_fetch_cmds $(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ @@ -22,15 +30,15 @@ define $(package)_extract_cmds echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ echo "$($(package)_sha256_hash_$(build_os)) $($(package)_source_dir)/$($(package)_file_name_$(build_os))" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ - mkdir mingw32 && \ - tar --strip-components=1 -xf $($(package)_source) -C mingw32 && \ + mkdir $(canonical_host) && \ + tar --strip-components=1 -xf $($(package)_source) -C $(canonical_host) && \ mkdir buildos && \ tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_file_name_$(build_os)) -C buildos endef define $(package)_stage_cmds ./install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig && \ - cp -r ../mingw32/rust-std-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu $($(package)_staging_dir)$(host_prefix)/native/lib/rustlib + ../$(canonical_host)/install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig endef else diff --git a/depends/patches/librustzcash/cargo.config b/depends/patches/librustzcash/cargo.config index a0252d1c681..84d447afb62 100644 --- a/depends/patches/librustzcash/cargo.config +++ b/depends/patches/librustzcash/cargo.config @@ -18,6 +18,3 @@ replace-with = "vendored-sources" [source.vendored-sources] directory = "CRATE_REGISTRY" - -[target.x86_64-pc-windows-gnu] -linker = "x86_64-w64-mingw32-gcc" From d2cd57c0f27c68485be3d311b08992bf9158d1e2 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 25 Jun 2018 14:12:44 -0400 Subject: [PATCH 006/127] depends: Add rust-std hash for aarch64-unknown-linux-gnu Usage on Debian / Ubuntu: > $ sudo apt install g++-aarch64-linux-gnu > $ HOST=aarch64-linux-gnu ./zcutil/build.sh Currently fails to cross-compile due to later configuration issues in the depends system that need to be worked around. --- depends/packages/rust.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/depends/packages/rust.mk b/depends/packages/rust.mk index b8227ff93aa..b892d8b7265 100644 --- a/depends/packages/rust.mk +++ b/depends/packages/rust.mk @@ -11,6 +11,7 @@ $(package)_sha256_hash_darwin=f0dfba507192f9b5c330b5984ba71d57d434475f3d62bd44a3 $(package)_rust_target_x86_64-w64-mingw32=x86_64-pc-windows-gnu # Mapping from Rust targets to SHA-256 hashes +$(package)_rust_std_sha256_hash_aarch64-unknown-linux-gnu=346efe3aef2aff7b71a611bf7661bcec5f9bc4025a599c2866ec5fd330247cb9 $(package)_rust_std_sha256_hash_x86_64-pc-windows-gnu=cad5f1454d591c13eeb3657f1c9dbfeb30e648f59680bd0765b94c63e7afc49e ifneq ($(canonical_host),$(build)) From 56df83d710ad1aa6c90460cdf81a346adb0d19a7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 13 Mar 2019 06:39:12 +0000 Subject: [PATCH 007/127] depends: Compile bdb with --disable-atomics on aarch64 This sidesteps the problem where the atomics check tries to run a test binary, which cannot be performed during cross compilation. We should replace this with a better solution in future. Part of #3710. --- depends/packages/bdb.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk index 6b385f2ab59..21019aeb71f 100644 --- a/depends/packages/bdb.mk +++ b/depends/packages/bdb.mk @@ -9,6 +9,7 @@ define $(package)_set_vars $(package)_config_opts=--disable-shared --enable-cxx --disable-replication $(package)_config_opts_mingw32=--enable-mingw $(package)_config_opts_linux=--with-pic +$(package)_config_opts_aarch64=--disable-atomicsupport $(package)_cxxflags=-std=c++11 endef From b1ef5eaef923b74e1055682ca97af5a4f1d3faef Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 13 Mar 2019 06:41:23 +0000 Subject: [PATCH 008/127] depends: Update .gitignore --- depends/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/depends/.gitignore b/depends/.gitignore index 1f163897b9e..3cb4b9ac155 100644 --- a/depends/.gitignore +++ b/depends/.gitignore @@ -7,3 +7,4 @@ x86_64* i686* mips* arm* +aarch64* From 98cfe4228c376b9224f8f72085a4fcb2cdca9cc4 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 13 Mar 2019 07:34:31 +0000 Subject: [PATCH 009/127] configure: Guess -march for libsnark OPTFLAGS instead of hard-coding When cross-compiling, this will remove the -march flag entirely unless the user specifies CONFIGURE_FLAGS="--with-gcc-arch=". --- build-aux/m4/ax_compiler_vendor.m4 | 117 +++++++++++++ build-aux/m4/ax_gcc_archflag.m4 | 267 +++++++++++++++++++++++++++++ build-aux/m4/ax_gcc_x86_cpuid.m4 | 89 ++++++++++ configure.ac | 4 + src/Makefile.am | 4 +- 5 files changed, 479 insertions(+), 2 deletions(-) create mode 100644 build-aux/m4/ax_compiler_vendor.m4 create mode 100644 build-aux/m4/ax_gcc_archflag.m4 create mode 100644 build-aux/m4/ax_gcc_x86_cpuid.m4 diff --git a/build-aux/m4/ax_compiler_vendor.m4 b/build-aux/m4/ax_compiler_vendor.m4 new file mode 100644 index 00000000000..f06e865405c --- /dev/null +++ b/build-aux/m4/ax_compiler_vendor.m4 @@ -0,0 +1,117 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPILER_VENDOR +# +# DESCRIPTION +# +# Determine the vendor of the C, C++ or Fortran compiler. The vendor is +# returned in the cache variable $ax_cv_c_compiler_vendor for C, +# $ax_cv_cxx_compiler_vendor for C++ or $ax_cv_fc_compiler_vendor for +# (modern) Fortran. The value is one of "intel", "ibm", "pathscale", +# "clang" (LLVM), "cray", "fujitsu", "sdcc", "sx", "portland" (PGI), "gnu" +# (GCC), "sun" (Oracle Developer Studio), "hp", "dec", "borland", +# "comeau", "kai", "lcc", "sgi", "microsoft", "metrowerks", "watcom", +# "tcc" (Tiny CC) or "unknown" (if the compiler cannot be determined). +# +# To check for a Fortran compiler, you must first call AC_FC_PP_SRCEXT +# with an appropriate preprocessor-enabled extension. For example: +# +# AC_LANG_PUSH([Fortran]) +# AC_PROG_FC +# AC_FC_PP_SRCEXT([F]) +# AX_COMPILER_VENDOR +# AC_LANG_POP([Fortran]) +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2008 Matteo Frigo +# Copyright (c) 2018-19 John Zaitseff +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 30 + +AC_DEFUN([AX_COMPILER_VENDOR], [dnl + AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, [dnl + dnl If you modify this list of vendors, please add similar support + dnl to ax_compiler_version.m4 if at all possible. + dnl + dnl Note: Do NOT check for GCC first since some other compilers + dnl define __GNUC__ to remain compatible with it. Compilers that + dnl are very slow to start (such as Intel) are listed first. + + vendors=" + intel: __ICC,__ECC,__INTEL_COMPILER + ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__,__ibmxl__ + pathscale: __PATHCC__,__PATHSCALE__ + clang: __clang__ + cray: _CRAYC + fujitsu: __FUJITSU + sdcc: SDCC,__SDCC + sx: _SX + portland: __PGI + gnu: __GNUC__ + sun: __SUNPRO_C,__SUNPRO_CC,__SUNPRO_F90,__SUNPRO_F95 + hp: __HP_cc,__HP_aCC + dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER + borland: __BORLANDC__,__CODEGEARC__,__TURBOC__ + comeau: __COMO__ + kai: __KCC + lcc: __LCC__ + sgi: __sgi,sgi + microsoft: _MSC_VER + metrowerks: __MWERKS__ + watcom: __WATCOMC__ + tcc: __TINYC__ + unknown: UNKNOWN + " + for ventest in $vendors; do + case $ventest in + *:) + vendor=$ventest + continue + ;; + *) + vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" + ;; + esac + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[ +#if !($vencpp) + thisisanerror; +#endif + ]])], [break]) + done + + ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1` + ]) +])dnl diff --git a/build-aux/m4/ax_gcc_archflag.m4 b/build-aux/m4/ax_gcc_archflag.m4 new file mode 100644 index 00000000000..c52b9b296e9 --- /dev/null +++ b/build-aux/m4/ax_gcc_archflag.m4 @@ -0,0 +1,267 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_gcc_archflag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_ARCHFLAG([PORTABLE?], [ACTION-SUCCESS], [ACTION-FAILURE]) +# +# DESCRIPTION +# +# This macro tries to guess the "native" arch corresponding to the target +# architecture for use with gcc's -march=arch or -mtune=arch flags. If +# found, the cache variable $ax_cv_gcc_archflag is set to this flag and +# ACTION-SUCCESS is executed; otherwise $ax_cv_gcc_archflag is set to +# "unknown" and ACTION-FAILURE is executed. The default ACTION-SUCCESS is +# to add $ax_cv_gcc_archflag to the end of $CFLAGS. +# +# PORTABLE? should be either [yes] (default) or [no]. In the former case, +# the flag is set to -mtune (or equivalent) so that the architecture is +# only used for tuning, but the instruction set used is still portable. In +# the latter case, the flag is set to -march (or equivalent) so that +# architecture-specific instructions are enabled. +# +# The user can specify --with-gcc-arch= in order to override the +# macro's choice of architecture, or --without-gcc-arch to disable this. +# +# When cross-compiling, or if $CC is not gcc, then ACTION-FAILURE is +# called unless the user specified --with-gcc-arch manually. +# +# Requires macros: AX_CHECK_COMPILE_FLAG, AX_GCC_X86_CPUID +# +# (The main emphasis here is on recent CPUs, on the principle that doing +# high-performance computing on old hardware is uncommon.) +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2008 Matteo Frigo +# Copyright (c) 2014 Tsukasa Oi +# Copyright (c) 2017-2018 Alexey Kopytov +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 22 + +AC_DEFUN([AX_GCC_ARCHFLAG], +[AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_SED]) +AC_REQUIRE([AX_COMPILER_VENDOR]) + +AC_ARG_WITH(gcc-arch, [AS_HELP_STRING([--with-gcc-arch=], [use architecture for gcc -march/-mtune, instead of guessing])], + ax_gcc_arch=$withval, ax_gcc_arch=yes) + +AC_MSG_CHECKING([for gcc architecture flag]) +AC_MSG_RESULT([]) +AC_CACHE_VAL(ax_cv_gcc_archflag, +[ +ax_cv_gcc_archflag="unknown" + +if test "$GCC" = yes; then + +if test "x$ax_gcc_arch" = xyes; then +ax_gcc_arch="" +if test "$cross_compiling" = no; then +case $host_cpu in + i[[3456]]86*|x86_64*|amd64*) # use cpuid codes + AX_GCC_X86_CPUID(0) + AX_GCC_X86_CPUID(1) + case $ax_cv_gcc_x86_cpuid_0 in + *:756e6547:6c65746e:49656e69) # Intel + case $ax_cv_gcc_x86_cpuid_1 in + *5[[4578]]?:*:*:*) ax_gcc_arch="pentium-mmx pentium" ;; + *5[[123]]?:*:*:*) ax_gcc_arch=pentium ;; + *0?61?:*:*:*|?61?:*:*:*|61?:*:*:*) ax_gcc_arch=pentiumpro ;; + *0?6[[356]]?:*:*:*|?6[[356]]?:*:*:*|6[[356]]?:*:*:*) ax_gcc_arch="pentium2 pentiumpro" ;; + *0?6[[78ab]]?:*:*:*|?6[[78ab]]?:*:*:*|6[[78ab]]?:*:*:*) ax_gcc_arch="pentium3 pentiumpro" ;; + *0?6[[9d]]?:*:*:*|?6[[9d]]?:*:*:*|6[[9d]]?:*:*:*|*1?65?:*:*:*) ax_gcc_arch="pentium-m pentium3 pentiumpro" ;; + *0?6e?:*:*:*|?6e?:*:*:*|6e?:*:*:*) ax_gcc_arch="yonah pentium-m pentium3 pentiumpro" ;; + *0?6f?:*:*:*|?6f?:*:*:*|6f?:*:*:*|*1?66?:*:*:*) ax_gcc_arch="core2 pentium-m pentium3 pentiumpro" ;; + *1?6[[7d]]?:*:*:*) ax_gcc_arch="penryn core2 pentium-m pentium3 pentiumpro" ;; + *1?6[[aef]]?:*:*:*|*2?6e?:*:*:*) ax_gcc_arch="nehalem corei7 core2 pentium-m pentium3 pentiumpro" ;; + *2?6[[5cf]]?:*:*:*) ax_gcc_arch="westmere corei7 core2 pentium-m pentium3 pentiumpro" ;; + *2?6[[ad]]?:*:*:*) ax_gcc_arch="sandybridge corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; + *3?6[[ae]]?:*:*:*) ax_gcc_arch="ivybridge core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; + *3?6[[cf]]?:*:*:*|*4?6[[56]]?:*:*:*) ax_gcc_arch="haswell core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; + *3?6d?:*:*:*|*4?6[[7f]]?:*:*:*|*5?66?:*:*:*) ax_gcc_arch="broadwell core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; + *1?6c?:*:*:*|*2?6[[67]]?:*:*:*|*3?6[[56]]?:*:*:*) ax_gcc_arch="bonnell atom core2 pentium-m pentium3 pentiumpro" ;; + *3?67?:*:*:*|*[[45]]?6[[ad]]?:*:*:*) ax_gcc_arch="silvermont atom core2 pentium-m pentium3 pentiumpro" ;; + *000?f[[012]]?:*:*:*|?f[[012]]?:*:*:*|f[[012]]?:*:*:*) ax_gcc_arch="pentium4 pentiumpro" ;; + *000?f[[346]]?:*:*:*|?f[[346]]?:*:*:*|f[[346]]?:*:*:*) ax_gcc_arch="nocona prescott pentium4 pentiumpro" ;; + # fallback + *5??:*:*:*) ax_gcc_arch=pentium ;; + *??6??:*:*:*) ax_gcc_arch="core2 pentiumpro" ;; + *6??:*:*:*) ax_gcc_arch=pentiumpro ;; + *00??f??:*:*:*|??f??:*:*:*|?f??:*:*:*|f??:*:*:*) ax_gcc_arch="pentium4 pentiumpro" ;; + esac ;; + *:68747541:444d4163:69746e65) # AMD + case $ax_cv_gcc_x86_cpuid_1 in + *5[[67]]?:*:*:*) ax_gcc_arch=k6 ;; + *5[[8]]?:*:*:*) ax_gcc_arch="k6-2 k6" ;; + *5[[9d]]?:*:*:*) ax_gcc_arch="k6-3 k6" ;; + *6[[12]]?:*:*:*) ax_gcc_arch="athlon k7" ;; + *6[[34]]?:*:*:*) ax_gcc_arch="athlon-tbird k7" ;; + *6[[678a]]?:*:*:*) ax_gcc_arch="athlon-xp athlon-4 athlon k7" ;; + *000?f[[4578bcef]]?:*:*:*|?f[[4578bcef]]?:*:*:*|f[[4578bcef]]?:*:*:*|*001?f[[4578bcf]]?:*:*:*|1?f[[4578bcf]]?:*:*:*) ax_gcc_arch="athlon64 k8" ;; + *002?f[[13457bcf]]?:*:*:*|2?f[[13457bcf]]?:*:*:*|*004?f[[138bcf]]?:*:*:*|4?f[[138bcf]]?:*:*:*|*005?f[[df]]?:*:*:*|5?f[[df]]?:*:*:*|*006?f[[8bcf]]?:*:*:*|6?f[[8bcf]]?:*:*:*|*007?f[[cf]]?:*:*:*|7?f[[cf]]?:*:*:*|*00c?f1?:*:*:*|c?f1?:*:*:*|*020?f3?:*:*:*|20?f3?:*:*:*) ax_gcc_arch="athlon64-sse3 k8-sse3 athlon64 k8" ;; + *010?f[[245689a]]?:*:*:*|10?f[[245689a]]?:*:*:*|*030?f1?:*:*:*|30?f1?:*:*:*) ax_gcc_arch="barcelona amdfam10 k8" ;; + *050?f[[12]]?:*:*:*|50?f[[12]]?:*:*:*) ax_gcc_arch="btver1 amdfam10 k8" ;; + *060?f1?:*:*:*|60?f1?:*:*:*) ax_gcc_arch="bdver1 amdfam10 k8" ;; + *060?f2?:*:*:*|60?f2?:*:*:*|*061?f[[03]]?:*:*:*|61?f[[03]]?:*:*:*) ax_gcc_arch="bdver2 bdver1 amdfam10 k8" ;; + *063?f0?:*:*:*|63?f0?:*:*:*) ax_gcc_arch="bdver3 bdver2 bdver1 amdfam10 k8" ;; + *07[[03]]?f0?:*:*:*|7[[03]]?f0?:*:*:*) ax_gcc_arch="btver2 btver1 amdfam10 k8" ;; + # fallback + *0[[13]]??f??:*:*:*|[[13]]??f??:*:*:*) ax_gcc_arch="barcelona amdfam10 k8" ;; + *020?f??:*:*:*|20?f??:*:*:*) ax_gcc_arch="athlon64-sse3 k8-sse3 athlon64 k8" ;; + *05??f??:*:*:*|5??f??:*:*:*) ax_gcc_arch="btver1 amdfam10 k8" ;; + *060?f??:*:*:*|60?f??:*:*:*) ax_gcc_arch="bdver1 amdfam10 k8" ;; + *061?f??:*:*:*|61?f??:*:*:*) ax_gcc_arch="bdver2 bdver1 amdfam10 k8" ;; + *06??f??:*:*:*|6??f??:*:*:*) ax_gcc_arch="bdver3 bdver2 bdver1 amdfam10 k8" ;; + *070?f??:*:*:*|70?f??:*:*:*) ax_gcc_arch="btver2 btver1 amdfam10 k8" ;; + *???f??:*:*:*) ax_gcc_arch="amdfam10 k8" ;; + esac ;; + *:746e6543:736c7561:48727561) # IDT / VIA (Centaur) + case $ax_cv_gcc_x86_cpuid_1 in + *54?:*:*:*) ax_gcc_arch=winchip-c6 ;; + *5[[89]]?:*:*:*) ax_gcc_arch=winchip2 ;; + *66?:*:*:*) ax_gcc_arch=winchip2 ;; + *6[[78]]?:*:*:*) ax_gcc_arch=c3 ;; + *6[[9adf]]?:*:*:*) ax_gcc_arch="c3-2 c3" ;; + esac ;; + esac + if test x"$ax_gcc_arch" = x; then # fallback + case $host_cpu in + i586*) ax_gcc_arch=pentium ;; + i686*) ax_gcc_arch=pentiumpro ;; + esac + fi + ;; + + sparc*) + AC_PATH_PROG([PRTDIAG], [prtdiag], [prtdiag], [$PATH:/usr/platform/`uname -i`/sbin/:/usr/platform/`uname -m`/sbin/]) + cputype=`(((grep cpu /proc/cpuinfo | cut -d: -f2) ; ($PRTDIAG -v |grep -i sparc) ; grep -i cpu /var/run/dmesg.boot ) | head -n 1) 2> /dev/null` + cputype=`echo "$cputype" | tr -d ' -' | $SED 's/SPARCIIi/SPARCII/' |tr $as_cr_LETTERS $as_cr_letters` + case $cputype in + *ultrasparciv*) ax_gcc_arch="ultrasparc4 ultrasparc3 ultrasparc v9" ;; + *ultrasparciii*) ax_gcc_arch="ultrasparc3 ultrasparc v9" ;; + *ultrasparc*) ax_gcc_arch="ultrasparc v9" ;; + *supersparc*|*tms390z5[[05]]*) ax_gcc_arch="supersparc v8" ;; + *hypersparc*|*rt62[[056]]*) ax_gcc_arch="hypersparc v8" ;; + *cypress*) ax_gcc_arch=cypress ;; + esac ;; + + alphaev5) ax_gcc_arch=ev5 ;; + alphaev56) ax_gcc_arch=ev56 ;; + alphapca56) ax_gcc_arch="pca56 ev56" ;; + alphapca57) ax_gcc_arch="pca57 pca56 ev56" ;; + alphaev6) ax_gcc_arch=ev6 ;; + alphaev67) ax_gcc_arch=ev67 ;; + alphaev68) ax_gcc_arch="ev68 ev67" ;; + alphaev69) ax_gcc_arch="ev69 ev68 ev67" ;; + alphaev7) ax_gcc_arch="ev7 ev69 ev68 ev67" ;; + alphaev79) ax_gcc_arch="ev79 ev7 ev69 ev68 ev67" ;; + + powerpc*) + cputype=`((grep cpu /proc/cpuinfo | head -n 1 | cut -d: -f2 | cut -d, -f1 | $SED 's/ //g') ; /usr/bin/machine ; /bin/machine; grep CPU /var/run/dmesg.boot | head -n 1 | cut -d" " -f2) 2> /dev/null` + cputype=`echo $cputype | $SED -e 's/ppc//g;s/ *//g'` + case $cputype in + *750*) ax_gcc_arch="750 G3" ;; + *740[[0-9]]*) ax_gcc_arch="$cputype 7400 G4" ;; + *74[[4-5]][[0-9]]*) ax_gcc_arch="$cputype 7450 G4" ;; + *74[[0-9]][[0-9]]*) ax_gcc_arch="$cputype G4" ;; + *970*) ax_gcc_arch="970 G5 power4";; + *POWER4*|*power4*|*gq*) ax_gcc_arch="power4 970";; + *POWER5*|*power5*|*gr*|*gs*) ax_gcc_arch="power5 power4 970";; + 603ev|8240) ax_gcc_arch="$cputype 603e 603";; + *POWER7*) ax_gcc_arch="power7";; + *POWER8*) ax_gcc_arch="power8";; + *POWER9*) ax_gcc_arch="power9";; + *POWER10*) ax_gcc_arch="power10";; + *) ax_gcc_arch=$cputype ;; + esac + ax_gcc_arch="$ax_gcc_arch powerpc" + ;; + aarch64) + cpuimpl=`grep 'CPU implementer' /proc/cpuinfo 2> /dev/null | cut -d: -f2 | tr -d " " | head -n 1` + cpuarch=`grep 'CPU architecture' /proc/cpuinfo 2> /dev/null | cut -d: -f2 | tr -d " " | head -n 1` + cpuvar=`grep 'CPU variant' /proc/cpuinfo 2> /dev/null | cut -d: -f2 | tr -d " " | head -n 1` + case $cpuimpl in + 0x42) case $cpuarch in + 8) case $cpuvar in + 0x0) ax_gcc_arch="thunderx2t99 vulcan armv8.1-a armv8-a+lse armv8-a native" ;; + esac + ;; + esac + ;; + 0x43) case $cpuarch in + 8) case $cpuvar in + 0x0) ax_gcc_arch="thunderx armv8-a native" ;; + 0x1) ax_gcc_arch="thunderx+lse armv8.1-a armv8-a+lse armv8-a native" ;; + esac + ;; + esac + ;; + esac + ;; +esac +fi # not cross-compiling +fi # guess arch + +if test "x$ax_gcc_arch" != x -a "x$ax_gcc_arch" != xno; then +if test "x[]m4_default([$1],yes)" = xyes; then # if we require portable code + flag_prefixes="-mtune=" + if test "x$ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor" = xclang; then flag_prefixes="-march="; fi + # -mcpu=$arch and m$arch generate nonportable code on every arch except + # x86. And some other arches (e.g. Alpha) don't accept -mtune. Grrr. + case $host_cpu in i*86|x86_64*|amd64*) flag_prefixes="$flag_prefixes -mcpu= -m";; esac +else + flag_prefixes="-march= -mcpu= -m" +fi +for flag_prefix in $flag_prefixes; do + for arch in $ax_gcc_arch; do + flag="$flag_prefix$arch" + AX_CHECK_COMPILE_FLAG($flag, [if test "x$ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor" = xclang; then + if test "x[]m4_default([$1],yes)" = xyes; then + if test "x$flag" = "x-march=$arch"; then flag=-mtune=$arch; fi + fi + fi; ax_cv_gcc_archflag=$flag; break]) + done + test "x$ax_cv_gcc_archflag" = xunknown || break +done +fi + +fi # $GCC=yes +]) +AC_MSG_CHECKING([for gcc architecture flag]) +AC_MSG_RESULT($ax_cv_gcc_archflag) +if test "x$ax_cv_gcc_archflag" = xunknown; then + m4_default([$3],:) +else + m4_default([$2], [CFLAGS="$CFLAGS $ax_cv_gcc_archflag"]) +fi +]) diff --git a/build-aux/m4/ax_gcc_x86_cpuid.m4 b/build-aux/m4/ax_gcc_x86_cpuid.m4 new file mode 100644 index 00000000000..df954658ee1 --- /dev/null +++ b/build-aux/m4/ax_gcc_x86_cpuid.m4 @@ -0,0 +1,89 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_gcc_x86_cpuid.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_X86_CPUID(OP) +# AX_GCC_X86_CPUID_COUNT(OP, COUNT) +# +# DESCRIPTION +# +# On Pentium and later x86 processors, with gcc or a compiler that has a +# compatible syntax for inline assembly instructions, run a small program +# that executes the cpuid instruction with input OP. This can be used to +# detect the CPU type. AX_GCC_X86_CPUID_COUNT takes an additional COUNT +# parameter that gets passed into register ECX before calling cpuid. +# +# On output, the values of the eax, ebx, ecx, and edx registers are stored +# as hexadecimal strings as "eax:ebx:ecx:edx" in the cache variable +# ax_cv_gcc_x86_cpuid_OP. +# +# If the cpuid instruction fails (because you are running a +# cross-compiler, or because you are not using gcc, or because you are on +# a processor that doesn't have this instruction), ax_cv_gcc_x86_cpuid_OP +# is set to the string "unknown". +# +# This macro mainly exists to be used in AX_GCC_ARCHFLAG. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2008 Matteo Frigo +# Copyright (c) 2015 Michael Petch +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 10 + +AC_DEFUN([AX_GCC_X86_CPUID], +[AX_GCC_X86_CPUID_COUNT($1, 0) +]) + +AC_DEFUN([AX_GCC_X86_CPUID_COUNT], +[AC_REQUIRE([AC_PROG_CC]) +AC_LANG_PUSH([C]) +AC_CACHE_CHECK(for x86 cpuid $1 output, ax_cv_gcc_x86_cpuid_$1, + [AC_RUN_IFELSE([AC_LANG_PROGRAM([#include ], [ + int op = $1, level = $2, eax, ebx, ecx, edx; + FILE *f; + __asm__ __volatile__ ("xchg %%ebx, %1\n" + "cpuid\n" + "xchg %%ebx, %1\n" + : "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx) + : "a" (op), "2" (level)); + + f = fopen("conftest_cpuid", "w"); if (!f) return 1; + fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx); + fclose(f); + return 0; +])], + [ax_cv_gcc_x86_cpuid_$1=`cat conftest_cpuid`; rm -f conftest_cpuid], + [ax_cv_gcc_x86_cpuid_$1=unknown; rm -f conftest_cpuid], + [ax_cv_gcc_x86_cpuid_$1=unknown])]) +AC_LANG_POP([C]) +]) diff --git a/configure.ac b/configure.ac index e6a9ea3f345..ac855644eed 100644 --- a/configure.ac +++ b/configure.ac @@ -760,6 +760,9 @@ else LIBSNARK_DEPINST="$prefix" fi +# Set optimization flags for libsnark +AX_GCC_ARCHFLAG([no], [LIBSNARK_OPTFLAGS="-O2 $ax_cv_gcc_archflag"], [LIBSNARK_OPTFLAGS="-O2"]) + # Additional Zcash flags AX_CHECK_COMPILE_FLAG([-fwrapv],[CXXFLAGS="$CXXFLAGS -fwrapv"]) AX_CHECK_COMPILE_FLAG([-fno-strict-aliasing],[CXXFLAGS="$CXXFLAGS -fno-strict-aliasing"]) @@ -898,6 +901,7 @@ AC_SUBST(ZMQ_LIBS) AC_SUBST(GMP_LIBS) AC_SUBST(GMPXX_LIBS) AC_SUBST(LIBSNARK_DEPINST) +AC_SUBST(LIBSNARK_OPTFLAGS) AC_SUBST(LIBZCASH_LIBS) AC_SUBST(PROTON_LIBS) AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile src/test/buildenv.py]) diff --git a/src/Makefile.am b/src/Makefile.am index 5733549ff91..2df328cc047 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,10 +64,10 @@ LIBSNARK_CONFIG_FLAGS += PLATFORM=darwin endif $(LIBSNARK): $(wildcard snark/src/*) - $(AM_V_at) CC="$(CC)" CXX="$(CXX)" AR="$(AR)" CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" + $(AM_V_at) CC="$(CC)" CXX="$(CXX)" AR="$(AR)" CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="$(LIBSNARK_OPTFLAGS)" libsnark-tests: $(wildcard snark/src/*) - $(AM_V_at) CC="$(CC)" CXX="$(CXX)" AR="$(AR)" CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" + $(AM_V_at) CC="$(CC)" CXX="$(CXX)" AR="$(AR)" CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="$(LIBSNARK_OPTFLAGS)" $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) From ee9ff2ce74e4162b9b0c48f53560cdbba45136e7 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 19 Mar 2019 12:55:55 -0600 Subject: [PATCH 010/127] Rename and update comment --- src/transaction_builder.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp index a2e515834d4..fbe1043a5f6 100644 --- a/src/transaction_builder.cpp +++ b/src/transaction_builder.cpp @@ -65,9 +65,9 @@ TransactionBuilder::TransactionBuilder( } // This exception is thrown in certain scenarios when building JoinSplits fails. -struct JSDException : public std::exception +struct JSDescException : public std::exception { - JSDException (const std::string msg_) : msg(msg_) {} + JSDescException (const std::string msg_) : msg(msg_) {} const char* what() { return msg.c_str(); } @@ -225,8 +225,9 @@ TransactionBuilderResult TransactionBuilder::Build() if (change > 0) { // Send change to the specified change address. If no change address - // was set, send change to the first Sapling address given as input, - // or the first Sprout address given as input. + // was set, send change to the first Sapling address given as input + // if any; otherwise the first Sprout address given as input. + // (A t-address can only be used as the change address if explicitly set.) if (saplingChangeAddr) { AddSaplingOutput(saplingChangeAddr->first, saplingChangeAddr->second, change); } else if (sproutChangeAddr) { @@ -346,7 +347,7 @@ TransactionBuilderResult TransactionBuilder::Build() if (!jsInputs.empty() || !jsOutputs.empty()) { try { CreateJSDescriptions(); - } catch (JSDException e) { + } catch (JSDescException e) { librustzcash_sapling_proving_ctx_free(ctx); return TransactionBuilderResult(e.what()); } catch (std::runtime_error e) { @@ -528,7 +529,7 @@ void TransactionBuilder::CreateJSDescriptions() if (it != intermediates.end()) { tree = it->second; } else if (!coinsView->GetSproutAnchorAt(prevJoinSplit.anchor, tree)) { - throw JSDException("Could not find previous JoinSplit anchor"); + throw JSDescException("Could not find previous JoinSplit anchor"); } } @@ -568,7 +569,7 @@ void TransactionBuilder::CreateJSDescriptions() LogPrint("zrpcunsafe", "spending change (amount=%s)\n", FormatMoney(plaintext.value())); } catch (const std::exception& e) { - throw JSDException("Error decrypting output note of previous JoinSplit"); + throw JSDescException("Error decrypting output note of previous JoinSplit"); } } @@ -585,7 +586,7 @@ void TransactionBuilder::CreateJSDescriptions() jsInput.witness.append(commitment); } if (jsAnchor != jsInput.witness.root()) { - throw JSDException("Witness for spendable note does not have same anchor as change input"); + throw JSDescException("Witness for spendable note does not have same anchor as change input"); } } @@ -614,7 +615,7 @@ void TransactionBuilder::CreateJSDescriptions() if (jsOutputsDeque.empty() && jsInputsDeque.empty()) { assert(!vpubNewProcessed); if (jsInputValue < vpubNewTarget) { - throw JSDException(strprintf("Insufficient funds for vpub_new %s", FormatMoney(vpubNewTarget))); + throw JSDescException(strprintf("Insufficient funds for vpub_new %s", FormatMoney(vpubNewTarget))); } outAmount += vpubNewTarget; vpub_new += vpubNewTarget; // funds flowing back to public pool From 7420711d9e1d5de0b10985e186609165d21a1bfb Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Wed, 20 Mar 2019 09:04:32 +0200 Subject: [PATCH 011/127] Electric Coin Company --- code_of_conduct.md | 2 +- contrib/debian/control | 2 +- contrib/debian/copyright | 2 +- zcutil/make-release.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code_of_conduct.md b/code_of_conduct.md index 82446d3831d..ceb5f506d62 100644 --- a/code_of_conduct.md +++ b/code_of_conduct.md @@ -25,7 +25,7 @@ reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. Note that contributors may be volunteers -who do not represent Zcash Company. They are free to express their own +who do not represent Electric Coin Company. They are free to express their own opinions so long as they adhere to these guidelines. By adopting this Code of Conduct, project maintainers commit themselves to diff --git a/contrib/debian/control b/contrib/debian/control index b0c220cf01c..c2c9d17d555 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -1,7 +1,7 @@ Source: zcash Section: utils Priority: optional -Maintainer: Zcash Company +Maintainer: Electric Coin Company Homepage: https://z.cash Build-Depends: autoconf, automake, bsdmainutils, build-essential, git, g++-multilib, libc6-dev, libtool, diff --git a/contrib/debian/copyright b/contrib/debian/copyright index 14cbe9e9aef..de1fdf97d19 100644 --- a/contrib/debian/copyright +++ b/contrib/debian/copyright @@ -1,6 +1,6 @@ Format: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?rev=174 Upstream-Name: Zcash -Upstream-Contact: Zcash Company +Upstream-Contact: Electric Coin Company Source: https://github.com/zcash/zcash Files: * diff --git a/zcutil/make-release.py b/zcutil/make-release.py index bc47d0b1909..303048ed00b 100755 --- a/zcutil/make-release.py +++ b/zcutil/make-release.py @@ -292,7 +292,7 @@ def gen_release_notes(release, releasefrom): @phase('Updating debian changelog.') def update_debian_changelog(release): os.environ['DEBEMAIL'] = 'team@z.cash' - os.environ['DEBFULLNAME'] = 'Zcash Company' + os.environ['DEBFULLNAME'] = 'Electric Coin Company' sh_log( 'debchange', '--newversion', release.debversion, From e0774bf8d320787be668773d492bb99bc69213a1 Mon Sep 17 00:00:00 2001 From: zebambam Date: Wed, 20 Mar 2019 08:55:58 -0700 Subject: [PATCH 012/127] Minor speling changes --- responsible_disclosure.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/responsible_disclosure.md b/responsible_disclosure.md index ddd6ca93b9c..1f3c9401bba 100644 --- a/responsible_disclosure.md +++ b/responsible_disclosure.md @@ -43,11 +43,11 @@ CDHCrwSovQRMHtoOWZijBNobO2y1d0FkUpzNlNw44Ssw0Vo= In the case where we become aware of security issues affecting other projects that has never affected Zcash, our intention is to inform those projects of security issues on a best effort basis. -In the case where we fix a security issue in Zcash that also affects the following neighboring projects, our intention is to engage in responsible disclosures with them as described in https://github.com/RD-Crypto-Spec/Responsible-Disclosure, subject to the deviations described in the that section. +In the case where we fix a security issue in Zcash that also affects the following neighboring projects, our intention is to engage in responsible disclosures with them as described in https://github.com/RD-Crypto-Spec/Responsible-Disclosure, subject to the deviations described in the section at the bottom of this document. ## Bilateral Responsible Disclosure Agreements -We have set up agreements with the following neighboring projects to share vulnerability information, subject to the deviaions described in the next section. +We have set up agreements with the following neighboring projects to share vulnerability information, subject to the deviations described in the next section. Specifically, we have agreed to engage in responsible disclosures for security issues affecting Zcash technology with the following contacts: From 361647d8dae304251da6fc39c22d626b45ace239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Wed, 20 Mar 2019 21:09:51 +0100 Subject: [PATCH 013/127] Update _COPYRIGHT_YEAR in configure.ac to 2019 Update _COPYRIGHT_YEAR in configure.ac to 2019 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 93efbb117c4..46e79b1107c 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ define(_CLIENT_VERSION_BUILD, 25) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) -define(_COPYRIGHT_YEAR, 2018) +define(_COPYRIGHT_YEAR, 2019) AC_INIT([Zcash],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_SUFFIX(_ZC_BUILD_VAL)],[https://github.com/zcash/zcash/issues],[zcash]) AC_CONFIG_SRCDIR([src/main.cpp]) AC_CONFIG_HEADERS([src/config/bitcoin-config.h]) From e1df250a0df342733eb4f4a180663dd750e5dbd4 Mon Sep 17 00:00:00 2001 From: Larry Ruane Date: Wed, 20 Mar 2019 16:29:06 -0600 Subject: [PATCH 014/127] fix enable-debug build DB_COINS undefined --- src/zcbenchmarks.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index 5283d50975e..d91e36d730a 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -453,9 +453,11 @@ double benchmark_increment_sapling_note_witnesses(size_t nTxs) // This class is based on the class CCoinsViewDB, but with limited functionality. // The construtor and the functions `GetCoins` and `HaveCoins` come directly from // CCoinsViewDB, but the rest are either mocks and/or don't really do anything. + +// The following constant is a duplicate of the one found in txdb.cpp +static const char DB_COINS = 'c'; + class FakeCoinsViewDB : public CCoinsView { - // The following constant is a duplicate of the one found in txdb.cpp - static const char DB_COINS = 'c'; CDBWrapper db; From 6cf0e50b56b39eda3cd2cf91e99a594f36e01618 Mon Sep 17 00:00:00 2001 From: Larry Ruane Date: Tue, 19 Mar 2019 13:28:02 -0600 Subject: [PATCH 015/127] add -addressindex changes for bitcore insight block explorer --- src/addressindex.h | 225 ++++++++++++++++++++++++++++++++++++++++++ src/init.cpp | 17 ++++ src/main.cpp | 144 ++++++++++++++++++++++++++- src/main.h | 20 ++-- src/script/script.cpp | 42 ++++++++ src/script/script.h | 6 ++ src/serialize.h | 11 +++ src/txdb.cpp | 83 ++++++++++++++++ src/txdb.h | 21 ++++ 9 files changed, 558 insertions(+), 11 deletions(-) create mode 100644 src/addressindex.h diff --git a/src/addressindex.h b/src/addressindex.h new file mode 100644 index 00000000000..e83c9fc2fdc --- /dev/null +++ b/src/addressindex.h @@ -0,0 +1,225 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_ADDRESSINDEX_H +#define BITCOIN_ADDRESSINDEX_H + +#include "uint256.h" +#include "amount.h" +#include "script/script.h" + +struct CAddressUnspentKey { + unsigned int type; + uint160 hashBytes; + uint256 txhash; + size_t index; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 57; + } + template + void Serialize(Stream& s) const { + ser_writedata8(s, type); + hashBytes.Serialize(s); + txhash.Serialize(s); + ser_writedata32(s, index); + } + template + void Unserialize(Stream& s) { + type = ser_readdata8(s); + hashBytes.Unserialize(s); + txhash.Unserialize(s); + index = ser_readdata32(s); + } + + CAddressUnspentKey(unsigned int addressType, uint160 addressHash, uint256 txid, size_t indexValue) { + type = addressType; + hashBytes = addressHash; + txhash = txid; + index = indexValue; + } + + CAddressUnspentKey() { + SetNull(); + } + + void SetNull() { + type = 0; + hashBytes.SetNull(); + txhash.SetNull(); + index = 0; + } +}; + +struct CAddressUnspentValue { + CAmount satoshis; + CScript script; + int blockHeight; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(satoshis); + READWRITE(*(CScriptBase*)(&script)); + READWRITE(blockHeight); + } + + CAddressUnspentValue(CAmount sats, CScript scriptPubKey, int height) { + satoshis = sats; + script = scriptPubKey; + blockHeight = height; + } + + CAddressUnspentValue() { + SetNull(); + } + + void SetNull() { + satoshis = -1; + script.clear(); + blockHeight = 0; + } + + bool IsNull() const { + return (satoshis == -1); + } +}; + +struct CAddressIndexKey { + unsigned int type; + uint160 hashBytes; + int blockHeight; + unsigned int txindex; + uint256 txhash; + size_t index; + bool spending; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 66; + } + template + void Serialize(Stream& s) const { + ser_writedata8(s, type); + hashBytes.Serialize(s); + // Heights are stored big-endian for key sorting in LevelDB + ser_writedata32be(s, blockHeight); + ser_writedata32be(s, txindex); + txhash.Serialize(s); + ser_writedata32(s, index); + char f = spending; + ser_writedata8(s, f); + } + template + void Unserialize(Stream& s) { + type = ser_readdata8(s); + hashBytes.Unserialize(s); + blockHeight = ser_readdata32be(s); + txindex = ser_readdata32be(s); + txhash.Unserialize(s); + index = ser_readdata32(s); + char f = ser_readdata8(s); + spending = f; + } + + CAddressIndexKey(unsigned int addressType, uint160 addressHash, int height, int blockindex, + uint256 txid, size_t indexValue, bool isSpending) { + type = addressType; + hashBytes = addressHash; + blockHeight = height; + txindex = blockindex; + txhash = txid; + index = indexValue; + spending = isSpending; + } + + CAddressIndexKey() { + SetNull(); + } + + void SetNull() { + type = 0; + hashBytes.SetNull(); + blockHeight = 0; + txindex = 0; + txhash.SetNull(); + index = 0; + spending = false; + } + +}; + +struct CAddressIndexIteratorKey { + unsigned int type; + uint160 hashBytes; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 21; + } + template + void Serialize(Stream& s) const { + ser_writedata8(s, type); + hashBytes.Serialize(s); + } + template + void Unserialize(Stream& s) { + type = ser_readdata8(s); + hashBytes.Unserialize(s); + } + + CAddressIndexIteratorKey(unsigned int addressType, uint160 addressHash) { + type = addressType; + hashBytes = addressHash; + } + + CAddressIndexIteratorKey() { + SetNull(); + } + + void SetNull() { + type = 0; + hashBytes.SetNull(); + } +}; + +struct CAddressIndexIteratorHeightKey { + unsigned int type; + uint160 hashBytes; + int blockHeight; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 25; + } + template + void Serialize(Stream& s) const { + ser_writedata8(s, type); + hashBytes.Serialize(s); + ser_writedata32be(s, blockHeight); + } + template + void Unserialize(Stream& s) { + type = ser_readdata8(s); + hashBytes.Unserialize(s); + blockHeight = ser_readdata32be(s); + } + + CAddressIndexIteratorHeightKey(unsigned int addressType, uint160 addressHash, int height) { + type = addressType; + hashBytes = addressHash; + blockHeight = height; + } + + CAddressIndexIteratorHeightKey() { + SetNull(); + } + + void SetNull() { + type = 0; + hashBytes.SetNull(); + blockHeight = 0; + } +}; + +#endif // BITCOIN_ADDRESSINDEX_H diff --git a/src/init.cpp b/src/init.cpp index f9da81e877d..ec459e36b21 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -841,6 +841,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(_("RPC method z_mergetoaddress requires -experimentalfeatures.")); } else if (mapArgs.count("-savesproutr1cs")) { return InitError(_("Saving the Sprout R1CS requires -experimentalfeatures.")); + } else if (mapArgs.count("-insightexplorer")) { + return InitError(_("Insight explorer requires -experimentalfeatures.")); } } @@ -1442,6 +1444,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) int64_t nBlockTreeDBCache = nTotalCache / 8; if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", false)) nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB + + // https://github.com/bitpay/bitcoin/commit/c91d78b578a8700a45be936cb5bb0931df8f4b87#diff-c865a8939105e6350a50af02766291b7R1233 + if (GetBoolArg("-insightexplorer", false)) { + if (!GetBoolArg("-txindex", false)) { + return InitError(_("-insightexplorer requires -txindex.")); + } + // increase cache if additional indices are needed + nBlockTreeDBCache = nTotalCache * 3 / 4; + } nTotalCache -= nBlockTreeDBCache; int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache nTotalCache -= nCoinDBCache; @@ -1503,6 +1514,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) break; } + // Check for changed -insightexplorer state + if (fInsightExplorer != GetBoolArg("-insightexplorer", false)) { + strLoadError = _("You need to rebuild the database using -reindex to change -insightexplorer"); + break; + } + // Check for changed -prune state. What we are concerned about is a user who has pruned blocks // in the past, but is now trying to run unpruned. if (fHavePruned && !fPruneMode) { diff --git a/src/main.cpp b/src/main.cpp index d0d8db976d1..4c47cfa0c80 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -67,6 +67,8 @@ bool fExperimentalMode = false; bool fImporting = false; bool fReindex = false; bool fTxIndex = false; +bool fInsightExplorer = false; // insightexplorer +bool fAddressIndex = false; // insightexplorer bool fHavePruned = false; bool fPruneMode = false; bool fIsBareMultisigStd = true; @@ -2226,8 +2228,11 @@ enum DisconnectResult }; /** Undo the effects of this block (with given index) on the UTXO set represented by coins. - * When UNCLEAN or FAILED is returned, view is left in an indeterminate state. */ -DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) + * When UNCLEAN or FAILED is returned, view is left in an indeterminate state. + * The addressIndex will be updated if requested. + */ +static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& state, + const CBlockIndex* pindex, CCoinsViewCache& view, const bool fUpdateAddressIndex) { assert(pindex->GetBlockHash() == view.GetBestBlock()); @@ -2248,11 +2253,35 @@ DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, error("DisconnectBlock(): block and undo data inconsistent"); return DISCONNECT_FAILED; } + std::vector addressIndex; + std::vector addressUnspentIndex; // undo transactions in reverse order for (int i = block.vtx.size() - 1; i >= 0; i--) { const CTransaction &tx = block.vtx[i]; - uint256 hash = tx.GetHash(); + uint256 const hash = tx.GetHash(); + + // insightexplorer + // https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-7ec3c68a81efff79b6ca22ac1f1eabbaR2236 + if (fAddressIndex && fUpdateAddressIndex) { + for (unsigned int k = tx.vout.size(); k-- > 0;) { + const CTxOut &out = tx.vout[k]; + int const scriptType = out.scriptPubKey.Type(); + if (scriptType > 0) { + uint160 const addrHash = out.scriptPubKey.AddressHash(); + + // undo receiving activity + addressIndex.push_back(make_pair( + CAddressIndexKey(scriptType, addrHash, pindex->nHeight, i, hash, k, false), + out.nValue)); + + // undo unspent index + addressUnspentIndex.push_back(make_pair( + CAddressUnspentKey(scriptType, addrHash, hash, k), + CAddressUnspentValue())); + } + } + } // Check that all outputs are available and match the outputs in the block itself // exactly. @@ -2288,6 +2317,27 @@ DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, const CTxInUndo &undo = txundo.vprevout[j]; if (!ApplyTxInUndo(undo, view, out)) fClean = false; + + // insightexplorer + // https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-7ec3c68a81efff79b6ca22ac1f1eabbaR2304 + if (fAddressIndex && fUpdateAddressIndex) { + const CTxIn input = tx.vin[j]; + const CTxOut &prevout = view.GetOutputFor(input); + int const scriptType = prevout.scriptPubKey.Type(); + if (scriptType > 0) { + uint160 const addrHash = prevout.scriptPubKey.AddressHash(); + + // undo spending activity + addressIndex.push_back(make_pair( + CAddressIndexKey(scriptType, addrHash, pindex->nHeight, i, hash, j, true), + prevout.nValue * -1)); + + // restore unspent index + addressUnspentIndex.push_back(make_pair( + CAddressUnspentKey(scriptType, addrHash, input.prevout.hash, input.prevout.n), + CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight))); + } + } } } } @@ -2309,6 +2359,17 @@ DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, // move best block pointer to prevout block view.SetBestBlock(pindex->pprev->GetBlockHash()); + // insightexplorer + if (fAddressIndex && fUpdateAddressIndex) { + if (!pblocktree->EraseAddressIndex(addressIndex)) { + AbortNode(state, "Failed to delete address index"); + return DISCONNECT_FAILED; + } + if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) { + AbortNode(state, "Failed to write address unspent index"); + return DISCONNECT_FAILED; + } + } return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; } @@ -2505,6 +2566,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin std::vector > vPos; vPos.reserve(block.vtx.size()); blockundo.vtxundo.reserve(block.vtx.size() - 1); + std::vector addressIndex; + std::vector addressUnspentIndex; // Construct the incremental merkle tree at the current // block position, @@ -2535,6 +2598,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction &tx = block.vtx[i]; + const uint256 hash = tx.GetHash(); nInputs += tx.vin.size(); nSigOps += GetLegacySigOpCount(tx); @@ -2553,6 +2617,30 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"), REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met"); + // insightexplorer + // https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-7ec3c68a81efff79b6ca22ac1f1eabbaR2597 + if (fAddressIndex) { + for (size_t j = 0; j < tx.vin.size(); j++) { + + const CTxIn input = tx.vin[j]; + const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); + int const scriptType = prevout.scriptPubKey.Type(); + if (scriptType > 0) { + uint160 const addrHash = prevout.scriptPubKey.AddressHash(); + + // record spending activity + addressIndex.push_back(make_pair( + CAddressIndexKey(scriptType, addrHash, pindex->nHeight, i, hash, j, true), + prevout.nValue * -1)); + + // remove address from unspent index + addressUnspentIndex.push_back(make_pair( + CAddressUnspentKey(scriptType, addrHash, input.prevout.hash, input.prevout.n), + CAddressUnspentValue())); + } + } + } + // Add in sigops done by pay-to-script-hash inputs; // this is to prevent a "rogue miner" from creating // an incredibly-expensive-to-validate block. @@ -2575,6 +2663,28 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin control.Add(vChecks); } + // insightexplorer + // https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-7ec3c68a81efff79b6ca22ac1f1eabbaR2656 + if (fAddressIndex) { + for (unsigned int k = 0; k < tx.vout.size(); k++) { + const CTxOut &out = tx.vout[k]; + int const scriptType = out.scriptPubKey.Type(); + if (scriptType > 0) { + uint160 const addrHash = out.scriptPubKey.AddressHash(); + + // record receiving activity + addressIndex.push_back(make_pair( + CAddressIndexKey(scriptType, addrHash, pindex->nHeight, i, hash, k, false), + out.nValue)); + + // record unspent output + addressUnspentIndex.push_back(make_pair( + CAddressUnspentKey(scriptType, addrHash, hash, k), + CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight))); + } + } + } + CTxUndo undoDummy; if (i > 0) { blockundo.vtxundo.push_back(CTxUndo()); @@ -2666,6 +2776,16 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!pblocktree->WriteTxIndex(vPos)) return AbortNode(state, "Failed to write transaction index"); + // insightexplorer + if (fAddressIndex) { + if (!pblocktree->WriteAddressIndex(addressIndex)) { + return AbortNode(state, "Failed to write address index"); + } + if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) { + return AbortNode(state, "Failed to write address unspent index"); + } + } + // add this block to the view's block chain view.SetBestBlock(pindex->GetBlockHash()); @@ -2860,7 +2980,8 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { int64_t nStart = GetTimeMicros(); { CCoinsViewCache view(pcoinsTip); - if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK) + // insightexplorer: update indices (true) + if (DisconnectBlock(block, state, pindexDelete, view, true) != DISCONNECT_OK) return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); assert(view.Flush()); } @@ -4195,6 +4316,12 @@ bool static LoadBlockIndexDB() pblocktree->ReadFlag("txindex", fTxIndex); LogPrintf("%s: transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled"); + // insightexplorer + // Check whether block explorer features are enabled + pblocktree->ReadFlag("insightexplorer", fInsightExplorer); + LogPrintf("%s: insight explorer %s\n", __func__, fAddressIndex ? "enabled" : "disabled"); + fAddressIndex = fInsightExplorer; + // Fill in-memory data BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) { @@ -4283,7 +4410,8 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth } // check level 3: check for inconsistencies during memory-only disconnect of tip blocks if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) { - DisconnectResult res = DisconnectBlock(block, pindex, coins); + // insightexplorer: do not update indices (false) + DisconnectResult res = DisconnectBlock(block, state, pindex, coins, false); if (res == DISCONNECT_FAILED) { return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); } @@ -4530,6 +4658,12 @@ bool InitBlockIndex() { // Use the provided setting for -txindex in the new database fTxIndex = GetBoolArg("-txindex", false); pblocktree->WriteFlag("txindex", fTxIndex); + + // Use the provided setting for -insightexplorer in the new database + fInsightExplorer = GetBoolArg("-insightexplorer", false); + pblocktree->WriteFlag("insightexplorer", fInsightExplorer); + fAddressIndex = fInsightExplorer; + LogPrintf("Initializing databases...\n"); // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) diff --git a/src/main.h b/src/main.h index ce489d9ae9c..3b8c6aff9db 100644 --- a/src/main.h +++ b/src/main.h @@ -26,6 +26,7 @@ #include "tinyformat.h" #include "txmempool.h" #include "uint256.h" +#include "addressindex.h" #include #include @@ -131,6 +132,19 @@ extern bool fImporting; extern bool fReindex; extern int nScriptCheckThreads; extern bool fTxIndex; + +// START insightexplorer +extern bool fInsightExplorer; + +// The following flags enable specific indices (DB tables), but are not exposed as +// separate command-line options; instead they are enabled by experimental feature "-insightexplorer" +// and are always equal to the overall controlling flag, fInsightExplorer. + +// Maintain a full address index, used to query for the balance, txids and unspent outputs for addresses +extern bool fAddressIndex; + +// END insightexplorer + extern bool fIsBareMultisigStd; extern bool fCheckBlockIndex; extern bool fCheckpointsEnabled; @@ -449,12 +463,6 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); /** Functions for validating blocks and updating the block tree */ -/** Undo the effects of this block (with given index) on the UTXO set represented by coins. - * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean - * will be true if no problems were found. Otherwise, the return value will be false in case - * of problems. Note that in any case, coins may be modified. */ -bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL); - /** Apply the effects of this block (with given index) on the UTXO set represented by coins */ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); diff --git a/src/script/script.cpp b/src/script/script.cpp index d5234cae803..32fe34b5949 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -201,6 +201,19 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const return subscript.GetSigOpCount(true); } +// insightexplorer +// https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-f7ca24fb80ddba0f291cb66344ca6fcbR204 +bool CScript::IsPayToPublicKeyHash() const +{ + // Extra-fast test for pay-to-pubkey-hash CScripts: + return (this->size() == 25 && + (*this)[0] == OP_DUP && + (*this)[1] == OP_HASH160 && + (*this)[2] == 0x14 && + (*this)[23] == OP_EQUALVERIFY && + (*this)[24] == OP_CHECKSIG); +} + bool CScript::IsPayToScriptHash() const { // Extra-fast test for pay-to-script-hash CScripts: @@ -227,3 +240,32 @@ bool CScript::IsPushOnly() const } return true; } + +// insightexplorer +int CScript::Type() const +{ + if (this->IsPayToPublicKeyHash()) + return 1; + if (this->IsPayToScriptHash()) + return 2; + // We don't know this script + return 0; +} + +// insightexplorer +uint160 CScript::AddressHash() const +{ + // where the address bytes begin depends on the script type + int start; + if (this->IsPayToPublicKeyHash()) + start = 3; + else if (this->IsPayToScriptHash()) + start = 2; + else { + // unknown script type; return an empty vector + vector hashBytes; + return uint160(hashBytes); + } + vector hashBytes(this->begin()+start, this->begin()+start+20); + return uint160(hashBytes); +} diff --git a/src/script/script.h b/src/script/script.h index 541ece1f519..6f88676118c 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -18,6 +18,8 @@ #include #include +#include "uint256.h" + static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes // Maximum script length in bytes @@ -565,8 +567,12 @@ class CScript : public CScriptBase */ unsigned int GetSigOpCount(const CScript& scriptSig) const; + bool IsPayToPublicKeyHash() const; bool IsPayToScriptHash() const; + int Type() const; + uint160 AddressHash() const; + /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ bool IsPushOnly() const; diff --git a/src/serialize.h b/src/serialize.h index a945650d6f5..ac2db6eddfb 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -110,6 +110,11 @@ template inline void ser_writedata32(Stream &s, uint32_t obj) obj = htole32(obj); s.write((char*)&obj, 4); } +template inline void ser_writedata32be(Stream &s, uint32_t obj) +{ + obj = htobe32(obj); + s.write((char*)&obj, 4); +} template inline void ser_writedata64(Stream &s, uint64_t obj) { obj = htole64(obj); @@ -133,6 +138,12 @@ template inline uint32_t ser_readdata32(Stream &s) s.read((char*)&obj, 4); return le32toh(obj); } +template inline uint32_t ser_readdata32be(Stream &s) +{ + uint32_t obj; + s.read((char*)&obj, 4); + return be32toh(obj); +} template inline uint64_t ser_readdata64(Stream &s) { uint64_t obj; diff --git a/src/txdb.cpp b/src/txdb.cpp index 8749ffcc6b1..162a790140b 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -35,6 +35,10 @@ static const char DB_FLAG = 'F'; static const char DB_REINDEX_FLAG = 'R'; static const char DB_LAST_BLOCK = 'l'; +// insightexplorer +static const char DB_ADDRESSINDEX = 'd'; +static const char DB_ADDRESSUNSPENTINDEX = 'u'; + CCoinsViewDB::CCoinsViewDB(std::string dbName, size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / dbName, nCacheSize, fMemory, fWipe) { } @@ -293,6 +297,85 @@ bool CBlockTreeDB::WriteTxIndex(const std::vector return WriteBatch(batch); } +// START insightexplorer +// https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-81e4f16a1b5d5b7ca25351a63d07cb80R183 +bool CBlockTreeDB::UpdateAddressUnspentIndex(const std::vector &vect) +{ + CDBBatch batch(*this); + for (std::vector::const_iterator it=vect.begin(); it!=vect.end(); it++) { + if (it->second.IsNull()) { + batch.Erase(make_pair(DB_ADDRESSUNSPENTINDEX, it->first)); + } else { + batch.Write(make_pair(DB_ADDRESSUNSPENTINDEX, it->first), it->second); + } + } + return WriteBatch(batch); +} + +bool CBlockTreeDB::ReadAddressUnspentIndex(uint160 addressHash, int type, std::vector &unspentOutputs) +{ + boost::scoped_ptr pcursor(NewIterator()); + + pcursor->Seek(make_pair(DB_ADDRESSUNSPENTINDEX, CAddressIndexIteratorKey(type, addressHash))); + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + if (!(pcursor->GetKey(key) && key.first == DB_ADDRESSUNSPENTINDEX && key.second.hashBytes == addressHash)) + break; + CAddressUnspentValue nValue; + if (pcursor->GetValue(nValue)) + return error("failed to get address unspent value"); + unspentOutputs.push_back(make_pair(key.second, nValue)); + pcursor->Next(); + } + return true; +} + +bool CBlockTreeDB::WriteAddressIndex(const std::vector &vect) { + CDBBatch batch(*this); + for (std::vector::const_iterator it=vect.begin(); it!=vect.end(); it++) + batch.Write(make_pair(DB_ADDRESSINDEX, it->first), it->second); + return WriteBatch(batch); +} + +bool CBlockTreeDB::EraseAddressIndex(const std::vector &vect) { + CDBBatch batch(*this); + for (std::vector::const_iterator it=vect.begin(); it!=vect.end(); it++) + batch.Erase(make_pair(DB_ADDRESSINDEX, it->first)); + return WriteBatch(batch); +} + +bool CBlockTreeDB::ReadAddressIndex( + uint160 addressHash, int type, + std::vector &addressIndex, + int start, int end) +{ + boost::scoped_ptr pcursor(NewIterator()); + + if (start > 0 && end > 0) { + pcursor->Seek(make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorHeightKey(type, addressHash, start))); + } else { + pcursor->Seek(make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorKey(type, addressHash))); + } + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + if (!(pcursor->GetKey(key) && key.first == DB_ADDRESSINDEX && key.second.hashBytes == addressHash)) + break; + if (end > 0 && key.second.blockHeight > end) + break; + CAmount nValue; + if (!pcursor->GetValue(nValue)) + return error("failed to get address index value"); + addressIndex.push_back(make_pair(key.second, nValue)); + pcursor->Next(); + } + return true; +} +// END insightexplorer + bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) { return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0'); } diff --git a/src/txdb.h b/src/txdb.h index a415ad2bbfd..305e93e9c15 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -17,6 +17,18 @@ class CBlockFileInfo; class CBlockIndex; struct CDiskTxPos; + +// START insightexplorer +struct CAddressUnspentKey; +struct CAddressUnspentValue; +struct CAddressIndexKey; +struct CAddressIndexIteratorKey; +struct CAddressIndexIteratorHeightKey; + +typedef std::pair CAddressUnspentDbEntry; +typedef std::pair CAddressIndexDbEntry; +// END insightexplorer + class uint256; //! -dbcache default (MiB) @@ -70,6 +82,15 @@ class CBlockTreeDB : public CDBWrapper bool ReadReindexing(bool &fReindex); bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos); bool WriteTxIndex(const std::vector > &list); + + // START insightexplorer + bool UpdateAddressUnspentIndex(const std::vector &vect); + bool ReadAddressUnspentIndex(uint160 addressHash, int type, std::vector &vect); + bool WriteAddressIndex(const std::vector &vect); + bool EraseAddressIndex(const std::vector &vect); + bool ReadAddressIndex(uint160 addressHash, int type, std::vector &addressIndex, int start = 0, int end = 0); + // END insightexplorer + bool WriteFlag(const std::string &name, bool fValue); bool ReadFlag(const std::string &name, bool &fValue); bool LoadBlockIndexGuts(); From ec81c709644147a8924ae2a9e1d38d31d6c30c81 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 4 Oct 2016 15:03:13 -0400 Subject: [PATCH 016/127] tests: adds unit test for IsPayToPublicKeyHash method --- src/Makefile.test.include | 1 + src/test/script_P2PKH_tests.cpp | 59 +++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src/test/script_P2PKH_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 91526ceb681..1eb6b262e91 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -86,6 +86,7 @@ BITCOIN_TESTS =\ test/sanity_tests.cpp \ test/scheduler_tests.cpp \ test/script_P2SH_tests.cpp \ + test/script_P2PKH_tests.cpp \ test/script_tests.cpp \ test/scriptnum_tests.cpp \ test/serialize_tests.cpp \ diff --git a/src/test/script_P2PKH_tests.cpp b/src/test/script_P2PKH_tests.cpp new file mode 100644 index 00000000000..3a7dc16608a --- /dev/null +++ b/src/test/script_P2PKH_tests.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "script/script.h" +#include "test/test_bitcoin.h" + +#include + +using namespace std; + +BOOST_FIXTURE_TEST_SUITE(script_P2PKH_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(IsPayToPublicKeyHash) +{ + // Test CScript::IsPayToPublicKeyHash() + uint160 dummy; + CScript p2pkh; + p2pkh << OP_DUP << OP_HASH160 << ToByteVector(dummy) << OP_EQUALVERIFY << OP_CHECKSIG; + BOOST_CHECK(p2pkh.IsPayToPublicKeyHash()); + + static const unsigned char direct[] = { + OP_DUP, OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUALVERIFY, OP_CHECKSIG + }; + BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToPublicKeyHash()); + + static const unsigned char notp2pkh1[] = { + OP_DUP, OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUALVERIFY, OP_CHECKSIG, OP_CHECKSIG + }; + BOOST_CHECK(!CScript(notp2pkh1, notp2pkh1+sizeof(notp2pkh1)).IsPayToPublicKeyHash()); + + static const unsigned char p2sh[] = { + OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL + }; + BOOST_CHECK(!CScript(p2sh, p2sh+sizeof(p2sh)).IsPayToPublicKeyHash()); + + static const unsigned char extra[] = { + OP_DUP, OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUALVERIFY, OP_CHECKSIG, OP_CHECKSIG + }; + BOOST_CHECK(!CScript(extra, extra+sizeof(extra)).IsPayToPublicKeyHash()); + + static const unsigned char missing[] = { + OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUALVERIFY, OP_CHECKSIG, OP_RETURN + }; + BOOST_CHECK(!CScript(missing, missing+sizeof(missing)).IsPayToPublicKeyHash()); + + static const unsigned char missing2[] = { + OP_DUP, OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + }; + BOOST_CHECK(!CScript(missing2, missing2+sizeof(missing)).IsPayToPublicKeyHash()); + + static const unsigned char tooshort[] = { + OP_DUP, OP_HASH160, 2, 0,0, OP_EQUALVERIFY, OP_CHECKSIG + }; + BOOST_CHECK(!CScript(tooshort, tooshort+sizeof(direct)).IsPayToPublicKeyHash()); + +} + +BOOST_AUTO_TEST_SUITE_END() From 885fce070a6aaf1c98e635551667a0dfa691d2a7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 2 Apr 2019 07:39:36 +0100 Subject: [PATCH 017/127] Add Blossom to upgrade list --- src/chainparams.cpp | 9 +++++++++ src/consensus/params.h | 1 + src/consensus/upgrades.cpp | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 511e6a40242..45b77a09ede 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -106,6 +106,9 @@ class CMainParams : public CChainParams { consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 347500; consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007; consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 419200; + consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nProtocolVersion = 170009; + consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight = + Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; // The best chain should have at least this much work. consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000c12875ded911cf"); @@ -285,6 +288,9 @@ class CTestNetParams : public CChainParams { consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 207500; consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007; consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 280000; + consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nProtocolVersion = 170008; + consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight = + Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; // The best chain should have at least this much work. consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000000001d0c4d9cd"); @@ -416,6 +422,9 @@ class CRegTestParams : public CChainParams { consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170006; consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nProtocolVersion = 170008; + consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight = + Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; // The best chain should have at least this much work. consensus.nMinimumChainWork = uint256S("0x00"); diff --git a/src/consensus/params.h b/src/consensus/params.h index 26288f24339..77f30bf4e69 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -26,6 +26,7 @@ enum UpgradeIndex { UPGRADE_TESTDUMMY, UPGRADE_OVERWINTER, UPGRADE_SAPLING, + UPGRADE_BLOSSOM, // NOTE: Also add new upgrades to NetworkUpgradeInfo in upgrades.cpp MAX_NETWORK_UPGRADES }; diff --git a/src/consensus/upgrades.cpp b/src/consensus/upgrades.cpp index 04be05cdf99..e11aaa260e4 100644 --- a/src/consensus/upgrades.cpp +++ b/src/consensus/upgrades.cpp @@ -28,6 +28,11 @@ const struct NUInfo NetworkUpgradeInfo[Consensus::MAX_NETWORK_UPGRADES] = { /*.nBranchId =*/ 0x76b809bb, /*.strName =*/ "Sapling", /*.strInfo =*/ "See https://z.cash/upgrade/sapling.html for details.", + }, + { + /*.nBranchId =*/ 0x2bb40e60, + /*.strName =*/ "Blossom", + /*.strInfo =*/ "See https://z.cash/upgrade/blossom.html for details.", } }; From 1f561f323f54191e1323a8cd2df101df4f054b62 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 4 Apr 2019 18:27:46 +0100 Subject: [PATCH 018/127] init: Fix new HD seed generation for previously-encrypted wallets Closes #3607. --- src/init.cpp | 8 ++++++-- src/wallet/wallet.cpp | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index f9da81e877d..6910cf30888 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1645,8 +1645,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (!pwalletMain->HaveHDSeed()) { - // generate a new HD seed - pwalletMain->GenerateNewSeed(); + // We can't set the new HD seed until the wallet is decrypted. + // https://github.com/zcash/zcash/issues/3607 + if (!pwalletMain->IsCrypted()) { + // generate a new HD seed + pwalletMain->GenerateNewSeed(); + } } if (fFirstRun) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 6dfa150252c..97500911a66 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -499,8 +499,14 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase) return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) continue; // try another master key - if (CCryptoKeyStore::Unlock(vMasterKey)) + if (CCryptoKeyStore::Unlock(vMasterKey)) { + // Now that the wallet is decrypted, ensure we have an HD seed. + // https://github.com/zcash/zcash/issues/3607 + if (!this->HaveHDSeed()) { + this->GenerateNewSeed(); + } return true; + } } } return false; From e4d40e4756135d2eafc29a558822f71990e13376 Mon Sep 17 00:00:00 2001 From: Mary Moore-Simmons Date: Tue, 9 Apr 2019 09:57:17 -0600 Subject: [PATCH 019/127] Creates checklist template for new PRs being opened and addresses Str4d's suggestion for using GitHub handles --- .github/pull_request_template.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..18694855b37 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,5 @@ +Please ensure this checklist is followed for any pull requests for this repo. This checklist must be checked by both the PR creator and by anyone who reviews the PR. +* [ ] Relevant documentation for this PR has to be completed and reviewed by the documentation team (@ioptio, @mdr0id, or @Eirik0) before the PR can be merged +* [ ] A test plan for the PR must be documented in the PR notes and included in the test plan for the next regular release + +As a note, all buildbot tests need to be passing and all appropriate code reviews need to be done before this PR can be merged From 82848efb0ea68e5653cf3e386bed02584d1e9404 Mon Sep 17 00:00:00 2001 From: Gareth Davies Date: Sun, 21 Apr 2019 06:56:08 -0700 Subject: [PATCH 020/127] Adding addressindex.h to Makefile.am Co-authored by: Daira Hopwood --- src/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.am b/src/Makefile.am index 5733549ff91..c8bb46fb897 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -114,6 +114,7 @@ LIBZCASH_H = \ .PHONY: FORCE collate-libsnark check-symbols check-security # bitcoin core # BITCOIN_CORE_H = \ + addressindex.h \ addrman.h \ alert.h \ amount.h \ From 4c1a8884f41d83f9af67447fa0e749b7164a431c Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 19 Apr 2019 10:54:51 -0700 Subject: [PATCH 021/127] Add testnet and regtest experimental feature: -developersetpoolsizezero --- src/chainparams.cpp | 9 +++++++++ src/init.cpp | 5 +++-- src/main.cpp | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 45b77a09ede..5857b0776bc 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -491,6 +491,10 @@ class CRegTestParams : public CChainParams { assert(idx > Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES); consensus.vUpgrades[idx].nActivationHeight = nActivationHeight; } + + void SetRegTestZIP209Enabled() { + fZIP209Enabled = true; + } }; static CRegTestParams regTestParams; @@ -523,6 +527,11 @@ void SelectParams(CBaseChainParams::Network network) { if (network == CBaseChainParams::REGTEST && mapArgs.count("-regtestprotectcoinbase")) { regTestParams.SetRegTestCoinbaseMustBeProtected(); } + + // When a developer is debugging turnstile violations in regtest mode, enable ZIP209 + if (network == CBaseChainParams::REGTEST && mapArgs.count("-developersetpoolsizezero")) { + regTestParams.SetRegTestZIP209Enabled(); + } } bool SelectParamsFromCommandLine() diff --git a/src/init.cpp b/src/init.cpp index ec459e36b21..d52e1baa36f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -834,8 +834,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (!fExperimentalMode) { if (mapArgs.count("-developerencryptwallet")) { return InitError(_("Wallet encryption requires -experimentalfeatures.")); - } - else if (mapArgs.count("-paymentdisclosure")) { + } else if (mapArgs.count("-developersetpoolsizezero")) { + return InitError(_("Setting the size of shielded pools to zero requires -experimentalfeatures.")); + } else if (mapArgs.count("-paymentdisclosure")) { return InitError(_("Payment disclosure requires -experimentalfeatures.")); } else if (mapArgs.count("-zmergetoaddress")) { return InitError(_("RPC method z_mergetoaddress requires -experimentalfeatures.")); diff --git a/src/main.cpp b/src/main.cpp index 4c47cfa0c80..72744b61a72 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3457,6 +3457,14 @@ void FallbackSproutValuePoolBalance( return; } + // When developer option -developersetpoolsizezero is enabled, we don't need a fallback balance. + if ((chainparams.NetworkIDString() == "test" || chainparams.NetworkIDString() == "regtest") && + fExperimentalMode && + mapArgs.count("-developersetpoolsizezero")) + { + return; + } + // Check if the height of this block matches the checkpoint if (pindex->nHeight == chainparams.SproutValuePoolCheckpointHeight()) { if (pindex->GetBlockHash() == chainparams.SproutValuePoolCheckpointBlockHash()) { @@ -4243,6 +4251,17 @@ bool static LoadBlockIndexDB() // Fall back to hardcoded Sprout value pool balance FallbackSproutValuePoolBalance(pindex, chainparams); + + // If developer option -developersetpoolsizezero has been enabled on testnet or in regtest mode, + // override and set the in-memory size of shielded pools to zero. An unshielding transaction + // can then be used to trigger and test the handling of turnstile violations. + if ((chainparams.NetworkIDString() == "test" || chainparams.NetworkIDString() == "regtest") && + fExperimentalMode && + mapArgs.count("-developersetpoolsizezero")) + { + pindex->nChainSproutValue = 0; + pindex->nChainSaplingValue = 0; + } } // Construct in-memory chain of branch IDs. // Relies on invariant: a block that does not activate a network upgrade From 3d018ab5560cf6115fcd4e3291a3ddebeb66482f Mon Sep 17 00:00:00 2001 From: Larry Ruane Date: Tue, 23 Apr 2019 11:06:23 -0600 Subject: [PATCH 022/127] add -spentindex changes for bitcore insight block explorer --- src/Makefile.am | 1 + src/main.cpp | 53 ++++++++++++++++++----- src/main.h | 4 ++ src/script/script.cpp | 3 +- src/spentindex.h | 97 +++++++++++++++++++++++++++++++++++++++++++ src/txdb.cpp | 18 +++++++- src/txdb.h | 5 +++ 7 files changed, 169 insertions(+), 12 deletions(-) create mode 100644 src/spentindex.h diff --git a/src/Makefile.am b/src/Makefile.am index c8bb46fb897..f3d20b8c431 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -189,6 +189,7 @@ BITCOIN_CORE_H = \ script/sign.h \ script/standard.h \ serialize.h \ + spentindex.h \ streams.h \ support/allocators/secure.h \ support/allocators/zeroafterfree.h \ diff --git a/src/main.cpp b/src/main.cpp index 4c47cfa0c80..6164406cb22 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -69,6 +69,7 @@ bool fReindex = false; bool fTxIndex = false; bool fInsightExplorer = false; // insightexplorer bool fAddressIndex = false; // insightexplorer +bool fSpentIndex = false; // insightexplorer bool fHavePruned = false; bool fPruneMode = false; bool fIsBareMultisigStd = true; @@ -2229,10 +2230,10 @@ enum DisconnectResult /** Undo the effects of this block (with given index) on the UTXO set represented by coins. * When UNCLEAN or FAILED is returned, view is left in an indeterminate state. - * The addressIndex will be updated if requested. + * The addressIndex and spentIndex will be updated if requested. */ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& state, - const CBlockIndex* pindex, CCoinsViewCache& view, const bool fUpdateAddressIndex) + const CBlockIndex* pindex, CCoinsViewCache& view, bool const updateIndices) { assert(pindex->GetBlockHash() == view.GetBestBlock()); @@ -2255,6 +2256,7 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s } std::vector addressIndex; std::vector addressUnspentIndex; + std::vector spentIndex; // undo transactions in reverse order for (int i = block.vtx.size() - 1; i >= 0; i--) { @@ -2263,7 +2265,7 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s // insightexplorer // https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-7ec3c68a81efff79b6ca22ac1f1eabbaR2236 - if (fAddressIndex && fUpdateAddressIndex) { + if (fAddressIndex && updateIndices) { for (unsigned int k = tx.vout.size(); k-- > 0;) { const CTxOut &out = tx.vout[k]; int const scriptType = out.scriptPubKey.Type(); @@ -2320,8 +2322,8 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s // insightexplorer // https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-7ec3c68a81efff79b6ca22ac1f1eabbaR2304 - if (fAddressIndex && fUpdateAddressIndex) { - const CTxIn input = tx.vin[j]; + const CTxIn input = tx.vin[j]; + if (fAddressIndex && updateIndices) { const CTxOut &prevout = view.GetOutputFor(input); int const scriptType = prevout.scriptPubKey.Type(); if (scriptType > 0) { @@ -2338,6 +2340,13 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight))); } } + // insightexplorer + if (fSpentIndex && updateIndices) { + // undo and delete the spent index + spentIndex.push_back(make_pair( + CSpentIndexKey(input.prevout.hash, input.prevout.n), + CSpentIndexValue())); + } } } } @@ -2360,7 +2369,7 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s view.SetBestBlock(pindex->pprev->GetBlockHash()); // insightexplorer - if (fAddressIndex && fUpdateAddressIndex) { + if (fAddressIndex && updateIndices) { if (!pblocktree->EraseAddressIndex(addressIndex)) { AbortNode(state, "Failed to delete address index"); return DISCONNECT_FAILED; @@ -2370,6 +2379,13 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s return DISCONNECT_FAILED; } } + // insightexplorer + if (fSpentIndex && updateIndices) { + if (!pblocktree->UpdateSpentIndex(spentIndex)) { + AbortNode(state, "Failed to write transaction index"); + return DISCONNECT_FAILED; + } + } return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; } @@ -2568,6 +2584,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin blockundo.vtxundo.reserve(block.vtx.size() - 1); std::vector addressIndex; std::vector addressUnspentIndex; + std::vector spentIndex; // Construct the incremental merkle tree at the current // block position, @@ -2619,15 +2636,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // insightexplorer // https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-7ec3c68a81efff79b6ca22ac1f1eabbaR2597 - if (fAddressIndex) { + if (fAddressIndex || fSpentIndex) { for (size_t j = 0; j < tx.vin.size(); j++) { const CTxIn input = tx.vin[j]; const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); int const scriptType = prevout.scriptPubKey.Type(); - if (scriptType > 0) { - uint160 const addrHash = prevout.scriptPubKey.AddressHash(); - + const uint160 addrHash = prevout.scriptPubKey.AddressHash(); + if (fAddressIndex && scriptType > 0) { // record spending activity addressIndex.push_back(make_pair( CAddressIndexKey(scriptType, addrHash, pindex->nHeight, i, hash, j, true), @@ -2638,6 +2654,15 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin CAddressUnspentKey(scriptType, addrHash, input.prevout.hash, input.prevout.n), CAddressUnspentValue())); } + if (fSpentIndex) { + // Add the spent index to determine the txid and input that spent an output + // and to find the amount and address from an input. + // If we do not recognize the script type, we still add an entry to the + // spentindex db, with a script type of 0 and addrhash of all zeroes. + spentIndex.push_back(make_pair( + CSpentIndexKey(input.prevout.hash, input.prevout.n), + CSpentIndexValue(hash, j, pindex->nHeight, prevout.nValue, scriptType, addrHash))); + } } } @@ -2785,6 +2810,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return AbortNode(state, "Failed to write address unspent index"); } } + // insightexplorer + if (fSpentIndex) { + if (!pblocktree->UpdateSpentIndex(spentIndex)) { + return AbortNode(state, "Failed to write spent index"); + } + } // add this block to the view's block chain view.SetBestBlock(pindex->GetBlockHash()); @@ -4321,6 +4352,7 @@ bool static LoadBlockIndexDB() pblocktree->ReadFlag("insightexplorer", fInsightExplorer); LogPrintf("%s: insight explorer %s\n", __func__, fAddressIndex ? "enabled" : "disabled"); fAddressIndex = fInsightExplorer; + fSpentIndex = fInsightExplorer; // Fill in-memory data BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) @@ -4663,6 +4695,7 @@ bool InitBlockIndex() { fInsightExplorer = GetBoolArg("-insightexplorer", false); pblocktree->WriteFlag("insightexplorer", fInsightExplorer); fAddressIndex = fInsightExplorer; + fSpentIndex = fInsightExplorer; LogPrintf("Initializing databases...\n"); diff --git a/src/main.h b/src/main.h index 3b8c6aff9db..f19fc84ff38 100644 --- a/src/main.h +++ b/src/main.h @@ -27,6 +27,7 @@ #include "txmempool.h" #include "uint256.h" #include "addressindex.h" +#include "spentindex.h" #include #include @@ -143,6 +144,9 @@ extern bool fInsightExplorer; // Maintain a full address index, used to query for the balance, txids and unspent outputs for addresses extern bool fAddressIndex; +// Maintain a full spent index, used to query the spending txid and input index for an outpoint +extern bool fSpentIndex; + // END insightexplorer extern bool fIsBareMultisigStd; diff --git a/src/script/script.cpp b/src/script/script.cpp index 32fe34b5949..9d13fd040cd 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -262,8 +262,9 @@ uint160 CScript::AddressHash() const else if (this->IsPayToScriptHash()) start = 2; else { - // unknown script type; return an empty vector + // unknown script type; return zeros vector hashBytes; + hashBytes.resize(20); return uint160(hashBytes); } vector hashBytes(this->begin()+start, this->begin()+start+20); diff --git a/src/spentindex.h b/src/spentindex.h new file mode 100644 index 00000000000..3e11b60809a --- /dev/null +++ b/src/spentindex.h @@ -0,0 +1,97 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_SPENTINDEX_H +#define BITCOIN_SPENTINDEX_H + +#include "uint256.h" +#include "amount.h" + +struct CSpentIndexKey { + uint256 txid; + unsigned int outputIndex; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(txid); + READWRITE(outputIndex); + } + + CSpentIndexKey(uint256 t, unsigned int i) { + txid = t; + outputIndex = i; + } + + CSpentIndexKey() { + SetNull(); + } + + void SetNull() { + txid.SetNull(); + outputIndex = 0; + } +}; + +struct CSpentIndexValue { + uint256 txid; + unsigned int inputIndex; + int blockHeight; + CAmount satoshis; + int addressType; + uint160 addressHash; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(txid); + READWRITE(inputIndex); + READWRITE(blockHeight); + READWRITE(satoshis); + READWRITE(addressType); + READWRITE(addressHash); + } + + CSpentIndexValue(uint256 t, unsigned int i, int h, CAmount s, int type, uint160 a) { + txid = t; + inputIndex = i; + blockHeight = h; + satoshis = s; + addressType = type; + addressHash = a; + } + + CSpentIndexValue() { + SetNull(); + } + + void SetNull() { + txid.SetNull(); + inputIndex = 0; + blockHeight = 0; + satoshis = 0; + addressType = 0; + addressHash.SetNull(); + } + + bool IsNull() const { + return txid.IsNull(); + } +}; + +struct CSpentIndexKeyCompare +{ + bool operator()(const CSpentIndexKey& a, const CSpentIndexKey& b) const { + if (a.txid == b.txid) { + return a.outputIndex < b.outputIndex; + } else { + return a.txid < b.txid; + } + } +}; + +#endif // BITCOIN_SPENTINDEX_H diff --git a/src/txdb.cpp b/src/txdb.cpp index 162a790140b..b0c89f7d367 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -38,7 +38,7 @@ static const char DB_LAST_BLOCK = 'l'; // insightexplorer static const char DB_ADDRESSINDEX = 'd'; static const char DB_ADDRESSUNSPENTINDEX = 'u'; - +static const char DB_SPENTINDEX = 'p'; CCoinsViewDB::CCoinsViewDB(std::string dbName, size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / dbName, nCacheSize, fMemory, fWipe) { } @@ -374,6 +374,22 @@ bool CBlockTreeDB::ReadAddressIndex( } return true; } + +bool CBlockTreeDB::ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) { + return Read(make_pair(DB_SPENTINDEX, key), value); +} + +bool CBlockTreeDB::UpdateSpentIndex(const std::vector &vect) { + CDBBatch batch(*this); + for (std::vector::const_iterator it=vect.begin(); it!=vect.end(); it++) { + if (it->second.IsNull()) { + batch.Erase(make_pair(DB_SPENTINDEX, it->first)); + } else { + batch.Write(make_pair(DB_SPENTINDEX, it->first), it->second); + } + } + return WriteBatch(batch); +} // END insightexplorer bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) { diff --git a/src/txdb.h b/src/txdb.h index 305e93e9c15..f1f78085184 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -24,9 +24,12 @@ struct CAddressUnspentValue; struct CAddressIndexKey; struct CAddressIndexIteratorKey; struct CAddressIndexIteratorHeightKey; +struct CSpentIndexKey; +struct CSpentIndexValue; typedef std::pair CAddressUnspentDbEntry; typedef std::pair CAddressIndexDbEntry; +typedef std::pair CSpentIndexDbEntry; // END insightexplorer class uint256; @@ -89,6 +92,8 @@ class CBlockTreeDB : public CDBWrapper bool WriteAddressIndex(const std::vector &vect); bool EraseAddressIndex(const std::vector &vect); bool ReadAddressIndex(uint160 addressHash, int type, std::vector &addressIndex, int start = 0, int end = 0); + bool ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value); + bool UpdateSpentIndex(const std::vector &vect); // END insightexplorer bool WriteFlag(const std::string &name, bool fValue); From c17d828ffdbce43d1fa0dc18a75d7d5a98945645 Mon Sep 17 00:00:00 2001 From: Larry Ruane Date: Fri, 12 Apr 2019 12:25:13 -0600 Subject: [PATCH 023/127] Update boost from v1.69.0 to v1.70.0. #3947 --- depends/packages/boost.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 3e274c7e48d..a5c90cece97 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,8 +1,8 @@ package=boost -$(package)_version=1_69_0 -$(package)_download_path=https://dl.bintray.com/boostorg/release/1.69.0/source +$(package)_version=1_70_0 +$(package)_download_path=https://dl.bintray.com/boostorg/release/1.70.0/source $(package)_file_name=$(package)_$($(package)_version).tar.bz2 -$(package)_sha256_hash=8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406 +$(package)_sha256_hash=430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778 define $(package)_set_vars $(package)_config_opts_release=variant=release From d6b47948bf04800e603708d034eb9dc9883e24e7 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 19 Apr 2019 10:57:12 -0700 Subject: [PATCH 024/127] Add qa test for experimental feature: -developersetpoolsizezero --- qa/pull-tester/rpc-tests.sh | 1 + qa/rpc-tests/turnstile.py | 204 ++++++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100755 qa/rpc-tests/turnstile.py diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 3d6be26dd5c..19c65a0b5f6 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -71,6 +71,7 @@ testScripts=( 'p2p_node_bloom.py' 'regtest_signrawtransaction.py' 'finalsaplingroot.py' + 'turnstile.py' ); testScriptsExt=( 'getblocktemplate_longpoll.py' diff --git a/qa/rpc-tests/turnstile.py b/qa/rpc-tests/turnstile.py new file mode 100755 index 00000000000..89d680f0b13 --- /dev/null +++ b/qa/rpc-tests/turnstile.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python +# Copyright (c) 2019 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test Sprout and Sapling turnstile violations +# +# Experimental feature -developersetpoolsizezero will, upon node launch, +# set the in-memory size of shielded pools to zero. +# +# An unshielding operation can then be used to verify: +# 1. Turnstile violating transactions are excluded by the miner +# 2. Turnstile violating blocks are rejected by nodes +# +# By default, ZIP209 support is disabled in regtest mode, but gets enabled +# when experimental feature -developersetpoolsizezero is switched on. +# +# To perform a manual turnstile test on testnet: +# 1. Launch zcashd +# 2. Shield transparent funds +# 3. Wait for transaction to be mined +# 4. Restart zcashd, enabling experimental feature -developersetpoolsizezero +# 5. Unshield funds +# 6. Wait for transaction to be mined (using testnet explorer or another node) +# 7. Verify zcashd rejected the block +# + +import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x." + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + get_coinbase_address, + start_node, start_nodes, + sync_blocks, sync_mempools, + initialize_chain_clean, connect_nodes_bi, + wait_and_assert_operationid_status, + bitcoind_processes +) +from decimal import Decimal + +NUPARAMS_ARGS = ['-nuparams=5ba81b19:100', # Overwinter + '-nuparams=76b809bb:101'] # Sapling +TURNSTILE_ARGS = ['-experimentalfeatures', + '-developersetpoolsizezero'] + +class TurnstileTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory " + self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 3) + + def setup_network(self, split=False): + self.nodes = start_nodes(3, self.options.tmpdir, + extra_args=[NUPARAMS_ARGS] * 3) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + self.is_network_split=False + self.sync_all() + + # Helper method to verify the size of a shielded value pool for a given node + def assert_pool_balance(self, node, name, balance): + pools = node.getblockchaininfo()['valuePools'] + for pool in pools: + if pool['id'] == name: + assert_equal(pool['chainValue'], balance, message="for pool named %r" % (name,)) + return + assert False, "pool named %r not found" % (name,) + + # Helper method to start a single node with extra args and sync to the network + def start_and_sync_node(self, index, args=[]): + self.nodes[index] = start_node(index, self.options.tmpdir, extra_args=NUPARAMS_ARGS + args) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + self.sync_all() + + # Helper method to stop and restart a single node with extra args and sync to the network + def restart_and_sync_node(self, index, args=[]): + self.nodes[index].stop() + bitcoind_processes[index].wait() + self.start_and_sync_node(index, args) + + def run_test(self): + # Sanity-check the test harness + self.nodes[0].generate(101) + assert_equal(self.nodes[0].getblockcount(), 101) + self.sync_all() + + # Node 0 shields some funds + dest_addr = self.nodes[0].z_getnewaddress(POOL_NAME.lower()) + taddr0 = get_coinbase_address(self.nodes[0]) + recipients = [] + recipients.append({"address": dest_addr, "amount": Decimal('10')}) + myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) + wait_and_assert_operationid_status(self.nodes[0], myopid) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + assert_equal(self.nodes[0].z_getbalance(dest_addr), Decimal('10')) + + # Verify size of shielded pool + self.assert_pool_balance(self.nodes[0], POOL_NAME.lower(), Decimal('10')) + self.assert_pool_balance(self.nodes[1], POOL_NAME.lower(), Decimal('10')) + self.assert_pool_balance(self.nodes[2], POOL_NAME.lower(), Decimal('10')) + + # Relaunch node 0 with in-memory size of value pools set to zero. + self.restart_and_sync_node(0, TURNSTILE_ARGS) + + # Verify size of shielded pool + self.assert_pool_balance(self.nodes[0], POOL_NAME.lower(), Decimal('0')) + self.assert_pool_balance(self.nodes[1], POOL_NAME.lower(), Decimal('10')) + self.assert_pool_balance(self.nodes[2], POOL_NAME.lower(), Decimal('10')) + + # Node 0 creates an unshielding transaction + recipients = [] + recipients.append({"address": taddr0, "amount": Decimal('1')}) + myopid = self.nodes[0].z_sendmany(dest_addr, recipients, 1, 0) + mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) + + # Verify transaction appears in mempool of nodes + self.sync_all() + assert(mytxid in self.nodes[0].getrawmempool()) + assert(mytxid in self.nodes[1].getrawmempool()) + assert(mytxid in self.nodes[2].getrawmempool()) + + # Node 0 mines a block + count = self.nodes[0].getblockcount() + self.nodes[0].generate(1) + self.sync_all() + + # Verify the mined block does not contain the unshielding transaction + block = self.nodes[0].getblock(self.nodes[0].getbestblockhash()) + assert_equal(len(block["tx"]), 1) + assert_equal(block["height"], count + 1) + + # Stop node 0 and check logs to verify the miner excluded the transaction from the block + self.nodes[0].stop() + bitcoind_processes[0].wait() + logpath = self.options.tmpdir + "/node0/regtest/debug.log" + foundErrorMsg = False + with open(logpath, "r") as myfile: + logdata = myfile.readlines() + for logline in logdata: + if "CreateNewBlock(): tx " + mytxid + " appears to violate " + POOL_NAME.capitalize() + " turnstile" in logline: + foundErrorMsg = True + break + assert(foundErrorMsg) + + # Launch node 0 with in-memory size of value pools set to zero. + self.start_and_sync_node(0, TURNSTILE_ARGS) + + # Node 1 mines a block + oldhash = self.nodes[0].getbestblockhash() + self.nodes[1].generate(1) + newhash = self.nodes[1].getbestblockhash() + + # Verify block contains the unshielding transaction + assert(mytxid in self.nodes[1].getblock(newhash)["tx"]) + + # Verify nodes 1 and 2 have accepted the block as valid + sync_blocks(self.nodes[1:3]) + sync_mempools(self.nodes[1:3]) + assert_equal(len(self.nodes[1].getrawmempool()), 0) + assert_equal(len(self.nodes[2].getrawmempool()), 0) + + # Verify node 0 has not accepted the block + assert_equal(oldhash, self.nodes[0].getbestblockhash()) + assert(mytxid in self.nodes[0].getrawmempool()) + self.assert_pool_balance(self.nodes[0], POOL_NAME.lower(), Decimal('0')) + + # Verify size of shielded pool + self.assert_pool_balance(self.nodes[0], POOL_NAME.lower(), Decimal('0')) + self.assert_pool_balance(self.nodes[1], POOL_NAME.lower(), Decimal('9')) + self.assert_pool_balance(self.nodes[2], POOL_NAME.lower(), Decimal('9')) + + # Stop node 0 and check logs to verify the block was rejected as a turnstile violation + self.nodes[0].stop() + bitcoind_processes[0].wait() + logpath = self.options.tmpdir + "/node0/regtest/debug.log" + foundConnectBlockErrorMsg = False + foundInvalidBlockErrorMsg = False + foundConnectTipErrorMsg = False + with open(logpath, "r") as myfile: + logdata = myfile.readlines() + for logline in logdata: + if "ConnectBlock(): turnstile violation in " + POOL_NAME.capitalize() + " shielded value pool" in logline: + foundConnectBlockErrorMsg = True + elif "InvalidChainFound: invalid block=" + newhash in logline: + foundInvalidBlockErrorMsg = True + elif "ConnectTip(): ConnectBlock " + newhash + " failed" in logline: + foundConnectTipErrorMsg = True + assert(foundConnectBlockErrorMsg and foundInvalidBlockErrorMsg and foundConnectTipErrorMsg) + + # Launch node 0 without overriding the pool size, so the node can sync with rest of network. + self.start_and_sync_node(0) + assert_equal(newhash, self.nodes[0].getbestblockhash()) + +if __name__ == '__main__': + POOL_NAME = "SPROUT" + TurnstileTest().main() + POOL_NAME = "SAPLING" + TurnstileTest().main() From fc79a848fba6d8ce51af933ccf7dac807db6f0c3 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 23 Apr 2019 22:57:30 -0700 Subject: [PATCH 025/127] Enable ZIP209 on mainnet and set fallback Sprout pool balance. --- src/chainparams.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 5857b0776bc..e0769fcae5f 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -193,6 +193,14 @@ class CMainParams : public CChainParams { // total number of tx / (checkpoint block height / (24 * 24)) }; + // Hardcoded fallback value for the Sprout shielded value pool balance + // for nodes that have not reindexed since the introduction of monitoring + // in #2795. + nSproutValuePoolCheckpointHeight = 520633; + nSproutValuePoolCheckpointBalance = 22145062442933; + fZIP209Enabled = true; + hashSproutValuePoolCheckpointBlock = uint256S("0000000000c7b46b6bc04b4cbf87d8bb08722aebd51232619b214f7273f8460e"); + // Founders reward script expects a vector of 2-of-3 multisig addresses vFoundersRewardAddress = { "t3Vz22vK5z2LcKEdg16Yv4FFneEL1zg9ojd", /* main-index: 0*/ From 867786d777a90fb1301772330460dff6a33f0c43 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 24 Apr 2019 08:40:17 -0700 Subject: [PATCH 026/127] Enable experimental feature -developersetpoolsizezero on mainnet. --- src/main.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 72744b61a72..927435ffe1a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3451,17 +3451,12 @@ void FallbackSproutValuePoolBalance( const CChainParams& chainparams ) { - // We might not want to enable the checkpointing for mainnet - // yet. if (!chainparams.ZIP209Enabled()) { return; } // When developer option -developersetpoolsizezero is enabled, we don't need a fallback balance. - if ((chainparams.NetworkIDString() == "test" || chainparams.NetworkIDString() == "regtest") && - fExperimentalMode && - mapArgs.count("-developersetpoolsizezero")) - { + if (fExperimentalMode && mapArgs.count("-developersetpoolsizezero")) { return; } @@ -4252,13 +4247,10 @@ bool static LoadBlockIndexDB() // Fall back to hardcoded Sprout value pool balance FallbackSproutValuePoolBalance(pindex, chainparams); - // If developer option -developersetpoolsizezero has been enabled on testnet or in regtest mode, + // If developer option -developersetpoolsizezero has been enabled, // override and set the in-memory size of shielded pools to zero. An unshielding transaction // can then be used to trigger and test the handling of turnstile violations. - if ((chainparams.NetworkIDString() == "test" || chainparams.NetworkIDString() == "regtest") && - fExperimentalMode && - mapArgs.count("-developersetpoolsizezero")) - { + if (fExperimentalMode && mapArgs.count("-developersetpoolsizezero")) { pindex->nChainSproutValue = 0; pindex->nChainSaplingValue = 0; } From 81a45d6984ef656f3b82829b20717a0c9d497d5b Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Mon, 18 Mar 2019 20:33:02 -0600 Subject: [PATCH 027/127] Add rpc to enable and disable Sprout to Sapling migration --- qa/pull-tester/rpc-tests.sh | 1 + qa/rpc-tests/sprout_sapling_migration.py | 96 +++++++++ qa/rpc-tests/test_framework/util.py | 13 +- src/Makefile.am | 2 + src/main.cpp | 5 + src/main.h | 1 + src/validationinterface.cpp | 3 + src/validationinterface.h | 3 + .../asyncrpcoperation_saplingmigration.cpp | 196 ++++++++++++++++++ .../asyncrpcoperation_saplingmigration.h | 31 +++ src/wallet/rpcwallet.cpp | 22 ++ src/wallet/wallet.cpp | 47 +++++ src/wallet/wallet.h | 6 + 13 files changed, 421 insertions(+), 5 deletions(-) create mode 100755 qa/rpc-tests/sprout_sapling_migration.py create mode 100644 src/wallet/asyncrpcoperation_saplingmigration.cpp create mode 100644 src/wallet/asyncrpcoperation_saplingmigration.h diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 19c65a0b5f6..d072898b26d 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -71,6 +71,7 @@ testScripts=( 'p2p_node_bloom.py' 'regtest_signrawtransaction.py' 'finalsaplingroot.py' + 'sprout_sapling_migration.py' 'turnstile.py' ); testScriptsExt=( diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py new file mode 100755 index 00000000000..726e5e2aa61 --- /dev/null +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python +# Copyright (c) 2019 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x." + +from decimal import Decimal +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, assert_true, get_coinbase_address, \ + initialize_chain_clean, start_nodes, wait_and_assert_operationid_status + + +class SproutSaplingMigration(BitcoinTestFramework): + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir, [[ + '-nuparams=5ba81b19:100', # Overwinter + '-nuparams=76b809bb:100', # Sapling + ]] * 4) + + def setup_chain(self): + print("Initializing test directory " + self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def run_test(self): + print "Mining blocks..." + self.nodes[0].generate(101) + self.sync_all() + + # Send some ZEC to a Sprout address + tAddr = get_coinbase_address(self.nodes[0]) + sproutAddr = self.nodes[0].z_getnewaddress('sprout') + saplingAddr = self.nodes[0].z_getnewaddress('sapling') + + opid = self.nodes[0].z_sendmany(tAddr, [{"address": sproutAddr, "amount": Decimal('10')}], 1, 0) + wait_and_assert_operationid_status(self.nodes[0], opid) + self.nodes[0].generate(1) + self.sync_all() + + assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('10')) + assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0')) + + # Migrate + assert_equal(True, self.nodes[0].z_setmigration(True)) + print "Mining to block 494..." + self.nodes[0].generate(392) # 102 -> 494 + self.sync_all() + + # At 494 we should have no async operations + assert_equal(0, len(self.nodes[0].z_getoperationstatus()), "num async operations at 494") + + self.nodes[0].generate(1) + self.sync_all() + + # At 495 we should have an async operation + operationstatus = self.nodes[0].z_getoperationstatus() + assert_equal(1, len(operationstatus), "num async operations at 495") + assert_equal('saplingmigration', operationstatus[0]['method']) + assert_equal(500, operationstatus[0]['target_height']) + + print "migration operation: {}".format(operationstatus) + migration_opid = operationstatus[0]['id'] + result = wait_and_assert_operationid_status(self.nodes[0], migration_opid) + print "result: {}".format(result) + assert_equal(0, len(self.nodes[0].getrawmempool()), "mempool size at 495") + + self.nodes[0].generate(3) + self.sync_all() + + # At 498 the mempool will be empty and no funds will have moved + assert_equal(0, len(self.nodes[0].getrawmempool()), "mempool size at 498") + assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('10')) + assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0')) + + self.nodes[0].generate(1) + self.sync_all() + + # At 499 there will be a transaction in the mempool and the note will be locked + assert_equal(1, len(self.nodes[0].getrawmempool()), "mempool size at 499") + assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('0')) + assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0')) + assert_true(self.nodes[0].z_getbalance(saplingAddr, 0) > Decimal('0'), "Unconfirmed sapling") + + self.nodes[0].generate(1) + self.sync_all() + + # At 500 funds will have moved + sprout_balance = self.nodes[0].z_getbalance(sproutAddr) + sapling_balance = self.nodes[0].z_getbalance(saplingAddr) + print "sprout balance: {}, sapling balance: {}".format(sprout_balance, sapling_balance) + assert_true(sprout_balance < Decimal('10'), "Should have less Sprout funds") + assert_true(sapling_balance > Decimal('0'), "Should have more Sapling funds") + + +if __name__ == '__main__': + SproutSaplingMigration().main() diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 77abec55dcd..7d15ec063c7 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -399,26 +399,29 @@ def wait_and_assert_operationid_status(node, myopid, in_status='success', in_err assert_true(result is not None, "timeout occured") status = result['status'] - txid = None + ret = None errormsg = None if status == "failed": errormsg = result['error']['message'] elif status == "success": - txid = result['result']['txid'] + if type(result['result']) is dict and result['result'].get('txid'): + ret = result['result']['txid'] + else: + ret = result['result'] if os.getenv("PYTHON_DEBUG", ""): print('...returned status: {}'.format(status)) if errormsg is not None: print('...returned error: {}'.format(errormsg)) - + assert_equal(in_status, status, "Operation returned mismatched status. Error Message: {}".format(errormsg)) if errormsg is not None: assert_true(in_errormsg is not None, "No error retured. Expected: {}".format(errormsg)) assert_true(in_errormsg in errormsg, "Error returned: {}. Error expected: {}".format(errormsg, in_errormsg)) - return result # if there was an error return the result + return result # if there was an error return the result else: - return txid # otherwise return the txid + return ret # otherwise return the txid # Find a coinbase address on the node, filtering by the number of UTXOs it has. # If no filter is provided, returns the coinbase address on the node containing diff --git a/src/Makefile.am b/src/Makefile.am index 16951f9d223..5924abfb6c6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -215,6 +215,7 @@ BITCOIN_CORE_H = \ validationinterface.h \ version.h \ wallet/asyncrpcoperation_mergetoaddress.h \ + wallet/asyncrpcoperation_saplingmigration.h \ wallet/asyncrpcoperation_sendmany.h \ wallet/asyncrpcoperation_shieldcoinbase.h \ wallet/crypter.h \ @@ -304,6 +305,7 @@ libbitcoin_wallet_a_SOURCES = \ zcbenchmarks.cpp \ zcbenchmarks.h \ wallet/asyncrpcoperation_mergetoaddress.cpp \ + wallet/asyncrpcoperation_saplingmigration.cpp \ wallet/asyncrpcoperation_sendmany.cpp \ wallet/asyncrpcoperation_shieldcoinbase.cpp \ wallet/crypter.cpp \ diff --git a/src/main.cpp b/src/main.cpp index 72744b61a72..782ab69b07f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -78,6 +78,7 @@ bool fCoinbaseEnforcedProtectionEnabled = true; size_t nCoinCacheUsage = 5000 * 300; uint64_t nPruneTarget = 0; bool fAlerts = DEFAULT_ALERTS; +bool fSaplingMigrationEnabled = false; /* If the tip is older than this (in seconds), the node is considered to be in initial block download. */ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; @@ -3104,6 +3105,10 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * EnforceNodeDeprecation(pindexNew->nHeight); + if (fSaplingMigrationEnabled) { + GetMainSignals().RunSaplingMigration(pindexNew->nHeight); + } + int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001); diff --git a/src/main.h b/src/main.h index 3b8c6aff9db..0e1fa669410 100644 --- a/src/main.h +++ b/src/main.h @@ -154,6 +154,7 @@ extern bool fCoinbaseEnforcedProtectionEnabled; extern size_t nCoinCacheUsage; extern CFeeRate minRelayTxFee; extern bool fAlerts; +extern bool fSaplingMigrationEnabled; extern int64_t nMaxTipAge; /** Best header we've seen so far (used for getheaders queries' starting points). */ diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 1dc3351ab27..bb3f800fc33 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -18,6 +18,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5)); + g_signals.RunSaplingMigration.connect(boost::bind(&CValidationInterface::RunSaplingMigration, pwalletIn, _1)); g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); @@ -33,6 +34,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5)); + g_signals.RunSaplingMigration.disconnect(boost::bind(&CValidationInterface::RunSaplingMigration, pwalletIn, _1)); g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); @@ -47,6 +49,7 @@ void UnregisterAllValidationInterfaces() { g_signals.Broadcast.disconnect_all_slots(); g_signals.Inventory.disconnect_all_slots(); g_signals.ChainTip.disconnect_all_slots(); + g_signals.RunSaplingMigration.disconnect_all_slots(); g_signals.SetBestChain.disconnect_all_slots(); g_signals.UpdatedTransaction.disconnect_all_slots(); g_signals.EraseTransaction.disconnect_all_slots(); diff --git a/src/validationinterface.h b/src/validationinterface.h index 7b02bd9da4a..9e443d13459 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -37,6 +37,7 @@ class CValidationInterface { virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {} virtual void EraseFromWallet(const uint256 &hash) {} virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree, bool added) {} + virtual void RunSaplingMigration(int blockHeight) {} virtual void SetBestChain(const CBlockLocator &locator) {} virtual void UpdatedTransaction(const uint256 &hash) {} virtual void Inventory(const uint256 &hash) {} @@ -60,6 +61,8 @@ struct CMainSignals { boost::signals2::signal UpdatedTransaction; /** Notifies listeners of a change to the tip of the active block chain. */ boost::signals2::signal ChainTip; + /** Notifies listeners that they may need to update the status of the Sprout->Sapling migration */ + boost::signals2::signal RunSaplingMigration; /** Notifies listeners of a new active block chain. */ boost::signals2::signal SetBestChain; /** Notifies listeners about an inventory item being seen on the network. */ diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp new file mode 100644 index 00000000000..6a043f9bf35 --- /dev/null +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -0,0 +1,196 @@ +#include "assert.h" +#include "boost/variant/static_visitor.hpp" +#include "asyncrpcoperation_saplingmigration.h" +#include "init.h" +#include "rpc/protocol.h" +#include "random.h" +#include "sync.h" +#include "tinyformat.h" +#include "transaction_builder.h" +#include "util.h" +#include "wallet.h" + +const CAmount FEE = 10000; + +AsyncRPCOperation_saplingmigration::AsyncRPCOperation_saplingmigration(int targetHeight) : targetHeight_(targetHeight) {} + +AsyncRPCOperation_saplingmigration::~AsyncRPCOperation_saplingmigration() {} + +void AsyncRPCOperation_saplingmigration::main() { + if (isCancelled()) + return; + + set_state(OperationStatus::EXECUTING); + start_execution_clock(); + + bool success = false; + + try { + success = main_impl(); + } catch (const UniValue& objError) { + int code = find_value(objError, "code").get_int(); + std::string message = find_value(objError, "message").get_str(); + set_error_code(code); + set_error_message(message); + } catch (const runtime_error& e) { + set_error_code(-1); + set_error_message("runtime error: " + string(e.what())); + } catch (const logic_error& e) { + set_error_code(-1); + set_error_message("logic error: " + string(e.what())); + } catch (const exception& e) { + set_error_code(-1); + set_error_message("general exception: " + string(e.what())); + } catch (...) { + set_error_code(-2); + set_error_message("unknown error"); + } + + stop_execution_clock(); + + if (success) { + set_state(OperationStatus::SUCCESS); + } else { + set_state(OperationStatus::FAILED); + } + + std::string s = strprintf("%s: Sprout->Sapling transactions sent. (status=%s", getId(), getStateAsString()); + if (success) { + s += strprintf(", success)\n"); + } else { + s += strprintf(", error=%s)\n", getErrorMessage()); + } + + LogPrintf("%s", s); +} + +bool AsyncRPCOperation_saplingmigration::main_impl() { + std::vector sproutEntries; + std::vector saplingEntries; + { + LOCK2(cs_main, pwalletMain->cs_wallet); + // Consider, should notes be sorted? + pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, "", 0); + } + if (sproutEntries.empty()) { // Consider, should the migration remain enabled? + fSaplingMigrationEnabled = false; + return true; + } + CAmount availableFunds = 0; + for (const CSproutNotePlaintextEntry& sproutEntry : sproutEntries) { + availableFunds = sproutEntry.plaintext.value(); + } + // If the remaining amount to be migrated is less than 0.01 ZEC, end the migration. + if (availableFunds < CENT) { + fSaplingMigrationEnabled = false; + return true; + } + + HDSeed seed; + if (!pwalletMain->GetHDSeed(seed)) { + throw JSONRPCError( + RPC_WALLET_ERROR, + "AsyncRPCOperation_AsyncRPCOperation_saplingmigration: HD seed not found"); + } + + libzcash::SaplingPaymentAddress migrationDestAddress = getMigrationDestAddress(seed); + + auto consensusParams = Params().GetConsensus(); + + // Up to the limit of 5, as many transactions are sent as are needed to migrate the remaining funds + int numTxCreated = 0; + int noteIndex = 0; + do { + CAmount amountToSend = chooseAmount(availableFunds); + auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain, pzcashParams); + std::vector fromNotes; + CAmount fromNoteAmount = 0; + while (fromNoteAmount < amountToSend) { + auto sproutEntry = sproutEntries[noteIndex++]; + fromNotes.push_back(sproutEntry); + fromNoteAmount += sproutEntry.plaintext.value(); + } + availableFunds -= fromNoteAmount; + for (const CSproutNotePlaintextEntry& sproutEntry : fromNotes) { + libzcash::SproutNote sproutNote = sproutEntry.plaintext.note(sproutEntry.address); + libzcash::SproutSpendingKey sproutSk; + pwalletMain->GetSproutSpendingKey(sproutEntry.address, sproutSk); + std::vector vOutPoints = {sproutEntry.jsop}; + // Each migration transaction SHOULD specify an anchor at height N-10 + // for each Sprout JoinSplit description + // TODO: the above functionality (in comment) is not implemented in zcashd + uint256 inputAnchor; + std::vector> vInputWitnesses; + pwalletMain->GetSproutNoteWitnesses(vOutPoints, vInputWitnesses, inputAnchor); + builder.AddSproutInput(sproutSk, sproutNote, vInputWitnesses[0].get()); + } + // The amount chosen *includes* the 0.0001 ZEC fee for this transaction, i.e. + // the value of the Sapling output will be 0.0001 ZEC less. + builder.SetFee(FEE); + builder.AddSaplingOutput(ovkForShieldingFromTaddr(seed), migrationDestAddress, amountToSend - FEE); + CTransaction tx = builder.Build().GetTxOrThrow(); + if (isCancelled()) { + break; + } + pwalletMain->AddPendingSaplingMigrationTx(tx); + ++numTxCreated; + } while (numTxCreated < 5 && availableFunds > CENT); + + UniValue res(UniValue::VOBJ); + res.push_back(Pair("num_tx_created", numTxCreated)); + set_result(res); + return true; +} + +CAmount AsyncRPCOperation_saplingmigration::chooseAmount(const CAmount& availableFunds) { + CAmount amount = 0; + do { + // 1. Choose an integer exponent uniformly in the range 6 to 8 inclusive. + int exponent = GetRand(3) + 6; + // 2. Choose an integer mantissa uniformly in the range 1 to 99 inclusive. + uint64_t mantissa = GetRand(99) + 1; + // 3. Calculate amount := (mantissa * 10^exponent) zatoshi. + int pow = std::pow(10, exponent); + amount = mantissa * pow; + // 4. If amount is greater than the amount remaining to send, repeat from step 1. + } while (amount > availableFunds); + return amount; +} + +// Unless otherwise specified, the migration destination address is the address for Sapling account 0 +libzcash::SaplingPaymentAddress AsyncRPCOperation_saplingmigration::getMigrationDestAddress(const HDSeed& seed) { + // Derive the address for Sapling account 0 + auto m = libzcash::SaplingExtendedSpendingKey::Master(seed); + uint32_t bip44CoinType = Params().BIP44CoinType(); + + // We use a fixed keypath scheme of m/32'/coin_type'/account' + // Derive m/32' + auto m_32h = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT); + // Derive m/32'/coin_type' + auto m_32h_cth = m_32h.Derive(bip44CoinType | ZIP32_HARDENED_KEY_LIMIT); + + // Derive account key at next index, skip keys already known to the wallet + libzcash::SaplingExtendedSpendingKey xsk = m_32h_cth.Derive(0 | ZIP32_HARDENED_KEY_LIMIT); + + libzcash::SaplingPaymentAddress toAddress = xsk.DefaultAddress(); + + // Refactor: this is similar logic as in the visitor HaveSpendingKeyForPaymentAddress and is used elsewhere + libzcash::SaplingIncomingViewingKey ivk; + libzcash::SaplingFullViewingKey fvk; + if (!(pwalletMain->GetSaplingIncomingViewingKey(toAddress, ivk) && + pwalletMain->GetSaplingFullViewingKey(ivk, fvk) && + pwalletMain->HaveSaplingSpendingKey(fvk))) { + // Sapling account 0 must be the first address returned by GenerateNewSaplingZKey + assert(pwalletMain->GenerateNewSaplingZKey() == toAddress); + } + + return toAddress; +} + +UniValue AsyncRPCOperation_saplingmigration::getStatus() const { + UniValue v = AsyncRPCOperation::getStatus(); + UniValue obj = v.get_obj(); + obj.push_back(Pair("method", "saplingmigration")); + obj.push_back(Pair("target_height", targetHeight_)); + return obj; +} diff --git a/src/wallet/asyncrpcoperation_saplingmigration.h b/src/wallet/asyncrpcoperation_saplingmigration.h new file mode 100644 index 00000000000..b520db408ff --- /dev/null +++ b/src/wallet/asyncrpcoperation_saplingmigration.h @@ -0,0 +1,31 @@ +#include "amount.h" +#include "asyncrpcoperation.h" +#include "univalue.h" +#include "zcash/Address.hpp" +#include "zcash/zip32.h" + +class AsyncRPCOperation_saplingmigration : public AsyncRPCOperation +{ +public: + AsyncRPCOperation_saplingmigration(int targetHeight); + virtual ~AsyncRPCOperation_saplingmigration(); + + // We don't want to be copied or moved around + AsyncRPCOperation_saplingmigration(AsyncRPCOperation_saplingmigration const&) = delete; // Copy construct + AsyncRPCOperation_saplingmigration(AsyncRPCOperation_saplingmigration&&) = delete; // Move construct + AsyncRPCOperation_saplingmigration& operator=(AsyncRPCOperation_saplingmigration const&) = delete; // Copy assign + AsyncRPCOperation_saplingmigration& operator=(AsyncRPCOperation_saplingmigration&&) = delete; // Move assign + + virtual void main(); + + virtual UniValue getStatus() const; + +private: + int targetHeight_; + + bool main_impl(); + + CAmount chooseAmount(const CAmount& availableFunds); + + libzcash::SaplingPaymentAddress getMigrationDestAddress(const HDSeed& seed); +}; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 4275f897f85..7cf5429a7b4 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3906,6 +3906,27 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) return operationId; } +UniValue z_setmigration(const UniValue& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + if (fHelp || params.size() != 1) + throw runtime_error( + "z_setmigration enabled\n" + "When enabled the Sprout to Sapling migration will attempt to migrate all funds from this wallet’s\n" + "Sprout addresses to either the address for Sapling account 0 or one specified by the parameter\n" + "'-migrationdestaddress'. This migration is designed to minimize information leakage. As a result,\n" + "for wallets with a significant Sprout balance, this process may take several weeks. The migration\n" + "works by sending, up to 5, as many transactions as possible whenever the blockchain reaches a height\n" + "equal to 499 modulo 500. The transaction amounts are picked according to the random distribution\n" + "specified in ZIP 308. The migration will end once the wallet’s Sprout balance is below 0.01 " + CURRENCY_UNIT + ".\n" + "\nArguments:\n" + "1. enabled (boolean, required) 'true' or 'false' to enable or disable respectively.\n" + "\nResult:\n" + "enabled (boolean) Whether or not migration is enabled (echos the argument).\n" + ); + fSaplingMigrationEnabled = params[0].get_bool(); + return fSaplingMigrationEnabled; +} /** When estimating the number of coinbase utxos we can shield in a single transaction: @@ -4660,6 +4681,7 @@ static const CRPCCommand commands[] = { "wallet", "z_gettotalbalance", &z_gettotalbalance, false }, { "wallet", "z_mergetoaddress", &z_mergetoaddress, false }, { "wallet", "z_sendmany", &z_sendmany, false }, + { "wallet", "z_setmigration", &z_setmigration, false }, { "wallet", "z_shieldcoinbase", &z_shieldcoinbase, false }, { "wallet", "z_getoperationstatus", &z_getoperationstatus, true }, { "wallet", "z_getoperationresult", &z_getoperationresult, true }, diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 6dfa150252c..4ddf5a0737d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -5,8 +5,10 @@ #include "wallet/wallet.h" +#include "asyncrpcqueue.h" #include "checkpoints.h" #include "coincontrol.h" +#include "core_io.h" #include "consensus/upgrades.h" #include "consensus/validation.h" #include "consensus/consensus.h" @@ -15,12 +17,14 @@ #include "main.h" #include "net.h" #include "rpc/protocol.h" +#include "rpc/server.h" #include "script/script.h" #include "script/sign.h" #include "timedata.h" #include "utilmoneystr.h" #include "zcash/Note.hpp" #include "crypter.h" +#include "wallet/asyncrpcoperation_saplingmigration.h" #include "zcash/zip32.h" #include @@ -32,6 +36,8 @@ using namespace std; using namespace libzcash; +extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); + /** * Settings */ @@ -566,6 +572,47 @@ void CWallet::ChainTip(const CBlockIndex *pindex, UpdateSaplingNullifierNoteMapForBlock(pblock); } +void CWallet::RunSaplingMigration(int blockHeight) { + if (!NetworkUpgradeActive(blockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { + return; + } + LOCK(cs_wallet); + // The migration transactions to be sent in a particular batch can take + // significant time to generate, and this time depends on the speed of the user's + // computer. If they were generated only after a block is seen at the target + // height minus 1, then this could leak information. Therefore, for target + // height N, implementations SHOULD start generating the transactions at around + // height N-5 + if (blockHeight % 500 == 495) { + if (saplingMigrationOperation != nullptr) { + saplingMigrationOperation->cancel(); + } + pendingSaplingMigrationTxs.clear(); + std::shared_ptr q = getAsyncRPCQueue(); + std::shared_ptr operation(new AsyncRPCOperation_saplingmigration(blockHeight + 5)); + saplingMigrationOperation = operation; + q->addOperation(operation); + } else if (blockHeight % 500 == 499) { + for (const CTransaction& transaction : pendingSaplingMigrationTxs) { + // The following is taken from z_sendmany/z_mergetoaddress + // Send the transaction + // TODO: Use CWallet::CommitTransaction instead of sendrawtransaction + auto signedtxn = EncodeHexTx(transaction); + UniValue params = UniValue(UniValue::VARR); + params.push_back(signedtxn); + UniValue sendResultValue = sendrawtransaction(params, false); + if (sendResultValue.isNull()) { + throw JSONRPCError(RPC_WALLET_ERROR, "sendrawtransaction did not return an error or a txid."); + } + } + pendingSaplingMigrationTxs.clear(); + } +} + +void CWallet::AddPendingSaplingMigrationTx(const CTransaction& tx) { + pendingSaplingMigrationTxs.push_back(tx); +} + void CWallet::SetBestChain(const CBlockLocator& loc) { CWalletDB walletdb(strWalletFile); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 3f43e434e83..9c2d602267e 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -7,6 +7,7 @@ #define BITCOIN_WALLET_WALLET_H #include "amount.h" +#include "asyncrpcoperation.h" #include "coins.h" #include "key.h" #include "keystore.h" @@ -755,6 +756,9 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface TxNullifiers mapTxSproutNullifiers; TxNullifiers mapTxSaplingNullifiers; + std::vector pendingSaplingMigrationTxs; + std::shared_ptr saplingMigrationOperation = nullptr; + void AddToTransparentSpends(const COutPoint& outpoint, const uint256& wtxid); void AddToSproutSpends(const uint256& nullifier, const uint256& wtxid); void AddToSaplingSpends(const uint256& nullifier, const uint256& wtxid); @@ -1183,6 +1187,8 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const; CAmount GetChange(const CTransaction& tx) const; void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree, bool added); + void RunSaplingMigration(int blockHeight); + void AddPendingSaplingMigrationTx(const CTransaction& tx); /** Saves witness caches and best block locator to disk. */ void SetBestChain(const CBlockLocator& loc); std::set> GetNullifiersForAddresses(const std::set & addresses); From 162bfc3a1edac35bb803438dcc2f72e183122da9 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 16 Apr 2019 19:05:15 -0600 Subject: [PATCH 028/127] Move migration logic to ChainTip --- src/main.cpp | 5 ----- src/main.h | 1 - src/validationinterface.cpp | 3 --- src/validationinterface.h | 3 --- .../asyncrpcoperation_saplingmigration.cpp | 4 ++-- src/wallet/rpcwallet.cpp | 5 +++-- src/wallet/wallet.cpp | 19 ++++++++++++++++--- src/wallet/wallet.h | 2 ++ 8 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 782ab69b07f..72744b61a72 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -78,7 +78,6 @@ bool fCoinbaseEnforcedProtectionEnabled = true; size_t nCoinCacheUsage = 5000 * 300; uint64_t nPruneTarget = 0; bool fAlerts = DEFAULT_ALERTS; -bool fSaplingMigrationEnabled = false; /* If the tip is older than this (in seconds), the node is considered to be in initial block download. */ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; @@ -3105,10 +3104,6 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * EnforceNodeDeprecation(pindexNew->nHeight); - if (fSaplingMigrationEnabled) { - GetMainSignals().RunSaplingMigration(pindexNew->nHeight); - } - int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001); diff --git a/src/main.h b/src/main.h index 0e1fa669410..3b8c6aff9db 100644 --- a/src/main.h +++ b/src/main.h @@ -154,7 +154,6 @@ extern bool fCoinbaseEnforcedProtectionEnabled; extern size_t nCoinCacheUsage; extern CFeeRate minRelayTxFee; extern bool fAlerts; -extern bool fSaplingMigrationEnabled; extern int64_t nMaxTipAge; /** Best header we've seen so far (used for getheaders queries' starting points). */ diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index bb3f800fc33..1dc3351ab27 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -18,7 +18,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5)); - g_signals.RunSaplingMigration.connect(boost::bind(&CValidationInterface::RunSaplingMigration, pwalletIn, _1)); g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); @@ -34,7 +33,6 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5)); - g_signals.RunSaplingMigration.disconnect(boost::bind(&CValidationInterface::RunSaplingMigration, pwalletIn, _1)); g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); @@ -49,7 +47,6 @@ void UnregisterAllValidationInterfaces() { g_signals.Broadcast.disconnect_all_slots(); g_signals.Inventory.disconnect_all_slots(); g_signals.ChainTip.disconnect_all_slots(); - g_signals.RunSaplingMigration.disconnect_all_slots(); g_signals.SetBestChain.disconnect_all_slots(); g_signals.UpdatedTransaction.disconnect_all_slots(); g_signals.EraseTransaction.disconnect_all_slots(); diff --git a/src/validationinterface.h b/src/validationinterface.h index 9e443d13459..7b02bd9da4a 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -37,7 +37,6 @@ class CValidationInterface { virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {} virtual void EraseFromWallet(const uint256 &hash) {} virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree, bool added) {} - virtual void RunSaplingMigration(int blockHeight) {} virtual void SetBestChain(const CBlockLocator &locator) {} virtual void UpdatedTransaction(const uint256 &hash) {} virtual void Inventory(const uint256 &hash) {} @@ -61,8 +60,6 @@ struct CMainSignals { boost::signals2::signal UpdatedTransaction; /** Notifies listeners of a change to the tip of the active block chain. */ boost::signals2::signal ChainTip; - /** Notifies listeners that they may need to update the status of the Sprout->Sapling migration */ - boost::signals2::signal RunSaplingMigration; /** Notifies listeners of a new active block chain. */ boost::signals2::signal SetBestChain; /** Notifies listeners about an inventory item being seen on the network. */ diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index 6a043f9bf35..fd40fb74a86 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -73,7 +73,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, "", 0); } if (sproutEntries.empty()) { // Consider, should the migration remain enabled? - fSaplingMigrationEnabled = false; + pwalletMain->fSaplingMigrationEnabled = false; return true; } CAmount availableFunds = 0; @@ -82,7 +82,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { } // If the remaining amount to be migrated is less than 0.01 ZEC, end the migration. if (availableFunds < CENT) { - fSaplingMigrationEnabled = false; + pwalletMain->fSaplingMigrationEnabled = false; return true; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 7cf5429a7b4..ea70b0a91c5 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3924,8 +3924,9 @@ UniValue z_setmigration(const UniValue& params, bool fHelp) { "\nResult:\n" "enabled (boolean) Whether or not migration is enabled (echos the argument).\n" ); - fSaplingMigrationEnabled = params[0].get_bool(); - return fSaplingMigrationEnabled; + LOCK(pwalletMain->cs_wallet); + pwalletMain->fSaplingMigrationEnabled = params[0].get_bool(); + return pwalletMain->fSaplingMigrationEnabled; } /** diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 4ddf5a0737d..9c310743600 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -558,6 +558,15 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, return false; } +void CWallet::ChainTipAdded(const CBlockIndex *pindex, + const CBlock *pblock, + SproutMerkleTree sproutTree, + SaplingMerkleTree saplingTree) +{ + IncrementNoteWitnesses(pindex, pblock, sproutTree, saplingTree); + UpdateSaplingNullifierNoteMapForBlock(pblock); +} + void CWallet::ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, @@ -565,11 +574,12 @@ void CWallet::ChainTip(const CBlockIndex *pindex, bool added) { if (added) { - IncrementNoteWitnesses(pindex, pblock, sproutTree, saplingTree); + ChainTipAdded(pindex, pblock, sproutTree, saplingTree); + RunSaplingMigration(pindex->nHeight); } else { DecrementNoteWitnesses(pindex); + UpdateSaplingNullifierNoteMapForBlock(pblock); } - UpdateSaplingNullifierNoteMapForBlock(pblock); } void CWallet::RunSaplingMigration(int blockHeight) { @@ -577,6 +587,9 @@ void CWallet::RunSaplingMigration(int blockHeight) { return; } LOCK(cs_wallet); + if (!fSaplingMigrationEnabled) { + return; + } // The migration transactions to be sent in a particular batch can take // significant time to generate, and this time depends on the speed of the user's // computer. If they were generated only after a block is seen at the target @@ -2491,7 +2504,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) } } // Increment note witness caches - ChainTip(pindex, &block, sproutTree, saplingTree, true); + ChainTipAdded(pindex, &block, sproutTree, saplingTree); pindex = chainActive.Next(pindex); if (GetTime() >= nNow + 60) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 9c2d602267e..7cd808b6250 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -771,6 +771,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface * incremental witness cache in any transaction in mapWallet. */ int64_t nWitnessCacheSize; + bool fSaplingMigrationEnabled = false; void ClearNoteWitnessCache(); @@ -836,6 +837,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface private: template void SyncMetaData(std::pair::iterator, typename TxSpendMap::iterator>); + void ChainTipAdded(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree); protected: bool UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx); From 699288b4b4330996dec6d356d405774e6751a9b2 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 16 Apr 2019 19:12:53 -0600 Subject: [PATCH 029/127] Documentation cleanup --- qa/rpc-tests/sprout_sapling_migration.py | 2 +- .../asyncrpcoperation_saplingmigration.cpp | 2 +- src/wallet/rpcwallet.cpp | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py index 726e5e2aa61..b888fb8e2eb 100755 --- a/qa/rpc-tests/sprout_sapling_migration.py +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -41,7 +41,7 @@ def run_test(self): assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0')) # Migrate - assert_equal(True, self.nodes[0].z_setmigration(True)) + self.nodes[0].z_setmigration(True) print "Mining to block 494..." self.nodes[0].generate(392) # 102 -> 494 self.sync_all() diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index fd40fb74a86..22157c68214 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -169,7 +169,7 @@ libzcash::SaplingPaymentAddress AsyncRPCOperation_saplingmigration::getMigration // Derive m/32'/coin_type' auto m_32h_cth = m_32h.Derive(bip44CoinType | ZIP32_HARDENED_KEY_LIMIT); - // Derive account key at next index, skip keys already known to the wallet + // Derive m/32'/coin_type'/0' libzcash::SaplingExtendedSpendingKey xsk = m_32h_cth.Derive(0 | ZIP32_HARDENED_KEY_LIMIT); libzcash::SaplingPaymentAddress toAddress = xsk.DefaultAddress(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ea70b0a91c5..347d65b189f 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3913,20 +3913,20 @@ UniValue z_setmigration(const UniValue& params, bool fHelp) { throw runtime_error( "z_setmigration enabled\n" "When enabled the Sprout to Sapling migration will attempt to migrate all funds from this wallet’s\n" - "Sprout addresses to either the address for Sapling account 0 or one specified by the parameter\n" - "'-migrationdestaddress'. This migration is designed to minimize information leakage. As a result,\n" - "for wallets with a significant Sprout balance, this process may take several weeks. The migration\n" - "works by sending, up to 5, as many transactions as possible whenever the blockchain reaches a height\n" - "equal to 499 modulo 500. The transaction amounts are picked according to the random distribution\n" - "specified in ZIP 308. The migration will end once the wallet’s Sprout balance is below 0.01 " + CURRENCY_UNIT + ".\n" + "Sprout addresses to either the address for Sapling account 0 or the address specified by the parameter\n" + "'-migrationdestaddress'.\n" + "\n" + "This migration is designed to minimize information leakage. As a result for wallets with a significant\n" + "Sprout balance, this process may take several weeks. The migration works by sending, up to 5, as many\n" + "transactions as possible whenever the blockchain reaches a height equal to 499 modulo 500. The transaction\n" + "amounts are picked according to the random distribution specified in ZIP 308. The migration will end once\n" + "the wallet’s Sprout balance is below" + strprintf("%s %s", FormatMoney(CENT), CURRENCY_UNIT) + ".\n" "\nArguments:\n" "1. enabled (boolean, required) 'true' or 'false' to enable or disable respectively.\n" - "\nResult:\n" - "enabled (boolean) Whether or not migration is enabled (echos the argument).\n" ); LOCK(pwalletMain->cs_wallet); pwalletMain->fSaplingMigrationEnabled = params[0].get_bool(); - return pwalletMain->fSaplingMigrationEnabled; + return NullUniValue; } /** From 7c4ad6e2986907e621496cd992010b264b37c63c Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 16 Apr 2019 19:35:04 -0600 Subject: [PATCH 030/127] Additional locking and race condition prevention --- src/wallet/wallet.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 9c310743600..07fafe42f1a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -606,6 +606,9 @@ void CWallet::RunSaplingMigration(int blockHeight) { saplingMigrationOperation = operation; q->addOperation(operation); } else if (blockHeight % 500 == 499) { + if (saplingMigrationOperation != nullptr) { + saplingMigrationOperation->cancel(); + } for (const CTransaction& transaction : pendingSaplingMigrationTxs) { // The following is taken from z_sendmany/z_mergetoaddress // Send the transaction @@ -623,6 +626,7 @@ void CWallet::RunSaplingMigration(int blockHeight) { } void CWallet::AddPendingSaplingMigrationTx(const CTransaction& tx) { + LOCK(cs_wallet); pendingSaplingMigrationTxs.push_back(tx); } From d2a584e35a1f85e28919b4b74bb97a6da3abaa9d Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Thu, 18 Apr 2019 15:41:27 -0600 Subject: [PATCH 031/127] Refactor wait_and_assert_operationid_status to allow returning the result --- qa/rpc-tests/sprout_sapling_migration.py | 12 +++++--- qa/rpc-tests/test_framework/util.py | 35 ++++++++++++------------ qa/rpc-tests/wallet_protectcoinbase.py | 4 +-- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py index b888fb8e2eb..0e606fb5eb6 100755 --- a/qa/rpc-tests/sprout_sapling_migration.py +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -8,7 +8,8 @@ from decimal import Decimal from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_true, get_coinbase_address, \ - initialize_chain_clean, start_nodes, wait_and_assert_operationid_status + initialize_chain_clean, start_nodes, wait_and_assert_operationid_status, \ + wait_and_assert_operationid_status_result class SproutSaplingMigration(BitcoinTestFramework): @@ -54,14 +55,17 @@ def run_test(self): # At 495 we should have an async operation operationstatus = self.nodes[0].z_getoperationstatus() + print "migration operation: {}".format(operationstatus) assert_equal(1, len(operationstatus), "num async operations at 495") assert_equal('saplingmigration', operationstatus[0]['method']) assert_equal(500, operationstatus[0]['target_height']) - print "migration operation: {}".format(operationstatus) - migration_opid = operationstatus[0]['id'] - result = wait_and_assert_operationid_status(self.nodes[0], migration_opid) + result = wait_and_assert_operationid_status_result(self.nodes[0], operationstatus[0]['id']) print "result: {}".format(result) + assert_equal('saplingmigration', result['method']) + assert_equal(500, result['target_height']) + assert_equal(1, result['result']['num_tx_created']) + assert_equal(0, len(self.nodes[0].getrawmempool()), "mempool size at 495") self.nodes[0].generate(3) diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 7d15ec063c7..590cb2d48a1 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -385,8 +385,9 @@ def assert_raises(exc, fun, *args, **kwds): def fail(message=""): raise AssertionError(message) -# Returns txid if operation was a success or None -def wait_and_assert_operationid_status(node, myopid, in_status='success', in_errormsg=None, timeout=300): + +# Returns an async operation result +def wait_and_assert_operationid_status_result(node, myopid, in_status='success', in_errormsg=None, timeout=300): print('waiting for async operation {}'.format(myopid)) result = None for _ in xrange(1, timeout): @@ -399,29 +400,29 @@ def wait_and_assert_operationid_status(node, myopid, in_status='success', in_err assert_true(result is not None, "timeout occured") status = result['status'] - ret = None + debug = os.getenv("PYTHON_DEBUG", "") + if debug: + print('...returned status: {}'.format(status)) + errormsg = None if status == "failed": errormsg = result['error']['message'] - elif status == "success": - if type(result['result']) is dict and result['result'].get('txid'): - ret = result['result']['txid'] - else: - ret = result['result'] - - if os.getenv("PYTHON_DEBUG", ""): - print('...returned status: {}'.format(status)) - if errormsg is not None: + if debug: print('...returned error: {}'.format(errormsg)) + assert_equal(in_errormsg, errormsg) assert_equal(in_status, status, "Operation returned mismatched status. Error Message: {}".format(errormsg)) - if errormsg is not None: - assert_true(in_errormsg is not None, "No error retured. Expected: {}".format(errormsg)) - assert_true(in_errormsg in errormsg, "Error returned: {}. Error expected: {}".format(errormsg, in_errormsg)) - return result # if there was an error return the result + return result + + +# Returns txid if operation was a success or None +def wait_and_assert_operationid_status(node, myopid, in_status='success', in_errormsg=None, timeout=300): + result = wait_and_assert_operationid_status_result(node, myopid, in_status, in_errormsg, timeout) + if result['status'] == "success": + return result['result']['txid'] else: - return ret # otherwise return the txid + return None # Find a coinbase address on the node, filtering by the number of UTXOs it has. # If no filter is provided, returns the coinbase address on the node containing diff --git a/qa/rpc-tests/wallet_protectcoinbase.py b/qa/rpc-tests/wallet_protectcoinbase.py index 85109931163..5eaed7c3a52 100755 --- a/qa/rpc-tests/wallet_protectcoinbase.py +++ b/qa/rpc-tests/wallet_protectcoinbase.py @@ -10,7 +10,7 @@ from test_framework.mininode import COIN from test_framework.util import assert_equal, initialize_chain_clean, \ start_nodes, connect_nodes_bi, wait_and_assert_operationid_status, \ - get_coinbase_address + wait_and_assert_operationid_status_result, get_coinbase_address import sys import timeit @@ -92,7 +92,7 @@ def run_test (self): recipients.append({"address":myzaddr, "amount":Decimal('1.23456789')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - error_result = wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "wallet does not allow any change", 10) + error_result = wait_and_assert_operationid_status_result(self.nodes[0], myopid, "failed", "wallet does not allow any change", 10) # Test that the returned status object contains a params field with the operation's input parameters assert_equal(error_result["method"], "z_sendmany") From 5519d16997c07c02932804e17dc23625be656e8b Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Thu, 25 Apr 2019 13:43:23 -0600 Subject: [PATCH 032/127] Set min depth when selecting notes to migrate --- qa/rpc-tests/sprout_sapling_migration.py | 1 + .../asyncrpcoperation_saplingmigration.cpp | 18 ++++++++++-------- .../asyncrpcoperation_saplingmigration.h | 2 ++ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py index 0e606fb5eb6..13dc2189001 100755 --- a/qa/rpc-tests/sprout_sapling_migration.py +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -94,6 +94,7 @@ def run_test(self): print "sprout balance: {}, sapling balance: {}".format(sprout_balance, sapling_balance) assert_true(sprout_balance < Decimal('10'), "Should have less Sprout funds") assert_true(sapling_balance > Decimal('0'), "Should have more Sapling funds") + assert_true(sprout_balance + sapling_balance, Decimal('9.9999')) if __name__ == '__main__': diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index 22157c68214..85962f75a9b 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -54,7 +54,7 @@ void AsyncRPCOperation_saplingmigration::main() { set_state(OperationStatus::FAILED); } - std::string s = strprintf("%s: Sprout->Sapling transactions sent. (status=%s", getId(), getStateAsString()); + std::string s = strprintf("%s: Sprout->Sapling transactions created. (status=%s", getId(), getStateAsString()); if (success) { s += strprintf(", success)\n"); } else { @@ -69,12 +69,10 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { std::vector saplingEntries; { LOCK2(cs_main, pwalletMain->cs_wallet); + // We set minDepth to 11 to avoid unconfirmed notes and in anticipation of specifying + // an anchor at height N-10 for each Sprout JoinSplit description // Consider, should notes be sorted? - pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, "", 0); - } - if (sproutEntries.empty()) { // Consider, should the migration remain enabled? - pwalletMain->fSaplingMigrationEnabled = false; - return true; + pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, "", 11); } CAmount availableFunds = 0; for (const CSproutNotePlaintextEntry& sproutEntry : sproutEntries) { @@ -82,7 +80,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { } // If the remaining amount to be migrated is less than 0.01 ZEC, end the migration. if (availableFunds < CENT) { - pwalletMain->fSaplingMigrationEnabled = false; + setMigrationResult(0); return true; } @@ -136,10 +134,14 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { ++numTxCreated; } while (numTxCreated < 5 && availableFunds > CENT); + setMigrationResult(numTxCreated); + return true; +} + +void AsyncRPCOperation_saplingmigration::setMigrationResult(int numTxCreated) { UniValue res(UniValue::VOBJ); res.push_back(Pair("num_tx_created", numTxCreated)); set_result(res); - return true; } CAmount AsyncRPCOperation_saplingmigration::chooseAmount(const CAmount& availableFunds) { diff --git a/src/wallet/asyncrpcoperation_saplingmigration.h b/src/wallet/asyncrpcoperation_saplingmigration.h index b520db408ff..af26281f613 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.h +++ b/src/wallet/asyncrpcoperation_saplingmigration.h @@ -25,6 +25,8 @@ class AsyncRPCOperation_saplingmigration : public AsyncRPCOperation bool main_impl(); + void setMigrationResult(int numTxCreated); + CAmount chooseAmount(const CAmount& availableFunds); libzcash::SaplingPaymentAddress getMigrationDestAddress(const HDSeed& seed); From 7fb8088288196ee9659bf14967ff1ea1b05b3b83 Mon Sep 17 00:00:00 2001 From: Larry Ruane Date: Thu, 21 Feb 2019 14:01:12 -0700 Subject: [PATCH 033/127] add -timestampindex for bitcore insight block explorer --- src/Makefile.am | 1 + src/main.cpp | 26 ++++++++- src/main.h | 1 + src/timestampindex.h | 131 +++++++++++++++++++++++++++++++++++++++++++ src/txdb.cpp | 52 +++++++++++++++++ src/txdb.h | 10 ++++ 6 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 src/timestampindex.h diff --git a/src/Makefile.am b/src/Makefile.am index 181ae7ec012..d698e124585 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -199,6 +199,7 @@ BITCOIN_CORE_H = \ sync.h \ threadsafety.h \ timedata.h \ + timestampindex.h \ tinyformat.h \ torcontrol.h \ transaction_builder.h \ diff --git a/src/main.cpp b/src/main.cpp index 33cb99320ca..e5c6c19b0b3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,6 +70,7 @@ bool fTxIndex = false; bool fInsightExplorer = false; // insightexplorer bool fAddressIndex = false; // insightexplorer bool fSpentIndex = false; // insightexplorer +bool fTimestampIndex = false; // insightexplorer bool fHavePruned = false; bool fPruneMode = false; bool fIsBareMultisigStd = true; @@ -2801,7 +2802,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!pblocktree->WriteTxIndex(vPos)) return AbortNode(state, "Failed to write transaction index"); - // insightexplorer + // START insightexplorer if (fAddressIndex) { if (!pblocktree->WriteAddressIndex(addressIndex)) { return AbortNode(state, "Failed to write address index"); @@ -2810,12 +2811,32 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return AbortNode(state, "Failed to write address unspent index"); } } - // insightexplorer if (fSpentIndex) { if (!pblocktree->UpdateSpentIndex(spentIndex)) { return AbortNode(state, "Failed to write spent index"); } } + if (fTimestampIndex) { + unsigned int logicalTS = pindex->nTime; + unsigned int prevLogicalTS = 0; + + // retrieve logical timestamp of the previous block + if (pindex->pprev) + if (!pblocktree->ReadTimestampBlockIndex(pindex->pprev->GetBlockHash(), prevLogicalTS)) + LogPrintf("%s: Failed to read previous block's logical timestamp\n", __func__); + + if (logicalTS <= prevLogicalTS) { + logicalTS = prevLogicalTS + 1; + LogPrintf("%s: Previous logical timestamp is newer Actual[%d] prevLogical[%d] Logical[%d]\n", __func__, pindex->nTime, prevLogicalTS, logicalTS); + } + + if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(logicalTS, pindex->GetBlockHash()))) + return AbortNode(state, "Failed to write timestamp index"); + + if (!pblocktree->WriteTimestampBlockIndex(CTimestampBlockIndexKey(pindex->GetBlockHash()), CTimestampBlockIndexValue(logicalTS))) + return AbortNode(state, "Failed to write blockhash index"); + } + // END insightexplorer // add this block to the view's block chain view.SetBestBlock(pindex->GetBlockHash()); @@ -4715,6 +4736,7 @@ bool InitBlockIndex() { pblocktree->WriteFlag("insightexplorer", fInsightExplorer); fAddressIndex = fInsightExplorer; fSpentIndex = fInsightExplorer; + fTimestampIndex = fInsightExplorer; LogPrintf("Initializing databases...\n"); diff --git a/src/main.h b/src/main.h index f19fc84ff38..df9e7ea3ab5 100644 --- a/src/main.h +++ b/src/main.h @@ -28,6 +28,7 @@ #include "uint256.h" #include "addressindex.h" #include "spentindex.h" +#include "timestampindex.h" #include #include diff --git a/src/timestampindex.h b/src/timestampindex.h new file mode 100644 index 00000000000..3e402872cf4 --- /dev/null +++ b/src/timestampindex.h @@ -0,0 +1,131 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_TIMESTAMPINDEX_H +#define BITCOIN_TIMESTAMPINDEX_H + +#include "uint256.h" + +struct CTimestampIndexIteratorKey { + unsigned int timestamp; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 4; + } + template + void Serialize(Stream& s) const { + ser_writedata32be(s, timestamp); + } + template + void Unserialize(Stream& s) { + timestamp = ser_readdata32be(s); + } + + CTimestampIndexIteratorKey(unsigned int time) { + timestamp = time; + } + + CTimestampIndexIteratorKey() { + SetNull(); + } + + void SetNull() { + timestamp = 0; + } +}; + +struct CTimestampIndexKey { + unsigned int timestamp; + uint256 blockHash; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 36; + } + template + void Serialize(Stream& s) const { + ser_writedata32be(s, timestamp); + blockHash.Serialize(s); + } + template + void Unserialize(Stream& s) { + timestamp = ser_readdata32be(s); + blockHash.Unserialize(s); + } + + CTimestampIndexKey(unsigned int time, uint256 hash) { + timestamp = time; + blockHash = hash; + } + + CTimestampIndexKey() { + SetNull(); + } + + void SetNull() { + timestamp = 0; + blockHash.SetNull(); + } +}; + +struct CTimestampBlockIndexKey { + uint256 blockHash; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 32; + } + + template + void Serialize(Stream& s) const { + blockHash.Serialize(s); + } + + template + void Unserialize(Stream& s) { + blockHash.Unserialize(s); + } + + CTimestampBlockIndexKey(uint256 hash) { + blockHash = hash; + } + + CTimestampBlockIndexKey() { + SetNull(); + } + + void SetNull() { + blockHash.SetNull(); + } +}; + +struct CTimestampBlockIndexValue { + unsigned int ltimestamp; + size_t GetSerializeSize(int nType, int nVersion) const { + return 4; + } + + template + void Serialize(Stream& s) const { + ser_writedata32be(s, ltimestamp); + } + + template + void Unserialize(Stream& s) { + ltimestamp = ser_readdata32be(s); + } + + CTimestampBlockIndexValue (unsigned int time) { + ltimestamp = time; + } + + CTimestampBlockIndexValue() { + SetNull(); + } + + void SetNull() { + ltimestamp = 0; + } +}; + +#endif // BITCOIN_TIMESTAMPINDEX_H diff --git a/src/txdb.cpp b/src/txdb.cpp index b0c89f7d367..5ed75f3c969 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -39,6 +39,8 @@ static const char DB_LAST_BLOCK = 'l'; static const char DB_ADDRESSINDEX = 'd'; static const char DB_ADDRESSUNSPENTINDEX = 'u'; static const char DB_SPENTINDEX = 'p'; +static const char DB_TIMESTAMPINDEX = 'T'; +static const char DB_BLOCKHASHINDEX = 'h'; CCoinsViewDB::CCoinsViewDB(std::string dbName, size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / dbName, nCacheSize, fMemory, fWipe) { } @@ -390,6 +392,56 @@ bool CBlockTreeDB::UpdateSpentIndex(const std::vector &vect) } return WriteBatch(batch); } + +bool CBlockTreeDB::WriteTimestampIndex(const CTimestampIndexKey ×tampIndex) { + CDBBatch batch(*this); + batch.Write(make_pair(DB_TIMESTAMPINDEX, timestampIndex), 0); + return WriteBatch(batch); +} + +bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned int &low, + const bool fActiveOnly, std::vector > &hashes) +{ + boost::scoped_ptr pcursor(NewIterator()); + + pcursor->Seek(make_pair(DB_TIMESTAMPINDEX, CTimestampIndexIteratorKey(low))); + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + if (!(pcursor->GetKey(key) && key.first == DB_TIMESTAMPINDEX && key.second.timestamp < high)) { + break; + } + if (fActiveOnly) { + CBlockIndex* pblockindex = mapBlockIndex[key.second.blockHash]; + if (chainActive.Contains(pblockindex)) { + hashes.push_back(std::make_pair(key.second.blockHash, key.second.timestamp)); + } + } else { + hashes.push_back(std::make_pair(key.second.blockHash, key.second.timestamp)); + } + pcursor->Next(); + } + return true; +} + +bool CBlockTreeDB::WriteTimestampBlockIndex(const CTimestampBlockIndexKey &blockhashIndex, + const CTimestampBlockIndexValue &logicalts) +{ + CDBBatch batch(*this); + batch.Write(make_pair(DB_BLOCKHASHINDEX, blockhashIndex), logicalts); + return WriteBatch(batch); +} + +bool CBlockTreeDB::ReadTimestampBlockIndex(const uint256 &hash, unsigned int <imestamp) +{ + CTimestampBlockIndexValue(lts); + if (!Read(std::make_pair(DB_BLOCKHASHINDEX, hash), lts)) + return false; + + ltimestamp = lts.ltimestamp; + return true; +} // END insightexplorer bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) { diff --git a/src/txdb.h b/src/txdb.h index f1f78085184..c00b2d68a11 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -26,6 +26,10 @@ struct CAddressIndexIteratorKey; struct CAddressIndexIteratorHeightKey; struct CSpentIndexKey; struct CSpentIndexValue; +struct CTimestampIndexKey; +struct CTimestampIndexIteratorKey; +struct CTimestampBlockIndexKey; +struct CTimestampBlockIndexValue; typedef std::pair CAddressUnspentDbEntry; typedef std::pair CAddressIndexDbEntry; @@ -94,6 +98,12 @@ class CBlockTreeDB : public CDBWrapper bool ReadAddressIndex(uint160 addressHash, int type, std::vector &addressIndex, int start = 0, int end = 0); bool ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value); bool UpdateSpentIndex(const std::vector &vect); + bool WriteTimestampIndex(const CTimestampIndexKey ×tampIndex); + bool ReadTimestampIndex(const unsigned int &high, const unsigned int &low, + const bool fActiveOnly, std::vector > &vect); + bool WriteTimestampBlockIndex(const CTimestampBlockIndexKey &blockhashIndex, + const CTimestampBlockIndexValue &logicalts); + bool ReadTimestampBlockIndex(const uint256 &hash, unsigned int &logicalTS); // END insightexplorer bool WriteFlag(const std::string &name, bool fValue); From 6acb37bcee606aac23a8895ef4a7b2bbc32b3634 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Fri, 26 Apr 2019 19:01:23 -0600 Subject: [PATCH 034/127] Check for full failure message in test case --- qa/rpc-tests/wallet_protectcoinbase.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qa/rpc-tests/wallet_protectcoinbase.py b/qa/rpc-tests/wallet_protectcoinbase.py index 5eaed7c3a52..e7a3b9e5a1c 100755 --- a/qa/rpc-tests/wallet_protectcoinbase.py +++ b/qa/rpc-tests/wallet_protectcoinbase.py @@ -84,7 +84,7 @@ def run_test (self): recipients= [{"address":myzaddr, "amount": Decimal('1')}] myopid = self.nodes[3].z_sendmany(mytaddr, recipients) - wait_and_assert_operationid_status(self.nodes[3], myopid, "failed", "no UTXOs found for taddr from address", 10) + wait_and_assert_operationid_status(self.nodes[3], myopid, "failed", "Insufficient funds, no UTXOs found for taddr from address.", 10) # This send will fail because our wallet does not allow any change when protecting a coinbase utxo, # as it's currently not possible to specify a change address in z_sendmany. @@ -92,7 +92,9 @@ def run_test (self): recipients.append({"address":myzaddr, "amount":Decimal('1.23456789')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - error_result = wait_and_assert_operationid_status_result(self.nodes[0], myopid, "failed", "wallet does not allow any change", 10) + error_result = wait_and_assert_operationid_status_result(self.nodes[0], myopid, "failed", ("Change 8.76533211 not allowed. " + "When shielding coinbase funds, the wallet does not allow any change " + "as there is currently no way to specify a change address in z_sendmany."), 10) # Test that the returned status object contains a params field with the operation's input parameters assert_equal(error_result["method"], "z_sendmany") From 8ffd63af2dc47deceaa4db3ee9d8b4435a9b7dff Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Mon, 29 Apr 2019 09:36:26 -0600 Subject: [PATCH 035/127] Add migration options to conf file Co-authored-by: Simon --- src/init.cpp | 14 ++++++++++++++ src/wallet/asyncrpcoperation_saplingmigration.cpp | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index 188e84490c0..7829ee8c214 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -37,6 +37,7 @@ #include "utilmoneystr.h" #include "validationinterface.h" #ifdef ENABLE_WALLET +#include "key_io.h" #include "wallet/wallet.h" #include "wallet/walletdb.h" #endif @@ -405,6 +406,8 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Wallet options:")); strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); strUsage += HelpMessageOpt("-keypool=", strprintf(_("Set key pool size to (default: %u)"), 100)); + strUsage += HelpMessageOpt("--migration=", _("Set to true to enable the Sprout to Sapling migration.")); + strUsage += HelpMessageOpt("-migrationdestaddress=", _("Set the Sapling migration address")); if (showDebug) strUsage += HelpMessageOpt("-mintxfee=", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(CWallet::minTxFee.GetFeePerK()))); @@ -1070,6 +1073,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fSendFreeTransactions = GetBoolArg("-sendfreetransactions", false); std::string strWalletFile = GetArg("-wallet", "wallet.dat"); + // Check Sapling migration address if set and is a valid Sapling address + if (mapArgs.count("-migrationdestaddress")) { + std::string migrationDestAddress = mapArgs["-migrationdestaddress"]; + libzcash::PaymentAddress address = DecodePaymentAddress(migrationDestAddress); + if (boost::get(&address) == nullptr) { + return InitError(_("-migrationdestaddress must be a valid Sapling address.")); + } + } #endif // ENABLE_WALLET fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", true); @@ -1671,6 +1682,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } + // Set sapling migration status + pwalletMain->fSaplingMigrationEnabled = GetBoolArg("-migration", false); + if (fFirstRun) { // Create new keyUser and set as default key diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index 85962f75a9b..4076415eaa2 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -2,6 +2,7 @@ #include "boost/variant/static_visitor.hpp" #include "asyncrpcoperation_saplingmigration.h" #include "init.h" +#include "key_io.h" #include "rpc/protocol.h" #include "random.h" #include "sync.h" @@ -161,6 +162,13 @@ CAmount AsyncRPCOperation_saplingmigration::chooseAmount(const CAmount& availabl // Unless otherwise specified, the migration destination address is the address for Sapling account 0 libzcash::SaplingPaymentAddress AsyncRPCOperation_saplingmigration::getMigrationDestAddress(const HDSeed& seed) { + if (mapArgs.count("-migrationdestaddress")) { + std::string migrationDestAddress = mapArgs["-migrationdestaddress"]; + auto address = DecodePaymentAddress(migrationDestAddress); + auto saplingAddress = boost::get(&address); + assert(saplingAddress != nullptr); // This is checked in init.cpp + return *saplingAddress; + } // Derive the address for Sapling account 0 auto m = libzcash::SaplingExtendedSpendingKey::Master(seed); uint32_t bip44CoinType = Params().BIP44CoinType(); From b9c7f274a472b61386dcfe294cc8590ff460fd7e Mon Sep 17 00:00:00 2001 From: str4d Date: Mon, 29 Apr 2019 09:55:07 -0600 Subject: [PATCH 036/127] remove extra hyphen Co-Authored-By: Eirik0 --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 7829ee8c214..653a05fcb31 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -406,7 +406,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Wallet options:")); strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); strUsage += HelpMessageOpt("-keypool=", strprintf(_("Set key pool size to (default: %u)"), 100)); - strUsage += HelpMessageOpt("--migration=", _("Set to true to enable the Sprout to Sapling migration.")); + strUsage += HelpMessageOpt("-migration=", _("Set to true to enable the Sprout to Sapling migration.")); strUsage += HelpMessageOpt("-migrationdestaddress=", _("Set the Sapling migration address")); if (showDebug) strUsage += HelpMessageOpt("-mintxfee=", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)", From 52cfa9c1ee43e90c96e31a712b42926b857b8ee6 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 24 Apr 2019 16:20:08 -0600 Subject: [PATCH 037/127] Create method for getting HD seed in RPCs --- src/wallet/asyncrpcoperation_mergetoaddress.cpp | 7 +------ src/wallet/asyncrpcoperation_saplingmigration.cpp | 8 +------- src/wallet/asyncrpcoperation_sendmany.cpp | 7 +------ src/wallet/asyncrpcoperation_shieldcoinbase.cpp | 7 +------ src/wallet/rpcdump.cpp | 3 +-- src/wallet/wallet.cpp | 8 ++++++++ src/wallet/wallet.h | 3 +++ 7 files changed, 16 insertions(+), 27 deletions(-) diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index a0b414614b3..b3870e6029d 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -348,12 +348,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl() // generate a common one from the HD seed. This ensures the data is // recoverable, while keeping it logically separate from the ZIP 32 // Sapling key hierarchy, which the user might not be using. - HDSeed seed; - if (!pwalletMain->GetHDSeed(seed)) { - throw JSONRPCError( - RPC_WALLET_ERROR, - "AsyncRPCOperation_sendmany: HD seed not found"); - } + HDSeed seed = pwalletMain->GetHDSeedForRPC(); ovk = ovkForShieldingFromTaddr(seed); } if (!ovk) { diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index 4076415eaa2..ab44bf76077 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -85,13 +85,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { return true; } - HDSeed seed; - if (!pwalletMain->GetHDSeed(seed)) { - throw JSONRPCError( - RPC_WALLET_ERROR, - "AsyncRPCOperation_AsyncRPCOperation_saplingmigration: HD seed not found"); - } - + HDSeed seed = pwalletMain->GetHDSeedForRPC(); libzcash::SaplingPaymentAddress migrationDestAddress = getMigrationDestAddress(seed); auto consensusParams = Params().GetConsensus(); diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index e33440a4d0e..e30c0748373 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -381,12 +381,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { // generate a common one from the HD seed. This ensures the data is // recoverable, while keeping it logically separate from the ZIP 32 // Sapling key hierarchy, which the user might not be using. - HDSeed seed; - if (!pwalletMain->GetHDSeed(seed)) { - throw JSONRPCError( - RPC_WALLET_ERROR, - "AsyncRPCOperation_sendmany::main_impl(): HD seed not found"); - } + HDSeed seed = pwalletMain->GetHDSeedForRPC(); ovk = ovkForShieldingFromTaddr(seed); } diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp index 4280ac2f15c..84811c6868e 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp @@ -247,12 +247,7 @@ bool ShieldToAddress::operator()(const libzcash::SaplingPaymentAddress &zaddr) c // generate a common one from the HD seed. This ensures the data is // recoverable, while keeping it logically separate from the ZIP 32 // Sapling key hierarchy, which the user might not be using. - HDSeed seed; - if (!pwalletMain->GetHDSeed(seed)) { - throw JSONRPCError( - RPC_WALLET_ERROR, - "CWallet::GenerateNewSaplingZKey(): HD seed not found"); - } + HDSeed seed = pwalletMain->GetHDSeedForRPC(); uint256 ovk = ovkForShieldingFromTaddr(seed); // Add transparent inputs diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 600d0de8bb0..8105f51768e 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -506,8 +506,7 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys) file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString()); file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime())); { - HDSeed hdSeed; - pwalletMain->GetHDSeed(hdSeed); + HDSeed hdSeed = pwalletMain->GetHDSeedForRPC(); auto rawSeed = hdSeed.RawSeed(); file << strprintf("# HDSeed=%s fingerprint=%s", HexStr(rawSeed.begin(), rawSeed.end()), hdSeed.Fingerprint().GetHex()); file << "\n"; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 93e668923c8..cf220fcf2a6 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2156,6 +2156,14 @@ bool CWallet::SetCryptedHDSeed(const uint256& seedFp, const std::vectorGetHDSeed(seed)) { + throw JSONRPCError(RPC_WALLET_ERROR, "HD seed not found"); + } + return seed; +} + void CWallet::SetHDChain(const CHDChain& chain, bool memonly) { LOCK(cs_wallet); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 7cd808b6250..6e4c239d9de 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1288,6 +1288,9 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool SetHDSeed(const HDSeed& seed); bool SetCryptedHDSeed(const uint256& seedFp, const std::vector &vchCryptedSecret); + /* Returns the wallet's HD seed or throw JSONRPCError(...) */ + HDSeed GetHDSeedForRPC() const; + /* Set the HD chain model (chain child index counters) */ void SetHDChain(const CHDChain& chain, bool memonly); const CHDChain& GetHDChain() const { return hdChain; } From 6e82d72852ec81624ad8f833e1fc429786f4dfce Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Fri, 26 Apr 2019 15:31:57 -0600 Subject: [PATCH 038/127] Add rpc to get Sprout to Sapling migration status --- qa/rpc-tests/sprout_sapling_migration.py | 48 ++++++++-- .../asyncrpcoperation_saplingmigration.h | 4 +- src/wallet/rpcwallet.cpp | 96 +++++++++++++++++++ 3 files changed, 140 insertions(+), 8 deletions(-) diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py index 13dc2189001..cdfaa5393cd 100755 --- a/qa/rpc-tests/sprout_sapling_migration.py +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -11,12 +11,36 @@ initialize_chain_clean, start_nodes, wait_and_assert_operationid_status, \ wait_and_assert_operationid_status_result +SAPLING_ADDR = 'zregtestsapling1ssqj3f3majnl270985gqcdqedd9t4nlttjqskccwevj2v20sc25deqspv3masufnwcdy67cydyy' +SAPLING_KEY = 'secret-extended-key-regtest1qv62zt2fqyqqpqrh2qzc08h7gncf4447jh9kvnnnhjg959fkwt7mhw9j8e9at7attx8z6u3953u86vcnsujdc2ckdlcmztjt44x3uxpah5mxtncxd0mqcnz9eq8rghh5m4j44ep5d9702sdvvwawqassulktfegrcp4twxgqdxx4eww3lau0mywuaeztpla2cmvagr5nj98elt45zh6fjznadl6wz52n2uyhdwcm2wlsu8fnxstrk6s4t55t8dy6jkgx5g0cwpchh5qffp8x5' + + +def check_migration_status( + node, + enabled, + non_zero_unmigrated_amount, + non_zero_unfinalized_migrated_amount, + non_zero_finalized_migrated_amount, + finalized_migration_transactions, + len_migration_txids +): + status = node.z_getmigrationstatus() + assert_equal(enabled, status['enabled']) + assert_equal(SAPLING_ADDR, status['destination_address']) + assert_equal(non_zero_unmigrated_amount, Decimal(status['unmigrated_amount']) > Decimal('0.00')) + assert_equal(non_zero_unfinalized_migrated_amount, Decimal(status['unfinalized_migrated_amount']) > Decimal('0')) + assert_equal(non_zero_finalized_migrated_amount, Decimal(status['finalized_migrated_amount']) > Decimal('0')) + assert_equal(finalized_migration_transactions, status['finalized_migration_transactions']) + assert_equal(len_migration_txids, len(status['migration_txids'])) + class SproutSaplingMigration(BitcoinTestFramework): def setup_nodes(self): return start_nodes(4, self.options.tmpdir, [[ '-nuparams=5ba81b19:100', # Overwinter '-nuparams=76b809bb:100', # Sapling + '-migration', + '-migrationdestaddress=' + SAPLING_ADDR ]] * 4) def setup_chain(self): @@ -24,6 +48,10 @@ def setup_chain(self): initialize_chain_clean(self.options.tmpdir, 4) def run_test(self): + check_migration_status(self.nodes[0], True, False, False, False, 0, 0) + self.nodes[0].z_setmigration(False) + check_migration_status(self.nodes[0], False, False, False, False, 0, 0) + print "Mining blocks..." self.nodes[0].generate(101) self.sync_all() @@ -31,7 +59,8 @@ def run_test(self): # Send some ZEC to a Sprout address tAddr = get_coinbase_address(self.nodes[0]) sproutAddr = self.nodes[0].z_getnewaddress('sprout') - saplingAddr = self.nodes[0].z_getnewaddress('sapling') + # Import a previously generated key to test '-migrationdestaddress' + self.nodes[0].z_importkey(SAPLING_KEY) opid = self.nodes[0].z_sendmany(tAddr, [{"address": sproutAddr, "amount": Decimal('10')}], 1, 0) wait_and_assert_operationid_status(self.nodes[0], opid) @@ -39,7 +68,7 @@ def run_test(self): self.sync_all() assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('10')) - assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0')) + assert_equal(self.nodes[0].z_getbalance(SAPLING_ADDR), Decimal('0')) # Migrate self.nodes[0].z_setmigration(True) @@ -49,6 +78,7 @@ def run_test(self): # At 494 we should have no async operations assert_equal(0, len(self.nodes[0].z_getoperationstatus()), "num async operations at 494") + check_migration_status(self.nodes[0], True, True, False, False, 0, 0) self.nodes[0].generate(1) self.sync_all() @@ -74,7 +104,7 @@ def run_test(self): # At 498 the mempool will be empty and no funds will have moved assert_equal(0, len(self.nodes[0].getrawmempool()), "mempool size at 498") assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('10')) - assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0')) + assert_equal(self.nodes[0].z_getbalance(SAPLING_ADDR), Decimal('0')) self.nodes[0].generate(1) self.sync_all() @@ -82,20 +112,26 @@ def run_test(self): # At 499 there will be a transaction in the mempool and the note will be locked assert_equal(1, len(self.nodes[0].getrawmempool()), "mempool size at 499") assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('0')) - assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0')) - assert_true(self.nodes[0].z_getbalance(saplingAddr, 0) > Decimal('0'), "Unconfirmed sapling") + assert_equal(self.nodes[0].z_getbalance(SAPLING_ADDR), Decimal('0')) + assert_true(self.nodes[0].z_getbalance(SAPLING_ADDR, 0) > Decimal('0'), "Unconfirmed sapling") self.nodes[0].generate(1) self.sync_all() # At 500 funds will have moved sprout_balance = self.nodes[0].z_getbalance(sproutAddr) - sapling_balance = self.nodes[0].z_getbalance(saplingAddr) + sapling_balance = self.nodes[0].z_getbalance(SAPLING_ADDR) print "sprout balance: {}, sapling balance: {}".format(sprout_balance, sapling_balance) assert_true(sprout_balance < Decimal('10'), "Should have less Sprout funds") assert_true(sapling_balance > Decimal('0'), "Should have more Sapling funds") assert_true(sprout_balance + sapling_balance, Decimal('9.9999')) + check_migration_status(self.nodes[0], True, True, True, False, 0, 1) + # At 510 the transactions will be considered 'finalized' + self.nodes[0].generate(10) + self.sync_all() + check_migration_status(self.nodes[0], True, True, False, True, 1, 1) + if __name__ == '__main__': SproutSaplingMigration().main() diff --git a/src/wallet/asyncrpcoperation_saplingmigration.h b/src/wallet/asyncrpcoperation_saplingmigration.h index af26281f613..e077c8eca32 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.h +++ b/src/wallet/asyncrpcoperation_saplingmigration.h @@ -16,6 +16,8 @@ class AsyncRPCOperation_saplingmigration : public AsyncRPCOperation AsyncRPCOperation_saplingmigration& operator=(AsyncRPCOperation_saplingmigration const&) = delete; // Copy assign AsyncRPCOperation_saplingmigration& operator=(AsyncRPCOperation_saplingmigration&&) = delete; // Move assign + static libzcash::SaplingPaymentAddress getMigrationDestAddress(const HDSeed& seed); + virtual void main(); virtual UniValue getStatus() const; @@ -28,6 +30,4 @@ class AsyncRPCOperation_saplingmigration : public AsyncRPCOperation void setMigrationResult(int numTxCreated); CAmount chooseAmount(const CAmount& availableFunds); - - libzcash::SaplingPaymentAddress getMigrationDestAddress(const HDSeed& seed); }; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 347d65b189f..c48ed2c158a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -27,6 +27,7 @@ #include "asyncrpcoperation.h" #include "asyncrpcqueue.h" #include "wallet/asyncrpcoperation_mergetoaddress.h" +#include "wallet/asyncrpcoperation_saplingmigration.h" #include "wallet/asyncrpcoperation_sendmany.h" #include "wallet/asyncrpcoperation_shieldcoinbase.h" @@ -3929,6 +3930,100 @@ UniValue z_setmigration(const UniValue& params, bool fHelp) { return NullUniValue; } +UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + if (fHelp || params.size() != 0) + throw runtime_error( + "z_getmigrationstatus\n" + "Returns information about the status of the Sprout to Sapling migration.\n" + "In the result a transactions is defined as finalized iff it has ten confirmations.\n" + "Note: It is possible that manually created transactions invloving this wallet\n" + "will be included in the result.\n" + "\nResult:\n" + "{\n" + " \"enabled\": true|false, (boolean) Whether or not migration is enabled\n" + " \"destination_address\": \"zaddr\", (string) The Sapling address which will receive Sprout funds\n" + " \"unmigrated_amount\": nnn.n, (numeric) The total amount of unmigrated " + CURRENCY_UNIT +" \n" + " \"unfinalized_migrated_amount\": nnn.n, (numeric) The total amount of unfinalized " + CURRENCY_UNIT + " \n" + " \"finalized_migrated_amount\": nnn.n, (numeric) The total amount of finalized " + CURRENCY_UNIT + " \n" + " \"finalized_migration_transactions\": nnn, (numeric) The number of migration transactions involving this wallet\n" + " \"time_started\": ttt, (numeric, optional) The block time of the first migration transaction\n" + " \"migration_txids\": [txids] (json array of strings) An array of all migration txids involving this wallet\n" + "}\n" + ); + LOCK2(cs_main, pwalletMain->cs_wallet); + UniValue migrationStatus(UniValue::VOBJ); + migrationStatus.push_back(Pair("enabled", pwalletMain->fSaplingMigrationEnabled)); + // The "destination_address" field MAY be omitted if the "-migrationaddress" + // parameter is not set and no default address has yet been generated. + // Note: The following function may return the default address even if it has not been added to the wallet + auto destinationAddress = AsyncRPCOperation_saplingmigration::getMigrationDestAddress(pwalletMain->GetHDSeedForRPC()); + migrationStatus.push_back(Pair("destination_address", EncodePaymentAddress(destinationAddress))); + // The values of "unmigrated_amount" and "migrated_amount" MUST take into + // account failed transactions, that were not mined within their expiration + // height. + { + std::vector sproutEntries; + std::vector saplingEntries; + pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, "", 1); + CAmount unmigratedAmount = 0; + for (const auto& sproutEntry : sproutEntries) { + unmigratedAmount += sproutEntry.plaintext.value(); + } + migrationStatus.push_back(Pair("unmigrated_amount", FormatMoney(unmigratedAmount))); + } + // "migration_txids" is a list of strings representing transaction IDs of all + // known migration transactions involving this wallet, as lowercase hexadecimal + // in RPC byte order. + UniValue migrationTxids(UniValue::VARR); + int currentHeight = chainActive.Height(); + CAmount unfinalizedMigratedAmount = 0; + CAmount finalizedMigratedAmount = 0; + int numFinalizedMigrationTxs = 0; + uint64_t timeStarted = 0; + for (const auto& txPair : pwalletMain->mapWallet) { + CWalletTx tx = txPair.second; + // A given transaction is defined as a migration transaction iff it has: + // * one or more Sprout JoinSplits with nonzero vpub_new field; and + // * no Sapling Spends, and; + // * one or more Sapling Outputs. + if (tx.vjoinsplit.size() > 0 && tx.vShieldedSpend.empty() && tx.vShieldedOutput.size() > 0) { + CAmount migrationAmount = 0; + for (const auto& js : tx.vjoinsplit) { + migrationAmount += js.vpub_new; + } + if (migrationAmount == 0) { + continue; + } + migrationTxids.push_back(txPair.first.ToString()); + CBlockIndex* blockIndex = mapBlockIndex[tx.hashBlock]; + // A transaction is "finalized" iff it has 10 confirmations. + // TODO: subject to change, if the recommended number of confirmations changes. + if (currentHeight >= blockIndex->nHeight + 10) { + finalizedMigratedAmount += migrationAmount; + ++numFinalizedMigrationTxs; + } else { + unfinalizedMigratedAmount += migrationAmount; + } + // The value of "time_started" is the earliest Unix timestamp of any known + // migration transaction involving this wallet; if there is no such transaction, + // then the field is absent. + if (timeStarted == 0 || timeStarted > blockIndex->GetBlockTime()) { + timeStarted = blockIndex->GetBlockTime(); + } + } + } + migrationStatus.push_back(Pair("unfinalized_migrated_amount", FormatMoney(unfinalizedMigratedAmount))); + migrationStatus.push_back(Pair("finalized_migrated_amount", FormatMoney(finalizedMigratedAmount))); + migrationStatus.push_back(Pair("finalized_migration_transactions", numFinalizedMigrationTxs)); + if (timeStarted > 0) { + migrationStatus.push_back(Pair("time_started", timeStarted)); + } + migrationStatus.push_back(Pair("migration_txids", migrationTxids)); + return migrationStatus; +} + /** When estimating the number of coinbase utxos we can shield in a single transaction: 1. Joinsplit description is 1802 bytes. @@ -4683,6 +4778,7 @@ static const CRPCCommand commands[] = { "wallet", "z_mergetoaddress", &z_mergetoaddress, false }, { "wallet", "z_sendmany", &z_sendmany, false }, { "wallet", "z_setmigration", &z_setmigration, false }, + { "wallet", "z_getmigrationstatus", &z_getmigrationstatus, false }, { "wallet", "z_shieldcoinbase", &z_shieldcoinbase, false }, { "wallet", "z_getoperationstatus", &z_getoperationstatus, true }, { "wallet", "z_getoperationresult", &z_getoperationresult, true }, From 5969bd8f553f53d52ee961a750d1e26b3b147c52 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Mon, 29 Apr 2019 10:39:05 -0600 Subject: [PATCH 039/127] Fix help message --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 653a05fcb31..30bdccd51ff 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -406,7 +406,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Wallet options:")); strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); strUsage += HelpMessageOpt("-keypool=", strprintf(_("Set key pool size to (default: %u)"), 100)); - strUsage += HelpMessageOpt("-migration=", _("Set to true to enable the Sprout to Sapling migration.")); + strUsage += HelpMessageOpt("-migration", _("Enable the Sprout to Sapling migration")); strUsage += HelpMessageOpt("-migrationdestaddress=", _("Set the Sapling migration address")); if (showDebug) strUsage += HelpMessageOpt("-mintxfee=", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)", From 2276133bb36af999d7b80842b320c9687512205b Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Mon, 29 Apr 2019 13:53:29 -0600 Subject: [PATCH 040/127] Test migration using both the parameter and the default Sapling address --- qa/rpc-tests/sprout_sapling_migration.py | 150 ++++++++++++++--------- 1 file changed, 92 insertions(+), 58 deletions(-) diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py index cdfaa5393cd..e364a2c87e5 100755 --- a/qa/rpc-tests/sprout_sapling_migration.py +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -18,6 +18,7 @@ def check_migration_status( node, enabled, + destination_address, non_zero_unmigrated_amount, non_zero_unfinalized_migrated_amount, non_zero_finalized_migrated_amount, @@ -26,7 +27,7 @@ def check_migration_status( ): status = node.z_getmigrationstatus() assert_equal(enabled, status['enabled']) - assert_equal(SAPLING_ADDR, status['destination_address']) + assert_equal(destination_address, status['destination_address']) assert_equal(non_zero_unmigrated_amount, Decimal(status['unmigrated_amount']) > Decimal('0.00')) assert_equal(non_zero_unfinalized_migrated_amount, Decimal(status['unfinalized_migrated_amount']) > Decimal('0')) assert_equal(non_zero_finalized_migrated_amount, Decimal(status['finalized_migrated_amount']) > Decimal('0')) @@ -36,101 +37,134 @@ def check_migration_status( class SproutSaplingMigration(BitcoinTestFramework): def setup_nodes(self): - return start_nodes(4, self.options.tmpdir, [[ + # Activate overwinter/sapling on all nodes + extra_args = [[ '-nuparams=5ba81b19:100', # Overwinter '-nuparams=76b809bb:100', # Sapling + ]] * 4 + # Add migration parameters to nodes[0] + extra_args[0] = extra_args[0] + [ '-migration', '-migrationdestaddress=' + SAPLING_ADDR - ]] * 4) + ] + assert_equal(4, len(extra_args[0])) + assert_equal(2, len(extra_args[1])) + return start_nodes(4, self.options.tmpdir, extra_args) def setup_chain(self): print("Initializing test directory " + self.options.tmpdir) initialize_chain_clean(self.options.tmpdir, 4) - def run_test(self): - check_migration_status(self.nodes[0], True, False, False, False, 0, 0) - self.nodes[0].z_setmigration(False) - check_migration_status(self.nodes[0], False, False, False, False, 0, 0) - - print "Mining blocks..." - self.nodes[0].generate(101) - self.sync_all() - - # Send some ZEC to a Sprout address - tAddr = get_coinbase_address(self.nodes[0]) - sproutAddr = self.nodes[0].z_getnewaddress('sprout') - # Import a previously generated key to test '-migrationdestaddress' - self.nodes[0].z_importkey(SAPLING_KEY) - - opid = self.nodes[0].z_sendmany(tAddr, [{"address": sproutAddr, "amount": Decimal('10')}], 1, 0) - wait_and_assert_operationid_status(self.nodes[0], opid) - self.nodes[0].generate(1) - self.sync_all() - - assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('10')) - assert_equal(self.nodes[0].z_getbalance(SAPLING_ADDR), Decimal('0')) + def run_migration_test(self, node, sproutAddr, saplingAddr, target_height): + # Make sure we are in a good state to run the test + assert_equal(102, node.getblockcount() % 500, "Should be at block 102 % 500") + assert_equal(node.z_getbalance(sproutAddr), Decimal('10')) + assert_equal(node.z_getbalance(saplingAddr), Decimal('0')) + check_migration_status(node, False, saplingAddr, True, False, False, 0, 0) # Migrate - self.nodes[0].z_setmigration(True) - print "Mining to block 494..." - self.nodes[0].generate(392) # 102 -> 494 + node.z_setmigration(True) + print "Mining to block 494 % 500..." + node.generate(392) # 102 % 500 -> 494 % 500 self.sync_all() - # At 494 we should have no async operations - assert_equal(0, len(self.nodes[0].z_getoperationstatus()), "num async operations at 494") - check_migration_status(self.nodes[0], True, True, False, False, 0, 0) + # At 494 % 500 we should have no async operations + assert_equal(0, len(node.z_getoperationstatus()), "num async operations at 494 % 500") + check_migration_status(node, True, saplingAddr, True, False, False, 0, 0) - self.nodes[0].generate(1) + node.generate(1) self.sync_all() - # At 495 we should have an async operation - operationstatus = self.nodes[0].z_getoperationstatus() + # At 495 % 500 we should have an async operation + operationstatus = node.z_getoperationstatus() print "migration operation: {}".format(operationstatus) - assert_equal(1, len(operationstatus), "num async operations at 495") + assert_equal(1, len(operationstatus), "num async operations at 495 % 500") assert_equal('saplingmigration', operationstatus[0]['method']) - assert_equal(500, operationstatus[0]['target_height']) + assert_equal(target_height, operationstatus[0]['target_height']) - result = wait_and_assert_operationid_status_result(self.nodes[0], operationstatus[0]['id']) + result = wait_and_assert_operationid_status_result(node, operationstatus[0]['id']) print "result: {}".format(result) assert_equal('saplingmigration', result['method']) - assert_equal(500, result['target_height']) + assert_equal(target_height, result['target_height']) assert_equal(1, result['result']['num_tx_created']) - assert_equal(0, len(self.nodes[0].getrawmempool()), "mempool size at 495") + assert_equal(0, len(node.getrawmempool()), "mempool size at 495 % 500") - self.nodes[0].generate(3) + node.generate(3) self.sync_all() - # At 498 the mempool will be empty and no funds will have moved - assert_equal(0, len(self.nodes[0].getrawmempool()), "mempool size at 498") - assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('10')) - assert_equal(self.nodes[0].z_getbalance(SAPLING_ADDR), Decimal('0')) + # At 498 % 500 the mempool will be empty and no funds will have moved + assert_equal(0, len(node.getrawmempool()), "mempool size at 498 % 500") + assert_equal(node.z_getbalance(sproutAddr), Decimal('10')) + assert_equal(node.z_getbalance(saplingAddr), Decimal('0')) - self.nodes[0].generate(1) + node.generate(1) self.sync_all() - # At 499 there will be a transaction in the mempool and the note will be locked - assert_equal(1, len(self.nodes[0].getrawmempool()), "mempool size at 499") - assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('0')) - assert_equal(self.nodes[0].z_getbalance(SAPLING_ADDR), Decimal('0')) - assert_true(self.nodes[0].z_getbalance(SAPLING_ADDR, 0) > Decimal('0'), "Unconfirmed sapling") + # At 499 % 500 there will be a transaction in the mempool and the note will be locked + assert_equal(1, len(node.getrawmempool()), "mempool size at 499 % 500") + assert_equal(node.z_getbalance(sproutAddr), Decimal('0')) + assert_equal(node.z_getbalance(saplingAddr), Decimal('0')) + assert_true(node.z_getbalance(saplingAddr, 0) > Decimal('0'), "Unconfirmed sapling balance at 499") - self.nodes[0].generate(1) + node.generate(1) self.sync_all() - # At 500 funds will have moved - sprout_balance = self.nodes[0].z_getbalance(sproutAddr) - sapling_balance = self.nodes[0].z_getbalance(SAPLING_ADDR) + # At 0 % 500 funds will have moved + sprout_balance = node.z_getbalance(sproutAddr) + sapling_balance = node.z_getbalance(saplingAddr) print "sprout balance: {}, sapling balance: {}".format(sprout_balance, sapling_balance) assert_true(sprout_balance < Decimal('10'), "Should have less Sprout funds") assert_true(sapling_balance > Decimal('0'), "Should have more Sapling funds") assert_true(sprout_balance + sapling_balance, Decimal('9.9999')) - check_migration_status(self.nodes[0], True, True, True, False, 0, 1) - # At 510 the transactions will be considered 'finalized' - self.nodes[0].generate(10) + check_migration_status(node, True, saplingAddr, True, True, False, 0, 1) + # At 10 % 500 the transactions will be considered 'finalized' + node.generate(10) + self.sync_all() + check_migration_status(node, True, saplingAddr, True, False, True, 1, 1) + + def send_to_sprout_zaddr(self, tAddr, sproutAddr): + # Send some ZEC to a Sprout address + opid = self.nodes[0].z_sendmany(tAddr, [{"address": sproutAddr, "amount": Decimal('10')}], 1, 0) + wait_and_assert_operationid_status(self.nodes[0], opid) + self.nodes[0].generate(1) + self.sync_all() + + def run_test(self): + # Check enabling via '-migration' and disabling via rpc + check_migration_status(self.nodes[0], True, SAPLING_ADDR, False, False, False, 0, 0) + self.nodes[0].z_setmigration(False) + check_migration_status(self.nodes[0], False, SAPLING_ADDR, False, False, False, 0, 0) + + # 1. Test using self.nodes[0] which has the parameter + print "Runing test using '-migrationdestaddress'..." + print "Mining blocks..." + self.nodes[0].generate(101) self.sync_all() - check_migration_status(self.nodes[0], True, True, False, True, 1, 1) + tAddr = get_coinbase_address(self.nodes[0]) + + # Import a previously generated key to test '-migrationdestaddress' + self.nodes[0].z_importkey(SAPLING_KEY) + sproutAddr0 = self.nodes[0].z_getnewaddress('sprout') + + self.send_to_sprout_zaddr(tAddr, sproutAddr0) + self.run_migration_test(self.nodes[0], sproutAddr0, SAPLING_ADDR, 500) + # Disable migration so only self.nodes[1] has a transaction in the mempool at block 999 + self.nodes[0].z_setmigration(False) + + # 2. Test using self.nodes[1] which will use the default Sapling address + print "Runing test using default Sapling address..." + # Mine more blocks so we start at 102 % 500 + print "Mining blocks..." + self.nodes[1].generate(91) # 511 -> 602 + self.sync_all() + + sproutAddr1 = self.nodes[1].z_getnewaddress('sprout') + saplingAddr1 = self.nodes[1].z_getnewaddress('sapling') + + self.send_to_sprout_zaddr(tAddr, sproutAddr1) + self.run_migration_test(self.nodes[1], sproutAddr1, saplingAddr1, 1000) if __name__ == '__main__': From 108e587c14f2fd3155af506bcc22d16510172437 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Mon, 29 Apr 2019 14:42:48 -0600 Subject: [PATCH 041/127] Fix typos and update documentation --- qa/rpc-tests/sprout_sapling_migration.py | 6 +++--- src/wallet/rpcwallet.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py index e364a2c87e5..2287f0740a4 100755 --- a/qa/rpc-tests/sprout_sapling_migration.py +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -105,7 +105,7 @@ def run_migration_test(self, node, sproutAddr, saplingAddr, target_height): assert_equal(1, len(node.getrawmempool()), "mempool size at 499 % 500") assert_equal(node.z_getbalance(sproutAddr), Decimal('0')) assert_equal(node.z_getbalance(saplingAddr), Decimal('0')) - assert_true(node.z_getbalance(saplingAddr, 0) > Decimal('0'), "Unconfirmed sapling balance at 499") + assert_true(node.z_getbalance(saplingAddr, 0) > Decimal('0'), "Unconfirmed sapling balance at 499 % 500") node.generate(1) self.sync_all() @@ -138,7 +138,7 @@ def run_test(self): check_migration_status(self.nodes[0], False, SAPLING_ADDR, False, False, False, 0, 0) # 1. Test using self.nodes[0] which has the parameter - print "Runing test using '-migrationdestaddress'..." + print "Running test using '-migrationdestaddress'..." print "Mining blocks..." self.nodes[0].generate(101) self.sync_all() @@ -154,7 +154,7 @@ def run_test(self): self.nodes[0].z_setmigration(False) # 2. Test using self.nodes[1] which will use the default Sapling address - print "Runing test using default Sapling address..." + print "Running test using default Sapling address..." # Mine more blocks so we start at 102 % 500 print "Mining blocks..." self.nodes[1].generate(91) # 511 -> 602 diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c48ed2c158a..5fe0a7b1d4b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3937,13 +3937,14 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { throw runtime_error( "z_getmigrationstatus\n" "Returns information about the status of the Sprout to Sapling migration.\n" - "In the result a transactions is defined as finalized iff it has ten confirmations.\n" - "Note: It is possible that manually created transactions invloving this wallet\n" + "In the result a transactions is defined as finalized if and only if it has\n" + "at least ten confirmations.\n" + "Note: It is possible that manually created transactions involving this wallet\n" "will be included in the result.\n" "\nResult:\n" "{\n" " \"enabled\": true|false, (boolean) Whether or not migration is enabled\n" - " \"destination_address\": \"zaddr\", (string) The Sapling address which will receive Sprout funds\n" + " \"destination_address\": \"zaddr\", (string) The Sapling address that will receive Sprout funds\n" " \"unmigrated_amount\": nnn.n, (numeric) The total amount of unmigrated " + CURRENCY_UNIT +" \n" " \"unfinalized_migrated_amount\": nnn.n, (numeric) The total amount of unfinalized " + CURRENCY_UNIT + " \n" " \"finalized_migrated_amount\": nnn.n, (numeric) The total amount of finalized " + CURRENCY_UNIT + " \n" @@ -3955,7 +3956,7 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { LOCK2(cs_main, pwalletMain->cs_wallet); UniValue migrationStatus(UniValue::VOBJ); migrationStatus.push_back(Pair("enabled", pwalletMain->fSaplingMigrationEnabled)); - // The "destination_address" field MAY be omitted if the "-migrationaddress" + // The "destination_address" field MAY be omitted if the "-migrationdestaddress" // parameter is not set and no default address has yet been generated. // Note: The following function may return the default address even if it has not been added to the wallet auto destinationAddress = AsyncRPCOperation_saplingmigration::getMigrationDestAddress(pwalletMain->GetHDSeedForRPC()); From e9530f40f22d33acee648252a109a2eba0babb56 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Mon, 29 Apr 2019 17:00:26 -0600 Subject: [PATCH 042/127] use -valueBalance rather than vpub_new to calculate migrated amount --- qa/rpc-tests/sprout_sapling_migration.py | 4 ++++ src/wallet/rpcwallet.cpp | 18 +++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py index 2287f0740a4..fd81c573052 100755 --- a/qa/rpc-tests/sprout_sapling_migration.py +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -123,6 +123,10 @@ def run_migration_test(self, node, sproutAddr, saplingAddr, target_height): node.generate(10) self.sync_all() check_migration_status(node, True, saplingAddr, True, False, True, 1, 1) + # Check exact migration status amounts to make sure we account for fee + status = node.z_getmigrationstatus() + assert_equal(sprout_balance, Decimal(status['unmigrated_amount'])) + assert_equal(sapling_balance, Decimal(status['finalized_migrated_amount'])) def send_to_sprout_zaddr(self, tAddr, sproutAddr): # Send some ZEC to a Sprout address diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5fe0a7b1d4b..651c1e3289e 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3989,23 +3989,27 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { // * one or more Sprout JoinSplits with nonzero vpub_new field; and // * no Sapling Spends, and; // * one or more Sapling Outputs. - if (tx.vjoinsplit.size() > 0 && tx.vShieldedSpend.empty() && tx.vShieldedOutput.size() > 0) { - CAmount migrationAmount = 0; + if (tx.vjoinsplit.size() > 0 && tx.vShieldedSpend.empty() && tx.vShieldedOutput.size() > 0 && + tx.vin.empty() && tx.vout.empty()) { + bool nonZeroVPubNew = false; for (const auto& js : tx.vjoinsplit) { - migrationAmount += js.vpub_new; + if (js.vpub_new > 0) { + nonZeroVPubNew = true; + break; + } } - if (migrationAmount == 0) { + if (!nonZeroVPubNew) { continue; } migrationTxids.push_back(txPair.first.ToString()); CBlockIndex* blockIndex = mapBlockIndex[tx.hashBlock]; - // A transaction is "finalized" iff it has 10 confirmations. + // A transaction is "finalized" iff it has at least 10 confirmations. // TODO: subject to change, if the recommended number of confirmations changes. if (currentHeight >= blockIndex->nHeight + 10) { - finalizedMigratedAmount += migrationAmount; + finalizedMigratedAmount -= tx.valueBalance; ++numFinalizedMigrationTxs; } else { - unfinalizedMigratedAmount += migrationAmount; + unfinalizedMigratedAmount -= tx.valueBalance; } // The value of "time_started" is the earliest Unix timestamp of any known // migration transaction involving this wallet; if there is no such transaction, From 345177cfc1085ee49e862760df8c03b8f6206923 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 30 Apr 2019 09:52:53 -0600 Subject: [PATCH 043/127] Do not look at vin/vout when determining migration txs and other cleanup --- qa/rpc-tests/sprout_sapling_migration.py | 16 ++++++++-------- src/wallet/rpcwallet.cpp | 5 ++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py index fd81c573052..5f47d779616 100755 --- a/qa/rpc-tests/sprout_sapling_migration.py +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -64,7 +64,7 @@ def run_migration_test(self, node, sproutAddr, saplingAddr, target_height): # Migrate node.z_setmigration(True) - print "Mining to block 494 % 500..." + print("Mining to block 494 % 500...") node.generate(392) # 102 % 500 -> 494 % 500 self.sync_all() @@ -77,13 +77,13 @@ def run_migration_test(self, node, sproutAddr, saplingAddr, target_height): # At 495 % 500 we should have an async operation operationstatus = node.z_getoperationstatus() - print "migration operation: {}".format(operationstatus) + print("migration operation: {}".format(operationstatus)) assert_equal(1, len(operationstatus), "num async operations at 495 % 500") assert_equal('saplingmigration', operationstatus[0]['method']) assert_equal(target_height, operationstatus[0]['target_height']) result = wait_and_assert_operationid_status_result(node, operationstatus[0]['id']) - print "result: {}".format(result) + print("result: {}".format(result)) assert_equal('saplingmigration', result['method']) assert_equal(target_height, result['target_height']) assert_equal(1, result['result']['num_tx_created']) @@ -113,7 +113,7 @@ def run_migration_test(self, node, sproutAddr, saplingAddr, target_height): # At 0 % 500 funds will have moved sprout_balance = node.z_getbalance(sproutAddr) sapling_balance = node.z_getbalance(saplingAddr) - print "sprout balance: {}, sapling balance: {}".format(sprout_balance, sapling_balance) + print("sprout balance: {}, sapling balance: {}".format(sprout_balance, sapling_balance)) assert_true(sprout_balance < Decimal('10'), "Should have less Sprout funds") assert_true(sapling_balance > Decimal('0'), "Should have more Sapling funds") assert_true(sprout_balance + sapling_balance, Decimal('9.9999')) @@ -142,8 +142,8 @@ def run_test(self): check_migration_status(self.nodes[0], False, SAPLING_ADDR, False, False, False, 0, 0) # 1. Test using self.nodes[0] which has the parameter - print "Running test using '-migrationdestaddress'..." - print "Mining blocks..." + print("Running test using '-migrationdestaddress'...") + print("Mining blocks...") self.nodes[0].generate(101) self.sync_all() tAddr = get_coinbase_address(self.nodes[0]) @@ -158,9 +158,9 @@ def run_test(self): self.nodes[0].z_setmigration(False) # 2. Test using self.nodes[1] which will use the default Sapling address - print "Running test using default Sapling address..." + print("Running test using default Sapling address...") # Mine more blocks so we start at 102 % 500 - print "Mining blocks..." + print("Mining blocks...") self.nodes[1].generate(91) # 511 -> 602 self.sync_all() diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 651c1e3289e..f8f0086665b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3949,7 +3949,7 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { " \"unfinalized_migrated_amount\": nnn.n, (numeric) The total amount of unfinalized " + CURRENCY_UNIT + " \n" " \"finalized_migrated_amount\": nnn.n, (numeric) The total amount of finalized " + CURRENCY_UNIT + " \n" " \"finalized_migration_transactions\": nnn, (numeric) The number of migration transactions involving this wallet\n" - " \"time_started\": ttt, (numeric, optional) The block time of the first migration transaction\n" + " \"time_started\": ttt, (numeric, optional) The block time of the first migration transaction as a Unix timestamp\n" " \"migration_txids\": [txids] (json array of strings) An array of all migration txids involving this wallet\n" "}\n" ); @@ -3989,8 +3989,7 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { // * one or more Sprout JoinSplits with nonzero vpub_new field; and // * no Sapling Spends, and; // * one or more Sapling Outputs. - if (tx.vjoinsplit.size() > 0 && tx.vShieldedSpend.empty() && tx.vShieldedOutput.size() > 0 && - tx.vin.empty() && tx.vout.empty()) { + if (tx.vjoinsplit.size() > 0 && tx.vShieldedSpend.empty() && tx.vShieldedOutput.size() > 0) { bool nonZeroVPubNew = false; for (const auto& js : tx.vjoinsplit) { if (js.vpub_new > 0) { From e14cf96642de67ebe2043b701e16e64168ca5079 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 30 Apr 2019 11:06:08 -0600 Subject: [PATCH 044/127] Calculate the number of confimations in the canonical way --- src/wallet/rpcwallet.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index f8f0086665b..d0e67a1b2e7 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3978,7 +3978,6 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { // known migration transactions involving this wallet, as lowercase hexadecimal // in RPC byte order. UniValue migrationTxids(UniValue::VARR); - int currentHeight = chainActive.Height(); CAmount unfinalizedMigratedAmount = 0; CAmount finalizedMigratedAmount = 0; int numFinalizedMigrationTxs = 0; @@ -4004,7 +4003,7 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { CBlockIndex* blockIndex = mapBlockIndex[tx.hashBlock]; // A transaction is "finalized" iff it has at least 10 confirmations. // TODO: subject to change, if the recommended number of confirmations changes. - if (currentHeight >= blockIndex->nHeight + 10) { + if (tx.GetDepthInMainChain() >= 10) { finalizedMigratedAmount -= tx.valueBalance; ++numFinalizedMigrationTxs; } else { From 3cad5f454fcf1933640b1d92351837e0858c0d0c Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 30 Apr 2019 15:47:03 -0600 Subject: [PATCH 045/127] Do not throw an exception if HD Seed is not found when exporting wallet --- src/wallet/rpcdump.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 8105f51768e..600d0de8bb0 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -506,7 +506,8 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys) file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString()); file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime())); { - HDSeed hdSeed = pwalletMain->GetHDSeedForRPC(); + HDSeed hdSeed; + pwalletMain->GetHDSeed(hdSeed); auto rawSeed = hdSeed.RawSeed(); file << strprintf("# HDSeed=%s fingerprint=%s", HexStr(rawSeed.begin(), rawSeed.end()), hdSeed.Fingerprint().GetHex()); file << "\n"; From 4cbe0a9d02712d802c28ca47eda98d49f150c146 Mon Sep 17 00:00:00 2001 From: Larry Ruane Date: Wed, 1 May 2019 10:03:24 -0600 Subject: [PATCH 046/127] 3873 z_setmigration cli bool enable arg conversion --- src/rpc/client.cpp | 3 ++- src/test/rpc_wallet_tests.cpp | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 5288d977e60..8838bd27390 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -130,7 +130,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "z_importkey", 2 }, { "z_importviewingkey", 2 }, { "z_getpaymentdisclosure", 1}, - { "z_getpaymentdisclosure", 2} + { "z_getpaymentdisclosure", 2}, + { "z_setmigration", 0}, }; class CRPCConvertTable diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index bfcc8f88d5e..f2cc09903d4 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -296,6 +296,15 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) BOOST_CHECK_NO_THROW(CallRPC("getblock 0 2")); BOOST_CHECK_THROW(CallRPC("getblock 0 -1"), runtime_error); // bad verbosity BOOST_CHECK_THROW(CallRPC("getblock 0 3"), runtime_error); // bad verbosity + + /* + * migration (sprout to sapling) + */ + BOOST_CHECK_NO_THROW(CallRPC("z_setmigration true")); + BOOST_CHECK_NO_THROW(CallRPC("z_setmigration false")); + BOOST_CHECK_THROW(CallRPC("z_setmigration"), runtime_error); + BOOST_CHECK_THROW(CallRPC("z_setmigration nonboolean"), runtime_error); + BOOST_CHECK_THROW(CallRPC("z_setmigration 1"), runtime_error); } BOOST_AUTO_TEST_CASE(rpc_wallet_getbalance) From 6c47e6fe7b67918700a970e2b1725e580f485b29 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 1 May 2019 14:15:14 -0600 Subject: [PATCH 047/127] make-release.py: Versioning changes for 2.0.5-rc1. --- README.md | 2 +- configure.ac | 4 ++-- contrib/gitian-descriptors/gitian-linux.yml | 2 +- src/clientversion.h | 4 ++-- src/deprecation.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d1c12009834..ebb83c2d482 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Zcash 2.0.4 +Zcash 2.0.5-rc1 =========== diff --git a/configure.ac b/configure.ac index 654d1f27f27..76001643263 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 2) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 4) -define(_CLIENT_VERSION_BUILD, 50) +define(_CLIENT_VERSION_REVISION, 5) +define(_CLIENT_VERSION_BUILD, 25) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 1d946ab8f6f..1dcdc6b8c04 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "zcash-2.0.4" +name: "zcash-2.0.5-rc1" enable_cache: true distro: "debian" suites: diff --git a/src/clientversion.h b/src/clientversion.h index 2ccd6aebe30..ace0b04d841 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -17,8 +17,8 @@ //! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 2 #define CLIENT_VERSION_MINOR 0 -#define CLIENT_VERSION_REVISION 4 -#define CLIENT_VERSION_BUILD 50 +#define CLIENT_VERSION_REVISION 5 +#define CLIENT_VERSION_BUILD 25 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/deprecation.h b/src/deprecation.h index 1ad95209a33..6c6076156ce 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -8,7 +8,7 @@ // Deprecation policy: // * Shut down 16 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 504600; +static const int APPROX_RELEASE_HEIGHT = 525525; static const int WEEKS_UNTIL_DEPRECATION = 16; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); From cf0a5ca28deb01a8c4b6e97aacfeb558ade2bc29 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 1 May 2019 14:16:08 -0600 Subject: [PATCH 048/127] make-release.py: Updated manpages for 2.0.5-rc1. --- doc/man/zcash-cli.1 | 10 +++++----- doc/man/zcash-tx.1 | 10 +++++----- doc/man/zcashd.1 | 18 +++++++++++++----- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index 3bb439b340e..e4c0ea7c6be 100644 --- a/doc/man/zcash-cli.1 +++ b/doc/man/zcash-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASH-CLI "1" "March 2019" "zcash-cli v2.0.4" "User Commands" +.TH ZCASH-CLI "1" "May 2019" "zcash-cli v2.0.5-rc1" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v2.0.4 +zcash-cli \- manual page for zcash-cli v2.0.5-rc1 .SH DESCRIPTION -Zcash RPC client version v2.0.4 +Zcash RPC client version v2.0.5\-rc1 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . @@ -75,8 +75,8 @@ Read extra arguments from standard input, one per line until EOF/Ctrl\-D In order to ensure you are adequately protecting your privacy when using Zcash, please see . -Copyright (C) 2009-2018 The Bitcoin Core Developers -Copyright (C) 2015-2018 The Zcash Developers +Copyright (C) 2009-2019 The Bitcoin Core Developers +Copyright (C) 2015-2019 The Zcash Developers This is experimental software. diff --git a/doc/man/zcash-tx.1 b/doc/man/zcash-tx.1 index 20466cb239d..3e494c23227 100644 --- a/doc/man/zcash-tx.1 +++ b/doc/man/zcash-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASH-TX "1" "March 2019" "zcash-tx v2.0.4" "User Commands" +.TH ZCASH-TX "1" "May 2019" "zcash-tx v2.0.5-rc1" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v2.0.4 +zcash-tx \- manual page for zcash-tx v2.0.5-rc1 .SH DESCRIPTION -Zcash zcash\-tx utility version v2.0.4 +Zcash zcash\-tx utility version v2.0.5\-rc1 .SS "Usage:" .TP zcash\-tx [options] [commands] @@ -88,8 +88,8 @@ Set register NAME to given JSON\-STRING In order to ensure you are adequately protecting your privacy when using Zcash, please see . -Copyright (C) 2009-2018 The Bitcoin Core Developers -Copyright (C) 2015-2018 The Zcash Developers +Copyright (C) 2009-2019 The Bitcoin Core Developers +Copyright (C) 2015-2019 The Zcash Developers This is experimental software. diff --git a/doc/man/zcashd.1 b/doc/man/zcashd.1 index f993c77a7a8..5e11981fcdb 100644 --- a/doc/man/zcashd.1 +++ b/doc/man/zcashd.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASHD "1" "March 2019" "zcashd v2.0.4" "User Commands" +.TH ZCASHD "1" "May 2019" "zcashd v2.0.5-rc1" "User Commands" .SH NAME -zcashd \- manual page for zcashd v2.0.4 +zcashd \- manual page for zcashd v2.0.5-rc1 .SH DESCRIPTION -Zcash Daemon version v2.0.4 +Zcash Daemon version v2.0.5\-rc1 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . @@ -240,6 +240,14 @@ Do not load the wallet and disable wallet RPC calls .IP Set key pool size to (default: 100) .HP +\fB\-migration\fR +.IP +Enable the Sprout to Sapling migration +.HP +\fB\-migrationdestaddress=\fR +.IP +Set the Sapling migration address +.HP \fB\-paytxfee=\fR .IP Fee (in ZEC/kB) to add to transactions you send (default: 0.00) @@ -470,8 +478,8 @@ console, 600 otherwise) In order to ensure you are adequately protecting your privacy when using Zcash, please see . -Copyright (C) 2009-2018 The Bitcoin Core Developers -Copyright (C) 2015-2018 The Zcash Developers +Copyright (C) 2009-2019 The Bitcoin Core Developers +Copyright (C) 2015-2019 The Zcash Developers This is experimental software. From 12a9e172e5901c2ffa428fa52790eb1453e0b0c0 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 1 May 2019 14:16:08 -0600 Subject: [PATCH 049/127] make-release.py: Updated release notes and changelog for 2.0.5-rc1. --- contrib/debian/changelog | 6 ++ doc/release-notes/release-notes-2.0.5-rc1.md | 73 ++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 doc/release-notes/release-notes-2.0.5-rc1.md diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 896237ef4b2..827d338b9d1 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +zcash (2.0.5~rc1) stable; urgency=medium + + * 2.0.5-rc1 release. + + -- Electric Coin Company Wed, 01 May 2019 14:16:08 -0600 + zcash (2.0.4) stable; urgency=medium * 2.0.4 release. diff --git a/doc/release-notes/release-notes-2.0.5-rc1.md b/doc/release-notes/release-notes-2.0.5-rc1.md new file mode 100644 index 00000000000..08640b1f443 --- /dev/null +++ b/doc/release-notes/release-notes-2.0.5-rc1.md @@ -0,0 +1,73 @@ +Changelog +========= + +Braydon Fuller (1): + tests: adds unit test for IsPayToPublicKeyHash method + +Dimitris Apostolou (1): + Electric Coin Company + +Eirik0 (22): + Split test in to multiple parts + Use a custom error type if creating joinsplit descriptions fails + Rename and update comment + Add rpc to enable and disable Sprout to Sapling migration + Move migration logic to ChainTip + Documentation cleanup + Additional locking and race condition prevention + Refactor wait_and_assert_operationid_status to allow returning the result + Set min depth when selecting notes to migrate + Check for full failure message in test case + Add migration options to conf file + Create method for getting HD seed in RPCs + Add rpc to get Sprout to Sapling migration status + Fix help message + Test migration using both the parameter and the default Sapling address + Fix typos and update documentation + use -valueBalance rather than vpub_new to calculate migrated amount + Do not look at vin/vout when determining migration txs and other cleanup + Calculate the number of confimations in the canonical way + Do not throw an exception if HD Seed is not found when exporting wallet + make-release.py: Versioning changes for 2.0.5-rc1. + make-release.py: Updated manpages for 2.0.5-rc1. + +Gareth Davies (1): + Adding addressindex.h to Makefile.am + +Jack Grigg (9): + Add Sprout support to TransactionBuilder + depends: Use full path to cargo binary + depends: Generalise the rust package cross-compilation functions + depends: Add rust-std hash for aarch64-unknown-linux-gnu + depends: Compile bdb with --disable-atomics on aarch64 + depends: Update .gitignore + configure: Guess -march for libsnark OPTFLAGS instead of hard-coding + Add Blossom to upgrade list + init: Fix new HD seed generation for previously-encrypted wallets + +Larry Ruane (6): + fix enable-debug build DB_COINS undefined + add -addressindex changes for bitcore insight block explorer + add -spentindex changes for bitcore insight block explorer + Update boost from v1.69.0 to v1.70.0. #3947 + add -timestampindex for bitcore insight block explorer + 3873 z_setmigration cli bool enable arg conversion + +Marius Kjærstad (1): + Update _COPYRIGHT_YEAR in configure.ac to 2019 + +Mary Moore-Simmons (1): + Creates checklist template for new PRs being opened and addresses Str4d's suggestion for using GitHub handles + +Simon Liu (4): + Add testnet and regtest experimental feature: -developersetpoolsizezero + Add qa test for experimental feature: -developersetpoolsizezero + Enable ZIP209 on mainnet and set fallback Sprout pool balance. + Enable experimental feature -developersetpoolsizezero on mainnet. + +Jack Grigg (1): + remove extra hyphen + +zebambam (1): + Minor speling changes + From 5bff7238079909643ba909cd832367c3820bf8ee Mon Sep 17 00:00:00 2001 From: Ian Munoz Date: Thu, 2 May 2019 11:47:25 -0400 Subject: [PATCH 050/127] add curl to package list for gitian lxc container --- contrib/gitian-descriptors/gitian-linux.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index d7f702b816e..3d150d5678f 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -7,6 +7,7 @@ suites: architectures: - "amd64" packages: +- "curl" - "autoconf" - "automake" - "bsdmainutils" From 68c17ffec83fb89ecc49bb874d2110a3156fe297 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 2 May 2019 14:37:50 -0700 Subject: [PATCH 051/127] Update chain work and checkpoint using block 525000. --- src/chainparams.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index e0769fcae5f..5f8dba4d2b2 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -111,7 +111,7 @@ class CMainParams : public CChainParams { Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000c12875ded911cf"); + consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000eeaf43c4e72d49"); /** * The message start string should be awesome! ⓩ❤ @@ -185,11 +185,12 @@ class CMainParams : public CChainParams { (270000, uint256S("0x00000000025c1cfa0258e33ab050aaa9338a3d4aaa3eb41defefc887779a9729")) (304600, uint256S("0x00000000028324e022a45014c4a4dc51e95d41e6bceb6ad554c5b65d5cea3ea5")) (410100, uint256S("0x0000000002c565958f783a24a4ac17cde898ff525e75ed9baf66861b0b9fcada")) - (497000, uint256S("0x0000000000abd333f0acca6ffdf78a167699686d6a7d25c33fca5f295061ffff")), - 1552501838, // * UNIX timestamp of last checkpoint block - 4463933, // * total number of transactions between genesis and last checkpoint + (497000, uint256S("0x0000000000abd333f0acca6ffdf78a167699686d6a7d25c33fca5f295061ffff")) + (525000, uint256S("0x0000000001a36c500378be8862d9bf1bea8f1616da6e155971b608139cc7e39b")), + 1556722044, // * UNIX timestamp of last checkpoint block + 4653556, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) - 5173 // * estimated number of transactions per day after checkpoint + 5106 // * estimated number of transactions per day after checkpoint // total number of tx / (checkpoint block height / (24 * 24)) }; From 95fe7ae6764e55ea9c2bba0eb94e51d8fa2f3e64 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Thu, 2 May 2019 19:34:52 -0600 Subject: [PATCH 052/127] Notable changes for v2.0.5 --- doc/release-notes.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/doc/release-notes.md b/doc/release-notes.md index a29094b5174..944e8e79473 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,3 +4,47 @@ release-notes at release time) Notable changes =============== +Sprout to Sapling Migration Tool +-------------------------------- +This release includes the addition of a tool that will enable users to migrate +shielded funds from the Sprout pool to the Sapling pool while minimizing +information leakage. + +The migration can be enabled using the RPC `z_setmigration` or by including +`-migration` in the `zcash.conf` file. Unless otherwise specified funds will be +migrated to the wallet's default Sapling address; it is also possible to set the +receiving Sapling address using the `-migrationdestaddress` option in `zcash.conf`. + +See [ZIP308](https://github.com/zcash/zips/blob/master/zip-0308.rst) for full details. + + +New consensus rule: Reject blocks that violate turnstile +-------------------------------------------------------- +In the 2.0.4 release the consensus rules were changed on testnet to enforce a +consensus rule which marks blocks as invalid if they would lead to a turnstile +violation in the Sprout or Shielded value pools. +**This release enforces the consensus rule change on mainnet** + +The motivations and deployment details can be found in the accompanying +[ZIP draft](https://github.com/zcash/zips/pull/210) and +[PR 3968](https://github.com/zcash/zcash/pull/3968). + +Developers can use a new experimental feature `-developersetpoolsizezero` to test +Sprout and Sapling turnstile violations. See [PR 3964](https://github.com/zcash/zcash/pull/3964) for more details. + + +64-bit ARMv8 support +-------------------- +Added ARMv8 (AArch64) support. This enables users to build zcash on even more +devices. + +For information on how to build see the [User Guide](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#build) + +Users on the Zcash forum have reported successes with both the Pine64 Rock64Pro +and Odroid C2 which contain 4GB and 2GB of RAM respectively. + +Just released, the Odroid N2 looks a great solution with 4GB of RAM. The newly +released Jetson Nano Developer Kit from Nvidia (also 4GB of RAM) is also worth +a look. The NanoPC-T3 Plus is another option but for the simplest/best +experience choose a board with 4GB of RAM. Just make sure before purchase that +the CPU supports the 64-bit ARMv8 architecture. From e152af3c7c8477f218c57b6b698531243ad264a9 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Fri, 3 May 2019 09:30:26 -0600 Subject: [PATCH 053/127] Add missing word to release notes --- doc/release-notes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 944e8e79473..d7935ff1b2c 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -43,8 +43,8 @@ For information on how to build see the [User Guide](https://zcash.readthedocs.i Users on the Zcash forum have reported successes with both the Pine64 Rock64Pro and Odroid C2 which contain 4GB and 2GB of RAM respectively. -Just released, the Odroid N2 looks a great solution with 4GB of RAM. The newly -released Jetson Nano Developer Kit from Nvidia (also 4GB of RAM) is also worth -a look. The NanoPC-T3 Plus is another option but for the simplest/best +Just released, the Odroid N2 looks like a great solution with 4GB of RAM. The +newly released Jetson Nano Developer Kit from Nvidia (also 4GB of RAM) is also +worth a look. The NanoPC-T3 Plus is another option but for the simplest/best experience choose a board with 4GB of RAM. Just make sure before purchase that the CPU supports the 64-bit ARMv8 architecture. From c1daa11d7b12d45258502fa4fe501a0e3d7ada26 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Fri, 3 May 2019 16:30:13 -0600 Subject: [PATCH 054/127] make-release.py: Versioning changes for 2.0.5. --- README.md | 2 +- configure.ac | 2 +- contrib/gitian-descriptors/gitian-linux.yml | 2 +- src/clientversion.h | 2 +- src/deprecation.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ebb83c2d482..4b55fb9decd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Zcash 2.0.5-rc1 +Zcash 2.0.5 =========== diff --git a/configure.ac b/configure.ac index 76001643263..797b71c73e6 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 2) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 5) -define(_CLIENT_VERSION_BUILD, 25) +define(_CLIENT_VERSION_BUILD, 50) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 80c2be98c0e..df50d864163 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "zcash-2.0.5-rc1" +name: "zcash-2.0.5" enable_cache: true distro: "debian" suites: diff --git a/src/clientversion.h b/src/clientversion.h index ace0b04d841..0e21ca63e5e 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -18,7 +18,7 @@ #define CLIENT_VERSION_MAJOR 2 #define CLIENT_VERSION_MINOR 0 #define CLIENT_VERSION_REVISION 5 -#define CLIENT_VERSION_BUILD 25 +#define CLIENT_VERSION_BUILD 50 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/deprecation.h b/src/deprecation.h index 6c6076156ce..d9abbebf1bb 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -8,7 +8,7 @@ // Deprecation policy: // * Shut down 16 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 525525; +static const int APPROX_RELEASE_HEIGHT = 528000; static const int WEEKS_UNTIL_DEPRECATION = 16; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); From 380babed987cf8749b0c2d3c9474ee87a8993859 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Fri, 3 May 2019 16:35:30 -0600 Subject: [PATCH 055/127] make-release.py: Updated manpages for 2.0.5. --- doc/man/zcash-cli.1 | 6 +++--- doc/man/zcash-tx.1 | 6 +++--- doc/man/zcashd.1 | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index e4c0ea7c6be..a54c9c7d265 100644 --- a/doc/man/zcash-cli.1 +++ b/doc/man/zcash-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASH-CLI "1" "May 2019" "zcash-cli v2.0.5-rc1" "User Commands" +.TH ZCASH-CLI "1" "May 2019" "zcash-cli v2.0.5" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v2.0.5-rc1 +zcash-cli \- manual page for zcash-cli v2.0.5 .SH DESCRIPTION -Zcash RPC client version v2.0.5\-rc1 +Zcash RPC client version v2.0.5 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . diff --git a/doc/man/zcash-tx.1 b/doc/man/zcash-tx.1 index 3e494c23227..df99ae127f2 100644 --- a/doc/man/zcash-tx.1 +++ b/doc/man/zcash-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASH-TX "1" "May 2019" "zcash-tx v2.0.5-rc1" "User Commands" +.TH ZCASH-TX "1" "May 2019" "zcash-tx v2.0.5" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v2.0.5-rc1 +zcash-tx \- manual page for zcash-tx v2.0.5 .SH DESCRIPTION -Zcash zcash\-tx utility version v2.0.5\-rc1 +Zcash zcash\-tx utility version v2.0.5 .SS "Usage:" .TP zcash\-tx [options] [commands] diff --git a/doc/man/zcashd.1 b/doc/man/zcashd.1 index 5e11981fcdb..d03182682e6 100644 --- a/doc/man/zcashd.1 +++ b/doc/man/zcashd.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASHD "1" "May 2019" "zcashd v2.0.5-rc1" "User Commands" +.TH ZCASHD "1" "May 2019" "zcashd v2.0.5" "User Commands" .SH NAME -zcashd \- manual page for zcashd v2.0.5-rc1 +zcashd \- manual page for zcashd v2.0.5 .SH DESCRIPTION -Zcash Daemon version v2.0.5\-rc1 +Zcash Daemon version v2.0.5 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . From 5d69949aaac6d86e11b6925e9321d00f8eb4eed1 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Fri, 3 May 2019 16:35:30 -0600 Subject: [PATCH 056/127] make-release.py: Updated release notes and changelog for 2.0.5. --- contrib/debian/changelog | 6 ++ doc/authors.md | 18 ++-- doc/release-notes.md | 44 -------- doc/release-notes/release-notes-2.0.5.md | 130 +++++++++++++++++++++++ 4 files changed, 147 insertions(+), 51 deletions(-) create mode 100644 doc/release-notes/release-notes-2.0.5.md diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 827d338b9d1..b9b8c076751 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +zcash (2.0.5) stable; urgency=medium + + * 2.0.5 release. + + -- Electric Coin Company Fri, 03 May 2019 16:35:30 -0600 + zcash (2.0.5~rc1) stable; urgency=medium * 2.0.5-rc1 release. diff --git a/doc/authors.md b/doc/authors.md index e82945efc15..95018c4b572 100644 --- a/doc/authors.md +++ b/doc/authors.md @@ -1,8 +1,8 @@ Zcash Contributors ================== -Jack Grigg (862) -Simon Liu (443) +Jack Grigg (863) +Simon Liu (448) Sean Bowe (278) Daira Hopwood (110) Eirik Ogilvie-Wigley (102) @@ -14,9 +14,10 @@ Nathan Wilcox (56) Pieter Wuille (54) Kevin Gallagher (38) Cory Fields (35) +Eirik0 (27) mdr0id (22) +Larry Ruane (22) Jonathan "Duke" Leto (17) -Larry Ruane (16) syd (15) Matt Corallo (13) Paige Peterson (11) @@ -27,12 +28,12 @@ kozyilmaz (8) fanquake (8) Jeff Garzik (7) Gregory Maxwell (7) +Marius Kjærstad (6) Luke Dashjr (6) David Mercer (6) Daniel Cousens (6) Suhas Daftuar (5) Pavel Janík (5) -Marius Kjærstad (5) Karl-Johan Alm (5) Johnathan Corgan (5) Charlie O'Keefe (5) @@ -44,16 +45,17 @@ Patrick Strateman (4) João Barbosa (4) Jorge Timón (4) George Tankersley (4) +Gareth Davies (4) +zebambam (3) lpescher (3) ca333 (3) Per Grön (3) Patick Strateman (3) Jason Davies (3) James O'Beirne (3) -Gareth Davies (3) +Dimitris Apostolou (3) Daniel Kraft (3) Alfie John (3) -zebambam (2) rofl0r (2) paveljanik (2) mruddy (2) @@ -71,7 +73,6 @@ Joe Turgeon (2) Jack Gavigan (2) ITH4Coinomia (2) Gavin Andresen (2) -Dimitris Apostolou (2) Brad Miller (2) Bjorn Hjortsberg (2) Amgad Abdelhafez (2) @@ -109,6 +110,7 @@ Nathaniel Mahieu (1) Murilo Santana (1) Maxwell Gubler (1) Matt Quinn (1) +Mary Moore-Simmons (1) Mark Friedenbach (1) Louis Nyffenegger (1) Leo Arias (1) @@ -118,6 +120,7 @@ Kevin Pan (1) Jonas Nick (1) Jeremy Rubin (1) Jeffrey Walton (1) +Ian Munoz (1) Ian Kelling (1) Gaurav Rana (1) Forrest Voight (1) @@ -131,6 +134,7 @@ Casey Rodarmor (1) Cameron Boehmer (1) Bryan Stitt (1) Bruno Arueira (1) +Braydon Fuller (1) Boris Hajduk (1) Bob McElrath (1) Bitcoin Error Log (1) diff --git a/doc/release-notes.md b/doc/release-notes.md index d7935ff1b2c..a29094b5174 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,47 +4,3 @@ release-notes at release time) Notable changes =============== -Sprout to Sapling Migration Tool --------------------------------- -This release includes the addition of a tool that will enable users to migrate -shielded funds from the Sprout pool to the Sapling pool while minimizing -information leakage. - -The migration can be enabled using the RPC `z_setmigration` or by including -`-migration` in the `zcash.conf` file. Unless otherwise specified funds will be -migrated to the wallet's default Sapling address; it is also possible to set the -receiving Sapling address using the `-migrationdestaddress` option in `zcash.conf`. - -See [ZIP308](https://github.com/zcash/zips/blob/master/zip-0308.rst) for full details. - - -New consensus rule: Reject blocks that violate turnstile --------------------------------------------------------- -In the 2.0.4 release the consensus rules were changed on testnet to enforce a -consensus rule which marks blocks as invalid if they would lead to a turnstile -violation in the Sprout or Shielded value pools. -**This release enforces the consensus rule change on mainnet** - -The motivations and deployment details can be found in the accompanying -[ZIP draft](https://github.com/zcash/zips/pull/210) and -[PR 3968](https://github.com/zcash/zcash/pull/3968). - -Developers can use a new experimental feature `-developersetpoolsizezero` to test -Sprout and Sapling turnstile violations. See [PR 3964](https://github.com/zcash/zcash/pull/3964) for more details. - - -64-bit ARMv8 support --------------------- -Added ARMv8 (AArch64) support. This enables users to build zcash on even more -devices. - -For information on how to build see the [User Guide](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#build) - -Users on the Zcash forum have reported successes with both the Pine64 Rock64Pro -and Odroid C2 which contain 4GB and 2GB of RAM respectively. - -Just released, the Odroid N2 looks like a great solution with 4GB of RAM. The -newly released Jetson Nano Developer Kit from Nvidia (also 4GB of RAM) is also -worth a look. The NanoPC-T3 Plus is another option but for the simplest/best -experience choose a board with 4GB of RAM. Just make sure before purchase that -the CPU supports the 64-bit ARMv8 architecture. diff --git a/doc/release-notes/release-notes-2.0.5.md b/doc/release-notes/release-notes-2.0.5.md new file mode 100644 index 00000000000..520060f1784 --- /dev/null +++ b/doc/release-notes/release-notes-2.0.5.md @@ -0,0 +1,130 @@ +Notable changes +=============== + +Sprout to Sapling Migration Tool +-------------------------------- +This release includes the addition of a tool that will enable users to migrate +shielded funds from the Sprout pool to the Sapling pool while minimizing +information leakage. + +The migration can be enabled using the RPC `z_setmigration` or by including +`-migration` in the `zcash.conf` file. Unless otherwise specified funds will be +migrated to the wallet's default Sapling address; it is also possible to set the +receiving Sapling address using the `-migrationdestaddress` option in `zcash.conf`. + +See [ZIP308](https://github.com/zcash/zips/blob/master/zip-0308.rst) for full details. + + +New consensus rule: Reject blocks that violate turnstile +-------------------------------------------------------- +In the 2.0.4 release the consensus rules were changed on testnet to enforce a +consensus rule which marks blocks as invalid if they would lead to a turnstile +violation in the Sprout or Shielded value pools. +**This release enforces the consensus rule change on mainnet** + +The motivations and deployment details can be found in the accompanying +[ZIP draft](https://github.com/zcash/zips/pull/210) and +[PR 3968](https://github.com/zcash/zcash/pull/3968). + +Developers can use a new experimental feature `-developersetpoolsizezero` to test +Sprout and Sapling turnstile violations. See [PR 3964](https://github.com/zcash/zcash/pull/3964) for more details. + + +64-bit ARMv8 support +-------------------- +Added ARMv8 (AArch64) support. This enables users to build zcash on even more +devices. + +For information on how to build see the [User Guide](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#build) + +Users on the Zcash forum have reported successes with both the Pine64 Rock64Pro +and Odroid C2 which contain 4GB and 2GB of RAM respectively. + +Just released, the Odroid N2 looks like a great solution with 4GB of RAM. The +newly released Jetson Nano Developer Kit from Nvidia (also 4GB of RAM) is also +worth a look. The NanoPC-T3 Plus is another option but for the simplest/best +experience choose a board with 4GB of RAM. Just make sure before purchase that +the CPU supports the 64-bit ARMv8 architecture. + +Changelog +========= + +Braydon Fuller (1): + tests: adds unit test for IsPayToPublicKeyHash method + +Dimitris Apostolou (1): + Electric Coin Company + +Eirik0 (27): + Split test in to multiple parts + Use a custom error type if creating joinsplit descriptions fails + Rename and update comment + Add rpc to enable and disable Sprout to Sapling migration + Move migration logic to ChainTip + Documentation cleanup + Additional locking and race condition prevention + Refactor wait_and_assert_operationid_status to allow returning the result + Set min depth when selecting notes to migrate + Check for full failure message in test case + Add migration options to conf file + Create method for getting HD seed in RPCs + Add rpc to get Sprout to Sapling migration status + Fix help message + Test migration using both the parameter and the default Sapling address + Fix typos and update documentation + use -valueBalance rather than vpub_new to calculate migrated amount + Do not look at vin/vout when determining migration txs and other cleanup + Calculate the number of confimations in the canonical way + Do not throw an exception if HD Seed is not found when exporting wallet + make-release.py: Versioning changes for 2.0.5-rc1. + make-release.py: Updated manpages for 2.0.5-rc1. + make-release.py: Updated release notes and changelog for 2.0.5-rc1. + Notable changes for v2.0.5 + Add missing word to release notes + make-release.py: Versioning changes for 2.0.5. + make-release.py: Updated manpages for 2.0.5. + +Gareth Davies (1): + Adding addressindex.h to Makefile.am + +Ian Munoz (1): + add curl to package list for gitian lxc container + +Jack Grigg (9): + Add Sprout support to TransactionBuilder + depends: Use full path to cargo binary + depends: Generalise the rust package cross-compilation functions + depends: Add rust-std hash for aarch64-unknown-linux-gnu + depends: Compile bdb with --disable-atomics on aarch64 + depends: Update .gitignore + configure: Guess -march for libsnark OPTFLAGS instead of hard-coding + Add Blossom to upgrade list + init: Fix new HD seed generation for previously-encrypted wallets + +Larry Ruane (6): + fix enable-debug build DB_COINS undefined + add -addressindex changes for bitcore insight block explorer + add -spentindex changes for bitcore insight block explorer + Update boost from v1.69.0 to v1.70.0. #3947 + add -timestampindex for bitcore insight block explorer + 3873 z_setmigration cli bool enable arg conversion + +Marius Kjærstad (1): + Update _COPYRIGHT_YEAR in configure.ac to 2019 + +Mary Moore-Simmons (1): + Creates checklist template for new PRs being opened and addresses Str4d's suggestion for using GitHub handles + +Simon Liu (5): + Add testnet and regtest experimental feature: -developersetpoolsizezero + Add qa test for experimental feature: -developersetpoolsizezero + Enable ZIP209 on mainnet and set fallback Sprout pool balance. + Enable experimental feature -developersetpoolsizezero on mainnet. + Update chain work and checkpoint using block 525000. + +Jack Grigg (1): + remove extra hyphen + +zebambam (1): + Minor speling changes + From 7cf4749d0d7f84b8906609d1d6c19d2fc8c7ce9b Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Sun, 5 May 2019 12:59:43 -0600 Subject: [PATCH 057/127] Correctly account for migration transactions in the mempool Co-authored-by: LarryRuane --- qa/rpc-tests/sprout_sapling_migration.py | 3 +++ src/wallet/rpcwallet.cpp | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py index 5f47d779616..3e5a094cf6f 100755 --- a/qa/rpc-tests/sprout_sapling_migration.py +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -106,6 +106,9 @@ def run_migration_test(self, node, sproutAddr, saplingAddr, target_height): assert_equal(node.z_getbalance(sproutAddr), Decimal('0')) assert_equal(node.z_getbalance(saplingAddr), Decimal('0')) assert_true(node.z_getbalance(saplingAddr, 0) > Decimal('0'), "Unconfirmed sapling balance at 499 % 500") + # Check that unmigrated amount + unfinalized = starting balance - fee + status = node.z_getmigrationstatus() + assert_equal(Decimal('9.9999'), Decimal(status['unmigrated_amount']) + Decimal(status['unfinalized_migrated_amount'])) node.generate(1) self.sync_all() diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index d0e67a1b2e7..fa93af02ddd 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3967,7 +3967,8 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { { std::vector sproutEntries; std::vector saplingEntries; - pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, "", 1); + std::set zaddrs; + pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, 0, INT_MAX, true, true, false); CAmount unmigratedAmount = 0; for (const auto& sproutEntry : sproutEntries) { unmigratedAmount += sproutEntry.plaintext.value(); @@ -4000,7 +4001,6 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { continue; } migrationTxids.push_back(txPair.first.ToString()); - CBlockIndex* blockIndex = mapBlockIndex[tx.hashBlock]; // A transaction is "finalized" iff it has at least 10 confirmations. // TODO: subject to change, if the recommended number of confirmations changes. if (tx.GetDepthInMainChain() >= 10) { @@ -4009,6 +4009,11 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { } else { unfinalizedMigratedAmount -= tx.valueBalance; } + // If the transaction is in the mempool it will not be associated with a block yet + if (tx.hashBlock.IsNull() || mapBlockIndex[tx.hashBlock] == nullptr) { + continue; + } + CBlockIndex* blockIndex = mapBlockIndex[tx.hashBlock]; // The value of "time_started" is the earliest Unix timestamp of any known // migration transaction involving this wallet; if there is no such transaction, // then the field is absent. From d48c3efca7960d08f3f54755f6205b4e55ec872f Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Mon, 6 May 2019 09:57:40 -0600 Subject: [PATCH 058/127] Store the migration operation id rather than the operation iteslf --- src/wallet/asyncrpcoperation_saplingmigration.cpp | 4 ++++ src/wallet/asyncrpcoperation_saplingmigration.h | 2 ++ src/wallet/wallet.cpp | 15 +++++++++------ src/wallet/wallet.h | 2 +- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index ab44bf76077..cb3f2c9d2d4 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -191,6 +191,10 @@ libzcash::SaplingPaymentAddress AsyncRPCOperation_saplingmigration::getMigration return toAddress; } +void AsyncRPCOperation_saplingmigration::cancel() { + set_state(OperationStatus::CANCELLED); +} + UniValue AsyncRPCOperation_saplingmigration::getStatus() const { UniValue v = AsyncRPCOperation::getStatus(); UniValue obj = v.get_obj(); diff --git a/src/wallet/asyncrpcoperation_saplingmigration.h b/src/wallet/asyncrpcoperation_saplingmigration.h index e077c8eca32..2f790fc14d5 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.h +++ b/src/wallet/asyncrpcoperation_saplingmigration.h @@ -20,6 +20,8 @@ class AsyncRPCOperation_saplingmigration : public AsyncRPCOperation virtual void main(); + virtual void cancel(); + virtual UniValue getStatus() const; private: diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index cf220fcf2a6..07c0a105da2 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -603,17 +603,20 @@ void CWallet::RunSaplingMigration(int blockHeight) { // height N, implementations SHOULD start generating the transactions at around // height N-5 if (blockHeight % 500 == 495) { - if (saplingMigrationOperation != nullptr) { - saplingMigrationOperation->cancel(); + std::shared_ptr q = getAsyncRPCQueue(); + std::shared_ptr lastOperation = q->popOperationForId(saplingMigrationOperationId); + if (lastOperation != nullptr) { + lastOperation->cancel(); } pendingSaplingMigrationTxs.clear(); - std::shared_ptr q = getAsyncRPCQueue(); std::shared_ptr operation(new AsyncRPCOperation_saplingmigration(blockHeight + 5)); - saplingMigrationOperation = operation; + saplingMigrationOperationId = operation->getId(); q->addOperation(operation); } else if (blockHeight % 500 == 499) { - if (saplingMigrationOperation != nullptr) { - saplingMigrationOperation->cancel(); + std::shared_ptr q = getAsyncRPCQueue(); + std::shared_ptr lastOperation = q->popOperationForId(saplingMigrationOperationId); + if (lastOperation != nullptr) { + lastOperation->cancel(); } for (const CTransaction& transaction : pendingSaplingMigrationTxs) { // The following is taken from z_sendmany/z_mergetoaddress diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 6e4c239d9de..fa137011199 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -757,7 +757,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface TxNullifiers mapTxSaplingNullifiers; std::vector pendingSaplingMigrationTxs; - std::shared_ptr saplingMigrationOperation = nullptr; + AsyncRPCOperationId saplingMigrationOperationId; void AddToTransparentSpends(const COutPoint& outpoint, const uint256& wtxid); void AddToSproutSpends(const uint256& nullifier, const uint256& wtxid); From 94e419f95d345f66b4c7a29fd84f3b31e10b84d0 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Mon, 6 May 2019 11:46:16 -0600 Subject: [PATCH 059/127] Rename variable and add comment --- src/wallet/rpcwallet.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index fa93af02ddd..ca291255892 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3967,8 +3967,10 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { { std::vector sproutEntries; std::vector saplingEntries; - std::set zaddrs; - pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, 0, INT_MAX, true, true, false); + std::set noFilter; + // Here we are looking for any and all Sprout notes for which we have the spending key, including those + // which are locked and/or only exist in the mempool, as they should be included in the unmigrated amount. + pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, noFilter, 0, INT_MAX, true, true, false); CAmount unmigratedAmount = 0; for (const auto& sproutEntry : sproutEntries) { unmigratedAmount += sproutEntry.plaintext.value(); From aa234062635368ba787adb0d8aa94dae43222f28 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Mon, 6 May 2019 15:51:21 -0600 Subject: [PATCH 060/127] Notable changes for v2.0.5-1 --- doc/release-notes.md | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/doc/release-notes.md b/doc/release-notes.md index a29094b5174..0d0f27e5b3b 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,3 +4,53 @@ release-notes at release time) Notable changes =============== +Sprout to Sapling Migration Tool +-------------------------------- +This release includes the addition of a tool that will enable users to migrate +shielded funds from the Sprout pool to the Sapling pool while minimizing +information leakage. + +The migration can be enabled using the RPC `z_setmigration` or by including +`-migration` in the `zcash.conf` file. Unless otherwise specified funds will be +migrated to the wallet's default Sapling address; it is also possible to set the +receiving Sapling address using the `-migrationdestaddress` option in `zcash.conf`. + +See [ZIP308](https://github.com/zcash/zips/blob/master/zip-0308.rst) for full details. + +Sprout to Sapling Migration Tool Fixes +-------------------------------------- +The 2.0.5-1 release includes fixes to the Sprout to Sapling Migration Tool +found in testing. We resolved an issue which would cause the zcash daemon to +crash if calling the RPC `z_getmigrationstatus` while a wallet's migration +transactions are in the mempool. + +New consensus rule: Reject blocks that violate turnstile +-------------------------------------------------------- +In the 2.0.4 release the consensus rules were changed on testnet to enforce a +consensus rule which marks blocks as invalid if they would lead to a turnstile +violation in the Sprout or Shielded value pools. +**This release enforces the consensus rule change on mainnet** + +The motivations and deployment details can be found in the accompanying +[ZIP draft](https://github.com/zcash/zips/pull/210) and +[PR 3968](https://github.com/zcash/zcash/pull/3968). + +Developers can use a new experimental feature `-developersetpoolsizezero` to test +Sprout and Sapling turnstile violations. See [PR 3964](https://github.com/zcash/zcash/pull/3964) for more details. + + +64-bit ARMv8 support +-------------------- +Added ARMv8 (AArch64) support. This enables users to build zcash on even more +devices. + +For information on how to build see the [User Guide](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#build) + +Users on the Zcash forum have reported successes with both the Pine64 Rock64Pro +and Odroid C2 which contain 4GB and 2GB of RAM respectively. + +Just released, the Odroid N2 looks like a great solution with 4GB of RAM. The +newly released Jetson Nano Developer Kit from Nvidia (also 4GB of RAM) is also +worth a look. The NanoPC-T3 Plus is another option but for the simplest/best +experience choose a board with 4GB of RAM. Just make sure before purchase that +the CPU supports the 64-bit ARMv8 architecture. From f0f7b3f012d208609f183a6f266d832d5526ce7c Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 7 May 2019 08:55:26 -0600 Subject: [PATCH 061/127] Fix summing available funds --- src/wallet/asyncrpcoperation_saplingmigration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index cb3f2c9d2d4..cb97bf04091 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -77,7 +77,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { } CAmount availableFunds = 0; for (const CSproutNotePlaintextEntry& sproutEntry : sproutEntries) { - availableFunds = sproutEntry.plaintext.value(); + availableFunds += sproutEntry.plaintext.value(); } // If the remaining amount to be migrated is less than 0.01 ZEC, end the migration. if (availableFunds < CENT) { From 5fd7af5f857cb3c7d439ec098f117c33ea2eca8a Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 7 May 2019 08:58:23 -0600 Subject: [PATCH 062/127] Add the amount migrated to the operation's result --- src/wallet/asyncrpcoperation_saplingmigration.cpp | 10 +++++++--- src/wallet/asyncrpcoperation_saplingmigration.h | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index cb97bf04091..7a45e6e3132 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -9,6 +9,7 @@ #include "tinyformat.h" #include "transaction_builder.h" #include "util.h" +#include "utilmoneystr.h" #include "wallet.h" const CAmount FEE = 10000; @@ -81,7 +82,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { } // If the remaining amount to be migrated is less than 0.01 ZEC, end the migration. if (availableFunds < CENT) { - setMigrationResult(0); + setMigrationResult(0, 0); return true; } @@ -92,6 +93,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { // Up to the limit of 5, as many transactions are sent as are needed to migrate the remaining funds int numTxCreated = 0; + CAmount amountMigrated = 0; int noteIndex = 0; do { CAmount amountToSend = chooseAmount(availableFunds); @@ -127,15 +129,17 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { } pwalletMain->AddPendingSaplingMigrationTx(tx); ++numTxCreated; + amountMigrated += amountToSend; } while (numTxCreated < 5 && availableFunds > CENT); - setMigrationResult(numTxCreated); + setMigrationResult(numTxCreated, amountMigrated); return true; } -void AsyncRPCOperation_saplingmigration::setMigrationResult(int numTxCreated) { +void AsyncRPCOperation_saplingmigration::setMigrationResult(int numTxCreated, CAmount amountMigrated) { UniValue res(UniValue::VOBJ); res.push_back(Pair("num_tx_created", numTxCreated)); + res.push_back(Pair("amount_migrated", FormatMoney(amountMigrated))); set_result(res); } diff --git a/src/wallet/asyncrpcoperation_saplingmigration.h b/src/wallet/asyncrpcoperation_saplingmigration.h index 2f790fc14d5..64319968f92 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.h +++ b/src/wallet/asyncrpcoperation_saplingmigration.h @@ -29,7 +29,7 @@ class AsyncRPCOperation_saplingmigration : public AsyncRPCOperation bool main_impl(); - void setMigrationResult(int numTxCreated); + void setMigrationResult(int numTxCreated, CAmount amountMigrated); CAmount chooseAmount(const CAmount& availableFunds); }; From ea8823ce519595ba21bdcd94339126af27da4f61 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 7 May 2019 12:02:54 -0600 Subject: [PATCH 063/127] coinsView is required when using TransactionBuilder if there may be Sprout change --- src/transaction_builder.cpp | 4 ++++ src/wallet/asyncrpcoperation_saplingmigration.cpp | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp index fbe1043a5f6..64f8238b80d 100644 --- a/src/transaction_builder.cpp +++ b/src/transaction_builder.cpp @@ -524,6 +524,10 @@ void TransactionBuilder::CreateJSDescriptions() // Update tree state with previous joinsplit SproutMerkleTree tree; { + // assert that coinsView is not null + assert(coinsView); + // We do not check cs_coinView because we do not set this in testing + // assert(cs_coinsView); LOCK(cs_coinsView); auto it = intermediates.find(prevJoinSplit.anchor); if (it != intermediates.end()) { diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index 7a45e6e3132..ac82717be70 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -95,9 +95,10 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { int numTxCreated = 0; CAmount amountMigrated = 0; int noteIndex = 0; + CCoinsViewCache coinsView(pcoinsTip); do { CAmount amountToSend = chooseAmount(availableFunds); - auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain, pzcashParams); + auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain, pzcashParams, &coinsView, &cs_main); std::vector fromNotes; CAmount fromNoteAmount = 0; while (fromNoteAmount < amountToSend) { From f809ff997f00a1dcd5bb15cfa7f3e1605c4437d9 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 8 May 2019 06:50:57 -0600 Subject: [PATCH 064/127] make-release.py: Versioning changes for 2.0.5-1. --- README.md | 2 +- configure.ac | 2 +- contrib/gitian-descriptors/gitian-linux.yml | 2 +- src/clientversion.h | 2 +- src/deprecation.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4b55fb9decd..5d6c06c6104 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Zcash 2.0.5 +Zcash 2.0.5-1 =========== diff --git a/configure.ac b/configure.ac index 797b71c73e6..0dc14ccbe9a 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 2) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 5) -define(_CLIENT_VERSION_BUILD, 50) +define(_CLIENT_VERSION_BUILD, 51) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index df50d864163..f0e40fd4082 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "zcash-2.0.5" +name: "zcash-2.0.5-1" enable_cache: true distro: "debian" suites: diff --git a/src/clientversion.h b/src/clientversion.h index 0e21ca63e5e..5e6b49a9d5d 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -18,7 +18,7 @@ #define CLIENT_VERSION_MAJOR 2 #define CLIENT_VERSION_MINOR 0 #define CLIENT_VERSION_REVISION 5 -#define CLIENT_VERSION_BUILD 50 +#define CLIENT_VERSION_BUILD 51 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/deprecation.h b/src/deprecation.h index d9abbebf1bb..a0dd736bcef 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -8,7 +8,7 @@ // Deprecation policy: // * Shut down 16 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 528000; +static const int APPROX_RELEASE_HEIGHT = 529250; static const int WEEKS_UNTIL_DEPRECATION = 16; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); From eceff9bed6ec74c3f87ea3aa3ba4f1a9755f2a3e Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 8 May 2019 06:57:28 -0600 Subject: [PATCH 065/127] make-release.py: Updated manpages for 2.0.5-1. --- doc/man/zcash-cli.1 | 6 +++--- doc/man/zcash-tx.1 | 6 +++--- doc/man/zcashd.1 | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index a54c9c7d265..a13df414a5a 100644 --- a/doc/man/zcash-cli.1 +++ b/doc/man/zcash-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASH-CLI "1" "May 2019" "zcash-cli v2.0.5" "User Commands" +.TH ZCASH-CLI "1" "May 2019" "zcash-cli v2.0.5-1" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v2.0.5 +zcash-cli \- manual page for zcash-cli v2.0.5-1 .SH DESCRIPTION -Zcash RPC client version v2.0.5 +Zcash RPC client version v2.0.5\-1 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . diff --git a/doc/man/zcash-tx.1 b/doc/man/zcash-tx.1 index df99ae127f2..fc0810578fd 100644 --- a/doc/man/zcash-tx.1 +++ b/doc/man/zcash-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASH-TX "1" "May 2019" "zcash-tx v2.0.5" "User Commands" +.TH ZCASH-TX "1" "May 2019" "zcash-tx v2.0.5-1" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v2.0.5 +zcash-tx \- manual page for zcash-tx v2.0.5-1 .SH DESCRIPTION -Zcash zcash\-tx utility version v2.0.5 +Zcash zcash\-tx utility version v2.0.5\-1 .SS "Usage:" .TP zcash\-tx [options] [commands] diff --git a/doc/man/zcashd.1 b/doc/man/zcashd.1 index d03182682e6..f47b35710ee 100644 --- a/doc/man/zcashd.1 +++ b/doc/man/zcashd.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASHD "1" "May 2019" "zcashd v2.0.5" "User Commands" +.TH ZCASHD "1" "May 2019" "zcashd v2.0.5-1" "User Commands" .SH NAME -zcashd \- manual page for zcashd v2.0.5 +zcashd \- manual page for zcashd v2.0.5-1 .SH DESCRIPTION -Zcash Daemon version v2.0.5 +Zcash Daemon version v2.0.5\-1 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . From dfa40412af4df0c1f7eb0cfd70746c8a573a63f0 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 8 May 2019 06:57:28 -0600 Subject: [PATCH 066/127] make-release.py: Updated release notes and changelog for 2.0.5-1. --- contrib/debian/changelog | 6 ++ doc/authors.md | 2 +- doc/release-notes.md | 50 ---------------- doc/release-notes/release-notes-2.0.5-1.md | 68 ++++++++++++++++++++++ 4 files changed, 75 insertions(+), 51 deletions(-) create mode 100644 doc/release-notes/release-notes-2.0.5-1.md diff --git a/contrib/debian/changelog b/contrib/debian/changelog index b9b8c076751..3814043023d 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +zcash (2.0.5+1) stable; urgency=medium + + * 2.0.5-1 release. + + -- Electric Coin Company Wed, 08 May 2019 06:57:28 -0600 + zcash (2.0.5) stable; urgency=medium * 2.0.5 release. diff --git a/doc/authors.md b/doc/authors.md index 95018c4b572..c196c34a06e 100644 --- a/doc/authors.md +++ b/doc/authors.md @@ -13,8 +13,8 @@ Jonas Schnelli (62) Nathan Wilcox (56) Pieter Wuille (54) Kevin Gallagher (38) +Eirik0 (36) Cory Fields (35) -Eirik0 (27) mdr0id (22) Larry Ruane (22) Jonathan "Duke" Leto (17) diff --git a/doc/release-notes.md b/doc/release-notes.md index 0d0f27e5b3b..a29094b5174 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,53 +4,3 @@ release-notes at release time) Notable changes =============== -Sprout to Sapling Migration Tool --------------------------------- -This release includes the addition of a tool that will enable users to migrate -shielded funds from the Sprout pool to the Sapling pool while minimizing -information leakage. - -The migration can be enabled using the RPC `z_setmigration` or by including -`-migration` in the `zcash.conf` file. Unless otherwise specified funds will be -migrated to the wallet's default Sapling address; it is also possible to set the -receiving Sapling address using the `-migrationdestaddress` option in `zcash.conf`. - -See [ZIP308](https://github.com/zcash/zips/blob/master/zip-0308.rst) for full details. - -Sprout to Sapling Migration Tool Fixes --------------------------------------- -The 2.0.5-1 release includes fixes to the Sprout to Sapling Migration Tool -found in testing. We resolved an issue which would cause the zcash daemon to -crash if calling the RPC `z_getmigrationstatus` while a wallet's migration -transactions are in the mempool. - -New consensus rule: Reject blocks that violate turnstile --------------------------------------------------------- -In the 2.0.4 release the consensus rules were changed on testnet to enforce a -consensus rule which marks blocks as invalid if they would lead to a turnstile -violation in the Sprout or Shielded value pools. -**This release enforces the consensus rule change on mainnet** - -The motivations and deployment details can be found in the accompanying -[ZIP draft](https://github.com/zcash/zips/pull/210) and -[PR 3968](https://github.com/zcash/zcash/pull/3968). - -Developers can use a new experimental feature `-developersetpoolsizezero` to test -Sprout and Sapling turnstile violations. See [PR 3964](https://github.com/zcash/zcash/pull/3964) for more details. - - -64-bit ARMv8 support --------------------- -Added ARMv8 (AArch64) support. This enables users to build zcash on even more -devices. - -For information on how to build see the [User Guide](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#build) - -Users on the Zcash forum have reported successes with both the Pine64 Rock64Pro -and Odroid C2 which contain 4GB and 2GB of RAM respectively. - -Just released, the Odroid N2 looks like a great solution with 4GB of RAM. The -newly released Jetson Nano Developer Kit from Nvidia (also 4GB of RAM) is also -worth a look. The NanoPC-T3 Plus is another option but for the simplest/best -experience choose a board with 4GB of RAM. Just make sure before purchase that -the CPU supports the 64-bit ARMv8 architecture. diff --git a/doc/release-notes/release-notes-2.0.5-1.md b/doc/release-notes/release-notes-2.0.5-1.md new file mode 100644 index 00000000000..ef02d80b571 --- /dev/null +++ b/doc/release-notes/release-notes-2.0.5-1.md @@ -0,0 +1,68 @@ +Notable changes +=============== + +Sprout to Sapling Migration Tool +-------------------------------- +This release includes the addition of a tool that will enable users to migrate +shielded funds from the Sprout pool to the Sapling pool while minimizing +information leakage. + +The migration can be enabled using the RPC `z_setmigration` or by including +`-migration` in the `zcash.conf` file. Unless otherwise specified funds will be +migrated to the wallet's default Sapling address; it is also possible to set the +receiving Sapling address using the `-migrationdestaddress` option in `zcash.conf`. + +See [ZIP308](https://github.com/zcash/zips/blob/master/zip-0308.rst) for full details. + +Sprout to Sapling Migration Tool Fixes +-------------------------------------- +The 2.0.5-1 release includes fixes to the Sprout to Sapling Migration Tool +found in testing. We resolved an issue which would cause the zcash daemon to +crash if calling the RPC `z_getmigrationstatus` while a wallet's migration +transactions are in the mempool. + +New consensus rule: Reject blocks that violate turnstile +-------------------------------------------------------- +In the 2.0.4 release the consensus rules were changed on testnet to enforce a +consensus rule which marks blocks as invalid if they would lead to a turnstile +violation in the Sprout or Shielded value pools. +**This release enforces the consensus rule change on mainnet** + +The motivations and deployment details can be found in the accompanying +[ZIP draft](https://github.com/zcash/zips/pull/210) and +[PR 3968](https://github.com/zcash/zcash/pull/3968). + +Developers can use a new experimental feature `-developersetpoolsizezero` to test +Sprout and Sapling turnstile violations. See [PR 3964](https://github.com/zcash/zcash/pull/3964) for more details. + + +64-bit ARMv8 support +-------------------- +Added ARMv8 (AArch64) support. This enables users to build zcash on even more +devices. + +For information on how to build see the [User Guide](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#build) + +Users on the Zcash forum have reported successes with both the Pine64 Rock64Pro +and Odroid C2 which contain 4GB and 2GB of RAM respectively. + +Just released, the Odroid N2 looks like a great solution with 4GB of RAM. The +newly released Jetson Nano Developer Kit from Nvidia (also 4GB of RAM) is also +worth a look. The NanoPC-T3 Plus is another option but for the simplest/best +experience choose a board with 4GB of RAM. Just make sure before purchase that +the CPU supports the 64-bit ARMv8 architecture. + +Changelog +========= + +Eirik0 (9): + Correctly account for migration transactions in the mempool + Store the migration operation id rather than the operation iteslf + Rename variable and add comment + Notable changes for v2.0.5-1 + Fix summing available funds + Add the amount migrated to the operation's result + coinsView is required when using TransactionBuilder if there may be Sprout change + make-release.py: Versioning changes for 2.0.5-1. + make-release.py: Updated manpages for 2.0.5-1. + From bda85eb06a6b7aa2342d7f3cdc2af52fa1250039 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 8 May 2019 20:32:04 -0700 Subject: [PATCH 067/127] Remove unused specifier from format string. The extra specifier meant that a runtime error would be thrown during Sprout to Sapling migration if `zrpcunsafe` logging was enabled: "tinyformat: Too many conversion specifiers in format string" --- src/transaction_builder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp index 64f8238b80d..6c9da0656bc 100644 --- a/src/transaction_builder.cpp +++ b/src/transaction_builder.cpp @@ -677,7 +677,7 @@ void TransactionBuilder::CreateJSDescription( std::array& inputMap, std::array& outputMap) { - LogPrint("zrpcunsafe", "%s: creating joinsplit at index %d (vpub_old=%s, vpub_new=%s, in[0]=%s, in[1]=%s, out[0]=%s, out[1]=%s)\n", + LogPrint("zrpcunsafe", "CreateJSDescription: creating joinsplit at index %d (vpub_old=%s, vpub_new=%s, in[0]=%s, in[1]=%s, out[0]=%s, out[1]=%s)\n", mtx.vjoinsplit.size(), FormatMoney(vpub_old), FormatMoney(vpub_new), FormatMoney(vjsin[0].note.value()), FormatMoney(vjsin[1].note.value()), From 6921c81b9ddff1b3ac7731661a5778bd4f59aa9b Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 9 May 2019 09:32:09 -0700 Subject: [PATCH 068/127] Don't allow migration when node is syncing at launch or after waking up. --- src/wallet/wallet.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 07c0a105da2..bde0eb9d119 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -581,7 +581,13 @@ void CWallet::ChainTip(const CBlockIndex *pindex, { if (added) { ChainTipAdded(pindex, pblock, sproutTree, saplingTree); - RunSaplingMigration(pindex->nHeight); + // Prevent migration transactions from being created when node is syncing after launch, + // and also when node wakes up from suspension/hibernation and incoming blocks are old. + if (!IsInitialBlockDownload() && + pblock->GetBlockTime() > GetAdjustedTime() - 3 * 60 * 60) + { + RunSaplingMigration(pindex->nHeight); + } } else { DecrementNoteWitnesses(pindex); UpdateSaplingNullifierNoteMapForBlock(pblock); From 5eb7129d951aa7b2221124ab6f904fc0ca19946e Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Fri, 10 May 2019 11:39:03 +0100 Subject: [PATCH 069/127] Generalize TransactionBuilder and CreateNewContextualCMutableTransaction to allow choosing the expiry delta. Signed-off-by: Daira Hopwood --- src/main.cpp | 11 +++++++++-- src/main.h | 5 ++++- src/transaction_builder.cpp | 3 ++- src/transaction_builder.h | 1 + src/wallet/asyncrpcoperation_saplingmigration.cpp | 3 ++- src/wallet/rpcwallet.cpp | 6 +++--- 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f7569a5ee62..ea105227427 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6612,12 +6612,19 @@ static class CMainCleanup // Set default values of new CMutableTransaction based on consensus rules at given height. CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight) { - CMutableTransaction mtx; + return CreateNewContextualCMutableTransaction(consensusParams, nHeight, expiryDelta); +} +CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight, int nExpiryDelta) { + CMutableTransaction mtx; bool isOverwintered = NetworkUpgradeActive(nHeight, consensusParams, Consensus::UPGRADE_OVERWINTER); if (isOverwintered) { mtx.fOverwintered = true; - mtx.nExpiryHeight = nHeight + expiryDelta; + mtx.nExpiryHeight = nHeight + nExpiryDelta; + + if (mtx.nExpiryHeight <= 0 || mtx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { + throw new std::runtime_error("CreateNewContextualCMutableTransaction: invalid expiry height"); + } // NOTE: If the expiry height crosses into an incompatible consensus epoch, and it is changed to the last block // of the current epoch (see below: Overwinter->Sapling), the transaction will be rejected if it falls within diff --git a/src/main.h b/src/main.h index df9e7ea3ab5..b78c1d831e9 100644 --- a/src/main.h +++ b/src/main.h @@ -595,7 +595,10 @@ int GetSpendHeight(const CCoinsViewCache& inputs); uint64_t CalculateCurrentUsage(); -/** Return a CMutableTransaction with contextual default values based on set of consensus rules at height */ +/** Return a CMutableTransaction with contextual default values based on set of consensus rules at nHeight, and the default expiry delta. */ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight); +/** Return a CMutableTransaction with contextual default values based on set of consensus rules at nHeight, and given expiry delta. */ +CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight, int nExpiryDelta); + #endif // BITCOIN_MAIN_H diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp index 6c9da0656bc..687c1a42024 100644 --- a/src/transaction_builder.cpp +++ b/src/transaction_builder.cpp @@ -50,6 +50,7 @@ std::string TransactionBuilderResult::GetError() { TransactionBuilder::TransactionBuilder( const Consensus::Params& consensusParams, int nHeight, + int nExpiryDelta, CKeyStore* keystore, ZCJoinSplit* sproutParams, CCoinsViewCache* coinsView, @@ -61,7 +62,7 @@ TransactionBuilder::TransactionBuilder( coinsView(coinsView), cs_coinsView(cs_coinsView) { - mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight); + mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight, nExpiryDelta); } // This exception is thrown in certain scenarios when building JoinSplits fails. diff --git a/src/transaction_builder.h b/src/transaction_builder.h index ee3c4e7ae45..46f38481ecc 100644 --- a/src/transaction_builder.h +++ b/src/transaction_builder.h @@ -95,6 +95,7 @@ class TransactionBuilder TransactionBuilder( const Consensus::Params& consensusParams, int nHeight, + int nExpiryDelta, CKeyStore* keyStore = nullptr, ZCJoinSplit* sproutParams = nullptr, CCoinsViewCache* coinsView = nullptr, diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index ac82717be70..5f34eaeee75 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -98,7 +98,8 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { CCoinsViewCache coinsView(pcoinsTip); do { CAmount amountToSend = chooseAmount(availableFunds); - auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain, pzcashParams, &coinsView, &cs_main); + auto builder = TransactionBuilder(consensusParams, targetHeight_, expiryDelta, pwalletMain, pzcashParams, + &coinsView, &cs_main); std::vector fromNotes; CAmount fromNoteAmount = 0; while (fromNoteAmount < amountToSend) { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ca291255892..61dd9e5869b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3888,7 +3888,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) // Builder (used if Sapling addresses are involved) boost::optional builder; if (noSproutAddrs) { - builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain); + builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, expiryDelta, pwalletMain); } // Contextual transaction we will build on @@ -4229,7 +4229,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) // Builder (used if Sapling addresses are involved) TransactionBuilder builder = TransactionBuilder( - Params().GetConsensus(), nextBlockHeight, pwalletMain); + Params().GetConsensus(), nextBlockHeight, expiryDelta, pwalletMain); // Contextual transaction we will build on // (used if no Sapling addresses are involved) @@ -4646,7 +4646,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) // Builder (used if Sapling addresses are involved) boost::optional builder; if (isToSaplingZaddr || saplingNoteInputs.size() > 0) { - builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain); + builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, expiryDelta, pwalletMain); } // Create operation and add to global queue std::shared_ptr q = getAsyncRPCQueue(); From 9cd34fc10af2d54dc93925dca1afd7cc0307aa68 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Fri, 10 May 2019 11:39:57 +0100 Subject: [PATCH 070/127] Repair calls to TransactionBuilder from tests. Signed-off-by: Daira Hopwood --- src/gtest/test_transaction_builder.cpp | 34 +++++++++++++------------- src/test/rpc_wallet_tests.cpp | 2 +- src/utiltest.cpp | 2 +- src/wallet/gtest/test_wallet.cpp | 24 +++++++++--------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/gtest/test_transaction_builder.cpp b/src/gtest/test_transaction_builder.cpp index 6676ef21eec..3fe71d21b31 100644 --- a/src/gtest/test_transaction_builder.cpp +++ b/src/gtest/test_transaction_builder.cpp @@ -93,7 +93,7 @@ TEST(TransactionBuilder, TransparentToSapling) // Create a shielding transaction from transparent to Sapling // 0.0005 t-ZEC in, 0.0004 z-ZEC out, 0.0001 t-ZEC fee - auto builder = TransactionBuilder(consensusParams, 1, &keystore); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 50000); builder.AddSaplingOutput(fvk_from.ovk, pk, 40000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -125,7 +125,7 @@ TEST(TransactionBuilder, SaplingToSapling) { // Create a Sapling-only transaction // 0.0004 z-ZEC in, 0.00025 z-ZEC out, 0.0001 t-ZEC fee, 0.00005 z-ZEC change - auto builder = TransactionBuilder(consensusParams, 2); + auto builder = TransactionBuilder(consensusParams, 2, expiryDelta); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); // Check that trying to add a different anchor fails @@ -166,7 +166,7 @@ TEST(TransactionBuilder, SaplingToSprout) { // - 0.0004 Sapling-ZEC in - 0.00025 Sprout-ZEC out // - 0.00005 Sapling-ZEC change // - 0.0001 t-ZEC fee - auto builder = TransactionBuilder(consensusParams, 2, nullptr, params); + auto builder = TransactionBuilder(consensusParams, 2, expiryDelta, nullptr, params); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSproutOutput(sproutAddr, 25000); auto tx = builder.Build().GetTxOrThrow(); @@ -218,7 +218,7 @@ TEST(TransactionBuilder, SproutToSproutAndSapling) { // - 0.00005 Sprout-ZEC change // - 0.00005 Sapling-ZEC out // - 0.00005 t-ZEC fee - auto builder = TransactionBuilder(consensusParams, 2, nullptr, params, &view); + auto builder = TransactionBuilder(consensusParams, 2, expiryDelta, nullptr, params, &view); builder.SetFee(5000); builder.AddSproutInput(sproutSk, sproutNote, sproutWitness); builder.AddSproutOutput(sproutAddr, 6000); @@ -255,7 +255,7 @@ TEST(TransactionBuilder, ThrowsOnSproutOutputWithoutParams) auto sk = libzcash::SproutSpendingKey::random(); auto addr = sk.address(); - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); ASSERT_THROW(builder.AddSproutOutput(addr, 10), std::runtime_error); } @@ -264,7 +264,7 @@ TEST(TransactionBuilder, ThrowsOnTransparentInputWithoutKeyStore) SelectParams(CBaseChainParams::REGTEST); auto consensusParams = Params().GetConsensus(); - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); ASSERT_THROW(builder.AddTransparentInput(COutPoint(), CScript(), 1), std::runtime_error); } @@ -275,7 +275,7 @@ TEST(TransactionBuilder, RejectsInvalidTransparentOutput) // Default CTxDestination type is an invalid address CTxDestination taddr; - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); ASSERT_THROW(builder.AddTransparentOutput(taddr, 50), UniValue); } @@ -286,7 +286,7 @@ TEST(TransactionBuilder, RejectsInvalidTransparentChangeAddress) // Default CTxDestination type is an invalid address CTxDestination taddr; - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); ASSERT_THROW(builder.SendChangeTo(taddr), UniValue); } @@ -311,13 +311,13 @@ TEST(TransactionBuilder, FailsWithNegativeChange) // Fail if there is only a Sapling output // 0.0005 z-ZEC out, 0.0001 t-ZEC fee - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); builder.AddSaplingOutput(fvk.ovk, pa, 50000, {}); EXPECT_EQ("Change cannot be negative", builder.Build().GetError()); // Fail if there is only a transparent output // 0.0005 t-ZEC out, 0.0001 t-ZEC fee - builder = TransactionBuilder(consensusParams, 1, &keystore); + builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); builder.AddTransparentOutput(taddr, 50000); EXPECT_EQ("Change cannot be negative", builder.Build().GetError()); @@ -359,14 +359,14 @@ TEST(TransactionBuilder, ChangeOutput) // No change address and no Sapling spends { - auto builder = TransactionBuilder(consensusParams, 1, &keystore); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000); EXPECT_EQ("Could not determine change address", builder.Build().GetError()); } // Change to the same address as the first Sapling spend { - auto builder = TransactionBuilder(consensusParams, 1, &keystore); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); auto tx = builder.Build().GetTxOrThrow(); @@ -381,7 +381,7 @@ TEST(TransactionBuilder, ChangeOutput) // Change to a Sapling address { - auto builder = TransactionBuilder(consensusParams, 1, &keystore); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000); builder.SendChangeTo(zChangeAddr, fvkOut.ovk); auto tx = builder.Build().GetTxOrThrow(); @@ -396,7 +396,7 @@ TEST(TransactionBuilder, ChangeOutput) // Change to a transparent address { - auto builder = TransactionBuilder(consensusParams, 1, &keystore); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000); builder.SendChangeTo(taddr); auto tx = builder.Build().GetTxOrThrow(); @@ -428,7 +428,7 @@ TEST(TransactionBuilder, SetFee) // Default fee { - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSaplingOutput(fvk.ovk, pa, 25000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -443,7 +443,7 @@ TEST(TransactionBuilder, SetFee) // Configured fee { - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSaplingOutput(fvk.ovk, pa, 25000, {}); builder.SetFee(20000); @@ -472,7 +472,7 @@ TEST(TransactionBuilder, CheckSaplingTxVersion) auto pk = sk.default_address(); // Cannot add Sapling outputs to a non-Sapling transaction - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); try { builder.AddSaplingOutput(uint256(), pk, 12345, {}); } catch (std::runtime_error const & err) { diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index f2cc09903d4..f04d3f2c216 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -1302,7 +1302,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_taddr_to_sapling) pwalletMain->AddToWallet(wtx, true, NULL); // Context that z_sendmany requires - auto builder = TransactionBuilder(consensusParams, nextBlockHeight, pwalletMain); + auto builder = TransactionBuilder(consensusParams, nextBlockHeight, expiryDelta, pwalletMain); mtx = CreateNewContextualCMutableTransaction(consensusParams, nextBlockHeight); std::vector recipients = { SendManyRecipient(zaddr1, 1 * COIN, "ABCD") }; diff --git a/src/utiltest.cpp b/src/utiltest.cpp index 8eb23249f27..e62c5611be3 100644 --- a/src/utiltest.cpp +++ b/src/utiltest.cpp @@ -232,7 +232,7 @@ CWalletTx GetValidSaplingReceive(const Consensus::Params& consensusParams, auto fvk = sk.expsk.full_viewing_key(); auto pa = sk.DefaultAddress(); - auto builder = TransactionBuilder(consensusParams, 1, &keyStore); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keyStore); builder.SetFee(0); builder.AddTransparentInput(COutPoint(), scriptPubKey, value); builder.AddSaplingOutput(fvk.ovk, pa, value, {}); diff --git a/src/wallet/gtest/test_wallet.cpp b/src/wallet/gtest/test_wallet.cpp index 9af4aa0609a..6d07bee388e 100644 --- a/src/wallet/gtest/test_wallet.cpp +++ b/src/wallet/gtest/test_wallet.cpp @@ -379,7 +379,7 @@ TEST(WalletTests, SetSaplingNoteAddrsInCWalletTx) { ASSERT_TRUE(nf); uint256 nullifier = nf.get(); - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); builder.AddSaplingSpend(expsk, note, anchor, witness); builder.AddSaplingOutput(fvk.ovk, pk, 50000, {}); builder.SetFee(0); @@ -506,7 +506,7 @@ TEST(WalletTests, FindMySaplingNotes) { auto testNote = GetTestSaplingNote(pa, 50000); // Generate transaction - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSaplingOutput(fvk.ovk, pa, 25000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -638,7 +638,7 @@ TEST(WalletTests, GetConflictedSaplingNotes) { auto witness = saplingTree.witness(); // Generate tx to create output note B - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); builder.AddSaplingSpend(expsk, note, anchor, witness); builder.AddSaplingOutput(fvk.ovk, pk, 35000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -692,13 +692,13 @@ TEST(WalletTests, GetConflictedSaplingNotes) { anchor = saplingTree.root(); // Create transaction to spend note B - auto builder2 = TransactionBuilder(consensusParams, 2); + auto builder2 = TransactionBuilder(consensusParams, 2, expiryDelta); builder2.AddSaplingSpend(expsk, note2, anchor, spend_note_witness); builder2.AddSaplingOutput(fvk.ovk, pk, 20000, {}); auto tx2 = builder2.Build().GetTxOrThrow(); // Create conflicting transaction which also spends note B - auto builder3 = TransactionBuilder(consensusParams, 2); + auto builder3 = TransactionBuilder(consensusParams, 2, expiryDelta); builder3.AddSaplingSpend(expsk, note2, anchor, spend_note_witness); builder3.AddSaplingOutput(fvk.ovk, pk, 19999, {}); auto tx3 = builder3.Build().GetTxOrThrow(); @@ -785,7 +785,7 @@ TEST(WalletTests, SaplingNullifierIsSpent) { auto testNote = GetTestSaplingNote(pa, 50000); // Generate transaction - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSaplingOutput(fvk.ovk, pa, 25000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -868,7 +868,7 @@ TEST(WalletTests, NavigateFromSaplingNullifierToNote) { auto testNote = GetTestSaplingNote(pa, 50000); // Generate transaction - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSaplingOutput(fvk.ovk, pa, 25000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -996,7 +996,7 @@ TEST(WalletTests, SpentSaplingNoteIsFromMe) { auto witness = saplingTree.witness(); // Generate transaction, which sends funds to note B - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); builder.AddSaplingSpend(expsk, note, anchor, witness); builder.AddSaplingOutput(fvk.ovk, pk, 25000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -1066,7 +1066,7 @@ TEST(WalletTests, SpentSaplingNoteIsFromMe) { anchor = saplingTree.root(); // Create transaction to spend note B - auto builder2 = TransactionBuilder(consensusParams, 2); + auto builder2 = TransactionBuilder(consensusParams, 2, expiryDelta); builder2.AddSaplingSpend(expsk, note2, anchor, spend_note_witness); builder2.AddSaplingOutput(fvk.ovk, pk, 12500, {}); auto tx2 = builder2.Build().GetTxOrThrow(); @@ -1771,7 +1771,7 @@ TEST(WalletTests, UpdatedSaplingNoteData) { auto testNote = GetTestSaplingNote(pa, 50000); // Generate transaction - auto builder = TransactionBuilder(consensusParams, 1); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSaplingOutput(fvk.ovk, pa2, 25000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -1912,7 +1912,7 @@ TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) { // Generate shielding tx from transparent to Sapling // 0.0005 t-ZEC in, 0.0004 z-ZEC out, 0.0001 t-ZEC fee - auto builder = TransactionBuilder(consensusParams, 1, &keystore); + auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 50000); builder.AddSaplingOutput(fvk.ovk, pk, 40000, {}); auto tx1 = builder.Build().GetTxOrThrow(); @@ -1967,7 +1967,7 @@ TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) { // Create a Sapling-only transaction // 0.0004 z-ZEC in, 0.00025 z-ZEC out, 0.0001 t-ZEC fee, 0.00005 z-ZEC change - auto builder2 = TransactionBuilder(consensusParams, 2); + auto builder2 = TransactionBuilder(consensusParams, 2, expiryDelta); builder2.AddSaplingSpend(expsk, note, anchor, witness); builder2.AddSaplingOutput(fvk.ovk, pk, 25000, {}); auto tx2 = builder2.Build().GetTxOrThrow(); From 14c0be6f27bcce3caaafde89d6e145fb54692cd6 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Fri, 10 May 2019 11:41:44 +0100 Subject: [PATCH 071/127] Change expiry delta for migration transactions to 450 blocks. Signed-off-by: Daira Hopwood --- src/wallet/asyncrpcoperation_saplingmigration.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index 5f34eaeee75..db478f27cb3 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -13,6 +13,7 @@ #include "wallet.h" const CAmount FEE = 10000; +const int MIGRATION_EXPIRY_DELTA = 450; AsyncRPCOperation_saplingmigration::AsyncRPCOperation_saplingmigration(int targetHeight) : targetHeight_(targetHeight) {} @@ -98,7 +99,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { CCoinsViewCache coinsView(pcoinsTip); do { CAmount amountToSend = chooseAmount(availableFunds); - auto builder = TransactionBuilder(consensusParams, targetHeight_, expiryDelta, pwalletMain, pzcashParams, + auto builder = TransactionBuilder(consensusParams, targetHeight_, MIGRATION_EXPIRY_DELTA, pwalletMain, pzcashParams, &coinsView, &cs_main); std::vector fromNotes; CAmount fromNoteAmount = 0; @@ -183,7 +184,7 @@ libzcash::SaplingPaymentAddress AsyncRPCOperation_saplingmigration::getMigration libzcash::SaplingExtendedSpendingKey xsk = m_32h_cth.Derive(0 | ZIP32_HARDENED_KEY_LIMIT); libzcash::SaplingPaymentAddress toAddress = xsk.DefaultAddress(); - + // Refactor: this is similar logic as in the visitor HaveSpendingKeyForPaymentAddress and is used elsewhere libzcash::SaplingIncomingViewingKey ivk; libzcash::SaplingFullViewingKey fvk; From e7529049fb825a5d496f84f145c16f2ee30cc993 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Fri, 10 May 2019 13:48:24 +0100 Subject: [PATCH 072/127] Test the expiry height of migration transactions. Signed-off-by: Daira Hopwood --- qa/rpc-tests/sprout_sapling_migration.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py index 3e5a094cf6f..c9ef9797a36 100755 --- a/qa/rpc-tests/sprout_sapling_migration.py +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -102,14 +102,25 @@ def run_migration_test(self, node, sproutAddr, saplingAddr, target_height): self.sync_all() # At 499 % 500 there will be a transaction in the mempool and the note will be locked - assert_equal(1, len(node.getrawmempool()), "mempool size at 499 % 500") + mempool = node.getrawmempool() + print("mempool: {}".format(mempool)) + assert_equal(1, len(mempool), "mempool size at 499 % 500") assert_equal(node.z_getbalance(sproutAddr), Decimal('0')) assert_equal(node.z_getbalance(saplingAddr), Decimal('0')) assert_true(node.z_getbalance(saplingAddr, 0) > Decimal('0'), "Unconfirmed sapling balance at 499 % 500") # Check that unmigrated amount + unfinalized = starting balance - fee status = node.z_getmigrationstatus() + print("status: {}".format(status)) assert_equal(Decimal('9.9999'), Decimal(status['unmigrated_amount']) + Decimal(status['unfinalized_migrated_amount'])) + # The transaction in the mempool should be the one listed in migration_txids, + # and it should expire at the next 450 % 500. + assert_equal(1, len(status['migration_txids'])) + txid = status['migration_txids'][0] + assert_equal(txid, mempool[0]) + tx = node.getrawtransaction(txid, 1) + assert_equal(target_height + 450, tx['expiryheight']) + node.generate(1) self.sync_all() From 9615caa8f9df8a7bae62cc5b1f1cb9d218ae01f7 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Fri, 10 May 2019 16:08:03 +0100 Subject: [PATCH 073/127] Fix cosmetic spacing issue in z_setmigration help. Signed-off-by: Daira Hopwood --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 61dd9e5869b..2fc71bbf445 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3921,7 +3921,7 @@ UniValue z_setmigration(const UniValue& params, bool fHelp) { "Sprout balance, this process may take several weeks. The migration works by sending, up to 5, as many\n" "transactions as possible whenever the blockchain reaches a height equal to 499 modulo 500. The transaction\n" "amounts are picked according to the random distribution specified in ZIP 308. The migration will end once\n" - "the wallet’s Sprout balance is below" + strprintf("%s %s", FormatMoney(CENT), CURRENCY_UNIT) + ".\n" + "the wallet’s Sprout balance is below " + strprintf("%s %s", FormatMoney(CENT), CURRENCY_UNIT) + ".\n" "\nArguments:\n" "1. enabled (boolean, required) 'true' or 'false' to enable or disable respectively.\n" ); From a84125aacd62ef4df79f67b7e8dfd844cb712d1c Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Fri, 10 May 2019 12:58:11 -0600 Subject: [PATCH 074/127] Fix tree depth in comment --- src/gtest/test_merkletree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gtest/test_merkletree.cpp b/src/gtest/test_merkletree.cpp index 23c39c04467..d55cb13179c 100644 --- a/src/gtest/test_merkletree.cpp +++ b/src/gtest/test_merkletree.cpp @@ -249,7 +249,7 @@ TEST(merkletree, EmptyrootsSapling) { } TEST(merkletree, emptyroot) { - // This literal is the depth-20 empty tree root with the bytes reversed to + // This literal is the depth-29 empty tree root with the bytes reversed to // account for the fact that uint256S() loads a big-endian representation of // an integer which converted to little-endian internally. uint256 expected = uint256S("59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7"); @@ -258,7 +258,7 @@ TEST(merkletree, emptyroot) { } TEST(merkletree, EmptyrootSapling) { - // This literal is the depth-20 empty tree root with the bytes reversed to + // This literal is the depth-32 empty tree root with the bytes reversed to // account for the fact that uint256S() loads a big-endian representation of // an integer which converted to little-endian internally. uint256 expected = uint256S("3e49b5f954aa9d3545bc6c37744661eea48d7c34e3000d82b7f0010c30f4c2fb"); From 7470ae8885cc1a5ede41abab3dab4104d9f0ce91 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Thu, 9 May 2019 11:56:37 -0600 Subject: [PATCH 075/127] Do not automatically remove async migration operations and return txids --- qa/rpc-tests/sprout_sapling_migration.py | 2 ++ src/wallet/asyncrpcoperation_saplingmigration.cpp | 15 +++++++++++---- src/wallet/asyncrpcoperation_saplingmigration.h | 2 +- src/wallet/wallet.cpp | 4 ++-- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py index c9ef9797a36..de2c68cc83b 100755 --- a/qa/rpc-tests/sprout_sapling_migration.py +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -87,6 +87,8 @@ def run_migration_test(self, node, sproutAddr, saplingAddr, target_height): assert_equal('saplingmigration', result['method']) assert_equal(target_height, result['target_height']) assert_equal(1, result['result']['num_tx_created']) + assert_equal(1, len(result['result']['migration_txids'])) + assert_true(result['result']['amount_migrated'] > Decimal('0')) assert_equal(0, len(node.getrawmempool()), "mempool size at 495 % 500") diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index db478f27cb3..465e18ee599 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -83,7 +83,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { } // If the remaining amount to be migrated is less than 0.01 ZEC, end the migration. if (availableFunds < CENT) { - setMigrationResult(0, 0); + setMigrationResult(0, 0, std::vector()); return true; } @@ -95,6 +95,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { // Up to the limit of 5, as many transactions are sent as are needed to migrate the remaining funds int numTxCreated = 0; CAmount amountMigrated = 0; + std::vector migrationTxIds; int noteIndex = 0; CCoinsViewCache coinsView(pcoinsTip); do { @@ -132,17 +133,23 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { } pwalletMain->AddPendingSaplingMigrationTx(tx); ++numTxCreated; - amountMigrated += amountToSend; + amountMigrated += amountToSend - FEE; + migrationTxIds.push_back(tx.GetHash().ToString()); } while (numTxCreated < 5 && availableFunds > CENT); - setMigrationResult(numTxCreated, amountMigrated); + setMigrationResult(numTxCreated, amountMigrated, migrationTxIds); return true; } -void AsyncRPCOperation_saplingmigration::setMigrationResult(int numTxCreated, CAmount amountMigrated) { +void AsyncRPCOperation_saplingmigration::setMigrationResult(int numTxCreated, const CAmount& amountMigrated, const std::vector& migrationTxIds) { UniValue res(UniValue::VOBJ); res.push_back(Pair("num_tx_created", numTxCreated)); res.push_back(Pair("amount_migrated", FormatMoney(amountMigrated))); + UniValue txIds(UniValue::VARR); + for (const std::string& txId : migrationTxIds) { + txIds.push_back(txId); + } + res.push_back(Pair("migration_txids", txIds)); set_result(res); } diff --git a/src/wallet/asyncrpcoperation_saplingmigration.h b/src/wallet/asyncrpcoperation_saplingmigration.h index 64319968f92..6e0c452f932 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.h +++ b/src/wallet/asyncrpcoperation_saplingmigration.h @@ -29,7 +29,7 @@ class AsyncRPCOperation_saplingmigration : public AsyncRPCOperation bool main_impl(); - void setMigrationResult(int numTxCreated, CAmount amountMigrated); + void setMigrationResult(int numTxCreated, const CAmount& amountMigrated, const std::vector& migrationTxIds); CAmount chooseAmount(const CAmount& availableFunds); }; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index bde0eb9d119..23030257a89 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -610,7 +610,7 @@ void CWallet::RunSaplingMigration(int blockHeight) { // height N-5 if (blockHeight % 500 == 495) { std::shared_ptr q = getAsyncRPCQueue(); - std::shared_ptr lastOperation = q->popOperationForId(saplingMigrationOperationId); + std::shared_ptr lastOperation = q->getOperationForId(saplingMigrationOperationId); if (lastOperation != nullptr) { lastOperation->cancel(); } @@ -620,7 +620,7 @@ void CWallet::RunSaplingMigration(int blockHeight) { q->addOperation(operation); } else if (blockHeight % 500 == 499) { std::shared_ptr q = getAsyncRPCQueue(); - std::shared_ptr lastOperation = q->popOperationForId(saplingMigrationOperationId); + std::shared_ptr lastOperation = q->getOperationForId(saplingMigrationOperationId); if (lastOperation != nullptr) { lastOperation->cancel(); } From 58348c79b3415435bbceceafaef64d78563a15f8 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Thu, 9 May 2019 15:13:10 -0600 Subject: [PATCH 076/127] Add logging for Sprout to Sapling migration transaction generation --- .../asyncrpcoperation_saplingmigration.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index 465e18ee599..21eddcfecd3 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -68,6 +68,7 @@ void AsyncRPCOperation_saplingmigration::main() { } bool AsyncRPCOperation_saplingmigration::main_impl() { + LogPrint("zrpcunsafe", "Beginning AsyncRPCOperation_saplingmigration. id=%s\n", getId()); std::vector sproutEntries; std::vector saplingEntries; { @@ -83,6 +84,8 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { } // If the remaining amount to be migrated is less than 0.01 ZEC, end the migration. if (availableFunds < CENT) { + LogPrint("zrpcunsafe", "%s: Available Sprout balance (%s) less than required minimum (%s). Stopping.\n", + getId(), FormatMoney(availableFunds), FormatMoney(CENT)); setMigrationResult(0, 0, std::vector()); return true; } @@ -102,6 +105,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { CAmount amountToSend = chooseAmount(availableFunds); auto builder = TransactionBuilder(consensusParams, targetHeight_, MIGRATION_EXPIRY_DELTA, pwalletMain, pzcashParams, &coinsView, &cs_main); + LogPrint("zrpcunsafe", "%s: Beginning creating transaction with Sapling output amount=%s\n", getId(), amountToSend - FEE); std::vector fromNotes; CAmount fromNoteAmount = 0; while (fromNoteAmount < amountToSend) { @@ -111,6 +115,15 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { } availableFunds -= fromNoteAmount; for (const CSproutNotePlaintextEntry& sproutEntry : fromNotes) { + std::string data(sproutEntry.plaintext.memo().begin(), sproutEntry.plaintext.memo().end()); + LogPrint("zrpcunsafe", "%s: Adding Sprout note input (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n", + getId(), + sproutEntry.jsop.hash.ToString().substr(0, 10), + sproutEntry.jsop.js, + int(sproutEntry.jsop.n), // uint8_t + FormatMoney(sproutEntry.plaintext.value()), + HexStr(data).substr(0, 10) + ); libzcash::SproutNote sproutNote = sproutEntry.plaintext.note(sproutEntry.address); libzcash::SproutSpendingKey sproutSk; pwalletMain->GetSproutSpendingKey(sproutEntry.address, sproutSk); @@ -129,14 +142,17 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { builder.AddSaplingOutput(ovkForShieldingFromTaddr(seed), migrationDestAddress, amountToSend - FEE); CTransaction tx = builder.Build().GetTxOrThrow(); if (isCancelled()) { + LogPrint("zrpcunsafe", "%s: Canceled. Stopping.\n"); break; } pwalletMain->AddPendingSaplingMigrationTx(tx); + LogPrint("zrpcunsafe", "%s: Added pending migration transaction with txid=%s\n", getId(), tx.GetHash().ToString()); ++numTxCreated; amountMigrated += amountToSend - FEE; migrationTxIds.push_back(tx.GetHash().ToString()); } while (numTxCreated < 5 && availableFunds > CENT); + LogPrint("zrpcunsafe", "%s: Created %d transactions with total Sapling output amount=%s\n", getId(), numTxCreated, FormatMoney(amountMigrated)); setMigrationResult(numTxCreated, amountMigrated, migrationTxIds); return true; } From 23d9826ef9d1425ded14b54575beffe5b4ab57e1 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Fri, 10 May 2019 13:29:50 -0600 Subject: [PATCH 077/127] Fix LogPrint statements --- qa/rpc-tests/sprout_sapling_migration.py | 5 +++-- src/wallet/asyncrpcoperation_mergetoaddress.cpp | 2 +- src/wallet/asyncrpcoperation_saplingmigration.cpp | 8 ++++---- src/wallet/asyncrpcoperation_sendmany.cpp | 4 ++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/qa/rpc-tests/sprout_sapling_migration.py b/qa/rpc-tests/sprout_sapling_migration.py index de2c68cc83b..03e1ccde77c 100755 --- a/qa/rpc-tests/sprout_sapling_migration.py +++ b/qa/rpc-tests/sprout_sapling_migration.py @@ -45,9 +45,10 @@ def setup_nodes(self): # Add migration parameters to nodes[0] extra_args[0] = extra_args[0] + [ '-migration', - '-migrationdestaddress=' + SAPLING_ADDR + '-migrationdestaddress=' + SAPLING_ADDR, + '-debug=zrpcunsafe' ] - assert_equal(4, len(extra_args[0])) + assert_equal(5, len(extra_args[0])) assert_equal(2, len(extra_args[1])) return start_nodes(4, self.options.tmpdir, extra_args) diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index b3870e6029d..0e5dd34096e 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -645,7 +645,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl() wtxHeight = mapBlockIndex[wtx.hashBlock]->nHeight; wtxDepth = wtx.GetDepthInMainChain(); } - LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n", + LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, jsoutindex=%d, amount=%s, height=%d, confirmations=%d)\n", getId(), jso.hash.ToString().substr(0, 10), jso.js, diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index 21eddcfecd3..8e1dda6159a 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -68,7 +68,7 @@ void AsyncRPCOperation_saplingmigration::main() { } bool AsyncRPCOperation_saplingmigration::main_impl() { - LogPrint("zrpcunsafe", "Beginning AsyncRPCOperation_saplingmigration. id=%s\n", getId()); + LogPrint("zrpcunsafe", "%s: Beginning AsyncRPCOperation_saplingmigration.\n", getId()); std::vector sproutEntries; std::vector saplingEntries; { @@ -105,7 +105,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { CAmount amountToSend = chooseAmount(availableFunds); auto builder = TransactionBuilder(consensusParams, targetHeight_, MIGRATION_EXPIRY_DELTA, pwalletMain, pzcashParams, &coinsView, &cs_main); - LogPrint("zrpcunsafe", "%s: Beginning creating transaction with Sapling output amount=%s\n", getId(), amountToSend - FEE); + LogPrint("zrpcunsafe", "%s: Beginning creating transaction with Sapling output amount=%s\n", getId(), FormatMoney(amountToSend - FEE)); std::vector fromNotes; CAmount fromNoteAmount = 0; while (fromNoteAmount < amountToSend) { @@ -116,7 +116,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { availableFunds -= fromNoteAmount; for (const CSproutNotePlaintextEntry& sproutEntry : fromNotes) { std::string data(sproutEntry.plaintext.memo().begin(), sproutEntry.plaintext.memo().end()); - LogPrint("zrpcunsafe", "%s: Adding Sprout note input (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n", + LogPrint("zrpcunsafe", "%s: Adding Sprout note input (txid=%s, vjoinsplit=%d, jsoutindex=%d, amount=%s, memo=%s)\n", getId(), sproutEntry.jsop.hash.ToString().substr(0, 10), sproutEntry.jsop.js, @@ -142,7 +142,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { builder.AddSaplingOutput(ovkForShieldingFromTaddr(seed), migrationDestAddress, amountToSend - FEE); CTransaction tx = builder.Build().GetTxOrThrow(); if (isCancelled()) { - LogPrint("zrpcunsafe", "%s: Canceled. Stopping.\n"); + LogPrint("zrpcunsafe", "%s: Canceled. Stopping.\n", getId()); break; } pwalletMain->AddPendingSaplingMigrationTx(tx); diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index e30c0748373..93ec59b539f 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -784,7 +784,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { wtxHeight = mapBlockIndex[wtx.hashBlock]->nHeight; wtxDepth = wtx.GetDepthInMainChain(); } - LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n", + LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, jsoutindex=%d, amount=%s, height=%d, confirmations=%d)\n", getId(), jso.hash.ToString().substr(0, 10), jso.js, @@ -1048,7 +1048,7 @@ bool AsyncRPCOperation_sendmany::find_unspent_notes() { for (CSproutNotePlaintextEntry & entry : sproutEntries) { z_sprout_inputs_.push_back(SendManyInputJSOP(entry.jsop, entry.plaintext.note(boost::get(frompaymentaddress_)), CAmount(entry.plaintext.value()))); std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end()); - LogPrint("zrpcunsafe", "%s: found unspent Sprout note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n", + LogPrint("zrpcunsafe", "%s: found unspent Sprout note (txid=%s, vjoinsplit=%d, jsoutindex=%d, amount=%s, memo=%s)\n", getId(), entry.jsop.hash.ToString().substr(0, 10), entry.jsop.js, From 5d1da630a24f06da5a798aa62629d03b83dc793c Mon Sep 17 00:00:00 2001 From: zebambam Date: Tue, 14 May 2019 07:51:08 -0700 Subject: [PATCH 078/127] Fixes #4013, added BitcoinABC as a disclosure partner --- responsible_disclosure.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/responsible_disclosure.md b/responsible_disclosure.md index 1f3c9401bba..718cf42d9c0 100644 --- a/responsible_disclosure.md +++ b/responsible_disclosure.md @@ -51,8 +51,9 @@ We have set up agreements with the following neighboring projects to share vulne Specifically, we have agreed to engage in responsible disclosures for security issues affecting Zcash technology with the following contacts: -- security@horizen.com via PGP -- ca333@komodoplatform.com via PGP +- Horizen security@horizen.com via PGP +- Komodo ca333@komodoplatform.com via PGP +- BitcoinABC https://github.com/Bitcoin-ABC/bitcoin-abc/blob/master/DISCLOSURE_POLICY.md ## Deviations from the Standard From 8c82f8f72f7a9ad690ea1d4ab6efb86067d831f3 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 14 May 2019 11:24:19 -0600 Subject: [PATCH 079/127] Notable changes for v2.0.5-2 --- doc/release-notes.md | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/doc/release-notes.md b/doc/release-notes.md index a29094b5174..1b6f60c88f5 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,3 +4,51 @@ release-notes at release time) Notable changes =============== +Sprout to Sapling Migration Tool +-------------------------------- +This release includes the addition of a tool that will enable users to migrate +shielded funds from the Sprout pool to the Sapling pool while minimizing +information leakage. + +The migration can be enabled using the RPC `z_setmigration` or by including +`migration=1` in the `zcash.conf` file. Unless otherwise specified funds will be +migrated to the wallet's default Sapling address; it is also possible to set the +receiving Sapling address using the `migrationdestaddress=` option in +`zcash.conf`. + +See [ZIP308](https://github.com/zcash/zips/blob/master/zip-0308.rst) for full details. + +Sprout to Sapling Migration Tool Fixes +-------------------------------------- +The 2.0.5-1 and 2.0.5-2 releases include fixes to the Sprout to Sapling +Migration Tool found in testing. For a complete list see the [2.0.5 milestone](https://github.com/zcash/zcash/milestone/79?closed=1) + +New consensus rule: Reject blocks that violate turnstile +-------------------------------------------------------- +In the 2.0.4 release the consensus rules were changed on testnet to enforce a +consensus rule which marks blocks as invalid if they would lead to a turnstile +violation in the Sprout or Shielded value pools. +**This release enforces the consensus rule change on mainnet** + +The motivations and deployment details can be found in the accompanying +[ZIP draft](https://github.com/zcash/zips/pull/210) and +[PR 3968](https://github.com/zcash/zcash/pull/3968). + +Developers can use a new experimental feature `-developersetpoolsizezero` to test +Sprout and Sapling turnstile violations. See [PR 3964](https://github.com/zcash/zcash/pull/3964) for more details. + +64-bit ARMv8 support +-------------------- +Added ARMv8 (AArch64) support. This enables users to build zcash on even more +devices. + +For information on how to build see the [User Guide](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#build) + +Users on the Zcash forum have reported successes with both the Pine64 Rock64Pro +and Odroid C2 which contain 4GB and 2GB of RAM respectively. + +Just released, the Odroid N2 looks like a great solution with 4GB of RAM. The +newly released Jetson Nano Developer Kit from Nvidia (also 4GB of RAM) is also +worth a look. The NanoPC-T3 Plus is another option but for the simplest/best +experience choose a board with 4GB of RAM. Just make sure before purchase that +the CPU supports the 64-bit ARMv8 architecture. From 44905b21da1a88209fa033fe81954303fce38dbd Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Tue, 14 May 2019 13:31:25 -0600 Subject: [PATCH 080/127] Release notes wording and punctuation --- doc/release-notes.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 1b6f60c88f5..560a5e43761 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -21,14 +21,16 @@ See [ZIP308](https://github.com/zcash/zips/blob/master/zip-0308.rst) for full de Sprout to Sapling Migration Tool Fixes -------------------------------------- The 2.0.5-1 and 2.0.5-2 releases include fixes to the Sprout to Sapling -Migration Tool found in testing. For a complete list see the [2.0.5 milestone](https://github.com/zcash/zcash/milestone/79?closed=1) +Migration Tool found in testing. + +For a complete list of changes in 2.0.5, 2.0.5-1 and 2.0.5-2, see the [2.0.5 milestone](https://github.com/zcash/zcash/milestone/79?closed=1). New consensus rule: Reject blocks that violate turnstile -------------------------------------------------------- In the 2.0.4 release the consensus rules were changed on testnet to enforce a consensus rule which marks blocks as invalid if they would lead to a turnstile violation in the Sprout or Shielded value pools. -**This release enforces the consensus rule change on mainnet** +**This release enforces the consensus rule change on mainnet.** The motivations and deployment details can be found in the accompanying [ZIP draft](https://github.com/zcash/zips/pull/210) and @@ -42,7 +44,7 @@ Sprout and Sapling turnstile violations. See [PR 3964](https://github.com/zcash/ Added ARMv8 (AArch64) support. This enables users to build zcash on even more devices. -For information on how to build see the [User Guide](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#build) +For information on how to build see the [User Guide](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#build). Users on the Zcash forum have reported successes with both the Pine64 Rock64Pro and Odroid C2 which contain 4GB and 2GB of RAM respectively. From c34d253fa67bac1479123e6af20c084340a31e2d Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 15 May 2019 09:49:44 -0600 Subject: [PATCH 081/127] make-release.py: Versioning changes for 2.0.5-2. --- README.md | 2 +- configure.ac | 2 +- contrib/gitian-descriptors/gitian-linux.yml | 2 +- src/clientversion.h | 2 +- src/deprecation.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5d6c06c6104..7d02cf0d349 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Zcash 2.0.5-1 +Zcash 2.0.5-2 =========== diff --git a/configure.ac b/configure.ac index 0dc14ccbe9a..a78439eda44 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 2) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 5) -define(_CLIENT_VERSION_BUILD, 51) +define(_CLIENT_VERSION_BUILD, 52) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index f0e40fd4082..edc714f1074 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "zcash-2.0.5-1" +name: "zcash-2.0.5-2" enable_cache: true distro: "debian" suites: diff --git a/src/clientversion.h b/src/clientversion.h index 5e6b49a9d5d..2455c56b48e 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -18,7 +18,7 @@ #define CLIENT_VERSION_MAJOR 2 #define CLIENT_VERSION_MINOR 0 #define CLIENT_VERSION_REVISION 5 -#define CLIENT_VERSION_BUILD 51 +#define CLIENT_VERSION_BUILD 52 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/deprecation.h b/src/deprecation.h index a0dd736bcef..13c752c426e 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -8,7 +8,7 @@ // Deprecation policy: // * Shut down 16 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 529250; +static const int APPROX_RELEASE_HEIGHT = 533500; static const int WEEKS_UNTIL_DEPRECATION = 16; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); From 3fc90655bf8bb4a189c1c64225efe8f6d2e4eb9f Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 15 May 2019 09:56:01 -0600 Subject: [PATCH 082/127] make-release.py: Updated manpages for 2.0.5-2. --- doc/man/zcash-cli.1 | 6 +++--- doc/man/zcash-tx.1 | 6 +++--- doc/man/zcashd.1 | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index a13df414a5a..c2f1b3447ff 100644 --- a/doc/man/zcash-cli.1 +++ b/doc/man/zcash-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASH-CLI "1" "May 2019" "zcash-cli v2.0.5-1" "User Commands" +.TH ZCASH-CLI "1" "May 2019" "zcash-cli v2.0.5-2" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v2.0.5-1 +zcash-cli \- manual page for zcash-cli v2.0.5-2 .SH DESCRIPTION -Zcash RPC client version v2.0.5\-1 +Zcash RPC client version v2.0.5\-2 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . diff --git a/doc/man/zcash-tx.1 b/doc/man/zcash-tx.1 index fc0810578fd..effac79bb36 100644 --- a/doc/man/zcash-tx.1 +++ b/doc/man/zcash-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASH-TX "1" "May 2019" "zcash-tx v2.0.5-1" "User Commands" +.TH ZCASH-TX "1" "May 2019" "zcash-tx v2.0.5-2" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v2.0.5-1 +zcash-tx \- manual page for zcash-tx v2.0.5-2 .SH DESCRIPTION -Zcash zcash\-tx utility version v2.0.5\-1 +Zcash zcash\-tx utility version v2.0.5\-2 .SS "Usage:" .TP zcash\-tx [options] [commands] diff --git a/doc/man/zcashd.1 b/doc/man/zcashd.1 index f47b35710ee..73d50333e6d 100644 --- a/doc/man/zcashd.1 +++ b/doc/man/zcashd.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASHD "1" "May 2019" "zcashd v2.0.5-1" "User Commands" +.TH ZCASHD "1" "May 2019" "zcashd v2.0.5-2" "User Commands" .SH NAME -zcashd \- manual page for zcashd v2.0.5-1 +zcashd \- manual page for zcashd v2.0.5-2 .SH DESCRIPTION -Zcash Daemon version v2.0.5\-1 +Zcash Daemon version v2.0.5\-2 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . From c75fb97d3af5f0721d82289ab59a89ba2d05e4e7 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 15 May 2019 09:56:01 -0600 Subject: [PATCH 083/127] make-release.py: Updated release notes and changelog for 2.0.5-2. --- contrib/debian/changelog | 6 ++ doc/authors.md | 6 +- doc/release-notes.md | 50 -------------- doc/release-notes/release-notes-2.0.5-2.md | 77 ++++++++++++++++++++++ 4 files changed, 86 insertions(+), 53 deletions(-) create mode 100644 doc/release-notes/release-notes-2.0.5-2.md diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 3814043023d..f48b6e7b6df 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +zcash (2.0.5+2) stable; urgency=medium + + * 2.0.5-2 release. + + -- Electric Coin Company Wed, 15 May 2019 09:56:01 -0600 + zcash (2.0.5+1) stable; urgency=medium * 2.0.5-1 release. diff --git a/doc/authors.md b/doc/authors.md index c196c34a06e..72d50f96b7e 100644 --- a/doc/authors.md +++ b/doc/authors.md @@ -2,9 +2,9 @@ Zcash Contributors ================== Jack Grigg (863) -Simon Liu (448) +Simon Liu (450) Sean Bowe (278) -Daira Hopwood (110) +Daira Hopwood (115) Eirik Ogilvie-Wigley (102) Jay Graber (89) Wladimir J. van der Laan (81) @@ -12,8 +12,8 @@ Taylor Hornby (73) Jonas Schnelli (62) Nathan Wilcox (56) Pieter Wuille (54) +Eirik0 (43) Kevin Gallagher (38) -Eirik0 (36) Cory Fields (35) mdr0id (22) Larry Ruane (22) diff --git a/doc/release-notes.md b/doc/release-notes.md index 560a5e43761..a29094b5174 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,53 +4,3 @@ release-notes at release time) Notable changes =============== -Sprout to Sapling Migration Tool --------------------------------- -This release includes the addition of a tool that will enable users to migrate -shielded funds from the Sprout pool to the Sapling pool while minimizing -information leakage. - -The migration can be enabled using the RPC `z_setmigration` or by including -`migration=1` in the `zcash.conf` file. Unless otherwise specified funds will be -migrated to the wallet's default Sapling address; it is also possible to set the -receiving Sapling address using the `migrationdestaddress=` option in -`zcash.conf`. - -See [ZIP308](https://github.com/zcash/zips/blob/master/zip-0308.rst) for full details. - -Sprout to Sapling Migration Tool Fixes --------------------------------------- -The 2.0.5-1 and 2.0.5-2 releases include fixes to the Sprout to Sapling -Migration Tool found in testing. - -For a complete list of changes in 2.0.5, 2.0.5-1 and 2.0.5-2, see the [2.0.5 milestone](https://github.com/zcash/zcash/milestone/79?closed=1). - -New consensus rule: Reject blocks that violate turnstile --------------------------------------------------------- -In the 2.0.4 release the consensus rules were changed on testnet to enforce a -consensus rule which marks blocks as invalid if they would lead to a turnstile -violation in the Sprout or Shielded value pools. -**This release enforces the consensus rule change on mainnet.** - -The motivations and deployment details can be found in the accompanying -[ZIP draft](https://github.com/zcash/zips/pull/210) and -[PR 3968](https://github.com/zcash/zcash/pull/3968). - -Developers can use a new experimental feature `-developersetpoolsizezero` to test -Sprout and Sapling turnstile violations. See [PR 3964](https://github.com/zcash/zcash/pull/3964) for more details. - -64-bit ARMv8 support --------------------- -Added ARMv8 (AArch64) support. This enables users to build zcash on even more -devices. - -For information on how to build see the [User Guide](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#build). - -Users on the Zcash forum have reported successes with both the Pine64 Rock64Pro -and Odroid C2 which contain 4GB and 2GB of RAM respectively. - -Just released, the Odroid N2 looks like a great solution with 4GB of RAM. The -newly released Jetson Nano Developer Kit from Nvidia (also 4GB of RAM) is also -worth a look. The NanoPC-T3 Plus is another option but for the simplest/best -experience choose a board with 4GB of RAM. Just make sure before purchase that -the CPU supports the 64-bit ARMv8 architecture. diff --git a/doc/release-notes/release-notes-2.0.5-2.md b/doc/release-notes/release-notes-2.0.5-2.md new file mode 100644 index 00000000000..6e65ee083fc --- /dev/null +++ b/doc/release-notes/release-notes-2.0.5-2.md @@ -0,0 +1,77 @@ +Notable changes +=============== + +Sprout to Sapling Migration Tool +-------------------------------- +This release includes the addition of a tool that will enable users to migrate +shielded funds from the Sprout pool to the Sapling pool while minimizing +information leakage. + +The migration can be enabled using the RPC `z_setmigration` or by including +`migration=1` in the `zcash.conf` file. Unless otherwise specified funds will be +migrated to the wallet's default Sapling address; it is also possible to set the +receiving Sapling address using the `migrationdestaddress=` option in +`zcash.conf`. + +See [ZIP308](https://github.com/zcash/zips/blob/master/zip-0308.rst) for full details. + +Sprout to Sapling Migration Tool Fixes +-------------------------------------- +The 2.0.5-1 and 2.0.5-2 releases include fixes to the Sprout to Sapling +Migration Tool found in testing. + +For a complete list of changes in 2.0.5, 2.0.5-1 and 2.0.5-2, see the [2.0.5 milestone](https://github.com/zcash/zcash/milestone/79?closed=1). + +New consensus rule: Reject blocks that violate turnstile +-------------------------------------------------------- +In the 2.0.4 release the consensus rules were changed on testnet to enforce a +consensus rule which marks blocks as invalid if they would lead to a turnstile +violation in the Sprout or Shielded value pools. +**This release enforces the consensus rule change on mainnet.** + +The motivations and deployment details can be found in the accompanying +[ZIP draft](https://github.com/zcash/zips/pull/210) and +[PR 3968](https://github.com/zcash/zcash/pull/3968). + +Developers can use a new experimental feature `-developersetpoolsizezero` to test +Sprout and Sapling turnstile violations. See [PR 3964](https://github.com/zcash/zcash/pull/3964) for more details. + +64-bit ARMv8 support +-------------------- +Added ARMv8 (AArch64) support. This enables users to build zcash on even more +devices. + +For information on how to build see the [User Guide](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#build). + +Users on the Zcash forum have reported successes with both the Pine64 Rock64Pro +and Odroid C2 which contain 4GB and 2GB of RAM respectively. + +Just released, the Odroid N2 looks like a great solution with 4GB of RAM. The +newly released Jetson Nano Developer Kit from Nvidia (also 4GB of RAM) is also +worth a look. The NanoPC-T3 Plus is another option but for the simplest/best +experience choose a board with 4GB of RAM. Just make sure before purchase that +the CPU supports the 64-bit ARMv8 architecture. + +Changelog +========= + +Daira Hopwood (5): + Generalize TransactionBuilder and CreateNewContextualCMutableTransaction to allow choosing the expiry delta. + Repair calls to TransactionBuilder from tests. + Change expiry delta for migration transactions to 450 blocks. + Test the expiry height of migration transactions. + Fix cosmetic spacing issue in z_setmigration help. + +Eirik0 (7): + Do not automatically remove async migration operations and return txids + Add logging for Sprout to Sapling migration transaction generation + Fix LogPrint statements + Notable changes for v2.0.5-2 + Release notes wording and punctuation + make-release.py: Versioning changes for 2.0.5-2. + make-release.py: Updated manpages for 2.0.5-2. + +Simon Liu (2): + Remove unused specifier from format string. + Don't allow migration when node is syncing at launch or after waking up. + From 408a1229521593adc7a678d0fd6b02b66de2d854 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 15 May 2019 10:45:25 -0600 Subject: [PATCH 084/127] Update ZIP reference --- doc/release-notes/release-notes-2.0.5-2.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/release-notes/release-notes-2.0.5-2.md b/doc/release-notes/release-notes-2.0.5-2.md index 6e65ee083fc..8d7dc947afd 100644 --- a/doc/release-notes/release-notes-2.0.5-2.md +++ b/doc/release-notes/release-notes-2.0.5-2.md @@ -29,8 +29,8 @@ consensus rule which marks blocks as invalid if they would lead to a turnstile violation in the Sprout or Shielded value pools. **This release enforces the consensus rule change on mainnet.** -The motivations and deployment details can be found in the accompanying -[ZIP draft](https://github.com/zcash/zips/pull/210) and +The motivations and deployment details can be found in +[ZIP209](https://github.com/zcash/zips/blob/master/zip-0209.rst) and [PR 3968](https://github.com/zcash/zcash/pull/3968). Developers can use a new experimental feature `-developersetpoolsizezero` to test From 831611edd36efa4dc0e3fc311e4df069827514a7 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 15 May 2019 11:06:37 -0700 Subject: [PATCH 085/127] Fix typo and clean up help message for RPC z_getmigrationstatus. --- src/wallet/rpcwallet.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2fc71bbf445..d9836a95820 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3937,8 +3937,7 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { throw runtime_error( "z_getmigrationstatus\n" "Returns information about the status of the Sprout to Sapling migration.\n" - "In the result a transactions is defined as finalized if and only if it has\n" - "at least ten confirmations.\n" + "A transaction is defined as finalized if it has at least ten confirmations.\n" "Note: It is possible that manually created transactions involving this wallet\n" "will be included in the result.\n" "\nResult:\n" From be04f76034c77f8dd634c51c402f00a7ea83d959 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 22 May 2019 15:47:05 -0600 Subject: [PATCH 086/127] Update author aliases --- zcutil/release-notes.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/zcutil/release-notes.py b/zcutil/release-notes.py index 6e0f277df32..4446e988f2d 100755 --- a/zcutil/release-notes.py +++ b/zcutil/release-notes.py @@ -20,14 +20,18 @@ ] author_aliases = { - 'Simon': 'Simon Liu', - 'bitcartel': 'Simon Liu', - 'EthanHeilman': 'Ethan Heilman', 'Ariel': 'Ariel Gabizon', 'arielgabizon': 'Ariel Gabizon', + 'bitcartel': 'Simon Liu', 'Charlie OKeefe': 'Charlie O\'Keefe', + 'Duke Leto': 'Jonathan \"Duke\" Leto', + 'Eirik0': 'Eirik Ogilvie-Wigley', + 'EthanHeilman': 'Ethan Heilman', + 'mdr0id': 'Marshall Gaucher', + 'paveljanik': 'Pavel Janik', + 'Simon': 'Simon Liu', 'str4d': 'Jack Grigg', - 'Duke Leto': 'Jonathan \"Duke\" Leto' + 'zebambam': 'Benjamin Winston' } def apply_author_aliases(name): From bb0a3e1cb54dac6ceca687034cc7021588bc199b Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Wed, 22 May 2019 16:01:50 -0600 Subject: [PATCH 087/127] Remove old mergetoaddress RPC test --- qa/rpc-tests/wallet_mergetoaddress.py | 368 -------------------------- 1 file changed, 368 deletions(-) delete mode 100755 qa/rpc-tests/wallet_mergetoaddress.py diff --git a/qa/rpc-tests/wallet_mergetoaddress.py b/qa/rpc-tests/wallet_mergetoaddress.py deleted file mode 100755 index 3c2f84aa85f..00000000000 --- a/qa/rpc-tests/wallet_mergetoaddress.py +++ /dev/null @@ -1,368 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2017 The Zcash developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x." - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.authproxy import JSONRPCException -from test_framework.util import assert_equal, initialize_chain_clean, \ - start_node, connect_nodes_bi, sync_blocks, sync_mempools, \ - wait_and_assert_operationid_status - -from decimal import Decimal - -class WalletMergeToAddressTest (BitcoinTestFramework): - - def setup_chain(self): - print("Initializing test directory "+self.options.tmpdir) - initialize_chain_clean(self.options.tmpdir, 4) - - def setup_network(self, split=False): - args = ['-debug=zrpcunsafe', '-experimentalfeatures', '-zmergetoaddress'] - self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, args)) - self.nodes.append(start_node(1, self.options.tmpdir, args)) - args2 = ['-debug=zrpcunsafe', '-experimentalfeatures', '-zmergetoaddress', '-mempooltxinputlimit=7'] - self.nodes.append(start_node(2, self.options.tmpdir, args2)) - connect_nodes_bi(self.nodes,0,1) - connect_nodes_bi(self.nodes,1,2) - connect_nodes_bi(self.nodes,0,2) - self.is_network_split=False - self.sync_all() - - def run_test (self): - print "Mining blocks..." - - self.nodes[0].generate(1) - do_not_shield_taddr = self.nodes[0].getnewaddress() - - self.nodes[0].generate(4) - walletinfo = self.nodes[0].getwalletinfo() - assert_equal(walletinfo['immature_balance'], 50) - assert_equal(walletinfo['balance'], 0) - self.sync_all() - self.nodes[2].generate(1) - self.nodes[2].getnewaddress() - self.nodes[2].generate(1) - self.nodes[2].getnewaddress() - self.nodes[2].generate(1) - self.sync_all() - self.nodes[1].generate(101) - self.sync_all() - assert_equal(self.nodes[0].getbalance(), 50) - assert_equal(self.nodes[1].getbalance(), 10) - assert_equal(self.nodes[2].getbalance(), 30) - - # Shield the coinbase - myzaddr = self.nodes[0].z_getnewaddress('sprout') - result = self.nodes[0].z_shieldcoinbase("*", myzaddr, 0) - wait_and_assert_operationid_status(self.nodes[0], result['opid']) - self.sync_all() - self.nodes[1].generate(1) - self.sync_all() - - # Prepare some UTXOs and notes for merging - mytaddr = self.nodes[0].getnewaddress() - mytaddr2 = self.nodes[0].getnewaddress() - mytaddr3 = self.nodes[0].getnewaddress() - result = self.nodes[0].z_sendmany(myzaddr, [ - {'address': do_not_shield_taddr, 'amount': 10}, - {'address': mytaddr, 'amount': 10}, - {'address': mytaddr2, 'amount': 10}, - {'address': mytaddr3, 'amount': 10}, - ], 1, 0) - wait_and_assert_operationid_status(self.nodes[0], result) - self.sync_all() - self.nodes[1].generate(1) - self.sync_all() - - # Merging will fail because from arguments need to be in an array - try: - self.nodes[0].z_mergetoaddress("*", myzaddr) - assert(False) - except JSONRPCException,e: - errorString = e.error['message'] - assert_equal("JSON value is not an array as expected" in errorString, True) - - # Merging will fail when trying to spend from watch-only address - self.nodes[2].importaddress(mytaddr) - try: - self.nodes[2].z_mergetoaddress([mytaddr], myzaddr) - assert(False) - except JSONRPCException,e: - errorString = e.error['message'] - assert_equal("Could not find any funds to merge" in errorString, True) - - # Merging will fail because fee is negative - try: - self.nodes[0].z_mergetoaddress(["*"], myzaddr, -1) - assert(False) - except JSONRPCException,e: - errorString = e.error['message'] - assert_equal("Amount out of range" in errorString, True) - - # Merging will fail because fee is larger than MAX_MONEY - try: - self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('21000000.00000001')) - assert(False) - except JSONRPCException,e: - errorString = e.error['message'] - assert_equal("Amount out of range" in errorString, True) - - # Merging will fail because fee is larger than sum of UTXOs - try: - self.nodes[0].z_mergetoaddress(["*"], myzaddr, 999) - assert(False) - except JSONRPCException,e: - errorString = e.error['message'] - assert_equal("Insufficient funds" in errorString, True) - - # Merging will fail because transparent limit parameter must be at least 0 - try: - self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), -1) - assert(False) - except JSONRPCException,e: - errorString = e.error['message'] - assert_equal("Limit on maximum number of UTXOs cannot be negative" in errorString, True) - - # Merging will fail because transparent limit parameter is absurdly large - try: - self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), 99999999999999) - assert(False) - except JSONRPCException,e: - errorString = e.error['message'] - assert_equal("JSON integer out of range" in errorString, True) - - # Merging will fail because shielded limit parameter must be at least 0 - try: - self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), 50, -1) - assert(False) - except JSONRPCException,e: - errorString = e.error['message'] - assert_equal("Limit on maximum number of notes cannot be negative" in errorString, True) - - # Merging will fail because shielded limit parameter is absurdly large - try: - self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), 50, 99999999999999) - assert(False) - except JSONRPCException,e: - errorString = e.error['message'] - assert_equal("JSON integer out of range" in errorString, True) - - # Merging will fail for this specific case where it would spend a fee and do nothing - try: - self.nodes[0].z_mergetoaddress([mytaddr], mytaddr) - assert(False) - except JSONRPCException,e: - errorString = e.error['message'] - assert_equal("Destination address is also the only source address, and all its funds are already merged" in errorString, True) - - # Merge UTXOs from node 0 of value 30, standard fee of 0.00010000 - result = self.nodes[0].z_mergetoaddress([mytaddr, mytaddr2, mytaddr3], myzaddr) - wait_and_assert_operationid_status(self.nodes[0], result['opid']) - self.sync_all() - self.nodes[1].generate(1) - self.sync_all() - - # Confirm balances and that do_not_shield_taddr containing funds of 10 was left alone - assert_equal(self.nodes[0].getbalance(), 10) - assert_equal(self.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0')) - assert_equal(self.nodes[0].z_getbalance(myzaddr), Decimal('39.99990000')) - assert_equal(self.nodes[1].getbalance(), 40) - assert_equal(self.nodes[2].getbalance(), 30) - - # Shield all notes to another z-addr - myzaddr2 = self.nodes[0].z_getnewaddress('sprout') - result = self.nodes[0].z_mergetoaddress(["ANY_ZADDR"], myzaddr2, 0) - assert_equal(result["mergingUTXOs"], Decimal('0')) - assert_equal(result["remainingUTXOs"], Decimal('0')) - assert_equal(result["mergingNotes"], Decimal('2')) - assert_equal(result["remainingNotes"], Decimal('0')) - wait_and_assert_operationid_status(self.nodes[0], result['opid']) - self.sync_all() - blockhash = self.nodes[1].generate(1) - self.sync_all() - - assert_equal(len(self.nodes[0].getblock(blockhash[0])['tx']), 2) - assert_equal(self.nodes[0].z_getbalance(myzaddr), 0) - assert_equal(self.nodes[0].z_getbalance(myzaddr2), Decimal('39.99990000')) - - # Shield coinbase UTXOs from any node 2 taddr, and set fee to 0 - result = self.nodes[2].z_shieldcoinbase("*", myzaddr, 0) - wait_and_assert_operationid_status(self.nodes[2], result['opid']) - self.sync_all() - self.nodes[1].generate(1) - self.sync_all() - - assert_equal(self.nodes[0].getbalance(), 10) - assert_equal(self.nodes[0].z_getbalance(myzaddr), Decimal('30')) - assert_equal(self.nodes[0].z_getbalance(myzaddr2), Decimal('39.99990000')) - assert_equal(self.nodes[1].getbalance(), 60) - assert_equal(self.nodes[2].getbalance(), 0) - - # Merge all notes from node 0 into a node 0 taddr, and set fee to 0 - result = self.nodes[0].z_mergetoaddress(["ANY_ZADDR"], mytaddr, 0) - wait_and_assert_operationid_status(self.nodes[0], result['opid']) - self.sync_all() - self.nodes[1].generate(1) - self.sync_all() - - assert_equal(self.nodes[0].getbalance(), Decimal('79.99990000')) - assert_equal(self.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0')) - assert_equal(self.nodes[0].z_getbalance(mytaddr), Decimal('69.99990000')) - assert_equal(self.nodes[0].z_getbalance(myzaddr), 0) - assert_equal(self.nodes[0].z_getbalance(myzaddr2), 0) - assert_equal(self.nodes[1].getbalance(), 70) - assert_equal(self.nodes[2].getbalance(), 0) - - # Merge all node 0 UTXOs together into a node 1 taddr, and set fee to 0 - self.nodes[1].getnewaddress() # Ensure we have an empty address - n1taddr = self.nodes[1].getnewaddress() - result = self.nodes[0].z_mergetoaddress(["ANY_TADDR"], n1taddr, 0) - wait_and_assert_operationid_status(self.nodes[0], result['opid']) - self.sync_all() - self.nodes[1].generate(1) - self.sync_all() - - assert_equal(self.nodes[0].getbalance(), 0) - assert_equal(self.nodes[0].z_getbalance(do_not_shield_taddr), 0) - assert_equal(self.nodes[0].z_getbalance(mytaddr), 0) - assert_equal(self.nodes[0].z_getbalance(myzaddr), 0) - assert_equal(self.nodes[1].getbalance(), Decimal('159.99990000')) - assert_equal(self.nodes[1].z_getbalance(n1taddr), Decimal('79.99990000')) - assert_equal(self.nodes[2].getbalance(), 0) - - # Generate 800 regular UTXOs on node 0, and 20 regular UTXOs on node 2 - mytaddr = self.nodes[0].getnewaddress() - n2taddr = self.nodes[2].getnewaddress() - self.nodes[1].generate(1000) - self.sync_all() - for i in range(800): - self.nodes[1].sendtoaddress(mytaddr, 1) - for i in range(20): - self.nodes[1].sendtoaddress(n2taddr, 1) - self.nodes[1].generate(1) - self.sync_all() - - # Merging the 800 UTXOs will occur over two transactions, since max tx size is 100,000 bytes. - # We don't verify mergingTransparentValue as UTXOs are not selected in any specific order, so value can change on each test run. - # We set an unrealistically high limit parameter of 99999, to verify that max tx size will constrain the number of UTXOs. - result = self.nodes[0].z_mergetoaddress([mytaddr], myzaddr, 0, 99999) - assert_equal(result["mergingUTXOs"], Decimal('662')) - assert_equal(result["remainingUTXOs"], Decimal('138')) - assert_equal(result["mergingNotes"], Decimal('0')) - assert_equal(result["mergingShieldedValue"], Decimal('0')) - assert_equal(result["remainingNotes"], Decimal('0')) - assert_equal(result["remainingShieldedValue"], Decimal('0')) - remainingTransparentValue = result["remainingTransparentValue"] - opid1 = result['opid'] - - # Verify that UTXOs are locked (not available for selection) by queuing up another merging operation - result = self.nodes[0].z_mergetoaddress([mytaddr], myzaddr, 0, 0) - assert_equal(result["mergingUTXOs"], Decimal('138')) - assert_equal(result["mergingTransparentValue"], Decimal(remainingTransparentValue)) - assert_equal(result["remainingUTXOs"], Decimal('0')) - assert_equal(result["remainingTransparentValue"], Decimal('0')) - assert_equal(result["mergingNotes"], Decimal('0')) - assert_equal(result["mergingShieldedValue"], Decimal('0')) - assert_equal(result["remainingNotes"], Decimal('0')) - assert_equal(result["remainingShieldedValue"], Decimal('0')) - opid2 = result['opid'] - - # wait for both aysnc operations to complete - wait_and_assert_operationid_status(self.nodes[0], opid1) - wait_and_assert_operationid_status(self.nodes[0], opid2) - - # sync_all() invokes sync_mempool() but node 2's mempool limit will cause tx1 and tx2 to be rejected. - # So instead, we sync on blocks and mempool for node 0 and node 1, and after a new block is generated - # which mines tx1 and tx2, all nodes will have an empty mempool which can then be synced. - sync_blocks(self.nodes[:2]) - sync_mempools(self.nodes[:2]) - # Generate enough blocks to ensure all transactions are mined - while self.nodes[1].getmempoolinfo()['size'] > 0: - self.nodes[1].generate(1) - self.sync_all() - - # Verify maximum number of UTXOs which node 2 can shield is limited by option -mempooltxinputlimit - # This option is used when the limit parameter is set to 0. - result = self.nodes[2].z_mergetoaddress([n2taddr], myzaddr, Decimal('0.0001'), 0) - assert_equal(result["mergingUTXOs"], Decimal('7')) - assert_equal(result["remainingUTXOs"], Decimal('13')) - assert_equal(result["mergingNotes"], Decimal('0')) - assert_equal(result["remainingNotes"], Decimal('0')) - wait_and_assert_operationid_status(self.nodes[2], result['opid']) - self.sync_all() - self.nodes[1].generate(1) - self.sync_all() - - # Verify maximum number of UTXOs which node 0 can shield is set by default limit parameter of 50 - mytaddr = self.nodes[0].getnewaddress() - for i in range(100): - self.nodes[1].sendtoaddress(mytaddr, 1) - self.nodes[1].generate(1) - self.sync_all() - result = self.nodes[0].z_mergetoaddress([mytaddr], myzaddr, Decimal('0.0001')) - assert_equal(result["mergingUTXOs"], Decimal('50')) - assert_equal(result["remainingUTXOs"], Decimal('50')) - assert_equal(result["mergingNotes"], Decimal('0')) - # Remaining notes are only counted if we are trying to merge any notes - assert_equal(result["remainingNotes"], Decimal('0')) - wait_and_assert_operationid_status(self.nodes[0], result['opid']) - - # Verify maximum number of UTXOs which node 0 can shield can be set by the limit parameter - result = self.nodes[0].z_mergetoaddress([mytaddr], myzaddr, Decimal('0.0001'), 33) - assert_equal(result["mergingUTXOs"], Decimal('33')) - assert_equal(result["remainingUTXOs"], Decimal('17')) - assert_equal(result["mergingNotes"], Decimal('0')) - # Remaining notes are only counted if we are trying to merge any notes - assert_equal(result["remainingNotes"], Decimal('0')) - wait_and_assert_operationid_status(self.nodes[0], result['opid']) - # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit - sync_blocks(self.nodes[:2]) - sync_mempools(self.nodes[:2]) - self.nodes[1].generate(1) - self.sync_all() - - # Verify maximum number of notes which node 0 can shield can be set by the limit parameter - # Also check that we can set off a second merge before the first one is complete - - # myzaddr has 5 notes at this point - result1 = self.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0.0001, 50, 2) - result2 = self.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0.0001, 50, 2) - - # First merge should select from all notes - assert_equal(result1["mergingUTXOs"], Decimal('0')) - # Remaining UTXOs are only counted if we are trying to merge any UTXOs - assert_equal(result1["remainingUTXOs"], Decimal('0')) - assert_equal(result1["mergingNotes"], Decimal('2')) - assert_equal(result1["remainingNotes"], Decimal('3')) - - # Second merge should ignore locked notes - assert_equal(result2["mergingUTXOs"], Decimal('0')) - assert_equal(result2["remainingUTXOs"], Decimal('0')) - assert_equal(result2["mergingNotes"], Decimal('2')) - assert_equal(result2["remainingNotes"], Decimal('1')) - wait_and_assert_operationid_status(self.nodes[0], result1['opid']) - wait_and_assert_operationid_status(self.nodes[0], result2['opid']) - - self.sync_all() - self.nodes[1].generate(1) - self.sync_all() - - # Shield both UTXOs and notes to a z-addr - result = self.nodes[0].z_mergetoaddress(["*"], myzaddr, 0, 10, 2) - assert_equal(result["mergingUTXOs"], Decimal('10')) - assert_equal(result["remainingUTXOs"], Decimal('7')) - assert_equal(result["mergingNotes"], Decimal('2')) - assert_equal(result["remainingNotes"], Decimal('1')) - wait_and_assert_operationid_status(self.nodes[0], result['opid']) - # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit - sync_blocks(self.nodes[:2]) - sync_mempools(self.nodes[:2]) - self.nodes[1].generate(1) - self.sync_all() - -if __name__ == '__main__': - WalletMergeToAddressTest().main() From a630f503491effb3a4fa7e42a5b14cb50e6f5d03 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Thu, 23 May 2019 09:24:46 -0600 Subject: [PATCH 088/127] Replace CSproutNotePlaintextEntry with SproutNoteEntry to match Sapling --- .../asyncrpcoperation_saplingmigration.cpp | 19 ++++++------ src/wallet/asyncrpcoperation_sendmany.cpp | 10 +++---- src/wallet/gtest/test_wallet.cpp | 2 +- src/wallet/rpcwallet.cpp | 30 +++++++++---------- src/wallet/wallet.cpp | 7 +++-- src/wallet/wallet.h | 11 +++---- 6 files changed, 40 insertions(+), 39 deletions(-) diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index 8e1dda6159a..d99bc539fe0 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -69,7 +69,7 @@ void AsyncRPCOperation_saplingmigration::main() { bool AsyncRPCOperation_saplingmigration::main_impl() { LogPrint("zrpcunsafe", "%s: Beginning AsyncRPCOperation_saplingmigration.\n", getId()); - std::vector sproutEntries; + std::vector sproutEntries; std::vector saplingEntries; { LOCK2(cs_main, pwalletMain->cs_wallet); @@ -79,8 +79,8 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, "", 11); } CAmount availableFunds = 0; - for (const CSproutNotePlaintextEntry& sproutEntry : sproutEntries) { - availableFunds += sproutEntry.plaintext.value(); + for (const SproutNoteEntry& sproutEntry : sproutEntries) { + availableFunds += sproutEntry.note.value(); } // If the remaining amount to be migrated is less than 0.01 ZEC, end the migration. if (availableFunds < CENT) { @@ -106,25 +106,24 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { auto builder = TransactionBuilder(consensusParams, targetHeight_, MIGRATION_EXPIRY_DELTA, pwalletMain, pzcashParams, &coinsView, &cs_main); LogPrint("zrpcunsafe", "%s: Beginning creating transaction with Sapling output amount=%s\n", getId(), FormatMoney(amountToSend - FEE)); - std::vector fromNotes; + std::vector fromNotes; CAmount fromNoteAmount = 0; while (fromNoteAmount < amountToSend) { auto sproutEntry = sproutEntries[noteIndex++]; fromNotes.push_back(sproutEntry); - fromNoteAmount += sproutEntry.plaintext.value(); + fromNoteAmount += sproutEntry.note.value(); } availableFunds -= fromNoteAmount; - for (const CSproutNotePlaintextEntry& sproutEntry : fromNotes) { - std::string data(sproutEntry.plaintext.memo().begin(), sproutEntry.plaintext.memo().end()); + for (const SproutNoteEntry& sproutEntry : fromNotes) { + std::string data(sproutEntry.memo.begin(), sproutEntry.memo.end()); LogPrint("zrpcunsafe", "%s: Adding Sprout note input (txid=%s, vjoinsplit=%d, jsoutindex=%d, amount=%s, memo=%s)\n", getId(), sproutEntry.jsop.hash.ToString().substr(0, 10), sproutEntry.jsop.js, int(sproutEntry.jsop.n), // uint8_t - FormatMoney(sproutEntry.plaintext.value()), + FormatMoney(sproutEntry.note.value()), HexStr(data).substr(0, 10) ); - libzcash::SproutNote sproutNote = sproutEntry.plaintext.note(sproutEntry.address); libzcash::SproutSpendingKey sproutSk; pwalletMain->GetSproutSpendingKey(sproutEntry.address, sproutSk); std::vector vOutPoints = {sproutEntry.jsop}; @@ -134,7 +133,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { uint256 inputAnchor; std::vector> vInputWitnesses; pwalletMain->GetSproutNoteWitnesses(vOutPoints, vInputWitnesses, inputAnchor); - builder.AddSproutInput(sproutSk, sproutNote, vInputWitnesses[0].get()); + builder.AddSproutInput(sproutSk, sproutEntry.note, vInputWitnesses[0].get()); } // The amount chosen *includes* the 0.0001 ZEC fee for this transaction, i.e. // the value of the Sapling output will be 0.0001 ZEC less. diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 93ec59b539f..9538a2736e6 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -1029,7 +1029,7 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) { bool AsyncRPCOperation_sendmany::find_unspent_notes() { - std::vector sproutEntries; + std::vector sproutEntries; std::vector saplingEntries; { LOCK2(cs_main, pwalletMain->cs_wallet); @@ -1045,15 +1045,15 @@ bool AsyncRPCOperation_sendmany::find_unspent_notes() { saplingEntries.clear(); } - for (CSproutNotePlaintextEntry & entry : sproutEntries) { - z_sprout_inputs_.push_back(SendManyInputJSOP(entry.jsop, entry.plaintext.note(boost::get(frompaymentaddress_)), CAmount(entry.plaintext.value()))); - std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end()); + for (SproutNoteEntry & entry : sproutEntries) { + z_sprout_inputs_.push_back(SendManyInputJSOP(entry.jsop, entry.note, CAmount(entry.note.value()))); + std::string data(entry.memo.begin(), entry.memo.end()); LogPrint("zrpcunsafe", "%s: found unspent Sprout note (txid=%s, vjoinsplit=%d, jsoutindex=%d, amount=%s, memo=%s)\n", getId(), entry.jsop.hash.ToString().substr(0, 10), entry.jsop.js, int(entry.jsop.n), // uint8_t - FormatMoney(entry.plaintext.value()), + FormatMoney(entry.note.value()), HexStr(data).substr(0, 10) ); } diff --git a/src/wallet/gtest/test_wallet.cpp b/src/wallet/gtest/test_wallet.cpp index 6d07bee388e..029753a9483 100644 --- a/src/wallet/gtest/test_wallet.cpp +++ b/src/wallet/gtest/test_wallet.cpp @@ -188,7 +188,7 @@ TEST(WalletTests, FindUnspentSproutNotes) { EXPECT_FALSE(wallet.IsSproutSpent(nullifier)); // We currently have an unspent and unconfirmed note in the wallet (depth of -1) - std::vector sproutEntries; + std::vector sproutEntries; std::vector saplingEntries; wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0); EXPECT_EQ(0, sproutEntries.size()); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2fc71bbf445..0fbda374a69 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2567,7 +2567,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) UniValue results(UniValue::VARR); if (zaddrs.size() > 0) { - std::vector sproutEntries; + std::vector sproutEntries; std::vector saplingEntries; pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false); std::set> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs); @@ -2581,8 +2581,8 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) bool hasSproutSpendingKey = pwalletMain->HaveSproutSpendingKey(boost::get(entry.address)); obj.push_back(Pair("spendable", hasSproutSpendingKey)); obj.push_back(Pair("address", EncodePaymentAddress(entry.address))); - obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value())))); - std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end()); + obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value())))); + std::string data(entry.memo.begin(), entry.memo.end()); obj.push_back(Pair("memo", HexStr(data))); if (hasSproutSpendingKey) { obj.push_back(Pair("change", pwalletMain->IsNoteSproutChange(nullifierSet, entry.address, entry.jsop))); @@ -3291,12 +3291,12 @@ CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ign CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) { CAmount balance = 0; - std::vector sproutEntries; + std::vector sproutEntries; std::vector saplingEntries; LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, address, minDepth, true, ignoreUnspendable); for (auto & entry : sproutEntries) { - balance += CAmount(entry.plaintext.value()); + balance += CAmount(entry.note.value()); } for (auto & entry : saplingEntries) { balance += CAmount(entry.note.value()); @@ -3356,7 +3356,7 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) } UniValue result(UniValue::VARR); - std::vector sproutEntries; + std::vector sproutEntries; std::vector saplingEntries; pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, fromaddress, nMinDepth, false, false); @@ -3367,11 +3367,11 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) } if (boost::get(&zaddr) != nullptr) { - for (CSproutNotePlaintextEntry & entry : sproutEntries) { + for (SproutNoteEntry & entry : sproutEntries) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid", entry.jsop.hash.ToString())); - obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value())))); - std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end()); + obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value())))); + std::string data(entry.memo.begin(), entry.memo.end()); obj.push_back(Pair("memo", HexStr(data))); obj.push_back(Pair("jsindex", entry.jsop.js)); obj.push_back(Pair("jsoutindex", entry.jsop.n)); @@ -3965,7 +3965,7 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { // account failed transactions, that were not mined within their expiration // height. { - std::vector sproutEntries; + std::vector sproutEntries; std::vector saplingEntries; std::set noFilter; // Here we are looking for any and all Sprout notes for which we have the spending key, including those @@ -3973,7 +3973,7 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, noFilter, 0, INT_MAX, true, true, false); CAmount unmigratedAmount = 0; for (const auto& sproutEntry : sproutEntries) { - unmigratedAmount += sproutEntry.plaintext.value(); + unmigratedAmount += sproutEntry.note.value(); } migrationStatus.push_back(Pair("unmigrated_amount", FormatMoney(unmigratedAmount))); } @@ -4525,7 +4525,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) if (useAnySprout || useAnySapling || zaddrs.size() > 0) { // Get available notes - std::vector sproutEntries; + std::vector sproutEntries; std::vector saplingEntries; pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs); @@ -4547,9 +4547,9 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) } // Find unspent notes and update estimated size - for (const CSproutNotePlaintextEntry& entry : sproutEntries) { + for (const SproutNoteEntry& entry : sproutEntries) { noteCounter++; - CAmount nValue = entry.plaintext.value(); + CAmount nValue = entry.note.value(); if (!maxedOutNotesFlag) { // If we haven't added any notes yet and the merge is to a @@ -4564,7 +4564,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) auto zaddr = entry.address; SproutSpendingKey zkey; pwalletMain->GetSproutSpendingKey(zaddr, zkey); - sproutNoteInputs.emplace_back(entry.jsop, entry.plaintext.note(zaddr), nValue, zkey); + sproutNoteInputs.emplace_back(entry.jsop, entry.note, nValue, zkey); mergedNoteValue += nValue; } } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 23030257a89..2a0e47b3a38 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4483,7 +4483,7 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee) * These notes are decrypted and added to the output parameter vector, outEntries. */ void CWallet::GetFilteredNotes( - std::vector& sproutEntries, + std::vector& sproutEntries, std::vector& saplingEntries, std::string address, int minDepth, @@ -4505,7 +4505,7 @@ void CWallet::GetFilteredNotes( * These notes are decrypted and added to the output parameter vector, outEntries. */ void CWallet::GetFilteredNotes( - std::vector& sproutEntries, + std::vector& sproutEntries, std::vector& saplingEntries, std::set& filterAddresses, int minDepth, @@ -4572,7 +4572,8 @@ void CWallet::GetFilteredNotes( hSig, (unsigned char) j); - sproutEntries.push_back(CSproutNotePlaintextEntry{jsop, pa, plaintext, wtx.GetDepthInMainChain()}); + sproutEntries.push_back(SproutNoteEntry { + jsop, pa, plaintext.note(pa), plaintext.memo(), wtx.GetDepthInMainChain() }); } catch (const note_decryption_failed &err) { // Couldn't decrypt with this spending key diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index fa137011199..6486f54c3e3 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -312,12 +312,13 @@ class SaplingNoteData typedef std::map mapSproutNoteData_t; typedef std::map mapSaplingNoteData_t; -/** Decrypted note, its location in a transaction, and number of confirmations. */ -struct CSproutNotePlaintextEntry +/** Sprout note, its location in a transaction, and number of confirmations. */ +struct SproutNoteEntry { JSOutPoint jsop; libzcash::SproutPaymentAddress address; - libzcash::SproutNotePlaintext plaintext; + libzcash::SproutNote note; + std::array memo; int confirmations; }; @@ -1301,7 +1302,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool LoadCryptedHDSeed(const uint256& seedFp, const std::vector& seed); /* Find notes filtered by payment address, min depth, ability to spend */ - void GetFilteredNotes(std::vector& sproutEntries, + void GetFilteredNotes(std::vector& sproutEntries, std::vector& saplingEntries, std::string address, int minDepth=1, @@ -1310,7 +1311,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface /* Find notes filtered by payment addresses, min depth, max depth, if they are spent, if a spending key is required, and if they are locked */ - void GetFilteredNotes(std::vector& sproutEntries, + void GetFilteredNotes(std::vector& sproutEntries, std::vector& saplingEntries, std::set& filterAddresses, int minDepth=1, From 9a529fd2176e6bb189b36cfd7fc7a09cab18ed92 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Sat, 8 Aug 2015 18:18:41 +0200 Subject: [PATCH 089/127] Add some const declarations where they are appropriate. Declare some arguments of functions as "const" pointers where they are not meant to be modified. --- src/main.cpp | 12 ++++++------ src/main.h | 8 ++++---- src/miner.cpp | 4 ++-- src/miner.h | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ea105227427..8806542cd97 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1677,7 +1677,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock // CBlock and CBlockIndex // -bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart) +bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart) { // Open history file to append CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); @@ -3093,7 +3093,7 @@ static int64_t nTimePostConnect = 0; * corresponding to pindexNew, to bypass loading it again from disk. * You probably want to call mempool.removeWithoutBranchId after this, with cs_main held. */ -bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) { +bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, const CBlock *pblock) { assert(pindexNew->pprev == chainActive.Tip()); // Read block from disk. int64_t nTime1 = GetTimeMicros(); @@ -3236,7 +3236,7 @@ static void PruneBlockIndexCandidates() { * Try to make some progress towards making pindexMostWork the active block. * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. */ -static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, CBlock *pblock) { +static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, const CBlock *pblock) { AssertLockHeld(cs_main); bool fInvalidFound = false; const CBlockIndex *pindexOldTip = chainActive.Tip(); @@ -3339,7 +3339,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo * or an activated best chain. pblock is either NULL or a pointer to a block * that is already loaded (to avoid loading it again from disk). */ -bool ActivateBestChain(CValidationState &state, CBlock *pblock) { +bool ActivateBestChain(CValidationState &state, const CBlock *pblock) { CBlockIndex *pindexNewTip = NULL; CBlockIndex *pindexMostWork = NULL; const CChainParams& chainParams = Params(); @@ -3938,7 +3938,7 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc return true; } -bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) +bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) { const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); @@ -4017,7 +4017,7 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned } -bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) +bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) { // Preliminary checks auto verifier = libzcash::ProofVerifier::Disabled(); diff --git a/src/main.h b/src/main.h index b78c1d831e9..b5f82cecad2 100644 --- a/src/main.h +++ b/src/main.h @@ -204,7 +204,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals); * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location. * @return True if state.IsValid() */ -bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp); +bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ @@ -241,7 +241,7 @@ std::string GetWarnings(const std::string& strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false); /** Find the best known block, and make it the tip of the block chain */ -bool ActivateBestChain(CValidationState &state, CBlock *pblock = NULL); +bool ActivateBestChain(CValidationState &state, const CBlock *pblock = NULL); CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); /** @@ -461,7 +461,7 @@ class CScriptCheck /** Functions for disk access for blocks */ -bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart); +bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart); bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos); bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); @@ -491,7 +491,7 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * - The only caller of AcceptBlock verifies JoinSplit proofs elsewhere. * If dbp is non-NULL, the file is known to already reside on disk */ -bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp); +bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp); bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL); diff --git a/src/miner.cpp b/src/miner.cpp index f83acfe4921..a5258f39d88 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -477,7 +477,7 @@ void GetScriptForMinerAddress(boost::shared_ptr &script) script->reserveScript = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; } -void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce) +void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce) { // Update nExtraNonce static uint256 hashPrevBlock; @@ -496,7 +496,7 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& pblock->hashMerkleRoot = pblock->BuildMerkleTree(); } -static bool ProcessBlockFound(CBlock* pblock, const CChainParams& chainparams) +static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams) { LogPrintf("%s\n", pblock->ToString()); LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue)); diff --git a/src/miner.h b/src/miner.h index 07098905445..1d1ebaf9b4d 100644 --- a/src/miner.h +++ b/src/miner.h @@ -30,7 +30,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); /** Get script for -mineraddress */ void GetScriptForMinerAddress(boost::shared_ptr &script); /** Modify the extranonce in a block */ -void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); +void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce); /** Run the miner threads */ void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams); #endif From cea06a4fd3a5ce5b18631c46fc451de663adb4e8 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 26 Jan 2018 23:31:44 +0000 Subject: [PATCH 090/127] Move Equihash parameters into consensus params --- src/chainparams.cpp | 24 ++++++++++++------------ src/chainparams.h | 4 ---- src/consensus/params.h | 2 ++ src/main.cpp | 4 ++-- src/miner.cpp | 4 ++-- src/pow.cpp | 6 +++--- src/pow.h | 2 +- src/rpc/mining.cpp | 4 ++-- src/test/miner_tests.cpp | 4 ++-- src/zcbenchmarks.cpp | 9 +++++---- 10 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 5f8dba4d2b2..01b65ddbe45 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -89,6 +89,10 @@ class CMainParams : public CChainParams { consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 4000; + const size_t N = 200, K = 9; + BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); + consensus.nEquihashN = N; + consensus.nEquihashK = K; consensus.powLimit = uint256S("0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowAveragingWindow = 17; assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); @@ -123,10 +127,6 @@ class CMainParams : public CChainParams { vAlertPubKey = ParseHex("04b7ecf0baa90495ceb4e4090f6b2fd37eec1e9c85fac68a487f3ce11589692e4a317479316ee814e066638e1db54e37a10689b70286e6315b1087b6615d179264"); nDefaultPort = 8233; nPruneAfterHeight = 100000; - const size_t N = 200, K = 9; - BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); - nEquihashN = N; - nEquihashK = K; genesis = CreateGenesisBlock( 1477641360, @@ -280,6 +280,10 @@ class CTestNetParams : public CChainParams { consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityRejectBlockOutdated = 75; consensus.nMajorityWindow = 400; + const size_t N = 200, K = 9; + BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); + consensus.nEquihashN = N; + consensus.nEquihashK = K; consensus.powLimit = uint256S("07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowAveragingWindow = 17; assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); @@ -311,10 +315,6 @@ class CTestNetParams : public CChainParams { vAlertPubKey = ParseHex("044e7a1553392325c871c5ace5d6ad73501c66f4c185d6b0453cf45dec5a1322e705c672ac1a27ef7cdaf588c10effdf50ed5f95f85f2f54a5f6159fca394ed0c6"); nDefaultPort = 18233; nPruneAfterHeight = 1000; - const size_t N = 200, K = 9; - BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); - nEquihashN = N; - nEquihashK = K; genesis = CreateGenesisBlock( 1477648033, @@ -412,6 +412,10 @@ class CRegTestParams : public CChainParams { consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; + const size_t N = 48, K = 5; + BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); + consensus.nEquihashN = N; + consensus.nEquihashK = K; consensus.powLimit = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); consensus.nPowAveragingWindow = 17; assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); @@ -444,10 +448,6 @@ class CRegTestParams : public CChainParams { pchMessageStart[3] = 0x5f; nDefaultPort = 18344; nPruneAfterHeight = 1000; - const size_t N = 48, K = 5; - BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); - nEquihashN = N; - nEquihashK = K; genesis = CreateGenesisBlock( 1296688602, diff --git a/src/chainparams.h b/src/chainparams.h index ce5c1d6a179..17ebe9d31a6 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -83,8 +83,6 @@ class CChainParams /** Policy: Filter transactions that do not match well-defined patterns */ bool RequireStandard() const { return fRequireStandard; } int64_t PruneAfterHeight() const { return nPruneAfterHeight; } - unsigned int EquihashN() const { return nEquihashN; } - unsigned int EquihashK() const { return nEquihashK; } std::string CurrencyUnits() const { return strCurrencyUnits; } uint32_t BIP44CoinType() const { return bip44CoinType; } /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */ @@ -113,8 +111,6 @@ class CChainParams std::vector vAlertPubKey; int nDefaultPort = 0; uint64_t nPruneAfterHeight = 0; - unsigned int nEquihashN = 0; - unsigned int nEquihashK = 0; std::vector vSeeds; std::vector base58Prefixes[MAX_BASE58_TYPES]; std::string bech32HRPs[MAX_BECH32_TYPES]; diff --git a/src/consensus/params.h b/src/consensus/params.h index 77f30bf4e69..9cd3a84617d 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -93,6 +93,8 @@ struct Params { int nMajorityWindow; NetworkUpgrade vUpgrades[MAX_NETWORK_UPGRADES]; /** Proof of work parameters */ + unsigned int nEquihashN = 0; + unsigned int nEquihashK = 0; uint256 powLimit; boost::optional nPowAllowMinDifficultyBlocksAfterHeight; int64_t nPowAveragingWindow; diff --git a/src/main.cpp b/src/main.cpp index 8806542cd97..7c374108639 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1716,7 +1716,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) } // Check the header - if (!(CheckEquihashSolution(&block, Params()) && + if (!(CheckEquihashSolution(&block, Params().GetConsensus()) && CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus()))) return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); @@ -3717,7 +3717,7 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f REJECT_INVALID, "version-too-low"); // Check Equihash solution is valid - if (fCheckPOW && !CheckEquihashSolution(&block, Params())) + if (fCheckPOW && !CheckEquihashSolution(&block, Params().GetConsensus())) return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"), REJECT_INVALID, "invalid-solution"); diff --git a/src/miner.cpp b/src/miner.cpp index a5258f39d88..1ca5e264fd9 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -533,8 +533,8 @@ void static BitcoinMiner(const CChainParams& chainparams) boost::shared_ptr coinbaseScript; GetMainSignals().ScriptForMining(coinbaseScript); - unsigned int n = chainparams.EquihashN(); - unsigned int k = chainparams.EquihashK(); + unsigned int n = chainparams.GetConsensus().nEquihashN; + unsigned int k = chainparams.GetConsensus().nEquihashK; std::string solver = GetArg("-equihashsolver", "default"); assert(solver == "tromp" || solver == "default"); diff --git a/src/pow.cpp b/src/pow.cpp index 743df08ee30..ec0410acca2 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -91,10 +91,10 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, return bnNew.GetCompact(); } -bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& params) +bool CheckEquihashSolution(const CBlockHeader *pblock, const Consensus::Params& params) { - unsigned int n = params.EquihashN(); - unsigned int k = params.EquihashK(); + unsigned int n = params.nEquihashN; + unsigned int k = params.nEquihashK; // Hash state crypto_generichash_blake2b_state state; diff --git a/src/pow.h b/src/pow.h index 30d0f5e63b7..e3cf822d8dd 100644 --- a/src/pow.h +++ b/src/pow.h @@ -22,7 +22,7 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, const Consensus::Params&); /** Check whether the Equihash solution in a block header is valid */ -bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams&); +bool CheckEquihashSolution(const CBlockHeader *pblock, const Consensus::Params&); /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 73963da1994..0287df80483 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -195,8 +195,8 @@ UniValue generate(const UniValue& params, bool fHelp) } unsigned int nExtraNonce = 0; UniValue blockHashes(UniValue::VARR); - unsigned int n = Params().EquihashN(); - unsigned int k = Params().EquihashK(); + unsigned int n = Params().GetConsensus().nEquihashN; + unsigned int k = Params().GetConsensus().nEquihashK; while (nHeight < nHeightEnd) { std::unique_ptr pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 3f6a0af77ea..263ff841722 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -182,8 +182,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) /* { arith_uint256 try_nonce(0); - unsigned int n = Params().EquihashN(); - unsigned int k = Params().EquihashK(); + unsigned int n = Params().GetConsensus().nEquihashN; + unsigned int k = Params().GetConsensus().nEquihashK; // Hash state crypto_generichash_blake2b_state eh_state; diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index d91e36d730a..d257ce8ece9 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -172,8 +172,9 @@ double benchmark_solve_equihash() CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << I; - unsigned int n = Params(CBaseChainParams::MAIN).EquihashN(); - unsigned int k = Params(CBaseChainParams::MAIN).EquihashK(); + auto params = Params(CBaseChainParams::MAIN).GetConsensus(); + unsigned int n = params.nEquihashN; + unsigned int k = params.nEquihashK; crypto_generichash_blake2b_state eh_state; EhInitialiseState(n, k, eh_state); crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size()); @@ -217,11 +218,11 @@ std::vector benchmark_solve_equihash_threaded(int nThreads) double benchmark_verify_equihash() { CChainParams params = Params(CBaseChainParams::MAIN); - CBlock genesis = Params(CBaseChainParams::MAIN).GenesisBlock(); + CBlock genesis = params.GenesisBlock(); CBlockHeader genesis_header = genesis.GetBlockHeader(); struct timeval tv_start; timer_start(tv_start); - CheckEquihashSolution(&genesis_header, params); + CheckEquihashSolution(&genesis_header, params.GetConsensus()); return timer_stop(tv_start); } From 71cf6ba98bf80a68b4bc435de124a7fa672055a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Fri, 17 Apr 2015 14:19:21 +0200 Subject: [PATCH 091/127] Globals: Explicit Consensus::Params arg for main: -CheckBlockIndex -DisconnectTip -GetTransaction -InvalidateBlock -ProcessGetData -ReadBlockFromDisk --- src/amqp/amqppublishnotifier.cpp | 4 +- src/main.cpp | 73 +++++++++++++++++--------------- src/main.h | 12 +++--- src/rest.cpp | 5 ++- src/rpc/blockchain.cpp | 4 +- src/rpc/rawtransaction.cpp | 6 +-- src/wallet/rpcdisclosure.cpp | 4 +- src/wallet/wallet.cpp | 6 +-- src/zmq/zmqpublishnotifier.cpp | 4 +- 9 files changed, 63 insertions(+), 55 deletions(-) diff --git a/src/amqp/amqppublishnotifier.cpp b/src/amqp/amqppublishnotifier.cpp index 589eb151fb6..2704d94c2c5 100644 --- a/src/amqp/amqppublishnotifier.cpp +++ b/src/amqp/amqppublishnotifier.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "amqppublishnotifier.h" +#include "chainparams.h" #include "main.h" #include "util.h" @@ -152,11 +153,12 @@ bool AMQPPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { LogPrint("amqp", "amqp: Publish rawblock %s\n", pindex->GetBlockHash().GetHex()); + const Consensus::Params& consensusParams = Params().GetConsensus(); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); { LOCK(cs_main); CBlock block; - if(!ReadBlockFromDisk(block, pindex)) { + if(!ReadBlockFromDisk(block, pindex, consensusParams)) { LogPrint("amqp", "amqp: Can't read block from disk"); return false; } diff --git a/src/main.cpp b/src/main.cpp index 7c374108639..00849af4048 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -104,7 +104,7 @@ void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); * in the last Consensus::Params::nMajorityWindow blocks, starting at pstart and going backwards. */ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams); -static void CheckBlockIndex(); +static void CheckBlockIndex(const Consensus::Params& consensusParams); /** Constant stuff for coinbase transactions we create: */ CScript COINBASE_FLAGS; @@ -1607,7 +1607,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } /** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */ -bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) +bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow) { CBlockIndex *pindexSlow = NULL; @@ -1653,7 +1653,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock if (pindexSlow) { CBlock block; - if (ReadBlockFromDisk(block, pindexSlow)) { + if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) { BOOST_FOREACH(const CTransaction &tx, block.vtx) { if (tx.GetHash() == hash) { txOut = tx; @@ -1698,7 +1698,7 @@ bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHea return true; } -bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams) { block.SetNull(); @@ -1716,16 +1716,16 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) } // Check the header - if (!(CheckEquihashSolution(&block, Params().GetConsensus()) && - CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus()))) + if (!(CheckEquihashSolution(&block, consensusParams) && + CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))) return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); return true; } -bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex) +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams) { - if (!ReadBlockFromDisk(block, pindex->GetBlockPos())) + if (!ReadBlockFromDisk(block, pindex->GetBlockPos(), consensusParams)) return false; if (block.GetHash() != pindex->GetBlockHash()) return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s", @@ -3019,12 +3019,12 @@ void static UpdateTip(CBlockIndex *pindexNew) { * Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and * mempool.removeWithoutBranchId after this, with cs_main held. */ -bool static DisconnectTip(CValidationState &state, bool fBare = false) { +bool static DisconnectTip(CValidationState &state, const Consensus::Params& consensusParams, bool fBare = false) { CBlockIndex *pindexDelete = chainActive.Tip(); assert(pindexDelete); // Read block from disk. CBlock block; - if (!ReadBlockFromDisk(block, pindexDelete)) + if (!ReadBlockFromDisk(block, pindexDelete, consensusParams)) return AbortNode(state, "Failed to read block"); // Apply the block atomically to the chain state. uint256 sproutAnchorBeforeDisconnect = pcoinsTip->GetBestAnchor(SPROUT); @@ -3094,12 +3094,13 @@ static int64_t nTimePostConnect = 0; * You probably want to call mempool.removeWithoutBranchId after this, with cs_main held. */ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, const CBlock *pblock) { + const CChainParams& chainparams = Params(); assert(pindexNew->pprev == chainActive.Tip()); // Read block from disk. int64_t nTime1 = GetTimeMicros(); CBlock block; if (!pblock) { - if (!ReadBlockFromDisk(block, pindexNew)) + if (!ReadBlockFromDisk(block, pindexNew, chainparams.GetConsensus())) return AbortNode(state, "Failed to read block"); pblock = █ } @@ -3237,6 +3238,7 @@ static void PruneBlockIndexCandidates() { * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. */ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, const CBlock *pblock) { + const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); bool fInvalidFound = false; const CBlockIndex *pindexOldTip = chainActive.Tip(); @@ -3270,7 +3272,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo // Disconnect active blocks which are no longer in the best chain. bool fBlocksDisconnected = false; while (chainActive.Tip() && chainActive.Tip() != pindexFork) { - if (!DisconnectTip(state)) + if (!DisconnectTip(state, chainparams.GetConsensus())) return false; fBlocksDisconnected = true; } @@ -3342,7 +3344,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo bool ActivateBestChain(CValidationState &state, const CBlock *pblock) { CBlockIndex *pindexNewTip = NULL; CBlockIndex *pindexMostWork = NULL; - const CChainParams& chainParams = Params(); + const CChainParams& chainparams = Params(); do { boost::this_thread::interruption_point(); @@ -3369,7 +3371,7 @@ bool ActivateBestChain(CValidationState &state, const CBlock *pblock) { // Relay inventory, but don't relay old inventory during initial block download. int nBlockEstimate = 0; if (fCheckpointsEnabled) - nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints()); + nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()); { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) @@ -3381,7 +3383,7 @@ bool ActivateBestChain(CValidationState &state, const CBlock *pblock) { uiInterface.NotifyBlockTip(hashNewTip); } } while(pindexMostWork != chainActive.Tip()); - CheckBlockIndex(); + CheckBlockIndex(chainparams.GetConsensus()); // Write changes periodically to disk, after relay. if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC)) { @@ -3391,7 +3393,8 @@ bool ActivateBestChain(CValidationState &state, const CBlock *pblock) { return true; } -bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { +bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex *pindex) +{ AssertLockHeld(cs_main); // Mark the block itself as invalid. @@ -3406,10 +3409,10 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { setBlockIndexCandidates.erase(pindexWalk); // ActivateBestChain considers blocks already in chainActive // unconditionally valid already, so force disconnect away from it. - if (!DisconnectTip(state)) { + if (!DisconnectTip(state, consensusParams)) { mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); mempool.removeWithoutBranchId( - CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); + CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, consensusParams)); return false; } } @@ -3427,7 +3430,7 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { InvalidChainFound(pindex); mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); mempool.removeWithoutBranchId( - CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); + CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, consensusParams)); return true; } @@ -4019,6 +4022,7 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) { + const CChainParams& chainparams = Params(); // Preliminary checks auto verifier = libzcash::ProofVerifier::Disabled(); bool checked = CheckBlock(*pblock, state, verifier); @@ -4037,7 +4041,7 @@ bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* if (pindex && pfrom) { mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); } - CheckBlockIndex(); + CheckBlockIndex(chainparams.GetConsensus()); if (!ret) return error("%s: AcceptBlock FAILED", __func__); } @@ -4432,6 +4436,7 @@ CVerifyDB::~CVerifyDB() bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) { + const CChainParams& chainparams = Params(); LOCK(cs_main); if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL) return true; @@ -4458,7 +4463,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth break; CBlock block; // check level 0: read from disk - if (!ReadBlockFromDisk(block, pindex)) + if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); // check level 1: verify block validity if (nCheckLevel >= 1 && !CheckBlock(block, state, verifier)) @@ -4501,7 +4506,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)))); pindex = chainActive.Next(pindex); CBlock block; - if (!ReadBlockFromDisk(block, pindex)) + if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); if (!ConnectBlock(block, state, pindex, coins)) return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); @@ -4597,7 +4602,7 @@ bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches) // of the blockchain). break; } - if (!DisconnectTip(state, true)) { + if (!DisconnectTip(state, params.GetConsensus(), true)) { return error("RewindBlockIndex: unable to disconnect block at height %i", pindex->nHeight); } // Occasionally flush state to disk. @@ -4659,7 +4664,7 @@ bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches) PruneBlockIndexCandidates(); - CheckBlockIndex(); + CheckBlockIndex(params.GetConsensus()); if (!FlushStateToDisk(state, FLUSH_STATE_ALWAYS)) { return false; @@ -4837,7 +4842,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) std::pair::iterator, std::multimap::iterator> range = mapBlocksUnknownParent.equal_range(head); while (range.first != range.second) { std::multimap::iterator it = range.first; - if (ReadBlockFromDisk(block, it->second)) + if (ReadBlockFromDisk(block, it->second, chainparams.GetConsensus())) { LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), head.ToString()); @@ -4864,9 +4869,8 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) return nLoaded > 0; } -void static CheckBlockIndex() +void static CheckBlockIndex(const Consensus::Params& consensusParams) { - const Consensus::Params& consensusParams = Params().GetConsensus(); if (!fCheckBlockIndex) { return; } @@ -5151,7 +5155,7 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) return true; } -void static ProcessGetData(CNode* pfrom) +void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams) { int currentHeight = GetHeight(); @@ -5198,7 +5202,7 @@ void static ProcessGetData(CNode* pfrom) { // Send block from disk CBlock block; - if (!ReadBlockFromDisk(block, (*mi).second)) + if (!ReadBlockFromDisk(block, (*mi).second, consensusParams)) assert(!"cannot load block from disk"); if (inv.type == MSG_BLOCK) pfrom->PushMessage("block", block); @@ -5630,7 +5634,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id); pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); - ProcessGetData(pfrom); + ProcessGetData(pfrom, chainparams.GetConsensus()); } @@ -5904,7 +5908,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexLast), uint256()); } - CheckBlockIndex(); + CheckBlockIndex(chainparams.GetConsensus()); } else if (strCommand == "block" && !fImporting && !fReindex) // Ignore blocks received while importing @@ -6208,6 +6212,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // requires LOCK(cs_vRecvMsg) bool ProcessMessages(CNode* pfrom) { + const CChainParams& chainparams = Params(); //if (fDebug) // LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size()); @@ -6222,7 +6227,7 @@ bool ProcessMessages(CNode* pfrom) bool fOk = true; if (!pfrom->vRecvGetData.empty()) - ProcessGetData(pfrom); + ProcessGetData(pfrom, chainparams.GetConsensus()); // this maintains the order of responses if (!pfrom->vRecvGetData.empty()) return fOk; @@ -6249,7 +6254,7 @@ bool ProcessMessages(CNode* pfrom) it++; // Scan for message start - if (memcmp(msg.hdr.pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0) { + if (memcmp(msg.hdr.pchMessageStart, chainparams.MessageStart(), MESSAGE_START_SIZE) != 0) { LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->id); fOk = false; break; @@ -6257,7 +6262,7 @@ bool ProcessMessages(CNode* pfrom) // Read header CMessageHeader& hdr = msg.hdr; - if (!hdr.IsValid(Params().MessageStart())) + if (!hdr.IsValid(chainparams.MessageStart())) { LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->id); continue; diff --git a/src/main.h b/src/main.h index b5f82cecad2..3e55f926970 100644 --- a/src/main.h +++ b/src/main.h @@ -239,7 +239,7 @@ bool IsInitialBlockDownload(); /** Format a string that describes several potential problems detected by the core */ std::string GetWarnings(const std::string& strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ -bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false); +bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false); /** Find the best known block, and make it the tip of the block chain */ bool ActivateBestChain(CValidationState &state, const CBlock *pblock = NULL); CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); @@ -462,9 +462,8 @@ class CScriptCheck /** Functions for disk access for blocks */ bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart); -bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos); -bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); - +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams); +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams); /** Functions for validating blocks and updating the block tree */ @@ -492,8 +491,7 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * If dbp is non-NULL, the file is known to already reside on disk */ bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp); -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL); - +bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex **ppindex= NULL); /** @@ -572,7 +570,7 @@ class CVerifyDB { CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator); /** Mark a block as invalid. */ -bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex); +bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex *pindex); /** Remove invalidity status from a block and its descendants. */ bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex); diff --git a/src/rest.cpp b/src/rest.cpp index 4f92bbb0af7..e70ce517aac 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "chainparams.h" #include "primitives/block.h" #include "primitives/transaction.h" #include "main.h" @@ -214,7 +215,7 @@ static bool rest_block(HTTPRequest* req, if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)"); - if (!ReadBlockFromDisk(block, pblockindex)) + if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } @@ -355,7 +356,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) CTransaction tx; uint256 hashBlock = uint256(); - if (!GetTransaction(hash, tx, hashBlock, true)) + if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 58089d0d676..235b682ce78 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -493,7 +493,7 @@ UniValue getblock(const UniValue& params, bool fHelp) if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); - if(!ReadBlockFromDisk(block, pblockindex)) + if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); if (verbosity == 0) @@ -976,7 +976,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); CBlockIndex* pblockindex = mapBlockIndex[hash]; - InvalidateBlock(state, pblockindex); + InvalidateBlock(state, Params().GetConsensus(), pblockindex); } if (state.IsValid()) { diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 90069112b8a..49768c24730 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -322,7 +322,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) CTransaction tx; uint256 hashBlock; - if (!GetTransaction(hash, tx, hashBlock, true)) + if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); string strHex = EncodeHexTx(tx); @@ -392,7 +392,7 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp) if (pblockindex == NULL) { CTransaction tx; - if (!GetTransaction(oneTxid, tx, hashBlock, false) || hashBlock.IsNull()) + if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); if (!mapBlockIndex.count(hashBlock)) throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); @@ -400,7 +400,7 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp) } CBlock block; - if(!ReadBlockFromDisk(block, pblockindex)) + if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); unsigned int ntxFound = 0; diff --git a/src/wallet/rpcdisclosure.cpp b/src/wallet/rpcdisclosure.cpp index df35bb6ddf2..82d20b76ce2 100644 --- a/src/wallet/rpcdisclosure.cpp +++ b/src/wallet/rpcdisclosure.cpp @@ -82,7 +82,7 @@ UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp) uint256 hashBlock; // Check txid has been seen - if (!GetTransaction(hash, tx, hashBlock, true)) { + if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); } @@ -210,7 +210,7 @@ UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp) CTransaction tx; uint256 hashBlock; // Check if we have seen the transaction - if (!GetTransaction(hash, tx, hashBlock, true)) { + if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 23030257a89..659431f19a2 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1134,7 +1134,7 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex, const CBlock* pblock {pblockIn}; CBlock block; if (!pblock) { - ReadBlockFromDisk(block, pindex); + ReadBlockFromDisk(block, pindex, Params().GetConsensus()); pblock = █ } @@ -2432,7 +2432,7 @@ void CWallet::WitnessNoteCommitment(std::vector commitments, while (pindex) { CBlock block; - ReadBlockFromDisk(block, pindex); + ReadBlockFromDisk(block, pindex, Params().GetConsensus()); BOOST_FOREACH(const CTransaction& tx, block.vtx) { @@ -2511,7 +2511,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); CBlock block; - ReadBlockFromDisk(block, pindex); + ReadBlockFromDisk(block, pindex, Params().GetConsensus()); BOOST_FOREACH(CTransaction& tx, block.vtx) { if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) { diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index 4567f25b1f9..28cf2e597dc 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "chainparams.h" #include "zmqpublishnotifier.h" #include "main.h" #include "util.h" @@ -164,11 +165,12 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { LogPrint("zmq", "zmq: Publish rawblock %s\n", pindex->GetBlockHash().GetHex()); + const Consensus::Params& consensusParams = Params().GetConsensus(); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); { LOCK(cs_main); CBlock block; - if(!ReadBlockFromDisk(block, pindex)) + if(!ReadBlockFromDisk(block, pindex, consensusParams)) { zmqError("Can't read block from disk"); return false; From 94debefbcfb6a64b2b9c5804894c1308c3d3d642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Tue, 10 Nov 2015 19:28:56 +0100 Subject: [PATCH 092/127] Globals: Make AcceptBlockHeader static (Fix #6163) ..and at the same time prevent AcceptBlockHeader() from calling global function Params() --- src/main.cpp | 7 +++---- src/main.h | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 00849af4048..e9611e19341 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3897,9 +3897,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn return true; } -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex) +static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex=NULL) { - const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); // Check for duplicate uint256 hash = block.GetHash(); @@ -3948,7 +3947,7 @@ bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex** ppi CBlockIndex *&pindex = *ppindex; - if (!AcceptBlockHeader(block, state, &pindex)) + if (!AcceptBlockHeader(block, state, chainparams, &pindex)) return false; // Try to process all requested blocks that we don't have, but only @@ -5887,7 +5886,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 20); return error("non-continuous headers sequence"); } - if (!AcceptBlockHeader(header, state, &pindexLast)) { + if (!AcceptBlockHeader(header, state, chainparams, &pindexLast)) { int nDoS; if (state.IsInvalid(nDoS)) { if (nDoS > 0) diff --git a/src/main.h b/src/main.h index 3e55f926970..818936e9438 100644 --- a/src/main.h +++ b/src/main.h @@ -491,7 +491,6 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * If dbp is non-NULL, the file is known to already reside on disk */ bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp); -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex **ppindex= NULL); /** From 8e5d8ca52a687ddf606fe6c589a52782eb0556a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Mon, 20 Apr 2015 00:17:11 +0200 Subject: [PATCH 093/127] Chainparams: Explicit CChainParams arg for main (pre miner): -ProcessNewBlock -TestBlockValidity --- src/main.cpp | 11 +++++------ src/main.h | 5 +++-- src/miner.cpp | 4 ++-- src/rpc/mining.cpp | 6 +++--- src/test/miner_tests.cpp | 3 ++- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index e9611e19341..c8e01725bb7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4019,9 +4019,8 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned } -bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp) { - const CChainParams& chainparams = Params(); // Preliminary checks auto verifier = libzcash::ProofVerifier::Disabled(); bool checked = CheckBlock(*pblock, state, verifier); @@ -4051,7 +4050,7 @@ bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* return true; } -bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * const pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) +bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) { AssertLockHeld(cs_main); assert(pindexPrev == chainActive.Tip()); @@ -4824,7 +4823,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) // process in case the block isn't known yet if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { CValidationState state; - if (ProcessNewBlock(state, NULL, &block, true, dbp)) + if (ProcessNewBlock(state, chainparams, NULL, &block, true, dbp)) nLoaded++; if (state.IsError()) break; @@ -4846,7 +4845,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), head.ToString()); CValidationState dummy; - if (ProcessNewBlock(dummy, NULL, &block, true, &it->second)) + if (ProcessNewBlock(dummy, chainparams, NULL, &block, true, &it->second)) { nLoaded++; queue.push_back(block.GetHash()); @@ -5926,7 +5925,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); - ProcessNewBlock(state, pfrom, &block, forceProcessing, NULL); + ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL); int nDoS; if (state.IsInvalid(nDoS)) { pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), diff --git a/src/main.h b/src/main.h index 818936e9438..1e3a5a4bcab 100644 --- a/src/main.h +++ b/src/main.h @@ -44,6 +44,7 @@ class CBlockIndex; class CBlockTreeDB; class CBloomFilter; +class CChainParams; class CInv; class CScriptCheck; class CValidationInterface; @@ -204,7 +205,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals); * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location. * @return True if state.IsValid() */ -bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp); +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ @@ -481,7 +482,7 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); /** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ -bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); +bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); /** * Store block on disk. diff --git a/src/miner.cpp b/src/miner.cpp index 1ca5e264fd9..5c921ca037e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -439,7 +439,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); CValidationState state; - if (!TestBlockValidity(state, *pblock, pindexPrev, false, false)) + if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed"); } @@ -513,7 +513,7 @@ static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainpar // Process this block the same as if we had received it from another node CValidationState state; - if (!ProcessNewBlock(state, NULL, pblock, true, NULL)) + if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)) return error("ZcashMiner: ProcessNewBlock, block not accepted"); TrackMinedBlock(pblock->GetHash()); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 0287df80483..1cd0848885a 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -247,7 +247,7 @@ UniValue generate(const UniValue& params, bool fHelp) } endloop: CValidationState state; - if (!ProcessNewBlock(state, NULL, pblock, true, NULL)) + if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); @@ -523,7 +523,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; CValidationState state; - TestBlockValidity(state, block, pindexPrev, false, true); + TestBlockValidity(state, Params(), block, pindexPrev, false, true); return BIP22ValidationResult(state); } } @@ -782,7 +782,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, NULL, &block, true, NULL); + bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); UnregisterValidationInterface(&sc); if (fBlockPresent) { diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 263ff841722..4c19f691657 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -138,6 +138,7 @@ struct { // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { + const CChainParams& chainparams = Params(CBaseChainParams::MAIN); CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; CBlockTemplate *pblocktemplate; CMutableTransaction tx,tx2; @@ -264,7 +265,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) pblock->hashFinalSaplingRoot = uint256(); CValidationState state; - BOOST_CHECK(ProcessNewBlock(state, NULL, pblock, true, NULL)); + BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)); BOOST_CHECK_MESSAGE(state.IsValid(), state.GetRejectReason()); pblock->hashPrevBlock = pblock->GetHash(); From 793a72e31f081dcf42da1a6b6f0474d8c0d9831b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Fri, 17 Apr 2015 14:19:52 +0200 Subject: [PATCH 094/127] Chainparams: Explicit CChainParams arg for miner: -BitcoinMiner -CreateNewBlock -GenerateBitcoins -ProcessBlockFound --- src/init.cpp | 2 +- src/miner.cpp | 13 ++++++------- src/miner.h | 2 +- src/rpc/mining.cpp | 4 ++-- src/test/miner_tests.cpp | 26 +++++++++++++------------- 5 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 30bdccd51ff..ae27f9fb845 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1868,7 +1868,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #ifdef ENABLE_MINING // Generate coins in the background - GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), Params()); + GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), chainparams); #endif // ********************************************************* Step 11: finished diff --git a/src/miner.cpp b/src/miner.cpp index 5c921ca037e..ee37c44c7ab 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -106,9 +106,8 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, } } -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) +CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn) { - const CChainParams& chainparams = Params(); // Create new block std::unique_ptr pblocktemplate(new CBlockTemplate()); if(!pblocktemplate.get()) @@ -117,7 +116,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios - if (Params().MineBlocksOnDemand()) + if (chainparams.MineBlocksOnDemand()) pblock->nVersion = GetArg("-blockversion", pblock->nVersion); // Add dummy coinbase tx as first transaction @@ -324,7 +323,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // create only contains transactions that are valid in new blocks. CValidationState state; PrecomputedTransactionData txdata(tx); - if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId)) + if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, chainparams.GetConsensus(), consensusBranchId)) continue; if (chainparams.ZIP209Enabled() && monitoring_pool_balances) { @@ -433,8 +432,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); pblock->hashFinalSaplingRoot = sapling_tree.root(); - UpdateTime(pblock, Params().GetConsensus(), pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); + UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nSolution.clear(); pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); @@ -579,7 +578,7 @@ void static BitcoinMiner(const CChainParams& chainparams) unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrev = chainActive.Tip(); - unique_ptr pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); + unique_ptr pblocktemplate(CreateNewBlock(chainparams, coinbaseScript->reserveScript)); if (!pblocktemplate.get()) { if (GetArg("-mineraddress", "").empty()) { diff --git a/src/miner.h b/src/miner.h index 1d1ebaf9b4d..9059be633e5 100644 --- a/src/miner.h +++ b/src/miner.h @@ -24,7 +24,7 @@ struct CBlockTemplate }; /** Generate a new block, without valid proof-of-work */ -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); +CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn); #ifdef ENABLE_MINING /** Get script for -mineraddress */ diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 1cd0848885a..670d2edd4f3 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -199,7 +199,7 @@ UniValue generate(const UniValue& params, bool fHelp) unsigned int k = Params().GetConsensus().nEquihashK; while (nHeight < nHeightEnd) { - std::unique_ptr pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); + std::unique_ptr pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); CBlock *pblock = &pblocktemplate->block; @@ -614,7 +614,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (!coinbaseScript->reserveScript.size()) throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet or -mineraddress)"); - pblocktemplate = CreateNewBlock(coinbaseScript->reserveScript); + pblocktemplate = CreateNewBlock(Params(), coinbaseScript->reserveScript); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 4c19f691657..23e7634abbd 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i) { // Simple block creation, nothing special yet: - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); CBlock *pblock = &pblocktemplate->block; // pointer for convenience pblock->nVersion = 4; @@ -274,7 +274,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) } // Just to make sure we can still make simple blocks - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; // block sigops > limit: 1000 CHECKMULTISIG + 1 @@ -293,7 +293,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -314,14 +314,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); // orphan in mempool hash = tx.GetHash(); mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -339,7 +339,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 49000LL; hash = tx.GetHash(); mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -350,7 +350,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 0; hash = tx.GetHash(); mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -368,7 +368,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue -= 10000; hash = tx.GetHash(); mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -382,17 +382,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); // subsidy changing int nHeight = chainActive.Height(); chainActive.Tip()->nHeight = 209999; - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = 210000; - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = nHeight; @@ -424,7 +424,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx2)); BOOST_CHECK(!CheckFinalTx(tx2, LOCKTIME_MEDIAN_TIME_PAST)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); // Neither tx should have made it into the template. BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1); @@ -439,7 +439,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) //BOOST_CHECK(CheckFinalTx(tx)); //BOOST_CHECK(CheckFinalTx(tx2)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 2); delete pblocktemplate; From 44b2d060efecc94fcc4f93ff4cc6720076c1cf8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Fri, 17 Apr 2015 14:40:24 +0200 Subject: [PATCH 095/127] Globals: Remove a bunch of Params() calls from main.cpp: 1) Chainparams: Explicit CChainParams arg for main: -AcceptBlock -AcceptBlockHeader -ActivateBestChain -ConnectTip -InitBlockIndex -LoadExternalBlockFile -VerifyDB parametric constructor 2) Also pickup more Params()\. in main.cpp 3) Pass nPruneAfterHeight explicitly to new FindFilesToPrune() in main.cpp --- src/init.cpp | 15 +++++----- src/main.cpp | 62 ++++++++++++++++++++------------------- src/main.h | 19 ++++-------- src/rpc/blockchain.cpp | 6 ++-- src/test/test_bitcoin.cpp | 3 +- 5 files changed, 50 insertions(+), 55 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index ae27f9fb845..2743f473104 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -606,6 +606,7 @@ void CleanupBlockRevFiles() void ThreadImport(std::vector vImportFiles) { + const CChainParams& chainparams = Params(); RenameThread("zcash-loadblk"); // -reindex if (fReindex) { @@ -619,14 +620,14 @@ void ThreadImport(std::vector vImportFiles) if (!file) break; // This error is logged in OpenBlockFile LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile); - LoadExternalBlockFile(file, &pos); + LoadExternalBlockFile(chainparams, file, &pos); nFile++; } pblocktree->WriteReindexing(false); fReindex = false; LogPrintf("Reindexing finished\n"); // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): - InitBlockIndex(); + InitBlockIndex(chainparams); } // hardcoded $DATADIR/bootstrap.dat @@ -637,7 +638,7 @@ void ThreadImport(std::vector vImportFiles) CImportingNow imp; boost::filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; LogPrintf("Importing bootstrap.dat...\n"); - LoadExternalBlockFile(file); + LoadExternalBlockFile(chainparams, file); RenameOver(pathBootstrap, pathBootstrapOld); } else { LogPrintf("Warning: Could not open bootstrap file %s\n", pathBootstrap.string()); @@ -650,7 +651,7 @@ void ThreadImport(std::vector vImportFiles) if (file) { CImportingNow imp; LogPrintf("Importing blocks file %s...\n", path.string()); - LoadExternalBlockFile(file); + LoadExternalBlockFile(chainparams, file); } else { LogPrintf("Warning: Could not open blocks file %s\n", path.string()); } @@ -1515,7 +1516,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); // Initialize the block index (no-op if non-empty database was already loaded) - if (!InitBlockIndex()) { + if (!InitBlockIndex(chainparams)) { strLoadError = _("Error initializing block database"); break; } @@ -1552,7 +1553,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n", MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", 288)); } - if (!CVerifyDB().VerifyDB(pcoinsdbview, GetArg("-checklevel", 3), + if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, GetArg("-checklevel", 3), GetArg("-checkblocks", 288))) { strLoadError = _("Corrupted block database detected"); break; @@ -1822,7 +1823,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) uiInterface.InitMessage(_("Activating best chain...")); // scan for better chains in the block chain database, that are not yet connected in the active best chain CValidationState state; - if (!ActivateBestChain(state)) + if (!ActivateBestChain(state, chainparams)) strErrors << "Failed to connect best block"; std::vector vImportFiles; diff --git a/src/main.cpp b/src/main.cpp index c8e01725bb7..ff8e2047726 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2869,6 +2869,7 @@ enum FlushStateMode { * or always and in all cases if we're in prune mode and are deleting files. */ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { + const CChainParams& chainparams = Params(); LOCK2(cs_main, cs_LastBlockFile); static int64_t nLastWrite = 0; static int64_t nLastFlush = 0; @@ -2877,7 +2878,7 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { bool fFlushForPrune = false; try { if (fPruneMode && fCheckForPruning && !fReindex) { - FindFilesToPrune(setFilesToPrune); + FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight()); fCheckForPruning = false; if (!setFilesToPrune.empty()) { fFlushForPrune = true; @@ -3093,8 +3094,8 @@ static int64_t nTimePostConnect = 0; * corresponding to pindexNew, to bypass loading it again from disk. * You probably want to call mempool.removeWithoutBranchId after this, with cs_main held. */ -bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, const CBlock *pblock) { - const CChainParams& chainparams = Params(); +bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock) +{ assert(pindexNew->pprev == chainActive.Tip()); // Read block from disk. int64_t nTime1 = GetTimeMicros(); @@ -3237,8 +3238,8 @@ static void PruneBlockIndexCandidates() { * Try to make some progress towards making pindexMostWork the active block. * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. */ -static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, const CBlock *pblock) { - const CChainParams& chainparams = Params(); +static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock) +{ AssertLockHeld(cs_main); bool fInvalidFound = false; const CBlockIndex *pindexOldTip = chainActive.Tip(); @@ -3296,7 +3297,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo // Connect new blocks. BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { - if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { + if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { if (state.IsInvalid()) { // The block violates a consensus rule. if (!state.CorruptionPossible()) @@ -3341,10 +3342,10 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo * or an activated best chain. pblock is either NULL or a pointer to a block * that is already loaded (to avoid loading it again from disk). */ -bool ActivateBestChain(CValidationState &state, const CBlock *pblock) { +bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock) +{ CBlockIndex *pindexNewTip = NULL; CBlockIndex *pindexMostWork = NULL; - const CChainParams& chainparams = Params(); do { boost::this_thread::interruption_point(); @@ -3357,7 +3358,7 @@ bool ActivateBestChain(CValidationState &state, const CBlock *pblock) { if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) return true; - if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL)) + if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL)) return false; pindexNewTip = chainActive.Tip(); @@ -3940,9 +3941,15 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state return true; } -bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) +/** + * Store block on disk. + * JoinSplit proofs are never verified, because: + * - AcceptBlock doesn't perform script checks either. + * - The only caller of AcceptBlock verifies JoinSplit proofs elsewhere. + * If dbp is non-NULL, the file is known to already reside on disk + */ +static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) { - const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); CBlockIndex *&pindex = *ppindex; @@ -4035,7 +4042,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c // Store to disk CBlockIndex *pindex = NULL; - bool ret = AcceptBlock(*pblock, state, &pindex, fRequested, dbp); + bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fRequested, dbp); if (pindex && pfrom) { mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); } @@ -4044,7 +4051,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c return error("%s: AcceptBlock FAILED", __func__); } - if (!ActivateBestChain(state, pblock)) + if (!ActivateBestChain(state, chainparams, pblock)) return error("%s: ActivateBestChain failed", __func__); return true; @@ -4134,13 +4141,13 @@ void UnlinkPrunedFiles(std::set& setFilesToPrune) } /* Calculate the block/rev files that should be deleted to remain under target*/ -void FindFilesToPrune(std::set& setFilesToPrune) +void FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfterHeight) { LOCK2(cs_main, cs_LastBlockFile); if (chainActive.Tip() == NULL || nPruneTarget == 0) { return; } - if (chainActive.Tip()->nHeight <= Params().PruneAfterHeight()) { + if (chainActive.Tip()->nHeight <= nPruneAfterHeight) { return; } @@ -4432,9 +4439,8 @@ CVerifyDB::~CVerifyDB() uiInterface.ShowProgress("", 100); } -bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) +bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) { - const CChainParams& chainparams = Params(); LOCK(cs_main); if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL) return true; @@ -4710,9 +4716,8 @@ bool LoadBlockIndex() return true; } - -bool InitBlockIndex() { - const CChainParams& chainparams = Params(); +bool InitBlockIndex(const CChainParams& chainparams) +{ LOCK(cs_main); // Initialize global variables that cannot be constructed at startup. @@ -4738,7 +4743,7 @@ bool InitBlockIndex() { // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) if (!fReindex) { try { - CBlock &block = const_cast(Params().GenesisBlock()); + CBlock &block = const_cast(chainparams.GenesisBlock()); // Start new block file unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); CDiskBlockPos blockPos; @@ -4750,7 +4755,7 @@ bool InitBlockIndex() { CBlockIndex *pindex = AddToBlockIndex(block); if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("LoadBlockIndex(): genesis block not accepted"); - if (!ActivateBestChain(state, &block)) + if (!ActivateBestChain(state, chainparams, &block)) return error("LoadBlockIndex(): genesis block cannot be activated"); // Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); @@ -4762,11 +4767,8 @@ bool InitBlockIndex() { return true; } - - -bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) +bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp) { - const CChainParams& chainparams = Params(); // Map of disk positions for blocks with unknown parent (only used for reindex) static std::multimap mapBlocksUnknownParent; int64_t nStart = GetTimeMillis(); @@ -4786,10 +4788,10 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) try { // locate a header unsigned char buf[MESSAGE_START_SIZE]; - blkdat.FindByte(Params().MessageStart()[0]); + blkdat.FindByte(chainparams.MessageStart()[0]); nRewind = blkdat.GetPos()+1; blkdat >> FLATDATA(buf); - if (memcmp(buf, Params().MessageStart(), MESSAGE_START_SIZE)) + if (memcmp(buf, chainparams.MessageStart(), MESSAGE_START_SIZE)) continue; // read size blkdat >> nSize; @@ -5188,7 +5190,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // best equivalent proof of work) than the best header chain we know about. send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) && - (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, Params().GetConsensus()) < nOneMonth); + (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, consensusParams) < nOneMonth); if (!send) { LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId()); } @@ -6081,7 +6083,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, uint256 alertHash = alert.GetHash(); if (pfrom->setKnown.count(alertHash) == 0) { - if (alert.ProcessAlert(Params().AlertKey())) + if (alert.ProcessAlert(chainparams.AlertKey())) { // Relay pfrom->setKnown.insert(alertHash); diff --git a/src/main.h b/src/main.h index 1e3a5a4bcab..467f3473ca2 100644 --- a/src/main.h +++ b/src/main.h @@ -215,9 +215,9 @@ FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false); /** Translation to a filesystem path */ boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix); /** Import blocks from an external file */ -bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp = NULL); +bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp = NULL); /** Initialize a new block tree database + block data on disk */ -bool InitBlockIndex(); +bool InitBlockIndex(const CChainParams& chainparams); /** Load the block tree and coins database from disk */ bool LoadBlockIndex(); /** Unload database information */ @@ -242,7 +242,7 @@ std::string GetWarnings(const std::string& strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false); /** Find the best known block, and make it the tip of the block chain */ -bool ActivateBestChain(CValidationState &state, const CBlock *pblock = NULL); +bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL); CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); /** @@ -260,7 +260,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); * * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned */ -void FindFilesToPrune(std::set& setFilesToPrune); +void FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfterHeight); /** * Actually unlink the specified files @@ -484,15 +484,6 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn /** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); -/** - * Store block on disk. - * JoinSplit proofs are never verified, because: - * - AcceptBlock doesn't perform script checks either. - * - The only caller of AcceptBlock verifies JoinSplit proofs elsewhere. - * If dbp is non-NULL, the file is known to already reside on disk - */ -bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp); - /** * When there are blocks in the active chain with missing data (e.g. if the @@ -563,7 +554,7 @@ class CVerifyDB { public: CVerifyDB(); ~CVerifyDB(); - bool VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth); + bool VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth); }; /** Find the last common block between the parameter chain and a locator. */ diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 235b682ce78..4305070e0aa 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -650,7 +650,7 @@ UniValue verifychain(const UniValue& params, bool fHelp) if (params.size() > 1) nCheckDepth = params[1].get_int(); - return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth); + return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth); } /** Implementation of IsSuperMajority with better feedback */ @@ -980,7 +980,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp) } if (state.IsValid()) { - ActivateBestChain(state); + ActivateBestChain(state, Params()); } if (!state.IsValid()) { @@ -1019,7 +1019,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp) } if (state.IsValid()) { - ActivateBestChain(state); + ActivateBestChain(state, Params()); } if (!state.IsValid()) { diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 3548b9d4bec..f23837da4aa 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -87,6 +87,7 @@ BasicTestingSetup::~BasicTestingSetup() TestingSetup::TestingSetup() { + const CChainParams& chainparams = Params(); // Ideally we'd move all the RPC tests to the functional testing framework // instead of unit tests, but for now we need these here. RegisterAllCoreRPCCommands(tableRPC); @@ -105,7 +106,7 @@ TestingSetup::TestingSetup() pblocktree = new CBlockTreeDB(1 << 20, true); pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsTip = new CCoinsViewCache(pcoinsdbview); - InitBlockIndex(); + InitBlockIndex(chainparams); #ifdef ENABLE_WALLET bool fFirstRun; pwalletMain = new CWallet("wallet.dat"); From 9b0f61af2d90a19603b6d1b46391b6e8b6cb8e30 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Sun, 31 Jan 2016 00:40:23 -0500 Subject: [PATCH 096/127] Improve block validity/ConnectBlock() comments Previously didn't make clear that the ContextualCheckBlock* functions meant the block headers as context - not the UTXO set itself - and that ConnectBlock() also did UTXO-related validity checks (in the future we may split that functionality into a separate UTXO-specific contextual check block function). Also, reordered to put validity checks first for better readability. --- src/main.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main.h b/src/main.h index 467f3473ca2..03ef1866bc2 100644 --- a/src/main.h +++ b/src/main.h @@ -468,19 +468,23 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus /** Functions for validating blocks and updating the block tree */ -/** Apply the effects of this block (with given index) on the UTXO set represented by coins */ -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); - /** Context-independent validity checks */ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); bool CheckBlock(const CBlock& block, CValidationState& state, libzcash::ProofVerifier& verifier, bool fCheckPOW = true, bool fCheckMerkleRoot = true); -/** Context-dependent validity checks */ +/** Context-dependent validity checks. + * By "context", we mean only the previous block headers, but not the UTXO + * set; UTXO-related validity checks are done in ConnectBlock(). */ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev); bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); +/** Apply the effects of this block (with given index) on the UTXO set represented by coins. + * Validity checks that depend on the UTXO set are also done; ConnectBlock() + * can fail if those validity checks fail (among other reasons). */ +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); + /** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); From 98f3010026fc06b398bf4ed3d5fb396afee46ee8 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 3 Apr 2016 11:49:36 +0200 Subject: [PATCH 097/127] [doc] Fix doxygen comments for members --- doc/developer-notes.md | 6 ++++++ src/chainparams.cpp | 4 ++-- src/main.cpp | 8 ++++---- src/main.h | 14 +++++++------- src/policy/fees.h | 4 ++-- src/rpc/client.cpp | 4 ++-- src/script/interpreter.cpp | 12 ++++++------ src/script/standard.h | 2 +- src/txmempool.h | 28 ++++++++++++++-------------- src/utiltime.cpp | 2 +- src/wallet/wallet.h | 8 ++++---- 11 files changed, 49 insertions(+), 43 deletions(-) diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 311dbcc46c6..ddbd7df1889 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -71,6 +71,12 @@ To describe a member or variable use: int var; //!< Detailed description after the member ``` +or +```cpp +//! Description before the member +int var; +``` + Also OK: ```c++ /// diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 01b65ddbe45..0980d78121e 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -458,8 +458,8 @@ class CRegTestParams : public CChainParams { assert(consensus.hashGenesisBlock == uint256S("0x029f11d80ef9765602235e1bc9727e3eb6ba20839319f761fee920d63401e327")); assert(genesis.hashMerkleRoot == uint256S("0xc4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb")); - vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds. - vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds. + vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds. + vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds. fMiningRequiresPeers = false; fDefaultConsistencyChecks = true; diff --git a/src/main.cpp b/src/main.cpp index ff8e2047726..9287f994435 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -200,10 +200,10 @@ namespace { /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */ struct QueuedBlock { uint256 hash; - CBlockIndex *pindex; //! Optional. - int64_t nTime; //! Time of "getdata" request in microseconds. - bool fValidatedHeaders; //! Whether this block has validated headers at the time of request. - int64_t nTimeDisconnect; //! The timeout for this block request (for disconnecting a slow peer) + CBlockIndex* pindex; //!< Optional. + int64_t nTime; //!< Time of "getdata" request in microseconds. + bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request. + int64_t nTimeDisconnect; //!< The timeout for this block request (for disconnecting a slow peer) }; map::iterator> > mapBlocksInFlight; diff --git a/src/main.h b/src/main.h index 03ef1866bc2..c7395dabd33 100644 --- a/src/main.h +++ b/src/main.h @@ -502,13 +502,13 @@ bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches); class CBlockFileInfo { public: - unsigned int nBlocks; //! number of blocks stored in file - unsigned int nSize; //! number of used bytes of block file - unsigned int nUndoSize; //! number of used bytes in the undo file - unsigned int nHeightFirst; //! lowest height of block in file - unsigned int nHeightLast; //! highest height of block in file - uint64_t nTimeFirst; //! earliest time of block in file - uint64_t nTimeLast; //! latest time of block in file + unsigned int nBlocks; //!< number of blocks stored in file + unsigned int nSize; //!< number of used bytes of block file + unsigned int nUndoSize; //!< number of used bytes in the undo file + unsigned int nHeightFirst; //!< lowest height of block in file + unsigned int nHeightLast; //!< highest height of block in file + uint64_t nTimeFirst; //!< earliest time of block in file + uint64_t nTimeLast; //!< latest time of block in file ADD_SERIALIZE_METHODS; diff --git a/src/policy/fees.h b/src/policy/fees.h index ee865c67911..52b0c36cdc7 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -259,8 +259,8 @@ class CBlockPolicyEstimator void Read(CAutoFile& filein); private: - CFeeRate minTrackedFee; //! Passed to constructor to avoid dependency on main - double minTrackedPriority; //! Set to AllowFreeThreshold + CFeeRate minTrackedFee; //!< Passed to constructor to avoid dependency on main + double minTrackedPriority; //!< Set to AllowFreeThreshold unsigned int nBestSeenHeight; struct TxStatsInfo { diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 8838bd27390..61c521a7b97 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -17,8 +17,8 @@ using namespace std; class CRPCConvertParam { public: - std::string methodName; //! method whose params want conversion - int paramIdx; //! 0-based idx of param to convert + std::string methodName; //!< method whose params want conversion + int paramIdx; //!< 0-based idx of param to convert }; static const CRPCConvertParam vRPCConvertParams[] = diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index ec1ac52551f..6719443d0b7 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -965,12 +965,12 @@ namespace { */ class CTransactionSignatureSerializer { private: - const CTransaction &txTo; //! reference to the spending transaction (the one being serialized) - const CScript &scriptCode; //! output script being consumed - const unsigned int nIn; //! input index of txTo being signed - const bool fAnyoneCanPay; //! whether the hashtype has the SIGHASH_ANYONECANPAY flag set - const bool fHashSingle; //! whether the hashtype is SIGHASH_SINGLE - const bool fHashNone; //! whether the hashtype is SIGHASH_NONE + const CTransaction& txTo; //!< reference to the spending transaction (the one being serialized) + const CScript& scriptCode; //!< output script being consumed + const unsigned int nIn; //!< input index of txTo being signed + const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set + const bool fHashSingle; //!< whether the hashtype is SIGHASH_SINGLE + const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE public: CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : diff --git a/src/script/standard.h b/src/script/standard.h index fdb02f7c74f..5dcff1c1a5a 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -25,7 +25,7 @@ class CScriptID : public uint160 CScriptID(const uint160& in) : uint160(in) {} }; -static const unsigned int MAX_OP_RETURN_RELAY = 80; //! bytes +static const unsigned int MAX_OP_RETURN_RELAY = 80; //!< bytes extern unsigned nMaxDatacarrierBytes; /** diff --git a/src/txmempool.h b/src/txmempool.h index ec8a8518aa4..ca8055c90e4 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -41,17 +41,17 @@ class CTxMemPoolEntry { private: CTransaction tx; - CAmount nFee; //! Cached to avoid expensive parent-transaction lookups - size_t nTxSize; //! ... and avoid recomputing tx size - size_t nModSize; //! ... and modified size for priority - size_t nUsageSize; //! ... and total memory usage - CFeeRate feeRate; //! ... and fee per kB - int64_t nTime; //! Local time when entering the mempool - double dPriority; //! Priority when entering the mempool - unsigned int nHeight; //! Chain height when entering the mempool - bool hadNoDependencies; //! Not dependent on any other txs when it entered the mempool - bool spendsCoinbase; //! keep track of transactions that spend a coinbase - uint32_t nBranchId; //! Branch ID this transaction is known to commit to, cached for efficiency + CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups + size_t nTxSize; //!< ... and avoid recomputing tx size + size_t nModSize; //!< ... and modified size for priority + size_t nUsageSize; //!< ... and total memory usage + CFeeRate feeRate; //!< ... and fee per kB + int64_t nTime; //!< Local time when entering the mempool + double dPriority; //!< Priority when entering the mempool + unsigned int nHeight; //!< Chain height when entering the mempool + bool hadNoDependencies; //!< Not dependent on any other txs when it entered the mempool + bool spendsCoinbase; //!< keep track of transactions that spend a coinbase + uint32_t nBranchId; //!< Branch ID this transaction is known to commit to, cached for efficiency public: CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, @@ -124,12 +124,12 @@ class CInPoint class CTxMemPool { private: - uint32_t nCheckFrequency; //! Value n means that n times in 2^32 we check. + uint32_t nCheckFrequency; //!< Value n means that n times in 2^32 we check. unsigned int nTransactionsUpdated; CBlockPolicyEstimator* minerPolicyEstimator; - uint64_t totalTxSize = 0; //! sum of all mempool tx' byte sizes - uint64_t cachedInnerUsage; //! sum of dynamic memory usage of all the map elements (NOT the maps themselves) + uint64_t totalTxSize = 0; //!< sum of all mempool tx' byte sizes + uint64_t cachedInnerUsage; //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves) std::map mapSproutNullifiers; std::map mapSaplingNullifiers; diff --git a/src/utiltime.cpp b/src/utiltime.cpp index f1a408a31d4..5d0b284fdf8 100644 --- a/src/utiltime.cpp +++ b/src/utiltime.cpp @@ -15,7 +15,7 @@ using namespace std; -static int64_t nMockTime = 0; //! For unit testing +static int64_t nMockTime = 0; //!< For unit testing int64_t GetTime() { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index fa137011199..bfd5c280c4e 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -404,11 +404,11 @@ class CWalletTx : public CMerkleTx mapSaplingNoteData_t mapSaplingNoteData; std::vector > vOrderForm; unsigned int fTimeReceivedIsTxTime; - unsigned int nTimeReceived; //! time received by this node + unsigned int nTimeReceived; //!< time received by this node unsigned int nTimeSmart; char fFromMe; std::string strFromAccount; - int64_t nOrderPos; //! position in ordered transaction list + int64_t nOrderPos; //!< position in ordered transaction list // memory only mutable bool fDebitCached; @@ -502,7 +502,7 @@ class CWalletTx : public CMerkleTx } READWRITE(*(CMerkleTx*)this); - std::vector vUnused; //! Used to be vtxPrev + std::vector vUnused; //!< Used to be vtxPrev READWRITE(vUnused); READWRITE(mapValue); READWRITE(mapSproutNoteData); @@ -648,7 +648,7 @@ class CAccountingEntry std::string strOtherAccount; std::string strComment; mapValue_t mapValue; - int64_t nOrderPos; //! position in ordered transaction list + int64_t nOrderPos; //!< position in ordered transaction list uint64_t nEntryNo; CAccountingEntry() From a68c8114e1e0edd2224a0891bd01d845ac4d0889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Wed, 6 Apr 2016 16:36:32 +0200 Subject: [PATCH 098/127] Globals: Explicitly pass const CChainParams& to UpdateTip() --- src/main.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 9287f994435..90a3e103fe4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2977,8 +2977,7 @@ void PruneAndFlush() { } /** Update chainActive and related internal data structures. */ -void static UpdateTip(CBlockIndex *pindexNew) { - const CChainParams& chainParams = Params(); +void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) { chainActive.SetTip(pindexNew); // New best block @@ -3020,7 +3019,9 @@ void static UpdateTip(CBlockIndex *pindexNew) { * Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and * mempool.removeWithoutBranchId after this, with cs_main held. */ -bool static DisconnectTip(CValidationState &state, const Consensus::Params& consensusParams, bool fBare = false) { +bool static DisconnectTip(CValidationState &state, const Consensus::Params& consensusParams, bool fBare = false) +{ + const CChainParams& chainparams = Params(); // TODO replace consensusParams parameter CBlockIndex *pindexDelete = chainActive.Tip(); assert(pindexDelete); // Read block from disk. @@ -3067,7 +3068,7 @@ bool static DisconnectTip(CValidationState &state, const Consensus::Params& cons } // Update chainActive and related variables. - UpdateTip(pindexDelete->pprev); + UpdateTip(pindexDelete->pprev, chainparams); // Get the current commitment tree SproutMerkleTree newSproutTree; SaplingMerkleTree newSaplingTree; @@ -3143,7 +3144,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, mempool.removeExpired(pindexNew->nHeight); // Update chainActive & related variables. - UpdateTip(pindexNew); + UpdateTip(pindexNew, chainparams); // Tell wallet about transactions that went from mempool // to conflicted: BOOST_FOREACH(const CTransaction &tx, txConflicted) { From f2baeb7cb6a0ac80cc7e40cd747d8a2a449d7bf1 Mon Sep 17 00:00:00 2001 From: face Date: Sun, 17 Apr 2016 10:58:50 +0300 Subject: [PATCH 099/127] Pass CChainParams to DisconnectTip() --- src/main.cpp | 17 ++++++++--------- src/main.h | 2 +- src/rpc/blockchain.cpp | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 90a3e103fe4..b46804a99bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3019,14 +3019,13 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) { * Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and * mempool.removeWithoutBranchId after this, with cs_main held. */ -bool static DisconnectTip(CValidationState &state, const Consensus::Params& consensusParams, bool fBare = false) +bool static DisconnectTip(CValidationState &state, const CChainParams& chainparams, bool fBare = false) { - const CChainParams& chainparams = Params(); // TODO replace consensusParams parameter CBlockIndex *pindexDelete = chainActive.Tip(); assert(pindexDelete); // Read block from disk. CBlock block; - if (!ReadBlockFromDisk(block, pindexDelete, consensusParams)) + if (!ReadBlockFromDisk(block, pindexDelete, chainparams.GetConsensus())) return AbortNode(state, "Failed to read block"); // Apply the block atomically to the chain state. uint256 sproutAnchorBeforeDisconnect = pcoinsTip->GetBestAnchor(SPROUT); @@ -3274,7 +3273,7 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c // Disconnect active blocks which are no longer in the best chain. bool fBlocksDisconnected = false; while (chainActive.Tip() && chainActive.Tip() != pindexFork) { - if (!DisconnectTip(state, chainparams.GetConsensus())) + if (!DisconnectTip(state, chainparams)) return false; fBlocksDisconnected = true; } @@ -3395,7 +3394,7 @@ bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, return true; } -bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex *pindex) +bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) { AssertLockHeld(cs_main); @@ -3411,10 +3410,10 @@ bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensus setBlockIndexCandidates.erase(pindexWalk); // ActivateBestChain considers blocks already in chainActive // unconditionally valid already, so force disconnect away from it. - if (!DisconnectTip(state, consensusParams)) { + if (!DisconnectTip(state, chainparams)) { mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); mempool.removeWithoutBranchId( - CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, consensusParams)); + CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, chainparams.GetConsensus())); return false; } } @@ -3432,7 +3431,7 @@ bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensus InvalidChainFound(pindex); mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); mempool.removeWithoutBranchId( - CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, consensusParams)); + CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, chainparams.GetConsensus())); return true; } @@ -4607,7 +4606,7 @@ bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches) // of the blockchain). break; } - if (!DisconnectTip(state, params.GetConsensus(), true)) { + if (!DisconnectTip(state, params, true)) { return error("RewindBlockIndex: unable to disconnect block at height %i", pindex->nHeight); } // Occasionally flush state to disk. diff --git a/src/main.h b/src/main.h index c7395dabd33..24652448791 100644 --- a/src/main.h +++ b/src/main.h @@ -565,7 +565,7 @@ class CVerifyDB { CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator); /** Mark a block as invalid. */ -bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex *pindex); +bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex); /** Remove invalidity status from a block and its descendants. */ bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 4305070e0aa..c0ca1f07c43 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -976,7 +976,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); CBlockIndex* pblockindex = mapBlockIndex[hash]; - InvalidateBlock(state, Params().GetConsensus(), pblockindex); + InvalidateBlock(state, Params(), pblockindex); } if (state.IsValid()) { From e9128c4a1dcbd2f6dc5f31dce46e76eba391e0f6 Mon Sep 17 00:00:00 2001 From: face Date: Tue, 19 Apr 2016 16:16:39 +0300 Subject: [PATCH 100/127] Explicitly pass CChainParams to ConnectBlock --- src/main.cpp | 10 +++++----- src/main.h | 3 ++- src/zcbenchmarks.cpp | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index b46804a99bf..b8fd9082785 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2490,9 +2490,9 @@ static int64_t nTimeIndex = 0; static int64_t nTimeCallbacks = 0; static int64_t nTimeTotal = 0; -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, + CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck) { - const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); bool fExpensiveChecks = true; @@ -3116,7 +3116,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); { CCoinsViewCache view(pcoinsTip); - bool rv = ConnectBlock(*pblock, state, pindexNew, view); + bool rv = ConnectBlock(*pblock, state, pindexNew, view, chainparams); GetMainSignals().BlockChecked(*pblock, state); if (!rv) { if (state.IsInvalid()) @@ -4076,7 +4076,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, return false; if (!ContextualCheckBlock(block, state, pindexPrev)) return false; - if (!ConnectBlock(block, state, &indexDummy, viewNew, true)) + if (!ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true)) return false; assert(state.IsValid()); @@ -4512,7 +4512,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, CBlock block; if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - if (!ConnectBlock(block, state, pindex, coins)) + if (!ConnectBlock(block, state, pindex, coins, chainparams)) return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); } } diff --git a/src/main.h b/src/main.h index 24652448791..51db65db4c4 100644 --- a/src/main.h +++ b/src/main.h @@ -483,7 +483,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn /** Apply the effects of this block (with given index) on the UTXO set represented by coins. * Validity checks that depend on the UTXO set are also done; ConnectBlock() * can fail if those validity checks fail (among other reasons). */ -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, + const CChainParams& chainparams, bool fJustCheck = false); /** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index d257ce8ece9..cb4cc181258 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -556,7 +556,7 @@ double benchmark_connectblock_slow() CValidationState state; struct timeval tv_start; timer_start(tv_start); - assert(ConnectBlock(block, state, &index, view, true)); + assert(ConnectBlock(block, state, &index, view, Params(), true)); auto duration = timer_stop(tv_start); // Undo alterations to global state From 3647f0a7b10fa96da632bda2a083915f741e1b2f Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 5 Apr 2016 15:14:48 +0200 Subject: [PATCH 101/127] =?UTF-8?q?Break=20circular=20dependency=20main=20?= =?UTF-8?q?=E2=86=94=20txdb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Break the circular dependency between main and txdb by: - Moving `CBlockFileInfo` from `main.h` to `chain.h`. I think this makes sense, as the other block-file stuff is there too. - Moving `CDiskTxPos` from `main.h` to `txdb.h`. This type seems specific to txdb. - Pass a functor `insertBlockIndex` to `LoadBlockIndexGuts`. This leaves it up to the caller how to insert block indices. Zcash: This does not actually break the circular dependency for us yet, as we still need to pull in bitcoin/bitcoin#7756 and bitcoin/bitcoin#7904. --- src/chain.h | 56 +++++++++++++++++++++++++++++++++++-- src/main.cpp | 3 +- src/main.h | 78 ---------------------------------------------------- src/txdb.cpp | 6 ++-- src/txdb.h | 32 +++++++++++++++++++-- 5 files changed, 87 insertions(+), 88 deletions(-) diff --git a/src/chain.h b/src/chain.h index a532c85642f..5a7b3ad9cf4 100644 --- a/src/chain.h +++ b/src/chain.h @@ -14,11 +14,63 @@ #include -#include - static const int SPROUT_VALUE_VERSION = 1001400; static const int SAPLING_VALUE_VERSION = 1010100; +class CBlockFileInfo +{ +public: + unsigned int nBlocks; //!< number of blocks stored in file + unsigned int nSize; //!< number of used bytes of block file + unsigned int nUndoSize; //!< number of used bytes in the undo file + unsigned int nHeightFirst; //!< lowest height of block in file + unsigned int nHeightLast; //!< highest height of block in file + uint64_t nTimeFirst; //!< earliest time of block in file + uint64_t nTimeLast; //!< latest time of block in file + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(VARINT(nBlocks)); + READWRITE(VARINT(nSize)); + READWRITE(VARINT(nUndoSize)); + READWRITE(VARINT(nHeightFirst)); + READWRITE(VARINT(nHeightLast)); + READWRITE(VARINT(nTimeFirst)); + READWRITE(VARINT(nTimeLast)); + } + + void SetNull() { + nBlocks = 0; + nSize = 0; + nUndoSize = 0; + nHeightFirst = 0; + nHeightLast = 0; + nTimeFirst = 0; + nTimeLast = 0; + } + + CBlockFileInfo() { + SetNull(); + } + + std::string ToString() const; + + /** update statistics (does not update nSize) */ + void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) { + if (nBlocks==0 || nHeightFirst > nHeightIn) + nHeightFirst = nHeightIn; + if (nBlocks==0 || nTimeFirst > nTimeIn) + nTimeFirst = nTimeIn; + nBlocks++; + if (nHeightIn > nHeightLast) + nHeightLast = nHeightIn; + if (nTimeIn > nTimeLast) + nTimeLast = nTimeIn; + } +}; + struct CDiskBlockPos { int nFile; diff --git a/src/main.cpp b/src/main.cpp index b8fd9082785..2485ea4503f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4258,8 +4258,7 @@ CBlockIndex * InsertBlockIndex(uint256 hash) bool static LoadBlockIndexDB() { const CChainParams& chainparams = Params(); - - if (!pblocktree->LoadBlockIndexGuts()) + if (!pblocktree->LoadBlockIndexGuts(InsertBlockIndex)) return false; boost::this_thread::interruption_point(); diff --git a/src/main.h b/src/main.h index 51db65db4c4..33e95247a4a 100644 --- a/src/main.h +++ b/src/main.h @@ -290,30 +290,6 @@ struct CNodeStateStats { std::vector vHeightInFlight; }; -struct CDiskTxPos : public CDiskBlockPos -{ - unsigned int nTxOffset; // after header - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(*(CDiskBlockPos*)this); - READWRITE(VARINT(nTxOffset)); - } - - CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) { - } - - CDiskTxPos() { - SetNull(); - } - - void SetNull() { - CDiskBlockPos::SetNull(); - nTxOffset = 0; - } -}; CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree); @@ -500,60 +476,6 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, */ bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches); -class CBlockFileInfo -{ -public: - unsigned int nBlocks; //!< number of blocks stored in file - unsigned int nSize; //!< number of used bytes of block file - unsigned int nUndoSize; //!< number of used bytes in the undo file - unsigned int nHeightFirst; //!< lowest height of block in file - unsigned int nHeightLast; //!< highest height of block in file - uint64_t nTimeFirst; //!< earliest time of block in file - uint64_t nTimeLast; //!< latest time of block in file - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(VARINT(nBlocks)); - READWRITE(VARINT(nSize)); - READWRITE(VARINT(nUndoSize)); - READWRITE(VARINT(nHeightFirst)); - READWRITE(VARINT(nHeightLast)); - READWRITE(VARINT(nTimeFirst)); - READWRITE(VARINT(nTimeLast)); - } - - void SetNull() { - nBlocks = 0; - nSize = 0; - nUndoSize = 0; - nHeightFirst = 0; - nHeightLast = 0; - nTimeFirst = 0; - nTimeLast = 0; - } - - CBlockFileInfo() { - SetNull(); - } - - std::string ToString() const; - - /** update statistics (does not update nSize) */ - void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) { - if (nBlocks==0 || nHeightFirst > nHeightIn) - nHeightFirst = nHeightIn; - if (nBlocks==0 || nTimeFirst > nTimeIn) - nTimeFirst = nTimeIn; - nBlocks++; - if (nHeightIn > nHeightLast) - nHeightLast = nHeightIn; - if (nTimeIn > nTimeLast) - nTimeLast = nTimeIn; - } -}; - /** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */ class CVerifyDB { public: diff --git a/src/txdb.cpp b/src/txdb.cpp index 5ed75f3c969..2d421d36934 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -456,7 +456,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { return true; } -bool CBlockTreeDB::LoadBlockIndexGuts() +bool CBlockTreeDB::LoadBlockIndexGuts(boost::function insertBlockIndex) { boost::scoped_ptr pcursor(NewIterator()); @@ -470,8 +470,8 @@ bool CBlockTreeDB::LoadBlockIndexGuts() CDiskBlockIndex diskindex; if (pcursor->GetValue(diskindex)) { // Construct block index object - CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); - pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); + CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHash()); + pindexNew->pprev = insertBlockIndex(diskindex.hashPrev); pindexNew->nHeight = diskindex.nHeight; pindexNew->nFile = diskindex.nFile; pindexNew->nDataPos = diskindex.nDataPos; diff --git a/src/txdb.h b/src/txdb.h index c00b2d68a11..e3ef5b57c33 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -8,15 +8,16 @@ #include "coins.h" #include "dbwrapper.h" +#include "chain.h" #include #include #include #include -class CBlockFileInfo; +#include + class CBlockIndex; -struct CDiskTxPos; // START insightexplorer struct CAddressUnspentKey; @@ -45,6 +46,31 @@ static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024; //! min. -dbcache in (MiB) static const int64_t nMinDbCache = 4; +struct CDiskTxPos : public CDiskBlockPos +{ + unsigned int nTxOffset; // after header + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(*(CDiskBlockPos*)this); + READWRITE(VARINT(nTxOffset)); + } + + CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) { + } + + CDiskTxPos() { + SetNull(); + } + + void SetNull() { + CDiskBlockPos::SetNull(); + nTxOffset = 0; + } +}; + /** CCoinsView backed by the coin database (chainstate/) */ class CCoinsViewDB : public CCoinsView { @@ -108,7 +134,7 @@ class CBlockTreeDB : public CDBWrapper bool WriteFlag(const std::string &name, bool fValue); bool ReadFlag(const std::string &name, bool &fValue); - bool LoadBlockIndexGuts(); + bool LoadBlockIndexGuts(boost::function insertBlockIndex); }; #endif // BITCOIN_TXDB_H From 9f7f70e0c3c82bf703b376a600adc6b3886f4a68 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 9 Mar 2018 14:07:04 +0000 Subject: [PATCH 102/127] Globals: Remove Zcash-specific Params() calls from main.cpp --- src/main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2485ea4503f..0c404c9069d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2609,7 +2609,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin assert(view.GetSaplingAnchorAt(view.GetBestAnchor(SAPLING), sapling_tree)); // Grab the consensus branch ID for the block's height - auto consensusBranchId = CurrentEpochBranchId(pindex->nHeight, Params().GetConsensus()); + auto consensusBranchId = CurrentEpochBranchId(pindex->nHeight, chainparams.GetConsensus()); std::vector txdata; txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated @@ -2787,7 +2787,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Move this if BLOCK_VALID_CONSENSUS is ever altered. static_assert(BLOCK_VALID_CONSENSUS == BLOCK_VALID_SCRIPTS, "nCachedBranchId must be set after all consensus rules have been validated."); - if (IsActivationHeightForAnyUpgrade(pindex->nHeight, Params().GetConsensus())) { + if (IsActivationHeightForAnyUpgrade(pindex->nHeight, chainparams.GetConsensus())) { pindex->nStatus |= BLOCK_ACTIVATES_UPGRADE; pindex->nCachedBranchId = CurrentEpochBranchId(pindex->nHeight, chainparams.GetConsensus()); } else if (pindex->pprev) { @@ -3325,7 +3325,7 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); } mempool.removeWithoutBranchId( - CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); + CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, chainparams.GetConsensus())); mempool.check(pcoinsTip); // Callbacks/notifications for a new best chain. @@ -5338,7 +5338,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } // Reject incoming connections from nodes that don't know about the current epoch - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = chainparams.GetConsensus(); auto currentEpoch = CurrentEpoch(GetHeight(), params); if (pfrom->nVersion < params.vUpgrades[currentEpoch].nProtocolVersion) { From 13cfabb36cd67397fce34c7544f2cef2990c4d5d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 14 Mar 2019 10:57:14 +0000 Subject: [PATCH 103/127] Globals: Explicitly pass const CChainParams& to IsStandardTx() --- src/main.cpp | 8 ++++---- src/main.h | 2 +- src/test/script_P2SH_tests.cpp | 6 +++--- src/test/transaction_tests.cpp | 34 ++++++++++++++++++---------------- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0c404c9069d..0d0a023b195 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -654,10 +654,10 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE } -bool IsStandardTx(const CTransaction& tx, string& reason, const int nHeight) +bool IsStandardTx(const CTransaction& tx, string& reason, const CChainParams& chainparams, const int nHeight) { - bool overwinterActive = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER); - bool saplingActive = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING); + bool overwinterActive = NetworkUpgradeActive(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_OVERWINTER); + bool saplingActive = NetworkUpgradeActive(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_SAPLING); if (saplingActive) { // Sapling standard rules apply @@ -1400,7 +1400,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Rather not work on nonstandard transactions (unless -testnet/-regtest) string reason; - if (Params().RequireStandard() && !IsStandardTx(tx, reason, nextBlockHeight)) + if (Params().RequireStandard() && !IsStandardTx(tx, reason, Params(), nextBlockHeight)) return state.DoS(0, error("AcceptToMemoryPool: nonstandard transaction: %s", reason), REJECT_NONSTANDARD, reason); diff --git a/src/main.h b/src/main.h index 33e95247a4a..ca631adba95 100644 --- a/src/main.h +++ b/src/main.h @@ -356,7 +356,7 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio /** Check for standard transaction types * @return True if all outputs (scriptPubKeys) use only standard transaction forms */ -bool IsStandardTx(const CTransaction& tx, std::string& reason, int nHeight = 0); +bool IsStandardTx(const CTransaction& tx, std::string& reason, const CChainParams& chainparams, int nHeight = 0); namespace Consensus { diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index fac63dbf564..80e293675a1 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -95,7 +95,7 @@ BOOST_DATA_TEST_CASE(sign, boost::unit_test::data::xrange(static_cast(Conse txFrom.vout[i+4].scriptPubKey = standardScripts[i]; txFrom.vout[i+4].nValue = COIN; } - BOOST_CHECK(IsStandardTx(txFrom, reason)); + BOOST_CHECK(IsStandardTx(txFrom, reason, Params())); CMutableTransaction txTo[8]; // Spending transactions for (int i = 0; i < 8; i++) @@ -198,7 +198,7 @@ BOOST_DATA_TEST_CASE(set, boost::unit_test::data::xrange(static_cast(Consen txFrom.vout[i].scriptPubKey = outer[i]; txFrom.vout[i].nValue = CENT; } - BOOST_CHECK(IsStandardTx(txFrom, reason)); + BOOST_CHECK(IsStandardTx(txFrom, reason, Params())); CMutableTransaction txTo[4]; // Spending transactions for (int i = 0; i < 4; i++) @@ -216,7 +216,7 @@ BOOST_DATA_TEST_CASE(set, boost::unit_test::data::xrange(static_cast(Consen for (int i = 0; i < 4; i++) { BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i)); - BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i)); + BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason, Params()), strprintf("txTo[%d].IsStandard", i)); } } diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 88f390c1774..3c190aa7f01 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -748,6 +748,7 @@ BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) { BOOST_AUTO_TEST_CASE(test_IsStandard) { LOCK(cs_main); + auto chainparams = Params(); CBasicKeyStore keystore; CCoinsView coinsDummy; CCoinsViewCache coins(&coinsDummy); @@ -765,48 +766,49 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); string reason; - BOOST_CHECK(IsStandardTx(t, reason)); + BOOST_CHECK(IsStandardTx(t, reason, chainparams)); t.vout[0].nValue = 53; // dust - BOOST_CHECK(!IsStandardTx(t, reason)); + BOOST_CHECK(!IsStandardTx(t, reason, chainparams)); t.vout[0].nValue = 2730; // not dust - BOOST_CHECK(IsStandardTx(t, reason)); + BOOST_CHECK(IsStandardTx(t, reason, chainparams)); t.vout[0].scriptPubKey = CScript() << OP_1; - BOOST_CHECK(!IsStandardTx(t, reason)); + BOOST_CHECK(!IsStandardTx(t, reason, chainparams)); // 80-byte TX_NULL_DATA (standard) t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); - BOOST_CHECK(IsStandardTx(t, reason)); + BOOST_CHECK(IsStandardTx(t, reason, chainparams)); // 81-byte TX_NULL_DATA (non-standard) t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"); - BOOST_CHECK(!IsStandardTx(t, reason)); + BOOST_CHECK(!IsStandardTx(t, reason, chainparams)); // TX_NULL_DATA w/o PUSHDATA t.vout.resize(1); t.vout[0].scriptPubKey = CScript() << OP_RETURN; - BOOST_CHECK(IsStandardTx(t, reason)); + BOOST_CHECK(IsStandardTx(t, reason, chainparams)); // Only one TX_NULL_DATA permitted in all cases t.vout.resize(2); t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); - BOOST_CHECK(!IsStandardTx(t, reason)); + BOOST_CHECK(!IsStandardTx(t, reason, chainparams)); t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); t.vout[1].scriptPubKey = CScript() << OP_RETURN; - BOOST_CHECK(!IsStandardTx(t, reason)); + BOOST_CHECK(!IsStandardTx(t, reason, chainparams)); t.vout[0].scriptPubKey = CScript() << OP_RETURN; t.vout[1].scriptPubKey = CScript() << OP_RETURN; - BOOST_CHECK(!IsStandardTx(t, reason)); + BOOST_CHECK(!IsStandardTx(t, reason, chainparams)); } BOOST_AUTO_TEST_CASE(test_IsStandardV2) { LOCK(cs_main); + auto chainparams = Params(); CBasicKeyStore keystore; CCoinsView coinsDummy; CCoinsViewCache coins(&coinsDummy); @@ -826,33 +828,33 @@ BOOST_AUTO_TEST_CASE(test_IsStandardV2) string reason; // A v2 transaction with no JoinSplits is still standard. t.nVersion = 2; - BOOST_CHECK(IsStandardTx(t, reason)); + BOOST_CHECK(IsStandardTx(t, reason, chainparams)); // ... and with one JoinSplit. t.vjoinsplit.push_back(JSDescription()); - BOOST_CHECK(IsStandardTx(t, reason)); + BOOST_CHECK(IsStandardTx(t, reason, chainparams)); // ... and when that JoinSplit takes from a transparent input. JSDescription *jsdesc = &t.vjoinsplit[0]; jsdesc->vpub_old = 10*CENT; t.vout[0].nValue -= 10*CENT; - BOOST_CHECK(IsStandardTx(t, reason)); + BOOST_CHECK(IsStandardTx(t, reason, chainparams)); // A v2 transaction with JoinSplits but no transparent inputs is standard. jsdesc->vpub_old = 0; jsdesc->vpub_new = 100*CENT; t.vout[0].nValue = 90*CENT; t.vin.resize(0); - BOOST_CHECK(IsStandardTx(t, reason)); + BOOST_CHECK(IsStandardTx(t, reason, chainparams)); // v2 transactions can still be non-standard for the same reasons as v1. t.vout[0].nValue = 53; // dust - BOOST_CHECK(!IsStandardTx(t, reason)); + BOOST_CHECK(!IsStandardTx(t, reason, chainparams)); // v3 is not standard. t.nVersion = 3; t.vout[0].nValue = 90*CENT; - BOOST_CHECK(!IsStandardTx(t, reason)); + BOOST_CHECK(!IsStandardTx(t, reason, chainparams)); } BOOST_AUTO_TEST_SUITE_END() From 7ef947c32bd22e7c3ef367b138a98bafadb328f2 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 14 Mar 2019 11:02:47 +0000 Subject: [PATCH 104/127] Globals: Explicit const CChainParams& arg for main: - CheckBlockHeader - CheckBlock --- src/gtest/test_checkblock.cpp | 4 ++-- src/main.cpp | 25 +++++++++++++++---------- src/main.h | 5 ++++- src/test/checkblock_tests.cpp | 2 +- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/gtest/test_checkblock.cpp b/src/gtest/test_checkblock.cpp index 2919e1314d7..de073565a2d 100644 --- a/src/gtest/test_checkblock.cpp +++ b/src/gtest/test_checkblock.cpp @@ -31,7 +31,7 @@ TEST(CheckBlock, VersionTooLow) { MockCValidationState state; EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "version-too-low", false)).Times(1); - EXPECT_FALSE(CheckBlock(block, state, verifier, false, false)); + EXPECT_FALSE(CheckBlock(block, state, Params(), verifier, false, false)); } @@ -64,7 +64,7 @@ TEST(CheckBlock, BlockSproutRejectsBadVersion) { auto verifier = libzcash::ProofVerifier::Strict(); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-version-too-low", false)).Times(1); - EXPECT_FALSE(CheckBlock(block, state, verifier, false, false)); + EXPECT_FALSE(CheckBlock(block, state, Params(), verifier, false, false)); } diff --git a/src/main.cpp b/src/main.cpp index 0d0a023b195..2c5f6b65d74 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2508,7 +2508,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin auto disabledVerifier = libzcash::ProofVerifier::Disabled(); // Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in - if (!CheckBlock(block, state, fExpensiveChecks ? verifier : disabledVerifier, !fJustCheck, !fJustCheck)) + if (!CheckBlock(block, state, chainparams, fExpensiveChecks ? verifier : disabledVerifier, !fJustCheck, !fJustCheck)) return false; // verify that the view's current state corresponds to the previous block @@ -3713,7 +3713,11 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne return true; } -bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW) +bool CheckBlockHeader( + const CBlockHeader& block, + CValidationState& state, + const CChainParams& chainparams, + bool fCheckPOW) { // Check block version if (block.nVersion < MIN_BLOCK_VERSION) @@ -3721,12 +3725,12 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f REJECT_INVALID, "version-too-low"); // Check Equihash solution is valid - if (fCheckPOW && !CheckEquihashSolution(&block, Params().GetConsensus())) + if (fCheckPOW && !CheckEquihashSolution(&block, chainparams.GetConsensus())) return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"), REJECT_INVALID, "invalid-solution"); // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) + if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), REJECT_INVALID, "high-hash"); @@ -3739,6 +3743,7 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f } bool CheckBlock(const CBlock& block, CValidationState& state, + const CChainParams& chainparams, libzcash::ProofVerifier& verifier, bool fCheckPOW, bool fCheckMerkleRoot) { @@ -3746,7 +3751,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, // Check that the header is valid (particularly PoW). This is mostly // redundant with the call in AcceptBlockHeader. - if (!CheckBlockHeader(block, state, fCheckPOW)) + if (!CheckBlockHeader(block, state, chainparams, fCheckPOW)) return false; // Check the merkle root. @@ -3915,7 +3920,7 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state return true; } - if (!CheckBlockHeader(block, state)) + if (!CheckBlockHeader(block, state, chainparams)) return false; // Get prev block index @@ -3980,7 +3985,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha // See method docstring for why this is always disabled auto verifier = libzcash::ProofVerifier::Disabled(); - if ((!CheckBlock(block, state, verifier)) || !ContextualCheckBlock(block, state, pindex->pprev)) { + if ((!CheckBlock(block, state, chainparams, verifier)) || !ContextualCheckBlock(block, state, pindex->pprev)) { if (state.IsInvalid() && !state.CorruptionPossible()) { pindex->nStatus |= BLOCK_FAILED_VALID; setDirtyBlockIndex.insert(pindex); @@ -4030,7 +4035,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c { // Preliminary checks auto verifier = libzcash::ProofVerifier::Disabled(); - bool checked = CheckBlock(*pblock, state, verifier); + bool checked = CheckBlock(*pblock, state, chainparams, verifier); { LOCK(cs_main); @@ -4072,7 +4077,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, // NOTE: CheckBlockHeader is called by CheckBlock if (!ContextualCheckBlockHeader(block, state, pindexPrev)) return false; - if (!CheckBlock(block, state, verifier, fCheckPOW, fCheckMerkleRoot)) + if (!CheckBlock(block, state, chainparams, verifier, fCheckPOW, fCheckMerkleRoot)) return false; if (!ContextualCheckBlock(block, state, pindexPrev)) return false; @@ -4469,7 +4474,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); // check level 1: verify block validity - if (nCheckLevel >= 1 && !CheckBlock(block, state, verifier)) + if (nCheckLevel >= 1 && !CheckBlock(block, state, chainparams, verifier)) return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); // check level 2: verify undo validity if (nCheckLevel >= 2 && pindex) { diff --git a/src/main.h b/src/main.h index ca631adba95..7e85094382e 100644 --- a/src/main.h +++ b/src/main.h @@ -445,8 +445,11 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus /** Functions for validating blocks and updating the block tree */ /** Context-independent validity checks */ -bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); +bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, + const CChainParams& chainparams, + bool fCheckPOW = true); bool CheckBlock(const CBlock& block, CValidationState& state, + const CChainParams& chainparams, libzcash::ProofVerifier& verifier, bool fCheckPOW = true, bool fCheckMerkleRoot = true); diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index c813c9af9ae..dc906282034 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(May15) // After May 15'th, big blocks are OK: forkingBlock.nTime = tMay15; // Invalidates PoW auto verifier = libzcash::ProofVerifier::Strict(); - BOOST_CHECK(CheckBlock(forkingBlock, state, verifier, false, false)); + BOOST_CHECK(CheckBlock(forkingBlock, state, Params(), verifier, false, false)); } SetMockTime(0); From be947219530bb4ec2a7c7d028163ce5c92763c0c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 14 Mar 2019 11:11:10 +0000 Subject: [PATCH 105/127] Globals: Explicitly pass const CChainParams& to ContextualCheckTransaction() --- src/gtest/test_checktransaction.cpp | 25 ++++++++++++++----------- src/gtest/test_transaction_builder.cpp | 8 ++++---- src/main.cpp | 11 ++++++----- src/main.h | 3 ++- src/test/transaction_tests.cpp | 4 ++-- 5 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index cf9d7744168..11eba2e9147 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -167,7 +167,7 @@ TEST(checktransaction_tests, BadTxnsOversize) { // ... but fails contextual ones! EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-oversize", false)).Times(1); - EXPECT_FALSE(ContextualCheckTransaction(tx, state, 1, 100)); + EXPECT_FALSE(ContextualCheckTransaction(tx, state, Params(), 1, 100)); } { @@ -188,7 +188,7 @@ TEST(checktransaction_tests, BadTxnsOversize) { MockCValidationState state; EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state)); - EXPECT_TRUE(ContextualCheckTransaction(tx, state, 1, 100)); + EXPECT_TRUE(ContextualCheckTransaction(tx, state, Params(), 1, 100)); // Revert to default RegtestDeactivateSapling(); @@ -496,6 +496,7 @@ TEST(checktransaction_tests, bad_txns_prevout_null) { TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) { SelectParams(CBaseChainParams::REGTEST); + auto chainparams = Params(); CMutableTransaction mtx = GetValidTransaction(); mtx.joinSplitSig[0] += 1; @@ -504,13 +505,14 @@ TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) { MockCValidationState state; // during initial block download, DoS ban score should be zero, else 100 EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); - ContextualCheckTransaction(tx, state, 0, 100, []() { return true; }); + ContextualCheckTransaction(tx, state, chainparams, 0, 100, []() { return true; }); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); - ContextualCheckTransaction(tx, state, 0, 100, []() { return false; }); + ContextualCheckTransaction(tx, state, chainparams, 0, 100, []() { return false; }); } TEST(checktransaction_tests, non_canonical_ed25519_signature) { SelectParams(CBaseChainParams::REGTEST); + auto chainparams = Params(); CMutableTransaction mtx = GetValidTransaction(); @@ -518,7 +520,7 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) { { CTransaction tx(mtx); MockCValidationState state; - EXPECT_TRUE(ContextualCheckTransaction(tx, state, 0, 100)); + EXPECT_TRUE(ContextualCheckTransaction(tx, state, chainparams, 0, 100)); } // Copied from libsodium/crypto_sign/ed25519/ref10/open.c @@ -540,9 +542,9 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) { MockCValidationState state; // during initial block download, DoS ban score should be zero, else 100 EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); - ContextualCheckTransaction(tx, state, 0, 100, []() { return true; }); + ContextualCheckTransaction(tx, state, chainparams, 0, 100, []() { return true; }); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); - ContextualCheckTransaction(tx, state, 0, 100, []() { return false; }); + ContextualCheckTransaction(tx, state, chainparams, 0, 100, []() { return false; }); } TEST(checktransaction_tests, OverwinterConstructors) { @@ -797,7 +799,7 @@ TEST(checktransaction_tests, OverwinterVersionNumberHigh) { UNSAFE_CTransaction tx(mtx); MockCValidationState state; EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-tx-overwinter-version-too-high", false)).Times(1); - ContextualCheckTransaction(tx, state, 1, 100); + ContextualCheckTransaction(tx, state, Params(), 1, 100); // Revert to default UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); @@ -822,6 +824,7 @@ TEST(checktransaction_tests, OverwinterBadVersionGroupId) { // This tests an Overwinter transaction checked against Sprout TEST(checktransaction_tests, OverwinterNotActive) { SelectParams(CBaseChainParams::TESTNET); + auto chainparams = Params(); CMutableTransaction mtx = GetValidTransaction(); mtx.fOverwintered = true; @@ -833,9 +836,9 @@ TEST(checktransaction_tests, OverwinterNotActive) { MockCValidationState state; // during initial block download, DoS ban score should be zero, else 100 EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1); - ContextualCheckTransaction(tx, state, 1, 100, []() { return true; }); + ContextualCheckTransaction(tx, state, chainparams, 1, 100, []() { return true; }); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1); - ContextualCheckTransaction(tx, state, 1, 100, []() { return false; }); + ContextualCheckTransaction(tx, state, chainparams, 1, 100, []() { return false; }); } // This tests a transaction without the fOverwintered flag set, against the Overwinter consensus rule set. @@ -852,7 +855,7 @@ TEST(checktransaction_tests, OverwinterFlagNotSet) { CTransaction tx(mtx); MockCValidationState state; EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-flag-not-set", false)).Times(1); - ContextualCheckTransaction(tx, state, 1, 100); + ContextualCheckTransaction(tx, state, Params(), 1, 100); // Revert to default UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); diff --git a/src/gtest/test_transaction_builder.cpp b/src/gtest/test_transaction_builder.cpp index 3fe71d21b31..5ebf1d737c6 100644 --- a/src/gtest/test_transaction_builder.cpp +++ b/src/gtest/test_transaction_builder.cpp @@ -106,7 +106,7 @@ TEST(TransactionBuilder, TransparentToSapling) EXPECT_EQ(tx.valueBalance, -40000); CValidationState state; - EXPECT_TRUE(ContextualCheckTransaction(tx, state, 2, 0)); + EXPECT_TRUE(ContextualCheckTransaction(tx, state, Params(), 2, 0)); EXPECT_EQ(state.GetRejectReason(), ""); // Revert to default @@ -143,7 +143,7 @@ TEST(TransactionBuilder, SaplingToSapling) { EXPECT_EQ(tx.valueBalance, 10000); CValidationState state; - EXPECT_TRUE(ContextualCheckTransaction(tx, state, 3, 0)); + EXPECT_TRUE(ContextualCheckTransaction(tx, state, Params(), 3, 0)); EXPECT_EQ(state.GetRejectReason(), ""); // Revert to default @@ -181,7 +181,7 @@ TEST(TransactionBuilder, SaplingToSprout) { EXPECT_EQ(tx.valueBalance, 35000); CValidationState state; - EXPECT_TRUE(ContextualCheckTransaction(tx, state, 3, 0)); + EXPECT_TRUE(ContextualCheckTransaction(tx, state, Params(), 3, 0)); EXPECT_EQ(state.GetRejectReason(), ""); // Revert to default @@ -242,7 +242,7 @@ TEST(TransactionBuilder, SproutToSproutAndSapling) { EXPECT_EQ(tx.valueBalance, -5000); CValidationState state; - EXPECT_TRUE(ContextualCheckTransaction(tx, state, 4, 0)); + EXPECT_TRUE(ContextualCheckTransaction(tx, state, Params(), 4, 0)); EXPECT_EQ(state.GetRejectReason(), ""); // Revert to default diff --git a/src/main.cpp b/src/main.cpp index 2c5f6b65d74..90cdb234225 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -891,12 +891,13 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in bool ContextualCheckTransaction( const CTransaction& tx, CValidationState &state, + const CChainParams& chainparams, const int nHeight, const int dosLevel, bool (*isInitBlockDownload)()) { - bool overwinterActive = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER); - bool saplingActive = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING); + bool overwinterActive = NetworkUpgradeActive(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_OVERWINTER); + bool saplingActive = NetworkUpgradeActive(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_SAPLING); bool isSprout = !overwinterActive; // If Sprout rules apply, reject transactions which are intended for Overwinter and beyond @@ -983,7 +984,7 @@ bool ContextualCheckTransaction( !tx.vShieldedSpend.empty() || !tx.vShieldedOutput.empty()) { - auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus()); + auto consensusBranchId = CurrentEpochBranchId(nHeight, chainparams.GetConsensus()); // Empty output script. CScript scriptCode; try { @@ -1382,7 +1383,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // DoS level set to 10 to be more forgiving. // Check transaction contextually against the set of consensus rules which apply in the next block to be mined. - if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) { + if (!ContextualCheckTransaction(tx, state, Params(), nextBlockHeight, 10)) { return error("AcceptToMemoryPool: ContextualCheckTransaction failed"); } @@ -3852,7 +3853,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn BOOST_FOREACH(const CTransaction& tx, block.vtx) { // Check transaction contextually against consensus rules at block height - if (!ContextualCheckTransaction(tx, state, nHeight, 100)) { + if (!ContextualCheckTransaction(tx, state, Params(), nHeight, 100)) { return false; // Failure reason has been set in validation state object } diff --git a/src/main.h b/src/main.h index 7e85094382e..af62a49f289 100644 --- a/src/main.h +++ b/src/main.h @@ -341,7 +341,8 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons std::vector *pvChecks = NULL); /** Check a transaction contextually against a set of consensus rules */ -bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, int nHeight, int dosLevel, +bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, + const CChainParams& chainparams, int nHeight, int dosLevel, bool (*isInitBlockDownload)() = IsInitialBlockDownload); /** Apply the effects of this transaction on the UTXO set represented by view */ diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 3c190aa7f01..4219e01f4ce 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -491,7 +491,7 @@ void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransa jsdesc->nullifiers[1] = GetRandHash(); BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state)); - BOOST_CHECK(!ContextualCheckTransaction(newTx, state, 0, 100)); + BOOST_CHECK(!ContextualCheckTransaction(newTx, state, Params(), 0, 100)); BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature"); // Empty output script. @@ -505,7 +505,7 @@ void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransa ) == 0); BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state)); - BOOST_CHECK(ContextualCheckTransaction(newTx, state, 0, 100)); + BOOST_CHECK(ContextualCheckTransaction(newTx, state, Params(), 0, 100)); } { // Ensure that values within the joinsplit are well-formed. From c6012fe9232011cfde86a0a43556439b919b5484 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 14 Mar 2019 11:18:32 +0000 Subject: [PATCH 106/127] Globals: Explicit const CChainParams& arg for main: - ContextualCheckBlockHeader - ContextualCheckBlock --- src/gtest/test_checkblock.cpp | 12 ++++++------ src/main.cpp | 23 +++++++++++++---------- src/main.h | 6 ++++-- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/gtest/test_checkblock.cpp b/src/gtest/test_checkblock.cpp index de073565a2d..4195647e815 100644 --- a/src/gtest/test_checkblock.cpp +++ b/src/gtest/test_checkblock.cpp @@ -117,7 +117,7 @@ class ContextualCheckBlockTest : public ::testing::Test { // We now expect this to be a valid block. MockCValidationState state; - EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev)); + EXPECT_TRUE(ContextualCheckBlock(block, state, Params(), &indexPrev)); } // Expects a height-1 block containing a given transaction to fail @@ -135,7 +135,7 @@ class ContextualCheckBlockTest : public ::testing::Test { // We now expect this to be an invalid block, for the given reason. MockCValidationState state; EXPECT_CALL(state, DoS(level, false, REJECT_INVALID, reason, false)).Times(1); - EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev)); + EXPECT_FALSE(ContextualCheckBlock(block, state, Params(), &indexPrev)); } }; @@ -152,7 +152,7 @@ TEST_F(ContextualCheckBlockTest, BadCoinbaseHeight) { // Treating block as genesis should pass MockCValidationState state; - EXPECT_TRUE(ContextualCheckBlock(block, state, NULL)); + EXPECT_TRUE(ContextualCheckBlock(block, state, Params(), NULL)); // Give the transaction a Founder's Reward vout mtx.vout.push_back(CTxOut( @@ -166,20 +166,20 @@ TEST_F(ContextualCheckBlockTest, BadCoinbaseHeight) { CBlockIndex indexPrev {prev}; indexPrev.nHeight = 0; EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-height", false)).Times(1); - EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev)); + EXPECT_FALSE(ContextualCheckBlock(block, state, Params(), &indexPrev)); // Setting to an incorrect height should fail mtx.vin[0].scriptSig = CScript() << 2 << OP_0; CTransaction tx3 {mtx}; block.vtx[0] = tx3; EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-height", false)).Times(1); - EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev)); + EXPECT_FALSE(ContextualCheckBlock(block, state, Params(), &indexPrev)); // After correcting the scriptSig, should pass mtx.vin[0].scriptSig = CScript() << 1 << OP_0; CTransaction tx4 {mtx}; block.vtx[0] = tx4; - EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev)); + EXPECT_TRUE(ContextualCheckBlock(block, state, Params(), &indexPrev)); } // TEST PLAN: first, check that each ruleset accepts its own transaction type. diff --git a/src/main.cpp b/src/main.cpp index 90cdb234225..64887fcdd87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3806,9 +3806,10 @@ bool CheckBlock(const CBlock& block, CValidationState& state, return true; } -bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev) +bool ContextualCheckBlockHeader( + const CBlockHeader& block, CValidationState& state, + const CChainParams& chainParams, CBlockIndex * const pindexPrev) { - const CChainParams& chainParams = Params(); const Consensus::Params& consensusParams = chainParams.GetConsensus(); uint256 hash = block.GetHash(); if (hash == consensusParams.hashGenesisBlock) @@ -3844,16 +3845,18 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta return true; } -bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex * const pindexPrev) +bool ContextualCheckBlock( + const CBlock& block, CValidationState& state, + const CChainParams& chainparams, CBlockIndex * const pindexPrev) { const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; - const Consensus::Params& consensusParams = Params().GetConsensus(); + const Consensus::Params& consensusParams = chainparams.GetConsensus(); // Check that all transactions are finalized BOOST_FOREACH(const CTransaction& tx, block.vtx) { // Check transaction contextually against consensus rules at block height - if (!ContextualCheckTransaction(tx, state, Params(), nHeight, 100)) { + if (!ContextualCheckTransaction(tx, state, chainparams, nHeight, 100)) { return false; // Failure reason has been set in validation state object } @@ -3888,7 +3891,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn bool found = false; BOOST_FOREACH(const CTxOut& output, block.vtx[0].vout) { - if (output.scriptPubKey == Params().GetFoundersRewardScriptAtHeight(nHeight)) { + if (output.scriptPubKey == chainparams.GetFoundersRewardScriptAtHeight(nHeight)) { if (output.nValue == (GetBlockSubsidy(nHeight, consensusParams) / 5)) { found = true; break; @@ -3935,7 +3938,7 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); } - if (!ContextualCheckBlockHeader(block, state, pindexPrev)) + if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev)) return false; if (pindex == NULL) @@ -3986,7 +3989,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha // See method docstring for why this is always disabled auto verifier = libzcash::ProofVerifier::Disabled(); - if ((!CheckBlock(block, state, chainparams, verifier)) || !ContextualCheckBlock(block, state, pindex->pprev)) { + if ((!CheckBlock(block, state, chainparams, verifier)) || !ContextualCheckBlock(block, state, chainparams, pindex->pprev)) { if (state.IsInvalid() && !state.CorruptionPossible()) { pindex->nStatus |= BLOCK_FAILED_VALID; setDirtyBlockIndex.insert(pindex); @@ -4076,11 +4079,11 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, auto verifier = libzcash::ProofVerifier::Disabled(); // NOTE: CheckBlockHeader is called by CheckBlock - if (!ContextualCheckBlockHeader(block, state, pindexPrev)) + if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev)) return false; if (!CheckBlock(block, state, chainparams, verifier, fCheckPOW, fCheckMerkleRoot)) return false; - if (!ContextualCheckBlock(block, state, pindexPrev)) + if (!ContextualCheckBlock(block, state, chainparams, pindexPrev)) return false; if (!ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true)) return false; diff --git a/src/main.h b/src/main.h index af62a49f289..be769b6eb88 100644 --- a/src/main.h +++ b/src/main.h @@ -457,8 +457,10 @@ bool CheckBlock(const CBlock& block, CValidationState& state, /** Context-dependent validity checks. * By "context", we mean only the previous block headers, but not the UTXO * set; UTXO-related validity checks are done in ConnectBlock(). */ -bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev); -bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); +bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, + const CChainParams& chainparams, CBlockIndex *pindexPrev); +bool ContextualCheckBlock(const CBlock& block, CValidationState& state, + const CChainParams& chainparams, CBlockIndex *pindexPrev); /** Apply the effects of this block (with given index) on the UTXO set represented by coins. * Validity checks that depend on the UTXO set are also done; ConnectBlock() From a3b64d8677200dbebdea18d7f1fe85b60c15833e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 14 Mar 2019 11:24:53 +0000 Subject: [PATCH 107/127] Globals: Explicitly pass const CChainParams& to DisconnectBlock() --- src/main.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 64887fcdd87..dad36f5d0a7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2235,7 +2235,8 @@ enum DisconnectResult * The addressIndex and spentIndex will be updated if requested. */ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& state, - const CBlockIndex* pindex, CCoinsViewCache& view, bool const updateIndices) + const CBlockIndex* pindex, CCoinsViewCache& view, const CChainParams& chainparams, + const bool updateIndices) { assert(pindex->GetBlockHash() == view.GetBestBlock()); @@ -2361,7 +2362,7 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s // However, this is only reliable if the last block was on or after // the Sapling activation height. Otherwise, the last anchor was the // empty root. - if (NetworkUpgradeActive(pindex->pprev->nHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { + if (NetworkUpgradeActive(pindex->pprev->nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_SAPLING)) { view.PopAnchor(pindex->pprev->hashFinalSaplingRoot, SAPLING); } else { view.PopAnchor(SaplingMerkleTree::empty_root(), SAPLING); @@ -3035,7 +3036,7 @@ bool static DisconnectTip(CValidationState &state, const CChainParams& chainpara { CCoinsViewCache view(pcoinsTip); // insightexplorer: update indices (true) - if (DisconnectBlock(block, state, pindexDelete, view, true) != DISCONNECT_OK) + if (DisconnectBlock(block, state, pindexDelete, view, chainparams, true) != DISCONNECT_OK) return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); assert(view.Flush()); } @@ -4492,7 +4493,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, // check level 3: check for inconsistencies during memory-only disconnect of tip blocks if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) { // insightexplorer: do not update indices (false) - DisconnectResult res = DisconnectBlock(block, state, pindex, coins, false); + DisconnectResult res = DisconnectBlock(block, state, pindex, coins, chainparams, false); if (res == DISCONNECT_FAILED) { return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); } From 9e0f75dcbd08302c473fc62c883ef5a658ff49ff Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 2 Apr 2019 02:07:02 +0100 Subject: [PATCH 108/127] Consistently use chainparams and consensusParams --- src/main.cpp | 20 ++++++++++---------- src/main.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index dad36f5d0a7..8b4bf1d6f8d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4531,7 +4531,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, return true; } -bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches) +bool RewindBlockIndex(const CChainParams& chainparams, bool& clearWitnessCaches) { LOCK(cs_main); @@ -4544,8 +4544,8 @@ bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches) // // - BLOCK_ACTIVATES_UPGRADE is set only on blocks that activate upgrades. // - nCachedBranchId for each block matches what we expect. - auto sufficientlyValidated = [¶ms](const CBlockIndex* pindex) { - auto consensus = params.GetConsensus(); + auto sufficientlyValidated = [&chainparams](const CBlockIndex* pindex) { + auto consensus = chainparams.GetConsensus(); bool fFlagSet = pindex->nStatus & BLOCK_ACTIVATES_UPGRADE; bool fFlagExpected = IsActivationHeightForAnyUpgrade(pindex->nHeight, consensus); return fFlagSet == fFlagExpected && @@ -4568,7 +4568,7 @@ bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches) if (rewindLength > 0) { LogPrintf("*** First insufficiently validated block at height %d, rewind length %d\n", nHeight, rewindLength); const uint256 *phashFirstInsufValidated = chainActive[nHeight]->phashBlock; - auto networkID = params.NetworkIDString(); + auto networkID = chainparams.NetworkIDString(); // This is true when we intend to do a long rewind. bool intendedRewind = @@ -4615,7 +4615,7 @@ bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches) // of the blockchain). break; } - if (!DisconnectTip(state, params, true)) { + if (!DisconnectTip(state, chainparams, true)) { return error("RewindBlockIndex: unable to disconnect block at height %i", pindex->nHeight); } // Occasionally flush state to disk. @@ -4677,7 +4677,7 @@ bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches) PruneBlockIndexCandidates(); - CheckBlockIndex(params.GetConsensus()); + CheckBlockIndex(chainparams.GetConsensus()); if (!FlushStateToDisk(state, FLUSH_STATE_ALWAYS)) { return false; @@ -5348,14 +5348,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } // Reject incoming connections from nodes that don't know about the current epoch - const Consensus::Params& params = chainparams.GetConsensus(); - auto currentEpoch = CurrentEpoch(GetHeight(), params); - if (pfrom->nVersion < params.vUpgrades[currentEpoch].nProtocolVersion) + const Consensus::Params& consensusParams = chainparams.GetConsensus(); + auto currentEpoch = CurrentEpoch(GetHeight(), consensusParams); + if (pfrom->nVersion < consensusParams.vUpgrades[currentEpoch].nProtocolVersion) { LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE, strprintf("Version must be %d or greater", - params.vUpgrades[currentEpoch].nProtocolVersion)); + consensusParams.vUpgrades[currentEpoch].nProtocolVersion)); pfrom->fDisconnect = true; return false; } diff --git a/src/main.h b/src/main.h index be769b6eb88..13b338dddc3 100644 --- a/src/main.h +++ b/src/main.h @@ -480,7 +480,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, * clearWitnessCaches is an output parameter that will be set to true iff * witness caches should be cleared in order to handle an intended long rewind. */ -bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches); +bool RewindBlockIndex(const CChainParams& chainparams, bool& clearWitnessCaches); /** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */ class CVerifyDB { From 3ffc29b88162b93419c28dadd0a4f7a55e57cda6 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 2 Apr 2019 02:30:33 +0100 Subject: [PATCH 109/127] Globals: Explicitly pass const CChainParams& to IsInitialBlockDownload() --- src/gtest/test_checktransaction.cpp | 12 ++--- src/main.cpp | 68 ++++++++++++++--------------- src/main.h | 6 +-- src/metrics.cpp | 4 +- src/miner.cpp | 2 +- src/rpc/mining.cpp | 2 +- src/test/alert_tests.cpp | 2 +- src/wallet/wallet.cpp | 2 +- 8 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index 11eba2e9147..6897d42e9a8 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -505,9 +505,9 @@ TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) { MockCValidationState state; // during initial block download, DoS ban score should be zero, else 100 EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); - ContextualCheckTransaction(tx, state, chainparams, 0, 100, []() { return true; }); + ContextualCheckTransaction(tx, state, chainparams, 0, 100, [](const CChainParams&) { return true; }); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); - ContextualCheckTransaction(tx, state, chainparams, 0, 100, []() { return false; }); + ContextualCheckTransaction(tx, state, chainparams, 0, 100, [](const CChainParams&) { return false; }); } TEST(checktransaction_tests, non_canonical_ed25519_signature) { @@ -542,9 +542,9 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) { MockCValidationState state; // during initial block download, DoS ban score should be zero, else 100 EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); - ContextualCheckTransaction(tx, state, chainparams, 0, 100, []() { return true; }); + ContextualCheckTransaction(tx, state, chainparams, 0, 100, [](const CChainParams&) { return true; }); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); - ContextualCheckTransaction(tx, state, chainparams, 0, 100, []() { return false; }); + ContextualCheckTransaction(tx, state, chainparams, 0, 100, [](const CChainParams&) { return false; }); } TEST(checktransaction_tests, OverwinterConstructors) { @@ -836,9 +836,9 @@ TEST(checktransaction_tests, OverwinterNotActive) { MockCValidationState state; // during initial block download, DoS ban score should be zero, else 100 EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1); - ContextualCheckTransaction(tx, state, chainparams, 1, 100, []() { return true; }); + ContextualCheckTransaction(tx, state, chainparams, 1, 100, [](const CChainParams&) { return true; }); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1); - ContextualCheckTransaction(tx, state, chainparams, 1, 100, []() { return false; }); + ContextualCheckTransaction(tx, state, chainparams, 1, 100, [](const CChainParams&) { return false; }); } // This tests a transaction without the fOverwintered flag set, against the Overwinter consensus rule set. diff --git a/src/main.cpp b/src/main.cpp index 8b4bf1d6f8d..3065e694fb5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -894,7 +894,7 @@ bool ContextualCheckTransaction( const CChainParams& chainparams, const int nHeight, const int dosLevel, - bool (*isInitBlockDownload)()) + bool (*isInitBlockDownload)(const CChainParams&)) { bool overwinterActive = NetworkUpgradeActive(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_OVERWINTER); bool saplingActive = NetworkUpgradeActive(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_SAPLING); @@ -902,7 +902,7 @@ bool ContextualCheckTransaction( // If Sprout rules apply, reject transactions which are intended for Overwinter and beyond if (isSprout && tx.fOverwintered) { - return state.DoS(isInitBlockDownload() ? 0 : dosLevel, + return state.DoS(isInitBlockDownload(chainparams) ? 0 : dosLevel, error("ContextualCheckTransaction(): overwinter is not active yet"), REJECT_INVALID, "tx-overwinter-not-active"); } @@ -916,7 +916,7 @@ bool ContextualCheckTransaction( // Reject transactions with non-Sapling version group ID if (tx.fOverwintered && tx.nVersionGroupId != SAPLING_VERSION_GROUP_ID) { - return state.DoS(isInitBlockDownload() ? 0 : dosLevel, + return state.DoS(isInitBlockDownload(chainparams) ? 0 : dosLevel, error("CheckTransaction(): invalid Sapling tx version"), REJECT_INVALID, "bad-sapling-tx-version-group-id"); } @@ -941,7 +941,7 @@ bool ContextualCheckTransaction( // Reject transactions with non-Overwinter version group ID if (tx.fOverwintered && tx.nVersionGroupId != OVERWINTER_VERSION_GROUP_ID) { - return state.DoS(isInitBlockDownload() ? 0 : dosLevel, + return state.DoS(isInitBlockDownload(chainparams) ? 0 : dosLevel, error("CheckTransaction(): invalid Overwinter tx version"), REJECT_INVALID, "bad-overwinter-tx-version-group-id"); } @@ -1005,7 +1005,7 @@ bool ContextualCheckTransaction( dataToBeSigned.begin(), 32, tx.joinSplitPubKey.begin() ) != 0) { - return state.DoS(isInitBlockDownload() ? 0 : 100, + return state.DoS(isInitBlockDownload(chainparams) ? 0 : 100, error("CheckTransaction(): invalid joinsplit signature"), REJECT_INVALID, "bad-txns-invalid-joinsplit-signature"); } @@ -1599,7 +1599,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } // Store transaction in memory - pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); + pool.addUnchecked(hash, entry, !IsInitialBlockDownload(Params())); } SyncWithWallets(tx, NULL); @@ -1762,10 +1762,8 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) return nSubsidy; } -bool IsInitialBlockDownload() +bool IsInitialBlockDownload(const CChainParams& chainParams) { - const CChainParams& chainParams = Params(); - // Once this function has returned false, it must remain false. static std::atomic latchToFalse{false}; // Optimization: pre-test latch before taking the lock. @@ -1793,12 +1791,12 @@ static bool fLargeWorkInvalidChainFound = false; static CBlockIndex *pindexBestForkTip = NULL; static CBlockIndex *pindexBestForkBase = NULL; -void CheckForkWarningConditions() +void CheckForkWarningConditions(const CChainParams& chainParams) { AssertLockHeld(cs_main); // Before we get past initial download, we cannot reliably alert about forks // (we assume we don't get stuck on a fork before finishing our initial sync) - if (IsInitialBlockDownload()) + if (IsInitialBlockDownload(chainParams)) return; // If our best fork is no longer within 288 blocks (+/- 12 hours if no one mines it) @@ -1836,7 +1834,7 @@ void CheckForkWarningConditions() } } -void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) +void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip, const CChainParams& chainParams) { AssertLockHeld(cs_main); // If we are on a fork that is sufficiently large, set a warning flag @@ -1866,7 +1864,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) pindexBestForkBase = pfork; } - CheckForkWarningConditions(); + CheckForkWarningConditions(chainParams); } // Requires cs_main. @@ -1889,7 +1887,7 @@ void Misbehaving(NodeId pnode, int howmuch) LogPrintf("%s: %s (%d -> %d)\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior); } -void static InvalidChainFound(CBlockIndex* pindexNew) +void static InvalidChainFound(CBlockIndex* pindexNew, const CChainParams& chainParams) { if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork) pindexBestInvalid = pindexNew; @@ -1903,10 +1901,10 @@ void static InvalidChainFound(CBlockIndex* pindexNew) LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__, tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime())); - CheckForkWarningConditions(); + CheckForkWarningConditions(chainParams); } -void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) { +void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state, const CChainParams& chainParams) { int nDoS = 0; if (state.IsInvalid(nDoS)) { std::map::iterator it = mapBlockSource.find(pindex->GetBlockHash()); @@ -1921,7 +1919,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state pindex->nStatus |= BLOCK_FAILED_VALID; setDirtyBlockIndex.insert(pindex); setBlockIndexCandidates.erase(pindex); - InvalidChainFound(pindex); + InvalidChainFound(pindex, chainParams); } } @@ -2429,10 +2427,11 @@ void ThreadScriptCheck() { // we're being fed a bad chain (blocks being generated much // too slowly or too quickly). // -void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, +void PartitionCheck(bool (*initialDownloadCheck)(const CChainParams&), + CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing) { - if (bestHeader == NULL || initialDownloadCheck()) return; + if (bestHeader == NULL || initialDownloadCheck(Params())) return; static int64_t lastAlertTime = 0; int64_t now = GetAdjustedTime(); @@ -2995,7 +2994,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) { // Check the version of the last 100 blocks to see if we need to upgrade: static bool fWarned = false; - if (!IsInitialBlockDownload() && !fWarned) + if (!IsInitialBlockDownload(chainParams) && !fWarned) { int nUpgraded = 0; const CBlockIndex* pindex = chainActive.Tip(); @@ -3122,7 +3121,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, GetMainSignals().BlockChecked(*pblock, state); if (!rv) { if (state.IsInvalid()) - InvalidBlockFound(pindexNew, state); + InvalidBlockFound(pindexNew, state, chainparams); return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); } mapBlockSource.erase(pindexNew->GetBlockHash()); @@ -3139,7 +3138,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); // Remove conflicting transactions from the mempool. list txConflicted; - mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload()); + mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload(chainparams)); // Remove transactions that expire at new block height from mempool mempool.removeExpired(pindexNew->nHeight); @@ -3303,7 +3302,7 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c if (state.IsInvalid()) { // The block violates a consensus rule. if (!state.CorruptionPossible()) - InvalidChainFound(vpindexToConnect.back()); + InvalidChainFound(vpindexToConnect.back(), chainparams); state = CValidationState(); fInvalidFound = true; fContinue = false; @@ -3332,9 +3331,9 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c // Callbacks/notifications for a new best chain. if (fInvalidFound) - CheckForkWarningConditionsOnNewFork(vpindexToConnect.back()); + CheckForkWarningConditionsOnNewFork(vpindexToConnect.back(), chainparams); else - CheckForkWarningConditions(); + CheckForkWarningConditions(chainparams); return true; } @@ -3364,7 +3363,7 @@ bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, return false; pindexNewTip = chainActive.Tip(); - fInitialDownload = IsInitialBlockDownload(); + fInitialDownload = IsInitialBlockDownload(chainparams); } // When we reach this point, we switched to a new tip (stored in pindexNewTip). @@ -3430,7 +3429,7 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C it++; } - InvalidChainFound(pindex); + InvalidChainFound(pindex, chainparams); mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); mempool.removeWithoutBranchId( CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, chainparams.GetConsensus())); @@ -5405,7 +5404,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (!pfrom->fInbound) { // Advertise our address - if (fListen && !IsInitialBlockDownload()) + if (fListen && !IsInitialBlockDownload(chainparams)) { CAddress addr = GetLocalAddress(&pfrom->addr); if (addr.IsRoutable()) @@ -5699,7 +5698,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LOCK(cs_main); - if (IsInitialBlockDownload()) + if (IsInitialBlockDownload(chainparams)) return true; CBlockIndex* pindex = NULL; @@ -5935,7 +5934,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // unless we're still syncing with the network. // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). - bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); + bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(chainparams); ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL); int nDoS; if (state.IsInvalid(nDoS)) { @@ -6342,7 +6341,8 @@ bool ProcessMessages(CNode* pfrom) bool SendMessages(CNode* pto, bool fSendTrickle) { - const Consensus::Params& consensusParams = Params().GetConsensus(); + const CChainParams& chainParams = Params(); + const Consensus::Params& consensusParams = chainParams.GetConsensus(); { // Don't send anything until we get its version message if (pto->nVersion == 0) @@ -6383,7 +6383,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Address refresh broadcast static int64_t nLastRebroadcast; - if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) + if (!IsInitialBlockDownload(chainParams) && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) @@ -6463,7 +6463,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Resend wallet transactions that haven't gotten in a block yet // Except during reindex, importing and IBD, when old wallet // transactions become unconfirmed and spams other nodes. - if (!fReindex && !fImporting && !IsInitialBlockDownload()) + if (!fReindex && !fImporting && !IsInitialBlockDownload(chainParams)) { GetMainSignals().Broadcast(nTimeBestReceived); } @@ -6552,7 +6552,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Message: getdata (blocks) // vector vGetData; - if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload(chainParams)) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { vector vToDownload; NodeId staller = -1; FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller); diff --git a/src/main.h b/src/main.h index 13b338dddc3..2b77875c482 100644 --- a/src/main.h +++ b/src/main.h @@ -234,9 +234,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); /** Try to detect Partition (network isolation) attacks against us */ -void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing); +void PartitionCheck(bool (*initialDownloadCheck)(const CChainParams&), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing); /** Check whether we are doing an initial block download (synchronizing from disk or network) */ -bool IsInitialBlockDownload(); +bool IsInitialBlockDownload(const CChainParams& chainParams); /** Format a string that describes several potential problems detected by the core */ std::string GetWarnings(const std::string& strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ @@ -343,7 +343,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons /** Check a transaction contextually against a set of consensus rules */ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, const CChainParams& chainparams, int nHeight, int dosLevel, - bool (*isInitBlockDownload)() = IsInitialBlockDownload); + bool (*isInitBlockDownload)(const CChainParams&) = IsInitialBlockDownload); /** Apply the effects of this transaction on the UTXO set represented by view */ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight); diff --git a/src/metrics.cpp b/src/metrics.cpp index 680b74bb53e..9eecc22e5d0 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -216,7 +216,7 @@ int printStats(bool mining) } auto localsolps = GetLocalSolPS(); - if (IsInitialBlockDownload()) { + if (IsInitialBlockDownload(Params())) { int netheight = EstimateNetHeight(height, tipmediantime, Params()); int downloadPercent = height * 100 / netheight; std::cout << " " << _("Downloading blocks") << " | " << height << " / ~" << netheight << " (" << downloadPercent << "%)" << std::endl; @@ -253,7 +253,7 @@ int printMiningStatus(bool mining) } if (fvNodesEmpty) { std::cout << _("Mining is paused while waiting for connections.") << std::endl; - } else if (IsInitialBlockDownload()) { + } else if (IsInitialBlockDownload(Params())) { std::cout << _("Mining is paused while downloading blocks.") << std::endl; } else { std::cout << _("Mining is paused (a JoinSplit may be in progress).") << std::endl; diff --git a/src/miner.cpp b/src/miner.cpp index ee37c44c7ab..bc8f6888ce8 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -565,7 +565,7 @@ void static BitcoinMiner(const CChainParams& chainparams) LOCK(cs_vNodes); fvNodesEmpty = vNodes.empty(); } - if (!fvNodesEmpty && !IsInitialBlockDownload()) + if (!fvNodesEmpty && !IsInitialBlockDownload(chainparams)) break; MilliSleep(1000); } while (true); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 670d2edd4f3..a75ab5924b1 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -534,7 +534,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (vNodes.empty()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Zcash is not connected!"); - if (IsInitialBlockDownload()) + if (IsInitialBlockDownload(Params())) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Zcash is downloading blocks..."); static unsigned int nTransactionsUpdatedLast; diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index a0b49b4ddc2..18acf1f67c5 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -383,7 +383,7 @@ BOOST_AUTO_TEST_CASE(AlertDisablesRPC) mapAlerts.clear(); } -static bool falseFunc() { return false; } +static bool falseFunc(const CChainParams&) { return false; } BOOST_AUTO_TEST_CASE(PartitionAlert) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 659431f19a2..8eba17c6bda 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -583,7 +583,7 @@ void CWallet::ChainTip(const CBlockIndex *pindex, ChainTipAdded(pindex, pblock, sproutTree, saplingTree); // Prevent migration transactions from being created when node is syncing after launch, // and also when node wakes up from suspension/hibernation and incoming blocks are old. - if (!IsInitialBlockDownload() && + if (!IsInitialBlockDownload(Params()) && pblock->GetBlockTime() > GetAdjustedTime() - 3 * 60 * 60) { RunSaplingMigration(pindex->nHeight); From e12d018464cad3c37689e30dcb8f1f95187261ee Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 29 Apr 2019 16:26:27 +0100 Subject: [PATCH 110/127] Globals: Explicitly pass const CChainParams& to ReceivedBlockTransactions() --- src/gtest/test_validation.cpp | 12 +++++++++--- src/main.cpp | 12 ++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/gtest/test_validation.cpp b/src/gtest/test_validation.cpp index 4e937d04266..0f66b8dcfb6 100644 --- a/src/gtest/test_validation.cpp +++ b/src/gtest/test_validation.cpp @@ -7,7 +7,12 @@ extern ZCJoinSplit* params; -extern bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos); +extern bool ReceivedBlockTransactions( + const CBlock &block, + CValidationState& state, + const CChainParams& chainparams, + CBlockIndex *pindexNew, + const CDiskBlockPos& pos); void ExpectOptionalAmount(CAmount expected, boost::optional actual) { EXPECT_TRUE((bool)actual); @@ -87,6 +92,7 @@ TEST(Validation, ContextualCheckInputsPassesWithCoinbase) { } TEST(Validation, ReceivedBlockTransactions) { + auto chainParams = Params(); auto sk = libzcash::SproutSpendingKey::random(); // Create a fake genesis block @@ -122,7 +128,7 @@ TEST(Validation, ReceivedBlockTransactions) { // Mark the second block's transactions as received first CValidationState state; - EXPECT_TRUE(ReceivedBlockTransactions(block2, state, &fakeIndex2, pos2)); + EXPECT_TRUE(ReceivedBlockTransactions(block2, state, chainParams, &fakeIndex2, pos2)); EXPECT_FALSE(fakeIndex1.IsValid(BLOCK_VALID_TRANSACTIONS)); EXPECT_TRUE(fakeIndex2.IsValid(BLOCK_VALID_TRANSACTIONS)); @@ -137,7 +143,7 @@ TEST(Validation, ReceivedBlockTransactions) { EXPECT_FALSE((bool)fakeIndex2.nChainSproutValue); // Now mark the first block's transactions as received - EXPECT_TRUE(ReceivedBlockTransactions(block1, state, &fakeIndex1, pos1)); + EXPECT_TRUE(ReceivedBlockTransactions(block1, state, chainParams, &fakeIndex1, pos1)); EXPECT_TRUE(fakeIndex1.IsValid(BLOCK_VALID_TRANSACTIONS)); EXPECT_TRUE(fakeIndex2.IsValid(BLOCK_VALID_TRANSACTIONS)); diff --git a/src/main.cpp b/src/main.cpp index 3065e694fb5..eb87d2786d3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3543,9 +3543,13 @@ void FallbackSproutValuePoolBalance( } /** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */ -bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos) +bool ReceivedBlockTransactions( + const CBlock &block, + CValidationState& state, + const CChainParams& chainparams, + CBlockIndex *pindexNew, + const CDiskBlockPos& pos) { - const CChainParams& chainparams = Params(); pindexNew->nTx = block.vtx.size(); pindexNew->nChainTx = 0; CAmount sproutValue = 0; @@ -4010,7 +4014,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha if (dbp == NULL) if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) AbortNode(state, "Failed to write block"); - if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) + if (!ReceivedBlockTransactions(block, state, chainparams, pindex, blockPos)) return error("AcceptBlock(): ReceivedBlockTransactions failed"); } catch (const std::runtime_error& e) { return AbortNode(state, std::string("System error: ") + e.what()); @@ -4761,7 +4765,7 @@ bool InitBlockIndex(const CChainParams& chainparams) if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) return error("LoadBlockIndex(): writing genesis block to disk failed"); CBlockIndex *pindex = AddToBlockIndex(block); - if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) + if (!ReceivedBlockTransactions(block, state, chainparams, pindex, blockPos)) return error("LoadBlockIndex(): genesis block not accepted"); if (!ActivateBestChain(state, chainparams, &block)) return error("LoadBlockIndex(): genesis block cannot be activated"); From 406b8ff509935fcbc30f84901963001ddba37f66 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Thu, 6 Jun 2019 13:49:11 -0600 Subject: [PATCH 111/127] z_getmigrationstatus help message wording change --- src/wallet/rpcwallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2e9139c6545..4cac157be4d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3937,8 +3937,8 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { throw runtime_error( "z_getmigrationstatus\n" "Returns information about the status of the Sprout to Sapling migration.\n" - "A transaction is defined as finalized if it has at least ten confirmations.\n" - "Note: It is possible that manually created transactions involving this wallet\n" + "Note: A transaction is defined as finalized if it has at least ten confirmations.\n" + "Also, it is possible that manually created transactions involving this wallet\n" "will be included in the result.\n" "\nResult:\n" "{\n" From a8055cfe10d501248dbdb515a12e51f7fd40ed20 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Thu, 21 Mar 2019 18:12:50 -0600 Subject: [PATCH 112/127] Fix z_mergetoaddress sending from ANY_SPROUT/ANY_SAPLING when the wallet contains both note types --- qa/pull-tester/rpc-tests.sh | 1 + qa/rpc-tests/mergetoaddress_helper.py | 8 ++- qa/rpc-tests/mergetoaddress_mixednotes.py | 82 +++++++++++++++++++++++ src/wallet/rpcwallet.cpp | 9 ++- 4 files changed, 98 insertions(+), 2 deletions(-) create mode 100755 qa/rpc-tests/mergetoaddress_mixednotes.py diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index d072898b26d..520c60837ef 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -31,6 +31,7 @@ testScripts=( 'wallet_listnotes.py' 'mergetoaddress_sprout.py' 'mergetoaddress_sapling.py' + 'mergetoaddress_mixednotes.py' 'listtransactions.py' 'mempool_resurrect_test.py' 'txn_doublespend.py' diff --git a/qa/rpc-tests/mergetoaddress_helper.py b/qa/rpc-tests/mergetoaddress_helper.py index cc829f8b8aa..962c2b7ff49 100755 --- a/qa/rpc-tests/mergetoaddress_helper.py +++ b/qa/rpc-tests/mergetoaddress_helper.py @@ -17,11 +17,12 @@ def assert_mergetoaddress_exception(expected_error_msg, merge_to_address_lambda): try: merge_to_address_lambda() - fail("Expected exception: %s" % expected_error_msg) except JSONRPCException as e: assert_equal(expected_error_msg, e.error['message']) except Exception as e: fail("Expected JSONRPCException. Found %s" % repr(e)) + else: + fail("Expected exception: %s" % expected_error_msg) class MergeToAddressHelper: @@ -152,6 +153,11 @@ def run_test(self, test): "Destination address is also the only source address, and all its funds are already merged.", lambda: test.nodes[0].z_mergetoaddress([mytaddr], mytaddr)) + # Merging will fail for this specific case where it would spend a fee and do nothing + assert_mergetoaddress_exception( + "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress", + lambda: test.nodes[0].z_mergetoaddress(["ANY_SPROUT", "ANY_SAPLING"], mytaddr)) + # Merge UTXOs from node 0 of value 30, standard fee of 0.00010000 result = test.nodes[0].z_mergetoaddress([mytaddr, mytaddr2, mytaddr3], myzaddr) wait_and_assert_operationid_status(test.nodes[0], result['opid']) diff --git a/qa/rpc-tests/mergetoaddress_mixednotes.py b/qa/rpc-tests/mergetoaddress_mixednotes.py new file mode 100755 index 00000000000..b787429aa99 --- /dev/null +++ b/qa/rpc-tests/mergetoaddress_mixednotes.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# Copyright (c) 2019 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x." + +from decimal import Decimal +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, get_coinbase_address, \ + initialize_chain_clean, start_nodes, wait_and_assert_operationid_status +from mergetoaddress_helper import assert_mergetoaddress_exception + + +class MergeToAddressMixedNotes(BitcoinTestFramework): + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir, [[ + '-nuparams=5ba81b19:100', # Overwinter + '-nuparams=76b809bb:100', # Sapling + '-experimentalfeatures', '-zmergetoaddress' + ]] * 4) + + def setup_chain(self): + print("Initializing test directory " + self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def run_test(self): + print "Mining blocks..." + self.nodes[0].generate(102) + self.sync_all() + + # Send some ZEC to Sprout/Sapling addresses + coinbase_addr = get_coinbase_address(self.nodes[0]) + sproutAddr = self.nodes[0].z_getnewaddress('sprout') + saplingAddr = self.nodes[0].z_getnewaddress('sapling') + t_addr = self.nodes[1].getnewaddress() + + opid = self.nodes[0].z_sendmany(coinbase_addr, [{"address": sproutAddr, "amount": Decimal('10')}], 1, 0) + wait_and_assert_operationid_status(self.nodes[0], opid) + self.nodes[0].generate(1) + self.sync_all() + assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('10')) + assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0')) + assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]), Decimal('0')) + # Make sure we cannot use "ANY_SPROUT" and "ANY_SAPLING" even if we only have Sprout Notes + assert_mergetoaddress_exception( + "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress", + lambda: self.nodes[0].z_mergetoaddress(["ANY_SPROUT", "ANY_SAPLING"], t_addr)) + opid = self.nodes[0].z_sendmany(coinbase_addr, [{"address": saplingAddr, "amount": Decimal('10')}], 1, 0) + wait_and_assert_operationid_status(self.nodes[0], opid) + self.nodes[0].generate(1) + self.sync_all() + + assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]), Decimal('0')) + + # Merge Sprout -> taddr + result = self.nodes[0].z_mergetoaddress(["ANY_SPROUT"], t_addr, 0) + wait_and_assert_operationid_status(self.nodes[0], result['opid']) + self.nodes[0].generate(1) + self.sync_all() + + assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('0')) + assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('10')) + assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]), Decimal('10')) + + # Make sure we cannot use "ANY_SPROUT" and "ANY_SAPLING" even if we only have Sapling Notes + assert_mergetoaddress_exception( + "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress", + lambda: self.nodes[0].z_mergetoaddress(["ANY_SPROUT", "ANY_SAPLING"], t_addr)) + # Merge Sapling -> taddr + result = self.nodes[0].z_mergetoaddress(["ANY_SAPLING"], t_addr, 0) + wait_and_assert_operationid_status(self.nodes[0], result['opid']) + self.nodes[0].generate(1) + self.sync_all() + + assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('0')) + assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0')) + assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]), Decimal('20')) + + +if __name__ == '__main__': + MergeToAddressMixedNotes().main() diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 4cac157be4d..c018c5410a6 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4532,8 +4532,15 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) if (!saplingActive && saplingEntries.size() > 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated"); } + // Do not include Sprout/Sapling notes if using "ANY_SAPLING"/"ANY_SPROUT" respectively + if (useAnySprout) { + saplingEntries.clear(); + } + if (useAnySapling) { + sproutEntries.clear(); + } // Sending from both Sprout and Sapling is currently unsupported using z_mergetoaddress - if (sproutEntries.size() > 0 && saplingEntries.size() > 0) { + if ((sproutEntries.size() > 0 && saplingEntries.size() > 0) || (useAnySprout && useAnySapling)) { throw JSONRPCError( RPC_INVALID_PARAMETER, "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress"); From cf30355fc3a29ce75059fd57f158a9f9e5982989 Mon Sep 17 00:00:00 2001 From: Eirik0 Date: Thu, 6 Jun 2019 16:46:06 -0600 Subject: [PATCH 113/127] Clarify what combinations of from addresses can be used in z_mergetoaddress --- src/wallet/rpcwallet.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c018c5410a6..309446dc38d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4297,7 +4297,9 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) " - \"ANY_TADDR\": Merge UTXOs from any taddrs belonging to the wallet.\n" " - \"ANY_SPROUT\": Merge notes from any Sprout zaddrs belonging to the wallet.\n" " - \"ANY_SAPLING\": Merge notes from any Sapling zaddrs belonging to the wallet.\n" - " If a special string is given, any given addresses of that type will be counted as duplicates and cause an error.\n" + " While it is possible to use a variety of different combinations of addresses and the above values,\n" + " it is not possible to send funds from both sprout and sapling addresses simultaneously. If a special\n" + " string is given, any given addresses of that type will be counted as duplicates and cause an error.\n" " [\n" " \"address\" (string) Can be a taddr or a zaddr\n" " ,...\n" From 346d11d3eb2f8162df0cb00b1d1f49d542495198 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Tue, 11 Jun 2019 17:27:49 +0100 Subject: [PATCH 114/127] Closes #3992. Remove obsolete warning message. Co-authored-by: Simon Signed-off-by: Daira Hopwood --- src/main.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index eb87d2786d3..4e1ef99d68a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2991,29 +2991,6 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) { Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); cvBlockChange.notify_all(); - - // Check the version of the last 100 blocks to see if we need to upgrade: - static bool fWarned = false; - if (!IsInitialBlockDownload(chainParams) && !fWarned) - { - int nUpgraded = 0; - const CBlockIndex* pindex = chainActive.Tip(); - for (int i = 0; i < 100 && pindex != NULL; i++) - { - if (pindex->nVersion > CBlock::CURRENT_VERSION) - ++nUpgraded; - pindex = pindex->pprev; - } - if (nUpgraded > 0) - LogPrintf("%s: %d of last 100 blocks above version %d\n", __func__, nUpgraded, (int)CBlock::CURRENT_VERSION); - if (nUpgraded > 100/2) - { - // strMiscWarning is read by GetWarnings(), called by the JSON-RPC code to warn the user: - strMiscWarning = _("Warning: This version is obsolete; upgrade required!"); - CAlert::Notify(strMiscWarning, true); - fWarned = true; - } - } } /** From f381d4e0856b5f6ebba429119f3fb97f83983c51 Mon Sep 17 00:00:00 2001 From: Larry Ruane Date: Tue, 7 May 2019 16:18:06 -0600 Subject: [PATCH 115/127] add spentindex to getrawtransaction RPC results --- qa/pull-tester/rpc-tests.sh | 1 + qa/rpc-tests/getrawtransaction_insight.py | 104 ++++++++++++++++++++++ src/main.cpp | 24 +++-- src/main.h | 1 + src/rpc/rawtransaction.cpp | 36 ++++++-- src/script/script.cpp | 8 +- src/script/script.h | 9 +- src/script/standard.cpp | 13 +++ src/script/standard.h | 3 + 9 files changed, 180 insertions(+), 19 deletions(-) create mode 100755 qa/rpc-tests/getrawtransaction_insight.py diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 520c60837ef..aeda0da2cbf 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -38,6 +38,7 @@ testScripts=( 'txn_doublespend.py --mineblock' 'getchaintips.py' 'rawtransactions.py' + 'getrawtransaction_insight.py' 'rest.py' 'mempool_spendcoinbase.py' 'mempool_reorg.py' diff --git a/qa/rpc-tests/getrawtransaction_insight.py b/qa/rpc-tests/getrawtransaction_insight.py new file mode 100755 index 00000000000..f18eed5d465 --- /dev/null +++ b/qa/rpc-tests/getrawtransaction_insight.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python2 +# Copyright (c) 2019 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test the new fields added to the output of getrawtransaction +# RPC for the Insight Explorer by the new spentindex +# + +from test_framework.test_framework import BitcoinTestFramework + +from test_framework.util import assert_equal +from test_framework.util import initialize_chain_clean +from test_framework.util import start_nodes, stop_nodes, connect_nodes +from test_framework.util import wait_bitcoinds + +from test_framework.mininode import COIN + + +class GetrawtransactionTest(BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self): + # -insightexplorer causes spentindex to be enabled (fSpentIndex = true) + + self.nodes = start_nodes(3, self.options.tmpdir, + [['-debug', '-txindex', '-experimentalfeatures', '-insightexplorer']]*3) + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[0], 2) + + self.is_network_split = False + self.sync_all() + + def run_test(self): + self.nodes[0].generate(105) + self.sync_all() + + chain_height = self.nodes[1].getblockcount() + assert_equal(chain_height, 105) + + # Test getrawtransaction changes and the getspentinfo RPC + + # send coinbase to address a + a = self.nodes[1].getnewaddress() + txid_a = self.nodes[0].sendtoaddress(a, 2) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + # send from a to b + # (the only utxo on node 1 is from address a) + b = self.nodes[2].getnewaddress() + txid_b = self.nodes[1].sendtoaddress(b, 1) + self.sync_all() + + # a to b transaction is not confirmed, so it has no height + tx_b = self.nodes[2].getrawtransaction(txid_b, 1) + assert('height' not in tx_b) + + self.sync_all() + tx_a = self.nodes[2].getrawtransaction(txid_a, 1) + + # txid_b is not yet confirmed, so these should not be set + assert('spentTxId' not in tx_a['vout'][0]) + assert('spentIndex' not in tx_a['vout'][0]) + assert('spentHeight' not in tx_a['vout'][0]) + + # confirm txid_b (a to b transaction) + self.nodes[0].generate(1) + self.sync_all() + + # Restart all nodes to ensure index files are saved to disk and recovered + stop_nodes(self.nodes) + wait_bitcoinds() + self.setup_network() + + # Check new fields added to getrawtransaction + tx_a = self.nodes[2].getrawtransaction(txid_a, 1) + assert_equal(tx_a['vin'][0]['value'], 10) # coinbase + assert_equal(tx_a['vin'][0]['valueSat'], 10*COIN) + # we want the non-change (payment) output + vout = filter(lambda o: o['value'] == 2, tx_a['vout']) + assert_equal(vout[0]['spentTxId'], txid_b) + assert_equal(vout[0]['spentIndex'], 0) + assert_equal(vout[0]['spentHeight'], 107) + assert_equal(tx_a['height'], 106) + + tx_b = self.nodes[2].getrawtransaction(txid_b, 1) + assert_equal(tx_b['vin'][0]['address'], a) + assert_equal(tx_b['vin'][0]['value'], 2) + assert_equal(tx_b['vin'][0]['valueSat'], 2*COIN) + # since this transaction's outputs haven't yet been + # spent, these fields should not be present + assert('spentTxId' not in tx_b['vout'][0]) + assert('spentIndex' not in tx_b['vout'][0]) + assert('spentHeight' not in tx_b['vout'][0]) + assert_equal(tx_b['height'], 107) + +if __name__ == '__main__': + GetrawtransactionTest().main() diff --git a/src/main.cpp b/src/main.cpp index eb87d2786d3..43e7f90e7c9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1607,6 +1607,14 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa return true; } +bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) +{ + AssertLockHeld(cs_main); + if (!fSpentIndex) + return false; + return pblocktree->ReadSpentIndex(key, value); +} + /** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow) { @@ -2269,8 +2277,8 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s if (fAddressIndex && updateIndices) { for (unsigned int k = tx.vout.size(); k-- > 0;) { const CTxOut &out = tx.vout[k]; - int const scriptType = out.scriptPubKey.Type(); - if (scriptType > 0) { + CScript::ScriptType scriptType = out.scriptPubKey.GetType(); + if (scriptType != CScript::UNKNOWN) { uint160 const addrHash = out.scriptPubKey.AddressHash(); // undo receiving activity @@ -2326,8 +2334,8 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s const CTxIn input = tx.vin[j]; if (fAddressIndex && updateIndices) { const CTxOut &prevout = view.GetOutputFor(input); - int const scriptType = prevout.scriptPubKey.Type(); - if (scriptType > 0) { + CScript::ScriptType scriptType = prevout.scriptPubKey.GetType(); + if (scriptType != CScript::UNKNOWN) { uint160 const addrHash = prevout.scriptPubKey.AddressHash(); // undo spending activity @@ -2643,9 +2651,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin const CTxIn input = tx.vin[j]; const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); - int const scriptType = prevout.scriptPubKey.Type(); + CScript::ScriptType scriptType = prevout.scriptPubKey.GetType(); const uint160 addrHash = prevout.scriptPubKey.AddressHash(); - if (fAddressIndex && scriptType > 0) { + if (fAddressIndex && scriptType != CScript::UNKNOWN) { // record spending activity addressIndex.push_back(make_pair( CAddressIndexKey(scriptType, addrHash, pindex->nHeight, i, hash, j, true), @@ -2695,8 +2703,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (fAddressIndex) { for (unsigned int k = 0; k < tx.vout.size(); k++) { const CTxOut &out = tx.vout[k]; - int const scriptType = out.scriptPubKey.Type(); - if (scriptType > 0) { + CScript::ScriptType scriptType = out.scriptPubKey.GetType(); + if (scriptType != CScript::UNKNOWN) { uint160 const addrHash = out.scriptPubKey.AddressHash(); // record receiving activity diff --git a/src/main.h b/src/main.h index 2b77875c482..cd2e39a0957 100644 --- a/src/main.h +++ b/src/main.h @@ -437,6 +437,7 @@ class CScriptCheck ScriptError GetScriptError() const { return error; } }; +bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value); /** Functions for disk access for blocks */ bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 49768c24730..80ff66ee7bd 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -147,7 +147,8 @@ UniValue TxShieldedOutputsToJSON(const CTransaction& tx) { void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) { - entry.push_back(Pair("txid", tx.GetHash().GetHex())); + const uint256 txid = tx.GetHash(); + entry.push_back(Pair("txid", txid.GetHex())); entry.push_back(Pair("overwintered", tx.fOverwintered)); entry.push_back(Pair("version", tx.nVersion)); if (tx.fOverwintered) { @@ -169,6 +170,20 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) o.push_back(Pair("asm", ScriptToAsmStr(txin.scriptSig, true))); o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); in.push_back(Pair("scriptSig", o)); + + // Add address and value info if spentindex enabled + CSpentIndexValue spentInfo; + CSpentIndexKey spentKey(txin.prevout.hash, txin.prevout.n); + if (GetSpentIndex(spentKey, spentInfo)) { + in.push_back(Pair("value", ValueFromAmount(spentInfo.satoshis))); + in.push_back(Pair("valueSat", spentInfo.satoshis)); + + boost::optional dest = + DestFromAddressHash(spentInfo.addressType, spentInfo.addressHash); + if (dest) { + in.push_back(Pair("address", EncodeDestination(*dest))); + } + } } in.push_back(Pair("sequence", (int64_t)txin.nSequence)); vin.push_back(in); @@ -184,6 +199,15 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) UniValue o(UniValue::VOBJ); ScriptPubKeyToJSON(txout.scriptPubKey, o, true); out.push_back(Pair("scriptPubKey", o)); + + // Add spent information if spentindex is enabled + CSpentIndexValue spentInfo; + CSpentIndexKey spentKey(txid, i); + if (GetSpentIndex(spentKey, spentInfo)) { + out.push_back(Pair("spentTxId", spentInfo.txid.GetHex())); + out.push_back(Pair("spentIndex", (int)spentInfo.inputIndex)); + out.push_back(Pair("spentHeight", spentInfo.blockHeight)); + } vout.push_back(out); } entry.push_back(Pair("vout", vout)); @@ -208,12 +232,14 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) if (mi != mapBlockIndex.end() && (*mi).second) { CBlockIndex* pindex = (*mi).second; if (chainActive.Contains(pindex)) { + entry.push_back(Pair("height", pindex->nHeight)); entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight)); entry.push_back(Pair("time", pindex->GetBlockTime())); entry.push_back(Pair("blocktime", pindex->GetBlockTime())); - } - else + } else { + entry.push_back(Pair("height", -1)); entry.push_back(Pair("confirmations", 0)); + } } } } @@ -312,14 +338,14 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1") ); - LOCK(cs_main); - uint256 hash = ParseHashV(params[0], "parameter 1"); bool fVerbose = false; if (params.size() > 1) fVerbose = (params[1].get_int() != 0); + LOCK(cs_main); + CTransaction tx; uint256 hashBlock; if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) diff --git a/src/script/script.cpp b/src/script/script.cpp index 9d13fd040cd..bcd1c6b2d11 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -242,14 +242,14 @@ bool CScript::IsPushOnly() const } // insightexplorer -int CScript::Type() const +CScript::ScriptType CScript::GetType() const { if (this->IsPayToPublicKeyHash()) - return 1; + return CScript::P2PKH; if (this->IsPayToScriptHash()) - return 2; + return CScript::P2SH; // We don't know this script - return 0; + return CScript::UNKNOWN; } // insightexplorer diff --git a/src/script/script.h b/src/script/script.h index 6f88676118c..2a511cd2eb5 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -567,10 +567,15 @@ class CScript : public CScriptBase */ unsigned int GetSigOpCount(const CScript& scriptSig) const; + // insightexplorer, there may be more script types in the future + enum ScriptType : int { + UNKNOWN = 0, + P2PKH = 1, + P2SH = 2, + }; bool IsPayToPublicKeyHash() const; bool IsPayToScriptHash() const; - - int Type() const; + ScriptType GetType() const; uint160 AddressHash() const; /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 88cde36988a..12df6d8556a 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -320,3 +320,16 @@ CScript GetScriptForMultisig(int nRequired, const std::vector& keys) bool IsValidDestination(const CTxDestination& dest) { return dest.which() != 0; } + +// insightexplorer +boost::optional DestFromAddressHash(int scriptType, uint160& addressHash) +{ + switch (scriptType) { + case CScript::P2PKH: + return CTxDestination(CKeyID(addressHash)); + case CScript::P2SH: + return CTxDestination(CScriptID(addressHash)); + default: + return boost::none; + } +} diff --git a/src/script/standard.h b/src/script/standard.h index 5dcff1c1a5a..40b3c329d6c 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -96,4 +96,7 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std:: CScript GetScriptForDestination(const CTxDestination& dest); CScript GetScriptForMultisig(int nRequired, const std::vector& keys); +// insightexplorer +boost::optional DestFromAddressHash(int scriptType, uint160& addressHash); + #endif // BITCOIN_SCRIPT_STANDARD_H From f7a4aab352e5c3f1e4bc22cc6c909b3e2aa240c7 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Wed, 12 Jun 2019 16:32:57 +0100 Subject: [PATCH 116/127] make-release.py: Versioning changes for 2.0.6-rc1. --- README.md | 2 +- configure.ac | 4 ++-- contrib/gitian-descriptors/gitian-linux.yml | 2 +- src/clientversion.h | 4 ++-- src/deprecation.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7d02cf0d349..92c99d49848 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Zcash 2.0.5-2 +Zcash 2.0.6-rc1 =========== diff --git a/configure.ac b/configure.ac index a78439eda44..bcbe56f9ec3 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 2) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 5) -define(_CLIENT_VERSION_BUILD, 52) +define(_CLIENT_VERSION_REVISION, 6) +define(_CLIENT_VERSION_BUILD, 25) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index edc714f1074..fe21b45fb4a 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "zcash-2.0.5-2" +name: "zcash-2.0.6-rc1" enable_cache: true distro: "debian" suites: diff --git a/src/clientversion.h b/src/clientversion.h index 2455c56b48e..5f8b9687026 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -17,8 +17,8 @@ //! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 2 #define CLIENT_VERSION_MINOR 0 -#define CLIENT_VERSION_REVISION 5 -#define CLIENT_VERSION_BUILD 52 +#define CLIENT_VERSION_REVISION 6 +#define CLIENT_VERSION_BUILD 25 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/deprecation.h b/src/deprecation.h index 13c752c426e..f581b07e5e1 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -8,7 +8,7 @@ // Deprecation policy: // * Shut down 16 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 533500; +static const int APPROX_RELEASE_HEIGHT = 549200; static const int WEEKS_UNTIL_DEPRECATION = 16; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); From 372ff78b2c74e70b3dca00996e3e9aa7e0a310f4 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Wed, 12 Jun 2019 16:36:56 +0100 Subject: [PATCH 117/127] make-release.py: Updated manpages for 2.0.6-rc1. --- doc/man/zcash-cli.1 | 8 ++++---- doc/man/zcash-tx.1 | 8 ++++---- doc/man/zcashd.1 | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index c2f1b3447ff..1abd7712599 100644 --- a/doc/man/zcash-cli.1 +++ b/doc/man/zcash-cli.1 @@ -1,9 +1,9 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASH-CLI "1" "May 2019" "zcash-cli v2.0.5-2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH ZCASH-CLI "1" "June 2019" "zcash-cli v2.0.6-rc1" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v2.0.5-2 +zcash-cli \- manual page for zcash-cli v2.0.6-rc1 .SH DESCRIPTION -Zcash RPC client version v2.0.5\-2 +Zcash RPC client version v2.0.6\-rc1 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . diff --git a/doc/man/zcash-tx.1 b/doc/man/zcash-tx.1 index effac79bb36..3e3c8b2bd13 100644 --- a/doc/man/zcash-tx.1 +++ b/doc/man/zcash-tx.1 @@ -1,9 +1,9 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASH-TX "1" "May 2019" "zcash-tx v2.0.5-2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH ZCASH-TX "1" "June 2019" "zcash-tx v2.0.6-rc1" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v2.0.5-2 +zcash-tx \- manual page for zcash-tx v2.0.6-rc1 .SH DESCRIPTION -Zcash zcash\-tx utility version v2.0.5\-2 +Zcash zcash\-tx utility version v2.0.6\-rc1 .SS "Usage:" .TP zcash\-tx [options] [commands] diff --git a/doc/man/zcashd.1 b/doc/man/zcashd.1 index 73d50333e6d..2af9ed904a9 100644 --- a/doc/man/zcashd.1 +++ b/doc/man/zcashd.1 @@ -1,9 +1,9 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH ZCASHD "1" "May 2019" "zcashd v2.0.5-2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH ZCASHD "1" "June 2019" "zcashd v2.0.6-rc1" "User Commands" .SH NAME -zcashd \- manual page for zcashd v2.0.5-2 +zcashd \- manual page for zcashd v2.0.6-rc1 .SH DESCRIPTION -Zcash Daemon version v2.0.5\-2 +Zcash Daemon version v2.0.6\-rc1 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . @@ -75,7 +75,7 @@ limit applied) .HP \fB\-par=\fR .IP -Set the number of script verification threads (\fB\-4\fR to 16, 0 = auto, <0 = +Set the number of script verification threads (\fB\-6\fR to 16, 0 = auto, <0 = leave that many cores free, default: 0) .HP \fB\-pid=\fR From c3afc3fde0138b2b990012c894e3653dcc1eb36e Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Wed, 12 Jun 2019 16:36:57 +0100 Subject: [PATCH 118/127] make-release.py: Updated release notes and changelog for 2.0.6-rc1. --- contrib/debian/changelog | 6 ++ doc/authors.md | 9 ++- doc/release-notes/release-notes-2.0.6-rc1.md | 62 ++++++++++++++++++++ 3 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 doc/release-notes/release-notes-2.0.6-rc1.md diff --git a/contrib/debian/changelog b/contrib/debian/changelog index f48b6e7b6df..af3c93a95d4 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +zcash (2.0.6~rc1) stable; urgency=medium + + * 2.0.6-rc1 release. + + -- Electric Coin Company Wed, 12 Jun 2019 16:36:57 +0100 + zcash (2.0.5+2) stable; urgency=medium * 2.0.5-2 release. diff --git a/doc/authors.md b/doc/authors.md index 72d50f96b7e..9bcdb5ef140 100644 --- a/doc/authors.md +++ b/doc/authors.md @@ -4,18 +4,17 @@ Zcash Contributors Jack Grigg (863) Simon Liu (450) Sean Bowe (278) +Eirik Ogilvie-Wigley (145) Daira Hopwood (115) -Eirik Ogilvie-Wigley (102) Jay Graber (89) Wladimir J. van der Laan (81) Taylor Hornby (73) Jonas Schnelli (62) Nathan Wilcox (56) Pieter Wuille (54) -Eirik0 (43) Kevin Gallagher (38) Cory Fields (35) -mdr0id (22) +Marshall Gaucher (22) Larry Ruane (22) Jonathan "Duke" Leto (17) syd (15) @@ -46,7 +45,6 @@ João Barbosa (4) Jorge Timón (4) George Tankersley (4) Gareth Davies (4) -zebambam (3) lpescher (3) ca333 (3) Per Grön (3) @@ -55,9 +53,9 @@ Jason Davies (3) James O'Beirne (3) Dimitris Apostolou (3) Daniel Kraft (3) +Benjamin Winston (3) Alfie John (3) rofl0r (2) -paveljanik (2) mruddy (2) kpcyrd (2) aniemerg (2) @@ -67,6 +65,7 @@ Robert C. Seacord (2) Pejvan (2) Pavol Rusnak (2) Pavel Vasin (2) +Pavel Janik (2) Matthew King (2) Kaz Wesley (2) Joe Turgeon (2) diff --git a/doc/release-notes/release-notes-2.0.6-rc1.md b/doc/release-notes/release-notes-2.0.6-rc1.md new file mode 100644 index 00000000000..ce40147200a --- /dev/null +++ b/doc/release-notes/release-notes-2.0.6-rc1.md @@ -0,0 +1,62 @@ +Changelog +========= + +Daira Hopwood (3): + Closes #3992. Remove obsolete warning message. + make-release.py: Versioning changes for 2.0.6-rc1. + make-release.py: Updated manpages for 2.0.6-rc1. + +Daniel Kraft (1): + Add some const declarations where they are appropriate. + +Eirik Ogilvie-Wigley (7): + Fix tree depth in comment + Update author aliases + Remove old mergetoaddress RPC test + Replace CSproutNotePlaintextEntry with SproutNoteEntry to match Sapling + z_getmigrationstatus help message wording change + Fix z_mergetoaddress sending from ANY_SPROUT/ANY_SAPLING when the wallet contains both note types + Clarify what combinations of from addresses can be used in z_mergetoaddress + +Jack Grigg (10): + Move Equihash parameters into consensus params + Globals: Remove Zcash-specific Params() calls from main.cpp + Globals: Explicitly pass const CChainParams& to IsStandardTx() + Globals: Explicit const CChainParams& arg for main: + Globals: Explicitly pass const CChainParams& to ContextualCheckTransaction() + Globals: Explicit const CChainParams& arg for main: + Globals: Explicitly pass const CChainParams& to DisconnectBlock() + Consistently use chainparams and consensusParams + Globals: Explicitly pass const CChainParams& to IsInitialBlockDownload() + Globals: Explicitly pass const CChainParams& to ReceivedBlockTransactions() + +Jorge Timón (6): + Globals: Explicit Consensus::Params arg for main: + Globals: Make AcceptBlockHeader static (Fix #6163) + Chainparams: Explicit CChainParams arg for main (pre miner): + Chainparams: Explicit CChainParams arg for miner: + Globals: Remove a bunch of Params() calls from main.cpp: + Globals: Explicitly pass const CChainParams& to UpdateTip() + +Larry Ruane (1): + add spentindex to getrawtransaction RPC results + +MarcoFalke (1): + [doc] Fix doxygen comments for members + +Peter Todd (1): + Improve block validity/ConnectBlock() comments + +Simon Liu (1): + Fix typo and clean up help message for RPC z_getmigrationstatus. + +Wladimir J. van der Laan (1): + Break circular dependency main ↔ txdb + +face (2): + Pass CChainParams to DisconnectTip() + Explicitly pass CChainParams to ConnectBlock + +Benjamin Winston (1): + Fixes #4013, added BitcoinABC as a disclosure partner + From 6a35b68fab53d6d4d7be435e431534d10884c15b Mon Sep 17 00:00:00 2001 From: Charlie O'Keefe Date: Wed, 12 Jun 2019 17:41:38 -0600 Subject: [PATCH 119/127] Add stretch to list of suites in gitian linux descriptors --- contrib/gitian-descriptors/gitian-linux.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index fe21b45fb4a..0e9d9d81f18 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -4,6 +4,7 @@ enable_cache: true distro: "debian" suites: - "jessie" +- "stretch" architectures: - "amd64" packages: From 246f17f6baaabfa9d701d01295f93e3e2fcf90e1 Mon Sep 17 00:00:00 2001 From: Mary Moore-Simmons Date: Fri, 14 Jun 2019 09:02:37 -0600 Subject: [PATCH 120/127] Fixes issue #3504: Changes to --version and adds a couple other useful commands. --- .github/ISSUE_TEMPLATE.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index a025e66aca0..9827e610503 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -31,7 +31,9 @@ Run `zcashd --version` to find out - Disk size: - Disk Type (HD/SDD): - Linux kernel version (uname -a): -- Compiler version (gcc -version): +- Compiler version (gcc --version): +- Linker version (ld --version): +- Assembler version (as --version): ### Any extra information that might be useful in the debugging process. This includes the relevant contents of `~/.zcash/debug.log`. You can paste raw text, attach the file directly in the issue or link to the text via a pastebin type site. From 6177b47d20a8b88d9cc063f298cb14b86c320861 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Fri, 14 Jun 2019 23:18:10 +0100 Subject: [PATCH 121/127] ld --version doesn't work on macOS. Signed-off-by: Daira Hopwood --- .github/ISSUE_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 9827e610503..a1592004001 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -32,7 +32,7 @@ Run `zcashd --version` to find out - Disk Type (HD/SDD): - Linux kernel version (uname -a): - Compiler version (gcc --version): -- Linker version (ld --version): +- Linker version (ld -v): - Assembler version (as --version): ### Any extra information that might be useful in the debugging process. From 3b4bc96bac59aa74aaa9cbde892812b41d319865 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 17 Jun 2019 13:12:11 -0600 Subject: [PATCH 122/127] Notable changes for 2.0.6 Co-authored-by: Daira Hopwood --- doc/release-notes.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/doc/release-notes.md b/doc/release-notes.md index a29094b5174..ff7355d93dd 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,3 +4,24 @@ release-notes at release time) Notable changes =============== +Debian Stretch is now a Supported Platform +------------------------------------------ + +We now provide reproducible builds for Stretch as well as for Jessie. + + +Fixed a bug in ``z_mergetoaddress`` +----------------------------------- + +We fixed a bug which prevented users sending from ``ANY_SPROUT`` or ``ANY_SAPLING`` +with ``z_mergetoaddress`` when a wallet contained both Sprout and Sapling notes. + + +Insight Explorer +---------------- + +We have been incorporating changes to support the Insight explorer directly from +``zcashd``. v2.0.6 includes the first change to an RPC method. If ``zcashd`` is +run with the flag ``--insightexplorer``` (this requires an index rebuild), the +RPC method ``getrawtransaction`` will now return additional information about +spend indices. From dbe49614c152801358f6208b90e0a524ca374ee1 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Tue, 18 Jun 2019 14:00:56 +0100 Subject: [PATCH 123/127] Tweak author aliases. Signed-off-by: Daira Hopwood --- zcutil/release-notes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zcutil/release-notes.py b/zcutil/release-notes.py index 4446e988f2d..0f9974e8ff3 100755 --- a/zcutil/release-notes.py +++ b/zcutil/release-notes.py @@ -27,8 +27,9 @@ 'Duke Leto': 'Jonathan \"Duke\" Leto', 'Eirik0': 'Eirik Ogilvie-Wigley', 'EthanHeilman': 'Ethan Heilman', + 'MarcoFalke': 'Marco Falke', 'mdr0id': 'Marshall Gaucher', - 'paveljanik': 'Pavel Janik', + 'paveljanik': 'Pavel Janík', 'Simon': 'Simon Liu', 'str4d': 'Jack Grigg', 'zebambam': 'Benjamin Winston' From f6e1e1577362fec98ed8745cb6511c917403abba Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Wed, 19 Jun 2019 00:19:54 +0100 Subject: [PATCH 124/127] Add coding declaration to zcutil/release-notes.py Signed-off-by: Daira Hopwood --- zcutil/release-notes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zcutil/release-notes.py b/zcutil/release-notes.py index 0f9974e8ff3..b1a262232e1 100755 --- a/zcutil/release-notes.py +++ b/zcutil/release-notes.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + import re, os, os.path import subprocess import argparse From ef2dcbf1d48faa57ffa238ae544c9848082f7733 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Wed, 19 Jun 2019 00:27:11 +0100 Subject: [PATCH 125/127] make-release.py: Versioning changes for 2.0.6. --- README.md | 2 +- configure.ac | 2 +- contrib/gitian-descriptors/gitian-linux.yml | 2 +- src/clientversion.h | 2 +- src/deprecation.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 92c99d49848..4f7931cd958 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Zcash 2.0.6-rc1 +Zcash 2.0.6 =========== diff --git a/configure.ac b/configure.ac index bcbe56f9ec3..05b4667e822 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 2) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 6) -define(_CLIENT_VERSION_BUILD, 25) +define(_CLIENT_VERSION_BUILD, 50) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 0e9d9d81f18..d770c29fc31 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "zcash-2.0.6-rc1" +name: "zcash-2.0.6" enable_cache: true distro: "debian" suites: diff --git a/src/clientversion.h b/src/clientversion.h index 5f8b9687026..259d6d4b3e5 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -18,7 +18,7 @@ #define CLIENT_VERSION_MAJOR 2 #define CLIENT_VERSION_MINOR 0 #define CLIENT_VERSION_REVISION 6 -#define CLIENT_VERSION_BUILD 25 +#define CLIENT_VERSION_BUILD 50 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/deprecation.h b/src/deprecation.h index f581b07e5e1..96ccd2ed717 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -8,7 +8,7 @@ // Deprecation policy: // * Shut down 16 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 549200; +static const int APPROX_RELEASE_HEIGHT = 553000; static const int WEEKS_UNTIL_DEPRECATION = 16; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); From a83969f6ce11932a3af483ec9f872f5248119853 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Wed, 19 Jun 2019 00:28:06 +0100 Subject: [PATCH 126/127] make-release.py: Updated manpages for 2.0.6. --- doc/man/zcash-cli.1 | 6 +++--- doc/man/zcash-tx.1 | 6 +++--- doc/man/zcashd.1 | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index 1abd7712599..741de3dba72 100644 --- a/doc/man/zcash-cli.1 +++ b/doc/man/zcash-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH ZCASH-CLI "1" "June 2019" "zcash-cli v2.0.6-rc1" "User Commands" +.TH ZCASH-CLI "1" "June 2019" "zcash-cli v2.0.6" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v2.0.6-rc1 +zcash-cli \- manual page for zcash-cli v2.0.6 .SH DESCRIPTION -Zcash RPC client version v2.0.6\-rc1 +Zcash RPC client version v2.0.6 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . diff --git a/doc/man/zcash-tx.1 b/doc/man/zcash-tx.1 index 3e3c8b2bd13..1353e34a7f4 100644 --- a/doc/man/zcash-tx.1 +++ b/doc/man/zcash-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH ZCASH-TX "1" "June 2019" "zcash-tx v2.0.6-rc1" "User Commands" +.TH ZCASH-TX "1" "June 2019" "zcash-tx v2.0.6" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v2.0.6-rc1 +zcash-tx \- manual page for zcash-tx v2.0.6 .SH DESCRIPTION -Zcash zcash\-tx utility version v2.0.6\-rc1 +Zcash zcash\-tx utility version v2.0.6 .SS "Usage:" .TP zcash\-tx [options] [commands] diff --git a/doc/man/zcashd.1 b/doc/man/zcashd.1 index 2af9ed904a9..491550c9768 100644 --- a/doc/man/zcashd.1 +++ b/doc/man/zcashd.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH ZCASHD "1" "June 2019" "zcashd v2.0.6-rc1" "User Commands" +.TH ZCASHD "1" "June 2019" "zcashd v2.0.6" "User Commands" .SH NAME -zcashd \- manual page for zcashd v2.0.6-rc1 +zcashd \- manual page for zcashd v2.0.6 .SH DESCRIPTION -Zcash Daemon version v2.0.6\-rc1 +Zcash Daemon version v2.0.6 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . From f2df508591d1d6309975e23eeb0c7fbd57d98543 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Wed, 19 Jun 2019 00:28:06 +0100 Subject: [PATCH 127/127] make-release.py: Updated release notes and changelog for 2.0.6. --- contrib/debian/changelog | 6 ++ doc/authors.md | 30 +++---- doc/release-notes.md | 21 ----- doc/release-notes/release-notes-2.0.6.md | 102 +++++++++++++++++++++++ 4 files changed, 123 insertions(+), 36 deletions(-) create mode 100644 doc/release-notes/release-notes-2.0.6.md diff --git a/contrib/debian/changelog b/contrib/debian/changelog index af3c93a95d4..ed12564cf6c 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +zcash (2.0.6) stable; urgency=medium + + * 2.0.6 release. + + -- Electric Coin Company Wed, 19 Jun 2019 00:28:06 +0100 + zcash (2.0.6~rc1) stable; urgency=medium * 2.0.6-rc1 release. diff --git a/doc/authors.md b/doc/authors.md index 9bcdb5ef140..6afdb557cdf 100644 --- a/doc/authors.md +++ b/doc/authors.md @@ -1,27 +1,28 @@ Zcash Contributors ================== -Jack Grigg (863) -Simon Liu (450) +Jack Grigg (873) +Simon Liu (451) Sean Bowe (278) -Eirik Ogilvie-Wigley (145) -Daira Hopwood (115) +Eirik Ogilvie-Wigley (152) +Daira Hopwood (124) Jay Graber (89) -Wladimir J. van der Laan (81) +Wladimir J. van der Laan (82) Taylor Hornby (73) Jonas Schnelli (62) Nathan Wilcox (56) Pieter Wuille (54) Kevin Gallagher (38) Cory Fields (35) +Larry Ruane (23) Marshall Gaucher (22) -Larry Ruane (22) Jonathan "Duke" Leto (17) syd (15) Matt Corallo (13) Paige Peterson (11) +Marco Falke (11) Ariel Gabizon (11) -MarcoFalke (10) +Jorge Timón (10) nomnombtc (9) kozyilmaz (8) fanquake (8) @@ -31,20 +32,21 @@ Marius Kjærstad (6) Luke Dashjr (6) David Mercer (6) Daniel Cousens (6) +Charlie O'Keefe (6) Suhas Daftuar (5) -Pavel Janík (5) +Peter Todd (5) Karl-Johan Alm (5) Johnathan Corgan (5) -Charlie O'Keefe (5) Alex Morcos (5) WO (4) Philip Kaufmann (4) -Peter Todd (4) +Pavel Janík (4) Patrick Strateman (4) João Barbosa (4) -Jorge Timón (4) George Tankersley (4) Gareth Davies (4) +Daniel Kraft (4) +Benjamin Winston (4) lpescher (3) ca333 (3) Per Grön (3) @@ -52,12 +54,11 @@ Patick Strateman (3) Jason Davies (3) James O'Beirne (3) Dimitris Apostolou (3) -Daniel Kraft (3) -Benjamin Winston (3) Alfie John (3) rofl0r (2) mruddy (2) kpcyrd (2) +face (2) aniemerg (2) UdjinM6 (2) Scott (2) @@ -65,8 +66,8 @@ Robert C. Seacord (2) Pejvan (2) Pavol Rusnak (2) Pavel Vasin (2) -Pavel Janik (2) Matthew King (2) +Mary Moore-Simmons (2) Kaz Wesley (2) Joe Turgeon (2) Jack Gavigan (2) @@ -109,7 +110,6 @@ Nathaniel Mahieu (1) Murilo Santana (1) Maxwell Gubler (1) Matt Quinn (1) -Mary Moore-Simmons (1) Mark Friedenbach (1) Louis Nyffenegger (1) Leo Arias (1) diff --git a/doc/release-notes.md b/doc/release-notes.md index ff7355d93dd..a29094b5174 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,24 +4,3 @@ release-notes at release time) Notable changes =============== -Debian Stretch is now a Supported Platform ------------------------------------------- - -We now provide reproducible builds for Stretch as well as for Jessie. - - -Fixed a bug in ``z_mergetoaddress`` ------------------------------------ - -We fixed a bug which prevented users sending from ``ANY_SPROUT`` or ``ANY_SAPLING`` -with ``z_mergetoaddress`` when a wallet contained both Sprout and Sapling notes. - - -Insight Explorer ----------------- - -We have been incorporating changes to support the Insight explorer directly from -``zcashd``. v2.0.6 includes the first change to an RPC method. If ``zcashd`` is -run with the flag ``--insightexplorer``` (this requires an index rebuild), the -RPC method ``getrawtransaction`` will now return additional information about -spend indices. diff --git a/doc/release-notes/release-notes-2.0.6.md b/doc/release-notes/release-notes-2.0.6.md new file mode 100644 index 00000000000..f1beec5117e --- /dev/null +++ b/doc/release-notes/release-notes-2.0.6.md @@ -0,0 +1,102 @@ +Notable changes +=============== + +Debian Stretch is now a Supported Platform +------------------------------------------ + +We now provide reproducible builds for Stretch as well as for Jessie. + + +Fixed a bug in ``z_mergetoaddress`` +----------------------------------- + +We fixed a bug which prevented users sending from ``ANY_SPROUT`` or ``ANY_SAPLING`` +with ``z_mergetoaddress`` when a wallet contained both Sprout and Sapling notes. + + +Insight Explorer +---------------- + +We have been incorporating changes to support the Insight explorer directly from +``zcashd``. v2.0.6 includes the first change to an RPC method. If ``zcashd`` is +run with the flag ``--insightexplorer``` (this requires an index rebuild), the +RPC method ``getrawtransaction`` will now return additional information about +spend indices. + +Changelog +========= + +Charlie O'Keefe (1): + Add stretch to list of suites in gitian linux descriptors + +Daira Hopwood (9): + Closes #3992. Remove obsolete warning message. + make-release.py: Versioning changes for 2.0.6-rc1. + make-release.py: Updated manpages for 2.0.6-rc1. + make-release.py: Updated release notes and changelog for 2.0.6-rc1. + ld --version doesn't work on macOS. + Tweak author aliases. + Add coding declaration to zcutil/release-notes.py + make-release.py: Versioning changes for 2.0.6. + make-release.py: Updated manpages for 2.0.6. + +Daniel Kraft (1): + Add some const declarations where they are appropriate. + +Eirik Ogilvie-Wigley (1): + Notable changes for 2.0.6 + +Eirik Ogilvie-Wigley (7): + Fix tree depth in comment + Update author aliases + Remove old mergetoaddress RPC test + Replace CSproutNotePlaintextEntry with SproutNoteEntry to match Sapling + z_getmigrationstatus help message wording change + Fix z_mergetoaddress sending from ANY_SPROUT/ANY_SAPLING when the wallet contains both note types + Clarify what combinations of from addresses can be used in z_mergetoaddress + +Jack Grigg (10): + Move Equihash parameters into consensus params + Globals: Remove Zcash-specific Params() calls from main.cpp + Globals: Explicitly pass const CChainParams& to IsStandardTx() + Globals: Explicit const CChainParams& arg for main: + Globals: Explicitly pass const CChainParams& to ContextualCheckTransaction() + Globals: Explicit const CChainParams& arg for main: + Globals: Explicitly pass const CChainParams& to DisconnectBlock() + Consistently use chainparams and consensusParams + Globals: Explicitly pass const CChainParams& to IsInitialBlockDownload() + Globals: Explicitly pass const CChainParams& to ReceivedBlockTransactions() + +Jorge Timón (6): + Globals: Explicit Consensus::Params arg for main: + Globals: Make AcceptBlockHeader static (Fix #6163) + Chainparams: Explicit CChainParams arg for main (pre miner): + Chainparams: Explicit CChainParams arg for miner: + Globals: Remove a bunch of Params() calls from main.cpp: + Globals: Explicitly pass const CChainParams& to UpdateTip() + +Larry Ruane (1): + add spentindex to getrawtransaction RPC results + +Marco Falke (1): + [doc] Fix doxygen comments for members + +Mary Moore-Simmons (1): + Fixes issue #3504: Changes to --version and adds a couple other useful commands. + +Peter Todd (1): + Improve block validity/ConnectBlock() comments + +Simon Liu (1): + Fix typo and clean up help message for RPC z_getmigrationstatus. + +Wladimir J. van der Laan (1): + Break circular dependency main ↔ txdb + +face (2): + Pass CChainParams to DisconnectTip() + Explicitly pass CChainParams to ConnectBlock + +Benjamin Winston (1): + Fixes #4013, added BitcoinABC as a disclosure partner +