mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
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]>
493 lines
15 KiB
Go
493 lines
15 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package rewardmanager
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/luxfi/geth/common"
|
|
ethtypes "github.com/luxfi/geth/core/types"
|
|
"github.com/luxfi/geth/core/vm"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/mock/gomock"
|
|
|
|
"github.com/luxfi/constants"
|
|
"github.com/luxfi/evm/commontype"
|
|
"github.com/luxfi/evm/core/state"
|
|
"github.com/luxfi/evm/precompile/allowlist/allowlisttest"
|
|
"github.com/luxfi/evm/precompile/precompileconfig"
|
|
"github.com/luxfi/evm/precompile/precompiletest"
|
|
"github.com/luxfi/evm/precompile/testutils"
|
|
)
|
|
|
|
var (
|
|
rewardAddress = common.HexToAddress("0x0123")
|
|
tests = map[string]precompiletest.PrecompileTest{
|
|
"set allow fee recipients from no role fails": {
|
|
Caller: allowlisttest.TestNoRoleAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackAllowFeeRecipients()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: AllowFeeRecipientsGasCost,
|
|
ReadOnly: false,
|
|
ExpectedErr: ErrCannotAllowFeeRecipients.Error(),
|
|
},
|
|
"set reward address from no role fails": {
|
|
Caller: allowlisttest.TestNoRoleAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackSetRewardAddress(rewardAddress)
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: SetRewardAddressGasCost,
|
|
ReadOnly: false,
|
|
ExpectedErr: ErrCannotSetRewardAddress.Error(),
|
|
},
|
|
"disable rewards from no role fails": {
|
|
Caller: allowlisttest.TestNoRoleAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackDisableRewards()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: DisableRewardsGasCost,
|
|
ReadOnly: false,
|
|
ExpectedErr: ErrCannotDisableRewards.Error(),
|
|
},
|
|
"set allow fee recipients from enabled succeeds": {
|
|
Caller: allowlisttest.TestEnabledAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackAllowFeeRecipients()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: AllowFeeRecipientsGasCost + FeeRecipientsAllowedEventGasCost,
|
|
ReadOnly: false,
|
|
ExpectedRes: []byte{},
|
|
AfterHook: func(t testing.TB, state *state.StateDB) {
|
|
_, isFeeRecipients := GetStoredRewardAddress(state)
|
|
require.True(t, isFeeRecipients)
|
|
|
|
logs := state.Logs()
|
|
assertFeeRecipientsAllowed(t, logs, allowlisttest.TestEnabledAddr)
|
|
},
|
|
},
|
|
"set fee recipients should not emit events pre-Durango": {
|
|
Caller: allowlisttest.TestEnabledAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackAllowFeeRecipients()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
ChainConfigFn: func(ctrl *gomock.Controller) precompileconfig.ChainConfig {
|
|
mockChainConfig := precompileconfig.NewMockChainConfig(ctrl)
|
|
mockChainConfig.EXPECT().GetFeeConfig().AnyTimes().Return(commontype.ValidTestFeeConfig)
|
|
mockChainConfig.EXPECT().AllowedFeeRecipients().AnyTimes().Return(false)
|
|
mockChainConfig.EXPECT().IsDurango(gomock.Any()).AnyTimes().Return(false)
|
|
return mockChainConfig
|
|
},
|
|
SuppliedGas: AllowFeeRecipientsGasCost,
|
|
ReadOnly: false,
|
|
ExpectedRes: []byte{},
|
|
AfterHook: func(t testing.TB, stateDB *state.StateDB) {
|
|
// Check no logs are stored in state
|
|
logs := stateDB.Logs()
|
|
require.Empty(t, logs)
|
|
},
|
|
},
|
|
"set reward address from enabled succeeds": {
|
|
Caller: allowlisttest.TestEnabledAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackSetRewardAddress(rewardAddress)
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: SetRewardAddressGasCost + RewardAddressChangedEventGasCost,
|
|
ReadOnly: false,
|
|
ExpectedRes: []byte{},
|
|
AfterHook: func(t testing.TB, state *state.StateDB) {
|
|
address, isFeeRecipients := GetStoredRewardAddress(state)
|
|
require.Equal(t, rewardAddress, address)
|
|
require.False(t, isFeeRecipients)
|
|
|
|
logs := state.Logs()
|
|
assertRewardAddressChanged(t, logs, allowlisttest.TestEnabledAddr, common.Address{}, rewardAddress)
|
|
},
|
|
},
|
|
"set allow fee recipients from manager succeeds": {
|
|
Caller: allowlisttest.TestManagerAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackAllowFeeRecipients()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: AllowFeeRecipientsGasCost + FeeRecipientsAllowedEventGasCost,
|
|
ReadOnly: false,
|
|
ExpectedRes: []byte{},
|
|
AfterHook: func(t testing.TB, state *state.StateDB) {
|
|
_, isFeeRecipients := GetStoredRewardAddress(state)
|
|
require.True(t, isFeeRecipients)
|
|
|
|
logs := state.Logs()
|
|
assertFeeRecipientsAllowed(t, logs, allowlisttest.TestManagerAddr)
|
|
},
|
|
},
|
|
"set reward address from manager succeeds": {
|
|
Caller: allowlisttest.TestManagerAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackSetRewardAddress(rewardAddress)
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: SetRewardAddressGasCost + RewardAddressChangedEventGasCost,
|
|
ReadOnly: false,
|
|
ExpectedRes: []byte{},
|
|
AfterHook: func(t testing.TB, state *state.StateDB) {
|
|
address, isFeeRecipients := GetStoredRewardAddress(state)
|
|
require.Equal(t, rewardAddress, address)
|
|
require.False(t, isFeeRecipients)
|
|
|
|
logs := state.Logs()
|
|
assertRewardAddressChanged(t, logs, allowlisttest.TestManagerAddr, common.Address{}, rewardAddress)
|
|
},
|
|
},
|
|
"change reward address should not emit events pre-Durango": {
|
|
Caller: allowlisttest.TestManagerAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackSetRewardAddress(rewardAddress)
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
ChainConfigFn: func(ctrl *gomock.Controller) precompileconfig.ChainConfig {
|
|
mockChainConfig := precompileconfig.NewMockChainConfig(ctrl)
|
|
mockChainConfig.EXPECT().GetFeeConfig().AnyTimes().Return(commontype.ValidTestFeeConfig)
|
|
mockChainConfig.EXPECT().AllowedFeeRecipients().AnyTimes().Return(false)
|
|
mockChainConfig.EXPECT().IsDurango(gomock.Any()).AnyTimes().Return(false)
|
|
return mockChainConfig
|
|
},
|
|
SuppliedGas: SetRewardAddressGasCost,
|
|
ReadOnly: false,
|
|
ExpectedRes: []byte{},
|
|
AfterHook: func(t testing.TB, stateDB *state.StateDB) {
|
|
// Check no logs are stored in state
|
|
logs := stateDB.Logs()
|
|
require.Empty(t, logs)
|
|
},
|
|
},
|
|
"disable rewards from manager succeeds": {
|
|
Caller: allowlisttest.TestManagerAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackDisableRewards()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: DisableRewardsGasCost + RewardsDisabledEventGasCost,
|
|
ReadOnly: false,
|
|
ExpectedRes: []byte{},
|
|
AfterHook: func(t testing.TB, state *state.StateDB) {
|
|
address, isFeeRecipients := GetStoredRewardAddress(state)
|
|
require.False(t, isFeeRecipients)
|
|
require.Equal(t, common.Address(constants.BlackholeAddr), address)
|
|
|
|
logs := state.Logs()
|
|
assertRewardsDisabled(t, logs, allowlisttest.TestManagerAddr)
|
|
},
|
|
},
|
|
"disable rewards from enabled succeeds": {
|
|
Caller: allowlisttest.TestEnabledAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackDisableRewards()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: DisableRewardsGasCost + RewardsDisabledEventGasCost,
|
|
ReadOnly: false,
|
|
ExpectedRes: []byte{},
|
|
AfterHook: func(t testing.TB, state *state.StateDB) {
|
|
address, isFeeRecipients := GetStoredRewardAddress(state)
|
|
require.False(t, isFeeRecipients)
|
|
require.Equal(t, common.Address(constants.BlackholeAddr), address)
|
|
|
|
logs := state.Logs()
|
|
assertRewardsDisabled(t, logs, allowlisttest.TestEnabledAddr)
|
|
},
|
|
},
|
|
"disable rewards should not emit event pre-Durango": {
|
|
Caller: allowlisttest.TestManagerAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackDisableRewards()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
ChainConfigFn: func(ctrl *gomock.Controller) precompileconfig.ChainConfig {
|
|
mockChainConfig := precompileconfig.NewMockChainConfig(ctrl)
|
|
mockChainConfig.EXPECT().GetFeeConfig().AnyTimes().Return(commontype.ValidTestFeeConfig)
|
|
mockChainConfig.EXPECT().AllowedFeeRecipients().AnyTimes().Return(false)
|
|
mockChainConfig.EXPECT().IsDurango(gomock.Any()).AnyTimes().Return(false)
|
|
return mockChainConfig
|
|
},
|
|
SuppliedGas: SetRewardAddressGasCost,
|
|
ReadOnly: false,
|
|
ExpectedRes: []byte{},
|
|
AfterHook: func(t testing.TB, stateDB *state.StateDB) {
|
|
// Check logs are not stored in state
|
|
logs := stateDB.Logs()
|
|
require.Empty(t, logs)
|
|
},
|
|
},
|
|
"get current reward address from no role succeeds": {
|
|
Caller: allowlisttest.TestNoRoleAddr,
|
|
BeforeHook: func(t testing.TB, state *state.StateDB) {
|
|
allowlisttest.SetDefaultRoles(Module.Address)(t, state)
|
|
StoreRewardAddress(testutils.WrapStateDB(state), rewardAddress)
|
|
},
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackCurrentRewardAddress()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: CurrentRewardAddressGasCost,
|
|
ReadOnly: false,
|
|
ExpectedRes: func() []byte {
|
|
res, err := PackCurrentRewardAddressOutput(rewardAddress)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return res
|
|
}(),
|
|
},
|
|
"get are fee recipients allowed from no role succeeds": {
|
|
Caller: allowlisttest.TestNoRoleAddr,
|
|
BeforeHook: func(t testing.TB, state *state.StateDB) {
|
|
allowlisttest.SetDefaultRoles(Module.Address)(t, state)
|
|
EnableAllowFeeRecipients(testutils.WrapStateDB(state))
|
|
},
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackAreFeeRecipientsAllowed()
|
|
require.NoError(t, err)
|
|
return input
|
|
},
|
|
SuppliedGas: AreFeeRecipientsAllowedGasCost,
|
|
ReadOnly: false,
|
|
ExpectedRes: func() []byte {
|
|
res, err := PackAreFeeRecipientsAllowedOutput(true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return res
|
|
}(),
|
|
},
|
|
"get initial config with address": {
|
|
Caller: allowlisttest.TestNoRoleAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackCurrentRewardAddress()
|
|
require.NoError(t, err)
|
|
return input
|
|
},
|
|
SuppliedGas: CurrentRewardAddressGasCost,
|
|
Config: &Config{
|
|
InitialRewardConfig: &InitialRewardConfig{
|
|
RewardAddress: rewardAddress,
|
|
},
|
|
},
|
|
ReadOnly: false,
|
|
ExpectedRes: func() []byte {
|
|
res, err := PackCurrentRewardAddressOutput(rewardAddress)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return res
|
|
}(),
|
|
},
|
|
"get initial config with allow fee recipients enabled": {
|
|
Caller: allowlisttest.TestNoRoleAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackAreFeeRecipientsAllowed()
|
|
require.NoError(t, err)
|
|
return input
|
|
},
|
|
SuppliedGas: AreFeeRecipientsAllowedGasCost,
|
|
Config: &Config{
|
|
InitialRewardConfig: &InitialRewardConfig{
|
|
AllowFeeRecipients: true,
|
|
},
|
|
},
|
|
ReadOnly: false,
|
|
ExpectedRes: func() []byte {
|
|
res, err := PackAreFeeRecipientsAllowedOutput(true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return res
|
|
}(),
|
|
},
|
|
"readOnly allow fee recipients with allowed role fails": {
|
|
Caller: allowlisttest.TestEnabledAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackAllowFeeRecipients()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: AllowFeeRecipientsGasCost,
|
|
ReadOnly: true,
|
|
ExpectedErr: vm.ErrWriteProtection.Error(),
|
|
},
|
|
"readOnly set reward address with allowed role fails": {
|
|
Caller: allowlisttest.TestEnabledAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackSetRewardAddress(rewardAddress)
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: SetRewardAddressGasCost,
|
|
ReadOnly: true,
|
|
ExpectedErr: vm.ErrWriteProtection.Error(),
|
|
},
|
|
"insufficient gas set reward address from allowed role": {
|
|
Caller: allowlisttest.TestEnabledAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackSetRewardAddress(rewardAddress)
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: SetRewardAddressGasCost + RewardAddressChangedEventGasCost - 1,
|
|
ReadOnly: false,
|
|
ExpectedErr: vm.ErrOutOfGas.Error(),
|
|
},
|
|
"insufficient gas allow fee recipients from allowed role": {
|
|
Caller: allowlisttest.TestEnabledAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackAllowFeeRecipients()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: AllowFeeRecipientsGasCost + FeeRecipientsAllowedEventGasCost - 1,
|
|
ReadOnly: false,
|
|
ExpectedErr: vm.ErrOutOfGas.Error(),
|
|
},
|
|
"insufficient gas read current reward address from allowed role": {
|
|
Caller: allowlisttest.TestEnabledAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackCurrentRewardAddress()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: CurrentRewardAddressGasCost - 1,
|
|
ReadOnly: false,
|
|
ExpectedErr: vm.ErrOutOfGas.Error(),
|
|
},
|
|
"insufficient gas are fee recipients allowed from allowed role": {
|
|
Caller: allowlisttest.TestEnabledAddr,
|
|
BeforeHook: allowlisttest.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
input, err := PackAreFeeRecipientsAllowed()
|
|
require.NoError(t, err)
|
|
|
|
return input
|
|
},
|
|
SuppliedGas: AreFeeRecipientsAllowedGasCost - 1,
|
|
ReadOnly: false,
|
|
ExpectedErr: vm.ErrOutOfGas.Error(),
|
|
},
|
|
}
|
|
)
|
|
|
|
func TestRewardManagerRun(t *testing.T) {
|
|
allowlisttest.RunPrecompileWithAllowListTests(t, Module, tests)
|
|
}
|
|
|
|
func assertRewardAddressChanged(
|
|
t testing.TB,
|
|
logs []*ethtypes.Log,
|
|
caller,
|
|
oldAddress,
|
|
newAddress common.Address) {
|
|
require.Len(t, logs, 1)
|
|
log := logs[0]
|
|
require.Equal(
|
|
t,
|
|
[]common.Hash{
|
|
RewardManagerABI.Events["RewardAddressChanged"].ID,
|
|
common.BytesToHash(caller[:]),
|
|
common.BytesToHash(oldAddress[:]),
|
|
common.BytesToHash(newAddress[:]),
|
|
},
|
|
log.Topics,
|
|
)
|
|
require.Empty(t, log.Data)
|
|
}
|
|
|
|
func assertRewardsDisabled(
|
|
t testing.TB,
|
|
logs []*ethtypes.Log,
|
|
caller common.Address) {
|
|
require.Len(t, logs, 1)
|
|
log := logs[0]
|
|
require.Equal(
|
|
t,
|
|
[]common.Hash{
|
|
RewardManagerABI.Events["RewardsDisabled"].ID,
|
|
common.BytesToHash(caller[:]),
|
|
},
|
|
log.Topics,
|
|
)
|
|
require.Empty(t, log.Data)
|
|
}
|
|
|
|
func assertFeeRecipientsAllowed(
|
|
t testing.TB,
|
|
logs []*ethtypes.Log,
|
|
caller common.Address) {
|
|
require.Len(t, logs, 1)
|
|
log := logs[0]
|
|
require.Equal(
|
|
t,
|
|
[]common.Hash{
|
|
RewardManagerABI.Events["FeeRecipientsAllowed"].ID,
|
|
common.BytesToHash(caller[:]),
|
|
},
|
|
log.Topics,
|
|
)
|
|
require.Empty(t, log.Data)
|
|
}
|