Skip to content

Commit d63fcec

Browse files
committed
handle system call
1 parent de5160c commit d63fcec

File tree

8 files changed

+3932
-1
lines changed

8 files changed

+3932
-1
lines changed

consensus/clique/clique.go

+4
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,10 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header
561561
return nil
562562
}
563563

564+
func (c *Clique) StartHook(chain consensus.ChainHeaderReader, header, parentHeader *types.Header, state *state.StateDB) error {
565+
return nil
566+
}
567+
564568
// Finalize implements consensus.Engine, ensuring no uncles are set, nor block
565569
// rewards given.
566570
func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {

consensus/consensus.go

+4
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ type Engine interface {
8181
// rules of a particular engine. The changes are executed inline.
8282
Prepare(chain ChainHeaderReader, header *types.Header) error
8383

84+
// StartHook calling before start apply transactions of block
85+
//StartHook(chain consensus.ChainHeaderReader, header *types.Header, preHeader *types.Header, state *state.StateDB) error
86+
StartHook(chain ChainHeaderReader, header, parentHeader *types.Header, state *state.StateDB) error
87+
8488
// Finalize runs any post-transaction state modifications (e.g. block rewards)
8589
// but does not assemble the block.
8690
//

consensus/ethash/consensus.go

+4
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,10 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H
590590
return nil
591591
}
592592

593+
func (ethash *Ethash) StartHook(chain consensus.ChainHeaderReader, header, preHeader *types.Header, state *state.StateDB) error {
594+
return nil
595+
}
596+
593597
// Finalize implements consensus.Engine, accumulating the block and uncle rewards,
594598
// setting the final state on the header
595599
func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {

consensus/l2/consensus.go

+51
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ import (
88
"github.com/morph-l2/go-ethereum/common"
99
"github.com/morph-l2/go-ethereum/consensus"
1010
"github.com/morph-l2/go-ethereum/consensus/misc"
11+
"github.com/morph-l2/go-ethereum/contracts/l2staking"
12+
"github.com/morph-l2/go-ethereum/core"
1113
"github.com/morph-l2/go-ethereum/core/state"
1214
"github.com/morph-l2/go-ethereum/core/types"
15+
"github.com/morph-l2/go-ethereum/core/vm"
1316
"github.com/morph-l2/go-ethereum/params"
17+
"github.com/morph-l2/go-ethereum/rollup/rcfg"
1418
"github.com/morph-l2/go-ethereum/rpc"
1519
"github.com/morph-l2/go-ethereum/trie"
1620
)
@@ -32,6 +36,26 @@ var (
3236
errInvalidCoinbase = errors.New("invalid coinbase")
3337
)
3438

39+
// chain context
40+
type chainContext struct {
41+
Chain consensus.ChainHeaderReader
42+
engine consensus.Engine
43+
}
44+
45+
func (c chainContext) Engine() consensus.Engine {
46+
return c.engine
47+
}
48+
49+
func (c chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
50+
return c.Chain.GetHeader(hash, number)
51+
}
52+
53+
func (c chainContext) Config() *params.ChainConfig {
54+
return c.Chain.Config()
55+
}
56+
57+
var _ = consensus.Engine(&Consensus{})
58+
3559
type Consensus struct {
3660
ethone consensus.Engine // Original consensus engine used in eth1, e.g. ethash or clique
3761
config *params.ChainConfig
@@ -194,6 +218,25 @@ func (l2 *Consensus) Prepare(chain consensus.ChainHeaderReader, header *types.He
194218
return nil
195219
}
196220

221+
// StartHook implements calling before start apply transactions of block
222+
func (l2 *Consensus) StartHook(chain consensus.ChainHeaderReader, header, preHeader *types.Header, state *state.StateDB) error {
223+
cx := chainContext{Chain: chain, engine: l2.ethone}
224+
blockContext := core.NewEVMBlockContext(header, cx, l2.config, nil)
225+
// TODO tracer
226+
evm := vm.NewEVM(blockContext, vm.TxContext{}, state, l2.config, vm.Config{Tracer: nil})
227+
stakingAbi, err := l2staking.L2StakingMetaData.GetAbi()
228+
if err != nil {
229+
return err
230+
}
231+
data, err := stakingAbi.Pack("recordBlocks", preHeader.Coinbase)
232+
if err != nil {
233+
return err
234+
}
235+
systemAddress := vm.AccountRef(rcfg.SystemAddress)
236+
_, _, err = evm.Call(systemAddress, rcfg.L2StakingAddress, data, 210000, common.Big0)
237+
return err
238+
}
239+
197240
// Finalize implements consensus.Engine, setting the final state on the header
198241
func (l2 *Consensus) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {
199242
// The block reward is no longer handled here. It's done by the
@@ -243,3 +286,11 @@ func (l2 *Consensus) APIs(chain consensus.ChainHeaderReader) []rpc.API {
243286
func (l2 *Consensus) Close() error {
244287
return l2.ethone.Close()
245288
}
289+
290+
//type XX struct {
291+
// consensus.ChainHeaderReader
292+
//}
293+
//
294+
//func (l2 *Consensus) Engine() consensus.Engine {
295+
// return l2.ethone
296+
//}

contracts/l2staking/l2staking.go

+3,614
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/state_processor.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
9292
blockContext := NewEVMBlockContext(header, p.bc, p.config, nil)
9393
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
9494
processorBlockTransactionGauge.Update(int64(block.Transactions().Len()))
95+
parentHeader := p.bc.GetHeaderByHash(block.ParentHash())
96+
if parentHeader == nil {
97+
// TODO
98+
}
99+
err := p.engine.StartHook(p.bc, header, parentHeader, statedb)
100+
if err != nil {
101+
return nil, nil, 0, err
102+
}
95103
// Iterate over and process the individual transactions
96104
for i, tx := range block.Transactions() {
97105
msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee)
@@ -108,7 +116,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
108116
}
109117
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
110118
finalizeBlockStartTime := time.Now()
111-
p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles())
112119
finalizeBlockTimer.Update(time.Since(finalizeBlockStartTime))
113120

114121
return receipts, allLogs, *usedGas, nil

rollup/rcfg/config.go

+6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ var (
3333
OverheadSlot = common.BigToHash(big.NewInt(2))
3434
ScalarSlot = common.BigToHash(big.NewInt(3))
3535

36+
// L2StakingAddress is the address of the l2 staking contract
37+
L2StakingAddress = common.HexToAddress("0x5300000000000000000000000000000000000015")
38+
39+
// SystemAddress is the address of the system
40+
SystemAddress = common.HexToAddress("0x5300000000000000000000000000000000000021")
41+
3642
// New fields added in the Curie hard fork
3743
L1BlobBaseFeeSlot = common.BigToHash(big.NewInt(6))
3844
CommitScalarSlot = common.BigToHash(big.NewInt(7))

rollup/tracing/tracing.go

+241
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,247 @@ func (env *TraceEnv) GetBlockTrace(block *types.Block) (*types.BlockTrace, error
272272
return env.fillBlockTrace(block)
273273
}
274274

275+
func (env *TraceEnv) getSystemResult(state *state.StateDB, block *types.Block) error {
276+
//tx := block.Transactions()[index]
277+
//msg, _ := tx.AsMessage(env.signer, block.BaseFee())
278+
//from, _ := types.Sender(env.signer, tx)
279+
//to := tx.To()
280+
281+
txctx := &Context{
282+
BlockHash: block.TxHash(),
283+
//TxIndex: index,
284+
//TxHash: tx.Hash(),
285+
}
286+
287+
sender := &types.AccountWrapper{
288+
Address: from,
289+
Nonce: state.GetNonce(from),
290+
Balance: (*hexutil.Big)(state.GetBalance(from)),
291+
KeccakCodeHash: state.GetKeccakCodeHash(from),
292+
PoseidonCodeHash: state.GetPoseidonCodeHash(from),
293+
CodeSize: state.GetCodeSize(from),
294+
}
295+
var receiver *types.AccountWrapper
296+
if to != nil {
297+
receiver = &types.AccountWrapper{
298+
Address: *to,
299+
Nonce: state.GetNonce(*to),
300+
Balance: (*hexutil.Big)(state.GetBalance(*to)),
301+
KeccakCodeHash: state.GetKeccakCodeHash(*to),
302+
PoseidonCodeHash: state.GetPoseidonCodeHash(*to),
303+
CodeSize: state.GetCodeSize(*to),
304+
}
305+
}
306+
307+
txContext := core.NewEVMTxContext(msg)
308+
tracerContext := tracers.Context{
309+
BlockHash: block.Hash(),
310+
//TxIndex: index,
311+
//TxHash: tx.Hash(),
312+
}
313+
callTracer, err := tracers.New("callTracer", &tracerContext, nil)
314+
if err != nil {
315+
return fmt.Errorf("failed to create callTracer: %w", err)
316+
}
317+
318+
applyMessageStart := time.Now()
319+
structLogger := vm.NewStructLogger(env.logConfig)
320+
tracer := NewMuxTracer(structLogger, callTracer)
321+
// Run the transaction with tracing enabled.
322+
vmenv := vm.NewEVM(env.blockCtx, txContext, state, env.chainConfig, vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
323+
324+
// Call Prepare to clear out the statedb access list
325+
state.SetTxContext(txctx.TxHash, txctx.TxIndex)
326+
327+
// Computes the new state by applying the given message.
328+
//l1DataFee, err := fees.CalculateL1DataFee(tx, state, env.chainConfig, block.Number())
329+
//if err != nil {
330+
// return err
331+
//}
332+
//result, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee)
333+
if err != nil {
334+
getTxResultApplyMessageTimer.UpdateSince(applyMessageStart)
335+
return err
336+
}
337+
getTxResultApplyMessageTimer.UpdateSince(applyMessageStart)
338+
339+
// If the result contains a revert reason, return it.
340+
returnVal := result.Return()
341+
if len(result.Revert()) > 0 {
342+
returnVal = result.Revert()
343+
}
344+
345+
createdAcc := structLogger.CreatedAccount()
346+
var after []*types.AccountWrapper
347+
if to == nil {
348+
if createdAcc == nil {
349+
return errors.New("unexpected tx: address for created contract unavailable")
350+
}
351+
to = &createdAcc.Address
352+
}
353+
// collect affected account after tx being applied
354+
for _, acc := range []common.Address{from, *to, env.coinbase} {
355+
after = append(after, &types.AccountWrapper{
356+
Address: acc,
357+
Nonce: state.GetNonce(acc),
358+
Balance: (*hexutil.Big)(state.GetBalance(acc)),
359+
KeccakCodeHash: state.GetKeccakCodeHash(acc),
360+
PoseidonCodeHash: state.GetPoseidonCodeHash(acc),
361+
CodeSize: state.GetCodeSize(acc),
362+
})
363+
}
364+
365+
//txStorageTrace := &types.StorageTrace{
366+
// Proofs: make(map[string][]hexutil.Bytes),
367+
// StorageProofs: make(map[string]map[string][]hexutil.Bytes),
368+
//}
369+
//// still we have no state root for per tx, only set the head and tail
370+
//if index == 0 {
371+
// txStorageTrace.RootBefore = state.GetRootHash()
372+
//}
373+
//if index == len(block.Transactions())-1 {
374+
// txStorageTrace.RootAfter = block.Root()
375+
//}
376+
377+
// merge bytecodes
378+
env.cMu.Lock()
379+
for codeHash, codeInfo := range structLogger.TracedBytecodes() {
380+
if codeHash != (common.Hash{}) {
381+
env.Codes[codeHash] = codeInfo
382+
}
383+
}
384+
env.cMu.Unlock()
385+
386+
// merge required proof data
387+
proofAccounts := structLogger.UpdatedAccounts()
388+
proofAccounts[vmenv.FeeRecipient()] = struct{}{}
389+
// add from/to address if it does not exist
390+
if _, ok := proofAccounts[from]; !ok {
391+
proofAccounts[from] = struct{}{}
392+
}
393+
if _, ok := proofAccounts[*to]; !ok {
394+
proofAccounts[*to] = struct{}{}
395+
}
396+
for addr := range proofAccounts {
397+
addrStr := addr.String()
398+
399+
env.pMu.Lock()
400+
checkedProof, existed := env.Proofs[addrStr]
401+
if existed {
402+
txStorageTrace.Proofs[addrStr] = checkedProof
403+
}
404+
env.pMu.Unlock()
405+
if existed {
406+
continue
407+
}
408+
proof, err := state.GetProof(addr)
409+
if err != nil {
410+
log.Error("Proof not available", "address", addrStr, "error", err)
411+
// but we still mark the proofs map with nil array
412+
}
413+
wrappedProof := types.WrapProof(proof)
414+
env.pMu.Lock()
415+
env.Proofs[addrStr] = wrappedProof
416+
txStorageTrace.Proofs[addrStr] = wrappedProof
417+
env.pMu.Unlock()
418+
}
419+
420+
zkTrieBuildStart := time.Now()
421+
proofStorages := structLogger.UpdatedStorages()
422+
for addr, keys := range proofStorages {
423+
if _, existed := txStorageTrace.StorageProofs[addr.String()]; !existed {
424+
txStorageTrace.StorageProofs[addr.String()] = make(map[string][]hexutil.Bytes)
425+
}
426+
427+
env.sMu.Lock()
428+
trie, err := state.GetStorageTrieForProof(addr)
429+
if err != nil {
430+
// but we still continue to next address
431+
log.Error("Storage trie not available", "error", err, "address", addr)
432+
env.sMu.Unlock()
433+
continue
434+
}
435+
zktrieTracer := state.NewProofTracer(trie)
436+
env.sMu.Unlock()
437+
438+
for key := range keys {
439+
addrStr := addr.String()
440+
keyStr := key.String()
441+
value := state.GetState(addr, key)
442+
isDelete := bytes.Equal(value.Bytes(), common.Hash{}.Bytes())
443+
444+
txm := txStorageTrace.StorageProofs[addrStr]
445+
env.sMu.Lock()
446+
m, existed := env.StorageProofs[addrStr]
447+
if !existed {
448+
m = make(map[string][]hexutil.Bytes)
449+
env.StorageProofs[addrStr] = m
450+
}
451+
if zktrieTracer.Available() && !env.ZkTrieTracer[addrStr].Available() {
452+
env.ZkTrieTracer[addrStr] = state.NewProofTracer(trie)
453+
}
454+
455+
if proof, existed := m[keyStr]; existed {
456+
txm[keyStr] = proof
457+
// still need to touch tracer for deletion
458+
if isDelete && zktrieTracer.Available() {
459+
env.ZkTrieTracer[addrStr].MarkDeletion(key)
460+
}
461+
env.sMu.Unlock()
462+
continue
463+
}
464+
env.sMu.Unlock()
465+
466+
var proof [][]byte
467+
var err error
468+
if zktrieTracer.Available() {
469+
proof, err = state.GetSecureTrieProof(zktrieTracer, key)
470+
} else {
471+
proof, err = state.GetSecureTrieProof(trie, key)
472+
}
473+
if err != nil {
474+
log.Error("Storage proof not available", "error", err, "address", addrStr, "key", keyStr)
475+
// but we still mark the proofs map with nil array
476+
}
477+
wrappedProof := types.WrapProof(proof)
478+
env.sMu.Lock()
479+
txm[keyStr] = wrappedProof
480+
m[keyStr] = wrappedProof
481+
if zktrieTracer.Available() {
482+
if isDelete {
483+
zktrieTracer.MarkDeletion(key)
484+
}
485+
env.ZkTrieTracer[addrStr].Merge(zktrieTracer)
486+
}
487+
env.sMu.Unlock()
488+
}
489+
}
490+
getTxResultZkTrieBuildTimer.UpdateSince(zkTrieBuildStart)
491+
492+
tracerResultTimer := time.Now()
493+
callTrace, err := callTracer.GetResult()
494+
if err != nil {
495+
return fmt.Errorf("failed to get callTracer result: %w", err)
496+
}
497+
getTxResultTracerResultTimer.UpdateSince(tracerResultTimer)
498+
499+
env.ExecutionResults[index] = &types.ExecutionResult{
500+
From: sender,
501+
To: receiver,
502+
AccountCreated: createdAcc,
503+
AccountsAfter: after,
504+
L1DataFee: (*hexutil.Big)(result.L1DataFee),
505+
Gas: result.UsedGas,
506+
Failed: result.Failed(),
507+
ReturnValue: fmt.Sprintf("%x", returnVal),
508+
StructLogs: vm.FormatLogs(structLogger.StructLogs()),
509+
CallTrace: callTrace,
510+
}
511+
env.TxStorageTraces[index] = txStorageTrace
512+
513+
return nil
514+
}
515+
275516
func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.Block) error {
276517
tx := block.Transactions()[index]
277518
msg, _ := tx.AsMessage(env.signer, block.BaseFee())

0 commit comments

Comments
 (0)