[Bundle 7/7] validation: Farewell, global Chainstate! #21866

pull dongcarl wants to merge 12 commits into bitcoin:master from dongcarl:2020-10-libbitcoinruntime-v9 changing 35 files +173 −291
  1. dongcarl commented at 8:51 pm on May 5, 2021: member

    Based on: #21767

    à la Mr. Sandman

    0Mr. Chainman, bring me a tip (bung, bung, bung, bung)
    1Make it the most work that I've ever seen (bung, bung, bung, bung)
    2Rewind old tip till we're at the fork point (bung, bung, bung, bung)
    3Then tell it that it's time to call Con-nectTip
    4
    5Chainman, I'm so alone (bung, bung, bung, bung)
    6No local objects to call my own (bung, bung, bung, bung)
    7Please make sure I have a ref
    8Mr. Chainman, bring me a tip!
    

    This is the last bundle in the #20158 series. Thanks everyone for their diligent review. I would like to call attention to #21766, where a few leftover improvements were collated.

    • Remove globals:
      • ChainstateManager g_chainman
      • CChainState& ChainstateActive()
      • CChain& ChainActive()
    • Remove all review-only assertions.
  2. DrahtBot added the label GUI on May 5, 2021
  3. DrahtBot added the label Mempool on May 5, 2021
  4. DrahtBot added the label Mining on May 5, 2021
  5. DrahtBot added the label P2P on May 5, 2021
  6. DrahtBot added the label RPC/REST/ZMQ on May 5, 2021
  7. DrahtBot added the label UTXO Db and Indexes on May 5, 2021
  8. DrahtBot added the label Validation on May 5, 2021
  9. DrahtBot added the label Wallet on May 5, 2021
  10. DrahtBot commented at 6:53 am on May 6, 2021: member

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #22155 (wallet test: Add test for subtract fee from recipient behavior by ryanofsky)
    • #21789 (refactor: Remove ::Params() global from CChainState by MarcoFalke)
    • #21706 (log: Mitigate disk filling attacks by globally rate limiting LogPrintf(…) by dergoegge)
    • #21603 (log: Mitigate disk filling attacks by rate limiting LogPrintf by dergoegge)
    • #21562 ([net processing] Various tidying up of PeerManagerImpl ctor by jnewbery)
    • #21526 (validation: UpdateTip/CheckBlockIndex assumeutxo support by jamesob)
    • #21061 ([p2p] Introduce node rebroadcast module by amitiuttarwar)
    • #20331 (allow -loadblock blocks to be unsorted by LarryRuane)
    • #20295 (rpc: getblockfrompeer by Sjors)
    • #19438 (Introduce deploymentstatus by ajtowns)
    • #19101 (refactor: remove ::vpwallets and related global variables by ryanofsky)
    • #16981 (Improve runtime performance of –reindex by LarryRuane)
    • #15719 (Wallet passive startup by ryanofsky)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  11. Sjors commented at 1:40 pm on May 6, 2021: member

    In the description of a839078c20f4ac3d92e14af7b287f2f0fddbc61e:

    1. It fixes the erroneous use of Ensure*() in rest.cpp, which caused crashes in REST contexts.

    Can you elaborate on this?

  12. dongcarl commented at 3:59 pm on May 6, 2021: member

    @Sjors EnsureAnyChainman uses the src/rpc way of returning errors, by doing:

    https://github.com/bitcoin/bitcoin/blob/59869704c0fe0f105d9cbc193e3670917c618b83/src/rpc/blockchain.cpp#L85

    However from my understanding, in src/rest, the way to return errors is to call RESTERR, which will fill the req in-out param with the right HTTP error.

    In other words, throwing a JSONRPCError in the context of src/rest is meaningless, and therefore might crash the node much like an assert would.

    (btw, that commit is part of Bundle 6)

  13. Sjors commented at 6:11 pm on May 6, 2021: member
    That makes sense, alright, I’ll check out episode 6 first.
  14. DrahtBot added the label Needs rebase on May 12, 2021
  15. MarcoFalke removed the label GUI on Jun 1, 2021
  16. MarcoFalke removed the label Mempool on Jun 1, 2021
  17. MarcoFalke removed the label Mining on Jun 1, 2021
  18. MarcoFalke removed the label P2P on Jun 1, 2021
  19. MarcoFalke removed the label RPC/REST/ZMQ on Jun 1, 2021
  20. MarcoFalke removed the label UTXO Db and Indexes on Jun 1, 2021
  21. MarcoFalke removed the label Wallet on Jun 1, 2021
  22. MarcoFalke added the label Refactoring on Jun 1, 2021
  23. dongcarl force-pushed on Jun 2, 2021
  24. dongcarl commented at 10:31 pm on June 2, 2021: member

    Pushed 8135fd659bd1f068aecf4d0ad3f3862127bb0886 -> 509264117c30704c2f048c702aa0ee9ac9657e7a

    • Rebased over merge of #21767
  25. DrahtBot removed the label Needs rebase on Jun 2, 2021
  26. laanwj added this to the "Blockers" column in a project

  27. in src/node/interfaces.cpp:215 in 509264117c outdated
    221-            LOCK(::cs_main);
    222-            active_chainstate = &m_context->chainman->ActiveChainstate();
    223-            assert(std::addressof(::ChainstateActive()) == std::addressof(*active_chainstate));
    224-        }
    225-        return active_chainstate->IsInitialBlockDownload();
    226+        return m_context->chainman->ActiveChainstate().IsInitialBlockDownload();
    


    ariard commented at 10:43 pm on June 8, 2021:
    I think you can directly rely on NodeImpl::chainman() method here.

    dongcarl commented at 3:03 pm on June 9, 2021:
    Nice catch!
  28. ariard commented at 10:44 pm on June 8, 2021: member
    Approach ACK 5092641
  29. dongcarl force-pushed on Jun 9, 2021
  30. dongcarl commented at 3:03 pm on June 9, 2021: member

    Pushed 509264117c…cc8cc9c4a2

  31. jnewbery commented at 11:15 am on June 10, 2021: member
    utACK cc8cc9c4a24bb638baa733c129a87346c66821ba
  32. jnewbery commented at 11:18 am on June 10, 2021: member
    This is a trivial rebase past #22084 (consecutive lines touched)
  33. jnewbery commented at 11:19 am on June 10, 2021: member

    Strong concept ACK for:

    Over time, we should probably move these mutable global state variables into ChainstateManager or CChainState so it’s easier to reason about their lifecycles.

    I’d be happy to review any of those changes. Please tag me in PRs that implement those.

  34. DrahtBot added the label Needs rebase on Jun 10, 2021
  35. in src/test/util/mining.cpp:82 in 1b21b6095a outdated
    79             .CreateNewBlock(coinbase_scriptPubKey)
    80             ->block);
    81 
    82     LOCK(cs_main);
    83-    block->nTime = ::ChainActive().Tip()->GetMedianTimePast() + 1;
    84+    block->nTime = Assert(node.chainman)->ActiveChain().Tip()->GetMedianTimePast() + 1;
    


    jamesob commented at 4:34 pm on June 10, 2021:
  36. in src/test/miner_tests.cpp:447 in f172c8a220 outdated
    439@@ -440,7 +440,11 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
    440     m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
    441     BOOST_CHECK(CheckFinalTx(::ChainActive().Tip(), CTransaction(tx), flags)); // Locktime passes
    442     BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail
    443-    BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, CreateBlockIndex(::ChainActive().Tip()->nHeight + 2))); // Sequence locks pass on 2nd block
    444+
    445+    {
    446+        CBlockIndex* active_chain_tip = m_node.chainman->ActiveChain().Tip();
    447+        BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, CreateBlockIndex(active_chain_tip->nHeight + 2, active_chain_tip))); // Sequence locks pass on 2nd block
    448+    }
    


    jamesob commented at 4:47 pm on June 10, 2021:

    https://github.com/bitcoin/bitcoin/pull/21866/commits/f172c8a220c29d1724c8c1a62cacc1ac8cbc2f17

    I don’t mind it but is there the temporary scope necessary? (Also ActiveTip() nits)

  37. in src/test/miner_tests.cpp:464 in f172c8a220 outdated
    461+        m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast
    462+
    463+    {
    464+        CBlockIndex* active_chain_tip = m_node.chainman->ActiveChain().Tip();
    465+        BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, CreateBlockIndex(active_chain_tip->nHeight + 1, active_chain_tip))); // Sequence locks pass 512 seconds later
    466+    }
    


    jamesob commented at 4:48 pm on June 10, 2021:
  38. laanwj added this to the milestone 22.0 on Jun 10, 2021
  39. init: Use existing chainman 464c313e30
  40. test/util: Use existing chainman in ::PrepareBlock f0dd5e6bb4
  41. test/miner_tests: Pass in chain tip to CreateBlockIndex 4d99b61014
  42. test: Pass in CoinsTip to ValidateCheckInputsForAllFlags e197076219
  43. scripted-diff: test: Use existing chainman in unit tests
    -BEGIN VERIFY SCRIPT-
    git ls-files -- src/test \
        | grep -v '^src/test/fuzz' \
        | xargs sed -i -E \
                -e 's@g_chainman\.m_blockman@m_node.chainman->m_blockman@g' \
                -e 's@([^:])(Chain(state|)Active)@\1::\2@g' \
                -e 's@::Chain(state|)Active\(\)@m_node.chainman->ActiveChain\1()@g'
    -END VERIFY SCRIPT-
    0d61634c06
  44. fuzz: Initialize a TestingSetup for test_one_input
    For fuzz tests that need it.
    ee0ab1e959
  45. scripted-diff: wallet/test: Use existing chainman
    -BEGIN VERIFY SCRIPT-
    git ls-files -- src/wallet/test \
        | xargs sed -i -E \
                -e 's@g_chainman\.m_blockman@m_node.chainman->m_blockman@g' \
                -e 's@([^:])(Chain(state|)Active)@\1::\2@g' \
                -e 's@::Chain(state|)Active\(\)@m_node.chainman->ActiveChain\1()@g'
    -END VERIFY SCRIPT-
    6c15de129c
  46. qt/test: Use existing chainman in ::TestGUI (can be scripted-diff) f323248aba
  47. tree-wide: Remove stray review-only assertion
    Unfortunately, these assertion don't fit the regex in the scripted-diff.
    Therefore, we remove it manually.
    3e82abb8dd
  48. scripted-diff: tree-wide: Remove all review-only assertions
    -BEGIN VERIFY SCRIPT-
    find_regex='((assert|CHECK_NONFATAL)\(std::addressof|TODO: REVIEW-ONLY)' \
        && git grep -l -E "$find_regex" -- . \
            | xargs sed -i -E "/${find_regex}/d"
    -END VERIFY SCRIPT-
    6c3b5dc0c1
  49. qt/test: Reset chainman in ~ChainstateManager instead
    There are some mutable, global state variables that are currently reset
    by UnloadBlockIndex such as pindexBestHeader which should be cleaned up
    whenever the ChainstateManager is unloaded/reset/destructed/etc.
    
    Not cleaning them up leads to bugs like a use-after-free that happens
    like so:
    
    1. At the end of a test, ChainstateManager is destructed, which also
       destructs BlockManager, which calls BlockManager::Unload to free all
       CBlockIndexes in its BlockMap
    2. Since pindexBestHeader is not cleaned up, it now points to an invalid
       location
    3. Another test starts to init, and calls LoadGenesisBlock, which calls
       AddToBlockIndex, which compares the genesis block with an invalid
       location
    4. Cute puppies perish by the hundreds
    
    Previously, for normal codepaths (e.g. bitcoind), we relied on the fact
    that our program will be unloaded by the operating system which
    effectively resets these variables. The one exception is in QT tests,
    where these variables had to be manually reset.
    
    Since now ChainstateManager is no longer a global, we can just put this
    logic in its destructor to make sure that callers are always correct.
    
    Over time, we should probably move these mutable global state variables
    into ChainstateManager or CChainState so it's easier to reason about
    their lifecycles.
    972c5166ee
  50. validation: Farewell, global Chainstate! 6f994882de
  51. dongcarl force-pushed on Jun 10, 2021
  52. dongcarl commented at 7:12 pm on June 10, 2021: member

    Pushed cc8cc9c4a24bb638baa733c129a87346c66821ba…6f994882deafe62e97f0a889d8bdb8c96dcf913d

    • Rebased on top of master

    I’d be happy to review any of those changes. Please tag me in PRs that implement those. @jnewbery will do! 😁 I’m cleaning up my old branch right now which conflicts with Marco’s node/blockstorage changes…

  53. DrahtBot removed the label Needs rebase on Jun 10, 2021
  54. jamesob approved
  55. jamesob commented at 11:39 pm on June 10, 2021: member

    ACK cc8cc9c4a24bb638baa733c129a87346c66821ba (jamesob/ackr/21866.1.dongcarl.bundle_7_7_validation_f)

    Many scripted-diffs make this an easy, mechanical change. All the ActiveTip() nits can be probably be addressed by doing a single scripted-diff cleanup that seds 'ActiveChain\(\).Tip\(\)'.

    Nice job with all the scripted-diffs; they make review much easier. Man oh man that’s a lot of asserts! I like your move of UnloadBlockIndex() into the ChainstateManager destructor.

    Nice work on this! Who ever thought we’d have chainstate deglobalized?? What a world.

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3ACK cc8cc9c4a24bb638baa733c129a87346c66821ba ([`jamesob/ackr/21866.1.dongcarl.bundle_7_7_validation_f`](https://github.com/jamesob/bitcoin/tree/ackr/21866.1.dongcarl.bundle_7_7_validation_f))
     4
     5-----BEGIN PGP SIGNATURE-----
     6
     7iQIzBAEBCgAdFiEEGNRVI1NPYuZCSIrGepNdrbLETwUFAmDCobMACgkQepNdrbLE
     8TwX7NhAAgxLYZY+ecZjwI2y5OmqMrOjtmX+SplLm8B+iPpJCfYRkMfqZPG5qaVJQ
     97eHCPBP6/V2Rx0CYgMFqX6G+3tJsW6k/ErahtuZXcp8nUEtyaOnt9jbDhdWRqAT9
    10MS0sEmvw/HNqz3qBpDW0aZs2OO6D01HUi2SkuCbze7zWiZYiAeeInUu1Du7tO0IQ
    11c3VqzJqz5XRVi64VF0fR5NeDgzgNYMTDWXEnwDK40JWB1gpM9uht5KuRGPLLfPl+
    12p7gDafWxoAbu9csPmKY9YIgPcQK2yKvQ5DSyWJVm57a0wHxlLFjGMCoprg7kbVn1
    13jaVyZ4EgghKT/NME6yhAeLBg8HAyaXNYaXISAlVyUM6FbvJ3p3sNpkgCbldz2xTH
    14nhiibFpwJbQVO/EoWw7Oy8TTe9FJGqlrhpXTR3vdsMy7g6gLwIzRQ71h43UVENs4
    15x4HnXfMEFPnIvt0W5xsSv6Ti+gWIB1e/nF/EdEwkmXD6s/6llqE7Bs1dGfDqb3jG
    16S9+2XsPy8KLgn+r3zSH66xKII70NdpUyjvQ9uNki8tVcTa5Jy905RgLxuldT2wrv
    17CGoazisooMRUfC44+a4Zn/w9IsxPzkUXP6RjmI9HfxF2f2vHWmv1IePwYJs0lD8U
    18M8x2upnRDRQe5QQn0+geIjsar4uRiEBphx6xBpSkFsWoDMmcP5Q=
    19=XPto
    20-----END PGP SIGNATURE-----
    
    0Tested on Linux-4.19.0-16-amd64-x86_64-with-glibc2.28
    1
    2Configured with ./configure LDFLAGS=-L/home/james/src/bitcoin/db4/lib/ CPPFLAGS=-I/home/james/src/bitcoin/db4/include/ CXXFLAGS=-fPIE -pipe -O2 -g -Wthread-safety-analysis -Wall -Werror=sign-compare -Wsign-compare -Werror=thread-safety-analysis --enable-wallet --enable-debug --with-daemon --enable-natpmp-default
    3
    4Compiled with /usr/bin/ccache /usr/local/bin/clang++ -std=c++17 -mavx -mavx2 -fPIE -pipe -O2 -g -Wthread-safety-analysis -Wall -Werror=sign-compare -Wsign-compare -Werror=thread-safety-analysis -O0 -g3 -ftrapv -fdebug-prefix-map=$(abs_srcdir)=.  -Wstack-protector -fstack-protector-all -fcf-protection=full -fstack-clash-protection -msse4 -msha -msse4.1 -msse4.2  i
    5
    6Compiler version: Debian clang version 11.1.0-++20210405104510+1fdec59bffc1-1~exp1~20210405085125.161
    
  56. jamesob commented at 0:02 am on June 11, 2021: member
    reACK https://github.com/bitcoin/bitcoin/pull/21866/commits/6f994882deafe62e97f0a889d8bdb8c96dcf913d based on the contents of git range-diff master ackr/21866.1.dongcarl.bundle_7_7_validation_f ackr/21866.2.dongcarl.bundle_7_7_validation_f and local build/test run.
  57. ariard commented at 4:01 pm on June 11, 2021: member

    Code Review ACK 6f99488.

    Diff since last review is using NodeImpl::chainman method in isInitialBlockDownload() and rebase changes from #22084.

  58. jnewbery commented at 4:07 pm on June 11, 2021: member
    utACK 6f994882deafe62e97f0a889d8bdb8c96dcf913d
  59. achow101 commented at 6:52 pm on June 11, 2021: member
    Code Review ACK 6f994882deafe62e97f0a889d8bdb8c96dcf913d
  60. ryanofsky approved
  61. ryanofsky commented at 8:44 pm on June 11, 2021: member

    Code review ACK 6f994882deafe62e97f0a889d8bdb8c96dcf913d.

    Just want to note so it isn’t forgotten that 972c5166ee685447a6d4bf5e501b07a0871fba85 commit message suggests some good future followup “Since now ChainstateManager is no longer a global, we can just put this [other variable cleanup] logic in its destructor to make sure that callers are always correct” which would make shutdown more comprehensible, and clean up the Qt tests

  62. fanquake merged this on Jun 12, 2021
  63. fanquake closed this on Jun 12, 2021

  64. fanquake removed this from the "Blockers" column in a project

  65. sidhujag referenced this in commit 9ac96c8db0 on Jun 14, 2021
  66. MarcoFalke commented at 8:19 am on June 14, 2021: member

    Just noting that commit 972c5166ee685447a6d4bf5e501b07a0871fba85 causes a segmentation fault because the commits are in the wrong order:

     0$ valgrind ./src/qt/test/test_bitcoin-qt 
     1==1844015== Memcheck, a memory error detector
     2==1844015== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
     3==1844015== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
     4==1844015== Command: ./src/qt/test/test_bitcoin-qt
     5...
     6********* Finished testing of RPCNestedTests *********
     7terminate called after throwing an instance of 'std::logic_error'
     8  what():  should not be overwriting a chainstate
     9==1844015== 
    10==1844015== Process terminating with default action of signal 6 (SIGABRT): dumping core
    11==1844015==    at 0x651A2A2: raise (in /usr/lib64/libc-2.33.so)
    12==1844015==    by 0x65038A3: abort (in /usr/lib64/libc-2.33.so)
    13==1844015==    by 0x61FEA45: ??? (in /usr/lib64/libstdc++.so.6.0.29)
    14==1844015==    by 0x620A29B: ??? (in /usr/lib64/libstdc++.so.6.0.29)
    15==1844015==    by 0x620A306: std::terminate() (in /usr/lib64/libstdc++.so.6.0.29)
    16==1844015==    by 0x620A5FC: __cxa_rethrow (in /usr/lib64/libstdc++.so.6.0.29)
    17==1844015==    by 0x4F392CD: ??? (in /usr/lib64/libQt5Test.so.5.15.2)
    18==1844015==    by 0x4F43B3F: QTest::qExec(QObject*, int, char**) (in /usr/lib64/libQt5Test.so.5.15.2)
    19==1844015==    by 0x196413: main (test_main.cpp:91)
    20==1844015== 
    21==1844015== Process terminating with default action of signal 11 (SIGSEGV)
    22==1844015==  General Protection Fault
    23==1844015==    at 0x4877C82: ??? (in /usr/lib64/libpthread-2.33.so)
    24==1844015==    by 0x660D03E: ??? (in /usr/lib64/libc-2.33.so)
    25==1844015==    by 0x664F60C: ??? (in /usr/lib64/libc-2.33.so)
    26==1844015==    by 0x664F261: __libc_freeres (in /usr/lib64/libc-2.33.so)
    27==1844015==    by 0x48351E7: _vgnU_freeres (vg_preloaded.c:74)
    28==1844015== 
    29==1844015== HEAP SUMMARY:
    30==1844015==     in use at exit: 45,331,308 bytes in 21,971 blocks
    31==1844015==   total heap usage: 128,095 allocs, 106,124 frees, 87,543,385 bytes allocated
    32==1844015== 
    33==1844015== LEAK SUMMARY:
    34==1844015==    definitely lost: 0 bytes in 0 blocks
    35==1844015==    indirectly lost: 0 bytes in 0 blocks
    36==1844015==      possibly lost: 22,704 bytes in 95 blocks
    37==1844015==    still reachable: 45,308,604 bytes in 21,876 blocks
    38==1844015==                       of which reachable via heuristic:
    39==1844015==                         stdstring          : 63 bytes in 1 blocks
    40==1844015==                         newarray           : 424 bytes in 11 blocks
    41==1844015==                         multipleinheritance: 71,160 bytes in 87 blocks
    42==1844015==         suppressed: 0 bytes in 0 blocks
    43==1844015== Rerun with --leak-check=full to see details of leaked memory
    44==1844015== 
    45==1844015== Use --track-origins=yes to see where uninitialised values come from
    46==1844015== For lists of detected and suppressed errors, rerun with: -s
    47==1844015== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
    48Segmentation fault (core dumped)
    
  67. MarcoFalke commented at 8:19 am on June 14, 2021: member
    Otherwise looks good
  68. fanquake referenced this in commit 0ccf9b2e55 on Oct 20, 2021
  69. sidhujag referenced this in commit f3d19d61cf on Oct 20, 2021
  70. gwillen referenced this in commit 34da23bd1a on Jun 1, 2022
  71. Fabcien referenced this in commit 2b80693062 on Jun 22, 2022
  72. Fabcien referenced this in commit 121c842f62 on Jun 22, 2022
  73. Fabcien referenced this in commit aeb423f1a1 on Jun 22, 2022
  74. Fabcien referenced this in commit 819bf80975 on Jun 22, 2022
  75. Fabcien referenced this in commit c5004dcda2 on Jun 29, 2022
  76. Fabcien referenced this in commit 88f0dc11af on Jun 30, 2022
  77. Fabcien referenced this in commit 0655265d8d on Jun 30, 2022
  78. Fabcien referenced this in commit c392b9db21 on Jun 30, 2022
  79. Fabcien referenced this in commit 7e8275e964 on Jun 30, 2022
  80. Fabcien referenced this in commit 7e0e3d2c3b on Jun 30, 2022
  81. Fabcien referenced this in commit c9189fd7a3 on Jul 15, 2022
  82. Fabcien referenced this in commit 3151d3637e on Jul 15, 2022
  83. Fabcien referenced this in commit f78286b329 on Jul 15, 2022
  84. DrahtBot locked this on Aug 16, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-09-28 22:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me