Files
mev-beta/pkg/arbitrum/gas_test.go
2025-09-16 11:05:47 -05:00

454 lines
13 KiB
Go

package arbitrum
import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/fraktal/mev-beta/internal/logger"
"github.com/stretchr/testify/assert"
)
// TestCalculateL1DataFee tests L1 data fee calculation
func TestCalculateL1DataFee(t *testing.T) {
logger := logger.New("info", "text", "")
// Test with nil calldata
fee := CalculateL1DataFee(nil, logger)
assert.Equal(t, big.NewInt(0), fee)
// Test with empty calldata
fee = CalculateL1DataFee([]byte{}, logger)
assert.Equal(t, big.NewInt(0), fee)
// Test with sample calldata
calldata := []byte("hello world")
fee = CalculateL1DataFee(calldata, logger)
assert.NotNil(t, fee)
assert.True(t, fee.Sign() >= 0)
// Test with longer calldata
longCalldata := make([]byte, 1000)
for i := range longCalldata {
longCalldata[i] = byte(i % 256)
}
fee = CalculateL1DataFee(longCalldata, logger)
assert.NotNil(t, fee)
assert.True(t, fee.Sign() >= 0)
// Fee for longer calldata should be higher than for shorter calldata
shortFee := CalculateL1DataFee(calldata, logger)
assert.True(t, fee.Cmp(shortFee) >= 0)
}
// TestCalculateL2Gas tests L2 gas calculation
func TestCalculateL2Gas(t *testing.T) {
logger := logger.New("info", "text", "")
// Test with nil transaction
gas := CalculateL2Gas(nil, logger)
assert.Equal(t, big.NewInt(0), gas)
// Test with transaction with gas limit
tx := &RPCTransaction{
Gas: "0x5208", // 21000 in decimal
}
gas = CalculateL2Gas(tx, logger)
assert.Equal(t, big.NewInt(21000), gas)
// Test with transaction with zero gas limit
txZero := &RPCTransaction{
Gas: "0x0",
}
gas = CalculateL2Gas(txZero, logger)
assert.Equal(t, big.NewInt(0), gas)
// Test with malformed gas field
txMalformed := &RPCTransaction{
Gas: "invalid_hex",
}
gas = CalculateL2Gas(txMalformed, logger)
assert.Equal(t, big.NewInt(0), gas)
}
// TestEstimateTotalGasCost tests total gas cost estimation
func TestEstimateTotalGasCost(t *testing.T) {
logger := logger.New("info", "text", "")
// Test with nil parameters
totalGas := EstimateTotalGasCost(nil, nil, logger)
assert.Equal(t, big.NewInt(0), totalGas)
// Test with valid parameters
calldata := []byte("sample_transaction_data")
tx := &RPCTransaction{
Gas: "0x5208", // 21000 in decimal
}
totalGas = EstimateTotalGasCost(calldata, tx, logger)
assert.NotNil(t, totalGas)
assert.True(t, totalGas.Sign() >= 0)
// Test components are included in total
l1Fee := CalculateL1DataFee(calldata, logger)
l2Gas := CalculateL2Gas(tx, logger)
// Total should be at least the sum of components
// (in reality it might be more complex, but for our test this is sufficient)
assert.True(t, totalGas.Cmp(l1Fee) >= 0)
assert.True(t, totalGas.Cmp(l2Gas) >= 0)
}
// TestParseBigInt tests big integer parsing
func TestParseBigInt(t *testing.T) {
logger := logger.New("info", "text", "")
// Test with valid hex string
result := parseBigInt("0x1234", logger)
assert.Equal(t, big.NewInt(0x1234), result)
// Test with valid decimal string
result = parseBigInt("1234", logger)
assert.Equal(t, big.NewInt(1234), result)
// Test with zero
result = parseBigInt("0x0", logger)
assert.Equal(t, big.NewInt(0), result)
// Test with empty string
result = parseBigInt("", logger)
assert.Equal(t, big.NewInt(0), result)
// Test with invalid hex string
result = parseBigInt("0xinvalid", logger)
assert.Equal(t, big.NewInt(0), result)
// Test with invalid decimal string
result = parseBigInt("invalid", logger)
assert.Equal(t, big.NewInt(0), result)
// Test with negative number
result = parseBigInt("-1234", logger)
assert.Equal(t, big.NewInt(-1234), result)
}
// TestRPCTransaction_GetSender tests sender extraction from RPC transaction
func TestRPCTransaction_GetSender(t *testing.T) {
// Test with transaction that has from field
tx := &RPCTransaction{
From: "0x1234567890123456789012345678901234567890",
}
sender := tx.GetSender()
assert.Equal(t, common.HexToAddress("0x1234567890123456789012345678901234567890"), sender)
// Test with transaction without from field (should return zero address)
txNoFrom := &RPCTransaction{}
sender = txNoFrom.GetSender()
assert.Equal(t, common.Address{}, sender)
// Test with invalid address format
txInvalid := &RPCTransaction{
From: "invalid_address",
}
sender = txInvalid.GetSender()
assert.Equal(t, common.Address{}, sender)
}
// TestRPCTransaction_GetTo tests to address extraction from RPC transaction
func TestRPCTransaction_GetTo(t *testing.T) {
// Test with transaction that has to field
tx := &RPCTransaction{
To: "0x1234567890123456789012345678901234567890",
}
to := tx.GetTo()
assert.Equal(t, common.HexToAddress("0x1234567890123456789012345678901234567890"), to)
// Test with transaction without to field (should return zero address)
txNoTo := &RPCTransaction{}
to = txNoTo.GetTo()
assert.Equal(t, common.Address{}, to)
// Test with invalid address format
txInvalid := &RPCTransaction{
To: "invalid_address",
}
to = txInvalid.GetTo()
assert.Equal(t, common.Address{}, to)
// Test with contract creation transaction (to field is null/empty)
txContractCreation := &RPCTransaction{
To: "", // Contract creation
}
to = txContractCreation.GetTo()
assert.Equal(t, common.Address{}, to)
}
// TestRPCTransaction_GetValue tests value extraction from RPC transaction
func TestRPCTransaction_GetValue(t *testing.T) {
logger := logger.New("info", "text", "")
// Test with transaction that has value
tx := &RPCTransaction{
Value: "0x1234",
}
value := tx.GetValue(logger)
assert.Equal(t, big.NewInt(0x1234), value)
// Test with transaction without value
txNoValue := &RPCTransaction{}
value = txNoValue.GetValue(logger)
assert.Equal(t, big.NewInt(0), value)
// Test with invalid value
txInvalid := &RPCTransaction{
Value: "invalid_value",
}
value = txInvalid.GetValue(logger)
assert.Equal(t, big.NewInt(0), value)
// Test with zero value
txZero := &RPCTransaction{
Value: "0x0",
}
value = txZero.GetValue(logger)
assert.Equal(t, big.NewInt(0), value)
}
// TestRPCTransaction_GetGasPrice tests gas price extraction from RPC transaction
func TestRPCTransaction_GetGasPrice(t *testing.T) {
logger := logger.New("info", "text", "")
// Test with transaction that has gasPrice
tx := &RPCTransaction{
GasPrice: "0x1234",
}
gasPrice := tx.GetGasPrice(logger)
assert.Equal(t, big.NewInt(0x1234), gasPrice)
// Test with transaction that has maxFeePerGas (EIP-1559)
txEIP1559 := &RPCTransaction{
MaxFeePerGas: "0x1234",
}
gasPrice = txEIP1559.GetGasPrice(logger)
assert.Equal(t, big.NewInt(0x1234), gasPrice)
// Test with transaction that has both (should prefer gasPrice)
txBoth := &RPCTransaction{
GasPrice: "0x1234",
MaxFeePerGas: "0x5678",
}
gasPrice = txBoth.GetGasPrice(logger)
assert.Equal(t, big.NewInt(0x1234), gasPrice)
// Test with transaction without gas price fields
txNoGasPrice := &RPCTransaction{}
gasPrice = txNoGasPrice.GetGasPrice(logger)
assert.Equal(t, big.NewInt(0), gasPrice)
// Test with invalid gas price
txInvalid := &RPCTransaction{
GasPrice: "invalid_gas_price",
}
gasPrice = txInvalid.GetGasPrice(logger)
assert.Equal(t, big.NewInt(0), gasPrice)
}
// TestRPCTransaction_GetGasLimit tests gas limit extraction from RPC transaction
func TestRPCTransaction_GetGasLimit(t *testing.T) {
logger := logger.New("info", "text", "")
// Test with transaction that has gas limit
tx := &RPCTransaction{
Gas: "0x5208", // 21000 in decimal
}
gasLimit := tx.GetGasLimit(logger)
assert.Equal(t, big.NewInt(21000), gasLimit)
// Test with transaction without gas limit
txNoGas := &RPCTransaction{}
gasLimit = txNoGas.GetGasLimit(logger)
assert.Equal(t, big.NewInt(0), gasLimit)
// Test with invalid gas limit
txInvalid := &RPCTransaction{
Gas: "invalid_gas_limit",
}
gasLimit = txInvalid.GetGasLimit(logger)
assert.Equal(t, big.NewInt(0), gasLimit)
// Test with zero gas limit
txZero := &RPCTransaction{
Gas: "0x0",
}
gasLimit = txZero.GetGasLimit(logger)
assert.Equal(t, big.NewInt(0), gasLimit)
}
// TestRPCTransaction_GetNonce tests nonce extraction from RPC transaction
func TestRPCTransaction_GetNonce(t *testing.T) {
logger := logger.New("info", "text", "")
// Test with transaction that has nonce
tx := &RPCTransaction{
Nonce: "0x1234",
}
nonce := tx.GetNonce(logger)
assert.Equal(t, uint64(0x1234), nonce)
// Test with transaction without nonce
txNoNonce := &RPCTransaction{}
nonce = txNoNonce.GetNonce(logger)
assert.Equal(t, uint64(0), nonce)
// Test with invalid nonce
txInvalid := &RPCTransaction{
Nonce: "invalid_nonce",
}
nonce = txInvalid.GetNonce(logger)
assert.Equal(t, uint64(0), nonce)
// Test with zero nonce
txZero := &RPCTransaction{
Nonce: "0x0",
}
nonce = txZero.GetNonce(logger)
assert.Equal(t, uint64(0), nonce)
}
// TestRPCTransaction_GetInput tests input data extraction from RPC transaction
func TestRPCTransaction_GetInput(t *testing.T) {
// Test with transaction that has input data
inputData := "0x1234567890abcdef"
tx := &RPCTransaction{
Input: inputData,
}
input := tx.GetInput()
assert.Equal(t, inputData, input)
// Test with transaction without input data
txNoInput := &RPCTransaction{}
input = txNoInput.GetInput()
assert.Equal(t, "", input)
// Test with empty input data
txEmpty := &RPCTransaction{
Input: "",
}
input = txEmpty.GetInput()
assert.Equal(t, "", input)
}
// TestRPCTransaction_IsContractCreation tests contract creation detection
func TestRPCTransaction_IsContractCreation(t *testing.T) {
// Test contract creation transaction (to field is null/empty)
txContractCreation := &RPCTransaction{
To: "", // Empty to field indicates contract creation
}
isCreation := txContractCreation.IsContractCreation()
assert.True(t, isCreation)
// Test regular transaction (to field is present)
txRegular := &RPCTransaction{
To: "0x1234567890123456789012345678901234567890",
}
isCreation = txRegular.IsContractCreation()
assert.False(t, isCreation)
// Test with nil to field
txNilTo := &RPCTransaction{
To: "", // Nil becomes empty string in JSON unmarshaling
}
isCreation = txNilTo.IsContractCreation()
assert.True(t, isCreation)
}
// TestCalculateL1DataFeeComponents tests the components of L1 data fee calculation
func TestCalculateL1DataFeeComponents(t *testing.T) {
logger := logger.New("info", "text", "")
// Test calldata cost calculation
calldata := []byte{0x00, 0x01, 0x02, 0x03, 0x04}
calldataCost := calculateCalldataCost(calldata)
assert.True(t, calldataCost >= int64(len(calldata)))
// Test with zero bytes (should cost less)
zeroBytes := []byte{0x00, 0x00, 0x00}
zeroCost := calculateCalldataCost(zeroBytes)
assert.True(t, zeroCost >= 0)
// Test with non-zero bytes (should cost more)
nonZeroBytes := []byte{0x01, 0x02, 0x03}
nonZeroCost := calculateCalldataCost(nonZeroBytes)
assert.True(t, nonZeroCost >= int64(len(nonZeroBytes)))
// Test L1 gas price parsing
validL1GasPrice := "0x3b9aca00" // 1 Gwei
l1GasPrice := parseL1GasPrice(validL1GasPrice, logger)
assert.Equal(t, big.NewInt(1000000000), l1GasPrice)
// Test invalid L1 gas price
invalidL1GasPrice := "invalid"
l1GasPrice = parseL1GasPrice(invalidL1GasPrice, logger)
assert.Equal(t, big.NewInt(defaultL1GasPrice), l1GasPrice)
// Test L1 fee calculation with parameters
calldataCostInt := int64(100)
l1GasPriceBig := big.NewInt(1000000000) // 1 Gwei
l1Fee := calculateL1Fee(calldataCostInt, l1GasPriceBig, logger)
assert.NotNil(t, l1Fee)
assert.True(t, l1Fee.Sign() >= 0)
}
// Helper function to calculate calldata cost (simulating internal logic)
func calculateCalldataCost(data []byte) int64 {
cost := int64(0)
for _, b := range data {
if b == 0 {
cost += 4 // Cost for zero byte
} else {
cost += 16 // Cost for non-zero byte
}
}
return cost
}
// Helper function to parse L1 gas price
func parseL1GasPrice(gasPrice string, logger *logger.Logger) *big.Int {
if gasPrice == "" {
return big.NewInt(defaultL1GasPrice)
}
result, ok := new(big.Int).SetString(gasPrice, 0)
if !ok {
logger.Warn("Invalid L1 gas price, using default")
return big.NewInt(defaultL1GasPrice)
}
return result
}
// Helper function to calculate L1 fee
func calculateL1Fee(calldataCost int64, l1GasPrice *big.Int, logger *logger.Logger) *big.Int {
// Simplified L1 fee calculation
// In reality, this would involve more complex Arbitrum-specific calculations
baseFee := big.NewInt(calldataCost)
fee := new(big.Int).Mul(baseFee, l1GasPrice)
// Apply scaling factor (simplified)
scalingFactor := big.NewInt(1000000000) // 1e9
fee.Div(fee, scalingFactor)
return fee
}
// TestGasConstants tests gas-related constants
func TestGasConstants(t *testing.T) {
// Test that default L1 gas price is reasonable (1 Gwei = 1,000,000,000 wei)
assert.Equal(t, int64(1000000000), defaultL1GasPrice)
// Test that default L2 gas limit is reasonable
assert.Equal(t, int64(30000000), defaultL2GasLimit)
// Test that zero byte cost is less than non-zero byte cost
assert.True(t, l1ZeroByteCost < l1NonZeroByteCost)
}