Unverified Commit 9b634717 authored by Fedor Sakharov's avatar Fedor Sakharov Committed by GitHub
Browse files

New service initial commit (#1234)



* New service initial commit

* More separation of the new and old services

* Fix review comments

* Adds polkadot.json

* Fix browser build

* Remove unused import

* Update node/service/src/lib.rs

Co-authored-by: Fedor Sakharov's avatarFedor Sakharov <fedor.sakharov@gmail.com>

* Remove duplicate json files

Co-authored-by: asynchronous rob's avatarRobert Habermeier <rphmeier@gmail.com>
parent 1696982d
Pipeline #96494 passed with stages
in 23 minutes and 6 seconds
......@@ -4071,6 +4071,7 @@ dependencies = [
"nix 0.17.0",
"parity-util-mem",
"polkadot-cli",
"polkadot-collator",
"polkadot-service",
"tempfile",
]
......@@ -4109,6 +4110,7 @@ dependencies = [
"futures 0.3.5",
"log 0.4.8",
"polkadot-service",
"polkadot-service-new",
"sc-cli",
"sc-client-api",
"sc-client-db",
......@@ -4137,6 +4139,7 @@ dependencies = [
"polkadot-network",
"polkadot-primitives",
"polkadot-service",
"polkadot-service-new",
"polkadot-validation",
"sc-cli",
"sc-client-api",
......@@ -4521,6 +4524,65 @@ dependencies = [
"westend-runtime",
]
[[package]]
name = "polkadot-service-new"
version = "0.8.3"
dependencies = [
"env_logger",
"frame-benchmarking",
"frame-system-rpc-runtime-api",
"futures 0.3.5",
"hex-literal",
"kusama-runtime",
"lazy_static",
"log 0.4.8",
"pallet-babe",
"pallet-im-online",
"pallet-staking",
"pallet-transaction-payment-rpc-runtime-api",
"parity-scale-codec",
"parking_lot 0.9.0",
"polkadot-network",
"polkadot-overseer",
"polkadot-primitives",
"polkadot-rpc",
"polkadot-runtime",
"polkadot-test-runtime-client",
"sc-authority-discovery",
"sc-basic-authorship",
"sc-block-builder",
"sc-chain-spec",
"sc-client-api",
"sc-client-db",
"sc-consensus",
"sc-consensus-babe",
"sc-executor",
"sc-finality-grandpa",
"sc-keystore",
"sc-network",
"sc-service",
"sc-telemetry",
"sc-transaction-pool",
"serde",
"slog",
"sp-api",
"sp-authority-discovery",
"sp-block-builder",
"sp-blockchain",
"sp-consensus",
"sp-consensus-babe",
"sp-core",
"sp-finality-grandpa",
"sp-inherents",
"sp-io",
"sp-offchain",
"sp-runtime",
"sp-session",
"sp-transaction-pool",
"substrate-prometheus-endpoint",
"westend-runtime",
]
[[package]]
name = "polkadot-statement-table"
version = "0.8.7"
......
......@@ -10,6 +10,8 @@ edition = "2018"
[dependencies]
cli = { package = "polkadot-cli", path = "cli" }
# It looks like this is the only way to pass features to it
collator = { package = "polkadot-collator", path = "collator" }
futures = "0.3.4"
service = { package = "polkadot-service", path = "service" }
parity-util-mem = { version = "*", default-features = false, features = ["jemalloc-global"] }
......@@ -42,6 +44,7 @@ members = [
"node/messages",
"node/overseer",
"node/service",
"parachain/test-parachains",
"parachain/test-parachains/adder",
......@@ -64,3 +67,7 @@ panic = "unwind"
[features]
runtime-benchmarks=["cli/runtime-benchmarks"]
service-rewr= [
"cli/service-rewr",
"collator/service-rewr",
]
......@@ -23,7 +23,8 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client-db = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
service = { package = "polkadot-service", path = "../service", default-features = false }
service = { package = "polkadot-service", path = "../service", default-features = false, optional = true }
service-new = { package = "polkadot-service-new", path = "../node/service", default-features = false, optional = true }
tokio = { version = "0.2.13", features = ["rt-threaded"], optional = true }
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
......@@ -38,7 +39,7 @@ browser-utils = { package = "substrate-browser-utils", git = "https://github.com
substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" }
[features]
default = [ "wasmtime", "db", "cli" ]
default = [ "wasmtime", "db", "cli", "service-old" ]
wasmtime = [ "sc-cli/wasmtime" ]
db = [ "service/db" ]
cli = [
......@@ -46,11 +47,13 @@ cli = [
"sc-cli",
"sc-service",
"frame-benchmarking-cli",
"service/full-node",
]
service-old = [ "service/full-node" ]
browser = [
"wasm-bindgen",
"wasm-bindgen-futures",
"browser-utils",
"service",
]
runtime-benchmarks = ["service/runtime-benchmarks"]
runtime-benchmarks = [ "service/runtime-benchmarks" ]
service-rewr = [ "service-new/full-node" ]
......@@ -15,7 +15,10 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use log::info;
#[cfg(not(feature = "service-rewr"))]
use service::{IdentifyVariant, self};
#[cfg(feature = "service-rewr")]
use service_new::{IdentifyVariant, self as service};
use sc_executor::NativeExecutionDispatch;
use sc_cli::{SubstrateCli, Result};
use crate::cli::{Cli, Subcommand};
......@@ -206,7 +209,7 @@ pub fn run() -> Result<()> {
if cfg!(feature = "browser") {
Err(sc_cli::Error::Input("Cannot run validation worker in browser".into()))
} else {
#[cfg(not(feature = "browser"))]
#[cfg(all(not(feature = "browser"), not(feature = "service-rewr")))]
service::run_validation_worker(&cmd.mem_id)?;
Ok(())
}
......
......@@ -26,11 +26,19 @@ mod cli;
#[cfg(feature = "cli")]
mod command;
#[cfg(not(feature = "service-rewr"))]
pub use service::{
AbstractService, ProvideRuntimeApi, CoreApi, ParachainHost, IdentifyVariant,
Block, self, RuntimeApiCollection, TFullClient
};
#[cfg(feature = "service-rewr")]
pub use service_new::{
self as service,
AbstractService, ProvideRuntimeApi, CoreApi, ParachainHost, IdentifyVariant,
Block, self, RuntimeApiCollection, TFullClient
};
#[cfg(feature = "cli")]
pub use cli::*;
......
......@@ -21,7 +21,8 @@ polkadot-primitives = { path = "../primitives" }
polkadot-cli = { path = "../cli" }
polkadot-network = { path = "../network" }
polkadot-validation = { path = "../validation" }
polkadot-service = { path = "../service" }
polkadot-service = { path = "../service", optional = true}
polkadot-service-new = { path = "../node/service", optional = true }
log = "0.4.8"
tokio = "0.2.13"
futures-timer = "2.0"
......@@ -29,3 +30,8 @@ codec = { package = "parity-scale-codec", version = "1.3.0" }
[dev-dependencies]
keyring = { package = "sp-keyring", git = "https://github.com/paritytech/substrate", branch = "master" }
[features]
default = ["service-old"]
service-old = [ "polkadot-service" ]
service-rewr = [ "polkadot-service-new" ]
......@@ -74,7 +74,13 @@ pub use sc_network::PeerId;
pub use service::RuntimeApiCollection;
pub use sc_cli::SubstrateCli;
use sp_api::{ConstructRuntimeApi, ApiExt, HashFor};
use polkadot_service::PolkadotClient;
#[cfg(not(feature = "service-rewr"))]
use polkadot_service::{FullNodeHandles, PolkadotClient};
#[cfg(feature = "service-rewr")]
use polkadot_service_new::{
self as polkadot_service,
Error as ServiceError, FullNodeHandles, PolkadotClient,
};
const COLLATION_TIMEOUT: Duration = Duration::from_secs(30);
......@@ -201,9 +207,46 @@ pub async fn collate<P>(
Ok(collation)
}
#[cfg(feature = "service-rewr")]
fn build_collator_service<SP, P, C, R, Extrinsic>(
_spawner: SP,
_handles: FullNodeHandles,
_client: Arc<C>,
_para_id: ParaId,
_key: Arc<CollatorPair>,
_build_parachain_context: P,
) -> Result<future::Ready<()>, polkadot_service::Error>
where
C: PolkadotClient<
service::Block,
service::TFullBackend<service::Block>,
R
> + 'static,
R: ConstructRuntimeApi<service::Block, C> + Sync + Send,
<R as ConstructRuntimeApi<service::Block, C>>::RuntimeApi:
sp_api::ApiExt<
service::Block,
StateBackend = <service::TFullBackend<service::Block> as service::Backend<service::Block>>::State,
>
+ RuntimeApiCollection<
Extrinsic,
StateBackend = <service::TFullBackend<service::Block> as service::Backend<service::Block>>::State,
>
+ Sync + Send,
P: BuildParachainContext,
P::ParachainContext: Send + 'static,
<P::ParachainContext as ParachainContext>::ProduceCandidate: Send,
Extrinsic: service::Codec + Send + Sync + 'static,
SP: Spawn + Clone + Send + Sync + 'static,
{
Err("Collator is not functional with the new service yet".into())
}
#[cfg(not(feature = "service-rewr"))]
fn build_collator_service<SP, P, C, R, Extrinsic>(
spawner: SP,
handles: polkadot_service::FullNodeHandles,
handles: FullNodeHandles,
client: Arc<C>,
para_id: ParaId,
key: Arc<CollatorPair>,
......@@ -408,6 +451,7 @@ where
Ok(())
}
#[cfg(not(feature = "service-rewr"))]
fn compute_targets(para_id: ParaId, session_keys: &[ValidatorId], roster: DutyRoster) -> HashSet<ValidatorId> {
use polkadot_primitives::parachain::Chain;
......
......@@ -56,6 +56,7 @@
use std::fmt::Debug;
use std::pin::Pin;
use std::sync::Arc;
use std::task::Poll;
use std::time::Duration;
use std::collections::HashSet;
......@@ -232,7 +233,7 @@ impl OverseerHandler {
/// [`Overseer`]: struct.Overseer.html
/// [`OverseerHandler`]: struct.OverseerHandler.html
pub async fn forward_events<P: BlockchainEvents<Block>>(
client: P,
client: Arc<P>,
mut handler: OverseerHandler,
) -> SubsystemResult<()> {
let mut finality = client.finality_notification_stream();
......
[package]
name = "polkadot-service-new"
version = "0.8.3"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
parking_lot = "0.9.0"
serde = { version = "1.0.102", features = ["derive"] }
lazy_static = "1.4.0"
log = "0.4.8"
futures = "0.3.4"
slog = "2.5.2"
hex-literal = "0.2.1"
polkadot-primitives = { path = "../../primitives" }
polkadot-runtime = { path = "../../runtime/polkadot" }
polkadot-overseer = { path = "../overseer" }
kusama-runtime = { path = "../../runtime/kusama" }
westend-runtime = { path = "../../runtime/westend" }
polkadot-network = { path = "../../network", optional = true }
polkadot-rpc = { path = "../../rpc" }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client-db = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
consensus_common = { package = "sp-consensus", git = "https://github.com/paritytech/substrate", branch = "master" }
grandpa = { package = "sc-finality-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" }
grandpa_primitives = { package = "sp-finality-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" }
inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master" }
service = { package = "sc-service", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
telemetry = { package = "sc-telemetry", git = "https://github.com/paritytech/substrate", branch = "master" }
sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-staking = { git = "https://github.com/paritytech/substrate", branch = "master" }
im-online = { package = "pallet-im-online", git = "https://github.com/paritytech/substrate", branch = "master" }
authority-discovery = { package = "sc-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master" }
authority-discovery-primitives = { package = "sp-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master" }
babe = { package = "sc-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master" }
babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master" }
sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
system_rpc_runtime_api = { package = "frame-system-rpc-runtime-api", git = "https://github.com/paritytech/substrate", branch = "master" }
codec = { package = "parity-scale-codec", version = "1.3.0" }
sp-session = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-offchain = { package = "sp-offchain", git = "https://github.com/paritytech/substrate", branch = "master" }
prometheus-endpoint = { package = "substrate-prometheus-endpoint", git = "https://github.com/paritytech/substrate", branch = "master" }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
[dev-dependencies]
polkadot-test-runtime-client = { path = "../../runtime/test-runtime/client" }
sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
env_logger = "0.7.0"
[features]
default = ["db", "full-node"]
db = ["service/db"]
runtime-benchmarks = ["polkadot-runtime/runtime-benchmarks", "kusama-runtime/runtime-benchmarks", "westend-runtime/runtime-benchmarks"]
full-node = []
= Polkadot Service
placeholder
//TODO Write content :) (https://github.com/paritytech/polkadot/issues/159)
This diff is collapsed.
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Polkadot Client meta trait
use sp_api::{ProvideRuntimeApi, ConstructRuntimeApi, CallApiAt};
use sp_blockchain::HeaderBackend;
use sp_runtime::traits::Block as BlockT;
use sc_client_api::{Backend as BackendT, BlockchainEvents};
/// Polkadot client abstraction, this super trait only pulls in functionality required for
/// polkadot internal crates like polkadot-collator.
pub trait PolkadotClient<Block, Backend, Runtime>:
BlockchainEvents<Block> + Sized + Send + Sync
+ ProvideRuntimeApi<Block, Api = Runtime::RuntimeApi>
+ HeaderBackend<Block>
+ CallApiAt<
Block,
Error = sp_blockchain::Error,
StateBackend = Backend ::State
>
where
Block: BlockT,
Backend: BackendT<Block>,
Runtime: ConstructRuntimeApi<Block, Self>
{}
impl<Block, Backend, Runtime, Client> PolkadotClient<Block, Backend, Runtime> for Client
where
Block: BlockT,
Runtime: ConstructRuntimeApi<Block, Self>,
Backend: BackendT<Block>,
Client: BlockchainEvents<Block> + ProvideRuntimeApi<Block, Api = Runtime::RuntimeApi> + HeaderBackend<Block>
+ Sized + Send + Sync
+ CallApiAt<
Block,
Error = sp_blockchain::Error,
StateBackend = Backend ::State
>
{}
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Polkadot-specific GRANDPA integration utilities.
use polkadot_primitives::Hash;
use sp_runtime::traits::{Block as BlockT, NumberFor};
/// A custom GRANDPA voting rule that "pauses" voting (i.e. keeps voting for the
/// same last finalized block) after a given block at height `N` has been
/// finalized and for a delay of `M` blocks, i.e. until the best block reaches
/// `N` + `M`, the voter will keep voting for block `N`.
pub(crate) struct PauseAfterBlockFor<N>(pub(crate) N, pub(crate) N);
impl<Block, B> grandpa::VotingRule<Block, B> for PauseAfterBlockFor<NumberFor<Block>> where
Block: BlockT,
B: sp_blockchain::HeaderBackend<Block>,
{
fn restrict_vote(
&self,
backend: &B,
base: &Block::Header,
best_target: &Block::Header,
current_target: &Block::Header,
) -> Option<(Block::Hash, NumberFor<Block>)> {
use sp_runtime::generic::BlockId;
use sp_runtime::traits::Header as _;
// walk backwards until we find the target block
let find_target = |
target_number: NumberFor<Block>,
current_header: &Block::Header
| {
let mut target_hash = current_header.hash();
let mut target_header = current_header.clone();
loop {
if *target_header.number() < target_number {
unreachable!(
"we are traversing backwards from a known block; \
blocks are stored contiguously; \
qed"
);
}
if *target_header.number() == target_number {
return Some((target_hash, target_number));
}
target_hash = *target_header.parent_hash();
target_header = backend.header(BlockId::Hash(target_hash)).ok()?
.expect("Header known to exist due to the existence of one of its descendents; qed");
}
};
// only restrict votes targeting a block higher than the block
// we've set for the pause
if *current_target.number() > self.0 {
// if we're past the pause period (i.e. `self.0 + self.1`)
// then we no longer need to restrict any votes
if *best_target.number() > self.0 + self.1 {
return None;
}
// if we've finalized the pause block, just keep returning it
// until best number increases enough to pass the condition above
if *base.number() >= self.0 {
return Some((base.hash(), *base.number()));
}
// otherwise find the target header at the pause block
// to vote on
return find_target(self.0, current_target);
}
None
}
}
/// GRANDPA hard forks due to borked migration of session keys after a runtime
/// upgrade (at #1491596), the signalled authority set changes were invalid
/// (blank keys) and were impossible to finalize. The authorities for these
/// intermediary pending changes are replaced with a static list comprised of
/// w3f validators and randomly selected validators from the latest session (at
/// #1500988).
pub(crate) fn kusama_hard_forks() -> Vec<(
grandpa_primitives::SetId,
(Hash, polkadot_primitives::BlockNumber),
grandpa_primitives::AuthorityList,
)> {
use sp_core::crypto::Ss58Codec;
use std::str::FromStr;
let forks = vec![
(
623,
"01e94e1e7e9cf07b3b0bf4e1717fce7448e5563901c2ef2e3b8e9ecaeba088b1",
1492283,
),
(
624,
"ddc4323c5e8966844dfaa87e0c2f74ef6b43115f17bf8e4ff38845a62d02b9a9",
1492436,
),
(
625,
"38ba115b296663e424e32d7b1655cd795719cef4fd7d579271a6d01086cf1628",
1492586,
),
(
626,
"f3172b6b8497c10fc772f5dada4eeb1f4c4919c97de9de2e1a439444d5a057ff",
1492955,
),
(
627,
"b26526aea299e9d24af29fdacd5cf4751a663d24894e3d0a37833aa14c58424a",
1493338,
),
(
628,
"3980d024327d53b8d01ef0d198a052cd058dd579508d8ed6283fe3614e0a3694",
1493913,
),
(
629,
"31f22997a786c25ee677786373368cae6fd501fd1bc4b212b8e267235c88179d",
1495083,
),
(
630,
"1c65eb250cf54b466c64f1a4003d1415a7ee275e49615450c0e0525179857eef",
1497404,
),
(
631,
"9e44116467cc9d7e224e36487bf2cf571698cae16b25f54a7430f1278331fdd8",
1498598,
),
];
let authorities = vec![
"CwjLJ1zPWK5Ao9WChAFp7rWGEgN3AyXXjTRPrqgm5WwBpoS",
"Dp8FHpZTzvoKXztkfrUAkF6xNf6sjVU5ZLZ29NEGUazouou",
"DtK7YfkhNWU6wEPF1dShsFdhtosVAuJPLkoGhKhG1r5LjKq",
"FLnHYBuoyThzqJ45tdb8P6yMLdocM7ir27Pg1AnpYoygm1K",
"FWEfJ5UMghr52UopgYjawAg6hQg3ztbQek75pfeRtLVi8pB",
"ECoLHAu7HKWGTB9od82HAtequYj6hvNHigkGSB9g3ApxAwB",
"GL1Tg3Uppo8GYL9NjKj4dWKcS6tW98REop9G5hpu7HgFwTa",
"ExnjU5LZMktrgtQBE3An6FsQfvaKG1ukxPqwhJydgdgarmY",
"CagLpgCBu5qJqYF2tpFX6BnU4yHvMGSjc7r3Ed1jY3tMbQt",
"DsrtmMsD4ijh3n4uodxPoiW9NZ7v7no5wVvPVj8fL1dfrWB",
"HQB4EctrVR68ozZDyBiRJzLRAEGh1YKgCkAsFjJcegL9RQA",
"H2YTYbXTFkDY1cGnv164ecnDT3hsD2bQXtyiDbcQuXcQZUV",
"H5WL8jXmbkCoEcLfvqJkbLUeGrDFsJiMXkhhRWn3joct1tE",
"DpB37GDrJDYcmg2df2eqsrPKMay1u8hyZ6sQi2FuUiUeNLu",
"FR8yjKRA9MTjvFGK8kfzrdC23Fr6xd7rfBvZXSjAsmuxURE",
"DxHPty3B9fpj3duu6Gc6gCSCAvsydJHJEY5G3oVYT8S5BYJ",
"DbVKC8ZJjevrhqSnZyJMMvmPL7oPPL4ed1roxawYnHVgyin",
"DVJV81kab2J6oTyRJ9T3NCwW2DSrysbWCssvMcE6cwZHnAd",
"Fg4rDAyzoVzf39Zo8JFPo4W314ntNWNwm3shr4xKe8M1fJg",
"GUaNcnAruMVxHGTs7gGpSUpigRJboQYQBBQyPohkFcP6NMH",
"J4BMGF4W9yWiJz4pkhQW73X6QMGpKUzmPppVnqzBCqw5dQq",
"E1cR61L1tdDEop4WdWVqcq1H1x6VqsDpSHvFyUeC41uruVJ",
"GoWLzBsj1f23YtdDpyntnvN1LwXKhF5TEeZvBeTVxofgWGR",
"CwHwmbogSwtRbrkajVBNubPvWmHBGU4bhMido54M9CjuKZD",
"FLT63y9oVXJnyiWMAL4RvWxsQx21Vymw9961Z7NRFmSG7rw",
"FoQ2y6JuHuHTG4rHFL3f2hCxfJMvtrq8wwPWdv8tsdkcyA8",
"D7QQKqqs8ocGorRA12h4QoBSHDia1DkHeXT4eMfjWQ483QH",
"J6z7FP35F9DiiU985bhkDTS3WxyeTBeoo9MtLdLoD3GiWPj",
"EjapydCK25AagodRbDECavHAy8yQY1tmeRhwUXhVWx4cFPv",
"H8admATcRkGCrF1dTDDBCjQDsYjMkuPaN9YwR2mSCj4DWMQ",