mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
parent
76756cea1c
commit
261983dbdb
1 changed files with 203 additions and 0 deletions
203
core/types/l2trace.go
Normal file
203
core/types/l2trace.go
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BlockTrace contains block execution traces and results required for rollers.
|
||||||
|
type BlockTrace struct {
|
||||||
|
ChainID uint64 `json:"chainID"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Coinbase *AccountWrapper `json:"coinbase"`
|
||||||
|
Header *Header `json:"header"`
|
||||||
|
Transactions []*TransactionData `json:"transactions"`
|
||||||
|
StorageTrace *StorageTrace `json:"storageTrace"`
|
||||||
|
TxStorageTraces []*StorageTrace `json:"txStorageTraces,omitempty"`
|
||||||
|
ExecutionResults []*ExecutionResult `json:"executionResults"`
|
||||||
|
MPTWitness *json.RawMessage `json:"mptwitness,omitempty"`
|
||||||
|
WithdrawTrieRoot common.Hash `json:"withdraw_trie_root,omitempty"`
|
||||||
|
StartL1QueueIndex uint64 `json:"startL1QueueIndex"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StorageTrace stores proofs of storage needed by storage circuit
|
||||||
|
type StorageTrace struct {
|
||||||
|
// Root hash before block execution:
|
||||||
|
RootBefore common.Hash `json:"rootBefore,omitempty"`
|
||||||
|
// Root hash after block execution, is nil if execution has failed
|
||||||
|
RootAfter common.Hash `json:"rootAfter,omitempty"`
|
||||||
|
|
||||||
|
// All proofs BEFORE execution, for accounts which would be used in tracing
|
||||||
|
Proofs map[string][]hexutil.Bytes `json:"proofs"`
|
||||||
|
|
||||||
|
// All storage proofs BEFORE execution
|
||||||
|
StorageProofs map[string]map[string][]hexutil.Bytes `json:"storageProofs,omitempty"`
|
||||||
|
|
||||||
|
// Node entries for deletion, no need to distinguish what it is from, just read them
|
||||||
|
// into the partial db
|
||||||
|
DeletionProofs []hexutil.Bytes `json:"deletionProofs,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecutionResult groups all structured logs emitted by the EVM
|
||||||
|
// while replaying a transaction in debug mode as well as transaction
|
||||||
|
// execution status, the amount of gas used and the return value
|
||||||
|
type ExecutionResult struct {
|
||||||
|
L1DataFee *hexutil.Big `json:"l1DataFee,omitempty"`
|
||||||
|
Gas uint64 `json:"gas"`
|
||||||
|
Failed bool `json:"failed"`
|
||||||
|
ReturnValue string `json:"returnValue"`
|
||||||
|
// Sender's account state (before Tx)
|
||||||
|
From *AccountWrapper `json:"from,omitempty"`
|
||||||
|
// Receiver's account state (before Tx)
|
||||||
|
To *AccountWrapper `json:"to,omitempty"`
|
||||||
|
// AccountCreated record the account if the tx is "create"
|
||||||
|
// (for creating inside a contract, we just handle CREATE op)
|
||||||
|
AccountCreated *AccountWrapper `json:"accountCreated,omitempty"`
|
||||||
|
|
||||||
|
// Record all accounts' state which would be affected AFTER tx executed
|
||||||
|
// currently they are just `from` and `to` account
|
||||||
|
AccountsAfter []*AccountWrapper `json:"accountAfter"`
|
||||||
|
|
||||||
|
// `PoseidonCodeHash` only exists when tx is a contract call.
|
||||||
|
PoseidonCodeHash *common.Hash `json:"poseidonCodeHash,omitempty"`
|
||||||
|
// If it is a contract call, the contract code is returned.
|
||||||
|
ByteCode string `json:"byteCode,omitempty"`
|
||||||
|
StructLogs []*StructLogRes `json:"structLogs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructLogRes stores a structured log emitted by the EVM while replaying a
|
||||||
|
// transaction in debug mode
|
||||||
|
type StructLogRes struct {
|
||||||
|
Pc uint64 `json:"pc"`
|
||||||
|
Op string `json:"op"`
|
||||||
|
Gas uint64 `json:"gas"`
|
||||||
|
GasCost uint64 `json:"gasCost"`
|
||||||
|
Depth int `json:"depth"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
Stack []string `json:"stack,omitempty"`
|
||||||
|
Memory []string `json:"memory,omitempty"`
|
||||||
|
Storage map[string]string `json:"storage,omitempty"`
|
||||||
|
RefundCounter uint64 `json:"refund,omitempty"`
|
||||||
|
ExtraData *ExtraData `json:"extraData,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStructLogResBasic Basic StructLogRes skeleton, Stack&Memory&Storage&ExtraData are separated from it for GC optimization;
|
||||||
|
// still need to fill in with Stack&Memory&Storage&ExtraData
|
||||||
|
func NewStructLogResBasic(pc uint64, op string, gas, gasCost uint64, depth int, refundCounter uint64, err error) *StructLogRes {
|
||||||
|
logRes := &StructLogRes{
|
||||||
|
Pc: pc,
|
||||||
|
Op: op,
|
||||||
|
Gas: gas,
|
||||||
|
GasCost: gasCost,
|
||||||
|
Depth: depth,
|
||||||
|
RefundCounter: refundCounter,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logRes.Error = err.Error()
|
||||||
|
}
|
||||||
|
return logRes
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExtraData struct {
|
||||||
|
// Indicate the call succeeds or not for CALL/CREATE op
|
||||||
|
CallFailed bool `json:"callFailed,omitempty"`
|
||||||
|
// CALL | CALLCODE | DELEGATECALL | STATICCALL: [tx.to address’s code, stack.nth_last(1) address’s code]
|
||||||
|
// CREATE | CREATE2: [created contract’s code]
|
||||||
|
// CODESIZE | CODECOPY: [contract’s code]
|
||||||
|
// EXTCODESIZE | EXTCODECOPY: [stack.nth_last(0) address’s code]
|
||||||
|
CodeList []string `json:"codeList,omitempty"`
|
||||||
|
// SSTORE | SLOAD: [storageProof]
|
||||||
|
// SELFDESTRUCT: [contract address’s account, stack.nth_last(0) address’s account]
|
||||||
|
// SELFBALANCE: [contract address’s account]
|
||||||
|
// BALANCE | EXTCODEHASH: [stack.nth_last(0) address’s account]
|
||||||
|
// CREATE | CREATE2: [created contract address’s account (before constructed),
|
||||||
|
// created contract address's account (after constructed)]
|
||||||
|
// CALL | CALLCODE: [caller contract address’s account,
|
||||||
|
// stack.nth_last(1) (i.e. callee) address’s account,
|
||||||
|
// callee contract address's account (value updated, before called)]
|
||||||
|
// STATICCALL: [stack.nth_last(1) (i.e. callee) address’s account,
|
||||||
|
// callee contract address's account (before called)]
|
||||||
|
StateList []*AccountWrapper `json:"proofList,omitempty"`
|
||||||
|
// The status of caller, it would be captured twice:
|
||||||
|
// 1. before execution and 2. updated in CaptureEnter (for CALL/CALLCODE it duplicated with StateList[0])
|
||||||
|
Caller []*AccountWrapper `json:"caller,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccountWrapper struct {
|
||||||
|
Address common.Address `json:"address"`
|
||||||
|
Nonce uint64 `json:"nonce"`
|
||||||
|
Balance *hexutil.Big `json:"balance"`
|
||||||
|
KeccakCodeHash common.Hash `json:"keccakCodeHash,omitempty"`
|
||||||
|
PoseidonCodeHash common.Hash `json:"poseidonCodeHash,omitempty"`
|
||||||
|
CodeSize uint64 `json:"codeSize"`
|
||||||
|
Storage *StorageWrapper `json:"storage,omitempty"` // StorageWrapper can be empty if irrelated to storage operation
|
||||||
|
}
|
||||||
|
|
||||||
|
// StorageWrapper while key & value can also be retrieved from StructLogRes.Storage,
|
||||||
|
// we still stored in here for roller's processing convenience.
|
||||||
|
type StorageWrapper struct {
|
||||||
|
Key string `json:"key,omitempty"`
|
||||||
|
Value string `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TransactionData struct {
|
||||||
|
Type uint8 `json:"type"`
|
||||||
|
Nonce uint64 `json:"nonce"`
|
||||||
|
TxHash string `json:"txHash"`
|
||||||
|
Gas uint64 `json:"gas"`
|
||||||
|
GasPrice *hexutil.Big `json:"gasPrice"`
|
||||||
|
From common.Address `json:"from"`
|
||||||
|
To *common.Address `json:"to"`
|
||||||
|
ChainId *hexutil.Big `json:"chainId"`
|
||||||
|
Value *hexutil.Big `json:"value"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
IsCreate bool `json:"isCreate"`
|
||||||
|
V *hexutil.Big `json:"v"`
|
||||||
|
R *hexutil.Big `json:"r"`
|
||||||
|
S *hexutil.Big `json:"s"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTransactionData returns a transaction that will serialize to the trace
|
||||||
|
// representation, with the given location metadata set (if available).
|
||||||
|
func NewTransactionData(tx *Transaction, blockNumber uint64, blockTime uint64, config *params.ChainConfig) *TransactionData {
|
||||||
|
signer := MakeSigner(config, big.NewInt(0).SetUint64(blockNumber), blockTime)
|
||||||
|
from, _ := Sender(signer, tx)
|
||||||
|
v, r, s := tx.RawSignatureValues()
|
||||||
|
|
||||||
|
nonce := tx.Nonce()
|
||||||
|
if tx.IsL1MessageTx() {
|
||||||
|
nonce = tx.L1MessageQueueIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &TransactionData{
|
||||||
|
Type: tx.Type(),
|
||||||
|
TxHash: tx.Hash().String(),
|
||||||
|
Nonce: nonce,
|
||||||
|
ChainId: (*hexutil.Big)(tx.ChainId()),
|
||||||
|
From: from,
|
||||||
|
Gas: tx.Gas(),
|
||||||
|
GasPrice: (*hexutil.Big)(tx.GasPrice()),
|
||||||
|
To: tx.To(),
|
||||||
|
Value: (*hexutil.Big)(tx.Value()),
|
||||||
|
Data: hexutil.Encode(tx.Data()),
|
||||||
|
IsCreate: tx.To() == nil,
|
||||||
|
V: (*hexutil.Big)(v),
|
||||||
|
R: (*hexutil.Big)(r),
|
||||||
|
S: (*hexutil.Big)(s),
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapProof turn the bytes array into proof type (array of hexutil.Bytes)
|
||||||
|
func WrapProof(proofBytes [][]byte) (wrappedProof []hexutil.Bytes) {
|
||||||
|
wrappedProof = make([]hexutil.Bytes, len(proofBytes))
|
||||||
|
for i, bt := range proofBytes {
|
||||||
|
wrappedProof[i] = bt
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue