feat(trace): Add header and upgrade TransactionTrace (#181)

* Add header and upgrade TransactionTrace

* Add header

* change blockResult struct

* rm chainID from TransactionData

* Rename blockResult to blockTrace in everywhere

* fix comments
This commit is contained in:
maskpp 2022-11-18 17:11:04 +08:00 committed by GitHub
parent f21acfee4a
commit 22963a115d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 88 additions and 134 deletions

View file

@ -21,9 +21,11 @@ var (
}
)
// BlockResult contains block execution traces and results required for rollers.
type BlockResult struct {
BlockTrace *BlockTrace `json:"blockTrace"`
// BlockTrace contains block execution traces and results required for rollers.
type BlockTrace struct {
Coinbase *AccountWrapper `json:"coinbase"`
Header *Header `json:"header"`
Transactions []*TransactionData `json:"transactions"`
StorageTrace *StorageTrace `json:"storageTrace"`
ExecutionResults []*ExecutionResult `json:"executionResults"`
MPTWitness *json.RawMessage `json:"mptwitness,omitempty"`

View file

@ -4,78 +4,23 @@ import (
"math/big"
"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/common/hexutil"
"github.com/scroll-tech/go-ethereum/params"
)
type BlockTrace struct {
Number *hexutil.Big `json:"number"`
Hash common.Hash `json:"hash"`
GasLimit uint64 `json:"gasLimit"`
Difficulty *hexutil.Big `json:"difficulty"`
BaseFee *hexutil.Big `json:"baseFee"`
Coinbase *AccountWrapper `json:"coinbase"`
Time uint64 `json:"time"`
Transactions []*TransactionTrace `json:"transactions"`
type TransactionData struct {
IsCreate bool `json:"isCreate"`
From common.Address `json:"from"`
*Transaction
}
type TransactionTrace 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"`
}
// NewTraceBlock supports necessary fields for roller.
func NewTraceBlock(config *params.ChainConfig, block *Block, coinbase *AccountWrapper) *BlockTrace {
txs := make([]*TransactionTrace, block.Transactions().Len())
for i, tx := range block.Transactions() {
txs[i] = newTraceTransaction(tx, block.NumberU64(), config)
}
return &BlockTrace{
Number: (*hexutil.Big)(block.Number()),
Hash: block.Hash(),
GasLimit: block.GasLimit(),
Difficulty: (*hexutil.Big)(block.Difficulty()),
BaseFee: (*hexutil.Big)(block.BaseFee()),
Coinbase: coinbase,
Time: block.Time(),
Transactions: txs,
}
}
// newTraceTransaction returns a transaction that will serialize to the trace
// NewTraceTransaction returns a transaction that will serialize to the trace
// representation, with the given location metadata set (if available).
func newTraceTransaction(tx *Transaction, blockNumber uint64, config *params.ChainConfig) *TransactionTrace {
func NewTraceTransaction(tx *Transaction, blockNumber uint64, config *params.ChainConfig) *TransactionData {
signer := MakeSigner(config, big.NewInt(0).SetUint64(blockNumber))
from, _ := Sender(signer, tx)
v, r, s := tx.RawSignatureValues()
result := &TransactionTrace{
Type: tx.Type(),
TxHash: tx.Hash().String(),
Nonce: tx.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 &TransactionData{
From: from,
IsCreate: tx.To() == nil,
Transaction: tx,
}
return result
}

View file

@ -19,7 +19,7 @@ import (
)
type TraceBlock interface {
GetBlockResultByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (trace *types.BlockResult, err error)
GetBlockTraceByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (trace *types.BlockTrace, err error)
}
type traceEnv struct {
@ -42,8 +42,8 @@ type traceEnv struct {
executionResults []*types.ExecutionResult
}
// GetBlockResultByNumberOrHash replays the block and returns the structured BlockResult by hash or number.
func (api *API) GetBlockResultByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (trace *types.BlockResult, err error) {
// GetBlockTraceByNumberOrHash replays the block and returns the structured BlockTrace by hash or number.
func (api *API) GetBlockTraceByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (trace *types.BlockTrace, err error) {
var block *types.Block
if number, ok := blockNrOrHash.Number(); ok {
block, err = api.blockByNumber(ctx, number)
@ -75,7 +75,7 @@ func (api *API) GetBlockResultByNumberOrHash(ctx context.Context, blockNrOrHash
return nil, err
}
return api.getBlockResult(block, env)
return api.getBlockTrace(block, env)
}
// Make trace environment for current block.
@ -130,7 +130,7 @@ func (api *API) createTraceEnv(ctx context.Context, config *TraceConfig, block *
return env, nil
}
func (api *API) getBlockResult(block *types.Block, env *traceEnv) (*types.BlockResult, error) {
func (api *API) getBlockTrace(block *types.Block, env *traceEnv) (*types.BlockTrace, error) {
// Execute all the transaction contained within the block concurrently
var (
txs = block.Transactions()
@ -190,7 +190,7 @@ func (api *API) getBlockResult(block *types.Block, env *traceEnv) (*types.BlockR
}
}
return api.fillBlockResult(env, block)
return api.fillBlockTrace(env, block)
}
func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, block *types.Block) error {
@ -328,22 +328,29 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
return nil
}
// Fill blockResult content after all the txs are finished running.
func (api *API) fillBlockResult(env *traceEnv, block *types.Block) (*types.BlockResult, error) {
// Fill blockTrace content after all the txs are finished running.
func (api *API) fillBlockTrace(env *traceEnv, block *types.Block) (*types.BlockTrace, error) {
statedb := env.state
txs := block.Transactions()
coinbase := types.AccountWrapper{
Address: env.coinbase,
Nonce: statedb.GetNonce(env.coinbase),
Balance: (*hexutil.Big)(statedb.GetBalance(env.coinbase)),
CodeHash: statedb.GetCodeHash(env.coinbase),
txs := make([]*types.TransactionData, block.Transactions().Len())
for i, tx := range block.Transactions() {
txs[i] = types.NewTraceTransaction(tx, block.NumberU64(), api.backend.ChainConfig())
}
blockResult := &types.BlockResult{
BlockTrace: types.NewTraceBlock(api.backend.ChainConfig(), block, &coinbase),
blockTrace := &types.BlockTrace{
Coinbase: &types.AccountWrapper{
Address: env.coinbase,
Nonce: statedb.GetNonce(env.coinbase),
Balance: (*hexutil.Big)(statedb.GetBalance(env.coinbase)),
CodeHash: statedb.GetCodeHash(env.coinbase),
},
Header: block.Header(),
StorageTrace: env.StorageTrace,
ExecutionResults: env.executionResults,
Transactions: txs,
}
for i, tx := range txs {
for i, tx := range block.Transactions() {
evmTrace := env.executionResults[i]
// probably a Contract Call
if len(tx.Data()) != 0 && tx.To() != nil {
@ -358,10 +365,10 @@ func (api *API) fillBlockResult(env *traceEnv, block *types.Block) (*types.Block
// only zktrie model has the ability to get `mptwitness`.
if api.backend.ChainConfig().Zktrie {
if err := zkproof.FillBlockResultForMPTWitness(zkproof.MPTWitnessType(api.backend.CacheConfig().MPTWitness), blockResult); err != nil {
if err := zkproof.FillBlockTraceForMPTWitness(zkproof.MPTWitnessType(api.backend.CacheConfig().MPTWitness), blockTrace); err != nil {
log.Error("fill mpt witness fail", "error", err)
}
}
return blockResult, nil
return blockTrace, nil
}

File diff suppressed because one or more lines are too long

View file

@ -325,21 +325,21 @@ func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header)
return ec.c.EthSubscribe(ctx, ch, "newHeads")
}
// GetBlockResultByHash returns the BlockResult given the block hash.
func (ec *Client) GetBlockResultByHash(ctx context.Context, blockHash common.Hash) (*types.BlockResult, error) {
blockResult := &types.BlockResult{}
return blockResult, ec.c.CallContext(ctx, &blockResult, "scroll_getBlockResultByNumberOrHash", blockHash)
// GetBlockTraceByHash returns the BlockTrace given the block hash.
func (ec *Client) GetBlockTraceByHash(ctx context.Context, blockHash common.Hash) (*types.BlockTrace, error) {
blockTrace := &types.BlockTrace{}
return blockTrace, ec.c.CallContext(ctx, &blockTrace, "scroll_getBlockTraceByNumberOrHash", blockHash)
}
// GetBlockResultByNumber returns the BlockResult given the block number.
func (ec *Client) GetBlockResultByNumber(ctx context.Context, number *big.Int) (*types.BlockResult, error) {
blockResult := &types.BlockResult{}
return blockResult, ec.c.CallContext(ctx, &blockResult, "scroll_getBlockResultByNumberOrHash", toBlockNumArg(number))
// GetBlockTraceByNumber returns the BlockTrace given the block number.
func (ec *Client) GetBlockTraceByNumber(ctx context.Context, number *big.Int) (*types.BlockTrace, error) {
blockTrace := &types.BlockTrace{}
return blockTrace, ec.c.CallContext(ctx, &blockTrace, "scroll_getBlockTraceByNumberOrHash", toBlockNumArg(number))
}
// SubscribeNewBlockResult subscribes to block execution trace when a new block is created.
func (ec *Client) SubscribeNewBlockResult(ctx context.Context, ch chan<- *types.BlockResult) (ethereum.Subscription, error) {
return ec.c.EthSubscribe(ctx, ch, "newBlockResult")
// SubscribeNewBlockTrace subscribes to block execution trace when a new block is created.
func (ec *Client) SubscribeNewBlockTrace(ctx context.Context, ch chan<- *types.BlockTrace) (ethereum.Subscription, error) {
return ec.c.EthSubscribe(ctx, ch, "newBlockTrace")
}
// State Access

View file

@ -22,7 +22,7 @@ func init() {
}
}
func loadStaff(t *testing.T, fname string) *types.BlockResult {
func loadStaff(t *testing.T, fname string) *types.BlockTrace {
f, err := os.Open(fname)
if err != nil {
t.Fatal(err)
@ -33,7 +33,7 @@ func loadStaff(t *testing.T, fname string) *types.BlockResult {
t.Fatal(err)
}
out := new(types.BlockResult)
out := new(types.BlockTrace)
err = json.Unmarshal(bt, out)
if err != nil {
@ -84,7 +84,7 @@ func TestGreeterTx(t *testing.T) {
}
}
traces, err := zkproof.HandleBlockResult(trace)
traces, err := zkproof.HandleBlockTrace(trace)
t.Log("traces: ", len(traces))
outObj, _ := json.Marshal(traces)
t.Log(string(outObj))
@ -95,7 +95,7 @@ func TestGreeterTx(t *testing.T) {
func TestTokenTx(t *testing.T) {
trace := loadStaff(t, "blocktraces/mpt_witness/token.json")
traces, err := zkproof.HandleBlockResult(trace)
traces, err := zkproof.HandleBlockTrace(trace)
outObj, _ := json.Marshal(traces)
t.Log(string(outObj))
if err != nil {
@ -106,7 +106,7 @@ func TestTokenTx(t *testing.T) {
func TestCallTx(t *testing.T) {
trace := loadStaff(t, "blocktraces/mpt_witness/call.json")
traces, err := zkproof.HandleBlockResult(trace)
traces, err := zkproof.HandleBlockTrace(trace)
outObj, _ := json.Marshal(traces)
t.Log(string(outObj))
if err != nil {
@ -114,7 +114,7 @@ func TestCallTx(t *testing.T) {
}
trace = loadStaff(t, "blocktraces/mpt_witness/call_edge.json")
traces, err = zkproof.HandleBlockResult(trace)
traces, err = zkproof.HandleBlockTrace(trace)
outObj, _ = json.Marshal(traces)
t.Log(string(outObj))
if err != nil {
@ -124,7 +124,7 @@ func TestCallTx(t *testing.T) {
func TestCreateTx(t *testing.T) {
trace := loadStaff(t, "blocktraces/mpt_witness/create.json")
traces, err := zkproof.HandleBlockResult(trace)
traces, err := zkproof.HandleBlockTrace(trace)
outObj, _ := json.Marshal(traces)
t.Log(string(outObj))
if err != nil {
@ -132,7 +132,7 @@ func TestCreateTx(t *testing.T) {
}
trace = loadStaff(t, "blocktraces/mpt_witness/deploy.json")
traces, err = zkproof.HandleBlockResult(trace)
traces, err = zkproof.HandleBlockTrace(trace)
outObj, _ = json.Marshal(traces)
t.Log(string(outObj))
if err != nil {
@ -143,7 +143,7 @@ func TestCreateTx(t *testing.T) {
func TestFailedCallTx(t *testing.T) {
trace := loadStaff(t, "blocktraces/mpt_witness/fail_call.json")
traces, err := zkproof.HandleBlockResult(trace)
traces, err := zkproof.HandleBlockTrace(trace)
outObj, _ := json.Marshal(traces)
t.Log(string(outObj))
if err != nil {
@ -151,7 +151,7 @@ func TestFailedCallTx(t *testing.T) {
}
trace = loadStaff(t, "blocktraces/mpt_witness/fail_create.json")
traces, err = zkproof.HandleBlockResult(trace)
traces, err = zkproof.HandleBlockTrace(trace)
outObj, _ = json.Marshal(traces)
t.Log(string(outObj))
if err != nil {
@ -163,7 +163,7 @@ func TestFailedCallTx(t *testing.T) {
//notice: now only work with OP_ORDER=2
func TestDeleteTx(t *testing.T) {
trace := loadStaff(t, "blocktraces/mpt_witness/delete.json")
traces, err := zkproof.HandleBlockResult(trace)
traces, err := zkproof.HandleBlockTrace(trace)
outObj, _ := json.Marshal(traces)
t.Log(string(outObj))
if err != nil {
@ -174,7 +174,7 @@ func TestDeleteTx(t *testing.T) {
//notice: now only work with OP_ORDER=2
func TestDestructTx(t *testing.T) {
trace := loadStaff(t, "blocktraces/mpt_witness/destruct.json")
traces, err := zkproof.HandleBlockResult(trace)
traces, err := zkproof.HandleBlockTrace(trace)
outObj, _ := json.Marshal(traces)
t.Log(string(outObj))
if err != nil {
@ -184,7 +184,7 @@ func TestDestructTx(t *testing.T) {
func TestMutipleTx(t *testing.T) {
trace := loadStaff(t, "blocktraces/mpt_witness/multi_txs.json")
traces, err := zkproof.HandleBlockResult(trace)
traces, err := zkproof.HandleBlockTrace(trace)
outObj, _ := json.Marshal(traces)
t.Log(string(outObj))
if err != nil {

View file

@ -239,7 +239,7 @@ const (
posCALL = 2
posSTATICCALL = 0
// posSELFDESTRUCT = 2
// posSELFDESTRUCT = 2
)
func getAccountState(l *types.StructLogRes, pos int) *types.AccountWrapper {
@ -737,12 +737,12 @@ var usedOrdererScheme = defaultOrdererScheme
func SetOrderScheme(t MPTWitnessType) { usedOrdererScheme = t }
// HandleBlockResult only for backward compatibility
func HandleBlockResult(block *types.BlockResult) ([]*StorageTrace, error) {
return HandleBlockResultEx(block, usedOrdererScheme)
// HandleBlockTrace only for backward compatibility
func HandleBlockTrace(block *types.BlockTrace) ([]*StorageTrace, error) {
return HandleBlockTraceEx(block, usedOrdererScheme)
}
func HandleBlockResultEx(block *types.BlockResult, ordererScheme MPTWitnessType) ([]*StorageTrace, error) {
func HandleBlockTraceEx(block *types.BlockTrace, ordererScheme MPTWitnessType) ([]*StorageTrace, error) {
writer, err := NewZkTrieProofWriter(block.StorageTrace)
if err != nil {
@ -767,8 +767,8 @@ func HandleBlockResultEx(block *types.BlockResult, ordererScheme MPTWitnessType)
// notice some coinbase addr (like all zero) is in fact not exist and should not be update
// TODO: not a good solution, just for patch ...
if coinbaseData := writer.tracingAccounts[block.BlockTrace.Coinbase.Address]; coinbaseData != nil {
od.absorb(block.BlockTrace.Coinbase)
if coinbaseData := writer.tracingAccounts[block.Coinbase.Address]; coinbaseData != nil {
od.absorb(block.Coinbase)
}
opDisp := od.end_absorb()
@ -791,13 +791,13 @@ func HandleBlockResultEx(block *types.BlockResult, ordererScheme MPTWitnessType)
}
func FillBlockResultForMPTWitness(order MPTWitnessType, block *types.BlockResult) error {
func FillBlockTraceForMPTWitness(order MPTWitnessType, block *types.BlockTrace) error {
if order == MPTWitnessNothing {
return nil
}
trace, err := HandleBlockResultEx(block, order)
trace, err := HandleBlockTraceEx(block, order)
if err != nil {
return err
}