MWEB: Included MWEB weight in feerate

This commit is contained in:
David Burkett 2022-01-29 21:40:05 -05:00 committed by Loshan T
parent 9a9dfec9ac
commit 147ad5aefd
25 changed files with 189 additions and 87 deletions

View File

@ -426,15 +426,16 @@ public:
}
return result;
}
CAmount getRequiredFee(unsigned int tx_bytes) override { return GetRequiredFee(*m_wallet, tx_bytes); }
CAmount getRequiredFee(unsigned int tx_bytes, uint64_t mweb_weight) override { return GetRequiredFee(*m_wallet, tx_bytes, mweb_weight); }
CAmount getMinimumFee(unsigned int tx_bytes,
uint64_t mweb_weight,
const CCoinControl& coin_control,
int* returned_target,
FeeReason* reason) override
{
FeeCalculation fee_calc;
CAmount result;
result = GetMinimumFee(*m_wallet, tx_bytes, coin_control, &fee_calc);
result = GetMinimumFee(*m_wallet, tx_bytes, mweb_weight, coin_control, &fee_calc);
if (returned_target) *returned_target = fee_calc.returnedTarget;
if (reason) *reason = fee_calc.reason;
return result;

View File

@ -235,10 +235,11 @@ public:
virtual std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) = 0;
//! Get required fee.
virtual CAmount getRequiredFee(unsigned int tx_bytes) = 0;
virtual CAmount getRequiredFee(unsigned int tx_bytes, uint64_t mweb_weight) = 0;
//! Get minimum fee.
virtual CAmount getMinimumFee(unsigned int tx_bytes,
uint64_t mweb_weight,
const CCoinControl& coin_control,
int* returned_target,
FeeReason* reason) = 0;

View File

