mirror of
https://github.com/luxfi/evmgpu.git
synced 2026-10-30 16:57:11 +00:00
constants.BlackholeAddr is a plain [20]byte rather than a geth common.Address, so constants pulls in neither geth nor crypto. Every site that wants an address now converts explicitly, and the two that read raw bytes convert first, since an array has no Bytes method. Assignability hides most of this from the compiler: a [20]byte argument, return value or assignment still satisfies a common.Address parameter. The two require.Equal assertions in rewardmanager do not, because reflect.DeepEqual compares types as well as contents, and they failed on identical bytes until converted. The conversion is free and compiles against both the currently tagged constants and the array, so this does not have to land with the version bump. Co-authored-by: Hanzo Dev <[email protected]>
183 lines
6.3 KiB
Go
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/evmgpu/accounts/abi"
|
|
"github.com/luxfi/evmgpu/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
|
|
}
|