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

feat: firehose live tracer with hooks tracing #55

Draft
wants to merge 72 commits into
base: feature/erigon-live-tracer-hook-port
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
ae0e05e
firehose tracer added
dhyaniarun1993 Oct 30, 2023
efa194d
fix bugs
dhyaniarun1993 Nov 2, 2023
cecd3b4
Merge branch 'feature/erigon-live-tracer-port' into feat/firehose-liv…
dhyaniarun1993 Nov 2, 2023
bdf5917
Merge branch 'feature/erigon-live-tracer-port' into feat/firehose-liv…
dhyaniarun1993 Nov 6, 2023
889f8be
feature/erigon-live-tracer-port merged
dhyaniarun1993 Nov 6, 2023
3029efe
Merge branch 'feature/erigon-live-tracer-port' into feat/firehose-liv…
dhyaniarun1993 Nov 6, 2023
73931ad
refactor
dhyaniarun1993 Nov 6, 2023
6766b46
Merge branch 'feature/erigon-live-tracer-port' into feat/firehose-liv…
dhyaniarun1993 Nov 7, 2023
dfcc4d0
Merge branch 'feature/erigon-live-tracer-port' into feat/firehose-liv…
dhyaniarun1993 Nov 28, 2023
983a37e
bugfixes
dhyaniarun1993 Nov 28, 2023
c55a05e
code refactor
dhyaniarun1993 Dec 6, 2023
c06028c
Merge branch 'feature/erigon-live-tracer-port' into feat/firehose-liv…
dhyaniarun1993 Dec 11, 2023
ad989aa
account creation backward compatibility
dhyaniarun1993 Dec 12, 2023
be910c9
executed code corner case
dhyaniarun1993 Dec 12, 2023
fa85b27
topic backward compatibility fix
dhyaniarun1993 Dec 13, 2023
1251baf
revert: topic backward compatibility fix
dhyaniarun1993 Dec 13, 2023
4bb66cd
feature/erigon-live-tracer-port merged
dhyaniarun1993 Jan 10, 2024
ff0e93a
Merge branch 'feature/erigon-live-tracer-port' into feat/firehose-liv…
dhyaniarun1993 Jan 11, 2024
88715da
remove delegate value hack
dhyaniarun1993 Jan 11, 2024
d37c193
fix comment
dhyaniarun1993 Feb 12, 2024
5a3c874
erigon tracer merged and conflict resolved
dhyaniarun1993 Feb 13, 2024
2741e7e
Updated when FIRE INIT is actually printed
dhyaniarun1993 Feb 13, 2024
36d5bf0
feature/erigon-live-tracer-port merged
dhyaniarun1993 Feb 16, 2024
9705550
merge code fixes
dhyaniarun1993 Feb 16, 2024
6bbe0a3
Reduce amount of changes to Geth Live Tracer to keep Firehose backwar…
dhyaniarun1993 Feb 16, 2024
9133014
added firehose pb
dhyaniarun1993 Feb 18, 2024
d110d39
revert back to streaming fast pb
dhyaniarun1993 Feb 19, 2024
fb7018e
revert back to streaming fast pb
dhyaniarun1993 Feb 19, 2024
b46f0fd
fire init bugfixes
dhyaniarun1993 Feb 19, 2024
15bf7e1
firehose printer bugfix
dhyaniarun1993 Feb 19, 2024
ac60358
bugfix
dhyaniarun1993 Feb 19, 2024
aa68ce4
ignore BalanceDecreaseSelfdestructBurn
dhyaniarun1993 Feb 20, 2024
22ee5a7
Merge branch 'feature/erigon-live-tracer-port' into feat/firehose-liv…
dhyaniarun1993 Feb 20, 2024
10ccb5a
merge: struct based logging
dhyaniarun1993 Mar 25, 2024
4eee7cc
refactor and bugfixes
dhyaniarun1993 Mar 25, 2024
386393a
Merge branch 'feature/erigon-live-tracer-hook-port' into feat/firehos…
dhyaniarun1993 Mar 25, 2024
d524a7e
init fixes
dhyaniarun1993 Mar 25, 2024
351a72f
test case fixed
dhyaniarun1993 Mar 25, 2024
f103524
Merge branch 'feature/erigon-live-tracer-hook-port' into feat/firehos…
dhyaniarun1993 Mar 25, 2024
3bce122
block init added
dhyaniarun1993 Mar 25, 2024
4114c82
storage change bugfix
dhyaniarun1993 Mar 25, 2024
65fbe2d
Merge branch 'feature/erigon-live-tracer-hook-port' into feat/firehos…
dhyaniarun1993 Mar 28, 2024
b1d952f
beacon block events added
dhyaniarun1993 Apr 9, 2024
ab0054a
beacon block hook added
dhyaniarun1993 Apr 10, 2024
b4ba00d
test: log call for beacon
dhyaniarun1993 Apr 15, 2024
3a62752
Ported various improvements done in the Firehose tracer
dhyaniarun1993 Apr 24, 2024
95b57b8
Added further tracing on config and apply backward compatibility value
dhyaniarun1993 Apr 24, 2024
bf16369
Fixed a few linting errors
dhyaniarun1993 Apr 24, 2024
a21cb5b
Merge branch 'feature/erigon-live-tracer-hook-port' into feat/firehos…
dhyaniarun1993 Apr 25, 2024
9255325
Merge branch 'feat/firehose-live-tracer-hook' into feat/firehose-live…
dhyaniarun1993 Apr 25, 2024
ba223ff
Adding standard Erigon logging on NewFirehose and on OnBlockchainInit
dhyaniarun1993 May 2, 2024
298a773
Renamed callerViewer to _callViewer
dhyaniarun1993 May 2, 2024
0ec10e0
Removed _callViewer
dhyaniarun1993 May 2, 2024
d474005
Fixed Kecakke256 computation panics in some transaction state
dhyaniarun1993 May 2, 2024
f850f53
Fixed opcode representation when debugging
dhyaniarun1993 May 2, 2024
8a596c5
Fixed the rare case where a tx receipt is nil
dhyaniarun1993 May 2, 2024
47afcd7
account creation bugfix for beacon block
dhyaniarun1993 May 7, 2024
ea4e27c
Merge pull request #56 from graphprotocol/feat/firehose-live-tracer-h…
dhyaniarun1993 May 7, 2024
62ccf70
test added
dhyaniarun1993 May 8, 2024
2c6eb8c
feature/erigon-live-tracer-hook-port merged
dhyaniarun1993 May 8, 2024
e6e767d
Merge branch 'feature/erigon-live-tracer-hook-port' into feat/firehos…
dhyaniarun1993 May 8, 2024
a99019a
nil check added for NewAccount hooks
dhyaniarun1993 May 8, 2024
2c0fdc3
system call refactored
dhyaniarun1993 May 8, 2024
31d261f
Merge branch 'feature/erigon-live-tracer-hook-port' into feat/firehos…
dhyaniarun1993 May 9, 2024
9d55402
Merge branch 'feature/erigon-live-tracer-hook-port' into feat/firehos…
dhyaniarun1993 May 9, 2024
87d342e
revert syscreate logging
dhyaniarun1993 May 9, 2024
0a08fe4
Merge branch 'feature/erigon-live-tracer-hook-port' into feat/firehos…
dhyaniarun1993 May 9, 2024
f198eda
block gas logging added
dhyaniarun1993 May 10, 2024
a277c6d
Merge branch 'feature/erigon-live-tracer-hook-port' into feat/firehos…
dhyaniarun1993 May 13, 2024
1a2801f
debug logging removed
dhyaniarun1993 May 14, 2024
34ac9f3
Merge branch 'feature/erigon-live-tracer-hook-port' into feat/firehos…
dhyaniarun1993 May 14, 2024
a66eb32
Merge branch 'feature/erigon-live-tracer-hook-port' into feat/firehos…
dhyaniarun1993 May 15, 2024
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 core/state/intra_block_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,10 @@ func (sdb *IntraBlockState) createObject(addr libcommon.Address, previous *state
sdb.journal.append(resetObjectChange{account: &addr, prev: previous})
}

