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)
}
}
}