Merge branch 'release/geth-1.15.11-fh3.0' into merge

This commit is contained in:
Matthieu Vachon 2025-06-06 14:36:46 -04:00
commit dadcfac961
29 changed files with 3483 additions and 320 deletions

174
.github/workflows/sf-release.yml vendored Normal file
View file

@ -0,0 +1,174 @@
name: Build, push and release (if tag)
on:
push:
tags:
- "*-v*"
branches:
- "firehose-fh3.0"
- "release/*"
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
strategy:
matrix:
include:
- platform: linux/amd64
platform_suffix: amd64
runner: ubuntu-22.04
- platform: linux/arm64
platform_suffix: arm64
runner: ubuntu-22.04-arm
runs-on: [ "${{ matrix.runner }}" ]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract version
id: extract-version
run: |
version="edge"
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
version=${GITHUB_REF#refs/tags/}
fi
echo "VERSION=${version}" >> "$GITHUB_OUTPUT"
- name: Generate docker tags/labels from github build context
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# The second sha tag is defined to uniquely identify the image and the platform,
# we append extract version, either edge or <tag>, this is necessary to avoid a
# race condition when pushing a tag and its related branches. In this case, three
# build are launched, but only one, the tag, will get it's version set to the tag.
#
# What happened is that non-tag Docker built image like `3b14725-amd64` was
# overwriting the tag Docker image also labeled `3b14725-amd64`. The `push` action
# was then merging an image that didn't have the version labels correctly set.
#
# Our image more looks like `3b14725-edge-amd64` or `3b14725-geth-v1.15.10-fh3.0-amd64`
# which mean the `push` can now pick the correct image depending on the type of build.
tags: |
type=ref,event=tag,prefix=
type=sha,prefix=
type=sha,prefix=,suffix=-${{ steps.extract-version.outputs.VERSION }}-${{ matrix.platform_suffix }}
type=edge,branch=firehose-fh3.0,priority=1
type=edge,branch=release/*,priority=1
flavor: |
latest=${{ startsWith(github.ref, 'refs/tags/') && !contains(github.ref, 'beta') && !contains(github.ref, 'rc') }}
prefix=geth-,onlatest=true
- name: Build and push Docker image (${{ matrix.platform }})
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile.sf
platforms: ${{ matrix.platform }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
provenance: false
# FIXME: Switch to Firehose Ethereum!
build-args: |
FIREHOSE_CORE=18bb86f
push:
needs: build
runs-on: ubuntu-22.04
permissions:
contents: read
packages: write
steps:
- name: Docker login
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate docker tags/labels from github build context
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=tag,prefix=
type=sha,prefix=
type=edge,branch=firehose-fh3.0,priority=1
type=edge,branch=release/*,priority=1
flavor: |
latest=${{ startsWith(github.ref, 'refs/tags/') && !contains(github.ref, 'beta') && !contains(github.ref, 'rc') }}
prefix=geth-,onlatest=true
sep-tags: ","
- name: Extract image
id: image
run: |
version="edge"
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
version=${GITHUB_REF#refs/tags/}
fi
echo "ID=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_SHA::7}-${version}" >> "$GITHUB_OUTPUT"
- name: Create and push manifest images
uses: Noelware/docker-manifest-action@0.4.3
with:
inputs: "${{ steps.meta.outputs.tags }}"
images: "${{ steps.image.outputs.ID }}-amd64, ${{ steps.image.outputs.ID }}-arm64"
push: true
release:
if: startsWith(github.ref, 'refs/tags/')
needs: build
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- name: Extract image
id: image
run: |
version="edge"
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
version=${GITHUB_REF#refs/tags/}
fi
echo "ID=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_SHA::7}-${version}" >> "$GITHUB_OUTPUT"
- name: Extract assets
if: startsWith(github.ref, 'refs/tags/')
run: |
# The --platform are not really needed here, but it removes the warning
docker cp $(docker create --platform=linux/amd64 ${{ steps.image.outputs.ID }}-amd64):/usr/local/bin/geth ./geth_linux
docker cp $(docker create --platform=linux/arm64 ${{ steps.image.outputs.ID }}-arm64):/usr/local/bin/geth ./geth_linux_arm64
- name: Release
uses: softprops/action-gh-release@v2
with:
prerelease: ${{ contains(github.ref, 'beta') || contains(github.ref, 'rc') }}
files: |
./geth_linux
./geth_linux_arm64

23
Dockerfile.sf Normal file
View file

@ -0,0 +1,23 @@
ARG FIREHOSE_CORE="18bb86f"
# Build Geth in a stock Go builder container
FROM golang:1.24-alpine AS builder
RUN apk add --no-cache gcc musl-dev linux-headers git
# Get dependencies - will also be cached if we won't change go.mod/go.sum
COPY go.mod /go-ethereum/
COPY go.sum /go-ethereum/
RUN cd /go-ethereum && go mod download
ADD . /go-ethereum
RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/geth
# FIXME: Actually put Firehose Ethereum when it's properly built
# Pull Geth into Firehose Core container (geth is statically linked, we can copy it from alpine to ubuntu)
FROM ghcr.io/streamingfast/firehose-core:${FIREHOSE_CORE}
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/geth
RUN ln -s /usr/local/bin/geth /app/geth
EXPOSE 8545 8546 30303 30303/udp

View file

@ -662,7 +662,7 @@ func maybeSkipArchive(env build.Environment) {
log.Printf("skipping archive creation because this is a PR build") log.Printf("skipping archive creation because this is a PR build")
os.Exit(0) os.Exit(0)
} }
if env.Branch != "master" && !strings.HasPrefix(env.Branch, "firehose") && !strings.HasPrefix(env.Tag, "v1.") && !strings.Contains(env.Tag, "fh") { if env.Branch != "master" && !strings.HasPrefix(env.Branch, "firehose") && !strings.HasPrefix(env.Branch, "release/") && !strings.HasPrefix(env.Tag, "v1.") && !strings.Contains(env.Tag, "fh") {
log.Printf("skipping archive creation because branch %q, tag %q is not on the inclusion list", env.Branch, env.Tag) log.Printf("skipping archive creation because branch %q, tag %q is not on the inclusion list", env.Branch, env.Tag)
os.Exit(0) os.Exit(0)
} }
@ -705,8 +705,9 @@ func doDockerBuildx(cmdline []string) {
case env.Branch == "master": case env.Branch == "master":
tags = []string{"latest"} tags = []string{"latest"}
case strings.HasPrefix(env.Tag, "v1."): case strings.HasPrefix(env.Tag, "v1."):
tags = []string{"stable", fmt.Sprintf("release-%v", version.Family), "v" + version.Semantic}
tags = []string{"stable", fmt.Sprintf("release-1.%d", params.VersionMinor), "v" + params.Version} tags = []string{"stable", fmt.Sprintf("release-1.%d", params.VersionMinor), "v" + params.Version}
case strings.HasPrefix(env.Branch, "firehose") || strings.HasPrefix(env.Branch, "release/"):
tags = []string{"edge-fh" + tracers.FirehoseProtocolVersion}
case strings.Contains(env.Tag, "fh"): case strings.Contains(env.Tag, "fh"):
tags = []string{"stable-fh" + tracers.FirehoseProtocolVersion, "v" + params.Version + "-fh" + tracers.FirehoseProtocolVersion} tags = []string{"stable-fh" + tracers.FirehoseProtocolVersion, "v" + params.Version + "-fh" + tracers.FirehoseProtocolVersion}
} }

View file

@ -593,6 +593,7 @@ var (
Name: "vmtrace", Name: "vmtrace",
Usage: "Name of tracer which should record internal VM operations (costly)", Usage: "Name of tracer which should record internal VM operations (costly)",
Category: flags.VMCategory, Category: flags.VMCategory,
Value: "",
} }
VMTraceJsonConfigFlag = &cli.StringFlag{ VMTraceJsonConfigFlag = &cli.StringFlag{
Name: "vmtrace.jsonconfig", Name: "vmtrace.jsonconfig",
@ -2002,13 +2003,11 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
}() }()
// VM tracing config. // VM tracing config.
if ctx.IsSet(VMTraceFlag.Name) {
if name := ctx.String(VMTraceFlag.Name); name != "" { if name := ctx.String(VMTraceFlag.Name); name != "" {
cfg.VMTrace = name cfg.VMTrace = name
cfg.VMTraceJsonConfig = ctx.String(VMTraceJsonConfigFlag.Name) cfg.VMTraceJsonConfig = ctx.String(VMTraceJsonConfigFlag.Name)
} }
} }
}
// MakeBeaconLightConfig constructs a beacon light client config based on the // MakeBeaconLightConfig constructs a beacon light client config based on the
// related command line flags. // related command line flags.
@ -2404,7 +2403,6 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
vmcfg := vm.Config{ vmcfg := vm.Config{
EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name), EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name),
} }
if ctx.IsSet(VMTraceFlag.Name) {
if name := ctx.String(VMTraceFlag.Name); name != "" { if name := ctx.String(VMTraceFlag.Name); name != "" {
config := json.RawMessage(ctx.String(VMTraceJsonConfigFlag.Name)) config := json.RawMessage(ctx.String(VMTraceJsonConfigFlag.Name))
t, err := tracers.LiveDirectory.New(name, config) t, err := tracers.LiveDirectory.New(name, config)
@ -2413,7 +2411,6 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
} }
vmcfg.Tracer = t vmcfg.Tracer = t
} }
}
// Disable transaction indexing/unindexing by default. // Disable transaction indexing/unindexing by default.
chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil, nil) chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil, nil)
if err != nil { if err != nil {

View file

@ -2641,7 +2641,11 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
} }
if bc.logger != nil && bc.logger.OnBlockEnd != nil { if bc.logger != nil && bc.logger.OnBlockEnd != nil {
defer func() { defer func() {
if recovered := recover(); recovered != nil {
panic(recovered)
} else {
bc.logger.OnBlockEnd(blockEndErr) bc.logger.OnBlockEnd(blockEndErr)
}
}() }()
} }

View file

@ -36,6 +36,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/core/vm/program" "github.com/ethereum/go-ethereum/core/vm/program"
@ -4783,3 +4784,43 @@ func TestEIP7702(t *testing.T) {
t.Fatalf("addr2 storage wrong: expected %d, got %d", fortyTwo, actual) t.Fatalf("addr2 storage wrong: expected %d, got %d", fortyTwo, actual)
} }
} }
func TestTracingBlockEndNotCalledOnPanic(t *testing.T) {
genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true, "path")
if err != nil {
t.Fatalf("failed to create pristine chain: %v", err)
}
defer blockchain.Stop()
blockEndCalled := false
hooks := &tracing.Hooks{
// This simulates a panic in the tracer
OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
panic("panic")
},
OnBlockEnd: func(err error) {
blockEndCalled = true
},
}
blockchain.logger = hooks
blockchain.vmConfig.Tracer = hooks
blocks := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 1, ethash.NewFullFaker(), genDb, 0)
func() {
defer func() {
if r := recover(); r == nil {
t.Fatalf("Expected panic, but got none, ensure that OnBalanceChange hook is called correctly to generate the panic")
}
}()
if _, err := blockchain.InsertChain(blocks); err != nil {
t.Fatalf("Failed to insert block: %v", err)
}
}()
if blockEndCalled {
t.Fatalf("OnBlockEnd should not be called on panic within the tracer")
}
}

View file

@ -171,6 +171,9 @@ type StateDB struct {
// Bor metrics // Bor metrics
BorConsensusTime time.Duration BorConsensusTime time.Duration
// requires to maintain Firehose 2.3 backward compatibility
hooks *tracing.Hooks
} }
// New creates a new state from a given trie. // New creates a new state from a given trie.
@ -1052,6 +1055,9 @@ func (s *StateDB) mvRecordWritten(object *stateObject) *stateObject {
// existing account with the given address, otherwise it will be silently overwritten. // existing account with the given address, otherwise it will be silently overwritten.
func (s *StateDB) createObject(addr common.Address) *stateObject { func (s *StateDB) createObject(addr common.Address) *stateObject {
obj := newObject(s, addr, nil) obj := newObject(s, addr, nil)
if s.hooks != nil && s.hooks.OnNewAccount != nil {
s.hooks.OnNewAccount(addr)
}
s.journal.append(createObjectChange{account: addr}) s.journal.append(createObjectChange{account: addr})
s.setStateObject(obj) s.setStateObject(obj)

View file

@ -42,6 +42,10 @@ func NewHookedState(stateDb *StateDB, hooks *tracing.Hooks) *hookedStateDB {
if s.hooks == nil { if s.hooks == nil {
s.hooks = new(tracing.Hooks) s.hooks = new(tracing.Hooks)
} }
// Requires to maintain Firehose 2.3 backward compatibility
stateDb.hooks = s.hooks
return s return s
} }

View file

@ -217,12 +217,15 @@ type Hooks struct {
// Block hash read // Block hash read
OnBlockHashRead BlockHashReadHook OnBlockHashRead BlockHashReadHook
// Firehose backward compatibility // Firehose requirements.
// 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 // Search a368bc8a3737 within the repository to find all the details
// those events anymore. The hook is registered conditionally based on the
// tracer configuration.
OnNewAccount func(address common.Address) OnNewAccount func(address common.Address)
// Firehose requirements.
//
// Search 11471b22bb0b within the repository to find all the details
OnKeccakPreimage func(hash common.Hash, preimage []byte)
} }
// BalanceChangeReason is used to indicate the reason for a balance change, useful // BalanceChangeReason is used to indicate the reason for a balance change, useful

View file

@ -273,6 +273,14 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
if evm.Config.EnablePreimageRecording { if evm.Config.EnablePreimageRecording {
evm.StateDB.AddPreimage(interpreter.hasherBuf, data) evm.StateDB.AddPreimage(interpreter.hasherBuf, data)
} }
// Firehose requirements.
//
// Search 11471b22bb0b within the repository to find all the details
if evm.Config.Tracer != nil && evm.Config.Tracer.OnKeccakPreimage != nil {
evm.Config.Tracer.OnKeccakPreimage(interpreter.hasherBuf, data)
}
size.SetBytes(interpreter.hasherBuf[:]) size.SetBytes(interpreter.hasherBuf[:])
return nil, nil return nil, nil

View file

@ -136,7 +136,13 @@ func NewSimulatedBeacon(period uint64, feeRecipient common.Address, eth *eth.Eth
engineAPI: engineAPI, engineAPI: engineAPI,
lastBlockTime: block.Time, lastBlockTime: block.Time,
curForkchoiceState: current, curForkchoiceState: current,
feeRecipient: feeRecipient, // FIXME (StreamingFast): Commented out because it changes the fee recipient which changes
// cold/hot storage access and leads to differences when running Battlefield. Tried setting
// `--miner.pending.feeRecipient=0x0000000000000000000000000000000000000000` but it didn't
// work. Will need to dig a bit more or just accept the changes for now (which would have
// cascading effects on other supported network that haven't updated yet to this).
// Commenting it out for now it's the easiest way to get the tests to pass.
// feeRecipient: feeRecipient,
}, nil }, nil
} }

View file

@ -9,6 +9,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math"
"math/big" "math/big"
"os" "os"
"regexp" "regexp"
@ -85,6 +86,7 @@ func NewTracingHooksFromFirehose(tracer *Firehose) *tracing.Hooks {
OnBlockStart: tracer.OnBlockStart, OnBlockStart: tracer.OnBlockStart,
OnBlockEnd: tracer.OnBlockEnd, OnBlockEnd: tracer.OnBlockEnd,
OnSkippedBlock: tracer.OnSkippedBlock, OnSkippedBlock: tracer.OnSkippedBlock,
OnClose: tracer.OnClose,
OnTxStart: tracer.OnTxStart, OnTxStart: tracer.OnTxStart,
OnTxEnd: tracer.OnTxEnd, OnTxEnd: tracer.OnTxEnd,
@ -103,16 +105,42 @@ func NewTracingHooksFromFirehose(tracer *Firehose) *tracing.Hooks {
OnSystemCallStart: tracer.OnSystemCallStart, OnSystemCallStart: tracer.OnSystemCallStart,
OnSystemCallEnd: tracer.OnSystemCallEnd, OnSystemCallEnd: tracer.OnSystemCallEnd,
// For a reason yet to be discovered, some transactions panics when trying to
// compute the keccak hash from a preimage when it comes the time to retrieve
// the memory location by inspecting the opcode's EVM stack arguments. The panic
// is an index out of bound error.
//
// To avoid the problem altogether, we return to our old Firehose tracer hook directly
// when the instructions is called within the EVM. That has the added benefit of
// avoiding re-computing the keccak results of the preimage again since at this location,
// we have both the result and the preimage.
//
// The cons of this is that we need to keep some Geth internal changes to have the hook
// called. But this is minimal as we do have to maintain a fork and the changes are actually
// minimal.
//
// Comment 11471b22bb0b (search '11471b22bb0b' within the repository to see all related code locations)
OnKeccakPreimage: tracer.OnKeccakPreimage,
// 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.
//
// This should actually be conditional but it's not possible to do it in the hooks // This should actually be conditional but it's not possible to do it in the hooks
// directly because the chain ID will be known only after the `OnBlockchainInit` call. // directly because the chain ID will be known only after the `OnBlockchainInit` call.
// So we register it unconditionally and the actual `OnNewAccount` hook will decide // So we register it unconditionally and the actual `OnNewAccount` hook will decide
// what it needs to do. // what it needs to do.
//
// Comment a368bc8a3737 (search 'a368bc8a3737' within the repository to see all related code locations)
OnNewAccount: tracer.OnNewAccount, OnNewAccount: tracer.OnNewAccount,
} }
} }
type FirehoseConfig struct { type FirehoseConfig struct {
ApplyBackwardCompatibility *bool `json:"applyBackwardCompatibility"` ApplyBackwardCompatibility *bool `json:"applyBackwardCompatibility"`
ConcurrentBlockFlushing int `json:"concurrentBlockFlushing"`
// Only used for testing, only possible through JSON configuration // Only used for testing, only possible through JSON configuration
private *privateFirehoseConfig private *privateFirehoseConfig
@ -133,6 +161,7 @@ func (c *FirehoseConfig) LogKeyValues() []any {
return []any{ return []any{
"config.applyBackwardCompatibility", applyBackwardCompatibility, "config.applyBackwardCompatibility", applyBackwardCompatibility,
"config.concurrentBlockFlushing", c.ConcurrentBlockFlushing,
} }
} }
@ -153,6 +182,8 @@ type Firehose struct {
hasher crypto.KeccakState // Keccak256 hasher instance shared across tracer needs (non-concurrent safe) hasher crypto.KeccakState // Keccak256 hasher instance shared across tracer needs (non-concurrent safe)
hasherBuf common.Hash // Keccak256 hasher result array shared across tracer needs (non-concurrent safe) hasherBuf common.Hash // Keccak256 hasher result array shared across tracer needs (non-concurrent safe)
tracerID string tracerID string
concurrentFlushQueue *ConcurrentFlushQueue
concurrentFlushBufferSize int
// The FirehoseTracer is used in multiple chains, some for which were produced using a legacy version // The FirehoseTracer is used in multiple chains, some for which were produced using a legacy version
// of the whole tracing infrastructure. This legacy version had many small bugs here and there that // of the whole tracing infrastructure. This legacy version had many small bugs here and there that
// we must "reproduce" on some chain to ensure that the FirehoseTracer produces the same output // we must "reproduce" on some chain to ensure that the FirehoseTracer produces the same output
@ -162,6 +193,7 @@ type Firehose struct {
// here. If not set in the config, then we inspect `OnBlockchainInit` the chain config to determine // here. If not set in the config, then we inspect `OnBlockchainInit` the chain config to determine
// if it's a network for which we must reproduce the legacy bugs. // if it's a network for which we must reproduce the legacy bugs.
applyBackwardCompatibility *bool applyBackwardCompatibility *bool
concurrentBlockFlushing int
// Block state // Block state
block *pbeth.Block block *pbeth.Block
@ -230,6 +262,8 @@ func NewFirehose(config *FirehoseConfig) *Firehose {
hasher: crypto.NewKeccakState(), hasher: crypto.NewKeccakState(),
tracerID: "global", tracerID: "global",
applyBackwardCompatibility: config.ApplyBackwardCompatibility, applyBackwardCompatibility: config.ApplyBackwardCompatibility,
concurrentBlockFlushing: config.ConcurrentBlockFlushing,
concurrentFlushBufferSize: 100,
// Block state // Block state
blockOrdinal: &Ordinal{}, blockOrdinal: &Ordinal{},
@ -346,6 +380,16 @@ func (f *Firehose) OnBlockchainInit(chainConfig *params.ChainConfig) {
applyBackwardCompatibilityLogSuffix = " (disabled)" applyBackwardCompatibilityLogSuffix = " (disabled)"
} }
if f.config.ConcurrentBlockFlushing > 0 {
log.Info("Firehose concurrent block flushing enabled, starting goroutine")
f.concurrentFlushQueue = NewConcurrentFlushQueue(
f.concurrentFlushBufferSize,
f.printBlockToFirehose,
f.flushToFirehose,
)
f.concurrentFlushQueue.Start(f.config.ConcurrentBlockFlushing)
}
log.Info("Firehose tracer initialized", log.Info("Firehose tracer initialized",
"chain_id", chainConfig.ChainID, "chain_id", chainConfig.ChainID,
"apply_backward_compatibility", fmt.Sprintf("%t%s", *f.applyBackwardCompatibility, applyBackwardCompatibilityLogSuffix), "apply_backward_compatibility", fmt.Sprintf("%t%s", *f.applyBackwardCompatibility, applyBackwardCompatibilityLogSuffix),
@ -489,7 +533,14 @@ func (f *Firehose) OnBlockEnd(err error) {
} }
f.ensureInBlockAndNotInTrx() f.ensureInBlockAndNotInTrx()
// Flush block to firehose and optionally use goroutine
if f.concurrentBlockFlushing > 0 {
f.concurrentFlushQueue.Enqueue(f.block, f.blockFinality)
} else {
f.printBlockToFirehose(f.block, f.blockFinality) f.printBlockToFirehose(f.block, f.blockFinality)
}
} else { } else {
// An error occurred, could have happen in transaction/call context, we must not check if in trx/call, only check in block // An error occurred, could have happen in transaction/call context, we must not check if in trx/call, only check in block
f.ensureInBlock(0) f.ensureInBlock(0)
@ -607,6 +658,13 @@ func (f *Firehose) reorderCallOrdinals(call *pbeth.Call, ordinalBase uint64) (or
return call.EndOrdinal return call.EndOrdinal
} }
func (f *Firehose) OnClose() {
if f.concurrentFlushQueue != nil {
log.Info("Firehose closing, flushing queued blocks to standard output")
f.concurrentFlushQueue.CloseChannels()
}
}
func (f *Firehose) OnSystemCallStart() { func (f *Firehose) OnSystemCallStart() {
firehoseInfo("system call start") firehoseInfo("system call start")
f.ensureInBlockAndNotInTrx() f.ensureInBlockAndNotInTrx()
@ -690,9 +748,8 @@ func (f *Firehose) onTxStart(tx *types.Transaction, hash common.Hash, from, to c
trx.BlobGasFeeCap = firehoseBigIntFromNative(tx.BlobGasFeeCap()) trx.BlobGasFeeCap = firehoseBigIntFromNative(tx.BlobGasFeeCap())
trx.BlobHashes = newBlobHashesFromChain(tx.BlobHashes()) trx.BlobHashes = newBlobHashesFromChain(tx.BlobHashes())
// Polygon doesn't have EIP-7702 yet [Search for polygon-eip-7702 across codebase for all places to uncomment] case types.SetCodeTxType:
// case types.SetCodeTxType: trx.SetCodeAuthorizations = newSetCodeAuthorizationsFromChain(tx.SetCodeAuthorizations())
// trx.SetCodeAuthorizations = newSetCodeAuthorizationsFromChain(tx.SetCodeAuthorizations())
} }
f.transaction = trx f.transaction = trx
@ -1064,6 +1121,8 @@ func (f *Firehose) invertWithdrawAndRefundBalanceChange(activeCall *pbeth.Call,
withdrawChange := changes[withdrawIndex] withdrawChange := changes[withdrawIndex]
changes[withdrawIndex] = changes[refundIndex] changes[withdrawIndex] = changes[refundIndex]
changes[refundIndex] = withdrawChange changes[refundIndex] = withdrawChange
return
} }
func (f *Firehose) removeFirstWithdrawBalanceChange(activeCall *pbeth.Call, lastWithdrawIndex int) { func (f *Firehose) removeFirstWithdrawBalanceChange(activeCall *pbeth.Call, lastWithdrawIndex int) {
@ -1126,8 +1185,9 @@ func (f *Firehose) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.
} }
switch opCode { switch opCode {
case vm.KECCAK256: // Bogus, search 11471b22bb0b within the repository to find all the details
f.onOpcodeKeccak256(activeCall, scope.StackData(), Memory(scope.MemoryData())) // case vm.KECCAK256:
// f.onOpcodeKeccak256(activeCall, scope.StackData(), Memory(scope.MemoryData()))
case vm.SELFDESTRUCT: case vm.SELFDESTRUCT:
f.ensureInCall() f.ensureInCall()
@ -1136,6 +1196,33 @@ func (f *Firehose) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.
} }
} }
func (f *Firehose) OnKeccakPreimage(hash common.Hash, preImage []byte) {
f.ensureInBlockAndInTrxAndInCall()
activeCall := f.callStack.Peek()
if activeCall.KeccakPreimages == nil {
activeCall.KeccakPreimages = make(map[string]string)
}
encodedData := hex.EncodeToString(preImage)
if *f.applyBackwardCompatibility {
// Known Firehose issue: It appears the old Firehose instrumentation have a bug
// where when the keccak256 preimage is empty, it is written as "." which is
// completely wrong.
//
// To keep the same behavior, we will write the preimage as a "." when the encoded
// data is an empty string.
if encodedData == "" {
encodedData = "."
}
}
activeCall.KeccakPreimages[hex.EncodeToString(hash[:])] = encodedData
}
// Unused due to bogus behavior, search 11471b22bb0b within the repository to find all the details
var _ any = new(Firehose).onOpcodeKeccak256
// onOpcodeKeccak256 is called during the SHA3 (a.k.a KECCAK256) opcode it's known // onOpcodeKeccak256 is called during the SHA3 (a.k.a KECCAK256) opcode it's known
// in Firehose tracer as Keccak preimages. The preimage is the input data that // in Firehose tracer as Keccak preimages. The preimage is the input data that
// was used to produce the given keccak hash. // was used to produce the given keccak hash.
@ -1238,14 +1325,13 @@ func (f *Firehose) callStart(source string, callType pbeth.CallType, from common
if f.blockRules.IsPrague && !f.inSystemCall && !f.blockIsGenesis && callType != pbeth.CallType_CREATE { if f.blockRules.IsPrague && !f.inSystemCall && !f.blockIsGenesis && callType != pbeth.CallType_CREATE {
firehoseTrace("call resolving delegation (from=%s)", from) firehoseTrace("call resolving delegation (from=%s)", from)
// Polygon doesn't have EIP-7702 yet [Search for polygon-eip-7702 across codebase for all places to uncomment] code := f.evm.StateDB.GetCode(to)
// code := f.evm.StateDB.GetCode(to) if len(code) != 0 {
// if len(code) != 0 { if target, ok := types.ParseDelegation(code); ok {
// if target, ok := types.ParseDelegation(code); ok { firehoseDebug("call resolved delegation (from=%s, delegates_to=%s)", from, target)
// firehoseDebug("call resolved delegation (from=%s, delegates_to=%s)", from, target) call.AddressDelegatesTo = target.Bytes()
// call.AddressDelegatesTo = target.Bytes() }
// } }
// }
} }
if *f.applyBackwardCompatibility { if *f.applyBackwardCompatibility {
@ -1835,6 +1921,9 @@ func (f *Firehose) isChainOneOf(chainIDs ...*big.Int) bool {
} }
func isChainIDOneOf(actualChainID *big.Int, chainIDs ...*big.Int) bool { func isChainIDOneOf(actualChainID *big.Int, chainIDs ...*big.Int) bool {
if actualChainID == nil {
return false
}
for _, chainID := range chainIDs { for _, chainID := range chainIDs {
if actualChainID.Cmp(chainID) == 0 { if actualChainID.Cmp(chainID) == 0 {
return true return true
@ -1861,15 +1950,19 @@ func (f *Firehose) panicInvalidState(msg string, callerSkip int) string {
panic(fmt.Errorf("%s (caller=%s, init=%t, inBlock=%t, inTransaction=%t, inCall=%t)", msg, caller, f.chainConfig != nil, f.block != nil, f.transaction != nil, f.callStack.HasActiveCall())) panic(fmt.Errorf("%s (caller=%s, init=%t, inBlock=%t, inTransaction=%t, inCall=%t)", msg, caller, f.chainConfig != nil, f.block != nil, f.transaction != nil, f.callStack.HasActiveCall()))
} }
// printBlockToFirehose is a helper function to print a block to Firehose protocl format. // printBlockToFirehose is a helper function to print a block to Firehose protocol format.
func (f *Firehose) printBlockToFirehose(block *pbeth.Block, finalityStatus *FinalityStatus) { func (f *Firehose) printBlockToFirehose(block *pbeth.Block, finalityStatus *FinalityStatus) {
headerSize := 225 // FIRE BLOCK:11 <blockNum:20> <blockHash:64> <prevNum:20> <prevHash:64> <libNum:20> <timestamp:20>
base64Size := math.Ceil(float64(proto.Size(block)) * 8 / 6)
bufferSize := headerSize + int(base64Size)
buf := bytes.NewBuffer(make([]byte, 0, bufferSize))
marshalled, err := proto.Marshal(block) marshalled, err := proto.Marshal(block)
if err != nil { if err != nil {
panic(fmt.Errorf("failed to marshal block: %w", err)) panic(fmt.Errorf("failed to marshal block: %w", err))
} }
f.outputBuffer.Reset()
previousHash := block.PreviousID() previousHash := block.PreviousID()
previousNum := 0 previousNum := 0
if block.Number > 0 { if block.Number > 0 {
@ -1888,9 +1981,9 @@ func (f *Firehose) printBlockToFirehose(block *pbeth.Block, finalityStatus *Fina
} }
// **Important* The final space in the Sprintf template is mandatory! // **Important* The final space in the Sprintf template is mandatory!
f.outputBuffer.WriteString(fmt.Sprintf("FIRE BLOCK %d %s %d %s %d %d ", block.Number, hex.EncodeToString(block.Hash), previousNum, previousHash, libNum, block.MustTime().UnixNano())) buf.WriteString(fmt.Sprintf("FIRE BLOCK %d %s %d %s %d %d ", block.Number, hex.EncodeToString(block.Hash), previousNum, previousHash, libNum, block.MustTime().UnixNano()))
encoder := base64.NewEncoder(base64.StdEncoding, f.outputBuffer) encoder := base64.NewEncoder(base64.StdEncoding, buf)
if _, err = encoder.Write(marshalled); err != nil { if _, err = encoder.Write(marshalled); err != nil {
panic(fmt.Errorf("write to encoder should have been infaillible: %w", err)) panic(fmt.Errorf("write to encoder should have been infaillible: %w", err))
} }
@ -1899,9 +1992,16 @@ func (f *Firehose) printBlockToFirehose(block *pbeth.Block, finalityStatus *Fina
panic(fmt.Errorf("closing encoder should have been infaillible: %w", err)) panic(fmt.Errorf("closing encoder should have been infaillible: %w", err))
} }
f.outputBuffer.WriteString("\n") buf.WriteString("\n")
f.flushToFirehose(f.outputBuffer.Bytes()) if f.concurrentBlockFlushing > 0 {
f.concurrentFlushQueue.outputQueue <- &outputJob{
blockNum: block.Number,
data: buf.Bytes(),
}
} else {
f.flushToFirehose(buf.Bytes())
}
} }
// printToFirehose is an easy way to print to Firehose format, it essentially // printToFirehose is an easy way to print to Firehose format, it essentially
@ -1966,11 +2066,10 @@ func newBlockHeaderFromChainHeader(hash common.Hash, h *types.Header) *pbeth.Blo
parentBeaconRootBytes = root.Bytes() parentBeaconRootBytes = root.Bytes()
} }
// Polygon doesn't have EIP-7702 yet [Search for polygon-eip-7702 across codebase for all places to uncomment] var requestHashBytes []byte
// var requestHashBytes []byte if hash := h.RequestsHash; hash != nil {
// if hash := h.RequestsHash; hash != nil { requestHashBytes = hash.Bytes()
// requestHashBytes = hash.Bytes() }
// }
pbHead := &pbeth.BlockHeader{ pbHead := &pbeth.BlockHeader{
Hash: hash.Bytes(), Hash: hash.Bytes(),
@ -1994,7 +2093,7 @@ func newBlockHeaderFromChainHeader(hash common.Hash, h *types.Header) *pbeth.Blo
BlobGasUsed: h.BlobGasUsed, BlobGasUsed: h.BlobGasUsed,
ExcessBlobGas: h.ExcessBlobGas, ExcessBlobGas: h.ExcessBlobGas,
ParentBeaconRoot: parentBeaconRootBytes, ParentBeaconRoot: parentBeaconRootBytes,
// RequestsHash: requestHashBytes, RequestsHash: requestHashBytes,
// This has been removed from Geth entirely, nothing best to do here than to set to nil (e.g. 0) // This has been removed from Geth entirely, nothing best to do here than to set to nil (e.g. 0)
TotalDifficulty: nil, TotalDifficulty: nil,
@ -2021,9 +2120,8 @@ func transactionTypeFromChainTxType(txType uint8) pbeth.TransactionTrace_Type {
return pbeth.TransactionTrace_TRX_TYPE_LEGACY return pbeth.TransactionTrace_TRX_TYPE_LEGACY
case types.BlobTxType: case types.BlobTxType:
return pbeth.TransactionTrace_TRX_TYPE_BLOB return pbeth.TransactionTrace_TRX_TYPE_BLOB
// Polygon doesn't have EIP-7702 yet [Search for polygon-eip-7702 across codebase for all places to uncomment] case types.SetCodeTxType:
// case types.SetCodeTxType: return pbeth.TransactionTrace_TRX_TYPE_SET_CODE
// return pbeth.TransactionTrace_TRX_TYPE_SET_CODE
default: default:
panic(fmt.Errorf("unknown transaction type %d", txType)) panic(fmt.Errorf("unknown transaction type %d", txType))
} }
@ -2141,37 +2239,37 @@ func newBlobHashesFromChain(blobHashes []common.Hash) (out [][]byte) {
return return
} }
// Polygon doesn't have EIP-7702 yet [Search for polygon-eip-7702 across codebase for all places to uncomment] func newSetCodeAuthorizationsFromChain(authorizations []types.SetCodeAuthorization) (out []*pbeth.SetCodeAuthorization) {
// func newSetCodeAuthorizationsFromChain(authorizations []types.SetCodeAuthorization) (out []*pbeth.SetCodeAuthorization) { if len(authorizations) == 0 {
// if len(authorizations) == 0 { return nil
// return nil }
// }
// out = make([]*pbeth.SetCodeAuthorization, len(authorizations)) out = make([]*pbeth.SetCodeAuthorization, len(authorizations))
// for i, authorization := range authorizations { for i, authorization := range authorizations {
// pbAuthorization := &pbeth.SetCodeAuthorization{ pbAuthorization := &pbeth.SetCodeAuthorization{
// ChainId: authorization.ChainID.Bytes(), ChainId: authorization.ChainID.Bytes(),
// Nonce: authorization.Nonce, Address: authorization.Address.Bytes(),
// V: uint32(authorization.V), Nonce: authorization.Nonce,
// R: normalizeSignaturePoint(authorization.R.Bytes()), V: uint32(authorization.V),
// S: normalizeSignaturePoint(authorization.S.Bytes()), R: normalizeSignaturePoint(authorization.R.Bytes()),
// } S: normalizeSignaturePoint(authorization.S.Bytes()),
}
// authority, err := authorization.Authority() authority, err := authorization.Authority()
// if err != nil { if err != nil {
// // The node skips invalid authorizations, we do the same, at transaction's end, we will // The node skips invalid authorizations, we do the same, at transaction's end, we will
// // also remove authorizations that didn't result into a code change. // also remove authorizations that didn't result into a code change.
// firehoseDebug("failed to compute authority for authorization at index %d (err=%s)", i, errorView(err)) firehoseDebug("failed to compute authority for authorization at index %d (err=%s)", i, errorView(err))
// pbAuthorization.Discarded = true pbAuthorization.Discarded = true
// } else { } else {
// pbAuthorization.Authority = authority.Bytes() pbAuthorization.Authority = authority.Bytes()
// } }
// out[i] = pbAuthorization out[i] = pbAuthorization
// } }
// return return
// } }
var balanceChangeReasonToPb = map[tracing.BalanceChangeReason]pbeth.BalanceChange_Reason{ var balanceChangeReasonToPb = map[tracing.BalanceChangeReason]pbeth.BalanceChange_Reason{
tracing.BalanceIncreaseRewardMineUncle: pbeth.BalanceChange_REASON_REWARD_MINE_UNCLE, tracing.BalanceIncreaseRewardMineUncle: pbeth.BalanceChange_REASON_REWARD_MINE_UNCLE,
@ -2188,7 +2286,6 @@ var balanceChangeReasonToPb = map[tracing.BalanceChangeReason]pbeth.BalanceChang
tracing.BalanceDecreaseSelfdestruct: pbeth.BalanceChange_REASON_SUICIDE_WITHDRAW, tracing.BalanceDecreaseSelfdestruct: pbeth.BalanceChange_REASON_SUICIDE_WITHDRAW,
tracing.BalanceDecreaseSelfdestructBurn: pbeth.BalanceChange_REASON_BURN, tracing.BalanceDecreaseSelfdestructBurn: pbeth.BalanceChange_REASON_BURN,
tracing.BalanceIncreaseWithdrawal: pbeth.BalanceChange_REASON_WITHDRAWAL, tracing.BalanceIncreaseWithdrawal: pbeth.BalanceChange_REASON_WITHDRAWAL,
tracing.BalanceChangeUnspecified: pbeth.BalanceChange_REASON_UNKNOWN, tracing.BalanceChangeUnspecified: pbeth.BalanceChange_REASON_UNKNOWN,
// Polygon specific balance change // Polygon specific balance change
@ -2220,10 +2317,8 @@ var gasChangeReasonToPb = map[tracing.GasChangeReason]pbeth.GasChange_Reason{
tracing.GasChangeWitnessContractInit: pbeth.GasChange_REASON_WITNESS_CONTRACT_INIT, tracing.GasChangeWitnessContractInit: pbeth.GasChange_REASON_WITNESS_CONTRACT_INIT,
tracing.GasChangeWitnessContractCreation: pbeth.GasChange_REASON_WITNESS_CONTRACT_CREATION, tracing.GasChangeWitnessContractCreation: pbeth.GasChange_REASON_WITNESS_CONTRACT_CREATION,
tracing.GasChangeWitnessCodeChunk: pbeth.GasChange_REASON_WITNESS_CODE_CHUNK, tracing.GasChangeWitnessCodeChunk: pbeth.GasChange_REASON_WITNESS_CODE_CHUNK,
// Polygon doesn't have EIP-7702 yet [Search for polygon-eip-7702 across codebase for all places to uncomment] tracing.GasChangeWitnessContractCollisionCheck: pbeth.GasChange_REASON_WITNESS_CONTRACT_COLLISION_CHECK,
// (This is not actually EIP-7702 related but will most probably be activated at the same time as EIP-7702) tracing.GasChangeTxDataFloor: pbeth.GasChange_REASON_TX_DATA_FLOOR,
// tracing.GasChangeWitnessContractCollisionCheck: pbeth.GasChange_REASON_WITNESS_CONTRACT_COLLISION_CHECK,
// tracing.GasChangeTxDataFloor: pbeth.GasChange_REASON_TX_DATA_FLOOR,
// Ignored, we track them manually, [newGasChange] ensure that we panic if we see Unknown // Ignored, we track them manually, [newGasChange] ensure that we panic if we see Unknown
tracing.GasChangeCallOpCode: pbeth.GasChange_REASON_UNKNOWN, tracing.GasChangeCallOpCode: pbeth.GasChange_REASON_UNKNOWN,
@ -2246,7 +2341,7 @@ func maxFeePerGas(tx *types.Transaction) *pbeth.BigInt {
case types.LegacyTxType, types.AccessListTxType: case types.LegacyTxType, types.AccessListTxType:
return nil return nil
case types.DynamicFeeTxType, types.BlobTxType /*, types.SetCodeTxType*/ : case types.DynamicFeeTxType, types.BlobTxType, types.SetCodeTxType:
return firehoseBigIntFromNative(tx.GasFeeCap()) return firehoseBigIntFromNative(tx.GasFeeCap())
} }
@ -2259,7 +2354,7 @@ func maxPriorityFeePerGas(tx *types.Transaction) *pbeth.BigInt {
case types.LegacyTxType, types.AccessListTxType: case types.LegacyTxType, types.AccessListTxType:
return nil return nil
case types.DynamicFeeTxType, types.BlobTxType /*, types.SetCodeTxType*/ : case types.DynamicFeeTxType, types.BlobTxType, types.SetCodeTxType:
return firehoseBigIntFromNative(tx.GasTipCap()) return firehoseBigIntFromNative(tx.GasTipCap())
} }
@ -2272,7 +2367,7 @@ func gasPrice(tx *types.Transaction, baseFee *big.Int) *pbeth.BigInt {
return firehoseBigIntFromNative(tx.GasPrice()) return firehoseBigIntFromNative(tx.GasPrice())
// In the context of dynamic fee transactions, `GasPrice() == GasFeeCap()` // In the context of dynamic fee transactions, `GasPrice() == GasFeeCap()`
case types.DynamicFeeTxType, types.BlobTxType /*, types.SetCodeTxType*/ : case types.DynamicFeeTxType, types.BlobTxType, types.SetCodeTxType:
if baseFee == nil { if baseFee == nil {
return firehoseBigIntFromNative(tx.GasPrice()) return firehoseBigIntFromNative(tx.GasPrice())
} }
@ -2668,7 +2763,7 @@ func staticFirehoseChainValidationOnInit() {
types.AccessListTxType: true, types.AccessListTxType: true,
types.DynamicFeeTxType: true, types.DynamicFeeTxType: true,
types.BlobTxType: true, types.BlobTxType: true,
//types.SetCodeTxType: true, types.SetCodeTxType: true,
} }
for txType := byte(0); txType < 255; txType++ { for txType := byte(0); txType < 255; txType++ {
@ -2842,7 +2937,7 @@ func (m Memory) GetPtr(offset, size int64) []byte {
// work because the memory is going to be expanded before the operation is actually // work because the memory is going to be expanded before the operation is actually
// executed so the memory will be of the correct size. // executed so the memory will be of the correct size.
// //
// In this situtation, we must pad with zeroes when the memory is not big enough. // In this situation, we must pad with zeroes when the memory is not big enough.
reminder := m[offset:] reminder := m[min(offset, int64(len(m))):]
return append(reminder, make([]byte, int(size)-len(reminder))...) return append(reminder, make([]byte, int(size)-len(reminder))...)
} }

View file

@ -0,0 +1,103 @@
package tracers
import (
pbeth "github.com/streamingfast/firehose-ethereum/types/pb/sf/ethereum/type/v2"
"sync"
)
type blockPrintJob struct {
block *pbeth.Block
finality *FinalityStatus
}
type outputJob struct {
blockNum uint64
data []byte
}
type ConcurrentFlushQueue struct {
bufferSize int
startSignal chan uint64
jobQueue chan *blockPrintJob
outputQueue chan *outputJob
printBlockFunc func(block *pbeth.Block, finality *FinalityStatus)
outputFunc func([]byte)
jobWG sync.WaitGroup
outputWG sync.WaitGroup
closeOnce sync.Once
}
func NewConcurrentFlushQueue(bufferSize int, printBlockFunc func(*pbeth.Block, *FinalityStatus), outputFunc func([]byte)) *ConcurrentFlushQueue {
return &ConcurrentFlushQueue{
startSignal: make(chan uint64, 1),
jobQueue: make(chan *blockPrintJob, bufferSize),
outputQueue: make(chan *outputJob, bufferSize),
outputFunc: outputFunc,
bufferSize: bufferSize,
printBlockFunc: printBlockFunc,
}
}
func (q *ConcurrentFlushQueue) Start(concurrency int) {
for i := 0; i < concurrency; i++ {
q.jobWG.Add(1)
go q.worker()
}
q.outputWG.Add(1)
go q.outputOrderer()
}
func (q *ConcurrentFlushQueue) Enqueue(block *pbeth.Block, finality *FinalityStatus) {
select {
case q.startSignal <- block.Number:
default:
}
q.jobQueue <- &blockPrintJob{
block: block,
finality: finality,
}
}
// CloseChannels signals goroutines to shut down and waits for them.
// It blocks until all concurrent block flushing operations are completed, ensuring a clean
// shutdown of the printing pipeline.
func (q *ConcurrentFlushQueue) CloseChannels() {
q.closeOnce.Do(func() {
close(q.jobQueue)
q.jobWG.Wait()
close(q.outputQueue)
q.outputWG.Wait()
})
}
// Instantiates a worker that listens for jobs
func (q *ConcurrentFlushQueue) worker() {
defer q.jobWG.Done()
for job := range q.jobQueue {
q.printBlockFunc(job.block, job.finality)
}
}
// Channel ensuring that blocks are linearly flushed out in order
func (q *ConcurrentFlushQueue) outputOrderer() {
defer q.outputWG.Done()
buffer := make(map[uint64][]byte)
next := <-q.startSignal
for job := range q.outputQueue {
buffer[job.blockNum] = job.data
for {
data, ok := buffer[next]
if !ok {
break
}
q.outputFunc(data)
delete(buffer, next)
next++
}
}
}

View file

@ -0,0 +1,144 @@
# Report: Concurrent Block Flushing in Tracer Processing System
## Section 1: Introduction
Currently, the tracer processing system operates in a linear fashion, requiring the complete processing of a block's code before proceeding to the next one. As a result, computationally expensive operations—such as `proto.Marshal` and base64 encoding, which are essential for flushing a block to the firehose—can introduce significant delays. To mitigate this bottleneck, a potential solution is to leverage concurrency by introducing goroutines. These heavy operations can be offloaded to a separate channel, enabling asynchronous processing. This approach allows the main execution flow to begin processing subsequent blocks while previous ones are being flushed, thereby improving overall throughput and reducing latency. The goal of this report is to outline the solution and provide benchmarking results.
## Section 2: Background
`proto.Marshal`, part of Protocol Buffers (protobuf), serializes structured data into a compact binary format. While efficient in output size, the process of traversing and encoding complex data structures—especially those with deeply nested or repeated fields—can be CPU-intensive. Additionally, memory allocations during marshaling can introduce further overhead.
Similarly, base64 encoding, which transforms binary data into an ASCII string format for transmission or storage, involves non-trivial byte-wise transformations and increases the data size. This added computational cost becomes significant when processing large blocks or high-throughput workloads.
Together, these operations introduce latency in a linear processing pipeline.
## Section 3: Method
### 3.1 Proposed Solution
A critical point in the tracer processing system is the `OnBlockEnd` hook, which invokes the `printBlockToFirehose` method. This method includes computationally expensive operations such as `proto.Marshal` and base64 encoding, which are necessary to serialize and flush the block data to the firehose.
To address this, the current solution introduces a worker queue mechanism. Specifically, a single goroutine backed by a channel is used to enqueue and process `printBlockToFirehose` tasks asynchronously. This decouples the expensive flush operations from the main block processing path, allowing the tracer to begin handling the next block immediately after `OnBlockEnd` is invoked. This behavior is controlled by the `FirehoseConfig.ConcurrencyBlockFlushing` flag: when set to `true`, the asynchronous flushing mode is enabled; when set to `false`, the system falls back to the default linear execution of `printBlockToFirehose`.
As part of future work, this model can be extended from a single worker goroutine to multiple concurrent workers. This could further improve throughput by increasing parallelism. However, such an enhancement must address critical challenges, including proper synchronization of shared resources like `output.Buffer` and maintaining the strict block ordering requirement—i.e., block N must be flushed before block N+1 to preserve data consistency.
### 3.2 Validation and Performance Metrics
The implementation was validated at multiple levels to ensure correctness, configurability, and performance improvements of the concurrent block flushing mechanism.
1. **Unit-Level Validation**
To confirm the functional correctness of the concurrent flushing implementation, a unit test was written that creates and processes 1,000 blocks, flushing each to an `InternalTestingBuffer`. The results were then compared against expected outputs to verify equivalence. The test confirms that the output produced by the concurrent mechanism matches that of the original linear method, thereby validating correctness at the unit level.
2. **Integration Testing on Battlefield-Ethereum**
To verify integration within the battlefield-ethereum environment, the feature was exposed via a new configuration flag: `CONCURRENT_BLOCK_FLUSHING`. This flag determines whether the system uses the default sequential method or the new concurrent implementation. The system can be toggled between these modes with the following commands:
Original (linear flushing):
```bash
./scripts/run_firehose_geth_dev.sh 3.0 prague
```
Concurrent flushing enabled:
```bash
CONCURRENT_BLOCK_FLUSHING=true ./scripts/run_firehose_geth_dev.sh 3.0 prague
```
Behavioral differences were observed through log output. In the concurrent mode, log lines such as:
```
"Closing channel: flushing the remaining blocks to firehose"
```
appear when the program is interrupted (e.g., via Ctrl + C), indicating that the concurrent flushing logic and cleanup path are active. These lines are absent in the linear configuration, confirming that the switch is functioning as intended.
Furthermore, when running the integration test suite using:
```bash
pnpm test:fh3.0:geth-dev
```
all tests passed successfully (64 passing), indicating that the concurrent implementation does not introduce regressions in battlefield compatibility.
3. **Performance Benchmarking**
To quantify performance differences, benchmarking was conducted using firehose-ethereum. The following command was used for both the baseline and concurrent configurations:
```bash
time geth --vmtrace=firehose \
--vmtrace.jsonconfig='{"concurrentBlockFlushing":<true|false>}' \
--synctarget=0x7ae82cb3e60f13272a59319a4b617022228227258e18e0c5e7404236d773d2a3 \
--syncmode=full --holesky --datadir=./geth --db.engine=pebble \
--state.scheme=path --port=30305 --authrpc.jwtsecret=jwt.txt \
--authrpc.addr=0.0.0.0 --authrpc.port=9551 --authrpc.vhosts="*" \
--http --http.addr=0.0.0.0 --http.api=eth,net,web3 --http.port=9545 \
--http.vhosts="*" --port=40303 --ws.port=9546 --ipcpath=/tmp/geth.ipc > /dev/null
```
The benchmark was conducted in two phases:
* With `concurrentBlockFlushing: false`, the node was synced to block 10,000, the data directory (`./geth`) was removed, and then resynced up to block 100,000.
* The same steps were repeated with `concurrentBlockFlushing: true`.
Note: A channel with a buffer of 100 was created to allow the tasks to queue without blocking the producer. \
The `time` command outputs wall-clock time and system/user CPU usage upon completion, providing a baseline for comparing performance between the linear and concurrent implementations. This methodology enables a controlled, reproducible environment for evaluating the effectiveness of the concurrent block flushing feature.
## Section 4: Analysis
The specifications of the operating system used for testing are as follows:
Model: Macbook Air \
Processor: Apple M1 chip \
Memory: 8 GB
### 4.1 Results
The following outlines the results for metric three:
**Until Block 10000**
**No concurrency**
Run 1: 71.49s user 15.56s system 56% cpu 2:34.28 total\
Run 2: 69.77s user 15.60s system 54% cpu 2:37.73 total\
Run 3: 68.81s user 15.12s system 53% cpu 2:38.18 total
**Concurrency**
Run 1: 69.61s user 14.97s system 55% cpu 2:32.85 total\
Run 2: 67.94s user 15.13s system 54% cpu 2:33.59 total\
Run 3: 68.60s user 16.37s system 48% cpu 2:54.22 total (Not sure what happened here)
**Until Block 100000**
**No concurrency**
364.19s user 172.14s system 34% cpu 26:13.33 total
**Concurrency**
358.42s user 171.21s system 35% cpu 25:11.97 total
**Table 1: Result comparison with and without concurrency**
| | No Concurrency | Concurrency |
| :-------------- | :------------- | :----------------- |
| **Block 10 000** | | |
| user | 70.02s | 68.72s |
| system | 15.43s | 15.49s |
| cpu | 54.33% | 52.33% |
| total | 2:36.73 | 2:40.22 (because of last run) |
| **Block 100 000**| | |
| user | 364.19s | 358.42s |
| system | 172.14s | 171.21s |
| cpu | 34% | 35% |
| total | 26:13.33 | 25:11.97 |
### 4.2 Discussion
Run 3 with concurrency seems to be an outlier. Without it, the general trend would be that every block saves around 0.0006 second, or 0.6 millisecond. \
User seems slightly lower, whereas system and cpu are relatively the same.
## Section 5: Conclusion
The implementation of a single goroutine seems to lead to a decrease in the total time by a factor of 0.6 millisecond per block.

View file

@ -0,0 +1,199 @@
# Report 2: Concurrent Block Flushing in Tracer Processing System
## Section 1: Introduction
Currently, the tracer processing system operates in a linear fashion, requiring the complete processing of a block's code before proceeding to the next one. As a result, computationally expensive operations—such as `proto.Marshal` and base64 encoding, which are essential for flushing a block to the firehose—can introduce significant delays. To mitigate this bottleneck, a potential solution is to leverage concurrency by introducing goroutines. These heavy operations can be offloaded to a separate channel, enabling asynchronous processing. This approach allows the main execution flow to begin processing subsequent blocks while previous ones are being flushed, thereby improving overall throughput and reducing latency. The goal of this report is to outline the solution and provide benchmarking results.
## Section 2: Background
`proto.Marshal`, part of Protocol Buffers (protobuf), serializes structured data into a compact binary format. While efficient in output size, the process of traversing and encoding complex data structures—especially those with deeply nested or repeated fields—can be CPU-intensive. Additionally, memory allocations during marshaling can introduce further overhead.
Similarly, base64 encoding, which transforms binary data into an ASCII string format for transmission or storage, involves non-trivial byte-wise transformations and increases the data size. This added computational cost becomes significant when processing large blocks or high-throughput workloads.
Together, these operations introduce latency in a linear processing pipeline.
## Section 3: Method
### 3.1 Proposed Solution
A critical point in the tracer processing system is the `OnBlockEnd` hook, which invokes the `printBlockToFirehose` method. This method includes computationally expensive operations such as `proto.Marshal` and base64 encoding, which are necessary to serialize and flush the block data to the firehose.
To address this, the proposed solution introduces a concurrency mechanism. Specifically, the user specifies a number of worker goroutines that will be concurrently working through the `FirehoseConfig.ConcurrencyBlockFlushing` configuration. There are three layers to this process:
1. A worker queue channel with a buffer of 100 is created. All `printBlockToFirehose` tasks are enqueued while waiting for a worker to take and process it.
2. A number of workers specified by the configuration will be taking and processing these tasks asynchronously until the data is in a byte format and ready to be sent to stdout. The goroutine will then send that data, along with the block number, to a second channel.
3. A final channel is created to store pairs of (block number, [byte]). This channel allows linear flushing by only allowing the current expected block number to be flushed, while storing the remaining blocks until it is their turn. To achieve this, a block number is stored globally the first time `OnBlockEnd` is called. Therefore, the channel will know the first block number expected to be flushed and will increment the expected number by one each time.
### 3.2 Validation and Performance Metrics
The implementation was validated at multiple levels to ensure correctness, configurability, and performance improvements of the concurrent block flushing mechanism.
1. **Unit-Level Validation**
To confirm the functional correctness of the concurrent flushing implementation, a unit test was written that creates and processes 1,000 blocks, flushing each to an `InternalTestingBuffer`. The results were then compared against expected outputs to verify equivalence. The test confirms that the output produced by the concurrent mechanism matches that of the original linear method, thereby validating correctness at the unit level.
2. **Integration Testing on Battlefield-Ethereum**
To verify integration within the battlefield-ethereum environment, the feature was exposed via a new configuration flag: `CONCURRENT_BLOCK_FLUSHING`. This flag determines the number of workers that will be processing tasks concurrently. \
Original (linear flushing):
```bash
./scripts/run_firehose_geth_dev.sh 3.0 prague
```
Concurrent flushing enabled:
```bash
CONCURRENT_BLOCK_FLUSHING=1 ./scripts/run_firehose_geth_dev.sh 3.0 prague
```
Behavioral differences were observed through log output. In the concurrent mode, log lines such as:
```
"Firehose closing, flushing queued blocks to standard output"
```
appear when the program is interrupted (e.g., via Ctrl + C), indicating that the concurrent flushing logic and cleanup path are active. These lines are absent in the linear configuration, confirming that the switch is functioning as intended.
Furthermore, when running the integration test suite using:
```bash
pnpm test:fh3.0:geth-dev
```
all tests passed successfully (64 passing), indicating that the concurrent implementation does not introduce regressions in battlefield compatibility.
3. **Performance Benchmarking**
To quantify performance differences, benchmarking was conducted using firehose-ethereum. The following command was used for both the baseline and concurrent configurations:
```bash
time geth --vmtrace=firehose \
--vmtrace.jsonconfig='{"concurrentBlockFlushing":<number_of_workers>}' \
--synctarget=<last_block_hash> \
--syncmode=full --holesky --datadir=./geth --db.engine=pebble \
--state.scheme=path --port=30305 --authrpc.jwtsecret=jwt.txt \
--authrpc.addr=0.0.0.0 --authrpc.port=9551 --authrpc.vhosts="*" \
--http --http.addr=0.0.0.0 --http.api=eth,net,web3 --http.port=9545 \
--http.vhosts="*" --port=40303 --ws.port=9546 --ipcpath=/tmp/geth.ipc > /dev/null
```
The benchmark was conducted in four phases:
* With `concurrentBlockFlushing: 0`, the node was synced to block 10,000, the data directory (`./geth`) was removed, and then resynced up to block 100,000.
* The same steps were repeated with `concurrentBlockFlushing: 10`.
* The same steps were repeated with `concurrentBlockFlushing: 100`.
* The same steps were repeated with `concurrentBlockFlushing: 1000`.
The `time` command outputs wall-clock time and system/user CPU usage upon completion, providing a baseline for comparing performance between the linear and concurrent implementations. This methodology enables a controlled, reproducible environment for evaluating the effectiveness of the concurrent block flushing feature.
## Section 4: Analysis
The specifications of the operating system used for testing are as follows:
Model: Macbook Air \
Processor: Apple M1 chip \
Memory: 8 GB
Geth version used is 1.15.10
### 4.1 Results
The following outlines the results for metric three:
### Until Block 10,000
#### No Concurrency
- Run 1: 84.43s user, 15.27s system, 61% CPU, 2:41.39 total
- Run 2: 86.76s user, 15.93s system, 64% CPU, 2:40.36 total
- Run 3: 78.30s user, 14.62s system, 55% CPU, 2:47.51 total
- Run 4: 78.29s user, 13.72s system, 55% CPU, 2:44.45 total
- Run 5: 83.29s user, 13.37s system, 59% CPU, 2:43.47 total
#### Concurrency (10 Goroutines)
- Run 1: 68.14s user, 13.85s system, 51% CPU, 2:39.27 total
- Run 2: 70.81s user, 14.10s system, 52% CPU, 2:40.37 total
- Run 3: 64.79s user, 13.65s system, 49% CPU, 2:39.22 total
- Run 4: 64.34s user, 15.18s system, 48% CPU, 2:43.25 total
- Run 5: 70.21s user, 15.58s system, 51% CPU, 2:47.34 total
#### Concurrency (100 Goroutines)
- Run 1: 71.19s user, 16.06s system, 53% CPU, 2:42.77 total
- Run 2: 66.74s user, 12.12s system, 51% CPU, 2:34.47 total
- Run 3: 72.53s user, 16.11s system, 56% CPU, 2:37.50 total
- Run 4: 70.99s user, 14.02s system, 56% CPU, 2:29.46 total
- Run 5: 65.86s user, 13.66s system, 54% CPU, 2:24.97 total
#### Concurrency (1000 Goroutines)
- Run 1: 68.44s user, 14.65s system, 54% CPU, 2:33.83 total
- Run 2: 72.79s user, 15.06s system, 55% CPU, 2:38.76 total
- Run 3: 65.60s user, 13.19s system, 53% CPU, 2:28.36 total
- Run 4: 71.82s user, 15.05s system, 54% CPU, 2:38.10 total
- Run 5: 71.36s user, 14.87s system, 56% CPU, 2:33.32 total
---
### Until Block 100,000
#### No Concurrency
- 331.03s user, 165.76s system, 32% CPU, 25:28.66 total
#### Concurrency (10 Goroutines)
- 383.44s user, 183.39s system, 37% CPU, 25:22.84 total
#### Concurrency (100 Goroutines)
- 399.57s user, 175.51s system, 37% CPU, 25:28.03 total
#### Concurrency (1000 Goroutines)
- 346.83s user, 165.96s system, 34% CPU, 25:02.78 total
---
### Table 1: Result Comparison with and Without Concurrency
#### Block 10,000 Summary
| Goroutines | User Time | System Time | CPU | Total Time |
|------------|-----------|-------------|-------|------------|
| 0 | 82.214s | 14.582s | 58.8% | 2:43.44 |
| 10 | 67.666s | 14.270s | 50.2% | 2:41.89 |
| 100 | 69.462s | 14.394s | 54.0% | 2:33.83 |
| 1000 | 69.990s | 14.564s | 54.4% | 2:34.47 |
#### Block 100,000 Summary
| Goroutines | User Time | System Time | CPU | Total Time |
|------------|-----------|-------------|--------|-------------|
| 0 | 331.03s | 165.76s | 32.0% | 25:28.66 |
| 10 | 383.44s | 183.39s | 37.0% | 25:22.84 |
| 100 | 399.57s | 175.51s | 37.0% | 25:28.03 |
| 1000 | 346.83s | 165.96s | 34.0% | 25:02.78 |
---
### 4.2 Discussion
The four parameters analyzed are **user**, **system**, **CPU**, and **total**.
- **System** and **CPU** times do not vary significantly with the implementation of goroutines.
- **User** and **Total** time are generally lower with the use of concurrency for 10,000 blocks.
- However, performance improvement for 100,000 blocks is less conclusive.
This could be due to:
- Single-run variance
- Varying system conditions during execution
- Larger processing overhead over a long duration
More runs and broader statistical analysis may be required to solidify findings.
## Section 5: Conclusion
The introduction of concurrency to the block flushing process demonstrates performance improvements for smaller workloads (up to 10,000 blocks), particularly in reducing user and total processing time. While results for larger workloads (100,000 blocks) show less consistent gains.

View file

@ -0,0 +1,146 @@
package tracers
import (
"encoding/hex"
"fmt"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
"regexp"
"strconv"
"strings"
"testing"
)
func TestFirehose_BlockPrintsToFirehose_SingleBlock(t *testing.T) {
f := NewFirehose(&FirehoseConfig{
ConcurrentBlockFlushing: 1,
ApplyBackwardCompatibility: ptr(false),
private: &privateFirehoseConfig{
FlushToTestBuffer: true,
},
})
f.OnBlockchainInit(params.AllEthashProtocolChanges)
blockNumbers := []uint64{0}
for i, blockNum := range blockNumbers {
f.OnBlockStart(blockEvent(blockNum))
f.onTxStart(txEvent(), hex2Hash(fmt.Sprintf("ABCD%d", i)), from, to)
f.OnCallEnter(0, byte(vm.CALL), from, to, nil, 0, nil)
f.OnBalanceChange(from, b(100), b(50), 0)
f.OnCallExit(0, nil, 0, nil, false)
f.OnTxEnd(txReceiptEvent(0), nil)
f.OnBlockEnd(nil)
}
f.OnClose()
lines := strings.Split(strings.TrimSpace(f.InternalTestingBuffer().String()), "\n")
require.Len(t, lines, 2)
fieldsInit := strings.SplitN(lines[0], " ", 3)
require.Equal(t, "FIRE", fieldsInit[0])
require.Equal(t, "INIT", fieldsInit[1])
require.Contains(t, fieldsInit[2], "geth")
fields := strings.SplitN(lines[1], " ", 4)
require.GreaterOrEqual(t, len(fields), 3)
require.Equal(t, "FIRE", fields[0])
require.Equal(t, "BLOCK", fields[1])
require.Equal(t, "0", fields[2])
}
func TestFirehose_BlocksPrintToFirehose_MultipleBlocksInOrder(t *testing.T) {
const blockCount = 100
const baseBlockNum = 0
f := NewFirehose(&FirehoseConfig{
ConcurrentBlockFlushing: 1,
ApplyBackwardCompatibility: ptr(false),
private: &privateFirehoseConfig{
FlushToTestBuffer: true,
},
})
f.OnBlockchainInit(params.AllEthashProtocolChanges)
blockHashes := make(map[uint64]string, blockCount)
for i := 0; i < blockCount; i++ {
blockNum := uint64(baseBlockNum + i)
f.OnBlockStart(blockEvent(blockNum))
blockHashes[blockNum] = hex.EncodeToString(f.block.Hash) // Store hash before block reset
f.onTxStart(txEvent(), hex2Hash(fmt.Sprintf("TX%d", i)), from, to)
f.OnCallEnter(0, byte(vm.CALL), from, to, nil, 0, nil)
f.OnBalanceChange(from, b(100), b(50), 0)
f.OnCallExit(0, nil, 0, nil, false)
f.OnTxEnd(txReceiptEvent(0), nil)
f.OnBlockEnd(nil)
}
f.OnClose()
output := f.InternalTestingBuffer().String()
extractedBlocks := extractBlocksFromOutput(t, output)
// Verify block count
require.Equal(t, blockCount, len(extractedBlocks),
"Expected %d blocks in output, found %d", blockCount, len(extractedBlocks))
// Verify blocks in order
for i, block := range extractedBlocks {
require.Equal(t, baseBlockNum+uint64(i), block.number, "Blocks out of order at position %d", i)
}
// Verify block hashes
for _, block := range extractedBlocks {
expectedHash, exists := blockHashes[block.number]
require.True(t, exists, "Block %d not found in tracked blocks", block.number)
require.Equal(t, expectedHash, block.hash,
"Hash mismatch for block %d", block.number)
}
}
type extractedBlock struct {
number uint64
hash string
}
func extractBlocksFromOutput(t *testing.T, output string) []extractedBlock {
t.Helper()
// Regex to extract the block number and hash from the FIRE BLOCK line
blockInfoRegex := regexp.MustCompile(`FIRE BLOCK (\d+) ([0-9a-fA-F]+)`)
lines := strings.Split(output, "\n")
var blocks []extractedBlock
for _, line := range lines {
if strings.HasPrefix(line, "FIRE BLOCK") {
matches := blockInfoRegex.FindStringSubmatch(line)
if len(matches) == 3 {
blockNumStr := matches[1]
blockHash := matches[2]
blockNum, err := strconv.ParseUint(blockNumStr, 10, 64)
require.NoError(t, err, "failed to parse block number: %s", blockNumStr)
blocks = append(blocks, extractedBlock{
number: blockNum,
hash: blockHash,
})
}
}
}
return blocks
}

View file

@ -1,7 +1,6 @@
package tracers package tracers
import ( import (
"cmp"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math" "math"
@ -112,10 +111,6 @@ var ignorePbFieldNames = map[string]bool{
// This was a Polygon specific field that existed for a while and has since been // This was a Polygon specific field that existed for a while and has since been
// removed. It can be safely ignored in all protocols now. // removed. It can be safely ignored in all protocols now.
"TxDependency": true, "TxDependency": true,
// Polygon doesn't have EIP-7702 yet [Search for polygon-eip-7702 across codebase for all places to uncomment]
// (RequestsHash is actually not EIP-7702, but will probably be activated in Polygon at the same time)
"RequestsHash": true,
} }
var pbFieldNameToGethMapping = map[string]string{ var pbFieldNameToGethMapping = map[string]string{
@ -135,22 +130,12 @@ var (
gethHeaderType = reflect.TypeFor[types.Header]() gethHeaderType = reflect.TypeFor[types.Header]()
) )
const (
shangaiHash = "5341947c531e5c9cf38202784b16ac66484fe1838aa6e825436b22321b927296"
pragueHash = "4ced4916132bbf6a7819a310bbac4abf354062a00efc980ea4f0bab406546ac5"
)
func Test_TypesHeader_AllConsensusFieldsAreKnown(t *testing.T) { func Test_TypesHeader_AllConsensusFieldsAreKnown(t *testing.T) {
inferredHash := pragueHash
if ignorePbFieldNames["RequestsHash"] {
inferredHash = shangaiHash
}
// This exact hash varies from protocol to protocol and also sometimes from one version to the other. // This exact hash varies from protocol to protocol and also sometimes from one version to the other.
// When adding support for a new hard-fork that adds new block header fields, it's normal that this value // When adding support for a new hard-fork that adds new block header fields, it's normal that this value
// changes. If you are sure the two struct are the same, then you can update the expected hash below // changes. If you are sure the two struct are the same, then you can update the expected hash below
// to the new value. // to the new value.
expectedHash := common.HexToHash(inferredHash) expectedHash := common.HexToHash("4ced4916132bbf6a7819a310bbac4abf354062a00efc980ea4f0bab406546ac5")
gethHeaderValue := reflect.New(gethHeaderType) gethHeaderValue := reflect.New(gethHeaderType)
fillAllFieldsWithNonEmptyValues(t, gethHeaderValue, reflect.VisibleFields(gethHeaderType)) fillAllFieldsWithNonEmptyValues(t, gethHeaderValue, reflect.VisibleFields(gethHeaderType))
@ -211,7 +196,7 @@ func TestFirehose_BalanceChangeAllMappedCorrectly(t *testing.T) {
for i := 0; i <= math.MaxUint8; i++ { for i := 0; i <= math.MaxUint8; i++ {
tracingReason := tracing.BalanceChangeReason(i) tracingReason := tracing.BalanceChangeReason(i)
if tracingReason == tracing.BalanceChangeUnspecified /** || tracingReason == tracing.BalanceChangeRevert */ { if tracingReason == tracing.BalanceChangeUnspecified || tracingReason == tracing.BalanceChangeRevert {
// Should never happen in Firehose tracer, only if tracer is wrapped with [tracing.WrapWithJournal] // Should never happen in Firehose tracer, only if tracer is wrapped with [tracing.WrapWithJournal]
continue continue
} }
@ -318,8 +303,8 @@ func fieldsCountMismatchMessage(t *testing.T, pbFieldNames map[string]bool, geth
"Missing in `*types.Header`:\n%s", "Missing in `*types.Header`:\n%s",
len(pbRemappedFieldNames), len(pbRemappedFieldNames),
len(gethFieldNames), len(gethFieldNames),
asIndentedJSON(t, mapSortedKeys(pbRemappedFieldNames)), asIndentedJSON(t, maps.Keys(pbRemappedFieldNames)),
asIndentedJSON(t, mapSortedKeys(gethFieldNames)), asIndentedJSON(t, maps.Keys(gethFieldNames)),
asIndentedJSON(t, missingInSet(gethFieldNames, pbRemappedFieldNames)), asIndentedJSON(t, missingInSet(gethFieldNames, pbRemappedFieldNames)),
asIndentedJSON(t, missingInSet(pbRemappedFieldNames, gethFieldNames)), asIndentedJSON(t, missingInSet(pbRemappedFieldNames, gethFieldNames)),
) )
@ -363,12 +348,6 @@ func filter[S ~[]T, T any](s S, f func(T) bool) (out S) {
return out return out
} }
func mapSortedKeys[M ~map[K]V, K cmp.Ordered, V any](m M) []K {
keys := maps.Keys(m)
slices.Sort(keys)
return keys
}
func TestFirehose_reorderIsolatedTransactionsAndOrdinals(t *testing.T) { func TestFirehose_reorderIsolatedTransactionsAndOrdinals(t *testing.T) {
tests := []struct { tests := []struct {
name string name string

View file

@ -7,7 +7,6 @@ import (
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/stateless"
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -30,7 +29,9 @@ func runPrestateBlock(t *testing.T, prestatePath string, hooks *tracing.Hooks) {
testState := tests.MakePreState(rawdb.NewMemoryDatabase(), prestate.Genesis.Alloc, false, rawdb.HashScheme) testState := tests.MakePreState(rawdb.NewMemoryDatabase(), prestate.Genesis.Alloc, false, rawdb.HashScheme)
defer testState.Close() defer testState.Close()
testState.StateDB.SetLogger(hooks) state.NewHookedState(testState.StateDB, hooks)
// testState.StateDB.SetLogger(hooks)
testState.StateDB.SetTxContext(tx.Hash(), 0) testState.StateDB.SetTxContext(tx.Hash(), 0)
block := types.NewBlock(&types.Header{ block := types.NewBlock(&types.Header{
@ -60,14 +61,12 @@ func runPrestateBlock(t *testing.T, prestatePath string, hooks *tracing.Hooks) {
msg, err := core.TransactionToMessage(tx, types.MakeSigner(prestate.Genesis.Config, header.Number, header.Time), header.BaseFee) msg, err := core.TransactionToMessage(tx, types.MakeSigner(prestate.Genesis.Config, header.Number, header.Time), header.BaseFee)
require.NoError(t, err) require.NoError(t, err)
txContext := core.NewEVMTxContext(msg)
blockContext := core.NewEVMBlockContext(block.Header(), prestate, &context.Coinbase) blockContext := core.NewEVMBlockContext(block.Header(), prestate, &context.Coinbase)
vmenv := vm.NewEVM(blockContext, txContext, testState.StateDB, prestate.Genesis.Config, vm.Config{Tracer: hooks}) vmenv := vm.NewEVM(blockContext, state.NewHookedState(testState.StateDB, hooks), prestate.Genesis.Config, vm.Config{Tracer: hooks})
usedGas := uint64(0) usedGas := uint64(0)
_, err = core.ApplyTransactionWithEVM( _, err = core.ApplyTransactionWithEVM(
msg, msg,
prestate.Config(),
new(core.GasPool).AddGas(block.GasLimit()), new(core.GasPool).AddGas(block.GasLimit()),
testState.StateDB, testState.StateDB,
header.Number, header.Number,
@ -90,18 +89,10 @@ type ignoreValidateStateValidator struct {
core.Validator core.Validator
} }
// ValidateBody validates the given block's content.
func (v ignoreValidateStateValidator) ValidateBody(block *types.Block) error { func (v ignoreValidateStateValidator) ValidateBody(block *types.Block) error {
return nil return v.Validator.ValidateBody(block)
} }
// ValidateState validates the given statedb and optionally the receipts and func (v ignoreValidateStateValidator) ValidateState(block *types.Block, state *state.StateDB, res *core.ProcessResult, stateless bool) error {
// gas used.
func (v ignoreValidateStateValidator) ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error {
return nil
}
// ValidateWitness cross validates a block execution with stateless remote clients.
func (v ignoreValidateStateValidator) ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error {
return nil return nil
} }

View file

@ -1,12 +1,15 @@
package firehose_test package firehose_test
import ( import (
"fmt"
"math/big" "math/big"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"testing" "testing"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/beacon"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
@ -14,15 +17,13 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/core/vm/program"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func init() {
log.SetDefault(log.NewLogger(log.NewTerminalHandler(os.Stdout, false)))
}
type tracingModel string type tracingModel string
const ( const (
@ -38,155 +39,159 @@ func TestFirehosePrestate(t *testing.T) {
"./testdata/TestFirehosePrestate/keccak256_wrong_diff", "./testdata/TestFirehosePrestate/keccak256_wrong_diff",
"./testdata/TestFirehosePrestate/suicide_double_withdraw", "./testdata/TestFirehosePrestate/suicide_double_withdraw",
"./testdata/TestFirehosePrestate/extra_account_creations", "./testdata/TestFirehosePrestate/extra_account_creations",
"./testdata/TestFirehosePrestate/keccak256_memory_out_of_bounds",
} }
for _, concurrent := range []int{0, 1} {
for _, folder := range testFolders { for _, folder := range testFolders {
name := filepath.Base(folder) name := filepath.Base(folder)
concurrencyLabel := "sequential"
if concurrent == 1 {
concurrencyLabel = "concurrent"
}
for _, model := range tracingModels { for _, model := range tracingModels {
t.Run(string(model)+"/"+name, func(t *testing.T) { t.Run(fmt.Sprintf("%s/%s/%s", model, name, concurrencyLabel), func(t *testing.T) {
tracer, tracingHooks, onClose := newFirehoseTestTracer(t, model) config := &tracers.FirehoseConfig{
defer onClose() ConcurrentBlockFlushing: concurrent,
}
tracer, tracingHooks, _ := newFirehoseTestTracer(t, model, config)
runPrestateBlock(t, filepath.Join(folder, "prestate.json"), tracingHooks) runPrestateBlock(t, filepath.Join(folder, "prestate.json"), tracingHooks)
tracer.OnClose()
genesisLine, blockLines, unknownLines := readTracerFirehoseLines(t, tracer) genesisLine, blockLines, unknownLines := readTracerFirehoseLines(t, tracer)
require.Len(t, unknownLines, 0, "Lines:\n%s", strings.Join(slicesMap(unknownLines, func(l unknownLine) string { return "- '" + string(l) + "'" }), "\n")) require.Len(t, unknownLines, 0, "Lines:\n%s", strings.Join(
slicesMap(unknownLines, func(l unknownLine) string { return "- '" + string(l) + "'" }), "\n"))
require.NotNil(t, genesisLine) require.NotNil(t, genesisLine)
blockLines.assertOnlyBlockEquals(t, filepath.Join(folder, string(model)), 1) blockLines.assertOnlyBlockEquals(t, filepath.Join(folder, string(model)), 1)
}) })
} }
}
}
}
func TestFirehose_EIP7702(t *testing.T) {
// Copied from ./core/blockchain_test.go#L4180 (TestEIP7702)
var (
config = *params.MergedTestChainConfig
signer = types.LatestSigner(&config)
engine = beacon.New(ethash.NewFaker())
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb")
cc = common.HexToAddress("0x000000000000000000000000000000000000cccc")
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
)
gspec := &core.Genesis{
Config: &config,
Alloc: types.GenesisAlloc{
addr1: {Balance: funds},
addr2: {Balance: funds},
aa: { // The address 0xAAAA calls into addr2
Code: program.New().Call(nil, addr2, 1, 0, 0, 0, 0).Bytes(),
Nonce: 0,
Balance: big.NewInt(0),
},
bb: { // The address 0xBBBB sstores 42 into slot 42.
Code: program.New().Sstore(0x42, 0x42).Bytes(),
Nonce: 0,
Balance: big.NewInt(0),
},
cc: { // The address 0xCCCC sstores 42 into slot 42.
Code: program.New().Sstore(0x42, 0x42).Bytes(),
Nonce: 0,
Balance: big.NewInt(0),
},
},
} }
// Sign authorization tuples.
// The way the auths are combined, it becomes
// 1. tx -> addr1 which is delegated to 0xaaaa
// 2. addr1:0xaaaa calls into addr2:0xbbbb
// 3. addr2:0xbbbb writes to storage
auth1, _ := types.SignSetCode(key1, types.SetCodeAuthorization{
ChainID: *uint256.MustFromBig(gspec.Config.ChainID),
Address: aa,
Nonce: 1,
})
auth2OverwrittenLaterInList, _ := types.SignSetCode(key2, types.SetCodeAuthorization{
Address: cc,
Nonce: 0,
})
auth3InvalidAuthority := auth2OverwrittenLaterInList
auth3InvalidAuthority.V = 4
auth4, _ := types.SignSetCode(key2, types.SetCodeAuthorization{
Address: bb,
Nonce: 1,
})
auth5InvalidNonce, _ := types.SignSetCode(key2, types.SetCodeAuthorization{
Address: bb,
Nonce: 1,
})
auth1Reset, _ := types.SignSetCode(key1, types.SetCodeAuthorization{
ChainID: *uint256.MustFromBig(gspec.Config.ChainID),
Address: common.Address{},
Nonce: 4,
})
_, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, 3, func(i int, b *core.BlockGen) {
b.SetCoinbase(aa)
if i == 0 {
txdata := &types.SetCodeTx{
ChainID: uint256.MustFromBig(gspec.Config.ChainID),
Nonce: 0,
To: addr1,
Gas: 500000,
GasFeeCap: uint256.MustFromBig(newGwei(5)),
GasTipCap: uint256.NewInt(2),
AuthList: []types.SetCodeAuthorization{auth1, auth2OverwrittenLaterInList, auth3InvalidAuthority, auth4, auth5InvalidNonce},
} }
tx := types.MustSignNewTx(key1, signer, txdata)
b.AddTx(tx)
} else if i == 1 {
txdata := &types.LegacyTx{
Nonce: 2,
To: &addr1,
Value: big.NewInt(0),
Gas: 500000,
GasPrice: newGwei(500),
}
tx := types.MustSignNewTx(key1, signer, txdata)
b.AddTx(tx)
} else if i == 2 {
txdata := &types.SetCodeTx{
ChainID: uint256.MustFromBig(gspec.Config.ChainID),
Nonce: 3,
To: addr1,
Gas: 500000,
GasFeeCap: uint256.MustFromBig(newGwei(5)),
GasTipCap: uint256.NewInt(2),
AuthList: []types.SetCodeAuthorization{auth1Reset},
}
tx := types.MustSignNewTx(key1, signer, txdata)
b.AddTx(tx)
}
})
// Polygon doesn't have EIP-7702 yet [Search for polygon-eip-7702 across codebase for all places to uncomment] testBlockTracesCorrectly(t, gspec, engine, blocks, "TestEIP7702")
// func TestFirehose_EIP7702(t *testing.T) { }
// // Copied from ./core/blockchain_test.go#L4180 (TestEIP7702)
// var (
// config = *params.MergedTestChainConfig
// signer = types.LatestSigner(&config)
// engine = beacon.New(ethash.NewFaker())
// key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
// key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
// addr1 = crypto.PubkeyToAddress(key1.PublicKey)
// addr2 = crypto.PubkeyToAddress(key2.PublicKey)
// aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
// bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb")
// cc = common.HexToAddress("0x000000000000000000000000000000000000cccc")
// funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
// )
// gspec := &core.Genesis{
// Config: &config,
// Alloc: types.GenesisAlloc{
// addr1: {Balance: funds},
// addr2: {Balance: funds},
// aa: { // The address 0xAAAA calls into addr2
// Code: program.New().Call(nil, addr2, 1, 0, 0, 0, 0).Bytes(),
// Nonce: 0,
// Balance: big.NewInt(0),
// },
// bb: { // The address 0xBBBB sstores 42 into slot 42.
// Code: program.New().Sstore(0x42, 0x42).Bytes(),
// Nonce: 0,
// Balance: big.NewInt(0),
// },
// cc: { // The address 0xCCCC sstores 42 into slot 42.
// Code: program.New().Sstore(0x42, 0x42).Bytes(),
// Nonce: 0,
// Balance: big.NewInt(0),
// },
// },
// }
// // Sign authorization tuples.
// // The way the auths are combined, it becomes
// // 1. tx -> addr1 which is delegated to 0xaaaa
// // 2. addr1:0xaaaa calls into addr2:0xbbbb
// // 3. addr2:0xbbbb writes to storage
// auth1, _ := types.SignSetCode(key1, types.SetCodeAuthorization{
// ChainID: *uint256.MustFromBig(gspec.Config.ChainID),
// Address: aa,
// Nonce: 1,
// })
// auth2OverwrittenLaterInList, _ := types.SignSetCode(key2, types.SetCodeAuthorization{
// Address: cc,
// Nonce: 0,
// })
// auth3InvalidAuthority := auth2OverwrittenLaterInList
// auth3InvalidAuthority.V = 4
// auth4, _ := types.SignSetCode(key2, types.SetCodeAuthorization{
// Address: bb,
// Nonce: 1,
// })
// auth5InvalidNonce, _ := types.SignSetCode(key2, types.SetCodeAuthorization{
// Address: bb,
// Nonce: 1,
// })
// auth1Reset, _ := types.SignSetCode(key1, types.SetCodeAuthorization{
// ChainID: *uint256.MustFromBig(gspec.Config.ChainID),
// Address: common.Address{},
// Nonce: 4,
// })
// _, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, 3, func(i int, b *core.BlockGen) {
// b.SetCoinbase(aa)
// if i == 0 {
// txdata := &types.SetCodeTx{
// ChainID: uint256.MustFromBig(gspec.Config.ChainID),
// Nonce: 0,
// To: addr1,
// Gas: 500000,
// GasFeeCap: uint256.MustFromBig(newGwei(5)),
// GasTipCap: uint256.NewInt(2),
// AuthList: []types.SetCodeAuthorization{auth1, auth2OverwrittenLaterInList, auth3InvalidAuthority, auth4, auth5InvalidNonce},
// }
// tx := types.MustSignNewTx(key1, signer, txdata)
// b.AddTx(tx)
// } else if i == 1 {
// txdata := &types.LegacyTx{
// Nonce: 2,
// To: &addr1,
// Value: big.NewInt(0),
// Gas: 500000,
// GasPrice: newGwei(500),
// }
// tx := types.MustSignNewTx(key1, signer, txdata)
// b.AddTx(tx)
// } else if i == 2 {
// txdata := &types.SetCodeTx{
// ChainID: uint256.MustFromBig(gspec.Config.ChainID),
// Nonce: 3,
// To: addr1,
// Gas: 500000,
// GasFeeCap: uint256.MustFromBig(newGwei(5)),
// GasTipCap: uint256.NewInt(2),
// AuthList: []types.SetCodeAuthorization{auth1Reset},
// }
// tx := types.MustSignNewTx(key1, signer, txdata)
// b.AddTx(tx)
// }
// })
// testBlockTracesCorrectly(t, gspec, engine, blocks, "TestEIP7702")
// }
func TestFirehose_SystemCalls(t *testing.T) { func TestFirehose_SystemCalls(t *testing.T) {
gspec := &core.Genesis{ gspec := &core.Genesis{
Config: params.MergedTestChainConfig, Config: params.MergedTestChainConfig,
Difficulty: big.NewInt(0),
} }
gspec.Config.ShanghaiBlock = big.NewInt(0)
gspec.Config.CancunBlock = big.NewInt(0)
engine := beacon.New(ethash.NewFaker()) engine := beacon.New(ethash.NewFaker())
_, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *core.BlockGen) { _, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *core.BlockGen) {})
})
testBlockTracesCorrectly(t, gspec, engine, blocks, "TestSystemCalls") testBlockTracesCorrectly(t, gspec, engine, blocks, "TestSystemCalls")
} }
@ -194,10 +199,19 @@ func TestFirehose_SystemCalls(t *testing.T) {
func testBlockTracesCorrectly(t *testing.T, genesisSpec *core.Genesis, engine consensus.Engine, blocks []*types.Block, goldenDir string) { func testBlockTracesCorrectly(t *testing.T, genesisSpec *core.Genesis, engine consensus.Engine, blocks []*types.Block, goldenDir string) {
t.Helper() t.Helper()
for _, concurrent := range []int{0, 1} {
concurrencyLabel := "sequential"
if concurrent == 1 {
concurrencyLabel = "concurrent"
}
for _, model := range tracingModels { for _, model := range tracingModels {
t.Run(string(model), func(t *testing.T) { t.Run(fmt.Sprintf("%s/%s", model, concurrencyLabel), func(t *testing.T) {
tracer, tracingHooks, onClose := newFirehoseTestTracer(t, model) config := &tracers.FirehoseConfig{
defer onClose() ConcurrentBlockFlushing: concurrent,
}
tracer, tracingHooks, _ := newFirehoseTestTracer(t, model, config)
var txLookupLimit uint64 = 100000 var txLookupLimit uint64 = 100000
chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesisSpec, nil, engine, vm.Config{Tracer: tracingHooks}, func(header *types.Header) bool { return true }, &txLookupLimit, nil) chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesisSpec, nil, engine, vm.Config{Tracer: tracingHooks}, func(header *types.Header) bool { return true }, &txLookupLimit, nil)
@ -205,14 +219,16 @@ func testBlockTracesCorrectly(t *testing.T, genesisSpec *core.Genesis, engine co
chain.SetBlockValidatorAndProcessorForTesting( chain.SetBlockValidatorAndProcessorForTesting(
ignoreValidateStateValidator{core.NewBlockValidator(genesisSpec.Config, chain)}, ignoreValidateStateValidator{core.NewBlockValidator(genesisSpec.Config, chain)},
core.NewStateProcessor(genesisSpec.Config, chain, chain.HeaderChain()), core.NewStateProcessor(genesisSpec.Config, chain.HeaderChain(), chain),
) )
defer chain.Stop() defer chain.Stop()
n, err := chain.InsertChain(blocks) n, err := chain.InsertChain(blocks)
require.NoError(t, err, "failed to insert chain block %d", n) require.NoError(t, err, "failed to insert chain block %d", n)
tracer.OnClose()
assertBlockEquals(t, tracer, filepath.Join("testdata", goldenDir, string(model)), len(blocks)) assertBlockEquals(t, tracer, filepath.Join("testdata", goldenDir, string(model)), len(blocks))
}) })
} }
} }
}

View file

@ -25,6 +25,7 @@ var configByName = map[string]*params.ChainConfig{
"mainnet": params.MainnetChainConfig, "mainnet": params.MainnetChainConfig,
"sepolia": params.SepoliaChainConfig, "sepolia": params.SepoliaChainConfig,
"holesky": params.HoleskyChainConfig, "holesky": params.HoleskyChainConfig,
"hoodi": params.HoodiChainConfig,
} }
func main() { func main() {

View file

@ -29,17 +29,22 @@ type firehoseInitLine struct {
type firehoseBlockLines []firehoseBlockLine type firehoseBlockLines []firehoseBlockLine
func newFirehoseTestTracer(t *testing.T, model tracingModel) (*tracers.Firehose, *tracing.Hooks, func()) { func newFirehoseTestTracer(t *testing.T, model tracingModel, config *tracers.FirehoseConfig) (*tracers.Firehose, *tracing.Hooks, func()) {
t.Helper() t.Helper()
tracer, err := tracers.NewFirehoseFromRawJSON(fmt.Appendf(nil, `{ concurrentBlockFlushing := 0
"applyBackwardCompatibility": %t, if config != nil {
concurrentBlockFlushing = config.ConcurrentBlockFlushing
}
tracer, err := tracers.NewFirehoseFromRawJSON([]byte(fmt.Sprintf(`{
"concurrentBlockFlushing": %d,
"_private": { "_private": {
"flushToTestBuffer": true, "flushToTestBuffer": true,
"ignoreGenesisBlock": true, "ignoreGenesisBlock": true,
"forcedBackwardCompatibility": %t "forcedBackwardCompatibility": %t
} }
}`, model == tracingModelFirehose2_3, model == tracingModelFirehose2_3)) }`, concurrentBlockFlushing, model == tracingModelFirehose2_3)))
require.NoError(t, err) require.NoError(t, err)
hooks := tracers.NewTracingHooksFromFirehose(tracer) hooks := tracers.NewTracingHooksFromFirehose(tracer)

View file

@ -13,7 +13,7 @@ import (
) )
func TestPolygon_TracerBlockLevelOnCodeChange(t *testing.T) { func TestPolygon_TracerBlockLevelOnCodeChange(t *testing.T) {
tracer, hooks, onClose := newFirehoseTestTracer(t, tracingModelFirehose2_3) tracer, hooks, onClose := newFirehoseTestTracer(t, tracingModelFirehose2_3, nil)
defer onClose() defer onClose()
hooks.OnBlockchainInit(params.BorMainnetChainConfig) hooks.OnBlockchainInit(params.BorMainnetChainConfig)

View file

@ -112,9 +112,16 @@ func (c *callContext) toBlockContext(genesis *core.Genesis) vm.BlockContext {
if genesis.Config.IsLondon(context.BlockNumber) { if genesis.Config.IsLondon(context.BlockNumber) {
context.BaseFee = (*big.Int)(c.BaseFee) context.BaseFee = (*big.Int)(c.BaseFee)
} }
if genesis.Config.TerminalTotalDifficulty != nil && genesis.Config.TerminalTotalDifficulty.Sign() == 0 {
context.Random = &genesis.Mixhash
}
if genesis.ExcessBlobGas != nil && genesis.BlobGasUsed != nil { if genesis.ExcessBlobGas != nil && genesis.BlobGasUsed != nil {
excessBlobGas := eip4844.CalcExcessBlobGas(*genesis.ExcessBlobGas, *genesis.BlobGasUsed) header := &types.Header{Number: genesis.Config.LondonBlock, Time: 0}
context.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas) excess := eip4844.CalcExcessBlobGas(genesis.Config, header, genesis.Timestamp)
header.ExcessBlobGas = &excess
context.BlobBaseFee = eip4844.CalcBlobFee(genesis.Config, header)
} }
return context return context
} }

View file

@ -0,0 +1,962 @@
{
"hash": "PT5GKGP/ugLfwGXXp9RBa/wB5gra0GvEqNSxx7R6Y5s=",
"header": {
"baseFeePerGas": {
"bytes": "Bw=="
},
"coinbase": "anqpuILVC7e8XaGiRHGcmfEvBqM=",
"difficulty": {
"bytes": "AA=="
},
"gasLimit": "30000000",
"hash": "PT5GKGP/ugLfwGXXp9RBa/wB5gra0GvEqNSxx7R6Y5s=",
"logsBloom": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"mixHash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"number": "3460304",
"parentBeaconRoot": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"parentHash": "mr9GCl11cgoHsVKbe6+Ox/HRXliVFnkmUUIHlrikawU=",
"receiptRoot": "VugfFxvMVab/g0XmksD4bltI4BuZbK3AAWIvteNjtCE=",
"stateRoot": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"timestamp": "2023-05-10T23:17:24Z",
"transactionsRoot": "LMyYgLoLWQJyxPWN14OGZp340jlzGyCXtV6Hn1Ug53Q=",
"uncleHash": "HcxN6N7HXXqrhbVntszUGtMSRRuUinQT8KFC/UDUk0c="
},
"number": "3460304",
"size": "703",
"transactionTraces": [
{
"beginOrdinal": "1",
"calls": [
{
"address": "2j44ckOSTvqcUng+8tOGyCQ2FKY=",
"balanceChanges": [
{
"address": "AtLONow0JRyvlrj6zXilGNYcIK8=",
"newValue": {
"bytes": "TczFiDGBPw=="
},
"oldValue": {
"bytes": "sw1e7C7iHw=="
},
"ordinal": "2",
"reason": "REASON_GAS_BUY"
},
{
"address": "AtLONow0JRyvlrj6zXilGNYcIK8=",
"newValue": {
"bytes": "qw0VEXdCzA=="
},
"oldValue": {
"bytes": "TczFiDGBPw=="
},
"ordinal": "126",
"reason": "REASON_GAS_REFUND"
},
{
"address": "anqpuILVC7e8XaGiRHGcmfEvBqM=",
"newValue": {
"bytes": "9EN66Y/eKNIC"
},
"oldValue": {
"bytes": "9ENy6UYEYcAC"
},
"ordinal": "127",
"reason": "REASON_REWARD_TRANSACTION_FEE"
}
],
"callType": "CALL",
"caller": "AtLONow0JRyvlrj6zXilGNYcIK8=",
"endOrdinal": "125",
"executedCode": true,
"failureReason": "execution reverted",
"gasChanges": [
{
"newValue": "28478568",
"oldValue": "28500000",
"ordinal": "3",
"reason": "REASON_INTRINSIC_GAS"
},
{
"newValue": "28475640",
"oldValue": "28478140",
"ordinal": "6",
"reason": "REASON_STATE_COLD_ACCESS"
},
{
"newValue": "444931",
"oldValue": "28478240",
"ordinal": "7",
"reason": "REASON_STATIC_CALL"
},
{
"newValue": "28472787",
"oldValue": "444931",
"ordinal": "10",
"reason": "REASON_REFUND_AFTER_EXECUTION"
},
{
"newValue": "28472730",
"oldValue": "28472742",
"ordinal": "11",
"reason": "REASON_RETURN_DATA_COPY"
},
{
"newValue": "444874",
"oldValue": "28472057",
"ordinal": "12",
"reason": "REASON_CALL"
},
{
"newValue": "26249590",
"oldValue": "444874",
"ordinal": "119",
"reason": "REASON_REFUND_AFTER_EXECUTION"
},
{
"newValue": "410146",
"oldValue": "26249473",
"ordinal": "120",
"reason": "REASON_STATIC_CALL"
},
{
"newValue": "26248520",
"oldValue": "410146",
"ordinal": "123",
"reason": "REASON_REFUND_AFTER_EXECUTION"
},
{
"newValue": "26248463",
"oldValue": "26248475",
"ordinal": "124",
"reason": "REASON_RETURN_DATA_COPY"
}
],
"gasConsumed": "2230685",
"gasLimit": "28478568",
"index": 1,
"input": "IHxk+wAAAAAAAAAAAAAAAF8iJW3HS0M3RCi9DdlHDFjTL+tC",
"nonceChanges": [
{
"address": "AtLONow0JRyvlrj6zXilGNYcIK8=",
"newValue": "181",
"oldValue": "180",
"ordinal": "4"
}
],
"returnData": "CMN5oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5BcnJheSBpcyBlbXB0eSBhZnRlciBjb2xsaXNpb24AAA==",
"stateReverted": true,
"statusFailed": true,
"statusReverted": true
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"beginOrdinal": "8",
"callType": "STATIC",
"caller": "2j44ckOSTvqcUng+8tOGyCQ2FKY=",
"depth": 1,
"endOrdinal": "9",
"executedCode": true,
"gasConsumed": "2853",
"gasLimit": "28030709",
"index": 2,
"input": "1QTqHQ==",
"parentIndex": 1,
"returnData": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"stateReverted": true
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"beginOrdinal": "13",
"callType": "CALL",
"caller": "2j44ckOSTvqcUng+8tOGyCQ2FKY=",
"depth": 1,
"endOrdinal": "118",
"executedCode": true,
"gasChanges": [
{
"newValue": "437839",
"oldValue": "28021853",
"ordinal": "14",
"reason": "REASON_DELEGATE_CALL"
},
{
"newValue": "25804756",
"oldValue": "437839",
"ordinal": "117",
"reason": "REASON_REFUND_AFTER_EXECUTION"
}
],
"gasConsumed": "2222367",
"gasLimit": "28027083",
"index": 3,
"input": "Sc3isg==",
"parentIndex": 1,
"stateReverted": true
},
{
"address": "UOorsqZJ5qfrzYE4mpuc7C3Ya2A=",
"beginOrdinal": "15",
"callType": "DELEGATE",
"caller": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"depth": 2,
"endOrdinal": "116",
"executedCode": true,
"gasConsumed": "2216997",
"gasLimit": "27583914",
"index": 4,
"input": "f6qFMgAAAAAAAAAAAAAAAF8iJW3HS0M3RCi9DdlHDFjTL+tCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQ=",
"keccakPreimages": {
"290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563": "0000000000000000000000000000000000000000000000000000000000000000"
},
"parentIndex": 3,
"stateReverted": true,
"storageChanges": [
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5WM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "16"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5WQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "17"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5WU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "18"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5WY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "19"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Wc=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "20"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Wg=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "21"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Wk=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "22"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Wo=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "23"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Ws=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "24"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Ww=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "25"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5W0=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "26"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5W4=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "27"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5W8=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "28"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XA=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "29"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XE=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "30"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XI=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "31"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "32"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "33"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "34"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "35"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Xc=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "36"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Xg=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "37"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Xk=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "38"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Xo=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "39"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Xs=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "40"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Xw=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "41"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5X0=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "42"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5X4=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "43"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5X8=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "44"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YA=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "45"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YE=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "46"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YI=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "47"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "48"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "49"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "50"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "51"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Yc=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "52"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Yg=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "53"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Yk=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "54"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Yo=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "55"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Ys=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "56"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Yw=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "57"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Y0=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "58"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Y4=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "59"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Y8=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "60"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZA=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "61"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZE=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "62"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZI=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "63"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "64"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "65"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "66"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "67"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Zc=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "68"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Zg=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "69"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Zk=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "70"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Zo=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "71"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Zs=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "72"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Zw=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "73"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Z0=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "74"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Z4=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "75"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Z8=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "76"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aA=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "77"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aE=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "78"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aI=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "79"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "80"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "81"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "82"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "83"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ac=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "84"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ag=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "85"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ak=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "86"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ao=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "87"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5as=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "88"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aw=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "89"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5a0=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "90"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5a4=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "91"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5a8=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "92"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bA=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "93"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bE=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "94"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bI=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "95"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "96"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "97"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "98"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "99"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bc=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "100"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bg=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "101"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bk=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "102"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bo=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "103"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bs=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "104"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bw=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "105"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5b0=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "106"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5b4=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "107"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5b8=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "108"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cA=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "109"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cE=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "110"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cI=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "111"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "112"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "113"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "114"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "115"
}
]
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"beginOrdinal": "121",
"callType": "STATIC",
"caller": "2j44ckOSTvqcUng+8tOGyCQ2FKY=",
"depth": 1,
"endOrdinal": "122",
"executedCode": true,
"gasConsumed": "853",
"gasLimit": "25839227",
"index": 5,
"input": "1QTqHQ==",
"parentIndex": 1,
"returnData": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"stateReverted": true
}
],
"endOrdinal": "128",
"from": "AtLONow0JRyvlrj6zXilGNYcIK8=",
"gasLimit": "28500000",
"gasPrice": {
"bytes": "O5rKBw=="
},
"gasUsed": "2252117",
"hash": "xN+EOFegte34Jkez7AZnqMUQsH3vyJ8UaASUisF6G4Q=",
"input": "IHxk+wAAAAAAAAAAAAAAAF8iJW3HS0M3RCi9DdlHDFjTL+tC",
"maxFeePerGas": {
"bytes": "O5rKDg=="
},
"maxPriorityFeePerGas": {
"bytes": "O5rKAA=="
},
"nonce": "180",
"r": "KFrm1Dvov1z9BAWBrbjrQuqkR4WMsDkhDZ7OMqVBleg=",
"receipt": {
"cumulativeGasUsed": "2252117",
"logsBloom": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"s": "OViP209UKSnUXm6W7eXbkAKkc3994n5qqgpOQn/9zHY=",
"status": "REVERTED",
"to": "2j44ckOSTvqcUng+8tOGyCQ2FKY=",
"type": "TRX_TYPE_DYNAMIC_FEE",
"v": "AQ=="
}
],
"ver": 3
}

View file

@ -0,0 +1,962 @@
{
"hash": "PT5GKGP/ugLfwGXXp9RBa/wB5gra0GvEqNSxx7R6Y5s=",
"header": {
"baseFeePerGas": {
"bytes": "Bw=="
},
"coinbase": "anqpuILVC7e8XaGiRHGcmfEvBqM=",
"difficulty": {
"bytes": "AA=="
},
"gasLimit": "30000000",
"hash": "PT5GKGP/ugLfwGXXp9RBa/wB5gra0GvEqNSxx7R6Y5s=",
"logsBloom": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"mixHash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"number": "3460304",
"parentBeaconRoot": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"parentHash": "mr9GCl11cgoHsVKbe6+Ox/HRXliVFnkmUUIHlrikawU=",
"receiptRoot": "VugfFxvMVab/g0XmksD4bltI4BuZbK3AAWIvteNjtCE=",
"stateRoot": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"timestamp": "2023-05-10T23:17:24Z",
"transactionsRoot": "LMyYgLoLWQJyxPWN14OGZp340jlzGyCXtV6Hn1Ug53Q=",
"uncleHash": "HcxN6N7HXXqrhbVntszUGtMSRRuUinQT8KFC/UDUk0c="
},
"number": "3460304",
"size": "703",
"transactionTraces": [
{
"beginOrdinal": "1",
"calls": [
{
"address": "2j44ckOSTvqcUng+8tOGyCQ2FKY=",
"balanceChanges": [
{
"address": "AtLONow0JRyvlrj6zXilGNYcIK8=",
"newValue": {
"bytes": "TczFiDGBPw=="
},
"oldValue": {
"bytes": "sw1e7C7iHw=="
},
"ordinal": "2",
"reason": "REASON_GAS_BUY"
},
{
"address": "AtLONow0JRyvlrj6zXilGNYcIK8=",
"newValue": {
"bytes": "qw0VEXdCzA=="
},
"oldValue": {
"bytes": "TczFiDGBPw=="
},
"ordinal": "126",
"reason": "REASON_GAS_REFUND"
},
{
"address": "anqpuILVC7e8XaGiRHGcmfEvBqM=",
"newValue": {
"bytes": "9EN66Y/eKNIC"
},
"oldValue": {
"bytes": "9ENy6UYEYcAC"
},
"ordinal": "127",
"reason": "REASON_REWARD_TRANSACTION_FEE"
}
],
"callType": "CALL",
"caller": "AtLONow0JRyvlrj6zXilGNYcIK8=",
"endOrdinal": "125",
"executedCode": true,
"failureReason": "execution reverted",
"gasChanges": [
{
"newValue": "28478568",
"oldValue": "28500000",
"ordinal": "3",
"reason": "REASON_INTRINSIC_GAS"
},
{
"newValue": "28475640",
"oldValue": "28478140",
"ordinal": "6",
"reason": "REASON_STATE_COLD_ACCESS"
},
{
"newValue": "444931",
"oldValue": "28478240",
"ordinal": "7",
"reason": "REASON_STATIC_CALL"
},
{
"newValue": "28472787",
"oldValue": "444931",
"ordinal": "10",
"reason": "REASON_REFUND_AFTER_EXECUTION"
},
{
"newValue": "28472730",
"oldValue": "28472742",
"ordinal": "11",
"reason": "REASON_RETURN_DATA_COPY"
},
{
"newValue": "444874",
"oldValue": "28472057",
"ordinal": "12",
"reason": "REASON_CALL"
},
{
"newValue": "26249590",
"oldValue": "444874",
"ordinal": "119",
"reason": "REASON_REFUND_AFTER_EXECUTION"
},
{
"newValue": "410146",
"oldValue": "26249473",
"ordinal": "120",
"reason": "REASON_STATIC_CALL"
},
{
"newValue": "26248520",
"oldValue": "410146",
"ordinal": "123",
"reason": "REASON_REFUND_AFTER_EXECUTION"
},
{
"newValue": "26248463",
"oldValue": "26248475",
"ordinal": "124",
"reason": "REASON_RETURN_DATA_COPY"
}
],
"gasConsumed": "2230685",
"gasLimit": "28478568",
"index": 1,
"input": "IHxk+wAAAAAAAAAAAAAAAF8iJW3HS0M3RCi9DdlHDFjTL+tC",
"nonceChanges": [
{
"address": "AtLONow0JRyvlrj6zXilGNYcIK8=",
"newValue": "181",
"oldValue": "180",
"ordinal": "4"
}
],
"returnData": "CMN5oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5BcnJheSBpcyBlbXB0eSBhZnRlciBjb2xsaXNpb24AAA==",
"stateReverted": true,
"statusFailed": true,
"statusReverted": true
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"beginOrdinal": "8",
"callType": "STATIC",
"caller": "2j44ckOSTvqcUng+8tOGyCQ2FKY=",
"depth": 1,
"endOrdinal": "9",
"executedCode": true,
"gasConsumed": "2853",
"gasLimit": "28030709",
"index": 2,
"input": "1QTqHQ==",
"parentIndex": 1,
"returnData": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"stateReverted": true
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"beginOrdinal": "13",
"callType": "CALL",
"caller": "2j44ckOSTvqcUng+8tOGyCQ2FKY=",
"depth": 1,
"endOrdinal": "118",
"executedCode": true,
"gasChanges": [
{
"newValue": "437839",
"oldValue": "28021853",
"ordinal": "14",
"reason": "REASON_DELEGATE_CALL"
},
{
"newValue": "25804756",
"oldValue": "437839",
"ordinal": "117",
"reason": "REASON_REFUND_AFTER_EXECUTION"
}
],
"gasConsumed": "2222367",
"gasLimit": "28027083",
"index": 3,
"input": "Sc3isg==",
"parentIndex": 1,
"stateReverted": true
},
{
"address": "UOorsqZJ5qfrzYE4mpuc7C3Ya2A=",
"beginOrdinal": "15",
"callType": "DELEGATE",
"caller": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"depth": 2,
"endOrdinal": "116",
"executedCode": true,
"gasConsumed": "2216997",
"gasLimit": "27583914",
"index": 4,
"input": "f6qFMgAAAAAAAAAAAAAAAF8iJW3HS0M3RCi9DdlHDFjTL+tCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQ=",
"keccakPreimages": {
"290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563": "0000000000000000000000000000000000000000000000000000000000000000"
},
"parentIndex": 3,
"stateReverted": true,
"storageChanges": [
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5WM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "16"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5WQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "17"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5WU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "18"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5WY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "19"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Wc=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "20"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Wg=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "21"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Wk=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "22"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Wo=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "23"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Ws=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "24"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Ww=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "25"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5W0=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "26"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5W4=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "27"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5W8=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "28"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XA=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "29"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XE=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "30"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XI=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "31"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "32"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "33"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "34"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5XY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "35"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Xc=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "36"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Xg=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "37"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Xk=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "38"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Xo=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "39"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Xs=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "40"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Xw=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "41"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5X0=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "42"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5X4=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "43"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5X8=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "44"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YA=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "45"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YE=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "46"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YI=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "47"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "48"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "49"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "50"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5YY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "51"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Yc=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "52"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Yg=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "53"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Yk=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "54"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Yo=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "55"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Ys=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "56"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Yw=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "57"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Y0=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "58"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Y4=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "59"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Y8=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "60"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZA=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "61"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZE=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "62"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZI=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "63"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "64"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "65"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "66"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ZY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "67"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Zc=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "68"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Zg=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "69"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Zk=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "70"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Zo=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "71"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Zs=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "72"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Zw=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "73"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Z0=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "74"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Z4=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "75"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5Z8=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "76"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aA=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "77"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aE=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "78"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aI=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "79"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "80"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "81"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "82"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "83"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ac=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "84"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ag=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "85"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ak=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "86"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5ao=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "87"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5as=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "88"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5aw=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "89"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5a0=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "90"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5a4=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "91"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5a8=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "92"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bA=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "93"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bE=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "94"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bI=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "95"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "96"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "97"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "98"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "99"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bc=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "100"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bg=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "101"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bk=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "102"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bo=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "103"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bs=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "104"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5bw=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "105"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5b0=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "106"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5b4=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "107"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5b8=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "108"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cA=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "109"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cE=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "110"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cI=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "111"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cM=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "112"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cQ=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "113"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cU=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "114"
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"key": "KQ3s2VSLYqjWA0WpiDhvyEumvJVIQAj2Ni+TFg7z5cY=",
"newValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=",
"oldValue": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"ordinal": "115"
}
]
},
{
"address": "XyIlbcdLQzdEKL0N2UcMWNMv60I=",
"beginOrdinal": "121",
"callType": "STATIC",
"caller": "2j44ckOSTvqcUng+8tOGyCQ2FKY=",
"depth": 1,
"endOrdinal": "122",
"executedCode": true,
"gasConsumed": "853",
"gasLimit": "25839227",
"index": 5,
"input": "1QTqHQ==",
"parentIndex": 1,
"returnData": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"stateReverted": true
}
],
"endOrdinal": "128",
"from": "AtLONow0JRyvlrj6zXilGNYcIK8=",
"gasLimit": "28500000",
"gasPrice": {
"bytes": "O5rKBw=="
},
"gasUsed": "2252117",
"hash": "xN+EOFegte34Jkez7AZnqMUQsH3vyJ8UaASUisF6G4Q=",
"input": "IHxk+wAAAAAAAAAAAAAAAF8iJW3HS0M3RCi9DdlHDFjTL+tC",
"maxFeePerGas": {
"bytes": "O5rKDg=="
},
"maxPriorityFeePerGas": {
"bytes": "O5rKAA=="
},
"nonce": "180",
"r": "KFrm1Dvov1z9BAWBrbjrQuqkR4WMsDkhDZ7OMqVBleg=",
"receipt": {
"cumulativeGasUsed": "2252117",
"logsBloom": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"s": "OViP209UKSnUXm6W7eXbkAKkc3994n5qqgpOQn/9zHY=",
"status": "REVERTED",
"to": "2j44ckOSTvqcUng+8tOGyCQ2FKY=",
"type": "TRX_TYPE_DYNAMIC_FEE",
"v": "AQ=="
}
],
"ver": 3
}

View file

@ -0,0 +1,286 @@
{
"context": {
"baseFeePerGas": "7",
"difficulty": "0",
"gasLimit": "30000000",
"miner": "0x6a7aa9b882d50bb7bc5da1a244719c99f12f06a3",
"number": "3460304",
"timestamp": "1683760644"
},
"genesis": {
"alloc": {
"0x02d2ce368c34251caf96b8facd78a518d61c20af": {
"balance": "0xb30d5eec2ee21f",
"nonce": "180"
},
"0x50ea2bb2a649e6a7ebcd81389a9b9cec2dd86b60": {
"balance": "0x0",
"code": "0x7350ea2bb2a649e6a7ebcd81389a9b9cec2dd86b6030146080604052600436106100355760003560e01c80637faa85321461003a575b600080fd5b81801561004657600080fd5b50610061600480360381019061005c9190610122565b610063565b005b6020812060005b828110156100835760018183015560018101905061006a565b50505050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100b98261008e565b9050919050565b6100c9816100ae565b81146100d457600080fd5b50565b6000813590506100e6816100c0565b92915050565b6000819050919050565b6100ff816100ec565b811461010a57600080fd5b50565b60008135905061011c816100f6565b92915050565b6000806040838503121561013957610138610089565b5b6000610147858286016100d7565b92505060206101588582860161010d565b915050925092905056fea2646970667358221220afea9dfb3d3d7e2eadc10ac0476650ccf8d156413743e3afa743eeeb662b765664736f6c63430008130033",
"nonce": "1"
},
"0x5f22256dc74b43374428bd0dd9470c58d32feb42": {
"balance": "0x0",
"code": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806349cde2b21461003b578063d504ea1d14610045575b600080fd5b610043610063565b005b61004d6100e8565b60405161005a9190610208565b60405180910390f35b3073ffffffffffffffffffffffffffffffffffffffff167350ea2bb2a649e6a7ebcd81389a9b9cec2dd86b60637faa853290916001546040518363ffffffff1660e01b81526004016100b692919061027a565b60006040518083038186803b1580156100ce57600080fd5b505af41580156100e2573d6000803e3d6000fd5b50505050565b6060600080548060200260200160405190810160405280929190818152602001828054801561013657602002820191906000526020600020905b815481526020019060010190808311610122575b5050505050905090565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000819050919050565b61017f8161016c565b82525050565b60006101918383610176565b60208301905092915050565b6000602082019050919050565b60006101b582610140565b6101bf818561014b565b93506101ca8361015c565b8060005b838110156101fb5781516101e28882610185565b97506101ed8361019d565b9250506001810190506101ce565b5085935050505092915050565b6000602082019050818103600083015261022281846101aa565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102558261022a565b9050919050565b6102658161024a565b82525050565b6102748161016c565b82525050565b600060408201905061028f600083018561025c565b61029c602083018461026b565b939250505056fea26469706673582212207e3de0d9d11d700097f896434fdb24e19335d678f7840fec5ce6312b40784bc564736f6c63430008130033",
"nonce": "1",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000064",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e564": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e565": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e567": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e568": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e569": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56a": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56b": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56c": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56d": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56e": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56f": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e570": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e571": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e572": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e573": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e574": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e575": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e576": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e577": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e578": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e579": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e57a": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e57b": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e57c": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e57d": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e57e": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e57f": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e580": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e581": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e582": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e583": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e584": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e585": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e586": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e587": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e588": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e589": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e58a": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e58b": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e58c": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e58d": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e58e": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e58f": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e590": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e591": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e592": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e593": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e594": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e595": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e596": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e597": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e598": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e599": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e59a": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e59b": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e59c": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e59d": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e59e": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e59f": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a0": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a1": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a2": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a3": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a4": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a5": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a6": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a7": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a8": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a9": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5aa": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ab": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ac": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ad": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ae": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5af": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b0": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b1": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b2": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b3": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b4": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b5": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b6": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b7": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b8": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b9": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ba": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5bb": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5bc": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5bd": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5be": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5bf": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c0": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c1": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c2": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c3": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c4": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c5": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c6": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"0x6a7aa9b882d50bb7bc5da1a244719c99f12f06a3": {
"balance": "0xf44372e9460461c002"
},
"0xda3e387243924efa9c52783ef2d386c8243614a6": {
"balance": "0x0",
"code": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063207c64fb14610030575b600080fd5b61004361003e36600461031b565b610057565b604051901515815260200160405180910390f35b6000816001600160a01b031663d504ea1d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610097573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526100bf9190810190610361565b51156101125760405162461bcd60e51b815260206004820152601a60248201527f496e697469616c206172726179206973206e6f7420656d70747900000000000060448201526064015b60405180910390fd5b816001600160a01b03166349cde2b26040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561014d57600080fd5b505af1158015610161573d6000803e3d6000fd5b505050506000826001600160a01b031663d504ea1d6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156101a5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526101cd9190810190610361565b905060008151116102205760405162461bcd60e51b815260206004820152601e60248201527f417272617920697320656d70747920616674657220636f6c6c6973696f6e00006044820152606401610109565b600c81511161027c5760405162461bcd60e51b815260206004820152602260248201527f417272617920697320746f6f20736d616c6c20616674657220636f6c6c69736960448201526137b760f11b6064820152608401610109565b60005b815181101561031157600082828151811061029c5761029c61041f565b6020026020010151116102ff5760405162461bcd60e51b815260206004820152602560248201527f417272617920656c656d656e74206973207a65726f20616674657220636f6c6c60448201526434b9b4b7b760d91b6064820152608401610109565b8061030981610435565b91505061027f565b5060019392505050565b60006020828403121561032d57600080fd5b81356001600160a01b038116811461034457600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b6000602080838503121561037457600080fd5b825167ffffffffffffffff8082111561038c57600080fd5b818501915085601f8301126103a057600080fd5b8151818111156103b2576103b261034b565b8060051b604051601f19603f830116810181811085821117156103d7576103d761034b565b6040529182528482019250838101850191888311156103f557600080fd5b938501935b82851015610413578451845293850193928501926103fa565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b60006001820161045557634e487b7160e01b600052601160045260246000fd5b506001019056fea264697066735822122047cc24c6199d43110286e75f5c41d0d96297b7c746895069f31a94594536b90a64736f6c63430008130033",
"nonce": "1"
}
},
"baseFeePerGas": "7",
"config": {
"chainId": 11155111,
"homesteadBlock": 0,
"daoForkSupport": true,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"muirGlacierBlock": 0,
"berlinBlock": 0,
"londonBlock": 0,
"mergeNetsplitBlock": 1735371,
"shanghaiTime": 1677557088,
"cancunTime": 1706655072,
"pragueTime": 1741159776,
"terminalTotalDifficulty": 17000000000000000,
"depositContractAddress": "0x7f02c3e3c98b133055b8b348b2ac625669ed295d",
"ethash": {},
"blobSchedule": {
"cancun": {
"target": 3,
"max": 6,
"baseFeeUpdateFraction": 3338477
},
"prague": {
"target": 6,
"max": 9,
"baseFeeUpdateFraction": 5007716
}
}
},
"difficulty": "0",
"extraData": "0xd883010b06846765746888676f312e32302e33856c696e7578",
"gasLimit": "30000000",
"hash": "0x521a4b2c4549dbcd50c8c3e3893a538467ec1e13f6e444fe3a9651a35ddbda5c",
"miner": "0xd9a5179f091d85051d3c982785efd1455cec8699",
"mixHash": "0xe7ca858d6c4d9c4b74da938e7a5a651a925c6d444e28ea5684f075d0f4afe2ea",
"nonce": "0x0000000000000000",
"number": "3460303",
"stateRoot": "0x2ffecfcbe0af2f147eadcfa736010788625ef9f9b7c1ec5f346df99be86fd28a",
"timestamp": "1683760632",
"totalDifficulty": "0",
"withdrawals": [
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x3334d",
"index": "0x728484",
"validatorIndex": "0x1da"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x263fa",
"index": "0x728485",
"validatorIndex": "0x1db"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x349d3",
"index": "0x728486",
"validatorIndex": "0x1dc"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x3334d",
"index": "0x728487",
"validatorIndex": "0x1dd"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x349d3",
"index": "0x728488",
"validatorIndex": "0x1de"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x3334d",
"index": "0x728489",
"validatorIndex": "0x1df"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x3334d",
"index": "0x72848a",
"validatorIndex": "0x1e0"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x3334d",
"index": "0x72848b",
"validatorIndex": "0x1e1"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x3334d",
"index": "0x72848c",
"validatorIndex": "0x1e2"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x3334d",
"index": "0x72848d",
"validatorIndex": "0x1e3"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x349d3",
"index": "0x72848e",
"validatorIndex": "0x1e4"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x3334d",
"index": "0x72848f",
"validatorIndex": "0x1e5"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x3334d",
"index": "0x728490",
"validatorIndex": "0x1e6"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x3334d",
"index": "0x728491",
"validatorIndex": "0x1e7"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x349d3",
"index": "0x728492",
"validatorIndex": "0x1e8"
},
{
"address": "0x25c4a76e7d118705e7ea2e9b7d8c59930d8acd3b",
"amount": "0x349d3",
"index": "0x728493",
"validatorIndex": "0x1e9"
}
],
"withdrawalsRoot": "0xd2617e59bfbbaf857d243f296517b7499f2f8fbed2862afb62e2c74c54c2eef3"
},
"input": "0xb89702f89483aa36a781b4843b9aca00843b9aca0e8401b2e02094da3e387243924efa9c52783ef2d386c8243614a680a4207c64fb0000000000000000000000005f22256dc74b43374428bd0dd9470c58d32feb42c001a0285ae6d43be8bf5cfd040581adb8eb42eaa447858cb039210d9ece32a54195e8a039588fdb4f542929d45e6e96ede5db9002a4737f7de27e6aaa0a4e427ffdcc76"
}

2
go.mod
View file

@ -78,6 +78,7 @@ require (
github.com/ryanuber/columnize v2.1.2+incompatible github.com/ryanuber/columnize v2.1.2+incompatible
github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil v3.21.11+incompatible
github.com/status-im/keycard-go v0.3.2 github.com/status-im/keycard-go v0.3.2
github.com/streamingfast/firehose-ethereum/types v0.0.0-20250507011922-e3d3efeda61d
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
github.com/supranational/blst v0.3.14 github.com/supranational/blst v0.3.14
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
@ -255,7 +256,6 @@ require (
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.18.2 // indirect github.com/spf13/viper v1.18.2 // indirect
github.com/streadway/amqp v1.1.0 // indirect github.com/streadway/amqp v1.1.0 // indirect
github.com/streamingfast/firehose-ethereum/types v0.0.0-20250228213600-8981db4edefa // indirect
github.com/stumble/gorocksdb v0.0.3 // indirect github.com/stumble/gorocksdb v0.0.3 // indirect
github.com/tendermint/btcd v0.1.1 // indirect github.com/tendermint/btcd v0.1.1 // indirect
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 // indirect github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 // indirect

4
go.sum
View file

@ -2709,8 +2709,8 @@ github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1Sd
github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM= github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM=
github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg= github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg=
github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/streamingfast/firehose-ethereum/types v0.0.0-20250228213600-8981db4edefa h1:QhMsEDwwfYCxfNdqmzHlT+4JlY7HXEvVubj0oyYyWOA= github.com/streamingfast/firehose-ethereum/types v0.0.0-20250507011922-e3d3efeda61d h1:UOY/wuuvgunXAeF2mxZFrZXW9djOs02t6Fpw+ABwwBY=
github.com/streamingfast/firehose-ethereum/types v0.0.0-20250228213600-8981db4edefa/go.mod h1:CG22ObinxSbKIP19bAj0uro0a290kzZTiBbjL8VR0SE= github.com/streamingfast/firehose-ethereum/types v0.0.0-20250507011922-e3d3efeda61d/go.mod h1:CG22ObinxSbKIP19bAj0uro0a290kzZTiBbjL8VR0SE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=

View file

@ -1,4 +1,4 @@
// Copyright 2018 The go-ethereum Authors // Copyright 2024 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify