Skip to content

Commit 772eb0d

Browse files
committed
Porting EVM tracer + Firehose to seiv2
1 parent 63f89a5 commit 772eb0d

30 files changed

+6707
-85
lines changed

app/app.go

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,19 @@ import (
77
"encoding/json"
88
"fmt"
99
"io"
10+
"math/big"
1011
"os"
1112
"path/filepath"
1213
"strings"
1314
"sync"
1415
"time"
1516

17+
ethcommon "github.com/ethereum/go-ethereum/common"
18+
ethhexutil "github.com/ethereum/go-ethereum/common/hexutil"
19+
ethtypes "github.com/ethereum/go-ethereum/core/types"
1620
"github.com/ethereum/go-ethereum/ethclient"
1721
ethrpc "github.com/ethereum/go-ethereum/rpc"
22+
1823
"github.com/sei-protocol/sei-chain/app/antedecorators"
1924
"github.com/sei-protocol/sei-chain/evmrpc"
2025
"github.com/sei-protocol/sei-chain/precompiles"
@@ -124,6 +129,8 @@ import (
124129
"github.com/sei-protocol/sei-chain/x/evm/blocktest"
125130
evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper"
126131
"github.com/sei-protocol/sei-chain/x/evm/replay"
132+
evmtracers "github.com/sei-protocol/sei-chain/x/evm/tracers"
133+
"github.com/sei-protocol/sei-chain/x/evm/tracing"
127134
evmtypes "github.com/sei-protocol/sei-chain/x/evm/types"
128135
"github.com/spf13/cast"
129136
abci "github.com/tendermint/tendermint/abci/types"
@@ -373,6 +380,7 @@ type App struct {
373380

374381
encodingConfig appparams.EncodingConfig
375382
evmRPCConfig evmrpc.Config
383+
evmTracer *tracing.Hooks
376384
}
377385

378386
// New returns a reference to an initialized blockchain app
@@ -609,6 +617,20 @@ func New(
609617
app.EvmKeeper.EthClient = ethclient.NewClient(rpcclient)
610618
}
611619

620+
if app.evmRPCConfig.LiveEVMTracer != "" {
621+
// PR_REVIEW_NOTE: So I moved this code from `ProcessBlock` and there, I had access to `ctx` so the code was actually looking
622+
// like `evmtypes.DefaultChainConfig().EthereumConfig(app.EvmKeeper.ChainID(ctx))`. But here, I don't have access to `ctx`
623+
// Is there another mean to get the EVM chainID from here? I need it to call `OnSeiBlockchainInit` on the logger,
624+
// so another solution would be to call this one later when EVM chainID is known. Last resort, we have a sync.Once
625+
// that we can use to call it only once.
626+
chainConfig := evmtypes.DefaultChainConfig().EthereumConfig(big.NewInt(int64(app.evmRPCConfig.LiveEVMTracerChainID)))
627+
evmTracer, err := evmtracers.NewBlockchainTracer(evmtracers.GlobalLiveTracerRegistry, app.evmRPCConfig.LiveEVMTracer, chainConfig)
628+
if err != nil {
629+
panic(fmt.Sprintf("error creating EVM tracer due to %s", err))
630+
}
631+
app.evmTracer = evmTracer
632+
}
633+
612634
customDependencyGenerators := aclmapping.NewCustomDependencyGenerator()
613635
aclOpts = append(aclOpts, aclkeeper.WithResourceTypeToStoreKeyMap(aclutils.ResourceTypeToStoreKeyMap))
614636
aclOpts = append(aclOpts, aclkeeper.WithDependencyGeneratorMappings(customDependencyGenerators.GetCustomDependencyGenerators(app.EvmKeeper)))
@@ -1401,12 +1423,23 @@ func (app *App) ProcessTXsWithOCC(ctx sdk.Context, txs [][]byte, typedTxs []sdk.
14011423
wg.Add(1)
14021424
go func(txIndex int, tx []byte) {
14031425
defer wg.Done()
1426+
1427+
var txTracer sdk.TxTracer
1428+
if app.evmTracer != nil {
1429+
txTracer = app.evmTracer
1430+
if app.evmTracer.GetTxTracer != nil {
1431+
txTracer = app.evmTracer.GetTxTracer(absoluteTxIndices[txIndex])
1432+
}
1433+
}
1434+
14041435
deliverTxEntry := &sdk.DeliverTxEntry{
14051436
Request: abci.RequestDeliverTx{Tx: tx},
14061437
SdkTx: typedTxs[txIndex],
14071438
Checksum: sha256.Sum256(tx),
14081439
AbsoluteIndex: absoluteTxIndices[txIndex],
1440+
TxTracer: txTracer,
14091441
}
1442+
14101443
// get prefill estimate
14111444
estimatedWritesets, err := app.AccessControlKeeper.GenerateEstimatedWritesets(ctx, app.GetAnteDepGenerator(), txIndex, typedTxs[txIndex])
14121445
// if no error, then we assign the mapped writesets for prefill estimate
@@ -1466,12 +1499,17 @@ func (app *App) BuildDependenciesAndRunTxs(ctx sdk.Context, txs [][]byte, typedT
14661499
return app.ProcessBlockSynchronous(ctx, txs, typedTxs, absoluteTxIndices), ctx
14671500
}
14681501

1469-
func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequest, lastCommit abci.CommitInfo) ([]abci.Event, []*abci.ExecTxResult, abci.ResponseEndBlock, error) {
1502+
func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequest, lastCommit abci.CommitInfo) (events []abci.Event, txResults []*abci.ExecTxResult, endBlockResp abci.ResponseEndBlock, err error) {
14701503
ctx = ctx.WithIsOCCEnabled(app.OccEnabled())
1504+
14711505
goCtx := app.decorateContextWithDexMemState(ctx.Context())
14721506
ctx = ctx.WithContext(goCtx)
14731507

1474-
events := []abci.Event{}
1508+
if app.evmTracer != nil {
1509+
ctx = evmtracers.SetCtxBlockchainTracer(ctx, app.evmTracer)
1510+
}
1511+
1512+
events = []abci.Event{}
14751513
beginBlockReq := abci.RequestBeginBlock{
14761514
Hash: req.GetHash(),
14771515
ByzantineValidators: utils.Map(req.GetByzantineValidators(), func(mis abci.Misbehavior) abci.Evidence {
@@ -1496,9 +1534,16 @@ func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequ
14961534
beginBlockResp := app.BeginBlock(ctx, beginBlockReq)
14971535
events = append(events, beginBlockResp.Events...)
14981536

1499-
txResults := make([]*abci.ExecTxResult, len(txs))
1537+
txResults = make([]*abci.ExecTxResult, len(txs))
15001538
typedTxs := app.DecodeTransactionsConcurrently(ctx, txs)
15011539

1540+
if app.evmTracer != nil {
1541+
header := ctx.BlockHeader()
1542+
app.evmTracer.OnSeiBlockStart(req.GetHash(), uint64(header.Size()), TmBlockHeaderToEVM(ctx, header, &app.EvmKeeper))
1543+
defer func() {
1544+
app.evmTracer.OnSeiBlockEnd(err)
1545+
}()
1546+
}
15021547
prioritizedTxs, otherTxs, prioritizedTypedTxs, otherTypedTxs, prioritizedIndices, otherIndices := app.PartitionPrioritizedTxs(ctx, txs, typedTxs)
15031548

15041549
// run the prioritized txs
@@ -1524,7 +1569,7 @@ func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequ
15241569
lazyWriteEvents := app.BankKeeper.WriteDeferredBalances(ctx)
15251570
events = append(events, lazyWriteEvents...)
15261571

1527-
endBlockResp := app.EndBlock(ctx, abci.RequestEndBlock{
1572+
endBlockResp = app.EndBlock(ctx, abci.RequestEndBlock{
15281573
Height: req.GetHeight(),
15291574
})
15301575

@@ -1835,3 +1880,38 @@ func init() {
18351880
// override max wasm size to 2MB
18361881
wasmtypes.MaxWasmSize = 2 * 1024 * 1024
18371882
}
1883+
1884+
func TmBlockHeaderToEVM(
1885+
ctx sdk.Context,
1886+
block tmproto.Header,
1887+
k *evmkeeper.Keeper,
1888+
) (header *ethtypes.Header) {
1889+
number := big.NewInt(block.Height)
1890+
lastHash := ethcommon.BytesToHash(block.LastBlockId.Hash)
1891+
appHash := ethcommon.BytesToHash(block.AppHash)
1892+
txHash := ethcommon.BytesToHash(block.DataHash)
1893+
resultHash := ethcommon.BytesToHash(block.LastResultsHash)
1894+
miner := ethcommon.BytesToAddress(block.ProposerAddress)
1895+
gasLimit, gasWanted := uint64(0), uint64(0)
1896+
1897+
header = &ethtypes.Header{
1898+
Number: number,
1899+
ParentHash: lastHash,
1900+
Nonce: ethtypes.BlockNonce{}, // inapplicable to Sei
1901+
MixDigest: ethcommon.Hash{}, // inapplicable to Sei
1902+
UncleHash: ethtypes.EmptyUncleHash, // inapplicable to Sei
1903+
Bloom: k.GetBlockBloom(ctx, block.Height),
1904+
Root: appHash,
1905+
Coinbase: miner,
1906+
Difficulty: big.NewInt(0), // inapplicable to Sei
1907+
Extra: ethhexutil.Bytes{}, // inapplicable to Sei
1908+
GasLimit: gasLimit,
1909+
GasUsed: gasWanted,
1910+
Time: uint64(block.Time.Unix()),
1911+
TxHash: txHash,
1912+
ReceiptHash: resultHash,
1913+
BaseFee: k.GetBaseFeePerGas(ctx).RoundInt().BigInt(),
1914+
}
1915+
1916+
return
1917+
}

app/eth_replay.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/cosmos/cosmos-sdk/client"
1212
sdk "github.com/cosmos/cosmos-sdk/types"
13+
ethtracing "github.com/ethereum/go-ethereum/core/tracing"
1314
ethtypes "github.com/ethereum/go-ethereum/core/types"
1415
"github.com/ethereum/go-ethereum/params"
1516
ethtests "github.com/ethereum/go-ethereum/tests"
@@ -81,7 +82,7 @@ func Replay(a *App) {
8182
for _, w := range b.Withdrawals() {
8283
amount := new(big.Int).SetUint64(w.Amount)
8384
amount = amount.Mul(amount, big.NewInt(params.GWei))
84-
s.AddBalance(w.Address, amount)
85+
s.AddBalance(w.Address, amount, ethtracing.BalanceIncreaseWithdrawal)
8586
}
8687
_, _ = s.Finalize()
8788
for _, tx := range b.Txs {

buf.gen.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: v1
2+
plugins:
3+
- plugin: buf.build/protocolbuffers/go:v1.31.0
4+
out: pb
5+
opt: paths=source_relative
6+

evmrpc/config.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,22 @@ type Config struct {
5353
// Timeout for EVM call in simulation
5454
SimulationEVMTimeout time.Duration `mapstructure:"simulation_evm_timeout"`
5555

56+
// The EVM tracer to use when doing node synchronization, applies to
57+
// all block produced but traces only EVM transactions.
58+
//
59+
// Refer to <TBC> for registered tracers
60+
//
61+
// PR_REVIEW_NOTE: It his an acceptable way of documenting the available tracers?
62+
// PR_REVIEW_NOTE: This section renders as `[evm]` in config but is named EVMRPC on top,
63+
// is live tracing of block synchronization should be here? Maybe "higher"
64+
// in the config hierarchy? We might think also about a way that later, we could
65+
// different trace active for Cosmos related function and EVM related function.
66+
LiveEVMTracer string `mapstructure:"live_evm_tracer"`
67+
68+
// PR_REVIEW_NOTE: This is a hackish workaround because I didn't how to get it in `app/app.go#New`,
69+
// this will not be part of the final PR.
70+
LiveEVMTracerChainID int `mapstructure:"live_evm_tracer_chain_id"`
71+
5672
// list of CORS allowed origins, separated by comma
5773
CORSOrigins string `mapstructure:"cors_origins"`
5874

@@ -113,6 +129,9 @@ const (
113129
flagCheckTxTimeout = "evm.checktx_timeout"
114130
flagSlow = "evm.slow"
115131
flagDenyList = "evm.deny_list"
132+
flagLiveEVMTracer = "evm.live_evm_tracer"
133+
// PR_REVIEW_NOTE: This is going to go away, temporary hack
134+
flagLiveEVMTracerChainID = "evm.live_evm_tracer_chain_id"
116135
)
117136

118137
func ReadConfig(opts servertypes.AppOptions) (Config, error) {
@@ -203,5 +222,16 @@ func ReadConfig(opts servertypes.AppOptions) (Config, error) {
203222
return cfg, err
204223
}
205224
}
225+
if v := opts.Get(flagLiveEVMTracer); v != nil {
226+
if cfg.LiveEVMTracer, err = cast.ToStringE(v); err != nil {
227+
return cfg, err
228+
}
229+
}
230+
if v := opts.Get(flagLiveEVMTracerChainID); v != nil {
231+
if cfg.LiveEVMTracerChainID, err = cast.ToIntE(v); err != nil {
232+
return cfg, err
233+
}
234+
}
235+
206236
return cfg, nil
207237
}

evmrpc/config_test.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package evmrpc_test
22

33
import (
4+
"fmt"
45
"testing"
56
"time"
67

@@ -26,6 +27,8 @@ type opts struct {
2627
maxTxPoolTxs interface{}
2728
slow interface{}
2829
denyList interface{}
30+
liveEVMTracer interface{}
31+
liveEVMTracerChainID interface{}
2932
}
3033

3134
func (o *opts) Get(k string) interface{} {
@@ -80,7 +83,13 @@ func (o *opts) Get(k string) interface{} {
8083
if k == "evm.deny_list" {
8184
return o.denyList
8285
}
83-
panic("unknown key")
86+
if k == "evm.live_evm_tracer" {
87+
return o.liveEVMTracer
88+
}
89+
if k == "evm.live_evm_tracer_chain_id" {
90+
return o.liveEVMTracerChainID
91+
}
92+
panic(fmt.Errorf("unknown key: %s", k))
8493
}
8594

8695
func TestReadConfig(t *testing.T) {
@@ -102,6 +111,8 @@ func TestReadConfig(t *testing.T) {
102111
1000,
103112
false,
104113
make([]string, 0),
114+
"",
115+
0,
105116
}
106117
_, err := evmrpc.ReadConfig(&goodOpts)
107118
require.Nil(t, err)

evmrpc/simulate.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ func (b *Backend) HeaderByNumber(ctx context.Context, bn rpc.BlockNumber) (*etht
263263
return b.getHeader(big.NewInt(height)), nil
264264
}
265265

266-
func (b *Backend) StateAtTransaction(ctx context.Context, block *ethtypes.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, vm.StateDB, tracers.StateReleaseFunc, error) {
266+
func (b *Backend) StateAtTransaction(ctx context.Context, block *ethtypes.Block, txIndex int, reexec uint64) (*ethtypes.Transaction, vm.BlockContext, vm.StateDB, tracers.StateReleaseFunc, error) {
267267
emptyRelease := func() {}
268268
// Short circuit if it's genesis block.
269269
if block.Number().Int64() == 0 {
@@ -286,7 +286,7 @@ func (b *Backend) StateAtTransaction(ctx context.Context, block *ethtypes.Block,
286286
return nil, vm.BlockContext{}, nil, nil, err
287287
}
288288
if idx == txIndex {
289-
return msg, *blockContext, statedb, emptyRelease, nil
289+
return tx, *blockContext, statedb, emptyRelease, nil
290290
}
291291
// Not yet the searched for transaction, execute on top of the current state
292292
vmenv := vm.NewEVM(*blockContext, txContext, statedb, b.ChainConfig(), vm.Config{})

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,10 +346,10 @@ require (
346346
replace (
347347
github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.1.0
348348
github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0
349-
github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.2.79-seiv2-hotfix
349+
github.com/cosmos/cosmos-sdk => github.com/streamingfast/sei-cosmos v0.0.0-20240327153024-8e22d1da5334
350350
github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.1.9
351351
github.com/cosmos/ibc-go/v3 => github.com/sei-protocol/sei-ibc-go/v3 v3.3.0
352-
github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-12
352+
github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-9.0.20240327165640-6ab0d196bac6
353353
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
354354
github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.33
355355
// Latest goleveldb is broken, we have to stick to this version

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,12 +1343,10 @@ github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod
13431343
github.com/securego/gosec/v2 v2.11.0 h1:+PDkpzR41OI2jrw1q6AdXZCbsNGNGT7pQjal0H0cArI=
13441344
github.com/securego/gosec/v2 v2.11.0/go.mod h1:SX8bptShuG8reGC0XS09+a4H2BoWSJi+fscA+Pulbpo=
13451345
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
1346-
github.com/sei-protocol/go-ethereum v1.13.5-sei-12 h1:sWGD3sV9F3Ilgmn8le8lhpfAwSi6n57I921cYuNvLuo=
1347-
github.com/sei-protocol/go-ethereum v1.13.5-sei-12/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ=
1346+
github.com/sei-protocol/go-ethereum v1.13.5-sei-9.0.20240327165640-6ab0d196bac6 h1:AU9VAvZsTGibuzzVmoX3taGOWjPJJct5ypXDg6vKKu0=
1347+
github.com/sei-protocol/go-ethereum v1.13.5-sei-9.0.20240327165640-6ab0d196bac6/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ=
13481348
github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQpIbXDA=
13491349
github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8=
1350-
github.com/sei-protocol/sei-cosmos v0.2.79-seiv2-hotfix h1:Yx2W7/xrGk13rpZfs+bkjx229b9LCbcCpcwTrzbz26Y=
1351-
github.com/sei-protocol/sei-cosmos v0.2.79-seiv2-hotfix/go.mod h1:ib/gp0gCxN7FXUZ40j5+x8BeyoI7AcX+rTvf53JoDsY=
13521350
github.com/sei-protocol/sei-db v0.0.33 h1:TspNkw/lW7fubR0TsOpmJdzWiLecMDOS5DAxFNQXQ6M=
13531351
github.com/sei-protocol/sei-db v0.0.33/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI=
13541352
github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHolIxgBE=
@@ -1430,6 +1428,8 @@ github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8L
14301428
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
14311429
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
14321430
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
1431+
github.com/streamingfast/sei-cosmos v0.0.0-20240327153024-8e22d1da5334 h1:+4kXknHWASf4Qq0yo67kDmZcBDeSUxVICb34CDEY6Kw=
1432+
github.com/streamingfast/sei-cosmos v0.0.0-20240327153024-8e22d1da5334/go.mod h1:ib/gp0gCxN7FXUZ40j5+x8BeyoI7AcX+rTvf53JoDsY=
14331433
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
14341434
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
14351435
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=

pb/sf/ethereum/type/v2/type.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package pbeth
2+
3+
import (
4+
"encoding/hex"
5+
"math/big"
6+
"time"
7+
)
8+
9+
var b0 = big.NewInt(0)
10+
11+
func (b *Block) PreviousID() string {
12+
return hex.EncodeToString(b.Header.ParentHash)
13+
}
14+
15+
func (b *Block) Time() time.Time {
16+
return b.Header.Timestamp.AsTime()
17+
}
18+
19+
func (m *BigInt) Native() *big.Int {
20+
if m == nil {
21+
return b0
22+
}
23+
24+
z := new(big.Int)
25+
z.SetBytes(m.Bytes)
26+
return z
27+
}

0 commit comments

Comments
 (0)