The principle used for the tor disconnection is really simple and smart ! It's also a good illustration of how hard is the task of core devs. By implementing something to secure the network (against spam in this case), you always have a risk that it's exploited for another kind of attack (tor disconnection in this case).
We're aware of that and specifically designed to address that— at least to the extent that we
easily can, there is a lot of room for improvement here. You cannot completely disconnect tor peers using the attack they described because we use tor in two distinct ways: One way is that we use tor via exit nodes, which that attack addresses— the other is that we use tor via hidden services. If you set onlynet=tor your tor-enabled node uses only this second mechanism, otherwise it uses both. Inbound connections from hidden services, if you have enabled them, are exempted from banning. Some nodes are dual stack— they receive connections via both IPv4 and tor hidden services, and thus act as bridges between the tor and non-tor hosts even if no tor exits are working.
It may well be the case that you could actually break Bitcoin on tor by
also DOS attacking the HS-accepting hosts, since there aren't enough of them, and the defense above works in part because some of the existing DOS protections are disabled for HS peers so HS accepting nodes are more DOS vulnerable— though it might also be the case that you'd just break the tor network first, and there isn't much we can do about that.
Last year
I proposed a novel approach using asymmetric storage costs to discourage hosts from connecting out to many peers concurrently, though since there have been no attacks (at least none that have risen to a sufficient level of irritation) there hasn't been a lot of interest in developing the idea further. Basically the idea has the outbound connecting host do a moderate amount of POW to precompute a table per peer they are connecting to that allows them to rapidly answer queries that the remote peer can efficiently compute (without storage), the remote peer continually challenges them, so that they must either constantly be doing a ton of POW work, or retain a fair amount of storage per peer. I'd envisioned this to be an optional thing peers could signal at their connection time ("I'm willing to use up to 1GB storage to get priority access"). All of these "make connections costly" approaches open new attack avenues, however— e.g. what happens when you start a lot of useless nodes for the purpose of just making peers waste effort to connect? The best answer I had is that nodes would only perform the costly work to secure their connections with a small number of their 'favorite' peers (e.g. randomly selected peers which have proven themselves to be helpful in the past), but this only requires the attacker to make their misbehaving nodes good for a while before they start misbehaving. Using sustained local storage as the costly thing instead of one time POW has the useful property that the storage can be freed if a peer stops being useful, but sadly my approach still requires the initial setup be somewhat computationally expensive or otherwise an attacker can skip the storage and just redo the setup for every challenge.
WRT topology, we've worked to keep the wiring random in order to make the topology likely to be an expander graph. Concern about not screwing up the topology is why we don't yet have peer rotation— the first and most obvious way to do it that I came up with broke the topology in simulation (resulted in clustering that had a smallish min-cut). I'm reasonably confident that I know ways that won't, but it's always scary to change something which is hard to analyze.