go-blockchain/consensus/freeze_test.go

134 lines
4.5 KiB
Go
Raw Normal View History

// Copyright (c) 2017-2026 Lethean (https://lt.hn)
//
// Licensed under the European Union Public Licence (EUPL) version 1.2.
// SPDX-License-Identifier: EUPL-1.2
//go:build !integration
package consensus
import (
"testing"
"dappco.re/go/core/blockchain/config"
"dappco.re/go/core/blockchain/types"
)
func TestIsPreHardforkFreeze_Good(t *testing.T) {
// Testnet HF5 activates at heights > 200.
// Freeze window: heights 141..200 (activation_height - period + 1 .. activation_height).
// Note: HF5 activation height is 200, meaning HF5 is active at height > 200 = 201+.
// The freeze applies for 60 blocks *before* the fork activates, so heights 141..200.
tests := []struct {
name string
height uint64
want bool
}{
{"well_before_freeze", 100, false},
{"just_before_freeze", 140, false},
{"first_freeze_block", 141, true},
{"mid_freeze", 170, true},
{"last_freeze_block", 200, true},
{"after_hf5_active", 201, false},
{"well_after_hf5", 300, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := IsPreHardforkFreeze(config.TestnetForks, config.HF5, tt.height)
if got != tt.want {
t.Errorf("IsPreHardforkFreeze(testnet, HF5, %d) = %v, want %v",
tt.height, got, tt.want)
}
})
}
}
func TestIsPreHardforkFreeze_Bad(t *testing.T) {
// Mainnet HF5 is at 999999999 — freeze window starts at 999999940.
// At typical mainnet heights, no freeze.
if IsPreHardforkFreeze(config.MainnetForks, config.HF5, 50000) {
t.Error("should not be in freeze period at mainnet height 50000")
}
}
func TestIsPreHardforkFreeze_Ugly(t *testing.T) {
// Unknown fork version — never frozen.
if IsPreHardforkFreeze(config.TestnetForks, 99, 150) {
t.Error("unknown fork version should never trigger freeze")
}
// Fork at height 0 (HF0) — freeze period would be negative/underflow,
// should return false.
if IsPreHardforkFreeze(config.TestnetForks, config.HF0Initial, 0) {
t.Error("fork at genesis should not trigger freeze")
}
}
func TestValidateBlockFreeze_Good(t *testing.T) {
// During freeze, coinbase transactions should still be accepted.
// This test verifies that ValidateBlock does not reject a block
// that only contains its miner transaction during the freeze window.
// (ValidateBlock validates the miner tx; regular tx validation is
// done separately per tx.)
//
// The freeze check applies to regular transactions via
// ValidateTransactionInBlock, not to the miner tx itself.
coinbaseTx := &types.Transaction{
Version: types.VersionPostHF4,
Vin: []types.TxInput{types.TxInputGenesis{Height: 150}},
}
_ = coinbaseTx // structural test — actual block validation needs more fields
}
func TestValidateTransactionInBlock_Good(t *testing.T) {
// Outside freeze window — regular transaction accepted.
tx := validV2Tx()
blob := make([]byte, 100)
err := ValidateTransactionInBlock(tx, blob, config.TestnetForks, 130)
if err != nil {
t.Errorf("expected no error outside freeze, got: %v", err)
}
}
func TestValidateTransactionInBlock_Bad(t *testing.T) {
// Inside freeze window — regular transaction rejected.
tx := validV2Tx()
blob := make([]byte, 100)
err := ValidateTransactionInBlock(tx, blob, config.TestnetForks, 150)
if err == nil {
t.Error("expected ErrPreHardforkFreeze during freeze window")
}
}
func TestValidateTransactionInBlock_Ugly(t *testing.T) {
// Coinbase transaction during freeze — the freeze check itself should
// not reject it (coinbase is exempt). The isCoinbase guard must pass.
// Note: ValidateTransaction separately rejects txin_gen in regular txs,
// but that is the expected path — coinbase txs are validated via
// ValidateMinerTx, not ValidateTransaction. This test verifies the
// freeze guard specifically exempts coinbase inputs.
tx := &types.Transaction{
Version: types.VersionPostHF4,
Vin: []types.TxInput{types.TxInputGenesis{Height: 150}},
Vout: []types.TxOutput{
types.TxOutputZarcanum{StealthAddress: types.PublicKey{1}},
types.TxOutputZarcanum{StealthAddress: types.PublicKey{2}},
},
}
// Directly verify the freeze exemption — isCoinbase should return true,
// and the freeze check should not trigger.
if !isCoinbase(tx) {
t.Fatal("expected coinbase transaction to be identified as coinbase")
}
if IsPreHardforkFreeze(config.TestnetForks, config.HF5, 150) {
// Good — we are in the freeze window. Coinbase should still bypass.
// The freeze check in ValidateTransactionInBlock gates on !isCoinbase,
// so coinbase txs never hit ErrPreHardforkFreeze.
} else {
t.Fatal("expected height 150 to be in freeze window")
}
}