To continue on the discussion from the reddit thread here 162, factoring in some of the discussions that I’ve had with Colin, the PoS-based anti-spam system would work as follows.
Add QoS tiers to the Nano protocol where nodes may deterministically identify a “safe” order to resolve transactions in the event of an ongoing spam attack.
This may be done by adding a timestamp field to the protocol to be used as a loose idea of when a request was made. The receiving nodes will verify that this timestamp field falls within a range (
GRACE_PERIOD) of their (the nodes’) current time and obeys other rules of the network that are carefully crafted to prevent spam attacks.
If this verification fails, the user’s requests fall into the lowest QoS tier (known as the normal queue). If this verification succeeds, the user’s transaction enters the priority queue, where its actual QoS is determined by the stake of the wallet issuing the transaction.
Tiebreakers in stake would be determined via the current method of the nonce complexity.
Attacker is assumed to be able to precompute effectively “infinite” PoW. This can feasibly be done via an ASIC that would outperform a mobile user by an order of 1012. Since mobile users need to be catered to with a relatively realistic PoW (<100 seconds), this means that the attacker would be able to generate at least 1010 more PoW than an acceptable user, or effectively infinite, with a price tag of around $105 USD.
Priority Queue – The new “normal” for the network; the location for all requests that conform to new timestamping rules. Within this queue, transactions are further divided into sub-queues based on the PoS of the transacting account.
Normal Queue – The old “normal” for the network; the location for all requests that do not conform to new timestamping rules. This is effectively the lowest QoS level in the network, and is processed after all PoS-based QoS that occurs in the Priority Queue.
To qualify for the Priority Queue, a transaction must meet all of the following criteria:
- The transaction must be timestamped, and the previous transaction within the user’s blockchain (if not the
OPENoperation) must also be timestamped. In the event of an
OPENoperation with an included
RECEIVE, the corresponding
SENDoperation must be timestamped.
- When a node receives the transaction, the timestamp must be within
GRACE_PERIODfrom the current time. This may be in either direction (past or future).
- The transaction’s timestamp must be at least
MINIMUM_GAPtime after the timestamp of the previous transaction.
RECEIVEoperations, the timestamp must be at least
MINIMUM_GAPtime after the corresponding
Rule (1) is the primary driver of the entire system. Without a timestamp on the current node and a timestamp on the previous node, there are no timestamps with which to compare anything.
Rule (2) combined with Rule (3) create a system whereby an attacker cannot simultaneously send more requests at once than
GRACE_WINDOW / MINIMUM_GAP without either (A) being forcibly throttled to
1 / MINIMUM_GAP TPS or (B) falling out of the Priority Queue for 1 transaction (effectively forcing the spam to be cleared fully before they are allowed to resume).
Rule (4) prevents attacks that involve an attacker with a large amount of Nano (106+) from sending Nano to new addresses repeatedly, by enforcing that the receiving accounts are also incrementing their timer by
MINIMUM_GAP based on the sender’s timestamp.
GRACE_PERIOD– The amount of permitted time-drift from the node’s timestamp that a node will allow a transaction to have to still qualify for the Priority Queue. For example, if a node’s time is
5:00, and they receive a request that has a
GRACE_PERIODof 30 seconds, then they are willing to accept the request into the Priority Queue as long as it’s dated for anywhere from
GRACE_WINDOW– Defined as
2 * GRACE_PERIOD, because the period is both into the past & future, so the window is the full amount of time of this period in both directions. In the above example, the
GRACE_WINDOWis 1 minute (30s in both directions;
05:00:30 - 04:59:30 = 00:01:00).
MINIMUM_GAP– The amount of increase one timestamp must have from the last timestamp in a chain. For example, if the timestamp of an account’s previous request is 05:02:25 and the
MINIMUM_GAPis 15 seconds, the next request must be dated for
SUSTAINED_TPS– This is, by definition, the multiplicative inverse of
1 / MINIMUM_GAP).
MAX_BURST– Defined as
GRACE_WINDOW / MINIMUM_GAP. This is the maximum amount of transactions that may be precomputed and sent simultaneously. It requires the attacker to use the full extent of their
TIME - GRACE_PERIODthrough
TIME + GRACE_PERIOD, incrementing every
These variables (particularly
MINIMUM_GAP) may be determined dynamically based on the PoS of the wallet in question. Ideally, this is done via empirical determination of valuable metrics.
For example, if it is determined that an exchange typically handles 1 TPS, with occasional bursts to 1,000 TPS during very busy times, this could be resolved into
MINIMUM_GAP = 1 AND
GRACE_PERIOD = 500 for wallets with more than 106 stake.
Lower users may have more restricted TPS (both in consistent TPS (
MINIMUM_GAP) as well as burst TPS (indirectly determined via
If a request falls within the Priority Queue, it is then resolved based on the stake of the wallet. A wallet with 107 Nano would have its transaction resolved before the actions of a wallet containing 103 Nano, and so on down the chain.
In the Reddit thread (and initial thoughts), the QoS tiers were separated into discrete chunks. However, there is no apparent reason why the QoS tiers could not be effectively a continuous scale whereby higher PoS always yields a higher QoS.
Sample Attack Considerations
Attack 1: Invested Attacker Single Account Spam
Problem: Attacker with high amount of Nano (106 – ~$35m investment) wants to spam attack the network by sending trivial amounts to another wallet.
Solution: Due to the limitations of Rule (2) + Rule (3), the attacker would be limited to
MAX_BURST requests before being throttled down to
SUSTAINED_TPS unless they’re willing to exit the Priority Queue. If they exit the Priority Queue, they must wait for the spam attack (which exists within the Priority Queue) to resolve itself, as well as all other Priority Queue traffic, before their new Normal Queue request is resolved. This means that they are effectively DoS’ing their own ability to continue the spam attack until the ongoing spam attack subsides.
Attack 2: Mass Account Spam
Problem: Attacker uses 1,000,000 wallets, each sending 0.0000001 Nano per second through the network, bypassing the protections offered by the Priority Queue within the Time-as-a-Currency system.
Solution: PoS4QoS ensures that these extremely low value wallets would be at such an exceptionally low QoS (due to having such little PoS) that they are effectively DoS’ing such a microscopic part of the ecosystem (extremely small requests & outdated nodes/mistakes that cause legitimate users to enter the Normal Queue) so as to make the attack unfeasible/unprofitable.
Attack 3: Invested Attacker Chaining New Account Spam
Problem: Attacker owns a large amount (106+) of Nano and wants to DoS the network by sending its entire balance to a new account, which will then immediately pass the entire balance to another new account, and so on.
Solution: Rule (4) of the timestamp rules ensures that the
RECEIVE block is upped a
MINIMUM_GAP from its corresponding
SEND block; this attack becomes identical to the above
Herd Immunity – It is fairly easy to envision a scenario where, in Attack#2, microscopic amounts of the legitimate traffic on the network are still vulnerable to a spam attack. However, by protecting the high-value members, launching this attack becomes unprofitable and ultimately pointless. By neutering the goal of the attack, the weakest transactions on the network (i.e., those worth < 0.0000001 Nano, or those in the Normal Queue due to error/mistake) gain protection implicitly.
Timestamp Trust? – Timestamps are not trusted to be correct. It is in the clients’ best interest to provide an accurate timestamp, so as to ensure that they are in the Priority Queue. The purpose of the timestamp and related variables (
MINIMUM_GAP) is for decentralized throttling, not a trustworthy reporting of time. However, in a pinch, these timestamps are better than nothing to identify the time at which a request was sent, which adds a small bonus for some forensics.
Time-as-a-Currency – I’ve thrown this term around a few times now; what does this really mean? The fundamental idea is that you are given a set block of time as a “currency” that you may spend (equal to
GRACE_WINDOW). However, you must spend it in minimum chunks (
MINIMUM_GAP). In addition, you regenerate this currency at a rate of
per second(time), all in a decentralized manner. The result of
MAX_BURSTis due to stockpiling your “currency” (time) up to its maximum reserve (
GRACE_WINDOW) and spending it all on as many requests as possible (
GRACE_WINDOW / MINIMUM_GAP).
Normal Queue Meaning – The Normal Queue is a bit of a misnomer. Perhaps better names would be the “Protected Queue” and the “Vulnerable Queue.” The “Protected Queue” (here called Priority Queue) is protected from spam attacks due to the Time-as-a-Currency rate limiting principle and further protected due to PoS4QoS. Meanwhile, the “Vulnerable Queue” (AKA Normal Queue) offers no such protection. However, that does not mean that the Normal Queue would be a spammed, worthless hole of requests. In fact, the Normal Queue is what is now the entire Nano network. In short, the worst attack that an attacker could launch against this (one that forces all nodes to the Normal Queue) would simply revert the network back to the status quo.
Wrote this over here to move the discussion from Reddit and have a place to keep the discussion centralized in an area that won’t “get away” from us. The real TL;DR is up top under “Summary” if interested.