Update transactions and events modules

This commit is contained in:
Enol Álvarez
2023-07-21 18:33:05 +02:00
parent 58e2534e9b
commit 3678208dad
14 changed files with 172 additions and 101 deletions

View File

@@ -1,40 +1,7 @@
mod pb;
#[path = "map_block_meta.rs"]
mod block_meta;
#[path = "map_filter_transaction.rs"]
mod filter_transaction;
#[path = "map_contract_events.rs"]
mod contract_events;
use pb::eth::transaction::v1::TransactionOption;
use substreams_ethereum::pb::eth::v2::Block;
use pb::eth::block_meta::v1::BlockMeta;
use crate::pb::eth::event::v1::Events;
mod map_block_meta;
mod map_filter_transactions;
mod map_contract_events;
mod util;
substreams_ethereum::init!();
#[substreams::handlers::map]
fn map_block_meta(blk: Block) -> Result<BlockMeta, substreams::errors::Error> {
let block_meta = block_meta::map_block_meta(&blk);
Ok(block_meta)
}
#[substreams::handlers::map]
pub fn map_filter_transaction(transaction_hash: String, blk: Block) -> Result<TransactionOption, substreams::errors::Error> {
let filtered_transaction = filter_transaction::filter_by_transaction_hash(transaction_hash, &blk);
Ok(filtered_transaction)
}
#[substreams::handlers::map]
fn map_contract_events(contract_address: String, blk: Block) -> Result<Events, substreams::errors::Error> {
let events: Events = contract_events::map_contract_events(contract_address, &blk);
Ok(events)
}

View File

