eth/bridge_event.cpp¶
Namespaces¶
| Name |
|---|
| eth |
Functions¶
| Name | |
|---|---|
| bool | operator==(const BridgeEventKey & lhs, const BridgeEventKey & rhs) |
| bool | operator<(const BridgeEventKey & lhs, const BridgeEventKey & rhs) |
| BridgeEventKey | bridge_event_key(const BridgeEventClaim & claim) |
| ReceiptLogVerificationResult | verify_receipt_log(const ReceiptResult & receipt, const BridgeEventClaim & claim) |
| Hash256 | compute_bridge_message_id(uint64_t src_chain_id, const Address & bridge_contract, const Hash256 & tx_hash, uint32_t log_index) Canonical message identifier for an EVM bridge source event. |
Functions Documentation¶
function operator==¶
function operator<¶
function bridge_event_key¶
function verify_receipt_log¶
ReceiptLogVerificationResult verify_receipt_log(
const ReceiptResult & receipt,
const BridgeEventClaim & claim
)
function compute_bridge_message_id¶
Hash256 compute_bridge_message_id(
uint64_t src_chain_id,
const Address & bridge_contract,
const Hash256 & tx_hash,
uint32_t log_index
)
Canonical message identifier for an EVM bridge source event.
Parameters:
- src_chain_id Numeric source chain ID.
- bridge_contract Bridge contract address on the source chain.
- tx_hash Transaction hash containing the event log.
- log_index Log index within the transaction receipt.
Return: 32-byte keccak-256 hash serving as the canonical message_id.
Computed as keccak256 over a deterministic big-endian encoding of: src_chain_id (8 bytes) || bridge_contract (20 bytes) || tx_hash (32 bytes) || log_index (4 bytes)
This identifier is stable across observers, replay attempts, and consensus rounds. It is used for deduplication, processing-state tracking, slot-key assignment, and anti-double-mint persistence.
Source code¶
// Copyright 2026 Genius Ventures, Inc.
// SPDX-License-Identifier: MIT
#include <eth/bridge_event.hpp>
#include <eth/abi_decoder.hpp>
#include <base/byte_encoding.hpp>
#include <algorithm>
namespace eth {
bool operator==(const BridgeEventKey& lhs, const BridgeEventKey& rhs) noexcept
{
return lhs.src_chain_id == rhs.src_chain_id
&& lhs.tx_hash == rhs.tx_hash
&& lhs.log_index == rhs.log_index;
}
bool operator<(const BridgeEventKey& lhs, const BridgeEventKey& rhs) noexcept
{
if (lhs.src_chain_id != rhs.src_chain_id)
{
return lhs.src_chain_id < rhs.src_chain_id;
}
if (lhs.tx_hash != rhs.tx_hash)
{
return std::lexicographical_compare(
lhs.tx_hash.begin(), lhs.tx_hash.end(),
rhs.tx_hash.begin(), rhs.tx_hash.end());
}
return lhs.log_index < rhs.log_index;
}
BridgeEventKey bridge_event_key(const BridgeEventClaim& claim) noexcept
{
return BridgeEventKey{
claim.src_chain_id,
claim.tx_hash,
claim.log_index,
};
}
bool EventDeduper::contains(const BridgeEventKey& key) const
{
return seen_.find(key) != seen_.end();
}
bool EventDeduper::mark_seen(const BridgeEventKey& key)
{
return seen_.insert(key).second;
}
size_t EventDeduper::size() const noexcept
{
return seen_.size();
}
void EventDeduper::clear() noexcept
{
seen_.clear();
}
ReceiptLogVerificationResult verify_receipt_log(
const ReceiptResult& receipt,
const BridgeEventClaim& claim) noexcept
{
if (!receipt.receipt.status.has_value())
{
return {ReceiptLogVerificationError::kMissingReceiptStatus};
}
if (!*receipt.receipt.status)
{
return {ReceiptLogVerificationError::kReceiptFailed};
}
if (receipt.block_hash != claim.block_hash)
{
return {ReceiptLogVerificationError::kBlockHashMismatch};
}
if (receipt.tx_hash != claim.tx_hash)
{
return {ReceiptLogVerificationError::kTxHashMismatch};
}
size_t receipt_log_index = claim.log_index;
if (!receipt.log_indices.empty())
{
const auto it = std::find(
receipt.log_indices.begin(),
receipt.log_indices.end(),
claim.log_index);
if (it == receipt.log_indices.end())
{
return {ReceiptLogVerificationError::kLogIndexOutOfRange};
}
receipt_log_index = static_cast<size_t>(std::distance(receipt.log_indices.begin(), it));
}
if (receipt_log_index >= receipt.receipt.logs.size())
{
return {ReceiptLogVerificationError::kLogIndexOutOfRange};
}
const auto& log = receipt.receipt.logs[receipt_log_index];
if (log.address != claim.bridge_contract)
{
return {ReceiptLogVerificationError::kContractMismatch};
}
if (log.topics.empty() || log.topics.front() != claim.event_topic0)
{
return {ReceiptLogVerificationError::kTopic0Mismatch};
}
if (!claim.topics.empty() && log.topics != claim.topics)
{
return {ReceiptLogVerificationError::kTopicsMismatch};
}
if (log.data != claim.data)
{
return {ReceiptLogVerificationError::kDataMismatch};
}
return {};
}
Hash256 compute_bridge_message_id(
uint64_t src_chain_id,
const Address& bridge_contract,
const Hash256& tx_hash,
uint32_t log_index) noexcept
{
namespace bytes = rlp::base::byte_encoding;
bytes::ByteBuffer input;
input.reserve(8 + 20 + 32 + 4);
bytes::append_u64_be(input, src_chain_id);
bytes::append_array(input, bridge_contract);
bytes::append_array(input, tx_hash);
bytes::append_u32_be(input, log_index);
return abi::keccak256(input.data(), input.size());
}
} // namespace eth
Updated on 2026-06-05 at 17:22:19 -0700