mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 22:11:02 +00:00
Submit exchange transactions to PoA node (#229)
* submit Eth exchange transactions * submit ethereum in docker-compose * submit Eth exchange transactions * fix duplicate message * fix relay script * lost file * cargo fmt --all * cargo +nightly clippy * Show sccache * remove test-helpers remains * what's going on with jsonrpsee + Cargo.lock? * relay-eth-submit-exchange-tx -> poa-exchange-tx-generator * Update relays/ethereum/src/main.rs Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * configuring exchange-gen loop using env variables * fixed signer account from dev chain to Arthur * improve debug prints * parse nonce from relay output * --eth-nonce= * fix compilation * cargo fmt --all * fix typo * duplicate relay output to tty * allow using from bash scripts tests * fix: U256::parse() expects hex string :/ * cargo fmt --all * BRIDGE_HASH: ${BRIDGE_HASH:-master} * script comment * generate exchange PoA transactions by Bertha * Bertha address Co-authored-by: Denis S. Soldatov aka General-Beck <general.beck@gmail.com> Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
This commit is contained in:
committed by
Bastian Köcher
parent
d3f6948050
commit
fddfbb5b1c
@@ -214,7 +214,7 @@ features = ["hmac"]
|
||||
[dev-dependencies.sp-bridge-eth-poa]
|
||||
version = "0.1.0"
|
||||
default-features = false
|
||||
features = ["std", "test-helpers"]
|
||||
features = ["std"]
|
||||
path = "../../../primitives/ethereum-poa"
|
||||
|
||||
[build-dependencies.wasm-builder-runner]
|
||||
@@ -264,6 +264,5 @@ runtime-benchmarks = [
|
||||
"libsecp256k1",
|
||||
"pallet-bridge-currency-exchange/runtime-benchmarks",
|
||||
"pallet-bridge-eth-poa/runtime-benchmarks",
|
||||
"sp-bridge-eth-poa/test-helpers",
|
||||
"sp-runtime/runtime-benchmarks",
|
||||
]
|
||||
|
||||
@@ -37,7 +37,7 @@ use sp_currency_exchange::{
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
/// Ethereum address where locked PoA funds must be sent to.
|
||||
const LOCK_FUNDS_ADDRESS: [u8; 20] = hex!("DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF");
|
||||
pub const LOCK_FUNDS_ADDRESS: [u8; 20] = hex!("DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF");
|
||||
|
||||
/// Ethereum transaction inclusion proof.
|
||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug)]
|
||||
|
||||
@@ -59,7 +59,7 @@ features = ["hmac"]
|
||||
# Dev Dependencies
|
||||
[dev-dependencies]
|
||||
# TODO: Stop renaming this on import
|
||||
primitives = { package = "sp-bridge-eth-poa", path = "../../primitives/ethereum-poa", features = ["std", "test-helpers"] }
|
||||
primitives = { package = "sp-bridge-eth-poa", path = "../../primitives/ethereum-poa", features = ["std"] }
|
||||
libsecp256k1 = { version = "0.3.4", features = ["hmac"] }
|
||||
|
||||
[features]
|
||||
@@ -78,5 +78,4 @@ std = [
|
||||
runtime-benchmarks = [
|
||||
"frame-benchmarking",
|
||||
"libsecp256k1",
|
||||
"primitives/test-helpers",
|
||||
]
|
||||
|
||||
@@ -47,18 +47,15 @@ default-features = false
|
||||
git = "https://github.com/paritytech/substrate.git"
|
||||
|
||||
[dependencies.libsecp256k1]
|
||||
optional = true
|
||||
version = "0.3.4"
|
||||
default-features = false
|
||||
features = ["hmac"]
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.2"
|
||||
libsecp256k1 = { version = "0.3.4", default-features = false, features = ["hmac"] }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
test-helpers = ["libsecp256k1"]
|
||||
std = [
|
||||
"serde/std",
|
||||
"serde-big-array",
|
||||
|
||||
@@ -54,7 +54,6 @@ pub type RawTransactionReceipt = Vec<u8>;
|
||||
/// An ethereum address.
|
||||
pub type Address = H160;
|
||||
|
||||
#[cfg(any(feature = "test-helpers", test))]
|
||||
pub mod signatures;
|
||||
|
||||
/// Complete header id.
|
||||
@@ -113,8 +112,7 @@ pub struct Transaction {
|
||||
}
|
||||
|
||||
/// Unsigned portion of ethereum transaction.
|
||||
#[derive(PartialEq, RuntimeDebug)]
|
||||
#[cfg_attr(test, derive(Clone))]
|
||||
#[derive(Clone, PartialEq, RuntimeDebug)]
|
||||
pub struct UnsignedTransaction {
|
||||
/// Sender nonce.
|
||||
pub nonce: U256,
|
||||
@@ -396,7 +394,6 @@ impl SealedEmptyStep {
|
||||
}
|
||||
|
||||
/// Returns rlp for the vector of empty steps (we only do encoding in tests).
|
||||
#[cfg(feature = "test-helpers")]
|
||||
pub fn rlp_of(empty_steps: &[SealedEmptyStep]) -> Bytes {
|
||||
let mut s = RlpStream::new();
|
||||
s.begin_list(empty_steps.len());
|
||||
|
||||
@@ -20,6 +20,7 @@ ethabi-derive = "12.0"
|
||||
ethereum-tx-sign = "3.0"
|
||||
futures = "0.3.5"
|
||||
hex = "0.4"
|
||||
hex-literal = "0.3"
|
||||
linked-hash-map = "0.5.3"
|
||||
log = "0.4.11"
|
||||
num-traits = "0.2"
|
||||
|
||||
@@ -106,6 +106,28 @@ subcommands:
|
||||
value_name: SUB_INITIAL_HEADER
|
||||
help: Encoded initial Substrate header.
|
||||
takes_value: true
|
||||
- eth-submit-exchange-tx:
|
||||
about: Submit lock funds transaction to Ethereum node.
|
||||
args:
|
||||
- eth-host: *eth-host
|
||||
- eth-port: *eth-port
|
||||
- eth-nonce:
|
||||
long: eth-nonce
|
||||
value_name: ETH_NONCE
|
||||
help: Nonce that have to be used when building transaction. If not specified, read from PoA node.
|
||||
takes_value: true
|
||||
- eth-signer: *eth-signer
|
||||
- eth-chain-id: *eth-chain-id
|
||||
- eth-amount:
|
||||
long: eth-amount
|
||||
value_name: ETH_AMOUNT
|
||||
help: Amount of ETH to lock (in wei).
|
||||
takes_value: true
|
||||
- sub-recipient:
|
||||
long: sub-recipient
|
||||
value_name: SUB_RECIPIENT
|
||||
help: Hex-encoded Public key of funds recipient in Substrate chain.
|
||||
takes_value: true
|
||||
- eth-exchange-sub:
|
||||
about: Submit proof of PoA lock funds transaction to Substrate node.
|
||||
args:
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common 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 Bridges Common 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 Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Submitting Ethereum -> Substrate exchange transactions.
|
||||
|
||||
use crate::ethereum_client::{EthereumConnectionParams, EthereumRpcClient, EthereumSigningParams};
|
||||
use crate::ethereum_types::{CallRequest, U256};
|
||||
use crate::rpc::EthereumRpc;
|
||||
|
||||
use bridge_node_runtime::exchange::LOCK_FUNDS_ADDRESS;
|
||||
use hex_literal::hex;
|
||||
use sp_bridge_eth_poa::{
|
||||
signatures::{SecretKey, SignTransaction},
|
||||
UnsignedTransaction,
|
||||
};
|
||||
|
||||
/// Ethereum exchange transaction params.
|
||||
#[derive(Debug)]
|
||||
pub struct EthereumExchangeSubmitParams {
|
||||
/// Ethereum connection params.
|
||||
pub eth: EthereumConnectionParams,
|
||||
/// Ethereum signing params.
|
||||
pub eth_sign: EthereumSigningParams,
|
||||
/// Ethereum signer nonce.
|
||||
pub eth_nonce: Option<U256>,
|
||||
/// Amount of Ethereum tokens to lock.
|
||||
pub eth_amount: U256,
|
||||
/// Funds recipient on Substrate side.
|
||||
pub sub_recipient: [u8; 32],
|
||||
}
|
||||
|
||||
impl Default for EthereumExchangeSubmitParams {
|
||||
fn default() -> Self {
|
||||
EthereumExchangeSubmitParams {
|
||||
eth: Default::default(),
|
||||
eth_sign: Default::default(),
|
||||
eth_nonce: None,
|
||||
eth_amount: 1_000_000_000_000_000_000_u64.into(), // 1 ETH
|
||||
sub_recipient: hex!("1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c"), // ferdie
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Submit single Ethereum -> Substrate exchange transaction.
|
||||
pub fn run(params: EthereumExchangeSubmitParams) {
|
||||
let mut local_pool = futures::executor::LocalPool::new();
|
||||
|
||||
let result: Result<_, String> = local_pool.run_until(async move {
|
||||
let eth_client = EthereumRpcClient::new(params.eth);
|
||||
|
||||
let eth_signer_address = params.eth_sign.signer.address();
|
||||
let sub_recipient_encoded = params.sub_recipient;
|
||||
let nonce = match params.eth_nonce {
|
||||
Some(eth_nonce) => eth_nonce,
|
||||
None => eth_client
|
||||
.account_nonce(eth_signer_address)
|
||||
.await
|
||||
.map_err(|err| format!("error fetching acount nonce: {:?}", err))?,
|
||||
};
|
||||
let gas = eth_client
|
||||
.estimate_gas(CallRequest {
|
||||
from: Some(eth_signer_address),
|
||||
to: Some(LOCK_FUNDS_ADDRESS.into()),
|
||||
value: Some(params.eth_amount),
|
||||
data: Some(sub_recipient_encoded.to_vec().into()),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.map_err(|err| format!("error estimating gas requirements: {:?}", err))?;
|
||||
let eth_tx_unsigned = UnsignedTransaction {
|
||||
nonce,
|
||||
gas_price: params.eth_sign.gas_price,
|
||||
gas,
|
||||
to: Some(LOCK_FUNDS_ADDRESS.into()),
|
||||
value: params.eth_amount,
|
||||
payload: sub_recipient_encoded.to_vec(),
|
||||
};
|
||||
let eth_tx_signed = eth_tx_unsigned.clone().sign_by(
|
||||
&SecretKey::parse(params.eth_sign.signer.secret().as_fixed_bytes())
|
||||
.expect("key is accepted by secp256k1::KeyPair and thus is valid; qed"),
|
||||
Some(params.eth_sign.chain_id),
|
||||
);
|
||||
eth_client
|
||||
.submit_transaction(eth_tx_signed)
|
||||
.await
|
||||
.map_err(|err| format!("error submitting transaction: {:?}", err))?;
|
||||
|
||||
Ok(eth_tx_unsigned)
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(eth_tx_unsigned) => {
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"Exchange transaction has been submitted to Ethereum node: {:?}",
|
||||
eth_tx_unsigned,
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!(
|
||||
target: "bridge",
|
||||
"Error submitting exchange transaction to Ethereum node: {}",
|
||||
err,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
mod ethereum_client;
|
||||
mod ethereum_deploy_contract;
|
||||
mod ethereum_exchange;
|
||||
mod ethereum_exchange_submit;
|
||||
mod ethereum_sync_loop;
|
||||
mod ethereum_types;
|
||||
mod exchange;
|
||||
@@ -85,14 +86,25 @@ fn main() {
|
||||
("eth-deploy-contract", Some(eth_deploy_matches)) => {
|
||||
log::info!(target: "bridge", "Deploying ETH contracts.");
|
||||
ethereum_deploy_contract::run(match ethereum_deploy_contract_params(ð_deploy_matches) {
|
||||
Ok(ethereum_deploy_matches) => ethereum_deploy_matches,
|
||||
Ok(ethereum_deploy_params) => ethereum_deploy_params,
|
||||
Err(err) => {
|
||||
log::error!(target: "bridge", "Error during contract deployment: {}", err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
("eth-submit-exchange-tx", Some(eth_exchange_submit_matches)) => {
|
||||
log::info!(target: "bridge", "Submitting ETH ➡ SUB exchange transaction.");
|
||||
ethereum_exchange_submit::run(match ethereum_exchange_submit_params(ð_exchange_submit_matches) {
|
||||
Ok(eth_exchange_submit_params) => eth_exchange_submit_params,
|
||||
Err(err) => {
|
||||
log::error!(target: "bridge", "Error submitting Eethereum exchange transaction: {}", err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
("eth-exchange-sub", Some(eth_exchange_matches)) => {
|
||||
log::info!(target: "bridge", "Starting ETH ➡ SUB exchange transactions relay.");
|
||||
ethereum_exchange::run(match ethereum_exchange_params(ð_exchange_matches) {
|
||||
Ok(eth_exchange_params) => eth_exchange_params,
|
||||
Err(err) => {
|
||||
@@ -256,6 +268,44 @@ fn ethereum_deploy_contract_params(
|
||||
Ok(eth_deploy_params)
|
||||
}
|
||||
|
||||
fn ethereum_exchange_submit_params(
|
||||
matches: &clap::ArgMatches,
|
||||
) -> Result<ethereum_exchange_submit::EthereumExchangeSubmitParams, String> {
|
||||
let mut params = ethereum_exchange_submit::EthereumExchangeSubmitParams::default();
|
||||
params.eth = ethereum_connection_params(matches)?;
|
||||
params.eth_sign = ethereum_signing_params(matches)?;
|
||||
|
||||
if let Some(eth_nonce) = matches.value_of("eth-nonce") {
|
||||
params.eth_nonce = Some(
|
||||
ethereum_types::U256::from_dec_str(ð_nonce).map_err(|e| format!("Failed to parse eth-nonce: {}", e))?,
|
||||
);
|
||||
}
|
||||
if let Some(eth_amount) = matches.value_of("eth-amount") {
|
||||
params.eth_amount = eth_amount
|
||||
.parse()
|
||||
.map_err(|e| format!("Failed to parse eth-amount: {}", e))?;
|
||||
}
|
||||
if let Some(sub_recipient) = matches.value_of("sub-recipient") {
|
||||
params.sub_recipient = hex::decode(&sub_recipient)
|
||||
.map_err(|err| err.to_string())
|
||||
.and_then(|vsub_recipient| {
|
||||
let expected_len = params.sub_recipient.len();
|
||||
if expected_len != vsub_recipient.len() {
|
||||
Err(format!("invalid length. Expected {} bytes", expected_len))
|
||||
} else {
|
||||
let mut sub_recipient = params.sub_recipient;
|
||||
sub_recipient.copy_from_slice(&vsub_recipient[..expected_len]);
|
||||
Ok(sub_recipient)
|
||||
}
|
||||
})
|
||||
.map_err(|e| format!("Failed to parse sub-recipient: {}", e))?;
|
||||
}
|
||||
|
||||
log::debug!(target: "bridge", "Submit Ethereum exchange tx params: {:?}", params);
|
||||
|
||||
Ok(params)
|
||||
}
|
||||
|
||||
fn ethereum_exchange_params(matches: &clap::ArgMatches) -> Result<ethereum_exchange::EthereumExchangeParams, String> {
|
||||
let mut params = ethereum_exchange::EthereumExchangeParams::default();
|
||||
params.eth = ethereum_connection_params(matches)?;
|
||||
@@ -279,6 +329,8 @@ fn ethereum_exchange_params(matches: &clap::ArgMatches) -> Result<ethereum_excha
|
||||
}),
|
||||
};
|
||||
|
||||
log::debug!(target: "bridge", "Ethereum exchange params: {:?}", params);
|
||||
|
||||
Ok(params)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user