shohu / c0ban

c0ban source tree
MIT License
0 stars 0 forks source link

Pass for test assumevalid.py #32

Closed shohu closed 6 years ago

shohu commented 6 years ago

Option explain

    strUsage +=HelpMessageOpt("-assumevalid=<hex>", strprintf(_("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)"), defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()));

Output

# test/functional/assumevalid.py
2018-03-27 05:12:54.846000 TestFramework (INFO): Initializing test directory /tmp/tests1sfc2fz
2018-03-27 05:12:55.115000 TestFramework.mininode (INFO): Connecting to Bitcoin Node: 127.0.0.1:12428
2018-03-27 05:12:55.683000 TestFramework.mininode (INFO): Connecting to Bitcoin Node: 127.0.0.1:12429
2018-03-27 05:12:56.046000 TestFramework.mininode (INFO): Connecting to Bitcoin Node: 127.0.0.1:12430

2018-03-27 05:14:58.054000 TestFramework (ERROR): Assertion failed
Traceback (most recent call last):
  File "/c0ban/test/functional/test_framework/test_framework.py", line 120, in main
    self.run_test()
  File "test/functional/assumevalid.py", line 194, in run_test
    node1.sync_with_ping(120)
  File "/c0ban/test/functional/test_framework/mininode.py", line 1623, in sync_with_ping
    wait_until(test_function, timeout=timeout, lock=mininode_lock)
  File "/c0ban/test/functional/test_framework/util.py", line 222, in wait_until
    assert_greater_than(timeout, time.time())
  File "/c0ban/test/functional/test_framework/util.py", line 42, in assert_greater_than
    raise AssertionError("%s <= %s" % (str(thing1), str(thing2)))
AssertionError: 1522127698.0296192 <= 1522127698.0538247
2018-03-27 05:14:58.079000 TestFramework (INFO): Stopping nodes
2018-03-27 05:15:00.329000 TestFramework (WARNING): Not cleaning up dir /tmp/tests1sfc2fz
2018-03-27 05:15:00.330000 TestFramework (ERROR): Test failed. Test logging available at /tmp/tests1sfc2fz/test_framework.log

c0band debug.log

2018-03-27 05:18:45.433377 received block 65708d49ec094f82ce7af9107cccf8a975c020f2a1ff5d7ad93531b9bd5aa3b1 peer=0
2018-03-27 05:18:45.434256   - Load block from disk: 0.00ms [0.00s]
2018-03-27 05:18:45.434296     - Sanity checks: 0.01ms [0.00s]
2018-03-27 05:18:45.434311     - Fork checks: 0.02ms [0.00s]
2018-03-27 05:18:45.434368       - Connect 2 transactions: 0.05ms (0.027ms/tx, 0.054ms/txin) [0.00s]
2018-03-27 05:18:45.434397 ERROR: ConnectBlock: CheckQueue failed
2018-03-27 05:18:45.434416 Misbehaving: 127.0.0.1:33872 peer=0 (0 -> 100) BAN THRESHOLD EXCEEDED
2018-03-27 05:18:45.434435 InvalidChainFound: invalid block=65708d49ec094f82ce7af9107cccf8a975c020f2a1ff5d7ad93531b9bd5aa3b1  height=102  log2_work=7.6865005  date=2016-11-01 00:01:43
2018-03-27 05:18:45.434450 InvalidChainFound:  current best=75233bf14470ec6889da430f1527fc5ea4e847621e1fa1253c9e4e726425d495  height=101  log2_work=7.6724253  date=2016-11-01 00:01:42
2018-03-27 05:18:45.434459 ERROR: ConnectTip(): ConnectBlock 65708d49ec094f82ce7af9107cccf8a975c020f2a1ff5d7ad93531b9bd5aa3b1 failed
2018-03-27 05:18:45.434473 InvalidChainFound: invalid block=65708d49ec094f82ce7af9107cccf8a975c020f2a1ff5d7ad93531b9bd5aa3b1  height=102  log2_work=7.6865005  date=2016-11-01 00:01:43
2018-03-27 05:18:45.434487 InvalidChainFound:  current best=75233bf14470ec6889da430f1527fc5ea4e847621e1fa1253c9e4e726425d495  height=101  log2_work=7.6724253  date=2016-11-01 00:01:42
2018-03-27 05:18:45.434497 Checking mempool with 0 transactions and 0 inputs
2018-03-27 05:18:45.434519 sending reject (63 bytes) peer=0
2018-03-27 05:18:45.434571 Warning: not banning local peer 127.0.0.1:33872!
shohu commented 6 years ago

Focus on "BAN THRESHOLD EXCEEDED"

// Requires cs_main.
void Misbehaving(NodeId pnode, int howmuch)
{
    if (howmuch == 0)
        return;

    CNodeState *state = State(pnode);
    if (state == nullptr)
        return;

    state->nMisbehavior += howmuch;
    int banscore = gArgs.GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD);
    if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore)
    {
        LogPrintf("%s: %s peer=%d (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, pnode, state->nMisbehavior-howmuch, state->nMisbehavior);
        state->fShouldBan = true;
    } else
        LogPrintf("%s: %s peer=%d (%d -> %d)\n", __func__, state->name, pnode, state->nMisbehavior-howmuch, state->nMisbehavior);
}
shohu commented 6 years ago