@ -89,6 +89,7 @@ void BlockAssembler::resetBlock()
// Reserve space for coinbase tx
nBlockWeight = 4000;
nBlockSigOpsCost = 400;
nBlockMWEBWeight = 0;
fIncludeWitness = false;
// These counters do not include coinbase tx
@ -98,6 +99,7 @@ void BlockAssembler::resetBlock()
Optional<int64_t> BlockAssembler::m_last_block_num_txs{nullopt};
Optional<int64_t> BlockAssembler::m_last_block_weight{nullopt};
Optional<int64_t> BlockAssembler::m_last_block_mweb_weight{nullopt};
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
{
@ -153,6 +155,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
m_last_block_num_txs = nBlockTx;
m_last_block_weight = nBlockWeight;
m_last_block_mweb_weight = nBlockMWEBWeight;
// Create coinbase transaction.
CMutableTransaction coinbaseTx;
@ -166,7 +169,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
pblocktemplate->vTxFees[0] = -nFees;
LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops %d\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);
LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops: %d MWEB weight: %u\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost, nBlockMWEBWeight);
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
@ -199,13 +202,15 @@ void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet)
}
}
bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost) const
bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost, int64_t packageMWEBWeight) const
{
// TODO: switch to weight-based accounting for packages instead of vsize-based accounting.
if (nBlockWeight + WITNESS_SCALE_FACTOR * packageSize >= nBlockMaxWeight)
return false;
if (nBlockSigOpsCost + packageSigOpsCost >= MAX_BLOCK_SIGOPS_COST)
return false;
if (nBlockMWEBWeight + packageMWEBWeight >= mw::MAX_BLOCK_WEIGHT)
return false;
return true;
}
@ -232,13 +237,14 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
nBlockWeight += iter->GetTxWeight();
++nBlockTx;
nBlockSigOpsCost += iter->GetSigOpCost();
nBlockMWEBWeight += iter->GetMWEBWeight();
nFees += iter->GetFee();
inBlock.insert(iter);
bool fPrintPriority = gArgs.GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
if (fPrintPriority) {
LogPrintf("fee %s txid %s\n",
CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
CFeeRate(iter->GetModifiedFee(), iter->GetTxSize(), iter->GetMWEBWeight()).ToString(),
iter->GetTx().GetHash().ToString());
}
}
@ -261,6 +267,7 @@ int BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& already
modEntry.nSizeWithAncestors -= it->GetTxSize();
modEntry.nModFeesWithAncestors -= it->GetModifiedFee();
modEntry.nSigOpCostWithAncestors -= it->GetSigOpCost();
modEntry.nMWEBWeightWithAncestors -= it->GetMWEBWeight();
mapModifiedTx.insert(modEntry);
} else {
mapModifiedTx.modify(mit, update_for_parent_inclusion(it));
@ -368,18 +375,20 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
uint64_t packageSize = iter->GetSizeWithAncestors();
CAmount packageFees = iter->GetModFeesWithAncestors();
int64_t packageSigOpsCost = iter->GetSigOpCostWithAncestors();
int64_t packageMWEBWeight = iter->GetMWEBWeightWithAncestors();
if (fUsingModified) {
packageSize = modit->nSizeWithAncestors;
packageFees = modit->nModFeesWithAncestors;
packageSigOpsCost = modit->nSigOpCostWithAncestors;
packageMWEBWeight = modit->nMWEBWeightWithAncestors;
}
if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
if (packageFees < blockMinFeeRate.GetTotalFee(packageSize, packageMWEBWeight)) {
// Everything else we might consider has a lower fee rate
return;
}
if (!TestPackage(packageSize, packageSigOpsCost)) {
if (!TestPackage(packageSize, packageSigOpsCost, packageMWEBWeight)) {
if (fUsingModified) {
// Since we always look at the best entry in mapModifiedTx,
// we must erase failed entries so that we can consider the

View File

@ -42,18 +42,22 @@ struct CTxMemPoolModifiedEntry {
nSizeWithAncestors = entry->GetSizeWithAncestors();
nModFeesWithAncestors = entry->GetModFeesWithAncestors();
nSigOpCostWithAncestors = entry->GetSigOpCostWithAncestors();
nMWEBWeightWithAncestors = entry->GetMWEBWeightWithAncestors();
}
int64_t GetModifiedFee() const { return iter->GetModifiedFee(); }
uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
int64_t GetMWEBWeightWithAncestors() const { return nMWEBWeightWithAncestors; }
size_t GetTxSize() const { return iter->GetTxSize(); }
uint64_t GetMWEBWeight() const { return iter->GetMWEBWeight(); }
const CTransaction& GetTx() const { return iter->GetTx(); }
CTxMemPool::txiter iter;
uint64_t nSizeWithAncestors;
CAmount nModFeesWithAncestors;
int64_t nSigOpCostWithAncestors;
int64_t nMWEBWeightWithAncestors;
};
/** Comparator for CTxMemPool::txiter objects.
@ -117,6 +121,7 @@ struct update_for_parent_inclusion
e.nModFeesWithAncestors -= iter->GetFee();
e.nSizeWithAncestors -= iter->GetTxSize();
e.nSigOpCostWithAncestors -= iter->GetSigOpCost();
e.nMWEBWeightWithAncestors -= iter->GetMWEBWeight();
}
CTxMemPool::txiter iter;
@ -138,6 +143,7 @@ private:
uint64_t nBlockWeight;
uint64_t nBlockTx;
uint64_t nBlockSigOpsCost;
uint64_t nBlockMWEBWeight;
CAmount nFees;
CTxMemPool::setEntries inBlock;
@ -162,6 +168,7 @@ public:
static Optional<int64_t> m_last_block_num_txs;
static Optional<int64_t> m_last_block_weight;
static Optional<int64_t> m_last_block_mweb_weight;
private:
// utility functions
@ -180,7 +187,7 @@ private:
/** Remove confirmed (inBlock) entries from given set */
void onlyUnconfirmed(CTxMemPool::setEntries& testSet);
/** Test if a new package would "fit" in the block */
bool TestPackage(uint64_t packageSize, int64_t packageSigOpsCost) const;
bool TestPackage(uint64_t packageSize, int64_t packageSigOpsCost, int64_t packageMWEBWeight) const;
/** Perform checks on each transaction in a package:
* locktime, premature-witness, serialized size (if necessary)
* These checks should always succeed, and they're here

View File

@ -4420,7 +4420,7 @@ bool PeerManager::SendMessages(CNode* pto)
CInv inv(state.m_wtxid_relay ? MSG_WTX : MSG_TX, hash);
pto->m_tx_relay->setInventoryTxToSend.erase(hash);
// Don't send transactions that peers will not put into their mempool
if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
if (txinfo.fee < filterrate.GetTotalFee(txinfo.vsize, txinfo.mweb_weight)) {
continue;
}
if (pto->m_tx_relay->pfilter) {
@ -4479,7 +4479,7 @@ bool PeerManager::SendMessages(CNode* pto)
auto txid = txinfo.tx->GetHash();
auto wtxid = txinfo.tx->GetWitnessHash();
// Peer told you to not send transactions at that feerate? Don't bother sending it.
if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
if (txinfo.fee < filterrate.GetTotalFee(txinfo.vsize, txinfo.mweb_weight)) {
continue;
}
if (pto->m_tx_relay->pfilter && !pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;

View File

@ -137,7 +137,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
result.estimated_vsize = size;
// Estimate fee rate
CFeeRate feerate(fee, size);
CFeeRate feerate(fee, size, ctx.mweb_tx.GetMWEBWeight());
result.estimated_feerate = feerate;
}

View File

@ -7,15 +7,26 @@
#include <tinyformat.h>
CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nBytes_)
static const CAmount BASE_MWEB_FEE = 100'000;
CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nBytes_, uint64_t mweb_weight)
: m_nFeePaid(nFeePaid), m_nBytes(nBytes_), m_weight(mweb_weight)
{
assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));
int64_t nSize = int64_t(nBytes_);
assert(mweb_weight <= uint64_t(std::numeric_limits<int64_t>::max()));
if (nSize > 0)
nSatoshisPerK = nFeePaid * 1000 / nSize;
else
CAmount mweb_fee = CAmount(mweb_weight) * BASE_MWEB_FEE;
if (mweb_fee > 0 && nFeePaid < mweb_fee) {
nSatoshisPerK = 0;
} else {
CAmount ltc_fee = (nFeePaid - mweb_fee);
int64_t nSize = int64_t(nBytes_);
if (nSize > 0)
nSatoshisPerK = ltc_fee * 1000 / nSize;
else
nSatoshisPerK = 0;
}
}
CAmount CFeeRate::GetFee(size_t nBytes_) const
@ -35,6 +46,35 @@ CAmount CFeeRate::GetFee(size_t nBytes_) const
return nFee;
}
CAmount CFeeRate::GetMWEBFee(uint64_t mweb_weight) const
{
assert(mweb_weight <= uint64_t(std::numeric_limits<int64_t>::max()));
return CAmount(mweb_weight) * BASE_MWEB_FEE;
}
CAmount CFeeRate::GetTotalFee(size_t nBytes, uint64_t mweb_weight) const
{
return GetFee(nBytes) + GetMWEBFee(mweb_weight);
}
bool CFeeRate::MeetsFeePerK(const CAmount& min_fee_per_k) const
{
// (mweb_weight * BASE_MWEB_FEE) litoshis are required as fee for MWEB transactions.
// Anything beyond that can be used to calculate nSatoshisPerK.
CAmount mweb_fee = CAmount(m_weight) * BASE_MWEB_FEE;
if (m_weight > 0 && m_nFeePaid < mweb_fee) {
return false;
}
// MWEB-to-MWEB transactions don't have a size to calculate nSatoshisPerK.
// Since we got this far, we know the transaction meets the minimum MWEB fee, so return true.
if (m_nBytes == 0 && m_weight > 0) {
return true;
}
return nSatoshisPerK >= min_fee_per_k;
}
std::string CFeeRate::ToString(const FeeEstimateMode& fee_estimate_mode) const
{
switch (fee_estimate_mode) {

View File

@ -30,6 +30,9 @@ class CFeeRate
{
private:
CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes
CAmount m_nFeePaid;
size_t m_nBytes;
uint64_t m_weight;
public:
/** Fee rate of 0 satoshis per kB */
@ -49,15 +52,26 @@ public:
* @param[in] nBytes size_t bytes (units) to construct with
* @returns fee rate
*/
CFeeRate(const CAmount& nFeePaid, size_t nBytes);
CFeeRate(const CAmount& nFeePaid, size_t nBytes_, uint64_t mweb_weight);
/**
* Return the fee in satoshis for the given size in bytes.
*/
CAmount GetFee(size_t nBytes) const;
CAmount GetFee(size_t nBytes_) const;
/**
* Return the fee in satoshis for the given MWEB weight.
*/
CAmount GetMWEBFee(uint64_t mweb_weight) const;
/**
* Return the fee in satoshis for the given size in bytes & MWEB weight.
*/
CAmount GetTotalFee(size_t nBytes, uint64_t mweb_weight) const;
/**
* Return the fee in satoshis for a size of 1000 bytes
*/
CAmount GetFeePerK() const { return GetFee(1000); }
bool MeetsFeePerK(const CAmount& min_fee_per_k) const;
friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }

View File

@ -534,7 +534,7 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
trackedTxs++;
// Feerates are stored and reported as BTC-per-kb:
CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
CFeeRate feeRate(entry.GetFee(), entry.GetTxSize(), entry.GetMWEBWeight());
mapMemPoolTxs[hash].blockHeight = txHeight;
unsigned int bucketIndex = feeStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
@ -564,7 +564,7 @@ bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxM
}
// Feerates are stored and reported as BTC-per-kb:
CFeeRate feeRate(entry->GetFee(), entry->GetTxSize());
CFeeRate feeRate(entry->GetFee(), entry->GetTxSize(), entry->GetMWEBWeight());
feeStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
shortStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());

