Add ZIP Draft: Addressing mempool denial-of-service

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira Hopwood 2019-09-16 21:02:09 +01:00
parent 89de83447a
commit 8e1c43b50a
1 changed files with 192 additions and 0 deletions

View File

@ -0,0 +1,192 @@
::
ZIP: Unassigned
Title: Addressing mempool denial-of-service
Owners: Daira Hopwood <daira@electriccoin.co>
Status: Draft
Category: Network
Created: 2019-09-09
License: MIT
Terminology
===========
The key words "MUST", "SHOULD", and "MAY" in this document are to be interpreted
as described in RFC 2119. [#RFC2119]_
Abstract
========
This proposal specifies a change to the behaviour of zcashd nodes intended to
mitigate denial-of-service from transaction flooding.
Motivation
==========
Adoption of this proposal would increase robustness of Zcash nodes against
denial-of-service attack, in particular attacks that attempt to exhaust node
memory.
Bitcoin Core added size limitation for the mempool in version 0.12
[#BitcoinCore-PR6722]_, defaulting to 300 MB. This was after Zcash forked from
Bitcoin Core.
Requirements
============
The memory usage of a nodes mempool should be bounded.
The eviction policy should as far as possible not be “gameable” by an adversary,
i.e. an adversary should not be able to cause legitimate transactions (that do not
themselves present any denial-of-service problem) to be preferentially evicted
relative to its own transactions.
Any configuration options should have reasonable defaults, i.e. without changing
relevant configuration, a node should be adequately protected from denial-of-service
via mempool memory exhaustion.
Non-requirements
================
The current architecture of Zcash imposes fundamental limits on scaling of
transaction throughput. This proposal does not increase the aggregate transaction
capacity of the network. (The Blossom upgrade does increase transaction capacity,
by a factor of two [#zip-0208]_.)
Denial-of-service issues in the messaging layer of the peer-to-peer protocol are
out of scope for this proposal.
This proposal is focused primarily on memory exhaustion attacks. It does not
attempt to use fees to make denial-of-service economically prohibitive, since that
is unlikely to be feasible while maintaining low fees for legitimate users. It
does not preclude changes in fee policy.
Specification
=============
This specification describes the intended behaviour of zcashd nodes. Other node
implementations MAY implement the same or similar behaviour, but this is not a
requirement of the network protocol. Thus, RFC 2119 conformance keywords below are
to be interpreted only as placing requirements on the zcashd implementation (and
potentially other implementations that have adopted this specification in full).
The mempool of a node holds a set of transactions. Each transaction has a cost,
which is an integer defined as:
max(serialized transaction size in bytes, 4000) + fee_penalty
where ``fee_penalty`` is 16000 if the transaction pays a fee less than
10000 zatoshi, otherwise 0.
Each node also MUST hold a FIFO queue RecentlyEvicted of pairs (txid, time), where
the time indicates when the given txid was evicted. This SHOULD be empty on node
startup. The size of RecentlyEvicted MUST never exceed 10000 entries.
There MUST be a configuration option ``mempool.tx_cost_limit``, which SHOULD default
to 80000000.
There MUST be a configuration option ``mempool.eviction_memory_minutes``, which
SHOULD default to 60.
On receiving a transaction:
* If it is in RecentlyEvicted, the transaction MUST be dropped.
* Calculate its cost. If the total cost of transactions in the mempool including
this one would exceed ``mempool.tx_cost_limit``, then the node MUST repeatedly
call EvictTransaction (with the new transaction included as a candidate to evict)
until the total cost does not exceed ``mempool.tx_cost_limit``.
EvictTransaction MUST do the following:
* Select a random transaction to evict, weighted by cost.
* Add the txid and the current time to RecentlyEvicted, dropping the oldest entry
in RecentlyEvicted if necessary to keep it to at most 10000 entries.
* Remove it from the mempool.
Nodes SHOULD remove transactions from RecentlyEvicted that were evicted more than
``mempool.eviction_memory_minutes`` minutes ago. This MAY be done periodically,
and/or just before RecentlyEvicted is accessed when receiving a transaction.
Rationale
=========
The accounting for transaction size should include some overhead per transaction,
to reflect the cost to the network of processing them (proof and signature
verification; networking overheads; size of in-memory data structures). The
implication of not including overhead is that a denial-of-service attacker would
be likely to use minimum-size transactions so that more of them would fit in a
block, increasing the unaccounted-for overhead. A possible counterargument would
be that the complexity of accounting for this overhead is unwarranted given that
the format of a transaction already imposes a minimum size. However, the proposed
cost function is almost as simple as using transaction size directly.
The threshold 4000 for the cost function is chosen so that the size in bytes of a
typical fully shielded Sapling transaction (with, say, 2 shielded outputs and up
to 5 shielded inputs) will fall below the threshold. This has the effect of
ensuring that such transactions are not evicted preferentially to typical
transparent transactions because of their size.
The proposed eviction policy differs significantly from that of Bitcoin Core
[#BitcoinCore-PR6722]_, which is primarily fee-based. This reflects differing
philosophies about the motivation for fees and the level of fee that legitimate
users can reasonably be expected to pay. The proposed cost function does involve
a penalty for transactions with a fee lower than the standard (0.0001 ZEC) value,
but since there is no further benefit to increasing the fee above the standard
value, it creates no pressure toward escalating fees. For transactions up to
4000 bytes, this penalty makes a transaction that pays less than the standard fee
value five times as likely to be chosen for eviction.
The default value of 80000000 for ``mempool.tx_cost_limit`` represents no more
than 40 blocks worth of transactions in the worst case, which is the default
expiration height after Blossom network upgrade [#zip-0208]_. It would serve no
purpose to make it larger.
The ``mempool.tx_cost_limit`` is a per-node configurable parameter in order to
provide flexibility for node operators to change it either in response to
attempted denial-of-service attacks, or if needed to handle spikes in transaction
demand. It may also be useful for nodes running in memory-constrained environments
to reduce this parameter.
The limit of 100000 entries in RecentlyEvicted bounds the memory needed for this
data structure. Since a txid is 32 bytes and a timestamp 8 bytes, 100000 entries
can be stored in ~4 MB, which is small compared to other node memory usage (in
particular, small compared to the maximum memory usage of the mempool itself under
the default ``mempool.tx_cost_limit``). 100000 entries should be sufficient to
mitigate any performance loss caused by re-accepting transactions that were
previously evicted. In particular, since a transaction has a minimum cost of 1000,
and the default ``mempool.tx_cost_limit`` is 80000000, at most 80000 transactions
can be in the mempool of a node using the default parameters. While the number of
transactions “in flight” or across the mempools of all nodes in the network could
exceed this number, we believe that is unlikely to be a problem in practice.
The default expiry of 40 blocks after Blossom activation represents an expected
time of 50 minutes. Therefore (even if some blocks are slow), most legitimate
transactions are expected to expire within 60 minutes. Note however that an
attackers transactions cannot be relied on to expire.
Deployment
==========
This specification is proposed to be implemented in zcashd v2.1.0.
Reference implementation
========================
TBD
References
==========
.. [#RFC2119] `Key words for use in RFCs to Indicate Requirement Levels <https://tools.ietf.org/html/rfc2119>`_
.. [#zip-0208] `Shorter Block Target Spacing <https://zips.z.cash/zip-0208>`_
.. [#BitcoinCore-PR6722] `Bitcoin Core PR 6722: Limit mempool by throwing away the cheapest txn and setting min relay fee to it <https://github.com/bitcoin/bitcoin/pull/6722>`_