diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index d45e6de7da..1b97b9876d 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -158,25 +158,30 @@ uint256 CTransaction::GetWitnessHash() const
bool CTransaction::HasValidFee() const
{
- CAmount totalFee = 0;
+ CAmountMap totalFee;
for (unsigned int i = 0; i < vout.size(); i++) {
CAmount fee = 0;
- if (vout[i].IsFee())
+ if (vout[i].IsFee()) {
fee = vout[i].nValue.GetAmount();
- if (fee == 0 || !MoneyRange(fee)) {
- return false;
+ if (fee == 0 || !MoneyRange(fee))
+ return false;
+ uint256 assetid;
+ vout[i].nAsset.GetAssetID(assetid);
+ totalFee[assetid] += fee;
}
- totalFee += fee;
}
return MoneyRange(totalFee);
}
-CAmount CTransaction::GetFee() const
+CAmountMap CTransaction::GetFee() const
{
- CAmount fee = 0;
+ CAmountMap fee;
for (unsigned int i = 0; i < vout.size(); i++)
- if (vout[i].IsFee())
- fee += vout[i].nValue.GetAmount();
+ if (vout[i].IsFee()) {
+ uint256 assetid;
+ vout[i].nAsset.GetAssetID(assetid);
+ fee[assetid] += vout[i].nValue.GetAmount();
+ }
return fee;
}
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 16deba00c1..056f24108b 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -370,7 +370,7 @@ public:
bool IsFee() const
{
uint256 assetid;
- if (scriptPubKey == CScript() && nValue.IsAmount() && nAsset.GetAssetID(assetid) && assetid == BITCOINID)
+ if (scriptPubKey == CScript() && nValue.IsAmount() && nAsset.IsAssetID())
return true;
return false;
}
@@ -664,7 +664,7 @@ public:
bool HasValidFee() const;
// Compute the fee from the explicit fee outputs. Must call HasValidFee first
- CAmount GetFee() const;
+ CAmountMap GetFee() const;
// Compute priority, given priority of inputs and (optionally) tx size
double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 900ac39a66..59d1d17b6b 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -211,7 +211,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "" + tr("Total credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "
";
}
- CAmount nTxFee = wtx.tx->GetFee();
+ CAmount nTxFee = wtx.tx->GetFee()[BITCOINID];
if (nTxFee > 0)
strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -nTxFee) + "
";
}
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 010c84b890..06de13397b 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -113,7 +113,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet *
//
// Debit
//
- CAmount nTxFee = wtx.tx->GetFee();
+ CAmount nTxFee = wtx.tx->GetFee()[BITCOINID];
for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++)
{
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 54b4c91e9f..fd12fef8d7 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -94,7 +94,6 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
entry.push_back(Pair("vsize", (int)::GetVirtualTransactionSize(tx)));
entry.push_back(Pair("version", tx.nVersion));
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
- entry.push_back(Pair("fee", ValueFromAmount(tx.GetFee())));
UniValue vin(UniValue::VARR);
for (unsigned int i = 0; i < tx.vin.size(); i++) {
@@ -127,7 +126,10 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
const CTxOut& txout = tx.vout[i];
UniValue out(UniValue::VOBJ);
if (txout.nValue.IsAmount())
- out.push_back(Pair("value", ValueFromAmount(txout.nValue.GetAmount())));
+ if (txout.IsFee())
+ out.push_back(Pair("fee_value", ValueFromAmount(txout.nValue.GetAmount())));
+ else
+ out.push_back(Pair("value", ValueFromAmount(txout.nValue.GetAmount())));
else {
int exp;
int mantissa;
@@ -213,7 +215,6 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
" \"vsize\" : n, (numeric) The virtual transaction size (differs from size for witness transactions)\n"
" \"version\" : n, (numeric) The version\n"
" \"locktime\" : ttt, (numeric) The lock time\n"
- " \"fee\" : x.xxx, (numeric) The transaction fee in " + CURRENCY_UNIT + "\n"
" \"vin\" : [ (array of json objects)\n"
" {\n"
" \"txid\": \"id\", (string) The transaction id\n"
@@ -230,6 +231,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
" \"vout\" : [ (array of json objects)\n"
" {\n"
" \"value\" : x.xxx, (numeric) The value in " + CURRENCY_UNIT + "\n"
+ " \"fee_value\" : x.xxx, (numeric) The fee value in " + CURRENCY_UNIT + "\n"
" \"n\" : n, (numeric) index\n"
" \"assetid\" : \"hex\" (string) the asset id, if unblinded\n"
" \"assettag\" : \"hex\" (string) the asset tag, if blinded\n"
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 827334e90c..873b2f4c7f 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -340,7 +340,7 @@ BOOST_AUTO_TEST_CASE(test_Get)
t1.vout.resize(1);
t1.vout[0].nValue = 90*CENT;
t1.vout[0].scriptPubKey << OP_1;
- BOOST_CHECK(CTransaction(t1).GetFee() == (50+21+22)*CENT - 90*CENT);
+ BOOST_CHECK(CTransaction(t1).GetFee()[BITCOINID] == (50+21+22)*CENT - 90*CENT);
BOOST_CHECK(AreInputsStandard(t1, coins));
BOOST_CHECK(VerifyAmounts(coins, t1));
diff --git a/src/validation.cpp b/src/validation.cpp
index 606b5b0105..a114ecded1 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -532,8 +532,10 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
// Coinbase transactions may not have eccessive scriptSigs or any fee outputs
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
- if (tx.HasValidFee() || tx.GetFee() != 0)
- return state.DoS(100, false, REJECT_INVALID, "bad-cb-fee");
+
+ for (unsigned int i = 0; i < tx.vout.size(); i++)
+ if (tx.vout[i].IsFee())
+ return state.DoS(100, false, REJECT_INVALID, "bad-cb-fee");
}
else
{
@@ -824,16 +826,16 @@ bool VerifyAmounts(const CCoinsViewCache& cache, const CTransaction& tx, std::ve
return true;
}
-bool VerifyCoinbaseAmount(const CTransaction& tx, const CAmount& fees, const uint256& feeID)
+bool VerifyCoinbaseAmount(const CTransaction& tx, const CAmountMap& mapFees)
{
assert(tx.IsCoinBase());
- CAmount remaining = fees;
+ CAmountMap remaining = mapFees;
for (unsigned int i = 0; i < tx.vout.size(); i++) {
if (!tx.vout[i].nValue.IsAmount() || !tx.vout[i].nAsset.IsAssetID())
return false;
- if (feeID != BITCOINID)
- return false;
- remaining -= tx.vout[i].nValue.GetAmount();
+ uint256 assetid;
+ tx.vout[i].nAsset.GetAssetID(assetid);
+ remaining[assetid] -= tx.vout[i].nValue.GetAmount();
}
return MoneyRange(remaining);
}
@@ -1032,7 +1034,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
if (!tx.HasValidFee())
return state.DoS(0, false, REJECT_INVALID, "bad-fees");
- CAmount nFees = tx.GetFee();
+ CAmount nFees = tx.GetFee()[BITCOINID];
// nModifiedFees includes any fee deltas from PrioritiseTransaction
CAmount nModifiedFees = nFees;
@@ -2480,7 +2482,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
CCheckQueueControl control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
std::vector prevheights;
- CAmount nFees = 0;
+ CAmountMap mapFees;
int nInputs = 0;
int64_t nSigOpsCost = 0;
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
@@ -2555,20 +2557,20 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
}
if (!tx.HasValidFee())
return state.DoS(100, error("ConnectBlock(): transaction fee overflowed"), REJECT_INVALID, "bad-fee-outofrange");
- nFees += tx.GetFee();
- if (!MoneyRange(nFees))
+ mapFees += tx.GetFee();
+ if (!MoneyRange(mapFees))
return state.DoS(100, error("ConnectBlock(): total block reward overflowed"), REJECT_INVALID, "bad-blockreward-outofrange");
}
int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001);
- CAmount blockReward = nFees;
+ CAmountMap blockReward = mapFees;
if (!MoneyRange(blockReward))
return state.DoS(100, error("ConnectBlock(): total block reward overflowed"), REJECT_INVALID, "bad-blockreward-outofrange");
- if (!VerifyCoinbaseAmount(*(block.vtx[0]), -blockReward, BITCOINID))
+ if (!VerifyCoinbaseAmount(*(block.vtx[0]), blockReward))
return state.DoS(100,
error("ConnectBlock(): coinbase pays too much (limit=%d)",
- blockReward),
+ blockReward[BITCOINID]),
REJECT_INVALID, "bad-cb-amount");
//Don't DoS ban in case of RPC script check failure
diff --git a/src/validation.h b/src/validation.h
index b5a1e28942..64d61874a8 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -410,7 +410,7 @@ bool VerifyAmounts(const CCoinsViewCache& cache, const CTransaction& tx, std::ve
* Verify the amounts of coinbase transactions. It will fail for any blinded amount or type.
* Each output must be IsAmount && IsAssetID.
*/
-bool VerifyCoinbaseAmount(const CTransaction& tx, const CAmount& fees, const uint256& feeID);
+bool VerifyCoinbaseAmount(const CTransaction& tx, const CAmountMap& mapFees);
/**
* Check if transaction is final and can be included in a block with the
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index c5bfdbbc63..a2c5464651 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1961,7 +1961,7 @@ UniValue gettransaction(const JSONRPCRequest& request)
CAmountMap nCredit = wtx.GetCredit(filter);
CAmountMap nDebit = wtx.GetDebit(filter);
assert(wtx.tx->HasValidFee());
- CAmount nFee = (wtx.IsFromMe(filter) ? -wtx.tx->GetFee() : 0);
+ CAmount nFee = (wtx.IsFromMe(filter) ? -wtx.tx->GetFee()[BITCOINID] : 0);
CAmountMap nNet = nCredit - nDebit;
nNet[pwalletMain->GetAssetIDFromLabel("bitcoin")] -= nFee;
@@ -3015,7 +3015,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
}
// calculate the old fee and fee-rate
- CAmount nOldFee = wtx.tx->GetFee();
+ CAmount nOldFee = wtx.tx->GetFee()[BITCOINID];
CFeeRate nOldFeeRate(nOldFee, txSize);
CAmount nNewFee;
CFeeRate nNewFeeRate;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index ff66176c1f..82db94fc01 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1466,7 +1466,7 @@ void CWalletTx::GetAmounts(list& listReceived,
CAmountMap nDebit = GetDebit(filter);
if (nDebit > CAmountMap()) // debit>0 means we signed/sent this transaction
{
- nFee = tx->GetFee();
+ nFee = tx->GetFee()[BITCOINID];
}
CTxDestination addressUnaccounted = CNoDestination();