Skip to content

Commit

Permalink
enable/disable precompiles through upgradeBytes (#148)
Browse files Browse the repository at this point in the history
* [wip] enable/disable precompile upgrades

* e2e json

* e2e genesis

* off by one

* omitEmpty -> omitempty

* custom json handling to avoid nested map

* simplify the config

* tx_pool: fix bug in calling IsTxAllowList

* precompile: add disable helpers

* plugin/evm: tentative UT

* precompile: move test helpers to their own file

* vm_test: fix gas / test

* fix copy/paste issue

* test fixes

* backward compatibility

* cleanup

* comment

* refactor: group NetworkUpgrades in struct

* rearrange Add/Disable helper methods

* move ethereum upgrades to chainConfig

* tx_gossiping_test: include eth upgrades

* vm_test: check for ErrSenderAddressNotAllowListed

* consensus/dummy: add clock

* TestTxAllowListDisablePrecompile: use clock

* vm_test.go: issueAndAccept helper / fixes

* vm_test: remove sleep

* support multiple activations/deactivations

* fix comment

* nit: simplify loop

* fix

* golang interfaces nil

* add some unit tests

* tests and fixes

* shutdown vm in test

* fix flakiness (AddRemoteSync)

* separate upgradeBytesConfig to its own struct

* add back wspace

* remove test helpers

* fix persitedUpgradeBytes

* make changes to embedding structure

* switch from getter to using an enum

* nit: fix strings

* upgrades_config.go -> precompile_config.go

* core: handle upgrade bytes in core.Blockchain

* nit: remove argument

* nit: less diff

* add equal check for StatefulPrecompileConfig

* split test

* upgrade_bytes_config_test -> upgrade_config_test

* revert AddRemoteSync -> addRemoteSync

* e2e tests: bump avalanche versions

* nit: remove args from run.sh in comments

* Upgrade nits (#167)

* Nits

* Nits

* Remove comment

* Fix

* Fixes

* upgradeBytes: verify increasing timestamps accross keys (#168)

* verify increasing timestamps accross keys

* nicer comparison

* Update plugin/evm/vm_upgrade_bytes_test.go

Co-authored-by: aaronbuchwald <[email protected]>

* unmarshal bytes to temp var

* test: reuse ctx

* test: add disable same time as enable test case

* merge (Read,Write) UpgradeConfig  w/ ChainConfig

* test disable/enable independent of timestamp

* rawdb: fix metadata accounting of upgradeConfig

* verify etherbase before genesis / minimize diff

* nit: BigNumEqual nil checks shortened version

* convert nested configs to json in String() (#175)

* Update plugin/evm/vm.go

Co-authored-by: Ceyhun Onur <[email protected]>
Co-authored-by: aaronbuchwald <[email protected]>
  • Loading branch information
3 people authored Jul 30, 2022
1 parent 43a4db6 commit 1a02bee
Show file tree
Hide file tree
Showing 32 changed files with 1,528 additions and 371 deletions.
6 changes: 4 additions & 2 deletions chain/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ func TestChain(t *testing.T) {
config := ethconfig.DefaultConfig
chainConfig := &params.ChainConfig{
ChainID: big.NewInt(1),
FeeConfig: params.DefaultFeeConfig,
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"),
Expand All @@ -206,8 +207,9 @@ func TestChain(t *testing.T) {
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
SubnetEVMTimestamp: big.NewInt(0),
FeeConfig: params.DefaultFeeConfig,
NetworkUpgrades: params.NetworkUpgrades{
SubnetEVMTimestamp: big.NewInt(0),
},
}

// reduce block gas cost since we use no tx in the blocks
Expand Down
2 changes: 1 addition & 1 deletion chain/test_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func NewDefaultChain(t *testing.T) (*ETHChain, chan core.NewTxPoolHeadEvent, <-c
config := ethconfig.NewDefaultConfig()
chainConfig := &params.ChainConfig{
ChainID: chainID,
FeeConfig: params.DefaultFeeConfig,
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"),
Expand All @@ -63,7 +64,6 @@ func NewDefaultChain(t *testing.T) (*ETHChain, chan core.NewTxPoolHeadEvent, <-c
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
FeeConfig: params.DefaultFeeConfig,
}

config.Genesis = &core.Genesis{
Expand Down
16 changes: 14 additions & 2 deletions consensus/dummy/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"math/big"
"time"

"github.com/ava-labs/avalanchego/utils/timer/mockable"
"github.com/ava-labs/subnet-evm/consensus"
"github.com/ava-labs/subnet-evm/core/state"
"github.com/ava-labs/subnet-evm/core/types"
Expand Down Expand Up @@ -37,22 +38,33 @@ const (

type (
DummyEngine struct {
clock *mockable.Clock
consensusMode Mode
}
)

func NewETHFaker() *DummyEngine {
return &DummyEngine{
clock: &mockable.Clock{},
consensusMode: ModeSkipBlockFee,
}
}

func NewFaker() *DummyEngine {
return &DummyEngine{}
return &DummyEngine{
clock: &mockable.Clock{},
}
}

func NewFakerWithClock(clock *mockable.Clock) *DummyEngine {
return &DummyEngine{
clock: clock,
}
}

func NewFullFaker() *DummyEngine {
return &DummyEngine{
clock: &mockable.Clock{},
consensusMode: ModeSkipHeader,
}
}
Expand Down Expand Up @@ -164,7 +176,7 @@ func (self *DummyEngine) verifyHeader(chain consensus.ChainHeaderReader, header
return err
}
// Verify the header's timestamp
if header.Time > uint64(time.Now().Add(allowedFutureBlockTime).Unix()) {
if header.Time > uint64(self.clock.Time().Add(allowedFutureBlockTime).Unix()) {
return consensus.ErrFutureBlock
}
// Verify the header's timestamp is not earlier than parent's
Expand Down
26 changes: 18 additions & 8 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,12 @@ func (e *GenesisMismatchError) Error() string {
//
// genesis == nil genesis != nil
// +------------------------------------------
// db has no genesis | main-net default | genesis
// db has genesis | from DB | genesis (if compatible)
// db has no genesis | ErrNoGenesis | genesis
// db has genesis | ErrNoGenesis | genesis (if compatible both block hash and chain config), else error

// The argument [genesis] must be specified and must contain a valid chain config.
// If the genesis block has already been set up, then we verify the hash matches the genesis passed in
// and that the chain config contained in genesis is backwards compatible with what is stored in the database.
//
// The stored chain configuration will be updated if it is compatible (i.e. does not
// specify a fork block below the local head block). In case of a conflict, the
Expand Down Expand Up @@ -226,7 +230,9 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig
return newcfg, err
}
storedcfg := rawdb.ReadChainConfig(db, stored)
// If there is no previously stored chain config, write the chain config to disk.
if storedcfg == nil {
// Note: this can happen since we did not previously write the genesis block and chain config in the same batch.
log.Warn("Found genesis block without chain config")
rawdb.WriteChainConfig(db, stored, newcfg)
return newcfg, nil
Expand Down Expand Up @@ -343,12 +349,16 @@ func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
if err := config.CheckConfigForkOrder(); err != nil {
return nil, err
}
rawdb.WriteBlock(db, block)
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil)
rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64())
rawdb.WriteHeadBlockHash(db, block.Hash())
rawdb.WriteHeadHeaderHash(db, block.Hash())
rawdb.WriteChainConfig(db, block.Hash(), config)
batch := db.NewBatch()
rawdb.WriteBlock(batch, block)
rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), nil)
rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64())
rawdb.WriteHeadBlockHash(batch, block.Hash())
rawdb.WriteHeadHeaderHash(batch, block.Hash())
rawdb.WriteChainConfig(batch, block.Hash(), config)
if err := batch.Write(); err != nil {
return nil, fmt.Errorf("failed to write genesis block: %w", err)
}
return block, nil
}

Expand Down
7 changes: 1 addition & 6 deletions core/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,7 @@ func TestStatefulPrecompilesConfigure(t *testing.T) {
"allow list enabled in genesis": {
getConfig: func() *params.ChainConfig {
config := *params.TestChainConfig
config.ContractDeployerAllowListConfig = precompile.ContractDeployerAllowListConfig{
AllowListConfig: precompile.AllowListConfig{
BlockTimestamp: big.NewInt(0),
AllowListAdmins: []common.Address{addr},
},
}
config.ContractDeployerAllowListConfig = precompile.NewContractDeployerAllowListConfig(big.NewInt(0), []common.Address{addr})
return &config
},
assertState: func(t *testing.T, sdb *state.StateDB) {
Expand Down
20 changes: 20 additions & 0 deletions core/rawdb/accessors_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,17 @@ func ReadChainConfig(db ethdb.KeyValueReader, hash common.Hash) *params.ChainCon
log.Error("Invalid chain config JSON", "hash", hash, "err", err)
return nil
}

// Read the upgrade config for this chain config
data, _ = db.Get(upgradeConfigKey(hash))
if len(data) == 0 {
return &config // return early if no upgrade config is found
}
if err := json.Unmarshal(data, &config.UpgradeConfig); err != nil {
log.Error("Invalid upgrade config JSON", "err", err)
return nil
}

return &config
}

Expand All @@ -89,6 +100,15 @@ func WriteChainConfig(db ethdb.KeyValueWriter, hash common.Hash, cfg *params.Cha
if err := db.Put(configKey(hash), data); err != nil {
log.Crit("Failed to store chain config", "err", err)
}

// Write the upgrade config for this chain config
data, err = json.Marshal(cfg.UpgradeConfig)
if err != nil {
log.Crit("Failed to JSON encode upgrade config", "err", err)
}
if err := db.Put(upgradeConfigKey(hash), data); err != nil {
log.Crit("Failed to store upgrade config", "err", err)
}
}

// crashList is a list of unclean-shutdown-markers, for rlp-encoding to the
Expand Down
2 changes: 2 additions & 0 deletions core/rawdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
preimages.Add(size)
case bytes.HasPrefix(key, configPrefix) && len(key) == (len(configPrefix)+common.HashLength):
metadata.Add(size)
case bytes.HasPrefix(key, upgradeConfigPrefix) && len(key) == (len(upgradeConfigPrefix)+common.HashLength):
metadata.Add(size)
case bytes.HasPrefix(key, bloomBitsPrefix) && len(key) == (len(bloomBitsPrefix)+10+common.HashLength):
bloomBits.Add(size)
case bytes.HasPrefix(key, BloomBitsIndexPrefix):
Expand Down
10 changes: 8 additions & 2 deletions core/rawdb/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ var (
SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value
CodePrefix = []byte("c") // CodePrefix + code hash -> account code

preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage
configPrefix = []byte("ethereum-config-") // config prefix for the db
preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage
configPrefix = []byte("ethereum-config-") // config prefix for the db
upgradeConfigPrefix = []byte("upgrade-config-") // upgrade bytes passed to the chain are stored with this prefix

// Chain index prefixes (use `i` + single byte to avoid mixing data types).
BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress
Expand Down Expand Up @@ -193,3 +194,8 @@ func IsCodeKey(key []byte) (bool, []byte) {
func configKey(hash common.Hash) []byte {
return append(configPrefix, hash.Bytes()...)
}

// upgradeConfigKey = upgradeConfigPrefix + hash
func upgradeConfigKey(hash common.Hash) []byte {
return append(upgradeConfigPrefix, hash.Bytes()...)
}
28 changes: 15 additions & 13 deletions core/state_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func TestStateProcessorErrors(t *testing.T) {
var (
config = &params.ChainConfig{
ChainID: big.NewInt(1),
FeeConfig: params.DefaultFeeConfig,
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP150Hash: common.Hash{},
Expand All @@ -61,8 +62,9 @@ func TestStateProcessorErrors(t *testing.T) {
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
SubnetEVMTimestamp: big.NewInt(0),
FeeConfig: params.DefaultFeeConfig,
NetworkUpgrades: params.NetworkUpgrades{
SubnetEVMTimestamp: big.NewInt(0),
},
}
signer = types.LatestSigner(config)
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
Expand Down Expand Up @@ -214,6 +216,7 @@ func TestStateProcessorErrors(t *testing.T) {
gspec = &Genesis{
Config: &params.ChainConfig{
ChainID: big.NewInt(1),
FeeConfig: params.DefaultFeeConfig,
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP150Hash: common.Hash{},
Expand All @@ -224,8 +227,9 @@ func TestStateProcessorErrors(t *testing.T) {
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
SubnetEVMTimestamp: big.NewInt(0),
FeeConfig: params.DefaultFeeConfig,
NetworkUpgrades: params.NetworkUpgrades{
SubnetEVMTimestamp: big.NewInt(0),
},
},
Alloc: GenesisAlloc{
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
Expand Down Expand Up @@ -308,12 +312,12 @@ func TestStateProcessorErrors(t *testing.T) {
// non-whitelisted TX Allow List address.
func TestBadTxAllowListBlock(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()

db = rawdb.NewMemoryDatabase()
testAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7")

config = &params.ChainConfig{
ChainID: big.NewInt(1),
FeeConfig: params.DefaultFeeConfig,
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP150Hash: common.Hash{},
Expand All @@ -324,13 +328,11 @@ func TestBadTxAllowListBlock(t *testing.T) {
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
SubnetEVMTimestamp: big.NewInt(0),
FeeConfig: params.DefaultFeeConfig,
TxAllowListConfig: precompile.TxAllowListConfig{
AllowListConfig: precompile.AllowListConfig{
BlockTimestamp: big.NewInt(0),
AllowListAdmins: []common.Address{},
},
NetworkUpgrades: params.NetworkUpgrades{
SubnetEVMTimestamp: big.NewInt(0),
},
PrecompileUpgrade: params.PrecompileUpgrade{
TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(0), []common.Address{}),
},
}
signer = types.LatestSigner(config)
Expand Down
18 changes: 2 additions & 16 deletions core/test_blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1546,22 +1546,8 @@ func TestStatefulPrecompiles(t *testing.T, create func(db ethdb.Database, chainC
genesisBalance := new(big.Int).Mul(big.NewInt(1000000), big.NewInt(params.Ether))
config := *params.TestChainConfig
// Set all of the required config parameters
config.ContractDeployerAllowListConfig = precompile.ContractDeployerAllowListConfig{
AllowListConfig: precompile.AllowListConfig{
BlockTimestamp: big.NewInt(0),
AllowListAdmins: []common.Address{
addr1,
},
},
}
config.FeeManagerConfig = precompile.FeeConfigManagerConfig{
AllowListConfig: precompile.AllowListConfig{
BlockTimestamp: big.NewInt(0),
AllowListAdmins: []common.Address{
addr1,
},
},
}
config.ContractDeployerAllowListConfig = precompile.NewContractDeployerAllowListConfig(big.NewInt(0), []common.Address{addr1})
config.FeeManagerConfig = precompile.NewFeeManagerConfig(big.NewInt(0), []common.Address{addr1})
gspec := &Genesis{
Config: &config,
Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}},
Expand Down
4 changes: 3 additions & 1 deletion core/vm/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ func setDefaults(cfg *Config) {
PetersburgBlock: new(big.Int),
IstanbulBlock: new(big.Int),
MuirGlacierBlock: new(big.Int),
SubnetEVMTimestamp: new(big.Int),
NetworkUpgrades: params.NetworkUpgrades{
SubnetEVMTimestamp: new(big.Int),
},
}
}

Expand Down
2 changes: 1 addition & 1 deletion eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func New(
chainDb: chainDb,
eventMux: new(event.TypeMux),
accountManager: stack.AccountManager(),
engine: dummy.NewFaker(),
engine: dummy.NewFakerWithClock(clock),
closeBloomHandler: make(chan struct{}),
networkID: config.NetworkId,
etherbase: config.Miner.Etherbase,
Expand Down
Loading

0 comments on commit 1a02bee

Please sign in to comment.