Skip to content

Commit

Permalink
Pass structured event log to ethereumInboundQueue.submit (#1003)
Browse files Browse the repository at this point in the history
  • Loading branch information
vgeddes authored Nov 12, 2023
1 parent 0801678 commit 8e921b2
Show file tree
Hide file tree
Showing 19 changed files with 256 additions and 130 deletions.
1 change: 0 additions & 1 deletion parachain/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 20 additions & 22 deletions parachain/pallets/ethereum-beacon-client/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,33 @@
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
use super::*;

use snowbridge_core::inbound::VerificationError::{self, *};
use snowbridge_core::inbound::{
VerificationError::{self, *},
*,
};
use snowbridge_ethereum::Receipt;

impl<T: Config> Verifier for Pallet<T> {
/// Verify a message by verifying the existence of the corresponding
/// Ethereum log in a block. Returns the log if successful. The execution header containing
/// the log should be in the beacon client storage, meaning it has been verified and is an
/// ancestor of a finalized beacon block.
fn verify(message: &Message) -> Result<(), VerificationError> {
fn verify(event_log: &Log, proof: &Proof) -> Result<(), VerificationError> {
log::info!(
target: "ethereum-beacon-client",
"💫 Verifying message with block hash {}",
message.proof.block_hash,
proof.block_hash,
);

let header =
<ExecutionHeaderBuffer<T>>::get(message.proof.block_hash).ok_or(HeaderNotFound)?;
let header = <ExecutionHeaderBuffer<T>>::get(proof.block_hash).ok_or(HeaderNotFound)?;

let receipt = match Self::verify_receipt_inclusion(header.receipts_root, &message.proof) {
let receipt = match Self::verify_receipt_inclusion(header.receipts_root, proof) {
Ok(receipt) => receipt,
Err(err) => {
log::error!(
target: "ethereum-beacon-client",
"💫 Verification of receipt inclusion failed for block {}: {:?}",
message.proof.block_hash,
proof.block_hash,
err
);
return Err(err)
Expand All @@ -36,35 +38,31 @@ impl<T: Config> Verifier for Pallet<T> {
log::trace!(
target: "ethereum-beacon-client",
"💫 Verified receipt inclusion for transaction at index {} in block {}",
message.proof.tx_index, message.proof.block_hash,
proof.tx_index, proof.block_hash,
);

let log = match rlp::decode(&message.data) {
Ok(log) => log,
Err(err) => {
log::error!(
target: "ethereum-beacon-client",
"💫 RLP log decoded failed {}: {:?}",
message.proof.block_hash,
err
);
return Err(InvalidLog)
},
event_log.validate().map_err(|_| InvalidLog)?;

// Convert snowbridge_core::inbound::Log to snowbridge_ethereum::Log.
let event_log = snowbridge_ethereum::Log {
address: event_log.address,
topics: event_log.topics.clone(),
data: event_log.data.clone(),
};

if !receipt.contains_log(&log) {
if !receipt.contains_log(&event_log) {
log::error!(
target: "ethereum-beacon-client",
"💫 Event log not found in receipt for transaction at index {} in block {}",
message.proof.tx_index, message.proof.block_hash,
proof.tx_index, proof.block_hash,
);
return Err(LogNotFound)
}

log::info!(
target: "ethereum-beacon-client",
"💫 Receipt verification successful for {}",
message.proof.block_hash,
proof.block_hash,
);

Ok(())
Expand Down
5 changes: 1 addition & 4 deletions parachain/pallets/ethereum-beacon-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,7 @@ use primitives::{
CompactBeaconState, CompactExecutionHeader, ExecutionHeaderState, ForkData, ForkVersion,
ForkVersions, PublicKeyPrepared, SigningData,
};
use snowbridge_core::{
inbound::{Message, Proof, Verifier},
BasicOperatingMode, RingBufferMap,
};
use snowbridge_core::{BasicOperatingMode, RingBufferMap};
use sp_core::H256;
use sp_std::prelude::*;
pub use weights::WeightInfo;
Expand Down
22 changes: 15 additions & 7 deletions parachain/pallets/ethereum-beacon-client/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub mod minimal {
use crate::config;
use hex_literal::hex;
use primitives::CompactExecutionHeader;
use snowbridge_core::inbound::{Message, Proof};
use snowbridge_core::inbound::{Log, Proof};
use sp_runtime::BuildStorage;
use std::{fs::File, path::PathBuf};

Expand Down Expand Up @@ -141,10 +141,18 @@ pub mod minimal {
load_fixture("next-finalized-header-update.minimal.json").unwrap()
}

pub fn get_message_verification_payload() -> Message {
Message {
data: hex!("f9011c94ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0f863a01b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ada000000000000000000000000000000000000000000000000000000000000003e8a00000000000000000000000000000000000000000000000000000000000000001b8a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000").to_vec(),
proof: Proof {
pub fn get_message_verification_payload() -> (Log, Proof) {
(
Log {
address: hex!("ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0").into(),
topics: vec![
hex!("1b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ad").into(),
hex!("00000000000000000000000000000000000000000000000000000000000003e8").into(),
hex!("0000000000000000000000000000000000000000000000000000000000000001").into(),
],
data: hex!("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000").into(),
},
Proof {
block_hash: hex!("05aaa60b0f27cce9e71909508527264b77ee14da7b5bf915fcc4e32715333213").into(),
tx_index: 0,
data: (vec![
Expand All @@ -156,8 +164,8 @@ pub mod minimal {
hex!("f851a0b9890f91ca0d77aa2a4adfaf9b9e40c94cac9e638b6d9797923865872944b646a060a634b9280e3a23fb63375e7bbdd9ab07fd379ab6a67e2312bbc112195fa358808080808080808080808080808080").to_vec(),
hex!("f9030820b9030402f90300018301d6e2b9010000000000000800000000000020040008000000000000000000000000400000008000000000000000000000000000000000000000000000000000000000042010000000001000000000000000000000000000000000040000000000000000000000000000000000000000000000008000000000000000002000000000000000000000000200000000000000200000000000100000000040000001000200008000000000000200000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000f901f5f87a942ffa5ecdbe006d30397c7636d3e015eee251369ff842a0c965575a00553e094ca7c5d14f02e107c258dda06867cbf9e0e69f80e71bbcc1a000000000000000000000000000000000000000000000000000000000000003e8a000000000000000000000000000000000000000000000000000000000000003e8f9011c94ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0f863a01b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ada000000000000000000000000000000000000000000000000000000000000003e8a00000000000000000000000000000000000000000000000000000000000000001b8a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000f858948cf6147918a5cbb672703f879f385036f8793a24e1a01449abf21e49fd025f33495e77f7b1461caefdd3d4bb646424a3f445c4576a5ba0000000000000000000000000440edffa1352b13227e8ee646f3ea37456dec701").to_vec(),
]),
},
}
}
)
}

pub fn get_message_verification_header() -> CompactExecutionHeader {
Expand Down
57 changes: 36 additions & 21 deletions parachain/pallets/ethereum-beacon-client/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -911,73 +911,88 @@ fn submit_execution_header_not_finalized() {
#[test]
fn verify_message() {
let header = get_message_verification_header();
let message = get_message_verification_payload();
let block_hash = message.proof.block_hash;
let (event_log, proof) = get_message_verification_payload();
let block_hash = proof.block_hash;

new_tester().execute_with(|| {
<ExecutionHeaderBuffer<Test>>::insert(block_hash, header);
assert_ok!(EthereumBeaconClient::verify(&message));
assert_ok!(EthereumBeaconClient::verify(&event_log, &proof));
});
}

#[test]
fn verify_message_missing_header() {
let message = get_message_verification_payload();
let (event_log, proof) = get_message_verification_payload();

new_tester().execute_with(|| {
assert_err!(EthereumBeaconClient::verify(&message), VerificationError::HeaderNotFound);
assert_err!(
EthereumBeaconClient::verify(&event_log, &proof),
VerificationError::HeaderNotFound
);
});
}

#[test]
fn verify_message_invalid_proof() {
let header = get_message_verification_header();
let mut message = get_message_verification_payload();
message.proof.data.1[0] = TEST_HASH.into();
let block_hash = message.proof.block_hash;
let (event_log, mut proof) = get_message_verification_payload();
proof.data.1[0] = TEST_HASH.into();
let block_hash = proof.block_hash;

new_tester().execute_with(|| {
<ExecutionHeaderBuffer<Test>>::insert(block_hash, header);
assert_err!(EthereumBeaconClient::verify(&message), VerificationError::InvalidProof);
assert_err!(
EthereumBeaconClient::verify(&event_log, &proof),
VerificationError::InvalidProof
);
});
}

#[test]
fn verify_message_invalid_receipts_root() {
let mut header = get_message_verification_header();
let message = get_message_verification_payload();
let block_hash = message.proof.block_hash;
let (event_log, proof) = get_message_verification_payload();
let block_hash = proof.block_hash;
header.receipts_root = TEST_HASH.into();

new_tester().execute_with(|| {
<ExecutionHeaderBuffer<Test>>::insert(block_hash, header);
assert_err!(EthereumBeaconClient::verify(&message), VerificationError::InvalidProof);
assert_err!(
EthereumBeaconClient::verify(&event_log, &proof),
VerificationError::InvalidProof
);
});
}

#[test]
fn verify_message_invalid_message_data() {
fn verify_message_invalid_log() {
let header = get_message_verification_header();
let mut message = get_message_verification_payload();
let block_hash = message.proof.block_hash;
message.data = TEST_HASH.into();
let (mut event_log, proof) = get_message_verification_payload();
let block_hash = proof.block_hash;
event_log.topics = vec![H256::zero(); 10];

new_tester().execute_with(|| {
<ExecutionHeaderBuffer<Test>>::insert(block_hash, header);
assert_err!(EthereumBeaconClient::verify(&message), VerificationError::InvalidLog);
assert_err!(
EthereumBeaconClient::verify(&event_log, &proof),
VerificationError::InvalidLog
);
});
}

#[test]
fn verify_message_receipt_does_not_contain_log() {
let header = get_message_verification_header();
let mut message = get_message_verification_payload();
let block_hash = message.proof.block_hash;
message.data = hex!("f9013c94ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0f863a01b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ada000000000000000000000000000000000000000000000000000000000000003e8a00000000000000000000000000000000000000000000000000000000000000002b8c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000068000f000000000000000101d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec70100000101001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c0000e8890423c78a0000000000000000000000000000000000000000000000000000000000000000").to_vec();
let (mut event_log, proof) = get_message_verification_payload();
let block_hash = proof.block_hash;
event_log.data = hex!("f9013c94ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0f863a01b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ada000000000000000000000000000000000000000000000000000000000000003e8a00000000000000000000000000000000000000000000000000000000000000002b8c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000068000f000000000000000101d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec70100000101001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c0000e8890423c78a0000000000000000000000000000000000000000000000000000000000000000").to_vec();

new_tester().execute_with(|| {
<ExecutionHeaderBuffer<Test>>::insert(block_hash, header);
assert_err!(EthereumBeaconClient::verify(&message), VerificationError::LogNotFound);
assert_err!(
EthereumBeaconClient::verify(&event_log, &proof),
VerificationError::LogNotFound
);
});
}

Expand Down
12 changes: 10 additions & 2 deletions parachain/pallets/inbound-queue/src/benchmarking/fixtures.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use hex_literal::hex;
use snowbridge_beacon_primitives::CompactExecutionHeader;
use snowbridge_core::inbound::{Message, Proof};
use snowbridge_core::inbound::{Log, Message, Proof};
use sp_std::vec;

pub struct InboundQueueTest {
Expand All @@ -17,7 +17,15 @@ pub fn make_create_message() -> InboundQueueTest {
receipts_root: hex!("0115ab735d37c5e4cdb0374d8bb547c6dd6ccaa996d996d1eabc5399a719219e").into(),
},
message: Message {
data: hex!("f8fc94eda338e4dc46038493b885327842fd3e301cab39f863a05066fbba677e15936860e04088ca4cad3acd4c19706962196a5346f1457f7169a000000000000000000000000000000000000000000000000000000000000003e8a0afad3c9777134532ae230b4fad334eef2e0dacbb965920412a7eaa59b07d640fb88000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").to_vec(),
event_log: Log {
address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(),
topics: vec![
hex!("5066fbba677e15936860e04088ca4cad3acd4c19706962196a5346f1457f7169").into(),
hex!("00000000000000000000000000000000000000000000000000000000000003e8").into(),
hex!("afad3c9777134532ae230b4fad334eef2e0dacbb965920412a7eaa59b07d640f").into(),
],
data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(),
},
proof: Proof {
block_hash: hex!("5f465744c166e9d10dc0031942a59ff82b640053253da517a1b576afdadb0363").into(),
tx_index: 0,
Expand Down
18 changes: 6 additions & 12 deletions parachain/pallets/inbound-queue/src/envelope.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
use snowbridge_core::ParaId;
use snowbridge_core::{inbound::Log, ParaId};

use sp_core::{RuntimeDebug, H160, H256};
use sp_std::{convert::TryFrom, prelude::*};

use alloy_primitives::{Address, Bytes, B256};
use alloy_rlp::RlpDecodable;
use alloy_primitives::B256;
use alloy_sol_types::{sol, SolEvent};

#[derive(RlpDecodable, RuntimeDebug)]
pub struct Log {
pub address: Address,
pub topics: Vec<B256>,
pub data: Bytes,
}

sol! {
event OutboundMessageAccepted(uint256 indexed destination, uint64 nonce, bytes32 indexed messageID, bytes payload);
}
Expand All @@ -42,11 +34,13 @@ impl TryFrom<Log> for Envelope {
type Error = EnvelopeDecodeError;

fn try_from(log: Log) -> Result<Self, Self::Error> {
let event = OutboundMessageAccepted::decode_log(log.topics, &log.data, true)
let topics: Vec<B256> = log.topics.iter().map(|x| B256::from_slice(x.as_ref())).collect();

let event = OutboundMessageAccepted::decode_log(topics, &log.data, true)
.map_err(|_| EnvelopeDecodeError)?;

Ok(Self {
gateway: H160::from(log.address.as_ref()),
gateway: log.address,
dest: event.destination.saturating_to::<u32>().into(),
nonce: event.nonce,
message_id: H256::from(event.messageID.as_ref()),
Expand Down
14 changes: 6 additions & 8 deletions parachain/pallets/inbound-queue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ pub mod weights;
#[cfg(test)]
mod test;

use alloy_rlp::Decodable as RlpDecodable;
use codec::{Decode, DecodeAll, Encode};
use envelope::{Envelope, Log};
use envelope::Envelope;
use frame_support::{
traits::{
fungible::{Inspect, Mutate},
Expand Down Expand Up @@ -216,13 +215,12 @@ pub mod pallet {
ensure!(!Self::operating_mode().is_halted(), Error::<T>::Halted);

// submit message to verifier for verification
T::Verifier::verify(&message).map_err(|e| Error::<T>::Verification(e))?;
T::Verifier::verify(&message.event_log, &message.proof)
.map_err(|e| Error::<T>::Verification(e))?;

let log = Log::decode(&mut message.data.as_slice())
.map_err(|_| Error::<T>::InvalidEnvelope)?;

// Decode log into an Envelope
let envelope = Envelope::try_from(log).map_err(|_| Error::<T>::InvalidEnvelope)?;
// Decode event log into an Envelope
let envelope =
Envelope::try_from(message.event_log).map_err(|_| Error::<T>::InvalidEnvelope)?;

// Verify that the message was submitted from the known Gateway contract
ensure!(T::GatewayAddress::get() == envelope.gateway, Error::<T>::InvalidGateway,);
Expand Down
Loading

0 comments on commit 8e921b2

Please sign in to comment.