View File

@ -469,6 +469,9 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel *
// calculation
if (nQuantity > 0)
{
// MW: TODO - Implement byte & fee estimation for MWEB
uint64_t mweb_weight = 0;
// Bytes
nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + 1 : 2) * 34) + 10; // always assume +1 output for change here
if (fWitness)
@ -486,7 +489,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel *
nBytes -= 34;
// Fee
nPayFee = model->wallet().getMinimumFee(nBytes, m_coin_control, nullptr /* returned_target */, nullptr /* reason */);
nPayFee = model->wallet().getMinimumFee(nBytes, mweb_weight, m_coin_control, nullptr /* returned_target */, nullptr /* reason */);
if (nPayAmount > 0)
{

View File

@ -179,7 +179,7 @@ void SendCoinsDialog::setModel(WalletModel *_model)
// Litecoin: Disable RBF
// connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateSmartFeeLabel);
// connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
CAmount requiredFee = model->wallet().getRequiredFee(1000);
CAmount requiredFee = model->wallet().getRequiredFee(1000, 0);
ui->customFee->SetMinValue(requiredFee);
if (ui->customFee->value() < requiredFee) {
ui->customFee->setValue(requiredFee);
@ -765,7 +765,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
m_coin_control->m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
int returned_target;
FeeReason reason;
CFeeRate feeRate = CFeeRate(model->wallet().getMinimumFee(1000, *m_coin_control, &returned_target, &reason));
CFeeRate feeRate = CFeeRate(model->wallet().getMinimumFee(1000, 0, *m_coin_control, &returned_target, &reason));
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB");

View File

@ -429,6 +429,7 @@ static RPCHelpMan getmininginfo()
UniValue obj(UniValue::VOBJ);
obj.pushKV("blocks", (int)::ChainActive().Height());
if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
if (BlockAssembler::m_last_block_mweb_weight) obj.pushKV("currentblockmwebweight", *BlockAssembler::m_last_block_mweb_weight);
if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
obj.pushKV("difficulty", (double)GetDifficulty(::ChainActive().Tip()));
obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request));

