From ba04aed9d9d0ab22f09ae10da66b02c5cfd9da62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Mon, 1 Jun 2015 17:06:56 +0200 Subject: [PATCH] HF Assets: coins.cpp: Adapt CCoinsViewCache::VerifyAmounts and CCoins::FromTx() Assets: Adapt CCoins::FromTx() to Asset definition transactions jerzy Assets: coins.cpp fix for txs spending genesis tx --- src/coins.cpp | 67 +++++++++++++++++++++++++++++++++++++++------------ src/coins.h | 14 ++++++++--- 2 files changed, 62 insertions(+), 19 deletions(-) diff --git a/src/coins.cpp b/src/coins.cpp index b7c8866661..27192e0d3d 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -4,6 +4,7 @@ #include "coins.h" +#include "chainparams.h" #include "random.h" #include @@ -255,11 +256,11 @@ const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const extern secp256k1_context* secp256k1_bitcoin_verify_context; -bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& excess) const +bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmountMap& mTxReward) const { - CAmount nPlainAmount = excess; + CAmountMap nPlainAmounts = mTxReward; std::vector vchData; - std::vector vpchCommitsIn, vpchCommitsOut; + std::map > vpchCommitsInMap, vpchCommitsOutMap; bool fNullRangeproof = false; vchData.resize(CTxOutValue::nCommitmentSize * (tx.vin.size() + tx.vout.size())); unsigned char *p = vchData.data(); @@ -270,29 +271,45 @@ bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& exces { const CTxOut& txOut = GetOutputFor(txin); const CTxOutValue& val = txOut.nValue; + CAssetID assetID; + if (txOut.assetID.IsNull()) { + bool isPrevGenesis = false; + for (unsigned int j = 0; j < Params().GenesisBlock().vtx.size(); ++j) { + if (Params().GenesisBlock().vtx[j].GetHash() == txin.prevout.hash) + isPrevGenesis = true; + } + assetID = isPrevGenesis ? Params().HashGenesisBlock() : CAssetID(txin.prevout.hash); + } + else + assetID = txOut.assetID; if (val.IsAmount()) - nPlainAmount -= val.GetAmount(); + nPlainAmounts[assetID] -= val.GetAmount(); else { + // Touch the asset ID in the map to later iterate + nPlainAmounts[assetID] += 0; assert(val.vchCommitment.size() == CTxOutValue::nCommitmentSize); memcpy(p, &val.vchCommitment[0], CTxOutValue::nCommitmentSize); - vpchCommitsIn.push_back(p); + vpchCommitsInMap[assetID].push_back(p); p += CTxOutValue::nCommitmentSize; } } } for (size_t i = 0; i < tx.vout.size(); ++i) { - const CTxOutValue& val = tx.vout[i].nValue; + const CTxOut& txOut = tx.vout[i]; + const CTxOutValue& val = txOut.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(); + nPlainAmounts[txOut.assetID] += val.GetAmount(); else { + // Touch the asset ID in the map to later iterate + nPlainAmounts[txOut.assetID] += 0; memcpy(p, &val.vchCommitment[0], CTxOutValue::nCommitmentSize); - vpchCommitsOut.push_back(p); + vpchCommitsOutMap[txOut.assetID].push_back(p); p += CTxOutValue::nCommitmentSize; if (val.vchRangeproof.empty()) @@ -300,17 +317,33 @@ bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& exces } } + for(std::map::const_iterator it = nPlainAmounts.begin(); it != nPlainAmounts.end(); ++it) { + const CAssetID& assetID = it->first; + const CAmount& nPlainAmount = nPlainAmounts[assetID]; + std::vector& vpchCommitsIn = vpchCommitsInMap[assetID]; + std::vector& vpchCommitsOut = vpchCommitsOutMap[assetID]; // If there are no encrypted input or output values, we can do simple math - if (vpchCommitsIn.size() + vpchCommitsOut.size() == 0) - return (nPlainAmount == 0); + if (vpchCommitsIn.size() + vpchCommitsOut.size() == 0) { + // Within an asset definition transaction, the asset being defined is identified with a 0 + if (assetID.IsNull()) { + // Only asset definitions can have null asset IDs in outputs + if (!tx.IsAssetDefinition()) + return false; + // Cannot issue negative amounts + if (nPlainAmount < 0) + return false; + } else if (nPlainAmount != 0) + return false; + } else { + // Newly issued assets cannot be confidential + if (assetID.IsNull()) + return false; if (!secp256k1_pedersen_verify_tally(secp256k1_bitcoin_verify_context, vpchCommitsIn.data(), vpchCommitsIn.size(), vpchCommitsOut.data(), vpchCommitsOut.size(), nPlainAmount)) return false; - // Rangeproof is optional in this case - if ((!vpchCommitsIn.empty()) && vpchCommitsOut.size() == 1 && nPlainAmount <= 0 && fNullRangeproof) - return true; - + // Rangeproof is optional in case none of the conditions are satisfied + if (!fNullRangeproof || vpchCommitsIn.empty() || vpchCommitsOut.size() != 1 || nPlainAmount > 0) { uint64_t min_value, max_value; for (size_t i = 0; i < tx.vout.size(); ++i) { @@ -320,14 +353,16 @@ bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& exces 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 = tx.nTxFee; - return VerifyAmounts(tx, excess); + return VerifyAmounts(tx, tx.GetTxRewardMap()); } bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const diff --git a/src/coins.h b/src/coins.h index a0c2ed6d05..64bf5a658a 100644 --- a/src/coins.h +++ b/src/coins.h @@ -88,6 +88,14 @@ public: void FromTx(const CTransaction &tx, int nHeightIn) { fCoinBase = tx.IsCoinBase(); vout = tx.vout; + // Within an asset definition transaction, the asset being defined is identified with a 0. + if (tx.IsAssetDefinition()) { + const CAssetID assetID = CAssetID(tx.GetHash()); + BOOST_FOREACH(CTxOut& txout, vout) + if (txout.assetID.IsNull()) + txout.assetID = assetID; + } + nHeight = nHeightIn; nVersion = tx.nVersion; ClearUnspendable(); @@ -430,13 +438,13 @@ public: unsigned int GetCacheSize() const; /** - * Verify the transaction's outputs spend exactly what its inputs provide, plus some excess amount. + * Verify the transaction's outputs spend exactly what its inputs provide, plus some excess amounts as transaction reward. * * @param[in] tx transaction for which we are checking totals - * @param[in] excess additional amount to consider (eg, fees) + * @param[in] txReward additional amounts to consider (eg, fees and subsidy) * @return True if totals are identical */ - bool VerifyAmounts(const CTransaction& tx, const CAmount& excess) const; + bool VerifyAmounts(const CTransaction& tx, const CAmountMap& mTxReward) const; bool VerifyAmounts(const CTransaction& tx) const; //! Check whether all prevouts of the transaction are present in the UTXO set represented by this view