mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
Merge remote-tracking branch 'origin/master' into firehose-fh3.0
# Conflicts: # cmd/evm/internal/t8ntool/execution.go # cmd/evm/internal/t8ntool/transition.go # cmd/utils/flags.go # consensus/beacon/consensus.go # core/blockchain.go # core/state_processor.go # core/tracing/hooks.go # core/vm/runtime/runtime.go # eth/backend.go # eth/tracers/api.go # eth/tracers/dir.go # eth/tracers/directory/tracers.go # eth/tracers/internal/tracetest/calltrace_test.go # eth/tracers/internal/tracetest/flat_calltrace_test.go # eth/tracers/js/goja.go # eth/tracers/js/tracer_test.go # eth/tracers/live/noop.go # eth/tracers/logger/logger.go # eth/tracers/native/4byte.go # eth/tracers/native/call.go # eth/tracers/native/call_flat.go # eth/tracers/native/mux.go # eth/tracers/native/noop.go # eth/tracers/native/prestate.go # eth/tracers/tracers.go # go.mod
This commit is contained in:
commit
262c3117f6
167 changed files with 6249 additions and 1034 deletions
20
.travis.yml
20
.travis.yml
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
os: linux
|
||||
arch: amd64
|
||||
dist: bionic
|
||||
go: 1.21.x
|
||||
go: 1.22.x
|
||||
env:
|
||||
- docker
|
||||
services:
|
||||
|
|
@ -33,7 +33,7 @@ jobs:
|
|||
os: linux
|
||||
arch: arm64
|
||||
dist: bionic
|
||||
go: 1.21.x
|
||||
go: 1.22.x
|
||||
env:
|
||||
- docker
|
||||
services:
|
||||
|
|
@ -51,7 +51,7 @@ jobs:
|
|||
os: linux
|
||||
dist: bionic
|
||||
sudo: required
|
||||
go: 1.21.x
|
||||
go: 1.22.x
|
||||
env:
|
||||
- azure-linux
|
||||
git:
|
||||
|
|
@ -85,7 +85,7 @@ jobs:
|
|||
if: type = push
|
||||
os: osx
|
||||
osx_image: xcode14.2
|
||||
go: 1.21.x
|
||||
go: 1.22.x
|
||||
env:
|
||||
- azure-osx
|
||||
git:
|
||||
|
|
@ -101,7 +101,7 @@ jobs:
|
|||
os: linux
|
||||
arch: amd64
|
||||
dist: bionic
|
||||
go: 1.21.x
|
||||
go: 1.22.x
|
||||
script:
|
||||
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES
|
||||
|
||||
|
|
@ -110,14 +110,14 @@ jobs:
|
|||
os: linux
|
||||
arch: arm64
|
||||
dist: bionic
|
||||
go: 1.20.x
|
||||
go: 1.21.x
|
||||
script:
|
||||
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES
|
||||
|
||||
- stage: build
|
||||
os: linux
|
||||
dist: bionic
|
||||
go: 1.20.x
|
||||
go: 1.21.x
|
||||
script:
|
||||
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ jobs:
|
|||
if: type = cron || (type = push && tag ~= /^v[0-9]/)
|
||||
os: linux
|
||||
dist: bionic
|
||||
go: 1.21.x
|
||||
go: 1.22.x
|
||||
env:
|
||||
- ubuntu-ppa
|
||||
git:
|
||||
|
|
@ -149,7 +149,7 @@ jobs:
|
|||
if: type = cron
|
||||
os: linux
|
||||
dist: bionic
|
||||
go: 1.21.x
|
||||
go: 1.22.x
|
||||
env:
|
||||
- azure-purge
|
||||
git:
|
||||
|
|
@ -162,7 +162,7 @@ jobs:
|
|||
if: type = cron
|
||||
os: linux
|
||||
dist: bionic
|
||||
go: 1.21.x
|
||||
go: 1.22.x
|
||||
script:
|
||||
- travis_wait 30 go run build/ci.go test -race $TEST_PACKAGES
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ ARG VERSION=""
|
|||
ARG BUILDNUM=""
|
||||
|
||||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.21-alpine as builder
|
||||
FROM golang:1.22-alpine as builder
|
||||
|
||||
RUN apk add --no-cache gcc musl-dev linux-headers git
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/
|
|||
EXPOSE 8545 8546 30303 30303/udp
|
||||
ENTRYPOINT ["geth"]
|
||||
|
||||
# Add some metadata labels to help programatic image consumption
|
||||
# Add some metadata labels to help programmatic image consumption
|
||||
ARG COMMIT=""
|
||||
ARG VERSION=""
|
||||
ARG BUILDNUM=""
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ ARG VERSION=""
|
|||
ARG BUILDNUM=""
|
||||
|
||||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.21-alpine as builder
|
||||
FROM golang:1.22-alpine as builder
|
||||
|
||||
RUN apk add --no-cache gcc musl-dev linux-headers git
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ COPY --from=builder /go-ethereum/build/bin/* /usr/local/bin/
|
|||
|
||||
EXPOSE 8545 8546 30303 30303/udp
|
||||
|
||||
# Add some metadata labels to help programatic image consumption
|
||||
# Add some metadata labels to help programmatic image consumption
|
||||
ARG COMMIT=""
|
||||
ARG VERSION=""
|
||||
ARG BUILDNUM=""
|
||||
|
|
|
|||
3
Makefile
3
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
# with Go source code. If you know what GOPATH is then you probably
|
||||
# don't need to bother with make.
|
||||
|
||||
.PHONY: geth android ios evm all test clean
|
||||
.PHONY: geth all test lint clean devtools help
|
||||
|
||||
GOBIN = ./build/bin
|
||||
GO ?= latest
|
||||
|
|
@ -47,4 +47,3 @@ devtools:
|
|||
help: Makefile
|
||||
@echo " Choose a command run in go-ethereum:"
|
||||
@sed -n 's/^#?//p' $< | column -t -s ':' | sort | sed -e 's/^/ /'
|
||||
.PHONY: help
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ archives are published at https://geth.ethereum.org/downloads/.
|
|||
|
||||
For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth).
|
||||
|
||||
Building `geth` requires both a Go (version 1.19 or later) and a C compiler. You can install
|
||||
Building `geth` requires both a Go (version 1.21 or later) and a C compiler. You can install
|
||||
them using your favourite package manager. Once the dependencies are installed, run
|
||||
|
||||
```shell
|
||||
|
|
|
|||
|
|
@ -142,10 +142,10 @@ func NewKeyStoreTransactorWithChainID(keystore *keystore.KeyStore, account accou
|
|||
// NewKeyedTransactorWithChainID is a utility method to easily create a transaction signer
|
||||
// from a single private key.
|
||||
func NewKeyedTransactorWithChainID(key *ecdsa.PrivateKey, chainID *big.Int) (*TransactOpts, error) {
|
||||
keyAddr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
if chainID == nil {
|
||||
return nil, ErrNoChainID
|
||||
}
|
||||
keyAddr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
signer := types.LatestSignerForChainID(chainID)
|
||||
return &TransactOpts{
|
||||
From: keyAddr,
|
||||
|
|
|
|||
|
|
@ -461,7 +461,7 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]int
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
sub, err := event.NewSubscription(func(quit <-chan struct{}) error {
|
||||
sub := event.NewSubscription(func(quit <-chan struct{}) error {
|
||||
for _, log := range buff {
|
||||
select {
|
||||
case logs <- log:
|
||||
|
|
@ -470,11 +470,8 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]int
|
|||
}
|
||||
}
|
||||
return nil
|
||||
}), nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return logs, sub, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
@ -31,7 +32,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// Minimum amount of time between cache reloads. This limit applies if the platform does
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"slices"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -30,7 +31,6 @@ import (
|
|||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -500,7 +500,5 @@ func (ks *KeyStore) isUpdating() bool {
|
|||
// zeroKey zeroes a private key in memory.
|
||||
func zeroKey(k *ecdsa.PrivateKey) {
|
||||
b := k.D.Bits()
|
||||
for i := range b {
|
||||
b[i] = 0
|
||||
}
|
||||
clear(b)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"math/rand"
|
||||
"os"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
|
@ -30,7 +31,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var testSigData = make([]byte, 32)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import (
|
|||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
|
|
@ -72,11 +71,11 @@ func NewSecureChannelSession(card *pcsc.Card, keyData []byte) (*SecureChannelSes
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("could not unmarshal public key from card: %v", err)
|
||||
}
|
||||
secret, _ := key.Curve.ScalarMult(cardPublic.X, cardPublic.Y, key.D.Bytes())
|
||||
secret, _ := crypto.S256().ScalarMult(cardPublic.X, cardPublic.Y, key.D.Bytes())
|
||||
return &SecureChannelSession{
|
||||
card: card,
|
||||
secret: secret.Bytes(),
|
||||
publicKey: elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y),
|
||||
publicKey: crypto.FromECDSAPub(&key.PublicKey),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,35 +17,25 @@
|
|||
package blsync
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
"github.com/ethereum/go-ethereum/beacon/light/request"
|
||||
"github.com/ethereum/go-ethereum/beacon/light/sync"
|
||||
"github.com/ethereum/go-ethereum/beacon/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/lru"
|
||||
ctypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/capella"
|
||||
"github.com/protolambda/zrnt/eth2/configs"
|
||||
"github.com/protolambda/ztyp/tree"
|
||||
)
|
||||
|
||||
// beaconBlockSync implements request.Module; it fetches the beacon blocks belonging
|
||||
// to the validated and prefetch heads.
|
||||
type beaconBlockSync struct {
|
||||
recentBlocks *lru.Cache[common.Hash, *capella.BeaconBlock]
|
||||
recentBlocks *lru.Cache[common.Hash, *types.BeaconBlock]
|
||||
locked map[common.Hash]request.ServerAndID
|
||||
serverHeads map[request.Server]common.Hash
|
||||
headTracker headTracker
|
||||
|
||||
lastHeadInfo types.HeadInfo
|
||||
chainHeadFeed *event.Feed
|
||||
chainHeadFeed event.FeedOf[types.ChainHeadEvent]
|
||||
}
|
||||
|
||||
type headTracker interface {
|
||||
|
|
@ -55,16 +45,19 @@ type headTracker interface {
|
|||
}
|
||||
|
||||
// newBeaconBlockSync returns a new beaconBlockSync.
|
||||
func newBeaconBlockSync(headTracker headTracker, chainHeadFeed *event.Feed) *beaconBlockSync {
|
||||
func newBeaconBlockSync(headTracker headTracker) *beaconBlockSync {
|
||||
return &beaconBlockSync{
|
||||
headTracker: headTracker,
|
||||
chainHeadFeed: chainHeadFeed,
|
||||
recentBlocks: lru.NewCache[common.Hash, *capella.BeaconBlock](10),
|
||||
locked: make(map[common.Hash]request.ServerAndID),
|
||||
serverHeads: make(map[request.Server]common.Hash),
|
||||
headTracker: headTracker,
|
||||
recentBlocks: lru.NewCache[common.Hash, *types.BeaconBlock](10),
|
||||
locked: make(map[common.Hash]request.ServerAndID),
|
||||
serverHeads: make(map[request.Server]common.Hash),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *beaconBlockSync) SubscribeChainHead(ch chan<- types.ChainHeadEvent) event.Subscription {
|
||||
return s.chainHeadFeed.Subscribe(ch)
|
||||
}
|
||||
|
||||
// Process implements request.Module.
|
||||
func (s *beaconBlockSync) Process(requester request.Requester, events []request.Event) {
|
||||
for _, event := range events {
|
||||
|
|
@ -73,7 +66,7 @@ func (s *beaconBlockSync) Process(requester request.Requester, events []request.
|
|||
sid, req, resp := event.RequestInfo()
|
||||
blockRoot := common.Hash(req.(sync.ReqBeaconBlock))
|
||||
if resp != nil {
|
||||
s.recentBlocks.Add(blockRoot, resp.(*capella.BeaconBlock))
|
||||
s.recentBlocks.Add(blockRoot, resp.(*types.BeaconBlock))
|
||||
}
|
||||
if s.locked[blockRoot] == sid {
|
||||
delete(s.locked, blockRoot)
|
||||
|
|
@ -112,63 +105,11 @@ func (s *beaconBlockSync) tryRequestBlock(requester request.Requester, blockRoot
|
|||
}
|
||||
}
|
||||
|
||||
func blockHeadInfo(block *capella.BeaconBlock) types.HeadInfo {
|
||||
func blockHeadInfo(block *types.BeaconBlock) types.HeadInfo {
|
||||
if block == nil {
|
||||
return types.HeadInfo{}
|
||||
}
|
||||
return types.HeadInfo{Slot: uint64(block.Slot), BlockRoot: beaconBlockHash(block)}
|
||||
}
|
||||
|
||||
// beaconBlockHash calculates the hash of a beacon block.
|
||||
func beaconBlockHash(beaconBlock *capella.BeaconBlock) common.Hash {
|
||||
return common.Hash(beaconBlock.HashTreeRoot(configs.Mainnet, tree.GetHashFn()))
|
||||
}
|
||||
|
||||
// getExecBlock extracts the execution block from the beacon block's payload.
|
||||
func getExecBlock(beaconBlock *capella.BeaconBlock) (*ctypes.Block, error) {
|
||||
payload := &beaconBlock.Body.ExecutionPayload
|
||||
txs := make([]*ctypes.Transaction, len(payload.Transactions))
|
||||
for i, opaqueTx := range payload.Transactions {
|
||||
var tx ctypes.Transaction
|
||||
if err := tx.UnmarshalBinary(opaqueTx); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse tx %d: %v", i, err)
|
||||
}
|
||||
txs[i] = &tx
|
||||
}
|
||||
withdrawals := make([]*ctypes.Withdrawal, len(payload.Withdrawals))
|
||||
for i, w := range payload.Withdrawals {
|
||||
withdrawals[i] = &ctypes.Withdrawal{
|
||||
Index: uint64(w.Index),
|
||||
Validator: uint64(w.ValidatorIndex),
|
||||
Address: common.Address(w.Address),
|
||||
Amount: uint64(w.Amount),
|
||||
}
|
||||
}
|
||||
wroot := ctypes.DeriveSha(ctypes.Withdrawals(withdrawals), trie.NewStackTrie(nil))
|
||||
execHeader := &ctypes.Header{
|
||||
ParentHash: common.Hash(payload.ParentHash),
|
||||
UncleHash: ctypes.EmptyUncleHash,
|
||||
Coinbase: common.Address(payload.FeeRecipient),
|
||||
Root: common.Hash(payload.StateRoot),
|
||||
TxHash: ctypes.DeriveSha(ctypes.Transactions(txs), trie.NewStackTrie(nil)),
|
||||
ReceiptHash: common.Hash(payload.ReceiptsRoot),
|
||||
Bloom: ctypes.Bloom(payload.LogsBloom),
|
||||
Difficulty: common.Big0,
|
||||
Number: new(big.Int).SetUint64(uint64(payload.BlockNumber)),
|
||||
GasLimit: uint64(payload.GasLimit),
|
||||
GasUsed: uint64(payload.GasUsed),
|
||||
Time: uint64(payload.Timestamp),
|
||||
Extra: []byte(payload.ExtraData),
|
||||
MixDigest: common.Hash(payload.PrevRandao), // reused in merge
|
||||
Nonce: ctypes.BlockNonce{}, // zero
|
||||
BaseFee: (*uint256.Int)(&payload.BaseFeePerGas).ToBig(),
|
||||
WithdrawalsHash: &wroot,
|
||||
}
|
||||
execBlock := ctypes.NewBlockWithHeader(execHeader).WithBody(txs, nil).WithWithdrawals(withdrawals)
|
||||
if execBlockHash := execBlock.Hash(); execBlockHash != common.Hash(payload.BlockHash) {
|
||||
return execBlock, fmt.Errorf("Sanity check failed, payload hash does not match (expected %x, got %x)", common.Hash(payload.BlockHash), execBlockHash)
|
||||
}
|
||||
return execBlock, nil
|
||||
return types.HeadInfo{Slot: block.Slot(), BlockRoot: block.Root()}
|
||||
}
|
||||
|
||||
func (s *beaconBlockSync) updateEventFeed() {
|
||||
|
|
@ -190,14 +131,16 @@ func (s *beaconBlockSync) updateEventFeed() {
|
|||
return
|
||||
}
|
||||
s.lastHeadInfo = headInfo
|
||||
|
||||
// new head block and finality info available; extract executable data and send event to feed
|
||||
execBlock, err := getExecBlock(headBlock)
|
||||
execBlock, err := headBlock.ExecutionPayload()
|
||||
if err != nil {
|
||||
log.Error("Error extracting execution block from validated beacon block", "error", err)
|
||||
return
|
||||
}
|
||||
s.chainHeadFeed.Send(types.ChainHeadEvent{
|
||||
HeadBlock: engine.BlockToExecutableData(execBlock, nil, nil).ExecutionPayload,
|
||||
Finalized: common.Hash(finality.Finalized.PayloadHeader.BlockHash),
|
||||
BeaconHead: head.Header,
|
||||
Block: execBlock,
|
||||
Finalized: finality.Finalized.PayloadHeader.BlockHash(),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,70 +23,69 @@ import (
|
|||
"github.com/ethereum/go-ethereum/beacon/light/sync"
|
||||
"github.com/ethereum/go-ethereum/beacon/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/capella"
|
||||
"github.com/protolambda/zrnt/eth2/configs"
|
||||
"github.com/protolambda/ztyp/tree"
|
||||
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/deneb"
|
||||
)
|
||||
|
||||
var (
|
||||
testServer1 = "testServer1"
|
||||
testServer2 = "testServer2"
|
||||
|
||||
testBlock1 = &capella.BeaconBlock{
|
||||
testBlock1 = types.NewBeaconBlock(&deneb.BeaconBlock{
|
||||
Slot: 123,
|
||||
Body: capella.BeaconBlockBody{
|
||||
ExecutionPayload: capella.ExecutionPayload{BlockNumber: 456},
|
||||
Body: deneb.BeaconBlockBody{
|
||||
ExecutionPayload: deneb.ExecutionPayload{
|
||||
BlockNumber: 456,
|
||||
BlockHash: zrntcommon.Hash32(common.HexToHash("905ac721c4058d9ed40b27b6b9c1bdd10d4333e4f3d9769100bf9dfb80e5d1f6")),
|
||||
},
|
||||
},
|
||||
}
|
||||
testBlock2 = &capella.BeaconBlock{
|
||||
})
|
||||
testBlock2 = types.NewBeaconBlock(&deneb.BeaconBlock{
|
||||
Slot: 124,
|
||||
Body: capella.BeaconBlockBody{
|
||||
ExecutionPayload: capella.ExecutionPayload{BlockNumber: 457},
|
||||
Body: deneb.BeaconBlockBody{
|
||||
ExecutionPayload: deneb.ExecutionPayload{
|
||||
BlockNumber: 457,
|
||||
BlockHash: zrntcommon.Hash32(common.HexToHash("011703f39c664efc1c6cf5f49ca09b595581eec572d4dfddd3d6179a9e63e655")),
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
func init() {
|
||||
eb1, _ := getExecBlock(testBlock1)
|
||||
testBlock1.Body.ExecutionPayload.BlockHash = tree.Root(eb1.Hash())
|
||||
eb2, _ := getExecBlock(testBlock2)
|
||||
testBlock2.Body.ExecutionPayload.BlockHash = tree.Root(eb2.Hash())
|
||||
}
|
||||
|
||||
func TestBlockSync(t *testing.T) {
|
||||
ht := &testHeadTracker{}
|
||||
eventFeed := new(event.Feed)
|
||||
blockSync := newBeaconBlockSync(ht, eventFeed)
|
||||
blockSync := newBeaconBlockSync(ht)
|
||||
headCh := make(chan types.ChainHeadEvent, 16)
|
||||
eventFeed.Subscribe(headCh)
|
||||
blockSync.SubscribeChainHead(headCh)
|
||||
ts := sync.NewTestScheduler(t, blockSync)
|
||||
ts.AddServer(testServer1, 1)
|
||||
ts.AddServer(testServer2, 1)
|
||||
|
||||
expHeadBlock := func(tci int, expHead *capella.BeaconBlock) {
|
||||
expHeadBlock := func(expHead *types.BeaconBlock) {
|
||||
t.Helper()
|
||||
var expNumber, headNumber uint64
|
||||
if expHead != nil {
|
||||
expNumber = uint64(expHead.Body.ExecutionPayload.BlockNumber)
|
||||
p, _ := expHead.ExecutionPayload()
|
||||
expNumber = p.NumberU64()
|
||||
}
|
||||
select {
|
||||
case event := <-headCh:
|
||||
headNumber = event.HeadBlock.Number
|
||||
headNumber = event.Block.NumberU64()
|
||||
default:
|
||||
}
|
||||
if headNumber != expNumber {
|
||||
t.Errorf("Wrong head block in test case #%d (expected block number %d, got %d)", tci, expNumber, headNumber)
|
||||
t.Errorf("Wrong head block, expected block number %d, got %d)", expNumber, headNumber)
|
||||
}
|
||||
}
|
||||
|
||||
// no block requests expected until head tracker knows about a head
|
||||
ts.Run(1)
|
||||
expHeadBlock(1, nil)
|
||||
expHeadBlock(nil)
|
||||
|
||||
// set block 1 as prefetch head, announced by server 2
|
||||
head1 := blockHeadInfo(testBlock1)
|
||||
ht.prefetch = head1
|
||||
ts.ServerEvent(sync.EvNewHead, testServer2, head1)
|
||||
|
||||
// expect request to server 2 which has announced the head
|
||||
ts.Run(2, testServer2, sync.ReqBeaconBlock(head1.BlockRoot))
|
||||
|
||||
|
|
@ -95,12 +94,12 @@ func TestBlockSync(t *testing.T) {
|
|||
ts.AddAllowance(testServer2, 1)
|
||||
ts.Run(3)
|
||||
// head block still not expected as the fetched block is not the validated head yet
|
||||
expHeadBlock(3, nil)
|
||||
expHeadBlock(nil)
|
||||
|
||||
// set as validated head, expect no further requests but block 1 set as head block
|
||||
ht.validated.Header = blockHeader(testBlock1)
|
||||
ht.validated.Header = testBlock1.Header()
|
||||
ts.Run(4)
|
||||
expHeadBlock(4, testBlock1)
|
||||
expHeadBlock(testBlock1)
|
||||
|
||||
// set block 2 as prefetch head, announced by server 1
|
||||
head2 := blockHeadInfo(testBlock2)
|
||||
|
|
@ -114,26 +113,16 @@ func TestBlockSync(t *testing.T) {
|
|||
ts.Run(6)
|
||||
|
||||
// set as validated head before retrieving block; now it's assumed to be available from server 2 too
|
||||
ht.validated.Header = blockHeader(testBlock2)
|
||||
ht.validated.Header = testBlock2.Header()
|
||||
// expect req2 retry to server 2
|
||||
ts.Run(7, testServer2, sync.ReqBeaconBlock(head2.BlockRoot))
|
||||
// now head block should be unavailable again
|
||||
expHeadBlock(4, nil)
|
||||
expHeadBlock(nil)
|
||||
|
||||
// valid response, now head block should be block 2 immediately as it is already validated
|
||||
ts.RequestEvent(request.EvResponse, ts.Request(7, 1), testBlock2)
|
||||
ts.Run(8)
|
||||
expHeadBlock(5, testBlock2)
|
||||
}
|
||||
|
||||
func blockHeader(block *capella.BeaconBlock) types.Header {
|
||||
return types.Header{
|
||||
Slot: uint64(block.Slot),
|
||||
ProposerIndex: uint64(block.ProposerIndex),
|
||||
ParentRoot: common.Hash(block.ParentRoot),
|
||||
StateRoot: common.Hash(block.StateRoot),
|
||||
BodyRoot: common.Hash(block.Body.HashTreeRoot(configs.Mainnet, tree.GetHashFn())),
|
||||
}
|
||||
expHeadBlock(testBlock2)
|
||||
}
|
||||
|
||||
type testHeadTracker struct {
|
||||
|
|
@ -151,9 +140,10 @@ func (h *testHeadTracker) ValidatedHead() (types.SignedHeader, bool) {
|
|||
|
||||
// TODO add test case for finality
|
||||
func (h *testHeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) {
|
||||
finalized := types.NewExecutionHeader(new(deneb.ExecutionPayloadHeader))
|
||||
return types.FinalityUpdate{
|
||||
Attested: types.HeaderWithExecProof{Header: h.validated.Header},
|
||||
Finalized: types.HeaderWithExecProof{PayloadHeader: &capella.ExecutionPayloadHeader{}},
|
||||
Finalized: types.HeaderWithExecProof{PayloadHeader: finalized},
|
||||
Signature: h.validated.Signature,
|
||||
SignatureSlot: h.validated.SignatureSlot,
|
||||
}, h.validated.Header != (types.Header{})
|
||||
|
|
|
|||
|
|
@ -28,14 +28,20 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common/mclock"
|
||||
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
scheduler *request.Scheduler
|
||||
chainHeadFeed *event.Feed
|
||||
urls []string
|
||||
customHeader map[string]string
|
||||
urls []string
|
||||
customHeader map[string]string
|
||||
chainConfig *lightClientConfig
|
||||
scheduler *request.Scheduler
|
||||
blockSync *beaconBlockSync
|
||||
engineRPC *rpc.Client
|
||||
|
||||
chainHeadSub event.Subscription
|
||||
engineClient *engineClient
|
||||
}
|
||||
|
||||
func NewClient(ctx *cli.Context) *Client {
|
||||
|
|
@ -53,6 +59,7 @@ func NewClient(ctx *cli.Context) *Client {
|
|||
}
|
||||
customHeader[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
|
||||
}
|
||||
|
||||
// create data structures
|
||||
var (
|
||||
db = memorydb.New()
|
||||
|
|
@ -63,11 +70,10 @@ func NewClient(ctx *cli.Context) *Client {
|
|||
headSync := sync.NewHeadSync(headTracker, committeeChain)
|
||||
|
||||
// set up scheduler and sync modules
|
||||
chainHeadFeed := new(event.Feed)
|
||||
scheduler := request.NewScheduler()
|
||||
checkpointInit := sync.NewCheckpointInit(committeeChain, chainConfig.Checkpoint)
|
||||
forwardSync := sync.NewForwardUpdateSync(committeeChain)
|
||||
beaconBlockSync := newBeaconBlockSync(headTracker, chainHeadFeed)
|
||||
beaconBlockSync := newBeaconBlockSync(headTracker)
|
||||
scheduler.RegisterTarget(headTracker)
|
||||
scheduler.RegisterTarget(committeeChain)
|
||||
scheduler.RegisterModule(checkpointInit, "checkpointInit")
|
||||
|
|
@ -76,28 +82,34 @@ func NewClient(ctx *cli.Context) *Client {
|
|||
scheduler.RegisterModule(beaconBlockSync, "beaconBlockSync")
|
||||
|
||||
return &Client{
|
||||
scheduler: scheduler,
|
||||
urls: ctx.StringSlice(utils.BeaconApiFlag.Name),
|
||||
customHeader: customHeader,
|
||||
chainHeadFeed: chainHeadFeed,
|
||||
scheduler: scheduler,
|
||||
urls: ctx.StringSlice(utils.BeaconApiFlag.Name),
|
||||
customHeader: customHeader,
|
||||
chainConfig: &chainConfig,
|
||||
blockSync: beaconBlockSync,
|
||||
}
|
||||
}
|
||||
|
||||
// SubscribeChainHeadEvent allows callers to subscribe a provided channel to new
|
||||
// head updates.
|
||||
func (c *Client) SubscribeChainHeadEvent(ch chan<- types.ChainHeadEvent) event.Subscription {
|
||||
return c.chainHeadFeed.Subscribe(ch)
|
||||
func (c *Client) SetEngineRPC(engine *rpc.Client) {
|
||||
c.engineRPC = engine
|
||||
}
|
||||
|
||||
func (c *Client) Start() {
|
||||
func (c *Client) Start() error {
|
||||
headCh := make(chan types.ChainHeadEvent, 16)
|
||||
c.chainHeadSub = c.blockSync.SubscribeChainHead(headCh)
|
||||
c.engineClient = startEngineClient(c.chainConfig, c.engineRPC, headCh)
|
||||
|
||||
c.scheduler.Start()
|
||||
// register server(s)
|
||||
for _, url := range c.urls {
|
||||
beaconApi := api.NewBeaconLightApi(url, c.customHeader)
|
||||
c.scheduler.RegisterServer(request.NewServer(api.NewApiServer(beaconApi), &mclock.System{}))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Stop() {
|
||||
func (c *Client) Stop() error {
|
||||
c.engineClient.stop()
|
||||
c.chainHeadSub.Unsubscribe()
|
||||
c.scheduler.Stop()
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ var (
|
|||
AddFork("GENESIS", 0, []byte{0, 0, 0, 0}).
|
||||
AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}).
|
||||
AddFork("BELLATRIX", 144896, []byte{2, 0, 0, 0}).
|
||||
AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}),
|
||||
AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}).
|
||||
AddFork("DENEB", 269568, []byte{4, 0, 0, 0}),
|
||||
Checkpoint: common.HexToHash("0x388be41594ec7d6a6894f18c73f3469f07e2c19a803de4755d335817ed8e2e5a"),
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +52,8 @@ var (
|
|||
AddFork("GENESIS", 0, []byte{144, 0, 0, 105}).
|
||||
AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}).
|
||||
AddFork("BELLATRIX", 100, []byte{144, 0, 0, 113}).
|
||||
AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}),
|
||||
AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}).
|
||||
AddFork("DENEB", 132608, []byte{144, 0, 0, 115}),
|
||||
Checkpoint: common.HexToHash("0x1005a6d9175e96bfbce4d35b80f468e9bff0b674e1e861d16e09e10005a58e81"),
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +65,8 @@ var (
|
|||
AddFork("GENESIS", 0, []byte{0, 0, 16, 32}).
|
||||
AddFork("ALTAIR", 36660, []byte{1, 0, 16, 32}).
|
||||
AddFork("BELLATRIX", 112260, []byte{2, 0, 16, 32}).
|
||||
AddFork("CAPELLA", 162304, []byte{3, 0, 16, 32}),
|
||||
AddFork("CAPELLA", 162304, []byte{3, 0, 16, 32}).
|
||||
AddFork("DENEB", 231680, []byte{4, 0, 16, 32}),
|
||||
Checkpoint: common.HexToHash("0x53a0f4f0a378e2c4ae0a9ee97407eb69d0d737d8d8cd0a5fb1093f42f7b81c49"),
|
||||
}
|
||||
)
|
||||
|
|
|
|||
147
beacon/blsync/engineclient.go
Normal file
147
beacon/blsync/engineclient.go
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package blsync
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
"github.com/ethereum/go-ethereum/beacon/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
ctypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
type engineClient struct {
|
||||
config *lightClientConfig
|
||||
rpc *rpc.Client
|
||||
rootCtx context.Context
|
||||
cancelRoot context.CancelFunc
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func startEngineClient(config *lightClientConfig, rpc *rpc.Client, headCh <-chan types.ChainHeadEvent) *engineClient {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ec := &engineClient{
|
||||
config: config,
|
||||
rpc: rpc,
|
||||
rootCtx: ctx,
|
||||
cancelRoot: cancel,
|
||||
}
|
||||
ec.wg.Add(1)
|
||||
go ec.updateLoop(headCh)
|
||||
return ec
|
||||
}
|
||||
|
||||
func (ec *engineClient) stop() {
|
||||
ec.cancelRoot()
|
||||
ec.wg.Wait()
|
||||
}
|
||||
|
||||
func (ec *engineClient) updateLoop(headCh <-chan types.ChainHeadEvent) {
|
||||
defer ec.wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ec.rootCtx.Done():
|
||||
return
|
||||
|
||||
case event := <-headCh:
|
||||
if ec.rpc == nil { // dry run, no engine API specified
|
||||
log.Info("New execution block retrieved", "number", event.Block.NumberU64(), "hash", event.Block.Hash(), "finalized", event.Finalized)
|
||||
continue
|
||||
}
|
||||
|
||||
fork := ec.config.ForkAtEpoch(event.BeaconHead.Epoch())
|
||||
forkName := strings.ToLower(fork.Name)
|
||||
|
||||
if status, err := ec.callNewPayload(forkName, event); err == nil {
|
||||
log.Info("Successful NewPayload", "number", event.Block.NumberU64(), "hash", event.Block.Hash(), "status", status)
|
||||
} else {
|
||||
log.Error("Failed NewPayload", "number", event.Block.NumberU64(), "hash", event.Block.Hash(), "error", err)
|
||||
}
|
||||
|
||||
if status, err := ec.callForkchoiceUpdated(forkName, event); err == nil {
|
||||
log.Info("Successful ForkchoiceUpdated", "head", event.Block.Hash(), "status", status)
|
||||
} else {
|
||||
log.Error("Failed ForkchoiceUpdated", "head", event.Block.Hash(), "error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ec *engineClient) callNewPayload(fork string, event types.ChainHeadEvent) (string, error) {
|
||||
execData := engine.BlockToExecutableData(event.Block, nil, nil).ExecutionPayload
|
||||
|
||||
var (
|
||||
method string
|
||||
params = []any{execData}
|
||||
)
|
||||
switch fork {
|
||||
case "deneb":
|
||||
method = "engine_newPayloadV3"
|
||||
parentBeaconRoot := event.BeaconHead.ParentRoot
|
||||
blobHashes := collectBlobHashes(event.Block)
|
||||
params = append(params, blobHashes, parentBeaconRoot)
|
||||
case "capella":
|
||||
method = "engine_newPayloadV2"
|
||||
default:
|
||||
method = "engine_newPayloadV1"
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(ec.rootCtx, time.Second*5)
|
||||
defer cancel()
|
||||
var resp engine.PayloadStatusV1
|
||||
err := ec.rpc.CallContext(ctx, &resp, method, params...)
|
||||
return resp.Status, err
|
||||
}
|
||||
|
||||
func collectBlobHashes(b *ctypes.Block) []common.Hash {
|
||||
list := make([]common.Hash, 0)
|
||||
for _, tx := range b.Transactions() {
|
||||
list = append(list, tx.BlobHashes()...)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (ec *engineClient) callForkchoiceUpdated(fork string, event types.ChainHeadEvent) (string, error) {
|
||||
update := engine.ForkchoiceStateV1{
|
||||
HeadBlockHash: event.Block.Hash(),
|
||||
SafeBlockHash: event.Finalized,
|
||||
FinalizedBlockHash: event.Finalized,
|
||||
}
|
||||
|
||||
var method string
|
||||
switch fork {
|
||||
case "deneb":
|
||||
method = "engine_forkchoiceUpdatedV3"
|
||||
case "capella":
|
||||
method = "engine_forkchoiceUpdatedV2"
|
||||
default:
|
||||
method = "engine_forkchoiceUpdatedV1"
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(ec.rootCtx, time.Second*5)
|
||||
defer cancel()
|
||||
var resp engine.ForkChoiceResponse
|
||||
err := ec.rpc.CallContext(ctx, &resp, method, update, nil)
|
||||
return resp.PayloadStatus.Status, err
|
||||
}
|
||||
|
|
@ -30,9 +30,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/beacon/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/capella"
|
||||
"github.com/protolambda/zrnt/eth2/configs"
|
||||
"github.com/protolambda/ztyp/tree"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -68,9 +65,9 @@ type jsonBeaconHeader struct {
|
|||
}
|
||||
|
||||
type jsonHeaderWithExecProof struct {
|
||||
Beacon types.Header `json:"beacon"`
|
||||
Execution *capella.ExecutionPayloadHeader `json:"execution"`
|
||||
ExecutionBranch merkle.Values `json:"execution_branch"`
|
||||
Beacon types.Header `json:"beacon"`
|
||||
Execution json.RawMessage `json:"execution"`
|
||||
ExecutionBranch merkle.Values `json:"execution_branch"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
|
|
@ -149,7 +146,7 @@ func (api *BeaconLightApi) httpGetf(format string, params ...any) ([]byte, error
|
|||
return api.httpGet(fmt.Sprintf(format, params...))
|
||||
}
|
||||
|
||||
// GetBestUpdateAndCommittee fetches and validates LightClientUpdate for given
|
||||
// GetBestUpdatesAndCommittees fetches and validates LightClientUpdate for given
|
||||
// period and full serialized committee for the next period (committee root hash
|
||||
// equals update.NextSyncCommitteeRoot).
|
||||
// Note that the results are validated but the update signature should be verified
|
||||
|
|
@ -244,33 +241,44 @@ func (api *BeaconLightApi) GetFinalityUpdate() (types.FinalityUpdate, error) {
|
|||
|
||||
func decodeFinalityUpdate(enc []byte) (types.FinalityUpdate, error) {
|
||||
var data struct {
|
||||
Data struct {
|
||||
Version string
|
||||
Data struct {
|
||||
Attested jsonHeaderWithExecProof `json:"attested_header"`
|
||||
Finalized jsonHeaderWithExecProof `json:"finalized_header"`
|
||||
FinalityBranch merkle.Values `json:"finality_branch"`
|
||||
Aggregate types.SyncAggregate `json:"sync_aggregate"`
|
||||
SignatureSlot common.Decimal `json:"signature_slot"`
|
||||
} `json:"data"`
|
||||
}
|
||||
}
|
||||
if err := json.Unmarshal(enc, &data); err != nil {
|
||||
return types.FinalityUpdate{}, err
|
||||
}
|
||||
|
||||
// Decode the execution payload headers.
|
||||
attestedExecHeader, err := types.ExecutionHeaderFromJSON(data.Version, data.Data.Attested.Execution)
|
||||
if err != nil {
|
||||
return types.FinalityUpdate{}, fmt.Errorf("invalid attested header: %v", err)
|
||||
}
|
||||
finalizedExecHeader, err := types.ExecutionHeaderFromJSON(data.Version, data.Data.Finalized.Execution)
|
||||
if err != nil {
|
||||
return types.FinalityUpdate{}, fmt.Errorf("invalid finalized header: %v", err)
|
||||
}
|
||||
// Perform sanity checks.
|
||||
if len(data.Data.Aggregate.Signers) != params.SyncCommitteeBitmaskSize {
|
||||
return types.FinalityUpdate{}, errors.New("invalid sync_committee_bits length")
|
||||
}
|
||||
if len(data.Data.Aggregate.Signature) != params.BLSSignatureSize {
|
||||
return types.FinalityUpdate{}, errors.New("invalid sync_committee_signature length")
|
||||
}
|
||||
|
||||
return types.FinalityUpdate{
|
||||
Attested: types.HeaderWithExecProof{
|
||||
Header: data.Data.Attested.Beacon,
|
||||
PayloadHeader: data.Data.Attested.Execution,
|
||||
PayloadHeader: attestedExecHeader,
|
||||
PayloadBranch: data.Data.Attested.ExecutionBranch,
|
||||
},
|
||||
Finalized: types.HeaderWithExecProof{
|
||||
Header: data.Data.Finalized.Beacon,
|
||||
PayloadHeader: data.Data.Finalized.Execution,
|
||||
PayloadHeader: finalizedExecHeader,
|
||||
PayloadBranch: data.Data.Finalized.ExecutionBranch,
|
||||
},
|
||||
FinalityBranch: data.Data.FinalityBranch,
|
||||
|
|
@ -359,27 +367,30 @@ func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types
|
|||
return checkpoint, nil
|
||||
}
|
||||
|
||||
func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*capella.BeaconBlock, error) {
|
||||
func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*types.BeaconBlock, error) {
|
||||
resp, err := api.httpGetf("/eth/v2/beacon/blocks/0x%x", blockRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var beaconBlockMessage struct {
|
||||
Data struct {
|
||||
Message capella.BeaconBlock `json:"message"`
|
||||
} `json:"data"`
|
||||
Version string
|
||||
Data struct {
|
||||
Message json.RawMessage `json:"message"`
|
||||
}
|
||||
}
|
||||
if err := json.Unmarshal(resp, &beaconBlockMessage); err != nil {
|
||||
return nil, fmt.Errorf("invalid block json data: %v", err)
|
||||
}
|
||||
beaconBlock := new(capella.BeaconBlock)
|
||||
*beaconBlock = beaconBlockMessage.Data.Message
|
||||
root := common.Hash(beaconBlock.HashTreeRoot(configs.Mainnet, tree.GetHashFn()))
|
||||
if root != blockRoot {
|
||||
return nil, fmt.Errorf("Beacon block root hash mismatch (expected: %x, got: %x)", blockRoot, root)
|
||||
block, err := types.BlockFromJSON(beaconBlockMessage.Version, beaconBlockMessage.Data.Message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconBlock, nil
|
||||
computedRoot := block.Root()
|
||||
if computedRoot != blockRoot {
|
||||
return nil, fmt.Errorf("Beacon block root hash mismatch (expected: %x, got: %x)", blockRoot, computedRoot)
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
func decodeHeadEvent(enc []byte) (uint64, common.Hash, error) {
|
||||
|
|
@ -456,7 +467,7 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
|
|||
select {
|
||||
case event, ok := <-stream.Events:
|
||||
if !ok {
|
||||
break
|
||||
return
|
||||
}
|
||||
switch event.Event() {
|
||||
case "head":
|
||||
|
|
@ -482,7 +493,7 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
|
|||
}
|
||||
case err, ok := <-stream.Errors:
|
||||
if !ok {
|
||||
break
|
||||
return
|
||||
}
|
||||
listener.OnError(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ func TestValidatedHead(t *testing.T) {
|
|||
ts.AddServer(testServer3, 1)
|
||||
ts.ServerEvent(EvNewSignedHead, testServer3, testSHead4)
|
||||
ts.Run(4)
|
||||
// future period annonced heads should be queued
|
||||
// future period announced heads should be queued
|
||||
ht.ExpValidated(t, 4, nil)
|
||||
|
||||
chain.SetNextSyncPeriod(2)
|
||||
|
|
|
|||
110
beacon/types/beacon_block.go
Normal file
110
beacon/types/beacon_block.go
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/capella"
|
||||
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/deneb"
|
||||
"github.com/protolambda/zrnt/eth2/configs"
|
||||
"github.com/protolambda/ztyp/tree"
|
||||
)
|
||||
|
||||
type blockObject interface {
|
||||
HashTreeRoot(spec *zrntcommon.Spec, hFn tree.HashFn) zrntcommon.Root
|
||||
Header(spec *zrntcommon.Spec) *zrntcommon.BeaconBlockHeader
|
||||
}
|
||||
|
||||
// BeaconBlock represents a full block in the beacon chain.
|
||||
type BeaconBlock struct {
|
||||
blockObj blockObject
|
||||
}
|
||||
|
||||
// BlockFromJSON decodes a beacon block from JSON.
|
||||
func BlockFromJSON(forkName string, data []byte) (*BeaconBlock, error) {
|
||||
var obj blockObject
|
||||
switch forkName {
|
||||
case "deneb":
|
||||
obj = new(deneb.BeaconBlock)
|
||||
case "capella":
|
||||
obj = new(capella.BeaconBlock)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported fork: " + forkName)
|
||||
}
|
||||
if err := json.Unmarshal(data, obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BeaconBlock{obj}, nil
|
||||
}
|
||||
|
||||
// NewBeaconBlock wraps a ZRNT block.
|
||||
func NewBeaconBlock(obj blockObject) *BeaconBlock {
|
||||
switch obj := obj.(type) {
|
||||
case *capella.BeaconBlock:
|
||||
return &BeaconBlock{obj}
|
||||
case *deneb.BeaconBlock:
|
||||
return &BeaconBlock{obj}
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported block type %T", obj))
|
||||
}
|
||||
}
|
||||
|
||||
// Slot returns the slot number of the block.
|
||||
func (b *BeaconBlock) Slot() uint64 {
|
||||
switch obj := b.blockObj.(type) {
|
||||
case *capella.BeaconBlock:
|
||||
return uint64(obj.Slot)
|
||||
case *deneb.BeaconBlock:
|
||||
return uint64(obj.Slot)
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported block type %T", b.blockObj))
|
||||
}
|
||||
}
|
||||
|
||||
// ExecutionPayload parses and returns the execution payload of the block.
|
||||
func (b *BeaconBlock) ExecutionPayload() (*types.Block, error) {
|
||||
switch obj := b.blockObj.(type) {
|
||||
case *capella.BeaconBlock:
|
||||
return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot)
|
||||
case *deneb.BeaconBlock:
|
||||
return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot)
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported block type %T", b.blockObj))
|
||||
}
|
||||
}
|
||||
|
||||
// Header returns the block's header data.
|
||||
func (b *BeaconBlock) Header() Header {
|
||||
switch obj := b.blockObj.(type) {
|
||||
case *capella.BeaconBlock:
|
||||
return headerFromZRNT(obj.Header(configs.Mainnet))
|
||||
case *deneb.BeaconBlock:
|
||||
return headerFromZRNT(obj.Header(configs.Mainnet))
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported block type %T", b.blockObj))
|
||||
}
|
||||
}
|
||||
|
||||
// Root computes the SSZ root hash of the block.
|
||||
func (b *BeaconBlock) Root() common.Hash {
|
||||
return common.Hash(b.blockObj.HashTreeRoot(configs.Mainnet, tree.GetHashFn()))
|
||||
}
|
||||
77
beacon/types/beacon_block_test.go
Normal file
77
beacon/types/beacon_block_test.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
func TestBlockFromJSON(t *testing.T) {
|
||||
type blocktest struct {
|
||||
file string
|
||||
version string
|
||||
wantSlot uint64
|
||||
wantBlockNumber uint64
|
||||
wantBlockHash common.Hash
|
||||
}
|
||||
tests := []blocktest{
|
||||
{
|
||||
file: "block_deneb.json",
|
||||
version: "deneb",
|
||||
wantSlot: 8631513,
|
||||
wantBlockNumber: 19431837,
|
||||
wantBlockHash: common.HexToHash("0x4cf7d9108fc01b50023ab7cab9b372a96068fddcadec551630393b65acb1f34c"),
|
||||
},
|
||||
{
|
||||
file: "block_capella.json",
|
||||
version: "capella",
|
||||
wantSlot: 7378495,
|
||||
wantBlockNumber: 18189758,
|
||||
wantBlockHash: common.HexToHash("0x802acf5c350f4252e31d83c431fcb259470250fa0edf49e8391cfee014239820"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.file, func(t *testing.T) {
|
||||
data, err := os.ReadFile(filepath.Join("testdata", test.file))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconBlock, err := BlockFromJSON(test.version, data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if beaconBlock.Slot() != test.wantSlot {
|
||||
t.Errorf("wrong slot number %d", beaconBlock.Slot())
|
||||
}
|
||||
execBlock, err := beaconBlock.ExecutionPayload()
|
||||
if err != nil {
|
||||
t.Fatalf("payload extraction failed: %v", err)
|
||||
}
|
||||
if execBlock.NumberU64() != test.wantBlockNumber {
|
||||
t.Errorf("wrong block number: %v", execBlock.NumberU64())
|
||||
}
|
||||
if execBlock.Hash() != test.wantBlockHash {
|
||||
t.Errorf("wrong block hash: %v", execBlock.Hash())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ const syncCommitteeDomain = 7
|
|||
// Fork describes a single beacon chain fork and also stores the calculated
|
||||
// signature domain used after this fork.
|
||||
type Fork struct {
|
||||
// Name of the fork in the chain config (config.yaml) file{
|
||||
// Name of the fork in the chain config (config.yaml) file
|
||||
Name string
|
||||
|
||||
// Epoch when given fork version is activated
|
||||
|
|
@ -110,6 +110,16 @@ type ChainConfig struct {
|
|||
Forks Forks
|
||||
}
|
||||
|
||||
// ForkAtEpoch returns the latest active fork at the given epoch.
|
||||
func (c *ChainConfig) ForkAtEpoch(epoch uint64) Fork {
|
||||
for i := len(c.Forks) - 1; i >= 0; i-- {
|
||||
if c.Forks[i].Epoch <= epoch {
|
||||
return *c.Forks[i]
|
||||
}
|
||||
}
|
||||
return Fork{}
|
||||
}
|
||||
|
||||
// AddFork adds a new item to the list of forks.
|
||||
func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig {
|
||||
fork := &Fork{
|
||||
|
|
|
|||
80
beacon/types/exec_header.go
Normal file
80
beacon/types/exec_header.go
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/beacon/merkle"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/capella"
|
||||
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/deneb"
|
||||
"github.com/protolambda/ztyp/tree"
|
||||
)
|
||||
|
||||
type headerObject interface {
|
||||
HashTreeRoot(hFn tree.HashFn) zrntcommon.Root
|
||||
}
|
||||
|
||||
type ExecutionHeader struct {
|
||||
obj headerObject
|
||||
}
|
||||
|
||||
// HeaderFromJSON decodes an execution header from JSON data provided by
|
||||
// the beacon chain API.
|
||||
func ExecutionHeaderFromJSON(forkName string, data []byte) (*ExecutionHeader, error) {
|
||||
var obj headerObject
|
||||
switch forkName {
|
||||
case "capella":
|
||||
obj = new(capella.ExecutionPayloadHeader)
|
||||
case "deneb":
|
||||
obj = new(deneb.ExecutionPayloadHeader)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported fork: " + forkName)
|
||||
}
|
||||
if err := json.Unmarshal(data, obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ExecutionHeader{obj: obj}, nil
|
||||
}
|
||||
|
||||
func NewExecutionHeader(obj headerObject) *ExecutionHeader {
|
||||
switch obj.(type) {
|
||||
case *capella.ExecutionPayloadHeader:
|
||||
case *deneb.ExecutionPayloadHeader:
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported ExecutionPayloadHeader type %T", obj))
|
||||
}
|
||||
return &ExecutionHeader{obj: obj}
|
||||
}
|
||||
|
||||
func (eh *ExecutionHeader) PayloadRoot() merkle.Value {
|
||||
return merkle.Value(eh.obj.HashTreeRoot(tree.GetHashFn()))
|
||||
}
|
||||
|
||||
func (eh *ExecutionHeader) BlockHash() common.Hash {
|
||||
switch obj := eh.obj.(type) {
|
||||
case *capella.ExecutionPayloadHeader:
|
||||
return common.Hash(obj.BlockHash)
|
||||
case *deneb.ExecutionPayloadHeader:
|
||||
return common.Hash(obj.BlockHash)
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported ExecutionPayloadHeader type %T", obj))
|
||||
}
|
||||
}
|
||||
144
beacon/types/exec_payload.go
Normal file
144
beacon/types/exec_payload.go
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/capella"
|
||||
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/deneb"
|
||||
)
|
||||
|
||||
type payloadType interface {
|
||||
*capella.ExecutionPayload | *deneb.ExecutionPayload
|
||||
}
|
||||
|
||||
// convertPayload converts a beacon chain execution payload to types.Block.
|
||||
func convertPayload[T payloadType](payload T, parentRoot *zrntcommon.Root) (*types.Block, error) {
|
||||
var (
|
||||
header types.Header
|
||||
transactions []*types.Transaction
|
||||
withdrawals []*types.Withdrawal
|
||||
expectedHash [32]byte
|
||||
err error
|
||||
)
|
||||
switch p := any(payload).(type) {
|
||||
case *capella.ExecutionPayload:
|
||||
convertCapellaHeader(p, &header)
|
||||
transactions, err = convertTransactions(p.Transactions, &header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
withdrawals = convertWithdrawals(p.Withdrawals, &header)
|
||||
expectedHash = p.BlockHash
|
||||
case *deneb.ExecutionPayload:
|
||||
convertDenebHeader(p, common.Hash(*parentRoot), &header)
|
||||
transactions, err = convertTransactions(p.Transactions, &header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
withdrawals = convertWithdrawals(p.Withdrawals, &header)
|
||||
expectedHash = p.BlockHash
|
||||
default:
|
||||
panic("unsupported block type")
|
||||
}
|
||||
|
||||
block := types.NewBlockWithHeader(&header)
|
||||
block = block.WithBody(transactions, nil)
|
||||
block = block.WithWithdrawals(withdrawals)
|
||||
hash := block.Hash()
|
||||
if hash != expectedHash {
|
||||
return block, fmt.Errorf("Sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash)
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
func convertCapellaHeader(payload *capella.ExecutionPayload, h *types.Header) {
|
||||
// note: h.TxHash is set in convertTransactions
|
||||
h.ParentHash = common.Hash(payload.ParentHash)
|
||||
h.UncleHash = types.EmptyUncleHash
|
||||
h.Coinbase = common.Address(payload.FeeRecipient)
|
||||
h.Root = common.Hash(payload.StateRoot)
|
||||
h.ReceiptHash = common.Hash(payload.ReceiptsRoot)
|
||||
h.Bloom = types.Bloom(payload.LogsBloom)
|
||||
h.Difficulty = common.Big0
|
||||
h.Number = new(big.Int).SetUint64(uint64(payload.BlockNumber))
|
||||
h.GasLimit = uint64(payload.GasLimit)
|
||||
h.GasUsed = uint64(payload.GasUsed)
|
||||
h.Time = uint64(payload.Timestamp)
|
||||
h.Extra = []byte(payload.ExtraData)
|
||||
h.MixDigest = common.Hash(payload.PrevRandao)
|
||||
h.Nonce = types.BlockNonce{}
|
||||
h.BaseFee = (*uint256.Int)(&payload.BaseFeePerGas).ToBig()
|
||||
}
|
||||
|
||||
func convertDenebHeader(payload *deneb.ExecutionPayload, parentRoot common.Hash, h *types.Header) {
|
||||
// note: h.TxHash is set in convertTransactions
|
||||
h.ParentHash = common.Hash(payload.ParentHash)
|
||||
h.UncleHash = types.EmptyUncleHash
|
||||
h.Coinbase = common.Address(payload.FeeRecipient)
|
||||
h.Root = common.Hash(payload.StateRoot)
|
||||
h.ReceiptHash = common.Hash(payload.ReceiptsRoot)
|
||||
h.Bloom = types.Bloom(payload.LogsBloom)
|
||||
h.Difficulty = common.Big0
|
||||
h.Number = new(big.Int).SetUint64(uint64(payload.BlockNumber))
|
||||
h.GasLimit = uint64(payload.GasLimit)
|
||||
h.GasUsed = uint64(payload.GasUsed)
|
||||
h.Time = uint64(payload.Timestamp)
|
||||
h.Extra = []byte(payload.ExtraData)
|
||||
h.MixDigest = common.Hash(payload.PrevRandao)
|
||||
h.Nonce = types.BlockNonce{}
|
||||
h.BaseFee = (*uint256.Int)(&payload.BaseFeePerGas).ToBig()
|
||||
// new in deneb
|
||||
h.BlobGasUsed = (*uint64)(&payload.BlobGasUsed)
|
||||
h.ExcessBlobGas = (*uint64)(&payload.ExcessBlobGas)
|
||||
h.ParentBeaconRoot = &parentRoot
|
||||
}
|
||||
|
||||
func convertTransactions(list zrntcommon.PayloadTransactions, execHeader *types.Header) ([]*types.Transaction, error) {
|
||||
txs := make([]*types.Transaction, len(list))
|
||||
for i, opaqueTx := range list {
|
||||
var tx types.Transaction
|
||||
if err := tx.UnmarshalBinary(opaqueTx); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse tx %d: %v", i, err)
|
||||
}
|
||||
txs[i] = &tx
|
||||
}
|
||||
execHeader.TxHash = types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil))
|
||||
return txs, nil
|
||||
}
|
||||
|
||||
func convertWithdrawals(list zrntcommon.Withdrawals, execHeader *types.Header) []*types.Withdrawal {
|
||||
withdrawals := make([]*types.Withdrawal, len(list))
|
||||
for i, w := range list {
|
||||
withdrawals[i] = &types.Withdrawal{
|
||||
Index: uint64(w.Index),
|
||||
Validator: uint64(w.ValidatorIndex),
|
||||
Address: common.Address(w.Address),
|
||||
Amount: uint64(w.Amount),
|
||||
}
|
||||
}
|
||||
wroot := types.DeriveSha(types.Withdrawals(withdrawals), trie.NewStackTrie(nil))
|
||||
execHeader.WithdrawalsHash = &wroot
|
||||
return withdrawals
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/beacon/merkle"
|
||||
"github.com/ethereum/go-ethereum/beacon/params"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
|
||||
|
|
@ -57,6 +58,16 @@ type Header struct {
|
|||
BodyRoot common.Hash `gencodec:"required" json:"body_root"`
|
||||
}
|
||||
|
||||
func headerFromZRNT(zh *zrntcommon.BeaconBlockHeader) Header {
|
||||
return Header{
|
||||
Slot: uint64(zh.Slot),
|
||||
ProposerIndex: uint64(zh.ProposerIndex),
|
||||
ParentRoot: common.Hash(zh.ParentRoot),
|
||||
StateRoot: common.Hash(zh.StateRoot),
|
||||
BodyRoot: common.Hash(zh.BodyRoot),
|
||||
}
|
||||
}
|
||||
|
||||
// headerMarshaling is a field type overrides for gencodec.
|
||||
type headerMarshaling struct {
|
||||
Slot common.Decimal
|
||||
|
|
|
|||
|
|
@ -20,12 +20,10 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
"github.com/ethereum/go-ethereum/beacon/merkle"
|
||||
"github.com/ethereum/go-ethereum/beacon/params"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/capella"
|
||||
"github.com/protolambda/ztyp/tree"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// HeadInfo represents an unvalidated new head announcement.
|
||||
|
|
@ -146,12 +144,12 @@ func (u UpdateScore) BetterThan(w UpdateScore) bool {
|
|||
|
||||
type HeaderWithExecProof struct {
|
||||
Header
|
||||
PayloadHeader *capella.ExecutionPayloadHeader
|
||||
PayloadHeader *ExecutionHeader
|
||||
PayloadBranch merkle.Values
|
||||
}
|
||||
|
||||
func (h *HeaderWithExecProof) Validate() error {
|
||||
payloadRoot := merkle.Value(h.PayloadHeader.HashTreeRoot(tree.GetHashFn()))
|
||||
payloadRoot := h.PayloadHeader.PayloadRoot()
|
||||
return merkle.VerifyProof(h.BodyRoot, params.BodyIndexExecPayload, h.PayloadBranch, payloadRoot)
|
||||
}
|
||||
|
||||
|
|
@ -187,6 +185,7 @@ func (u *FinalityUpdate) Validate() error {
|
|||
// latest accepted head of the beacon chain, along with the hash of the latest
|
||||
// finalized execution block.
|
||||
type ChainHeadEvent struct {
|
||||
HeadBlock *engine.ExecutableData
|
||||
Finalized common.Hash
|
||||
BeaconHead Header
|
||||
Block *types.Block
|
||||
Finalized common.Hash
|
||||
}
|
||||
|
|
|
|||
1703
beacon/types/testdata/block_capella.json
vendored
Normal file
1703
beacon/types/testdata/block_capella.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
2644
beacon/types/testdata/block_deneb.json
vendored
Normal file
2644
beacon/types/testdata/block_deneb.json
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -5,22 +5,22 @@
|
|||
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
|
||||
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
|
||||
|
||||
# version:golang 1.21.6
|
||||
# version:golang 1.22.1
|
||||
# https://go.dev/dl/
|
||||
124926a62e45f78daabbaedb9c011d97633186a33c238ffc1e25320c02046248 go1.21.6.src.tar.gz
|
||||
31d6ecca09010ab351e51343a5af81d678902061fee871f912bdd5ef4d778850 go1.21.6.darwin-amd64.tar.gz
|
||||
0ff541fb37c38e5e5c5bcecc8f4f43c5ffd5e3a6c33a5d3e4003ded66fcfb331 go1.21.6.darwin-arm64.tar.gz
|
||||
a1d1a149b34bf0f53965a237682c6da1140acabb131bf0e597240e4a140b0e5e go1.21.6.freebsd-386.tar.gz
|
||||
de59e1217e4398b1522eed8dddabab2fa1b97aecbdca3af08e34832b4f0e3f81 go1.21.6.freebsd-amd64.tar.gz
|
||||
05d09041b5a1193c14e4b2db3f7fcc649b236c567f5eb93305c537851b72dd95 go1.21.6.linux-386.tar.gz
|
||||
3f934f40ac360b9c01f616a9aa1796d227d8b0328bf64cb045c7b8c4ee9caea4 go1.21.6.linux-amd64.tar.gz
|
||||
e2e8aa88e1b5170a0d495d7d9c766af2b2b6c6925a8f8956d834ad6b4cacbd9a go1.21.6.linux-arm64.tar.gz
|
||||
6a8eda6cc6a799ff25e74ce0c13fdc1a76c0983a0bb07c789a2a3454bf6ec9b2 go1.21.6.linux-armv6l.tar.gz
|
||||
e872b1e9a3f2f08fd4554615a32ca9123a4ba877ab6d19d36abc3424f86bc07f go1.21.6.linux-ppc64le.tar.gz
|
||||
92894d0f732d3379bc414ffdd617eaadad47e1d72610e10d69a1156db03fc052 go1.21.6.linux-s390x.tar.gz
|
||||
65b38857135cf45c80e1d267e0ce4f80fe149326c68835217da4f2da9b7943fe go1.21.6.windows-386.zip
|
||||
27ac9dd6e66fb3fd0acfa6792ff053c86e7d2c055b022f4b5d53bfddec9e3301 go1.21.6.windows-amd64.zip
|
||||
b93aff8f3c882c764c66a39b7a1483b0460e051e9992bf3435479129e5051bcd go1.21.6.windows-arm64.zip
|
||||
79c9b91d7f109515a25fc3ecdaad125d67e6bdb54f6d4d98580f46799caea321 go1.22.1.src.tar.gz
|
||||
3bc971772f4712fec0364f4bc3de06af22a00a12daab10b6f717fdcd13156cc0 go1.22.1.darwin-amd64.tar.gz
|
||||
f6a9cec6b8a002fcc9c0ee24ec04d67f430a52abc3cfd613836986bcc00d8383 go1.22.1.darwin-arm64.tar.gz
|
||||
99f81c10d5a3f8a886faf8fa86aaa2aaf929fbed54a972ae5eec3c5e0bdb961a go1.22.1.freebsd-386.tar.gz
|
||||
51c614ddd92ee4a9913a14c39bf80508d9cfba08561f24d2f075fd00f3cfb067 go1.22.1.freebsd-amd64.tar.gz
|
||||
8484df36d3d40139eaf0fe5e647b006435d826cc12f9ae72973bf7ec265e0ae4 go1.22.1.linux-386.tar.gz
|
||||
aab8e15785c997ae20f9c88422ee35d962c4562212bb0f879d052a35c8307c7f go1.22.1.linux-amd64.tar.gz
|
||||
e56685a245b6a0c592fc4a55f0b7803af5b3f827aaa29feab1f40e491acf35b8 go1.22.1.linux-arm64.tar.gz
|
||||
8cb7a90e48c20daed39a6ac8b8a40760030ba5e93c12274c42191d868687c281 go1.22.1.linux-armv6l.tar.gz
|
||||
ac775e19d93cc1668999b77cfe8c8964abfbc658718feccfe6e0eb87663cd668 go1.22.1.linux-ppc64le.tar.gz
|
||||
7bb7dd8e10f95c9a4cc4f6bef44c816a6e7c9e03f56ac6af6efbb082b19b379f go1.22.1.linux-s390x.tar.gz
|
||||
0c5ebb7eb39b7884ec99f92b425d4c03a96a72443562aafbf6e7d15c42a3108a go1.22.1.windows-386.zip
|
||||
cf9c66a208a106402a527f5b956269ca506cfe535fc388e828d249ea88ed28ba go1.22.1.windows-amd64.zip
|
||||
85b8511b298c9f4199ecae26afafcc3d46155bac934d43f2357b9224bcaa310f go1.22.1.windows-arm64.zip
|
||||
|
||||
# version:golangci 1.55.2
|
||||
# https://github.com/golangci/golangci-lint/releases/
|
||||
|
|
|
|||
|
|
@ -46,13 +46,12 @@ import (
|
|||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
"github.com/ethereum/go-ethereum/beacon/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
func updateEngineApi(client *rpc.Client, headCh chan types.ChainHeadEvent) {
|
||||
for event := range headCh {
|
||||
if client == nil { // dry run, no engine API specified
|
||||
log.Info("New execution block retrieved", "block number", event.HeadBlock.Number, "block hash", event.HeadBlock.BlockHash, "finalized block hash", event.Finalized)
|
||||
} else {
|
||||
if status, err := callNewPayloadV2(client, event.HeadBlock); err == nil {
|
||||
log.Info("Successful NewPayload", "block number", event.HeadBlock.Number, "block hash", event.HeadBlock.BlockHash, "status", status)
|
||||
} else {
|
||||
log.Error("Failed NewPayload", "block number", event.HeadBlock.Number, "block hash", event.HeadBlock.BlockHash, "error", err)
|
||||
}
|
||||
if status, err := callForkchoiceUpdatedV1(client, event.HeadBlock.BlockHash, event.Finalized); err == nil {
|
||||
log.Info("Successful ForkchoiceUpdated", "head", event.HeadBlock.BlockHash, "status", status)
|
||||
} else {
|
||||
log.Error("Failed ForkchoiceUpdated", "head", event.HeadBlock.BlockHash, "error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func callNewPayloadV2(client *rpc.Client, execData *engine.ExecutableData) (string, error) {
|
||||
var resp engine.PayloadStatusV1
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
err := client.CallContext(ctx, &resp, "engine_newPayloadV2", execData)
|
||||
cancel()
|
||||
return resp.Status, err
|
||||
}
|
||||
|
||||
func callForkchoiceUpdatedV1(client *rpc.Client, headHash, finalizedHash common.Hash) (string, error) {
|
||||
var resp engine.ForkChoiceResponse
|
||||
update := engine.ForkchoiceStateV1{
|
||||
HeadBlockHash: headHash,
|
||||
SafeBlockHash: finalizedHash,
|
||||
FinalizedBlockHash: finalizedHash,
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
err := client.CallContext(ctx, &resp, "engine_forkchoiceUpdatedV1", update, nil)
|
||||
cancel()
|
||||
return resp.PayloadStatus.Status, err
|
||||
}
|
||||
|
|
@ -23,7 +23,6 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/beacon/blsync"
|
||||
"github.com/ethereum/go-ethereum/beacon/types"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
|
@ -87,16 +86,14 @@ func sync(ctx *cli.Context) error {
|
|||
verbosity := log.FromLegacyLevel(ctx.Int(verbosityFlag.Name))
|
||||
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(output, verbosity, usecolor)))
|
||||
|
||||
headCh := make(chan types.ChainHeadEvent, 16)
|
||||
// set up blsync
|
||||
client := blsync.NewClient(ctx)
|
||||
sub := client.SubscribeChainHeadEvent(headCh)
|
||||
go updateEngineApi(makeRPCClient(ctx), headCh)
|
||||
client.SetEngineRPC(makeRPCClient(ctx))
|
||||
client.Start()
|
||||
|
||||
// run until stopped
|
||||
<-ctx.Done()
|
||||
client.Stop()
|
||||
sub.Unsubscribe()
|
||||
close(headCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
|
@ -32,7 +33,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p/dnsdisc"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -183,8 +183,8 @@ var attrFormatters = map[string]func(rlp.RawValue) (string, bool){
|
|||
}
|
||||
|
||||
func formatAttrRaw(v rlp.RawValue) (string, bool) {
|
||||
s := hex.EncodeToString(v)
|
||||
return s, true
|
||||
content, _, err := rlp.SplitString(v)
|
||||
return hex.EncodeToString(content), err == nil
|
||||
}
|
||||
|
||||
func formatAttrString(v rlp.RawValue) (string, bool) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
|
|
@ -40,7 +41,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// Chain is a lightweight blockchain-like store which can read a hivechain
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
const jsonIndent = " "
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/directory"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
|
@ -123,7 +123,7 @@ type rejectedTx struct {
|
|||
// Apply applies a set of transactions to a pre-state
|
||||
func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
txIt txIterator, miningReward int64,
|
||||
getTracerFn func(txIndex int, txHash common.Hash) (*directory.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) {
|
||||
getTracerFn func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) {
|
||||
// Capture errors for BLOCKHASH operation, if we haven't been supplied the
|
||||
// required blockhashes
|
||||
var hashError error
|
||||
|
|
@ -173,7 +173,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
// Calculate the BlobBaseFee
|
||||
var excessBlobGas uint64
|
||||
if pre.Env.ExcessBlobGas != nil {
|
||||
excessBlobGas := *pre.Env.ExcessBlobGas
|
||||
excessBlobGas = *pre.Env.ExcessBlobGas
|
||||
vmContext.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas)
|
||||
} else {
|
||||
// If it is not explicitly defined, but we have the parent values, we try
|
||||
|
|
@ -422,7 +422,7 @@ func calcDifficulty(config *params.ChainConfig, number, currentTime, parentTime
|
|||
return ethash.CalcDifficulty(config, currentTime, parent)
|
||||
}
|
||||
|
||||
func writeTraceResult(tracer *directory.Tracer, f io.WriteCloser) error {
|
||||
func writeTraceResult(tracer *tracers.Tracer, f io.WriteCloser) error {
|
||||
defer f.Close()
|
||||
result, err := tracer.GetResult()
|
||||
if err != nil || result == nil {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/directory"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
|
@ -81,7 +81,7 @@ type input struct {
|
|||
}
|
||||
|
||||
func Transition(ctx *cli.Context) error {
|
||||
var getTracer = func(txIndex int, txHash common.Hash) (*directory.Tracer, io.WriteCloser, error) { return nil, nil, nil }
|
||||
var getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { return nil, nil, nil }
|
||||
|
||||
baseDir, err := createBasedir(ctx)
|
||||
if err != nil {
|
||||
|
|
@ -96,13 +96,13 @@ func Transition(ctx *cli.Context) error {
|
|||
EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name),
|
||||
Debug: true,
|
||||
}
|
||||
getTracer = func(txIndex int, txHash common.Hash) (*directory.Tracer, io.WriteCloser, error) {
|
||||
getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) {
|
||||
traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String())))
|
||||
if err != nil {
|
||||
return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err))
|
||||
}
|
||||
logger := logger.NewJSONLogger(logConfig, traceFile)
|
||||
tracer := &directory.Tracer{
|
||||
tracer := &tracers.Tracer{
|
||||
Hooks: logger,
|
||||
// jsonLogger streams out result to file.
|
||||
GetResult: func() (json.RawMessage, error) { return nil, nil },
|
||||
|
|
@ -115,12 +115,12 @@ func Transition(ctx *cli.Context) error {
|
|||
if ctx.IsSet(TraceTracerConfigFlag.Name) {
|
||||
config = []byte(ctx.String(TraceTracerConfigFlag.Name))
|
||||
}
|
||||
getTracer = func(txIndex int, txHash common.Hash) (*directory.Tracer, io.WriteCloser, error) {
|
||||
getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) {
|
||||
traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.json", txIndex, txHash.String())))
|
||||
if err != nil {
|
||||
return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err))
|
||||
}
|
||||
tracer, err := directory.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config)
|
||||
tracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config)
|
||||
if err != nil {
|
||||
return nil, nil, NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %w", err))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ func stateTestCmd(ctx *cli.Context) error {
|
|||
}
|
||||
// Load the test content from the input file
|
||||
if len(ctx.Args().First()) != 0 {
|
||||
return runStateTest(ctx.Args().First(), cfg, ctx.Bool(MachineFlag.Name), ctx.Bool(DumpFlag.Name))
|
||||
return runStateTest(ctx.Args().First(), cfg, ctx.Bool(DumpFlag.Name))
|
||||
}
|
||||
// Read filenames from stdin and execute back-to-back
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
|
@ -76,7 +76,7 @@ func stateTestCmd(ctx *cli.Context) error {
|
|||
if len(fname) == 0 {
|
||||
return nil
|
||||
}
|
||||
if err := runStateTest(fname, cfg, ctx.Bool(MachineFlag.Name), ctx.Bool(DumpFlag.Name)); err != nil {
|
||||
if err := runStateTest(fname, cfg, ctx.Bool(DumpFlag.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -84,7 +84,7 @@ func stateTestCmd(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
// runStateTest loads the state-test given by fname, and executes the test.
|
||||
func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error {
|
||||
func runStateTest(fname string, cfg vm.Config, dump bool) error {
|
||||
src, err := os.ReadFile(fname)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -105,9 +105,7 @@ func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error {
|
|||
if tstate.StateDB != nil {
|
||||
root = tstate.StateDB.IntermediateRoot(false)
|
||||
result.Root = &root
|
||||
if jsonOut {
|
||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
||||
if dump { // Dump any state to aid debugging
|
||||
cpy, _ := state.New(root, tstate.StateDB.Database(), nil)
|
||||
dump := cpy.RawDump(nil)
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/naoina/toml"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
|
@ -214,9 +215,9 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
|||
}
|
||||
utils.RegisterFullSyncTester(stack, eth, common.BytesToHash(hex))
|
||||
}
|
||||
// Start the dev mode if requested, or launch the engine API for
|
||||
// interacting with external consensus client.
|
||||
|
||||
if ctx.IsSet(utils.DeveloperFlag.Name) {
|
||||
// Start dev mode.
|
||||
simBeacon, err := catalyst.NewSimulatedBeacon(ctx.Uint64(utils.DeveloperPeriodFlag.Name), eth)
|
||||
if err != nil {
|
||||
utils.Fatalf("failed to register dev mode catalyst service: %v", err)
|
||||
|
|
@ -224,8 +225,14 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
|||
catalyst.RegisterSimulatedBeaconAPIs(stack, simBeacon)
|
||||
stack.RegisterLifecycle(simBeacon)
|
||||
} else if ctx.IsSet(utils.BeaconApiFlag.Name) {
|
||||
stack.RegisterLifecycle(catalyst.NewBlsync(blsync.NewClient(ctx), eth))
|
||||
// Start blsync mode.
|
||||
srv := rpc.NewServer()
|
||||
srv.RegisterName("engine", catalyst.NewConsensusAPI(eth))
|
||||
blsyncer := blsync.NewClient(ctx)
|
||||
blsyncer.SetEngineRPC(rpc.DialInProc(srv))
|
||||
stack.RegisterLifecycle(blsyncer)
|
||||
} else {
|
||||
// Launch the engine API for interacting with external consensus client.
|
||||
err := catalyst.Register(stack, eth)
|
||||
if err != nil {
|
||||
utils.Fatalf("failed to register catalyst service: %v", err)
|
||||
|
|
|
|||
|
|
@ -33,11 +33,14 @@ import (
|
|||
"github.com/ethereum/go-ethereum/console/prompt"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
|
@ -79,6 +82,7 @@ Remove blockchain and state databases`,
|
|||
dbExportCmd,
|
||||
dbMetadataCmd,
|
||||
dbCheckStateContentCmd,
|
||||
dbInspectHistoryCmd,
|
||||
},
|
||||
}
|
||||
dbInspectCmd = &cli.Command{
|
||||
|
|
@ -203,6 +207,28 @@ WARNING: This is a low-level operation which may cause database corruption!`,
|
|||
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||
Description: "Shows metadata about the chain status.",
|
||||
}
|
||||
dbInspectHistoryCmd = &cli.Command{
|
||||
Action: inspectHistory,
|
||||
Name: "inspect-history",
|
||||
Usage: "Inspect the state history within block range",
|
||||
ArgsUsage: "<address> [OPTIONAL <storage-slot>]",
|
||||
Flags: flags.Merge([]cli.Flag{
|
||||
utils.SyncModeFlag,
|
||||
&cli.Uint64Flag{
|
||||
Name: "start",
|
||||
Usage: "block number of the range start, zero means earliest history",
|
||||
},
|
||||
&cli.Uint64Flag{
|
||||
Name: "end",
|
||||
Usage: "block number of the range end(included), zero means latest history",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "raw",
|
||||
Usage: "display the decoded raw state value (otherwise shows rlp-encoded value)",
|
||||
},
|
||||
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||
Description: "This command queries the history of the account or storage slot within the specified block range",
|
||||
}
|
||||
)
|
||||
|
||||
func removeDB(ctx *cli.Context) error {
|
||||
|
|
@ -759,3 +785,145 @@ func showMetaData(ctx *cli.Context) error {
|
|||
table.Render()
|
||||
return nil
|
||||
}
|
||||
|
||||
func inspectAccount(db *triedb.Database, start uint64, end uint64, address common.Address, raw bool) error {
|
||||
stats, err := db.AccountHistory(address, start, end)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Account history:\n\taddress: %s\n\tblockrange: [#%d-#%d]\n", address.Hex(), stats.Start, stats.End)
|
||||
|
||||
from := stats.Start
|
||||
for i := 0; i < len(stats.Blocks); i++ {
|
||||
var content string
|
||||
if len(stats.Origins[i]) == 0 {
|
||||
content = "<empty>"
|
||||
} else {
|
||||
if !raw {
|
||||
content = fmt.Sprintf("%#x", stats.Origins[i])
|
||||
} else {
|
||||
account := new(types.SlimAccount)
|
||||
if err := rlp.DecodeBytes(stats.Origins[i], account); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
code := "<nil>"
|
||||
if len(account.CodeHash) > 0 {
|
||||
code = fmt.Sprintf("%#x", account.CodeHash)
|
||||
}
|
||||
root := "<nil>"
|
||||
if len(account.Root) > 0 {
|
||||
root = fmt.Sprintf("%#x", account.Root)
|
||||
}
|
||||
content = fmt.Sprintf("nonce: %d, balance: %d, codeHash: %s, root: %s", account.Nonce, account.Balance, code, root)
|
||||
}
|
||||
}
|
||||
fmt.Printf("#%d - #%d: %s\n", from, stats.Blocks[i], content)
|
||||
from = stats.Blocks[i]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func inspectStorage(db *triedb.Database, start uint64, end uint64, address common.Address, slot common.Hash, raw bool) error {
|
||||
// The hash of storage slot key is utilized in the history
|
||||
// rather than the raw slot key, make the conversion.
|
||||
slotHash := crypto.Keccak256Hash(slot.Bytes())
|
||||
stats, err := db.StorageHistory(address, slotHash, start, end)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Storage history:\n\taddress: %s\n\tslot: %s\n\tblockrange: [#%d-#%d]\n", address.Hex(), slot.Hex(), stats.Start, stats.End)
|
||||
|
||||
from := stats.Start
|
||||
for i := 0; i < len(stats.Blocks); i++ {
|
||||
var content string
|
||||
if len(stats.Origins[i]) == 0 {
|
||||
content = "<empty>"
|
||||
} else {
|
||||
if !raw {
|
||||
content = fmt.Sprintf("%#x", stats.Origins[i])
|
||||
} else {
|
||||
_, data, _, err := rlp.Split(stats.Origins[i])
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to decode storage slot, %v", err)
|
||||
return err
|
||||
}
|
||||
content = fmt.Sprintf("%#x", data)
|
||||
}
|
||||
}
|
||||
fmt.Printf("#%d - #%d: %s\n", from, stats.Blocks[i], content)
|
||||
from = stats.Blocks[i]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func inspectHistory(ctx *cli.Context) error {
|
||||
if ctx.NArg() == 0 || ctx.NArg() > 2 {
|
||||
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
|
||||
}
|
||||
var (
|
||||
address common.Address
|
||||
slot common.Hash
|
||||
)
|
||||
if err := address.UnmarshalText([]byte(ctx.Args().Get(0))); err != nil {
|
||||
return err
|
||||
}
|
||||
if ctx.NArg() > 1 {
|
||||
if err := slot.UnmarshalText([]byte(ctx.Args().Get(1))); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Load the databases.
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||
defer db.Close()
|
||||
|
||||
triedb := utils.MakeTrieDatabase(ctx, db, false, false, false)
|
||||
defer triedb.Close()
|
||||
|
||||
var (
|
||||
err error
|
||||
start uint64 // the id of first history object to query
|
||||
end uint64 // the id (included) of last history object to query
|
||||
)
|
||||
// State histories are identified by state ID rather than block number.
|
||||
// To address this, load the corresponding block header and perform the
|
||||
// conversion by this function.
|
||||
blockToID := func(blockNumber uint64) (uint64, error) {
|
||||
header := rawdb.ReadHeader(db, rawdb.ReadCanonicalHash(db, blockNumber), blockNumber)
|
||||
if header == nil {
|
||||
return 0, fmt.Errorf("block #%d is not existent", blockNumber)
|
||||
}
|
||||
id := rawdb.ReadStateID(db, header.Root)
|
||||
if id == nil {
|
||||
first, last, err := triedb.HistoryRange()
|
||||
if err == nil {
|
||||
return 0, fmt.Errorf("history of block #%d is not existent, available history range: [#%d-#%d]", blockNumber, first, last)
|
||||
}
|
||||
return 0, fmt.Errorf("history of block #%d is not existent", blockNumber)
|
||||
}
|
||||
return *id, nil
|
||||
}
|
||||
// Parse the starting block number for inspection.
|
||||
startNumber := ctx.Uint64("start")
|
||||
if startNumber != 0 {
|
||||
start, err = blockToID(startNumber)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Parse the ending block number for inspection.
|
||||
endBlock := ctx.Uint64("end")
|
||||
if endBlock != 0 {
|
||||
end, err = blockToID(endBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Inspect the state history.
|
||||
if slot == (common.Hash{}) {
|
||||
return inspectAccount(triedb, start, end, address, ctx.Bool("raw"))
|
||||
}
|
||||
return inspectStorage(triedb, start, end, address, slot, ctx.Bool("raw"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/eth/filters"
|
||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/directory/live"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/ethdb/remotedb"
|
||||
"github.com/ethereum/go-ethereum/ethstats"
|
||||
|
|
@ -2196,7 +2195,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
|||
if ctx.IsSet(VMTraceConfigFlag.Name) {
|
||||
config = json.RawMessage(ctx.String(VMTraceConfigFlag.Name))
|
||||
}
|
||||
t, err := live.Directory.New(name, config)
|
||||
t, err := tracers.LiveDirectory.New(name, config)
|
||||
if err != nil {
|
||||
Fatalf("Failed to create tracer %q: %v", name, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@
|
|||
package prque
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"container/heap"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/mclock"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// LazyQueue is a priority queue data structure where priorities can change over
|
||||
|
|
@ -33,7 +33,7 @@ import (
|
|||
//
|
||||
// If the upper estimate is exceeded then Update should be called for that item.
|
||||
// A global Refresh function should also be called periodically.
|
||||
type LazyQueue[P constraints.Ordered, V any] struct {
|
||||
type LazyQueue[P cmp.Ordered, V any] struct {
|
||||
clock mclock.Clock
|
||||
// Items are stored in one of two internal queues ordered by estimated max
|
||||
// priority until the next and the next-after-next refresh. Update and Refresh
|
||||
|
|
@ -50,12 +50,12 @@ type LazyQueue[P constraints.Ordered, V any] struct {
|
|||
}
|
||||
|
||||
type (
|
||||
PriorityCallback[P constraints.Ordered, V any] func(data V) P // actual priority callback
|
||||
MaxPriorityCallback[P constraints.Ordered, V any] func(data V, until mclock.AbsTime) P // estimated maximum priority callback
|
||||
PriorityCallback[P cmp.Ordered, V any] func(data V) P // actual priority callback
|
||||
MaxPriorityCallback[P cmp.Ordered, V any] func(data V, until mclock.AbsTime) P // estimated maximum priority callback
|
||||
)
|
||||
|
||||
// NewLazyQueue creates a new lazy queue
|
||||
func NewLazyQueue[P constraints.Ordered, V any](setIndex SetIndexCallback[V], priority PriorityCallback[P, V], maxPriority MaxPriorityCallback[P, V], clock mclock.Clock, refreshPeriod time.Duration) *LazyQueue[P, V] {
|
||||
func NewLazyQueue[P cmp.Ordered, V any](setIndex SetIndexCallback[V], priority PriorityCallback[P, V], maxPriority MaxPriorityCallback[P, V], clock mclock.Clock, refreshPeriod time.Duration) *LazyQueue[P, V] {
|
||||
q := &LazyQueue[P, V]{
|
||||
popQueue: newSstack[P, V](nil),
|
||||
setIndex: setIndex,
|
||||
|
|
|
|||
|
|
@ -18,18 +18,17 @@
|
|||
package prque
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"container/heap"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// Priority queue data structure.
|
||||
type Prque[P constraints.Ordered, V any] struct {
|
||||
type Prque[P cmp.Ordered, V any] struct {
|
||||
cont *sstack[P, V]
|
||||
}
|
||||
|
||||
// New creates a new priority queue.
|
||||
func New[P constraints.Ordered, V any](setIndex SetIndexCallback[V]) *Prque[P, V] {
|
||||
func New[P cmp.Ordered, V any](setIndex SetIndexCallback[V]) *Prque[P, V] {
|
||||
return &Prque[P, V]{newSstack[P, V](setIndex)}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@
|
|||
|
||||
package prque
|
||||
|
||||
import "golang.org/x/exp/constraints"
|
||||
import "cmp"
|
||||
|
||||
// The size of a block of data
|
||||
const blockSize = 4096
|
||||
|
||||
// A prioritized item in the sorted stack.
|
||||
type item[P constraints.Ordered, V any] struct {
|
||||
type item[P cmp.Ordered, V any] struct {
|
||||
value V
|
||||
priority P
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ type SetIndexCallback[V any] func(data V, index int)
|
|||
// Internal sortable stack data structure. Implements the Push and Pop ops for
|
||||
// the stack (heap) functionality and the Len, Less and Swap methods for the
|
||||
// sortability requirements of the heaps.
|
||||
type sstack[P constraints.Ordered, V any] struct {
|
||||
type sstack[P cmp.Ordered, V any] struct {
|
||||
setIndex SetIndexCallback[V]
|
||||
size int
|
||||
capacity int
|
||||
|
|
@ -40,7 +40,7 @@ type sstack[P constraints.Ordered, V any] struct {
|
|||
}
|
||||
|
||||
// Creates a new, empty stack.
|
||||
func newSstack[P constraints.Ordered, V any](setIndex SetIndexCallback[V]) *sstack[P, V] {
|
||||
func newSstack[P cmp.Ordered, V any](setIndex SetIndexCallback[V]) *sstack[P, V] {
|
||||
result := new(sstack[P, V])
|
||||
result.setIndex = setIndex
|
||||
result.active = make([]*item[P, V], blockSize)
|
||||
|
|
|
|||
|
|
@ -475,3 +475,14 @@ func (d *Decimal) UnmarshalJSON(input []byte) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
type PrettyBytes []byte
|
||||
|
||||
// TerminalString implements log.TerminalStringer, formatting a string for console
|
||||
// output during logging.
|
||||
func (b PrettyBytes) TerminalString() string {
|
||||
if len(b) < 7 {
|
||||
return fmt.Sprintf("%x", b)
|
||||
}
|
||||
return fmt.Sprintf("%#x...%x (%dB)", b[:3], b[len(b)-3:], len(b))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -349,46 +349,46 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H
|
|||
}
|
||||
|
||||
// Finalize implements consensus.Engine and processes withdrawals on top.
|
||||
func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, stateDB *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
|
||||
func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) {
|
||||
if !beacon.IsPoSHeader(header) {
|
||||
beacon.ethone.Finalize(chain, header, stateDB, txs, uncles, nil)
|
||||
beacon.ethone.Finalize(chain, header, state, body)
|
||||
return
|
||||
}
|
||||
// Withdrawals processing.
|
||||
for _, w := range withdrawals {
|
||||
for _, w := range body.Withdrawals {
|
||||
// Convert amount from gwei to wei.
|
||||
amount := new(uint256.Int).SetUint64(w.Amount)
|
||||
amount = amount.Mul(amount, uint256.NewInt(params.GWei))
|
||||
stateDB.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal)
|
||||
state.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal)
|
||||
}
|
||||
// No block reward which is issued by consensus layer instead.
|
||||
}
|
||||
|
||||
// FinalizeAndAssemble implements consensus.Engine, setting the final state and
|
||||
// assembling the block.
|
||||
func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) {
|
||||
func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
|
||||
if !beacon.IsPoSHeader(header) {
|
||||
return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts, nil)
|
||||
return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts)
|
||||
}
|
||||
shanghai := chain.Config().IsShanghai(header.Number, header.Time)
|
||||
if shanghai {
|
||||
// All blocks after Shanghai must include a withdrawals root.
|
||||
if withdrawals == nil {
|
||||
withdrawals = make([]*types.Withdrawal, 0)
|
||||
if body.Withdrawals == nil {
|
||||
body.Withdrawals = make([]*types.Withdrawal, 0)
|
||||
}
|
||||
} else {
|
||||
if len(withdrawals) > 0 {
|
||||
if len(body.Withdrawals) > 0 {
|
||||
return nil, errors.New("withdrawals set before Shanghai activation")
|
||||
}
|
||||
}
|
||||
// Finalize and assemble the block.
|
||||
beacon.Finalize(chain, header, state, txs, uncles, withdrawals)
|
||||
beacon.Finalize(chain, header, state, body)
|
||||
|
||||
// Assign the final state root to header.
|
||||
header.Root = state.IntermediateRoot(true)
|
||||
|
||||
// Assemble and return the final block.
|
||||
return types.NewBlockWithWithdrawals(header, txs, uncles, receipts, withdrawals, trie.NewStackTrie(nil)), nil
|
||||
return types.NewBlockWithWithdrawals(header, body.Transactions, body.Uncles, receipts, body.Withdrawals, trie.NewStackTrie(nil)), nil
|
||||
}
|
||||
|
||||
// Seal generates a new sealing request for the given input block and pushes
|
||||
|
|
|
|||
|
|
@ -580,24 +580,24 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header
|
|||
|
||||
// Finalize implements consensus.Engine. There is no post-transaction
|
||||
// consensus rules in clique, do nothing here.
|
||||
func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
|
||||
func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) {
|
||||
// No block rewards in PoA, so the state remains as is
|
||||
}
|
||||
|
||||
// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
|
||||
// nor block rewards given, and returns the final block.
|
||||
func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) {
|
||||
if len(withdrawals) > 0 {
|
||||
func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
|
||||
if len(body.Withdrawals) > 0 {
|
||||
return nil, errors.New("clique does not support withdrawals")
|
||||
}
|
||||
// Finalize block
|
||||
c.Finalize(chain, header, state, txs, uncles, nil)
|
||||
c.Finalize(chain, header, state, body)
|
||||
|
||||
// Assign the final state root to header.
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||
|
||||
// Assemble and return the final block for sealing.
|
||||
return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), nil
|
||||
return types.NewBlock(header, body.Transactions, nil, receipts, trie.NewStackTrie(nil)), nil
|
||||
}
|
||||
|
||||
// Authorize injects a private key into the consensus engine to mint new blocks
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package clique
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -28,7 +29,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// Vote represents a single vote that an authorized signer made to modify the
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -30,7 +31,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// testerAccountPool is a pool to maintain currently active tester accounts,
|
||||
|
|
|
|||
|
|
@ -88,16 +88,14 @@ type Engine interface {
|
|||
//
|
||||
// Note: The state database might be updated to reflect any consensus rules
|
||||
// that happen at finalization (e.g. block rewards).
|
||||
Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
|
||||
uncles []*types.Header, withdrawals []*types.Withdrawal)
|
||||
Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body)
|
||||
|
||||
// FinalizeAndAssemble runs any post-transaction state modifications (e.g. block
|
||||
// rewards or process withdrawals) and assembles the final block.
|
||||
//
|
||||
// Note: The block header and state database might be updated to reflect any
|
||||
// consensus rules that happen at finalization (e.g. block rewards).
|
||||
FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
|
||||
uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error)
|
||||
FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error)
|
||||
|
||||
// Seal generates a new sealing request for the given input block and pushes
|
||||
// the result into the given channel.
|
||||
|
|
|
|||
|
|
@ -502,25 +502,25 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H
|
|||
}
|
||||
|
||||
// Finalize implements consensus.Engine, accumulating the block and uncle rewards.
|
||||
func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
|
||||
func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) {
|
||||
// Accumulate any block and uncle rewards
|
||||
accumulateRewards(chain.Config(), state, header, uncles)
|
||||
accumulateRewards(chain.Config(), state, header, body.Uncles)
|
||||
}
|
||||
|
||||
// FinalizeAndAssemble implements consensus.Engine, accumulating the block and
|
||||
// uncle rewards, setting the final state and assembling the block.
|
||||
func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) {
|
||||
if len(withdrawals) > 0 {
|
||||
func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
|
||||
if len(body.Withdrawals) > 0 {
|
||||
return nil, errors.New("ethash does not support withdrawals")
|
||||
}
|
||||
// Finalize block
|
||||
ethash.Finalize(chain, header, state, txs, uncles, nil)
|
||||
ethash.Finalize(chain, header, state, body)
|
||||
|
||||
// Assign the final state root to header.
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||
|
||||
// Header seems complete, assemble into a block and return
|
||||
return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil
|
||||
return types.NewBlock(header, body.Transactions, body.Uncles, receipts, trie.NewStackTrie(nil)), nil
|
||||
}
|
||||
|
||||
// SealHash returns the hash of a block prior to it being sealed.
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ func (it *instructionIterator) Next() bool {
|
|||
|
||||
it.op = vm.OpCode(it.code[it.pc])
|
||||
if it.op.IsPush() {
|
||||
a := uint64(it.op) - uint64(vm.PUSH1) + 1
|
||||
a := uint64(it.op) - uint64(vm.PUSH0)
|
||||
u := it.pc + 1 + a
|
||||
if uint64(len(it.code)) <= it.pc || uint64(len(it.code)) < u {
|
||||
it.error = fmt.Errorf("incomplete push instruction at %v", it.pc)
|
||||
|
|
|
|||
|
|
@ -914,7 +914,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
|||
// touching the header chain altogether, unless the freezer is broken
|
||||
if repair {
|
||||
if target, force := updateFn(bc.db, bc.CurrentBlock()); force {
|
||||
bc.hc.SetHead(target.Number.Uint64(), updateFn, delFn)
|
||||
bc.hc.SetHead(target.Number.Uint64(), nil, delFn)
|
||||
}
|
||||
} else {
|
||||
// Rewind the chain to the requested head and keep going backwards until a
|
||||
|
|
@ -1845,6 +1845,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps)
|
||||
|
||||
go func(start time.Time, followup *types.Block, throwaway *state.StateDB) {
|
||||
// Disable tracing for prefetcher executions.
|
||||
vmCfg := bc.vmConfig
|
||||
vmCfg.Tracer = nil
|
||||
bc.prefetcher.Prefetch(followup, throwaway, vmCfg, &followupInterrupt)
|
||||
|
|
|
|||
|
|
@ -345,7 +345,8 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||
gen(i, b)
|
||||
}
|
||||
|
||||
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, b.txs, b.uncles, b.receipts, b.withdrawals)
|
||||
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals}
|
||||
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ func TestGeneratePOSChain(t *testing.T) {
|
|||
gspec = &Genesis{
|
||||
Config: &config,
|
||||
Alloc: types.GenesisAlloc{
|
||||
address: {Balance: funds},
|
||||
params.BeaconRootsStorageAddress: {Balance: common.Big0, Code: asm4788},
|
||||
address: {Balance: funds},
|
||||
params.BeaconRootsAddress: {Balance: common.Big0, Code: asm4788},
|
||||
},
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
Difficulty: common.Big1,
|
||||
|
|
@ -180,7 +180,7 @@ func TestGeneratePOSChain(t *testing.T) {
|
|||
}
|
||||
state, _ := blockchain.State()
|
||||
idx := block.Time()%8191 + 8191
|
||||
got := state.GetState(params.BeaconRootsStorageAddress, common.BigToHash(new(big.Int).SetUint64(idx)))
|
||||
got := state.GetState(params.BeaconRootsAddress, common.BigToHash(new(big.Int).SetUint64(idx)))
|
||||
if got != want {
|
||||
t.Fatalf("block %d, wrong parent beacon root in state: got %s, want %s", i, got, want)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,12 +24,12 @@ import (
|
|||
"math"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -30,12 +30,12 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type allocItem struct {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"slices"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||
|
|
@ -31,7 +32,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// ReadCanonicalHash retrieves the hash assigned to a canonical block number.
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ func TestFreezerReadonlyValidate(t *testing.T) {
|
|||
}
|
||||
require.NoError(t, f.Close())
|
||||
|
||||
// Re-openening as readonly should fail when validating
|
||||
// Re-opening as readonly should fail when validating
|
||||
// table lengths.
|
||||
_, err = NewFreezer(dir, "", true, 2049, tables)
|
||||
if err == nil {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"slices"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
|
@ -29,7 +30,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
bloomfilter "github.com/holiman/bloomfilter/v2"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ package snapshot
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// weightedIterator is a iterator with an assigned weight. It is used to prioritise
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"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/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -102,7 +101,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
return nil, nil, 0, errors.New("withdrawals before shanghai")
|
||||
}
|
||||
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
||||
p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), withdrawals)
|
||||
p.engine.Finalize(p.bc, header, statedb, block.Body())
|
||||
|
||||
return receipts, allLogs, *usedGas, nil
|
||||
}
|
||||
|
|
@ -112,14 +111,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
// this method takes an already created EVM instance as input.
|
||||
func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxStart != nil {
|
||||
evm.Config.Tracer.OnTxStart(&tracing.VMContext{
|
||||
ChainConfig: evm.ChainConfig(),
|
||||
StateDB: statedb,
|
||||
BlockNumber: evm.Context.BlockNumber,
|
||||
Time: evm.Context.Time,
|
||||
Coinbase: evm.Context.Coinbase,
|
||||
Random: evm.Context.Random,
|
||||
}, tx, msg.From)
|
||||
evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||
if evm.Config.Tracer.OnTxEnd != nil {
|
||||
defer func() {
|
||||
evm.Config.Tracer.OnTxEnd(receipt, err)
|
||||
|
|
@ -202,11 +194,11 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat
|
|||
GasPrice: common.Big0,
|
||||
GasFeeCap: common.Big0,
|
||||
GasTipCap: common.Big0,
|
||||
To: ¶ms.BeaconRootsStorageAddress,
|
||||
To: ¶ms.BeaconRootsAddress,
|
||||
Data: beaconRoot[:],
|
||||
}
|
||||
vmenv.Reset(NewEVMTxContext(msg), statedb)
|
||||
statedb.AddAddressToAccessList(params.BeaconRootsStorageAddress)
|
||||
statedb.AddAddressToAccessList(params.BeaconRootsAddress)
|
||||
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||
statedb.Finalise(true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import (
|
|||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// log2_1_125 is used in the eviction priority calculation.
|
||||
var log2_1_125 = math.Log2(1.125)
|
||||
// log1_125 is used in the eviction priority calculation.
|
||||
var log1_125 = math.Log(1.125)
|
||||
|
||||
// evictionPriority calculates the eviction priority based on the algorithm
|
||||
// described in the BlobPool docs for both fee components.
|
||||
|
|
@ -57,8 +57,8 @@ func evictionPriority1D(basefeeJumps float64, txfeeJumps float64) int {
|
|||
|
||||
// dynamicFeeJumps calculates the log1.125(fee), namely the number of fee jumps
|
||||
// needed to reach the requested one. We only use it when calculating the jumps
|
||||
// between 2 fees, so it doesn't matter from what exact number with returns.
|
||||
// it returns the result from (0, 1, 1.125).
|
||||
// between 2 fees, so it doesn't matter from what exact number it returns.
|
||||
// It returns the result from (0, 1, 1.125).
|
||||
//
|
||||
// This method is very expensive, taking about 75ns on a very recent laptop CPU,
|
||||
// but the result does not change with the lifetime of a transaction, so it can
|
||||
|
|
@ -67,7 +67,7 @@ func dynamicFeeJumps(fee *uint256.Int) float64 {
|
|||
if fee.IsZero() {
|
||||
return 0 // can't log2 zero, should never happen outside tests, but don't choke
|
||||
}
|
||||
return math.Log2(fee.Float64()) / log2_1_125
|
||||
return math.Log(fee.Float64()) / log1_125
|
||||
}
|
||||
|
||||
// intLog2 is a helper to calculate the integral part of a log2 of an unsigned
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"container/heap"
|
||||
"math"
|
||||
"math/big"
|
||||
"slices"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
|
@ -28,7 +29,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/holiman/uint256"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// nonceHeap is a heap.Interface implementation over 64bit unsigned integers for
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import (
|
|||
|
||||
var (
|
||||
// blobTxMinBlobGasPrice is the big.Int version of the configured protocol
|
||||
// parameter to avoid constucting a new big integer for every transaction.
|
||||
// parameter to avoid constructing a new big integer for every transaction.
|
||||
blobTxMinBlobGasPrice = big.NewInt(params.BlobTxMinBlobGasprice)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -93,9 +93,7 @@ func BenchmarkJumpdestOpAnalysis(bench *testing.B) {
|
|||
bits := make(bitvec, len(code)/8+1+4)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := range bits {
|
||||
bits[j] = 0
|
||||
}
|
||||
clear(bits)
|
||||
codeBitmapInternal(code, bits)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
|||
sender = vm.AccountRef(cfg.Origin)
|
||||
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time)
|
||||
)
|
||||
if cfg.EVMConfig.Tracer != nil {
|
||||
if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil {
|
||||
cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin)
|
||||
}
|
||||
// Execute the preparatory steps for state transition which includes:
|
||||
|
|
@ -159,7 +159,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
|
|||
sender = vm.AccountRef(cfg.Origin)
|
||||
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time)
|
||||
)
|
||||
if cfg.EVMConfig.Tracer != nil {
|
||||
if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil {
|
||||
cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin)
|
||||
}
|
||||
// Execute the preparatory steps for state transition which includes:
|
||||
|
|
@ -190,7 +190,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
|
|||
statedb = cfg.State
|
||||
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time)
|
||||
)
|
||||
if cfg.EVMConfig.Tracer != nil {
|
||||
if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil {
|
||||
cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin)
|
||||
}
|
||||
// Execute the preparatory steps for state transition which includes:
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/directory"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
||||
|
|
@ -331,7 +331,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
|
|||
cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
cfg.GasLimit = gas
|
||||
if len(tracerCode) > 0 {
|
||||
tracer, err := directory.DefaultDirectory.New(tracerCode, new(directory.Context), nil)
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
|
@ -827,7 +827,7 @@ func TestRuntimeJSTracer(t *testing.T) {
|
|||
statedb.SetCode(common.HexToAddress("0xee"), calleeCode)
|
||||
statedb.SetCode(common.HexToAddress("0xff"), suicideCode)
|
||||
|
||||
tracer, err := directory.DefaultDirectory.New(jsTracer, new(directory.Context), nil)
|
||||
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -862,7 +862,7 @@ func TestJSTracerCreateTx(t *testing.T) {
|
|||
code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)}
|
||||
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
tracer, err := directory.DefaultDirectory.New(jsTracer, new(directory.Context), nil)
|
||||
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import (
|
|||
)
|
||||
|
||||
// BUG(agl): this implementation is not constant time.
|
||||
// TODO(agl): keep GF(p²) elements in Mongomery form.
|
||||
// TODO(agl): keep GF(p²) elements in Montgomery form.
|
||||
|
||||
// G1 is an abstract cyclic group. The zero value is suitable for use as the
|
||||
// output of an operation, but cannot be used as an input.
|
||||
|
|
|
|||
|
|
@ -51,6 +51,15 @@ var (
|
|||
|
||||
var errInvalidPubkey = errors.New("invalid secp256k1 public key")
|
||||
|
||||
// EllipticCurve contains curve operations.
|
||||
type EllipticCurve interface {
|
||||
elliptic.Curve
|
||||
|
||||
// Point marshaling/unmarshaing.
|
||||
Marshal(x, y *big.Int) []byte
|
||||
Unmarshal(data []byte) (x, y *big.Int)
|
||||
}
|
||||
|
||||
// KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports
|
||||
// Read to get a variable amount of data from the hash state. Read is faster than Sum
|
||||
// because it doesn't copy the internal state, but also modifies the internal state.
|
||||
|
|
@ -148,7 +157,7 @@ func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) {
|
|||
return nil, errors.New("invalid private key, zero or negative")
|
||||
}
|
||||
|
||||
priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d)
|
||||
priv.PublicKey.X, priv.PublicKey.Y = S256().ScalarBaseMult(d)
|
||||
if priv.PublicKey.X == nil {
|
||||
return nil, errors.New("invalid private key")
|
||||
}
|
||||
|
|
@ -165,7 +174,7 @@ func FromECDSA(priv *ecdsa.PrivateKey) []byte {
|
|||
|
||||
// UnmarshalPubkey converts bytes to a secp256k1 public key.
|
||||
func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) {
|
||||
x, y := elliptic.Unmarshal(S256(), pub)
|
||||
x, y := S256().Unmarshal(pub)
|
||||
if x == nil {
|
||||
return nil, errInvalidPubkey
|
||||
}
|
||||
|
|
@ -176,7 +185,7 @@ func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
|
|||
if pub == nil || pub.X == nil || pub.Y == nil {
|
||||
return nil
|
||||
}
|
||||
return elliptic.Marshal(S256(), pub.X, pub.Y)
|
||||
return S256().Marshal(pub.X, pub.Y)
|
||||
}
|
||||
|
||||
// HexToECDSA parses a secp256k1 private key.
|
||||
|
|
@ -278,7 +287,5 @@ func PubkeyToAddress(p ecdsa.PublicKey) common.Address {
|
|||
}
|
||||
|
||||
func zeroBytes(bytes []byte) {
|
||||
for i := range bytes {
|
||||
bytes[i] = 0
|
||||
}
|
||||
clear(bytes)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ import (
|
|||
"hash"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -95,15 +97,15 @@ func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey {
|
|||
// Generate an elliptic curve public / private keypair. If params is nil,
|
||||
// the recommended default parameters for the key will be chosen.
|
||||
func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) {
|
||||
pb, x, y, err := elliptic.GenerateKey(curve, rand)
|
||||
sk, err := ecdsa.GenerateKey(curve, rand)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
prv = new(PrivateKey)
|
||||
prv.PublicKey.X = x
|
||||
prv.PublicKey.Y = y
|
||||
prv.PublicKey.X = sk.X
|
||||
prv.PublicKey.Y = sk.Y
|
||||
prv.PublicKey.Curve = curve
|
||||
prv.D = new(big.Int).SetBytes(pb)
|
||||
prv.D = new(big.Int).Set(sk.D)
|
||||
if params == nil {
|
||||
params = ParamsFromCurve(curve)
|
||||
}
|
||||
|
|
@ -255,12 +257,15 @@ func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err e
|
|||
|
||||
d := messageTag(params.Hash, Km, em, s2)
|
||||
|
||||
Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y)
|
||||
ct = make([]byte, len(Rb)+len(em)+len(d))
|
||||
copy(ct, Rb)
|
||||
copy(ct[len(Rb):], em)
|
||||
copy(ct[len(Rb)+len(em):], d)
|
||||
return ct, nil
|
||||
if curve, ok := pub.Curve.(crypto.EllipticCurve); ok {
|
||||
Rb := curve.Marshal(R.PublicKey.X, R.PublicKey.Y)
|
||||
ct = make([]byte, len(Rb)+len(em)+len(d))
|
||||
copy(ct, Rb)
|
||||
copy(ct[len(Rb):], em)
|
||||
copy(ct[len(Rb)+len(em):], d)
|
||||
return ct, nil
|
||||
}
|
||||
return nil, ErrInvalidCurve
|
||||
}
|
||||
|
||||
// Decrypt decrypts an ECIES ciphertext.
|
||||
|
|
@ -297,21 +302,24 @@ func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
|
|||
|
||||
R := new(PublicKey)
|
||||
R.Curve = prv.PublicKey.Curve
|
||||
R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen])
|
||||
if R.X == nil {
|
||||
return nil, ErrInvalidPublicKey
|
||||
}
|
||||
|
||||
z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
Ke, Km := deriveKeys(hash, z, s1, params.KeyLen)
|
||||
if curve, ok := R.Curve.(crypto.EllipticCurve); ok {
|
||||
R.X, R.Y = curve.Unmarshal(c[:rLen])
|
||||
if R.X == nil {
|
||||
return nil, ErrInvalidPublicKey
|
||||
}
|
||||
|
||||
d := messageTag(params.Hash, Km, c[mStart:mEnd], s2)
|
||||
if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 {
|
||||
return nil, ErrInvalidMessage
|
||||
}
|
||||
z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
Ke, Km := deriveKeys(hash, z, s1, params.KeyLen)
|
||||
|
||||
return symDecrypt(params, Ke, c[mStart:mEnd])
|
||||
d := messageTag(params.Hash, Km, c[mStart:mEnd], s2)
|
||||
if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 {
|
||||
return nil, ErrInvalidMessage
|
||||
}
|
||||
return symDecrypt(params, Ke, c[mStart:mEnd])
|
||||
}
|
||||
return nil, ErrInvalidCurve
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,12 +44,8 @@ func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int,
|
|||
// Unpack the result and clear temporaries.
|
||||
x := new(big.Int).SetBytes(point[:32])
|
||||
y := new(big.Int).SetBytes(point[32:])
|
||||
for i := range point {
|
||||
point[i] = 0
|
||||
}
|
||||
for i := range padded {
|
||||
scalar[i] = 0
|
||||
}
|
||||
clear(point)
|
||||
clear(scalar)
|
||||
if res != 1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ package secp256k1
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
|
|
@ -24,7 +23,7 @@ func generateKeyPair() (pubkey, privkey []byte) {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pubkey = elliptic.Marshal(S256(), key.X, key.Y)
|
||||
pubkey = S256().Marshal(key.X, key.Y)
|
||||
|
||||
privkey = make([]byte, 32)
|
||||
blob := key.D.Bytes()
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ package crypto
|
|||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
|
|
@ -40,9 +39,7 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
x, y := elliptic.Unmarshal(S256(), s)
|
||||
return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil
|
||||
return UnmarshalPubkey(s)
|
||||
}
|
||||
|
||||
// Sign calculates an ECDSA signature.
|
||||
|
|
@ -84,6 +81,6 @@ func CompressPubkey(pubkey *ecdsa.PublicKey) []byte {
|
|||
}
|
||||
|
||||
// S256 returns an instance of the secp256k1 curve.
|
||||
func S256() elliptic.Curve {
|
||||
func S256() EllipticCurve {
|
||||
return secp256k1.S256()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ package crypto
|
|||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
btc_ecdsa "github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
||||
|
|
@ -58,7 +58,13 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pub.ToECDSA(), nil
|
||||
// We need to explicitly set the curve here, because we're wrapping
|
||||
// the original curve to add (un-)marshalling
|
||||
return &ecdsa.PublicKey{
|
||||
Curve: S256(),
|
||||
X: pub.X(),
|
||||
Y: pub.Y(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Sign calculates an ECDSA signature.
|
||||
|
|
@ -73,7 +79,7 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
|
|||
if len(hash) != 32 {
|
||||
return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
|
||||
}
|
||||
if prv.Curve != btcec.S256() {
|
||||
if prv.Curve != S256() {
|
||||
return nil, errors.New("private key curve is not secp256k1")
|
||||
}
|
||||
// ecdsa.PrivateKey -> btcec.PrivateKey
|
||||
|
|
@ -128,7 +134,13 @@ func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return key.ToECDSA(), nil
|
||||
// We need to explicitly set the curve here, because we're wrapping
|
||||
// the original curve to add (un-)marshalling
|
||||
return &ecdsa.PublicKey{
|
||||
Curve: S256(),
|
||||
X: key.X(),
|
||||
Y: key.Y(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CompressPubkey encodes a public key to the 33-byte compressed format. The
|
||||
|
|
@ -147,6 +159,38 @@ func CompressPubkey(pubkey *ecdsa.PublicKey) []byte {
|
|||
}
|
||||
|
||||
// S256 returns an instance of the secp256k1 curve.
|
||||
func S256() elliptic.Curve {
|
||||
return btcec.S256()
|
||||
func S256() EllipticCurve {
|
||||
return btCurve{btcec.S256()}
|
||||
}
|
||||
|
||||
type btCurve struct {
|
||||
*btcec.KoblitzCurve
|
||||
}
|
||||
|
||||
// Marshall converts a point given as (x, y) into a byte slice.
|
||||
func (curve btCurve) Marshal(x, y *big.Int) []byte {
|
||||
byteLen := (curve.Params().BitSize + 7) / 8
|
||||
|
||||
ret := make([]byte, 1+2*byteLen)
|
||||
ret[0] = 4 // uncompressed point
|
||||
|
||||
x.FillBytes(ret[1 : 1+byteLen])
|
||||
y.FillBytes(ret[1+byteLen : 1+2*byteLen])
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On
|
||||
// error, x = nil.
|
||||
func (curve btCurve) Unmarshal(data []byte) (x, y *big.Int) {
|
||||
byteLen := (curve.Params().BitSize + 7) / 8
|
||||
if len(data) != 1+2*byteLen {
|
||||
return nil, nil
|
||||
}
|
||||
if data[0] != 4 { // uncompressed form
|
||||
return nil, nil
|
||||
}
|
||||
x = new(big.Int).SetBytes(data[1 : 1+byteLen])
|
||||
y = new(big.Int).SetBytes(data[1+byteLen:])
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
|
@ -32,7 +33,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
"github.com/holiman/uint256"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var dumper = spew.ConfigState{Indent: " "}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/directory/live"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
|
|
@ -101,8 +101,8 @@ type Ethereum struct {
|
|||
shutdownTracker *shutdowncheck.ShutdownTracker // Tracks if and when the node has shutdown ungracefully
|
||||
}
|
||||
|
||||
// New creates a new Ethereum object (including the
|
||||
// initialisation of the common Ethereum object)
|
||||
// New creates a new Ethereum object (including the initialisation of the common Ethereum object),
|
||||
// whose lifecycle will be managed by the provided node.
|
||||
func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||
// Ensure configuration values are compatible and sane
|
||||
if config.SyncMode == downloader.LightSync {
|
||||
|
|
@ -206,7 +206,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
if config.VMTraceConfig != "" {
|
||||
traceConfig = json.RawMessage(config.VMTraceConfig)
|
||||
}
|
||||
t, err := live.Directory.New(config.VMTrace, traceConfig)
|
||||
t, err := tracers.LiveDirectory.New(config.VMTrace, traceConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to create tracer %s: %v", config.VMTrace, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package catalyst
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -540,7 +541,33 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
|
|||
log.Trace("Engine API request received", "method", "NewPayload", "number", params.Number, "hash", params.BlockHash)
|
||||
block, err := engine.ExecutableDataToBlock(params, versionedHashes, beaconRoot)
|
||||
if err != nil {
|
||||
log.Warn("Invalid NewPayload params", "params", params, "error", err)
|
||||
bgu := "nil"
|
||||
if params.BlobGasUsed != nil {
|
||||
bgu = strconv.Itoa(int(*params.BlobGasUsed))
|
||||
}
|
||||
ebg := "nil"
|
||||
if params.BlobGasUsed != nil {
|
||||
ebg = strconv.Itoa(int(*params.ExcessBlobGas))
|
||||
}
|
||||
log.Warn("Invalid NewPayload params",
|
||||
"params.Number", params.Number,
|
||||
"params.ParentHash", params.ParentHash,
|
||||
"params.BlockHash", params.BlockHash,
|
||||
"params.StateRoot", params.StateRoot,
|
||||
"params.FeeRecipient", params.FeeRecipient,
|
||||
"params.LogsBloom", common.PrettyBytes(params.LogsBloom),
|
||||
"params.Random", params.Random,
|
||||
"params.GasLimit", params.GasLimit,
|
||||
"params.GasUsed", params.GasUsed,
|
||||
"params.Timestamp", params.Timestamp,
|
||||
"params.ExtraData", common.PrettyBytes(params.ExtraData),
|
||||
"params.BaseFeePerGas", params.BaseFeePerGas,
|
||||
"params.BlobGasUsed", bgu,
|
||||
"params.ExcessBlobGas", ebg,
|
||||
"len(params.Transactions)", len(params.Transactions),
|
||||
"len(params.Withdrawals)", len(params.Withdrawals),
|
||||
"beaconRoot", beaconRoot,
|
||||
"error", err)
|
||||
return api.invalid(err, nil), nil
|
||||
}
|
||||
// Stash away the last update to warn the user if the beacon client goes offline
|
||||
|
|
@ -567,7 +594,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
|
|||
// update after legit payload executions.
|
||||
parent := api.eth.BlockChain().GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||
if parent == nil {
|
||||
return api.delayPayloadImport(block)
|
||||
return api.delayPayloadImport(block), nil
|
||||
}
|
||||
// We have an existing parent, do some sanity checks to avoid the beacon client
|
||||
// triggering too early
|
||||
|
|
@ -593,7 +620,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
|
|||
// into the database directly will conflict with the assumptions of snap sync
|
||||
// that it has an empty db that it can fill itself.
|
||||
if api.eth.SyncMode() != downloader.FullSync {
|
||||
return api.delayPayloadImport(block)
|
||||
return api.delayPayloadImport(block), nil
|
||||
}
|
||||
if !api.eth.BlockChain().HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
|
||||
api.remoteBlocks.put(block.Hash(), block.Header())
|
||||
|
|
@ -619,11 +646,11 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
|
|||
// either via a forkchoice update or a sync extension. This method is meant to
|
||||
// be called by the newpayload command when the block seems to be ok, but some
|
||||
// prerequisite prevents it from being processed (e.g. no parent, or snap sync).
|
||||
func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (engine.PayloadStatusV1, error) {
|
||||
func (api *ConsensusAPI) delayPayloadImport(block *types.Block) engine.PayloadStatusV1 {
|
||||
// Sanity check that this block's parent is not on a previously invalidated
|
||||
// chain. If it is, mark the block as invalid too.
|
||||
if res := api.checkInvalidAncestor(block.ParentHash(), block.Hash()); res != nil {
|
||||
return *res, nil
|
||||
return *res
|
||||
}
|
||||
// Stash the block away for a potential forced forkchoice update to it
|
||||
// at a later time.
|
||||
|
|
@ -635,7 +662,7 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (engine.PayloadS
|
|||
err := api.eth.Downloader().BeaconExtend(api.eth.SyncMode(), block.Header())
|
||||
if err == nil {
|
||||
log.Debug("Payload accepted for sync extension", "number", block.NumberU64(), "hash", block.Hash())
|
||||
return engine.PayloadStatusV1{Status: engine.SYNCING}, nil
|
||||
return engine.PayloadStatusV1{Status: engine.SYNCING}
|
||||
}
|
||||
// Either no beacon sync was started yet, or it rejected the delivered
|
||||
// payload as non-integratable on top of the existing sync. We'll just
|
||||
|
|
@ -652,7 +679,7 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (engine.PayloadS
|
|||
// and cannot afford concurrent out-if-band modifications via imports.
|
||||
log.Warn("Ignoring payload while snap syncing", "number", block.NumberU64(), "hash", block.Hash(), "reason", err)
|
||||
}
|
||||
return engine.PayloadStatusV1{Status: engine.SYNCING}, nil
|
||||
return engine.PayloadStatusV1{Status: engine.SYNCING}
|
||||
}
|
||||
|
||||
// setInvalidAncestor is a callback for the downloader to notify us if a bad block
|
||||
|
|
|
|||
|
|
@ -72,8 +72,8 @@ func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) {
|
|||
genesis := &core.Genesis{
|
||||
Config: &config,
|
||||
Alloc: types.GenesisAlloc{
|
||||
testAddr: {Balance: testBalance},
|
||||
params.BeaconRootsStorageAddress: {Balance: common.Big0, Code: common.Hex2Bytes("3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500")},
|
||||
testAddr: {Balance: testBalance},
|
||||
params.BeaconRootsAddress: {Balance: common.Big0, Code: common.Hex2Bytes("3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500")},
|
||||
},
|
||||
ExtraData: []byte("test genesis"),
|
||||
Timestamp: 9000,
|
||||
|
|
@ -1650,10 +1650,10 @@ func TestParentBeaconBlockRoot(t *testing.T) {
|
|||
rootIdx = common.BigToHash(big.NewInt(int64((execData.ExecutionPayload.Timestamp % 98304) + 98304)))
|
||||
)
|
||||
|
||||
if num := db.GetState(params.BeaconRootsStorageAddress, timeIdx); num != timeIdx {
|
||||
if num := db.GetState(params.BeaconRootsAddress, timeIdx); num != timeIdx {
|
||||
t.Fatalf("incorrect number stored: want %s, got %s", timeIdx, num)
|
||||
}
|
||||
if root := db.GetState(params.BeaconRootsStorageAddress, rootIdx); root != *blockParams.BeaconRoot {
|
||||
if root := db.GetState(params.BeaconRootsAddress, rootIdx); root != *blockParams.BeaconRoot {
|
||||
t.Fatalf("incorrect root stored: want %s, got %s", *blockParams.BeaconRoot, root)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,88 +0,0 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package catalyst
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
"github.com/ethereum/go-ethereum/beacon/types"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
// Blsync tracks the head of the beacon chain through the beacon light client
|
||||
// and drives the local node via ConsensusAPI.
|
||||
type Blsync struct {
|
||||
engine *ConsensusAPI
|
||||
client Client
|
||||
headCh chan types.ChainHeadEvent
|
||||
headSub event.Subscription
|
||||
|
||||
quitCh chan struct{}
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
SubscribeChainHeadEvent(ch chan<- types.ChainHeadEvent) event.Subscription
|
||||
Start()
|
||||
Stop()
|
||||
}
|
||||
|
||||
// NewBlsync creates a new beacon light syncer.
|
||||
func NewBlsync(client Client, eth *eth.Ethereum) *Blsync {
|
||||
return &Blsync{
|
||||
engine: newConsensusAPIWithoutHeartbeat(eth),
|
||||
client: client,
|
||||
headCh: make(chan types.ChainHeadEvent, 16),
|
||||
quitCh: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Start starts underlying beacon light client and the sync logic for driving
|
||||
// the local node.
|
||||
func (b *Blsync) Start() error {
|
||||
log.Info("Beacon light sync started")
|
||||
b.headSub = b.client.SubscribeChainHeadEvent(b.headCh)
|
||||
go b.client.Start()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-b.quitCh:
|
||||
return nil
|
||||
case head := <-b.headCh:
|
||||
if _, err := b.engine.NewPayloadV2(*head.HeadBlock); err != nil {
|
||||
log.Error("failed to send new payload", "err", err)
|
||||
continue
|
||||
}
|
||||
update := engine.ForkchoiceStateV1{
|
||||
HeadBlockHash: head.HeadBlock.BlockHash,
|
||||
SafeBlockHash: head.Finalized, //TODO pass finalized or empty hash here?
|
||||
FinalizedBlockHash: head.Finalized,
|
||||
}
|
||||
if _, err := b.engine.ForkchoiceUpdatedV1(update, nil); err != nil {
|
||||
log.Error("failed to send forkchoice updated", "err", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stop signals to the light client and syncer to exit.
|
||||
func (b *Blsync) Stop() error {
|
||||
b.client.Stop()
|
||||
close(b.quitCh)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -39,10 +39,10 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
MaxBlockFetch = 128 // Amount of blocks to be fetched per retrieval request
|
||||
MaxHeaderFetch = 192 // Amount of block headers to be fetched per retrieval request
|
||||
MaxSkeletonSize = 128 // Number of header fetches to need for a skeleton assembly
|
||||
MaxReceiptFetch = 256 // Amount of transaction receipts to allow fetching per request
|
||||
MaxBlockFetch = 128 // Number of blocks to be fetched per retrieval request
|
||||
MaxHeaderFetch = 192 // Number of block headers to be fetched per retrieval request
|
||||
MaxSkeletonSize = 128 // Number of header fetches needed for a skeleton assembly
|
||||
MaxReceiptFetch = 256 // Number of transaction receipts to allow fetching per request
|
||||
|
||||
maxQueuedHeaders = 32 * 1024 // [eth/62] Maximum number of headers to queue for import (DOS protection)
|
||||
maxHeadersProcess = 2048 // Number of header download results to import at once into the chain
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package downloader
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"os"
|
||||
|
|
@ -32,7 +33,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
// makeChain creates a chain of n blocks starting at and including parent.
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"slices"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -30,7 +31,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package gasprice
|
|||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -30,7 +31,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
const sampleNumber = 3 // Number of transactions sampled in a block
|
||||
|
|
|
|||
|
|
@ -390,7 +390,7 @@ func testTransactionPropagation(t *testing.T, protocol uint) {
|
|||
}
|
||||
// Interconnect all the sink handlers with the source handler
|
||||
for i, sink := range sinks {
|
||||
sink := sink // Closure for gorotuine below
|
||||
sink := sink // Closure for goroutine below
|
||||
|
||||
sourcePipe, sinkPipe := p2p.MsgPipe()
|
||||
defer sourcePipe.Close()
|
||||
|
|
|
|||
|
|
@ -42,14 +42,6 @@ const (
|
|||
maxQueuedTxAnns = 4096
|
||||
)
|
||||
|
||||
// max is a helper function which returns the larger of the two given integers.
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Peer is a collection of relevant information we have about a `eth` peer.
|
||||
type Peer struct {
|
||||
id string // Unique ID for the peer, cached
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
mrand "math/rand"
|
||||
"slices"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -32,16 +33,15 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/internal/testrand"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/testutil"
|
||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
"github.com/ethereum/go-ethereum/triedb/pathdb"
|
||||
"github.com/holiman/uint256"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
func TestHashing(t *testing.T) {
|
||||
|
|
@ -1816,8 +1816,8 @@ func makeUnevenStorageTrie(owner common.Hash, slots int, db *triedb.Database) (c
|
|||
break
|
||||
}
|
||||
for j := 0; j < slots/3; j++ {
|
||||
key := append([]byte{byte(n)}, testutil.RandBytes(31)...)
|
||||
val, _ := rlp.EncodeToBytes(testutil.RandBytes(32))
|
||||
key := append([]byte{byte(n)}, testrand.Bytes(31)...)
|
||||
val, _ := rlp.EncodeToBytes(testrand.Bytes(32))
|
||||
|
||||
elem := &kv{key, val}
|
||||
tr.MustUpdate(elem.k, elem.v)
|
||||
|
|
@ -1873,8 +1873,9 @@ func verifyTrie(scheme string, db ethdb.KeyValueStore, root common.Hash, t *test
|
|||
// TestSyncAccountPerformance tests how efficient the snap algo is at minimizing
|
||||
// state healing
|
||||
func TestSyncAccountPerformance(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// These tests must not run in parallel: they modify the
|
||||
// global var accountConcurrency
|
||||
// t.Parallel()
|
||||
testSyncAccountPerformance(t, rawdb.HashScheme)
|
||||
testSyncAccountPerformance(t, rawdb.PathScheme)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/directory"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
|
|
@ -273,7 +272,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
|
|||
// Trace all the transactions contained within
|
||||
for i, tx := range task.block.Transactions() {
|
||||
msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee())
|
||||
txctx := &directory.Context{
|
||||
txctx := &Context{
|
||||
BlockHash: task.block.Hash(),
|
||||
BlockNumber: task.block.Number(),
|
||||
TxIndex: i,
|
||||
|
|
@ -590,7 +589,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
|||
// process that generates states in one thread and traces txes
|
||||
// in separate worker threads.
|
||||
if config != nil && config.Tracer != nil && *config.Tracer != "" {
|
||||
if isJS := directory.DefaultDirectory.IsJS(*config.Tracer); isJS {
|
||||
if isJS := DefaultDirectory.IsJS(*config.Tracer); isJS {
|
||||
return api.traceBlockParallel(ctx, block, statedb, config)
|
||||
}
|
||||
}
|
||||
|
|
@ -605,7 +604,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
|||
for i, tx := range txs {
|
||||
// Generate the next state snapshot fast without tracing
|
||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||
txctx := &directory.Context{
|
||||
txctx := &Context{
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: block.Number(),
|
||||
TxIndex: i,
|
||||
|
|
@ -644,7 +643,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
|
|||
// Fetch and execute the next transaction trace tasks
|
||||
for task := range jobs {
|
||||
msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee())
|
||||
txctx := &directory.Context{
|
||||
txctx := &Context{
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: block.Number(),
|
||||
TxIndex: task.index,
|
||||
|
|
@ -859,7 +858,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
|
|||
return nil, err
|
||||
}
|
||||
|
||||
txctx := &directory.Context{
|
||||
txctx := &Context{
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: block.Number(),
|
||||
TxIndex: int(index),
|
||||
|
|
@ -926,27 +925,26 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
|||
config.BlockOverrides.Apply(&vmctx)
|
||||
}
|
||||
// Execute the trace
|
||||
msg, err := args.ToMessage(api.backend.RPCGasCap(), vmctx.BaseFee)
|
||||
if err != nil {
|
||||
if err := args.CallDefaults(api.backend.RPCGasCap(), vmctx.BaseFee, api.backend.ChainConfig().ChainID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tx, err := argsToTransaction(api.backend, &args, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var traceConfig *TraceConfig
|
||||
var (
|
||||
msg = args.ToMessage(vmctx.BaseFee)
|
||||
tx = args.ToTransaction()
|
||||
traceConfig *TraceConfig
|
||||
)
|
||||
if config != nil {
|
||||
traceConfig = &config.TraceConfig
|
||||
}
|
||||
return api.traceTx(ctx, tx, msg, new(directory.Context), vmctx, statedb, traceConfig)
|
||||
return api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig)
|
||||
}
|
||||
|
||||
// traceTx configures a new tracer according to the provided configuration, and
|
||||
// executes the given message in the provided environment. The return value will
|
||||
// be tracer dependent.
|
||||
func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *directory.Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
|
||||
func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
|
||||
var (
|
||||
tracer *directory.Tracer
|
||||
tracer *Tracer
|
||||
err error
|
||||
timeout = defaultTraceTimeout
|
||||
usedGas uint64
|
||||
|
|
@ -955,9 +953,15 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
|
|||
config = &TraceConfig{}
|
||||
}
|
||||
// Default tracer is the struct logger
|
||||
tracer = logger.NewStructLogger(config.Config).Tracer()
|
||||
if config.Tracer != nil {
|
||||
tracer, err = directory.DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
|
||||
if config.Tracer == nil {
|
||||
logger := logger.NewStructLogger(config.Config)
|
||||
tracer = &Tracer{
|
||||
Hooks: logger.Hooks(),
|
||||
GetResult: logger.GetResult,
|
||||
Stop: logger.Stop,
|
||||
}
|
||||
} else {
|
||||
tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1050,54 +1054,3 @@ func overrideConfig(original *params.ChainConfig, override *params.ChainConfig)
|
|||
|
||||
return copy, canon
|
||||
}
|
||||
|
||||
// argsToTransaction produces a Transaction object given call arguments.
|
||||
// The `msg` field must be converted from the same arguments.
|
||||
func argsToTransaction(b Backend, args *ethapi.TransactionArgs, msg *core.Message) (*types.Transaction, error) {
|
||||
chainID := b.ChainConfig().ChainID
|
||||
if args.ChainID != nil {
|
||||
if have := (*big.Int)(args.ChainID); have.Cmp(chainID) != 0 {
|
||||
return nil, fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, chainID)
|
||||
}
|
||||
}
|
||||
var data types.TxData
|
||||
switch {
|
||||
case args.MaxFeePerGas != nil:
|
||||
al := types.AccessList{}
|
||||
if args.AccessList != nil {
|
||||
al = *args.AccessList
|
||||
}
|
||||
data = &types.DynamicFeeTx{
|
||||
To: args.To,
|
||||
ChainID: chainID,
|
||||
Nonce: msg.Nonce,
|
||||
Gas: msg.GasLimit,
|
||||
GasFeeCap: msg.GasFeeCap,
|
||||
GasTipCap: msg.GasTipCap,
|
||||
Value: msg.Value,
|
||||
Data: msg.Data,
|
||||
AccessList: al,
|
||||
}
|
||||
case args.AccessList != nil:
|
||||
data = &types.AccessListTx{
|
||||
To: args.To,
|
||||
ChainID: chainID,
|
||||
Nonce: msg.Nonce,
|
||||
Gas: msg.GasLimit,
|
||||
GasPrice: msg.GasPrice,
|
||||
Value: msg.Value,
|
||||
Data: msg.Data,
|
||||
AccessList: *args.AccessList,
|
||||
}
|
||||
default:
|
||||
data = &types.LegacyTx{
|
||||
To: args.To,
|
||||
Nonce: msg.Nonce,
|
||||
Gas: msg.GasLimit,
|
||||
GasPrice: msg.GasPrice,
|
||||
Value: msg.Value,
|
||||
Data: msg.Data,
|
||||
}
|
||||
}
|
||||
return types.NewTx(data), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"slices"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -43,7 +44,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -14,10 +14,7 @@
|
|||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Package directory provides functionality to lookup tracers by name.
|
||||
// It also includes utility functions that are imported by the other
|
||||
// tracing packages.
|
||||
package directory
|
||||
package tracers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
|
@ -24,7 +24,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/directory/live"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
pbeth "github.com/ethereum/go-ethereum/pb/sf/ethereum/type/v2"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
|
|
@ -45,7 +44,7 @@ var emptyCommonHash = common.Hash{}
|
|||
func init() {
|
||||
staticFirehoseChainValidationOnInit()
|
||||
|
||||
live.Directory.Register("firehose", newFirehoseTracer)
|
||||
LiveDirectory.Register("firehose", newFirehoseTracer)
|
||||
}
|
||||
|
||||
func newFirehoseTracer(cfg json.RawMessage) (*tracing.Hooks, error) {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/directory"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/tests"
|
||||
|
|
@ -139,7 +139,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
)
|
||||
state.Close()
|
||||
|
||||
tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), test.TracerConfig)
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
|
@ -247,7 +247,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
|
|||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), nil)
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil)
|
||||
if err != nil {
|
||||
b.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
|
@ -283,8 +283,8 @@ func TestInternals(t *testing.T) {
|
|||
BaseFee: new(big.Int),
|
||||
}
|
||||
)
|
||||
mkTracer := func(name string, cfg json.RawMessage) *directory.Tracer {
|
||||
tr, err := directory.DefaultDirectory.New(name, nil, cfg)
|
||||
mkTracer := func(name string, cfg json.RawMessage) *tracers.Tracer {
|
||||
tr, err := tracers.DefaultDirectory.New(name, nil, cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
|
@ -294,7 +294,7 @@ func TestInternals(t *testing.T) {
|
|||
for _, tc := range []struct {
|
||||
name string
|
||||
code []byte
|
||||
tracer *directory.Tracer
|
||||
tracer *tracers.Tracer
|
||||
want string
|
||||
}{
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/directory"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/tests"
|
||||
)
|
||||
|
|
@ -97,7 +97,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
|
|||
defer state.Close()
|
||||
|
||||
// Create the tracer, the EVM environment and run it
|
||||
tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), test.TracerConfig)
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/directory"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/tests"
|
||||
)
|
||||
|
||||
|
|
@ -113,7 +113,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
context.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas)
|
||||
}
|
||||
|
||||
tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), test.TracerConfig)
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
package directory
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
@ -62,6 +62,7 @@ func memoryCopy(m []byte, offset, size int64) (cpy []byte) {
|
|||
return
|
||||
}
|
||||
|
||||
// MemoryPtr returns a pointer to a slice of memory.
|
||||
func MemoryPtr(m []byte, offset, size int64) []byte {
|
||||
if size == 0 {
|
||||
return nil
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
package directory
|
||||
package internal
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
|
@ -25,7 +25,8 @@ import (
|
|||
"github.com/dop251/goja"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/directory"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/internal"
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -44,16 +45,16 @@ func init() {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
type ctorFn = func(*directory.Context, json.RawMessage) (*directory.Tracer, error)
|
||||
type ctorFn = func(*tracers.Context, json.RawMessage) (*tracers.Tracer, error)
|
||||
lookup := func(code string) ctorFn {
|
||||
return func(ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) {
|
||||
return func(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
|
||||
return newJsTracer(code, ctx, cfg)
|
||||
}
|
||||
}
|
||||
for name, code := range assetTracers {
|
||||
directory.DefaultDirectory.Register(name, lookup(code), true)
|
||||
tracers.DefaultDirectory.Register(name, lookup(code), true)
|
||||
}
|
||||
directory.DefaultDirectory.RegisterJSEval(newJsTracer)
|
||||
tracers.DefaultDirectory.RegisterJSEval(newJsTracer)
|
||||
}
|
||||
|
||||
// bigIntProgram is compiled once and the exported function mostly invoked to convert
|
||||
|
|
@ -136,7 +137,7 @@ type jsTracer struct {
|
|||
// The methods `result` and `fault` are required to be present.
|
||||
// The methods `step`, `enter`, and `exit` are optional, but note that
|
||||
// `enter` and `exit` always go together.
|
||||
func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) {
|
||||
func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
|
||||
vm := goja.New()
|
||||
// By default field names are exported to JS as is, i.e. capitalized.
|
||||
vm.SetFieldNameMapper(goja.UncapFieldNameMapper())
|
||||
|
|
@ -149,7 +150,7 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*dir
|
|||
t.setBuiltinFunctions()
|
||||
|
||||
if ctx == nil {
|
||||
ctx = new(directory.Context)
|
||||
ctx = new(tracers.Context)
|
||||
}
|
||||
if ctx.BlockHash != (common.Hash{}) {
|
||||
blockHash, err := t.toBuf(vm, ctx.BlockHash.Bytes())
|
||||
|
|
@ -220,7 +221,7 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*dir
|
|||
t.frameResultValue = t.frameResult.setupObject()
|
||||
t.logValue = t.log.setupObject()
|
||||
|
||||
return &directory.Tracer{
|
||||
return &tracers.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
OnTxStart: t.OnTxStart,
|
||||
OnTxEnd: t.OnTxEnd,
|
||||
|
|
@ -643,7 +644,7 @@ func (mo *memoryObj) slice(begin, end int64) ([]byte, error) {
|
|||
if end < begin || begin < 0 {
|
||||
return nil, fmt.Errorf("tracer accessed out of bound memory: offset %d, end %d", begin, end)
|
||||
}
|
||||
slice, err := directory.GetMemoryCopyPadded(mo.memory, begin, end-begin)
|
||||
slice, err := internal.GetMemoryCopyPadded(mo.memory, begin, end-begin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -669,7 +670,7 @@ func (mo *memoryObj) getUint(addr int64) (*big.Int, error) {
|
|||
if len(mo.memory) < int(addr)+32 || addr < 0 {
|
||||
return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", len(mo.memory), addr, 32)
|
||||
}
|
||||
return new(big.Int).SetBytes(directory.MemoryPtr(mo.memory, addr, 32)), nil
|
||||
return new(big.Int).SetBytes(internal.MemoryPtr(mo.memory, addr, 32)), nil
|
||||
}
|
||||
|
||||
func (mo *memoryObj) Length() int {
|
||||
|
|
@ -709,7 +710,7 @@ func (s *stackObj) peek(idx int) (*big.Int, error) {
|
|||
if len(s.stack) <= idx || idx < 0 {
|
||||
return nil, fmt.Errorf("tracer accessed out of bound stack: size %d, index %d", len(s.stack), idx)
|
||||
}
|
||||
return directory.StackBack(s.stack, idx).ToBig(), nil
|
||||
return internal.StackBack(s.stack, idx).ToBig(), nil
|
||||
}
|
||||
|
||||
func (s *stackObj) Length() int {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/directory"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
|
@ -62,7 +62,7 @@ func testCtx() *vmContext {
|
|||
return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}}
|
||||
}
|
||||
|
||||
func runTrace(tracer *directory.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) {
|
||||
func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) {
|
||||
var (
|
||||
env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer.Hooks})
|
||||
gasLimit uint64 = 31000
|
||||
|
|
@ -265,14 +265,14 @@ func TestIsPrecompile(t *testing.T) {
|
|||
|
||||
func TestEnterExit(t *testing.T) {
|
||||
// test that either both or none of enter() and exit() are defined
|
||||
if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(directory.Context), nil); err == nil {
|
||||
if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context), nil); err == nil {
|
||||
t.Fatal("tracer creation should've failed without exit() definition")
|
||||
}
|
||||
if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(directory.Context), nil); err != nil {
|
||||
if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context), nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// test that the enter and exit method are correctly invoked and the values passed
|
||||
tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(directory.Context), nil)
|
||||
tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -294,7 +294,7 @@ func TestEnterExit(t *testing.T) {
|
|||
|
||||
func TestSetup(t *testing.T) {
|
||||
// Test empty config
|
||||
_, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(directory.Context), nil)
|
||||
_, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(tracers.Context), nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
|
@ -304,12 +304,12 @@ func TestSetup(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
// Test no setup func
|
||||
_, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(directory.Context), cfg)
|
||||
_, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(tracers.Context), cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Test config value
|
||||
tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(directory.Context), cfg)
|
||||
tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(tracers.Context), cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package live
|
||||
package tracers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
|
@ -9,21 +9,21 @@ import (
|
|||
|
||||
type ctorFunc func(config json.RawMessage) (*tracing.Hooks, error)
|
||||
|
||||
// Directory is the collection of tracers which can be used
|
||||
// LiveDirectory is the collection of tracers which can be used
|
||||
// during normal block import operations.
|
||||
var Directory = directory{elems: make(map[string]ctorFunc)}
|
||||
var LiveDirectory = liveDirectory{elems: make(map[string]ctorFunc)}
|
||||
|
||||
type directory struct {
|
||||
type liveDirectory struct {
|
||||
elems map[string]ctorFunc
|
||||
}
|
||||
|
||||
// Register registers a tracer constructor by name.
|
||||
func (d *directory) Register(name string, f ctorFunc) {
|
||||
func (d *liveDirectory) Register(name string, f ctorFunc) {
|
||||
d.elems[name] = f
|
||||
}
|
||||
|
||||
// New instantiates a tracer by name.
|
||||
func (d *directory) New(name string, config json.RawMessage) (*tracing.Hooks, error) {
|
||||
func (d *liveDirectory) New(name string, config json.RawMessage) (*tracing.Hooks, error) {
|
||||
if f, ok := d.elems[name]; ok {
|
||||
return f(config)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue