github.com/MetalBlockchain/subnet-evm@v0.4.9/core/stateful_precompile_test.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package core
     5  
     6  import (
     7  	"math/big"
     8  	"testing"
     9  
    10  	"github.com/MetalBlockchain/metalgo/snow"
    11  	"github.com/MetalBlockchain/subnet-evm/commontype"
    12  	"github.com/MetalBlockchain/subnet-evm/constants"
    13  	"github.com/MetalBlockchain/subnet-evm/core/rawdb"
    14  	"github.com/MetalBlockchain/subnet-evm/core/state"
    15  	"github.com/MetalBlockchain/subnet-evm/params"
    16  	"github.com/MetalBlockchain/subnet-evm/precompile"
    17  	"github.com/MetalBlockchain/subnet-evm/vmerrs"
    18  	"github.com/ethereum/go-ethereum/common"
    19  	"github.com/ethereum/go-ethereum/common/math"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  var (
    24  	_ precompile.BlockContext              = &mockBlockContext{}
    25  	_ precompile.PrecompileAccessibleState = &mockAccessibleState{}
    26  
    27  	testFeeConfig = commontype.FeeConfig{
    28  		GasLimit:        big.NewInt(8_000_000),
    29  		TargetBlockRate: 2, // in seconds
    30  
    31  		MinBaseFee:               big.NewInt(25_000_000_000),
    32  		TargetGas:                big.NewInt(15_000_000),
    33  		BaseFeeChangeDenominator: big.NewInt(36),
    34  
    35  		MinBlockGasCost:  big.NewInt(0),
    36  		MaxBlockGasCost:  big.NewInt(1_000_000),
    37  		BlockGasCostStep: big.NewInt(200_000),
    38  	}
    39  
    40  	testBlockNumber = big.NewInt(7)
    41  )
    42  
    43  type mockBlockContext struct {
    44  	blockNumber *big.Int
    45  	timestamp   uint64
    46  }
    47  
    48  func (mb *mockBlockContext) Number() *big.Int    { return mb.blockNumber }
    49  func (mb *mockBlockContext) Timestamp() *big.Int { return new(big.Int).SetUint64(mb.timestamp) }
    50  
    51  type mockAccessibleState struct {
    52  	state        *state.StateDB
    53  	blockContext *mockBlockContext
    54  	snowContext  *snow.Context
    55  }
    56  
    57  func (m *mockAccessibleState) GetStateDB() precompile.StateDB { return m.state }
    58  
    59  func (m *mockAccessibleState) GetBlockContext() precompile.BlockContext { return m.blockContext }
    60  
    61  func (m *mockAccessibleState) GetSnowContext() *snow.Context { return m.snowContext }
    62  
    63  func (m *mockAccessibleState) CallFromPrecompile(caller common.Address, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
    64  	return nil, 0, nil
    65  }
    66  
    67  // This test is added within the core package so that it can import all of the required code
    68  // without creating any import cycles
    69  func TestContractDeployerAllowListRun(t *testing.T) {
    70  	type test struct {
    71  		caller      common.Address
    72  		input       func() []byte
    73  		suppliedGas uint64
    74  		readOnly    bool
    75  
    76  		expectedRes []byte
    77  		expectedErr string
    78  
    79  		assertState func(t *testing.T, state *state.StateDB)
    80  	}
    81  
    82  	adminAddr := common.HexToAddress("0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC")
    83  	noRoleAddr := common.HexToAddress("0xF60C45c607D0f41687c94C314d300f483661E13a")
    84  
    85  	for name, test := range map[string]test{
    86  		"set admin": {
    87  			caller: adminAddr,
    88  			input: func() []byte {
    89  				input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListAdmin)
    90  				require.NoError(t, err)
    91  
    92  				return input
    93  			},
    94  			suppliedGas: precompile.ModifyAllowListGasCost,
    95  			readOnly:    false,
    96  			expectedRes: []byte{},
    97  			assertState: func(t *testing.T, state *state.StateDB) {
    98  				res := precompile.GetContractDeployerAllowListStatus(state, noRoleAddr)
    99  				require.Equal(t, precompile.AllowListAdmin, res)
   100  			},
   101  		},
   102  		"set deployer": {
   103  			caller: adminAddr,
   104  			input: func() []byte {
   105  				input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled)
   106  				require.NoError(t, err)
   107  
   108  				return input
   109  			},
   110  			suppliedGas: precompile.ModifyAllowListGasCost,
   111  			readOnly:    false,
   112  			expectedRes: []byte{},
   113  			assertState: func(t *testing.T, state *state.StateDB) {
   114  				res := precompile.GetContractDeployerAllowListStatus(state, noRoleAddr)
   115  				require.Equal(t, precompile.AllowListEnabled, res)
   116  			},
   117  		},
   118  		"set no role": {
   119  			caller: adminAddr,
   120  			input: func() []byte {
   121  				input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole)
   122  				require.NoError(t, err)
   123  
   124  				return input
   125  			},
   126  			suppliedGas: precompile.ModifyAllowListGasCost,
   127  			readOnly:    false,
   128  			expectedRes: []byte{},
   129  			assertState: func(t *testing.T, state *state.StateDB) {
   130  				res := precompile.GetContractDeployerAllowListStatus(state, adminAddr)
   131  				require.Equal(t, precompile.AllowListNoRole, res)
   132  			},
   133  		},
   134  		"set no role from non-admin": {
   135  			caller: noRoleAddr,
   136  			input: func() []byte {
   137  				input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole)
   138  				require.NoError(t, err)
   139  
   140  				return input
   141  			},
   142  			suppliedGas: precompile.ModifyAllowListGasCost,
   143  			readOnly:    false,
   144  			expectedErr: precompile.ErrCannotModifyAllowList.Error(),
   145  		},
   146  		"set deployer from non-admin": {
   147  			caller: noRoleAddr,
   148  			input: func() []byte {
   149  				input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListEnabled)
   150  				require.NoError(t, err)
   151  
   152  				return input
   153  			},
   154  			suppliedGas: precompile.ModifyAllowListGasCost,
   155  			readOnly:    false,
   156  			expectedErr: precompile.ErrCannotModifyAllowList.Error(),
   157  		},
   158  		"set admin from non-admin": {
   159  			caller: noRoleAddr,
   160  			input: func() []byte {
   161  				input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListAdmin)
   162  				require.NoError(t, err)
   163  
   164  				return input
   165  			},
   166  			suppliedGas: precompile.ModifyAllowListGasCost,
   167  			readOnly:    false,
   168  			expectedErr: precompile.ErrCannotModifyAllowList.Error(),
   169  		},
   170  		"set no role with readOnly enabled": {
   171  			caller: adminAddr,
   172  			input: func() []byte {
   173  				input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole)
   174  				require.NoError(t, err)
   175  
   176  				return input
   177  			},
   178  			suppliedGas: precompile.ModifyAllowListGasCost,
   179  			readOnly:    true,
   180  			expectedErr: vmerrs.ErrWriteProtection.Error(),
   181  		},
   182  		"set no role insufficient gas": {
   183  			caller: adminAddr,
   184  			input: func() []byte {
   185  				input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole)
   186  				require.NoError(t, err)
   187  
   188  				return input
   189  			},
   190  			suppliedGas: precompile.ModifyAllowListGasCost - 1,
   191  			readOnly:    false,
   192  			expectedErr: vmerrs.ErrOutOfGas.Error(),
   193  		},
   194  		"read allow list no role": {
   195  			caller: noRoleAddr,
   196  			input: func() []byte {
   197  				return precompile.PackReadAllowList(noRoleAddr)
   198  			},
   199  			suppliedGas: precompile.ReadAllowListGasCost,
   200  			readOnly:    false,
   201  			expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(),
   202  			assertState: nil,
   203  		},
   204  		"read allow list admin role": {
   205  			caller: adminAddr,
   206  			input: func() []byte {
   207  				return precompile.PackReadAllowList(noRoleAddr)
   208  			},
   209  			suppliedGas: precompile.ReadAllowListGasCost,
   210  			readOnly:    false,
   211  			expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(),
   212  			assertState: nil,
   213  		},
   214  		"read allow list with readOnly enabled": {
   215  			caller: adminAddr,
   216  			input: func() []byte {
   217  				return precompile.PackReadAllowList(noRoleAddr)
   218  			},
   219  			suppliedGas: precompile.ReadAllowListGasCost,
   220  			readOnly:    true,
   221  			expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(),
   222  			assertState: nil,
   223  		},
   224  		"read allow list out of gas": {
   225  			caller: adminAddr,
   226  			input: func() []byte {
   227  				return precompile.PackReadAllowList(noRoleAddr)
   228  			},
   229  			suppliedGas: precompile.ReadAllowListGasCost - 1,
   230  			readOnly:    true,
   231  			expectedErr: vmerrs.ErrOutOfGas.Error(),
   232  		},
   233  	} {
   234  		t.Run(name, func(t *testing.T) {
   235  			db := rawdb.NewMemoryDatabase()
   236  			state, err := state.New(common.Hash{}, state.NewDatabase(db), nil)
   237  			require.NoError(t, err)
   238  
   239  			// Set up the state so that each address has the expected permissions at the start.
   240  			precompile.SetContractDeployerAllowListStatus(state, adminAddr, precompile.AllowListAdmin)
   241  			precompile.SetContractDeployerAllowListStatus(state, noRoleAddr, precompile.AllowListNoRole)
   242  			require.Equal(t, precompile.AllowListAdmin, precompile.GetContractDeployerAllowListStatus(state, adminAddr))
   243  			require.Equal(t, precompile.AllowListNoRole, precompile.GetContractDeployerAllowListStatus(state, noRoleAddr))
   244  
   245  			blockContext := &mockBlockContext{blockNumber: common.Big0}
   246  			ret, remainingGas, err := precompile.ContractDeployerAllowListPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.ContractDeployerAllowListAddress, test.input(), test.suppliedGas, test.readOnly)
   247  			if len(test.expectedErr) != 0 {
   248  				require.ErrorContains(t, err, test.expectedErr)
   249  			} else {
   250  				require.NoError(t, err)
   251  			}
   252  
   253  			require.Equal(t, uint64(0), remainingGas)
   254  			require.Equal(t, test.expectedRes, ret)
   255  
   256  			if test.assertState != nil {
   257  				test.assertState(t, state)
   258  			}
   259  		})
   260  	}
   261  }
   262  
   263  func TestTxAllowListRun(t *testing.T) {
   264  	type test struct {
   265  		caller         common.Address
   266  		precompileAddr common.Address
   267  		input          func() []byte
   268  		suppliedGas    uint64
   269  		readOnly       bool
   270  
   271  		expectedRes []byte
   272  		expectedErr string
   273  
   274  		assertState func(t *testing.T, state *state.StateDB)
   275  	}
   276  
   277  	adminAddr := common.HexToAddress("0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC")
   278  	noRoleAddr := common.HexToAddress("0xF60C45c607D0f41687c94C314d300f483661E13a")
   279  
   280  	for name, test := range map[string]test{
   281  		"set admin": {
   282  			caller: adminAddr,
   283  			input: func() []byte {
   284  				input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListAdmin)
   285  				require.NoError(t, err)
   286  
   287  				return input
   288  			},
   289  			suppliedGas: precompile.ModifyAllowListGasCost,
   290  			readOnly:    false,
   291  			expectedRes: []byte{},
   292  			assertState: func(t *testing.T, state *state.StateDB) {
   293  				res := precompile.GetTxAllowListStatus(state, noRoleAddr)
   294  				require.Equal(t, precompile.AllowListAdmin, res)
   295  			},
   296  		},
   297  		"set allowed": {
   298  			caller: adminAddr,
   299  			input: func() []byte {
   300  				input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled)
   301  				require.NoError(t, err)
   302  
   303  				return input
   304  			},
   305  			suppliedGas: precompile.ModifyAllowListGasCost,
   306  			readOnly:    false,
   307  			expectedRes: []byte{},
   308  			assertState: func(t *testing.T, state *state.StateDB) {
   309  				res := precompile.GetTxAllowListStatus(state, noRoleAddr)
   310  				require.Equal(t, precompile.AllowListEnabled, res)
   311  			},
   312  		},
   313  		"set no role": {
   314  			caller: adminAddr,
   315  			input: func() []byte {
   316  				input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole)
   317  				require.NoError(t, err)
   318  
   319  				return input
   320  			},
   321  			suppliedGas: precompile.ModifyAllowListGasCost,
   322  			readOnly:    false,
   323  			expectedRes: []byte{},
   324  			assertState: func(t *testing.T, state *state.StateDB) {
   325  				res := precompile.GetTxAllowListStatus(state, adminAddr)
   326  				require.Equal(t, precompile.AllowListNoRole, res)
   327  			},
   328  		},
   329  		"set no role from non-admin": {
   330  			caller: noRoleAddr,
   331  			input: func() []byte {
   332  				input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole)
   333  				require.NoError(t, err)
   334  
   335  				return input
   336  			},
   337  			suppliedGas: precompile.ModifyAllowListGasCost,
   338  			readOnly:    false,
   339  			expectedErr: precompile.ErrCannotModifyAllowList.Error(),
   340  		},
   341  		"set allowed from non-admin": {
   342  			caller: noRoleAddr,
   343  			input: func() []byte {
   344  				input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListEnabled)
   345  				require.NoError(t, err)
   346  
   347  				return input
   348  			},
   349  			suppliedGas: precompile.ModifyAllowListGasCost,
   350  			readOnly:    false,
   351  			expectedErr: precompile.ErrCannotModifyAllowList.Error(),
   352  		},
   353  		"set admin from non-admin": {
   354  			caller: noRoleAddr,
   355  			input: func() []byte {
   356  				input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListAdmin)
   357  				require.NoError(t, err)
   358  
   359  				return input
   360  			},
   361  			suppliedGas: precompile.ModifyAllowListGasCost,
   362  			readOnly:    false,
   363  			expectedErr: precompile.ErrCannotModifyAllowList.Error(),
   364  		},
   365  		"set no role with readOnly enabled": {
   366  			caller:         adminAddr,
   367  			precompileAddr: precompile.TxAllowListAddress,
   368  			input: func() []byte {
   369  				input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole)
   370  				require.NoError(t, err)
   371  
   372  				return input
   373  			},
   374  			suppliedGas: precompile.ModifyAllowListGasCost,
   375  			readOnly:    true,
   376  			expectedErr: vmerrs.ErrWriteProtection.Error(),
   377  		},
   378  		"set no role insufficient gas": {
   379  			caller: adminAddr,
   380  			input: func() []byte {
   381  				input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole)
   382  				require.NoError(t, err)
   383  
   384  				return input
   385  			},
   386  			suppliedGas: precompile.ModifyAllowListGasCost - 1,
   387  			readOnly:    false,
   388  			expectedErr: vmerrs.ErrOutOfGas.Error(),
   389  		},
   390  		"read allow list no role": {
   391  			caller: noRoleAddr,
   392  			input: func() []byte {
   393  				return precompile.PackReadAllowList(noRoleAddr)
   394  			},
   395  			suppliedGas: precompile.ReadAllowListGasCost,
   396  			readOnly:    false,
   397  			expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(),
   398  			assertState: nil,
   399  		},
   400  		"read allow list admin role": {
   401  			caller: adminAddr,
   402  			input: func() []byte {
   403  				return precompile.PackReadAllowList(noRoleAddr)
   404  			},
   405  			suppliedGas: precompile.ReadAllowListGasCost,
   406  			readOnly:    false,
   407  			expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(),
   408  			assertState: nil,
   409  		},
   410  		"read allow list with readOnly enabled": {
   411  			caller: adminAddr,
   412  			input: func() []byte {
   413  				return precompile.PackReadAllowList(noRoleAddr)
   414  			},
   415  			suppliedGas: precompile.ReadAllowListGasCost,
   416  			readOnly:    true,
   417  			expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(),
   418  			assertState: nil,
   419  		},
   420  		"read allow list out of gas": {
   421  			caller: adminAddr,
   422  			input: func() []byte {
   423  				return precompile.PackReadAllowList(noRoleAddr)
   424  			},
   425  			suppliedGas: precompile.ReadAllowListGasCost - 1,
   426  			readOnly:    true,
   427  			expectedErr: vmerrs.ErrOutOfGas.Error(),
   428  		},
   429  	} {
   430  		t.Run(name, func(t *testing.T) {
   431  			db := rawdb.NewMemoryDatabase()
   432  			state, err := state.New(common.Hash{}, state.NewDatabase(db), nil)
   433  			require.NoError(t, err)
   434  
   435  			// Set up the state so that each address has the expected permissions at the start.
   436  			precompile.SetTxAllowListStatus(state, adminAddr, precompile.AllowListAdmin)
   437  			require.Equal(t, precompile.AllowListAdmin, precompile.GetTxAllowListStatus(state, adminAddr))
   438  
   439  			blockContext := &mockBlockContext{blockNumber: common.Big0}
   440  			ret, remainingGas, err := precompile.TxAllowListPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.TxAllowListAddress, test.input(), test.suppliedGas, test.readOnly)
   441  			if len(test.expectedErr) != 0 {
   442  				require.ErrorContains(t, err, test.expectedErr)
   443  			} else {
   444  				require.NoError(t, err)
   445  			}
   446  
   447  			require.Equal(t, uint64(0), remainingGas)
   448  			require.Equal(t, test.expectedRes, ret)
   449  
   450  			if test.assertState != nil {
   451  				test.assertState(t, state)
   452  			}
   453  		})
   454  	}
   455  }
   456  
   457  func TestContractNativeMinterRun(t *testing.T) {
   458  	type test struct {
   459  		caller      common.Address
   460  		input       func() []byte
   461  		suppliedGas uint64
   462  		readOnly    bool
   463  		config      *precompile.ContractNativeMinterConfig
   464  
   465  		expectedRes []byte
   466  		expectedErr string
   467  
   468  		assertState func(t *testing.T, state *state.StateDB)
   469  	}
   470  
   471  	adminAddr := common.HexToAddress("0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC")
   472  	enabledAddr := common.HexToAddress("0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B")
   473  	noRoleAddr := common.HexToAddress("0xF60C45c607D0f41687c94C314d300f483661E13a")
   474  	testAddr := common.HexToAddress("0x123456789")
   475  
   476  	for name, test := range map[string]test{
   477  		"mint funds from no role fails": {
   478  			caller: noRoleAddr,
   479  			input: func() []byte {
   480  				input, err := precompile.PackMintInput(noRoleAddr, common.Big1)
   481  				require.NoError(t, err)
   482  
   483  				return input
   484  			},
   485  			suppliedGas: precompile.MintGasCost,
   486  			readOnly:    false,
   487  			expectedErr: precompile.ErrCannotMint.Error(),
   488  		},
   489  		"mint funds from enabled address": {
   490  			caller: enabledAddr,
   491  			input: func() []byte {
   492  				input, err := precompile.PackMintInput(enabledAddr, common.Big1)
   493  				require.NoError(t, err)
   494  
   495  				return input
   496  			},
   497  			suppliedGas: precompile.MintGasCost,
   498  			readOnly:    false,
   499  			expectedRes: []byte{},
   500  			assertState: func(t *testing.T, state *state.StateDB) {
   501  				require.Equal(t, common.Big1, state.GetBalance(enabledAddr), "expected minted funds")
   502  			},
   503  		},
   504  		"enabled role by config": {
   505  			caller: noRoleAddr,
   506  			input: func() []byte {
   507  				return precompile.PackReadAllowList(testAddr)
   508  			},
   509  			suppliedGas: precompile.ReadAllowListGasCost,
   510  			readOnly:    false,
   511  			expectedRes: common.Hash(precompile.AllowListEnabled).Bytes(),
   512  			assertState: func(t *testing.T, state *state.StateDB) {
   513  				require.Equal(t, precompile.AllowListEnabled, precompile.GetContractNativeMinterStatus(state, testAddr))
   514  			},
   515  			config: &precompile.ContractNativeMinterConfig{
   516  				AllowListConfig: precompile.AllowListConfig{EnabledAddresses: []common.Address{testAddr}},
   517  			},
   518  		},
   519  		"initial mint funds": {
   520  			caller: enabledAddr,
   521  			config: &precompile.ContractNativeMinterConfig{
   522  				InitialMint: map[common.Address]*math.HexOrDecimal256{
   523  					enabledAddr: math.NewHexOrDecimal256(2),
   524  				},
   525  			},
   526  			input: func() []byte {
   527  				return precompile.PackReadAllowList(noRoleAddr)
   528  			},
   529  			suppliedGas: precompile.ReadAllowListGasCost,
   530  			readOnly:    false,
   531  			expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(),
   532  			assertState: func(t *testing.T, state *state.StateDB) {
   533  				require.Equal(t, common.Big2, state.GetBalance(enabledAddr), "expected minted funds")
   534  			},
   535  		},
   536  		"mint funds from admin address": {
   537  			caller: adminAddr,
   538  			input: func() []byte {
   539  				input, err := precompile.PackMintInput(adminAddr, common.Big1)
   540  				require.NoError(t, err)
   541  
   542  				return input
   543  			},
   544  			suppliedGas: precompile.MintGasCost,
   545  			readOnly:    false,
   546  			expectedRes: []byte{},
   547  			assertState: func(t *testing.T, state *state.StateDB) {
   548  				require.Equal(t, common.Big1, state.GetBalance(adminAddr), "expected minted funds")
   549  			},
   550  		},
   551  		"mint max big funds": {
   552  			caller: adminAddr,
   553  			input: func() []byte {
   554  				input, err := precompile.PackMintInput(adminAddr, math.MaxBig256)
   555  				require.NoError(t, err)
   556  
   557  				return input
   558  			},
   559  			suppliedGas: precompile.MintGasCost,
   560  			readOnly:    false,
   561  			expectedRes: []byte{},
   562  			assertState: func(t *testing.T, state *state.StateDB) {
   563  				require.Equal(t, math.MaxBig256, state.GetBalance(adminAddr), "expected minted funds")
   564  			},
   565  		},
   566  		"readOnly mint with noRole fails": {
   567  			caller: noRoleAddr,
   568  			input: func() []byte {
   569  				input, err := precompile.PackMintInput(adminAddr, common.Big1)
   570  				require.NoError(t, err)
   571  
   572  				return input
   573  			},
   574  			suppliedGas: precompile.MintGasCost,
   575  			readOnly:    true,
   576  			expectedErr: vmerrs.ErrWriteProtection.Error(),
   577  		},
   578  		"readOnly mint with allow role fails": {
   579  			caller: enabledAddr,
   580  			input: func() []byte {
   581  				input, err := precompile.PackMintInput(enabledAddr, common.Big1)
   582  				require.NoError(t, err)
   583  
   584  				return input
   585  			},
   586  			suppliedGas: precompile.MintGasCost,
   587  			readOnly:    true,
   588  			expectedErr: vmerrs.ErrWriteProtection.Error(),
   589  		},
   590  		"readOnly mint with admin role fails": {
   591  			caller: adminAddr,
   592  			input: func() []byte {
   593  				input, err := precompile.PackMintInput(adminAddr, common.Big1)
   594  				require.NoError(t, err)
   595  
   596  				return input
   597  			},
   598  			suppliedGas: precompile.MintGasCost,
   599  			readOnly:    true,
   600  			expectedErr: vmerrs.ErrWriteProtection.Error(),
   601  		},
   602  		"insufficient gas mint from admin": {
   603  			caller: adminAddr,
   604  			input: func() []byte {
   605  				input, err := precompile.PackMintInput(enabledAddr, common.Big1)
   606  				require.NoError(t, err)
   607  
   608  				return input
   609  			},
   610  			suppliedGas: precompile.MintGasCost - 1,
   611  			readOnly:    false,
   612  			expectedErr: vmerrs.ErrOutOfGas.Error(),
   613  		},
   614  		"read from noRole address": {
   615  			caller: noRoleAddr,
   616  			input: func() []byte {
   617  				return precompile.PackReadAllowList(noRoleAddr)
   618  			},
   619  			suppliedGas: precompile.ReadAllowListGasCost,
   620  			readOnly:    false,
   621  			expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(),
   622  			assertState: func(t *testing.T, state *state.StateDB) {},
   623  		},
   624  		"read from noRole address readOnly enabled": {
   625  			caller: noRoleAddr,
   626  			input: func() []byte {
   627  				return precompile.PackReadAllowList(noRoleAddr)
   628  			},
   629  			suppliedGas: precompile.ReadAllowListGasCost,
   630  			readOnly:    true,
   631  			expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(),
   632  			assertState: func(t *testing.T, state *state.StateDB) {},
   633  		},
   634  		"read from noRole address with insufficient gas": {
   635  			caller: noRoleAddr,
   636  			input: func() []byte {
   637  				return precompile.PackReadAllowList(noRoleAddr)
   638  			},
   639  			suppliedGas: precompile.ReadAllowListGasCost - 1,
   640  			readOnly:    false,
   641  			expectedErr: vmerrs.ErrOutOfGas.Error(),
   642  		},
   643  		"set allow role from admin": {
   644  			caller: adminAddr,
   645  			input: func() []byte {
   646  				input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled)
   647  				require.NoError(t, err)
   648  
   649  				return input
   650  			},
   651  			suppliedGas: precompile.ModifyAllowListGasCost,
   652  			readOnly:    false,
   653  			expectedRes: []byte{},
   654  			assertState: func(t *testing.T, state *state.StateDB) {
   655  				res := precompile.GetContractNativeMinterStatus(state, noRoleAddr)
   656  				require.Equal(t, precompile.AllowListEnabled, res)
   657  			},
   658  		},
   659  		"set allow role from non-admin fails": {
   660  			caller: enabledAddr,
   661  			input: func() []byte {
   662  				input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled)
   663  				require.NoError(t, err)
   664  
   665  				return input
   666  			},
   667  			suppliedGas: precompile.ModifyAllowListGasCost,
   668  			readOnly:    false,
   669  			expectedErr: precompile.ErrCannotModifyAllowList.Error(),
   670  		},
   671  	} {
   672  		t.Run(name, func(t *testing.T) {
   673  			db := rawdb.NewMemoryDatabase()
   674  			state, err := state.New(common.Hash{}, state.NewDatabase(db), nil)
   675  			require.NoError(t, err)
   676  
   677  			// Set up the state so that each address has the expected permissions at the start.
   678  			precompile.SetContractNativeMinterStatus(state, adminAddr, precompile.AllowListAdmin)
   679  			precompile.SetContractNativeMinterStatus(state, enabledAddr, precompile.AllowListEnabled)
   680  			precompile.SetContractNativeMinterStatus(state, noRoleAddr, precompile.AllowListNoRole)
   681  			require.Equal(t, precompile.AllowListAdmin, precompile.GetContractNativeMinterStatus(state, adminAddr))
   682  			require.Equal(t, precompile.AllowListEnabled, precompile.GetContractNativeMinterStatus(state, enabledAddr))
   683  			require.Equal(t, precompile.AllowListNoRole, precompile.GetContractNativeMinterStatus(state, noRoleAddr))
   684  
   685  			blockContext := &mockBlockContext{blockNumber: common.Big0}
   686  			if test.config != nil {
   687  				test.config.Configure(params.TestChainConfig, state, blockContext)
   688  			}
   689  			ret, remainingGas, err := precompile.ContractNativeMinterPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.ContractNativeMinterAddress, test.input(), test.suppliedGas, test.readOnly)
   690  			if len(test.expectedErr) != 0 {
   691  				require.ErrorContains(t, err, test.expectedErr)
   692  			} else {
   693  				require.NoError(t, err)
   694  			}
   695  
   696  			require.Equal(t, uint64(0), remainingGas)
   697  			require.Equal(t, test.expectedRes, ret)
   698  
   699  			if test.assertState != nil {
   700  				test.assertState(t, state)
   701  			}
   702  		})
   703  	}
   704  }
   705  
   706  func TestFeeConfigManagerRun(t *testing.T) {
   707  	type test struct {
   708  		caller       common.Address
   709  		preCondition func(t *testing.T, state *state.StateDB)
   710  		input        func() []byte
   711  		suppliedGas  uint64
   712  		readOnly     bool
   713  		config       *precompile.FeeConfigManagerConfig
   714  
   715  		expectedRes []byte
   716  		expectedErr string
   717  
   718  		assertState func(t *testing.T, state *state.StateDB)
   719  	}
   720  
   721  	adminAddr := common.HexToAddress("0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC")
   722  	enabledAddr := common.HexToAddress("0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B")
   723  	noRoleAddr := common.HexToAddress("0xF60C45c607D0f41687c94C314d300f483661E13a")
   724  
   725  	for name, test := range map[string]test{
   726  		"set config from no role fails": {
   727  			caller: noRoleAddr,
   728  			input: func() []byte {
   729  				input, err := precompile.PackSetFeeConfig(testFeeConfig)
   730  				require.NoError(t, err)
   731  
   732  				return input
   733  			},
   734  			suppliedGas: precompile.SetFeeConfigGasCost,
   735  			readOnly:    false,
   736  			expectedErr: precompile.ErrCannotChangeFee.Error(),
   737  		},
   738  		"set config from enabled address": {
   739  			caller: enabledAddr,
   740  			input: func() []byte {
   741  				input, err := precompile.PackSetFeeConfig(testFeeConfig)
   742  				require.NoError(t, err)
   743  
   744  				return input
   745  			},
   746  			suppliedGas: precompile.SetFeeConfigGasCost,
   747  			readOnly:    false,
   748  			expectedRes: []byte{},
   749  			assertState: func(t *testing.T, state *state.StateDB) {
   750  				feeConfig := precompile.GetStoredFeeConfig(state)
   751  				require.Equal(t, testFeeConfig, feeConfig)
   752  			},
   753  		},
   754  		"set invalid config from enabled address": {
   755  			caller: enabledAddr,
   756  			input: func() []byte {
   757  				feeConfig := testFeeConfig
   758  				feeConfig.MinBlockGasCost = new(big.Int).Mul(feeConfig.MaxBlockGasCost, common.Big2)
   759  				input, err := precompile.PackSetFeeConfig(feeConfig)
   760  				require.NoError(t, err)
   761  
   762  				return input
   763  			},
   764  			suppliedGas: precompile.SetFeeConfigGasCost,
   765  			readOnly:    false,
   766  			expectedRes: nil,
   767  			config: &precompile.FeeConfigManagerConfig{
   768  				InitialFeeConfig: &testFeeConfig,
   769  			},
   770  			expectedErr: "cannot be greater than maxBlockGasCost",
   771  			assertState: func(t *testing.T, state *state.StateDB) {
   772  				feeConfig := precompile.GetStoredFeeConfig(state)
   773  				require.Equal(t, testFeeConfig, feeConfig)
   774  			},
   775  		},
   776  		"set config from admin address": {
   777  			caller: adminAddr,
   778  			input: func() []byte {
   779  				input, err := precompile.PackSetFeeConfig(testFeeConfig)
   780  				require.NoError(t, err)
   781  
   782  				return input
   783  			},
   784  			suppliedGas: precompile.SetFeeConfigGasCost,
   785  			readOnly:    false,
   786  			expectedRes: []byte{},
   787  			assertState: func(t *testing.T, state *state.StateDB) {
   788  				feeConfig := precompile.GetStoredFeeConfig(state)
   789  				require.Equal(t, testFeeConfig, feeConfig)
   790  				lastChangedAt := precompile.GetFeeConfigLastChangedAt(state)
   791  				require.EqualValues(t, testBlockNumber, lastChangedAt)
   792  			},
   793  		},
   794  		"get fee config from non-enabled address": {
   795  			caller: noRoleAddr,
   796  			preCondition: func(t *testing.T, state *state.StateDB) {
   797  				err := precompile.StoreFeeConfig(state, testFeeConfig, &mockBlockContext{blockNumber: big.NewInt(6)})
   798  				require.NoError(t, err)
   799  			},
   800  			input: func() []byte {
   801  				return precompile.PackGetFeeConfigInput()
   802  			},
   803  			suppliedGas: precompile.GetFeeConfigGasCost,
   804  			readOnly:    true,
   805  			expectedRes: func() []byte {
   806  				res, err := precompile.PackFeeConfig(testFeeConfig)
   807  				require.NoError(t, err)
   808  				return res
   809  			}(),
   810  			assertState: func(t *testing.T, state *state.StateDB) {
   811  				feeConfig := precompile.GetStoredFeeConfig(state)
   812  				lastChangedAt := precompile.GetFeeConfigLastChangedAt(state)
   813  				require.Equal(t, testFeeConfig, feeConfig)
   814  				require.EqualValues(t, big.NewInt(6), lastChangedAt)
   815  			},
   816  		},
   817  		"get initial fee config": {
   818  			caller: noRoleAddr,
   819  			input: func() []byte {
   820  				return precompile.PackGetFeeConfigInput()
   821  			},
   822  			suppliedGas: precompile.GetFeeConfigGasCost,
   823  			config: &precompile.FeeConfigManagerConfig{
   824  				InitialFeeConfig: &testFeeConfig,
   825  			},
   826  			readOnly: true,
   827  			expectedRes: func() []byte {
   828  				res, err := precompile.PackFeeConfig(testFeeConfig)
   829  				require.NoError(t, err)
   830  				return res
   831  			}(),
   832  			assertState: func(t *testing.T, state *state.StateDB) {
   833  				feeConfig := precompile.GetStoredFeeConfig(state)
   834  				lastChangedAt := precompile.GetFeeConfigLastChangedAt(state)
   835  				require.Equal(t, testFeeConfig, feeConfig)
   836  				require.EqualValues(t, testBlockNumber, lastChangedAt)
   837  			},
   838  		},
   839  		"get last changed at from non-enabled address": {
   840  			caller: noRoleAddr,
   841  			preCondition: func(t *testing.T, state *state.StateDB) {
   842  				err := precompile.StoreFeeConfig(state, testFeeConfig, &mockBlockContext{blockNumber: testBlockNumber})
   843  				require.NoError(t, err)
   844  			},
   845  			input: func() []byte {
   846  				return precompile.PackGetLastChangedAtInput()
   847  			},
   848  			suppliedGas: precompile.GetLastChangedAtGasCost,
   849  			readOnly:    true,
   850  			expectedRes: common.BigToHash(testBlockNumber).Bytes(),
   851  			assertState: func(t *testing.T, state *state.StateDB) {
   852  				feeConfig := precompile.GetStoredFeeConfig(state)
   853  				lastChangedAt := precompile.GetFeeConfigLastChangedAt(state)
   854  				require.Equal(t, testFeeConfig, feeConfig)
   855  				require.Equal(t, testBlockNumber, lastChangedAt)
   856  			},
   857  		},
   858  		"readOnly setFeeConfig with noRole fails": {
   859  			caller: noRoleAddr,
   860  			input: func() []byte {
   861  				input, err := precompile.PackSetFeeConfig(testFeeConfig)
   862  				require.NoError(t, err)
   863  
   864  				return input
   865  			},
   866  			suppliedGas: precompile.SetFeeConfigGasCost,
   867  			readOnly:    true,
   868  			expectedErr: vmerrs.ErrWriteProtection.Error(),
   869  		},
   870  		"readOnly setFeeConfig with allow role fails": {
   871  			caller: enabledAddr,
   872  			input: func() []byte {
   873  				input, err := precompile.PackSetFeeConfig(testFeeConfig)
   874  				require.NoError(t, err)
   875  
   876  				return input
   877  			},
   878  			suppliedGas: precompile.SetFeeConfigGasCost,
   879  			readOnly:    true,
   880  			expectedErr: vmerrs.ErrWriteProtection.Error(),
   881  		},
   882  		"readOnly setFeeConfig with admin role fails": {
   883  			caller: adminAddr,
   884  			input: func() []byte {
   885  				input, err := precompile.PackSetFeeConfig(testFeeConfig)
   886  				require.NoError(t, err)
   887  
   888  				return input
   889  			},
   890  			suppliedGas: precompile.SetFeeConfigGasCost,
   891  			readOnly:    true,
   892  			expectedErr: vmerrs.ErrWriteProtection.Error(),
   893  		},
   894  		"insufficient gas setFeeConfig from admin": {
   895  			caller: adminAddr,
   896  			input: func() []byte {
   897  				input, err := precompile.PackSetFeeConfig(testFeeConfig)
   898  				require.NoError(t, err)
   899  
   900  				return input
   901  			},
   902  			suppliedGas: precompile.SetFeeConfigGasCost - 1,
   903  			readOnly:    false,
   904  			expectedErr: vmerrs.ErrOutOfGas.Error(),
   905  		},
   906  		"set allow role from admin": {
   907  			caller: adminAddr,
   908  			input: func() []byte {
   909  				input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled)
   910  				require.NoError(t, err)
   911  
   912  				return input
   913  			},
   914  			suppliedGas: precompile.ModifyAllowListGasCost,
   915  			readOnly:    false,
   916  			expectedRes: []byte{},
   917  			assertState: func(t *testing.T, state *state.StateDB) {
   918  				res := precompile.GetFeeConfigManagerStatus(state, noRoleAddr)
   919  				require.Equal(t, precompile.AllowListEnabled, res)
   920  			},
   921  		},
   922  		"set allow role from non-admin fails": {
   923  			caller: enabledAddr,
   924  			input: func() []byte {
   925  				input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled)
   926  				require.NoError(t, err)
   927  
   928  				return input
   929  			},
   930  			suppliedGas: precompile.ModifyAllowListGasCost,
   931  			readOnly:    false,
   932  			expectedErr: precompile.ErrCannotModifyAllowList.Error(),
   933  		},
   934  	} {
   935  		t.Run(name, func(t *testing.T) {
   936  			db := rawdb.NewMemoryDatabase()
   937  			state, err := state.New(common.Hash{}, state.NewDatabase(db), nil)
   938  			require.NoError(t, err)
   939  
   940  			// Set up the state so that each address has the expected permissions at the start.
   941  			precompile.SetFeeConfigManagerStatus(state, adminAddr, precompile.AllowListAdmin)
   942  			precompile.SetFeeConfigManagerStatus(state, enabledAddr, precompile.AllowListEnabled)
   943  			precompile.SetFeeConfigManagerStatus(state, noRoleAddr, precompile.AllowListNoRole)
   944  
   945  			if test.preCondition != nil {
   946  				test.preCondition(t, state)
   947  			}
   948  
   949  			blockContext := &mockBlockContext{blockNumber: testBlockNumber}
   950  			if test.config != nil {
   951  				test.config.Configure(params.TestChainConfig, state, blockContext)
   952  			}
   953  			ret, remainingGas, err := precompile.FeeConfigManagerPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.FeeConfigManagerAddress, test.input(), test.suppliedGas, test.readOnly)
   954  			if len(test.expectedErr) != 0 {
   955  				require.ErrorContains(t, err, test.expectedErr)
   956  			} else {
   957  				require.NoError(t, err)
   958  			}
   959  
   960  			require.Equal(t, uint64(0), remainingGas)
   961  			require.Equal(t, test.expectedRes, ret)
   962  
   963  			if test.assertState != nil {
   964  				test.assertState(t, state)
   965  			}
   966  		})
   967  	}
   968  }
   969  
   970  func TestRewardManagerRun(t *testing.T) {
   971  	type test struct {
   972  		caller       common.Address
   973  		preCondition func(t *testing.T, state *state.StateDB)
   974  		input        func() []byte
   975  		suppliedGas  uint64
   976  		readOnly     bool
   977  		config       *precompile.RewardManagerConfig
   978  
   979  		expectedRes []byte
   980  		expectedErr string
   981  
   982  		assertState func(t *testing.T, state *state.StateDB)
   983  	}
   984  
   985  	adminAddr := common.HexToAddress("0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC")
   986  	enabledAddr := common.HexToAddress("0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B")
   987  	noRoleAddr := common.HexToAddress("0xF60C45c607D0f41687c94C314d300f483661E13a")
   988  	testAddr := common.HexToAddress("0x0123")
   989  
   990  	for name, test := range map[string]test{
   991  		"set allow fee recipients from no role fails": {
   992  			caller: noRoleAddr,
   993  			input: func() []byte {
   994  				input, err := precompile.PackAllowFeeRecipients()
   995  				require.NoError(t, err)
   996  
   997  				return input
   998  			},
   999  			suppliedGas: precompile.AllowFeeRecipientsGasCost,
  1000  			readOnly:    false,
  1001  			expectedErr: precompile.ErrCannotAllowFeeRecipients.Error(),
  1002  		},
  1003  		"set reward address from no role fails": {
  1004  			caller: noRoleAddr,
  1005  			input: func() []byte {
  1006  				input, err := precompile.PackSetRewardAddress(testAddr)
  1007  				require.NoError(t, err)
  1008  
  1009  				return input
  1010  			},
  1011  			suppliedGas: precompile.SetRewardAddressGasCost,
  1012  			readOnly:    false,
  1013  			expectedErr: precompile.ErrCannotSetRewardAddress.Error(),
  1014  		},
  1015  		"disable rewards from no role fails": {
  1016  			caller: noRoleAddr,
  1017  			input: func() []byte {
  1018  				input, err := precompile.PackDisableRewards()
  1019  				require.NoError(t, err)
  1020  
  1021  				return input
  1022  			},
  1023  			suppliedGas: precompile.DisableRewardsGasCost,
  1024  			readOnly:    false,
  1025  			expectedErr: precompile.ErrCannotDisableRewards.Error(),
  1026  		},
  1027  		"set allow fee recipients from enabled succeeds": {
  1028  			caller: enabledAddr,
  1029  			input: func() []byte {
  1030  				input, err := precompile.PackAllowFeeRecipients()
  1031  				require.NoError(t, err)
  1032  
  1033  				return input
  1034  			},
  1035  			suppliedGas: precompile.AllowFeeRecipientsGasCost,
  1036  			readOnly:    false,
  1037  			expectedRes: []byte{},
  1038  			assertState: func(t *testing.T, state *state.StateDB) {
  1039  				_, isFeeRecipients := precompile.GetStoredRewardAddress(state)
  1040  				require.True(t, isFeeRecipients)
  1041  			},
  1042  		},
  1043  		"set reward address from enabled succeeds": {
  1044  			caller: enabledAddr,
  1045  			input: func() []byte {
  1046  				input, err := precompile.PackSetRewardAddress(testAddr)
  1047  				require.NoError(t, err)
  1048  
  1049  				return input
  1050  			},
  1051  			suppliedGas: precompile.SetRewardAddressGasCost,
  1052  			readOnly:    false,
  1053  			expectedRes: []byte{},
  1054  			assertState: func(t *testing.T, state *state.StateDB) {
  1055  				address, isFeeRecipients := precompile.GetStoredRewardAddress(state)
  1056  				require.Equal(t, testAddr, address)
  1057  				require.False(t, isFeeRecipients)
  1058  			},
  1059  		},
  1060  		"disable rewards from enabled succeeds": {
  1061  			caller: enabledAddr,
  1062  			input: func() []byte {
  1063  				input, err := precompile.PackDisableRewards()
  1064  				require.NoError(t, err)
  1065  
  1066  				return input
  1067  			},
  1068  			suppliedGas: precompile.DisableRewardsGasCost,
  1069  			readOnly:    false,
  1070  			expectedRes: []byte{},
  1071  			assertState: func(t *testing.T, state *state.StateDB) {
  1072  				address, isFeeRecipients := precompile.GetStoredRewardAddress(state)
  1073  				require.False(t, isFeeRecipients)
  1074  				require.Equal(t, constants.BlackholeAddr, address)
  1075  			},
  1076  		},
  1077  		"get current reward address from no role succeeds": {
  1078  			caller: noRoleAddr,
  1079  			preCondition: func(t *testing.T, state *state.StateDB) {
  1080  				precompile.StoreRewardAddress(state, testAddr)
  1081  			},
  1082  			input: func() []byte {
  1083  				input, err := precompile.PackCurrentRewardAddress()
  1084  				require.NoError(t, err)
  1085  
  1086  				return input
  1087  			},
  1088  			suppliedGas: precompile.CurrentRewardAddressGasCost,
  1089  			readOnly:    false,
  1090  			expectedRes: func() []byte {
  1091  				res, err := precompile.PackCurrentRewardAddressOutput(testAddr)
  1092  				require.NoError(t, err)
  1093  				return res
  1094  			}(),
  1095  		},
  1096  		"get are fee recipients allowed from no role succeeds": {
  1097  			caller: noRoleAddr,
  1098  			preCondition: func(t *testing.T, state *state.StateDB) {
  1099  				precompile.EnableAllowFeeRecipients(state)
  1100  			},
  1101  			input: func() []byte {
  1102  				input, err := precompile.PackAreFeeRecipientsAllowed()
  1103  				require.NoError(t, err)
  1104  				return input
  1105  			},
  1106  			suppliedGas: precompile.AreFeeRecipientsAllowedGasCost,
  1107  			readOnly:    false,
  1108  			expectedRes: func() []byte {
  1109  				res, err := precompile.PackAreFeeRecipientsAllowedOutput(true)
  1110  				require.NoError(t, err)
  1111  				return res
  1112  			}(),
  1113  		},
  1114  		"get initial config with address": {
  1115  			caller: noRoleAddr,
  1116  			input: func() []byte {
  1117  				input, err := precompile.PackCurrentRewardAddress()
  1118  				require.NoError(t, err)
  1119  				return input
  1120  			},
  1121  			suppliedGas: precompile.CurrentRewardAddressGasCost,
  1122  			config: &precompile.RewardManagerConfig{
  1123  				InitialRewardConfig: &precompile.InitialRewardConfig{
  1124  					RewardAddress: testAddr,
  1125  				},
  1126  			},
  1127  			readOnly: false,
  1128  			expectedRes: func() []byte {
  1129  				res, err := precompile.PackCurrentRewardAddressOutput(testAddr)
  1130  				require.NoError(t, err)
  1131  				return res
  1132  			}(),
  1133  		},
  1134  		"get initial config with allow fee recipients enabled": {
  1135  			caller: noRoleAddr,
  1136  			input: func() []byte {
  1137  				input, err := precompile.PackAreFeeRecipientsAllowed()
  1138  				require.NoError(t, err)
  1139  				return input
  1140  			},
  1141  			suppliedGas: precompile.AreFeeRecipientsAllowedGasCost,
  1142  			config: &precompile.RewardManagerConfig{
  1143  				InitialRewardConfig: &precompile.InitialRewardConfig{
  1144  					AllowFeeRecipients: true,
  1145  				},
  1146  			},
  1147  			readOnly: false,
  1148  			expectedRes: func() []byte {
  1149  				res, err := precompile.PackAreFeeRecipientsAllowedOutput(true)
  1150  				require.NoError(t, err)
  1151  				return res
  1152  			}(),
  1153  		},
  1154  		"readOnly allow fee recipients with allowed role fails": {
  1155  			caller: enabledAddr,
  1156  			input: func() []byte {
  1157  				input, err := precompile.PackAllowFeeRecipients()
  1158  				require.NoError(t, err)
  1159  
  1160  				return input
  1161  			},
  1162  			suppliedGas: precompile.AllowFeeRecipientsGasCost,
  1163  			readOnly:    true,
  1164  			expectedErr: vmerrs.ErrWriteProtection.Error(),
  1165  		},
  1166  		"readOnly set reward addresss with allowed role fails": {
  1167  			caller: enabledAddr,
  1168  			input: func() []byte {
  1169  				input, err := precompile.PackSetRewardAddress(testAddr)
  1170  				require.NoError(t, err)
  1171  
  1172  				return input
  1173  			},
  1174  			suppliedGas: precompile.SetRewardAddressGasCost,
  1175  			readOnly:    true,
  1176  			expectedErr: vmerrs.ErrWriteProtection.Error(),
  1177  		},
  1178  		"insufficient gas set reward address from allowed role": {
  1179  			caller: enabledAddr,
  1180  			input: func() []byte {
  1181  				input, err := precompile.PackSetRewardAddress(testAddr)
  1182  				require.NoError(t, err)
  1183  
  1184  				return input
  1185  			},
  1186  			suppliedGas: precompile.SetRewardAddressGasCost - 1,
  1187  			readOnly:    false,
  1188  			expectedErr: vmerrs.ErrOutOfGas.Error(),
  1189  		},
  1190  		"insufficient gas allow fee recipients from allowed role": {
  1191  			caller: enabledAddr,
  1192  			input: func() []byte {
  1193  				input, err := precompile.PackAllowFeeRecipients()
  1194  				require.NoError(t, err)
  1195  
  1196  				return input
  1197  			},
  1198  			suppliedGas: precompile.AllowFeeRecipientsGasCost - 1,
  1199  			readOnly:    false,
  1200  			expectedErr: vmerrs.ErrOutOfGas.Error(),
  1201  		},
  1202  		"insufficient gas read current reward address from allowed role": {
  1203  			caller: enabledAddr,
  1204  			input: func() []byte {
  1205  				input, err := precompile.PackCurrentRewardAddress()
  1206  				require.NoError(t, err)
  1207  
  1208  				return input
  1209  			},
  1210  			suppliedGas: precompile.CurrentRewardAddressGasCost - 1,
  1211  			readOnly:    false,
  1212  			expectedErr: vmerrs.ErrOutOfGas.Error(),
  1213  		},
  1214  		"insufficient gas are fee recipients allowed from allowed role": {
  1215  			caller: enabledAddr,
  1216  			input: func() []byte {
  1217  				input, err := precompile.PackAreFeeRecipientsAllowed()
  1218  				require.NoError(t, err)
  1219  
  1220  				return input
  1221  			},
  1222  			suppliedGas: precompile.AreFeeRecipientsAllowedGasCost - 1,
  1223  			readOnly:    false,
  1224  			expectedErr: vmerrs.ErrOutOfGas.Error(),
  1225  		},
  1226  		"set allow role from admin": {
  1227  			caller: adminAddr,
  1228  			input: func() []byte {
  1229  				input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled)
  1230  				require.NoError(t, err)
  1231  
  1232  				return input
  1233  			},
  1234  			suppliedGas: precompile.ModifyAllowListGasCost,
  1235  			readOnly:    false,
  1236  			expectedRes: []byte{},
  1237  			assertState: func(t *testing.T, state *state.StateDB) {
  1238  				res := precompile.GetRewardManagerAllowListStatus(state, noRoleAddr)
  1239  				require.Equal(t, precompile.AllowListEnabled, res)
  1240  			},
  1241  		},
  1242  		"set allow role from non-admin fails": {
  1243  			caller: enabledAddr,
  1244  			input: func() []byte {
  1245  				input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled)
  1246  				require.NoError(t, err)
  1247  
  1248  				return input
  1249  			},
  1250  			suppliedGas: precompile.ModifyAllowListGasCost,
  1251  			readOnly:    false,
  1252  			expectedErr: precompile.ErrCannotModifyAllowList.Error(),
  1253  		},
  1254  	} {
  1255  		t.Run(name, func(t *testing.T) {
  1256  			db := rawdb.NewMemoryDatabase()
  1257  			state, err := state.New(common.Hash{}, state.NewDatabase(db), nil)
  1258  			require.NoError(t, err)
  1259  
  1260  			// Set up the state so that each address has the expected permissions at the start.
  1261  			precompile.SetRewardManagerAllowListStatus(state, adminAddr, precompile.AllowListAdmin)
  1262  			precompile.SetRewardManagerAllowListStatus(state, enabledAddr, precompile.AllowListEnabled)
  1263  			precompile.SetRewardManagerAllowListStatus(state, noRoleAddr, precompile.AllowListNoRole)
  1264  
  1265  			if test.preCondition != nil {
  1266  				test.preCondition(t, state)
  1267  			}
  1268  
  1269  			blockContext := &mockBlockContext{blockNumber: testBlockNumber}
  1270  			if test.config != nil {
  1271  				test.config.Configure(params.TestChainConfig, state, blockContext)
  1272  			}
  1273  			ret, remainingGas, err := precompile.RewardManagerPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.RewardManagerAddress, test.input(), test.suppliedGas, test.readOnly)
  1274  			if len(test.expectedErr) != 0 {
  1275  				require.ErrorContains(t, err, test.expectedErr)
  1276  			} else {
  1277  				require.NoError(t, err)
  1278  			}
  1279  
  1280  			require.Equal(t, uint64(0), remainingGas)
  1281  			require.Equal(t, test.expectedRes, ret)
  1282  
  1283  			if test.assertState != nil {
  1284  				test.assertState(t, state)
  1285  			}
  1286  		})
  1287  	}
  1288  }