Files
zeekayandHanzo Dev b50fd4ba8f Take the geth address conversion locally now that BlackholeAddr is an array
constants.BlackholeAddr is a plain [20]byte, so constants no longer imports
geth. The fourteen sites here all want a geth common.Address, and each file
already imports geth/common, so each takes the free conversion itself.

Only one site was a compile error: the .Bytes() method call in
rewardmanager.DisableFeeRewards. Everywhere else [20]byte is assignable to
common.Address, so the change was invisible to the compiler, and the two
require.Equal assertions in rewardmanager would have compiled and then failed
at run time, because reflect.DeepEqual compares types before bytes. Those two
are wrapped for that reason, not for style.

The two failures in core, TestHeadPin_Across4096Boundary_NoLeak and the
invalid-chainID-0 panic in TestCreateThenDeletePostByzantium, reproduce
identically with these lines reverted and are unrelated.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-06 00:28:23 -07:00

183 lines
6.3 KiB
Go

// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package nativeminter
import (
"fmt"
"math/big"
"testing"
"github.com/luxfi/constants"
"github.com/luxfi/crypto"
"github.com/luxfi/evm/accounts/abi"
"github.com/luxfi/evm/precompile/contract"
"github.com/luxfi/geth/common"
"github.com/stretchr/testify/require"
)
var (
mintSignature = contract.CalculateFunctionSelector("mintNativeCoin(address,uint256)") // address, amount
)
func FuzzPackMintNativeCoinEqualTest(f *testing.F) {
key, err := crypto.GenerateKey()
require.NoError(f, err)
addr := crypto.PubkeyToAddress(key.PublicKey)
testAddrBytes := addr.Bytes()
f.Add(testAddrBytes, common.Big0.Bytes())
f.Add(testAddrBytes, common.Big1.Bytes())
f.Add(testAddrBytes, abi.MaxUint256.Bytes())
f.Add(testAddrBytes, new(big.Int).Sub(abi.MaxUint256, common.Big1).Bytes())
f.Add(testAddrBytes, new(big.Int).Add(abi.MaxUint256, common.Big1).Bytes())
f.Add(common.Address(constants.BlackholeAddr).Bytes(), common.Big2.Bytes())
f.Fuzz(func(t *testing.T, b []byte, bigIntBytes []byte) {
bigIntVal := new(big.Int).SetBytes(bigIntBytes)
doCheckOutputs := bigIntVal.Cmp(abi.MaxUint256) <= 0
// we can only check if outputs are correct if the value is less than MaxUint256
// otherwise the value will be truncated when packed,
// and thus unpacked output will not be equal to the value
testOldPackMintNativeCoinEqual(t, common.BytesToAddress(b), bigIntVal, doCheckOutputs)
})
}
func TestUnpackMintNativeCoinInput(t *testing.T) {
testInputBytes, err := PackMintNativeCoin(common.Address(constants.BlackholeAddr), common.Big2)
require.NoError(t, err)
// exclude 4 bytes for function selector
testInputBytes = testInputBytes[4:]
tests := []struct {
name string
input []byte
strictMode bool
expectedErr string
expectedOldErr string
expectedAddr common.Address
expectedAmount *big.Int
}{
{
name: "empty input strict mode",
input: []byte{},
strictMode: true,
expectedErr: ErrInvalidLen.Error(),
expectedOldErr: ErrInvalidLen.Error(),
},
{
name: "empty input",
input: []byte{},
strictMode: false,
expectedErr: "attempting to unmarshal an empty string",
expectedOldErr: ErrInvalidLen.Error(),
},
{
name: "input with extra bytes strict mode",
input: append(testInputBytes, make([]byte, 32)...),
strictMode: true,
expectedErr: ErrInvalidLen.Error(),
expectedOldErr: ErrInvalidLen.Error(),
},
{
name: "input with extra bytes",
input: append(testInputBytes, make([]byte, 32)...),
strictMode: false,
expectedErr: "",
expectedOldErr: ErrInvalidLen.Error(),
expectedAddr: common.Address(constants.BlackholeAddr),
expectedAmount: common.Big2,
},
{
name: "input with extra bytes (not divisible by 32) strict mode",
input: append(testInputBytes, make([]byte, 33)...),
strictMode: true,
expectedErr: ErrInvalidLen.Error(),
expectedOldErr: ErrInvalidLen.Error(),
},
{
name: "input with extra bytes (not divisible by 32)",
input: append(testInputBytes, make([]byte, 33)...),
strictMode: false,
expectedAddr: common.Address(constants.BlackholeAddr),
expectedAmount: common.Big2,
expectedOldErr: ErrInvalidLen.Error(),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
unpackedAddress, unpackedAmount, err := UnpackMintNativeCoinInput(test.input, test.strictMode)
if test.expectedErr != "" {
require.ErrorContains(t, err, test.expectedErr)
} else {
require.NoError(t, err)
require.Equal(t, test.expectedAddr, unpackedAddress)
require.True(t, test.expectedAmount.Cmp(unpackedAmount) == 0, "expected %s, got %s", test.expectedAmount.String(), unpackedAmount.String())
}
oldUnpackedAddress, oldUnpackedAmount, oldErr := OldUnpackMintNativeCoinInput(test.input)
if test.expectedOldErr != "" {
require.ErrorContains(t, oldErr, test.expectedOldErr)
} else {
require.NoError(t, oldErr)
require.Equal(t, test.expectedAddr, oldUnpackedAddress)
require.True(t, test.expectedAmount.Cmp(oldUnpackedAmount) == 0, "expected %s, got %s", test.expectedAmount.String(), oldUnpackedAmount.String())
}
})
}
}
func TestFunctionSignatures(t *testing.T) {
// Test that the mintNativeCoin signature is correct
abiMintNativeCoin := NativeMinterABI.Methods["mintNativeCoin"]
require.Equal(t, mintSignature, abiMintNativeCoin.ID)
}
func testOldPackMintNativeCoinEqual(t *testing.T, addr common.Address, amount *big.Int, checkOutputs bool) {
t.Helper()
t.Run(fmt.Sprintf("TestUnpackAndPacks, addr: %s, amount: %s", addr.String(), amount.String()), func(t *testing.T) {
input, err := OldPackMintNativeCoinInput(addr, amount)
input2, err2 := PackMintNativeCoin(addr, amount)
if err != nil {
require.ErrorContains(t, err2, err.Error())
return
}
require.NoError(t, err2)
require.Equal(t, input, input2)
input = input[4:]
to, assetAmount, err := OldUnpackMintNativeCoinInput(input)
unpackedAddr, unpackedAmount, err2 := UnpackMintNativeCoinInput(input, true)
if err != nil {
require.ErrorContains(t, err2, err.Error())
return
}
require.NoError(t, err2)
require.Equal(t, to, unpackedAddr)
require.Equal(t, assetAmount.Bytes(), unpackedAmount.Bytes())
if checkOutputs {
require.Equal(t, addr, to)
require.Equal(t, amount.Bytes(), assetAmount.Bytes())
}
})
}
func OldPackMintNativeCoinInput(address common.Address, amount *big.Int) ([]byte, error) {
// function selector (4 bytes) + input(hash for address + hash for amount)
res := make([]byte, contract.SelectorLen+mintInputLen)
err := contract.PackOrderedHashesWithSelector(res, mintSignature, []common.Hash{
common.BytesToHash(address[:]),
common.BigToHash(amount),
})
return res, err
}
func OldUnpackMintNativeCoinInput(input []byte) (common.Address, *big.Int, error) {
mintInputAddressSlot := 0
mintInputAmountSlot := 1
if len(input) != mintInputLen {
return common.Address{}, nil, fmt.Errorf("%w: %d", ErrInvalidLen, len(input))
}
to := common.BytesToAddress(contract.PackedHash(input, mintInputAddressSlot))
assetAmount := new(big.Int).SetBytes(contract.PackedHash(input, mintInputAmountSlot))
return to, assetAmount, nil
}