if sdb.logger != nil && sdb.logger.OnNewAccount != nil {
sdb.logger.OnNewAccount(addr, previous != nil)
}

newobj.newlyCreated = true
sdb.setStateObject(addr, newobj)
return newobj
Expand Down
7 changes: 7 additions & 0 deletions core/tracing/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ type Hooks struct {
OnCodeChange CodeChangeHook
OnStorageChange StorageChangeHook
OnLog LogHook

// Firehose backward compatibility
// This hook exist because some current Firehose supported chains requires it
// but this field is going to be deprecated and newer chains will not produced
// those events anymore. The hook is registered conditionally based on the
// tracer configuration.
OnNewAccount func(address libcommon.Address, previousExisted bool)
}

// BalanceChangeReason is used to indicate the reason for a balance change, useful
Expand Down
5 changes: 4 additions & 1 deletion core/vm/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,10 @@ func Call(address libcommon.Address, input []byte, cfg *Config) ([]byte, uint64,

vmenv := NewEnv(cfg)

sender := cfg.State.GetOrNewStateObject(cfg.Origin)
// Hack for firehose
// we don't want to track the origin account creation
// sender := cfg.State.GetOrNewStateObject(cfg.Origin)
sender := vm.AccountRef(cfg.Origin)
statedb := cfg.State
rules := vmenv.ChainRules()
if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil {
Expand Down
81 changes: 81 additions & 0 deletions eth/tracers/internal/tracetest/firehose/blockchain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package firehose_test

import (
"math/big"
"testing"

"github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon/core"
"github.com/ledgerwatch/erigon/core/state"
"github.com/ledgerwatch/erigon/core/tracing"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/vm"
"github.com/ledgerwatch/erigon/tests"
"github.com/ledgerwatch/erigon/turbo/stages/mock"
"github.com/ledgerwatch/log/v3"
"github.com/stretchr/testify/require"
)

func runPrestateBlock(t *testing.T, prestatePath string, hooks *tracing.Hooks) {
t.Helper()

prestate := readPrestateData(t, prestatePath)
tx, err := types.UnmarshalTransactionFromBinary(common.FromHex(prestate.Input), false)
if err != nil {
t.Fatalf("failed to parse testcase input: %v", err)
}

context, err := prestate.Context.toBlockContext(prestate.Genesis)
require.NoError(t, err)
rules := prestate.Genesis.Config.Rules(context.BlockNumber, context.Time)

m := mock.Mock(t)
dbTx, err := m.DB.BeginRw(m.Ctx)
require.NoError(t, err)
defer dbTx.Rollback()
stateDB, _ := tests.MakePreState(rules, dbTx, prestate.Genesis.Alloc, uint64(context.BlockNumber), m.HistoryV3)

var logger = log.New("test")
genesisBlock, _, err := core.GenesisToBlock(prestate.Genesis, "", logger, nil)
require.NoError(t, err)

block := types.NewBlock(&types.Header{
ParentHash: genesisBlock.Hash(),
Number: big.NewInt(int64(context.BlockNumber)),
Difficulty: context.Difficulty,
Coinbase: context.Coinbase,
Time: context.Time,
GasLimit: context.GasLimit,
BaseFee: context.BaseFee.ToBig(),
ParentBeaconBlockRoot: ptr(common.Hash{}),
}, []types.Transaction{tx}, nil, nil, nil)

stateDB.SetLogger(hooks)
stateDB.SetTxContext(tx.Hash(), block.Hash(), 0)

hooks.OnBlockchainInit(prestate.Genesis.Config)
hooks.OnBlockStart(tracing.BlockEvent{
Block: block,
TD: prestate.TotalDifficulty,
})

usedGas := uint64(0)
usedBlobGas := uint64(0)
_, _, err = core.ApplyTransaction(
prestate.Genesis.Config,
nil,
nil,
&context.Coinbase,
new(core.GasPool).AddGas(block.GasLimit()),
stateDB,
state.NewNoopWriter(),
block.Header(),
tx,
&usedGas,
&usedBlobGas,
vm.Config{Tracer: hooks},
)
require.NoError(t, err)

hooks.OnBlockEnd(nil)
}
39 changes: 39 additions & 0 deletions eth/tracers/internal/tracetest/firehose/firehose_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package firehose_test

import (
"encoding/json"
"path/filepath"
"strings"
"testing"

"github.com/ledgerwatch/erigon/eth/tracers/live"
"github.com/stretchr/testify/require"
)

func TestFirehosePrestate(t *testing.T) {
testFolders := []string{
// "./testdata/TestFirehosePrestate/keccak256_too_few_memory_bytes_get_padded",
"./testdata/TestFirehosePrestate/keccak256_wrong_diff",
}

for _, folder := range testFolders {
name := filepath.Base(folder)

t.Run(name, func(t *testing.T) {
tracer, err := live.NewFirehoseFromRawJSON(json.RawMessage(`{
"applyBackwardsCompatibility": true,
"_private": {
"flushToTestBuffer": true
}
}`))
require.NoError(t, err)

runPrestateBlock(t, filepath.Join(folder, "prestate.json"), live.NewTracingHooksFromFirehose(tracer))
genesisLine, blockLines, unknownLines := readTracerFirehoseLines(t, tracer)
require.Len(t, unknownLines, 0, "Lines:\n%s", strings.Join(slicesMap(unknownLines, func(l unknwonLine) string { return "- '" + string(l) + "'" }), "\n"))
require.NotNil(t, genesisLine)
blockLines.assertOnlyBlockEquals(t, folder, 1)
})
}

}
159 changes: 159 additions & 0 deletions eth/tracers/internal/tracetest/firehose/helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package firehose_test

import (
"bytes"
"encoding/base64"
"fmt"
"os"
"path/filepath"
"testing"

"github.com/ledgerwatch/erigon/eth/tracers/live"
pbeth "github.com/ledgerwatch/erigon/pb/sf/ethereum/type/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
)

type firehoseInitLine struct {
ProtocolVersion string
NodeName string
NodeVersion string
}

type firehoseBlockLines []firehoseBlockLine

func (lines firehoseBlockLines) assertEquals(t *testing.T, goldenDir string, expected ...firehoseBlockLineParams) {
actualParams := slicesMap(lines, func(l firehoseBlockLine) firehoseBlockLineParams { return l.Params })
require.Equal(t, expected, actualParams, "Actual lines block params do not match expected lines block params")

lines.assertOnlyBlockEquals(t, goldenDir, len(expected))
}

func (lines firehoseBlockLines) assertOnlyBlockEquals(t *testing.T, goldenDir string, expectedBlockCount int) {
t.Helper()

require.Len(t, lines, expectedBlockCount, "Expected %d blocks, got %d", expectedBlockCount, len(lines))
goldenUpdate := os.Getenv("GOLDEN_UPDATE") == "true"

for _, line := range lines {
goldenPath := filepath.Join(goldenDir, fmt.Sprintf("block.%d.golden.json", line.Block.Header.Number))
if !goldenUpdate && !fileExists(t, goldenPath) {
t.Fatalf("the golden file %q does not exist, re-run with 'GOLDEN_UPDATE=true go test ./... -run %q' to generate the intial version", goldenPath, t.Name())
}

content, err := protojson.MarshalOptions{Indent: " "}.Marshal(line.Block)
require.NoError(t, err)

if goldenUpdate {
require.NoError(t, os.MkdirAll(filepath.Dir(goldenPath), 0755))
require.NoError(t, os.WriteFile(goldenPath, content, 0644))
}

expected, err := os.ReadFile(goldenPath)
require.NoError(t, err)

expectedBlock := &pbeth.Block{}
require.NoError(t, protojson.Unmarshal(expected, expectedBlock))

if !proto.Equal(expectedBlock, line.Block) {
assert.EqualExportedValues(t, expectedBlock, line.Block, "Run 'GOLDEN_UPDATE=true go test ./... -run %q' to update golden file", t.Name())
}
}
}

func fileExists(t *testing.T, path string) bool {
t.Helper()
stat, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return false
}

t.Fatal(err)
}

return !stat.IsDir()
}

