// 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" ) // validV2Tx returns a minimal valid v2 (Zarcanum) transaction for testing. func validV2Tx() *types.Transaction { return &types.Transaction{ Version: types.VersionPostHF4, Vin: []types.TxInput{ types.TxInputZC{ KeyImage: types.KeyImage{1}, }, }, Vout: []types.TxOutput{ types.TxOutputZarcanum{StealthAddress: types.PublicKey{1}}, types.TxOutputZarcanum{StealthAddress: types.PublicKey{2}}, }, } } // validV3Tx returns a minimal valid v3 (HF5) transaction for testing. func validV3Tx() *types.Transaction { return &types.Transaction{ Version: types.VersionPostHF5, HardforkID: 5, Vin: []types.TxInput{ types.TxInputZC{ KeyImage: types.KeyImage{1}, }, }, Vout: []types.TxOutput{ types.TxOutputZarcanum{StealthAddress: types.PublicKey{1}}, types.TxOutputZarcanum{StealthAddress: types.PublicKey{2}}, }, } } func TestCheckTxVersion_Good(t *testing.T) { tests := []struct { name string tx *types.Transaction forks []config.HardFork height uint64 }{ // v1 transaction before HF4 — valid. {"v1_before_hf4", validV1Tx(), config.MainnetForks, 5000}, // v2 transaction after HF4, before HF5 — valid. {"v2_after_hf4_before_hf5", validV2Tx(), config.TestnetForks, 150}, // v3 transaction after HF5 — valid. {"v3_after_hf5", validV3Tx(), config.TestnetForks, 250}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := checkTxVersion(tt.tx, newTransactionForkState(tt.forks, tt.height), tt.height) if err != nil { t.Errorf("checkTxVersion returned unexpected error: %v", err) } }) } } func TestCheckTxVersion_Bad(t *testing.T) { tests := []struct { name string tx *types.Transaction forks []config.HardFork height uint64 }{ // v0 regular transaction before HF4 — must still be v1. {"v0_before_hf4", func() *types.Transaction { tx := validV1Tx() tx.Version = types.VersionInitial return tx }(), config.MainnetForks, 5000}, // v1 transaction after HF4 — must be v2. {"v1_after_hf4", validV1Tx(), config.TestnetForks, 150}, // v2 transaction after HF5 — must be v3. {"v2_after_hf5", validV2Tx(), config.TestnetForks, 250}, // v3 transaction after HF4 but before HF5 — too early. {"v3_after_hf4_before_hf5", validV3Tx(), config.TestnetForks, 150}, // v3 transaction after HF5 with wrong hardfork id. {"v3_after_hf5_wrong_hardfork", func() *types.Transaction { tx := validV3Tx() tx.HardforkID = 4 return tx }(), config.TestnetForks, 250}, // v3 transaction before HF5 — too early. {"v3_before_hf5", validV3Tx(), config.TestnetForks, 150}, // future version must be rejected. {"v4_after_hf5", func() *types.Transaction { tx := validV3Tx() tx.Version = types.VersionPostHF5 + 1 return tx }(), config.TestnetForks, 250}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := checkTxVersion(tt.tx, newTransactionForkState(tt.forks, tt.height), tt.height) if err == nil { t.Error("expected ErrTxVersionInvalid, got nil") } }) } } func TestCheckTxVersion_Ugly(t *testing.T) { // v2 at exact HF4 activation boundary (height 101 on testnet, HF4.Height=100). txHF4 := validV2Tx() err := checkTxVersion(txHF4, newTransactionForkState(config.TestnetForks, 101), 101) if err != nil { t.Errorf("v2 at HF4 activation boundary should be valid: %v", err) } // v1 at exact HF4 activation boundary should be rejected. txPreHF4 := validV1Tx() err = checkTxVersion(txPreHF4, newTransactionForkState(config.TestnetForks, 101), 101) if err == nil { t.Error("v1 at HF4 activation boundary should be rejected") } // v3 at exact HF5 activation boundary (height 201 on testnet, HF5.Height=200). tx := validV3Tx() err = checkTxVersion(tx, newTransactionForkState(config.TestnetForks, 201), 201) if err != nil { t.Errorf("v3 at HF5 activation boundary should be valid: %v", err) } // v2 at exact HF5 activation boundary — should be rejected. tx2 := validV2Tx() err = checkTxVersion(tx2, newTransactionForkState(config.TestnetForks, 201), 201) if err == nil { t.Error("v2 at HF5 activation boundary should be rejected") } }