blockchain.cpp 中的 GetMinFee()
"mempoolminfee" : n, (numeric) Minimum fee rate in BTC/kB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee "minrelaytxfee" : n, (numeric) Current minimum relay fee for transactions
<https://bitcoincore.org/en/doc/0.21.0/rpc/blockchain/getmempoolinfo/>
我試圖了解如何
mempoolminfee
計算。根據上述文件,它應該是最大minrelaytxfee
和最小的記憶體池費用。我知道minrelaytxfee
是一個配置選項,可以由使用者設置為任何內容。什麼是其他費用:“最低記憶體池費用”?查看
getmempoolinfo
RPC 的程式碼,我在一個標頭檔中發現了這條註釋,它解釋了用於計算的函式:ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK()));
<https://github.com/bitcoin/bitcoin/blob/fdd80b0a53b4af0b29cb6e03118e2456d053a757/src/rpc/blockchain.cpp#L1655>
/** The minimum fee to get into the mempool, which may itself not be enough * for larger-sized transactions. * The incrementalRelayFee policy variable is used to bound the time it * takes the fee rate to go back down all the way to 0. When the feerate * would otherwise be half of this, it is set to 0 instead. */
<https://github.com/bitcoin/bitcoin/blob/fdd80b0a53b4af0b29cb6e03118e2456d053a757/src/txmempool.h#L731>
CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const { LOCK(cs); if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0) return CFeeRate(llround(rollingMinimumFeeRate)); int64_t time = GetTime(); if (time > lastRollingFeeUpdate + 10) { double halflife = ROLLING_FEE_HALFLIFE; if (DynamicMemoryUsage() < sizelimit / 4) halflife /= 4; else if (DynamicMemoryUsage() < sizelimit / 2) halflife /= 2; rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife); lastRollingFeeUpdate = time; if (rollingMinimumFeeRate < (double)incrementalRelayFee.GetFeePerK() / 2) { rollingMinimumFeeRate = 0; return CFeeRate(0); } } return std::max(CFeeRate(llround(rollingMinimumFeeRate)), incrementalRelayFee); }
<https://github.com/bitcoin/bitcoin/blob/fdd80b0a53b4af0b29cb6e03118e2456d053a757/src/txmempool.cpp#L1080>
我仍然不明白 GetMinFee() 是做什麼的。有人可以用不同的方式解釋或使用一些例子嗎?
如果我保存
minrelaytxfee=0.0002
andincrementalrelayfee=0.0003
,mempoolminfee
是 0.0002 這不是兩者的最大值。
從記憶體池的角度來看,這
rollingMinimumFeeRate
是實際的最低費率(minrelayfee 與程式碼庫的其他部分有關)。它從 0 開始,每當由於大小限製而將交易包從記憶體池中逐出時都會更新。當記憶體池達到其配置的最大值時,它會刪除最低費用包以釋放空間,並將 設置rollingMinimumFeeRate
為已刪除包支付的費用。但是你可能想知道它是如何
rollingMinimumFeeRate
下降的?如果達到最大記憶體池大小,但交易得到確認並且記憶體池的大小減小,會發生什麼?rollingMinimumFeeRate
需求最終會減少,這就是正在GetMinFee
做的事情。
GetMinFee
是更新的第二部分rollingMinimumFeeRate
。它根據計劃以指數方式減少它。如果自更改(向上或向下)以來已超過 10 秒rollingMinimumFeeRate
,則它將除以 2 的某個冪。如果記憶體池已滿一半以上,並且沒有刪除任何包以
rollingMinimumFeeRate
再次增加,那麼 12 小時後,它將是其原始值的一半。也就是說,rollingMinimumFeeRate
當記憶體池至少半滿時,它的半衰期為 12 小時。當記憶體池在四分之一滿和半滿之間時,這個半衰期會減少。在這種情況下,為 6 小時。而當記憶體池不到四分之一滿時,半衰期為 3 小時。這就是本節的作用:
double halflife = ROLLING_FEE_HALFLIFE; if (DynamicMemoryUsage() < sizelimit / 4) halflife /= 4; else if (DynamicMemoryUsage() < sizelimit / 2) halflife /= 2;
為了計算減少的
rollingMinimumFeeRate
,我們想計算自上次更新以來已經過去了多少時間,併計算出我們想要的半衰期應該低多少。這就是這條線的作用:rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife);
這真的只是半衰期公式:
N(t) = N_0 * (1/2) ^ (t/t_1/2)
。
N_0
是初始量 (rollingMinimumFeeRate
),t
是經過的時間 (time - lastRollingFeeUpdate
),t_1/2
是我們想要的半衰期 (halflife
)。如果將指數移動到分數中,減少公式,然後用程式碼寫出來,就會得到前面提到的計算線。此更新的最後一部分是檢查是否
rollingMinimumFeeRate
小於增量RelayFee 的一半。如果是,則rollingMinimumFeeRate
設置為 0。這樣做是因為指數衰減意味著從rollingMinimumFeeRate
技術上講永遠不會達到 0(這就是指數衰減函式的工作原理)。因此,我們只是將其限制為不少於incrementalRelayFee
. 一旦達到這個值,它就會重置為 0,因為到那時,它無論如何都會非常低。我們使用它
incrementalRelayFee
作為下限,因為這是交易在考慮衝突後需要支付的最低費用才能被中繼。所以一筆交易必須至少支付incrementalRelayFee
,所以我們可以rollingMinimumFeeRate
在它小於 之後放棄incrementalRelayFee
,但為了安全起見,我們以該價值的一半進行。最後一部分
GetMinFee
在函式的頂部,這只是在rollingMinimumFeeRate
我們找到一個塊之前電流不會改變,並且當它已經為 0 時返回它的優化。第一部分很重要,因為我們不想要當沒有從記憶體池中刪除東西時降低記憶體池的最低費用。