diff --git a/.gitignore b/.gitignore index 2c869ceadb307..fe33b7c0ebcb6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ workspace.code-workspace # Node modules node_modules/ + +#Intellij project file +.idea \ No newline at end of file diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 2983ce74a89ad..7117be95471d5 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -9819,9 +9819,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.82" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ "itoa 1.0.1", "ryu", diff --git a/parachain/pallets/ethereum-beacon-client/Cargo.toml b/parachain/pallets/ethereum-beacon-client/Cargo.toml index fb99ca826c91f..bc770b73a84a6 100644 --- a/parachain/pallets/ethereum-beacon-client/Cargo.toml +++ b/parachain/pallets/ethereum-beacon-client/Cargo.toml @@ -62,3 +62,4 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] +minimal = [] diff --git a/parachain/pallets/ethereum-beacon-client/src/config.rs b/parachain/pallets/ethereum-beacon-client/src/config.rs index 2254461d8a544..0caa56735503e 100644 --- a/parachain/pallets/ethereum-beacon-client/src/config.rs +++ b/parachain/pallets/ethereum-beacon-client/src/config.rs @@ -1,17 +1,39 @@ -pub const MAX_PROPOSER_SLASHINGS: usize = 16; +#[cfg(feature = "minimal")] +mod minimal; -pub const MAX_ATTESTER_SLASHINGS: usize = 2; +#[cfg(not(feature = "minimal"))] +mod mainnet; -pub const MAX_ATTESTATIONS: usize = 128; +#[cfg(feature = "minimal")] +pub use minimal::*; -pub const MAX_DEPOSITS: usize = 16; +#[cfg(not(feature = "minimal"))] +pub use mainnet::*; -pub const MAX_VOLUNTARY_EXITS: usize = 16; +use snowbridge_beacon_primitives::ForkVersion; + +pub const CURRENT_SYNC_COMMITTEE_INDEX: u64 = 22; +pub const CURRENT_SYNC_COMMITTEE_DEPTH: u64 = 5; + +pub const NEXT_SYNC_COMMITTEE_DEPTH: u64 = 5; +pub const NEXT_SYNC_COMMITTEE_INDEX: u64 = 23; + +pub const FINALIZED_ROOT_DEPTH: u64 = 6; +pub const FINALIZED_ROOT_INDEX: u64 = 41; +pub const MAX_PROPOSER_SLASHINGS: usize = 16; +pub const MAX_ATTESTER_SLASHINGS: usize = 2; +pub const MAX_ATTESTATIONS: usize = 128; +pub const MAX_DEPOSITS: usize = 16; +pub const MAX_VOLUNTARY_EXITS: usize = 16; pub const MAX_VALIDATORS_PER_COMMITTEE: usize = 2048; +pub const MAX_EXTRA_DATA_BYTES: usize = 32; pub const DEPOSIT_CONTRACT_TREE_DEPTH: usize = 32; -pub const MAX_EXTRA_DATA_BYTES: usize = 32; +/// GENESIS_FORK_VERSION('0x00000000') +pub const GENESIS_FORK_VERSION: ForkVersion = [30, 30, 30, 30]; -pub const SYNC_COMMITTEE_SIZE: usize = 512; +/// DomainType('0x07000000') +/// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#domain-types +pub const DOMAIN_SYNC_COMMITTEE: [u8; 4] = [7, 0, 0, 0]; \ No newline at end of file diff --git a/parachain/pallets/ethereum-beacon-client/src/config/mainnet.rs b/parachain/pallets/ethereum-beacon-client/src/config/mainnet.rs new file mode 100644 index 0000000000000..e6870c4c66d2b --- /dev/null +++ b/parachain/pallets/ethereum-beacon-client/src/config/mainnet.rs @@ -0,0 +1,3 @@ +pub const SLOTS_PER_EPOCH: u64 = 32; +pub const EPOCHS_PER_SYNC_COMMITTEE_PERIOD: u64 = 256; +pub const SYNC_COMMITTEE_SIZE: usize = 512; \ No newline at end of file diff --git a/parachain/pallets/ethereum-beacon-client/src/config/minimal.rs b/parachain/pallets/ethereum-beacon-client/src/config/minimal.rs new file mode 100644 index 0000000000000..1c5feada2eaf0 --- /dev/null +++ b/parachain/pallets/ethereum-beacon-client/src/config/minimal.rs @@ -0,0 +1,3 @@ +pub const SLOTS_PER_EPOCH: u64 = 8; +pub const EPOCHS_PER_SYNC_COMMITTEE_PERIOD: u64 = 8; +pub const SYNC_COMMITTEE_SIZE: usize = 32; \ No newline at end of file diff --git a/parachain/pallets/ethereum-beacon-client/src/lib.rs b/parachain/pallets/ethereum-beacon-client/src/lib.rs index 01adb2ef19430..681824ebf4cfa 100644 --- a/parachain/pallets/ethereum-beacon-client/src/lib.rs +++ b/parachain/pallets/ethereum-beacon-client/src/lib.rs @@ -2,12 +2,12 @@ #![cfg_attr(not(feature = "std"), no_std)] mod merkleization; +pub mod config; #[cfg(test)] mod mock; #[cfg(test)] mod tests; mod ssz; -mod config; use codec::{Decode, Encode}; use frame_support::{dispatch::DispatchResult, log, transactional}; @@ -17,31 +17,9 @@ use sp_core::H256; use sp_io::hashing::sha2_256; use sp_runtime::RuntimeDebug; use sp_std::prelude::*; -use snowbridge_beacon_primitives::{SyncCommittee, BeaconHeader, SyncAggregate, ForkData, Root, Domain, PublicKey, SigningData, ExecutionHeader, BeaconBlock}; +use snowbridge_beacon_primitives::{SyncCommittee, BeaconHeader, SyncAggregate, ForkData, Root, Domain, PublicKey, SigningData, ExecutionHeader, BeaconBlock, ProofBranch, ForkVersion}; use snowbridge_core::{Message, Verifier}; - -const SLOTS_PER_EPOCH: u64 = 32; - -const EPOCHS_PER_SYNC_COMMITTEE_PERIOD: u64 = 256; - -const CURRENT_SYNC_COMMITTEE_INDEX: u64 = 22; -const CURRENT_SYNC_COMMITTEE_DEPTH: u64 = 5; - -const NEXT_SYNC_COMMITTEE_DEPTH: u64 = 5; -const NEXT_SYNC_COMMITTEE_INDEX: u64 = 23; - -const FINALIZED_ROOT_DEPTH: u64 = 6; -const FINALIZED_ROOT_INDEX: u64 = 41; - -/// GENESIS_FORK_VERSION('0x00000000') -const GENESIS_FORK_VERSION: ForkVersion = [30, 30, 30, 30]; - -/// DomainType('0x07000000') -/// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#domain-types -const DOMAIN_SYNC_COMMITTEE: [u8; 4] = [7, 0, 0, 0]; - -type ProofBranch = Vec; -type ForkVersion = [u8; 4]; +use crate::merkleization::get_sync_committee_bits; #[derive(Clone, Default, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] @@ -174,6 +152,12 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { + log::info!( + target: "ethereum-beacon-client", + "💫 Sync committee size is: {}", + config::SYNC_COMMITTEE_SIZE + ); + Pallet::::initial_sync( self.initial_sync.clone(), ).unwrap(); @@ -181,7 +165,8 @@ pub mod pallet { } #[pallet::call] - impl Pallet { + impl Pallet + { #[pallet::weight(1_000_000)] #[transactional] pub fn sync_committee_period_update( @@ -292,8 +277,8 @@ pub mod pallet { initial_sync.current_sync_committee.clone(), initial_sync.current_sync_committee_branch, initial_sync.header.state_root, - CURRENT_SYNC_COMMITTEE_DEPTH, - CURRENT_SYNC_COMMITTEE_INDEX, + config::CURRENT_SYNC_COMMITTEE_DEPTH, + config::CURRENT_SYNC_COMMITTEE_INDEX, )?; let period = Self::compute_current_sync_period(initial_sync.header.slot); @@ -311,15 +296,15 @@ pub mod pallet { fn process_sync_committee_period_update( update: SyncCommitteePeriodUpdate, ) -> DispatchResult { - let sync_committee_bits = merkleization::get_sync_committee_bits(update.sync_aggregate.sync_committee_bits.clone()) + let sync_committee_bits = get_sync_committee_bits(update.sync_aggregate.sync_committee_bits.clone()) .map_err(|_| DispatchError::Other("Couldn't process sync committee bits"))?; Self::sync_committee_participation_is_supermajority(sync_committee_bits.clone())?; Self::verify_sync_committee( update.next_sync_committee.clone(), update.next_sync_committee_branch, update.finalized_header.state_root, - NEXT_SYNC_COMMITTEE_DEPTH, - NEXT_SYNC_COMMITTEE_INDEX, + config::NEXT_SYNC_COMMITTEE_DEPTH, + config::NEXT_SYNC_COMMITTEE_INDEX, )?; let block_root: H256 = merkleization::hash_tree_root_beacon_header(update.finalized_header.clone()) @@ -328,8 +313,8 @@ pub mod pallet { block_root, update.finality_branch, update.attested_header.state_root, - FINALIZED_ROOT_DEPTH, - FINALIZED_ROOT_INDEX, + config::FINALIZED_ROOT_DEPTH, + config::FINALIZED_ROOT_INDEX, )?; let current_period = Self::compute_current_sync_period(update.attested_header.slot); @@ -352,7 +337,7 @@ pub mod pallet { } fn process_finalized_header(update: FinalizedHeaderUpdate) -> DispatchResult { - let sync_committee_bits = merkleization::get_sync_committee_bits(update.sync_aggregate.sync_committee_bits.clone()) + let sync_committee_bits = get_sync_committee_bits(update.sync_aggregate.sync_committee_bits.clone()) .map_err(|_| DispatchError::Other("Couldn't process sync committee bits"))?; Self::sync_committee_participation_is_supermajority(sync_committee_bits.clone())?; @@ -362,8 +347,8 @@ pub mod pallet { block_root, update.finality_branch, update.attested_header.state_root, - FINALIZED_ROOT_DEPTH, - FINALIZED_ROOT_INDEX, + config::FINALIZED_ROOT_DEPTH, + config::FINALIZED_ROOT_INDEX, )?; let current_period = Self::compute_current_sync_period(update.attested_header.slot); @@ -414,7 +399,7 @@ pub mod pallet { }; let validators_root = >::get(); - let sync_committee_bits = merkleization::get_sync_committee_bits(update.sync_aggregate.sync_committee_bits.clone()) + let sync_committee_bits = get_sync_committee_bits(update.sync_aggregate.sync_committee_bits.clone()) .map_err(|_| DispatchError::Other("Couldn't process sync committee bits"))?; Self::verify_signed_header( sync_committee_bits, @@ -476,7 +461,7 @@ pub mod pallet { } } - let domain_type = DOMAIN_SYNC_COMMITTEE.to_vec(); + let domain_type = config::DOMAIN_SYNC_COMMITTEE.to_vec(); // Domains are used for for seeds, for signatures, and for selecting aggregators. let domain = Self::compute_domain(domain_type, Some(fork_version), validators_root)?; // Hash tree root of SigningData - object root + domain @@ -599,6 +584,12 @@ pub mod pallet { let latest_committee_period = >::get(); + log::trace!( + target: "ethereum-beacon-client", + "💫 Saved sync committee for period {}.", + period + ); + if period > latest_committee_period { log::trace!( target: "ethereum-beacon-client", @@ -652,7 +643,7 @@ pub mod pallet { } pub(super) fn compute_current_sync_period(slot: u64) -> u64 { - slot / SLOTS_PER_EPOCH / EPOCHS_PER_SYNC_COMMITTEE_PERIOD + slot / config::SLOTS_PER_EPOCH / config::EPOCHS_PER_SYNC_COMMITTEE_PERIOD } /// Return the domain for the domain_type and fork_version. @@ -663,7 +654,7 @@ pub mod pallet { ) -> Result { let unwrapped_fork_version: ForkVersion; if fork_version.is_none() { - unwrapped_fork_version = GENESIS_FORK_VERSION; + unwrapped_fork_version = config::GENESIS_FORK_VERSION; } else { unwrapped_fork_version = fork_version.unwrap(); } diff --git a/parachain/pallets/ethereum-beacon-client/src/merkleization.rs b/parachain/pallets/ethereum-beacon-client/src/merkleization.rs index 6522a2a1480c6..804e80053edd2 100644 --- a/parachain/pallets/ethereum-beacon-client/src/merkleization.rs +++ b/parachain/pallets/ethereum-beacon-client/src/merkleization.rs @@ -7,7 +7,7 @@ use ssz_rs::U256; use byte_slice_cast::AsByteSlice; use snowbridge_beacon_primitives::{SyncAggregate, Attestation, Checkpoint, Eth1Data, BeaconHeader, AttesterSlashing, ExecutionPayload, SigningData, ForkData, SyncCommittee, AttestationData, Body, ProposerSlashing, Deposit, VoluntaryExit}; use crate::ssz::*; -use crate::config; +use crate::config as config; #[derive(Debug)] pub enum MerkleizationError { @@ -227,7 +227,7 @@ pub fn hash_tree_root_sync_committee(sync_committee: SyncCommittee) -> Result<[u pubkeys_vec.push(conv_pubkey); } - let pubkeys = Vector::, 512>::from_iter(pubkeys_vec.clone()); + let pubkeys = Vector::, { config::SYNC_COMMITTEE_SIZE }>::from_iter(pubkeys_vec.clone()); let agg = Vector::::from_iter(sync_committee.aggregate_pubkey.0); diff --git a/parachain/pallets/ethereum-beacon-client/src/ssz.rs b/parachain/pallets/ethereum-beacon-client/src/ssz.rs index 2c11a71ef78bd..de501e60f0cb4 100644 --- a/parachain/pallets/ethereum-beacon-client/src/ssz.rs +++ b/parachain/pallets/ethereum-beacon-client/src/ssz.rs @@ -2,7 +2,7 @@ use ssz_rs_derive::SimpleSerialize; use ssz_rs::{Deserialize, Sized, Bitlist, Bitvector, U256}; use ssz_rs::prelude::{Vector, List}; use sp_std::{vec::Vec, vec}; -use crate::config; +use crate::config as config; #[derive(Default, Debug, SimpleSerialize, Clone)] pub struct SSZVoluntaryExit { @@ -98,13 +98,13 @@ pub struct SSZBeaconBlockHeader { #[derive(Default, SimpleSerialize)] pub struct SSZSyncCommittee { - pub pubkeys: Vector, 512>, + pub pubkeys: Vector, { config::SYNC_COMMITTEE_SIZE }>, pub aggregate_pubkey: Vector, } #[derive(Default, Debug, SimpleSerialize, Clone)] pub struct SSZSyncAggregate { - pub sync_committee_bits: Bitvector<{ config::SYNC_COMMITTEE_SIZE} >, + pub sync_committee_bits: Bitvector<{ config::SYNC_COMMITTEE_SIZE }>, pub sync_committee_signature: Vector, } diff --git a/parachain/primitives/beacon/src/lib.rs b/parachain/primitives/beacon/src/lib.rs index 087f5c3cadd7e..f5b41ef023639 100644 --- a/parachain/primitives/beacon/src/lib.rs +++ b/parachain/primitives/beacon/src/lib.rs @@ -18,6 +18,9 @@ use core::fmt::Formatter; pub type Root = H256; pub type Domain = H256; pub type ValidatorIndex = u64; +pub type ProofBranch = Vec; +pub type ForkVersion = [u8; 4]; + #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] pub struct PublicKey(pub [u8; 48]); diff --git a/parachain/runtime/snowbase/Cargo.toml b/parachain/runtime/snowbase/Cargo.toml index 3f19a78edbbe0..e07fca3052e87 100644 --- a/parachain/runtime/snowbase/Cargo.toml +++ b/parachain/runtime/snowbase/Cargo.toml @@ -76,7 +76,7 @@ basic-channel = { path = "../../pallets/basic-channel", package = "snowbridge-ba incentivized-channel = { path = "../../pallets/incentivized-channel", package = "snowbridge-incentivized-channel", default-features = false } dispatch = { path = "../../pallets/dispatch", package = "snowbridge-dispatch", default-features = false } ethereum-light-client = { path = "../../pallets/ethereum-light-client", package = "snowbridge-ethereum-light-client", default-features = false } -ethereum-beacon-client = { path = "../../pallets/ethereum-beacon-client", package = "snowbridge-ethereum-beacon-client", default-features = false } +ethereum-beacon-client = { path = "../../pallets/ethereum-beacon-client", package = "snowbridge-ethereum-beacon-client", default-features = false, features=["minimal"]} dot-app = { path = "../../pallets/dot-app", package = "snowbridge-dot-app", default-features = false } eth-app = { path = "../../pallets/eth-app", package = "snowbridge-eth-app", default-features = false } erc20-app = { path = "../../pallets/erc20-app", package = "snowbridge-erc20-app", default-features = false } diff --git a/parachain/runtime/snowblink/Cargo.toml b/parachain/runtime/snowblink/Cargo.toml index 6a8562f355d65..ad07c8beb4b8b 100644 --- a/parachain/runtime/snowblink/Cargo.toml +++ b/parachain/runtime/snowblink/Cargo.toml @@ -75,7 +75,7 @@ basic-channel = { path = "../../pallets/basic-channel", package = "snowbridge-ba incentivized-channel = { path = "../../pallets/incentivized-channel", package = "snowbridge-incentivized-channel", default-features = false } dispatch = { path = "../../pallets/dispatch", package = "snowbridge-dispatch", default-features = false } ethereum-light-client = { path = "../../pallets/ethereum-light-client", package = "snowbridge-ethereum-light-client", default-features = false } -ethereum-beacon-client = { path = "../../pallets/ethereum-beacon-client", package = "snowbridge-ethereum-beacon-client", default-features = false } +ethereum-beacon-client = { path = "../../pallets/ethereum-beacon-client", package = "snowbridge-ethereum-beacon-client", default-features = false} dot-app = { path = "../../pallets/dot-app", package = "snowbridge-dot-app", default-features = false } eth-app = { path = "../../pallets/eth-app", package = "snowbridge-eth-app", default-features = false } erc20-app = { path = "../../pallets/erc20-app", package = "snowbridge-erc20-app", default-features = false } diff --git a/parachain/runtime/snowbridge/Cargo.toml b/parachain/runtime/snowbridge/Cargo.toml index 9510893b675fa..40ebd4e0f21ed 100644 --- a/parachain/runtime/snowbridge/Cargo.toml +++ b/parachain/runtime/snowbridge/Cargo.toml @@ -75,7 +75,7 @@ basic-channel = { path = "../../pallets/basic-channel", package = "snowbridge-ba incentivized-channel = { path = "../../pallets/incentivized-channel", package = "snowbridge-incentivized-channel", default-features = false } dispatch = { path = "../../pallets/dispatch", package = "snowbridge-dispatch", default-features = false } ethereum-light-client = { path = "../../pallets/ethereum-light-client", package = "snowbridge-ethereum-light-client", default-features = false } -ethereum-beacon-client = { path = "../../pallets/ethereum-beacon-client", package = "snowbridge-ethereum-beacon-client", default-features = false } +ethereum-beacon-client = { path = "../../pallets/ethereum-beacon-client", package = "snowbridge-ethereum-beacon-client", default-features = false} dot-app = { path = "../../pallets/dot-app", package = "snowbridge-dot-app", default-features = false } eth-app = { path = "../../pallets/eth-app", package = "snowbridge-eth-app", default-features = false } erc20-app = { path = "../../pallets/erc20-app", package = "snowbridge-erc20-app", default-features = false } diff --git a/relayer/relays/beacon/config.go b/relayer/relays/beacon/config.go index 222475d32e7eb..ec0092553ac86 100644 --- a/relayer/relays/beacon/config.go +++ b/relayer/relays/beacon/config.go @@ -7,6 +7,16 @@ type Config struct { Sink SinkConfig `mapstructure:"sink"` } +type SpecSettings struct { + SlotsInEpoch uint64 `mapstructure:"slotsInEpoch"` + EpochsPerSyncCommitteePeriod uint64 `mapstructure:"epochsPerSyncCommitteePeriod"` +} + +type Spec struct { + Minimal SpecSettings `mapstructure:"minimal"` + Mainnet SpecSettings `mapstructure:"mainnet"` +} + type SourceConfig struct { Beacon BeaconConfig `mapstructure:"beacon"` Ethereum config.EthereumConfig `mapstructure:"ethereum"` @@ -21,8 +31,18 @@ type ContractsConfig struct { type BeaconConfig struct { Endpoint string `mapstructure:"endpoint"` FinalizedUpdateEndpoint string `mapstructure:"finalizedUpdateEndpoint"` + Spec Spec `mapstructure:"spec"` + ActiveSpec string `mapstructure:"activeSpec"` } type SinkConfig struct { Parachain config.ParachainConfig `mapstructure:"parachain"` } + +func (c Config) GetSpecSettings() SpecSettings { + if c.Source.Beacon.ActiveSpec == "minimal" { + return c.Source.Beacon.Spec.Minimal + } + + return c.Source.Beacon.Spec.Mainnet +} diff --git a/relayer/relays/beacon/main.go b/relayer/relays/beacon/main.go index fa46a5d65d8bd..648417b7f3554 100644 --- a/relayer/relays/beacon/main.go +++ b/relayer/relays/beacon/main.go @@ -37,8 +37,10 @@ func NewRelay( } func (r *Relay) Start(ctx context.Context, eg *errgroup.Group) error { + specSettings := r.config.GetSpecSettings() + r.paraconn = parachain.NewConnection(r.config.Sink.Parachain.Endpoint, r.keypair.AsKeyringPair()) - r.syncer = syncer.New(r.config.Source.Beacon.Endpoint) + r.syncer = syncer.New(r.config.Source.Beacon.Endpoint, specSettings.SlotsInEpoch, specSettings.EpochsPerSyncCommitteePeriod) r.ethconn = ethereum.NewConnection(r.config.Source.Ethereum.Endpoint, nil) err := r.paraconn.Connect(ctx) @@ -88,7 +90,9 @@ func (r *Relay) Sync(ctx context.Context) error { logrus.WithField("period", latestSyncedPeriod).Info("last beacon synced sync committee found") - r.syncer.Cache.SyncCommitteePeriodsSynced, err = r.syncer.GetSyncPeriodsToFetch(latestSyncedPeriod) + r.syncer.Cache.SetLastSyncedSyncCommitteePeriod(latestSyncedPeriod) + + periodsToSync, err := r.syncer.GetSyncPeriodsToFetch(latestSyncedPeriod) if err != nil { logrus.WithError(err).Error("unable to check sync committee periods to be fetched") @@ -96,10 +100,10 @@ func (r *Relay) Sync(ctx context.Context) error { } logrus.WithFields(logrus.Fields{ - "periods": r.syncer.Cache.SyncCommitteePeriodsSynced, + "periods": periodsToSync, }).Info("sync committee periods that needs fetching") - for _, period := range r.syncer.Cache.SyncCommitteePeriodsSynced { + for _, period := range periodsToSync { err := r.SyncCommitteePeriodUpdate(ctx, period) if err != nil { return err @@ -136,7 +140,7 @@ func (r *Relay) Sync(ctx context.Context) error { } func (r *Relay) SyncCommitteePeriodUpdate(ctx context.Context, period uint64) error { - syncCommitteeUpdate, err := r.syncer.GetSyncCommitteePeriodUpdate(period, period) + syncCommitteeUpdate, err := r.syncer.GetSyncCommitteePeriodUpdate(period) switch { case errors.Is(err, syncer.ErrCommitteeUpdateHeaderInDifferentSyncPeriod): @@ -159,7 +163,14 @@ func (r *Relay) SyncCommitteePeriodUpdate(ctx context.Context, period uint64) er "period": period, }).Info("syncing sync committee for period") - return r.writer.WriteToParachain(ctx, "EthereumBeaconClient.sync_committee_period_update", syncCommitteeUpdate) + err = r.writer.WriteToParachain(ctx, "EthereumBeaconClient.sync_committee_period_update", syncCommitteeUpdate) + if err != nil { + return err + } + + r.syncer.Cache.SetLastSyncedSyncCommitteePeriod(period) + + return nil } func (r *Relay) SyncFinalizedHeader(ctx context.Context) (syncer.FinalizedHeaderUpdate, common.Hash, error) { @@ -185,17 +196,15 @@ func (r *Relay) SyncFinalizedHeader(ctx context.Context) (syncer.FinalizedHeader "blockRoot": blockRoot, }).Info("syncing finalized header at slot") - currentSyncPeriod := syncer.ComputeSyncPeriodAtSlot(uint64(finalizedHeaderUpdate.AttestedHeader.Slot)) + currentSyncPeriod := r.syncer.ComputeSyncPeriodAtSlot(uint64(finalizedHeaderUpdate.AttestedHeader.Slot)) - if !syncer.IsInArray(r.syncer.Cache.SyncCommitteePeriodsSynced, currentSyncPeriod) { + if r.syncer.Cache.LastSyncedSyncCommitteePeriod < currentSyncPeriod { logrus.WithField("period", currentSyncPeriod).Info("sync period rolled over, getting sync committee update") err := r.SyncCommitteePeriodUpdate(ctx, currentSyncPeriod) if err != nil { return syncer.FinalizedHeaderUpdate{}, common.Hash{}, err } - - r.syncer.Cache.AddSyncCommitteePeriod(currentSyncPeriod) } err = r.writer.WriteToParachain(ctx, "EthereumBeaconClient.import_finalized_header", finalizedHeaderUpdate) diff --git a/relayer/relays/beacon/parachain-writer.go b/relayer/relays/beacon/parachain-writer.go index dc7e861f65916..fa112acecda35 100644 --- a/relayer/relays/beacon/parachain-writer.go +++ b/relayer/relays/beacon/parachain-writer.go @@ -128,9 +128,9 @@ func (wr *ParachainWriter) getLastSyncedSyncCommitteePeriod() (uint64, error) { } var period types.U64 - ok, err := wr.conn.API().RPC.State.GetStorageLatest(key, &period) - if err != nil || !ok { - return 0, fmt.Errorf("get storage for latest synced sync committee period: %w", err) + _, err = wr.conn.API().RPC.State.GetStorageLatest(key, &period) + if err != nil { + return 0, fmt.Errorf("get storage for latest synced sync committee period (err): %w", err) } return uint64(period), nil diff --git a/relayer/relays/beacon/syncer/api.go b/relayer/relays/beacon/syncer/api.go index 6ceb428e07554..71248f1a14179 100644 --- a/relayer/relays/beacon/syncer/api.go +++ b/relayer/relays/beacon/syncer/api.go @@ -7,6 +7,7 @@ import ( "io" "net/http" "strconv" + "strings" "github.com/ethereum/go-ethereum/common" ) @@ -23,7 +24,7 @@ type BeaconClientTracker interface { GetFinalizedHeader() (BeaconHeader, error) GetHeadHeader() (BeaconHeader, error) GetHeader(id string) (BeaconHeader, error) - GetSyncCommitteePeriodUpdate(from, to uint64) (SyncCommitteePeriodUpdateResponse, error) + GetSyncCommitteePeriodUpdate(from uint64) (SyncCommitteePeriodUpdateResponse, error) GetHeadCheckpoint() (FinalizedCheckpointResponse, error) GetBeaconBlock(slot uint64) (BeaconBlockResponse, error) GetBeaconBlockBySlot(slot uint64) (BeaconBlockResponse, error) @@ -32,7 +33,8 @@ type BeaconClientTracker interface { } var ( - ErrNotFound = errors.New("not found") + ErrNotFound = errors.New("not found") + ErrSyncCommitteeUpdateNotAvailable = errors.New("no sync committee update available") ) type BeaconClient struct { @@ -198,6 +200,12 @@ type VoluntaryExitResponse struct { ValidatorIndex string `json:"validator_index"` } +type ErrorMessage struct { + StatusCode int `json:"statusCode"` + Error string `json:"error"` + Message string `json:"message"` +} + type BeaconBlockResponse struct { Data struct { Message struct { @@ -359,8 +367,8 @@ type SyncCommitteePeriodUpdateResponse struct { } `json:"data"` } -func (b *BeaconClient) GetSyncCommitteePeriodUpdate(from, to uint64) (SyncCommitteePeriodUpdateResponse, error) { - req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/eth/v1/lightclient/committee_updates?from=%d&to=%d", b.endpoint, from, to), nil) +func (b *BeaconClient) GetSyncCommitteePeriodUpdate(from uint64) (SyncCommitteePeriodUpdateResponse, error) { + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/eth/v1/light_client/updates?start_period=%d&count=1", b.endpoint, from), nil) if err != nil { return SyncCommitteePeriodUpdateResponse{}, fmt.Errorf("%s: %w", ConstructRequestErrorMessage, err) } @@ -372,6 +380,22 @@ func (b *BeaconClient) GetSyncCommitteePeriodUpdate(from, to uint64) (SyncCommit } if res.StatusCode != http.StatusOK { + bodyBytes, err := io.ReadAll(res.Body) + if err != nil { + return SyncCommitteePeriodUpdateResponse{}, fmt.Errorf("%s: %w", HTTPStatusNotOKErrorMessage, err) + } + + var response ErrorMessage + + err = json.Unmarshal(bodyBytes, &response) + if err != nil { + return SyncCommitteePeriodUpdateResponse{}, fmt.Errorf("%s: %w", HTTPStatusNotOKErrorMessage, err) + } + + if strings.Contains(response.Message, "No partialUpdate available") { + return SyncCommitteePeriodUpdateResponse{}, ErrSyncCommitteeUpdateNotAvailable + } + return SyncCommitteePeriodUpdateResponse{}, fmt.Errorf("%s :%d", HTTPStatusNotOKErrorMessage, res.StatusCode) } @@ -537,6 +561,7 @@ func (b *BeaconClient) GetCheckpoint(state string) (FinalizedCheckpointResponse, return response, nil } + type LatestFinalisedUpdateResponse struct { Data struct { AttestedHeader HeaderResponse `json:"attested_header"` @@ -548,7 +573,7 @@ type LatestFinalisedUpdateResponse struct { } func (b *BeaconClient) GetLatestFinalizedUpdate() (LatestFinalisedUpdateResponse, error) { - req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/eth/v1/lightclient/latest_finalized_head_update/", b.endpoint), nil) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/eth/v1/light_client/finality_update/", b.endpoint), nil) if err != nil { return LatestFinalisedUpdateResponse{}, fmt.Errorf("%s: %w", ConstructRequestErrorMessage, err) } diff --git a/relayer/relays/beacon/syncer/cache.go b/relayer/relays/beacon/syncer/cache.go index 2a693c1c118cf..2b77810ccce0f 100644 --- a/relayer/relays/beacon/syncer/cache.go +++ b/relayer/relays/beacon/syncer/cache.go @@ -7,24 +7,26 @@ import ( ) type BeaconCache struct { - SyncCommitteePeriodsSynced []uint64 - FinalizedHeaders []common.Hash - HeadersMap map[common.Hash]uint64 - mu sync.Mutex + LastSyncedSyncCommitteePeriod uint64 + FinalizedHeaders []common.Hash + HeadersMap map[common.Hash]uint64 + mu sync.Mutex } func NewBeaconCache() *BeaconCache { return &BeaconCache{ - SyncCommitteePeriodsSynced: []uint64{}, - FinalizedHeaders: []common.Hash{}, - HeadersMap: map[common.Hash]uint64{}, + LastSyncedSyncCommitteePeriod: 0, + FinalizedHeaders: []common.Hash{}, + HeadersMap: map[common.Hash]uint64{}, } } -func (b *BeaconCache) AddSyncCommitteePeriod(period uint64) { +func (b *BeaconCache) SetLastSyncedSyncCommitteePeriod(period uint64) { b.mu.Lock() // mutux lock since both the finalized and latest headers write to this slice in separate Goroutines defer b.mu.Unlock() - b.SyncCommitteePeriodsSynced = append(b.SyncCommitteePeriodsSynced, period) + if period > b.LastSyncedSyncCommitteePeriod { + b.LastSyncedSyncCommitteePeriod = period + } } func (b *BeaconCache) LastFinalizedHeader() common.Hash { diff --git a/relayer/relays/beacon/syncer/syncer.go b/relayer/relays/beacon/syncer/syncer.go index 9b055a1f5d1f9..1ffef5a464f04 100644 --- a/relayer/relays/beacon/syncer/syncer.go +++ b/relayer/relays/beacon/syncer/syncer.go @@ -16,20 +16,19 @@ import ( var ErrCommitteeUpdateHeaderInDifferentSyncPeriod = errors.New("not found") -const ( - SlotsInEpoch uint64 = 32 - EpochsPerSyncCommitteePeriod uint64 = 256 -) - type Syncer struct { - Client BeaconClient - Cache BeaconCache + Client BeaconClient + Cache BeaconCache + SlotsInEpoch uint64 + EpochsPerSyncCommitteePeriod uint64 } -func New(endpoint string) *Syncer { +func New(endpoint string, slotsInEpoch, epochsPerSyncCommitteePeriod uint64) *Syncer { return &Syncer{ - Client: *NewBeaconClient(endpoint), - Cache: *NewBeaconCache(), + Client: *NewBeaconClient(endpoint), + Cache: *NewBeaconCache(), + SlotsInEpoch: slotsInEpoch, + EpochsPerSyncCommitteePeriod: epochsPerSyncCommitteePeriod, } } @@ -107,7 +106,8 @@ func (s *Syncer) GetSyncPeriodsToFetch(checkpointSyncPeriod uint64) ([]uint64, e return []uint64{}, fmt.Errorf("parse slot as int: %w", err) } - currentSyncPeriod := ComputeSyncPeriodAtSlot(slot) + currentSyncPeriod := s.ComputeSyncPeriodAtSlot(slot) + if checkpointSyncPeriod == currentSyncPeriod { return []uint64{}, nil } @@ -120,8 +120,8 @@ func (s *Syncer) GetSyncPeriodsToFetch(checkpointSyncPeriod uint64) ([]uint64, e return syncPeriodsToFetch, nil } -func (s *Syncer) GetSyncCommitteePeriodUpdate(from, to uint64) (SyncCommitteePeriodUpdate, error) { - committeeUpdates, err := s.Client.GetSyncCommitteePeriodUpdate(from, to) +func (s *Syncer) GetSyncCommitteePeriodUpdate(from uint64) (SyncCommitteePeriodUpdate, error) { + committeeUpdates, err := s.Client.GetSyncCommitteePeriodUpdate(from) if err != nil { return SyncCommitteePeriodUpdate{}, fmt.Errorf("fetch sync committee period update: %w", err) } @@ -167,10 +167,10 @@ func (s *Syncer) GetSyncCommitteePeriodUpdate(from, to uint64) (SyncCommitteePer ForkVersion: forkVersion, } - finalizedHeaderSlot := ComputeSyncPeriodAtSlot(uint64(finalizedHeader.Slot)) + finalizedHeaderSlot := s.ComputeSyncPeriodAtSlot(uint64(finalizedHeader.Slot)) if finalizedHeaderSlot != from { - return SyncCommitteePeriodUpdate{}, ErrCommitteeUpdateHeaderInDifferentSyncPeriod + return syncCommitteePeriodUpdate, ErrCommitteeUpdateHeaderInDifferentSyncPeriod } return syncCommitteePeriodUpdate, err @@ -314,16 +314,8 @@ func (s *Syncer) GetSyncAggregateForSlot(slot uint64) (scale.SyncAggregate, erro return blockScale.Body.SyncAggregate, nil } -func computeEpochAtSlot(slot uint64) uint64 { - return slot / SlotsInEpoch -} - -func computeEpochForNextPeriod(epoch uint64) uint64 { - return epoch + (EpochsPerSyncCommitteePeriod - (epoch % EpochsPerSyncCommitteePeriod)) -} - -func ComputeSyncPeriodAtSlot(slot uint64) uint64 { - return slot / (SlotsInEpoch * EpochsPerSyncCommitteePeriod) +func (s *Syncer) ComputeSyncPeriodAtSlot(slot uint64) uint64 { + return slot / (s.SlotsInEpoch * s.EpochsPerSyncCommitteePeriod) } func IsInArray(values []uint64, toCheck uint64) bool { diff --git a/relayer/relays/beacon/syncer/syncer_test.go b/relayer/relays/beacon/syncer/syncer_test.go index 6559df263d099..191fddf6976ab 100644 --- a/relayer/relays/beacon/syncer/syncer_test.go +++ b/relayer/relays/beacon/syncer/syncer_test.go @@ -37,37 +37,6 @@ func TestComputeEpochAtSlot(t *testing.T) { } } -func TestComputeEpochForNextPeriod(t *testing.T) { - values := []struct { - name string - epoch uint64 - expected uint64 - }{ - { - name: "first epoch", - epoch: 0, - expected: 256, - }, - { - name: "another epoch", - epoch: 30, - expected: 256, - }, - { - name: "another epoch", - epoch: 513, - expected: 768, - }, - } - - for _, tt := range values { - total := computeEpochForNextPeriod(tt.epoch) - if total != tt.expected { - t.Errorf("TestComputeEpochForNextPeriod of epoch (%d) was incorrect, got: %d, want: %d.", tt.epoch, total, tt.expected) - } - } -} - func TestHexToBinaryString(t *testing.T) { values := []struct { name string diff --git a/test/.envrc-example b/test/.envrc-example index 7b326f016c4e8..77992929f031d 100644 --- a/test/.envrc-example +++ b/test/.envrc-example @@ -26,6 +26,8 @@ export PARACHAIN_ID=1000 # export ETH_RPC_ENDPOINT=https://ropsten.infura.io/v3 # export ETH_WS_ENDPOINT=wss://ropsten.infura.io/ws/v3 +# export BEACON_HTTP_ENDPOINT=https://lodestar-ropsten.chainsafe.io + # export ROPSTEN_PRIVATE_KEY= # Your deployment account private key # export BEEFY_RELAY_ETH_KEY= # Your Beefy relayer account private key # export PARACHAIN_RELAY_ETH_KEY= # Your Parachain relayer account private key diff --git a/test/README.md b/test/README.md index 677ccb13ec747..5c3d656995d6b 100644 --- a/test/README.md +++ b/test/README.md @@ -1,6 +1,6 @@ # Local Testnet -The E2E tests run against local deployments of the parachain, relayer and ethereum (geth). +The E2E tests run against local deployments of the parachain, relayer, the ethereum execution layer (geth) and the ethereum consensus layer (lodestar). ## Requirements @@ -37,6 +37,8 @@ The E2E tests run against local deployments of the parachain, relayer and ethere * direnv - https://direnv.net/ +* lodestar - https://chainsafe.github.io/lodestar/installation/ + ## Setup ### Install NPM dependencies diff --git a/test/config/beacon-relay.json b/test/config/beacon-relay.json index 77670f8fbadbe..7d2d4ffd8057b 100644 --- a/test/config/beacon-relay.json +++ b/test/config/beacon-relay.json @@ -1,13 +1,25 @@ { "source": { "beacon": { - "endpoint": "http://localhost:9596" + "endpoint": "http://localhost:9596", + "spec": { + "minimal": { + "slotsInEpoch": 8, + "epochsPerSyncCommitteePeriod": 8 + }, + "mainnet": { + "slotsInEpoch": 32, + "epochsPerSyncCommitteePeriod": 256 + } + }, + "activeSpec": "mainnet" }, "ethereum": { "endpoint": "ws://localhost:8546" }, "contracts": { - "BasicOutboundChannel": null + "BasicOutboundChannel": null, + "IncentivizedOutboundChannel": null } }, "sink": { diff --git a/test/config/genesis.json b/test/config/genesis.json index bc974b43b4129..0c507d8fde248 100644 --- a/test/config/genesis.json +++ b/test/config/genesis.json @@ -12,7 +12,8 @@ "muirGlacierBlock": 0, "berlinBlock": 0, "londonBlock": 0, - "ethash": {} + "ethash": {}, + "terminalTotalDifficulty": 0 }, "difficulty": "0x9FFE0", "gasLimit": "80000000", diff --git a/test/config/jwtsecret b/test/config/jwtsecret new file mode 100644 index 0000000000000..583b13cc50682 --- /dev/null +++ b/test/config/jwtsecret @@ -0,0 +1 @@ +0xdc6457099f127cf0bac78de8b297df04951281909db4f58b43def7c7151e765d \ No newline at end of file diff --git a/test/scripts/start-services.sh b/test/scripts/start-services.sh index b4bb92b26d393..a4cebae8d5d7f 100755 --- a/test/scripts/start-services.sh +++ b/test/scripts/start-services.sh @@ -14,7 +14,7 @@ parachain_relay_eth_key="${PARACHAIN_RELAY_ETH_KEY:-0x8013383de6e5a891e7754ae1ef beefy_relay_eth_key="${BEEFY_RELAY_ETH_KEY:-0x935b65c833ced92c43ef9de6bff30703d941bd92a2637cb00cfad389f5862109}" start_beacon_sync="${START_BEACON_SYNC:-false}" -lodestar_endpoint_http="http://localhost:9596" +beacon_endpoint_http="${BEACON_HTTP_ENDPOINT:-http://localhost:9596}" output_dir=/tmp/snowbridge @@ -35,43 +35,64 @@ start_geth() { local data_dir="$output_dir/geth" - geth init --datadir "$data_dir" config/genesis.json - geth account import --datadir "$data_dir" --password /dev/null config/dev-example-key0.prv - geth account import --datadir "$data_dir" --password /dev/null config/dev-example-key1.prv - geth --vmdebug --datadir "$data_dir" --networkid 15 \ - --http --http.api debug,personal,eth,net,web3,txpool --ws --ws.api debug,eth,net,web3 \ - --rpc.allow-unprotected-txs --mine --miner.threads=1 \ - --miner.etherbase=0x0000000000000000000000000000000000000000 \ - --allow-insecure-unlock \ - --unlock 0xBe68fC2d8249eb60bfCf0e71D5A0d2F2e292c4eD,0x89b4AB1eF20763630df9743ACF155865600daFF2 \ - --password /dev/null \ - --rpc.gascap 100000000 \ - --trace "$data_dir/trace" \ - --gcmode archive \ - --miner.gasprice=0 \ - > "$output_dir/geth.log" 2>&1 & -} - -start_geth_for_beacon_node() { - geth --"$eth_network" \ - --datadir "/home/ubuntu/projects/go-ethereum/${eth_network}data" \ - --authrpc.addr localhost \ - --authrpc.port 8551 \ - --http \ - --authrpc.vhosts localhost \ - --authrpc.jwtsecret "/home/ubuntu/projects/go-ethereum/${eth_network}data/jwtsecret" \ - --http.api eth,net \ - --override.terminaltotaldifficulty 50000000000000000 \ - > "$output_dir/geth_beacon.log" 2>&1 & + if [ "$eth_network" == "localhost" ]; then + echo "Starting geth local net" + + geth init --datadir "$data_dir" config/genesis.json + geth account import --datadir "$data_dir" --password /dev/null config/dev-example-key0.prv + geth account import --datadir "$data_dir" --password /dev/null config/dev-example-key1.prv + geth --vmdebug --datadir "$data_dir" --networkid 15 \ + --http --http.api debug,personal,eth,net,web3,txpool,engine,miner --ws --ws.api debug,eth,net,web3 \ + --rpc.allow-unprotected-txs --mine --miner.threads=1 \ + --miner.etherbase=0x0000000000000000000000000000000000000000 \ + --allow-insecure-unlock \ + --authrpc.jwtsecret config/jwtsecret \ + --unlock 0xBe68fC2d8249eb60bfCf0e71D5A0d2F2e292c4eD,0x89b4AB1eF20763630df9743ACF155865600daFF2 \ + --password /dev/null \ + --rpc.gascap 100000000 \ + --trace "$data_dir/trace" \ + --gcmode archive \ + --miner.gasprice=0 \ + > "$output_dir/geth.log" 2>&1 & + fi } start_lodestar() { - lodestar beacon \ - --rootDir="/home/ubuntu/projects/lodestar-beacondata" \ - --network=$eth_network \ - --api.rest.api="beacon,config,events,node,validator,lightclient" \ - --jwt-secret "/home/ubuntu/projects/go-ethereum/${eth_network}data/jwtsecret" \ - > "$output_dir/lodestar_beacon.log" 2>&1 & + if [ "$start_beacon_sync" == "false" ]; then + return + fi + + if [ "$eth_network" == "localhost" ]; then + echo "Waiting for geth API to be ready" + sleep 2 + + genesisHash=$(curl http://localhost:8545 \ + -X POST \ + -H 'Content-Type: application/json' \ + -d '{"jsonrpc": "2.0", "id": "1", "method": "eth_getBlockByNumber","params": ["0x0", false]}' | jq -r '.result.hash') + + timestamp=$(date -d'+10second' +%s) + + echo "Starting lodestar local net" + + lodestar dev \ + --genesisValidators 8 \ + --genesisTime $timestamp \ + --startValidators "0..7" \ + --enr.ip "127.0.0.1" \ + --rootDir "$output_dir/beacon-$timestamp" \ + --reset \ + --terminal-total-difficulty-override 0 \ + --genesisEth1Hash $genesisHash \ + --params.ALTAIR_FORK_EPOCH 0 \ + --params.BELLATRIX_FORK_EPOCH 0 \ + --eth1.enabled=true \ + --api.rest.api="beacon,config,events,node,validator,lightclient" \ + --jwt-secret config/jwtsecret \ + > "$output_dir/lodestar.log" 2>&1 & + fi + + echo "Started up beacon node" } deploy_contracts() @@ -120,13 +141,13 @@ start_polkadot_launch() | node scripts/helpers/transformEthHeader.js > "$output_dir/initialHeader.json" if [ "$start_beacon_sync" == "true" ]; then - initial_beacon_block=$(curl "$lodestar_endpoint_http/eth/v1/beacon/states/head/finality_checkpoints" \ + initial_beacon_block=$(curl "$beacon_endpoint_http/eth/v1/beacon/states/head/finality_checkpoints" \ | jq -r '.data.finalized.root') - curl "$lodestar_endpoint_http/eth/v1/lightclient/snapshot/$initial_beacon_block" \ + curl "$beacon_endpoint_http/eth/v1/light_client/bootstrap/$initial_beacon_block" \ | node scripts/helpers/transformInitialBeaconSync.js > "$output_dir/initialBeaconSync_tmp.json" - validatorsRoot=$(curl "$lodestar_endpoint_http/eth/v1/beacon/genesis" \ + validatorsRoot=$(curl "$beacon_endpoint_http/eth/v1/beacon/genesis" \ | jq -r '.data.genesis_validators_root') jq \ @@ -235,15 +256,24 @@ start_relayer() ' \ config/ethereum-relay.json > $output_dir/ethereum-relay.json + active_spec="mainnet" + if [ "$eth_network" == "localhost" ]; then + active_spec="minimal" + fi + # Configure beacon relay jq \ --arg k1 "$(address_for BasicOutboundChannel)" \ --arg k2 "$(address_for IncentivizedOutboundChannel)" \ --arg infura_endpoint_ws $infura_endpoint_ws \ + --arg beacon_endpoint_http $beacon_endpoint_http \ + --arg active_spec $active_spec \ ' .source.contracts.BasicOutboundChannel = $k1 | .source.contracts.IncentivizedOutboundChannel = $k2 | .source.ethereum.endpoint = $infura_endpoint_ws + | .source.beacon.endpoint = $beacon_endpoint_http + | .source.beacon.activeSpec = $active_spec ' \ config/beacon-relay.json > $output_dir/beacon-relay.json @@ -321,19 +351,8 @@ mkdir "$output_dir/bin" export PATH="$output_dir/bin:$PATH" -if [ "$eth_network" == "localhost" ] && [ "$start_beacon_sync" == "true" ]; then - echo "Beacon sync not supported for localhost yet." - exit 1 -fi - -if [ "$eth_network" == "localhost" ]; then - start_geth -fi - -if [ "$start_beacon_sync" == "true" ]; then - start_geth_for_beacon_node - start_lodestar -fi +start_geth +start_lodestar deploy_contracts start_polkadot_launch @@ -357,7 +376,6 @@ until grep "Done retrieving finalized headers" ethereum-relay.log > /dev/null; d sleep 5 done - echo "Testnet has been initialized" wait diff --git a/test/tsconfig.json b/test/tsconfig.json index 887ca2a36b323..69c70975fb183 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -8,5 +8,5 @@ "forceConsistentCasingInFileNames": true, "outDir": "dist" }, - "files": ["./scripts/make-xcm-transfer.ts"], + "files": ["./scripts/make-xcm-transfer.ts"] } diff --git a/test/yarn.lock b/test/yarn.lock index 48c83ecf7da7e..21897f4bf5674 100644 --- a/test/yarn.lock +++ b/test/yarn.lock @@ -4216,4 +4216,4 @@ yn@3.1.1: yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== \ No newline at end of file