Skip to content

Commit

Permalink
Generalized upgrades rb nits0 (#512)
Browse files Browse the repository at this point in the history
* Minor improvements

* restore readOnly

* more updates

* Add back readOnly to allow list tests

---------

Co-authored-by: Aaron Buchwald <aaron.buchwald56@gmail.com>
  • Loading branch information
darioush and aaronbuchwald authored Feb 16, 2023
1 parent 292fd6e commit 8877388
Show file tree
Hide file tree
Showing 27 changed files with 156 additions and 181 deletions.
12 changes: 6 additions & 6 deletions core/state_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ import (
)

var (
chainConfig = params.TestChainConfig
signer = types.LatestSigner(chainConfig)
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
config = params.TestChainConfig
signer = types.LatestSigner(config)
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
)

func makeTx(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction {
Expand All @@ -71,12 +71,12 @@ func mkDynamicTx(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, ga
// blockchain imports bad blocks, meaning blocks which have valid headers but
// contain invalid transactions
func TestStateProcessorErrors(t *testing.T) {
chainConfig.FeeConfig.MinBaseFee = params.TestMaxBaseFee
config.FeeConfig.MinBaseFee = params.TestMaxBaseFee
{ // Tests against a 'recent' chain definition
var (
db = rawdb.NewMemoryDatabase()
gspec = &Genesis{
Config: chainConfig,
Config: config,
Alloc: GenesisAlloc{
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
Balance: big.NewInt(2000000000000000000), // 2 ether
Expand Down Expand Up @@ -254,7 +254,7 @@ func TestStateProcessorErrors(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
gspec = &Genesis{
Config: chainConfig,
Config: config,
Alloc: GenesisAlloc{
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
Balance: big.NewInt(1000000000000000000), // 1 ether
Expand Down
2 changes: 1 addition & 1 deletion core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ func (st *StateTransition) preCheck() error {
if st.evm.ChainConfig().IsPrecompileEnabled(txallowlist.ContractAddress, st.evm.Context.Time) {
txAllowListRole := txallowlist.GetTxAllowListStatus(st.state, st.msg.From())
if !txAllowListRole.IsEnabled() {
return fmt.Errorf("%w: %s", txallowlist.ErrSenderAddressNotAllowListed, st.msg.From())
return fmt.Errorf("%w: %s", vmerrs.ErrSenderAddressNotAllowListed, st.msg.From())
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"github.com/ava-labs/subnet-evm/params"
"github.com/ava-labs/subnet-evm/precompile/contracts/feemanager"
"github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist"
"github.com/ava-labs/subnet-evm/vmerrs"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/prque"
Expand Down Expand Up @@ -698,7 +699,7 @@ func (pool *TxPool) checkTxState(from common.Address, tx *types.Transaction) err
if pool.chainconfig.IsPrecompileEnabled(txallowlist.ContractAddress, headTimestamp) {
txAllowListRole := txallowlist.GetTxAllowListStatus(pool.currentState, from)
if !txAllowListRole.IsEnabled() {
return fmt.Errorf("%w: %s", txallowlist.ErrSenderAddressNotAllowListed, from)
return fmt.Errorf("%w: %s", vmerrs.ErrSenderAddressNotAllowListed, from)
}
}
return nil
Expand Down
3 changes: 1 addition & 2 deletions params/chain_config_precompiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ func (ccp *ChainConfigPrecompiles) UnmarshalJSON(data []byte) error {
key := module.ConfigKey
if value, ok := raw[key]; ok {
conf := module.NewConfig()
err := json.Unmarshal(value, conf)
if err != nil {
if err := json.Unmarshal(value, conf); err != nil {
return err
}
(*ccp)[key] = conf
Expand Down
10 changes: 4 additions & 6 deletions params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,7 @@ func (c *ChainConfig) UnmarshalJSON(data []byte) error {
// Alias ChainConfig to avoid recursion
type _ChainConfig ChainConfig
tmp := _ChainConfig{}
err := json.Unmarshal(data, &tmp)
if err != nil {
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}

Expand All @@ -194,14 +193,13 @@ func (c ChainConfig) MarshalJSON() ([]byte, error) {
return nil, err
}

// Marshal PrecompileUpgrade
// To include PrecompileUpgrades, we unmarshal the json representing c
// then directly add the corresponding keys to the json.
raw := make(map[string]json.RawMessage)
err = json.Unmarshal(tmp, &raw)
if err != nil {
if err := json.Unmarshal(tmp, &raw); err != nil {
return nil, err
}

// Marshal Precompiles and inline them into the JSON
for key, value := range c.GenesisPrecompiles {
conf, err := json.Marshal(value)
if err != nil {
Expand Down
9 changes: 5 additions & 4 deletions params/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ func TestConfigUnmarshalJSON(t *testing.T) {
AllowFeeRecipients: true,
})

testContractNativeMinterConfig := nativeminter.NewConfig(big.NewInt(0),
testContractNativeMinterConfig := nativeminter.NewConfig(
big.NewInt(0),
[]common.Address{common.HexToAddress("0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC")},
nil,
nil,
Expand Down Expand Up @@ -193,9 +194,9 @@ func TestConfigUnmarshalJSON(t *testing.T) {
require.Equal(rewardManagerConfig.Key(), rewardmanager.ConfigKey)
require.True(rewardManagerConfig.Equal(testRewardManagerConfig))

contractNativeMinterConfig := c.GenesisPrecompiles[nativeminter.ConfigKey]
require.Equal(contractNativeMinterConfig.Key(), nativeminter.ConfigKey)
require.True(contractNativeMinterConfig.Equal(testContractNativeMinterConfig))
nativeMinterConfig := c.GenesisPrecompiles[nativeminter.ConfigKey]
require.Equal(nativeMinterConfig.Key(), nativeminter.ConfigKey)
require.True(nativeMinterConfig.Equal(testContractNativeMinterConfig))

// Marshal and unmarshal again and check that the result is the same
marshaled, err := json.Marshal(c)
Expand Down
16 changes: 8 additions & 8 deletions params/precompile_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,19 +180,19 @@ func TestVerifyPrecompiles(t *testing.T) {
admins := []common.Address{{1}}
tests := []struct {
name string
upgrade ChainConfigPrecompiles
precompiles ChainConfigPrecompiles
expectedError string
}{
{
name: "invalid allow list config in tx allowlist",
upgrade: ChainConfigPrecompiles{
precompiles: ChainConfigPrecompiles{
txallowlist.ConfigKey: txallowlist.NewConfig(big.NewInt(3), admins, admins),
},
expectedError: "cannot set address",
},
{
name: "invalid initial fee manager config",
upgrade: ChainConfigPrecompiles{
precompiles: ChainConfigPrecompiles{
feemanager.ConfigKey: feemanager.NewConfig(big.NewInt(3), admins, nil,
&commontype.FeeConfig{
GasLimit: big.NewInt(-1),
Expand All @@ -206,7 +206,7 @@ func TestVerifyPrecompiles(t *testing.T) {
require := require.New(t)
baseConfig := *SubnetEVMDefaultChainConfig
config := &baseConfig
config.GenesisPrecompiles = tt.upgrade
config.GenesisPrecompiles = tt.precompiles

err := config.Verify()
if tt.expectedError == "" {
Expand Down Expand Up @@ -301,10 +301,10 @@ func TestPrecompileUpgradeUnmarshalJSON(t *testing.T) {
})
require.True(rewardManagerConf.Equal(testRewardManagerConfig))

contractNativeMinterConf := upgradeConfig.PrecompileUpgrades[1]
require.Equal(contractNativeMinterConf.Key(), nativeminter.ConfigKey)
testContractNativeMinterConfig := nativeminter.NewConfig(big.NewInt(1671543172), nil, nil, nil)
require.True(contractNativeMinterConf.Equal(testContractNativeMinterConfig))
nativeMinterConfig := upgradeConfig.PrecompileUpgrades[1]
require.Equal(nativeMinterConfig.Key(), nativeminter.ConfigKey)
expectedNativeMinterConfig := nativeminter.NewConfig(big.NewInt(1671543172), nil, nil, nil)
require.True(nativeMinterConfig.Equal(expectedNativeMinterConfig))

// Marshal and unmarshal again and check that the result is the same
upgradeBytes2, err := json.Marshal(upgradeConfig)
Expand Down
29 changes: 15 additions & 14 deletions params/precompile_upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ var errNoKey = errors.New("PrecompileUpgrade cannot be empty")
// PrecompileUpgrade is a helper struct embedded in UpgradeConfig.
// It is used to unmarshal the json into the correct precompile config type
// based on the key. Keys are defined in each precompile module, and registered in
// params/precompile_modules.go.
// precompile/registry/registry.go.
type PrecompileUpgrade struct {
config.Config
}

// UnmarshalJSON unmarshals the json into the correct precompile config type
// based on the key. Keys are defined in each precompile module, and registered in
// params/precompile_modules.go.
// precompile/registry/registry.go.
// Ex: {"feeManagerConfig": {...}} where "feeManagerConfig" is the key
func (u *PrecompileUpgrade) UnmarshalJSON(data []byte) error {
raw := make(map[string]json.RawMessage)
Expand All @@ -47,8 +48,7 @@ func (u *PrecompileUpgrade) UnmarshalJSON(data []byte) error {
return fmt.Errorf("unknown precompile config: %s", key)
}
config := module.NewConfig()
err := json.Unmarshal(value, config)
if err != nil {
if err := json.Unmarshal(value, config); err != nil {
return err
}
u.Config = config
Expand Down Expand Up @@ -163,13 +163,12 @@ func (c *ChainConfig) GetActivePrecompileConfig(address common.Address, blockTim
// GetActivatingPrecompileConfigs returns all upgrades configured to activate during the state transition from a block with timestamp [from]
// to a block with timestamp [to].
func (c *ChainConfig) GetActivatingPrecompileConfigs(address common.Address, from *big.Int, to *big.Int, upgrades []PrecompileUpgrade) []config.Config {
configs := make([]config.Config, 0)

// Get key from address.
module, ok := modules.GetPrecompileModuleByAddress(address)
if !ok {
return configs
return nil
}
configs := make([]config.Config, 0)
key := module.ConfigKey
// First check the embedded [upgrade] for precompiles configured
// in the genesis chain config.
Expand All @@ -191,11 +190,12 @@ func (c *ChainConfig) GetActivatingPrecompileConfigs(address common.Address, fro
}

// CheckPrecompilesCompatible checks if [precompileUpgrades] are compatible with [c] at [headTimestamp].
// Returns a ConfigCompatError if upgrades already forked at [headTimestamp] are missing from
// [precompileUpgrades]. Upgrades not already forked may be modified or absent from [precompileUpgrades].
// Returns a ConfigCompatError if upgrades already activated at [headTimestamp] are missing from
// [precompileUpgrades]. Upgrades not already activated may be modified or absent from [precompileUpgrades].
// Returns nil if [precompileUpgrades] is compatible with [c].
// Assumes given timestamp is the last accepted block timestamp.
// This ensures that as long as the node has not accepted a block with a different rule set it will allow a new upgrade to be applied as long as it activates after the last accepted block.
// This ensures that as long as the node has not accepted a block with a different rule set it will allow a
// new upgrade to be applied as long as it activates after the last accepted block.
func (c *ChainConfig) CheckPrecompilesCompatible(precompileUpgrades []PrecompileUpgrade, lastTimestamp *big.Int) *ConfigCompatError {
for _, module := range modules.RegisteredModules() {
if err := c.checkPrecompileCompatible(module.Address, precompileUpgrades, lastTimestamp); err != nil {
Expand All @@ -206,15 +206,16 @@ func (c *ChainConfig) CheckPrecompilesCompatible(precompileUpgrades []Precompile
return nil
}

// checkPrecompileCompatible verifies that the precompile specified by [address] is compatible between [c] and [precompileUpgrades] at [headTimestamp].
// Returns an error if upgrades already forked at [headTimestamp] are missing from [precompileUpgrades].
// checkPrecompileCompatible verifies that the precompile specified by [address] is compatible between [c]
// and [precompileUpgrades] at [headTimestamp].
// Returns an error if upgrades already activated at [headTimestamp] are missing from [precompileUpgrades].
// Upgrades that have already gone into effect cannot be modified or absent from [precompileUpgrades].
func (c *ChainConfig) checkPrecompileCompatible(address common.Address, precompileUpgrades []PrecompileUpgrade, lastTimestamp *big.Int) *ConfigCompatError {
// all active upgrades must match
// All active upgrades (from nil to [lastTimestamp]) must match.
activeUpgrades := c.GetActivatingPrecompileConfigs(address, nil, lastTimestamp, c.PrecompileUpgrades)
newUpgrades := c.GetActivatingPrecompileConfigs(address, nil, lastTimestamp, precompileUpgrades)

// first, check existing upgrades are there
// Check activated upgrades are still present.
for i, upgrade := range activeUpgrades {
if len(newUpgrades) <= i {
// missing upgrade
Expand All @@ -224,7 +225,7 @@ func (c *ChainConfig) checkPrecompileCompatible(address common.Address, precompi
nil,
)
}
// All upgrades that have forked must be identical.
// All upgrades that have activated must be identical.
if !upgrade.Equal(newUpgrades[i]) {
return newCompatError(
fmt.Sprintf("PrecompileUpgrade[%d]", i),
Expand Down
4 changes: 2 additions & 2 deletions plugin/evm/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2237,7 +2237,7 @@ func TestTxAllowListSuccessfulTx(t *testing.T) {
}

errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1})
if err := errs[0]; !errors.Is(err, txallowlist.ErrSenderAddressNotAllowListed) {
if err := errs[0]; !errors.Is(err, vmerrs.ErrSenderAddressNotAllowListed) {
t.Fatalf("expected ErrSenderAddressNotAllowListed, got: %s", err)
}

Expand Down Expand Up @@ -2334,7 +2334,7 @@ func TestTxAllowListDisablePrecompile(t *testing.T) {
}

errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1})
if err := errs[0]; !errors.Is(err, txallowlist.ErrSenderAddressNotAllowListed) {
if err := errs[0]; !errors.Is(err, vmerrs.ErrSenderAddressNotAllowListed) {
t.Fatalf("expected ErrSenderAddressNotAllowListed, got: %s", err)
}

Expand Down
5 changes: 3 additions & 2 deletions plugin/evm/vm_upgrade_bytes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/ava-labs/subnet-evm/metrics"
"github.com/ava-labs/subnet-evm/params"
"github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist"
"github.com/ava-labs/subnet-evm/vmerrs"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -57,7 +58,7 @@ func TestVMUpgradeBytesPrecompile(t *testing.T) {
t.Fatal(err)
}
errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1})
if err := errs[0]; !errors.Is(err, txallowlist.ErrSenderAddressNotAllowListed) {
if err := errs[0]; !errors.Is(err, vmerrs.ErrSenderAddressNotAllowListed) {
t.Fatalf("expected ErrSenderAddressNotAllowListed, got: %s", err)
}

Expand Down Expand Up @@ -108,7 +109,7 @@ func TestVMUpgradeBytesPrecompile(t *testing.T) {

// Submit a rejected transaction, should throw an error
errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1})
if err := errs[0]; !errors.Is(err, txallowlist.ErrSenderAddressNotAllowListed) {
if err := errs[0]; !errors.Is(err, vmerrs.ErrSenderAddressNotAllowListed) {
t.Fatalf("expected ErrSenderAddressNotAllowListed, got: %s", err)
}

Expand Down
27 changes: 12 additions & 15 deletions precompile/allowlist/allowlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,18 @@ package allowlist
import (
"errors"
"fmt"
"math/big"

"github.com/ava-labs/subnet-evm/precompile/contract"
"github.com/ava-labs/subnet-evm/vmerrs"
"github.com/ethereum/go-ethereum/common"
)

// AllowList is a precompile that allows the admin to set the permissions of
// addresses. AllowList itself is not a precompile, but rather a helper
// function that is used by other precompiles to determine if an address has
// permissions.
// The permissions are:
// 1. No role assigned - this is equivalent to common.Hash{} and deletes the key from the DB when set
// 2. Enabled are allowed to take certain actions
// 3. Admin - allowed to modify both the admin and enabled list as well as take certain actions
// AllowList is an abstraction that allows other precompiles to manage
// which addresses can call the precompile by maintaining an allowlist
// in the storage trie. Each account may have one of the following roles:
// 1. NoRole - this is equivalent to common.Hash{} and deletes the key from the DB when set
// 2. EnabledRole - allowed to call the precompile
// 3. Admin - allowed to modify both the allowlist and call the precompile

const (
SetAdminFuncKey = "setAdmin"
Expand All @@ -32,10 +29,12 @@ const (
ReadAllowListGasCost = contract.ReadGasCostPerSlot
)

const allowListInputLen = common.HashLength

var (
NoRole Role = Role(common.BigToHash(big.NewInt(0))) // No role assigned - this is equivalent to common.Hash{} and deletes the key from the DB when set
EnabledRole Role = Role(common.BigToHash(big.NewInt(1))) // Deployers are allowed to create new contracts
AdminRole Role = Role(common.BigToHash(big.NewInt(2))) // Admin - allowed to modify both the admin and deployer list as well as deploy contracts
NoRole = Role(common.BigToHash(common.Big0)) // NoRole - this is equivalent to common.Hash{} and deletes the key from the DB when set
EnabledRole = Role(common.BigToHash(common.Big1)) // EnabledRole - allowed to call the precompile
AdminRole = Role(common.BigToHash(common.Big2)) // Admin - allowed to modify both the allowlist and call the precompile

// AllowList function signatures
setAdminSignature = contract.CalculateFunctionSelector("setAdmin(address)")
Expand All @@ -44,8 +43,6 @@ var (
readAllowListSignature = contract.CalculateFunctionSelector("readAllowList(address)")
// Error returned when an invalid write is attempted
ErrCannotModifyAllowList = errors.New("non-admin cannot modify allow list")

allowListInputLen = common.HashLength
)

// GetAllowListStatus returns the allow list role of [address] for the precompile
Expand Down Expand Up @@ -152,7 +149,7 @@ func createReadAllowList(precompileAddr common.Address) contract.RunStatefulPrec
}
}

// createAllowListPrecompile returns a StatefulPrecompiledContract with R/W control of an allow list at [precompileAddr]
// CreateAllowListPrecompile returns a StatefulPrecompiledContract with R/W control of an allow list at [precompileAddr]
func CreateAllowListPrecompile(precompileAddr common.Address) contract.StatefulPrecompiledContract {
// Construct the contract with no fallback function.
allowListFuncs := CreateAllowListFunctions(precompileAddr)
Expand Down
Loading

0 comments on commit 8877388

Please sign in to comment.