From 0b19a9b5b97ebd2f67b86744bd5bd1c2fa2c3d76 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:54:47 -0500 Subject: [PATCH] improve parsing of graph relation types --- src/extract_transactions.rs | 81 ++++++++++++++++++++++++++----------- src/table_structs.rs | 33 ++++++++++----- 2 files changed, 80 insertions(+), 34 deletions(-) diff --git a/src/extract_transactions.rs b/src/extract_transactions.rs index e6e8771..da194f6 100644 --- a/src/extract_transactions.rs +++ b/src/extract_transactions.rs @@ -1,4 +1,4 @@ -use crate::table_structs::{RelationLabel, TransferTx, WarehouseEvent, WarehouseTxMaster}; +use crate::table_structs::{RelationLabel, UserEventTypes, WarehouseEvent, WarehouseTxMaster}; use anyhow::Result; use chrono::DateTime; use diem_crypto::HashValue; @@ -9,6 +9,7 @@ use libra_backwards_compatibility::sdk::v6_libra_framework_sdk_builder::EntryFun use libra_backwards_compatibility::sdk::v7_libra_framework_sdk_builder::EntryFunctionCall as V7EntryFunctionCall; use libra_cached_packages::libra_stdlib::EntryFunctionCall; use libra_storage::read_tx_chunk::{load_chunk, load_tx_chunk_manifest}; +use libra_types::move_resource::coin_register_event::CoinRegisterEvent; use libra_types::util::format_signed_transaction; use serde_json::json; use std::path::Path; @@ -76,8 +77,8 @@ pub async fn extract_current_transactions( events.append(&mut decoded_events); if let Some(signed_transaction) = tx.try_as_signed_user_txn() { - let mut tx = make_master_tx(signed_transaction, epoch, round, timestamp)?; - tx.events = decoded_events; + let tx = + make_master_tx(signed_transaction, epoch, round, timestamp, decoded_events)?; // sanity check that we are talking about the same block, and reading vectors sequentially. assert!(tx.tx_hash == tx_hash_info, "transaction hashes do not match in transaction vector and transaction_info vector"); @@ -103,6 +104,7 @@ pub fn make_master_tx( epoch: u64, round: u64, block_timestamp: u64, + events: Vec, ) -> Result { let tx_hash = user_tx.clone().committed_hash(); let raw = user_tx.raw_transaction_ref(); @@ -117,8 +119,9 @@ pub fn make_master_tx( } diem_types::transaction::TransactionPayload::Multisig(_multisig) => "Multisig".to_string(), }; + let relation_label = get_relation(user_tx, &events); - let mut tx = WarehouseTxMaster { + let tx = WarehouseTxMaster { tx_hash, expiration_timestamp: user_tx.expiration_timestamp_secs(), sender: user_tx.sender().to_hex_literal(), @@ -127,17 +130,12 @@ pub fn make_master_tx( block_timestamp, function, recipient: None, - // args: function_args_to_json(user_tx)?, entry_function: None, - relation_label: RelationLabel::Unknown, + relation_label, block_datetime: DateTime::from_timestamp_micros(block_timestamp as i64).unwrap(), - events: vec![], + events, }; - if let Ok(deposit) = try_decode_deposit_tx(user_tx) { - tx.recipient = Some(deposit.to.to_hex_literal()); - } - Ok(tx) } @@ -154,19 +152,28 @@ pub fn decode_events( } let event_name = el.type_tag().to_canonical_string(); + let mut event = UserEventTypes::Other; let mut data = json!("unknown data"); if let Ok(e) = WithdrawEvent::try_from_bytes(el.event_data()) { - data = json!(e); + data = json!(&e); + event = UserEventTypes::Withdraw(e); } if let Ok(e) = DepositEvent::try_from_bytes(el.event_data()) { - data = json!(e); + data = json!(&e); + event = UserEventTypes::Deposit(e); + } + + if let Ok(e) = CoinRegisterEvent::try_from_bytes(el.event_data()) { + data = json!(&e); + event = UserEventTypes::Onboard(e); } Some(WarehouseEvent { tx_hash, + event, event_name, data, }) @@ -199,16 +206,42 @@ pub fn function_args_to_json(user_tx: &SignedTransaction) -> Result Result { - let (to, amount) = match EntryFunctionCall::decode(user_tx.payload()) { - Some(EntryFunctionCall::OlAccountTransfer { to, amount }) => (to, amount), - // many variants - _ => anyhow::bail!("not a deposit tx"), - }; +fn get_relation(user_tx: &SignedTransaction, events: &[WarehouseEvent]) -> RelationLabel { + match EntryFunctionCall::decode(user_tx.payload()) { + Some(EntryFunctionCall::OlAccountTransfer { to, amount: _ }) => { + if is_onboarding_event(events) { + RelationLabel::Onboarding(to) + } else { + RelationLabel::Transfer(to) + } + } + // TODO: get other entry functions with known counter parties + // if nothing is found try to decipher from events + _ => RelationLabel::Tx, + } +} + +fn is_onboarding_event(events: &[WarehouseEvent]) -> bool { + let withdraw = events.iter().any(|e| { + if let UserEventTypes::Withdraw(_) = e.event { + return true; + } + false + }); + + let deposit = events.iter().any(|e| { + if let UserEventTypes::Deposit(_) = e.event { + return true; + } + false + }); + + let onboard = events.iter().any(|e| { + if let UserEventTypes::Onboard(_) = e.event { + return true; + } + false + }); - Ok(TransferTx { - tx_hash: user_tx.clone().committed_hash(), - to, - amount, - }) + withdraw && deposit && onboard } diff --git a/src/table_structs.rs b/src/table_structs.rs index 466bd42..9334e6e 100644 --- a/src/table_structs.rs +++ b/src/table_structs.rs @@ -2,43 +2,56 @@ use crate::cypher_templates::to_cypher_object; use chrono::{DateTime, Utc}; use diem_crypto::HashValue; +use diem_types::account_config::{DepositEvent, WithdrawEvent}; use libra_backwards_compatibility::sdk::v7_libra_framework_sdk_builder::EntryFunctionCall; -use libra_types::exports::AccountAddress; +use libra_types::{exports::AccountAddress, move_resource::coin_register_event::CoinRegisterEvent}; use neo4rs::{BoltList, BoltMap, BoltType}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum RelationLabel { - Unknown, - Transfer, - Onboarding, - Vouch, + Tx, // undefined tx + Transfer(AccountAddress), + Onboarding(AccountAddress), + Vouch(AccountAddress), Configuration, Miner, - Script, - MiscEntryFunction, + // Script, + // MiscEntryFunction, } +// TODO: deprecate? #[derive(Debug, Clone)] pub struct TransferTx { - pub tx_hash: HashValue, // primary key + pub tx_hash: HashValue, pub to: AccountAddress, pub amount: u64, } +// TODO: deprecate? #[derive(Debug, Clone)] pub struct MiscTx { pub tx_hash: HashValue, // primary key pub data: serde_json::Value, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct WarehouseEvent { pub tx_hash: HashValue, // primary key + pub event: UserEventTypes, pub event_name: String, pub data: serde_json::Value, } +#[derive(Debug, Serialize, Deserialize)] + +pub enum UserEventTypes { + Withdraw(WithdrawEvent), + Deposit(DepositEvent), + Onboard(CoinRegisterEvent), + Other, +} + #[derive(Debug, Deserialize, Clone, Serialize)] pub enum EntryFunctionArgs { V7(EntryFunctionCall), @@ -47,7 +60,7 @@ pub enum EntryFunctionArgs { // V5(V5EntryFunctionCall), } -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize)] pub struct WarehouseTxMaster { pub tx_hash: HashValue, // primary key pub relation_label: RelationLabel,