From 3a0d49401ff856d3ac6b44c8a07a3807231d754c Mon Sep 17 00:00:00 2001 From: Virgil Date: Sat, 4 Apr 2026 15:55:09 +0000 Subject: [PATCH] fix(consensus): reject unknown tx variants Tighten semantic validation so unknown transaction inputs, outputs, and bare output targets are rejected explicitly instead of falling through the default case.\n\nCo-Authored-By: Charon --- consensus/tx.go | 10 ++++++++-- consensus/tx_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/consensus/tx.go b/consensus/tx.go index a24bbc7..90d178d 100644 --- a/consensus/tx.go +++ b/consensus/tx.go @@ -119,11 +119,12 @@ func checkInputTypes(tx *types.Transaction, hf1Active, hf4Active bool) error { if !hf1Active { return coreerr.E("checkInputTypes", fmt.Sprintf("tag %d pre-HF1", vin.InputType()), ErrInvalidInputType) } - default: - // Future types (ZC) — accept if HF4+. + case types.TxInputZC: if !hf4Active { return coreerr.E("checkInputTypes", fmt.Sprintf("tag %d pre-HF4", vin.InputType()), ErrInvalidInputType) } + default: + return coreerr.E("checkInputTypes", fmt.Sprintf("unsupported input type %T", vin), ErrInvalidInputType) } } return nil @@ -150,13 +151,18 @@ func checkOutputs(tx *types.Transaction, hf1Active, hf4Active bool) error { } // HTLC and Multisig output targets require at least HF1. switch o.Target.(type) { + case types.TxOutToKey: case types.TxOutHTLC, types.TxOutMultisig: if !hf1Active { return coreerr.E("checkOutputs", fmt.Sprintf("output %d: HTLC/multisig target pre-HF1", i), ErrInvalidOutput) } + default: + return coreerr.E("checkOutputs", fmt.Sprintf("output %d: unsupported target type %T", i, o.Target), ErrInvalidOutput) } case types.TxOutputZarcanum: // Validated by proof verification. + default: + return coreerr.E("checkOutputs", fmt.Sprintf("unsupported output type %T", vout), ErrInvalidOutput) } } diff --git a/consensus/tx_test.go b/consensus/tx_test.go index 2ea2e40..96db144 100644 --- a/consensus/tx_test.go +++ b/consensus/tx_test.go @@ -16,6 +16,18 @@ import ( "github.com/stretchr/testify/require" ) +type unknownTxInput struct{} + +func (unknownTxInput) InputType() uint8 { return 99 } + +type unknownTxOutput struct{} + +func (unknownTxOutput) OutputType() uint8 { return 99 } + +type unknownTxOutputTarget struct{} + +func (unknownTxOutputTarget) TargetType() uint8 { return 99 } + // validV1Tx returns a minimal valid v1 transaction for testing. func validV1Tx() *types.Transaction { return &types.Transaction{ @@ -73,6 +85,14 @@ func TestValidateTransaction_InvalidInputType(t *testing.T) { assert.ErrorIs(t, err, ErrInvalidInputType) } +func TestValidateTransaction_UnknownInputType(t *testing.T) { + tx := validV1Tx() + tx.Vin = []types.TxInput{unknownTxInput{}} + blob := make([]byte, 100) + err := ValidateTransaction(tx, blob, config.MainnetForks, 5000) + assert.ErrorIs(t, err, ErrInvalidInputType) +} + func TestValidateTransaction_NoOutputs(t *testing.T) { tx := validV1Tx() tx.Vout = nil @@ -102,6 +122,24 @@ func TestValidateTransaction_ZeroOutputAmount(t *testing.T) { assert.ErrorIs(t, err, ErrInvalidOutput) } +func TestValidateTransaction_UnsupportedOutputType(t *testing.T) { + tx := validV1Tx() + tx.Vout = []types.TxOutput{unknownTxOutput{}} + blob := make([]byte, 100) + err := ValidateTransaction(tx, blob, config.MainnetForks, 5000) + assert.ErrorIs(t, err, ErrInvalidOutput) +} + +func TestValidateTransaction_UnsupportedBareTargetType(t *testing.T) { + tx := validV1Tx() + tx.Vout = []types.TxOutput{ + types.TxOutputBare{Amount: 90, Target: unknownTxOutputTarget{}}, + } + blob := make([]byte, 100) + err := ValidateTransaction(tx, blob, config.MainnetForks, 5000) + assert.ErrorIs(t, err, ErrInvalidOutput) +} + func TestValidateTransaction_DuplicateKeyImage(t *testing.T) { ki := types.KeyImage{42} tx := &types.Transaction{ @@ -238,6 +276,8 @@ func TestCheckOutputs_MultisigTargetPostHF1_Good(t *testing.T) { require.NoError(t, err) } +type unknownTxOutputTarget struct{} + // --- Key image tests for HTLC (Task 8) --- func TestCheckKeyImages_HTLCDuplicate_Bad(t *testing.T) {