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

WIP:Handle system call #178

Open
wants to merge 9 commits into
base: main
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
4 changes: 4 additions & 0 deletions consensus/clique/clique.go
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,10 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header
return nil
}

func (c *Clique) StartHook(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB) error {
return nil
}

// Finalize implements consensus.Engine, ensuring no uncles are set, nor block
// rewards given.
func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {
Expand Down
4 changes: 4 additions & 0 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ type Engine interface {
// rules of a particular engine. The changes are executed inline.
Prepare(chain ChainHeaderReader, header *types.Header) error

// StartHook calling before start apply transactions of block
//StartHook(chain consensus.ChainHeaderReader, header *types.Header, preHeader *types.Header, state *state.StateDB) error
StartHook(chain ChainHeaderReader, header *types.Header, state *state.StateDB) error

// Finalize runs any post-transaction state modifications (e.g. block rewards)
// but does not assemble the block.
//
Expand Down
4 changes: 4 additions & 0 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,10 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H
return nil
}

func (ethash *Ethash) StartHook(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB) error {
return nil
}

// Finalize implements consensus.Engine, accumulating the block and uncle rewards,
// setting the final state on the header
func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {
Expand Down
66 changes: 64 additions & 2 deletions consensus/l2/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,22 @@ import (
"github.com/morph-l2/go-ethereum/common"
"github.com/morph-l2/go-ethereum/consensus"
"github.com/morph-l2/go-ethereum/consensus/misc"
"github.com/morph-l2/go-ethereum/contracts/l2staking"
"github.com/morph-l2/go-ethereum/contracts/morphtoken"
"github.com/morph-l2/go-ethereum/core"
"github.com/morph-l2/go-ethereum/core/state"
"github.com/morph-l2/go-ethereum/core/types"
"github.com/morph-l2/go-ethereum/core/vm"
"github.com/morph-l2/go-ethereum/params"
"github.com/morph-l2/go-ethereum/rollup/rcfg"
"github.com/morph-l2/go-ethereum/rpc"
"github.com/morph-l2/go-ethereum/trie"
)

var (
l2Difficulty = common.Big0 // The default block difficulty in the l2 consensus
l2Nonce = types.EncodeNonce(0) // The default block nonce in the l2 consensus
l2Difficulty = common.Big0 // The default block difficulty in the l2 consensus
l2Nonce = types.EncodeNonce(0) // The default block nonce in the l2 consensus
rewardEpoch uint64 = 86400
)

// Various error messages to mark blocks invalid. These should be private to
Expand All @@ -32,6 +38,26 @@ var (
errInvalidCoinbase = errors.New("invalid coinbase")
)

// chain context
type chainContext struct {
Chain consensus.ChainHeaderReader
engine consensus.Engine
}

func (c chainContext) Engine() consensus.Engine {
return c.engine
}

func (c chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
return c.Chain.GetHeader(hash, number)
}

func (c chainContext) Config() *params.ChainConfig {
return c.Chain.Config()
}

var _ = consensus.Engine(&Consensus{})

type Consensus struct {
ethone consensus.Engine // Original consensus engine used in eth1, e.g. ethash or clique
config *params.ChainConfig
Expand Down Expand Up @@ -194,6 +220,42 @@ func (l2 *Consensus) Prepare(chain consensus.ChainHeaderReader, header *types.He
return nil
}

// StartHook implements calling before start apply transactions of block
func (l2 *Consensus) StartHook(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB) error {
rewardStarted := state.GetState(rcfg.L2StakingAddress, rcfg.RewardStartedSlot).Big()
if rewardStarted.Cmp(common.Big1) != 0 {
return nil
}
parentHeader := chain.GetHeaderByHash(header.ParentHash)
if parentHeader == nil {
return consensus.ErrUnknownAncestor
}
cx := chainContext{Chain: chain, engine: l2.ethone}
blockContext := core.NewEVMBlockContext(header, cx, l2.config, nil)
// TODO tracer
evm := vm.NewEVM(blockContext, vm.TxContext{}, state, l2.config, vm.Config{Tracer: nil})
stakingCallData, err := l2staking.PacketData(parentHeader.Coinbase)
if err != nil {
return err
}
systemAddress := vm.AccountRef(rcfg.SystemAddress)
_, _, err = evm.Call(systemAddress, rcfg.L2StakingAddress, stakingCallData, params.MaxGasLimit, common.Big0)
if err != nil {
return err
}
if (parentHeader.Time / rewardEpoch) != (header.Time / rewardEpoch) {
callData, err := morphtoken.PacketData()
if err != nil {
return err
}
_, _, err = evm.Call(systemAddress, rcfg.MorphTokenAddress, callData, params.MaxGasLimit, common.Big0)
if err != nil {
return err
}
}
return nil
}

// Finalize implements consensus.Engine, setting the final state on the header
func (l2 *Consensus) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {
// The block reward is no longer handled here. It's done by the
Expand Down
42 changes: 42 additions & 0 deletions contracts/l2staking/l2staking.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package l2staking

import (
"fmt"
"strings"
"sync"

"github.com/morph-l2/go-ethereum/accounts/abi"
"github.com/morph-l2/go-ethereum/common"
)

const jsonData = `[{"inputs":[{"internalType":"address","name":"sequencerAddr","type":"address"}],"name":"recordBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"}]`

var (
l2StakingABI *abi.ABI
loadOnce sync.Once
loadErr error
)

func Abi() (*abi.ABI, error) {
loadOnce.Do(func() {
stakingABI, err := abi.JSON(strings.NewReader(jsonData))
if err != nil {
loadErr = fmt.Errorf("failed to parse ABI: %w", err)
return
}
l2StakingABI = &stakingABI
})
return l2StakingABI, loadErr
}

func PacketData(addr common.Address) ([]byte, error) {
a, err := Abi()
if err != nil {
return nil, fmt.Errorf("failed to get ABI: %w", err)
}
data, err := a.Pack("recordBlocks", addr)
if err != nil {
return nil, fmt.Errorf("failed to pack data: %w", err)
}
return data, nil
}
13 changes: 13 additions & 0 deletions contracts/l2staking/l2staking_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package l2staking

import (
"testing"

"github.com/morph-l2/go-ethereum/common"
"github.com/stretchr/testify/require"
)

func TestPackData(t *testing.T) {
_, err := PacketData(common.HexToAddress("0x01"))
require.NoError(t, err)
}
41 changes: 41 additions & 0 deletions contracts/morphtoken/morph_token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package morphtoken

import (
"fmt"
"strings"
"sync"

"github.com/morph-l2/go-ethereum/accounts/abi"
)

const jsonData = `[{"inputs":[],"name":"mintInflations","outputs":[],"stateMutability":"nonpayable","type":"function"}]`

var (
morphTokenABI *abi.ABI
loadOnce sync.Once
loadErr error
)

func Abi() (*abi.ABI, error) {
loadOnce.Do(func() {
tokenABI, err := abi.JSON(strings.NewReader(jsonData))
if err != nil {
loadErr = fmt.Errorf("failed to parse ABI: %w", err)
return
}
morphTokenABI = &tokenABI
})
return morphTokenABI, loadErr
}

func PacketData() ([]byte, error) {
a, err := Abi()
if err != nil {
return nil, fmt.Errorf("failed to get ABI: %w", err)
}
data, err := a.Pack("mintInflations")
if err != nil {
return nil, fmt.Errorf("failed to pack data: %w", err)
}
return data, nil
}
12 changes: 12 additions & 0 deletions contracts/morphtoken/morph_token_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package morphtoken

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestPackData(t *testing.T) {
_, err := PacketData()
require.NoError(t, err)
}
4 changes: 4 additions & 0 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
blockContext := NewEVMBlockContext(header, p.bc, p.config, nil)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
processorBlockTransactionGauge.Update(int64(block.Transactions().Len()))
err := p.engine.StartHook(p.bc, header, statedb)
if err != nil {
return nil, nil, 0, err
}
// Iterate over and process the individual transactions
for i, tx := range block.Transactions() {
msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee)
Expand Down
1 change: 1 addition & 0 deletions core/types/l2trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type BlockTrace struct {
Bytecodes []*BytecodeTrace `json:"codes"`
TxStorageTraces []*StorageTrace `json:"txStorageTraces,omitempty"`
ExecutionResults []*ExecutionResult `json:"executionResults"`
StartHookResult *ExecutionResult `json:"startHookResult,omitempty"`
WithdrawTrieRoot common.Hash `json:"withdraw_trie_root,omitempty"`
SequencerSetVerifyHash common.Hash `json:"sequencer_set_verify_hash,omitempty"`
StartL1QueueIndex uint64 `json:"startL1QueueIndex"`
Expand Down
10 changes: 10 additions & 0 deletions rollup/rcfg/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ var (
OverheadSlot = common.BigToHash(big.NewInt(2))
ScalarSlot = common.BigToHash(big.NewInt(3))

// MorphTokenAddress is the address of the morph token contract
MorphTokenAddress = common.HexToAddress("0x5300000000000000000000000000000000000013")

// L2StakingAddress is the address of the l2 staking contract
L2StakingAddress = common.HexToAddress("0x5300000000000000000000000000000000000015")
RewardStartedSlot = common.BigToHash(big.NewInt(4))

// SystemAddress is the address of the system
SystemAddress = common.HexToAddress("0x5300000000000000000000000000000000000021")

// New fields added in the Curie hard fork
L1BlobBaseFeeSlot = common.BigToHash(big.NewInt(6))
CommitScalarSlot = common.BigToHash(big.NewInt(7))
Expand Down
Loading