View File

@ -858,7 +858,7 @@ static RPCHelpMan sendrawtransaction()
CFeeRate(AmountFromValue(request.params[1]));
int64_t virtual_size = GetVirtualTransactionSize(*tx);
CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetTotalFee(virtual_size, tx->mweb_tx.GetMWEBWeight());
std::string err_string;
AssertLockNotHeld(cs_main);
@ -939,7 +939,7 @@ static RPCHelpMan testmempoolaccept()
CTxMemPool& mempool = EnsureMemPool(request.context);
int64_t virtual_size = GetVirtualTransactionSize(*tx);
CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetTotalFee(virtual_size, tx->mweb_tx.GetMWEBWeight());
UniValue result(UniValue::VARR);
UniValue result_0(UniValue::VOBJ);

View File

@ -69,21 +69,21 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
BOOST_CHECK_EQUAL(feeRate.GetFee(100), altFeeRate.GetFee(100));
// Check full constructor
BOOST_CHECK(CFeeRate(CAmount(-1), 0) == CFeeRate(0));
BOOST_CHECK(CFeeRate(CAmount(0), 0) == CFeeRate(0));
BOOST_CHECK(CFeeRate(CAmount(1), 0) == CFeeRate(0));
BOOST_CHECK(CFeeRate(CAmount(-1), 0, 0) == CFeeRate(0));
BOOST_CHECK(CFeeRate(CAmount(0), 0, 0) == CFeeRate(0));
BOOST_CHECK(CFeeRate(CAmount(1), 0, 0) == CFeeRate(0));
// default value
BOOST_CHECK(CFeeRate(CAmount(-1), 1000) == CFeeRate(-1));
BOOST_CHECK(CFeeRate(CAmount(0), 1000) == CFeeRate(0));
BOOST_CHECK(CFeeRate(CAmount(1), 1000) == CFeeRate(1));
BOOST_CHECK(CFeeRate(CAmount(-1), 1000, 0) == CFeeRate(-1));
BOOST_CHECK(CFeeRate(CAmount(0), 1000, 0) == CFeeRate(0));
BOOST_CHECK(CFeeRate(CAmount(1), 1000, 0) == CFeeRate(1));
// lost precision (can only resolve satoshis per kB)
BOOST_CHECK(CFeeRate(CAmount(1), 1001) == CFeeRate(0));
BOOST_CHECK(CFeeRate(CAmount(2), 1001) == CFeeRate(1));
BOOST_CHECK(CFeeRate(CAmount(1), 1001, 0) == CFeeRate(0));
BOOST_CHECK(CFeeRate(CAmount(2), 1001, 0) == CFeeRate(1));
// some more integer checks
BOOST_CHECK(CFeeRate(CAmount(26), 789) == CFeeRate(32));
BOOST_CHECK(CFeeRate(CAmount(27), 789) == CFeeRate(34));
BOOST_CHECK(CFeeRate(CAmount(26), 789, 0) == CFeeRate(32));
BOOST_CHECK(CFeeRate(CAmount(27), 789, 0) == CFeeRate(34));
// Maximum size in bytes, should not crash
CFeeRate(MAX_MONEY, std::numeric_limits<size_t>::max() >> 1).GetFeePerK();
CFeeRate(MAX_MONEY, std::numeric_limits<size_t>::max() >> 1, std::numeric_limits<size_t>::max() >> 1).GetFeePerK();
}
BOOST_AUTO_TEST_CASE(BinaryOperatorTest)

View File

@ -471,7 +471,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(!pool.exists(tx2.GetHash()));
BOOST_CHECK(!pool.exists(tx3.GetHash()));
CFeeRate maxFeeRateRemoved(25000, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2)));
CFeeRate maxFeeRateRemoved(25000, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2)), 0);
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
CMutableTransaction tx4 = CMutableTransaction();

View File

@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
tx.vin[0].scriptSig = garbage;
tx.vout.resize(1);
tx.vout[0].nValue=0LL;
CFeeRate baseRate(basefee, GetVirtualTransactionSize(CTransaction(tx)));
CFeeRate baseRate(basefee, GetVirtualTransactionSize(CTransaction(tx)), 0);
// Create a fake block
std::vector<CTransactionRef> block;

View File

