Skip to content

TestForkChoicePreserveEqualTD

NEW-ETC — no upstream or core-geth original.

File forkchoice_preserve_pow_test.go
Symbol TestForkChoicePreserveEqualTD
Ref etc/v1.17.4-full-node

NEW-ETC regression guard: the equal-TD, same-height tie-break honours the preserve callback deterministically (a preserved block is kept, a preserved competitor adopted) rather than falling back to the nil-preserve 50/50 coin flip.

// TestForkChoicePreserveEqualTD verifies the equal-TD, same-height tie-break honours the
// preserve callback: a preserved block is kept and a preserved competitor is adopted,
// deterministically (not the nil-preserve 50/50 fallback).
func TestForkChoicePreserveEqualTD(t *testing.T) {
    current := &types.Header{Number: big.NewInt(10), Extra: []byte("current")}
    extern := &types.Header{Number: big.NewInt(10), Extra: []byte("extern")}

    reader := &preserveTestReader{tds: map[common.Hash]*big.Int{
        current.Hash(): big.NewInt(1000),
        extern.Hash():  big.NewInt(1000), // equal TD, same height -> tie-break
    }}

    // Our own block is the local one: the tie must not reorg away from it.
    keepLocal := NewForkChoice(reader, func(h *types.Header) bool { return h.Hash() == current.Hash() })
    for i := 0; i < 64; i++ { // repeat: a nil-preserve fallback would flip ~half the time
        if needed, err := keepLocal.ReorgNeeded(current, extern); err != nil || needed {
            t.Fatalf("preserved local head: expected no reorg, got needed=%v err=%v", needed, err)
        }
    }

    // The competitor is the local one: the tie must reorg toward it.
    takeExtern := NewForkChoice(reader, func(h *types.Header) bool { return h.Hash() == extern.Hash() })
    for i := 0; i < 64; i++ {
        if needed, err := takeExtern.ReorgNeeded(current, extern); err != nil || !needed {
            t.Fatalf("preserved competitor: expected reorg, got needed=%v err=%v", needed, err)
        }
    }
}

← Total Difficulty (TD)