Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(core/types): remove Blocks's Timestamp() method #1429

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package {{.Package}}

import (
"fmt"
"math/big"

"github.com/ava-labs/subnet-evm/precompile/precompileconfig"
"github.com/ava-labs/subnet-evm/precompile/contract"
Expand Down Expand Up @@ -59,7 +60,7 @@ func (*configurator) MakeConfig() precompileconfig.Config {
// This function is called by the EVM once per precompile contract activation.
// You can use this function to set up your precompile contract's initial state,
// by using the [cfg] config and [state] stateDB.
func (*configurator) Configure(chainConfig precompileconfig.ChainConfig, cfg precompileconfig.Config, state contract.StateDB, blockContext contract.ConfigurationBlockContext) error {
func (*configurator) Configure(chainConfig precompileconfig.ChainConfig, cfg precompileconfig.Config, state contract.StateDB, blockNumber *big.Int, blockTime uint64) error {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a breaking change to all precompiles (external and internal precompiles). While having a simple params is better, we should also evaluate this with the future extension possibilities. IMO having a blockContext interface is less cumbersome to extend.

// CUSTOM CODE STARTS HERE
{{- if .Contract.AllowList}}
config, ok := cfg.(*Config)
Expand All @@ -68,7 +69,7 @@ func (*configurator) Configure(chainConfig precompileconfig.ChainConfig, cfg pre
}

// AllowList is activated for this precompile. Configuring allowlist addresses here.
return config.AllowListConfig.Configure(chainConfig, ContractAddress, state, blockContext)
return config.AllowListConfig.Configure(chainConfig, ContractAddress, state)
{{- else}}
if _, ok := cfg.(*Config); !ok {
return fmt.Errorf("expected config type %T, got %T: %v", &Config{}, cfg, cfg)
Expand Down
2 changes: 1 addition & 1 deletion core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
b := &BlockGen{i: i, cm: cm, parent: parent, statedb: statedb, engine: engine}
b.header = cm.makeHeader(parent, gap, statedb, b.engine)

err := ApplyUpgrades(config, &parent.Header().Time, b, statedb)
err := ApplyUpgrades(config, &parent.Header().Time, b.Number(), b.Timestamp(), statedb)
if err != nil {
return nil, nil, fmt.Errorf("failed to configure precompiles %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ func (g *Genesis) toBlock(db ethdb.Database, triedb *triedb.Database) *types.Blo
}

// Configure any stateful precompiles that should be enabled in the genesis.
err = ApplyPrecompileActivations(g.Config, nil, types.NewBlockWithHeader(head), statedb)
err = ApplyPrecompileActivations(g.Config, nil, head.Number, head.Time, statedb)
if err != nil {
panic(fmt.Sprintf("unable to configure precompiles in genesis block: %v", err))
}
Expand Down
24 changes: 11 additions & 13 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import (
"github.com/ava-labs/subnet-evm/core/types"
"github.com/ava-labs/subnet-evm/core/vm"
"github.com/ava-labs/subnet-evm/params"
"github.com/ava-labs/subnet-evm/precompile/contract"
"github.com/ava-labs/subnet-evm/precompile/modules"
"github.com/ava-labs/subnet-evm/stateupgrade"
"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -82,7 +81,7 @@ func (p *StateProcessor) Process(block *types.Block, parent *types.Header, state
)

// Configure any upgrades that should go into effect during this block.
err := ApplyUpgrades(p.config, &parent.Time, block, statedb)
err := ApplyUpgrades(p.config, &parent.Time, header.Number, header.Time, statedb)
if err != nil {
log.Error("failed to configure precompiles processing block", "hash", block.Hash(), "number", block.NumberU64(), "timestamp", block.Time(), "err", err)
return nil, nil, 0, err
Expand Down Expand Up @@ -208,14 +207,13 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat
// to apply the necessary state transitions for the upgrade.
// This function is called within genesis setup to configure the starting state for precompiles enabled at genesis.
// In block processing and building, ApplyUpgrades is called instead which also applies state upgrades.
func ApplyPrecompileActivations(c *params.ChainConfig, parentTimestamp *uint64, blockContext contract.ConfigurationBlockContext, statedb *state.StateDB) error {
blockTimestamp := blockContext.Timestamp()
func ApplyPrecompileActivations(c *params.ChainConfig, parentTimestamp *uint64, blockNumber *big.Int, blockTime uint64, statedb *state.StateDB) error {
// Note: RegisteredModules returns precompiles sorted by module addresses.
// This ensures that the order we call Configure for each precompile is consistent.
// This ensures even if precompiles read/write state other than their own they will observe
// an identical global state in a deterministic order when they are configured.
for _, module := range modules.RegisteredModules() {
for _, activatingConfig := range c.GetActivatingPrecompileConfigs(module.Address, parentTimestamp, blockTimestamp, c.PrecompileUpgrades) {
for _, activatingConfig := range c.GetActivatingPrecompileConfigs(module.Address, parentTimestamp, blockTime, c.PrecompileUpgrades) {
// If this transition activates the upgrade, configure the stateful precompile.
// (or deconfigure it if it is being disabled.)
if activatingConfig.IsDisabled() {
Expand Down Expand Up @@ -243,7 +241,7 @@ func ApplyPrecompileActivations(c *params.ChainConfig, parentTimestamp *uint64,
// can be called from within Solidity contracts. Solidity adds a check before invoking a contract to ensure
// that it does not attempt to invoke a non-existent contract.
statedb.SetCode(module.Address, []byte{0x1})
if err := module.Configure(c, activatingConfig, statedb, blockContext); err != nil {
if err := module.Configure(c, activatingConfig, statedb, blockNumber, blockTime); err != nil {
return fmt.Errorf("could not configure precompile, name: %s, reason: %w", module.ConfigKey, err)
}
}
Expand All @@ -255,11 +253,11 @@ func ApplyPrecompileActivations(c *params.ChainConfig, parentTimestamp *uint64,
// applyStateUpgrades checks if any of the state upgrades specified by the chain config are activated by the block
// transition from [parentTimestamp] to the timestamp set in [header]. If this is the case, it calls [Configure]
// to apply the necessary state transitions for the upgrade.
func applyStateUpgrades(c *params.ChainConfig, parentTimestamp *uint64, blockContext contract.ConfigurationBlockContext, statedb *state.StateDB) error {
func applyStateUpgrades(c *params.ChainConfig, parentTimestamp *uint64, blockNumber *big.Int, blockTime uint64, statedb *state.StateDB) error {
// Apply state upgrades
for _, upgrade := range c.GetActivatingStateUpgrades(parentTimestamp, blockContext.Timestamp(), c.StateUpgrades) {
log.Info("Applying state upgrade", "blockNumber", blockContext.Number(), "upgrade", upgrade)
if err := stateupgrade.Configure(&upgrade, c, statedb, blockContext); err != nil {
for _, upgrade := range c.GetActivatingStateUpgrades(parentTimestamp, blockTime, c.StateUpgrades) {
log.Info("Applying state upgrade", "blockNumber", blockNumber, "upgrade", upgrade)
if err := stateupgrade.Configure(&upgrade, c, statedb, blockNumber); err != nil {
return fmt.Errorf("could not configure state upgrade: %w", err)
}
}
Expand All @@ -272,9 +270,9 @@ func applyStateUpgrades(c *params.ChainConfig, parentTimestamp *uint64, blockCon
// This function is called:
// - in block processing to update the state when processing a block.
// - in the miner to apply the state upgrades when producing a block.
func ApplyUpgrades(c *params.ChainConfig, parentTimestamp *uint64, blockContext contract.ConfigurationBlockContext, statedb *state.StateDB) error {
if err := ApplyPrecompileActivations(c, parentTimestamp, blockContext, statedb); err != nil {
func ApplyUpgrades(c *params.ChainConfig, parentTimestamp *uint64, blockNumber *big.Int, blockTime uint64, statedb *state.StateDB) error {
if err := ApplyPrecompileActivations(c, parentTimestamp, blockNumber, blockTime, statedb); err != nil {
return err
}
return applyStateUpgrades(c, parentTimestamp, blockContext, statedb)
return applyStateUpgrades(c, parentTimestamp, blockNumber, blockTime, statedb)
}
1 change: 0 additions & 1 deletion core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,6 @@ func (b *Block) GasLimit() uint64 { return b.header.GasLimit }
func (b *Block) GasUsed() uint64 { return b.header.GasUsed }
func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) }
func (b *Block) Time() uint64 { return b.header.Time }
func (b *Block) Timestamp() uint64 { return b.header.Time }

func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() }
func (b *Block) MixDigest() common.Hash { return b.header.MixDigest }
Expand Down
14 changes: 8 additions & 6 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import (

var (
_ contract.AccessibleState = &EVM{}
_ contract.BlockContext = &BlockContext{}
_ contract.BlockContext = &PrecompileBlockContext{}
)

// IsProhibited returns true if [addr] is in the prohibited list of addresses which should
Expand Down Expand Up @@ -125,15 +125,17 @@ type BlockContext struct {
BlobBaseFee *big.Int // Provides information for BLOBBASEFEE (0 if vm runs with NoBaseFee flag and 0 blob gas price)
}

func (b *BlockContext) Number() *big.Int {
type PrecompileBlockContext struct{ BlockContext }

func (b *PrecompileBlockContext) Number() *big.Int {
return b.BlockNumber
}

func (b *BlockContext) Timestamp() uint64 {
return b.Time
func (b *PrecompileBlockContext) Time() uint64 {
return b.BlockContext.Time
}

func (b *BlockContext) GetPredicateResults(txHash common.Hash, address common.Address) []byte {
func (b *PrecompileBlockContext) GetPredicateResults(txHash common.Hash, address common.Address) []byte {
if b.PredicateResults == nil {
return nil
}
Expand Down Expand Up @@ -242,7 +244,7 @@ func (evm *EVM) GetStateDB() contract.StateDB {

// GetBlockContext returns the evm's BlockContext
func (evm *EVM) GetBlockContext() contract.BlockContext {
return &evm.Context
return &PrecompileBlockContext{evm.Context}
}

// Interpreter returns the current interpreter
Expand Down
2 changes: 1 addition & 1 deletion eth/state_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ func (eth *Ethereum) StateAtNextBlock(ctx context.Context, parent *types.Block,
}

// Apply upgrades here for the [nextBlock]
err = core.ApplyUpgrades(eth.blockchain.Config(), &parent.Header().Time, nextBlock, statedb)
err = core.ApplyUpgrades(eth.blockchain.Config(), &parent.Header().Time, nextBlock.Number(), nextBlock.Time(), statedb)
if err != nil {
release()
return nil, nil, err
Expand Down
2 changes: 1 addition & 1 deletion eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
config.BlockOverrides.Apply(&vmctx)
// Apply all relevant upgrades from [originalTime] to the block time set in the override.
// Should be applied before the state overrides.
err = core.ApplyUpgrades(api.backend.ChainConfig(), &originalTime, &vmctx, statedb)
err = core.ApplyUpgrades(api.backend.ChainConfig(), &originalTime, vmctx.BlockNumber, vmctx.Time, statedb)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion eth/tracers/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (b *testBackend) StateAtNextBlock(ctx context.Context, parent, nextBlock *t
return nil, nil, err
}
// Apply upgrades to the parent state
err = core.ApplyUpgrades(b.chainConfig, &parent.Header().Time, nextBlock, statedb)
err = core.ApplyUpgrades(b.chainConfig, &parent.Header().Time, nextBlock.Number(), nextBlock.Time(), statedb)
if err != nil {
release()
return nil, nil, err
Expand Down
2 changes: 1 addition & 1 deletion miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func (w *worker) commitNewWork(predicateContext *precompileconfig.PredicateConte
env.state.StopPrefetcher()
}()
// Configure any upgrades that should go into effect during this block.
err = core.ApplyUpgrades(w.chainConfig, &parent.Time, types.NewBlockWithHeader(header), env.state)
err = core.ApplyUpgrades(w.chainConfig, &parent.Time, header.Number, header.Time, env.state)
if err != nil {
log.Error("failed to configure precompiles mining new block", "parent", parent.Hash(), "number", header.Number, "timestamp", header.Time, "err", err)
return nil, err
Expand Down
6 changes: 3 additions & 3 deletions plugin/evm/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (b *Block) Accept(context.Context) error {
// Call Accept for relevant precompile logs. Note we do this prior to
// calling Accept on the blockChain so any side effects (eg warp signatures)
// take place before the accepted log is emitted to subscribers.
rules := b.vm.chainConfig.Rules(b.ethBlock.Number(), b.ethBlock.Timestamp())
rules := b.vm.chainConfig.Rules(b.ethBlock.Number(), b.ethBlock.Time())
if err := b.handlePrecompileAccept(rules); err != nil {
return err
}
Expand Down Expand Up @@ -153,7 +153,7 @@ func (b *Block) Verify(context.Context) error {

// ShouldVerifyWithContext implements the block.WithVerifyContext interface
func (b *Block) ShouldVerifyWithContext(context.Context) (bool, error) {
predicates := b.vm.chainConfig.Rules(b.ethBlock.Number(), b.ethBlock.Timestamp()).Predicaters
predicates := b.vm.chainConfig.Rules(b.ethBlock.Number(), b.ethBlock.Time()).Predicaters
// Short circuit early if there are no predicates to verify
if len(predicates) == 0 {
return false, nil
Expand Down Expand Up @@ -219,7 +219,7 @@ func (b *Block) verify(predicateContext *precompileconfig.PredicateContext, writ

// verifyPredicates verifies the predicates in the block are valid according to predicateContext.
func (b *Block) verifyPredicates(predicateContext *precompileconfig.PredicateContext) error {
rules := b.vm.chainConfig.Rules(b.ethBlock.Number(), b.ethBlock.Timestamp())
rules := b.vm.chainConfig.Rules(b.ethBlock.Number(), b.ethBlock.Time())

switch {
case !rules.IsDurango && rules.PredicatersExist():
Expand Down
10 changes: 5 additions & 5 deletions plugin/evm/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2393,7 +2393,7 @@ func TestTxAllowListDisablePrecompile(t *testing.T) {
require.Equal(t, signedTx0.Hash(), txs[0].Hash())

// verify the issued block is after the network upgrade
require.GreaterOrEqual(t, int64(block.Timestamp()), disableAllowListTimestamp.Unix())
require.GreaterOrEqual(t, int64(block.Time()), disableAllowListTimestamp.Unix())

<-newTxPoolHeadChan // wait for new head in tx pool

Expand Down Expand Up @@ -2772,7 +2772,7 @@ func TestRewardManagerPrecompileSetRewardAddress(t *testing.T) {
// to determine the coinbase for this block before full deactivation in the
// next block.
require.Equal(t, testAddr, ethBlock.Coinbase())
require.GreaterOrEqual(t, int64(ethBlock.Timestamp()), disableTime.Unix())
require.GreaterOrEqual(t, int64(ethBlock.Time()), disableTime.Unix())

vm.clock.Set(vm.clock.Time().Add(3 * time.Hour)) // let time pass to decrease gas price
// issue another block to verify that the reward manager is disabled
Expand All @@ -2792,7 +2792,7 @@ func TestRewardManagerPrecompileSetRewardAddress(t *testing.T) {
// reward manager was disabled at previous block
// so this block should revert back to enabling fee recipients
require.Equal(t, etherBase, ethBlock.Coinbase())
require.GreaterOrEqual(t, int64(ethBlock.Timestamp()), disableTime.Unix())
require.GreaterOrEqual(t, int64(ethBlock.Time()), disableTime.Unix())

// Verify that Blackhole has received fees
blkState, err = vm.blockChain.StateAt(ethBlock.Root())
Expand Down Expand Up @@ -2906,7 +2906,7 @@ func TestRewardManagerPrecompileAllowFeeRecipients(t *testing.T) {
require.Equal(t, newHead.Head.Hash(), common.Hash(blk.ID()))
ethBlock = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
require.Equal(t, etherBase, ethBlock.Coinbase()) // reward address was activated at previous block
require.GreaterOrEqual(t, int64(ethBlock.Timestamp()), disableTime.Unix())
require.GreaterOrEqual(t, int64(ethBlock.Time()), disableTime.Unix())

vm.clock.Set(vm.clock.Time().Add(3 * time.Hour)) // let time pass so that gas price is reduced
tx2 = types.NewTransaction(uint64(2), testEthAddrs[0], big.NewInt(2), 21000, big.NewInt(testMinGasPrice), nil)
Expand All @@ -2923,7 +2923,7 @@ func TestRewardManagerPrecompileAllowFeeRecipients(t *testing.T) {
require.Equal(t, newHead.Head.Hash(), common.Hash(blk.ID()))
ethBlock = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
require.Equal(t, constants.BlackholeAddr, ethBlock.Coinbase()) // reward address was activated at previous block
require.Greater(t, int64(ethBlock.Timestamp()), disableTime.Unix())
require.Greater(t, int64(ethBlock.Time()), disableTime.Unix())

// Verify that Blackhole has received fees
blkState, err = vm.blockChain.StateAt(ethBlock.Root())
Expand Down
2 changes: 1 addition & 1 deletion plugin/evm/vm_upgrade_bytes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func TestVMUpgradeBytesPrecompile(t *testing.T) {
assert.Equal(t, signedTx0.Hash(), txs[0].Hash())

// verify the issued block is after the network upgrade
assert.GreaterOrEqual(t, int64(block.Timestamp()), disableAllowListTimestamp.Unix())
assert.GreaterOrEqual(t, int64(block.Time()), disableAllowListTimestamp.Unix())

<-newTxPoolHeadChan // wait for new head in tx pool

Expand Down
6 changes: 4 additions & 2 deletions precompile/allowlist/allowlist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package allowlist

import (
"math/big"
"testing"

"github.com/ava-labs/subnet-evm/core/state"
Expand Down Expand Up @@ -49,10 +50,11 @@ func (d *dummyConfigurator) Configure(
chainConfig precompileconfig.ChainConfig,
precompileConfig precompileconfig.Config,
state contract.StateDB,
blockContext contract.ConfigurationBlockContext,
blockNumber *big.Int,
blockTime uint64,
) error {
cfg := precompileConfig.(*dummyConfig)
return cfg.AllowListConfig.Configure(chainConfig, dummyAddr, state, blockContext)
return cfg.AllowListConfig.Configure(chainConfig, dummyAddr, state)
}

func TestAllowListRun(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions precompile/allowlist/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ type AllowListConfig struct {
}

// Configure initializes the address space of [precompileAddr] by initializing the role of each of
// the addresses in [AllowListAdmins].
func (c *AllowListConfig) Configure(chainConfig precompileconfig.ChainConfig, precompileAddr common.Address, state contract.StateDB, blockContext contract.ConfigurationBlockContext) error {
// the addresses in [AllowListConfig].
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we keep the arguments for this method for symmetry with the other methods (even though unused)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand what symmetry you are thinking about? With the Configurator.Configure??

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my thought, even though the AllowList is not a precompile it follows through the phases of Configure along with the precompile.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related question: what would be the cost of changing the signature of AllowListConfig.Configure if needed in the future? 🤔

Copy link
Collaborator

@darioush darioush Jan 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Less than the other method, as the AllowList is not part of the precompile interface but more a partial implementation that's used by some of the precompiles.

As I mentioned I have a subjective preference for methods that do similar things to all take the same arguments but this is not a strong preference.

func (c *AllowListConfig) Configure(chainConfig precompileconfig.ChainConfig, precompileAddr common.Address, state contract.StateDB) error {
for _, enabledAddr := range c.EnabledAddresses {
SetAllowListRole(state, precompileAddr, enabledAddr, EnabledRole)
}
Expand Down
12 changes: 4 additions & 8 deletions precompile/contract/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,9 @@ type AccessibleState interface {
GetChainConfig() precompileconfig.ChainConfig
}

// ConfigurationBlockContext defines the interface required to configure a precompile.
type ConfigurationBlockContext interface {
Number() *big.Int
Timestamp() uint64
}

type BlockContext interface {
ConfigurationBlockContext
Number() *big.Int
Time() uint64
// GetPredicateResults returns an arbitrary byte array result of verifying the predicates
// of the given transaction, precompile address pair.
GetPredicateResults(txHash common.Hash, precompileAddress common.Address) []byte
Expand All @@ -71,6 +66,7 @@ type Configurator interface {
chainConfig precompileconfig.ChainConfig,
precompileconfig precompileconfig.Config,
state StateDB,
blockContext ConfigurationBlockContext,
blockNumber *big.Int,
blockTime uint64,
) error
}
12 changes: 6 additions & 6 deletions precompile/contract/mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion precompile/contract/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,5 @@ func ParseABI(rawABI string) abi.ABI {
}

func IsDurangoActivated(evm AccessibleState) bool {
return evm.GetChainConfig().IsDurango(evm.GetBlockContext().Timestamp())
return evm.GetChainConfig().IsDurango(evm.GetBlockContext().Time())
}
Loading
Loading