Backport of [[https://github.com/bitcoin/bitcoin/pull/20188 | core#20188]]
This backport is out of order so much has been refactored. Compare this patch against git blame of Core master to get an idea of what changed. There are too many changes to list here.