Understanding why transactions are taking longer to be mined and what is going on with the mempool

I’m seeing a lot of confusion about what is going with the mempool, and why transactions are getting longer to get mined.

Before I explain everything, let me summarize what is the solution:

Wallets need to update their fees to follow the ZIP-317 specification.

If these issues are bothering you, ask (nicely) the developer of your wallet to update it.

Now for the details. Be advise that it’s pretty possible that I got some of this wrong, so hopefully someone will correct me if that happens.

The spam / sandblasting attack

Check this block size chart:

Around June of 2022, someone started spamming the Zcash blockchain with huge transactions. This increased block size and made both nodes and wallets struggle to handle that load.

Due to the privacy nature of Zcash, in order for you wallet find transactions sent to you, it needs to try to decrypt every single transaction in the block chain. With the spam attack this became increasingly more costly.


The proportional fee

To attempt to address this issue, ZIP-317 was designed and then published in October 2022. It changes the Zcash default free from a fixed value of 1000 zatoshi to a fee that is proportional with the number of “logical actions” in a transaction. Roughly speaking:

  • Each transparent input or output is a logical action (more precisely the larger number between those, and also taking account the input/output size since it can vary)
  • Each Sapling Spend or Output is a logical action (again, more precisely, the larger number between those)
  • Each Orchard Action is a logical action.

The new default fee is then 5000 zatoshis per logical action, with a minimum of 10000 zatoshis.

Note that a regular transaction, that usually has 2 actions, will have a 10000 zatoshi fee (up from the previous 1000).

The new fee rules

Now what happens with transactions that don’t pay this fee?

If they were blocked, wallets would stop working when ZIP-317 was activated. Thus these rules were created (I’m simplifying some things for clarity, so this is not 100% precise):

  • Each block can have transactions with 50 “unpaid actions” (i.e. number of actions in a transaction that doesn’t pay the new default fee). These transactions are chosen weighted by how “much” they fail to pay the default fee.
  • If the mempool is full and a new tx is received, it evicts an existing transaction, given preference to “unpaid” txs (weighted on how “much” the fail to pay the default fee).

So this means that legitime transactions from wallets that weren’t updated with the new fee will still be able to get through, inside the unpaid action limit. Sure, spam txs can get in too, but since they are much bigger then are much more “unpaid” and thus will have a much higher chance of getting evicted.

The consequences of these rules are:

  • Spam transactions will take much longer to be mined, and thus will fill the mempool. That is, it’s very likely that the mempool will become full while the spam endures.
  • Legitimate transactions from wallets with old fees will still get into the mempool and be mined, regardless if the mempool is full or not.
  • In some rare cases, transactions will totally fail to get mined - if they have more than 50 logical actions (i.e. you received ZEC through 50 txs and want to send all that ZEC somewhere) and don’t pay the new fee.

ZIP-317 activation

ZIP-317 was effectively activated in April 2023 with zcashd 5.5.0 (it’s not a consensus rule, but a behavior change on the mempool and mining RPC).

You can see in the graph above that it was effective. Wallets kept working.

But they still needed to update to the new fee to guarantee that the transactions they generated will be given priority in the mempool and in mined blocks!

The spam attack change

The attacker is certainly paying attention. They couldn’t fill the blocks with spam txs anymore, unless they paid higher fees and they don’t seem to want to afford that. So they changed the nature of the spam transaction. Instead of creating big transactions, they started creating the smallest possible transactions with ~50 unpaid actions.

What this entails is that the mempool could now be completely filled with spam transactions (since the mempool is limited by size). Like I mentioned, this won’t prevent legitimate txs with old fees from getting through. But now it’s less likely that a legitimate txs will be chosen to be mined since there are much more transactions in the mempool - even if a single spam tx is less likely to get chosen, there are much more of them and the chance of one of them getting chosen is high.

So what is the solution

It’s relatively simple: wallets need to update to the new ZIP-317 fee. We could try to make adjustments to the mempool rules, but it seems just easier to update the wallets.

Why are some transactions getting stuck forever?

If the transaction doesn’t pay the new fee, it will take much longer to be mined - possibly indefinitely longer due to the probabilistic transaction selection process for mining. The solution to this already exists in the Zcash protocol - wallets can set an expiry height, and then the tx will never be mined after the expiry height is reached. This allows users to safely try again (possibly with an adjusted fee). Apparently some wallets don’t do that so they should be updated too. (I’m not certain which ones)

Does that solve everything?

Unfortunately there will be still a lingering issue. With the mempool now full all the time, while legitimate transactions will still be able to get through, wallets that monitor the mempool for transactions sent to the user will have a harder time since they have to decrypt all of them.

One possible simple mitigation is for lightwalletd maitainers to reduce the mempool size of the zcash node backing the lightwalletd server. Due to the mempool rules, it’s more likely that legitimate transactions will get into the node mempool in comparison to spam transactions.

What about sync times?

Unfortunately wallet accounts that were created before the spam attack will take a looong time to sync when restoring a seed (or if you don’t remember the wallet birthday). There is no easy way around that, other than trying to optimize the syncing procedure to be faster.

New accounts should have an easier time. (Note that you can create a new wallet and transfer all your funds to it, and write down its birthday!)

Regardless, there are improvements that can be made to the sync procedure, which is exactly what ECC is working on with Spend Before Sync.

In the long term, there may be ways to offload trial decryption to servers without loss of privacy, but this requires a lot more research.

What is the current status of wallets

I’m not 100% sure about these (please correct me if I’m wrong) and this will evolve hopefully soon so it might be outdated:

  • Ywallet now allows users to chose the fee. Try 10000 zatoshi for a reasonable default.
  • Zingo changed to a fixed 10000 zatoshi (which helps with the more common transactions)
  • Nighthawk is waiting on an update of the ECC SDK.

Could this all have been handled better?

Hindsight is 20/20 and I appreciate all the work that went into ZIP-317, but my personal opinion is yes.

  • ZIP-317 could have been designed and finished faster. We should have stopped everything else to get this done as fast as possible.
  • ZIP-317 could have been deployed faster. IIRC it got entangled with other zcashd updates related to Spend before Sync, but we should have done it before that.
  • ZIP-317 should be advertised more so that wallet developers became aware of its importance and updated the wallets ASAP. Apparently no one knows about it! Or/also wallet developers could have tried to follow more closely what was going on. In any case there’s definitely a communication issue.

Also the DEFAULT_TX_EXPIRY_DELTA is 40 (blocks). I believe most wallets uses this constant for building transactions.
The spam transactions has an expiry delta of ~210000 blocks.

Ideally, the protocol and the end user UI change as atomically as possible.


Sounds like an easy filter - block txns with stupid expiry.

1 Like