From 178590d099edae01b60f53775c3a2001458d65fd Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Fri, 24 May 2024 21:37:25 +0200 Subject: [PATCH 01/20] sync finalized headers on demand --- relayer/chain/parachain/writer.go | 8 +- relayer/relays/beacon/header/header.go | 74 ++++++++++++++----- .../header/syncer/scale/beacon_scale.go | 6 +- relayer/relays/beacon/header/syncer/syncer.go | 14 ++++ relayer/relays/execution/main.go | 28 +++++-- 5 files changed, 102 insertions(+), 28 deletions(-) diff --git a/relayer/chain/parachain/writer.go b/relayer/chain/parachain/writer.go index 6291943c3..94bc82367 100644 --- a/relayer/chain/parachain/writer.go +++ b/relayer/chain/parachain/writer.go @@ -16,7 +16,7 @@ import ( ) type ChainWriter interface { - BatchCall(ctx context.Context, extrinsic string, calls []interface{}) error + BatchCall(ctx context.Context, extrinsic []string, calls []interface{}) error WriteToParachainAndRateLimit(ctx context.Context, extrinsicName string, payload ...interface{}) error WriteToParachainAndWatch(ctx context.Context, extrinsicName string, payload ...interface{}) error GetLastFinalizedHeaderState() (state.FinalizedHeader, error) @@ -69,7 +69,7 @@ func (wr *ParachainWriter) Start(ctx context.Context, eg *errgroup.Group) error return nil } -func (wr *ParachainWriter) BatchCall(ctx context.Context, extrinsic string, calls []interface{}) error { +func (wr *ParachainWriter) BatchCall(ctx context.Context, extrinsic []string, calls []interface{}) error { batchSize := int(wr.maxBatchCallSize) var j int for i := 0; i < len(calls); i += batchSize { @@ -80,13 +80,13 @@ func (wr *ParachainWriter) BatchCall(ctx context.Context, extrinsic string, call slicedCalls := append([]interface{}{}, calls[i:j]...) encodedCalls := make([]types.Call, len(slicedCalls)) for k := range slicedCalls { - call, err := wr.prepCall(extrinsic, slicedCalls[k]) + call, err := wr.prepCall(extrinsic[k], slicedCalls[k]) if err != nil { return err } encodedCalls[k] = *call } - err := wr.WriteToParachainAndRateLimit(ctx, "Utility.batch_all", encodedCalls) + err := wr.WriteToParachainAndWatch(ctx, "Utility.batch_all", encodedCalls) if err != nil { return fmt.Errorf("batch call failed: %w", err) } diff --git a/relayer/relays/beacon/header/header.go b/relayer/relays/beacon/header/header.go index 950d2cdcb..3a7d8ce48 100644 --- a/relayer/relays/beacon/header/header.go +++ b/relayer/relays/beacon/header/header.go @@ -71,7 +71,7 @@ func (h *Header) Sync(ctx context.Context, eg *errgroup.Group) error { log.Info("starting to sync finalized headers") - ticker := time.NewTicker(time.Second * 10) + ticker := time.NewTicker(time.Minute * 1) eg.Go(func() error { for { @@ -167,17 +167,16 @@ func (h *Header) SyncCommitteePeriodUpdate(ctx context.Context, period uint64) e func (h *Header) SyncFinalizedHeader(ctx context.Context) error { // When the chain has been processed up until now, keep getting finalized block updates and send that to the parachain - update, err := h.syncer.GetFinalizedUpdate() + finalizedHeader, err := h.syncer.GetFinalizedHeader() if err != nil { return fmt.Errorf("fetch finalized header update from Ethereum beacon client: %w", err) } log.WithFields(log.Fields{ - "slot": update.Payload.FinalizedHeader.Slot, - "blockRoot": update.FinalizedHeaderBlockRoot, + "slot": finalizedHeader.Slot, }).Info("syncing finalized header from Ethereum beacon client") - currentSyncPeriod := h.protocol.ComputeSyncPeriodAtSlot(uint64(update.Payload.AttestedHeader.Slot)) + currentSyncPeriod := h.protocol.ComputeSyncPeriodAtSlot(uint64(finalizedHeader.Slot)) lastSyncedPeriod := h.protocol.ComputeSyncPeriodAtSlot(h.cache.Finalized.LastSyncedSlot) if lastSyncedPeriod < currentSyncPeriod { @@ -187,7 +186,7 @@ func (h *Header) SyncFinalizedHeader(ctx context.Context) error { } } - return h.updateFinalizedHeaderOnchain(ctx, update) + return nil } // Write the provided finalized header update (possibly containing a sync committee) on-chain and check if it was @@ -321,8 +320,6 @@ func (h *Header) populateFinalizedCheckpoint(slot uint64) error { return fmt.Errorf("fetch block roots for slot %d: %w", slot, err) } - log.Info("populating checkpoint") - h.cache.AddCheckPoint(blockRoot, blockRootsProof.Tree, slot) return nil @@ -411,25 +408,68 @@ func (h *Header) getHeaderUpdateBySlot(slot uint64) (scale.HeaderUpdatePayload, return h.syncer.GetHeaderUpdate(blockRoot, &checkpoint) } -func (h *Header) FetchExecutionProof(blockRoot common.Hash) (scale.HeaderUpdatePayload, error) { - var headerUpdate scale.HeaderUpdatePayload +func (h *Header) FetchExecutionProof(blockRoot common.Hash) (scale.MessagePayload, error) { header, err := h.syncer.Client.GetHeaderByBlockRoot(blockRoot) if err != nil { - return headerUpdate, fmt.Errorf("get beacon header by blockRoot: %w", err) + return scale.MessagePayload{}, fmt.Errorf("get beacon header by blockRoot: %w", err) } lastFinalizedHeaderState, err := h.writer.GetLastFinalizedHeaderState() if err != nil { - return headerUpdate, fmt.Errorf("fetch last finalized header state: %w", err) + return scale.MessagePayload{}, fmt.Errorf("fetch last finalized header state: %w", err) } - if header.Slot > lastFinalizedHeaderState.BeaconSlot { - return headerUpdate, ErrBeaconHeaderNotFinalized + // There is a finalized header on-chain that will be able to verify the header containing the message. + if header.Slot <= lastFinalizedHeaderState.BeaconSlot { + headerUpdate, err := h.getHeaderUpdateBySlot(header.Slot) + if err != nil { + return scale.MessagePayload{}, fmt.Errorf("get header update by slot with ancestry proof: %w", err) + } + + return scale.MessagePayload{ + HeaderPayload: headerUpdate, + FinalizedPayload: nil, + }, nil } - headerUpdate, err = h.getHeaderUpdateBySlot(header.Slot) + + // The latest finalized header on-chain is older than the header containing the message, so we need to sync the + // finalized header with the message. + finalizedHeader, err := h.syncer.GetFinalizedHeader() if err != nil { - return headerUpdate, fmt.Errorf("get header update by slot with ancestry proof: %w", err) + return scale.MessagePayload{}, err + } + + // If the header is not finalized yet, we can't do anything further. + if header.Slot > uint64(finalizedHeader.Slot) { + return scale.MessagePayload{}, ErrBeaconHeaderNotFinalized } - return headerUpdate, nil + + var finalizedUpdate scale.Update + // If we import the last finalized header, the gap between the finalized headers would be too large, so import + // a slightly older header. + if lastFinalizedHeaderState.BeaconSlot+h.protocol.SlotsPerHistoricalRoot < uint64(finalizedHeader.Slot) { + finalizedUpdate, err = h.syncer.GetFinalizedUpdateAtAttestedSlot(lastFinalizedHeaderState.BeaconSlot, lastFinalizedHeaderState.BeaconSlot+h.protocol.SlotsPerHistoricalRoot, false) + if err != nil { + return scale.MessagePayload{}, fmt.Errorf("get finalized update at attested slot: %w", err) + } + } else { + finalizedUpdate, err = h.syncer.GetFinalizedUpdate() + if err != nil { + return scale.MessagePayload{}, fmt.Errorf("get finalized update: %w", err) + } + } + + checkpoint := cache.Proof{ + FinalizedBlockRoot: finalizedUpdate.FinalizedHeaderBlockRoot, + BlockRootsTree: finalizedUpdate.BlockRootsTree, + Slot: uint64(finalizedUpdate.Payload.FinalizedHeader.Slot), + } + headerUpdate, err := h.syncer.GetHeaderUpdate(blockRoot, &checkpoint) + + return scale.MessagePayload{ + HeaderPayload: headerUpdate, + FinalizedPayload: &finalizedUpdate, + }, nil + } func (h *Header) isInitialSyncPeriod() bool { diff --git a/relayer/relays/beacon/header/syncer/scale/beacon_scale.go b/relayer/relays/beacon/header/syncer/scale/beacon_scale.go index a78a7f017..b18c6d520 100644 --- a/relayer/relays/beacon/header/syncer/scale/beacon_scale.go +++ b/relayer/relays/beacon/header/syncer/scale/beacon_scale.go @@ -32,6 +32,11 @@ type Update struct { BlockRootsTree *ssz.Node } +type MessagePayload struct { + HeaderPayload HeaderUpdatePayload + FinalizedPayload *Update +} + type UpdatePayload struct { AttestedHeader BeaconHeader SyncAggregate SyncAggregate @@ -42,7 +47,6 @@ type UpdatePayload struct { BlockRootsRoot types.H256 BlockRootsBranch []types.H256 } - type OptionNextSyncCommitteeUpdatePayload struct { HasValue bool Value NextSyncCommitteeUpdatePayload diff --git a/relayer/relays/beacon/header/syncer/syncer.go b/relayer/relays/beacon/header/syncer/syncer.go index 3cc25c40a..40b1bea17 100644 --- a/relayer/relays/beacon/header/syncer/syncer.go +++ b/relayer/relays/beacon/header/syncer/syncer.go @@ -279,6 +279,20 @@ func (s *Syncer) GetBlockRootsFromState(beaconState state.BeaconState) (scale.Bl }, nil } +func (s *Syncer) GetFinalizedHeader() (scale.BeaconHeader, error) { + finalizedUpdate, err := s.Client.GetLatestFinalizedUpdate() + if err != nil { + return scale.BeaconHeader{}, fmt.Errorf("fetch finalized update: %w", err) + } + + finalizedHeader, err := finalizedUpdate.Data.FinalizedHeader.Beacon.ToScale() + if err != nil { + return scale.BeaconHeader{}, fmt.Errorf("convert finalized header to scale: %w", err) + } + + return finalizedHeader, nil +} + func (s *Syncer) GetFinalizedUpdate() (scale.Update, error) { finalizedUpdate, err := s.Client.GetLatestFinalizedUpdate() if err != nil { diff --git a/relayer/relays/execution/main.go b/relayer/relays/execution/main.go index 210cc2843..fb4e6d323 100644 --- a/relayer/relays/execution/main.go +++ b/relayer/relays/execution/main.go @@ -167,7 +167,7 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { } // ParentBeaconRoot in https://eips.ethereum.org/EIPS/eip-4788 from Deneb onward - executionProof, err := beaconHeader.FetchExecutionProof(*blockHeader.ParentBeaconRoot) + messagePayload, err := beaconHeader.FetchExecutionProof(*blockHeader.ParentBeaconRoot) if err == header.ErrBeaconHeaderNotFinalized { logger.Warn("beacon header not finalized, just skipped") continue @@ -175,18 +175,34 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { if err != nil { return fmt.Errorf("fetch execution header proof: %w", err) } - inboundMsg.Proof.ExecutionProof = executionProof + inboundMsg.Proof.ExecutionProof = messagePayload.HeaderPayload logger.WithFields(logrus.Fields{ "EventLog": inboundMsg.EventLog, "Proof": inboundMsg.Proof, }).Debug("Generated message from Ethereum log") - err = writer.WriteToParachainAndWatch(ctx, "EthereumInboundQueue.submit", inboundMsg) - if err != nil { - logger.Error("inbound message fail to sent") - return fmt.Errorf("write to parachain: %w", err) + if messagePayload.FinalizedPayload == nil { + err = writer.WriteToParachainAndWatch(ctx, "EthereumInboundQueue.submit", inboundMsg) + if err != nil { + logger.Error("inbound message fail to send") + return fmt.Errorf("write to parachain: %w", err) + } + } else { + logger.WithFields(logrus.Fields{ + "finalized_slot": messagePayload.FinalizedPayload.Payload.FinalizedHeader.Slot, + "finalized_root": messagePayload.FinalizedPayload.FinalizedHeaderBlockRoot, + "message_slot": messagePayload.HeaderPayload.Header.Slot, + }).Debug("Batching finalized header update with message") + extrinsics := []string{"EthereumBeaconClient.submit", "EthereumInboundQueue.submit"} + payloads := []interface{}{inboundMsg, messagePayload.FinalizedPayload.Payload} + err = writer.BatchCall(ctx, extrinsics, payloads) + if err != nil { + logger.Error("batch call message fail to send") + return fmt.Errorf("write to parachain: %w", err) + } } + paraNonce, _ = r.fetchLatestParachainNonce() if paraNonce != ev.Nonce { logger.Error("inbound message sent but fail to execute") From bd56320bbd7d4168c701a3340eb2276989e7e9b9 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Fri, 24 May 2024 21:58:32 +0200 Subject: [PATCH 02/20] fix tests --- relayer/relays/beacon/mock/mock_writer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relayer/relays/beacon/mock/mock_writer.go b/relayer/relays/beacon/mock/mock_writer.go index 15b48ab6d..b0700e7cc 100644 --- a/relayer/relays/beacon/mock/mock_writer.go +++ b/relayer/relays/beacon/mock/mock_writer.go @@ -27,7 +27,7 @@ func (m *Writer) GetFinalizedBeaconRootByIndex(index uint32) (types.H256, error) return types.H256{}, nil } -func (m *Writer) BatchCall(ctx context.Context, extrinsic string, calls []interface{}) error { +func (m *Writer) BatchCall(ctx context.Context, extrinsic []string, calls []interface{}) error { return nil } From b897bc364c775a238b3838347c0b519955a872d8 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Mon, 27 May 2024 11:30:04 +0200 Subject: [PATCH 03/20] refactor --- relayer/relays/beacon/header/header.go | 20 +++---- relayer/relays/execution/main.go | 80 +++++++++++++++----------- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/relayer/relays/beacon/header/header.go b/relayer/relays/beacon/header/header.go index 3a7d8ce48..5cd2a83bc 100644 --- a/relayer/relays/beacon/header/header.go +++ b/relayer/relays/beacon/header/header.go @@ -408,24 +408,24 @@ func (h *Header) getHeaderUpdateBySlot(slot uint64) (scale.HeaderUpdatePayload, return h.syncer.GetHeaderUpdate(blockRoot, &checkpoint) } -func (h *Header) FetchExecutionProof(blockRoot common.Hash) (scale.MessagePayload, error) { +func (h *Header) FetchExecutionProof(blockRoot common.Hash) (scale.ProofPayload, error) { header, err := h.syncer.Client.GetHeaderByBlockRoot(blockRoot) if err != nil { - return scale.MessagePayload{}, fmt.Errorf("get beacon header by blockRoot: %w", err) + return scale.ProofPayload{}, fmt.Errorf("get beacon header by blockRoot: %w", err) } lastFinalizedHeaderState, err := h.writer.GetLastFinalizedHeaderState() if err != nil { - return scale.MessagePayload{}, fmt.Errorf("fetch last finalized header state: %w", err) + return scale.ProofPayload{}, fmt.Errorf("fetch last finalized header state: %w", err) } // There is a finalized header on-chain that will be able to verify the header containing the message. if header.Slot <= lastFinalizedHeaderState.BeaconSlot { headerUpdate, err := h.getHeaderUpdateBySlot(header.Slot) if err != nil { - return scale.MessagePayload{}, fmt.Errorf("get header update by slot with ancestry proof: %w", err) + return scale.ProofPayload{}, fmt.Errorf("get header update by slot with ancestry proof: %w", err) } - return scale.MessagePayload{ + return scale.ProofPayload{ HeaderPayload: headerUpdate, FinalizedPayload: nil, }, nil @@ -435,12 +435,12 @@ func (h *Header) FetchExecutionProof(blockRoot common.Hash) (scale.MessagePayloa // finalized header with the message. finalizedHeader, err := h.syncer.GetFinalizedHeader() if err != nil { - return scale.MessagePayload{}, err + return scale.ProofPayload{}, err } // If the header is not finalized yet, we can't do anything further. if header.Slot > uint64(finalizedHeader.Slot) { - return scale.MessagePayload{}, ErrBeaconHeaderNotFinalized + return scale.ProofPayload{}, ErrBeaconHeaderNotFinalized } var finalizedUpdate scale.Update @@ -449,12 +449,12 @@ func (h *Header) FetchExecutionProof(blockRoot common.Hash) (scale.MessagePayloa if lastFinalizedHeaderState.BeaconSlot+h.protocol.SlotsPerHistoricalRoot < uint64(finalizedHeader.Slot) { finalizedUpdate, err = h.syncer.GetFinalizedUpdateAtAttestedSlot(lastFinalizedHeaderState.BeaconSlot, lastFinalizedHeaderState.BeaconSlot+h.protocol.SlotsPerHistoricalRoot, false) if err != nil { - return scale.MessagePayload{}, fmt.Errorf("get finalized update at attested slot: %w", err) + return scale.ProofPayload{}, fmt.Errorf("get finalized update at attested slot: %w", err) } } else { finalizedUpdate, err = h.syncer.GetFinalizedUpdate() if err != nil { - return scale.MessagePayload{}, fmt.Errorf("get finalized update: %w", err) + return scale.ProofPayload{}, fmt.Errorf("get finalized update: %w", err) } } @@ -465,7 +465,7 @@ func (h *Header) FetchExecutionProof(blockRoot common.Hash) (scale.MessagePayloa } headerUpdate, err := h.syncer.GetHeaderUpdate(blockRoot, &checkpoint) - return scale.MessagePayload{ + return scale.ProofPayload{ HeaderPayload: headerUpdate, FinalizedPayload: &finalizedUpdate, }, nil diff --git a/relayer/relays/execution/main.go b/relayer/relays/execution/main.go index fb4e6d323..dcb7d88ad 100644 --- a/relayer/relays/execution/main.go +++ b/relayer/relays/execution/main.go @@ -2,6 +2,7 @@ package execution import ( "context" + "errors" "fmt" "math/big" "sort" @@ -18,6 +19,7 @@ import ( "github.com/snowfork/snowbridge/relayer/crypto/sr25519" "github.com/snowfork/snowbridge/relayer/relays/beacon/header" "github.com/snowfork/snowbridge/relayer/relays/beacon/header/syncer/api" + "github.com/snowfork/snowbridge/relayer/relays/beacon/header/syncer/scale" "github.com/snowfork/snowbridge/relayer/relays/beacon/protocol" "github.com/snowfork/snowbridge/relayer/relays/beacon/store" "golang.org/x/sync/errgroup" @@ -30,6 +32,7 @@ type Relay struct { ethconn *ethereum.Connection gatewayContract *contracts.Gateway beaconHeader *header.Header + writer *parachain.ParachainWriter } func NewRelay( @@ -58,13 +61,13 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { } r.ethconn = ethconn - writer := parachain.NewParachainWriter( + r.writer = parachain.NewParachainWriter( paraconn, r.config.Sink.Parachain.MaxWatchedExtrinsics, r.config.Sink.Parachain.MaxBatchCallSize, ) - err = writer.Start(ctx, eg) + err = r.writer.Start(ctx, eg) if err != nil { return err } @@ -87,11 +90,10 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { store := store.New(r.config.Source.Beacon.DataStore.Location, r.config.Source.Beacon.DataStore.MaxEntries, *p) store.Connect() - defer store.Close() beaconAPI := api.NewBeaconClient(r.config.Source.Beacon.Endpoint, r.config.Source.Beacon.StateEndpoint) beaconHeader := header.New( - writer, + r.writer, beaconAPI, r.config.Source.Beacon.Spec, &store, @@ -167,45 +169,22 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { } // ParentBeaconRoot in https://eips.ethereum.org/EIPS/eip-4788 from Deneb onward - messagePayload, err := beaconHeader.FetchExecutionProof(*blockHeader.ParentBeaconRoot) - if err == header.ErrBeaconHeaderNotFinalized { + proof, err := beaconHeader.FetchExecutionProof(*blockHeader.ParentBeaconRoot) + if errors.Is(err, header.ErrBeaconHeaderNotFinalized) { logger.Warn("beacon header not finalized, just skipped") continue } if err != nil { return fmt.Errorf("fetch execution header proof: %w", err) } - inboundMsg.Proof.ExecutionProof = messagePayload.HeaderPayload - - logger.WithFields(logrus.Fields{ - "EventLog": inboundMsg.EventLog, - "Proof": inboundMsg.Proof, - }).Debug("Generated message from Ethereum log") - - if messagePayload.FinalizedPayload == nil { - err = writer.WriteToParachainAndWatch(ctx, "EthereumInboundQueue.submit", inboundMsg) - if err != nil { - logger.Error("inbound message fail to send") - return fmt.Errorf("write to parachain: %w", err) - } - } else { - logger.WithFields(logrus.Fields{ - "finalized_slot": messagePayload.FinalizedPayload.Payload.FinalizedHeader.Slot, - "finalized_root": messagePayload.FinalizedPayload.FinalizedHeaderBlockRoot, - "message_slot": messagePayload.HeaderPayload.Header.Slot, - }).Debug("Batching finalized header update with message") - extrinsics := []string{"EthereumBeaconClient.submit", "EthereumInboundQueue.submit"} - payloads := []interface{}{inboundMsg, messagePayload.FinalizedPayload.Payload} - err = writer.BatchCall(ctx, extrinsics, payloads) - if err != nil { - logger.Error("batch call message fail to send") - return fmt.Errorf("write to parachain: %w", err) - } + + err = r.writeToParachain(ctx, proof, inboundMsg) + if err != nil { + return fmt.Errorf("write to parachain: %w", err) } paraNonce, _ = r.fetchLatestParachainNonce() if paraNonce != ev.Nonce { - logger.Error("inbound message sent but fail to execute") return fmt.Errorf("inbound message fail to execute") } logger.Info("inbound message executed successfully") @@ -214,6 +193,41 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { } } +func (r *Relay) writeToParachain(ctx context.Context, proof scale.ProofPayload, inboundMsg *parachain.Message) error { + inboundMsg.Proof.ExecutionProof = proof.HeaderPayload + + log.WithFields(logrus.Fields{ + "EventLog": inboundMsg.EventLog, + "Proof": inboundMsg.Proof, + }).Debug("Generated message from Ethereum log") + + // There is already a valid finalized header on-chain that can prove the message + if proof.FinalizedPayload == nil { + err := r.writer.WriteToParachainAndWatch(ctx, "EthereumInboundQueue.submit", inboundMsg) + if err != nil { + return fmt.Errorf("submit message to inbound queue: %w", err) + } + + return nil + } + + log.WithFields(logrus.Fields{ + "finalized_slot": proof.FinalizedPayload.Payload.FinalizedHeader.Slot, + "finalized_root": proof.FinalizedPayload.FinalizedHeaderBlockRoot, + "message_slot": proof.HeaderPayload.Header.Slot, + }).Debug("Batching finalized header update with message") + + extrinsics := []string{"EthereumBeaconClient.submit", "EthereumInboundQueue.submit"} + payloads := []interface{}{proof.FinalizedPayload.Payload, inboundMsg} + // Batch the finalized header update with the inbound message + err := r.writer.BatchCall(ctx, extrinsics, payloads) + if err != nil { + return fmt.Errorf("batch call containing finalized header update and inbound queue message: %w", err) + } + + return nil +} + func (r *Relay) fetchLatestParachainNonce() (uint64, error) { paraID := r.config.Source.ChannelID encodedParaID, err := types.EncodeToBytes(r.config.Source.ChannelID) From 47a073e24780e709259a0fadf29cbea372ecb421 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Mon, 27 May 2024 11:54:41 +0200 Subject: [PATCH 04/20] missing change --- relayer/relays/beacon/header/syncer/scale/beacon_scale.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relayer/relays/beacon/header/syncer/scale/beacon_scale.go b/relayer/relays/beacon/header/syncer/scale/beacon_scale.go index b18c6d520..18cd8f258 100644 --- a/relayer/relays/beacon/header/syncer/scale/beacon_scale.go +++ b/relayer/relays/beacon/header/syncer/scale/beacon_scale.go @@ -32,7 +32,7 @@ type Update struct { BlockRootsTree *ssz.Node } -type MessagePayload struct { +type ProofPayload struct { HeaderPayload HeaderUpdatePayload FinalizedPayload *Update } From 8505af30d170937228934f4b5a42efaeaf73acfa Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Mon, 27 May 2024 14:54:26 +0200 Subject: [PATCH 05/20] fixes --- relayer/relays/beacon/header/header.go | 2 +- .../relays/beacon/protocol/protocol_test.go | 44 +++++++++++++++++++ web/packages/test/config/execution-relay.json | 1 + 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/relayer/relays/beacon/header/header.go b/relayer/relays/beacon/header/header.go index 5cd2a83bc..32bb30c23 100644 --- a/relayer/relays/beacon/header/header.go +++ b/relayer/relays/beacon/header/header.go @@ -447,7 +447,7 @@ func (h *Header) FetchExecutionProof(blockRoot common.Hash) (scale.ProofPayload, // If we import the last finalized header, the gap between the finalized headers would be too large, so import // a slightly older header. if lastFinalizedHeaderState.BeaconSlot+h.protocol.SlotsPerHistoricalRoot < uint64(finalizedHeader.Slot) { - finalizedUpdate, err = h.syncer.GetFinalizedUpdateAtAttestedSlot(lastFinalizedHeaderState.BeaconSlot, lastFinalizedHeaderState.BeaconSlot+h.protocol.SlotsPerHistoricalRoot, false) + finalizedUpdate, err = h.syncer.GetFinalizedUpdateAtAttestedSlot(header.Slot, lastFinalizedHeaderState.BeaconSlot+h.protocol.SlotsPerHistoricalRoot, false) if err != nil { return scale.ProofPayload{}, fmt.Errorf("get finalized update at attested slot: %w", err) } diff --git a/relayer/relays/beacon/protocol/protocol_test.go b/relayer/relays/beacon/protocol/protocol_test.go index 2ad82608c..a8a2c5b8d 100644 --- a/relayer/relays/beacon/protocol/protocol_test.go +++ b/relayer/relays/beacon/protocol/protocol_test.go @@ -1,6 +1,7 @@ package protocol import ( + "errors" "testing" "github.com/stretchr/testify/assert" @@ -75,3 +76,46 @@ func TestCalculateNextCheckpointSlot(t *testing.T) { assert.Equal(t, tt.expected, result, "expected %t but found %t for slot %d", tt.expected, result, tt.slot) } } + +func TestSyncCommitteeBits(t *testing.T) { + values := []struct { + name string + bits string + expected bool + err error + }{ + { + name: "empty1", + bits: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + expected: false, + err: nil, + }, + { + name: "not supermajority", + bits: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + expected: false, + err: nil, + }, + { + name: "supermajority", + bits: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000", + expected: true, + err: nil, + }, + { + name: "invalid hex", + bits: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000", + expected: false, + err: errors.New("encoding/hex: odd length hex string"), + }, + } + + p := Protocol{} + p.Settings.SyncCommitteeSize = 512 + + for _, tt := range values { + result, err := p.SyncCommitteeSuperMajority(tt.bits) + assert.Equal(t, tt.err, err, "expected %t but found %t", tt.err, err) + assert.Equal(t, tt.expected, result, "expected %t but found %t", tt.expected, result) + } +} diff --git a/web/packages/test/config/execution-relay.json b/web/packages/test/config/execution-relay.json index c1e8b72f0..e1769e2f7 100644 --- a/web/packages/test/config/execution-relay.json +++ b/web/packages/test/config/execution-relay.json @@ -11,6 +11,7 @@ "endpoint": "http://127.0.0.1:9596", "stateEndpoint": "http://127.0.0.1:9596", "spec": { + "syncCommitteeSize": 512, "slotsInEpoch": 32, "epochsPerSyncCommitteePeriod": 256, "denebForkedEpoch": 0 From f327b8a18e4fdb1994d9dbf50582726a8c7c93a3 Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 May 2024 10:15:53 +0800 Subject: [PATCH 06/20] Remove lodestar from git modules & Use geth from nix package --- .gitmodules | 4 +--- flake.lock | 24 ++++++++++++++++++++--- lodestar | 2 +- scripts/init.sh | 23 ++++++++++------------ web/packages/test/scripts/build-binary.sh | 3 +-- 5 files changed, 34 insertions(+), 22 deletions(-) mode change 160000 => 120000 lodestar diff --git a/.gitmodules b/.gitmodules index e1c59569a..b87b18857 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,6 +13,4 @@ [submodule "contracts/lib/prb-math"] path = contracts/lib/prb-math url = https://github.com/PaulRBerg/prb-math -[submodule "lodestar"] - path = lodestar - url = https://github.com/Snowfork/lodestar + diff --git a/flake.lock b/flake.lock index 61b5385a7..ab1c96a30 100644 --- a/flake.lock +++ b/flake.lock @@ -1,12 +1,15 @@ { "nodes": { "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1676283394, - "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { @@ -85,6 +88,21 @@ "foundry": "foundry", "nixpkgs": "nixpkgs_2" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/lodestar b/lodestar deleted file mode 160000 index 5d93a629c..000000000 --- a/lodestar +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5d93a629c0fd1fdd32160cbf7717e7a6b22f7f2d diff --git a/lodestar b/lodestar new file mode 120000 index 000000000..3baf43d12 --- /dev/null +++ b/lodestar @@ -0,0 +1 @@ +../lodestar \ No newline at end of file diff --git a/scripts/init.sh b/scripts/init.sh index ceff160a9..c8ceec534 100755 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -11,11 +11,18 @@ pushd polkadot-sdk git checkout snowbridge popd popd - ln -sf ../polkadot-sdk polkadot-sdk -echo "Setting up submodules" -git submodule update --init --recursive || true +echo "Checkout lodestar Snowfork fork" +pushd .. + if [ ! -d "lodestar" ]; then + git clone https://github.com/Snowfork/lodestar + fi + pushd lodestar + git checkout snowbridge + popd +popd +ln -sf ../lodestar lodestar echo "Setting up git hooks" git config --local core.hooksPath hooks/ @@ -36,13 +43,3 @@ cargo install cargo-fuzz echo "Installing web packages" (cd web && pnpm install) -echo "Download geth to replace the nix version" -OS=$(uname -s | tr A-Z a-z) -MACHINE_TYPE=$(uname -m | tr A-Z a-z | sed 's/x86_64/amd64/') - -geth_package=geth-$OS-$MACHINE_TYPE-1.13.11-8f7eb9cc -curl https://gethstore.blob.core.windows.net/builds/$geth_package.tar.gz -o /tmp/geth.tar.gz || { echo 'Download failed'; exit 1; } -mkdir -p $GOPATH/bin -tar -xvf /tmp/geth.tar.gz -C $GOPATH -cp $GOPATH/$geth_package/geth $GOPATH/bin -geth version diff --git a/web/packages/test/scripts/build-binary.sh b/web/packages/test/scripts/build-binary.sh index 74ecfdaa7..837823604 100755 --- a/web/packages/test/scripts/build-binary.sh +++ b/web/packages/test/scripts/build-binary.sh @@ -17,8 +17,7 @@ build_binaries() { # Check that all 3 binaries are available and no changes made in the polkadot and substrate dirs if [[ ! -e "target/release/polkadot" || ! -e "target/release/polkadot-execute-worker" || ! -e "target/release/polkadot-prepare-worker" || "$changes_detected" -eq 1 ]]; then echo "Building polkadot binary, due to changes detected in polkadot or substrate, or binaries not found" - # Increase session length to 2 mins - ROCOCO_EPOCH_DURATION=20 cargo build --release --locked --bin polkadot --bin polkadot-execute-worker --bin polkadot-prepare-worker + cargo build --release --locked --bin polkadot --bin polkadot-execute-worker --bin polkadot-prepare-worker else echo "No changes detected in polkadot or substrate and binaries are available, not rebuilding relaychain binaries." fi From 586fd58e2e136b3736c39dff56831ca77d0f6614 Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 May 2024 10:28:53 +0800 Subject: [PATCH 07/20] Cleanup build script --- web/packages/test/scripts/build-binary.sh | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/web/packages/test/scripts/build-binary.sh b/web/packages/test/scripts/build-binary.sh index 837823604..43aa20dfb 100755 --- a/web/packages/test/scripts/build-binary.sh +++ b/web/packages/test/scripts/build-binary.sh @@ -59,25 +59,9 @@ build_relayer() { cp $relay_bin "$output_bin_dir" } -set_slot_time() { - local new_value=$1 - echo "Hack lodestar for faster slot time" - local preset_mainnet_config_file="$root_dir/lodestar/packages/config/src/chainConfig/configs/mainnet.ts" - if [[ "$(uname)" == "Darwin" && -z "${IN_NIX_SHELL:-}" ]]; then - gsed -i "s/SECONDS_PER_SLOT: .*/SECONDS_PER_SLOT: $new_value,/g" $preset_mainnet_config_file - else - sed -i "s/SECONDS_PER_SLOT: .*/SECONDS_PER_SLOT: $new_value,/g" $preset_mainnet_config_file - fi -} - build_lodestar() { if [ "$rebuild_lodestar" == "true" ]; then pushd $root_dir/lodestar - if [ "$eth_fast_mode" == "true" ]; then - set_slot_time 1 - else - set_slot_time 12 - fi yarn install && yarn run build popd fi From 74aa302c5c6e98cb425285ad97abdef13b367802 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Tue, 28 May 2024 10:31:07 +0200 Subject: [PATCH 08/20] fixes --- relayer/relays/beacon/header/header.go | 4 ++-- relayer/relays/execution/main.go | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/relayer/relays/beacon/header/header.go b/relayer/relays/beacon/header/header.go index 32bb30c23..fccb2bba6 100644 --- a/relayer/relays/beacon/header/header.go +++ b/relayer/relays/beacon/header/header.go @@ -71,7 +71,7 @@ func (h *Header) Sync(ctx context.Context, eg *errgroup.Group) error { log.Info("starting to sync finalized headers") - ticker := time.NewTicker(time.Minute * 1) + ticker := time.NewTicker(time.Minute * 5) eg.Go(func() error { for { @@ -174,7 +174,7 @@ func (h *Header) SyncFinalizedHeader(ctx context.Context) error { log.WithFields(log.Fields{ "slot": finalizedHeader.Slot, - }).Info("syncing finalized header from Ethereum beacon client") + }).Info("checking finalized header") currentSyncPeriod := h.protocol.ComputeSyncPeriodAtSlot(uint64(finalizedHeader.Slot)) lastSyncedPeriod := h.protocol.ComputeSyncPeriodAtSlot(h.cache.Finalized.LastSyncedSlot) diff --git a/relayer/relays/execution/main.go b/relayer/relays/execution/main.go index dcb7d88ad..b32bc8ad3 100644 --- a/relayer/relays/execution/main.go +++ b/relayer/relays/execution/main.go @@ -280,8 +280,6 @@ func (r *Relay) findEvents( blockNumber := latestFinalizedBlockNumber for { - log.Info("loop") - var begin uint64 if blockNumber < BlocksPerQuery { begin = 0 @@ -375,5 +373,11 @@ func (r *Relay) makeInboundMessage( return nil, err } + log.WithFields(logrus.Fields{ + "blockHash": event.Raw.BlockHash.Hex(), + "blockNumber": event.Raw.BlockNumber, + "txHash": event.Raw.TxHash.Hex(), + }).Info("found message") + return msg, nil } From 60c9d216329e78af7396f91a9ace8588e6b31528 Mon Sep 17 00:00:00 2001 From: Clara van Staden Date: Fri, 24 May 2024 19:38:58 +0200 Subject: [PATCH 09/20] apply long range sync changes --- relayer/cmd/generate_beacon_data.go | 10 +- relayer/cmd/import_beacon_state.go | 5 + relayer/relays/beacon/header/header.go | 42 +++-- relayer/relays/beacon/header/header_test.go | 10 +- relayer/relays/beacon/header/syncer/syncer.go | 172 ++++++++++++++++-- relayer/relays/beacon/state/beacon.go | 8 +- relayer/relays/beacon/state/beacon_deneb.go | 5 +- .../beacon/state/beacon_deneb_encoding.go | 2 +- .../relays/beacon/state/beacon_encoding.go | 2 +- .../test/scripts/force-beacon-checkpoint.sh | 12 ++ web/packages/test/scripts/start-polkadot.sh | 46 +++++ 11 files changed, 277 insertions(+), 37 deletions(-) create mode 100755 web/packages/test/scripts/force-beacon-checkpoint.sh create mode 100755 web/packages/test/scripts/start-polkadot.sh diff --git a/relayer/cmd/generate_beacon_data.go b/relayer/cmd/generate_beacon_data.go index 1635303ad..dfa13e860 100644 --- a/relayer/cmd/generate_beacon_data.go +++ b/relayer/cmd/generate_beacon_data.go @@ -55,6 +55,7 @@ func generateBeaconCheckpointCmd() *cobra.Command { } cmd.Flags().String("config", "/tmp/snowbridge/beacon-relay.json", "Path to the beacon relay config") + cmd.Flags().Uint64("finalized-slot", 0, "Optional finalized slot to create checkpoint at") cmd.Flags().Bool("export-json", false, "Export Json") return cmd @@ -117,6 +118,7 @@ func generateBeaconCheckpoint(cmd *cobra.Command, _ []string) error { if err != nil { return err } + finalizedSlot, _ := cmd.Flags().GetUint64("finalized-slot") viper.SetConfigFile(config) @@ -138,7 +140,13 @@ func generateBeaconCheckpoint(cmd *cobra.Command, _ []string) error { client := api.NewBeaconClient(conf.Source.Beacon.Endpoint, conf.Source.Beacon.StateEndpoint) s := syncer.New(client, &store, p) - checkPointScale, err := s.GetCheckpoint() + var checkPointScale scale.BeaconCheckpoint + if finalizedSlot == 0 { + checkPointScale, err = s.GetCheckpoint() + } else { + checkPointScale, err = s.GetCheckpointAtSlot(finalizedSlot) + } + if err != nil { return fmt.Errorf("get initial sync: %w", err) } diff --git a/relayer/cmd/import_beacon_state.go b/relayer/cmd/import_beacon_state.go index 8884b72f3..f683e48db 100644 --- a/relayer/cmd/import_beacon_state.go +++ b/relayer/cmd/import_beacon_state.go @@ -106,6 +106,11 @@ func importBeaconState(cmd *cobra.Command, _ []string) error { attestedSlot := attestedState.GetSlot() finalizedSlot := finalizedState.GetSlot() + err = syncer.ValidatePair(finalizedSlot, attestedSlot, attestedState) + if err != nil { + return fmt.Errorf("state pair validation failed: %w", err) + } + err = store.WriteEntry(attestedSlot, finalizedSlot, attestedData, finalizedData) if err != nil { return fmt.Errorf("write beacon store entry: %w", err) diff --git a/relayer/relays/beacon/header/header.go b/relayer/relays/beacon/header/header.go index fccb2bba6..a36e28cbe 100644 --- a/relayer/relays/beacon/header/header.go +++ b/relayer/relays/beacon/header/header.go @@ -23,6 +23,7 @@ import ( var ErrFinalizedHeaderUnchanged = errors.New("finalized header unchanged") var ErrFinalizedHeaderNotImported = errors.New("finalized header not imported") +var ErrInterimHeaderNotImported = errors.New("interim finalized header not imported") var ErrSyncCommitteeNotImported = errors.New("sync committee not imported") var ErrSyncCommitteeLatency = errors.New("sync committee latency found") var ErrExecutionHeaderNotImported = errors.New("execution header not imported") @@ -63,6 +64,7 @@ func (h *Header) Sync(ctx context.Context, eg *errgroup.Group) error { // Special handling here for the initial checkpoint to sync the next sync committee which is not included in initial // checkpoint. if h.isInitialSyncPeriod() { + log.Info("syncing next sync committee for initial checkpoint") err = h.SyncCommitteePeriodUpdate(ctx, latestSyncedPeriod) if err != nil { return fmt.Errorf("sync next committee for initial sync period: %w", err) @@ -128,16 +130,27 @@ func (h *Header) SyncCommitteePeriodUpdate(ctx context.Context, period uint64) e // finalized header if uint64(update.Payload.FinalizedHeader.Slot) > h.cache.Finalized.LastSyncedSlot { diff := uint64(update.Payload.FinalizedHeader.Slot) - h.cache.Finalized.LastSyncedSlot - log.WithFields(log.Fields{"diff": diff, "last_finalized_slot": h.cache.Finalized.LastSyncedSlot, "new_finalized_slot": uint64(update.Payload.FinalizedHeader.Slot)}).Info("checking max latency") - if diff > h.protocol.Settings.SlotsInEpoch*h.protocol.Settings.EpochsPerSyncCommitteePeriod { - log.Info("syncing an interim update") - err = h.syncInterimFinalizedUpdate(ctx, h.cache.Finalized.LastSyncedSlot, uint64(update.Payload.FinalizedHeader.Slot)) + minSlot := h.cache.Finalized.LastSyncedSlot + for diff > h.protocol.Settings.SlotsInEpoch*h.protocol.Settings.EpochsPerSyncCommitteePeriod { + log.WithFields(log.Fields{ + "diff": diff, + "last_finalized_slot": h.cache.Finalized.LastSyncedSlot, + "new_finalized_slot": uint64(update.Payload.FinalizedHeader.Slot), + }).Info("interim update required") + + interimUpdate, err := h.syncInterimFinalizedUpdate(ctx, minSlot, uint64(update.Payload.FinalizedHeader.Slot)) if err != nil { return fmt.Errorf("sync interim finalized header update: %w", err) } + + diff = uint64(update.Payload.FinalizedHeader.Slot) - uint64(interimUpdate.Payload.FinalizedHeader.Slot) + minSlot = uint64(update.Payload.FinalizedHeader.Slot) + h.protocol.Settings.SlotsInEpoch + log.WithFields(log.Fields{ + "new_diff": diff, + "interim_finalized_slot": uint64(interimUpdate.Payload.FinalizedHeader.Slot), + "new_finalized_slot": uint64(update.Payload.FinalizedHeader.Slot), + }).Info("interim update synced successfully") } - } else { - log.Info("interim update not required") } log.WithFields(log.Fields{ @@ -242,24 +255,29 @@ func (h *Header) SyncHeaders(ctx context.Context) error { return nil } -func (h *Header) syncInterimFinalizedUpdate(ctx context.Context, lastSyncedSlot, newCheckpointSlot uint64) error { +func (h *Header) syncInterimFinalizedUpdate(ctx context.Context, lastSyncedSlot, newCheckpointSlot uint64) (scale.Update, error) { + currentPeriod := h.protocol.ComputeSyncPeriodAtSlot(lastSyncedSlot) + // Calculate the range that the interim finalized header update may be in minSlot := newCheckpointSlot - h.protocol.SlotsPerHistoricalRoot - maxSlot := lastSyncedSlot + h.protocol.SlotsPerHistoricalRoot + maxSlot := ((currentPeriod + 1) * h.protocol.SlotsPerHistoricalRoot) - h.protocol.Settings.SlotsInEpoch // just before the new sync committee boundary finalizedUpdate, err := h.syncer.GetFinalizedUpdateAtAttestedSlot(minSlot, maxSlot, false) if err != nil { - return fmt.Errorf("get interim checkpoint to update chain (last synced slot %d, new slot: %d): %w", lastSyncedSlot, newCheckpointSlot, err) + return scale.Update{}, fmt.Errorf("get interim checkpoint to update chain (last synced slot %d, new slot: %d): %w", lastSyncedSlot, newCheckpointSlot, err) } log.WithField("slot", finalizedUpdate.Payload.FinalizedHeader.Slot).Info("syncing an interim update to on-chain") err = h.updateFinalizedHeaderOnchain(ctx, finalizedUpdate) - if err != nil { - return fmt.Errorf("update interim finalized header on-chain: %w", err) + switch { + case errors.Is(err, ErrFinalizedHeaderNotImported): + return scale.Update{}, ErrInterimHeaderNotImported + case err != nil: + return scale.Update{}, fmt.Errorf("update interim finalized header on-chain: %w", err) } - return nil + return finalizedUpdate, nil } func (h *Header) syncLaggingSyncCommitteePeriods(ctx context.Context, latestSyncedPeriod, currentSyncPeriod uint64) error { diff --git a/relayer/relays/beacon/header/header_test.go b/relayer/relays/beacon/header/header_test.go index 03b20db33..210fa16f6 100644 --- a/relayer/relays/beacon/header/header_test.go +++ b/relayer/relays/beacon/header/header_test.go @@ -68,7 +68,7 @@ func TestSyncInterimFinalizedUpdate_WithDataFromAPI(t *testing.T) { ) // Find a checkpoint for a slot that is just out of the on-chain synced finalized header block roots range - err = h.syncInterimFinalizedUpdate(context.Background(), 4563072, 4571360) + _, err = h.syncInterimFinalizedUpdate(context.Background(), 4563072, 4571360) require.NoError(t, err) } @@ -131,7 +131,7 @@ func TestSyncInterimFinalizedUpdate_WithDataFromStore(t *testing.T) { ) // Find a checkpoint for a slot that is just out of the on-chain synced finalized header block roots range - err = h.syncInterimFinalizedUpdate(context.Background(), 4563072, 4571360) + _, err = h.syncInterimFinalizedUpdate(context.Background(), 4563072, 4571360) require.NoError(t, err) } @@ -196,7 +196,7 @@ func TestSyncInterimFinalizedUpdate_WithDataFromStoreWithDifferentBlocks(t *test ) // Find a checkpoint for a slot that is just out of the on-chain synced finalized header block roots range - err = h.syncInterimFinalizedUpdate(context.Background(), 4563072, 4571360) + _, err = h.syncInterimFinalizedUpdate(context.Background(), 4563072, 4571360) require.NoError(t, err) } @@ -241,7 +241,7 @@ func TestSyncInterimFinalizedUpdate_BeaconStateNotAvailableInAPIAndStore(t *test ) // Find a checkpoint for a slot that is just out of the on-chain synced finalized header block roots range - err = h.syncInterimFinalizedUpdate(context.Background(), 4570722, 4578922) + _, err = h.syncInterimFinalizedUpdate(context.Background(), 4570722, 4578922) require.Error(t, err) } @@ -279,6 +279,6 @@ func TestSyncInterimFinalizedUpdate_NoValidBlocksFound(t *testing.T) { ) // Find a checkpoint for a slot that is just out of the on-chain synced finalized header block roots range - err = h.syncInterimFinalizedUpdate(context.Background(), 4570722, 4578922) + _, err = h.syncInterimFinalizedUpdate(context.Background(), 4570722, 4578922) require.Errorf(t, err, "cannot find blocks at boundaries") } diff --git a/relayer/relays/beacon/header/syncer/syncer.go b/relayer/relays/beacon/header/syncer/syncer.go index 40b1bea17..9e6f0e7d3 100644 --- a/relayer/relays/beacon/header/syncer/syncer.go +++ b/relayer/relays/beacon/header/syncer/syncer.go @@ -1,8 +1,10 @@ package syncer import ( + "encoding/json" "errors" "fmt" + "os" "strconv" "github.com/snowfork/go-substrate-rpc-client/v4/types" @@ -21,10 +23,11 @@ import ( ) const ( - BlockRootGeneralizedIndex = 37 - FinalizedCheckpointGeneralizedIndex = 105 - NextSyncCommitteeGeneralizedIndex = 55 - ExecutionPayloadGeneralizedIndex = 25 + BlockRootGeneralizedIndex = 37 + FinalizedCheckpointGeneralizedIndex = 105 + CurrentSyncCommitteeGeneralizedIndex = 54 + NextSyncCommitteeGeneralizedIndex = 55 + ExecutionPayloadGeneralizedIndex = 25 ) var ( @@ -95,6 +98,100 @@ func (s *Syncer) GetCheckpoint() (scale.BeaconCheckpoint, error) { }, nil } +func (s *Syncer) GetCheckpointFromFile(file string) (scale.BeaconCheckpoint, error) { + type CheckPointResponse struct { + Header api.BeaconHeader `json:"header"` + CurrentSyncCommittee api.SyncCommitteeResponse `json:"current_sync_committee"` + CurrentSyncCommitteeBranch []string `json:"current_sync_committee_branch"` + ValidatorsRoot string `json:"validators_root"` + BlockRootsRoot string `json:"block_roots_root"` + BlockRootsRootBranch []string `json:"block_roots_branch"` + } + var response CheckPointResponse + + byteValue, err := os.ReadFile(file) + if err != nil { + return scale.BeaconCheckpoint{}, err + } + + err = json.Unmarshal(byteValue, &response) + if err != nil { + return scale.BeaconCheckpoint{}, err + } + + header, err := response.Header.ToScale() + if err != nil { + return scale.BeaconCheckpoint{}, err + } + + currentSyncCommittee, err := response.CurrentSyncCommittee.ToScale() + if err != nil { + return scale.BeaconCheckpoint{}, err + } + + return scale.BeaconCheckpoint{ + Header: header, + CurrentSyncCommittee: currentSyncCommittee, + CurrentSyncCommitteeBranch: util.ProofBranchToScale(response.CurrentSyncCommitteeBranch), + ValidatorsRoot: types.H256(common.HexToHash(response.ValidatorsRoot)), + BlockRootsRoot: types.H256(common.HexToHash(response.BlockRootsRoot)), + BlockRootsBranch: util.ProofBranchToScale(response.BlockRootsRootBranch), + }, nil +} + +func (s *Syncer) GetCheckpointAtSlot(slot uint64) (scale.BeaconCheckpoint, error) { + checkpoint, err := s.GetFinalizedUpdateAtAttestedSlot(slot, slot, false) + if err != nil { + return scale.BeaconCheckpoint{}, fmt.Errorf("get finalized update at slot: %w", err) + } + + genesis, err := s.Client.GetGenesis() + if err != nil { + return scale.BeaconCheckpoint{}, fmt.Errorf("get genesis: %w", err) + } + + finalizedState, err := s.getBeaconStateAtSlot(slot) + + blockRootsProof, err := s.GetBlockRootsFromState(finalizedState) + if err != nil { + return scale.BeaconCheckpoint{}, fmt.Errorf("fetch block roots: %w", err) + } + + syncCommittee := finalizedState.GetCurrentSyncCommittee() + if err != nil { + return scale.BeaconCheckpoint{}, fmt.Errorf("convert sync committee to scale: %w", err) + } + + stateTree, err := finalizedState.GetTree() + if err != nil { + return scale.BeaconCheckpoint{}, fmt.Errorf("get state tree: %w", err) + } + + _ = stateTree.Hash() // necessary to populate the proof tree values + + proof, err := stateTree.Prove(CurrentSyncCommitteeGeneralizedIndex) + if err != nil { + return scale.BeaconCheckpoint{}, fmt.Errorf("get block roof proof: %w", err) + } + + pubkeys, err := util.ByteArrayToPublicKeyArray(syncCommittee.PubKeys) + if err != nil { + return scale.BeaconCheckpoint{}, fmt.Errorf("bytes to pubkey array: %w", err) + } + + return scale.BeaconCheckpoint{ + Header: checkpoint.Payload.FinalizedHeader, + CurrentSyncCommittee: scale.SyncCommittee{ + Pubkeys: pubkeys, + AggregatePubkey: syncCommittee.AggregatePubKey, + }, + CurrentSyncCommitteeBranch: util.BytesBranchToScale(proof.Hashes), + ValidatorsRoot: types.H256(genesis.ValidatorsRoot), + BlockRootsRoot: blockRootsProof.Leaf, + BlockRootsBranch: blockRootsProof.Proof, + }, nil +} + // GetSyncCommitteePeriodUpdate fetches a sync committee update from the light client API endpoint. If it fails // (typically because it cannot download the finalized header beacon state because the slot does not fall on a 32 // slot interval, due to a missed block), it will construct an update manually from data download from the beacon @@ -582,6 +679,37 @@ func (s *Syncer) findValidUpdatePair(slot uint64) (uint64, uint64, error) { return finalizedHeader.Slot, attestedHeader.Slot, nil } +func (s *Syncer) ValidatePair(finalizedSlot, attestedSlot uint64, attestedState state.BeaconState) error { + finalizedCheckpoint := attestedState.GetFinalizedCheckpoint() + finalizedHeader, err := s.Client.GetHeaderByBlockRoot(common.BytesToHash(finalizedCheckpoint.Root)) + if err != nil { + return fmt.Errorf("unable to download finalized header from attested state") + } + + if finalizedHeader.Slot != finalizedSlot { + return fmt.Errorf("finalized state in attested state does not match provided finalized state, attested state finalized slot: %d, finalized slot provided: %d", finalizedHeader.Slot, finalizedSlot) + } + + nextHeader, err := s.FindBeaconHeaderWithBlockIncluded(attestedSlot + 1) + if err != nil { + return fmt.Errorf("get sync aggregate header: %d err: %w", attestedSlot+1, err) + } + nextBlock, err := s.Client.GetBeaconBlockBySlot(nextHeader.Slot) + if err != nil { + return fmt.Errorf("get sync aggregate block: %d err: %w", nextHeader.Slot, err) + } + + superMajority, err := s.protocol.SyncCommitteeSuperMajority(nextBlock.Data.Message.Body.SyncAggregate.SyncCommitteeBits) + if err != nil { + return fmt.Errorf("compute sync committee supermajority: %d err: %w", nextHeader.Slot, err) + } + if !superMajority { + return fmt.Errorf("sync committee at slot not supermajority: %d", nextHeader.Slot) + } + + return nil +} + func (s *Syncer) GetFinalizedUpdateWithSyncCommittee(syncCommitteePeriod uint64) (scale.Update, error) { minSlot := syncCommitteePeriod * s.protocol.SlotsPerHistoricalRoot maxSlot := ((syncCommitteePeriod + 1) * s.protocol.SlotsPerHistoricalRoot) - s.protocol.Settings.SlotsInEpoch // just before the new sync committee boundary @@ -605,17 +733,31 @@ func (s *Syncer) GetFinalizedUpdateAtAttestedSlot(minSlot, maxSlot uint64, fetch // Try getting beacon data from the API first data, err := s.getBeaconDataFromClient(attestedSlot) if err != nil { - log.WithFields(log.Fields{"minSlot": minSlot, "maxSlot": maxSlot}).Info("attempting to find in beacon store") // If it fails, using the beacon store and look for a relevant finalized update - data, err = s.getBestMatchBeaconDataFromStore(minSlot, maxSlot) - if err != nil { - return update, fmt.Errorf("fetch beacon data from api and data store failure: %w", err) - } + for { + if minSlot > maxSlot { + return update, fmt.Errorf("find beacon state store options exhausted: %w", err) + } + + data, err = s.getBestMatchBeaconDataFromStore(minSlot, maxSlot) + if err != nil { + return update, fmt.Errorf("fetch beacon data from api and data store failure: %w", err) + } - // The datastore may not have found the attested slot we wanted, but provided another valid one - attestedSlot = data.AttestedSlot + err = s.ValidatePair(data.FinalizedHeader.Slot, data.AttestedSlot, data.AttestedState) + if err != nil { + minSlot = data.FinalizedHeader.Slot + 1 + log.WithError(err).WithField("minSlot", minSlot).Warn("pair retrieved from database invalid") + continue + } + + // The datastore may not have found the attested slot we wanted, but provided another valid one + attestedSlot = data.AttestedSlot + break + } } + log.WithFields(log.Fields{"finalizedSlot": data.FinalizedHeader.Slot, "attestedSlot": data.AttestedSlot}).Info("found slot pair for finalized update") // Finalized header proof stateTree, err := data.AttestedState.GetTree() if err != nil { @@ -634,7 +776,7 @@ func (s *Syncer) GetFinalizedUpdateAtAttestedSlot(minSlot, maxSlot uint64, fetch return update, fmt.Errorf("get finalized header proof: %w", err) } - nextSyncCommittee := data.AttestedState.GetSyncSyncCommittee() + nextSyncCommittee := data.AttestedState.GetNextSyncCommittee() syncCommitteePubKeys, err := util.ByteArrayToPublicKeyArray(nextSyncCommittee.PubKeys) nextSyncCommitteeScale = scale.OptionNextSyncCommitteeUpdatePayload{ @@ -803,18 +945,20 @@ func (s *Syncer) getBestMatchBeaconDataFromStore(minSlot, maxSlot uint64) (final return response, fmt.Errorf("fetch header: %w", err) } + if response.FinalizedHeader.Slot != response.FinalizedState.GetSlot() { + return response, fmt.Errorf("finalized slot in state does not match attested finalized state: %w", err) + } + return response, nil } func (s *Syncer) getBeaconState(slot uint64) ([]byte, error) { data, err := s.Client.GetBeaconState(strconv.FormatUint(slot, 10)) if err != nil { - log.WithFields(log.Fields{"slot": slot, "err": err}).Warn("unable to download ssz state from api, trying store") data, err = s.store.GetBeaconStateData(slot) if err != nil { return nil, fmt.Errorf("fetch beacon state from store: %w", err) } - log.WithField("slot", slot).Info("found state in store") } return data, nil } diff --git a/relayer/relays/beacon/state/beacon.go b/relayer/relays/beacon/state/beacon.go index ef0ff7539..bd0f5e890 100644 --- a/relayer/relays/beacon/state/beacon.go +++ b/relayer/relays/beacon/state/beacon.go @@ -164,7 +164,8 @@ type BeaconState interface { GetBlockRoots() [][]byte GetTree() (*ssz.Node, error) GetFinalizedCheckpoint() *Checkpoint - GetSyncSyncCommittee() *SyncCommittee + GetCurrentSyncCommittee() *SyncCommittee + GetNextSyncCommittee() *SyncCommittee } type SyncAggregate interface { @@ -318,6 +319,9 @@ func (b *BeaconStateCapellaMainnet) GetFinalizedCheckpoint() *Checkpoint { return b.FinalizedCheckpoint } -func (b *BeaconStateCapellaMainnet) GetSyncSyncCommittee() *SyncCommittee { +func (b *BeaconStateCapellaMainnet) GetNextSyncCommittee() *SyncCommittee { return b.NextSyncCommittee } +func (b *BeaconStateCapellaMainnet) GetCurrentSyncCommittee() *SyncCommittee { + return b.CurrentSyncCommittee +} diff --git a/relayer/relays/beacon/state/beacon_deneb.go b/relayer/relays/beacon/state/beacon_deneb.go index bd889c8b1..f68f43ccf 100644 --- a/relayer/relays/beacon/state/beacon_deneb.go +++ b/relayer/relays/beacon/state/beacon_deneb.go @@ -134,6 +134,9 @@ func (b *BeaconStateDenebMainnet) GetFinalizedCheckpoint() *Checkpoint { return b.FinalizedCheckpoint } -func (b *BeaconStateDenebMainnet) GetSyncSyncCommittee() *SyncCommittee { +func (b *BeaconStateDenebMainnet) GetNextSyncCommittee() *SyncCommittee { return b.NextSyncCommittee } +func (b *BeaconStateDenebMainnet) GetCurrentSyncCommittee() *SyncCommittee { + return b.CurrentSyncCommittee +} diff --git a/relayer/relays/beacon/state/beacon_deneb_encoding.go b/relayer/relays/beacon/state/beacon_deneb_encoding.go index 2ad6ca4f2..f041c55b0 100644 --- a/relayer/relays/beacon/state/beacon_deneb_encoding.go +++ b/relayer/relays/beacon/state/beacon_deneb_encoding.go @@ -1,5 +1,5 @@ // Code generated by fastssz. DO NOT EDIT. -// Hash: 2d1815cffaa3bda65721acc72bdfc0e47fdeb4193ba7500d237e58f2369c3628 +// Hash: 03b5096ab94e41e2c740924a4ae7ea8fdd515fe3dd4861032a569e28bcba8bb4 // Version: 0.1.3 package state diff --git a/relayer/relays/beacon/state/beacon_encoding.go b/relayer/relays/beacon/state/beacon_encoding.go index ce50a6e58..ea9e3b1fb 100644 --- a/relayer/relays/beacon/state/beacon_encoding.go +++ b/relayer/relays/beacon/state/beacon_encoding.go @@ -1,5 +1,5 @@ // Code generated by fastssz. DO NOT EDIT. -// Hash: 2d1815cffaa3bda65721acc72bdfc0e47fdeb4193ba7500d237e58f2369c3628 +// Hash: 03b5096ab94e41e2c740924a4ae7ea8fdd515fe3dd4861032a569e28bcba8bb4 // Version: 0.1.3 package state diff --git a/web/packages/test/scripts/force-beacon-checkpoint.sh b/web/packages/test/scripts/force-beacon-checkpoint.sh new file mode 100755 index 000000000..bd5cd1364 --- /dev/null +++ b/web/packages/test/scripts/force-beacon-checkpoint.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +source scripts/set-env.sh +source scripts/xcm-helper.sh + +pushd $root_dir +check_point_hex=$($relay_bin generate-beacon-checkpoint --finalized-slot 9043968 --config /opt/config/beacon-relay.json --export-json) +popd +transact_call="0x5200"$check_point_hex +send_governance_transact_from_relaychain $BRIDGE_HUB_PARAID "$transact_call" 180000000000 900000 diff --git a/web/packages/test/scripts/start-polkadot.sh b/web/packages/test/scripts/start-polkadot.sh new file mode 100755 index 000000000..2028e6514 --- /dev/null +++ b/web/packages/test/scripts/start-polkadot.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -eu + +start=$(date +%s) + +from_start_services=true + +source scripts/set-env.sh +source scripts/build-binary.sh + +trap kill_all SIGINT SIGTERM EXIT +cleanup + +# 0. check required tools +echo "Check building tools" +check_tool + +# 1. install binary if required +echo "Installing binaries if required" +build_binaries +build_relayer + +# 2. start polkadot +echo "Starting polkadot nodes" +source scripts/deploy-polkadot.sh +deploy_polkadot + +# 4. generate beefy checkpoint +echo "Generate beefy checkpoint" +source scripts/generate-beefy-checkpoint.sh +generate_beefy_checkpoint + +# 6. config substrate +echo "Config Substrate" +source scripts/configure-substrate.sh +configure_substrate + +echo "Prod testnet has been initialized" + +end=$(date +%s) +runtime=$((end - start)) +minutes=$(((runtime % 3600) / 60)) +seconds=$(((runtime % 3600) % 60)) +echo "Took $minutes minutes $seconds seconds" + +wait From 1a3c8daff5239bf7e8c774a2165d8b28a8961465 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Tue, 28 May 2024 11:27:27 +0200 Subject: [PATCH 10/20] add sync committee majority check --- relayer/relays/beacon/header/syncer/syncer.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/relayer/relays/beacon/header/syncer/syncer.go b/relayer/relays/beacon/header/syncer/syncer.go index 9e6f0e7d3..809ba0908 100644 --- a/relayer/relays/beacon/header/syncer/syncer.go +++ b/relayer/relays/beacon/header/syncer/syncer.go @@ -426,6 +426,19 @@ func (s *Syncer) GetFinalizedUpdate() (scale.Update, error) { return scale.Update{}, fmt.Errorf("parse signature slot as int: %w", err) } + signatureBlock, err := s.Client.GetBeaconBlockBySlot(signatureSlot) + if err != nil { + return scale.Update{}, fmt.Errorf("get signature block: %w", err) + } + + superMajority, err := s.protocol.SyncCommitteeSuperMajority(signatureBlock.Data.Message.Body.SyncAggregate.SyncCommitteeBits) + if err != nil { + return scale.Update{}, fmt.Errorf("compute sync committee supermajority: %d err: %w", signatureSlot, err) + } + if !superMajority { + return scale.Update{}, fmt.Errorf("sync committee at slot not supermajority: %d", signatureSlot) + } + updatePayload := scale.UpdatePayload{ AttestedHeader: attestedHeader, SyncAggregate: syncAggregate, From 772a68d6ede05556e8650e28f83e0f37ddcd8ffa Mon Sep 17 00:00:00 2001 From: ron Date: Fri, 31 May 2024 11:01:32 +0800 Subject: [PATCH 11/20] Build source from official repo without fork --- flake.nix | 1 + scripts/init.sh | 4 ++-- web/packages/test/scripts/build-binary.sh | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 8529150e7..c44ac3995 100644 --- a/flake.nix +++ b/flake.nix @@ -86,6 +86,7 @@ export RUSTUP_HOME=$PWD/.rustup export RUST_NIGHTLY_VERSION=nightly-2024-02-08 export PATH=$CARGO_HOME/bin:$PATH + export LODESTAR_VERSION=v1.16.0 eval "$(direnv hook bash)" diff --git a/scripts/init.sh b/scripts/init.sh index c8ceec534..40dc967d3 100755 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -16,10 +16,10 @@ ln -sf ../polkadot-sdk polkadot-sdk echo "Checkout lodestar Snowfork fork" pushd .. if [ ! -d "lodestar" ]; then - git clone https://github.com/Snowfork/lodestar + git clone https://github.com/ChainSafe/lodestar fi pushd lodestar - git checkout snowbridge + git checkout $LODESTAR_VERSION popd popd ln -sf ../lodestar lodestar diff --git a/web/packages/test/scripts/build-binary.sh b/web/packages/test/scripts/build-binary.sh index 43aa20dfb..837823604 100755 --- a/web/packages/test/scripts/build-binary.sh +++ b/web/packages/test/scripts/build-binary.sh @@ -59,9 +59,25 @@ build_relayer() { cp $relay_bin "$output_bin_dir" } +set_slot_time() { + local new_value=$1 + echo "Hack lodestar for faster slot time" + local preset_mainnet_config_file="$root_dir/lodestar/packages/config/src/chainConfig/configs/mainnet.ts" + if [[ "$(uname)" == "Darwin" && -z "${IN_NIX_SHELL:-}" ]]; then + gsed -i "s/SECONDS_PER_SLOT: .*/SECONDS_PER_SLOT: $new_value,/g" $preset_mainnet_config_file + else + sed -i "s/SECONDS_PER_SLOT: .*/SECONDS_PER_SLOT: $new_value,/g" $preset_mainnet_config_file + fi +} + build_lodestar() { if [ "$rebuild_lodestar" == "true" ]; then pushd $root_dir/lodestar + if [ "$eth_fast_mode" == "true" ]; then + set_slot_time 1 + else + set_slot_time 12 + fi yarn install && yarn run build popd fi From 11aadb8cdf04215ea85724e6889fabb51aca53c4 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Fri, 31 May 2024 08:43:04 +0200 Subject: [PATCH 12/20] update finalized header every 4 hours --- relayer/config/config.go | 1 + relayer/relays/beacon/header/header.go | 38 ++++++++++++++----- relayer/relays/beacon/header/header_test.go | 42 +++++++++++++++++++++ relayer/relays/beacon/main.go | 1 + relayer/relays/execution/main.go | 1 + web/packages/test/config/beacon-relay.json | 3 +- 6 files changed, 75 insertions(+), 11 deletions(-) diff --git a/relayer/config/config.go b/relayer/config/config.go index a2ad0161b..667521501 100644 --- a/relayer/config/config.go +++ b/relayer/config/config.go @@ -8,6 +8,7 @@ type ParachainConfig struct { Endpoint string `mapstructure:"endpoint"` MaxWatchedExtrinsics int64 `mapstructure:"maxWatchedExtrinsics"` MaxBatchCallSize int64 `mapstructure:"maxBatchCallSize"` + UpdateSlotInterval uint64 `mapstructure:"updateSlotInterval"` } type EthereumConfig struct { diff --git a/relayer/relays/beacon/header/header.go b/relayer/relays/beacon/header/header.go index a36e28cbe..15f98fec5 100644 --- a/relayer/relays/beacon/header/header.go +++ b/relayer/relays/beacon/header/header.go @@ -30,18 +30,20 @@ var ErrExecutionHeaderNotImported = errors.New("execution header not imported") var ErrBeaconHeaderNotFinalized = errors.New("beacon header not finalized") type Header struct { - cache *cache.BeaconCache - writer parachain.ChainWriter - syncer *syncer.Syncer - protocol *protocol.Protocol + cache *cache.BeaconCache + writer parachain.ChainWriter + syncer *syncer.Syncer + protocol *protocol.Protocol + updateSlotInterval uint64 } -func New(writer parachain.ChainWriter, client api.BeaconAPI, setting config.SpecSettings, store store.BeaconStore, protocol *protocol.Protocol) Header { +func New(writer parachain.ChainWriter, client api.BeaconAPI, setting config.SpecSettings, store store.BeaconStore, protocol *protocol.Protocol, updateSlotInterval uint64) Header { return Header{ - cache: cache.New(setting.SlotsInEpoch, setting.EpochsPerSyncCommitteePeriod), - writer: writer, - syncer: syncer.New(client, store, protocol), - protocol: protocol, + cache: cache.New(setting.SlotsInEpoch, setting.EpochsPerSyncCommitteePeriod), + writer: writer, + syncer: syncer.New(client, store, protocol), + protocol: protocol, + updateSlotInterval: updateSlotInterval, } } @@ -182,7 +184,7 @@ func (h *Header) SyncFinalizedHeader(ctx context.Context) error { // When the chain has been processed up until now, keep getting finalized block updates and send that to the parachain finalizedHeader, err := h.syncer.GetFinalizedHeader() if err != nil { - return fmt.Errorf("fetch finalized header update from Ethereum beacon client: %w", err) + return fmt.Errorf("fetch finalized header from Ethereum beacon client: %w", err) } log.WithFields(log.Fields{ @@ -199,6 +201,18 @@ func (h *Header) SyncFinalizedHeader(ctx context.Context) error { } } + if h.shouldUpdate(uint64(finalizedHeader.Slot), h.cache.Finalized.LastSyncedSlot) { + update, err := h.syncer.GetFinalizedUpdate() + if err != nil { + return fmt.Errorf("fetch finalized update from Ethereum beacon client: %w", err) + } + + err = h.updateFinalizedHeaderOnchain(ctx, update) + if err != nil { + return fmt.Errorf("sync finalized header on-chain: %w", err) + } + } + return nil } @@ -532,3 +546,7 @@ func (h *Header) findLatestCheckPoint(slot uint64) (state.FinalizedHeader, error return beaconState, fmt.Errorf("no checkpoint on chain for slot %d", slot) } + +func (h *Header) shouldUpdate(currentFinalizedSlot, latestSyncedSlot uint64) bool { + return currentFinalizedSlot >= latestSyncedSlot+h.updateSlotInterval +} diff --git a/relayer/relays/beacon/header/header_test.go b/relayer/relays/beacon/header/header_test.go index 210fa16f6..5ff7cee5e 100644 --- a/relayer/relays/beacon/header/header_test.go +++ b/relayer/relays/beacon/header/header_test.go @@ -10,6 +10,7 @@ import ( "github.com/snowfork/snowbridge/relayer/relays/beacon/state" "github.com/snowfork/snowbridge/relayer/relays/beacon/store" "github.com/snowfork/snowbridge/relayer/relays/testutil" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "testing" ) @@ -65,6 +66,7 @@ func TestSyncInterimFinalizedUpdate_WithDataFromAPI(t *testing.T) { settings, &beaconStore, p, + 316, ) // Find a checkpoint for a slot that is just out of the on-chain synced finalized header block roots range @@ -128,6 +130,7 @@ func TestSyncInterimFinalizedUpdate_WithDataFromStore(t *testing.T) { settings, &beaconStore, p, + 316, ) // Find a checkpoint for a slot that is just out of the on-chain synced finalized header block roots range @@ -193,6 +196,7 @@ func TestSyncInterimFinalizedUpdate_WithDataFromStoreWithDifferentBlocks(t *test settings, &beaconStore, p, + 316, ) // Find a checkpoint for a slot that is just out of the on-chain synced finalized header block roots range @@ -238,6 +242,7 @@ func TestSyncInterimFinalizedUpdate_BeaconStateNotAvailableInAPIAndStore(t *test settings, &beaconStore, p, + 316, ) // Find a checkpoint for a slot that is just out of the on-chain synced finalized header block roots range @@ -276,9 +281,46 @@ func TestSyncInterimFinalizedUpdate_NoValidBlocksFound(t *testing.T) { settings, &beaconStore, p, + 316, ) // Find a checkpoint for a slot that is just out of the on-chain synced finalized header block roots range _, err = h.syncInterimFinalizedUpdate(context.Background(), 4570722, 4578922) require.Errorf(t, err, "cannot find blocks at boundaries") } + +func TestShouldUpdate(t *testing.T) { + values := []struct { + name string + apiSlot uint64 + onChainSlot uint64 + result bool + }{ + { + name: "should sync, equal to interval", + apiSlot: 500, + onChainSlot: 200, + result: true, + }, + { + name: "should sync, large gap", + apiSlot: 800, + onChainSlot: 200, + result: true, + }, + { + name: "should not sync", + apiSlot: 500, + onChainSlot: 201, + result: false, + }, + } + + h := Header{} + h.updateSlotInterval = 300 + + for _, tt := range values { + result := h.shouldUpdate(tt.apiSlot, tt.onChainSlot) + assert.Equal(t, tt.result, result, "expected %t but found %t", tt.result, result) + } +} diff --git a/relayer/relays/beacon/main.go b/relayer/relays/beacon/main.go index 3c80885b7..cf1079aa2 100644 --- a/relayer/relays/beacon/main.go +++ b/relayer/relays/beacon/main.go @@ -67,6 +67,7 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { specSettings, &s, p, + 316, ) return headers.Sync(ctx, eg) diff --git a/relayer/relays/execution/main.go b/relayer/relays/execution/main.go index b32bc8ad3..71b3ebe01 100644 --- a/relayer/relays/execution/main.go +++ b/relayer/relays/execution/main.go @@ -98,6 +98,7 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { r.config.Source.Beacon.Spec, &store, p, + r.config.Sink.Parachain.UpdateSlotInterval, ) r.beaconHeader = &beaconHeader diff --git a/web/packages/test/config/beacon-relay.json b/web/packages/test/config/beacon-relay.json index bbc033b5c..dfe87f547 100644 --- a/web/packages/test/config/beacon-relay.json +++ b/web/packages/test/config/beacon-relay.json @@ -19,7 +19,8 @@ "parachain": { "endpoint": "ws://127.0.0.1:11144", "maxWatchedExtrinsics": 8, - "maxBatchCallSize": 8 + "maxBatchCallSize": 8, + "updateSlotInterval": 316 } } } From ecbf6c5abfffb5291be8753c48c608438eeb4089 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Fri, 31 May 2024 11:43:04 +0200 Subject: [PATCH 13/20] update js deps --- scripts/init.sh | 3 +- web/packages/test/package.json | 6 +- web/pnpm-lock.yaml | 263 +++++++++++++++++++++++++++++---- 3 files changed, 242 insertions(+), 30 deletions(-) diff --git a/scripts/init.sh b/scripts/init.sh index 40dc967d3..3439d595a 100755 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -17,12 +17,13 @@ echo "Checkout lodestar Snowfork fork" pushd .. if [ ! -d "lodestar" ]; then git clone https://github.com/ChainSafe/lodestar + ln -sf ../lodestar lodestar fi pushd lodestar + git fetch git checkout $LODESTAR_VERSION popd popd -ln -sf ../lodestar lodestar echo "Setting up git hooks" git config --local core.hooksPath hooks/ diff --git a/web/packages/test/package.json b/web/packages/test/package.json index a88880f61..11915658a 100644 --- a/web/packages/test/package.json +++ b/web/packages/test/package.json @@ -9,10 +9,10 @@ "directory": "web/packages/test" }, "devDependencies": { - "@polkadot/api": "^10.12.1", - "@polkadot/api-cli": "^0.56.2", + "@polkadot/api": "^11.2.1", + "@polkadot/api-cli": "^0.56.11", "@polkadot/keyring": "^12.6.2", - "@polkadot/types": "^10.12.1", + "@polkadot/types": "^11.2.1", "@polkadot/util": "^12.6.2", "@polkadot/util-crypto": "^12.6.2", "@types/keccak": "^3.0.1", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 61ed8fe11..e51c1f251 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -228,17 +228,17 @@ importers: packages/test: devDependencies: '@polkadot/api': - specifier: ^10.12.1 - version: 10.12.1 + specifier: ^11.2.1 + version: 11.2.1 '@polkadot/api-cli': - specifier: ^0.56.2 - version: 0.56.2 + specifier: ^0.56.11 + version: 0.56.11 '@polkadot/keyring': specifier: ^12.6.2 version: 12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2) '@polkadot/types': - specifier: ^10.12.1 - version: 10.12.1 + specifier: ^11.2.1 + version: 11.2.1 '@polkadot/util': specifier: ^12.6.2 version: 12.6.2 @@ -344,9 +344,6 @@ importers: '@types/lodash': specifier: ^4.14.186 version: 4.14.187 - '@types/node': - specifier: ^18.13.0 - version: 18.16.8 '@types/secp256k1': specifier: ^4.0.3 version: 4.0.3 @@ -384,6 +381,9 @@ importers: specifier: ^3.0.5 version: 3.0.5 devDependencies: + '@types/node': + specifier: ^18.16.8 + version: 18.19.31 '@typescript-eslint/eslint-plugin': specifier: ^5.42.0 version: 5.42.0(@typescript-eslint/parser@5.42.0)(eslint@8.26.0)(typescript@5.1.6) @@ -398,7 +398,7 @@ importers: version: 8.5.0(eslint@8.26.0) ts-node: specifier: ^10.9.1 - version: 10.9.1(@types/node@18.16.8)(typescript@5.1.6) + version: 10.9.1(@types/node@18.19.31)(typescript@5.1.6) tsconfig-paths: specifier: ^4.2.0 version: 4.2.0 @@ -1395,6 +1395,7 @@ packages: '@polkadot-api/substrate-client': 0.0.1-12c4b0432a814086c3c1a3b8052b31c72c2c9ad3.1.0 '@polkadot-api/utils': 0.0.1-12c4b0432a814086c3c1a3b8052b31c72c2c9ad3.1.0 rxjs: 7.8.1 + dev: false optional: true /@polkadot-api/client@0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0(rxjs@7.8.1): @@ -1414,12 +1415,12 @@ packages: /@polkadot-api/json-rpc-provider-proxy@0.0.1: resolution: {integrity: sha512-gmVDUP8LpCH0BXewbzqXF2sdHddq1H1q+XrAW2of+KZj4woQkIGBRGTJHeBEVHe30EB+UejR1N2dT4PO/RvDdg==} requiresBuild: true - dev: false optional: true /@polkadot-api/json-rpc-provider-proxy@0.0.1-12c4b0432a814086c3c1a3b8052b31c72c2c9ad3.1.0: resolution: {integrity: sha512-hzupcyUtObK6W1dyyeEp4BJBHRiGecB6t6YJQPk78UY1PnLsqFiboNh5doAywf+DoGBT1YXlxbYBAE3Wg43c9w==} requiresBuild: true + dev: false optional: true /@polkadot-api/json-rpc-provider-proxy@0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0: @@ -1431,12 +1432,12 @@ packages: /@polkadot-api/json-rpc-provider@0.0.1: resolution: {integrity: sha512-/SMC/l7foRjpykLTUTacIH05H3mr9ip8b5xxfwXlVezXrNVLp3Cv0GX6uItkKd+ZjzVPf3PFrDF2B2/HLSNESA==} requiresBuild: true - dev: false optional: true /@polkadot-api/json-rpc-provider@0.0.1-12c4b0432a814086c3c1a3b8052b31c72c2c9ad3.1.0: resolution: {integrity: sha512-772gcl5MXdmIvXuhJwVqM/APp+6f6ocRGfzcYoFfdghJ4A68l9ir1SDny691vcJXE8CQ7NAcz5Gl3t1Gz1MIqg==} requiresBuild: true + dev: false optional: true /@polkadot-api/json-rpc-provider@0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0: @@ -1451,7 +1452,6 @@ packages: dependencies: '@polkadot-api/substrate-bindings': 0.0.1 '@polkadot-api/utils': 0.0.1 - dev: false optional: true /@polkadot-api/metadata-builders@0.0.1-12c4b0432a814086c3c1a3b8052b31c72c2c9ad3.1.0: @@ -1460,6 +1460,7 @@ packages: dependencies: '@polkadot-api/substrate-bindings': 0.0.1-12c4b0432a814086c3c1a3b8052b31c72c2c9ad3.1.0 '@polkadot-api/utils': 0.0.1-12c4b0432a814086c3c1a3b8052b31c72c2c9ad3.1.0 + dev: false optional: true /@polkadot-api/metadata-builders@0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0: @@ -1482,7 +1483,6 @@ packages: '@polkadot-api/substrate-client': 0.0.1 '@polkadot-api/utils': 0.0.1 rxjs: 7.8.1 - dev: false optional: true /@polkadot-api/substrate-bindings@0.0.1: @@ -1493,7 +1493,6 @@ packages: '@polkadot-api/utils': 0.0.1 '@scure/base': 1.1.5 scale-ts: 1.6.0 - dev: false optional: true /@polkadot-api/substrate-bindings@0.0.1-12c4b0432a814086c3c1a3b8052b31c72c2c9ad3.1.0: @@ -1504,6 +1503,7 @@ packages: '@polkadot-api/utils': 0.0.1-12c4b0432a814086c3c1a3b8052b31c72c2c9ad3.1.0 '@scure/base': 1.1.5 scale-ts: 1.6.0 + dev: false optional: true /@polkadot-api/substrate-bindings@0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0: @@ -1520,12 +1520,12 @@ packages: /@polkadot-api/substrate-client@0.0.1: resolution: {integrity: sha512-9Bg9SGc3AwE+wXONQoW8GC00N3v6lCZLW74HQzqB6ROdcm5VAHM4CB/xRzWSUF9CXL78ugiwtHx3wBcpx4H4Wg==} requiresBuild: true - dev: false optional: true /@polkadot-api/substrate-client@0.0.1-12c4b0432a814086c3c1a3b8052b31c72c2c9ad3.1.0: resolution: {integrity: sha512-rHLhKLJxv9CSplu+tXOgpxBwYDXCh32xwbJcZqxMWlXkjoNI2OB9hulX/3GJ0NE/ngMh3DV1hrqNLmyc/8PU+A==} requiresBuild: true + dev: false optional: true /@polkadot-api/substrate-client@0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0: @@ -1537,12 +1537,12 @@ packages: /@polkadot-api/utils@0.0.1: resolution: {integrity: sha512-3j+pRmlF9SgiYDabSdZsBSsN5XHbpXOAce1lWj56IEEaFZVjsiCaxDOA7C9nCcgfVXuvnbxqqEGQvnY+QfBAUw==} requiresBuild: true - dev: false optional: true /@polkadot-api/utils@0.0.1-12c4b0432a814086c3c1a3b8052b31c72c2c9ad3.1.0: resolution: {integrity: sha512-H7hOfilvx65wYxMjAI130rK34GcAPzMEuoP5W693N0PsXYc1QeoEHSza5NSgoN1U4jGNzDBoxu0al2WGKo1B5g==} requiresBuild: true + dev: false optional: true /@polkadot-api/utils@0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0: @@ -1566,6 +1566,7 @@ packages: - bufferutil - supports-color - utf-8-validate + dev: false /@polkadot/api-augment@10.12.6: resolution: {integrity: sha512-CZHaFAd6zexk3JCm1mY5doE1E634xNpKaTGpbs61Ch285d5EqBY25GdzGNiMprNl4VyRFT4N7dXKfwEdsM6Z9w==} @@ -1601,6 +1602,23 @@ packages: - utf-8-validate dev: false + /@polkadot/api-augment@11.2.1: + resolution: {integrity: sha512-Huo457lCqeavbrf1O/2qQYGNFWURLXndW4vNkj8AP+I757WIqebhc6K3+mz+KoV1aTsX/qwaiEgeoTjrrIwcqA==} + engines: {node: '>=18'} + dependencies: + '@polkadot/api-base': 11.2.1 + '@polkadot/rpc-augment': 11.2.1 + '@polkadot/types': 11.2.1 + '@polkadot/types-augment': 11.2.1 + '@polkadot/types-codec': 11.2.1 + '@polkadot/util': 12.6.2 + tslib: 2.6.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /@polkadot/api-base@10.12.1: resolution: {integrity: sha512-USfcGxO8RBOLSwYDdUArNt9jLR/r8qVhCs8iGEGoGnaSkTcJrvT1YzZ0Qy+QF3ZjZ5GfsnzRonBg3N6drHo6fQ==} engines: {node: '>=18'} @@ -1614,6 +1632,7 @@ packages: - bufferutil - supports-color - utf-8-validate + dev: false /@polkadot/api-base@10.12.6: resolution: {integrity: sha512-6EzMettffiadB5j0X2nValtrEZJ2dKZMArfWHbSCV1QRSPOaMO3Phf/idqtF8HgBHD3FCHJ+JsZEns6xpkpteg==} @@ -1645,15 +1664,30 @@ packages: - utf-8-validate dev: false - /@polkadot/api-cli@0.56.2: - resolution: {integrity: sha512-/a2PSs7kZicjzqTmPRmDepWMRh25a3WsuJdXKlFUHxQSXMRRT4rLPpBJonkXCV8F8XE+7eDQBKMg9dVYClmV6g==} + /@polkadot/api-base@11.2.1: + resolution: {integrity: sha512-lVYTHQf8S4rpOJ9d1jvQjviHLE6zljl13vmgs+gXHGJwMAqhhNwKY3ZMQW/u/bRE2uKk0cAlahtsRtiFpjHAfw==} + engines: {node: '>=18'} + dependencies: + '@polkadot/rpc-core': 11.2.1 + '@polkadot/types': 11.2.1 + '@polkadot/util': 12.6.2 + rxjs: 7.8.1 + tslib: 2.6.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + + /@polkadot/api-cli@0.56.11: + resolution: {integrity: sha512-D/Tm9MMkgZMVqnnqK7653Cy18PF9Kt4IrT4pLSqJt8VDW7vzKHyqjH7Rbv1BDQEUVsyhc85wMwxsWncCbSAuxQ==} engines: {node: '>=18'} hasBin: true dependencies: - '@polkadot/api': 10.12.6 - '@polkadot/api-augment': 10.12.1 + '@polkadot/api': 11.2.1 + '@polkadot/api-augment': 11.2.1 '@polkadot/keyring': 12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2) - '@polkadot/types': 10.12.6 + '@polkadot/types': 11.2.1 '@polkadot/util': 12.6.2 '@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2) tslib: 2.6.2 @@ -1682,6 +1716,7 @@ packages: - bufferutil - supports-color - utf-8-validate + dev: false /@polkadot/api-derive@10.12.6: resolution: {integrity: sha512-stjciYU9caSvPrcPo40zwPu15O7Q9OK9ldMFyyQkDdUT4cCE0LHuCmTNwcm4XhQq3XXJn+e7WNdhBfquwvkuhw==} @@ -1723,6 +1758,26 @@ packages: - utf-8-validate dev: false + /@polkadot/api-derive@11.2.1: + resolution: {integrity: sha512-ts6D6tXmvhBpHDT7E03TStXfG6+/bXCvJ7HZUVNDXi4P9cToClzJVOX5uKsPI5/MUYDEq13scxPyQK63m8SsHg==} + engines: {node: '>=18'} + dependencies: + '@polkadot/api': 11.2.1 + '@polkadot/api-augment': 11.2.1 + '@polkadot/api-base': 11.2.1 + '@polkadot/rpc-core': 11.2.1 + '@polkadot/types': 11.2.1 + '@polkadot/types-codec': 11.2.1 + '@polkadot/util': 12.6.2 + '@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2) + rxjs: 7.8.1 + tslib: 2.6.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /@polkadot/api@10.12.1: resolution: {integrity: sha512-6pZPpgyxSphse9PCZ/QxUygk0BYbcCNjr5ERZZsTE/F1znZ62Ce63A8AE0bwga9ITkiVISLDSU36hghKs3tVhA==} engines: {node: '>=18'} @@ -1748,6 +1803,7 @@ packages: - bufferutil - supports-color - utf-8-validate + dev: false /@polkadot/api@10.12.6: resolution: {integrity: sha512-qWF7qFLZtpSILuPeZcvz0oCBXe89XndDjzgCnflvEVIUkQvxtFM8mDXpzI4bz8klrLYHlyFbP7HJl/xLi+XTew==} @@ -1803,6 +1859,33 @@ packages: - utf-8-validate dev: false + /@polkadot/api@11.2.1: + resolution: {integrity: sha512-NwcWadMt+mrJ3T7RuwpnaIYtH4x0eix+GiKRtLMtIO32uAfhwVyMnqvLtxDxa4XDJ/es2rtSMYG+t0b1BTM+xQ==} + engines: {node: '>=18'} + dependencies: + '@polkadot/api-augment': 11.2.1 + '@polkadot/api-base': 11.2.1 + '@polkadot/api-derive': 11.2.1 + '@polkadot/keyring': 12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2) + '@polkadot/rpc-augment': 11.2.1 + '@polkadot/rpc-core': 11.2.1 + '@polkadot/rpc-provider': 11.2.1 + '@polkadot/types': 11.2.1 + '@polkadot/types-augment': 11.2.1 + '@polkadot/types-codec': 11.2.1 + '@polkadot/types-create': 11.2.1 + '@polkadot/types-known': 11.2.1 + '@polkadot/util': 12.6.2 + '@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2) + eventemitter3: 5.0.1 + rxjs: 7.8.1 + tslib: 2.6.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /@polkadot/keyring@12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2): resolution: {integrity: sha512-O3Q7GVmRYm8q7HuB3S0+Yf/q/EB2egKRRU3fv9b3B7V+A52tKzA+vIwEmNVaD1g5FKW9oB97rmpggs0zaKFqHw==} engines: {node: '>=18'} @@ -1835,6 +1918,7 @@ packages: - bufferutil - supports-color - utf-8-validate + dev: false /@polkadot/rpc-augment@10.12.6: resolution: {integrity: sha512-MMZgdZtVygHqgsmCdKhfaN9ywf6im72xJzc9H8fkqyoJ+cGVy36uI3e8YwEM9vV6g/nallFmz4mU46u8/TjGlw==} @@ -1866,6 +1950,21 @@ packages: - utf-8-validate dev: false + /@polkadot/rpc-augment@11.2.1: + resolution: {integrity: sha512-AbkqWTnKCi71LdqFVbCyYelf5N/Wtj4jFnpRd8z7tIbbiAnNRW61dBgdF9jZ8jd9Z0JvfAmCmG17uCEdsqfNjA==} + engines: {node: '>=18'} + dependencies: + '@polkadot/rpc-core': 11.2.1 + '@polkadot/types': 11.2.1 + '@polkadot/types-codec': 11.2.1 + '@polkadot/util': 12.6.2 + tslib: 2.6.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /@polkadot/rpc-core@10.12.1: resolution: {integrity: sha512-e8UViFN4p2STOhKL5HVxMI9ugzxrq1Ir85Pxpf2N29J8h4L8RwOuc6IPyn18uuKQakkl5b7EjsE2VKecjT4iUw==} engines: {node: '>=18'} @@ -1880,6 +1979,7 @@ packages: - bufferutil - supports-color - utf-8-validate + dev: false /@polkadot/rpc-core@10.12.6: resolution: {integrity: sha512-aBXhkryv2NMNg+cWajn/G0DF13inXIW+6iZV9cGc6lfsYT9Di/sasO0EIx7UUZW3ILYQ6Gh9jRgNLkwSNlAV9Q==} @@ -1913,6 +2013,22 @@ packages: - utf-8-validate dev: false + /@polkadot/rpc-core@11.2.1: + resolution: {integrity: sha512-GHNIHDvBts6HDvySfYksuLccaVnI+fc7ubY1uYcJMoyGv9pLhMtveH4Ft7NTxqkBqopbPXZHc8ca9CaIeBVr7w==} + engines: {node: '>=18'} + dependencies: + '@polkadot/rpc-augment': 11.2.1 + '@polkadot/rpc-provider': 11.2.1 + '@polkadot/types': 11.2.1 + '@polkadot/util': 12.6.2 + rxjs: 7.8.1 + tslib: 2.6.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /@polkadot/rpc-provider@10.12.1: resolution: {integrity: sha512-fLUK/j9M/eBthx1w40NEC94wIMHbCzSEpT3jTgFHHT9fu3HrMjZZlFUXuwjGF2Dqkjj9lTuy1W0R/4kx1RMOHw==} engines: {node: '>=18'} @@ -1935,6 +2051,7 @@ packages: - bufferutil - supports-color - utf-8-validate + dev: false /@polkadot/rpc-provider@10.12.6: resolution: {integrity: sha512-xLmzb2rMQXEWQlrIDY3E3IXo1jcV9+Vy3A8zMw/s/UIrwXZ3I0TefP8+mXcqEjLkkz7zwldDQvHfdmtnxdE14g==} @@ -1984,6 +2101,30 @@ packages: - utf-8-validate dev: false + /@polkadot/rpc-provider@11.2.1: + resolution: {integrity: sha512-TO9pdxNmTweK1vi9JYUAoLr/JYJUwPJTTdrSJrmGmiNPaM7txbQVgtT4suQYflVZTgXUYR7OYQ201fH+Qb9J9w==} + engines: {node: '>=18'} + dependencies: + '@polkadot/keyring': 12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2) + '@polkadot/types': 11.2.1 + '@polkadot/types-support': 11.2.1 + '@polkadot/util': 12.6.2 + '@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2) + '@polkadot/x-fetch': 12.6.2 + '@polkadot/x-global': 12.6.2 + '@polkadot/x-ws': 12.6.2 + eventemitter3: 5.0.1 + mock-socket: 9.3.1 + nock: 13.5.4 + tslib: 2.6.2 + optionalDependencies: + '@substrate/connect': 0.8.10 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /@polkadot/types-augment@10.12.1: resolution: {integrity: sha512-FZFBP7u5fky7tB9K4D1MoKEU4yXJhysGpr+FItYFJ+y6R+R2KTA0LFjLHtGzXYmijDRNOoIdCFwRDWinkdpWZA==} engines: {node: '>=18'} @@ -1992,6 +2133,7 @@ packages: '@polkadot/types-codec': 10.12.1 '@polkadot/util': 12.6.2 tslib: 2.6.2 + dev: false /@polkadot/types-augment@10.12.6: resolution: {integrity: sha512-eUNanLs0w7SQLlsjFs7kTPfOTclfjllJxghwRqWZFHWjUbVcGcPwr8ITv/mfx1WTCqUqLMe6K8CPJ7BSggAWBA==} @@ -2013,6 +2155,16 @@ packages: tslib: 2.6.2 dev: false + /@polkadot/types-augment@11.2.1: + resolution: {integrity: sha512-3zBsuSKjZlMEeDVqPTkLnFvjPdyGcW3UBihzCgpTmXhLSuwTbsscMwKtKwIPkOHHQPYJYyZXTMkurMXCJOz2kA==} + engines: {node: '>=18'} + dependencies: + '@polkadot/types': 11.2.1 + '@polkadot/types-codec': 11.2.1 + '@polkadot/util': 12.6.2 + tslib: 2.6.2 + dev: true + /@polkadot/types-codec@10.12.1: resolution: {integrity: sha512-f6jVI0gIaPwelirtds4W3q4uLboNnzbi/2844/vwlVO4BRLvpoXU8Ee3KuUTU+Qclg14I+S0Zm491O/Op2vgGw==} engines: {node: '>=18'} @@ -2020,6 +2172,7 @@ packages: '@polkadot/util': 12.6.2 '@polkadot/x-bigint': 12.6.2 tslib: 2.6.2 + dev: false /@polkadot/types-codec@10.12.6: resolution: {integrity: sha512-yCzKdj/mLhjSG3mR1XhQdzzpAy0Exv9UuEhGQHPpdjkF0CCfVgsFoOAF3ScsSzwacJxGgxPWvlk849DfTrBYGA==} @@ -2048,6 +2201,15 @@ packages: tslib: 2.6.2 dev: false + /@polkadot/types-codec@11.2.1: + resolution: {integrity: sha512-9VRRf1g/nahAC3/VSiCSUIRL7uuup04JEZLIAG2LaDgmCBOSV9dt1Yj9114bRUrHHkeUSBmiq64+YX1hZMpQzQ==} + engines: {node: '>=18'} + dependencies: + '@polkadot/util': 12.6.2 + '@polkadot/x-bigint': 12.6.2 + tslib: 2.6.2 + dev: true + /@polkadot/types-create@10.12.1: resolution: {integrity: sha512-ZpWUNrDaJQO1iYwtOva68S2xlEzfpQOPW5IylqlnV6izmavQvClwr7i2y3vL52YjoFNa3ZPEhxvwH7o4NtWB0A==} engines: {node: '>=18'} @@ -2055,6 +2217,7 @@ packages: '@polkadot/types-codec': 10.12.1 '@polkadot/util': 12.6.2 tslib: 2.6.2 + dev: false /@polkadot/types-create@10.12.6: resolution: {integrity: sha512-byuPy7IUFjzoxG3qrP4kEScfR92KFOAkaJksNT4kDZILPCeZSPPN7cLqdejypwDBqJthTJM0LqKK4g+eHGKdvw==} @@ -2074,6 +2237,15 @@ packages: tslib: 2.6.2 dev: false + /@polkadot/types-create@11.2.1: + resolution: {integrity: sha512-Y0Zri7x6/rHURVNLMi6i1+rmJDLCn8OQl8BIvRmsIBkCYh2oCzy0g9aqVoCdm+QnoUU5ZNtu+U/gj1kL5ODivQ==} + engines: {node: '>=18'} + dependencies: + '@polkadot/types-codec': 11.2.1 + '@polkadot/util': 12.6.2 + tslib: 2.6.2 + dev: true + /@polkadot/types-known@10.12.1: resolution: {integrity: sha512-qmUZ1HqPRvgrCMmRGrJy7FYuSjACxG1Htf/SSJwfWkwR+prFXQeMmADEmG8L3d9KZ/L1Mat/MF/9it0FrzX6aA==} engines: {node: '>=18'} @@ -2084,6 +2256,7 @@ packages: '@polkadot/types-create': 10.12.1 '@polkadot/util': 12.6.2 tslib: 2.6.2 + dev: false /@polkadot/types-known@10.12.6: resolution: {integrity: sha512-E/LWfOAPUW7YKAiioY7Ax/s+G4cuNQop3U/TPPM7sxXOv9hSia2hgFjtiU4NyTRVwf1O07YASXtYSecdSgcCuQ==} @@ -2109,12 +2282,25 @@ packages: tslib: 2.6.2 dev: false + /@polkadot/types-known@11.2.1: + resolution: {integrity: sha512-dnbmVKagVI6ARuZaGMGc67HPeHGrR7/lcwfS7jGzEmRcoQk7p/UQjWfOk/LG9NzvQkmRVbE0Gqskn4VorqnTbA==} + engines: {node: '>=18'} + dependencies: + '@polkadot/networks': 12.6.2 + '@polkadot/types': 11.2.1 + '@polkadot/types-codec': 11.2.1 + '@polkadot/types-create': 11.2.1 + '@polkadot/util': 12.6.2 + tslib: 2.6.2 + dev: true + /@polkadot/types-support@10.12.1: resolution: {integrity: sha512-H9eR2BAjSjWE+eq2jYhd8w5fgdCKy8XKUWQJ6VNvgxDtVeVMoPgY4iqLFwZUeuQjFiZJVMshCR63zjlRM1x3fg==} engines: {node: '>=18'} dependencies: '@polkadot/util': 12.6.2 tslib: 2.6.2 + dev: false /@polkadot/types-support@10.12.6: resolution: {integrity: sha512-SMq/hUZJLCZXq26pNDaxgXNJqAJD8YhVXWXulCg0YvbIoVwEkFE66TEkUbtoRLKcsZXbPdxJ3JfSoa9r6Ewhnw==} @@ -2132,6 +2318,14 @@ packages: tslib: 2.6.2 dev: false + /@polkadot/types-support@11.2.1: + resolution: {integrity: sha512-VGSUDUEQjt8K3Bv8gHYAE/nD98qPPuZ2DcikM9z9isw04qj2amxZaS26+iknJ9KSCzWgrNBHjcr5Q0o76//2yA==} + engines: {node: '>=18'} + dependencies: + '@polkadot/util': 12.6.2 + tslib: 2.6.2 + dev: true + /@polkadot/types@10.12.1: resolution: {integrity: sha512-rQ3OdKPAw0YucjD+97dYoEmhKLPIGDj0jd2vIwvfazeowwy854Hp3uYcPyGBq74l5hPo+6xYMySEqq7o99Nc0Q==} engines: {node: '>=18'} @@ -2144,6 +2338,7 @@ packages: '@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2) rxjs: 7.8.1 tslib: 2.6.2 + dev: false /@polkadot/types@10.12.6: resolution: {integrity: sha512-ByjvZkKJclHSWEETk1m9HPYn/IdIyjWONOdy7Ih+/Nd0wVIahvXDYbV4CXe25xO0RhfFJzkGIZP+LFHL5F63Uw==} @@ -2173,6 +2368,20 @@ packages: tslib: 2.6.2 dev: false + /@polkadot/types@11.2.1: + resolution: {integrity: sha512-NVPhO/eFPkL8arWk4xVbsJzRdGfue3gJK+A2iYzOfCr9rDHEj99B+E2Z0Or6zDN6n+thgQYwsr19rKgXvAc18Q==} + engines: {node: '>=18'} + dependencies: + '@polkadot/keyring': 12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2) + '@polkadot/types-augment': 11.2.1 + '@polkadot/types-codec': 11.2.1 + '@polkadot/types-create': 11.2.1 + '@polkadot/util': 12.6.2 + '@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2) + rxjs: 7.8.1 + tslib: 2.6.2 + dev: true + /@polkadot/util-crypto@12.6.2(@polkadot/util@12.6.2): resolution: {integrity: sha512-FEWI/dJ7wDMNN1WOzZAjQoIcCP/3vz3wvAp5QQm+lOrzOLj0iDmaIGIcBkz8HVm3ErfSe/uKP0KS4jgV/ib+Mg==} engines: {node: '>=18'} @@ -2844,7 +3053,6 @@ packages: transitivePeerDependencies: - bufferutil - utf-8-validate - dev: false optional: true /@substrate/connect@0.8.7: @@ -2858,6 +3066,7 @@ packages: transitivePeerDependencies: - bufferutil - utf-8-validate + dev: false optional: true /@substrate/connect@0.8.8: @@ -2888,6 +3097,7 @@ packages: '@substrate/connect-known-chains': 1.1.4 rxjs: 7.8.1 smoldot: 2.0.21 + dev: false optional: true /@substrate/light-client-extension-helpers@0.0.4(smoldot@2.0.22): @@ -2921,7 +3131,6 @@ packages: '@substrate/connect-known-chains': 1.1.4 rxjs: 7.8.1 smoldot: 2.0.22 - dev: false optional: true /@substrate/ss58-registry@1.44.0: @@ -3036,6 +3245,7 @@ packages: /@types/node@18.16.8: resolution: {integrity: sha512-p0iAXcfWCOTCBbsExHIDFCfwsqFwBTgETJveKMT+Ci3LY9YqQCI91F5S+TB20+aRCXpcWfvx5Qr5EccnwCm2NA==} + dev: true /@types/node@18.19.31: resolution: {integrity: sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==} @@ -7016,6 +7226,7 @@ packages: transitivePeerDependencies: - bufferutil - utf-8-validate + dev: false optional: true /smoldot@2.0.22: @@ -7378,7 +7589,7 @@ packages: yn: 3.1.1 dev: true - /ts-node@10.9.1(@types/node@18.16.8)(typescript@5.1.6): + /ts-node@10.9.1(@types/node@18.19.31)(typescript@5.1.6): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -7397,7 +7608,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 - '@types/node': 18.16.8 + '@types/node': 18.19.31 acorn: 8.8.2 acorn-walk: 8.2.0 arg: 4.1.3 From 60d029cbf9bf05b956fcfe8b1e01265f1d80d949 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Mon, 3 Jun 2024 11:52:32 +0200 Subject: [PATCH 14/20] adds instant verification flag --- relayer/relays/beacon/header/header.go | 32 +++++++++++-------- relayer/relays/execution/config.go | 5 +-- relayer/relays/execution/main.go | 9 +++--- web/packages/test/config/execution-relay.json | 7 +++- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/relayer/relays/beacon/header/header.go b/relayer/relays/beacon/header/header.go index 15f98fec5..28dfc55f8 100644 --- a/relayer/relays/beacon/header/header.go +++ b/relayer/relays/beacon/header/header.go @@ -75,7 +75,7 @@ func (h *Header) Sync(ctx context.Context, eg *errgroup.Group) error { log.Info("starting to sync finalized headers") - ticker := time.NewTicker(time.Minute * 5) + ticker := time.NewTicker(time.Minute * 2) eg.Go(func() error { for { @@ -440,7 +440,7 @@ func (h *Header) getHeaderUpdateBySlot(slot uint64) (scale.HeaderUpdatePayload, return h.syncer.GetHeaderUpdate(blockRoot, &checkpoint) } -func (h *Header) FetchExecutionProof(blockRoot common.Hash) (scale.ProofPayload, error) { +func (h *Header) FetchExecutionProof(blockRoot common.Hash, instantVerification bool) (scale.ProofPayload, error) { header, err := h.syncer.Client.GetHeaderByBlockRoot(blockRoot) if err != nil { return scale.ProofPayload{}, fmt.Errorf("get beacon header by blockRoot: %w", err) @@ -450,6 +450,22 @@ func (h *Header) FetchExecutionProof(blockRoot common.Hash) (scale.ProofPayload, return scale.ProofPayload{}, fmt.Errorf("fetch last finalized header state: %w", err) } + // The latest finalized header on-chain is older than the header containing the message, so we need to sync the + // finalized header with the message. + finalizedHeader, err := h.syncer.GetFinalizedHeader() + if err != nil { + return scale.ProofPayload{}, err + } + + // If the header is not finalized yet, we can't do anything further. + if header.Slot > uint64(finalizedHeader.Slot) { + return scale.ProofPayload{}, fmt.Errorf("chain not finalized yet: %w", ErrBeaconHeaderNotFinalized) + } + + if header.Slot > lastFinalizedHeaderState.BeaconSlot && !instantVerification { + return scale.ProofPayload{}, fmt.Errorf("on-chain header not recent enough and instantVerification is off: %w", ErrBeaconHeaderNotFinalized) + } + // There is a finalized header on-chain that will be able to verify the header containing the message. if header.Slot <= lastFinalizedHeaderState.BeaconSlot { headerUpdate, err := h.getHeaderUpdateBySlot(header.Slot) @@ -463,18 +479,6 @@ func (h *Header) FetchExecutionProof(blockRoot common.Hash) (scale.ProofPayload, }, nil } - // The latest finalized header on-chain is older than the header containing the message, so we need to sync the - // finalized header with the message. - finalizedHeader, err := h.syncer.GetFinalizedHeader() - if err != nil { - return scale.ProofPayload{}, err - } - - // If the header is not finalized yet, we can't do anything further. - if header.Slot > uint64(finalizedHeader.Slot) { - return scale.ProofPayload{}, ErrBeaconHeaderNotFinalized - } - var finalizedUpdate scale.Update // If we import the last finalized header, the gap between the finalized headers would be too large, so import // a slightly older header. diff --git a/relayer/relays/execution/config.go b/relayer/relays/execution/config.go index 1f97b635f..61fd15180 100644 --- a/relayer/relays/execution/config.go +++ b/relayer/relays/execution/config.go @@ -6,8 +6,9 @@ import ( ) type Config struct { - Source SourceConfig `mapstructure:"source"` - Sink SinkConfig `mapstructure:"sink"` + Source SourceConfig `mapstructure:"source"` + Sink SinkConfig `mapstructure:"sink"` + InstantVerification bool `mapstructure:"instantVerification"` } type SourceConfig struct { diff --git a/relayer/relays/execution/main.go b/relayer/relays/execution/main.go index 71b3ebe01..a7b2faa99 100644 --- a/relayer/relays/execution/main.go +++ b/relayer/relays/execution/main.go @@ -122,9 +122,10 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { } log.WithFields(log.Fields{ - "channelId": types.H256(r.config.Source.ChannelID).Hex(), - "paraNonce": paraNonce, - "ethNonce": ethNonce, + "channelId": types.H256(r.config.Source.ChannelID).Hex(), + "paraNonce": paraNonce, + "ethNonce": ethNonce, + "instantVerification": r.config.InstantVerification, }).Info("Polled Nonces") if paraNonce == ethNonce { @@ -170,7 +171,7 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { } // ParentBeaconRoot in https://eips.ethereum.org/EIPS/eip-4788 from Deneb onward - proof, err := beaconHeader.FetchExecutionProof(*blockHeader.ParentBeaconRoot) + proof, err := beaconHeader.FetchExecutionProof(*blockHeader.ParentBeaconRoot, r.config.InstantVerification) if errors.Is(err, header.ErrBeaconHeaderNotFinalized) { logger.Warn("beacon header not finalized, just skipped") continue diff --git a/web/packages/test/config/execution-relay.json b/web/packages/test/config/execution-relay.json index e1769e2f7..319ef61a3 100644 --- a/web/packages/test/config/execution-relay.json +++ b/web/packages/test/config/execution-relay.json @@ -15,6 +15,10 @@ "slotsInEpoch": 32, "epochsPerSyncCommitteePeriod": 256, "denebForkedEpoch": 0 + }, + "datastore": { + "location": "/tmp/snowbridge/beaconstore", + "maxEntries": 100 } } }, @@ -24,5 +28,6 @@ "maxWatchedExtrinsics": 8, "maxBatchCallSize": 8 } - } + }, + "instantVerification": false } From 0c22608c3d77f608fb9c7eda530fbe644194e827 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Mon, 3 Jun 2024 12:46:54 +0200 Subject: [PATCH 15/20] fallback methods log error reason --- relayer/relays/beacon/header/syncer/syncer.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/relayer/relays/beacon/header/syncer/syncer.go b/relayer/relays/beacon/header/syncer/syncer.go index 809ba0908..7f23cb66e 100644 --- a/relayer/relays/beacon/header/syncer/syncer.go +++ b/relayer/relays/beacon/header/syncer/syncer.go @@ -746,6 +746,7 @@ func (s *Syncer) GetFinalizedUpdateAtAttestedSlot(minSlot, maxSlot uint64, fetch // Try getting beacon data from the API first data, err := s.getBeaconDataFromClient(attestedSlot) if err != nil { + log.WithError(err).Warn("unable to fetch beacon data from API, trying beacon store") // If it fails, using the beacon store and look for a relevant finalized update for { if minSlot > maxSlot { @@ -968,6 +969,7 @@ func (s *Syncer) getBestMatchBeaconDataFromStore(minSlot, maxSlot uint64) (final func (s *Syncer) getBeaconState(slot uint64) ([]byte, error) { data, err := s.Client.GetBeaconState(strconv.FormatUint(slot, 10)) if err != nil { + log.WithError(err).Warn("unable to fetch beacon state from API, trying beacon store") data, err = s.store.GetBeaconStateData(slot) if err != nil { return nil, fmt.Errorf("fetch beacon state from store: %w", err) From 4a76149383e09190b234cc22312ebf9325fda46d Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Mon, 3 Jun 2024 19:44:29 +0200 Subject: [PATCH 16/20] validate config files --- relayer/cmd/run/beacon/command.go | 8 +++- relayer/cmd/run/execution/command.go | 6 +++ relayer/config/config.go | 18 ++++++++ relayer/relays/beacon/config/config.go | 42 +++++++++++++++++++ relayer/relays/execution/config.go | 19 +++++++++ web/packages/test/config/execution-relay.json | 3 +- 6 files changed, 94 insertions(+), 2 deletions(-) diff --git a/relayer/cmd/run/beacon/command.go b/relayer/cmd/run/beacon/command.go index d82e6539c..906b3b95d 100644 --- a/relayer/cmd/run/beacon/command.go +++ b/relayer/cmd/run/beacon/command.go @@ -2,6 +2,7 @@ package beacon import ( "context" + "fmt" "log" "os" "os/signal" @@ -51,11 +52,16 @@ func run(_ *cobra.Command, _ []string) error { } var config config.Config - err := viper.Unmarshal(&config) + err := viper.UnmarshalExact(&config) if err != nil { return err } + err = config.Validate() + if err != nil { + return fmt.Errorf("config file validation failed: %w", err) + } + keypair, err := parachain.ResolvePrivateKey(privateKey, privateKeyFile) if err != nil { return err diff --git a/relayer/cmd/run/execution/command.go b/relayer/cmd/run/execution/command.go index 9bdc7a499..2d693012a 100644 --- a/relayer/cmd/run/execution/command.go +++ b/relayer/cmd/run/execution/command.go @@ -3,6 +3,7 @@ package execution import ( "context" "encoding/hex" + "fmt" "log" "os" "os/signal" @@ -59,6 +60,11 @@ func run(_ *cobra.Command, _ []string) error { return err } + err = config.Validate() + if err != nil { + return fmt.Errorf("config file validation failed: %w", err) + } + keypair, err := parachain.ResolvePrivateKey(privateKey, privateKeyFile) if err != nil { return err diff --git a/relayer/config/config.go b/relayer/config/config.go index 667521501..b61d4959e 100644 --- a/relayer/config/config.go +++ b/relayer/config/config.go @@ -1,5 +1,7 @@ package config +import "errors" + type PolkadotConfig struct { Endpoint string `mapstructure:"endpoint"` } @@ -17,3 +19,19 @@ type EthereumConfig struct { GasTipCap uint64 `mapstructure:"gas-tip-cap"` GasLimit uint64 `mapstructure:"gas-limit"` } + +func (p ParachainConfig) Validate() error { + if p.Endpoint == "" { + return errors.New("parachain endpoint is not set") + } + if p.UpdateSlotInterval == 0 { + return errors.New("parachain config UpdateSlotInterval is 0") + } + if p.MaxWatchedExtrinsics == 0 { + return errors.New("parachain config MaxWatchedExtrinsics is 0") + } + if p.MaxBatchCallSize == 0 { + return errors.New("parachain config MaxBatchCallSize is 0") + } + return nil +} diff --git a/relayer/relays/beacon/config/config.go b/relayer/relays/beacon/config/config.go index 95351f40a..7fe37adf8 100644 --- a/relayer/relays/beacon/config/config.go +++ b/relayer/relays/beacon/config/config.go @@ -1,6 +1,8 @@ package config import ( + "errors" + "fmt" "github.com/snowfork/snowbridge/relayer/config" ) @@ -35,3 +37,43 @@ type BeaconConfig struct { type SinkConfig struct { Parachain config.ParachainConfig `mapstructure:"parachain"` } + +func (c Config) Validate() error { + err := c.Source.Beacon.Validate() + if err != nil { + return fmt.Errorf("beacon config validation: %w", err) + } + err = c.Sink.Parachain.Validate() + if err != nil { + return fmt.Errorf("parachain config validation: %w", err) + } + return nil +} + +func (b BeaconConfig) Validate() error { + // spec settings + if b.Spec.EpochsPerSyncCommitteePeriod == 0 { + return errors.New("setting EpochsPerSyncCommitteePeriod is 0") + } + if b.Spec.SlotsInEpoch == 0 { + return errors.New("setting SlotsInEpoch is 0") + } + if b.Spec.SyncCommitteeSize == 0 { + return errors.New("setting SyncCommitteeSize is 0") + } + // data store + if b.DataStore.Location == "" { + return errors.New("datastore Location is empty") + } + if b.DataStore.MaxEntries == 0 { + return errors.New("datastore MaxEntries is 0") + } + // api endpoints + if b.Endpoint == "" { + return errors.New("beacon Endpoint is empty") + } + if b.StateEndpoint == "" { + return errors.New("beacon StateEndpoint is empty") + } + return nil +} diff --git a/relayer/relays/execution/config.go b/relayer/relays/execution/config.go index 61fd15180..54ea8bd0f 100644 --- a/relayer/relays/execution/config.go +++ b/relayer/relays/execution/config.go @@ -1,6 +1,7 @@ package execution import ( + "fmt" "github.com/snowfork/snowbridge/relayer/config" beaconconf "github.com/snowfork/snowbridge/relayer/relays/beacon/config" ) @@ -27,3 +28,21 @@ type SinkConfig struct { } type ChannelID [32]byte + +func (c Config) Validate() error { + err := c.Source.Beacon.Validate() + if err != nil { + return fmt.Errorf("beacon config validation: %w", err) + } + err = c.Sink.Parachain.Validate() + if err != nil { + return fmt.Errorf("parachain config validation: %w", err) + } + if c.Source.ChannelID == [32]byte{} { + return fmt.Errorf("channel ID is empty") + } + if c.Source.Contracts.Gateway == "" { + return fmt.Errorf("gateway contract is empty") + } + return nil +} diff --git a/web/packages/test/config/execution-relay.json b/web/packages/test/config/execution-relay.json index 319ef61a3..4705f0458 100644 --- a/web/packages/test/config/execution-relay.json +++ b/web/packages/test/config/execution-relay.json @@ -26,7 +26,8 @@ "parachain": { "endpoint": "ws://127.0.0.1:11144", "maxWatchedExtrinsics": 8, - "maxBatchCallSize": 8 + "maxBatchCallSize": 8, + "UpdateSlotInterval": 316 } }, "instantVerification": false From 6b5abcf68a94aabcece80e79a636aa3e1297320f Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Tue, 18 Jun 2024 11:15:48 +0200 Subject: [PATCH 17/20] merge damage --- web/pnpm-lock.yaml | 196 --------------------------------------------- 1 file changed, 196 deletions(-) diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 90a2b2eb6..904e46532 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -1601,23 +1601,6 @@ packages: - supports-color - utf-8-validate - /@polkadot/api-augment@11.2.1: - resolution: {integrity: sha512-Huo457lCqeavbrf1O/2qQYGNFWURLXndW4vNkj8AP+I757WIqebhc6K3+mz+KoV1aTsX/qwaiEgeoTjrrIwcqA==} - engines: {node: '>=18'} - dependencies: - '@polkadot/api-base': 11.2.1 - '@polkadot/rpc-augment': 11.2.1 - '@polkadot/types': 11.2.1 - '@polkadot/types-augment': 11.2.1 - '@polkadot/types-codec': 11.2.1 - '@polkadot/util': 12.6.2 - tslib: 2.6.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - /@polkadot/api-base@10.12.1: resolution: {integrity: sha512-USfcGxO8RBOLSwYDdUArNt9jLR/r8qVhCs8iGEGoGnaSkTcJrvT1YzZ0Qy+QF3ZjZ5GfsnzRonBg3N6drHo6fQ==} engines: {node: '>=18'} @@ -1662,21 +1645,6 @@ packages: - supports-color - utf-8-validate - /@polkadot/api-base@11.2.1: - resolution: {integrity: sha512-lVYTHQf8S4rpOJ9d1jvQjviHLE6zljl13vmgs+gXHGJwMAqhhNwKY3ZMQW/u/bRE2uKk0cAlahtsRtiFpjHAfw==} - engines: {node: '>=18'} - dependencies: - '@polkadot/rpc-core': 11.2.1 - '@polkadot/types': 11.2.1 - '@polkadot/util': 12.6.2 - rxjs: 7.8.1 - tslib: 2.6.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - /@polkadot/api-cli@0.56.11: resolution: {integrity: sha512-D/Tm9MMkgZMVqnnqK7653Cy18PF9Kt4IrT4pLSqJt8VDW7vzKHyqjH7Rbv1BDQEUVsyhc85wMwxsWncCbSAuxQ==} engines: {node: '>=18'} @@ -1755,26 +1723,6 @@ packages: - supports-color - utf-8-validate - /@polkadot/api-derive@11.2.1: - resolution: {integrity: sha512-ts6D6tXmvhBpHDT7E03TStXfG6+/bXCvJ7HZUVNDXi4P9cToClzJVOX5uKsPI5/MUYDEq13scxPyQK63m8SsHg==} - engines: {node: '>=18'} - dependencies: - '@polkadot/api': 11.2.1 - '@polkadot/api-augment': 11.2.1 - '@polkadot/api-base': 11.2.1 - '@polkadot/rpc-core': 11.2.1 - '@polkadot/types': 11.2.1 - '@polkadot/types-codec': 11.2.1 - '@polkadot/util': 12.6.2 - '@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2) - rxjs: 7.8.1 - tslib: 2.6.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - /@polkadot/api@10.12.1: resolution: {integrity: sha512-6pZPpgyxSphse9PCZ/QxUygk0BYbcCNjr5ERZZsTE/F1znZ62Ce63A8AE0bwga9ITkiVISLDSU36hghKs3tVhA==} engines: {node: '>=18'} @@ -1855,33 +1803,6 @@ packages: - supports-color - utf-8-validate - /@polkadot/api@11.2.1: - resolution: {integrity: sha512-NwcWadMt+mrJ3T7RuwpnaIYtH4x0eix+GiKRtLMtIO32uAfhwVyMnqvLtxDxa4XDJ/es2rtSMYG+t0b1BTM+xQ==} - engines: {node: '>=18'} - dependencies: - '@polkadot/api-augment': 11.2.1 - '@polkadot/api-base': 11.2.1 - '@polkadot/api-derive': 11.2.1 - '@polkadot/keyring': 12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2) - '@polkadot/rpc-augment': 11.2.1 - '@polkadot/rpc-core': 11.2.1 - '@polkadot/rpc-provider': 11.2.1 - '@polkadot/types': 11.2.1 - '@polkadot/types-augment': 11.2.1 - '@polkadot/types-codec': 11.2.1 - '@polkadot/types-create': 11.2.1 - '@polkadot/types-known': 11.2.1 - '@polkadot/util': 12.6.2 - '@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2) - eventemitter3: 5.0.1 - rxjs: 7.8.1 - tslib: 2.6.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - /@polkadot/keyring@12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2): resolution: {integrity: sha512-O3Q7GVmRYm8q7HuB3S0+Yf/q/EB2egKRRU3fv9b3B7V+A52tKzA+vIwEmNVaD1g5FKW9oB97rmpggs0zaKFqHw==} engines: {node: '>=18'} @@ -1945,21 +1866,6 @@ packages: - supports-color - utf-8-validate - /@polkadot/rpc-augment@11.2.1: - resolution: {integrity: sha512-AbkqWTnKCi71LdqFVbCyYelf5N/Wtj4jFnpRd8z7tIbbiAnNRW61dBgdF9jZ8jd9Z0JvfAmCmG17uCEdsqfNjA==} - engines: {node: '>=18'} - dependencies: - '@polkadot/rpc-core': 11.2.1 - '@polkadot/types': 11.2.1 - '@polkadot/types-codec': 11.2.1 - '@polkadot/util': 12.6.2 - tslib: 2.6.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - /@polkadot/rpc-core@10.12.1: resolution: {integrity: sha512-e8UViFN4p2STOhKL5HVxMI9ugzxrq1Ir85Pxpf2N29J8h4L8RwOuc6IPyn18uuKQakkl5b7EjsE2VKecjT4iUw==} engines: {node: '>=18'} @@ -2007,22 +1913,6 @@ packages: - supports-color - utf-8-validate - /@polkadot/rpc-core@11.2.1: - resolution: {integrity: sha512-GHNIHDvBts6HDvySfYksuLccaVnI+fc7ubY1uYcJMoyGv9pLhMtveH4Ft7NTxqkBqopbPXZHc8ca9CaIeBVr7w==} - engines: {node: '>=18'} - dependencies: - '@polkadot/rpc-augment': 11.2.1 - '@polkadot/rpc-provider': 11.2.1 - '@polkadot/types': 11.2.1 - '@polkadot/util': 12.6.2 - rxjs: 7.8.1 - tslib: 2.6.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - /@polkadot/rpc-provider@10.12.1: resolution: {integrity: sha512-fLUK/j9M/eBthx1w40NEC94wIMHbCzSEpT3jTgFHHT9fu3HrMjZZlFUXuwjGF2Dqkjj9lTuy1W0R/4kx1RMOHw==} engines: {node: '>=18'} @@ -2094,30 +1984,6 @@ packages: - supports-color - utf-8-validate - /@polkadot/rpc-provider@11.2.1: - resolution: {integrity: sha512-TO9pdxNmTweK1vi9JYUAoLr/JYJUwPJTTdrSJrmGmiNPaM7txbQVgtT4suQYflVZTgXUYR7OYQ201fH+Qb9J9w==} - engines: {node: '>=18'} - dependencies: - '@polkadot/keyring': 12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2) - '@polkadot/types': 11.2.1 - '@polkadot/types-support': 11.2.1 - '@polkadot/util': 12.6.2 - '@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2) - '@polkadot/x-fetch': 12.6.2 - '@polkadot/x-global': 12.6.2 - '@polkadot/x-ws': 12.6.2 - eventemitter3: 5.0.1 - mock-socket: 9.3.1 - nock: 13.5.4 - tslib: 2.6.2 - optionalDependencies: - '@substrate/connect': 0.8.10 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - /@polkadot/types-augment@10.12.1: resolution: {integrity: sha512-FZFBP7u5fky7tB9K4D1MoKEU4yXJhysGpr+FItYFJ+y6R+R2KTA0LFjLHtGzXYmijDRNOoIdCFwRDWinkdpWZA==} engines: {node: '>=18'} @@ -2147,16 +2013,6 @@ packages: '@polkadot/util': 12.6.2 tslib: 2.6.2 - /@polkadot/types-augment@11.2.1: - resolution: {integrity: sha512-3zBsuSKjZlMEeDVqPTkLnFvjPdyGcW3UBihzCgpTmXhLSuwTbsscMwKtKwIPkOHHQPYJYyZXTMkurMXCJOz2kA==} - engines: {node: '>=18'} - dependencies: - '@polkadot/types': 11.2.1 - '@polkadot/types-codec': 11.2.1 - '@polkadot/util': 12.6.2 - tslib: 2.6.2 - dev: true - /@polkadot/types-codec@10.12.1: resolution: {integrity: sha512-f6jVI0gIaPwelirtds4W3q4uLboNnzbi/2844/vwlVO4BRLvpoXU8Ee3KuUTU+Qclg14I+S0Zm491O/Op2vgGw==} engines: {node: '>=18'} @@ -2192,15 +2048,6 @@ packages: '@polkadot/x-bigint': 12.6.2 tslib: 2.6.2 - /@polkadot/types-codec@11.2.1: - resolution: {integrity: sha512-9VRRf1g/nahAC3/VSiCSUIRL7uuup04JEZLIAG2LaDgmCBOSV9dt1Yj9114bRUrHHkeUSBmiq64+YX1hZMpQzQ==} - engines: {node: '>=18'} - dependencies: - '@polkadot/util': 12.6.2 - '@polkadot/x-bigint': 12.6.2 - tslib: 2.6.2 - dev: true - /@polkadot/types-create@10.12.1: resolution: {integrity: sha512-ZpWUNrDaJQO1iYwtOva68S2xlEzfpQOPW5IylqlnV6izmavQvClwr7i2y3vL52YjoFNa3ZPEhxvwH7o4NtWB0A==} engines: {node: '>=18'} @@ -2227,15 +2074,6 @@ packages: '@polkadot/util': 12.6.2 tslib: 2.6.2 - /@polkadot/types-create@11.2.1: - resolution: {integrity: sha512-Y0Zri7x6/rHURVNLMi6i1+rmJDLCn8OQl8BIvRmsIBkCYh2oCzy0g9aqVoCdm+QnoUU5ZNtu+U/gj1kL5ODivQ==} - engines: {node: '>=18'} - dependencies: - '@polkadot/types-codec': 11.2.1 - '@polkadot/util': 12.6.2 - tslib: 2.6.2 - dev: true - /@polkadot/types-known@10.12.1: resolution: {integrity: sha512-qmUZ1HqPRvgrCMmRGrJy7FYuSjACxG1Htf/SSJwfWkwR+prFXQeMmADEmG8L3d9KZ/L1Mat/MF/9it0FrzX6aA==} engines: {node: '>=18'} @@ -2271,18 +2109,6 @@ packages: '@polkadot/util': 12.6.2 tslib: 2.6.2 - /@polkadot/types-known@11.2.1: - resolution: {integrity: sha512-dnbmVKagVI6ARuZaGMGc67HPeHGrR7/lcwfS7jGzEmRcoQk7p/UQjWfOk/LG9NzvQkmRVbE0Gqskn4VorqnTbA==} - engines: {node: '>=18'} - dependencies: - '@polkadot/networks': 12.6.2 - '@polkadot/types': 11.2.1 - '@polkadot/types-codec': 11.2.1 - '@polkadot/types-create': 11.2.1 - '@polkadot/util': 12.6.2 - tslib: 2.6.2 - dev: true - /@polkadot/types-support@10.12.1: resolution: {integrity: sha512-H9eR2BAjSjWE+eq2jYhd8w5fgdCKy8XKUWQJ6VNvgxDtVeVMoPgY4iqLFwZUeuQjFiZJVMshCR63zjlRM1x3fg==} engines: {node: '>=18'} @@ -2306,14 +2132,6 @@ packages: '@polkadot/util': 12.6.2 tslib: 2.6.2 - /@polkadot/types-support@11.2.1: - resolution: {integrity: sha512-VGSUDUEQjt8K3Bv8gHYAE/nD98qPPuZ2DcikM9z9isw04qj2amxZaS26+iknJ9KSCzWgrNBHjcr5Q0o76//2yA==} - engines: {node: '>=18'} - dependencies: - '@polkadot/util': 12.6.2 - tslib: 2.6.2 - dev: true - /@polkadot/types@10.12.1: resolution: {integrity: sha512-rQ3OdKPAw0YucjD+97dYoEmhKLPIGDj0jd2vIwvfazeowwy854Hp3uYcPyGBq74l5hPo+6xYMySEqq7o99Nc0Q==} engines: {node: '>=18'} @@ -2355,20 +2173,6 @@ packages: rxjs: 7.8.1 tslib: 2.6.2 - /@polkadot/types@11.2.1: - resolution: {integrity: sha512-NVPhO/eFPkL8arWk4xVbsJzRdGfue3gJK+A2iYzOfCr9rDHEj99B+E2Z0Or6zDN6n+thgQYwsr19rKgXvAc18Q==} - engines: {node: '>=18'} - dependencies: - '@polkadot/keyring': 12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2) - '@polkadot/types-augment': 11.2.1 - '@polkadot/types-codec': 11.2.1 - '@polkadot/types-create': 11.2.1 - '@polkadot/util': 12.6.2 - '@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2) - rxjs: 7.8.1 - tslib: 2.6.2 - dev: true - /@polkadot/util-crypto@12.6.2(@polkadot/util@12.6.2): resolution: {integrity: sha512-FEWI/dJ7wDMNN1WOzZAjQoIcCP/3vz3wvAp5QQm+lOrzOLj0iDmaIGIcBkz8HVm3ErfSe/uKP0KS4jgV/ib+Mg==} engines: {node: '>=18'} From e17f15980cd84c791f38da8d83287cbd198713fa Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Wed, 19 Jun 2024 09:26:06 +0200 Subject: [PATCH 18/20] validate config --- relayer/cmd/run/beefy/command.go | 8 +++++- relayer/cmd/run/execution/command.go | 3 +-- relayer/cmd/run/parachain/command.go | 9 +++++-- relayer/config/config.go | 22 +++++++++++++--- relayer/relays/beacon/config/config.go | 18 ++++++------- relayer/relays/beefy/config.go | 19 ++++++++++++++ relayer/relays/execution/config.go | 4 +-- relayer/relays/parachain/config.go | 36 ++++++++++++++++++++++++++ 8 files changed, 99 insertions(+), 20 deletions(-) diff --git a/relayer/cmd/run/beefy/command.go b/relayer/cmd/run/beefy/command.go index 302fe22ed..59f4a461b 100644 --- a/relayer/cmd/run/beefy/command.go +++ b/relayer/cmd/run/beefy/command.go @@ -2,6 +2,7 @@ package beefy import ( "context" + "fmt" "log" "os" "os/signal" @@ -50,11 +51,16 @@ func run(_ *cobra.Command, _ []string) error { } var config beefy.Config - err := viper.Unmarshal(&config) + err := viper.UnmarshalExact(&config) if err != nil { return err } + err = config.Validate() + if err != nil { + return fmt.Errorf("config file validation failed: %w", err) + } + keypair, err := ethereum.ResolvePrivateKey(privateKey, privateKeyFile, privateKeyID) if err != nil { return err diff --git a/relayer/cmd/run/execution/command.go b/relayer/cmd/run/execution/command.go index 7f901ade3..b1a12486d 100644 --- a/relayer/cmd/run/execution/command.go +++ b/relayer/cmd/run/execution/command.go @@ -42,7 +42,6 @@ func Command() *cobra.Command { cmd.Flags().StringVar(&privateKeyFile, "substrate.private-key-file", "", "The file from which to read the private key URI") cmd.Flags().StringVar(&privateKeyID, "substrate.private-key-id", "", "The secret id to lookup the private key in AWS Secrets Manager") - return cmd } @@ -58,7 +57,7 @@ func run(_ *cobra.Command, _ []string) error { } var config execution.Config - err := viper.Unmarshal(&config, viper.DecodeHook(HexHookFunc())) + err := viper.UnmarshalExact(&config, viper.DecodeHook(HexHookFunc())) if err != nil { return err } diff --git a/relayer/cmd/run/parachain/command.go b/relayer/cmd/run/parachain/command.go index 759d07ac3..7cda7872d 100644 --- a/relayer/cmd/run/parachain/command.go +++ b/relayer/cmd/run/parachain/command.go @@ -3,6 +3,7 @@ package parachain import ( "context" "encoding/hex" + "fmt" "log" "os" "os/signal" @@ -41,7 +42,6 @@ func Command() *cobra.Command { cmd.Flags().StringVar(&privateKeyFile, "ethereum.private-key-file", "", "The file from which to read the private key") cmd.Flags().StringVar(&privateKeyID, "ethereum.private-key-id", "", "The secret id to lookup the private key in AWS Secrets Manager") - return cmd } @@ -55,11 +55,16 @@ func run(_ *cobra.Command, _ []string) error { } var config parachain.Config - err := viper.Unmarshal(&config, viper.DecodeHook(HexHookFunc())) + err := viper.UnmarshalExact(&config, viper.DecodeHook(HexHookFunc())) if err != nil { return err } + err = config.Validate() + if err != nil { + return fmt.Errorf("config file validation failed: %w", err) + } + keypair, err := ethereum.ResolvePrivateKey(privateKey, privateKeyFile, privateKeyID) if err != nil { return err diff --git a/relayer/config/config.go b/relayer/config/config.go index b61d4959e..7de9054cd 100644 --- a/relayer/config/config.go +++ b/relayer/config/config.go @@ -22,16 +22,30 @@ type EthereumConfig struct { func (p ParachainConfig) Validate() error { if p.Endpoint == "" { - return errors.New("parachain endpoint is not set") + return errors.New("parachain [endpoint] config is not set") } if p.UpdateSlotInterval == 0 { - return errors.New("parachain config UpdateSlotInterval is 0") + return errors.New("parachain [updateSlotInterval] config is not set") } if p.MaxWatchedExtrinsics == 0 { - return errors.New("parachain config MaxWatchedExtrinsics is 0") + return errors.New("parachain config [maxWatchedExtrinsics] is not set") } if p.MaxBatchCallSize == 0 { - return errors.New("parachain config MaxBatchCallSize is 0") + return errors.New("parachain config [maxBatchCallSize] is not set") + } + return nil +} + +func (e EthereumConfig) Validate() error { + if e.Endpoint == "" { + return errors.New("ethereum [endpoint] config is not set") + } + return nil +} + +func (p PolkadotConfig) Validate() error { + if p.Endpoint == "" { + return errors.New("polkadot [endpoint] config is not set") } return nil } diff --git a/relayer/relays/beacon/config/config.go b/relayer/relays/beacon/config/config.go index 7fe37adf8..ea3df6534 100644 --- a/relayer/relays/beacon/config/config.go +++ b/relayer/relays/beacon/config/config.go @@ -41,11 +41,11 @@ type SinkConfig struct { func (c Config) Validate() error { err := c.Source.Beacon.Validate() if err != nil { - return fmt.Errorf("beacon config validation: %w", err) + return fmt.Errorf("source beacon config: %w", err) } err = c.Sink.Parachain.Validate() if err != nil { - return fmt.Errorf("parachain config validation: %w", err) + return fmt.Errorf("sink parachain config: %w", err) } return nil } @@ -53,27 +53,27 @@ func (c Config) Validate() error { func (b BeaconConfig) Validate() error { // spec settings if b.Spec.EpochsPerSyncCommitteePeriod == 0 { - return errors.New("setting EpochsPerSyncCommitteePeriod is 0") + return errors.New("source beacon setting [epochsPerSyncCommitteePeriod] is not set") } if b.Spec.SlotsInEpoch == 0 { - return errors.New("setting SlotsInEpoch is 0") + return errors.New("source beacon setting [slotsInEpoch] is not set") } if b.Spec.SyncCommitteeSize == 0 { - return errors.New("setting SyncCommitteeSize is 0") + return errors.New("source beacon setting [syncCommitteeSize] is not set") } // data store if b.DataStore.Location == "" { - return errors.New("datastore Location is empty") + return errors.New("source beacon datastore [location] is not set") } if b.DataStore.MaxEntries == 0 { - return errors.New("datastore MaxEntries is 0") + return errors.New("source beacon datastore [maxEntries] is not set") } // api endpoints if b.Endpoint == "" { - return errors.New("beacon Endpoint is empty") + return errors.New("source beacon setting [endpoint] is not set") } if b.StateEndpoint == "" { - return errors.New("beacon StateEndpoint is empty") + return errors.New("source beacon setting [stateEndpoint] is not set") } return nil } diff --git a/relayer/relays/beefy/config.go b/relayer/relays/beefy/config.go index b6a472bbb..cf8735a84 100644 --- a/relayer/relays/beefy/config.go +++ b/relayer/relays/beefy/config.go @@ -1,6 +1,7 @@ package beefy import ( + "fmt" "github.com/snowfork/snowbridge/relayer/config" ) @@ -26,3 +27,21 @@ type SinkConfig struct { type ContractsConfig struct { BeefyClient string `mapstructure:"BeefyClient"` } + +func (c Config) Validate() error { + err := c.Source.Polkadot.Validate() + if err != nil { + return fmt.Errorf("source polkadot config: %w", err) + } + err = c.Sink.Ethereum.Validate() + if err != nil { + return fmt.Errorf("sink ethereum config: %w", err) + } + if c.Sink.DescendantsUntilFinal == 0 { + return fmt.Errorf("sink ethereum setting [descendants-until-final] is not set") + } + if c.Sink.Contracts.BeefyClient == "" { + return fmt.Errorf("sink contracts setting [BeefyClient] is not set") + } + return nil +} diff --git a/relayer/relays/execution/config.go b/relayer/relays/execution/config.go index 54ea8bd0f..6a474e8ba 100644 --- a/relayer/relays/execution/config.go +++ b/relayer/relays/execution/config.go @@ -39,10 +39,10 @@ func (c Config) Validate() error { return fmt.Errorf("parachain config validation: %w", err) } if c.Source.ChannelID == [32]byte{} { - return fmt.Errorf("channel ID is empty") + return fmt.Errorf("source setting [channel-id] is not set") } if c.Source.Contracts.Gateway == "" { - return fmt.Errorf("gateway contract is empty") + return fmt.Errorf("source setting [gateway] is not set") } return nil } diff --git a/relayer/relays/parachain/config.go b/relayer/relays/parachain/config.go index e4eafb388..fcd8a32e4 100644 --- a/relayer/relays/parachain/config.go +++ b/relayer/relays/parachain/config.go @@ -1,6 +1,7 @@ package parachain import ( + "fmt" "github.com/snowfork/snowbridge/relayer/config" ) @@ -32,3 +33,38 @@ type SinkContractsConfig struct { } type ChannelID [32]byte + +func (c Config) Validate() error { + // Source + err := c.Source.Polkadot.Validate() + if err != nil { + return fmt.Errorf("source polkadot config: %w", err) + } + err = c.Source.Parachain.Validate() + if err != nil { + return fmt.Errorf("source parachain config: %w", err) + } + err = c.Source.Ethereum.Validate() + if err != nil { + return fmt.Errorf("source ethereum config: %w", err) + } + if c.Source.Contracts.BeefyClient == "" { + return fmt.Errorf("source contracts setting [BeefyClient] is not set") + } + if c.Source.Contracts.Gateway == "" { + return fmt.Errorf("source contracts setting [Gateway] is not set") + } + if c.Source.ChannelID == [32]byte{} { + return fmt.Errorf("source setting [channel-id] is not set") + } + + // Sink + err = c.Sink.Ethereum.Validate() + if err != nil { + return fmt.Errorf("sink ethereum config: %w", err) + } + if c.Sink.Contracts.Gateway == "" { + return fmt.Errorf("sink contracts setting [Gateway] is not set") + } + return nil +} From 7b5936711f4b4d4c1d83ecf8aeb58d8c894925b5 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Wed, 19 Jun 2024 16:27:02 +0200 Subject: [PATCH 19/20] config cleanup --- relayer/chain/parachain/writer.go | 5 +---- relayer/cmd/import_execution_header.go | 2 +- relayer/config/config.go | 16 ++++------------ relayer/relays/beacon/config/config.go | 6 +++++- relayer/relays/beacon/main.go | 3 +-- relayer/relays/execution/main.go | 3 +-- web/packages/test/config/beacon-relay.json | 7 +++---- web/packages/test/config/execution-relay.json | 4 +--- web/packages/test/config/parachain-relay.json | 4 ++-- web/packages/test/scripts/start-relayer.sh | 1 - 10 files changed, 19 insertions(+), 32 deletions(-) diff --git a/relayer/chain/parachain/writer.go b/relayer/chain/parachain/writer.go index 94bc82367..387734517 100644 --- a/relayer/chain/parachain/writer.go +++ b/relayer/chain/parachain/writer.go @@ -34,19 +34,16 @@ type ParachainWriter struct { pool *ExtrinsicPool genesisHash types.Hash maxWatchedExtrinsics int64 - maxBatchCallSize int64 mu sync.Mutex } func NewParachainWriter( conn *Connection, maxWatchedExtrinsics int64, - maxBatchCallSize int64, ) *ParachainWriter { return &ParachainWriter{ conn: conn, maxWatchedExtrinsics: maxWatchedExtrinsics, - maxBatchCallSize: maxBatchCallSize, } } @@ -70,7 +67,7 @@ func (wr *ParachainWriter) Start(ctx context.Context, eg *errgroup.Group) error } func (wr *ParachainWriter) BatchCall(ctx context.Context, extrinsic []string, calls []interface{}) error { - batchSize := int(wr.maxBatchCallSize) + batchSize := int(wr.maxWatchedExtrinsics) var j int for i := 0; i < len(calls); i += batchSize { j += batchSize diff --git a/relayer/cmd/import_execution_header.go b/relayer/cmd/import_execution_header.go index 121fac298..c003131e9 100644 --- a/relayer/cmd/import_execution_header.go +++ b/relayer/cmd/import_execution_header.go @@ -101,7 +101,7 @@ func importExecutionHeaderFn(cmd *cobra.Command, _ []string) error { return fmt.Errorf("connect to parachain: %w", err) } - writer := parachain.NewParachainWriter(paraconn, 8, 8) + writer := parachain.NewParachainWriter(paraconn, 8) err = writer.Start(ctx, eg) if err != nil { return fmt.Errorf("start parachain conn: %w", err) diff --git a/relayer/config/config.go b/relayer/config/config.go index 7de9054cd..71a19a1ca 100644 --- a/relayer/config/config.go +++ b/relayer/config/config.go @@ -9,8 +9,6 @@ type PolkadotConfig struct { type ParachainConfig struct { Endpoint string `mapstructure:"endpoint"` MaxWatchedExtrinsics int64 `mapstructure:"maxWatchedExtrinsics"` - MaxBatchCallSize int64 `mapstructure:"maxBatchCallSize"` - UpdateSlotInterval uint64 `mapstructure:"updateSlotInterval"` } type EthereumConfig struct { @@ -22,30 +20,24 @@ type EthereumConfig struct { func (p ParachainConfig) Validate() error { if p.Endpoint == "" { - return errors.New("parachain [endpoint] config is not set") - } - if p.UpdateSlotInterval == 0 { - return errors.New("parachain [updateSlotInterval] config is not set") + return errors.New("[endpoint] is not set") } if p.MaxWatchedExtrinsics == 0 { - return errors.New("parachain config [maxWatchedExtrinsics] is not set") - } - if p.MaxBatchCallSize == 0 { - return errors.New("parachain config [maxBatchCallSize] is not set") + return errors.New("[maxWatchedExtrinsics] is not set") } return nil } func (e EthereumConfig) Validate() error { if e.Endpoint == "" { - return errors.New("ethereum [endpoint] config is not set") + return errors.New("[endpoint] config is not set") } return nil } func (p PolkadotConfig) Validate() error { if p.Endpoint == "" { - return errors.New("polkadot [endpoint] config is not set") + return errors.New("[endpoint] config is not set") } return nil } diff --git a/relayer/relays/beacon/config/config.go b/relayer/relays/beacon/config/config.go index ea3df6534..1e3b46559 100644 --- a/relayer/relays/beacon/config/config.go +++ b/relayer/relays/beacon/config/config.go @@ -35,7 +35,8 @@ type BeaconConfig struct { } type SinkConfig struct { - Parachain config.ParachainConfig `mapstructure:"parachain"` + Parachain config.ParachainConfig `mapstructure:"parachain"` + UpdateSlotInterval uint64 `mapstructure:"updateSlotInterval"` } func (c Config) Validate() error { @@ -47,6 +48,9 @@ func (c Config) Validate() error { if err != nil { return fmt.Errorf("sink parachain config: %w", err) } + if c.Sink.UpdateSlotInterval == 0 { + return errors.New("parachain [updateSlotInterval] config is not set") + } return nil } diff --git a/relayer/relays/beacon/main.go b/relayer/relays/beacon/main.go index cf1079aa2..2fc42223f 100644 --- a/relayer/relays/beacon/main.go +++ b/relayer/relays/beacon/main.go @@ -44,7 +44,6 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { writer := parachain.NewParachainWriter( paraconn, r.config.Sink.Parachain.MaxWatchedExtrinsics, - r.config.Sink.Parachain.MaxBatchCallSize, ) p := protocol.New(specSettings) @@ -67,7 +66,7 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { specSettings, &s, p, - 316, + r.config.Sink.UpdateSlotInterval, ) return headers.Sync(ctx, eg) diff --git a/relayer/relays/execution/main.go b/relayer/relays/execution/main.go index a7b2faa99..c16c03270 100644 --- a/relayer/relays/execution/main.go +++ b/relayer/relays/execution/main.go @@ -64,7 +64,6 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { r.writer = parachain.NewParachainWriter( paraconn, r.config.Sink.Parachain.MaxWatchedExtrinsics, - r.config.Sink.Parachain.MaxBatchCallSize, ) err = r.writer.Start(ctx, eg) @@ -98,7 +97,7 @@ func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { r.config.Source.Beacon.Spec, &store, p, - r.config.Sink.Parachain.UpdateSlotInterval, + 0, // setting is not used in the execution relay ) r.beaconHeader = &beaconHeader diff --git a/web/packages/test/config/beacon-relay.json b/web/packages/test/config/beacon-relay.json index dfe87f547..6528c4986 100644 --- a/web/packages/test/config/beacon-relay.json +++ b/web/packages/test/config/beacon-relay.json @@ -18,9 +18,8 @@ "sink": { "parachain": { "endpoint": "ws://127.0.0.1:11144", - "maxWatchedExtrinsics": 8, - "maxBatchCallSize": 8, - "updateSlotInterval": 316 - } + "maxWatchedExtrinsics": 8 + }, + "updateSlotInterval": 316 } } diff --git a/web/packages/test/config/execution-relay.json b/web/packages/test/config/execution-relay.json index 4705f0458..2d3d66c90 100644 --- a/web/packages/test/config/execution-relay.json +++ b/web/packages/test/config/execution-relay.json @@ -25,9 +25,7 @@ "sink": { "parachain": { "endpoint": "ws://127.0.0.1:11144", - "maxWatchedExtrinsics": 8, - "maxBatchCallSize": 8, - "UpdateSlotInterval": 316 + "maxWatchedExtrinsics": 8 } }, "instantVerification": false diff --git a/web/packages/test/config/parachain-relay.json b/web/packages/test/config/parachain-relay.json index 8348c60db..8af630607 100644 --- a/web/packages/test/config/parachain-relay.json +++ b/web/packages/test/config/parachain-relay.json @@ -7,13 +7,13 @@ "endpoint": "ws://127.0.0.1:9944" }, "parachain": { - "endpoint": "ws://127.0.0.1:11144" + "endpoint": "ws://127.0.0.1:11144", + "maxWatchedExtrinsics": 8 }, "contracts": { "BeefyClient": null, "Gateway": null }, - "beefy-activation-block": 0, "channel-id": null }, "sink": { diff --git a/web/packages/test/scripts/start-relayer.sh b/web/packages/test/scripts/start-relayer.sh index 029397b69..cb1a2b392 100755 --- a/web/packages/test/scripts/start-relayer.sh +++ b/web/packages/test/scripts/start-relayer.sh @@ -11,7 +11,6 @@ config_relayer() { --arg eth_gas_limit $eth_gas_limit \ ' .sink.contracts.BeefyClient = $k1 - | .source.ethereum.endpoint = $eth_endpoint_ws | .sink.ethereum.endpoint = $eth_endpoint_ws | .sink.ethereum."gas-limit" = $eth_gas_limit ' \ From 295367427c7956855e011536a75a38a2585c5aa6 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Thu, 20 Jun 2024 08:57:33 +0200 Subject: [PATCH 20/20] rollback forge version --- flake.lock | 6 +++--- smoketest/Cargo.lock | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 0d3db2b06..ab1c96a30 100644 --- a/flake.lock +++ b/flake.lock @@ -39,11 +39,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1717405880, - "narHash": "sha256-qcXXOnRSl0sGKm7JknntBU4su8/342YKZvjklHsIl+Q=", + "lastModified": 1714727549, + "narHash": "sha256-CWXRTxxcgMfQubJugpeg3yVWIfm70MYTtgaKWKgD60U=", "owner": "shazow", "repo": "foundry.nix", - "rev": "708c0df1e36b5185a727a3c517a5100e46392792", + "rev": "47cf189ec395eda4b3e0623179d1075c8027ca97", "type": "github" }, "original": { diff --git a/smoketest/Cargo.lock b/smoketest/Cargo.lock index 3d39e0475..b7bc5bd1c 100644 --- a/smoketest/Cargo.lock +++ b/smoketest/Cargo.lock @@ -4439,9 +4439,8 @@ dependencies = [ [[package]] name = "sp-arithmetic" -version = "23.0.0" +version = "24.0.0" dependencies = [ - "docify", "integer-sqrt", "num-traits", "parity-scale-codec", @@ -4768,15 +4767,16 @@ dependencies = [ [[package]] name = "sp-weights" -version = "27.0.0" +version = "28.0.0" dependencies = [ "bounded-collections", "parity-scale-codec", "scale-info", "serde", "smallvec", - "sp-arithmetic 23.0.0", + "sp-arithmetic 24.0.0", "sp-debug-derive 14.0.0", + "sp-std 14.0.0", ] [[package]] @@ -4840,7 +4840,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "staging-xcm" -version = "7.0.0" +version = "8.0.1" dependencies = [ "array-bytes", "bounded-collections", @@ -4851,7 +4851,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-weights 27.0.0", + "sp-weights 28.0.0", "xcm-procedural", ] @@ -6247,7 +6247,7 @@ dependencies = [ [[package]] name = "xcm-procedural" -version = "7.0.0" +version = "8.0.0" dependencies = [ "Inflector", "proc-macro2",