go-ethereum/portalnetwork/beacon/light_client_test.go
2024-09-06 22:51:51 +08:00

198 lines
5.6 KiB
Go

package beacon
import (
"encoding/json"
"os"
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/internal/testlog"
"github.com/ethereum/go-ethereum/log"
"github.com/protolambda/zrnt/eth2/beacon/capella"
"github.com/protolambda/zrnt/eth2/beacon/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var _ ConsensusAPI = (*MockConsensusAPI)(nil)
type MockConsensusAPI struct {
testdataDir string
}
func NewMockConsensusAPI(path string) (ConsensusAPI, error) {
return &MockConsensusAPI{testdataDir: path}, nil
}
func (m MockConsensusAPI) GetUpdates(_, _ uint64) ([]common.SpecObj, error) {
jsonStr, _ := os.ReadFile(m.testdataDir + "/updates.json")
updates := make([]*capella.LightClientUpdate, 0)
_ = json.Unmarshal(jsonStr, &updates)
res := make([]common.SpecObj, 0)
for _, item := range updates {
res = append(res, item)
}
return res, nil
}
func (m MockConsensusAPI) GetBootstrap(_ common.Root) (common.SpecObj, error) {
jsonStr, _ := os.ReadFile(m.testdataDir + "/bootstrap.json")
bootstrap := &capella.LightClientBootstrap{}
_ = json.Unmarshal(jsonStr, &bootstrap)
return bootstrap, nil
}
func (m MockConsensusAPI) GetFinalityUpdate() (common.SpecObj, error) {
jsonStr, _ := os.ReadFile(m.testdataDir + "/finality.json")
finality := &capella.LightClientFinalityUpdate{}
_ = json.Unmarshal(jsonStr, &finality)
return finality, nil
}
func (m MockConsensusAPI) GetOptimisticUpdate() (common.SpecObj, error) {
jsonStr, _ := os.ReadFile(m.testdataDir + "/optimistic.json")
optimistic := &capella.LightClientOptimisticUpdate{}
_ = json.Unmarshal(jsonStr, &optimistic)
return optimistic, nil
}
func (m MockConsensusAPI) ChainID() uint64 {
panic("implement me")
}
func (m MockConsensusAPI) Name() string {
return "mock"
}
func getClient(strictCheckpointAge bool, t *testing.T) (*ConsensusLightClient, error) {
baseConfig := Mainnet()
api, err := NewMockConsensusAPI("testdata/mockdata")
assert.NoError(t, err)
config := &Config{
ConsensusAPI: api.Name(),
Chain: baseConfig.Chain,
Spec: baseConfig.Spec,
StrictCheckpointAge: strictCheckpointAge,
}
checkpoint := common.Root(hexutil.MustDecode("0xc62aa0de55e6f21230fa63713715e1a6c13e73005e89f6389da271955d819bde"))
client, err := NewConsensusLightClient(api, config, checkpoint, testlog.Logger(t, log.LvlTrace))
if err != nil {
return nil, err
}
return client, nil
}
func TestVerifyCheckpointAgeInvalid(t *testing.T) {
_, err := getClient(true, t)
assert.ErrorContains(t, err, "checkpoint is too old")
}
func TestVerifyUpdate(t *testing.T) {
client, err := getClient(false, t)
require.NoError(t, err)
client.Config.MaxCheckpointAge = 123123123
period := CalcSyncPeriod(uint64(client.Store.FinalizedHeader.Slot))
updates, err := client.API.GetUpdates(period, MaxRequestLightClientUpdates)
require.NoError(t, err)
// normal
err = client.VerifyUpdate(updates[0])
require.NoError(t, err)
// ErrInvalidNextSyncCommitteeProof
genericUpdate, err := FromLightClientUpdate(updates[0])
require.NoError(t, err)
genericUpdate.NextSyncCommittee.Pubkeys[0] = common.BLSPubkey{}
err = client.VerifyGenericUpdate(genericUpdate)
require.Equal(t, ErrInvalidNextSyncCommitteeProof, err)
// ErrInvalidFinalityProof
updates, err = client.API.GetUpdates(period, MaxRequestLightClientUpdates)
require.NoError(t, err)
genericUpdate, err = FromLightClientUpdate(updates[0])
require.NoError(t, err)
genericUpdate.FinalizedHeader = &common.BeaconBlockHeader{}
err = client.VerifyGenericUpdate(genericUpdate)
require.Equal(t, ErrInvalidFinalityProof, err)
// ErrInvalidSignature
updates, err = client.API.GetUpdates(period, MaxRequestLightClientUpdates)
require.NoError(t, err)
genericUpdate, err = FromLightClientUpdate(updates[0])
require.NoError(t, err)
genericUpdate.SyncAggregate.SyncCommitteeSignature[1] = 0xFE
err = client.VerifyGenericUpdate(genericUpdate)
require.Error(t, err)
}
func TestVerifyFinalityUpdate(t *testing.T) {
client, err := getClient(false, t)
require.NoError(t, err)
update, err := client.API.GetFinalityUpdate()
require.NoError(t, err)
// normal
err = client.VerifyFinalityUpdate(update)
require.NoError(t, err)
genericUpdate, err := FromLightClientFinalityUpdate(update)
require.NoError(t, err)
genericUpdate.FinalizedHeader = &common.BeaconBlockHeader{}
err = client.VerifyGenericUpdate(genericUpdate)
require.Equal(t, ErrInvalidFinalityProof, err)
// ErrInvalidSignature
update, err = client.API.GetFinalityUpdate()
require.NoError(t, err)
genericUpdate, err = FromLightClientFinalityUpdate(update)
require.NoError(t, err)
genericUpdate.SyncAggregate.SyncCommitteeSignature[1] = 0xFE
err = client.VerifyGenericUpdate(genericUpdate)
require.Error(t, err)
}
func TestVerifyOptimisticUpdate(t *testing.T) {
client, err := getClient(false, t)
require.NoError(t, err)
update, err := client.API.GetOptimisticUpdate()
require.NoError(t, err)
// normal
err = client.VerifyOptimisticUpdate(update)
require.NoError(t, err)
genericUpdate, err := FromLightClientOptimisticUpdate(update)
require.NoError(t, err)
genericUpdate.SyncAggregate.SyncCommitteeSignature = common.BLSSignature{}
err = client.VerifyGenericUpdate(genericUpdate)
require.Error(t, err)
}
func TestSync(t *testing.T) {
client, err := getClient(false, t)
require.NoError(t, err)
err = client.Sync()
require.NoError(t, err)
header := client.GetHeader()
require.Equal(t, header.Slot, common.Slot(7358726))
finalizedHead := client.GetFinalityHeader()
require.Equal(t, finalizedHead.Slot, common.Slot(7358656))
}