@@ -2,15 +2,16 @@ use substreams_ethereum::pb::eth::v2::Block;
use crate::pb::eth::block_meta::v1::BlockMeta;
use substreams::Hex;
pub fn map_block_meta (blk: &Block) -> BlockMeta {
#[substreams::handlers::map]
fn map_block_meta(blk: Block) -> Result<BlockMeta, substreams::errors::Error> {
let header = blk.header.as_ref().unwrap();
let hash_string = Hex(&blk.hash).to_string();
let parent_hash_string = Hex(&header.parent_hash).to_string();
return BlockMeta {
Ok(BlockMeta {
number: blk.number,
hash: hash_string,
parent_hash: parent_hash_string
}
})
}

View File

@@ -1,34 +1,52 @@
mod pb;
use crate::pb::eth::event::v1::Events;
use crate::pb::eth::event::v1::Event;
use substreams_ethereum::pb::eth::v2::Block;
use substreams::Hex;
use substreams_ethereum::pb::eth::v2::Log;
use substreams_ethereum::pb::eth::v2::TransactionTrace;
use substreams::errors::Error;
use crate::util;
#[substreams::handlers::map]
fn map_contract_events(contract_address: String, blk: Block) -> Result<Events, Error> {
let error = verify_parameter(&contract_address);
if error.is_some() {
return Err(error.unwrap());
}
pub fn map_contract_events(contract_address: String, blk: &Block) -> Events {
let mut events: Vec<Event> = Vec::new();
let contract_address_as_vec = match Hex::decode(&contract_address) {
Ok(address) => address,
Err(error) => return Err(Error::Unexpected(error.to_string())),
};
for tr in &blk.transaction_traces {
let to = Hex(&tr.to).to_string();
if to == contract_address {
let transaction_events = &mut get_transaction_events(&tr);
events.append(transaction_events);
for transaction in &blk.transaction_traces {
if transaction.to == contract_address_as_vec {
let transaction_events = get_transaction_events(&transaction);
events.extend(transaction_events);
}
}
return Events { events }
Ok(Events { events })
}
fn verify_parameter(contract_address: &String) -> Option<Error> {
if !util::is_address_valid(contract_address) {
return Some(Error::Unexpected(String::from("Contract address is not valid")))
}
return None
}
fn get_transaction_events(transaction: &TransactionTrace) -> Vec<Event> {
let mut transaction_events: Vec<Event> = Vec::new();
for log in &transaction.receipt().receipt.logs {
let address = Hex(&log.address).to_string();
let address = util::hexadecimal_to_string(&log.address);
let topics = get_log_topics(&log);
transaction_events.push(create_event_from(address, topics, &transaction.hash))
let event = create_event_from(address, topics, util::hexadecimal_to_string(&transaction.hash));
transaction_events.push(event)
}
return transaction_events;
@@ -38,19 +56,18 @@ fn get_log_topics(log: &Log) -> Vec<String> {
let mut topics: Vec<String> = Vec::new();
for topic in &log.topics {
let topic_string = Hex(topic).to_string();
let topic_string = util::hexadecimal_to_string(topic);
topics.push(topic_string)
}
return topics;
}
fn create_event_from(address: String, topics: Vec<String>, hash: &Vec<u8>) -> Event {
let hash_as_string = Hex(hash).to_string();
fn create_event_from(address: String, topics: Vec<String>, hash: String) -> Event {
return Event {
address,
topics,
tx_hash: hash_as_string
tx_hash: hash
}
}

View File

@@ -1,32 +0,0 @@
mod pb;
use substreams_ethereum::pb::eth::v2::Block;
use substreams::Hex;
use crate::pb::eth::transaction::v1::TransactionOption;
use crate::pb::eth::transaction::v1::Transaction;
pub fn filter_by_transaction_hash(transaction_hash: String, blk: &Block) -> TransactionOption {
let transaction_traces = &blk.transaction_traces;
for transfer in transaction_traces {
//let transferValue = transfer;
let hash = &transfer.hash;
let from = &transfer.from;
let to = &transfer.to;
if Hex(hash).to_string() == transaction_hash {
let trans = Transaction { from: Hex(from).to_string(), to: Hex(to).to_string(), hash: Hex(hash).to_string() };
return transfer_option_of(Some(trans));
}
}
return empty_transfer_option()
}
fn transfer_option_of (transaction: Option<Transaction>) -> TransactionOption {
return TransactionOption { transaction }
}
fn empty_transfer_option() -> TransactionOption {
return transfer_option_of(None)
}

View File

@@ -0,0 +1,77 @@
use substreams_ethereum::pb::eth::v2::{Block, TransactionTraceStatus};
use crate::pb::eth::transaction::v1::{Transaction, Transactions};
use serde::Deserialize;
use substreams::errors::Error;
use crate::util;
#[derive(Deserialize)]
struct TransactionFilterParams {
hash: Option<String>,
to: Option<String>,
from: Option<String>
}
#[substreams::handlers::map]
pub fn map_filter_transactions(params: String, blk: Block) -> Result<Transactions, Vec<substreams::errors::Error>> {
let filters: TransactionFilterParams = serde_qs::from_str(&params).unwrap();
let errors = verify_filter_params(&filters);
if errors.len() > 0 {
return Err(errors)
}
let mut filtered_transactions: Vec<Transaction> = Vec::new();
for transaction in &blk.transaction_traces {
let tx_hash = util::hexadecimal_to_string(&transaction.hash);
let tx_from = util::hexadecimal_to_string(&transaction.from);
let tx_to = util::hexadecimal_to_string(&transaction.to);
let mut current_transaction_filtered = true;
if !filter_by_parameter(&filters.hash, &tx_hash) ||
!filter_by_parameter(&filters.from, &tx_from) ||
!filter_by_parameter(&filters.to, &tx_to) ||
transaction.status != (TransactionTraceStatus::Succeeded as i32) {
current_transaction_filtered = false
}
if current_transaction_filtered {
let trans = Transaction { from: tx_from, to: tx_to, hash: tx_hash };
filtered_transactions.push(trans)
}
}
Ok(Transactions { transactions: filtered_transactions })
}
fn verify_filter_params(params: &TransactionFilterParams) -> Vec<substreams::errors::Error> {
let mut errors: Vec<substreams::errors::Error> = Vec::new();
if params.hash.is_some()
&& !util::is_transaction_hash_valid(&params.hash.as_ref().unwrap()) {
errors.push(Error::Unexpected(String::from("Transaction hash is not valid")));
}
if params.from.is_some()
&& !util::is_address_valid(&params.from.as_ref().unwrap()) {
errors.push(Error::Unexpected(String::from("'from' address is not valid")));
}
if params.to.is_some()
&& !util::is_address_valid(&params.to.as_ref().unwrap()) {
errors.push(Error::Unexpected(String::from("'to' address is not valid")));
}
return errors;
}
fn filter_by_parameter(parameter: &Option<String>, transaction_field: &String) -> bool {
if parameter.is_none() {
return true;
}
if parameter.as_ref().unwrap() == transaction_field {
return true
}
return false;
}

View File

@@ -1,9 +1,9 @@
// @generated
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TransactionOption {
#[prost(message, optional, tag="1")]
pub transaction: ::core::option::Option<Transaction>,
pub struct Transactions {
#[prost(message, repeated, tag="1")]
pub transactions: ::prost::alloc::vec::Vec<Transaction>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]

View File

@@ -0,0 +1,23 @@
use substreams::Hex;
pub fn hexadecimal_to_string(hex: &Vec<u8>) -> String {
return Hex::encode(hex);
}
pub fn is_transaction_hash_valid(hash: &String) -> bool {
// A transaction hash is always 64 hexadecimal characters
if hash.len() != 64 {
return false;
}
return true;
}
pub fn is_address_valid(address: &String) -> bool {
// An address is always 40 hexadecimal characters
if address.len() != 40 {
return false;
}
return true;
}