Limit by bucket within active elections

Credit goes to keeri.

Problem: drastic CPS drop across all buckets

Cause: the active elections container can fill up with elections from a single bucket. The problem is made worse when multi-account spam makes prioritization by LRU unreliable for consensus, leading to Nodes having different active elections.

Proposed solution: limit the number of elections allowed in the container from each balance bucket, which will prevent any one bucket from affecting all others

4 Likes

This may be necessary but I'd suggest we look at other ways to make sure the same blocks make it into the active election container across nodes first.

There was a thought on discord to group blocks with "close" LRU values and then sort those by block hash. At first glance, this seems like a good idea. Maybe round to the nearest 10 seconds then sort by block hash.

To me, segregating the AEC could hamper honest users, and increase the time it takes to clear spam focused on one (or only a few) buckets.

I agree some kind of limit would be required to avoid a bucket (or a few buckets) affecting all others.
But I think a fixed limit on each bucket might not work very well.

If the limit is set too high, say 50% of the total, spam two buckets would lead to the same old issue, it increases the difficulty, but just not that ideal.

If the limit is too low, it would reduce the throughput.

Here are my suggested modifications based on the idea of limit.

Proposed Solution 1:
Reserve a small amount of the elections for each bucket, or each bucket group*. Say 10-20% in total for all buckets, with the remaining 80-90% free to use by any buckets like now.
I.e. if a election from a bucket is below the reserved amount, it should always go into the Action Elections Container without problem

Proposed Solution 2:
For each RR iteration, instead of picking one election from each bucket to put into the AEC directly (Active Elections Container) (which I believe what it is right now, please correct me if I am wrong), we do this:

  1. select one election from each bucket as representative
  2. let only a fixed number of these elections from (1) to go into the AEC, say 20
  3. the selection on (2) should be based on the number of elections of corresponding bucket in the AEC, either
    • pick those elections which belongs to bucket with the least weight* in AEC
    • pick those elections which belongs to buckets that is least recently used (credits goes to keeri)
  4. add a bit more delay between iterations as the AEC is close to full, allowing new elections to have chance to compete

*Bucket group - simply like a larger bucket, e.g. bucket 1-4 belongs to a group while bucket 5-9 belongs to another
*weight = number of elections from the corresponding bucket in AEC

Proposal 3:
combine 1 and 2

Edit: these proposals can still be used together with a hard limit on each bucket (or bucket group) to further increase the difficulty for spammers

This may be necessary but I'd suggest we look at other ways to make sure the same blocks make it into the active election container across nodes first.

From what we've seen in the tests so far, I think LRU and RR are getting the same blocks into the AEC, before saturation. The trouble comes after saturation and/or when the AEC gets full - then timing becomes much more inconsistent and elections get desynced. My guess is that the timing can be off quite significantly, which would limit the benefit of grouping "close" values and sorting them (since different sets of transactions are "close" for different nodes)

Spammers can fill the AEC queue if they make transactions while the network is unsaturated, and then everyone is affected (even in empty buckets or with aged LRU accounts) because they can't get in the AEC. And then the issue is compounded by timing becoming more unreliable at saturation, and elections get desynced/stuck

Enforcing some kind of bucketized round robin (or general space reservation) in the AEC would be to mirror what happens in the election scheduler to prevent resource starvation of all buckets by one bucket

Proposed Solution 1:
Reserve a small amount of the elections for each bucket, or each bucket group*. Say 10-20% in total for all buckets, with the remaining 80-90% free to use by any buckets like now.
I.e. if a election from a bucket is below the reserved amount, it should always go into the Action Elections Container without problem

This sounds pretty similar to @Tipanano's proposal here. Once the AEC is 90% full, nodes would drop the transaction with the lowest vote weight and a >10-30 second election age, in favor of incoming transactions

Umm, I am sorry, but it doesn't feel quite similar to me at all. The only similarity is the purpose of the two proposals.
@Tipanano suggested to drop transactions in AEC, while my Proposal 1 involves no dropping.

Let me try to explain by rephrasing. IMPORTANT: below is the conceptual meaning, the implementation should be much simplier with counts
Say we have a "Main AEC", and then "AEC 1", "AEC 2", ... up to "AEC 128" which are for individual buckets.
When RR goes through each bucket, and tries to put in AEC, say when RR reaches bucket 16 and found a transaction, it tries to put it into "AEC 16", if it is full, it tries again with "Main AEC".

I suppose this proposal and the one from @Tipanano are actually complementary, but not the same thing.

1 Like

Ahh, I see what you're saying now. I misread your post - thanks for the clarification! Tipanano's suggestion reserves the last 10% for all newcomers (any bucket), whereas your suggestion splits that 10-20% into distinct reserved buckets

1 Like

Maybe I'm misunderstanding things but below saturation aren't all blocks getting into the AEC? So by definition they're all the same blocks across nodes?

I agree that if timing gaps between nodes or large this is a non starter.

Something like this seems to align with the original idea, that low balance accounts have a claim to only a small part of the network.

Is there reason to reconsider the RR mechanism pulling from all 128 buckets equally? This has never made much sense to me as it gives way more attention to "dust" buckets. Granted below saturation, whatever bucket is getting spammed could fill the AEC.

It seems to me that it's logical to have some way to boot low balance, low LRU blocks from the AEC quickly once full. It goes back to the whole idea that "dust" accounts shouldn't be given the full consideration of the network.

If we keep "dust" level accounts at bay, can anyone really afford to launch a spam account with enough different accounts (this seems to be the issue in beta testing) in higher level (i.e. human usage) buckets?

1 Like

In thinking more about this AEC issue. I'm all for booting blocks sooner rather than later. And by booting I mean dropping from the node entirely.

It seems to me that if you're transaction is having trouble gaining vote weight once in the AEC then it's likely "grouped" with transactions of similar balance and LRU. The most likely cause is your transaction is actually part of a coodinated spam (e.g. the beta network tests). Putting these transactions back into a bucket just keeps likely spam around.

I suppose there is the random chance you get a significant number of honest accounts with similar balance conducting transactions at similar intervals (LRU) but this seems unlikely, and even more unlikely if the buckets/RR were more tailored to real world usage.

If you end up in this situation, unless you have another account to use, then you're probably "stuck" until the spam blocks clear. Which seems like even more reason to drop transactions which aren't gaining voting weight.

I suppose the spammer could republish their booted blocks but that probably highlights the original idea of the buckets. Make it such that a spammer can't afford to have enough accounts to disrupt real world users with reasonable account balances.

1 Like