@ -22,12 +22,13 @@
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
int64_t _nTime, unsigned int _entryHeight,
bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp)
: tx(_tx), nFee(_nFee), nTxWeight(GetTransactionWeight(*tx)), nUsageSize(RecursiveDynamicUsage(tx)), nTime(_nTime), entryHeight(_entryHeight),
: tx(_tx), nFee(_nFee), nTxWeight(GetTransactionWeight(*tx)), mweb_weight(tx->mweb_tx.GetMWEBWeight()), nUsageSize(RecursiveDynamicUsage(tx)), nTime(_nTime), entryHeight(_entryHeight),
spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp), m_epoch(0)
{
nCountWithDescendants = 1;
nSizeWithDescendants = GetTxSize();
nModFeesWithDescendants = nFee;
nMWEBWeightWithDescendants = mweb_weight;
feeDelta = 0;
@ -35,6 +36,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFe
nSizeWithAncestors = GetTxSize();
nModFeesWithAncestors = nFee;
nSigOpCostWithAncestors = sigOpCost;
nMWEBWeightWithAncestors = mweb_weight;
}
void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)
@ -86,17 +88,19 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan
int64_t modifySize = 0;
CAmount modifyFee = 0;
int64_t modifyCount = 0;
int64_t modifyMWEBWeight = 0;
for (const CTxMemPoolEntry& descendant : descendants) {
if (!setExclude.count(descendant.GetTx().GetHash())) {
modifySize += descendant.GetTxSize();
modifyFee += descendant.GetModifiedFee();
modifyMWEBWeight += descendant.GetMWEBWeight();
modifyCount++;
cachedDescendants[updateIt].insert(mapTx.iterator_to(descendant));
// Update ancestor state for each descendant
mapTx.modify(mapTx.iterator_to(descendant), update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCost()));
mapTx.modify(mapTx.iterator_to(descendant), update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCost(), updateIt->GetMWEBWeight()));
}
}
mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount));
mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount, modifyMWEBWeight));
}
// vHashesToUpdate is the set of transaction hashes from a disconnected block
@ -224,8 +228,9 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors
const int64_t updateCount = (add ? 1 : -1);
const int64_t updateSize = updateCount * it->GetTxSize();
const CAmount updateFee = updateCount * it->GetModifiedFee();
const int64_t updateMWEBWeight = updateCount * it->GetMWEBWeight();
for (txiter ancestorIt : setAncestors) {
mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount));
mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount, updateMWEBWeight));
}
}
@ -235,12 +240,14 @@ void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncesto
int64_t updateSize = 0;
CAmount updateFee = 0;
int64_t updateSigOpsCost = 0;
int64_t updateMWEBWeight = 0;
for (txiter ancestorIt : setAncestors) {
updateSize += ancestorIt->GetTxSize();
updateFee += ancestorIt->GetModifiedFee();
updateSigOpsCost += ancestorIt->GetSigOpCost();
updateMWEBWeight += ancestorIt->GetMWEBWeight();
}
mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, updateSigOpsCost));
mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, updateSigOpsCost, updateMWEBWeight));
}
void CTxMemPool::UpdateChildrenForRemoval(txiter it)
@ -270,8 +277,9 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
int64_t modifySize = -((int64_t)removeIt->GetTxSize());
CAmount modifyFee = -removeIt->GetModifiedFee();
int modifySigOps = -removeIt->GetSigOpCost();
int64_t modifyMWEBWeight = -((int64_t)removeIt->GetMWEBWeight());
for (txiter dit : setDescendants) {
mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, -1, modifySigOps));
mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, -1, modifySigOps, modifyMWEBWeight));
}
}
}
@ -311,24 +319,28 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
}
}
void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount)
void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifyMWEBWeight)
{
nSizeWithDescendants += modifySize;
assert(int64_t(nSizeWithDescendants) > 0);
nModFeesWithDescendants += modifyFee;
nCountWithDescendants += modifyCount;
assert(int64_t(nCountWithDescendants) > 0);
nMWEBWeightWithDescendants += modifyMWEBWeight;
assert(int64_t(nMWEBWeightWithDescendants) >= 0);
}
void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps)
void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps, int64_t modifyMWEBWeight)
{
nSizeWithAncestors += modifySize;
assert(int64_t(nSizeWithAncestors) > 0);
assert(int64_t(nSizeWithAncestors) >= 0);
nModFeesWithAncestors += modifyFee;
nCountWithAncestors += modifyCount;
assert(int64_t(nCountWithAncestors) > 0);
nSigOpCostWithAncestors += modifySigOps;
assert(int(nSigOpCostWithAncestors) >= 0);
nMWEBWeightWithAncestors += modifyMWEBWeight;
assert(int64_t(nMWEBWeightWithAncestors) >= 0);
}
CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator)
@ -800,7 +812,7 @@ void CTxMemPool::queryHashes(std::vector<uint256>& vtxid) const
}
static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) {
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), it->GetFee(), it->GetTxSize(), it->GetModifiedFee() - it->GetFee()};
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), it->GetFee(), it->GetTxSize(), it->GetMWEBWeight(), it->GetModifiedFee() - it->GetFee()};
}
std::vector<TxMempoolInfo> CTxMemPool::infoAll() const
@ -852,14 +864,14 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeD
std::string dummy;
CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
for (txiter ancestorIt : setAncestors) {
mapTx.modify(ancestorIt, update_descendant_state(0, nFeeDelta, 0));
mapTx.modify(ancestorIt, update_descendant_state(0, nFeeDelta, 0, 0));
}
// Now update all descendants' modified fees with ancestors
setEntries setDescendants;
CalculateDescendants(it, setDescendants);
setDescendants.erase(it);
for (txiter descendantIt : setDescendants) {
mapTx.modify(descendantIt, update_ancestor_state(0, nFeeDelta, 0, 0));
mapTx.modify(descendantIt, update_ancestor_state(0, nFeeDelta, 0, 0, 0));
}
++nTransactionsUpdated;
}
@ -1047,7 +1059,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends
// "minimum reasonable fee rate" (ie some value under which we consider txn
// to have 0 fee). This way, we don't allow txn to enter mempool with feerate
// equal to txn which were removed with no block in between.
CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants());
CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants(), it->GetMWEBWeightWithDescendants());
removed += incrementalRelayFee;
trackPackageRemoved(removed);
maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed);

