mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-24 05:25:48 +00:00
Run RustFmt as part of the CI (#37)
* Run RustFmt as part of the CI * Format repo * Run RustFmt before the default Travis build step Apparently if you override `script` you also need to make sure to `build` and `test` the code yourself. * Format repo
This commit is contained in:
committed by
Bastian Köcher
parent
d904a282c8
commit
e5f998d7d9
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use vergen::{ConstantsFlags, generate_cargo_keys};
|
use vergen::{generate_cargo_keys, ConstantsFlags};
|
||||||
|
|
||||||
const ERROR_MSG: &str = "Failed to generate metadata files";
|
const ERROR_MSG: &str = "Failed to generate metadata files";
|
||||||
|
|
||||||
|
|||||||
@@ -14,16 +14,15 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use sp_core::{Pair, Public, sr25519};
|
|
||||||
use bridge_node_runtime::{
|
use bridge_node_runtime::{
|
||||||
AccountId, AuraConfig, BalancesConfig, BridgeEthPoAConfig,
|
AccountId, AuraConfig, BalancesConfig, BridgeEthPoAConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,
|
||||||
GenesisConfig, GrandpaConfig, SudoConfig, SystemConfig,
|
SystemConfig, WASM_BINARY,
|
||||||
WASM_BINARY, Signature
|
|
||||||
};
|
};
|
||||||
use sp_consensus_aura::sr25519::{AuthorityId as AuraId};
|
use grandpa_primitives::AuthorityId as GrandpaId;
|
||||||
use grandpa_primitives::{AuthorityId as GrandpaId};
|
|
||||||
use sc_service;
|
use sc_service;
|
||||||
use sp_runtime::traits::{Verify, IdentifyAccount};
|
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
||||||
|
use sp_core::{sr25519, Pair, Public};
|
||||||
|
use sp_runtime::traits::{IdentifyAccount, Verify};
|
||||||
|
|
||||||
/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
|
/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
|
||||||
pub type ChainSpec = sc_service::ChainSpec<GenesisConfig>;
|
pub type ChainSpec = sc_service::ChainSpec<GenesisConfig>;
|
||||||
@@ -47,18 +46,16 @@ pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Pu
|
|||||||
type AccountPublic = <Signature as Verify>::Signer;
|
type AccountPublic = <Signature as Verify>::Signer;
|
||||||
|
|
||||||
/// Helper function to generate an account ID from seed
|
/// Helper function to generate an account ID from seed
|
||||||
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId where
|
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
|
||||||
AccountPublic: From<<TPublic::Pair as Pair>::Public>
|
where
|
||||||
|
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
|
||||||
{
|
{
|
||||||
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
|
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to generate an authority key for Aura
|
/// Helper function to generate an authority key for Aura
|
||||||
pub fn get_authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {
|
pub fn get_authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {
|
||||||
(
|
(get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))
|
||||||
get_from_seed::<AuraId>(s),
|
|
||||||
get_from_seed::<GrandpaId>(s),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Alternative {
|
impl Alternative {
|
||||||
@@ -68,24 +65,24 @@ impl Alternative {
|
|||||||
Alternative::Development => ChainSpec::from_genesis(
|
Alternative::Development => ChainSpec::from_genesis(
|
||||||
"Development",
|
"Development",
|
||||||
"dev",
|
"dev",
|
||||||
|| testnet_genesis(
|
|| {
|
||||||
vec![
|
testnet_genesis(
|
||||||
get_authority_keys_from_seed("Alice"),
|
vec![get_authority_keys_from_seed("Alice")],
|
||||||
],
|
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
|
||||||
vec![
|
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
vec![
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
||||||
],
|
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||||
true,
|
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||||
),
|
],
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
},
|
||||||
vec![],
|
vec![],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None
|
None,
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -98,17 +95,19 @@ impl Alternative {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testnet_genesis(initial_authorities: Vec<(AuraId, GrandpaId)>,
|
fn testnet_genesis(
|
||||||
|
initial_authorities: Vec<(AuraId, GrandpaId)>,
|
||||||
root_key: AccountId,
|
root_key: AccountId,
|
||||||
endowed_accounts: Vec<AccountId>,
|
endowed_accounts: Vec<AccountId>,
|
||||||
_enable_println: bool) -> GenesisConfig {
|
_enable_println: bool,
|
||||||
|
) -> GenesisConfig {
|
||||||
GenesisConfig {
|
GenesisConfig {
|
||||||
frame_system: Some(SystemConfig {
|
frame_system: Some(SystemConfig {
|
||||||
code: WASM_BINARY.to_vec(),
|
code: WASM_BINARY.to_vec(),
|
||||||
changes_trie_config: Default::default(),
|
changes_trie_config: Default::default(),
|
||||||
}),
|
}),
|
||||||
pallet_balances: Some(BalancesConfig {
|
pallet_balances: Some(BalancesConfig {
|
||||||
balances: endowed_accounts.iter().cloned().map(|k|(k, 1 << 60)).collect(),
|
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
|
||||||
}),
|
}),
|
||||||
pallet_aura: Some(AuraConfig {
|
pallet_aura: Some(AuraConfig {
|
||||||
authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),
|
authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),
|
||||||
@@ -117,9 +116,7 @@ fn testnet_genesis(initial_authorities: Vec<(AuraId, GrandpaId)>,
|
|||||||
pallet_grandpa: Some(GrandpaConfig {
|
pallet_grandpa: Some(GrandpaConfig {
|
||||||
authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect(),
|
authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect(),
|
||||||
}),
|
}),
|
||||||
pallet_sudo: Some(SudoConfig {
|
pallet_sudo: Some(SudoConfig { key: root_key }),
|
||||||
key: root_key,
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,45 +129,85 @@ pub fn load_spec(id: &str) -> Result<Option<ChainSpec>, String> {
|
|||||||
|
|
||||||
fn load_kovan_config() -> Option<BridgeEthPoAConfig> {
|
fn load_kovan_config() -> Option<BridgeEthPoAConfig> {
|
||||||
Some(BridgeEthPoAConfig {
|
Some(BridgeEthPoAConfig {
|
||||||
initial_header: sp_bridge_eth_poa::Header {
|
initial_header: sp_bridge_eth_poa::Header {
|
||||||
parent_hash: Default::default(),
|
parent_hash: Default::default(),
|
||||||
timestamp: 0,
|
timestamp: 0,
|
||||||
number: 0,
|
number: 0,
|
||||||
author: Default::default(),
|
author: Default::default(),
|
||||||
transactions_root: "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".parse().unwrap(),
|
transactions_root: "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
|
||||||
uncles_hash: "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347".parse().unwrap(),
|
.parse()
|
||||||
extra_data: vec![],
|
.unwrap(),
|
||||||
state_root: "2480155b48a1cea17d67dbfdfaafe821c1d19cdd478c5358e8ec56dec24502b2".parse().unwrap(),
|
uncles_hash: "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||||
receipts_root: "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".parse().unwrap(),
|
.parse()
|
||||||
log_bloom: Default::default(),
|
.unwrap(),
|
||||||
gas_used: Default::default(),
|
extra_data: vec![],
|
||||||
gas_limit: 6000000.into(),
|
state_root: "2480155b48a1cea17d67dbfdfaafe821c1d19cdd478c5358e8ec56dec24502b2"
|
||||||
difficulty: 131072.into(),
|
.parse()
|
||||||
seal: vec![
|
.unwrap(),
|
||||||
vec![128].into(),
|
receipts_root: "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
|
||||||
vec![184, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].into(),
|
.parse()
|
||||||
],
|
.unwrap(),
|
||||||
},
|
log_bloom: Default::default(),
|
||||||
initial_difficulty: 0.into(),
|
gas_used: Default::default(),
|
||||||
initial_validators: vec![
|
gas_limit: 6000000.into(),
|
||||||
[0x00, 0xD6, 0xCc, 0x1B, 0xA9, 0xcf, 0x89, 0xBD, 0x2e, 0x58,
|
difficulty: 131072.into(),
|
||||||
0x00, 0x97, 0x41, 0xf4, 0xF7, 0x32, 0x5B, 0xAd, 0xc0, 0xED].into(),
|
seal: vec![
|
||||||
[0x00, 0x42, 0x7f, 0xea, 0xe2, 0x41, 0x9c, 0x15, 0xb8, 0x9d,
|
vec![128].into(),
|
||||||
0x1c, 0x21, 0xaf, 0x10, 0xd1, 0xb6, 0x65, 0x0a, 0x4d, 0x3d].into(),
|
vec![
|
||||||
[0x4E, 0xd9, 0xB0, 0x8e, 0x63, 0x54, 0xC7, 0x0f, 0xE6, 0xF8,
|
184, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0xCB, 0x04, 0x11, 0xb0, 0xd3, 0x24, 0x6b, 0x42, 0x4d, 0x6c].into(),
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
[0x00, 0x20, 0xee, 0x4B, 0xe0, 0xe2, 0x02, 0x7d, 0x76, 0x60,
|
0, 0,
|
||||||
0x3c, 0xB7, 0x51, 0xeE, 0x06, 0x95, 0x19, 0xbA, 0x81, 0xA1].into(),
|
]
|
||||||
[0x00, 0x10, 0xf9, 0x4b, 0x29, 0x6a, 0x85, 0x2a, 0xaa, 0xc5,
|
.into(),
|
||||||
0x2e, 0xa6, 0xc5, 0xac, 0x72, 0xe0, 0x3a, 0xfd, 0x03, 0x2d].into(),
|
|
||||||
[0x00, 0x77, 0x33, 0xa1, 0xFE, 0x69, 0xCF, 0x3f, 0x2C, 0xF9,
|
|
||||||
0x89, 0xF8, 0x1C, 0x7b, 0x4c, 0xAc, 0x16, 0x93, 0x38, 0x7A].into(),
|
|
||||||
[0x00, 0xE6, 0xd2, 0xb9, 0x31, 0xF5, 0x5a, 0x3f, 0x17, 0x01,
|
|
||||||
0xc7, 0x38, 0x9d, 0x59, 0x2a, 0x77, 0x78, 0x89, 0x78, 0x79].into(),
|
|
||||||
[0x00, 0xe4, 0xa1, 0x06, 0x50, 0xe5, 0xa6, 0xD6, 0x00, 0x1C,
|
|
||||||
0x38, 0xff, 0x8E, 0x64, 0xF9, 0x70, 0x16, 0xa1, 0x64, 0x5c].into(),
|
|
||||||
[0x00, 0xa0, 0xa2, 0x4b, 0x9f, 0x0e, 0x5e, 0xc7, 0xaa, 0x4c,
|
|
||||||
0x73, 0x89, 0xb8, 0x30, 0x2f, 0xd0, 0x12, 0x31, 0x94, 0xde].into(),
|
|
||||||
],
|
],
|
||||||
})
|
},
|
||||||
|
initial_difficulty: 0.into(),
|
||||||
|
initial_validators: vec![
|
||||||
|
[
|
||||||
|
0x00, 0xD6, 0xCc, 0x1B, 0xA9, 0xcf, 0x89, 0xBD, 0x2e, 0x58, 0x00, 0x97, 0x41, 0xf4, 0xF7, 0x32, 0x5B,
|
||||||
|
0xAd, 0xc0, 0xED,
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
[
|
||||||
|
0x00, 0x42, 0x7f, 0xea, 0xe2, 0x41, 0x9c, 0x15, 0xb8, 0x9d, 0x1c, 0x21, 0xaf, 0x10, 0xd1, 0xb6, 0x65,
|
||||||
|
0x0a, 0x4d, 0x3d,
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
[
|
||||||
|
0x4E, 0xd9, 0xB0, 0x8e, 0x63, 0x54, 0xC7, 0x0f, 0xE6, 0xF8, 0xCB, 0x04, 0x11, 0xb0, 0xd3, 0x24, 0x6b,
|
||||||
|
0x42, 0x4d, 0x6c,
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
[
|
||||||
|
0x00, 0x20, 0xee, 0x4B, 0xe0, 0xe2, 0x02, 0x7d, 0x76, 0x60, 0x3c, 0xB7, 0x51, 0xeE, 0x06, 0x95, 0x19,
|
||||||
|
0xbA, 0x81, 0xA1,
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
[
|
||||||
|
0x00, 0x10, 0xf9, 0x4b, 0x29, 0x6a, 0x85, 0x2a, 0xaa, 0xc5, 0x2e, 0xa6, 0xc5, 0xac, 0x72, 0xe0, 0x3a,
|
||||||
|
0xfd, 0x03, 0x2d,
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
[
|
||||||
|
0x00, 0x77, 0x33, 0xa1, 0xFE, 0x69, 0xCF, 0x3f, 0x2C, 0xF9, 0x89, 0xF8, 0x1C, 0x7b, 0x4c, 0xAc, 0x16,
|
||||||
|
0x93, 0x38, 0x7A,
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
[
|
||||||
|
0x00, 0xE6, 0xd2, 0xb9, 0x31, 0xF5, 0x5a, 0x3f, 0x17, 0x01, 0xc7, 0x38, 0x9d, 0x59, 0x2a, 0x77, 0x78,
|
||||||
|
0x89, 0x78, 0x79,
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
[
|
||||||
|
0x00, 0xe4, 0xa1, 0x06, 0x50, 0xe5, 0xa6, 0xD6, 0x00, 0x1C, 0x38, 0xff, 0x8E, 0x64, 0xF9, 0x70, 0x16,
|
||||||
|
0xa1, 0x64, 0x5c,
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
[
|
||||||
|
0x00, 0xa0, 0xa2, 0x4b, 0x9f, 0x0e, 0x5e, 0xc7, 0xaa, 0x4c, 0x73, 0x89, 0xb8, 0x30, 0x2f, 0xd0, 0x12,
|
||||||
|
0x31, 0x94, 0xde,
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,11 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair};
|
|
||||||
use sc_cli::VersionInfo;
|
|
||||||
use crate::service;
|
|
||||||
use crate::chain_spec;
|
use crate::chain_spec;
|
||||||
use crate::cli::Cli;
|
use crate::cli::Cli;
|
||||||
|
use crate::service;
|
||||||
|
use sc_cli::VersionInfo;
|
||||||
|
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
|
||||||
|
|
||||||
/// Parse and run command line arguments
|
/// Parse and run command line arguments
|
||||||
pub fn run(version: VersionInfo) -> sc_cli::Result<()> {
|
pub fn run(version: VersionInfo) -> sc_cli::Result<()> {
|
||||||
@@ -46,20 +46,12 @@ pub fn run(version: VersionInfo) -> sc_cli::Result<()> {
|
|||||||
Some(subcommand) => {
|
Some(subcommand) => {
|
||||||
subcommand.init(&version)?;
|
subcommand.init(&version)?;
|
||||||
subcommand.update_config(&mut config, chain_spec::load_spec, &version)?;
|
subcommand.update_config(&mut config, chain_spec::load_spec, &version)?;
|
||||||
subcommand.run(
|
subcommand.run(config, |config: _| Ok(new_full_start!(config).0))
|
||||||
config,
|
}
|
||||||
|config: _| Ok(new_full_start!(config).0),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
None => {
|
None => {
|
||||||
opt.run.init(&version)?;
|
opt.run.init(&version)?;
|
||||||
opt.run.update_config(&mut config, chain_spec::load_spec, &version)?;
|
opt.run.update_config(&mut config, chain_spec::load_spec, &version)?;
|
||||||
opt.run.run(
|
opt.run.run(config, service::new_light, service::new_full, &version)
|
||||||
config,
|
}
|
||||||
service::new_light,
|
|
||||||
service::new_full,
|
|
||||||
&version,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,16 +16,16 @@
|
|||||||
|
|
||||||
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
|
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use bridge_node_runtime::{self, opaque::Block, GenesisConfig, RuntimeApi};
|
||||||
use std::time::Duration;
|
use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
|
||||||
use sc_client::LongestChain;
|
use sc_client::LongestChain;
|
||||||
use bridge_node_runtime::{self, GenesisConfig, opaque::Block, RuntimeApi};
|
|
||||||
use sc_service::{error::{Error as ServiceError}, AbstractService, Configuration, ServiceBuilder};
|
|
||||||
use sp_inherents::InherentDataProviders;
|
|
||||||
use sc_executor::native_executor_instance;
|
use sc_executor::native_executor_instance;
|
||||||
pub use sc_executor::NativeExecutor;
|
pub use sc_executor::NativeExecutor;
|
||||||
use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair};
|
use sc_service::{error::Error as ServiceError, AbstractService, Configuration, ServiceBuilder};
|
||||||
use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
|
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
|
||||||
|
use sp_inherents::InherentDataProviders;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
// Our native executor instance.
|
// Our native executor instance.
|
||||||
native_executor_instance!(
|
native_executor_instance!(
|
||||||
@@ -44,48 +44,50 @@ macro_rules! new_full_start {
|
|||||||
let inherent_data_providers = sp_inherents::InherentDataProviders::new();
|
let inherent_data_providers = sp_inherents::InherentDataProviders::new();
|
||||||
|
|
||||||
let builder = sc_service::ServiceBuilder::new_full::<
|
let builder = sc_service::ServiceBuilder::new_full::<
|
||||||
bridge_node_runtime::opaque::Block, bridge_node_runtime::RuntimeApi, crate::service::Executor
|
bridge_node_runtime::opaque::Block,
|
||||||
|
bridge_node_runtime::RuntimeApi,
|
||||||
|
crate::service::Executor,
|
||||||
>($config)?
|
>($config)?
|
||||||
.with_select_chain(|_config, backend| {
|
.with_select_chain(|_config, backend| Ok(sc_client::LongestChain::new(backend.clone())))?
|
||||||
Ok(sc_client::LongestChain::new(backend.clone()))
|
.with_transaction_pool(|config, client, _fetcher| {
|
||||||
})?
|
let pool_api = sc_transaction_pool::FullChainApi::new(client.clone());
|
||||||
.with_transaction_pool(|config, client, _fetcher| {
|
Ok(sc_transaction_pool::BasicPool::new(
|
||||||
let pool_api = sc_transaction_pool::FullChainApi::new(client.clone());
|
config,
|
||||||
Ok(sc_transaction_pool::BasicPool::new(config, std::sync::Arc::new(pool_api)))
|
std::sync::Arc::new(pool_api),
|
||||||
})?
|
))
|
||||||
.with_import_queue(|_config, client, mut select_chain, _transaction_pool| {
|
})?
|
||||||
let select_chain = select_chain.take()
|
.with_import_queue(|_config, client, mut select_chain, _transaction_pool| {
|
||||||
.ok_or_else(|| sc_service::Error::SelectChainRequired)?;
|
let select_chain = select_chain
|
||||||
|
.take()
|
||||||
|
.ok_or_else(|| sc_service::Error::SelectChainRequired)?;
|
||||||
|
|
||||||
let (grandpa_block_import, grandpa_link) =
|
let (grandpa_block_import, grandpa_link) = grandpa::block_import(client.clone(), &*client, select_chain)?;
|
||||||
grandpa::block_import(client.clone(), &*client, select_chain)?;
|
|
||||||
|
|
||||||
let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(
|
let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(
|
||||||
grandpa_block_import.clone(), client.clone(),
|
grandpa_block_import.clone(),
|
||||||
);
|
client.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair>(
|
let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair>(
|
||||||
sc_consensus_aura::slot_duration(&*client)?,
|
sc_consensus_aura::slot_duration(&*client)?,
|
||||||
aura_block_import,
|
aura_block_import,
|
||||||
Some(Box::new(grandpa_block_import.clone())),
|
Some(Box::new(grandpa_block_import.clone())),
|
||||||
None,
|
None,
|
||||||
client,
|
client,
|
||||||
inherent_data_providers.clone(),
|
inherent_data_providers.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
import_setup = Some((grandpa_block_import, grandpa_link));
|
import_setup = Some((grandpa_block_import, grandpa_link));
|
||||||
|
|
||||||
Ok(import_queue)
|
Ok(import_queue)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
(builder, import_setup, inherent_data_providers)
|
(builder, import_setup, inherent_data_providers)
|
||||||
}}
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a new service for a full client.
|
/// Builds a new service for a full client.
|
||||||
pub fn new_full(config: Configuration<GenesisConfig>)
|
pub fn new_full(config: Configuration<GenesisConfig>) -> Result<impl AbstractService, ServiceError> {
|
||||||
-> Result<impl AbstractService, ServiceError>
|
|
||||||
{
|
|
||||||
let is_authority = config.roles.is_authority();
|
let is_authority = config.roles.is_authority();
|
||||||
let force_authoring = config.force_authoring;
|
let force_authoring = config.force_authoring;
|
||||||
let name = config.name.clone();
|
let name = config.name.clone();
|
||||||
@@ -98,14 +100,14 @@ pub fn new_full(config: Configuration<GenesisConfig>)
|
|||||||
|
|
||||||
let (builder, mut import_setup, inherent_data_providers) = new_full_start!(config);
|
let (builder, mut import_setup, inherent_data_providers) = new_full_start!(config);
|
||||||
|
|
||||||
let (block_import, grandpa_link) =
|
let (block_import, grandpa_link) = import_setup
|
||||||
import_setup.take()
|
.take()
|
||||||
.expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
|
.expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
|
||||||
|
|
||||||
let service = builder
|
let service = builder
|
||||||
.with_finality_proof_provider(|client, backend|
|
.with_finality_proof_provider(|client, backend| {
|
||||||
Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _)
|
Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _)
|
||||||
)?
|
})?
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
if participates_in_consensus {
|
if participates_in_consensus {
|
||||||
@@ -115,11 +117,9 @@ pub fn new_full(config: Configuration<GenesisConfig>)
|
|||||||
};
|
};
|
||||||
|
|
||||||
let client = service.client();
|
let client = service.client();
|
||||||
let select_chain = service.select_chain()
|
let select_chain = service.select_chain().ok_or(ServiceError::SelectChainRequired)?;
|
||||||
.ok_or(ServiceError::SelectChainRequired)?;
|
|
||||||
|
|
||||||
let can_author_with =
|
let can_author_with = sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
|
||||||
sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
|
|
||||||
|
|
||||||
let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _>(
|
let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _>(
|
||||||
sc_consensus_aura::slot_duration(&*client)?,
|
sc_consensus_aura::slot_duration(&*client)?,
|
||||||
@@ -177,38 +177,28 @@ pub fn new_full(config: Configuration<GenesisConfig>)
|
|||||||
|
|
||||||
// the GRANDPA voter task is considered infallible, i.e.
|
// the GRANDPA voter task is considered infallible, i.e.
|
||||||
// if it fails we take down the service with it.
|
// if it fails we take down the service with it.
|
||||||
service.spawn_essential_task(
|
service.spawn_essential_task("grandpa-voter", grandpa::run_grandpa_voter(grandpa_config)?);
|
||||||
"grandpa-voter",
|
|
||||||
grandpa::run_grandpa_voter(grandpa_config)?
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
grandpa::setup_disabled_grandpa(
|
grandpa::setup_disabled_grandpa(service.client(), &inherent_data_providers, service.network())?;
|
||||||
service.client(),
|
|
||||||
&inherent_data_providers,
|
|
||||||
service.network(),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(service)
|
Ok(service)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a new service for a light client.
|
/// Builds a new service for a light client.
|
||||||
pub fn new_light(config: Configuration<GenesisConfig>)
|
pub fn new_light(config: Configuration<GenesisConfig>) -> Result<impl AbstractService, ServiceError> {
|
||||||
-> Result<impl AbstractService, ServiceError>
|
|
||||||
{
|
|
||||||
let inherent_data_providers = InherentDataProviders::new();
|
let inherent_data_providers = InherentDataProviders::new();
|
||||||
|
|
||||||
ServiceBuilder::new_light::<Block, RuntimeApi, Executor>(config)?
|
ServiceBuilder::new_light::<Block, RuntimeApi, Executor>(config)?
|
||||||
.with_select_chain(|_config, backend| {
|
.with_select_chain(|_config, backend| Ok(LongestChain::new(backend.clone())))?
|
||||||
Ok(LongestChain::new(backend.clone()))
|
|
||||||
})?
|
|
||||||
.with_transaction_pool(|config, client, fetcher| {
|
.with_transaction_pool(|config, client, fetcher| {
|
||||||
let fetcher = fetcher
|
let fetcher = fetcher.ok_or_else(|| "Trying to start light transaction pool without active fetcher")?;
|
||||||
.ok_or_else(|| "Trying to start light transaction pool without active fetcher")?;
|
|
||||||
|
|
||||||
let pool_api = sc_transaction_pool::LightChainApi::new(client.clone(), fetcher.clone());
|
let pool_api = sc_transaction_pool::LightChainApi::new(client.clone(), fetcher.clone());
|
||||||
let pool = sc_transaction_pool::BasicPool::with_revalidation_type(
|
let pool = sc_transaction_pool::BasicPool::with_revalidation_type(
|
||||||
config, Arc::new(pool_api), sc_transaction_pool::RevalidationType::Light,
|
config,
|
||||||
|
Arc::new(pool_api),
|
||||||
|
sc_transaction_pool::RevalidationType::Light,
|
||||||
);
|
);
|
||||||
Ok(pool)
|
Ok(pool)
|
||||||
})?
|
})?
|
||||||
@@ -216,12 +206,10 @@ pub fn new_light(config: Configuration<GenesisConfig>)
|
|||||||
let fetch_checker = fetcher
|
let fetch_checker = fetcher
|
||||||
.map(|fetcher| fetcher.checker().clone())
|
.map(|fetcher| fetcher.checker().clone())
|
||||||
.ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
|
.ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
|
||||||
let grandpa_block_import = grandpa::light_block_import(
|
let grandpa_block_import =
|
||||||
client.clone(), backend, &*client.clone(), Arc::new(fetch_checker),
|
grandpa::light_block_import(client.clone(), backend, &*client.clone(), Arc::new(fetch_checker))?;
|
||||||
)?;
|
|
||||||
let finality_proof_import = grandpa_block_import.clone();
|
let finality_proof_import = grandpa_block_import.clone();
|
||||||
let finality_proof_request_builder =
|
let finality_proof_request_builder = finality_proof_import.create_finality_proof_request_builder();
|
||||||
finality_proof_import.create_finality_proof_request_builder();
|
|
||||||
|
|
||||||
let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair>(
|
let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair>(
|
||||||
sc_consensus_aura::slot_duration(&*client)?,
|
sc_consensus_aura::slot_duration(&*client)?,
|
||||||
@@ -234,8 +222,8 @@ pub fn new_light(config: Configuration<GenesisConfig>)
|
|||||||
|
|
||||||
Ok((import_queue, finality_proof_request_builder))
|
Ok((import_queue, finality_proof_request_builder))
|
||||||
})?
|
})?
|
||||||
.with_finality_proof_provider(|client, backend|
|
.with_finality_proof_provider(|client, backend| {
|
||||||
Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _)
|
Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _)
|
||||||
)?
|
})?
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,41 +18,35 @@
|
|||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
|
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
|
||||||
#![recursion_limit="256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
// Make the WASM binary available.
|
// Make the WASM binary available.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||||
|
|
||||||
use sp_std::prelude::*;
|
use pallet_grandpa::fg_primitives;
|
||||||
use sp_core::OpaqueMetadata;
|
use pallet_grandpa::AuthorityList as GrandpaAuthorityList;
|
||||||
use sp_runtime::{
|
|
||||||
ApplyExtrinsicResult, transaction_validity::TransactionValidity, generic, create_runtime_str,
|
|
||||||
impl_opaque_keys, MultiSignature,
|
|
||||||
};
|
|
||||||
use sp_runtime::traits::{
|
|
||||||
BlakeTwo256, Block as BlockT, IdentityLookup, Verify, ConvertInto, IdentifyAccount
|
|
||||||
};
|
|
||||||
use sp_api::impl_runtime_apis;
|
use sp_api::impl_runtime_apis;
|
||||||
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
||||||
use pallet_grandpa::AuthorityList as GrandpaAuthorityList;
|
use sp_core::OpaqueMetadata;
|
||||||
use pallet_grandpa::fg_primitives;
|
use sp_runtime::traits::{BlakeTwo256, Block as BlockT, ConvertInto, IdentifyAccount, IdentityLookup, Verify};
|
||||||
use sp_version::RuntimeVersion;
|
use sp_runtime::{
|
||||||
|
create_runtime_str, generic, impl_opaque_keys, transaction_validity::TransactionValidity, ApplyExtrinsicResult,
|
||||||
|
MultiSignature,
|
||||||
|
};
|
||||||
|
use sp_std::prelude::*;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use sp_version::NativeVersion;
|
use sp_version::NativeVersion;
|
||||||
|
use sp_version::RuntimeVersion;
|
||||||
|
|
||||||
// A few exports that help ease life for downstream crates.
|
// A few exports that help ease life for downstream crates.
|
||||||
|
pub use frame_support::{construct_runtime, parameter_types, traits::Randomness, weights::Weight, StorageValue};
|
||||||
|
pub use pallet_balances::Call as BalancesCall;
|
||||||
|
pub use pallet_bridge_eth_poa::Call as BridgeEthPoACall;
|
||||||
|
pub use pallet_timestamp::Call as TimestampCall;
|
||||||
#[cfg(any(feature = "std", test))]
|
#[cfg(any(feature = "std", test))]
|
||||||
pub use sp_runtime::BuildStorage;
|
pub use sp_runtime::BuildStorage;
|
||||||
pub use pallet_timestamp::Call as TimestampCall;
|
pub use sp_runtime::{Perbill, Permill};
|
||||||
pub use pallet_balances::Call as BalancesCall;
|
|
||||||
pub use sp_runtime::{Permill, Perbill};
|
|
||||||
pub use frame_support::{
|
|
||||||
StorageValue, construct_runtime, parameter_types,
|
|
||||||
traits::Randomness,
|
|
||||||
weights::Weight,
|
|
||||||
};
|
|
||||||
pub use pallet_bridge_eth_poa::Call as BridgeEthPoACall;
|
|
||||||
|
|
||||||
/// An index to a block.
|
/// An index to a block.
|
||||||
pub type BlockNumber = u32;
|
pub type BlockNumber = u32;
|
||||||
@@ -274,7 +268,7 @@ pub type SignedExtra = (
|
|||||||
frame_system::CheckEra<Runtime>,
|
frame_system::CheckEra<Runtime>,
|
||||||
frame_system::CheckNonce<Runtime>,
|
frame_system::CheckNonce<Runtime>,
|
||||||
frame_system::CheckWeight<Runtime>,
|
frame_system::CheckWeight<Runtime>,
|
||||||
pallet_transaction_payment::ChargeTransactionPayment<Runtime>
|
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
|
||||||
);
|
);
|
||||||
/// The payload being signed in transactions.
|
/// The payload being signed in transactions.
|
||||||
pub type SignedPayload = generic::SignedPayload<Call, SignedExtra>;
|
pub type SignedPayload = generic::SignedPayload<Call, SignedExtra>;
|
||||||
@@ -283,7 +277,8 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signatu
|
|||||||
/// Extrinsic type that has already been checked.
|
/// Extrinsic type that has already been checked.
|
||||||
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>;
|
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>;
|
||||||
/// Executive: handles dispatch to the various modules.
|
/// Executive: handles dispatch to the various modules.
|
||||||
pub type Executive = frame_executive::Executive<Runtime, Block, frame_system::ChainContext<Runtime>, Runtime, AllModules>;
|
pub type Executive =
|
||||||
|
frame_executive::Executive<Runtime, Block, frame_system::ChainContext<Runtime>, Runtime, AllModules>;
|
||||||
|
|
||||||
impl_runtime_apis! {
|
impl_runtime_apis! {
|
||||||
impl sp_api::Core<Block> for Runtime {
|
impl sp_api::Core<Block> for Runtime {
|
||||||
|
|||||||
@@ -100,7 +100,13 @@ fn prepare_votes<S: Storage>(
|
|||||||
header: &Header,
|
header: &Header,
|
||||||
submitter: Option<&S::Submitter>,
|
submitter: Option<&S::Submitter>,
|
||||||
two_thirds_majority_transition: u64,
|
two_thirds_majority_transition: u64,
|
||||||
) -> Result<(BTreeMap<Address, u64>, VecDeque<(H256, u64, Option<S::Submitter>, BTreeSet<Address>)>), Error> {
|
) -> Result<
|
||||||
|
(
|
||||||
|
BTreeMap<Address, u64>,
|
||||||
|
VecDeque<(H256, u64, Option<S::Submitter>, BTreeSet<Address>)>,
|
||||||
|
),
|
||||||
|
Error,
|
||||||
|
> {
|
||||||
// this fn can only work with single validators set
|
// this fn can only work with single validators set
|
||||||
if !validators.contains(&header.author) {
|
if !validators.contains(&header.author) {
|
||||||
return Err(Error::NotValidator);
|
return Err(Error::NotValidator);
|
||||||
|
|||||||
@@ -36,10 +36,7 @@ use crate::validators::{Validators, ValidatorsConfiguration};
|
|||||||
use crate::verification::verify_aura_header;
|
use crate::verification::verify_aura_header;
|
||||||
use crate::{AuraConfiguration, Storage};
|
use crate::{AuraConfiguration, Storage};
|
||||||
use primitives::{Header, Receipt, H256};
|
use primitives::{Header, Receipt, H256};
|
||||||
use sp_std::{
|
use sp_std::{collections::btree_map::BTreeMap, prelude::*};
|
||||||
collections::btree_map::BTreeMap,
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Maximal number of headers behind best blocks that we are aiming to store. When there
|
/// Maximal number of headers behind best blocks that we are aiming to store. When there
|
||||||
/// are too many unfinalized headers, it slows down finalization tracking significantly.
|
/// are too many unfinalized headers, it slows down finalization tracking significantly.
|
||||||
@@ -89,7 +86,7 @@ pub fn import_headers<S: Storage>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
useful += 1;
|
useful += 1;
|
||||||
},
|
}
|
||||||
Err(Error::AncientHeader) | Err(Error::KnownHeader) => useless += 1,
|
Err(Error::AncientHeader) | Err(Error::KnownHeader) => useless += 1,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
}
|
}
|
||||||
@@ -143,16 +140,14 @@ pub fn import_header<S: Storage>(
|
|||||||
let total_difficulty = import_context.total_difficulty() + header.difficulty;
|
let total_difficulty = import_context.total_difficulty() + header.difficulty;
|
||||||
let is_best = total_difficulty > best_total_difficulty;
|
let is_best = total_difficulty > best_total_difficulty;
|
||||||
let header_number = header.number;
|
let header_number = header.number;
|
||||||
storage.insert_header(
|
storage.insert_header(import_context.into_import_header(
|
||||||
import_context.into_import_header(
|
is_best,
|
||||||
is_best,
|
hash,
|
||||||
hash,
|
header,
|
||||||
header,
|
total_difficulty,
|
||||||
total_difficulty,
|
enacted_change,
|
||||||
enacted_change,
|
scheduled_change,
|
||||||
scheduled_change,
|
));
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// now mark finalized headers && prune old headers
|
// now mark finalized headers && prune old headers
|
||||||
storage.finalize_headers(
|
storage.finalize_headers(
|
||||||
@@ -300,18 +295,18 @@ mod tests {
|
|||||||
let mut latest_block_hash = Default::default();
|
let mut latest_block_hash = Default::default();
|
||||||
for i in 1..11 {
|
for i in 1..11 {
|
||||||
let header = block_i(&storage, i, &validators);
|
let header = block_i(&storage, i, &validators);
|
||||||
let (rolling_last_block_hash, finalized_blocks) =
|
let (rolling_last_block_hash, finalized_blocks) = import_header(
|
||||||
import_header(
|
&mut storage,
|
||||||
&mut storage,
|
&kovan_aura_config(),
|
||||||
&kovan_aura_config(),
|
&validators_config,
|
||||||
&validators_config,
|
10,
|
||||||
10,
|
Some(100),
|
||||||
Some(100),
|
header,
|
||||||
header,
|
None,
|
||||||
None,
|
)
|
||||||
).unwrap();
|
.unwrap();
|
||||||
match i {
|
match i {
|
||||||
2 ..= 10 => assert_eq!(
|
2..=10 => assert_eq!(
|
||||||
finalized_blocks,
|
finalized_blocks,
|
||||||
vec![(i - 1, block_i(&storage, i - 1, &validators).hash(), Some(100))],
|
vec![(i - 1, block_i(&storage, i - 1, &validators).hash(), Some(100))],
|
||||||
"At {}",
|
"At {}",
|
||||||
@@ -341,7 +336,8 @@ mod tests {
|
|||||||
Some(vec![crate::validators::tests::validators_change_recept(
|
Some(vec![crate::validators::tests::validators_change_recept(
|
||||||
latest_block_hash,
|
latest_block_hash,
|
||||||
)]),
|
)]),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
finalized_blocks,
|
finalized_blocks,
|
||||||
vec![(10, block_i(&storage, 10, &validators).hash(), Some(100))],
|
vec![(10, block_i(&storage, 10, &validators).hash(), Some(100))],
|
||||||
@@ -366,20 +362,17 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let header = signed_header(&validators, header, step as _);
|
let header = signed_header(&validators, header, step as _);
|
||||||
expected_blocks.push((i, header.hash(), Some(102)));
|
expected_blocks.push((i, header.hash(), Some(102)));
|
||||||
let (rolling_last_block_hash, finalized_blocks) =
|
let (rolling_last_block_hash, finalized_blocks) = import_header(
|
||||||
import_header(
|
&mut storage,
|
||||||
&mut storage,
|
&kovan_aura_config(),
|
||||||
&kovan_aura_config(),
|
&validators_config,
|
||||||
&validators_config,
|
10,
|
||||||
10,
|
Some(102),
|
||||||
Some(102),
|
header,
|
||||||
header,
|
None,
|
||||||
None,
|
)
|
||||||
).unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(finalized_blocks, vec![],);
|
||||||
finalized_blocks,
|
|
||||||
vec![],
|
|
||||||
);
|
|
||||||
latest_block_hash = rolling_last_block_hash;
|
latest_block_hash = rolling_last_block_hash;
|
||||||
step += 3;
|
step += 3;
|
||||||
}
|
}
|
||||||
@@ -406,7 +399,8 @@ mod tests {
|
|||||||
Some(103),
|
Some(103),
|
||||||
header,
|
header,
|
||||||
None,
|
None,
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(finalized_blocks, expected_blocks);
|
assert_eq!(finalized_blocks, expected_blocks);
|
||||||
assert_eq!(storage.oldest_unpruned_block(), 15);
|
assert_eq!(storage.oldest_unpruned_block(), 15);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,12 +36,7 @@ use codec::{Decode, Encode};
|
|||||||
use frame_support::{decl_module, decl_storage};
|
use frame_support::{decl_module, decl_storage};
|
||||||
use primitives::{Address, Header, Receipt, H256, U256};
|
use primitives::{Address, Header, Receipt, H256, U256};
|
||||||
use sp_runtime::RuntimeDebug;
|
use sp_runtime::RuntimeDebug;
|
||||||
use sp_std::{
|
use sp_std::{cmp::Ord, collections::btree_map::BTreeMap, iter::from_fn, prelude::*};
|
||||||
prelude::*,
|
|
||||||
cmp::Ord,
|
|
||||||
collections::btree_map::BTreeMap,
|
|
||||||
iter::from_fn,
|
|
||||||
};
|
|
||||||
use validators::{ValidatorsConfiguration, ValidatorsSource};
|
use validators::{ValidatorsConfiguration, ValidatorsSource};
|
||||||
|
|
||||||
pub use import::{header_import_requires_receipts, import_header};
|
pub use import::{header_import_requires_receipts, import_header};
|
||||||
@@ -481,7 +476,10 @@ impl<T: Trait> Storage for BridgeStorage<T> {
|
|||||||
// ensure that unfinalized headers we want to prune do not have scheduled changes
|
// ensure that unfinalized headers we want to prune do not have scheduled changes
|
||||||
if number > finalized_number {
|
if number > finalized_number {
|
||||||
if let Some(ref blocks_at_number) = blocks_at_number {
|
if let Some(ref blocks_at_number) = blocks_at_number {
|
||||||
if blocks_at_number.iter().any(|block| ScheduledChanges::contains_key(block)) {
|
if blocks_at_number
|
||||||
|
.iter()
|
||||||
|
.any(|block| ScheduledChanges::contains_key(block))
|
||||||
|
{
|
||||||
HeadersByNumber::insert(number, blocks_at_number);
|
HeadersByNumber::insert(number, blocks_at_number);
|
||||||
OldestUnprunedBlock::put(number);
|
OldestUnprunedBlock::put(number);
|
||||||
return;
|
return;
|
||||||
@@ -776,7 +774,9 @@ pub(crate) mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn header(&self, hash: &H256) -> Option<(Header, Option<Self::Submitter>)> {
|
fn header(&self, hash: &H256) -> Option<(Header, Option<Self::Submitter>)> {
|
||||||
self.headers.get(hash).map(|header| (header.header.clone(), header.submitter.clone()))
|
self.headers
|
||||||
|
.get(hash)
|
||||||
|
.map(|header| (header.header.clone(), header.submitter.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_context(
|
fn import_context(
|
||||||
|
|||||||
@@ -198,10 +198,7 @@ mod tests {
|
|||||||
empty_step
|
empty_step
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_with_config(
|
fn verify_with_config(config: &AuraConfiguration, header: &Header) -> Result<ImportContext<AccountId>, Error> {
|
||||||
config: &AuraConfiguration,
|
|
||||||
header: &Header,
|
|
||||||
) -> Result<ImportContext<AccountId>, Error> {
|
|
||||||
let storage = InMemoryStorage::new(genesis(), validators_addresses(3));
|
let storage = InMemoryStorage::new(genesis(), validators_addresses(3));
|
||||||
verify_aura_header(&storage, &config, None, header)
|
verify_aura_header(&storage, &config, None, header)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,18 +30,13 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use crate::ethereum_sync_loop::MaybeConnectionError;
|
||||||
|
use crate::ethereum_types::{Header, HeaderId, Receipt, H256, U64};
|
||||||
use jsonrpsee::common::Params;
|
use jsonrpsee::common::Params;
|
||||||
use jsonrpsee::raw::{
|
use jsonrpsee::raw::{RawClient, RawClientError};
|
||||||
RawClient,
|
use jsonrpsee::transport::http::{HttpTransportClient, RequestError};
|
||||||
RawClientError,
|
|
||||||
};
|
|
||||||
use jsonrpsee::transport::http::{
|
|
||||||
HttpTransportClient, RequestError
|
|
||||||
};
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde_json::{from_value, to_value};
|
use serde_json::{from_value, to_value};
|
||||||
use crate::ethereum_sync_loop::MaybeConnectionError;
|
|
||||||
use crate::ethereum_types::{H256, Header, HeaderId, Receipt, U64};
|
|
||||||
|
|
||||||
/// Proof of hash serialization success.
|
/// Proof of hash serialization success.
|
||||||
const HASH_SERIALIZATION_PROOF: &'static str = "hash serialization never fails; qed";
|
const HASH_SERIALIZATION_PROOF: &'static str = "hash serialization never fails; qed";
|
||||||
@@ -87,11 +82,7 @@ pub fn client(uri: &str) -> Client {
|
|||||||
|
|
||||||
/// Retrieve best known block number from Ethereum node.
|
/// Retrieve best known block number from Ethereum node.
|
||||||
pub async fn best_block_number(client: Client) -> (Client, Result<u64, Error>) {
|
pub async fn best_block_number(client: Client) -> (Client, Result<u64, Error>) {
|
||||||
let (client, result) = call_rpc::<U64>(
|
let (client, result) = call_rpc::<U64>(client, "eth_blockNumber", Params::None).await;
|
||||||
client,
|
|
||||||
"eth_blockNumber",
|
|
||||||
Params::None,
|
|
||||||
).await;
|
|
||||||
(client, result.map(|x| x.as_u64()))
|
(client, result.map(|x| x.as_u64()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,11 +95,17 @@ pub async fn header_by_number(client: Client, number: u64) -> (Client, Result<He
|
|||||||
to_value(U64::from(number)).expect(INT_SERIALIZATION_PROOF),
|
to_value(U64::from(number)).expect(INT_SERIALIZATION_PROOF),
|
||||||
to_value(false).expect(BOOL_SERIALIZATION_PROOF),
|
to_value(false).expect(BOOL_SERIALIZATION_PROOF),
|
||||||
]),
|
]),
|
||||||
).await;
|
)
|
||||||
(client, header.and_then(|header: Header| match header.number.is_some() && header.hash.is_some() {
|
.await;
|
||||||
true => Ok(header),
|
(
|
||||||
false => Err(Error::IncompleteHeader),
|
client,
|
||||||
}))
|
header.and_then(
|
||||||
|
|header: Header| match header.number.is_some() && header.hash.is_some() {
|
||||||
|
true => Ok(header),
|
||||||
|
false => Err(Error::IncompleteHeader),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve block header by its hash from Ethereum node.
|
/// Retrieve block header by its hash from Ethereum node.
|
||||||
@@ -120,11 +117,17 @@ pub async fn header_by_hash(client: Client, hash: H256) -> (Client, Result<Heade
|
|||||||
to_value(hash).expect(HASH_SERIALIZATION_PROOF),
|
to_value(hash).expect(HASH_SERIALIZATION_PROOF),
|
||||||
to_value(false).expect(BOOL_SERIALIZATION_PROOF),
|
to_value(false).expect(BOOL_SERIALIZATION_PROOF),
|
||||||
]),
|
]),
|
||||||
).await;
|
)
|
||||||
(client, header.and_then(|header: Header| match header.number.is_none() && header.hash.is_none() {
|
.await;
|
||||||
true => Ok(header),
|
(
|
||||||
false => Err(Error::IncompleteHeader),
|
client,
|
||||||
}))
|
header.and_then(
|
||||||
|
|header: Header| match header.number.is_none() && header.hash.is_none() {
|
||||||
|
true => Ok(header),
|
||||||
|
false => Err(Error::IncompleteHeader),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve transactions receipts for given block.
|
/// Retrieve transactions receipts for given block.
|
||||||
@@ -151,16 +154,16 @@ async fn transaction_receipt(client: Client, hash: H256) -> (Client, Result<Rece
|
|||||||
let (client, receipt) = call_rpc::<Receipt>(
|
let (client, receipt) = call_rpc::<Receipt>(
|
||||||
client,
|
client,
|
||||||
"eth_getTransactionReceipt",
|
"eth_getTransactionReceipt",
|
||||||
Params::Array(vec![
|
Params::Array(vec![to_value(hash).expect(HASH_SERIALIZATION_PROOF)]),
|
||||||
to_value(hash).expect(HASH_SERIALIZATION_PROOF),
|
)
|
||||||
]),
|
.await;
|
||||||
).await;
|
(
|
||||||
(client, receipt.and_then(|receipt| {
|
client,
|
||||||
match receipt.gas_used.is_some() {
|
receipt.and_then(|receipt| match receipt.gas_used.is_some() {
|
||||||
true => Ok(receipt),
|
true => Ok(receipt),
|
||||||
false => Err(Error::IncompleteReceipt),
|
false => Err(Error::IncompleteReceipt),
|
||||||
}
|
}),
|
||||||
}))
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls RPC on Ethereum node.
|
/// Calls RPC on Ethereum node.
|
||||||
|
|||||||
@@ -30,12 +30,10 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use crate::ethereum_types::{Header, HeaderId, HeaderStatus, QueuedHeader, Receipt, H256};
|
||||||
use std::collections::{
|
use std::collections::{
|
||||||
BTreeMap, HashMap, HashSet,
|
btree_map::Entry as BTreeMapEntry, hash_map::Entry as HashMapEntry, BTreeMap, HashMap, HashSet,
|
||||||
btree_map::Entry as BTreeMapEntry,
|
|
||||||
hash_map::Entry as HashMapEntry,
|
|
||||||
};
|
};
|
||||||
use crate::ethereum_types::{H256, Header, HeaderId, HeaderStatus, QueuedHeader, Receipt};
|
|
||||||
|
|
||||||
type HeadersQueue = BTreeMap<u64, HashMap<H256, QueuedHeader>>;
|
type HeadersQueue = BTreeMap<u64, HashMap<H256, QueuedHeader>>;
|
||||||
type KnownHeaders = BTreeMap<u64, HashMap<H256, HeaderStatus>>;
|
type KnownHeaders = BTreeMap<u64, HashMap<H256, HeaderStatus>>;
|
||||||
@@ -79,9 +77,15 @@ impl QueuedHeaders {
|
|||||||
pub fn headers_in_status(&self, status: HeaderStatus) -> usize {
|
pub fn headers_in_status(&self, status: HeaderStatus) -> usize {
|
||||||
match status {
|
match status {
|
||||||
HeaderStatus::Unknown | HeaderStatus::Synced => return 0,
|
HeaderStatus::Unknown | HeaderStatus::Synced => return 0,
|
||||||
HeaderStatus::MaybeOrphan => self.maybe_orphan.values().fold(0, |total, headers| total + headers.len()),
|
HeaderStatus::MaybeOrphan => self
|
||||||
|
.maybe_orphan
|
||||||
|
.values()
|
||||||
|
.fold(0, |total, headers| total + headers.len()),
|
||||||
HeaderStatus::Orphan => self.orphan.values().fold(0, |total, headers| total + headers.len()),
|
HeaderStatus::Orphan => self.orphan.values().fold(0, |total, headers| total + headers.len()),
|
||||||
HeaderStatus::MaybeReceipts => self.maybe_receipts.values().fold(0, |total, headers| total + headers.len()),
|
HeaderStatus::MaybeReceipts => self
|
||||||
|
.maybe_receipts
|
||||||
|
.values()
|
||||||
|
.fold(0, |total, headers| total + headers.len()),
|
||||||
HeaderStatus::Receipts => self.receipts.values().fold(0, |total, headers| total + headers.len()),
|
HeaderStatus::Receipts => self.receipts.values().fold(0, |total, headers| total + headers.len()),
|
||||||
HeaderStatus::Ready => self.ready.values().fold(0, |total, headers| total + headers.len()),
|
HeaderStatus::Ready => self.ready.values().fold(0, |total, headers| total + headers.len()),
|
||||||
HeaderStatus::Submitted => self.submitted.values().fold(0, |total, headers| total + headers.len()),
|
HeaderStatus::Submitted => self.submitted.values().fold(0, |total, headers| total + headers.len()),
|
||||||
@@ -90,9 +94,14 @@ impl QueuedHeaders {
|
|||||||
|
|
||||||
/// Returns number of headers that are currently in the queue.
|
/// Returns number of headers that are currently in the queue.
|
||||||
pub fn total_headers(&self) -> usize {
|
pub fn total_headers(&self) -> usize {
|
||||||
self.maybe_orphan.values().fold(0, |total, headers| total + headers.len())
|
self.maybe_orphan
|
||||||
|
.values()
|
||||||
|
.fold(0, |total, headers| total + headers.len())
|
||||||
+ self.orphan.values().fold(0, |total, headers| total + headers.len())
|
+ self.orphan.values().fold(0, |total, headers| total + headers.len())
|
||||||
+ self.maybe_receipts.values().fold(0, |total, headers| total + headers.len())
|
+ self
|
||||||
|
.maybe_receipts
|
||||||
|
.values()
|
||||||
|
.fold(0, |total, headers| total + headers.len())
|
||||||
+ self.receipts.values().fold(0, |total, headers| total + headers.len())
|
+ self.receipts.values().fold(0, |total, headers| total + headers.len())
|
||||||
+ self.ready.values().fold(0, |total, headers| total + headers.len())
|
+ self.ready.values().fold(0, |total, headers| total + headers.len())
|
||||||
}
|
}
|
||||||
@@ -171,16 +180,19 @@ impl QueuedHeaders {
|
|||||||
HeaderStatus::Unknown | HeaderStatus::MaybeOrphan => {
|
HeaderStatus::Unknown | HeaderStatus::MaybeOrphan => {
|
||||||
insert_header(&mut self.maybe_orphan, id, header);
|
insert_header(&mut self.maybe_orphan, id, header);
|
||||||
HeaderStatus::MaybeOrphan
|
HeaderStatus::MaybeOrphan
|
||||||
},
|
}
|
||||||
HeaderStatus::Orphan => {
|
HeaderStatus::Orphan => {
|
||||||
insert_header(&mut self.orphan, id, header);
|
insert_header(&mut self.orphan, id, header);
|
||||||
HeaderStatus::Orphan
|
HeaderStatus::Orphan
|
||||||
}
|
}
|
||||||
HeaderStatus::MaybeReceipts | HeaderStatus::Receipts | HeaderStatus::Ready
|
HeaderStatus::MaybeReceipts
|
||||||
| HeaderStatus::Submitted | HeaderStatus::Synced => {
|
| HeaderStatus::Receipts
|
||||||
|
| HeaderStatus::Ready
|
||||||
|
| HeaderStatus::Submitted
|
||||||
|
| HeaderStatus::Synced => {
|
||||||
insert_header(&mut self.maybe_receipts, id, header);
|
insert_header(&mut self.maybe_receipts, id, header);
|
||||||
HeaderStatus::MaybeReceipts
|
HeaderStatus::MaybeReceipts
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.known_headers.entry(id.0).or_default().insert(id.1, status);
|
self.known_headers.entry(id.0).or_default().insert(id.1, status);
|
||||||
@@ -202,10 +214,12 @@ impl QueuedHeaders {
|
|||||||
HeaderStatus::Ready => remove_header(&mut self.ready, ¤t),
|
HeaderStatus::Ready => remove_header(&mut self.ready, ¤t),
|
||||||
HeaderStatus::Submitted => remove_header(&mut self.submitted, ¤t),
|
HeaderStatus::Submitted => remove_header(&mut self.submitted, ¤t),
|
||||||
HeaderStatus::Synced => break,
|
HeaderStatus::Synced => break,
|
||||||
}.expect("header has a given status; given queue has the header; qed");
|
}
|
||||||
|
.expect("header has a given status; given queue has the header; qed");
|
||||||
|
|
||||||
log::debug!(target: "bridge", "Ethereum header {:?} is now {:?}", current, HeaderStatus::Synced);
|
log::debug!(target: "bridge", "Ethereum header {:?} is now {:?}", current, HeaderStatus::Synced);
|
||||||
*self.known_headers
|
*self
|
||||||
|
.known_headers
|
||||||
.entry(current.0)
|
.entry(current.0)
|
||||||
.or_default()
|
.or_default()
|
||||||
.entry(current.1)
|
.entry(current.1)
|
||||||
@@ -215,7 +229,8 @@ impl QueuedHeaders {
|
|||||||
|
|
||||||
// remember that the header is synced
|
// remember that the header is synced
|
||||||
log::debug!(target: "bridge", "Ethereum header {:?} is now {:?}", id, HeaderStatus::Synced);
|
log::debug!(target: "bridge", "Ethereum header {:?} is now {:?}", id, HeaderStatus::Synced);
|
||||||
*self.known_headers
|
*self
|
||||||
|
.known_headers
|
||||||
.entry(id.0)
|
.entry(id.0)
|
||||||
.or_default()
|
.or_default()
|
||||||
.entry(id.1)
|
.entry(id.1)
|
||||||
@@ -303,7 +318,7 @@ impl QueuedHeaders {
|
|||||||
if prune_border <= self.prune_border {
|
if prune_border <= self.prune_border {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prune_queue(&mut self.maybe_orphan, prune_border);
|
prune_queue(&mut self.maybe_orphan, prune_border);
|
||||||
prune_queue(&mut self.orphan, prune_border);
|
prune_queue(&mut self.orphan, prune_border);
|
||||||
prune_queue(&mut self.maybe_receipts, prune_border);
|
prune_queue(&mut self.maybe_receipts, prune_border);
|
||||||
@@ -402,7 +417,10 @@ fn move_header_descendants(
|
|||||||
if current_parents.contains(&entry.get().header().parent_hash) {
|
if current_parents.contains(&entry.get().header().parent_hash) {
|
||||||
let header_to_move = entry.remove();
|
let header_to_move = entry.remove();
|
||||||
let header_to_move_id = header_to_move.id();
|
let header_to_move_id = header_to_move.id();
|
||||||
known_headers.entry(header_to_move_id.0).or_default().insert(header_to_move_id.1, destination_status);
|
known_headers
|
||||||
|
.entry(header_to_move_id.0)
|
||||||
|
.or_default()
|
||||||
|
.insert(header_to_move_id.1, destination_status);
|
||||||
headers_to_move.push((header_to_move_id, header_to_move));
|
headers_to_move.push((header_to_move_id, header_to_move));
|
||||||
|
|
||||||
log::debug!(
|
log::debug!(
|
||||||
@@ -438,7 +456,8 @@ fn oldest_header(queue: &HeadersQueue) -> Option<&QueuedHeader> {
|
|||||||
|
|
||||||
/// Return oldest headers from the queue until functor will return false.
|
/// Return oldest headers from the queue until functor will return false.
|
||||||
fn oldest_headers(queue: &HeadersQueue, mut f: impl FnMut(&QueuedHeader) -> bool) -> Option<Vec<&QueuedHeader>> {
|
fn oldest_headers(queue: &HeadersQueue, mut f: impl FnMut(&QueuedHeader) -> bool) -> Option<Vec<&QueuedHeader>> {
|
||||||
let result = queue.values()
|
let result = queue
|
||||||
|
.values()
|
||||||
.flat_map(|h| h.values())
|
.flat_map(|h| h.values())
|
||||||
.take_while(|h| f(h))
|
.take_while(|h| f(h))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@@ -490,11 +509,27 @@ pub(crate) mod tests {
|
|||||||
fn total_headers_works() {
|
fn total_headers_works() {
|
||||||
// total headers just sums up number of headers in every queue
|
// total headers just sums up number of headers in every queue
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.maybe_orphan.entry(1).or_default().insert(hash(1), Default::default());
|
queue
|
||||||
queue.maybe_orphan.entry(1).or_default().insert(hash(2), Default::default());
|
.maybe_orphan
|
||||||
queue.maybe_orphan.entry(2).or_default().insert(hash(3), Default::default());
|
.entry(1)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(1), Default::default());
|
||||||
|
queue
|
||||||
|
.maybe_orphan
|
||||||
|
.entry(1)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(2), Default::default());
|
||||||
|
queue
|
||||||
|
.maybe_orphan
|
||||||
|
.entry(2)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(3), Default::default());
|
||||||
queue.orphan.entry(3).or_default().insert(hash(4), Default::default());
|
queue.orphan.entry(3).or_default().insert(hash(4), Default::default());
|
||||||
queue.maybe_receipts.entry(4).or_default().insert(hash(5), Default::default());
|
queue
|
||||||
|
.maybe_receipts
|
||||||
|
.entry(4)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(5), Default::default());
|
||||||
queue.ready.entry(5).or_default().insert(hash(6), Default::default());
|
queue.ready.entry(5).or_default().insert(hash(6), Default::default());
|
||||||
assert_eq!(queue.total_headers(), 6);
|
assert_eq!(queue.total_headers(), 6);
|
||||||
}
|
}
|
||||||
@@ -503,21 +538,41 @@ pub(crate) mod tests {
|
|||||||
fn best_queued_number_works() {
|
fn best_queued_number_works() {
|
||||||
// initially there are headers in MaybeOrphan queue only
|
// initially there are headers in MaybeOrphan queue only
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.maybe_orphan.entry(1).or_default().insert(hash(1), Default::default());
|
queue
|
||||||
queue.maybe_orphan.entry(1).or_default().insert(hash(2), Default::default());
|
.maybe_orphan
|
||||||
queue.maybe_orphan.entry(3).or_default().insert(hash(3), Default::default());
|
.entry(1)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(1), Default::default());
|
||||||
|
queue
|
||||||
|
.maybe_orphan
|
||||||
|
.entry(1)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(2), Default::default());
|
||||||
|
queue
|
||||||
|
.maybe_orphan
|
||||||
|
.entry(3)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(3), Default::default());
|
||||||
assert_eq!(queue.best_queued_number(), 3);
|
assert_eq!(queue.best_queued_number(), 3);
|
||||||
// and then there's better header in Orphan
|
// and then there's better header in Orphan
|
||||||
queue.orphan.entry(10).or_default().insert(hash(10), Default::default());
|
queue.orphan.entry(10).or_default().insert(hash(10), Default::default());
|
||||||
assert_eq!(queue.best_queued_number(), 10);
|
assert_eq!(queue.best_queued_number(), 10);
|
||||||
// and then there's better header in MaybeReceipts
|
// and then there's better header in MaybeReceipts
|
||||||
queue.maybe_receipts.entry(20).or_default().insert(hash(20), Default::default());
|
queue
|
||||||
|
.maybe_receipts
|
||||||
|
.entry(20)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(20), Default::default());
|
||||||
assert_eq!(queue.best_queued_number(), 20);
|
assert_eq!(queue.best_queued_number(), 20);
|
||||||
// and then there's better header in Ready
|
// and then there's better header in Ready
|
||||||
queue.ready.entry(30).or_default().insert(hash(30), Default::default());
|
queue.ready.entry(30).or_default().insert(hash(30), Default::default());
|
||||||
assert_eq!(queue.best_queued_number(), 30);
|
assert_eq!(queue.best_queued_number(), 30);
|
||||||
// and then there's better header in MaybeOrphan again
|
// and then there's better header in MaybeOrphan again
|
||||||
queue.maybe_orphan.entry(40).or_default().insert(hash(40), Default::default());
|
queue
|
||||||
|
.maybe_orphan
|
||||||
|
.entry(40)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(40), Default::default());
|
||||||
assert_eq!(queue.best_queued_number(), 40);
|
assert_eq!(queue.best_queued_number(), 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,7 +582,11 @@ pub(crate) mod tests {
|
|||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
assert_eq!(queue.status(&id(10)), HeaderStatus::Unknown);
|
assert_eq!(queue.status(&id(10)), HeaderStatus::Unknown);
|
||||||
// and status is read from the KnownHeaders
|
// and status is read from the KnownHeaders
|
||||||
queue.known_headers.entry(10).or_default().insert(hash(10), HeaderStatus::Ready);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(10)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(10), HeaderStatus::Ready);
|
||||||
assert_eq!(queue.status(&id(10)), HeaderStatus::Ready);
|
assert_eq!(queue.status(&id(10)), HeaderStatus::Ready);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,50 +595,83 @@ pub(crate) mod tests {
|
|||||||
// initially we have oldest header #10
|
// initially we have oldest header #10
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.maybe_orphan.entry(10).or_default().insert(hash(1), header(100));
|
queue.maybe_orphan.entry(10).or_default().insert(hash(1), header(100));
|
||||||
assert_eq!(queue.header(HeaderStatus::MaybeOrphan).unwrap().header().hash.unwrap(), hash(100));
|
assert_eq!(
|
||||||
|
queue.header(HeaderStatus::MaybeOrphan).unwrap().header().hash.unwrap(),
|
||||||
|
hash(100)
|
||||||
|
);
|
||||||
// inserting #20 changes nothing
|
// inserting #20 changes nothing
|
||||||
queue.maybe_orphan.entry(20).or_default().insert(hash(1), header(101));
|
queue.maybe_orphan.entry(20).or_default().insert(hash(1), header(101));
|
||||||
assert_eq!(queue.header(HeaderStatus::MaybeOrphan).unwrap().header().hash.unwrap(), hash(100));
|
assert_eq!(
|
||||||
|
queue.header(HeaderStatus::MaybeOrphan).unwrap().header().hash.unwrap(),
|
||||||
|
hash(100)
|
||||||
|
);
|
||||||
// inserting #5 makes it oldest
|
// inserting #5 makes it oldest
|
||||||
queue.maybe_orphan.entry(5).or_default().insert(hash(1), header(102));
|
queue.maybe_orphan.entry(5).or_default().insert(hash(1), header(102));
|
||||||
assert_eq!(queue.header(HeaderStatus::MaybeOrphan).unwrap().header().hash.unwrap(), hash(102));
|
assert_eq!(
|
||||||
|
queue.header(HeaderStatus::MaybeOrphan).unwrap().header().hash.unwrap(),
|
||||||
|
hash(102)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn header_response_works() {
|
fn header_response_works() {
|
||||||
// when parent is Synced, we insert to MaybeReceipts
|
// when parent is Synced, we insert to MaybeReceipts
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::Synced);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::Synced);
|
||||||
queue.header_response(header(101).header().clone());
|
queue.header_response(header(101).header().clone());
|
||||||
assert_eq!(queue.status(&id(101)), HeaderStatus::MaybeReceipts);
|
assert_eq!(queue.status(&id(101)), HeaderStatus::MaybeReceipts);
|
||||||
|
|
||||||
// when parent is Ready, we insert to MaybeReceipts
|
// when parent is Ready, we insert to MaybeReceipts
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::Ready);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::Ready);
|
||||||
queue.header_response(header(101).header().clone());
|
queue.header_response(header(101).header().clone());
|
||||||
assert_eq!(queue.status(&id(101)), HeaderStatus::MaybeReceipts);
|
assert_eq!(queue.status(&id(101)), HeaderStatus::MaybeReceipts);
|
||||||
|
|
||||||
// when parent is Receipts, we insert to MaybeReceipts
|
// when parent is Receipts, we insert to MaybeReceipts
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::Receipts);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::Receipts);
|
||||||
queue.header_response(header(101).header().clone());
|
queue.header_response(header(101).header().clone());
|
||||||
assert_eq!(queue.status(&id(101)), HeaderStatus::MaybeReceipts);
|
assert_eq!(queue.status(&id(101)), HeaderStatus::MaybeReceipts);
|
||||||
|
|
||||||
// when parent is MaybeReceipts, we insert to MaybeReceipts
|
// when parent is MaybeReceipts, we insert to MaybeReceipts
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::MaybeReceipts);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::MaybeReceipts);
|
||||||
queue.header_response(header(101).header().clone());
|
queue.header_response(header(101).header().clone());
|
||||||
assert_eq!(queue.status(&id(101)), HeaderStatus::MaybeReceipts);
|
assert_eq!(queue.status(&id(101)), HeaderStatus::MaybeReceipts);
|
||||||
|
|
||||||
// when parent is Orphan, we insert to Orphan
|
// when parent is Orphan, we insert to Orphan
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::Orphan);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::Orphan);
|
||||||
queue.header_response(header(101).header().clone());
|
queue.header_response(header(101).header().clone());
|
||||||
assert_eq!(queue.status(&id(101)), HeaderStatus::Orphan);
|
assert_eq!(queue.status(&id(101)), HeaderStatus::Orphan);
|
||||||
|
|
||||||
// when parent is MaybeOrphan, we insert to MaybeOrphan
|
// when parent is MaybeOrphan, we insert to MaybeOrphan
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::MaybeOrphan);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::MaybeOrphan);
|
||||||
queue.header_response(header(101).header().clone());
|
queue.header_response(header(101).header().clone());
|
||||||
assert_eq!(queue.status(&id(101)), HeaderStatus::MaybeOrphan);
|
assert_eq!(queue.status(&id(101)), HeaderStatus::MaybeOrphan);
|
||||||
|
|
||||||
@@ -599,15 +691,39 @@ pub(crate) mod tests {
|
|||||||
// #97 in Receipts
|
// #97 in Receipts
|
||||||
// #96 in Ready
|
// #96 in Ready
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::MaybeOrphan);
|
queue
|
||||||
queue.maybe_orphan.entry(100).or_default().insert(hash(100), header(100));
|
.known_headers
|
||||||
queue.known_headers.entry(99).or_default().insert(hash(99), HeaderStatus::Orphan);
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::MaybeOrphan);
|
||||||
|
queue
|
||||||
|
.maybe_orphan
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), header(100));
|
||||||
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(99)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(99), HeaderStatus::Orphan);
|
||||||
queue.orphan.entry(99).or_default().insert(hash(99), header(99));
|
queue.orphan.entry(99).or_default().insert(hash(99), header(99));
|
||||||
queue.known_headers.entry(98).or_default().insert(hash(98), HeaderStatus::MaybeReceipts);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(98)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(98), HeaderStatus::MaybeReceipts);
|
||||||
queue.maybe_receipts.entry(98).or_default().insert(hash(98), header(98));
|
queue.maybe_receipts.entry(98).or_default().insert(hash(98), header(98));
|
||||||
queue.known_headers.entry(97).or_default().insert(hash(97), HeaderStatus::Receipts);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(97)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(97), HeaderStatus::Receipts);
|
||||||
queue.receipts.entry(97).or_default().insert(hash(97), header(97));
|
queue.receipts.entry(97).or_default().insert(hash(97), header(97));
|
||||||
queue.known_headers.entry(96).or_default().insert(hash(96), HeaderStatus::Ready);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(96)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(96), HeaderStatus::Ready);
|
||||||
queue.ready.entry(96).or_default().insert(hash(96), header(96));
|
queue.ready.entry(96).or_default().insert(hash(96), header(96));
|
||||||
queue.substrate_best_header_response(&id(100));
|
queue.substrate_best_header_response(&id(100));
|
||||||
|
|
||||||
@@ -618,7 +734,10 @@ pub(crate) mod tests {
|
|||||||
assert!(queue.receipts.is_empty());
|
assert!(queue.receipts.is_empty());
|
||||||
assert!(queue.ready.is_empty());
|
assert!(queue.ready.is_empty());
|
||||||
assert_eq!(queue.known_headers.len(), 5);
|
assert_eq!(queue.known_headers.len(), 5);
|
||||||
assert!(queue.known_headers.values().all(|s| s.values().all(|s| *s == HeaderStatus::Synced)));
|
assert!(queue
|
||||||
|
.known_headers
|
||||||
|
.values()
|
||||||
|
.all(|s| s.values().all(|s| *s == HeaderStatus::Synced)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -629,11 +748,27 @@ pub(crate) mod tests {
|
|||||||
// #102 in MaybeOrphan
|
// #102 in MaybeOrphan
|
||||||
// #103 in Orphan
|
// #103 in Orphan
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(101).or_default().insert(hash(101), HeaderStatus::Orphan);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(101)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(101), HeaderStatus::Orphan);
|
||||||
queue.orphan.entry(101).or_default().insert(hash(101), header(101));
|
queue.orphan.entry(101).or_default().insert(hash(101), header(101));
|
||||||
queue.known_headers.entry(102).or_default().insert(hash(102), HeaderStatus::MaybeOrphan);
|
queue
|
||||||
queue.maybe_orphan.entry(102).or_default().insert(hash(102), header(102));
|
.known_headers
|
||||||
queue.known_headers.entry(103).or_default().insert(hash(103), HeaderStatus::Orphan);
|
.entry(102)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(102), HeaderStatus::MaybeOrphan);
|
||||||
|
queue
|
||||||
|
.maybe_orphan
|
||||||
|
.entry(102)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(102), header(102));
|
||||||
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(103)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(103), HeaderStatus::Orphan);
|
||||||
queue.orphan.entry(103).or_default().insert(hash(103), header(103));
|
queue.orphan.entry(103).or_default().insert(hash(103), header(103));
|
||||||
queue.substrate_best_header_response(&id(100));
|
queue.substrate_best_header_response(&id(100));
|
||||||
|
|
||||||
@@ -655,12 +790,32 @@ pub(crate) mod tests {
|
|||||||
// and we have asked for MaybeOrphan status of #100.parent (i.e. #99)
|
// and we have asked for MaybeOrphan status of #100.parent (i.e. #99)
|
||||||
// and the response is: YES, #99 is known to the Substrate runtime
|
// and the response is: YES, #99 is known to the Substrate runtime
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::MaybeOrphan);
|
queue
|
||||||
queue.maybe_orphan.entry(100).or_default().insert(hash(100), header(100));
|
.known_headers
|
||||||
queue.known_headers.entry(101).or_default().insert(hash(101), HeaderStatus::Orphan);
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::MaybeOrphan);
|
||||||
|
queue
|
||||||
|
.maybe_orphan
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), header(100));
|
||||||
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(101)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(101), HeaderStatus::Orphan);
|
||||||
queue.orphan.entry(101).or_default().insert(hash(101), header(101));
|
queue.orphan.entry(101).or_default().insert(hash(101), header(101));
|
||||||
queue.known_headers.entry(102).or_default().insert(hash(102), HeaderStatus::MaybeOrphan);
|
queue
|
||||||
queue.maybe_orphan.entry(102).or_default().insert(hash(102), header(102));
|
.known_headers
|
||||||
|
.entry(102)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(102), HeaderStatus::MaybeOrphan);
|
||||||
|
queue
|
||||||
|
.maybe_orphan
|
||||||
|
.entry(102)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(102), header(102));
|
||||||
queue.maybe_orphan_response(&id(99), true);
|
queue.maybe_orphan_response(&id(99), true);
|
||||||
|
|
||||||
// then all headers (#100..#103) are moved to the MaybeReceipts queue
|
// then all headers (#100..#103) are moved to the MaybeReceipts queue
|
||||||
@@ -680,10 +835,26 @@ pub(crate) mod tests {
|
|||||||
// and we have asked for MaybeOrphan status of #100.parent (i.e. #99)
|
// and we have asked for MaybeOrphan status of #100.parent (i.e. #99)
|
||||||
// and the response is: NO, #99 is NOT known to the Substrate runtime
|
// and the response is: NO, #99 is NOT known to the Substrate runtime
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::MaybeOrphan);
|
queue
|
||||||
queue.maybe_orphan.entry(100).or_default().insert(hash(100), header(100));
|
.known_headers
|
||||||
queue.known_headers.entry(101).or_default().insert(hash(101), HeaderStatus::MaybeOrphan);
|
.entry(100)
|
||||||
queue.maybe_orphan.entry(101).or_default().insert(hash(101), header(101));
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::MaybeOrphan);
|
||||||
|
queue
|
||||||
|
.maybe_orphan
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), header(100));
|
||||||
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(101)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(101), HeaderStatus::MaybeOrphan);
|
||||||
|
queue
|
||||||
|
.maybe_orphan
|
||||||
|
.entry(101)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(101), header(101));
|
||||||
queue.maybe_orphan_response(&id(99), false);
|
queue.maybe_orphan_response(&id(99), false);
|
||||||
|
|
||||||
// then all headers (#100..#101) are moved to the Orphan queue
|
// then all headers (#100..#101) are moved to the Orphan queue
|
||||||
@@ -696,8 +867,16 @@ pub(crate) mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn positive_maybe_receipts_response_works() {
|
fn positive_maybe_receipts_response_works() {
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::MaybeReceipts);
|
queue
|
||||||
queue.maybe_receipts.entry(100).or_default().insert(hash(100), header(100));
|
.known_headers
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::MaybeReceipts);
|
||||||
|
queue
|
||||||
|
.maybe_receipts
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), header(100));
|
||||||
queue.maybe_receipts_response(&id(100), true);
|
queue.maybe_receipts_response(&id(100), true);
|
||||||
assert!(queue.maybe_receipts.is_empty());
|
assert!(queue.maybe_receipts.is_empty());
|
||||||
assert_eq!(queue.receipts.len(), 1);
|
assert_eq!(queue.receipts.len(), 1);
|
||||||
@@ -707,8 +886,16 @@ pub(crate) mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn negative_maybe_receipts_response_works() {
|
fn negative_maybe_receipts_response_works() {
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::MaybeReceipts);
|
queue
|
||||||
queue.maybe_receipts.entry(100).or_default().insert(hash(100), header(100));
|
.known_headers
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::MaybeReceipts);
|
||||||
|
queue
|
||||||
|
.maybe_receipts
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), header(100));
|
||||||
queue.maybe_receipts_response(&id(100), false);
|
queue.maybe_receipts_response(&id(100), false);
|
||||||
assert!(queue.maybe_receipts.is_empty());
|
assert!(queue.maybe_receipts.is_empty());
|
||||||
assert_eq!(queue.ready.len(), 1);
|
assert_eq!(queue.ready.len(), 1);
|
||||||
@@ -718,7 +905,11 @@ pub(crate) mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn receipts_response_works() {
|
fn receipts_response_works() {
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::Receipts);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::Receipts);
|
||||||
queue.receipts.entry(100).or_default().insert(hash(100), header(100));
|
queue.receipts.entry(100).or_default().insert(hash(100), header(100));
|
||||||
queue.receipts_response(&id(100), Vec::new());
|
queue.receipts_response(&id(100), Vec::new());
|
||||||
assert!(queue.receipts.is_empty());
|
assert!(queue.receipts.is_empty());
|
||||||
@@ -729,7 +920,11 @@ pub(crate) mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn header_submitted_works() {
|
fn header_submitted_works() {
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::Ready);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::Ready);
|
||||||
queue.ready.entry(100).or_default().insert(hash(100), header(100));
|
queue.ready.entry(100).or_default().insert(hash(100), header(100));
|
||||||
queue.headers_submitted(vec![id(100)]);
|
queue.headers_submitted(vec![id(100)]);
|
||||||
assert!(queue.ready.is_empty());
|
assert!(queue.ready.is_empty());
|
||||||
@@ -739,15 +934,43 @@ pub(crate) mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn prune_works() {
|
fn prune_works() {
|
||||||
let mut queue = QueuedHeaders::default();
|
let mut queue = QueuedHeaders::default();
|
||||||
queue.known_headers.entry(104).or_default().insert(hash(104), HeaderStatus::MaybeOrphan);
|
queue
|
||||||
queue.maybe_orphan.entry(104).or_default().insert(hash(104), header(104));
|
.known_headers
|
||||||
queue.known_headers.entry(103).or_default().insert(hash(103), HeaderStatus::Orphan);
|
.entry(104)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(104), HeaderStatus::MaybeOrphan);
|
||||||
|
queue
|
||||||
|
.maybe_orphan
|
||||||
|
.entry(104)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(104), header(104));
|
||||||
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(103)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(103), HeaderStatus::Orphan);
|
||||||
queue.orphan.entry(103).or_default().insert(hash(103), header(103));
|
queue.orphan.entry(103).or_default().insert(hash(103), header(103));
|
||||||
queue.known_headers.entry(102).or_default().insert(hash(102), HeaderStatus::MaybeReceipts);
|
queue
|
||||||
queue.maybe_receipts.entry(102).or_default().insert(hash(102), header(102));
|
.known_headers
|
||||||
queue.known_headers.entry(101).or_default().insert(hash(101), HeaderStatus::Receipts);
|
.entry(102)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(102), HeaderStatus::MaybeReceipts);
|
||||||
|
queue
|
||||||
|
.maybe_receipts
|
||||||
|
.entry(102)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(102), header(102));
|
||||||
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(101)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(101), HeaderStatus::Receipts);
|
||||||
queue.receipts.entry(101).or_default().insert(hash(101), header(101));
|
queue.receipts.entry(101).or_default().insert(hash(101), header(101));
|
||||||
queue.known_headers.entry(100).or_default().insert(hash(100), HeaderStatus::Ready);
|
queue
|
||||||
|
.known_headers
|
||||||
|
.entry(100)
|
||||||
|
.or_default()
|
||||||
|
.insert(hash(100), HeaderStatus::Ready);
|
||||||
queue.ready.entry(100).or_default().insert(hash(100), header(100));
|
queue.ready.entry(100).or_default().insert(hash(100), header(100));
|
||||||
|
|
||||||
queue.prune(102);
|
queue.prune(102);
|
||||||
|
|||||||
@@ -30,11 +30,11 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use codec::Encode;
|
|
||||||
use crate::ethereum_headers::QueuedHeaders;
|
use crate::ethereum_headers::QueuedHeaders;
|
||||||
use crate::ethereum_types::{HeaderId, HeaderStatus, QueuedHeader};
|
|
||||||
use crate::ethereum_sync_loop::EthereumSyncParams;
|
use crate::ethereum_sync_loop::EthereumSyncParams;
|
||||||
|
use crate::ethereum_types::{HeaderId, HeaderStatus, QueuedHeader};
|
||||||
use crate::substrate_types::{into_substrate_ethereum_header, into_substrate_ethereum_receipts};
|
use crate::substrate_types::{into_substrate_ethereum_header, into_substrate_ethereum_receipts};
|
||||||
|
use codec::Encode;
|
||||||
|
|
||||||
/// Ethereum headers synchronization context.
|
/// Ethereum headers synchronization context.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -63,7 +63,8 @@ impl HeadersSync {
|
|||||||
/// Returns true if we have synced almost all known headers.
|
/// Returns true if we have synced almost all known headers.
|
||||||
pub fn is_almost_synced(&self) -> bool {
|
pub fn is_almost_synced(&self) -> bool {
|
||||||
match self.target_header_number {
|
match self.target_header_number {
|
||||||
Some(target_header_number) => self.best_header
|
Some(target_header_number) => self
|
||||||
|
.best_header
|
||||||
.map(|best| target_header_number.saturating_sub(best.0) < 4)
|
.map(|best| target_header_number.saturating_sub(best.0) < 4)
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
None => true,
|
None => true,
|
||||||
@@ -100,10 +101,7 @@ impl HeadersSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we assume that there were no reorgs if we have already downloaded best header
|
// we assume that there were no reorgs if we have already downloaded best header
|
||||||
let best_downloaded_number = std::cmp::max(
|
let best_downloaded_number = std::cmp::max(self.headers.best_queued_number(), best_header.0);
|
||||||
self.headers.best_queued_number(),
|
|
||||||
best_header.0,
|
|
||||||
);
|
|
||||||
if best_downloaded_number == target_header_number {
|
if best_downloaded_number == target_header_number {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -115,7 +113,9 @@ impl HeadersSync {
|
|||||||
/// Select headers that need to be submitted to the Substrate node.
|
/// Select headers that need to be submitted to the Substrate node.
|
||||||
pub fn select_headers_to_submit(&self) -> Option<Vec<&QueuedHeader>> {
|
pub fn select_headers_to_submit(&self) -> Option<Vec<&QueuedHeader>> {
|
||||||
let headers_in_submit_status = self.headers.headers_in_status(HeaderStatus::Submitted);
|
let headers_in_submit_status = self.headers.headers_in_status(HeaderStatus::Submitted);
|
||||||
let headers_to_submit_count = self.params.max_headers_in_submitted_status
|
let headers_to_submit_count = self
|
||||||
|
.params
|
||||||
|
.max_headers_in_submitted_status
|
||||||
.checked_sub(headers_in_submit_status)?;
|
.checked_sub(headers_in_submit_status)?;
|
||||||
|
|
||||||
let mut total_size = 0;
|
let mut total_size = 0;
|
||||||
@@ -129,7 +129,8 @@ impl HeadersSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let encoded_size = into_substrate_ethereum_header(header.header()).encode().len()
|
let encoded_size = into_substrate_ethereum_header(header.header()).encode().len()
|
||||||
+ into_substrate_ethereum_receipts(header.receipts()).map(|receipts| receipts.encode().len())
|
+ into_substrate_ethereum_receipts(header.receipts())
|
||||||
|
.map(|receipts| receipts.encode().len())
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
if total_headers != 0 && total_size + encoded_size > self.params.max_headers_size_in_single_submit {
|
if total_headers != 0 && total_size + encoded_size > self.params.max_headers_size_in_single_submit {
|
||||||
return false;
|
return false;
|
||||||
@@ -162,7 +163,8 @@ impl HeadersSync {
|
|||||||
self.headers.substrate_best_header_response(&best_header);
|
self.headers.substrate_best_header_response(&best_header);
|
||||||
|
|
||||||
// prune ancient headers
|
// prune ancient headers
|
||||||
self.headers.prune(best_header.0.saturating_sub(self.params.prune_depth));
|
self.headers
|
||||||
|
.prune(best_header.0.saturating_sub(self.params.prune_depth));
|
||||||
|
|
||||||
// finally remember the best header itself
|
// finally remember the best header itself
|
||||||
self.best_header = Some(best_header);
|
self.best_header = Some(best_header);
|
||||||
@@ -180,9 +182,9 @@ impl HeadersSync {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::ethereum_headers::tests::{header, id};
|
|
||||||
use crate::ethereum_types::{H256, HeaderStatus};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::ethereum_headers::tests::{header, id};
|
||||||
|
use crate::ethereum_types::{HeaderStatus, H256};
|
||||||
|
|
||||||
fn side_hash(number: u64) -> H256 {
|
fn side_hash(number: u64) -> H256 {
|
||||||
H256::from_low_u64_le(1000 + number)
|
H256::from_low_u64_le(1000 + number)
|
||||||
|
|||||||
@@ -30,10 +30,10 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use futures::{future::FutureExt, stream::StreamExt};
|
|
||||||
use crate::ethereum_client;
|
use crate::ethereum_client;
|
||||||
use crate::ethereum_types::HeaderStatus as EthereumHeaderStatus;
|
use crate::ethereum_types::HeaderStatus as EthereumHeaderStatus;
|
||||||
use crate::substrate_client;
|
use crate::substrate_client;
|
||||||
|
use futures::{future::FutureExt, stream::StreamExt};
|
||||||
|
|
||||||
// TODO: when SharedClient will be available, switch to Substrate headers subscription
|
// TODO: when SharedClient will be available, switch to Substrate headers subscription
|
||||||
// (because we do not need old Substrate headers)
|
// (because we do not need old Substrate headers)
|
||||||
@@ -98,7 +98,10 @@ impl std::fmt::Debug for EthereumSyncParams {
|
|||||||
.field("max_future_headers_to_download", &self.max_future_headers_to_download)
|
.field("max_future_headers_to_download", &self.max_future_headers_to_download)
|
||||||
.field("max_headers_in_submitted_status", &self.max_headers_in_submitted_status)
|
.field("max_headers_in_submitted_status", &self.max_headers_in_submitted_status)
|
||||||
.field("max_headers_in_single_submit", &self.max_headers_in_single_submit)
|
.field("max_headers_in_single_submit", &self.max_headers_in_single_submit)
|
||||||
.field("max_headers_size_in_single_submit", &self.max_headers_size_in_single_submit)
|
.field(
|
||||||
|
"max_headers_size_in_single_submit",
|
||||||
|
&self.max_headers_size_in_single_submit,
|
||||||
|
)
|
||||||
.field("prune_depth", &self.prune_depth)
|
.field("prune_depth", &self.prune_depth)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
@@ -136,9 +139,7 @@ pub fn run(params: EthereumSyncParams) {
|
|||||||
|
|
||||||
let mut eth_maybe_client = None;
|
let mut eth_maybe_client = None;
|
||||||
let mut eth_best_block_number_required = false;
|
let mut eth_best_block_number_required = false;
|
||||||
let eth_best_block_number_future = ethereum_client::best_block_number(
|
let eth_best_block_number_future = ethereum_client::best_block_number(ethereum_client::client(ð_uri)).fuse();
|
||||||
ethereum_client::client(ð_uri)
|
|
||||||
).fuse();
|
|
||||||
let eth_new_header_future = futures::future::Fuse::terminated();
|
let eth_new_header_future = futures::future::Fuse::terminated();
|
||||||
let eth_orphan_header_future = futures::future::Fuse::terminated();
|
let eth_orphan_header_future = futures::future::Fuse::terminated();
|
||||||
let eth_receipts_future = futures::future::Fuse::terminated();
|
let eth_receipts_future = futures::future::Fuse::terminated();
|
||||||
@@ -147,9 +148,8 @@ pub fn run(params: EthereumSyncParams) {
|
|||||||
|
|
||||||
let mut sub_maybe_client = None;
|
let mut sub_maybe_client = None;
|
||||||
let mut sub_best_block_required = false;
|
let mut sub_best_block_required = false;
|
||||||
let sub_best_block_future = substrate_client::best_ethereum_block(
|
let sub_best_block_future =
|
||||||
substrate_client::client(&sub_uri, sub_signer),
|
substrate_client::best_ethereum_block(substrate_client::client(&sub_uri, sub_signer)).fuse();
|
||||||
).fuse();
|
|
||||||
let sub_receipts_check_future = futures::future::Fuse::terminated();
|
let sub_receipts_check_future = futures::future::Fuse::terminated();
|
||||||
let sub_existence_status_future = futures::future::Fuse::terminated();
|
let sub_existence_status_future = futures::future::Fuse::terminated();
|
||||||
let sub_submit_header_future = futures::future::Fuse::terminated();
|
let sub_submit_header_future = futures::future::Fuse::terminated();
|
||||||
@@ -326,7 +326,7 @@ pub fn run(params: EthereumSyncParams) {
|
|||||||
// 2) check transactions receipts - it stops us from downloading/submitting new blocks;
|
// 2) check transactions receipts - it stops us from downloading/submitting new blocks;
|
||||||
// 3) check existence - it stops us from submitting new blocks;
|
// 3) check existence - it stops us from submitting new blocks;
|
||||||
// 4) submit header
|
// 4) submit header
|
||||||
|
|
||||||
if sub_best_block_required {
|
if sub_best_block_required {
|
||||||
log::debug!(target: "bridge", "Asking Substrate about best block");
|
log::debug!(target: "bridge", "Asking Substrate about best block");
|
||||||
sub_best_block_future.set(substrate_client::best_ethereum_block(sub_client).fuse());
|
sub_best_block_future.set(substrate_client::best_ethereum_block(sub_client).fuse());
|
||||||
@@ -338,9 +338,8 @@ pub fn run(params: EthereumSyncParams) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let header = header.clone();
|
let header = header.clone();
|
||||||
sub_receipts_check_future.set(
|
sub_receipts_check_future
|
||||||
substrate_client::ethereum_receipts_required(sub_client, header).fuse()
|
.set(substrate_client::ethereum_receipts_required(sub_client, header).fuse());
|
||||||
);
|
|
||||||
} else if let Some(header) = eth_sync.headers().header(EthereumHeaderStatus::MaybeOrphan) {
|
} else if let Some(header) = eth_sync.headers().header(EthereumHeaderStatus::MaybeOrphan) {
|
||||||
// for MaybeOrphan we actually ask for parent' header existence
|
// for MaybeOrphan we actually ask for parent' header existence
|
||||||
let parent_id = header.parent_id();
|
let parent_id = header.parent_id();
|
||||||
@@ -351,9 +350,8 @@ pub fn run(params: EthereumSyncParams) {
|
|||||||
parent_id,
|
parent_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
sub_existence_status_future.set(
|
sub_existence_status_future
|
||||||
substrate_client::ethereum_header_known(sub_client, parent_id).fuse(),
|
.set(substrate_client::ethereum_header_known(sub_client, parent_id).fuse());
|
||||||
);
|
|
||||||
} else if let Some(headers) = eth_sync.select_headers_to_submit() {
|
} else if let Some(headers) = eth_sync.select_headers_to_submit() {
|
||||||
let ids = match headers.len() {
|
let ids = match headers.len() {
|
||||||
1 => format!("{:?}", headers[0].id()),
|
1 => format!("{:?}", headers[0].id()),
|
||||||
@@ -368,9 +366,7 @@ pub fn run(params: EthereumSyncParams) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let headers = headers.into_iter().cloned().collect();
|
let headers = headers.into_iter().cloned().collect();
|
||||||
sub_submit_header_future.set(
|
sub_submit_header_future.set(substrate_client::submit_ethereum_headers(sub_client, headers).fuse());
|
||||||
substrate_client::submit_ethereum_headers(sub_client, headers).fuse(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// remember that we have submitted some headers
|
// remember that we have submitted some headers
|
||||||
if stall_countdown.is_none() {
|
if stall_countdown.is_none() {
|
||||||
@@ -400,11 +396,8 @@ pub fn run(params: EthereumSyncParams) {
|
|||||||
id,
|
id,
|
||||||
);
|
);
|
||||||
eth_receipts_future.set(
|
eth_receipts_future.set(
|
||||||
ethereum_client::transactions_receipts(
|
ethereum_client::transactions_receipts(eth_client, id, header.header().transactions.clone())
|
||||||
eth_client,
|
.fuse(),
|
||||||
id,
|
|
||||||
header.header().transactions.clone(),
|
|
||||||
).fuse()
|
|
||||||
);
|
);
|
||||||
} else if let Some(header) = eth_sync.headers().header(EthereumHeaderStatus::Orphan) {
|
} else if let Some(header) = eth_sync.headers().header(EthereumHeaderStatus::Orphan) {
|
||||||
// for Orphan we actually ask for parent' header
|
// for Orphan we actually ask for parent' header
|
||||||
@@ -416,9 +409,7 @@ pub fn run(params: EthereumSyncParams) {
|
|||||||
parent_id,
|
parent_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
eth_orphan_header_future.set(
|
eth_orphan_header_future.set(ethereum_client::header_by_hash(eth_client, parent_id.1).fuse());
|
||||||
ethereum_client::header_by_hash(eth_client, parent_id.1).fuse(),
|
|
||||||
);
|
|
||||||
} else if let Some(id) = eth_sync.select_new_header_to_download() {
|
} else if let Some(id) = eth_sync.select_new_header_to_download() {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
target: "bridge",
|
target: "bridge",
|
||||||
@@ -426,9 +417,7 @@ pub fn run(params: EthereumSyncParams) {
|
|||||||
id,
|
id,
|
||||||
);
|
);
|
||||||
|
|
||||||
eth_new_header_future.set(
|
eth_new_header_future.set(ethereum_client::header_by_number(eth_client, id).fuse());
|
||||||
ethereum_client::header_by_number(eth_client, id).fuse(),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
eth_maybe_client = Some(eth_client);
|
eth_maybe_client = Some(eth_client);
|
||||||
}
|
}
|
||||||
@@ -469,7 +458,10 @@ async fn delay<T>(timeout_ms: u64, retval: T) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn interval(timeout_ms: u64) -> impl futures::Stream<Item = ()> {
|
fn interval(timeout_ms: u64) -> impl futures::Stream<Item = ()> {
|
||||||
futures::stream::unfold((), move |_| async move { delay(timeout_ms, ()).await; Some(((), ())) })
|
futures::stream::unfold((), move |_| async move {
|
||||||
|
delay(timeout_ms, ()).await;
|
||||||
|
Some(((), ()))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_future_result<TClient, TResult, TError, TGoOfflineFuture>(
|
fn process_future_result<TClient, TResult, TError, TGoOfflineFuture>(
|
||||||
@@ -488,7 +480,7 @@ fn process_future_result<TClient, TResult, TError, TGoOfflineFuture>(
|
|||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
*maybe_client = Some(client);
|
*maybe_client = Some(client);
|
||||||
on_success(result);
|
on_success(result);
|
||||||
},
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
if error.is_connection_error() {
|
if error.is_connection_error() {
|
||||||
go_offline_future.set(go_offline(client).fuse());
|
go_offline_future.set(go_offline(client).fuse());
|
||||||
@@ -497,6 +489,6 @@ fn process_future_result<TClient, TResult, TError, TGoOfflineFuture>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
log::error!(target: "bridge", "{}: {:?}", error_pattern, error);
|
log::error!(target: "bridge", "{}: {:?}", error_pattern, error);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,10 @@ pub struct HeaderId(pub u64, pub H256);
|
|||||||
|
|
||||||
impl From<&Header> for HeaderId {
|
impl From<&Header> for HeaderId {
|
||||||
fn from(header: &Header) -> HeaderId {
|
fn from(header: &Header) -> HeaderId {
|
||||||
HeaderId(header.number.expect(HEADER_ID_PROOF).as_u64(), header.hash.expect(HEADER_ID_PROOF))
|
HeaderId(
|
||||||
|
header.number.expect(HEADER_ID_PROOF).as_u64(),
|
||||||
|
header.hash.expect(HEADER_ID_PROOF),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#![recursion_limit="1024"]
|
#![recursion_limit = "1024"]
|
||||||
|
|
||||||
mod ethereum_client;
|
mod ethereum_client;
|
||||||
mod ethereum_headers;
|
mod ethereum_headers;
|
||||||
@@ -40,8 +40,8 @@ mod ethereum_types;
|
|||||||
mod substrate_client;
|
mod substrate_client;
|
||||||
mod substrate_types;
|
mod substrate_types;
|
||||||
|
|
||||||
use std::io::Write;
|
|
||||||
use sp_core::crypto::Pair;
|
use sp_core::crypto::Pair;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
initialize();
|
initialize();
|
||||||
@@ -51,7 +51,7 @@ fn main() {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!(target: "bridge", "Error parsing parameters: {}", err);
|
log::error!(target: "bridge", "Error parsing parameters: {}", err);
|
||||||
return;
|
return;
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,8 +66,8 @@ fn initialize() {
|
|||||||
builder.parse_filters(&filters);
|
builder.parse_filters(&filters);
|
||||||
builder.format(move |buf, record| {
|
builder.format(move |buf, record| {
|
||||||
writeln!(buf, "{}", {
|
writeln!(buf, "{}", {
|
||||||
let timestamp = time::strftime("%Y-%m-%d %H:%M:%S %Z", &time::now())
|
let timestamp =
|
||||||
.expect("Time is incorrectly formatted");
|
time::strftime("%Y-%m-%d %H:%M:%S %Z", &time::now()).expect("Time is incorrectly formatted");
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
format!("{} {} {} {}", timestamp, record.level(), record.target(), record.args())
|
format!("{} {} {} {}", timestamp, record.level(), record.target(), record.args())
|
||||||
} else {
|
} else {
|
||||||
@@ -79,11 +79,13 @@ fn initialize() {
|
|||||||
log::Level::Debug => Color::Fixed(14).paint(record.level().to_string()),
|
log::Level::Debug => Color::Fixed(14).paint(record.level().to_string()),
|
||||||
log::Level::Trace => Color::Fixed(12).paint(record.level().to_string()),
|
log::Level::Trace => Color::Fixed(12).paint(record.level().to_string()),
|
||||||
};
|
};
|
||||||
format!("{} {} {} {}"
|
format!(
|
||||||
, Color::Fixed(8).bold().paint(timestamp)
|
"{} {} {} {}",
|
||||||
, log_level
|
Color::Fixed(8).bold().paint(timestamp),
|
||||||
, Color::Fixed(8).paint(record.target())
|
log_level,
|
||||||
, record.args())
|
Color::Fixed(8).paint(record.target()),
|
||||||
|
record.args()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -110,8 +112,8 @@ fn ethereum_sync_params() -> Result<ethereum_sync_loop::EthereumSyncParams, Stri
|
|||||||
}
|
}
|
||||||
if let Some(sub_signer) = matches.value_of("sub-signer") {
|
if let Some(sub_signer) = matches.value_of("sub-signer") {
|
||||||
let sub_signer_password = matches.value_of("sub-signer-password");
|
let sub_signer_password = matches.value_of("sub-signer-password");
|
||||||
eth_sync_params.sub_signer = sp_core::sr25519::Pair::from_string(sub_signer, sub_signer_password)
|
eth_sync_params.sub_signer =
|
||||||
.map_err(|e| format!("{:?}", e))?;
|
sp_core::sr25519::Pair::from_string(sub_signer, sub_signer_password).map_err(|e| format!("{:?}", e))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(eth_sync_params)
|
Ok(eth_sync_params)
|
||||||
|
|||||||
@@ -30,29 +30,16 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use codec::{Encode, Decode};
|
use crate::ethereum_sync_loop::MaybeConnectionError;
|
||||||
|
use crate::ethereum_types::{Bytes, HeaderId as EthereumHeaderId, QueuedHeader as QueuedEthereumHeader, H256};
|
||||||
|
use crate::substrate_types::{into_substrate_ethereum_header, into_substrate_ethereum_receipts, TransactionHash};
|
||||||
|
use codec::{Decode, Encode};
|
||||||
use jsonrpsee::common::Params;
|
use jsonrpsee::common::Params;
|
||||||
use jsonrpsee::raw::{
|
use jsonrpsee::raw::{RawClient, RawClientError};
|
||||||
RawClient, RawClientError
|
use jsonrpsee::transport::http::{HttpTransportClient, RequestError};
|
||||||
};
|
|
||||||
use jsonrpsee::transport::http::{
|
|
||||||
HttpTransportClient, RequestError
|
|
||||||
};
|
|
||||||
use serde_json::{from_value, to_value};
|
use serde_json::{from_value, to_value};
|
||||||
use sp_core::crypto::Pair;
|
use sp_core::crypto::Pair;
|
||||||
use sp_runtime::traits::IdentifyAccount;
|
use sp_runtime::traits::IdentifyAccount;
|
||||||
use crate::ethereum_sync_loop::MaybeConnectionError;
|
|
||||||
use crate::ethereum_types::{
|
|
||||||
Bytes,
|
|
||||||
H256,
|
|
||||||
HeaderId as EthereumHeaderId,
|
|
||||||
QueuedHeader as QueuedEthereumHeader,
|
|
||||||
};
|
|
||||||
use crate::substrate_types::{
|
|
||||||
TransactionHash,
|
|
||||||
into_substrate_ethereum_header,
|
|
||||||
into_substrate_ethereum_receipts,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Substrate client type.
|
/// Substrate client type.
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
@@ -105,7 +92,8 @@ pub async fn best_ethereum_block(client: Client) -> (Client, Result<EthereumHead
|
|||||||
to_value("EthereumHeadersApi_best_block").unwrap(),
|
to_value("EthereumHeadersApi_best_block").unwrap(),
|
||||||
to_value("0x").unwrap(),
|
to_value("0x").unwrap(),
|
||||||
]),
|
]),
|
||||||
).await;
|
)
|
||||||
|
.await;
|
||||||
(client, result.map(|(num, hash)| EthereumHeaderId(num, hash)))
|
(client, result.map(|(num, hash)| EthereumHeaderId(num, hash)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,8 +112,12 @@ pub async fn ethereum_receipts_required(
|
|||||||
to_value("EthereumHeadersApi_is_import_requires_receipts").unwrap(),
|
to_value("EthereumHeadersApi_is_import_requires_receipts").unwrap(),
|
||||||
to_value(Bytes(encoded_header)).unwrap(),
|
to_value(Bytes(encoded_header)).unwrap(),
|
||||||
]),
|
]),
|
||||||
).await;
|
)
|
||||||
(client, receipts_required.map(|receipts_required| (id, receipts_required)))
|
.await;
|
||||||
|
(
|
||||||
|
client,
|
||||||
|
receipts_required.map(|receipts_required| (id, receipts_required)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if Ethereum header is known to Substrate runtime.
|
/// Returns true if Ethereum header is known to Substrate runtime.
|
||||||
@@ -147,7 +139,8 @@ pub async fn ethereum_header_known(
|
|||||||
to_value("EthereumHeadersApi_is_known_block").unwrap(),
|
to_value("EthereumHeadersApi_is_known_block").unwrap(),
|
||||||
to_value(Bytes(encoded_id)).unwrap(),
|
to_value(Bytes(encoded_id)).unwrap(),
|
||||||
]),
|
]),
|
||||||
).await;
|
)
|
||||||
|
.await;
|
||||||
(client, is_known_block.map(|is_known_block| (id, is_known_block)))
|
(client, is_known_block.map(|is_known_block| (id, is_known_block)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +160,7 @@ pub async fn submit_ethereum_headers(
|
|||||||
};
|
};
|
||||||
client.genesis_hash = Some(genesis_hash);
|
client.genesis_hash = Some(genesis_hash);
|
||||||
(client, genesis_hash)
|
(client, genesis_hash)
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
let account_id = client.signer.public().as_array_ref().clone().into();
|
let account_id = client.signer.public().as_array_ref().clone().into();
|
||||||
let (client, nonce) = next_account_index(client, account_id).await;
|
let (client, nonce) = next_account_index(client, account_id).await;
|
||||||
@@ -175,20 +168,14 @@ pub async fn submit_ethereum_headers(
|
|||||||
Ok(nonce) => nonce,
|
Ok(nonce) => nonce,
|
||||||
Err(err) => return (client, Err(err)),
|
Err(err) => return (client, Err(err)),
|
||||||
};
|
};
|
||||||
let transaction = create_submit_transaction(
|
let transaction = create_submit_transaction(headers, &client.signer, nonce, genesis_hash);
|
||||||
headers,
|
|
||||||
&client.signer,
|
|
||||||
nonce,
|
|
||||||
genesis_hash,
|
|
||||||
);
|
|
||||||
let encoded_transaction = transaction.encode();
|
let encoded_transaction = transaction.encode();
|
||||||
let (client, transaction_hash) = call_rpc(
|
let (client, transaction_hash) = call_rpc(
|
||||||
client,
|
client,
|
||||||
"author_submitExtrinsic",
|
"author_submitExtrinsic",
|
||||||
Params::Array(vec![
|
Params::Array(vec![to_value(Bytes(encoded_transaction)).unwrap()]),
|
||||||
to_value(Bytes(encoded_transaction)).unwrap(),
|
)
|
||||||
]),
|
.await;
|
||||||
).await;
|
|
||||||
(client, transaction_hash.map(|transaction_hash| (transaction_hash, ids)))
|
(client, transaction_hash.map(|transaction_hash| (transaction_hash, ids)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,10 +184,9 @@ async fn block_hash_by_number(client: Client, number: u64) -> (Client, Result<H2
|
|||||||
call_rpc(
|
call_rpc(
|
||||||
client,
|
client,
|
||||||
"chain_getBlockHash",
|
"chain_getBlockHash",
|
||||||
Params::Array(vec![
|
Params::Array(vec![to_value(number).unwrap()]),
|
||||||
to_value(number).unwrap(),
|
)
|
||||||
]),
|
.await
|
||||||
).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get substrate account nonce.
|
/// Get substrate account nonce.
|
||||||
@@ -213,24 +199,15 @@ async fn next_account_index(
|
|||||||
let (client, index) = call_rpc_u64(
|
let (client, index) = call_rpc_u64(
|
||||||
client,
|
client,
|
||||||
"system_accountNextIndex",
|
"system_accountNextIndex",
|
||||||
Params::Array(vec![
|
Params::Array(vec![to_value(account.to_ss58check()).unwrap()]),
|
||||||
to_value(account.to_ss58check()).unwrap(),
|
)
|
||||||
]),
|
.await;
|
||||||
).await;
|
|
||||||
(client, index.map(|index| index as _))
|
(client, index.map(|index| index as _))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls RPC on Substrate node that returns Bytes.
|
/// Calls RPC on Substrate node that returns Bytes.
|
||||||
async fn call_rpc<T: Decode>(
|
async fn call_rpc<T: Decode>(mut client: Client, method: &'static str, params: Params) -> (Client, Result<T, Error>) {
|
||||||
mut client: Client,
|
async fn do_call_rpc<T: Decode>(client: &mut Client, method: &'static str, params: Params) -> Result<T, Error> {
|
||||||
method: &'static str,
|
|
||||||
params: Params,
|
|
||||||
) -> (Client, Result<T, Error>) {
|
|
||||||
async fn do_call_rpc<T: Decode>(
|
|
||||||
client: &mut Client,
|
|
||||||
method: &'static str,
|
|
||||||
params: Params,
|
|
||||||
) -> Result<T, Error> {
|
|
||||||
let request_id = client
|
let request_id = client
|
||||||
.rpc_client
|
.rpc_client
|
||||||
.start_request(method, params)
|
.start_request(method, params)
|
||||||
@@ -253,16 +230,8 @@ async fn call_rpc<T: Decode>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Calls RPC on Substrate node that returns u64.
|
/// Calls RPC on Substrate node that returns u64.
|
||||||
async fn call_rpc_u64(
|
async fn call_rpc_u64(mut client: Client, method: &'static str, params: Params) -> (Client, Result<u64, Error>) {
|
||||||
mut client: Client,
|
async fn do_call_rpc(client: &mut Client, method: &'static str, params: Params) -> Result<u64, Error> {
|
||||||
method: &'static str,
|
|
||||||
params: Params,
|
|
||||||
) -> (Client, Result<u64, Error>) {
|
|
||||||
async fn do_call_rpc(
|
|
||||||
client: &mut Client,
|
|
||||||
method: &'static str,
|
|
||||||
params: Params,
|
|
||||||
) -> Result<u64, Error> {
|
|
||||||
let request_id = client
|
let request_id = client
|
||||||
.rpc_client
|
.rpc_client
|
||||||
.start_request(method, params)
|
.start_request(method, params)
|
||||||
@@ -290,20 +259,18 @@ fn create_submit_transaction(
|
|||||||
index: node_primitives::Index,
|
index: node_primitives::Index,
|
||||||
genesis_hash: H256,
|
genesis_hash: H256,
|
||||||
) -> bridge_node_runtime::UncheckedExtrinsic {
|
) -> bridge_node_runtime::UncheckedExtrinsic {
|
||||||
let function = bridge_node_runtime::Call::BridgeEthPoA(
|
let function = bridge_node_runtime::Call::BridgeEthPoA(bridge_node_runtime::BridgeEthPoACall::import_headers(
|
||||||
bridge_node_runtime::BridgeEthPoACall::import_headers(
|
headers
|
||||||
headers
|
.into_iter()
|
||||||
.into_iter()
|
.map(|header| {
|
||||||
.map(|header| {
|
let (header, receipts) = header.extract();
|
||||||
let (header, receipts) = header.extract();
|
(
|
||||||
(
|
into_substrate_ethereum_header(&header),
|
||||||
into_substrate_ethereum_header(&header),
|
into_substrate_ethereum_receipts(&receipts),
|
||||||
into_substrate_ethereum_receipts(&receipts),
|
)
|
||||||
)
|
})
|
||||||
})
|
.collect(),
|
||||||
.collect(),
|
));
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
let extra = |i: node_primitives::Index, f: node_primitives::Balance| {
|
let extra = |i: node_primitives::Index, f: node_primitives::Balance| {
|
||||||
(
|
(
|
||||||
@@ -331,10 +298,5 @@ fn create_submit_transaction(
|
|||||||
let signer: sp_runtime::MultiSigner = signer.public().into();
|
let signer: sp_runtime::MultiSigner = signer.public().into();
|
||||||
let (function, extra, _) = raw_payload.deconstruct();
|
let (function, extra, _) = raw_payload.deconstruct();
|
||||||
|
|
||||||
bridge_node_runtime::UncheckedExtrinsic::new_signed(
|
bridge_node_runtime::UncheckedExtrinsic::new_signed(function, signer.into_account().into(), signature.into(), extra)
|
||||||
function,
|
|
||||||
signer.into_account().into(),
|
|
||||||
signature.into(),
|
|
||||||
extra,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,17 +30,14 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
pub use sp_bridge_eth_poa::{
|
|
||||||
Address, Bloom, Bytes, H256, Header as SubstrateEthereumHeader,
|
|
||||||
LogEntry as SubstrateEthereumLogEntry, Receipt as SubstrateEthereumReceipt,
|
|
||||||
TransactionOutcome as SubstrateEthereumTransactionOutcome, U256,
|
|
||||||
};
|
|
||||||
pub use crate::ethereum_types::H256 as TransactionHash;
|
pub use crate::ethereum_types::H256 as TransactionHash;
|
||||||
use crate::ethereum_types::{
|
use crate::ethereum_types::{
|
||||||
HEADER_ID_PROOF as ETHEREUM_HEADER_ID_PROOF,
|
Header as EthereumHeader, Receipt as EthereumReceipt, HEADER_ID_PROOF as ETHEREUM_HEADER_ID_PROOF,
|
||||||
RECEIPT_GAS_USED_PROOF as ETHEREUM_RECEIPT_GAS_USED_PROOF,
|
RECEIPT_GAS_USED_PROOF as ETHEREUM_RECEIPT_GAS_USED_PROOF,
|
||||||
Header as EthereumHeader,
|
};
|
||||||
Receipt as EthereumReceipt,
|
pub use sp_bridge_eth_poa::{
|
||||||
|
Address, Bloom, Bytes, Header as SubstrateEthereumHeader, LogEntry as SubstrateEthereumLogEntry,
|
||||||
|
Receipt as SubstrateEthereumReceipt, TransactionOutcome as SubstrateEthereumTransactionOutcome, H256, U256,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Convert Ethereum header into Ethereum header for Substrate.
|
/// Convert Ethereum header into Ethereum header for Substrate.
|
||||||
@@ -67,18 +64,27 @@ pub fn into_substrate_ethereum_header(header: &EthereumHeader) -> SubstrateEther
|
|||||||
pub fn into_substrate_ethereum_receipts(
|
pub fn into_substrate_ethereum_receipts(
|
||||||
receipts: &Option<Vec<EthereumReceipt>>,
|
receipts: &Option<Vec<EthereumReceipt>>,
|
||||||
) -> Option<Vec<SubstrateEthereumReceipt>> {
|
) -> Option<Vec<SubstrateEthereumReceipt>> {
|
||||||
receipts.as_ref().map(|receipts| receipts.iter().map(|receipt| SubstrateEthereumReceipt {
|
receipts.as_ref().map(|receipts| {
|
||||||
gas_used: receipt.gas_used.expect(ETHEREUM_RECEIPT_GAS_USED_PROOF),
|
receipts
|
||||||
log_bloom: receipt.logs_bloom.data().into(),
|
.iter()
|
||||||
logs: receipt.logs.iter().map(|log_entry| SubstrateEthereumLogEntry {
|
.map(|receipt| SubstrateEthereumReceipt {
|
||||||
address: log_entry.address,
|
gas_used: receipt.gas_used.expect(ETHEREUM_RECEIPT_GAS_USED_PROOF),
|
||||||
topics: log_entry.topics.clone(),
|
log_bloom: receipt.logs_bloom.data().into(),
|
||||||
data: log_entry.data.0.clone(),
|
logs: receipt
|
||||||
}).collect(),
|
.logs
|
||||||
outcome: match (receipt.status, receipt.root) {
|
.iter()
|
||||||
(Some(status), None) => SubstrateEthereumTransactionOutcome::StatusCode(status.as_u64() as u8),
|
.map(|log_entry| SubstrateEthereumLogEntry {
|
||||||
(None, Some(root)) => SubstrateEthereumTransactionOutcome::StateRoot(root),
|
address: log_entry.address,
|
||||||
_ => SubstrateEthereumTransactionOutcome::Unknown,
|
topics: log_entry.topics.clone(),
|
||||||
},
|
data: log_entry.data.0.clone(),
|
||||||
}).collect())
|
})
|
||||||
|
.collect(),
|
||||||
|
outcome: match (receipt.status, receipt.root) {
|
||||||
|
(Some(status), None) => SubstrateEthereumTransactionOutcome::StatusCode(status.as_u64() as u8),
|
||||||
|
(None, Some(root)) => SubstrateEthereumTransactionOutcome::StateRoot(root),
|
||||||
|
_ => SubstrateEthereumTransactionOutcome::Unknown,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,22 +15,27 @@
|
|||||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
use crate::params::{Params, RPCUrlParam};
|
||||||
use crate::rpc::{self, SubstrateRPC};
|
use crate::rpc::{self, SubstrateRPC};
|
||||||
use crate::params::{RPCUrlParam, Params};
|
|
||||||
|
|
||||||
use futures::{prelude::*, channel::{mpsc, oneshot}, future, select};
|
use futures::{
|
||||||
|
channel::{mpsc, oneshot},
|
||||||
|
future,
|
||||||
|
prelude::*,
|
||||||
|
select,
|
||||||
|
};
|
||||||
use jsonrpsee::{
|
use jsonrpsee::{
|
||||||
raw::client::{RawClient, RawClientError, RawClientEvent, RawClientRequestId, RawClientSubscription},
|
raw::client::{RawClient, RawClientError, RawClientEvent, RawClientRequestId, RawClientSubscription},
|
||||||
transport::{
|
transport::{
|
||||||
|
ws::{WsConnecError, WsTransportClient},
|
||||||
TransportClient,
|
TransportClient,
|
||||||
ws::{WsTransportClient, WsConnecError},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use node_primitives::{Hash, Header};
|
use node_primitives::{Hash, Header};
|
||||||
|
use sp_core::Bytes;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use sp_core::Bytes;
|
|
||||||
|
|
||||||
type ChainId = Hash;
|
type ChainId = Hash;
|
||||||
|
|
||||||
@@ -71,24 +76,25 @@ async fn init_rpc_connection(url: &RPCUrlParam) -> Result<Chain, Error> {
|
|||||||
let genesis_hash = rpc::genesis_block_hash(&mut client)
|
let genesis_hash = rpc::genesis_block_hash(&mut client)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Error::RPCError(e.to_string()))?
|
.map_err(|e| Error::RPCError(e.to_string()))?
|
||||||
.ok_or_else(|| Error::InvalidChainState(format!(
|
.ok_or_else(|| {
|
||||||
"chain with RPC URL {} is missing a genesis block hash",
|
Error::InvalidChainState(format!(
|
||||||
url_str,
|
"chain with RPC URL {} is missing a genesis block hash",
|
||||||
)))?;
|
url_str,
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
let latest_finalized_hash = SubstrateRPC::chain_finalized_head(&mut client)
|
let latest_finalized_hash = SubstrateRPC::chain_finalized_head(&mut client)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Error::RPCError(e.to_string()))?;
|
.map_err(|e| Error::RPCError(e.to_string()))?;
|
||||||
let latest_finalized_header = SubstrateRPC::chain_header(
|
let latest_finalized_header = SubstrateRPC::chain_header(&mut client, Some(latest_finalized_hash))
|
||||||
&mut client,
|
|
||||||
Some(latest_finalized_hash)
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Error::RPCError(e.to_string()))?
|
.map_err(|e| Error::RPCError(e.to_string()))?
|
||||||
.ok_or_else(|| Error::InvalidChainState(format!(
|
.ok_or_else(|| {
|
||||||
"chain {} is missing header for finalized block hash {}",
|
Error::InvalidChainState(format!(
|
||||||
genesis_hash, latest_finalized_hash
|
"chain {} is missing header for finalized block hash {}",
|
||||||
)))?;
|
genesis_hash, latest_finalized_hash
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
let (sender, receiver) = mpsc::channel(0);
|
let (sender, receiver) = mpsc::channel(0);
|
||||||
|
|
||||||
@@ -101,41 +107,35 @@ async fn init_rpc_connection(url: &RPCUrlParam) -> Result<Chain, Error> {
|
|||||||
state: ChainState {
|
state: ChainState {
|
||||||
current_finalized_head: latest_finalized_header,
|
current_finalized_head: latest_finalized_header,
|
||||||
bridges: HashMap::new(),
|
bridges: HashMap::new(),
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns IDs of the bridged chains.
|
/// Returns IDs of the bridged chains.
|
||||||
async fn read_bridges(chain: &mut Chain, chain_ids: &[Hash])
|
async fn read_bridges(chain: &mut Chain, chain_ids: &[Hash]) -> Result<Vec<Hash>, Error> {
|
||||||
-> Result<Vec<Hash>, Error>
|
|
||||||
{
|
|
||||||
// This should make an RPC call to read this information from the bridge pallet state.
|
// This should make an RPC call to read this information from the bridge pallet state.
|
||||||
// For now, just pretend every chain is bridged to every other chain.
|
// For now, just pretend every chain is bridged to every other chain.
|
||||||
//
|
//
|
||||||
// TODO: The correct thing.
|
// TODO: The correct thing.
|
||||||
Ok(
|
Ok(chain_ids
|
||||||
chain_ids
|
.iter()
|
||||||
.iter()
|
.cloned()
|
||||||
.cloned()
|
.filter(|&chain_id| chain_id != chain.genesis_hash)
|
||||||
.filter(|&chain_id| chain_id != chain.genesis_hash)
|
.collect())
|
||||||
.collect()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_async(
|
pub async fn run_async(params: Params, exit: Box<dyn Future<Output = ()> + Unpin + Send>) -> Result<(), Error> {
|
||||||
params: Params,
|
|
||||||
exit: Box<dyn Future<Output=()> + Unpin + Send>
|
|
||||||
) -> Result<(), Error>
|
|
||||||
{
|
|
||||||
let chains = init_chains(¶ms).await?;
|
let chains = init_chains(¶ms).await?;
|
||||||
|
|
||||||
let (chain_tasks, exit_signals) = chains.into_iter()
|
let (chain_tasks, exit_signals) = chains
|
||||||
|
.into_iter()
|
||||||
.map(|(chain_id, chain_cell)| {
|
.map(|(chain_id, chain_cell)| {
|
||||||
let chain = chain_cell.into_inner();
|
let chain = chain_cell.into_inner();
|
||||||
let (task_exit_signal, task_exit_receiver) = oneshot::channel();
|
let (task_exit_signal, task_exit_receiver) = oneshot::channel();
|
||||||
let task_exit = Box::new(task_exit_receiver.map(|result| {
|
let task_exit = Box::new(
|
||||||
result.expect("task_exit_signal is not dropped before send() is called")
|
task_exit_receiver
|
||||||
}));
|
.map(|result| result.expect("task_exit_signal is not dropped before send() is called")),
|
||||||
|
);
|
||||||
let chain_task = async_std::task::spawn(async move {
|
let chain_task = async_std::task::spawn(async move {
|
||||||
if let Err(err) = chain_task(chain_id, chain, task_exit).await {
|
if let Err(err) = chain_task(chain_id, chain, task_exit).await {
|
||||||
log::error!("Error in task for chain {}: {}", chain_id, err);
|
log::error!("Error in task for chain {}: {}", chain_id, err);
|
||||||
@@ -156,39 +156,43 @@ pub async fn run_async(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initial_next_events<'a>(chains: &'a HashMap<ChainId, RefCell<Chain>>)
|
fn initial_next_events<'a>(
|
||||||
-> Vec<Pin<Box<dyn Future<Output=Result<(ChainId, RawClientEvent), Error>> + 'a>>>
|
chains: &'a HashMap<ChainId, RefCell<Chain>>,
|
||||||
{
|
) -> Vec<Pin<Box<dyn Future<Output = Result<(ChainId, RawClientEvent), Error>> + 'a>>> {
|
||||||
chains.values()
|
chains
|
||||||
|
.values()
|
||||||
.map(|chain_cell| async move {
|
.map(|chain_cell| async move {
|
||||||
let mut chain = chain_cell.borrow_mut();
|
let mut chain = chain_cell.borrow_mut();
|
||||||
let event = chain.client.next_event()
|
let event = chain
|
||||||
|
.client
|
||||||
|
.next_event()
|
||||||
.await
|
.await
|
||||||
.map_err(|err| Error::RPCError(err.to_string()))?;
|
.map_err(|err| Error::RPCError(err.to_string()))?;
|
||||||
Ok((chain.genesis_hash, event))
|
Ok((chain.genesis_hash, event))
|
||||||
})
|
})
|
||||||
.map(|fut| Box::pin(fut) as Pin<Box<dyn Future<Output=_>>>)
|
.map(|fut| Box::pin(fut) as Pin<Box<dyn Future<Output = _>>>)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn next_event<'a>(
|
async fn next_event<'a>(
|
||||||
next_events: Vec<Pin<Box<dyn Future<Output=Result<(ChainId, RawClientEvent), Error>> + 'a>>>,
|
next_events: Vec<Pin<Box<dyn Future<Output = Result<(ChainId, RawClientEvent), Error>> + 'a>>>,
|
||||||
chains: &'a HashMap<ChainId, RefCell<Chain>>,
|
chains: &'a HashMap<ChainId, RefCell<Chain>>,
|
||||||
)
|
) -> (
|
||||||
-> (
|
Result<(Hash, RawClientEvent), Error>,
|
||||||
Result<(Hash, RawClientEvent), Error>,
|
Vec<Pin<Box<dyn Future<Output = Result<(ChainId, RawClientEvent), Error>> + 'a>>>,
|
||||||
Vec<Pin<Box<dyn Future<Output=Result<(ChainId, RawClientEvent), Error>> +'a>>>
|
) {
|
||||||
)
|
|
||||||
{
|
|
||||||
let (result, _, mut rest) = future::select_all(next_events).await;
|
let (result, _, mut rest) = future::select_all(next_events).await;
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok((chain_id, _)) => {
|
Ok((chain_id, _)) => {
|
||||||
let fut = async move {
|
let fut = async move {
|
||||||
let chain_cell = chains.get(&chain_id)
|
let chain_cell = chains
|
||||||
|
.get(&chain_id)
|
||||||
.expect("chain must be in the map as a function precondition; qed");
|
.expect("chain must be in the map as a function precondition; qed");
|
||||||
let mut chain = chain_cell.borrow_mut();
|
let mut chain = chain_cell.borrow_mut();
|
||||||
let event = chain.client.next_event()
|
let event = chain
|
||||||
|
.client
|
||||||
|
.next_event()
|
||||||
.await
|
.await
|
||||||
.map_err(|err| Error::RPCError(err.to_string()))?;
|
.map_err(|err| Error::RPCError(err.to_string()))?;
|
||||||
Ok((chain_id, event))
|
Ok((chain_id, event))
|
||||||
@@ -209,9 +213,7 @@ async fn init_chains(params: &Params) -> Result<HashMap<ChainId, RefCell<Chain>>
|
|||||||
.collect::<Result<HashMap<_, _>, _>>()?;
|
.collect::<Result<HashMap<_, _>, _>>()?;
|
||||||
|
|
||||||
// TODO: Remove when read_bridges is implemented correctly.
|
// TODO: Remove when read_bridges is implemented correctly.
|
||||||
let chain_ids = chains.keys()
|
let chain_ids = chains.keys().cloned().collect::<Vec<_>>();
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
// let chain_ids_slice = chain_ids.as_slice();
|
// let chain_ids_slice = chain_ids.as_slice();
|
||||||
|
|
||||||
for (&chain_id, chain_cell) in chains.iter() {
|
for (&chain_id, chain_cell) in chains.iter() {
|
||||||
@@ -229,15 +231,18 @@ async fn init_chains(params: &Params) -> Result<HashMap<ChainId, RefCell<Chain>>
|
|||||||
let genesis_head = SubstrateRPC::chain_header(&mut chain.client, chain_id)
|
let genesis_head = SubstrateRPC::chain_header(&mut chain.client, chain_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Error::RPCError(e.to_string()))?
|
.map_err(|e| Error::RPCError(e.to_string()))?
|
||||||
.ok_or_else(|| Error::InvalidChainState(format!(
|
.ok_or_else(|| {
|
||||||
"chain {} is missing a genesis block header", chain_id
|
Error::InvalidChainState(format!("chain {} is missing a genesis block header", chain_id))
|
||||||
)))?;
|
})?;
|
||||||
|
|
||||||
let channel = chain.sender.clone();
|
let channel = chain.sender.clone();
|
||||||
chain.state.bridges.insert(bridged_chain_id, BridgeState {
|
chain.state.bridges.insert(
|
||||||
channel,
|
bridged_chain_id,
|
||||||
locally_finalized_head_on_bridged_chain: genesis_head,
|
BridgeState {
|
||||||
});
|
channel,
|
||||||
|
locally_finalized_head_on_bridged_chain: genesis_head,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// The conditional ensures that we don't log twice per pair of chains.
|
// The conditional ensures that we don't log twice per pair of chains.
|
||||||
if chain_id.as_ref() < bridged_chain_id.as_ref() {
|
if chain_id.as_ref() < bridged_chain_id.as_ref() {
|
||||||
@@ -250,28 +255,25 @@ async fn init_chains(params: &Params) -> Result<HashMap<ChainId, RefCell<Chain>>
|
|||||||
Ok(chains)
|
Ok(chains)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn setup_subscriptions(chain: &mut Chain)
|
async fn setup_subscriptions(
|
||||||
-> Result<(RawClientRequestId, RawClientRequestId), RawClientError<WsConnecError>>
|
chain: &mut Chain,
|
||||||
{
|
) -> Result<(RawClientRequestId, RawClientRequestId), RawClientError<WsConnecError>> {
|
||||||
let new_heads_subscription_id = chain.client
|
let new_heads_subscription_id = chain
|
||||||
.start_subscription(
|
.client
|
||||||
"chain_subscribeNewHeads",
|
.start_subscription("chain_subscribeNewHeads", jsonrpsee::common::Params::None)
|
||||||
jsonrpsee::common::Params::None,
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.map_err(RawClientError::Inner)?;
|
.map_err(RawClientError::Inner)?;
|
||||||
|
|
||||||
let finalized_heads_subscription_id = chain.client
|
let finalized_heads_subscription_id = chain
|
||||||
.start_subscription(
|
.client
|
||||||
"chain_subscribeFinalizedHeads",
|
.start_subscription("chain_subscribeFinalizedHeads", jsonrpsee::common::Params::None)
|
||||||
jsonrpsee::common::Params::None,
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.map_err(RawClientError::Inner)?;
|
.map_err(RawClientError::Inner)?;
|
||||||
|
|
||||||
let new_heads_subscription =
|
let new_heads_subscription = chain
|
||||||
chain.client.subscription_by_id(new_heads_subscription_id)
|
.client
|
||||||
.expect("subscription_id was returned from start_subscription above; qed");
|
.subscription_by_id(new_heads_subscription_id)
|
||||||
|
.expect("subscription_id was returned from start_subscription above; qed");
|
||||||
let new_heads_subscription = match new_heads_subscription {
|
let new_heads_subscription = match new_heads_subscription {
|
||||||
RawClientSubscription::Active(_) => {}
|
RawClientSubscription::Active(_) => {}
|
||||||
RawClientSubscription::Pending(subscription) => {
|
RawClientSubscription::Pending(subscription) => {
|
||||||
@@ -279,9 +281,10 @@ async fn setup_subscriptions(chain: &mut Chain)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let finalized_heads_subscription =
|
let finalized_heads_subscription = chain
|
||||||
chain.client.subscription_by_id(finalized_heads_subscription_id)
|
.client
|
||||||
.expect("subscription_id was returned from start_subscription above; qed");
|
.subscription_by_id(finalized_heads_subscription_id)
|
||||||
|
.expect("subscription_id was returned from start_subscription above; qed");
|
||||||
let finalized_heads_subscription = match finalized_heads_subscription {
|
let finalized_heads_subscription = match finalized_heads_subscription {
|
||||||
RawClientSubscription::Active(subscription) => {}
|
RawClientSubscription::Active(subscription) => {}
|
||||||
RawClientSubscription::Pending(subscription) => {
|
RawClientSubscription::Pending(subscription) => {
|
||||||
@@ -298,27 +301,26 @@ async fn handle_rpc_event(
|
|||||||
event: RawClientEvent,
|
event: RawClientEvent,
|
||||||
new_heads_subscription_id: RawClientRequestId,
|
new_heads_subscription_id: RawClientRequestId,
|
||||||
finalized_heads_subscription_id: RawClientRequestId,
|
finalized_heads_subscription_id: RawClientRequestId,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error> {
|
||||||
{
|
|
||||||
match event {
|
match event {
|
||||||
RawClientEvent::SubscriptionNotif { request_id, result } =>
|
RawClientEvent::SubscriptionNotif { request_id, result } => {
|
||||||
if request_id == new_heads_subscription_id {
|
if request_id == new_heads_subscription_id {
|
||||||
let header: Header = serde_json::from_value(result)
|
let header: Header = serde_json::from_value(result).map_err(Error::SerializationError)?;
|
||||||
.map_err(Error::SerializationError)?;
|
|
||||||
log::info!("Received new head {:?} on chain {}", header, chain_id);
|
log::info!("Received new head {:?} on chain {}", header, chain_id);
|
||||||
} else if request_id == finalized_heads_subscription_id {
|
} else if request_id == finalized_heads_subscription_id {
|
||||||
let header: Header = serde_json::from_value(result)
|
let header: Header = serde_json::from_value(result).map_err(Error::SerializationError)?;
|
||||||
.map_err(Error::SerializationError)?;
|
|
||||||
log::info!("Received finalized head {:?} on chain {}", header, chain_id);
|
log::info!("Received finalized head {:?} on chain {}", header, chain_id);
|
||||||
|
|
||||||
// let old_finalized_head = chain_state.current_finalized_head;
|
// let old_finalized_head = chain_state.current_finalized_head;
|
||||||
chain.state.current_finalized_head = header;
|
chain.state.current_finalized_head = header;
|
||||||
for (bridged_chain_id, bridged_chain) in chain.state.bridges.iter_mut() {
|
for (bridged_chain_id, bridged_chain) in chain.state.bridges.iter_mut() {
|
||||||
if bridged_chain.locally_finalized_head_on_bridged_chain.number <
|
if bridged_chain.locally_finalized_head_on_bridged_chain.number
|
||||||
chain.state.current_finalized_head.number {
|
< chain.state.current_finalized_head.number
|
||||||
|
{
|
||||||
// Craft and submit an extrinsic over RPC
|
// Craft and submit an extrinsic over RPC
|
||||||
log::info!("Sending command to submit extrinsic to chain {}", chain_id);
|
log::info!("Sending command to submit extrinsic to chain {}", chain_id);
|
||||||
let mut send_event = bridged_chain.channel
|
let mut send_event = bridged_chain
|
||||||
|
.channel
|
||||||
.send(Event::SubmitExtrinsic(Bytes(Vec::new())))
|
.send(Event::SubmitExtrinsic(Bytes(Vec::new())))
|
||||||
.fuse();
|
.fuse();
|
||||||
|
|
||||||
@@ -343,12 +345,17 @@ async fn handle_rpc_event(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::RPCError(format!(
|
return Err(Error::RPCError(format!(
|
||||||
"unexpected subscription response with request ID {:?}", request_id
|
"unexpected subscription response with request ID {:?}",
|
||||||
|
request_id
|
||||||
)));
|
)));
|
||||||
},
|
}
|
||||||
_ => return Err(Error::RPCError(format!(
|
}
|
||||||
"unexpected RPC event from chain {}: {:?}", chain_id, event
|
_ => {
|
||||||
))),
|
return Err(Error::RPCError(format!(
|
||||||
|
"unexpected RPC event from chain {}: {:?}",
|
||||||
|
chain_id, event
|
||||||
|
)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -358,8 +365,7 @@ async fn handle_bridge_event<R: TransportClient>(
|
|||||||
chain_id: ChainId,
|
chain_id: ChainId,
|
||||||
rpc_client: &mut RawClient<R>,
|
rpc_client: &mut RawClient<R>,
|
||||||
event: Event,
|
event: Event,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error> {
|
||||||
{
|
|
||||||
match event {
|
match event {
|
||||||
Event::SubmitExtrinsic(data) => {
|
Event::SubmitExtrinsic(data) => {
|
||||||
log::info!("Submitting extrinsic to chain {}", chain_id);
|
log::info!("Submitting extrinsic to chain {}", chain_id);
|
||||||
@@ -374,13 +380,11 @@ async fn handle_bridge_event<R: TransportClient>(
|
|||||||
async fn chain_task(
|
async fn chain_task(
|
||||||
chain_id: ChainId,
|
chain_id: ChainId,
|
||||||
mut chain: Chain,
|
mut chain: Chain,
|
||||||
exit: impl Future<Output=()> + Unpin + Send
|
exit: impl Future<Output = ()> + Unpin + Send,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error> {
|
||||||
{
|
let (new_heads_subscription_id, finalized_heads_subscription_id) = setup_subscriptions(&mut chain)
|
||||||
let (new_heads_subscription_id, finalized_heads_subscription_id) =
|
.await
|
||||||
setup_subscriptions(&mut chain)
|
.map_err(|e| Error::RPCError(e.to_string()))?;
|
||||||
.await
|
|
||||||
.map_err(|e| Error::RPCError(e.to_string()))?;
|
|
||||||
|
|
||||||
let mut exit = exit.fuse();
|
let mut exit = exit.fuse();
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ mod rpc;
|
|||||||
use bridge::run_async;
|
use bridge::run_async;
|
||||||
use params::{Params, RPCUrlParam};
|
use params::{Params, RPCUrlParam};
|
||||||
|
|
||||||
use clap::{App, Arg, value_t, values_t};
|
use clap::{value_t, values_t, App, Arg};
|
||||||
use futures::{prelude::*, channel};
|
use futures::{channel, prelude::*};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
@@ -32,9 +32,7 @@ fn main() {
|
|||||||
env_logger::init();
|
env_logger::init();
|
||||||
let exit = setup_exit_handler();
|
let exit = setup_exit_handler();
|
||||||
|
|
||||||
let result = async_std::task::block_on(async move {
|
let result = async_std::task::block_on(async move { run_async(params, exit).await });
|
||||||
run_async(params, exit).await
|
|
||||||
});
|
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
log::error!("{}", err);
|
log::error!("{}", err);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
@@ -60,22 +58,17 @@ fn parse_args() -> Params {
|
|||||||
.value_name("HOST[:PORT]")
|
.value_name("HOST[:PORT]")
|
||||||
.help("The URL of a bridged Substrate node")
|
.help("The URL of a bridged Substrate node")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.multiple(true)
|
.multiple(true),
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let base_path = value_t!(matches, "base-path", String)
|
let base_path = value_t!(matches, "base-path", String).unwrap_or_else(|e| e.exit());
|
||||||
.unwrap_or_else(|e| e.exit());
|
let rpc_urls = values_t!(matches, "rpc-url", RPCUrlParam).unwrap_or_else(|e| e.exit());
|
||||||
let rpc_urls = values_t!(matches, "rpc-url", RPCUrlParam)
|
|
||||||
.unwrap_or_else(|e| e.exit());
|
|
||||||
|
|
||||||
Params {
|
Params { base_path, rpc_urls }
|
||||||
base_path,
|
|
||||||
rpc_urls,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_exit_handler() -> Box<dyn Future<Output=()> + Unpin + Send> {
|
fn setup_exit_handler() -> Box<dyn Future<Output = ()> + Unpin + Send> {
|
||||||
let (exit_sender, exit_receiver) = channel::oneshot::channel();
|
let (exit_sender, exit_receiver) = channel::oneshot::channel();
|
||||||
let exit_sender = Cell::new(Some(exit_sender));
|
let exit_sender = Cell::new(Some(exit_sender));
|
||||||
|
|
||||||
@@ -86,11 +79,11 @@ fn setup_exit_handler() -> Box<dyn Future<Output=()> + Unpin + Send> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.expect("must be able to set Ctrl-C handler");
|
.expect("must be able to set Ctrl-C handler");
|
||||||
|
|
||||||
Box::new(exit_receiver.map(|result| {
|
Box::new(
|
||||||
result.expect(
|
exit_receiver.map(|result| {
|
||||||
"exit_sender cannot be dropped as it is moved into a globally-referenced closure"
|
result.expect("exit_sender cannot be dropped as it is moved into a globally-referenced closure")
|
||||||
)
|
}),
|
||||||
}))
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
use url::Url;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
const DEFAULT_WS_PORT: u16 = 9944;
|
const DEFAULT_WS_PORT: u16 = 9944;
|
||||||
|
|
||||||
@@ -42,8 +42,8 @@ impl FromStr for RPCUrlParam {
|
|||||||
type Err = Error;
|
type Err = Error;
|
||||||
|
|
||||||
fn from_str(url_str: &str) -> Result<Self, Self::Err> {
|
fn from_str(url_str: &str) -> Result<Self, Self::Err> {
|
||||||
let mut url = Url::parse(url_str)
|
let mut url =
|
||||||
.map_err(|e| Error::UrlError(format!("could not parse {}: {}", url_str, e)))?;
|
Url::parse(url_str).map_err(|e| Error::UrlError(format!("could not parse {}: {}", url_str, e)))?;
|
||||||
|
|
||||||
if url.scheme() != "ws" {
|
if url.scheme() != "ws" {
|
||||||
return Err(Error::UrlError(format!("must have scheme ws, found {}", url.scheme())));
|
return Err(Error::UrlError(format!("must have scheme ws, found {}", url.scheme())));
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ jsonrpsee::rpc_api! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn genesis_block_hash<R: TransportClient>(client: &mut RawClient<R>)
|
pub async fn genesis_block_hash<R: TransportClient>(
|
||||||
-> Result<Option<Hash>, RawClientError<R::Error>>
|
client: &mut RawClient<R>,
|
||||||
{
|
) -> Result<Option<Hash>, RawClientError<R::Error>> {
|
||||||
SubstrateRPC::chain_block_hash(client, Some(NumberOrHex::Number(0))).await
|
SubstrateRPC::chain_block_hash(client, Some(NumberOrHex::Number(0))).await
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user