mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
* Ran gopls modernize to fix everything go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./... * Override rules_go provided dependency for golang.org/x/tools to v0.38.0. To update this, checked out rules_go, then ran `bazel run //go/tools/releaser -- upgrade-dep -mirror=false org_golang_x_tools` and copied the patches. * Fix buildtag violations and ignore buildtag violations in external * Introduce modernize analyzer package. * Add modernize "any" analyzer. * Fix violations of any analyzer * Add modernize "appendclipped" analyzer. * Fix violations of appendclipped * Add modernize "bloop" analyzer. * Add modernize "fmtappendf" analyzer. * Add modernize "forvar" analyzer. * Add modernize "mapsloop" analyzer. * Add modernize "minmax" analyzer. * Fix violations of minmax analyzer * Add modernize "omitzero" analyzer. * Add modernize "rangeint" analyzer. * Fix violations of rangeint. * Add modernize "reflecttypefor" analyzer. * Fix violations of reflecttypefor analyzer. * Add modernize "slicescontains" analyzer. * Add modernize "slicessort" analyzer. * Add modernize "slicesdelete" analyzer. This is disabled by default for now. See https://go.dev/issue/73686. * Add modernize "stringscutprefix" analyzer. * Add modernize "stringsbuilder" analyzer. * Fix violations of stringsbuilder analyzer. * Add modernize "stringsseq" analyzer. * Add modernize "testingcontext" analyzer. * Add modernize "waitgroup" analyzer. * Changelog fragment * gofmt * gazelle * Add modernize "newexpr" analyzer. * Disable newexpr until go1.26 * Add more details in WORKSPACE on how to update the override * @nalepae feedback on min() * gofmt * Fix violations of forvar
285 lines
7.2 KiB
Go
285 lines
7.2 KiB
Go
// Package testing provides useful mocks for an eth1 powchain
|
|
// service as needed by unit tests for the beacon node.
|
|
package testing
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"math/big"
|
|
"net/http/httptest"
|
|
"time"
|
|
|
|
"github.com/OffchainLabs/prysm/v7/async/event"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/execution/types"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
|
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
|
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/ethclient/simulated"
|
|
"github.com/ethereum/go-ethereum/rpc"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// Chain defines a properly functioning mock for the powchain service.
|
|
type Chain struct {
|
|
ChainFeed *event.Feed
|
|
LatestBlockNumber *big.Int
|
|
HashesByHeight map[int][]byte
|
|
TimesByHeight map[int]uint64
|
|
BlockNumberByTime map[uint64]*big.Int
|
|
Eth1Data *ethpb.Eth1Data
|
|
GenesisEth1Block *big.Int
|
|
GenesisState state.BeaconState
|
|
CurrEndpoint string
|
|
CurrError error
|
|
Endpoints []string
|
|
Errors []error
|
|
}
|
|
|
|
// GenesisTime represents a static past date - JAN 01 2000.
|
|
var GenesisTime = time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC).Unix()
|
|
|
|
// New creates a new mock chain with empty block info.
|
|
func New() *Chain {
|
|
return &Chain{
|
|
HashesByHeight: make(map[int][]byte),
|
|
TimesByHeight: make(map[int]uint64),
|
|
BlockNumberByTime: make(map[uint64]*big.Int),
|
|
}
|
|
}
|
|
|
|
// GenesisExecutionChainInfo --
|
|
func (m *Chain) GenesisExecutionChainInfo() (uint64, *big.Int) {
|
|
blk := m.GenesisEth1Block
|
|
if blk == nil {
|
|
blk = big.NewInt(GenesisTime)
|
|
}
|
|
return uint64(GenesisTime), blk
|
|
}
|
|
|
|
// BlockExists --
|
|
func (m *Chain) BlockExists(_ context.Context, hash common.Hash) (bool, *big.Int, error) {
|
|
// Reverse the map of heights by hash.
|
|
heightsByHash := make(map[[32]byte]int, len(m.HashesByHeight))
|
|
for k, v := range m.HashesByHeight {
|
|
h := bytesutil.ToBytes32(v)
|
|
heightsByHash[h] = k
|
|
}
|
|
val, ok := heightsByHash[hash]
|
|
if !ok {
|
|
return false, nil, fmt.Errorf("could not fetch height for hash: %#x", hash)
|
|
}
|
|
return true, big.NewInt(int64(val)), nil
|
|
}
|
|
|
|
// BlockHashByHeight --
|
|
func (m *Chain) BlockHashByHeight(_ context.Context, height *big.Int) (common.Hash, error) {
|
|
k := int(height.Int64())
|
|
val, ok := m.HashesByHeight[k]
|
|
if !ok {
|
|
return [32]byte{}, fmt.Errorf("could not fetch hash for height: %v", height)
|
|
}
|
|
return bytesutil.ToBytes32(val), nil
|
|
}
|
|
|
|
// BlockTimeByHeight --
|
|
func (m *Chain) BlockTimeByHeight(_ context.Context, height *big.Int) (uint64, error) {
|
|
h := int(height.Int64())
|
|
return m.TimesByHeight[h], nil
|
|
}
|
|
|
|
// BlockByTimestamp --
|
|
func (m *Chain) BlockByTimestamp(_ context.Context, time uint64) (*types.HeaderInfo, error) {
|
|
var chosenTime uint64
|
|
var chosenNumber *big.Int
|
|
for t, num := range m.BlockNumberByTime {
|
|
if t > chosenTime && t <= time {
|
|
chosenNumber = num
|
|
chosenTime = t
|
|
}
|
|
}
|
|
return &types.HeaderInfo{Number: chosenNumber, Time: chosenTime}, nil
|
|
}
|
|
|
|
// ChainStartEth1Data --
|
|
func (m *Chain) ChainStartEth1Data() *ethpb.Eth1Data {
|
|
return m.Eth1Data
|
|
}
|
|
|
|
// PreGenesisState --
|
|
func (m *Chain) PreGenesisState() state.BeaconState {
|
|
return m.GenesisState
|
|
}
|
|
|
|
// ClearPreGenesisData --
|
|
func (*Chain) ClearPreGenesisData() {
|
|
// no-op
|
|
}
|
|
|
|
func (*Chain) ExecutionClientConnected() bool {
|
|
return true
|
|
}
|
|
|
|
func (m *Chain) ExecutionClientEndpoint() string {
|
|
return m.CurrEndpoint
|
|
}
|
|
|
|
func (m *Chain) ExecutionClientConnectionErr() error {
|
|
return m.CurrError
|
|
}
|
|
|
|
func (m *Chain) ETH1Endpoints() []string {
|
|
return m.Endpoints
|
|
}
|
|
|
|
func (m *Chain) ETH1ConnectionErrors() []error {
|
|
return m.Errors
|
|
}
|
|
|
|
// RPCClient defines the mock rpc client.
|
|
type RPCClient struct {
|
|
Backend *simulated.Backend
|
|
BlockNumMap map[uint64]*types.HeaderInfo
|
|
}
|
|
|
|
func (*RPCClient) Close() {}
|
|
|
|
func (r *RPCClient) CallContext(ctx context.Context, obj any, methodName string, args ...any) error {
|
|
if r.BlockNumMap != nil && methodName == "eth_getBlockByNumber" {
|
|
val, ok := args[0].(string)
|
|
if !ok {
|
|
return errors.Errorf("wrong argument type provided: %T", args[0])
|
|
}
|
|
num, err := hexutil.DecodeBig(val)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
b := r.BlockNumMap[num.Uint64()]
|
|
assertedObj, ok := obj.(**types.HeaderInfo)
|
|
if !ok {
|
|
return errors.Errorf("wrong argument type provided: %T", obj)
|
|
}
|
|
*assertedObj = b
|
|
return nil
|
|
}
|
|
if r.Backend == nil && methodName == "eth_getBlockByNumber" {
|
|
h := &gethTypes.Header{
|
|
Number: big.NewInt(15),
|
|
Time: 150,
|
|
}
|
|
assertedObj, ok := obj.(**types.HeaderInfo)
|
|
if !ok {
|
|
return errors.Errorf("wrong argument type provided: %T", obj)
|
|
}
|
|
*assertedObj = &types.HeaderInfo{
|
|
Hash: h.Hash(),
|
|
Number: h.Number,
|
|
Time: h.Time,
|
|
}
|
|
return nil
|
|
}
|
|
switch methodName {
|
|
case "eth_getBlockByNumber":
|
|
val, ok := args[0].(string)
|
|
if !ok {
|
|
return errors.Errorf("wrong argument type provided: %T", args[0])
|
|
}
|
|
var num *big.Int
|
|
var err error
|
|
if val != "latest" {
|
|
num, err = hexutil.DecodeBig(val)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
h, err := r.Backend.Client().HeaderByNumber(ctx, num)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
assertedObj, ok := obj.(**types.HeaderInfo)
|
|
if !ok {
|
|
return errors.Errorf("wrong argument type provided: %T", obj)
|
|
}
|
|
*assertedObj = &types.HeaderInfo{
|
|
Hash: h.Hash(),
|
|
Number: h.Number,
|
|
Time: h.Time,
|
|
}
|
|
case "eth_getBlockByHash":
|
|
val, ok := args[0].(common.Hash)
|
|
if !ok {
|
|
return errors.Errorf("wrong argument type provided: %T", args[0])
|
|
}
|
|
h, err := r.Backend.Client().HeaderByHash(ctx, val)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
assertedObj, ok := obj.(**types.HeaderInfo)
|
|
if !ok {
|
|
return errors.Errorf("wrong argument type provided: %T", obj)
|
|
}
|
|
*assertedObj = &types.HeaderInfo{
|
|
Hash: h.Hash(),
|
|
Number: h.Number,
|
|
Time: h.Time,
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// BatchCall --
|
|
func (r *RPCClient) BatchCall(b []rpc.BatchElem) error {
|
|
if r.Backend == nil {
|
|
return nil
|
|
}
|
|
|
|
for _, e := range b {
|
|
num, err := hexutil.DecodeBig(e.Args[0].(string))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
h, err := r.Backend.Client().HeaderByNumber(context.Background(), num)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e.Result.(*types.HeaderInfo) = types.HeaderInfo{Number: h.Number, Time: h.Time, Hash: h.Hash()}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// InsertBlock adds provided block info into the chain.
|
|
func (m *Chain) InsertBlock(height int, time uint64, hash []byte) *Chain {
|
|
m.HashesByHeight[height] = hash
|
|
m.TimesByHeight[height] = time
|
|
m.BlockNumberByTime[time] = big.NewInt(int64(height))
|
|
return m
|
|
}
|
|
|
|
func SetupRPCServer() (*rpc.Server, string, error) {
|
|
srv := rpc.NewServer()
|
|
if err := srv.RegisterName("eth", &testETHRPC{}); err != nil {
|
|
return nil, "", err
|
|
}
|
|
if err := srv.RegisterName("net", &testETHRPC{}); err != nil {
|
|
return nil, "", err
|
|
}
|
|
hs := httptest.NewUnstartedServer(srv)
|
|
hs.Start()
|
|
return srv, hs.URL, nil
|
|
}
|
|
|
|
type testETHRPC struct{}
|
|
|
|
func (*testETHRPC) NoArgsRets() {}
|
|
|
|
func (*testETHRPC) ChainId(_ context.Context) *hexutil.Big {
|
|
return (*hexutil.Big)(big.NewInt(int64(params.BeaconConfig().DepositChainID)))
|
|
}
|
|
|
|
func (*testETHRPC) Version(_ context.Context) string {
|
|
return fmt.Sprintf("%d", params.BeaconConfig().DepositNetworkID)
|
|
}
|