View File

@ -89,6 +89,7 @@ private:
mutable Children m_children;
const CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
const size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize())
const uint64_t mweb_weight;
const size_t nUsageSize; //!< ... and total memory usage
const int64_t nTime; //!< Local time when entering the mempool
const unsigned int entryHeight; //!< Chain height when entering the mempool
@ -103,12 +104,14 @@ private:
uint64_t nCountWithDescendants; //!< number of descendant transactions
uint64_t nSizeWithDescendants; //!< ... and size
CAmount nModFeesWithDescendants; //!< ... and total fees (all including us)
uint64_t nMWEBWeightWithDescendants;
// Analogous statistics for ancestor transactions
uint64_t nCountWithAncestors;
uint64_t nSizeWithAncestors;
CAmount nModFeesWithAncestors;
int64_t nSigOpCostWithAncestors;
int64_t nMWEBWeightWithAncestors;
public:
CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
@ -121,6 +124,7 @@ public:
const CAmount& GetFee() const { return nFee; }
size_t GetTxSize() const;
size_t GetTxWeight() const { return nTxWeight; }
size_t GetMWEBWeight() const { return mweb_weight; }
std::chrono::seconds GetTime() const { return std::chrono::seconds{nTime}; }
unsigned int GetHeight() const { return entryHeight; }
int64_t GetSigOpCost() const { return sigOpCost; }
@ -129,9 +133,9 @@ public:
const LockPoints& GetLockPoints() const { return lockPoints; }
// Adjusts the descendant state.
void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifyMWEBWeight);
// Adjusts the ancestor state
void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps);
void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps, int64_t modifyMWEBWeight);
// Updates the fee delta used for mining priority score, and the
// modified fees with descendants.
void UpdateFeeDelta(int64_t feeDelta);
@ -141,6 +145,7 @@ public:
uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
uint64_t GetMWEBWeightWithDescendants() const { return nMWEBWeightWithDescendants; }
bool GetSpendsCoinbase() const { return spendsCoinbase; }
@ -148,6 +153,7 @@ public:
uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
int64_t GetSigOpCostWithAncestors() const { return nSigOpCostWithAncestors; }
uint64_t GetMWEBWeightWithAncestors() const { return nMWEBWeightWithAncestors; }
const Parents& GetMemPoolParentsConst() const { return m_parents; }
const Children& GetMemPoolChildrenConst() const { return m_children; }
@ -161,33 +167,35 @@ public:
// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index.
struct update_descendant_state
{
update_descendant_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount) :
modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount)
update_descendant_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount, int64_t _modifyMWEBWeight) :
modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount), modifyMWEBWeight(_modifyMWEBWeight)
{}
void operator() (CTxMemPoolEntry &e)
{ e.UpdateDescendantState(modifySize, modifyFee, modifyCount); }
{ e.UpdateDescendantState(modifySize, modifyFee, modifyCount, modifyMWEBWeight); }
private:
int64_t modifySize;
CAmount modifyFee;
int64_t modifyCount;
int64_t modifyMWEBWeight;
};
struct update_ancestor_state
{
update_ancestor_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount, int64_t _modifySigOpsCost) :
modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount), modifySigOpsCost(_modifySigOpsCost)
update_ancestor_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount, int64_t _modifySigOpsCost, int64_t _modifyMWEBWeight) :
modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount), modifySigOpsCost(_modifySigOpsCost), modifyMWEBWeight(_modifyMWEBWeight)
{}
void operator() (CTxMemPoolEntry &e)
{ e.UpdateAncestorState(modifySize, modifyFee, modifyCount, modifySigOpsCost); }
{ e.UpdateAncestorState(modifySize, modifyFee, modifyCount, modifySigOpsCost, modifyMWEBWeight); }
private:
int64_t modifySize;
CAmount modifyFee;
int64_t modifyCount;
int64_t modifySigOpsCost;
int64_t modifyMWEBWeight;
};
struct update_fee_delta
@ -382,6 +390,9 @@ struct TxMempoolInfo
/** Virtual size of the transaction. */
size_t vsize;
/** MWEB weight */
uint64_t mweb_weight;
/** The fee delta. */
int64_t nFeeDelta;
};

