The NEO network has again been targeted by spam attacks, motivating a rapid response from core and community developers alike. NEO users experienced the repercussions in the form of light wallet outages, slow transactions and issues with GAS claims.
Spam attacks on NEO are ordinarily designed to be nullified through the use of a 20 free transaction limit in blocks. Malicious actors, who send thousands of spam transactions in attempt to clog the network by taking advantage of NEO’s free transaction model, will be unable to fill blocks. With this approach, users should be able to enter blocks by adding a small priority fee on their legitimate transactions, which can be added using wallets such as NEON or Aphelion. This bypasses the 20 free transaction limit and allows a transaction to enter a block regardless of the quantity of spam.
A combination of three small bugs were found to prevent the code from behaving as intended, allowing the spam to slow the network. Members of the development community quickly located and proposed fixes to these bugs, which have since been merged.
The first bug fix was applied by Master Contract Token and HashPuppies developer, hal0x2328, who noticed a break statement that was preventing blocks from filling up with transactions as intended. Instead, transactions would only be added to blocks until the 20 free transaction limit was reached, then no further transactions would be included due to the use of the break statement, preventing further iteration on the list of transactions.
If the first transactions added to the block were free, this resulted in blocks only containing 21 transactions – 20 free transactions, plus the miner transaction. Priority transactions were not being prioritized as intended, and a number of 21 transaction blocks containing only free transactions were propagated to the network.
This issue was compounded due to a secondary issue with rounding that was preventing transactions from being properly ranked according to their network fees. Ordinarily, nodes should attempt to pick the best 499 transactions for each block by ranking them based on the added transaction fee, divided by the size in bytes.
This is designed to allow the transactions with the highest attached fee per byte to be prioritized for addition to blocks first. However, due to a bug in how this rank was calculated, a small priority network fee combined with a large size in bytes could potentially equal zero due to rounding. This meant those transactions would not be adequately prioritized over free transactions.
This issue was detected by the community developers @belane, @jseagrave21 and @f27d, who resolved the problem by adding a secondary sort for the ranking process based on the network fee alone. This allows priority transactions to be properly ordered and prioritized.
The third bug fix was applied by HappyNodes developer @wingyungchan, which uses the same solution as the previous fix. A method used to trim the mempool to prevent it going beyond the current maximum of 50,000 transactions also experienced the same rounding error when determining which transactions to trim. Adding the additional sort by network fee allowed the CheckMemPool() method to rank paid transactions ahead of free transactions as intended.
Future Anti-Spam Measures
The bug fixes should enable blocks to properly fill to capacity and cause priority fees to work as intended, which should also help avoid issues such as long block times. This is because fewer transactions will clog up the mempool before being added to blocks. The changes do not directly prevent spam themselves, however they should negate their effectiveness.
To address the issue of spam at its source, the current consideration is the addition of a nominal transaction fee to all transactions. This fee would be small enough that it would not affect users, but it would help prevent large quantities of spam transactions. However, there are ongoing discussions for approaches that will balance the need for anti-spam measures with the desire for free transactions.
NEO’s senior R&D manager Malcolm Lerider also mentioned on Discord that there is a possibility for transaction fees to be distributed to all NEO holders, rather than exclusively to consensus nodes as originally designed. This has proven to be a popular suggestion, but its impact on the NEO economic model requires evaluation before any implementation.