From bf009e4ba100f393a69fb0b3c48dc4e89ad2ab13 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 20 May 2015 10:24:16 +0000 Subject: [PATCH] Consensus support for blinded amounts --- src/coins.cpp | 94 ++++++++++++++++++++++++---------- src/coins.h | 12 ----- src/compressor.h | 4 ++ src/core_write.cpp | 1 + src/main.cpp | 8 +-- src/main.h | 6 +-- src/miner.cpp | 4 +- src/primitives/transaction.cpp | 68 +++++++++++++++--------- src/primitives/transaction.h | 32 +++++++----- src/pubkey.cpp | 5 +- src/rpcblockchain.cpp | 1 + src/rpcmining.cpp | 2 + src/rpcrawtransaction.cpp | 1 + src/script/interpreter.cpp | 21 ++++++-- src/script/interpreter.h | 14 ++--- src/script/sigcache.h | 2 +- 16 files changed, 177 insertions(+), 98 deletions(-) diff --git a/src/coins.cpp b/src/coins.cpp index 9a6cb9ae43..b5d873c6a6 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -8,6 +8,8 @@ #include +#include + /** * calculate number of bytes for the bitmask, and its number of non-zero bytes * each bit in the bitmask represents the availability of one output, but the @@ -250,41 +252,78 @@ const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const return coins->vout[input.prevout.n]; } -CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const -{ - if (tx.IsCoinBase()) - return 0; - - CAmount nResult = 0; - for (unsigned int i = 0; i < tx.vin.size(); i++) - { - const CTxOutValue& val = GetOutputFor(tx.vin[i]).nValue; - assert(val.IsAmount()); - nResult += val.GetAmount(); - } - - return nResult; -} - -CAmount CCoinsViewCache::GetValueInExcess(const CTransaction& tx) const -{ - const CAmount nValueIn = GetValueIn(tx); - const CAmount nValueOut = tx.GetValueOut(); - return nValueIn - nValueOut; -} +extern secp256k1_context_t* secp256k1_bitcoin_verify_context; bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& excess) const { - CAmount nInAmount = GetValueIn(tx); - if (nInAmount < excess) + CAmount nPlainAmount = excess; + std::vector vchData; + std::vector vpchCommitsIn, vpchCommitsOut; + bool fNullRangeproof = false; + vchData.resize(CTxOutValue::nCommitmentSize * (tx.vin.size() + tx.vout.size())); + unsigned char *p = vchData.data(); + if (!tx.IsCoinBase()) + { + for (size_t i = 0; i < tx.vin.size(); ++i) + { + const CTxOutValue& val = GetOutputFor(tx.vin[i]).nValue; + if (val.IsAmount()) + nPlainAmount -= val.GetAmount(); + else + { + assert(val.vchCommitment.size() == CTxOutValue::nCommitmentSize); + memcpy(p, &val.vchCommitment[0], CTxOutValue::nCommitmentSize); + vpchCommitsIn.push_back(p); + p += CTxOutValue::nCommitmentSize; + } + } + } + for (size_t i = 0; i < tx.vout.size(); ++i) + { + const CTxOutValue& val = tx.vout[i].nValue; + assert(val.vchCommitment.size() == CTxOutValue::nCommitmentSize); + if (val.vchNonceCommitment.size() > CTxOutValue::nCommitmentSize || val.vchRangeproof.size() > 5000) + return false; + if (val.IsAmount()) + nPlainAmount += val.GetAmount(); + else + { + memcpy(p, &val.vchCommitment[0], CTxOutValue::nCommitmentSize); + vpchCommitsOut.push_back(p); + p += CTxOutValue::nCommitmentSize; + + if (val.vchRangeproof.empty()) + fNullRangeproof = true; + } + } + + // If there are no encrypted input or output values, we can do simple math + if (vpchCommitsIn.size() + vpchCommitsOut.size() == 0) + return (nPlainAmount == 0); + + if (!secp256k1_pedersen_verify_tally(secp256k1_bitcoin_verify_context, vpchCommitsIn.data(), vpchCommitsIn.size(), vpchCommitsOut.data(), vpchCommitsOut.size(), nPlainAmount)) return false; - nInAmount -= excess; - return nInAmount == tx.GetValueOut(); + + // Rangeproof is optional in this case + if ((!vpchCommitsIn.empty()) && vpchCommitsOut.size() == 1 && nPlainAmount <= 0 && fNullRangeproof) + return true; + + uint64_t min_value, max_value; + for (size_t i = 0; i < tx.vout.size(); ++i) + { + const CTxOutValue& val = tx.vout[i].nValue; + if (val.IsAmount()) + continue; + if (!secp256k1_rangeproof_verify(secp256k1_bitcoin_verify_context, &min_value, &max_value, &val.vchCommitment[0], val.vchRangeproof.data(), val.vchRangeproof.size())) + return false; + } + + return true; } bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx) const { - const CAmount excess = GetValueInExcess(tx); + const CAmount& excess = tx.nTxFee; return VerifyAmounts(tx, excess); } @@ -322,6 +361,7 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const int nCoinsHeight = coins->nHeight == 0x7fffffff ? nHeight + 1 : coins->nHeight; if (nCoinsHeight < nHeight + nOffset) { const CTxOutValue& val = coins->vout[txin.prevout.n].nValue; + // FIXME: This assumes all blinded values are COIN CAmount nAmount = COIN; if (val.IsAmount()) nAmount = val.GetAmount(); diff --git a/src/coins.h b/src/coins.h index 9299458478..a0c2ed6d05 100644 --- a/src/coins.h +++ b/src/coins.h @@ -429,18 +429,6 @@ public: //! Calculate the size of the cache (in number of transactions) unsigned int GetCacheSize() const; - /** - * Amount of bitcoins coming in to a transaction - * Note that lightweight clients may not know anything besides the hash of previous transactions, - * so may not be able to calculate this. - * - * @param[in] tx transaction for which we are checking input total - * @return Sum of value of all inputs (scriptSigs) - */ - CAmount GetValueIn(const CTransaction& tx) const; - - CAmount GetValueInExcess(const CTransaction& tx) const; - /** * Verify the transaction's outputs spend exactly what its inputs provide, plus some excess amount. * diff --git a/src/compressor.h b/src/compressor.h index a2839e3f35..cf0c086876 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -107,6 +107,7 @@ public: template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { +#if 0 // TODO: Actually compress numeric values at least if (!ser_action.ForRead()) { assert(txout.nValue.IsAmount()); // FIXME uint64_t nVal = CompressAmount(txout.nValue.GetAmount()); @@ -116,6 +117,9 @@ public: READWRITE(VARINT(nVal)); txout.nValue = DecompressAmount(nVal); } +#else + READWRITE(txout.nValue); +#endif CScriptCompressor cscript(REF(txout.scriptPubKey)); READWRITE(cscript); } diff --git a/src/core_write.cpp b/src/core_write.cpp index d644f8a611..c3982dfa00 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -128,6 +128,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) UniValue outValue(UniValue::VNUM, FormatMoney(txout.nValue.GetAmount())); out.pushKV("value", outValue); } + // TODO: Non-Amount values out.pushKV("n", (int64_t)i); UniValue o(UniValue::VOBJ); diff --git a/src/main.cpp b/src/main.cpp index fa979a6a06..6dea8150d3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1096,7 +1096,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Bring the best block into scope view.GetBestBlock(); - nFees = view.GetValueInExcess(tx); + nFees = tx.nTxFee; if (!view.VerifyAmounts(tx, nFees)) return state.DoS(0, error("AcceptToMemoryPool : input amounts do not match output amounts %s", @@ -1576,7 +1576,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi } } - const CAmount nTxFee = inputs.GetValueInExcess(tx); + const CAmount& nTxFee = tx.nTxFee; if (nTxFee < 0) return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString()), REJECT_INVALID, "bad-txns-fee-negative"); @@ -1598,7 +1598,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // before the last block chain checkpoint. This is safe because block merkle hashes are // still computed and checked, and any change will be caught at the next checkpoint. if (fScriptChecks) { - CAmount prevValueIn = -1; + CTxOutValue prevValueIn = -1; for (unsigned int i = 0; i < tx.vin.size(); i++) { const COutPoint &prevout = tx.vin[i].prevout; const CCoins* coins = inputs.AccessCoins(prevout.hash); @@ -1880,7 +1880,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin REJECT_INVALID, "bad-blk-sigops"); } - nFees += view.GetValueInExcess(tx); + nFees += tx.nTxFee; std::vector vChecks; if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL)) diff --git a/src/main.h b/src/main.h index c71d1fccc4..1607618345 100644 --- a/src/main.h +++ b/src/main.h @@ -354,8 +354,8 @@ private: CScript scriptPubKey; const CTransaction *ptxTo; unsigned int nIn; - CAmount nValueIn; - CAmount nValueInPreviousIn; + CTxOutValue nValueIn; + CTxOutValue nValueInPreviousIn; CAmount nTxFee; int nSpendHeight; unsigned int nFlags; @@ -364,7 +364,7 @@ private: public: CScriptCheck(): ptxTo(0), nIn(0), nValueIn(-1), nValueInPreviousIn(-1), nTxFee(-1), nSpendHeight(-1), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {} - CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, CAmount nValueInPreviousInIn, CAmount nTxFeeIn, int nSpendHeightIn, unsigned int nFlagsIn, bool cacheIn) : + CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, CTxOutValue nValueInPreviousInIn, CAmount nTxFeeIn, int nSpendHeightIn, unsigned int nFlagsIn, bool cacheIn) : scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), ptxTo(&txToIn), nIn(nInIn), nValueIn(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue), nValueInPreviousIn(nValueInPreviousInIn), nTxFee(nTxFeeIn), nSpendHeight(nSpendHeightIn), diff --git a/src/miner.cpp b/src/miner.cpp index 4b3409e415..5f90d37bdd 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -96,7 +96,7 @@ int64_t UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev) static CFeeRate CalculateSubjectiveFeeRateAndPriority(const CCoinsViewCache& view, const CTransaction& tx, const unsigned int& nTxSize, double& dPriority) { const uint256& hash = tx.GetHash(); - CAmount nTxFees = view.GetValueInExcess(tx); + CAmount nTxFees = tx.nTxFee; mempool.ApplyDeltas(hash, dPriority, nTxFees); return CFeeRate(nTxFees, nTxSize); @@ -281,7 +281,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (!view.HaveInputs(tx)) continue; - CAmount nTxFees = view.GetValueInExcess(tx); + const CAmount& nTxFees = tx.nTxFee; nTxSigOps += GetP2SHSigOpCount(tx, view); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 94716036f2..8a604bc6b3 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -10,39 +10,72 @@ #include "utilstrencodings.h" CTxOutValue::CTxOutValue() -: nAmount(-1) { + vchCommitment.resize(nCommitmentSize); + memset(&vchCommitment[0], 0xff, nCommitmentSize); } CTxOutValue::CTxOutValue(CAmount nAmountIn) -: nAmount(nAmountIn) { + vchCommitment.resize(nCommitmentSize); + assert(vchCommitment.size() > sizeof(nAmountIn) + 1); + memset(&vchCommitment[0], 0, vchCommitment.size() - sizeof(nAmountIn)); + for (size_t i = 0; i < sizeof(nAmountIn); ++i) + vchCommitment[vchCommitment.size() - (i + 1)] = ((nAmountIn >> (i * 8)) & 0xff); +} + +CTxOutValue::CTxOutValue(const std::vector& vchValueCommitmentIn, const std::vector& vchRangeproofIn) +: vchCommitment(vchValueCommitmentIn), vchRangeproof(vchRangeproofIn) +{ + assert(vchCommitment.size() == nCommitmentSize); + assert(vchCommitment[0] == 2 || vchCommitment[0] == 3); } bool CTxOutValue::IsValid() const { - return nAmount >= 0; + switch (vchCommitment[0]) + { + case 0: + { + // Ensure all but the last sizeof(CAmount) bytes are zero + for (size_t i = vchCommitment.size() - sizeof(CAmount); --i > 0; ) + if (vchCommitment[i]) + return false; + return true; + } + case 2: + case 3: + // FIXME: Additional checks? + return true; + default: + return false; + } } bool CTxOutValue::IsNull() const { - return nAmount == -1; + return vchCommitment[0] == 0xff; } bool CTxOutValue::IsAmount() const { - return nAmount != -1; + return !vchCommitment[0]; } CAmount CTxOutValue::GetAmount() const { assert(IsAmount()); + CAmount nAmount = 0; + for (size_t i = 0; i < sizeof(nAmount); ++i) + nAmount |= CAmount(vchCommitment[vchCommitment.size() - (i + 1)]) << (i * 8); return nAmount; } bool operator==(const CTxOutValue& a, const CTxOutValue& b) { - return a.nAmount == b.nAmount; + return a.vchRangeproof == b.vchRangeproof && + a.vchCommitment == b.vchCommitment && + a.vchNonceCommitment == b.vchNonceCommitment; } bool operator!=(const CTxOutValue& a, const CTxOutValue& b) { @@ -94,8 +127,8 @@ std::string CTxOut::ToString() const return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", (nValue.IsAmount() ? strprintf("%d.%08d", nValue.GetAmount() / COIN, nValue.GetAmount() % COIN) : std::string("UNKNOWN")), scriptPubKey.ToString().substr(0,30)); } -CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {} -CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {} +CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nTxFee(0), nLockTime(0) {} +CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), nTxFee(tx.nTxFee), vout(tx.vout), nLockTime(tx.nLockTime) {} uint256 CMutableTransaction::GetHash() const { @@ -107,14 +140,15 @@ void CTransaction::UpdateHash() const *const_cast(&hash) = SerializeHash(*this); } -CTransaction::CTransaction() : hash(0), nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0) { } +CTransaction::CTransaction() : hash(0), nVersion(CTransaction::CURRENT_VERSION), vin(), nTxFee(0), vout(), nLockTime(0) { } -CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) { +CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), nTxFee(tx.nTxFee), vout(tx.vout), nLockTime(tx.nLockTime) { UpdateHash(); } CTransaction& CTransaction::operator=(const CTransaction &tx) { *const_cast(&nVersion) = tx.nVersion; + *const_cast(&nTxFee) = tx.nTxFee; *const_cast*>(&vin) = tx.vin; *const_cast*>(&vout) = tx.vout; *const_cast(&nLockTime) = tx.nLockTime; @@ -122,20 +156,6 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) { return *this; } -CAmount CTransaction::GetValueOut() const -{ - CAmount nValueOut = 0; - for (std::vector::const_iterator it(vout.begin()); it != vout.end(); ++it) - { - assert(it->nValue.IsAmount()); - const CAmount nAmount = it->nValue.GetAmount(); - nValueOut += nAmount; - if (!MoneyRange(nAmount) || !MoneyRange(nValueOut)) - throw std::runtime_error("CTransaction::GetValueOut() : value out of range"); - } - return nValueOut; -} - double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const { nTxSize = CalculateModifiedSize(nTxSize); diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 1f124d2694..ea8ca2dcd7 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -13,16 +13,25 @@ class CTxOutValue { - CAmount nAmount; public: + static const size_t nCommitmentSize = 33; + + std::vector vchCommitment; + std::vector vchRangeproof; + std::vector vchNonceCommitment; + CTxOutValue(); CTxOutValue(CAmount); + CTxOutValue(const std::vector& vchValueCommitment, const std::vector& vchRangeproofIn); ADD_SERIALIZE_METHODS; - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(nAmount); + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) + { + READWRITE(REF(CFlatData(&vchCommitment[0], &vchCommitment[nCommitmentSize]))); + READWRITE(vchRangeproof); + READWRITE(vchNonceCommitment); } bool IsValid() const; @@ -130,7 +139,7 @@ public: SetNull(); } - CTxOut(const CTxOutValue& nValueIn, CScript scriptPubKeyIn); + CTxOut(const CTxOutValue& valueIn, CScript scriptPubKeyIn); ADD_SERIALIZE_METHODS; @@ -142,13 +151,13 @@ public: void SetNull() { - nValue = -1; + nValue = CTxOutValue(); scriptPubKey.clear(); } bool IsNull() const { - return (nValue == -1); + return nValue.IsNull() && scriptPubKey.empty(); } bool IsDust(CFeeRate minRelayTxFee) const @@ -204,6 +213,7 @@ public: // structure, including the hash. const int32_t nVersion; const std::vector vin; + const CAmount nTxFee; const std::vector vout; const uint32_t nLockTime; @@ -222,6 +232,7 @@ public: READWRITE(*const_cast(&this->nVersion)); nVersion = this->nVersion; READWRITE(*const_cast*>(&vin)); + READWRITE(*const_cast(&nTxFee)); READWRITE(*const_cast*>(&vout)); READWRITE(*const_cast(&nLockTime)); if (ser_action.ForRead()) @@ -236,11 +247,6 @@ public: return hash; } - // Return sum of txouts. - CAmount GetValueOut() const; - // GetValueIn() is a method on CCoinsViewCache, because - // inputs must be known to compute value in. - // Compute priority, given priority of inputs and (optionally) tx size double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const; @@ -270,6 +276,7 @@ struct CMutableTransaction { int32_t nVersion; std::vector vin; + CAmount nTxFee; std::vector vout; uint32_t nLockTime; @@ -283,6 +290,7 @@ struct CMutableTransaction READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(vin); + READWRITE(nTxFee); READWRITE(vout); READWRITE(nLockTime); } diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 162be80079..6baf49b26b 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -6,7 +6,8 @@ #include -static secp256k1_context_t* secp256k1_context = NULL; +secp256k1_context_t* secp256k1_bitcoin_verify_context = NULL; +static secp256k1_context_t*& secp256k1_context = secp256k1_bitcoin_verify_context; bool CPubKey::Verify(const uint256 &hash, const std::vector& vchSig) const { if (!IsValid()) @@ -87,7 +88,7 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const { void ECC_Verify_Start() { assert(secp256k1_context == NULL); - secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_COMMIT | SECP256K1_CONTEXT_RANGEPROOF); assert(ctx != NULL); secp256k1_context = ctx; diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 253c771ffd..2230ba5ccd 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -395,6 +395,7 @@ Value gettxout(const Array& params, bool fHelp) ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1)); if (coins.vout[n].nValue.IsAmount()) ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue.GetAmount()))); + // TODO: Non-Amount values Object o; ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true); ret.push_back(Pair("scriptPubKey", o)); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 3bad4d4890..1cd647034a 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -661,7 +661,9 @@ Value getblocktemplate(const Array& params, bool fHelp) result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("transactions", transactions)); result.push_back(Pair("coinbaseaux", aux)); +#if 0 // FIXME: GBT won't work with non-Bitcoin transaction formats! at the very least, we'll need to change to coinbasetxn result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue.GetAmount())); +#endif result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); result.push_back(Pair("target", GetChallengeStrHex(*pblock))); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index a4beebbf28..5832727303 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -83,6 +83,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) Object out; if (txout.nValue.IsAmount()) out.push_back(Pair("value", ValueFromAmount(txout.nValue.GetAmount()))); + // TODO: Non-Amount values out.push_back(Pair("n", (int64_t)i)); Object o; ScriptPubKeyToJSON(txout.scriptPubKey, o, true); diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index b41b59fbf2..ad0f41009b 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -35,13 +35,26 @@ typedef vector valtype; //! anonymous namespace namespace { +static secp256k1_context_t* secp256k1_context = NULL; + class CSecp256k1Init { public: CSecp256k1Init() { - secp256k1_start(SECP256K1_START_VERIFY); + assert(secp256k1_context == NULL); + + secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + assert(ctx != NULL); + + secp256k1_context = ctx; } + ~CSecp256k1Init() { - secp256k1_stop(); + secp256k1_context_t *ctx = secp256k1_context; + secp256k1_context = NULL; + + if (ctx) { + secp256k1_context_destroy(ctx); + } } }; static CSecp256k1Init instance_of_csecp256k1; @@ -1703,7 +1716,7 @@ COutPoint TransactionSignatureChecker::GetPrevOut() const return txTo->vin[nIn].prevout; } -CAmount TransactionSignatureChecker::GetValueIn() const +CTxOutValue TransactionSignatureChecker::GetValueIn() const { return nInValue; } @@ -1713,7 +1726,7 @@ CAmount TransactionSignatureChecker::GetTransactionFee() const return nTransactionFee; } -CAmount TransactionSignatureChecker::GetValueInPrevIn() const +CTxOutValue TransactionSignatureChecker::GetValueInPrevIn() const { return nInMinusOneValue; } diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 8bbda18285..3020829952 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -105,12 +105,12 @@ public: virtual CTxOut GetOutputOffsetFromCurrent(const int offset) const; virtual COutPoint GetPrevOut() const; - virtual CAmount GetValueIn() const + virtual CTxOutValue GetValueIn() const { return -1; } - virtual CAmount GetValueInPrevIn() const + virtual CTxOutValue GetValueInPrevIn() const { return -1; } @@ -156,17 +156,17 @@ public: class TransactionSignatureChecker : public TransactionNoWithdrawsSignatureChecker { private: - const CAmount nInValue; - const CAmount nInMinusOneValue; + const CTxOutValue nInValue; + const CTxOutValue nInMinusOneValue; const CAmount nTransactionFee; const int nSpendHeight; public: - TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, CAmount nInValueIn, CAmount nInMinusOneValueIn, CAmount nTransactionFeeIn, int nSpendHeightIn) : TransactionNoWithdrawsSignatureChecker(txToIn, nInIn), nInValue(nInValueIn), nInMinusOneValue(nInMinusOneValueIn), nTransactionFee(nTransactionFeeIn), nSpendHeight(nSpendHeightIn) {} + TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, CTxOutValue nInValueIn, CTxOutValue nInMinusOneValueIn, CAmount nTransactionFeeIn, int nSpendHeightIn) : TransactionNoWithdrawsSignatureChecker(txToIn, nInIn), nInValue(nInValueIn), nInMinusOneValue(nInMinusOneValueIn), nTransactionFee(nTransactionFeeIn), nSpendHeight(nSpendHeightIn) {} CTxOut GetOutputOffsetFromCurrent(const int offset) const; COutPoint GetPrevOut() const; - CAmount GetValueIn() const; - CAmount GetValueInPrevIn() const; + CTxOutValue GetValueIn() const; + CTxOutValue GetValueInPrevIn() const; CAmount GetTransactionFee() const; #ifdef FEDERATED_PEG_SIDECHAIN_ONLY bool IsConfirmedBitcoinBlock(const uint256& hash, bool fConservativeConfirmationRequirements) const; diff --git a/src/script/sigcache.h b/src/script/sigcache.h index f3e1e56e46..3bb0e21b4c 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -18,7 +18,7 @@ private: bool store; public: - CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, CAmount nInValueIn, CAmount nInMinusOneValueIn, CAmount nTransactionFeeIn, int nSpendHeightIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn, nInValueIn, nInMinusOneValueIn, nTransactionFeeIn, nSpendHeightIn), store(storeIn) {} + CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, CTxOutValue nInValueIn, CTxOutValue nInMinusOneValueIn, CAmount nTransactionFeeIn, int nSpendHeightIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn, nInValueIn, nInMinusOneValueIn, nTransactionFeeIn, nSpendHeightIn), store(storeIn) {} bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; };