View File

@ -522,15 +522,15 @@ private:
bool Finalize(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Compare a package's feerate against minimum allowed.
bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state)
bool CheckFeeRate(size_t package_size, uint64_t mweb_weight, CAmount package_fee, TxValidationState& state)
{
CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size);
CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetTotalFee(package_size, mweb_weight);
if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
}
if (package_fee < ::minRelayTxFee.GetFee(package_size)) {
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size)));
if (package_fee < ::minRelayTxFee.GetTotalFee(package_size, mweb_weight)) {
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetTotalFee(package_size, mweb_weight)));
}
return true;
}
@ -729,6 +729,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
entry.reset(new CTxMemPoolEntry(ptx, nFees, nAcceptTime, ::ChainActive().Height(),
fSpendsCoinbase, nSigOpsCost, lp));
unsigned int nSize = entry->GetTxSize();
uint64_t mweb_weight = entry->GetMWEBWeight();
if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST)
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops",
@ -736,7 +737,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// No transactions are allowed below minRelayTxFee except from disconnected
// blocks
if (!bypass_limits && !CheckFeeRate(nSize, nModifiedFees, state)) return false;
if (!bypass_limits && !CheckFeeRate(nSize, mweb_weight, nModifiedFees, state)) return false;
const CTxMemPool::setEntries setIterConflicting = m_pool.GetIterSet(setConflicts);
// Calculate in-mempool ancestors, up to a limit.
@ -825,7 +826,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
fReplacementTransaction = setConflicts.size();
if (fReplacementTransaction)
{
CFeeRate newFeeRate(nModifiedFees, nSize);
CFeeRate newFeeRate(nModifiedFees, nSize, mweb_weight);
std::set<uint256> setConflictsParents;
const int maxDescendantsToVisit = 100;
for (const auto& mi : setIterConflicting) {
@ -843,7 +844,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// mean high feerate children are ignored when deciding whether
// or not to replace, we do require the replacement to pay more
// overall fees too, mitigating most cases.
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize(), mi->GetMWEBWeight());
if (newFeeRate <= oldFeeRate)
{
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee",
@ -918,13 +919,13 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// Finally in addition to paying more fees than the conflicts the
// new transaction must pay for its own bandwidth.
CAmount nDeltaFees = nModifiedFees - nConflictingFees;
if (nDeltaFees < ::incrementalRelayFee.GetFee(nSize))
if (nDeltaFees < ::incrementalRelayFee.GetTotalFee(nSize, mweb_weight))
{
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee",
strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
hash.ToString(),
FormatMoney(nDeltaFees),
FormatMoney(::incrementalRelayFee.GetFee(nSize))));
FormatMoney(::incrementalRelayFee.GetTotalFee(nSize, mweb_weight))));
}
}
return true;

View File

@ -66,6 +66,7 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wt
// in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
// moment earlier. In this case, we report an error to the user, who may adjust the fee.
CFeeRate minMempoolFeeRate = wallet.chain().mempoolMinFee();
const uint64_t mweb_weight = wtx.tx->mweb_tx.GetMWEBWeight();
if (newFeerate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
errors.push_back(strprintf(
@ -75,7 +76,7 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wt
return feebumper::Result::WALLET_ERROR;
}
CAmount new_total_fee = newFeerate.GetFee(maxTxSize);
CAmount new_total_fee = newFeerate.GetTotalFee(maxTxSize, mweb_weight);
CFeeRate incrementalRelayFee = std::max(wallet.chain().relayIncrementalFee(), CFeeRate(WALLET_INCREMENTAL_RELAY_FEE));
@ -83,17 +84,17 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wt
isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
CAmount old_fee = wtx.GetDebit(filter) - wtx.tx->GetValueOut();
const int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
CFeeRate nOldFeeRate(old_fee, txSize);
CFeeRate nOldFeeRate(old_fee, txSize, mweb_weight);
// Min total fee is old fee + relay fee
CAmount minTotalFee = nOldFeeRate.GetFee(maxTxSize) + incrementalRelayFee.GetFee(maxTxSize);
CAmount minTotalFee = nOldFeeRate.GetTotalFee(maxTxSize, mweb_weight) + incrementalRelayFee.GetFee(maxTxSize);
if (new_total_fee < minTotalFee) {
errors.push_back(strprintf(Untranslated("Insufficient total fee %s, must be at least %s (oldFee %s + incrementalFee %s)"),
FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxTxSize)), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))));
FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetTotalFee(maxTxSize, mweb_weight)), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))));
return feebumper::Result::INVALID_PARAMETER;
}
CAmount requiredFee = GetRequiredFee(wallet, maxTxSize);
CAmount requiredFee = GetRequiredFee(wallet, maxTxSize, mweb_weight);
if (new_total_fee < requiredFee) {
errors.push_back(strprintf(Untranslated("Insufficient total fee (cannot be less than required fee %s)"),
FormatMoney(requiredFee)));
@ -117,7 +118,7 @@ static CFeeRate EstimateFeeRate(const CWallet& wallet, const CWalletTx& wtx, con
// the tx fee/vsize, so it may have been rounded down. Add 1 satoshi to the
// result.
int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
CFeeRate feerate(old_fee, txSize);
CFeeRate feerate(old_fee, txSize, wtx.tx->mweb_tx.GetMWEBWeight());
feerate += CFeeRate(1);
// The node has a configurable incremental relay fee. Increment the fee by

View File

@ -9,15 +9,15 @@
#include <wallet/wallet.h>
CAmount GetRequiredFee(const CWallet& wallet, unsigned int nTxBytes)
CAmount GetRequiredFee(const CWallet& wallet, unsigned int nTxBytes, uint64_t mweb_weight)
{
return GetRequiredFeeRate(wallet).GetFee(nTxBytes);
return GetRequiredFeeRate(wallet).GetTotalFee(nTxBytes, mweb_weight);
}
CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinControl& coin_control, FeeCalculation* feeCalc)
CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, uint64_t mweb_weight, const CCoinControl& coin_control, FeeCalculation* feeCalc)
{
return GetMinimumFeeRate(wallet, coin_control, feeCalc).GetFee(nTxBytes);
return GetMinimumFeeRate(wallet, coin_control, feeCalc).GetTotalFee(nTxBytes, mweb_weight);
}
CFeeRate GetRequiredFeeRate(const CWallet& wallet)

