mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 21:08:10 -05:00
Remove Geth Bindings From Prysm (#11586)
* check in changes * gaz * preston's review * comment * fix up * remove test * gaz * preston's review * fix it
This commit is contained in:
@@ -129,7 +129,6 @@ go_test(
|
||||
"@com_github_ethereum_go_ethereum//core/beacon:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//trie:go_default_library",
|
||||
"@com_github_holiman_uint256//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/types"
|
||||
@@ -133,14 +132,11 @@ func (c *headerCache) HeaderInfoByHeight(height *big.Int) (bool, *types.HeaderIn
|
||||
// size limit. This method should be called in sequential header number order if
|
||||
// the desired behavior is that the blocks with the highest header number should
|
||||
// be present in the cache.
|
||||
func (c *headerCache) AddHeader(hdr *gethTypes.Header) error {
|
||||
func (c *headerCache) AddHeader(hdr *types.HeaderInfo) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
hInfo, err := types.HeaderToHeaderInfo(hdr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hInfo := hdr.Copy()
|
||||
|
||||
if err := c.hashCache.AddIfNotPresent(hInfo); err != nil {
|
||||
return err
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/types"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
)
|
||||
@@ -44,34 +44,30 @@ func TestHeightKeyFn_InvalidObj(t *testing.T) {
|
||||
func TestBlockCache_byHash(t *testing.T) {
|
||||
cache := newHeaderCache()
|
||||
|
||||
header := &gethTypes.Header{
|
||||
ParentHash: common.HexToHash("0x12345"),
|
||||
Number: big.NewInt(55),
|
||||
header := &types.HeaderInfo{
|
||||
Number: big.NewInt(55),
|
||||
}
|
||||
|
||||
exists, _, err := cache.HeaderInfoByHash(header.Hash())
|
||||
exists, _, err := cache.HeaderInfoByHash(header.Hash)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, exists, "Expected block info not to exist in empty cache")
|
||||
|
||||
err = cache.AddHeader(header)
|
||||
require.NoError(t, err)
|
||||
|
||||
exists, fetchedInfo, err := cache.HeaderInfoByHash(header.Hash())
|
||||
exists, fetchedInfo, err := cache.HeaderInfoByHash(header.Hash)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, exists, "Expected headerInfo to exist")
|
||||
assert.Equal(t, 0, fetchedInfo.Number.Cmp(header.Number), "Expected fetched info number to be equal")
|
||||
assert.Equal(t, header.Hash(), fetchedInfo.Hash, "Expected hash to be equal")
|
||||
assert.Equal(t, header.Hash, fetchedInfo.Hash, "Expected hash to be equal")
|
||||
|
||||
}
|
||||
|
||||
func TestBlockCache_byHeight(t *testing.T) {
|
||||
cache := newHeaderCache()
|
||||
|
||||
header := &gethTypes.Header{
|
||||
ParentHash: common.HexToHash("0x12345"),
|
||||
Number: big.NewInt(55),
|
||||
header := &types.HeaderInfo{
|
||||
Number: big.NewInt(55),
|
||||
}
|
||||
|
||||
exists, _, err := cache.HeaderInfoByHeight(header.Number)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, exists, "Expected block info not to exist in empty cache")
|
||||
@@ -84,7 +80,7 @@ func TestBlockCache_byHeight(t *testing.T) {
|
||||
assert.Equal(t, true, exists, "Expected headerInfo to exist")
|
||||
|
||||
assert.Equal(t, 0, fetchedInfo.Number.Cmp(header.Number), "Expected fetched info number to be equal")
|
||||
assert.Equal(t, header.Hash(), fetchedInfo.Hash, "Expected hash to be equal")
|
||||
assert.Equal(t, header.Hash, fetchedInfo.Hash, "Expected hash to be equal")
|
||||
|
||||
}
|
||||
|
||||
@@ -92,8 +88,9 @@ func TestBlockCache_maxSize(t *testing.T) {
|
||||
cache := newHeaderCache()
|
||||
|
||||
for i := int64(0); i < int64(maxCacheSize+10); i++ {
|
||||
header := &gethTypes.Header{
|
||||
header := &types.HeaderInfo{
|
||||
Number: big.NewInt(i),
|
||||
Hash: common.Hash(bytesutil.ToBytes32(bytesutil.Bytes32(uint64(i)))),
|
||||
}
|
||||
err := cache.AddHeader(header)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -35,7 +35,7 @@ func (s *Service) BlockExists(ctx context.Context, hash common.Hash) (bool, *big
|
||||
return true, hdrInfo.Number, nil
|
||||
}
|
||||
span.AddAttributes(trace.BoolAttribute("blockCacheHit", false))
|
||||
header, err := s.eth1DataFetcher.HeaderByHash(ctx, hash)
|
||||
header, err := s.HeaderByHash(ctx, hash)
|
||||
if err != nil {
|
||||
return false, big.NewInt(0), errors.Wrap(err, "could not query block with given hash")
|
||||
}
|
||||
@@ -61,33 +61,33 @@ func (s *Service) BlockHashByHeight(ctx context.Context, height *big.Int) (commo
|
||||
}
|
||||
span.AddAttributes(trace.BoolAttribute("headerCacheHit", false))
|
||||
|
||||
if s.eth1DataFetcher == nil {
|
||||
err := errors.New("nil eth1DataFetcher")
|
||||
if s.rpcClient == nil {
|
||||
err := errors.New("nil rpc client")
|
||||
tracing.AnnotateError(span, err)
|
||||
return [32]byte{}, err
|
||||
}
|
||||
|
||||
header, err := s.eth1DataFetcher.HeaderByNumber(ctx, height)
|
||||
header, err := s.HeaderByNumber(ctx, height)
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, fmt.Sprintf("could not query header with height %d", height.Uint64()))
|
||||
}
|
||||
if err := s.headerCache.AddHeader(header); err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
return header.Hash(), nil
|
||||
return header.Hash, nil
|
||||
}
|
||||
|
||||
// BlockTimeByHeight fetches an eth1 block timestamp by its height.
|
||||
func (s *Service) BlockTimeByHeight(ctx context.Context, height *big.Int) (uint64, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "powchain.BlockTimeByHeight")
|
||||
defer span.End()
|
||||
if s.eth1DataFetcher == nil {
|
||||
err := errors.New("nil eth1DataFetcher")
|
||||
if s.rpcClient == nil {
|
||||
err := errors.New("nil rpc client")
|
||||
tracing.AnnotateError(span, err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
header, err := s.eth1DataFetcher.HeaderByNumber(ctx, height)
|
||||
header, err := s.HeaderByNumber(ctx, height)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, fmt.Sprintf("could not query block with height %d", height.Uint64()))
|
||||
}
|
||||
@@ -207,20 +207,17 @@ func (s *Service) retrieveHeaderInfo(ctx context.Context, bNum uint64) (*types.H
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
blk, err := s.eth1DataFetcher.HeaderByNumber(ctx, bn)
|
||||
hdr, err := s.HeaderByNumber(ctx, bn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if blk == nil {
|
||||
if hdr == nil {
|
||||
return nil, errors.Errorf("header with the number %d does not exist", bNum)
|
||||
}
|
||||
if err := s.headerCache.AddHeader(blk); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info, err = types.HeaderToHeaderInfo(blk)
|
||||
if err != nil {
|
||||
if err := s.headerCache.AddHeader(hdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info = hdr
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"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/trie"
|
||||
dbutil "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
mockExecution "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/testing"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/types"
|
||||
contracts "github.com/prysmaticlabs/prysm/v3/contracts/deposit"
|
||||
"github.com/prysmaticlabs/prysm/v3/contracts/deposit/mock"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
)
|
||||
|
||||
func setDefaultMocks(service *Service) *Service {
|
||||
service.eth1DataFetcher = &goodFetcher{}
|
||||
service.httpLogger = &goodLogger{}
|
||||
service.cfg.stateNotifier = &goodNotifier{}
|
||||
return service
|
||||
@@ -44,7 +43,6 @@ func TestLatestMainchainInfo_OK(t *testing.T) {
|
||||
|
||||
web3Service = setDefaultMocks(web3Service)
|
||||
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
|
||||
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
|
||||
|
||||
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
|
||||
require.NoError(t, err)
|
||||
@@ -57,7 +55,7 @@ func TestLatestMainchainInfo_OK(t *testing.T) {
|
||||
<-exitRoutine
|
||||
}()
|
||||
|
||||
header, err := web3Service.eth1DataFetcher.HeaderByNumber(web3Service.ctx, nil)
|
||||
header, err := web3Service.HeaderByNumber(web3Service.ctx, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
tickerChan := make(chan time.Time)
|
||||
@@ -67,7 +65,7 @@ func TestLatestMainchainInfo_OK(t *testing.T) {
|
||||
exitRoutine <- true
|
||||
|
||||
assert.Equal(t, web3Service.latestEth1Data.BlockHeight, header.Number.Uint64())
|
||||
assert.Equal(t, hexutil.Encode(web3Service.latestEth1Data.BlockHash), header.Hash().Hex())
|
||||
assert.Equal(t, hexutil.Encode(web3Service.latestEth1Data.BlockHash), header.Hash.Hex())
|
||||
assert.Equal(t, web3Service.latestEth1Data.BlockTime, header.Time)
|
||||
}
|
||||
|
||||
@@ -85,6 +83,7 @@ func TestBlockHashByHeight_ReturnsHash(t *testing.T) {
|
||||
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
|
||||
|
||||
web3Service = setDefaultMocks(web3Service)
|
||||
web3Service.rpcClient = &mockExecution.RPCClient{}
|
||||
ctx := context.Background()
|
||||
|
||||
header := &gethTypes.Header{
|
||||
@@ -117,15 +116,17 @@ func TestBlockHashByHeight_ReturnsError_WhenNoEth1Client(t *testing.T) {
|
||||
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
|
||||
|
||||
web3Service = setDefaultMocks(web3Service)
|
||||
web3Service.eth1DataFetcher = nil
|
||||
web3Service.rpcClient = nil
|
||||
ctx := context.Background()
|
||||
|
||||
_, err = web3Service.BlockHashByHeight(ctx, big.NewInt(0))
|
||||
require.ErrorContains(t, "nil eth1DataFetcher", err)
|
||||
require.ErrorContains(t, "nil rpc client", err)
|
||||
}
|
||||
|
||||
func TestBlockExists_ValidHash(t *testing.T) {
|
||||
beaconDB := dbutil.SetupDB(t)
|
||||
testAcc, err := mock.Setup()
|
||||
require.NoError(t, err, "Unable to set up simulated backend")
|
||||
server, endpoint, err := mockExecution.SetupRPCServer()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
@@ -138,16 +139,10 @@ func TestBlockExists_ValidHash(t *testing.T) {
|
||||
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
|
||||
|
||||
web3Service = setDefaultMocks(web3Service)
|
||||
|
||||
block := gethTypes.NewBlock(
|
||||
&gethTypes.Header{
|
||||
Number: big.NewInt(0),
|
||||
},
|
||||
[]*gethTypes.Transaction{},
|
||||
[]*gethTypes.Header{},
|
||||
[]*gethTypes.Receipt{},
|
||||
new(trie.Trie),
|
||||
)
|
||||
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
|
||||
testAcc.Backend.Commit()
|
||||
block, err := testAcc.Backend.BlockByNumber(context.Background(), big.NewInt(0))
|
||||
assert.NoError(t, err)
|
||||
|
||||
exists, height, err := web3Service.BlockExists(context.Background(), block.Hash())
|
||||
require.NoError(t, err, "Could not get block hash with given height")
|
||||
@@ -191,17 +186,15 @@ func TestBlockExists_UsesCachedBlockInfo(t *testing.T) {
|
||||
WithDatabase(beaconDB),
|
||||
)
|
||||
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
|
||||
// nil eth1DataFetcher would panic if cached value not used
|
||||
web3Service.eth1DataFetcher = nil
|
||||
|
||||
header := &gethTypes.Header{
|
||||
header := &types.HeaderInfo{
|
||||
Number: big.NewInt(0),
|
||||
}
|
||||
|
||||
err = web3Service.headerCache.AddHeader(header)
|
||||
require.NoError(t, err)
|
||||
|
||||
exists, height, err := web3Service.BlockExists(context.Background(), header.Hash())
|
||||
exists, height, err := web3Service.BlockExists(context.Background(), header.Hash)
|
||||
require.NoError(t, err, "Could not get block hash with given height")
|
||||
require.Equal(t, true, exists)
|
||||
require.Equal(t, 0, height.Cmp(header.Number))
|
||||
@@ -222,7 +215,7 @@ func TestService_BlockNumberByTimestamp(t *testing.T) {
|
||||
)
|
||||
require.NoError(t, err)
|
||||
web3Service = setDefaultMocks(web3Service)
|
||||
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
|
||||
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
|
||||
|
||||
for i := 0; i < 200; i++ {
|
||||
testAcc.Backend.Commit()
|
||||
@@ -254,7 +247,7 @@ func TestService_BlockNumberByTimestampLessTargetTime(t *testing.T) {
|
||||
)
|
||||
require.NoError(t, err)
|
||||
web3Service = setDefaultMocks(web3Service)
|
||||
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
|
||||
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
|
||||
|
||||
for i := 0; i < 200; i++ {
|
||||
testAcc.Backend.Commit()
|
||||
@@ -292,7 +285,7 @@ func TestService_BlockNumberByTimestampMoreTargetTime(t *testing.T) {
|
||||
)
|
||||
require.NoError(t, err)
|
||||
web3Service = setDefaultMocks(web3Service)
|
||||
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
|
||||
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
|
||||
|
||||
for i := 0; i < 200; i++ {
|
||||
testAcc.Backend.Commit()
|
||||
@@ -329,9 +322,9 @@ func TestService_BlockTimeByHeight_ReturnsError_WhenNoEth1Client(t *testing.T) {
|
||||
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
|
||||
|
||||
web3Service = setDefaultMocks(web3Service)
|
||||
web3Service.eth1DataFetcher = nil
|
||||
web3Service.rpcClient = nil
|
||||
ctx := context.Background()
|
||||
|
||||
_, err = web3Service.BlockTimeByHeight(ctx, big.NewInt(0))
|
||||
require.ErrorContains(t, "nil eth1DataFetcher", err)
|
||||
require.ErrorContains(t, "nil rpc client", err)
|
||||
}
|
||||
|
||||
@@ -8,11 +8,13 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
gethRPC "github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/types"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
@@ -354,6 +356,26 @@ func (s *Service) ExecutionBlocksByHashes(ctx context.Context, hashes []common.H
|
||||
return execBlks, nil
|
||||
}
|
||||
|
||||
// HeaderByHash returns the relevant header details for the provided block hash.
|
||||
func (s *Service) HeaderByHash(ctx context.Context, hash common.Hash) (*types.HeaderInfo, error) {
|
||||
var hdr *types.HeaderInfo
|
||||
err := s.rpcClient.CallContext(ctx, &hdr, ExecutionBlockByHashMethod, hash, false /* no transactions */)
|
||||
if err == nil && hdr == nil {
|
||||
err = ethereum.NotFound
|
||||
}
|
||||
return hdr, err
|
||||
}
|
||||
|
||||
// HeaderByNumber returns the relevant header details for the provided block number.
|
||||
func (s *Service) HeaderByNumber(ctx context.Context, number *big.Int) (*types.HeaderInfo, error) {
|
||||
var hdr *types.HeaderInfo
|
||||
err := s.rpcClient.CallContext(ctx, &hdr, ExecutionBlockByNumberMethod, toBlockNumArg(number), false /* no transactions */)
|
||||
if err == nil && hdr == nil {
|
||||
err = ethereum.NotFound
|
||||
}
|
||||
return hdr, err
|
||||
}
|
||||
|
||||
// ReconstructFullBellatrixBlock takes in a blinded beacon block and reconstructs
|
||||
// a beacon block with a full execution payload via the engine API.
|
||||
func (s *Service) ReconstructFullBellatrixBlock(
|
||||
@@ -610,3 +632,22 @@ func buildEmptyExecutionPayload() *pb.ExecutionPayload {
|
||||
ExtraData: make([]byte, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func toBlockNumArg(number *big.Int) string {
|
||||
if number == nil {
|
||||
return "latest"
|
||||
}
|
||||
pending := big.NewInt(-1)
|
||||
if number.Cmp(pending) == 0 {
|
||||
return "pending"
|
||||
}
|
||||
finalized := big.NewInt(int64(gethRPC.FinalizedBlockNumber))
|
||||
if number.Cmp(finalized) == 0 {
|
||||
return "finalized"
|
||||
}
|
||||
safe := big.NewInt(int64(gethRPC.SafeBlockNumber))
|
||||
if number.Cmp(safe) == 0 {
|
||||
return "safe"
|
||||
}
|
||||
return hexutil.EncodeBig(number)
|
||||
}
|
||||
|
||||
@@ -11,10 +11,12 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"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/rpc"
|
||||
gethRPC "github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/pkg/errors"
|
||||
mocks "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/testing"
|
||||
@@ -24,6 +26,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/util"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -36,6 +39,18 @@ var (
|
||||
_ = EngineCaller(&mocks.EngineClient{})
|
||||
)
|
||||
|
||||
type RPCClientBad struct {
|
||||
}
|
||||
|
||||
func (RPCClientBad) Close() {}
|
||||
func (RPCClientBad) BatchCall([]gethRPC.BatchElem) error {
|
||||
return errors.New("rpc client is not initialized")
|
||||
}
|
||||
|
||||
func (RPCClientBad) CallContext(context.Context, interface{}, string, ...interface{}) error {
|
||||
return ethereum.NotFound
|
||||
}
|
||||
|
||||
func TestClient_IPC(t *testing.T) {
|
||||
server := newTestIPCServer(t)
|
||||
defer server.Stop()
|
||||
@@ -1215,6 +1230,78 @@ func Test_fullPayloadFromExecutionBlock(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeaderByHash_NotFound(t *testing.T) {
|
||||
srv := &Service{}
|
||||
srv.rpcClient = RPCClientBad{}
|
||||
|
||||
_, err := srv.HeaderByHash(context.Background(), common.Hash([32]byte{}))
|
||||
assert.Equal(t, ethereum.NotFound, err)
|
||||
}
|
||||
|
||||
func TestHeaderByNumber_NotFound(t *testing.T) {
|
||||
srv := &Service{}
|
||||
srv.rpcClient = RPCClientBad{}
|
||||
|
||||
_, err := srv.HeaderByNumber(context.Background(), big.NewInt(100))
|
||||
assert.Equal(t, ethereum.NotFound, err)
|
||||
}
|
||||
|
||||
func TestToBlockNumArg(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
number *big.Int
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "genesis",
|
||||
number: big.NewInt(0),
|
||||
want: "0x0",
|
||||
},
|
||||
{
|
||||
name: "near genesis block",
|
||||
number: big.NewInt(300),
|
||||
want: "0x12c",
|
||||
},
|
||||
{
|
||||
name: "current block",
|
||||
number: big.NewInt(15838075),
|
||||
want: "0xf1ab7b",
|
||||
},
|
||||
{
|
||||
name: "far off block",
|
||||
number: big.NewInt(12032894823020),
|
||||
want: "0xaf1a06bea6c",
|
||||
},
|
||||
{
|
||||
name: "latest block",
|
||||
number: nil,
|
||||
want: "latest",
|
||||
},
|
||||
{
|
||||
name: "pending block",
|
||||
number: big.NewInt(-1),
|
||||
want: "pending",
|
||||
},
|
||||
{
|
||||
name: "finalized block",
|
||||
number: big.NewInt(-3),
|
||||
want: "finalized",
|
||||
},
|
||||
{
|
||||
name: "safe block",
|
||||
number: big.NewInt(-4),
|
||||
want: "safe",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := toBlockNumArg(tt.number); got != tt.want {
|
||||
t.Errorf("toBlockNumArg() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type testEngineService struct{}
|
||||
|
||||
func (*testEngineService) NoArgsRets() {}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
statefeed "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||
coreState "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/types"
|
||||
statenative "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
contracts "github.com/prysmaticlabs/prysm/v3/contracts/deposit"
|
||||
@@ -284,7 +285,7 @@ func (s *Service) processPastLogs(ctx context.Context) error {
|
||||
currentBlockNum = deploymentBlock
|
||||
}
|
||||
// To store all blocks.
|
||||
headersMap := make(map[uint64]*gethtypes.Header)
|
||||
headersMap := make(map[uint64]*types.HeaderInfo)
|
||||
rawLogCount, err := s.depositContractCaller.GetDepositCount(&bind.CallOpts{})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -341,7 +342,7 @@ func (s *Service) processPastLogs(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) processBlockInBatch(ctx context.Context, currentBlockNum uint64, latestFollowHeight uint64, batchSize uint64, additiveFactor uint64, logCount uint64, headersMap map[uint64]*gethtypes.Header) (uint64, uint64, error) {
|
||||
func (s *Service) processBlockInBatch(ctx context.Context, currentBlockNum uint64, latestFollowHeight uint64, batchSize uint64, additiveFactor uint64, logCount uint64, headersMap map[uint64]*types.HeaderInfo) (uint64, uint64, error) {
|
||||
// Batch request the desired headers and store them in a
|
||||
// map for quick access.
|
||||
requestHeaders := func(startBlk uint64, endBlk uint64) error {
|
||||
@@ -499,11 +500,11 @@ func (s *Service) processChainStartFromBlockNum(ctx context.Context, blkNum *big
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) processChainStartFromHeader(ctx context.Context, header *gethtypes.Header) {
|
||||
s.processChainStartIfReady(ctx, header.Hash(), header.Number, header.Time)
|
||||
func (s *Service) processChainStartFromHeader(ctx context.Context, header *types.HeaderInfo) {
|
||||
s.processChainStartIfReady(ctx, header.Hash, header.Number, header.Time)
|
||||
}
|
||||
|
||||
func (s *Service) checkHeaderRange(ctx context.Context, start, end uint64, headersMap map[uint64]*gethtypes.Header,
|
||||
func (s *Service) checkHeaderRange(ctx context.Context, start, end uint64, headersMap map[uint64]*types.HeaderInfo,
|
||||
requestHeaders func(uint64, uint64) error) error {
|
||||
for i := start; i <= end; i++ {
|
||||
if !s.chainStartData.Chainstarted {
|
||||
|
||||
@@ -308,6 +308,7 @@ func TestProcessETH2GenesisLog(t *testing.T) {
|
||||
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
|
||||
web3Service = setDefaultMocks(web3Service)
|
||||
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
|
||||
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
|
||||
require.NoError(t, err)
|
||||
params.SetupTestConfigCleanup(t)
|
||||
bConfig := params.MinimalSpecConfig().Copy()
|
||||
@@ -403,7 +404,6 @@ func TestProcessETH2GenesisLog_CorrectNumOfDeposits(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
|
||||
web3Service.httpLogger = testAcc.Backend
|
||||
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
|
||||
web3Service.latestEth1Data.LastRequestedBlock = 0
|
||||
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
|
||||
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
|
||||
@@ -501,7 +501,6 @@ func TestProcessETH2GenesisLog_LargePeriodOfNoLogs(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
|
||||
web3Service.httpLogger = testAcc.Backend
|
||||
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
|
||||
web3Service.latestEth1Data.LastRequestedBlock = 0
|
||||
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
|
||||
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
|
||||
@@ -613,7 +612,6 @@ func newPowchainService(t *testing.T, eth1Backend *mock.TestAccount, beaconDB db
|
||||
require.NoError(t, err)
|
||||
|
||||
web3Service.rpcClient = &mockExecution.RPCClient{Backend: eth1Backend.Backend}
|
||||
web3Service.eth1DataFetcher = &goodFetcher{backend: eth1Backend.Backend}
|
||||
web3Service.httpLogger = &goodLogger{backend: eth1Backend.Backend}
|
||||
params.SetupTestConfigCleanup(t)
|
||||
bConfig := params.MinimalSpecConfig().Copy()
|
||||
|
||||
@@ -26,7 +26,6 @@ func (s *Service) setupExecutionClientConnections(ctx context.Context, currEndpo
|
||||
fetcher := ethclient.NewClient(client)
|
||||
s.rpcClient = client
|
||||
s.httpLogger = fetcher
|
||||
s.eth1DataFetcher = fetcher
|
||||
|
||||
depositContractCaller, err := contracts.NewDepositContractCaller(s.cfg.depositContractAddr, fetcher)
|
||||
if err != nil {
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||
gethRPC "github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
@@ -97,14 +96,6 @@ type Chain interface {
|
||||
POWBlockFetcher
|
||||
}
|
||||
|
||||
// RPCDataFetcher defines a subset of methods conformed to by ETH1.0 RPC clients for
|
||||
// fetching eth1 data from the clients.
|
||||
type RPCDataFetcher interface {
|
||||
Close()
|
||||
HeaderByNumber(ctx context.Context, number *big.Int) (*gethTypes.Header, error)
|
||||
HeaderByHash(ctx context.Context, hash common.Hash) (*gethTypes.Header, error)
|
||||
}
|
||||
|
||||
// RPCClient defines the rpc methods required to interact with the eth1 node.
|
||||
type RPCClient interface {
|
||||
Close()
|
||||
@@ -154,7 +145,6 @@ type Service struct {
|
||||
cancel context.CancelFunc
|
||||
eth1HeadTicker *time.Ticker
|
||||
httpLogger bind.ContractFilterer
|
||||
eth1DataFetcher RPCDataFetcher
|
||||
rpcClient RPCClient
|
||||
headerCache *headerCache // cache to store block hash/block height.
|
||||
latestEth1Data *ethpb.LatestETH1Data
|
||||
@@ -264,9 +254,6 @@ func (s *Service) Stop() error {
|
||||
if s.rpcClient != nil {
|
||||
s.rpcClient.Close()
|
||||
}
|
||||
if s.eth1DataFetcher != nil {
|
||||
s.eth1DataFetcher.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -398,36 +385,35 @@ func (s *Service) initDepositCaches(ctx context.Context, ctrs []*ethpb.DepositCo
|
||||
|
||||
// processBlockHeader adds a newly observed eth1 block to the block cache and
|
||||
// updates the latest blockHeight, blockHash, and blockTime properties of the service.
|
||||
func (s *Service) processBlockHeader(header *gethTypes.Header) {
|
||||
func (s *Service) processBlockHeader(header *types.HeaderInfo) {
|
||||
defer safelyHandlePanic()
|
||||
blockNumberGauge.Set(float64(header.Number.Int64()))
|
||||
s.latestEth1DataLock.Lock()
|
||||
s.latestEth1Data.BlockHeight = header.Number.Uint64()
|
||||
s.latestEth1Data.BlockHash = header.Hash().Bytes()
|
||||
s.latestEth1Data.BlockHash = header.Hash.Bytes()
|
||||
s.latestEth1Data.BlockTime = header.Time
|
||||
s.latestEth1DataLock.Unlock()
|
||||
log.WithFields(logrus.Fields{
|
||||
"blockNumber": s.latestEth1Data.BlockHeight,
|
||||
"blockHash": hexutil.Encode(s.latestEth1Data.BlockHash),
|
||||
"difficulty": header.Difficulty.String(),
|
||||
}).Debug("Latest eth1 chain event")
|
||||
}
|
||||
|
||||
// batchRequestHeaders requests the block range specified in the arguments. Instead of requesting
|
||||
// each block in one call, it batches all requests into a single rpc call.
|
||||
func (s *Service) batchRequestHeaders(startBlock, endBlock uint64) ([]*gethTypes.Header, error) {
|
||||
func (s *Service) batchRequestHeaders(startBlock, endBlock uint64) ([]*types.HeaderInfo, error) {
|
||||
if startBlock > endBlock {
|
||||
return nil, fmt.Errorf("start block height %d cannot be > end block height %d", startBlock, endBlock)
|
||||
}
|
||||
requestRange := (endBlock - startBlock) + 1
|
||||
elems := make([]gethRPC.BatchElem, 0, requestRange)
|
||||
headers := make([]*gethTypes.Header, 0, requestRange)
|
||||
headers := make([]*types.HeaderInfo, 0, requestRange)
|
||||
errs := make([]error, 0, requestRange)
|
||||
if requestRange == 0 {
|
||||
return headers, nil
|
||||
}
|
||||
for i := startBlock; i <= endBlock; i++ {
|
||||
header := &gethTypes.Header{}
|
||||
header := &types.HeaderInfo{}
|
||||
err := error(nil)
|
||||
elems = append(elems, gethRPC.BatchElem{
|
||||
Method: "eth_getBlockByNumber",
|
||||
@@ -523,7 +509,7 @@ func (s *Service) initPOWService() {
|
||||
return
|
||||
default:
|
||||
ctx := s.ctx
|
||||
header, err := s.eth1DataFetcher.HeaderByNumber(ctx, nil)
|
||||
header, err := s.HeaderByNumber(ctx, nil)
|
||||
if err != nil {
|
||||
s.retryExecutionClientConnection(ctx, err)
|
||||
errorLogger(err, "Unable to retrieve latest execution client header")
|
||||
@@ -532,7 +518,7 @@ func (s *Service) initPOWService() {
|
||||
|
||||
s.latestEth1DataLock.Lock()
|
||||
s.latestEth1Data.BlockHeight = header.Number.Uint64()
|
||||
s.latestEth1Data.BlockHash = header.Hash().Bytes()
|
||||
s.latestEth1Data.BlockHash = header.Hash.Bytes()
|
||||
s.latestEth1Data.BlockTime = header.Time
|
||||
s.latestEth1DataLock.Unlock()
|
||||
|
||||
@@ -562,7 +548,7 @@ func (s *Service) initPOWService() {
|
||||
// In the event our provided chainstart data references a non-existent block hash,
|
||||
// we assume the genesis block to be 0.
|
||||
if genHash != [32]byte{} {
|
||||
genHeader, err := s.eth1DataFetcher.HeaderByHash(ctx, genHash)
|
||||
genHeader, err := s.HeaderByHash(ctx, genHash)
|
||||
if err != nil {
|
||||
s.retryExecutionClientConnection(ctx, err)
|
||||
errorLogger(err, "Unable to retrieve proof-of-stake genesis block data")
|
||||
@@ -601,7 +587,7 @@ func (s *Service) run(done <-chan struct{}) {
|
||||
log.Debug("Context closed, exiting goroutine")
|
||||
return
|
||||
case <-s.eth1HeadTicker.C:
|
||||
head, err := s.eth1DataFetcher.HeaderByNumber(s.ctx, nil)
|
||||
head, err := s.HeaderByNumber(s.ctx, nil)
|
||||
if err != nil {
|
||||
s.pollConnectionStatus(s.ctx)
|
||||
log.WithError(err).Debug("Could not fetch latest eth1 header")
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package execution
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -20,6 +18,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/cache/depositcache"
|
||||
dbutil "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
mockExecution "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/testing"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/types"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
@@ -80,56 +79,6 @@ func (g *goodNotifier) StateFeed() *event.Feed {
|
||||
return g.MockStateFeed
|
||||
}
|
||||
|
||||
type goodFetcher struct {
|
||||
backend *backends.SimulatedBackend
|
||||
blockNumMap map[uint64]*gethTypes.Header
|
||||
}
|
||||
|
||||
func (_ *goodFetcher) Close() {}
|
||||
|
||||
func (g *goodFetcher) HeaderByHash(_ context.Context, hash common.Hash) (*gethTypes.Header, error) {
|
||||
if bytes.Equal(hash.Bytes(), common.BytesToHash([]byte{0}).Bytes()) {
|
||||
return nil, fmt.Errorf("expected block hash to be nonzero %v", hash)
|
||||
}
|
||||
if g.backend == nil {
|
||||
return &gethTypes.Header{
|
||||
Number: big.NewInt(0),
|
||||
}, nil
|
||||
}
|
||||
header := g.backend.Blockchain().GetHeaderByHash(hash)
|
||||
if header == nil {
|
||||
return nil, errors.New("nil header returned")
|
||||
}
|
||||
return header, nil
|
||||
|
||||
}
|
||||
|
||||
func (g *goodFetcher) HeaderByNumber(_ context.Context, number *big.Int) (*gethTypes.Header, error) {
|
||||
if g.backend == nil && g.blockNumMap == nil {
|
||||
return &gethTypes.Header{
|
||||
Number: big.NewInt(15),
|
||||
Time: 150,
|
||||
}, nil
|
||||
}
|
||||
if g.blockNumMap != nil {
|
||||
return g.blockNumMap[number.Uint64()], nil
|
||||
}
|
||||
var header *gethTypes.Header
|
||||
if number == nil {
|
||||
header = g.backend.Blockchain().CurrentHeader()
|
||||
} else {
|
||||
header = g.backend.Blockchain().GetHeaderByNumber(number.Uint64())
|
||||
}
|
||||
if header == nil {
|
||||
return nil, errors.New("nil header returned")
|
||||
}
|
||||
return header, nil
|
||||
}
|
||||
|
||||
func (_ *goodFetcher) SyncProgress(_ context.Context) (*ethereum.SyncProgress, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var depositsReqForChainStart = 64
|
||||
|
||||
func TestStart_OK(t *testing.T) {
|
||||
@@ -229,7 +178,6 @@ func TestService_Eth1Synced(t *testing.T) {
|
||||
web3Service = setDefaultMocks(web3Service)
|
||||
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
|
||||
require.NoError(t, err)
|
||||
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
|
||||
|
||||
currTime := testAcc.Backend.Blockchain().CurrentHeader().Time
|
||||
now := time.Now()
|
||||
@@ -261,7 +209,7 @@ func TestFollowBlock_OK(t *testing.T) {
|
||||
params.OverrideBeaconConfig(conf)
|
||||
|
||||
web3Service = setDefaultMocks(web3Service)
|
||||
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
|
||||
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
|
||||
baseHeight := testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
|
||||
// process follow_distance blocks
|
||||
for i := 0; i < int(params.BeaconConfig().Eth1FollowDistance); i++ {
|
||||
@@ -330,7 +278,7 @@ func TestHandlePanic_OK(t *testing.T) {
|
||||
)
|
||||
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
|
||||
// nil eth1DataFetcher would panic if cached value not used
|
||||
web3Service.eth1DataFetcher = nil
|
||||
web3Service.rpcClient = nil
|
||||
web3Service.processBlockHeader(nil)
|
||||
require.LogsContain(t, hook, "Panicked when handling data from ETH 1.0 Chain!")
|
||||
}
|
||||
@@ -371,7 +319,6 @@ func TestLogTillGenesis_OK(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
|
||||
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
|
||||
web3Service.httpLogger = testAcc.Backend
|
||||
for i := 0; i < 30; i++ {
|
||||
testAcc.Backend.Commit()
|
||||
@@ -506,7 +453,6 @@ func TestNewService_EarliestVotingBlock(t *testing.T) {
|
||||
WithDatabase(beaconDB),
|
||||
)
|
||||
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
|
||||
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
|
||||
// simulated backend sets eth1 block
|
||||
// time as 10 seconds
|
||||
params.SetupTestConfigCleanup(t)
|
||||
@@ -800,18 +746,23 @@ func TestService_CacheBlockHeaders(t *testing.T) {
|
||||
func TestService_FollowBlock(t *testing.T) {
|
||||
followTime := params.BeaconConfig().Eth1FollowDistance * params.BeaconConfig().SecondsPerETH1Block
|
||||
followTime += 10000
|
||||
bMap := make(map[uint64]*gethTypes.Header)
|
||||
bMap := make(map[uint64]*types.HeaderInfo)
|
||||
for i := uint64(3000); i > 0; i-- {
|
||||
bMap[i] = &gethTypes.Header{
|
||||
h := &gethTypes.Header{
|
||||
Number: big.NewInt(int64(i)),
|
||||
Time: followTime + (i * 40),
|
||||
}
|
||||
bMap[i] = &types.HeaderInfo{
|
||||
Number: h.Number,
|
||||
Hash: h.Hash(),
|
||||
Time: h.Time,
|
||||
}
|
||||
}
|
||||
s := &Service{
|
||||
cfg: &config{eth1HeaderReqLimit: 1000},
|
||||
eth1DataFetcher: &goodFetcher{blockNumMap: bMap},
|
||||
headerCache: newHeaderCache(),
|
||||
latestEth1Data: ðpb.LatestETH1Data{BlockTime: (3000 * 40) + followTime, BlockHeight: 3000},
|
||||
cfg: &config{eth1HeaderReqLimit: 1000},
|
||||
rpcClient: &mockExecution.RPCClient{BlockNumMap: bMap},
|
||||
headerCache: newHeaderCache(),
|
||||
latestEth1Data: ðpb.LatestETH1Data{BlockTime: (3000 * 40) + followTime, BlockHeight: 3000},
|
||||
}
|
||||
h, err := s.followedBlockHeight(context.Background())
|
||||
assert.NoError(t, err)
|
||||
@@ -839,7 +790,7 @@ func (s *slowRPCClient) BatchCall(b []rpc.BatchElem) error {
|
||||
return err
|
||||
}
|
||||
h := &gethTypes.Header{Number: num}
|
||||
*e.Result.(*gethTypes.Header) = *h
|
||||
*e.Result.(*types.HeaderInfo) = types.HeaderInfo{Number: h.Number, Hash: h.Hash()}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/async/event"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/types"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
@@ -140,12 +141,92 @@ func (m *Chain) ETH1ConnectionErrors() []error {
|
||||
|
||||
// RPCClient defines the mock rpc client.
|
||||
type RPCClient struct {
|
||||
Backend *backends.SimulatedBackend
|
||||
Backend *backends.SimulatedBackend
|
||||
BlockNumMap map[uint64]*types.HeaderInfo
|
||||
}
|
||||
|
||||
func (*RPCClient) Close() {}
|
||||
|
||||
func (*RPCClient) CallContext(_ context.Context, _ interface{}, _ string, _ ...interface{}) error {
|
||||
func (r *RPCClient) CallContext(ctx context.Context, obj interface{}, methodName string, args ...interface{}) 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.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.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
|
||||
}
|
||||
|
||||
@@ -164,7 +245,7 @@ func (r *RPCClient) BatchCall(b []rpc.BatchElem) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*e.Result.(*gethTypes.Header) = *h
|
||||
*e.Result.(*types.HeaderInfo) = types.HeaderInfo{Number: h.Number, Time: h.Time, Hash: h.Hash()}
|
||||
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -8,7 +8,7 @@ go_library(
|
||||
deps = [
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@ go_test(
|
||||
srcs = ["eth1_types_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//testing/assert:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,33 +1,20 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
)
|
||||
|
||||
// HeaderInfo specifies the block header information in the ETH 1.0 chain.
|
||||
type HeaderInfo struct {
|
||||
Number *big.Int
|
||||
Hash common.Hash
|
||||
Time uint64
|
||||
}
|
||||
|
||||
// HeaderToHeaderInfo converts an eth1 header to a header metadata type.
|
||||
func HeaderToHeaderInfo(hdr *gethTypes.Header) (*HeaderInfo, error) {
|
||||
if hdr.Number == nil {
|
||||
// A nil number will panic when calling *big.Int.Set(...)
|
||||
return nil, errors.New("cannot convert block header with nil block number")
|
||||
}
|
||||
|
||||
return &HeaderInfo{
|
||||
Hash: hdr.Hash(),
|
||||
Number: new(big.Int).Set(hdr.Number),
|
||||
Time: hdr.Time,
|
||||
}, nil
|
||||
Number *big.Int `json:"number"`
|
||||
Hash common.Hash `json:"hash"`
|
||||
Time uint64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
// Copy sends out a copy of the current header info.
|
||||
@@ -38,3 +25,44 @@ func (h *HeaderInfo) Copy() *HeaderInfo {
|
||||
Time: h.Time,
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (h *HeaderInfo) MarshalJSON() ([]byte, error) {
|
||||
type HeaderInfoJson struct {
|
||||
Number *hexutil.Big `json:"number"`
|
||||
Hash common.Hash `json:"hash"`
|
||||
Time hexutil.Uint64 `json:"timestamp"`
|
||||
}
|
||||
var enc HeaderInfoJson
|
||||
|
||||
enc.Number = (*hexutil.Big)(h.Number)
|
||||
enc.Hash = h.Hash
|
||||
enc.Time = hexutil.Uint64(h.Time)
|
||||
return json.Marshal(enc)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (h *HeaderInfo) UnmarshalJSON(data []byte) error {
|
||||
type HeaderInfoJson struct {
|
||||
Number *hexutil.Big `json:"number"`
|
||||
Hash *common.Hash `json:"hash"`
|
||||
Time *hexutil.Uint64 `json:"timestamp"`
|
||||
}
|
||||
var dec HeaderInfoJson
|
||||
if err := json.Unmarshal(data, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
if dec.Time == nil {
|
||||
return errors.New("missing required field 'timestamp'")
|
||||
}
|
||||
h.Time = uint64(*dec.Time)
|
||||
if dec.Number == nil {
|
||||
return errors.New("missing required field 'number'")
|
||||
}
|
||||
h.Number = (*big.Int)(dec.Number)
|
||||
if dec.Hash == nil {
|
||||
return errors.New("missing required field 'hash'")
|
||||
}
|
||||
h.Hash = *dec.Hash
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,53 +1,68 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
)
|
||||
|
||||
func Test_headerToHeaderInfo(t *testing.T) {
|
||||
type args struct {
|
||||
hdr *gethTypes.Header
|
||||
}
|
||||
func TestRoundtrip_HeaderInfo(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *HeaderInfo
|
||||
hInfo HeaderInfo
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "OK",
|
||||
args: args{hdr: &gethTypes.Header{
|
||||
Number: big.NewInt(500),
|
||||
Time: 2345,
|
||||
}},
|
||||
want: &HeaderInfo{
|
||||
Number: big.NewInt(500),
|
||||
name: "normal header object",
|
||||
hInfo: HeaderInfo{
|
||||
Number: big.NewInt(1000),
|
||||
Hash: common.Hash{239, 10, 13, 71, 156, 192, 23, 93, 73, 154, 255, 209, 163, 204, 129, 12, 179, 183, 65, 70, 205, 200, 57, 12, 17, 211, 209, 4, 104, 133, 73, 86},
|
||||
Time: 2345,
|
||||
Time: 1000,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "nil number",
|
||||
args: args{hdr: &gethTypes.Header{
|
||||
Time: 2345,
|
||||
}},
|
||||
name: "large header object",
|
||||
hInfo: HeaderInfo{
|
||||
Number: big.NewInt(10023982389238920),
|
||||
Hash: common.Hash{192, 19, 18, 71, 156, 239, 23, 93, 73, 17, 255, 209, 163, 204, 129, 12, 179, 129, 65, 70, 209, 200, 57, 12, 17, 211, 209, 4, 104, 57, 73, 86},
|
||||
Time: math.MaxUint64,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "missing number",
|
||||
hInfo: HeaderInfo{
|
||||
Hash: common.Hash{192, 19, 18, 71, 156, 239, 23, 93, 73, 17, 255, 209, 163, 204, 129, 12, 179, 129, 65, 70, 209, 200, 57, 12, 17, 211, 209, 4, 104, 57, 73, 86},
|
||||
Time: math.MaxUint64,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := HeaderToHeaderInfo(tt.args.hdr)
|
||||
h := &HeaderInfo{
|
||||
Number: tt.hInfo.Number,
|
||||
Hash: tt.hInfo.Hash,
|
||||
Time: tt.hInfo.Time,
|
||||
}
|
||||
recv, err := h.MarshalJSON()
|
||||
assert.NoError(t, err)
|
||||
newH := &HeaderInfo{}
|
||||
err = newH.UnmarshalJSON(recv)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("headerToHeaderInfo() error = %v, wantErr %v", err, tt.wantErr)
|
||||
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("headerToHeaderInfo() got = %v, want %v", got, tt.want)
|
||||
if tt.wantErr {
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(*newH, tt.hInfo) {
|
||||
t.Errorf("MarshalJSON() got = %v, want %v", newH, tt.hInfo)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user