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
This commit is contained in:
Jorge Timón 2015-06-01 17:06:56 +02:00
parent f406c03568
commit ba04aed9d9
2 changed files with 62 additions and 19 deletions

View file

@ -4,6 +4,7 @@
#include "coins.h"
#include "chainparams.h"
#include "random.h"
#include <assert.h>
@ -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<unsigned char> vchData;
std::vector<unsigned char *> vpchCommitsIn, vpchCommitsOut;
std::map<CAssetID, std::vector<unsigned char *> > 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<CAssetID, CAmount>::const_iterator it = nPlainAmounts.begin(); it != nPlainAmounts.end(); ++it) {
const CAssetID& assetID = it->first;
const CAmount& nPlainAmount = nPlainAmounts[assetID];
std::vector<unsigned char *>& vpchCommitsIn = vpchCommitsInMap[assetID];
std::vector<unsigned char *>& 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

View file

@ -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