View File

@ -17,13 +17,13 @@ struct FeeCalculation;
* Return the minimum required absolute fee for this size
* based on the required fee rate
*/
CAmount GetRequiredFee(const CWallet& wallet, unsigned int nTxBytes);
CAmount GetRequiredFee(const CWallet& wallet, unsigned int nTxBytes, uint64_t mweb_weight);
/**
* Estimate the minimum fee considering user set parameters
* and the required fee
*/
CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinControl& coin_control, FeeCalculation* feeCalc);
CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, uint64_t mweb_weight, const CCoinControl& coin_control, FeeCalculation* feeCalc);
/**
* Return the minimum required feerate taking into account the

View File

@ -216,7 +216,7 @@ static void SetFeeEstimateMode(const CWallet& wallet, CCoinControl& cc, const Un
if (!estimate_mode.isNull() && estimate_mode.get_str() != "unset") {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and fee_rate");
}
cc.m_feerate = CFeeRate(AmountFromValue(fee_rate), COIN);
cc.m_feerate = CFeeRate(AmountFromValue(fee_rate), COIN, 0);
if (override_min_fee) cc.fOverrideFeeRate = true;
// Default RBF to true for explicit fee_rate, if unset.
if (cc.m_signal_bip125_rbf == nullopt) cc.m_signal_bip125_rbf = true;
@ -2338,8 +2338,8 @@ static RPCHelpMan settxfee()
LOCK(pwallet->cs_wallet);
CAmount nAmount = AmountFromValue(request.params[0]);
CFeeRate tx_fee_rate(nAmount, 1000);
CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000);
CFeeRate tx_fee_rate(nAmount, 1000, 0);
CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000, 0);
if (tx_fee_rate == CFeeRate(0)) {
// automatic selection
} else if (tx_fee_rate < pwallet->chain().relayMinFee()) {

View File

@ -2509,7 +2509,7 @@ bool CWallet::SignTransaction(CMutableTransaction& tx) const
return false;
}
const CWalletTx& wtx = mi->second;
coins[input.prevout] = Coin(wtx.tx->vout[input.prevout.n], wtx.m_confirm.block_height, wtx.IsCoinBase());
coins[input.prevout] = Coin(wtx.tx->vout[input.prevout.n], wtx.m_confirm.block_height, wtx.IsCoinBase(), wtx.IsHogEx());
}
std::map<int, std::string> input_errors;
return SignTransaction(tx, coins, SIGHASH_ALL, input_errors);
@ -3956,7 +3956,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
warnings.push_back(AmountHighWarn("-paytxfee") + Untranslated(" ") +
_("This is the transaction fee you will pay if you send a transaction."));
}
walletInstance->m_pay_tx_fee = CFeeRate(nFeePerK, 1000);
walletInstance->m_pay_tx_fee = CFeeRate(nFeePerK, 1000, 0);
if (walletInstance->m_pay_tx_fee < chain.relayMinFee()) {
error = strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
gArgs.GetArg("-paytxfee", ""), chain.relayMinFee().ToString());
@ -3973,7 +3973,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
if (nMaxFee > HIGH_MAX_TX_FEE) {
warnings.push_back(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
}
if (CFeeRate(nMaxFee, 1000) < chain.relayMinFee()) {
if (CFeeRate(nMaxFee, 1000, 0) < chain.relayMinFee()) {
error = strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
gArgs.GetArg("-maxtxfee", ""), chain.relayMinFee().ToString());
return nullptr;

View File

@ -549,6 +549,7 @@ public:
const uint256& GetHash() const { return tx->GetHash(); }
bool IsCoinBase() const { return tx->IsCoinBase(); }
bool IsImmatureCoinBase() const;
bool IsHogEx() const { return tx->IsHogEx(); }
// Disable copying of CWalletTx objects to prevent bugs where instances get
// copied in and out of the mapWallet map, and fields are updated in the