Посмотрел исходники текущей trunk версии оф. клиента.
- Клиент не придерживает транзакцию в случае её некорректности, например, при вызове sendrawtransaction генерирует исключение (файл rpcrawtransaction.cpp, функция sendrawtransaction):
if (!fHave) {
// push to local node
CValidationState state;
if (!mempool.accept(state, tx, false, NULL))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); // TODO: report validation state
}
...
RelayTransaction(tx, hashTx);
Судя по всему, где-то выше по стеку исключение перехватывается и выводится сообщение об ошибке. Однако mempool.accept не проверяет минимальность комиссий, если третий параметр fLimitFree == false. В случае корректности транзакция передаётся соседям (RelayTransaction).
- При приёме транзакции от соседа mempool.accept проверяет допустимость комиссий (main.cpp, ProcessMessage, fLimitFree == true):
else if (strCommand == "tx")
{
...
bool fMissingInputs = false;
CValidationState state;
if (mempool.accept(state, tx, true, &fMissingInputs))
{
RelayTransaction(tx, inv.hash, vMsg);
...
}
else if (fMissingInputs)
{
AddOrphanTx(vMsg);
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded
unsigned int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS);
if (nEvicted > 0)
printf("mapOrphan overflow, removed %u tx\n", nEvicted);
}
int nDoS;
if (state.IsInvalid(nDoS))
pfrom->Misbehaving(nDoS);
}
Никаких ответных сообщений не отсылается, просто если транзакция не принята в mempool, то сосед, её приславший, увеличивает свою "негативную карму" (pfrom->Misbehaving(nDoS)) и при превышении последней порогового значения отправляется во временный бан.
- Из mempool'а корректные транзакции, похоже, не удаляются вообще до принятия их в блок. По крайней мере "
grep -n mempool.remove *" выдал только случай получения нового блока (main.cpp, функция SetBestChain). Т.е. транзакции в memory-пуле ждут до победного. Единственное исключение - orphan-транзакции, т.е. такие, чьи входы клиенту ещё не полностью известны (либо транзакции, чьи выходы тратит orphanная, ещё не получены, либо вообще ещё не отправлены в сеть - есть такая фича у оф. клиента). Для таких транзакций буфер ограничен (LimitOrphanTxSize) и отделён от mempool'а.
- Свои транзакции периодически перепосылаются соседям (wallet.cpp, CWallet::ResendWalletTransactions).
Хотя это довольно поверхностное копание в исходниках. Например, я пока не выяснил, перепосылаются ли периодически чужие корректные транзакции соседям, что такое фильтры (межклиентские команды filterload/filteradd/filterclear), не углублялся в вопрос, что такое inventory (CInv). Да и политики могут отличаться от версии к версии и даже от узла к узлу (наложением своих патчей). Но на первый взгляд так.