func slicesMap[T any, U any](s []T, f func(T) U) []U {
result := make([]U, len(s))
for i, v := range s {
result[i] = f(v)
}
return result
}

type firehoseBlockLine struct {
// We split params and block to make it easier to compare stuff
Params firehoseBlockLineParams
Block *pbeth.Block
}

type firehoseBlockLineParams struct {
Number string
Hash string
PreviousNum string
PreviousHash string
LibNum string
Time string
}

type unknwonLine string

func readTracerFirehoseLines(t *testing.T, tracer *live.Firehose) (genesisLine *firehoseInitLine, blockLines firehoseBlockLines, unknownLines []unknwonLine) {
t.Helper()

lines := bytes.Split(tracer.InternalTestingBuffer().Bytes(), []byte{'\n'})
for _, line := range lines {
if len(line) == 0 {
continue
}

parts := bytes.Split(line, []byte{' '})
if len(parts) == 0 || string(parts[0]) != "FIRE" {
unknownLines = append(unknownLines, unknwonLine(line))
continue
}

action := string(parts[1])
fireParts := parts[2:]
switch action {
case "INIT":
genesisLine = &firehoseInitLine{
ProtocolVersion: string(fireParts[0]),
NodeName: string(fireParts[1]),
NodeVersion: string(fireParts[2]),
}

case "BLOCK":
protoBytes, err := base64.StdEncoding.DecodeString(string(fireParts[6]))
require.NoError(t, err)

block := &pbeth.Block{}
require.NoError(t, proto.Unmarshal(protoBytes, block))

blockLines = append(blockLines, firehoseBlockLine{
Params: firehoseBlockLineParams{
Number: string(fireParts[0]),
Hash: string(fireParts[1]),
PreviousNum: string(fireParts[2]),
PreviousHash: string(fireParts[3]),
LibNum: string(fireParts[4]),
Time: string(fireParts[5]),
},
Block: block,
})

default:
unknownLines = append(unknownLines, unknwonLine(line))
}
}

return
}

func ptr[T any](v T) *T {
return &v
}
Loading