mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 05:11:02 +00:00
Squashed commit of slava-async-bridge:
commit 657deb4cf4b90f24b9c5bfd62764b197776c262c Author: Hernando Castano <castano.ha@gmail.com> Date: Wed Jan 29 20:14:20 2020 -0500 Move Slava's bridge code into relays folder commit 4868c42c7da959dde7252766996b3ed4e408e439 Author: Hernando Castano <castano.ha@gmail.com> Date: Wed Jan 29 20:01:06 2020 -0500 Move files into `modules/ethereum` commit d1093f3e4238acb1a1a020011452cb928d3f8d7a Merge: 29dc6f9 bfd30ef Author: Hernando Castano <castano.ha@gmail.com> Date: Wed Jan 29 19:59:27 2020 -0500 Merge branch 'master' of slava-async-bridge commit 29dc6f97b1b7d1db99086d35a5336f43d2f0f8af Author: Hernando Castano <castano.ha@gmail.com> Date: Wed Jan 29 19:51:31 2020 -0500 Squashed commit of the following: commit 265365920836bb1d286c9b48b1902a2de278fdd9 Author: Hernando Castano <castano.ha@gmail.com> Date: Wed Jan 29 19:51:15 2020 -0500 Move hc-jp-bridge repo to different folder commit 8271991e95320baba70bd1cb9c4234d0ffd5b638 Merge: 57d0811 304cbc5 Author: Hernando Castano <castano.ha@gmail.com> Date: Wed Jan 29 19:36:41 2020 -0500 Merge branch 'hc-jp-bridge-module' of hc-jp-bridge-module commit 304cbc5f02d003ffa5404c1c01e461e5b8539888 Author: Hernando Castano <HCastano@users.noreply.github.com> Date: Wed Jan 29 00:38:27 2020 -0500 Update bridge pallet to work with the (almost) lastest master (#4672) * Update decl_error usage * WIP: Update error handling to use DispatchResult * Get module compiling with new error handling * Make tests compile again Main change was updating the usage of InMemoryBackend * Move `sp-state-machine` into dev-dependencies * Bump dependencies to v2.0.0 * Remove some stray comments * Appy code review suggestion commit 510cd6d96372688517496efa61773ea2839f8474 Author: Hernando Castano <HCastano@users.noreply.github.com> Date: Tue Dec 17 12:52:51 2019 -0500 Move Bridge Pallet into FRAME (#4373) * Move `bridge` crate into `frame` folder * Make `bridge` pallet compile after `the-big-reorg` commit ab54e838ef75e6a3f68fd0944bf22598c10c552f Author: Hernando Castano <castano.ha@gmail.com> Date: Mon Nov 11 21:56:40 2019 +0100 Use new StorageProof type from #3834 commit 8fc8911fd1b4acc2274c6863fb3dba91b30c90af Author: Hernando Castano <HCastano@users.noreply.github.com> Date: Tue Nov 5 00:50:34 2019 +0100 Verify Ancestry between Headers (#3963) * Create module for checking ancestry proofs * Use Vec of Headers instead of a HashMap * Move the ancestry verification into the lib.rs file * Change the proof format to exclude `child` and `ancestor` headers * Add a testing function for building header chains * Rename AncestorNotFound error to InvalidAncestryProof * Use ancestor hash instead of header when verifying ancestry * Clean up some stuff missed in the merge commit dbe85738b68358b790cf927b34a804b965a88f96 or: Hernando Castano <HCastano@users.noreply.github.com> Date: Fri Nov 1 15:41:58 2019 +0100 Check given Grandpa validator set against set found in storage (#3915) * Make StorageProofChecker happy * Update some tests * Check given validator set against set found in storage * Use Finality Grandpa's Authority Id and Weight * Add better error handling * Use error type from decl_error! macro commit 31b09216603d3e9c21144ce8c0b6bf59307a4f97 or: Hernando Castano <HCastano@users.noreply.github.com> Date: Wed Oct 23 14:55:37 2019 +0200 Make tests work after the changes introduced in #3793 (#3874) * Make tests work after the changes introduced in #3793 * Remove unneccessary import commit bce6d804aa86504599ff912387295c58f846cbf3 Author: Jim Posen <jim.posen@gmail.com> Date: Thu Oct 10 12:18:58 2019 +0200 Logic for checking Substrate proofs from within runtime module. (#3783) commit a7013e94b6c772c1d45a7cacbb445f73f6554fca Author: Hernando Castano <castano.ha@gmail.com> Date: Fri Oct 4 15:21:00 2019 +0300 Allow tracking of multiple bridges commit 3cf648242d631e32bd553a67df54bf5a48912839 Author: Hernando Castano <castano.ha@gmail.com> Date: Tue Oct 1 14:55:04 2019 +0200 Add BridgeId => Bridge mapping commit 001c74c45072213e01857d0a2454379b447c5a76 Author: Hernando Castano <castano.ha@gmail.com> Date: Tue Oct 1 11:10:19 2019 +0200 Get the mock runtime for tests set up commit 38443a1e8b424ed2f148eb95121d009f730e3b5a Author: Hernando Castano <castano.ha@gmail.com> Date: Fri Sep 27 14:52:53 2019 +0200 Clean up some warnings commit bdc3b01401e89c7111f8bf71f84c50750d25089f Author: Hernando Castano <castano.ha@gmail.com> Date: Thu Sep 26 16:41:01 2019 +0200 Add more skeleton code commit 26995efbf4bac2842eb2822322f7ad3c3e88feb8 Author: Hernando Castano <castano.ha@gmail.com> Date: Wed Sep 25 15:16:57 2019 +0200 Create `bridge` module skeleton commit bfd30ef8363b1483ef1107ae1eb958a4e944c93b Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Tue Dec 10 12:10:53 2019 +0300 actually use signer from CLI to sign Substrate transactions commit 504028eac60d9d14ba95b506cd355b0d2f405ce0 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Tue Dec 10 12:02:22 2019 +0300 go offline for a bit on connection error commit 446d0c8d20187dfd1beb173958ea28f2ad97887d Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Tue Dec 10 11:25:50 2019 +0300 enable info logs by default commit d039c60ec72bc91adfdad85442bc99a93b7f8e8d Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Tue Dec 10 11:12:51 2019 +0300 support basic CLI arguments commit 65c6d48e23576f36e8541878b920a03730226392 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Mon Dec 9 15:37:48 2019 +0300 fix restart commit 96e94c1c4b22d732078f8c401b872c5f8246c3fe Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Mon Dec 9 14:57:53 2019 +0300 license commit 68f4191e6cdd211ac8975e0b79f8a6f46a3ca953 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Mon Dec 9 14:56:05 2019 +0300 restart sync when Substrate reorgs && we are unlucky commit 29887c446167d580d73cc03a0b71c31890cafb51 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Mon Dec 9 13:49:31 2019 +0300 only read genesis hash once commit 832492b8393fe2063adf9c58c2b9e060dc3e4efb Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Mon Dec 9 13:23:26 2019 +0300 changed TODO commit 9dbc130e5fa036ae63d973819daf30f4ed6ffb5b Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Mon Dec 9 13:16:56 2019 +0300 removed obsolete exit future commit d03408cd8284eb0c61e7e96429b4f6199353e030 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Mon Dec 9 13:16:17 2019 +0300 removed obsolete TODOs + moved a couple of TODOs to runtime module commit ed8bec44b79f9a2ce829e59f10181368b2f42139 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Mon Dec 9 12:37:05 2019 +0300 explained TODO fix commit aa9c4c66ec2904eeb6072d654718b0ac0b7d8803 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Mon Dec 9 12:28:09 2019 +0300 fix tx outcome serialization commit 126f8f5484dac8c4af588ae86dc8855919d6c822 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Mon Dec 9 12:05:05 2019 +0300 prune old ethereum headers when Substrate best header is too far in the future commit c7bd301e631a44fe3263e188d0956081aa84f31e Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Fri Dec 6 12:51:50 2019 +0300 fix trace commit 549bb7acdb30cfdafe6c8600f0410212539ea63d Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Fri Dec 6 12:51:26 2019 +0300 tx hashes are already a part of Block response commit 7864017909f87ea36955d605a924c3c88bc88df3 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Thu Dec 5 12:29:37 2019 +0300 submit bunch of headers at once + some fixes commit 96485f85d38c144f0771f02ba692216a60356665 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Wed Dec 4 17:22:13 2019 +0300 print status messages commit ae0ec4c087136db653339537daab7f96a8c21b65 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Wed Dec 4 17:06:00 2019 +0300 continue actual Substrate client implementation commit 8146293740d70b88904568ff8e5acdfbadf06fd3 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Wed Dec 4 13:49:30 2019 +0300 fix IncompleteHeader condition commit 767c6201157dabcccf7f62e643681ca298224fb1 Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Wed Dec 4 10:55:06 2019 +0300 actual Substrate client implementation commit 221fd4ccd2b1eea12c9dacf800d80e15ec115c1b Author: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Wed Nov 20 17:28:13 2019 +0300 initial commit
This commit is contained in:
committed by
Bastian Köcher
parent
d530bf2199
commit
479c5bd99a
@@ -0,0 +1,320 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity-Bridge.
|
||||
|
||||
// Parity-Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity-Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity-Bridge. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
use jsonrpsee_core::{client::ClientError, common::Params};
|
||||
use jsonrpsee_http::{HttpClient, RequestError, http_client};
|
||||
use serde_json::{from_value, to_value};
|
||||
use sp_core::crypto::Pair;
|
||||
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.
|
||||
pub struct Client {
|
||||
/// Substrate RPC client.
|
||||
rpc_client: HttpClient,
|
||||
/// Transactions signer.
|
||||
signer: sp_core::sr25519::Pair,
|
||||
/// Genesis block hash.
|
||||
genesis_hash: Option<H256>,
|
||||
}
|
||||
|
||||
/// All possible errors that can occur during interacting with Ethereum node.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Request start failed.
|
||||
StartRequestFailed(RequestError),
|
||||
/// Request not found (should never occur?).
|
||||
RequestNotFound,
|
||||
/// Failed to receive response.
|
||||
ResponseRetrievalFailed(ClientError<RequestError>),
|
||||
/// Failed to parse response.
|
||||
ResponseParseFailed,
|
||||
}
|
||||
|
||||
impl MaybeConnectionError for Error {
|
||||
fn is_connection_error(&self) -> bool {
|
||||
match *self {
|
||||
Error::StartRequestFailed(_) | Error::ResponseRetrievalFailed(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns client that is able to call RPCs on Substrate node.
|
||||
pub fn client(uri: &str, signer: sp_core::sr25519::Pair) -> Client {
|
||||
Client {
|
||||
rpc_client: http_client(uri),
|
||||
signer,
|
||||
genesis_hash: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns best Ethereum block that Substrate runtime knows of.
|
||||
pub async fn best_ethereum_block(client: Client) -> (Client, Result<EthereumHeaderId, Error>) {
|
||||
let (client, result) = call_rpc::<(u64, H256)>(
|
||||
client,
|
||||
"state_call",
|
||||
Params::Array(vec![
|
||||
to_value("EthereumHeadersApi_best_block").unwrap(),
|
||||
to_value("0x").unwrap(),
|
||||
]),
|
||||
).await;
|
||||
(client, result.map(|(num, hash)| EthereumHeaderId(num, hash)))
|
||||
}
|
||||
|
||||
/// Returns true if transactions receipts are required for Ethereum header submission.
|
||||
pub async fn ethereum_receipts_required(
|
||||
client: Client,
|
||||
header: QueuedEthereumHeader,
|
||||
) -> (Client, Result<(EthereumHeaderId, bool), Error>) {
|
||||
let id = header.id();
|
||||
let header = into_substrate_ethereum_header(header.header());
|
||||
let encoded_header = header.encode();
|
||||
let (client, receipts_required) = call_rpc(
|
||||
client,
|
||||
"state_call",
|
||||
Params::Array(vec![
|
||||
to_value("EthereumHeadersApi_is_import_requires_receipts").unwrap(),
|
||||
to_value(Bytes(encoded_header)).unwrap(),
|
||||
]),
|
||||
).await;
|
||||
(client, receipts_required.map(|receipts_required| (id, receipts_required)))
|
||||
}
|
||||
|
||||
/// Returns true if Ethereum header is known to Substrate runtime.
|
||||
pub async fn ethereum_header_known(
|
||||
client: Client,
|
||||
id: EthereumHeaderId,
|
||||
) -> (Client, Result<(EthereumHeaderId, bool), Error>) {
|
||||
// Substrate module could prune old headers. So this fn could return false even
|
||||
// if header is synced. And we'll mark corresponding Ethereum header as Orphan.
|
||||
//
|
||||
// But when we'll read best header from Substrate next time, we will know that
|
||||
// there's a better header => this Orphan will either be marked as synced, or
|
||||
// eventually pruned.
|
||||
let encoded_id = id.1.encode();
|
||||
let (client, is_known_block) = call_rpc(
|
||||
client,
|
||||
"state_call",
|
||||
Params::Array(vec![
|
||||
to_value("EthereumHeadersApi_is_known_block").unwrap(),
|
||||
to_value(Bytes(encoded_id)).unwrap(),
|
||||
]),
|
||||
).await;
|
||||
(client, is_known_block.map(|is_known_block| (id, is_known_block)))
|
||||
}
|
||||
|
||||
/// Submits Ethereum header to Substrate runtime.
|
||||
pub async fn submit_ethereum_headers(
|
||||
client: Client,
|
||||
headers: Vec<QueuedEthereumHeader>,
|
||||
) -> (Client, Result<(TransactionHash, Vec<EthereumHeaderId>), Error>) {
|
||||
let ids = headers.iter().map(|header| header.id()).collect();
|
||||
let (client, genesis_hash) = match client.genesis_hash {
|
||||
Some(genesis_hash) => (client, genesis_hash),
|
||||
None => {
|
||||
let (mut client, genesis_hash) = block_hash_by_number(client, 0).await;
|
||||
let genesis_hash = match genesis_hash {
|
||||
Ok(genesis_hash) => genesis_hash,
|
||||
Err(err) => return (client, Err(err)),
|
||||
};
|
||||
client.genesis_hash = Some(genesis_hash);
|
||||
(client, genesis_hash)
|
||||
},
|
||||
};
|
||||
let account_id = client.signer.public().as_array_ref().clone().into();
|
||||
let (client, nonce) = next_account_index(client, account_id).await;
|
||||
let nonce = match nonce {
|
||||
Ok(nonce) => nonce,
|
||||
Err(err) => return (client, Err(err)),
|
||||
};
|
||||
let transaction = create_submit_transaction(
|
||||
headers,
|
||||
&client.signer,
|
||||
nonce,
|
||||
genesis_hash,
|
||||
);
|
||||
let encoded_transaction = transaction.encode();
|
||||
let (client, transaction_hash) = call_rpc(
|
||||
client,
|
||||
"author_submitExtrinsic",
|
||||
Params::Array(vec![
|
||||
to_value(Bytes(encoded_transaction)).unwrap(),
|
||||
]),
|
||||
).await;
|
||||
(client, transaction_hash.map(|transaction_hash| (transaction_hash, ids)))
|
||||
}
|
||||
|
||||
/// Get Substrate block hash by its number.
|
||||
async fn block_hash_by_number(client: Client, number: u64) -> (Client, Result<H256, Error>) {
|
||||
call_rpc(
|
||||
client,
|
||||
"chain_getBlockHash",
|
||||
Params::Array(vec![
|
||||
to_value(number).unwrap(),
|
||||
]),
|
||||
).await
|
||||
}
|
||||
|
||||
/// Get substrate account nonce.
|
||||
async fn next_account_index(
|
||||
client: Client,
|
||||
account: node_primitives::AccountId,
|
||||
) -> (Client, Result<node_primitives::Index, Error>) {
|
||||
use sp_core::crypto::Ss58Codec;
|
||||
|
||||
let (client, index) = call_rpc_u64(
|
||||
client,
|
||||
"system_accountNextIndex",
|
||||
Params::Array(vec![
|
||||
to_value(account.to_ss58check()).unwrap(),
|
||||
]),
|
||||
).await;
|
||||
(client, index.map(|index| index as _))
|
||||
}
|
||||
|
||||
/// Calls RPC on Substrate node that returns Bytes.
|
||||
async fn call_rpc<T: Decode>(
|
||||
mut client: Client,
|
||||
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
|
||||
.rpc_client
|
||||
.start_request(method, params)
|
||||
.await
|
||||
.map_err(Error::StartRequestFailed)?;
|
||||
// WARN: if there'll be need for executing >1 request at a time, we should avoid
|
||||
// calling request_by_id
|
||||
let response = client
|
||||
.rpc_client
|
||||
.request_by_id(request_id)
|
||||
.ok_or(Error::RequestNotFound)?
|
||||
.await
|
||||
.map_err(Error::ResponseRetrievalFailed)?;
|
||||
let encoded_response: Bytes = from_value(response).map_err(|_| Error::ResponseParseFailed)?;
|
||||
Decode::decode(&mut &encoded_response.0[..]).map_err(|_| Error::ResponseParseFailed)
|
||||
}
|
||||
|
||||
let result = do_call_rpc(&mut client, method, params).await;
|
||||
(client, result)
|
||||
}
|
||||
|
||||
/// Calls RPC on Substrate node that returns u64.
|
||||
async fn call_rpc_u64(
|
||||
mut client: Client,
|
||||
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
|
||||
.rpc_client
|
||||
.start_request(method, params)
|
||||
.await
|
||||
.map_err(Error::StartRequestFailed)?;
|
||||
// WARN: if there'll be need for executing >1 request at a time, we should avoid
|
||||
// calling request_by_id
|
||||
let response = client
|
||||
.rpc_client
|
||||
.request_by_id(request_id)
|
||||
.ok_or(Error::RequestNotFound)?
|
||||
.await
|
||||
.map_err(Error::ResponseRetrievalFailed)?;
|
||||
response.as_u64().ok_or(Error::ResponseParseFailed)
|
||||
}
|
||||
|
||||
let result = do_call_rpc(&mut client, method, params).await;
|
||||
(client, result)
|
||||
}
|
||||
|
||||
/// Create Substrate transaction for submitting Ethereum header.
|
||||
fn create_submit_transaction(
|
||||
headers: Vec<QueuedEthereumHeader>,
|
||||
signer: &sp_core::sr25519::Pair,
|
||||
index: node_primitives::Index,
|
||||
genesis_hash: H256,
|
||||
) -> node_runtime::UncheckedExtrinsic {
|
||||
let function = node_runtime::Call::BridgeEthPoa(
|
||||
node_runtime::BridgeEthPoaCall::import_headers(
|
||||
headers
|
||||
.into_iter()
|
||||
.map(|header| {
|
||||
let (header, receipts) = header.extract();
|
||||
(
|
||||
into_substrate_ethereum_header(&header),
|
||||
into_substrate_ethereum_receipts(&receipts),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
);
|
||||
|
||||
let extra = |i: node_primitives::Index, f: node_primitives::Balance| {
|
||||
(
|
||||
frame_system::CheckVersion::<node_runtime::Runtime>::new(),
|
||||
frame_system::CheckGenesis::<node_runtime::Runtime>::new(),
|
||||
frame_system::CheckEra::<node_runtime::Runtime>::from(sp_runtime::generic::Era::Immortal),
|
||||
frame_system::CheckNonce::<node_runtime::Runtime>::from(i),
|
||||
frame_system::CheckWeight::<node_runtime::Runtime>::new(),
|
||||
pallet_transaction_payment::ChargeTransactionPayment::<node_runtime::Runtime>::from(f),
|
||||
Default::default(),
|
||||
)
|
||||
};
|
||||
let raw_payload = node_runtime::SignedPayload::from_raw(
|
||||
function,
|
||||
extra(index, 0),
|
||||
(
|
||||
198, // VERSION.spec_version as u32,
|
||||
genesis_hash,
|
||||
genesis_hash,
|
||||
(),
|
||||
(),
|
||||
(),
|
||||
(),
|
||||
),
|
||||
);
|
||||
let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
|
||||
let signer: sp_runtime::MultiSigner = signer.public().into();
|
||||
let (function, extra, _) = raw_payload.deconstruct();
|
||||
|
||||
node_runtime::UncheckedExtrinsic::new_signed(
|
||||
function,
|
||||
signer.into_account().into(),
|
||||
signature.into(),
|
||||
extra,
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user