bitdex has quit [Remote host closed the connection]
bitdex has joined #bitcoin-core-dev
<sipa>
_aj_: in what way does the formula i implemented differ from what you thought?
Saturday7 has joined #bitcoin-core-dev
<sipa>
ah, the use of time-since-send, rather than a fixed % per trickle?
f321x has quit [Ping timeout: 272 seconds]
Guest81 has quit [Quit: Client closed]
<_aj_>
sipa: i was making the drain rate proportional to the incoming rate, rather than the queue size?
<sipa>
08:12:33 < sipa> it should just be past_avg -= to_send
<sipa>
08:12:46 < sipa> .. and then past_avg just becomes equal to the queue size
<sipa>
i stopped using a separate variable for tracking rate here, because the queue size is an exact proxy for it
<_aj_>
hmm
<_aj_>
well then it must just be that i was using the average time rather than the actual time?
<sipa>
yeah
<_aj_>
right, because we stopped scaling past_avg down by q
<sipa>
also, you use max(target, queue_size * (1-q)) rather than (target + queue_size * (1-q))
<_aj_>
sure, but that should be a trivial difference
<sipa>
indeed
<_aj_>
so this is just saying either max(70, 0.08 * inv_to_send.size()) or 70 + 0.08 * inv_to_send.size() ?
<_aj_>
and a queue of 5000 gives a inv of size 400 or 470 or so
<sipa>
right
WizJin_ has joined #bitcoin-core-dev
<sipa>
you think using actual time is worse than avg_time?
<_aj_>
i think having a queue of only 5000 and sending a single inv with 2000 entries seems bad/unnecessary? i can't remember what it takes for us to start ignoring invs though
<_aj_>
the more predictable the size of our invs are over some unit of time, the better for erlay, i think?
WizJin__ has quit [Ping timeout: 256 seconds]
<_aj_>
so 0.08 there is just changing the current 5-per-1000 logic from an avg-time-in-q of ~1000 seconds to 60 seconds
<_aj_>
or changing 5-per-1000 to ~5-per-60
<sipa>
right
<sipa>
i like the real-time formula better because it means the amount sent per time is less variable (because it doesn't depend on the trickle timing)
<sipa>
but of course the amount sent per trickle is more variable
<_aj_>
should just be "0.08 * time_since / target" without the exp() stuff in the case?
<_aj_>
"that case". why would my fingers type "the" there, seriously.
<sipa>
_aj_: sure, that also has the "just a function of time" property, but no longer has an average-time-in-queue that's independent of incoming rate
<_aj_>
sipa: that property feels contradictory to the goal of smoothing out spikes -- doesn't smoothing out spikes imply that a high incoming rate should be associated with a higher aveage-time-in-queue?
<sipa>
_aj_: at low/reasonable rate, yes; at high rate, i think a fixed avg-time-in-queue is desirable because the alternative is a possibility for a quickly growing queue
<sipa>
the alternative is dropping transactions at the source
f321x has joined #bitcoin-core-dev
<sipa>
the earlier quadratic formula i suggest was even more aggressive, in that it results in a decreasing time in queue with increasing rate
<_aj_>
i guess there's a few different rates -- ~5-7 tx/s is what we see normally; < 14 tx/s is what we cope with without this; sustained <80 tx/s would give us a queue of ~5000 which seems fine; but dumping 50k or 100k txs (12MB?) in short order is possible too...
<sipa>
should we have 3 "parameter rates", 1 for "no delay", 1 for "smooth out", 1 for "drop stuff" ?
<_aj_>
could we rate limit in RelayTransaction? use a token bucket with an 80/s rate, and just create a global queue of transactions to relay onwards once we have tokens again if we run out?
<sipa>
that lacks the nice quality-sorting we can do at inv time
<_aj_>
we could quality-sort the RelayTransaction queue
<sipa>
that would have the cpu-resource benefit of only doing the sorting oncew
<sipa>
rather than for every peer
<_aj_>
maybe? we'd need to go through the entire queue every now and then to drop stuff that's been removed from the mempool?
<_aj_>
maybe as a global queue the mempool could manage it and directly remove txs from it though
Zenton_ has quit [Quit: Leaving]
<sipa>
but you'd still need per-peer data to know what has been relayed to them alreasy
<sipa>
though, the alreadyknown filter already partially has this information
<sipa>
this is sounding a bit like dzxzg's idea earlier
Zenton has joined #bitcoin-core-dev
cold has quit [Ping timeout: 252 seconds]
midnight has quit [Ping timeout: 252 seconds]
cold has joined #bitcoin-core-dev
midnight has joined #bitcoin-core-dev
<_aj_>
sipa: if you cap the RelayTransaction rate at 80/s, and do 0.08*q for inv, i think that caps the per-peer q at perhaps 5000 txs?
<_aj_>
sipa: (ie, 1000 in the queue due to sustained load, plus a minute's worth of 80/s txs for another 4800, where a minute between invs happens maybe once every 9 days?
bitdex has quit [Remote host closed the connection]
bitdex has joined #bitcoin-core-dev
f321x has quit [Remote host closed the connection]
f321x has joined #bitcoin-core-dev
<_aj_>
sipa: maybe could have a set<txiter> of unrelayed txs managed by the mempool, sorted by quality; and use the quality lookup to remove tx from the set when they're removed from the mempool? would be removing and reinserting when the quality score changes (if chunking changes?) though
<sipa>
_aj_: and refcounted by how many peers it still needs to be relayed to?
<_aj_>
sipa: i think it gets relayed to everyone that's currently connected as soon as it gets a token?
<_aj_>
sipa: i guess could track time and compare against CNode::m_connected or perhaps track VERACK time or mempool sequence?
<sipa>
_aj_: could have a timeout, where transactions can only stay in the set of unrelayed txn for a finite amount of time, and if they reach that timeout (not evicted by better relayable ones, and not yet relayed to everyone), just blast it out
<_aj_>
sipa: if you had a boost::multi_index instead of a set, a timeout would be easy to manage. would've gone with dropping (not relaying) rather than blasting out though. a set<txiter> is 32B per tx, so 100k txs in the queue is just 3MB, and if you've got 100k backlog dropping stuff at the bottom seems fine
<_aj_>
sipa: oh, the other thing you could do is increase the mempool minfee when the to-relay queue gets too big
<_aj_>
(or have a separate "min incoming fee" and increase that and apply it to feefilter)
bitdex has quit [Remote host closed the connection]
bitdex has joined #bitcoin-core-dev
f321x has quit [Remote host closed the connection]
f321x has joined #bitcoin-core-dev
f321x has quit [Remote host closed the connection]
f321x has joined #bitcoin-core-dev
Artea has quit [Ping timeout: 244 seconds]
bitdex has quit [Quit: = ""]
TheRec_ has quit [Read error: Connection reset by peer]
TheRec has joined #bitcoin-core-dev
TheRec has joined #bitcoin-core-dev
Cory18 has quit [Quit: Client closed]
Cory18 has joined #bitcoin-core-dev
<sipa>
_aj_: i'm wondering if post-cluster-mempool, we could do something like keep per-peer an iterator into the chunk index ("mostly relayed every chunk with feerates higher than this") + a set of unrelayed transactions before that point
<sipa>
and at inv time, first take from the unrelayed set (using the existing heapify approach, i guess), and if it empties, start advancing the iterator
<sipa>
effectively making the entire chunk index the set of to-be-relayed transactions
<sipa>
it doesn't even need to be an iterator; for layer separation it'd be fine to just store a per-peer chunk feerate, and a set of transactions whose chunk feerate is (or was, at some point) higher than that
PaperSword has quit [Remote host closed the connection]
PaperSword has joined #bitcoin-core-dev
Christoph_ has joined #bitcoin-core-dev
f321x has quit [Quit: f321x]
<_aj_>
sipa: i don't see how that would work at all? we'll get new transactions both above and below the iterator, and need to keep track of anything not relayed in either case?
<sipa>
well you don't need to keep track of any transaction with a feerate below the "up to this feerate" value
<sipa>
because it's just implicitly all transactions whose feerate below that point that still need to be relayed
<sipa>
but it may indeed not gain us much, as in the steady state, that feerate will equal the feefilter rate
<_aj_>
sipa: if your mempool has feerates from 10sat/vb to 50sat/vb, and you've relayed everything, and your iterator is at 50sat/vb; then you get a huge mass of txs in the 20sat/vb to 120sat/vb range, your pointer will just get stuck at 20sat/vb and not do you any good?
<_aj_>
oh, below that point, so it's stuck at 10sat/vb forever
<sipa>
i guess the feerate i'm imagining being stored is "the lowest chunk feerate of any mempool transaction which you've relayed to this peer"
<sipa>
anything with a lower feerate you don't need to add to the set
<sipa>
but it sounds like a mess to keep track of, and i'm not sure it really helps with anything
Christoph_ has quit [Quit: Christoph_]
<_aj_>
i just can't see how this can do anything useful? you'll have relayed txs both above and below any pointer (above because that's priority, below because they're old and there was less pressure), and you'll get new txs both above and below, so you have to track the ones below (because they're less likely to be sent) and may have to track the ones above (if the rate becomes too high)?
Guyver2 has left #bitcoin-core-dev [Closing Window]
<sipa>
yeah
<sipa>
please disregard
<_aj_>
you could invert the logic at a point -- track the ones to be relayed above a point, and track the ones already relayed below that point; but that seems fiddly and probably not useful