diff --git a/core/vm/evm.go b/core/vm/evm.go index f1a44bbcd7..e56c413c04 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -46,21 +46,14 @@ var ( _ precompile.BlockContext = &BlockContext{} ) -var prohibitedAddresses = map[common.Address]struct{}{ - constants.BlackholeAddr: {}, -} - -func init() { - for _, addr := range precompile.UsedAddresses { - prohibitedAddresses[addr] = struct{}{} - } -} - // IsProhibited returns true if [addr] is in the prohibited list of addresses which should // not be allowed as an EOA or newly created contract address. func IsProhibited(addr common.Address) bool { - _, ok := prohibitedAddresses[addr] - return ok + if addr == constants.BlackholeAddr { + return true + } + + return precompile.ReservedAddress(addr) } // emptyCodeHash is used by create to ensure deployment is disallowed to already diff --git a/precompile/params.go b/precompile/params.go index 28fabcf38e..4174464000 100644 --- a/precompile/params.go +++ b/precompile/params.go @@ -3,7 +3,11 @@ package precompile -import "github.com/ethereum/go-ethereum/common" +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" +) // Gas costs for stateful precompiles const ( @@ -23,8 +27,11 @@ const ( // Designated addresses of stateful precompiles // Note: it is important that none of these addresses conflict with each other or any other precompiles // in core/vm/contracts.go. -// We start at 0x0200000000000000000000000000000000000000 and will increment by 1 from here to reduce -// the risk of conflicts. +// The first stateful precompiles were added in coreth to support nativeAssetCall and nativeAssetBalance. New stateful precompiles +// originating in coreth will continue at this prefix, so we reserve this range in subnet-evm so that they can be migrated into +// subnet-evm without issue. These start at the address: 0x0100000000000000000000000000000000000000 and will increment by 1. +// Optional precompiles implemented in subnet-evm start at 0x0200000000000000000000000000000000000000 and will increment by 1 +// from here to reduce the risk of conflicts. // For forks of subnet-evm, users should start at 0x0300000000000000000000000000000000000000 to ensure // that their own modifications do not conflict with stateful precompiles that may be added to subnet-evm // in the future. @@ -40,4 +47,38 @@ var ( TxAllowListAddress, FeeConfigManagerAddress, } + reservedRanges = []AddressRange{ + { + common.HexToAddress("0x0100000000000000000000000000000000000000"), + common.HexToAddress("0x01000000000000000000000000000000000000ff"), + }, + { + common.HexToAddress("0x0200000000000000000000000000000000000000"), + common.HexToAddress("0x02000000000000000000000000000000000000ff"), + }, + { + common.HexToAddress("0x0300000000000000000000000000000000000000"), + common.HexToAddress("0x03000000000000000000000000000000000000ff"), + }, + } ) + +// UsedAddress returns true if [addr] is in a reserved range for custom precompiles +func ReservedAddress(addr common.Address) bool { + for _, reservedRange := range reservedRanges { + if reservedRange.Contains(addr) { + return true + } + } + + return false +} + +func init() { + // Ensure that every address used by a precompile is in a reserved range. + for _, addr := range UsedAddresses { + if !ReservedAddress(addr) { + panic(fmt.Errorf("address %s used for stateful precompile but not specified in any reserved range", addr)) + } + } +} diff --git a/precompile/reserved_range.go b/precompile/reserved_range.go new file mode 100644 index 0000000000..d2627bffa4 --- /dev/null +++ b/precompile/reserved_range.go @@ -0,0 +1,26 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package precompile + +import ( + "bytes" + + "github.com/ethereum/go-ethereum/common" +) + +// Gas costs for stateful precompiles +// can be added here eg. +// const MintGasCost = 30_000 + +// AddressRange represents a continuous range of addresses +type AddressRange struct { + Start common.Address + End common.Address +} + +// Contains returns true iff [addr] is contained within the (inclusive) +func (a *AddressRange) Contains(addr common.Address) bool { + addrBytes := addr.Bytes() + return bytes.Compare(addrBytes, a.Start[:]) >= 0 && bytes.Compare(addrBytes, a.End[:]) <= 0 +}