From 777d67cdc3c22f227d3189eff993a837c33addbd Mon Sep 17 00:00:00 2001 From: fearlessfe <505380967@qq.com> Date: Fri, 6 Sep 2024 22:51:51 +0800 Subject: [PATCH] refactor: portal api --- portalnetwork/beacon/beacon_network.go | 1 + portalnetwork/beacon/light_client.go | 16 +- portalnetwork/beacon/light_client_test.go | 12 +- portalnetwork/beacon/lightclient/interface.go | 12 -- portalnetwork/beacon/lightclient/mock_rpc.go | 42 ----- .../beacon/lightclient/portal_rpc.go | 153 ----------------- portalnetwork/beacon/portal_api.go | 159 +++++++++++++++--- 7 files changed, 148 insertions(+), 247 deletions(-) delete mode 100644 portalnetwork/beacon/lightclient/interface.go delete mode 100644 portalnetwork/beacon/lightclient/mock_rpc.go delete mode 100644 portalnetwork/beacon/lightclient/portal_rpc.go diff --git a/portalnetwork/beacon/beacon_network.go b/portalnetwork/beacon/beacon_network.go index 066f9f1bf1..a2d196ca3a 100644 --- a/portalnetwork/beacon/beacon_network.go +++ b/portalnetwork/beacon/beacon_network.go @@ -32,6 +32,7 @@ type BeaconNetwork struct { log log.Logger closeCtx context.Context closeFunc context.CancelFunc + // lightClient *ConsensusLightClient } func NewBeaconNetwork(portalProtocol *discover.PortalProtocol) *BeaconNetwork { diff --git a/portalnetwork/beacon/light_client.go b/portalnetwork/beacon/light_client.go index ab5658abcc..e2f9353aae 100644 --- a/portalnetwork/beacon/light_client.go +++ b/portalnetwork/beacon/light_client.go @@ -30,10 +30,10 @@ var ( ) type ConsensusAPI interface { + GetBootstrap(blockRoot common.Root) (common.SpecObj, error) GetUpdates(firstPeriod, count uint64) ([]common.SpecObj, error) - GetCheckpointData(checkpointHash common.Root) (common.SpecObj, error) - GetFinalityData() (common.SpecObj, error) - GetOptimisticData() (common.SpecObj, error) + GetFinalityUpdate() (common.SpecObj, error) + GetOptimisticUpdate() (common.SpecObj, error) ChainID() uint64 Name() string } @@ -174,7 +174,7 @@ func (c *ConsensusLightClient) Sync() error { c.ApplyUpdate(update) } - finalityUpdate, err := c.API.GetFinalityData() + finalityUpdate, err := c.API.GetFinalityUpdate() if err != nil { return err } @@ -184,7 +184,7 @@ func (c *ConsensusLightClient) Sync() error { } c.ApplyFinalityUpdate(finalityUpdate) - optimisticUpdate, err := c.API.GetOptimisticData() + optimisticUpdate, err := c.API.GetOptimisticUpdate() if err != nil { return err } @@ -199,7 +199,7 @@ func (c *ConsensusLightClient) Sync() error { } func (c *ConsensusLightClient) Advance() error { - finalityUpdate, err := c.API.GetFinalityData() + finalityUpdate, err := c.API.GetFinalityUpdate() if err != nil { return err } @@ -209,7 +209,7 @@ func (c *ConsensusLightClient) Advance() error { } c.ApplyFinalityUpdate(finalityUpdate) - optimisticUpdate, err := c.API.GetOptimisticData() + optimisticUpdate, err := c.API.GetOptimisticUpdate() if err != nil { return err } @@ -240,7 +240,7 @@ func (c *ConsensusLightClient) Advance() error { } func (c *ConsensusLightClient) bootstrap() error { - forkedBootstrap, err := c.API.GetCheckpointData(c.InitialCheckpoint) + forkedBootstrap, err := c.API.GetBootstrap(c.InitialCheckpoint) if err != nil { return err } diff --git a/portalnetwork/beacon/light_client_test.go b/portalnetwork/beacon/light_client_test.go index a558e29f5f..6a72c68f19 100644 --- a/portalnetwork/beacon/light_client_test.go +++ b/portalnetwork/beacon/light_client_test.go @@ -38,7 +38,7 @@ func (m MockConsensusAPI) GetUpdates(_, _ uint64) ([]common.SpecObj, error) { return res, nil } -func (m MockConsensusAPI) GetCheckpointData(_ common.Root) (common.SpecObj, error) { +func (m MockConsensusAPI) GetBootstrap(_ common.Root) (common.SpecObj, error) { jsonStr, _ := os.ReadFile(m.testdataDir + "/bootstrap.json") bootstrap := &capella.LightClientBootstrap{} @@ -47,7 +47,7 @@ func (m MockConsensusAPI) GetCheckpointData(_ common.Root) (common.SpecObj, erro return bootstrap, nil } -func (m MockConsensusAPI) GetFinalityData() (common.SpecObj, error) { +func (m MockConsensusAPI) GetFinalityUpdate() (common.SpecObj, error) { jsonStr, _ := os.ReadFile(m.testdataDir + "/finality.json") finality := &capella.LightClientFinalityUpdate{} @@ -56,7 +56,7 @@ func (m MockConsensusAPI) GetFinalityData() (common.SpecObj, error) { return finality, nil } -func (m MockConsensusAPI) GetOptimisticData() (common.SpecObj, error) { +func (m MockConsensusAPI) GetOptimisticUpdate() (common.SpecObj, error) { jsonStr, _ := os.ReadFile(m.testdataDir + "/optimistic.json") optimistic := &capella.LightClientOptimisticUpdate{} @@ -140,7 +140,7 @@ func TestVerifyFinalityUpdate(t *testing.T) { client, err := getClient(false, t) require.NoError(t, err) - update, err := client.API.GetFinalityData() + update, err := client.API.GetFinalityUpdate() require.NoError(t, err) // normal @@ -154,7 +154,7 @@ func TestVerifyFinalityUpdate(t *testing.T) { err = client.VerifyGenericUpdate(genericUpdate) require.Equal(t, ErrInvalidFinalityProof, err) // ErrInvalidSignature - update, err = client.API.GetFinalityData() + update, err = client.API.GetFinalityUpdate() require.NoError(t, err) genericUpdate, err = FromLightClientFinalityUpdate(update) @@ -168,7 +168,7 @@ func TestVerifyOptimisticUpdate(t *testing.T) { client, err := getClient(false, t) require.NoError(t, err) - update, err := client.API.GetOptimisticData() + update, err := client.API.GetOptimisticUpdate() require.NoError(t, err) // normal diff --git a/portalnetwork/beacon/lightclient/interface.go b/portalnetwork/beacon/lightclient/interface.go deleted file mode 100644 index cd2f801757..0000000000 --- a/portalnetwork/beacon/lightclient/interface.go +++ /dev/null @@ -1,12 +0,0 @@ -package lightclient - -import "github.com/protolambda/zrnt/eth2/beacon/common" - -type ConsensusAPI interface { - GetBootstrap(blockRoot common.Root) (common.SpecObj, error) - GetUpdates(firstPeriod, count uint64) ([]common.SpecObj, error) - GetFinalityUpdate() (common.SpecObj, error) - GetOptimisticUpdate() (common.SpecObj, error) - ChainID() uint64 - Name() string -} \ No newline at end of file diff --git a/portalnetwork/beacon/lightclient/mock_rpc.go b/portalnetwork/beacon/lightclient/mock_rpc.go deleted file mode 100644 index 452feb2035..0000000000 --- a/portalnetwork/beacon/lightclient/mock_rpc.go +++ /dev/null @@ -1,42 +0,0 @@ -package lightclient - -import ( - "github.com/protolambda/zrnt/eth2/beacon/common" - "github.com/protolambda/ztyp/tree" -) - -var _ ConsensusAPI = (*MockRpc)(nil) - -type MockRpc struct { - testdataDir string -} - -// ChainID implements ConsensusAPI. -func (m *MockRpc) ChainID() uint64 { - panic("unimplemented") -} - -// GetBootstrap implements ConsensusAPI. -func (m *MockRpc) GetBootstrap(blockRoot tree.Root) (common.SpecObj, error) { - panic("unimplemented") -} - -// GetFinalityUpdate implements ConsensusAPI. -func (m *MockRpc) GetFinalityUpdate() (common.SpecObj, error) { - panic("unimplemented") -} - -// GetOptimisticUpdate implements ConsensusAPI. -func (m *MockRpc) GetOptimisticUpdate() (common.SpecObj, error) { - panic("unimplemented") -} - -// GetUpdates implements ConsensusAPI. -func (m *MockRpc) GetUpdates(firstPeriod uint64, count uint64) ([]common.SpecObj, error) { - panic("unimplemented") -} - -// Name implements ConsensusAPI. -func (m *MockRpc) Name() string { - panic("unimplemented") -} diff --git a/portalnetwork/beacon/lightclient/portal_rpc.go b/portalnetwork/beacon/lightclient/portal_rpc.go deleted file mode 100644 index c6c0a0d963..0000000000 --- a/portalnetwork/beacon/lightclient/portal_rpc.go +++ /dev/null @@ -1,153 +0,0 @@ -package lightclient - -import ( - "bytes" - "errors" - "time" - - "github.com/ethereum/go-ethereum/p2p/discover" - "github.com/ethereum/go-ethereum/portalnetwork/beacon" - "github.com/ethereum/go-ethereum/portalnetwork/storage" - "github.com/protolambda/zrnt/eth2/beacon/common" - "github.com/protolambda/ztyp/codec" - "github.com/protolambda/ztyp/tree" -) - -var _ ConsensusAPI = &PortalRpc{} - -type PortalRpc struct { - portalProtocol *discover.PortalProtocol - spec *common.Spec -} - -// ChainID implements ConsensusAPI. -func (p *PortalRpc) ChainID() uint64 { - return 1 -} - -// GetCheckpointData implements ConsensusAPI. -func (p *PortalRpc) GetBootstrap(blockRoot tree.Root) (common.SpecObj, error) { - bootstrapKey := &beacon.LightClientBootstrapKey{ - BlockHash: blockRoot[:], - } - contentKeyBytes, err := bootstrapKey.MarshalSSZ() - if err != nil { - return nil, err - } - contentKey := storage.NewContentKey(beacon.LightClientBootstrap, contentKeyBytes).Encode() - // Get from local - contentId := p.portalProtocol.ToContentId(contentKey) - res, err := p.getContent(contentKey, contentId) - if err != nil { - return nil, err - } - forkedLightClientBootstrap := &beacon.ForkedLightClientBootstrap{} - err = forkedLightClientBootstrap.Deserialize(p.spec, codec.NewDecodingReader(bytes.NewReader(res), uint64(len(res)))) - if err != nil { - return nil, err - } - return forkedLightClientBootstrap.Bootstrap, nil -} - -// GetFinalityData implements ConsensusAPI. -func (p *PortalRpc) GetFinalityUpdate() (common.SpecObj, error) { - // Get the finality update for the most recent finalized epoch. We use 0 as the finalized - // slot because the finalized slot is not known at this point and the protocol is - // designed to return the most recent which is > 0 - finUpdateKey := &beacon.LightClientFinalityUpdateKey{ - FinalizedSlot: 0, - } - contentKeyBytes, err := finUpdateKey.MarshalSSZ() - if err != nil { - return nil, err - } - contentKey := storage.NewContentKey(beacon.LightClientFinalityUpdate, contentKeyBytes).Encode() - // Get from local - contentId := p.portalProtocol.ToContentId(contentKey) - res, err := p.getContent(contentKey, contentId) - if err != nil { - return nil, err - } - finalityUpdate := &beacon.ForkedLightClientFinalityUpdate{} - err = finalityUpdate.Deserialize(p.spec, codec.NewDecodingReader(bytes.NewReader(res), uint64(len(res)))) - if err != nil { - return nil, err - } - return finalityUpdate.LightClientFinalityUpdate, nil -} - -// GetOptimisticData implements ConsensusAPI. -func (p *PortalRpc) GetOptimisticUpdate() (common.SpecObj, error) { - currentSlot := p.spec.TimeToSlot(common.Timestamp(time.Now().Unix()), common.Timestamp(beacon.BeaconGenesisTime)) - optimisticUpdateKey := &beacon.LightClientOptimisticUpdateKey{ - OptimisticSlot: uint64(currentSlot), - } - contentKeyBytes, err := optimisticUpdateKey.MarshalSSZ() - if err != nil { - return nil, err - } - contentKey := storage.NewContentKey(beacon.LightClientOptimisticUpdate, contentKeyBytes).Encode() - // Get from local - contentId := p.portalProtocol.ToContentId(contentKey) - res, err := p.getContent(contentKey, contentId) - if err != nil { - return nil, err - } - optimisticUpdate := &beacon.ForkedLightClientOptimisticUpdate{} - err = optimisticUpdate.Deserialize(p.spec, codec.NewDecodingReader(bytes.NewReader(res), uint64(len(res)))) - if err != nil { - return nil, err - } - return optimisticUpdate.LightClientOptimisticUpdate, nil -} - -// GetUpdates implements ConsensusAPI. -func (p *PortalRpc) GetUpdates(firstPeriod uint64, count uint64) ([]common.SpecObj, error) { - lightClientUpdateKey := &beacon.LightClientUpdateKey{ - StartPeriod: firstPeriod, - Count: count, - } - contentKeyBytes, err := lightClientUpdateKey.MarshalSSZ() - if err != nil { - return nil, err - } - contentKey := storage.NewContentKey(beacon.LightClientUpdate, contentKeyBytes).Encode() - // Get from local - contentId := p.portalProtocol.ToContentId(contentKey) - data, err := p.getContent(contentKey, contentId) - if err != nil { - return nil, err - } - var lightClientUpdateRange beacon.LightClientUpdateRange = make([]beacon.ForkedLightClientUpdate, 0) - err = lightClientUpdateRange.Deserialize(p.spec, codec.NewDecodingReader(bytes.NewReader(data), uint64(len(data)))) - if err != nil { - return nil, err - } - res := make([]common.SpecObj, len(lightClientUpdateRange)) - - for i, item := range lightClientUpdateRange { - res[i] = item.LightClientUpdate - } - return res, nil -} - -// Name implements ConsensusAPI. -func (p *PortalRpc) Name() string { - return "portal" -} - -func (p *PortalRpc) getContent(contentKey, contentId []byte) ([]byte, error) { - res, err := p.portalProtocol.Get(contentKey, contentId) - // other error - if err != nil && !errors.Is(err, storage.ErrContentNotFound) { - return nil, err - } - if res == nil { - // Get from remote - res, _, err = p.portalProtocol.ContentLookup(contentKey, contentId) - if err != nil { - return nil, err - } - } - return res, nil -} diff --git a/portalnetwork/beacon/portal_api.go b/portalnetwork/beacon/portal_api.go index 9f8158e1ad..8f4ddad728 100644 --- a/portalnetwork/beacon/portal_api.go +++ b/portalnetwork/beacon/portal_api.go @@ -1,9 +1,14 @@ package beacon import ( + "bytes" + "errors" "time" - zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common" + "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/portalnetwork/storage" + "github.com/protolambda/zrnt/eth2/beacon/common" + "github.com/protolambda/ztyp/codec" "github.com/protolambda/ztyp/tree" ) @@ -12,40 +17,142 @@ const BeaconGenesisTime uint64 = 1606824023 var _ ConsensusAPI = &PortalLightApi{} type PortalLightApi struct { - bn *BeaconNetwork + portalProtocol *discover.PortalProtocol + spec *common.Spec } func NewPortalLightApi() *PortalLightApi { return &PortalLightApi{} } -func (api *PortalLightApi) GetUpdates(firstPeriod, count uint64) ([]zrntcommon.SpecObj, error) { - return api.bn.GetUpdates(firstPeriod, count) -} - -func (api *PortalLightApi) GetCheckpointData(checkpointHash tree.Root) (zrntcommon.SpecObj, error) { - return api.bn.GetCheckpointData(checkpointHash) -} - -func (api *PortalLightApi) GetFinalityData() (zrntcommon.SpecObj, error) { - expectedCurrentSlot := api.bn.spec.TimeToSlot(zrntcommon.Timestamp(time.Now().Unix()), zrntcommon.Timestamp(BeaconGenesisTime)) - recentEpochStart := expectedCurrentSlot - (expectedCurrentSlot % api.bn.spec.SLOTS_PER_EPOCH) + 1 - return api.bn.GetFinalityUpdate(uint64(recentEpochStart)) -} - -func (api *PortalLightApi) GetOptimisticData() (zrntcommon.SpecObj, error) { - expectedCurrentSlot := api.bn.spec.TimeToSlot(zrntcommon.Timestamp(time.Now().Unix()), zrntcommon.Timestamp(BeaconGenesisTime)) - return api.bn.GetOptimisticUpdate(uint64(expectedCurrentSlot)) -} - -func (api *PortalLightApi) ChainID() uint64 { +// ChainID implements ConsensusAPI. +func (p *PortalLightApi) ChainID() uint64 { return 1 } -func (api *PortalLightApi) Name() string { +// GetCheckpointData implements ConsensusAPI. +func (p *PortalLightApi) GetBootstrap(blockRoot tree.Root) (common.SpecObj, error) { + bootstrapKey := &LightClientBootstrapKey{ + BlockHash: blockRoot[:], + } + contentKeyBytes, err := bootstrapKey.MarshalSSZ() + if err != nil { + return nil, err + } + contentKey := storage.NewContentKey(LightClientBootstrap, contentKeyBytes).Encode() + // Get from local + contentId := p.portalProtocol.ToContentId(contentKey) + res, err := p.getContent(contentKey, contentId) + if err != nil { + return nil, err + } + forkedLightClientBootstrap := &ForkedLightClientBootstrap{} + err = forkedLightClientBootstrap.Deserialize(p.spec, codec.NewDecodingReader(bytes.NewReader(res), uint64(len(res)))) + if err != nil { + return nil, err + } + return forkedLightClientBootstrap.Bootstrap, nil +} + +// GetFinalityData implements ConsensusAPI. +func (p *PortalLightApi) GetFinalityUpdate() (common.SpecObj, error) { + // Get the finality update for the most recent finalized epoch. We use 0 as the finalized + // slot because the finalized slot is not known at this point and the protocol is + // designed to return the most recent which is > 0 + finUpdateKey := &LightClientFinalityUpdateKey{ + FinalizedSlot: 0, + } + contentKeyBytes, err := finUpdateKey.MarshalSSZ() + if err != nil { + return nil, err + } + contentKey := storage.NewContentKey(LightClientFinalityUpdate, contentKeyBytes).Encode() + // Get from local + contentId := p.portalProtocol.ToContentId(contentKey) + res, err := p.getContent(contentKey, contentId) + if err != nil { + return nil, err + } + finalityUpdate := &ForkedLightClientFinalityUpdate{} + err = finalityUpdate.Deserialize(p.spec, codec.NewDecodingReader(bytes.NewReader(res), uint64(len(res)))) + if err != nil { + return nil, err + } + return finalityUpdate.LightClientFinalityUpdate, nil +} + +// GetOptimisticData implements ConsensusAPI. +func (p *PortalLightApi) GetOptimisticUpdate() (common.SpecObj, error) { + currentSlot := p.spec.TimeToSlot(common.Timestamp(time.Now().Unix()), common.Timestamp(BeaconGenesisTime)) + optimisticUpdateKey := &LightClientOptimisticUpdateKey{ + OptimisticSlot: uint64(currentSlot), + } + contentKeyBytes, err := optimisticUpdateKey.MarshalSSZ() + if err != nil { + return nil, err + } + contentKey := storage.NewContentKey(LightClientOptimisticUpdate, contentKeyBytes).Encode() + // Get from local + contentId := p.portalProtocol.ToContentId(contentKey) + res, err := p.getContent(contentKey, contentId) + if err != nil { + return nil, err + } + optimisticUpdate := &ForkedLightClientOptimisticUpdate{} + err = optimisticUpdate.Deserialize(p.spec, codec.NewDecodingReader(bytes.NewReader(res), uint64(len(res)))) + if err != nil { + return nil, err + } + return optimisticUpdate.LightClientOptimisticUpdate, nil +} + +// GetUpdates implements ConsensusAPI. +func (p *PortalLightApi) GetUpdates(firstPeriod uint64, count uint64) ([]common.SpecObj, error) { + lightClientUpdateKey := &LightClientUpdateKey{ + StartPeriod: firstPeriod, + Count: count, + } + contentKeyBytes, err := lightClientUpdateKey.MarshalSSZ() + if err != nil { + return nil, err + } + contentKey := storage.NewContentKey(LightClientUpdate, contentKeyBytes).Encode() + // Get from local + contentId := p.portalProtocol.ToContentId(contentKey) + data, err := p.getContent(contentKey, contentId) + if err != nil { + return nil, err + } + var lightClientUpdateRange LightClientUpdateRange = make([]ForkedLightClientUpdate, 0) + err = lightClientUpdateRange.Deserialize(p.spec, codec.NewDecodingReader(bytes.NewReader(data), uint64(len(data)))) + if err != nil { + return nil, err + } + res := make([]common.SpecObj, len(lightClientUpdateRange)) + + for i, item := range lightClientUpdateRange { + res[i] = item.LightClientUpdate + } + return res, nil +} + +// Name implements ConsensusAPI. +func (p *PortalLightApi) Name() string { return "portal" } -// func CurrentSlot() uint64 { - -// } +func (p *PortalLightApi) getContent(contentKey, contentId []byte) ([]byte, error) { + res, err := p.portalProtocol.Get(contentKey, contentId) + // other error + if err != nil && !errors.Is(err, storage.ErrContentNotFound) { + return nil, err + } + if res == nil { + // Get from remote + res, _, err = p.portalProtocol.ContentLookup(contentKey, contentId) + if err != nil { + return nil, err + } + } + return res, nil +}