| 234 | } |
| 235 | |
| 236 | bool AcceptToMemoryPool(CTxMemPool &pool, CValidationState &state, CBaseTx *pBaseTx, |
| 237 | bool fLimitFree, bool fRejectInsaneFee) { |
| 238 | AssertLockHeld(cs_main); |
| 239 | |
| 240 | auto bm = MAKE_BENCHMARK("AcceptToMemoryPool"); |
| 241 | // is it already in the memory pool? |
| 242 | uint256 hash = pBaseTx->GetHash(); |
| 243 | if (pool.Exists(hash)) |
| 244 | return state.Invalid(ERRORMSG("AcceptToMemoryPool() : txid: %s already in mempool", hash.GetHex()), |
| 245 | REJECT_INVALID, "tx-already-in-mempool"); |
| 246 | |
| 247 | // is it a miner reward tx or price median tx? |
| 248 | if (pBaseTx->IsRelayForbidden()) |
| 249 | return state.Invalid(ERRORMSG("AcceptToMemoryPool() : forbid tx=%s to accept to memory pool! txid=%s", |
| 250 | pBaseTx->GetTxTypeName(), hash.GetHex()), REJECT_INVALID, "tx-coinbase-to-mempool"); |
| 251 | |
| 252 | // Rather not work on nonstandard transactions (unless -testnet/-regtest) |
| 253 | string reason; |
| 254 | if (SysCfg().NetworkID() == MAIN_NET && !IsStandardTx(pBaseTx, reason)) |
| 255 | return state.DoS(0, ERRORMSG("AcceptToMemoryPool() : txid: %s is nonstandard transaction due to %s", |
| 256 | hash.GetHex(), reason), REJECT_NONSTANDARD, reason); |
| 257 | |
| 258 | auto spCW = std::make_shared<CCacheWrapper>(mempool.cw.get()); |
| 259 | |
| 260 | CBlockIndex *pTip = chainActive.Tip(); |
| 261 | if (pTip == nullptr) throw runtime_error("AcceptToMemoryPool(), pChainTip is nullptr"); |
| 262 | HeightType newHeight = pTip->height + 1; |
| 263 | uint32_t fuelRate = GetElementForBurn(pTip); |
| 264 | uint32_t blockTime = pTip->GetBlockTime(); |
| 265 | uint32_t prevBlockTime = pTip->pprev != nullptr ? pTip->pprev->GetBlockTime() : pTip->GetBlockTime(); |
| 266 | |
| 267 | { |
| 268 | auto bm = MAKE_BENCHMARK("check tx before add mempool"); |
| 269 | const auto &bpRegid = GetBlockBpRegid(*chainActive.TipBlock()); |
| 270 | CTxExecuteContext context(newHeight, 0, fuelRate, blockTime, prevBlockTime, bpRegid, spCW.get(), &state); |
| 271 | if (!pBaseTx->CheckBaseTx(context) || !pBaseTx->CheckTx(context)) |
| 272 | return ERRORMSG("AcceptToMemoryPool() : CheckBaseTx/CheckTx failed, txid: %s", hash.GetHex()); |
| 273 | } |
| 274 | |
| 275 | CTxMemPoolEntry entry(pBaseTx, GetTime(), newHeight); |
| 276 | auto nFees = std::get<1>(entry.GetFees()); |
| 277 | auto nSize = entry.GetTxSize(); |
| 278 | // Continuously rate-limit free trx |
| 279 | // This mitigates 'penny-flooding' -- sending thousands of free transactions just to |
| 280 | // be annoying or make others' transactions take longer to confirm. |
| 281 | if (fLimitFree && nFees < MIN_RELAY_TX_FEE) { |
| 282 | static CCriticalSection csFreeLimiter; |
| 283 | static double dFreeCount; |
| 284 | static int64_t nLastTime; |
| 285 | int64_t nNow = GetTime(); |
| 286 | |
| 287 | LOCK(csFreeLimiter); |
| 288 | // Use an exponentially decaying ~10-second window: |
| 289 | dFreeCount *= pow(1.0 - 1.0 / 10.0, (double)(nNow - nLastTime)); |
| 290 | nLastTime = nNow; |
| 291 | // -limitfreerelay unit is thousand-bytes-per-minute |
| 292 | // At default rate it would take over a month to fill 1GB |
| 293 | if (dFreeCount >= SysCfg().GetArg("-limitfreerelay", 15) * 10 * 1000 / 60) |
no test coverage detected