Make transactions receipts part of transaction inclusion proof (#236)

* make receipts part of tx proof

* is_successful_raw_receipt_with_empty_data

* cargo fmt --all

* clippy

* fix everything
This commit is contained in:
Svyatoslav Nikolsky
2020-07-28 13:57:25 +03:00
committed by Bastian Köcher
parent 70135cb797
commit 156ec9862f
10 changed files with 305 additions and 77 deletions
@@ -31,6 +31,7 @@ use crate::rpc_errors::RpcError;
use crate::substrate_client::{
SubmitEthereumExchangeTransactionProof, SubstrateConnectionParams, SubstrateRpcClient, SubstrateSigningParams,
};
use crate::substrate_types::into_substrate_ethereum_receipt;
use crate::sync_types::HeaderId;
use async_trait::async_trait;
@@ -169,12 +170,17 @@ impl SourceClient<EthereumToSubstrateExchange> for EthereumTransactionsSource {
node are having `raw` field; qed";
const BLOCK_HAS_HASH_FIELD_PROOF: &str = "RPC level checks that block has `hash` field; qed";
let transaction_proof = block
.0
.transactions
.iter()
.map(|tx| tx.raw.clone().expect(TRANSACTION_HAS_RAW_FIELD_PROOF).0)
.collect();
let mut transaction_proof = Vec::with_capacity(block.0.transactions.len());
for tx in &block.0.transactions {
let raw_tx_receipt = self
.client
.transaction_receipt(tx.hash)
.await
.map(|receipt| into_substrate_ethereum_receipt(&receipt))
.map(|receipt| receipt.rlp())?;
let raw_tx = tx.raw.clone().expect(TRANSACTION_HAS_RAW_FIELD_PROOF).0;
transaction_proof.push((raw_tx, raw_tx_receipt));
}
Ok(EthereumTransactionInclusionProof {
block: block.0.hash.expect(BLOCK_HAS_HASH_FIELD_PROOF),
@@ -221,11 +227,18 @@ impl TargetClient<EthereumToSubstrateExchange> for SubstrateTransactionsTarget {
async fn filter_transaction_proof(&self, proof: &EthereumTransactionInclusionProof) -> Result<bool, Self::Error> {
// let's try to parse transaction locally
let parse_result = bridge_node_runtime::exchange::EthTransaction::parse(&proof.proof[proof.index as usize]);
let (raw_tx, raw_tx_receipt) = &proof.proof[proof.index as usize];
let parse_result = bridge_node_runtime::exchange::EthTransaction::parse(raw_tx);
if parse_result.is_err() {
return Ok(false);
}
// now let's check if transaction is successful
match sp_bridge_eth_poa::Receipt::is_successful_raw_receipt(raw_tx_receipt) {
Ok(true) => (),
_ => return Ok(false),
}
// seems that transaction is relayable - let's check if runtime is able to import it
// (we can't if e.g. header is pruned or there's some issue with tx data)
self.client.verify_exchange_transaction_proof(proof.clone()).await
+25 -23
View File
@@ -100,27 +100,29 @@ pub fn into_substrate_ethereum_header(header: &EthereumHeader) -> SubstrateEther
pub fn into_substrate_ethereum_receipts(
receipts: &Option<Vec<EthereumReceipt>>,
) -> Option<Vec<SubstrateEthereumReceipt>> {
receipts.as_ref().map(|receipts| {
receipts
.iter()
.map(|receipt| SubstrateEthereumReceipt {
gas_used: receipt.gas_used.expect(ETHEREUM_RECEIPT_GAS_USED_PROOF),
log_bloom: receipt.logs_bloom.data().into(),
logs: receipt
.logs
.iter()
.map(|log_entry| SubstrateEthereumLogEntry {
address: log_entry.address,
topics: log_entry.topics.clone(),
data: log_entry.data.0.clone(),
})
.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()
})
receipts
.as_ref()
.map(|receipts| receipts.iter().map(into_substrate_ethereum_receipt).collect())
}
/// Convert Ethereum transactions receipt into Ethereum transactions receipt for Substrate.
pub fn into_substrate_ethereum_receipt(receipt: &EthereumReceipt) -> SubstrateEthereumReceipt {
SubstrateEthereumReceipt {
gas_used: receipt.gas_used.expect(ETHEREUM_RECEIPT_GAS_USED_PROOF),
log_bloom: receipt.logs_bloom.data().into(),
logs: receipt
.logs
.iter()
.map(|log_entry| SubstrateEthereumLogEntry {
address: log_entry.address,
topics: log_entry.topics.clone(),
data: log_entry.data.0.clone(),
})
.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,
},
}
}