CheckQueue failed

2018-03-27 05:18:45.434397 ERROR: ConnectBlock: CheckQueue failed
/** Apply the effects of this block (with given index) on the UTXO set represented by coins.
 *  Validity checks that depend on the UTXO set are also done; ConnectBlock()
 *  can fail if those validity checks fail (among other reasons). */
static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
                  CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false)
{
 :
 :
    if (!control.Wait())
        return state.DoS(100, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed");
shohu commented 6 years ago

-assumevalid Option

    bool fScriptChecks = true;
    if (!hashAssumeValid.IsNull()) {
        // We've been configured with the hash of a block which has been externally verified to have a valid history.
        // A suitable default value is included with the software and updated from time to time.  Because validity
        //  relative to a piece of software is an objective fact these defaults can be easily reviewed.
        // This setting doesn't force the selection of any particular chain but makes validating some faster by
        //  effectively caching the result of part of the verification.
        BlockMap::const_iterator  it = mapBlockIndex.find(hashAssumeValid);
        if (it != mapBlockIndex.end()) {
            if (it->second->GetAncestor(pindex->nHeight) == pindex &&
                pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
                pindexBestHeader->nChainWork >= nMinimumChainWork) {
                // This block is a member of the assumed verified chain and an ancestor of the best header.
                // The equivalent time check discourages hash power from extorting the network via DOS attack
                //  into accepting an invalid block through telling users they must manually set assumevalid.
                //  Requiring a software change or burying the invalid block, regardless of the setting, makes
                //  it hard to hide the implication of the demand.  This also avoids having release candidates
                //  that are hardly doing any signature verification at all in testing without having to
                //  artificially set the default assumed verified block further back.
                // The test against nMinimumChainWork prevents the skipping when denied access to any chain at
                //  least as good as the expected chain.
                fScriptChecks = (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, chainparams.GetConsensus()) <= 60 * 60 * 24 * 7 * 2);
            }
        }
    }

testcode

We build a chain that includes and invalid signature for one of the
transactions:

    0:        genesis block
    1:        block 1 with coinbase transaction output.
    2-101:    bury that block with 100 blocks so the coinbase transaction
              output can be spent
    102:      a block containing a transaction spending the coinbase
              transaction output. The transaction has an invalid signature.
    103-2202: bury the bad block with just over two weeks' worth of blocks
              (2100 blocks)
        # Bury the assumed valid block 2100 deep
        for i in range(2100):
            block = create_block(self.tip, create_coinbase(height), self.block_time)
            block.nVersion = 4
            block.solve()
            self.blocks.append(block)
            self.tip = block.sha256
            self.block_time += 1
            height += 1

2100 * 10分 / 60 / 24 = 14.58 days. over two weeks


int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)
{
    arith_uint256 r;
    int sign = 1;
    if (to.nChainWork > from.nChainWork) {
        r = to.nChainWork - from.nChainWork;
    } else {
        r = from.nChainWork - to.nChainWork;
        sign = -1;
    }
    r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip);
    if (r.bits() > 63) {
        return sign * std::numeric_limits<int64_t>::max();
    }
    return sign * r.GetLow64();
}
arith_uint256 GetBlockProof(const CBlockIndex& block)
{
    arith_uint256 bnTarget;
    bool fNegative;
    bool fOverflow;
    bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
    if (fNegative || fOverflow || bnTarget == 0)
        return 0;
    // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
    // as it's too large for an arith_uint256. However, as 2**256 is at least as large
    // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
    // or ~bnTarget / (nTarget+1) + 1.
    return (~bnTarget / (bnTarget + 1)) + 1;
}

bitcoin

consensus.nPowTargetSpacing = 10 * 60;

c0ban

consensus.nPowTargetSpacing = 32;
shohu commented 6 years ago

Changed GetBlockProofEquivalentTime

Currently Threshold is "two weeks"

fScriptChecks = (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, chainparams.GetConsensus()) <= 60 * 60 * 24 * 7 * 2);

This function use nPowTargetSpacing parameter. Bitcoin's this parameter is about 20 times c0ban's parameter. So I change following time (Threshold is about 17 hours.)

fScriptChecks = (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, chainparams.GetConsensus()) <= 60 * 60 * 24 * 7 * 2 / 20);

2018-03-27 15 06 47

I passed test after above chnaged ! šŸ‘

# test/functional/assumevalid.py
2018-03-27 06:05:48.264000 TestFramework (INFO): Initializing test directory /tmp/test0mfzhvom
2018-03-27 06:05:48.546000 TestFramework.mininode (INFO): Connecting to Bitcoin Node: 127.0.0.1:13629
2018-03-27 06:05:49.126000 TestFramework.mininode (INFO): Connecting to Bitcoin Node: 127.0.0.1:13630
2018-03-27 06:05:49.440000 TestFramework.mininode (INFO): Connecting to Bitcoin Node: 127.0.0.1:13631
2018-03-27 06:05:56.414000 TestFramework (INFO): Stopping nodes
2018-03-27 06:05:58.679000 TestFramework (INFO): Cleaning up
2018-03-27 06:05:58.683000 TestFramework (INFO): Tests successful