Skip to content

Commit

Permalink
chore: add test for reference decoding from neon proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
polachok committed Feb 12, 2024
1 parent d5f6ea6 commit 5ccc6ce
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 27 deletions.
171 changes: 145 additions & 26 deletions parse/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use common::solana_sdk::transaction::VersionedTransaction;
use thiserror::Error;

use common::evm_loader::types::Address;
use common::evm_loader::types::{Address, Transaction};
use common::solana_sdk::signature::Signature;
use common::types::{NeonTxInfo, SolanaTransaction};

use self::log::NeonLogInfo;

mod log;
mod transaction;

Expand All @@ -30,15 +33,7 @@ struct SolTxMetaInfo {
pub ident: SolTxSigSlotInfo,
}

pub fn parse(transaction: SolanaTransaction) -> Result<Vec<NeonTxInfo>, Error> {
let SolanaTransaction { slot, tx, .. } = transaction;
let sig_slot_info = SolTxSigSlotInfo {
signature: tx.signatures[0],
block_slot: slot,
};
let _meta_info = SolTxMetaInfo {
ident: sig_slot_info,
};
fn parse_transactions(tx: VersionedTransaction) -> Result<Vec<(usize, Transaction)>, Error> {
let mut txs = Vec::new();
for (idx, ix) in tx.message.instructions().iter().enumerate() {
let neon_tx = transaction::parse(&ix.data)?;
Expand All @@ -47,13 +42,23 @@ pub fn parse(transaction: SolanaTransaction) -> Result<Vec<NeonTxInfo>, Error> {
txs.push((idx, neon_tx));
}
}
let log_info = match log::parse(transaction.log_messages) {
Ok(log) => log,
Err(err) => panic!("log parsing error {:?}", err),
};
tracing::info!("log info {:?}", log_info);
Ok(txs)
}

fn merge_logs_transactions(
txs: Vec<(usize, Transaction)>,
log_info: NeonLogInfo,
slot: u64,
tx_idx: u64,
) -> Vec<NeonTxInfo> {
let mut tx_infos = Vec::new();
for (idx, tx) in txs {
let canceled = log_info
.ret
.as_ref()
.map(|r| r.is_canceled)
.unwrap_or_default(); // TODO

let tx_info = NeonTxInfo {
tx_type: 0, // TODO
neon_signature: log_info.sig.map(hex::encode).unwrap_or_default(), // TODO
Expand All @@ -70,22 +75,136 @@ pub fn parse(transaction: SolanaTransaction) -> Result<Vec<NeonTxInfo>, Error> {
.ix
.as_ref()
.map(|i| i.total_gas_used)
.unwrap_or_default(), // TODO:
// unclear what this is
sol_signature: String::default(), // TODO: should be in input?
sol_slot: transaction.slot,
sol_tx_idx: transaction.tx_idx,
.unwrap_or_default(), // TODO: unclear what this is
sol_signature: String::default(), // TODO: should be in input?
sol_slot: slot,
sol_tx_idx: tx_idx,
sol_ix_idx: idx as u64,
sol_ix_inner_idx: 0, // TODO: what is this?
status: log_info.ret.as_ref().map(|r| r.status).unwrap_or_default(), // TODO
is_cancelled: log_info
.ret
.as_ref()
.map(|r| r.is_canceled)
.unwrap_or_default(), // TODO
is_completed: false, // TODO: ???
is_cancelled: canceled,
is_completed: !canceled, // TODO: ???
};
tx_infos.push(tx_info);
}
tx_infos
}

pub fn parse(transaction: SolanaTransaction) -> Result<Vec<NeonTxInfo>, Error> {
let SolanaTransaction {
slot, tx, tx_idx, ..
} = transaction;
let sig_slot_info = SolTxSigSlotInfo {
signature: tx.signatures[0],
block_slot: slot,
};
let _meta_info = SolTxMetaInfo {
ident: sig_slot_info,
};
let neon_txs = parse_transactions(tx)?;

let log_info = match log::parse(transaction.log_messages) {
Ok(log) => log,
Err(err) => panic!("log parsing error {:?}", err),
};
let tx_infos = merge_logs_transactions(neon_txs, log_info, slot, tx_idx);
Ok(tx_infos)
}

#[cfg(test)]
mod tests {
use super::*;
use common::solana_transaction_status::EncodedTransactionWithStatusMeta;
use serde::Deserialize;
use std::collections::HashMap;
use test_log::test;

#[allow(dead_code)]
#[derive(Debug, Deserialize)]
struct ReferenceRow {
neon_sig: String,
tx_type: u8,
from_addr: String,
sol_sig: String,
sol_ix_idx: u64,
sol_ix_inner_idx: Option<u64>,
block_slot: u64,
tx_idx: u64,
nonce: String,
gas_price: String,
gas_limit: String,
value: String,
gas_used: String,
sum_gas_used: String,
to_addr: String,
contract: Option<String>,
status: String,
is_canceled: bool,
is_completed: bool,
}

type Reference = HashMap<String, Vec<ReferenceRow>>;

#[test]
fn parse_2f() {
let transaction_path = "tests/data/2FSmsnCJYenPWsbrK1vFpkhgeFGKXC13gB3wDwqqyUfEnZmWpEJ6iUSjtLrtNn5QZh54bz5brWMonccG7WHA4Wp5.json";
let reference_path = "tests/data/reference/2FSmsnCJYenPWsbrK1vFpkhgeFGKXC13gB3wDwqqyUfEnZmWpEJ6iUSjtLrtNn5QZh54bz5brWMonccG7WHA4Wp5.json";

let encoded: EncodedTransactionWithStatusMeta =
serde_json::from_str(&std::fs::read_to_string(transaction_path).unwrap()).unwrap();
let tx = encoded.transaction.decode().unwrap();
let neon_txs = parse_transactions(tx).unwrap();
let logs = match encoded.meta.unwrap().log_messages {
common::solana_transaction_status::option_serializer::OptionSerializer::Some(logs) => {
logs
}
_ => panic!("no logs"),
};
let logs = log::parse(logs).unwrap();
let neon_tx_infos = merge_logs_transactions(neon_txs, logs, 276140928, 3);
let references: Vec<_> =
serde_json::from_str::<Reference>(&std::fs::read_to_string(reference_path).unwrap())
.unwrap()
.into_values()
.flatten()
.collect();
assert_eq!(neon_tx_infos.len(), references.len());
for (info, refr) in neon_tx_infos.iter().zip(references) {
let neon_sig = format!("0x{}", info.neon_signature);
assert_eq!(refr.neon_sig, neon_sig);
assert_eq!(refr.tx_type, info.tx_type);
// fails as we don't set from address
//assert_eq!(refr.from_addr, format!("0x{}", info.from));
// fails as we don't set signature
//assert_eq!(refr.sol_sig, info.sol_signature);
assert_eq!(refr.sol_ix_idx, info.sol_ix_idx);
// fails as we don't set inner index
//assert_eq!(refr.sol_ix_inner_idx, Some(info.sol_ix_inner_idx));
assert_eq!(refr.block_slot, info.sol_slot);
assert_eq!(refr.tx_idx, info.sol_tx_idx);
assert_eq!(refr.nonce, format!("{:#0x}", info.transaction.nonce()));
assert_eq!(
refr.gas_price,
format!("{:#0x}", info.transaction.gas_price())
);
assert_eq!(
refr.gas_limit,
format!("{:#0x}", info.transaction.gas_limit())
);
assert_eq!(refr.value, format!("{:#0x}", info.transaction.value()));
assert_eq!(refr.gas_used, format!("{:#0x}", info.gas_used));
// fails for unknown reason
//assert_eq!(refr.sum_gas_used, format!("{:#0x}", info.sum_gas_used));
// fails for unknown reason
// assert_eq!(
// refr.to_addr,
// format!("0x{}", info.transaction.target().unwrap())
// );
assert_eq!(refr.contract, info.contract.map(|c| format!("0x{}", c)));
// fails for unknown reason
//assert_eq!(refr.status, format!("{:#0x}", info.status));
assert_eq!(refr.is_canceled, info.is_cancelled);
assert_eq!(refr.is_completed, info.is_completed);
}
}
}
16 changes: 15 additions & 1 deletion parse/src/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub struct NeonLogTxIx {

#[derive(Debug, Copy, Clone)]
enum Mnemonic {
Miner,
Hash,
Return,
Log(u8),
Expand Down Expand Up @@ -271,6 +272,11 @@ impl Mnemonic {
is_canceled: false,
})
}

// TODO
fn decode_miner(_input: &str) {
warn!("miner opcode not implemented yet")
}
}

#[derive(Debug, Error)]
Expand All @@ -283,6 +289,7 @@ impl FromStr for Mnemonic {
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"HASH" => Ok(Mnemonic::Hash),
"MINER" => Ok(Mnemonic::Miner),
"RETURN" => Ok(Mnemonic::Return),
"ENTER" => Ok(Mnemonic::Enter),
"EXIT" => Ok(Mnemonic::Exit),
Expand All @@ -292,7 +299,10 @@ impl FromStr for Mnemonic {
let n = n.parse().map_err(|_| BadMnemonic)?;
Ok(Mnemonic::Log(n))
}
_ => Err(BadMnemonic),
s => {
println!("Invalid mnemonic {}", s);
Err(BadMnemonic)
}
}
}
}
Expand Down Expand Up @@ -363,6 +373,10 @@ pub fn parse(lines: impl IntoIterator<Item = impl AsRef<str>>) -> Result<NeonLog
}
neon_tx_ix = Some(Mnemonic::decode_tx_gas(rest)?);
}
Mnemonic::Miner => {
// TODO
Mnemonic::decode_miner(rest);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"SELECT neon_sig, tx_type, from_addr, sol_sig, sol_ix_idx, sol_ix_inner_idx, block_slot, tx_idx, nonce, gas_price, gas_limit, value, gas_used, sum_gas_used, to_addr, contract, status, is_canceled, is_completed, v, r, s, calldata, logs\nFROM public.neon_transactions where sol_sig = '2FSmsnCJYenPWsbrK1vFpkhgeFGKXC13gB3wDwqqyUfEnZmWpEJ6iUSjtLrtNn5QZh54bz5brWMonccG7WHA4Wp5' limit 5": [
{
"neon_sig" : "0xc6a0f130f273b774b1725b058a0f9be2b2486816542cf53a7e426220f7b613d1",
"tx_type" : 0,
"from_addr" : "0x9115cb3a0415731e921635fcbd2b6dfbe6f0995e",
"sol_sig" : "2FSmsnCJYenPWsbrK1vFpkhgeFGKXC13gB3wDwqqyUfEnZmWpEJ6iUSjtLrtNn5QZh54bz5brWMonccG7WHA4Wp5",
"sol_ix_idx" : 2,
"sol_ix_inner_idx" : null,
"block_slot" : 276140928,
"tx_idx" : 3,
"nonce" : "0xe3e",
"gas_price" : "0x122e18d945",
"gas_limit" : "0x61a8",
"value" : "0x695b1a0d000",
"gas_used" : "0x2710",
"sum_gas_used" : "0x9c40",
"to_addr" : "0x0543a5311319ea73b867c39c33c4d9ba5d6e517b",
"contract" : null,
"status" : "0x1",
"is_canceled" : false,
"is_completed" : true,
"v" : "0x1d3581bf",
"r" : "0xd0b4714cb793966390c1f52ee45b3311a0e604b05125254a23bf15fccd12f7b3",
"s" : "0x72312df0810b665af85901aa8a0e3a0f1babfcad3772605940ec57be80a97f3b",
"calldata" : "0xfe1e0a70edc32599c9c63e6ffe1b0c4faa20e0dafb4e55576fac4c109b4a7bd0",
"logs" : [{"event_type": 101, "is_hidden": true, "address": "0x0543a5311319ea73b867c39c33c4d9ba5d6e517b", "topic_list": [], "data": "0x", "sol_sig": "2FSmsnCJYenPWsbrK1vFpkhgeFGKXC13gB3wDwqqyUfEnZmWpEJ6iUSjtLrtNn5QZh54bz5brWMonccG7WHA4Wp5", "idx": 2, "inner_idx": null, "total_gas_used": 10000, "is_reverted": false, "event_level": 1, "event_order": 1, "neon_sig": "0xc6a0f130f273b774b1725b058a0f9be2b2486816542cf53a7e426220f7b613d1", "block_hash": "0x4b40b04fb905d2a39070fc15cbe94d972d511090534098b43b26b51b76e3d9aa", "block_slot": 276140928, "neon_tx_idx": 3, "block_log_idx": null, "neon_tx_log_idx": null}, {"event_type": 201, "is_hidden": true, "address": "0x0543a5311319ea73b867c39c33c4d9ba5d6e517b", "topic_list": [], "data": "0x", "sol_sig": "2FSmsnCJYenPWsbrK1vFpkhgeFGKXC13gB3wDwqqyUfEnZmWpEJ6iUSjtLrtNn5QZh54bz5brWMonccG7WHA4Wp5", "idx": 2, "inner_idx": null, "total_gas_used": 10001, "is_reverted": false, "event_level": 1, "event_order": 2, "neon_sig": "0xc6a0f130f273b774b1725b058a0f9be2b2486816542cf53a7e426220f7b613d1", "block_hash": "0x4b40b04fb905d2a39070fc15cbe94d972d511090534098b43b26b51b76e3d9aa", "block_slot": 276140928, "neon_tx_idx": 3, "block_log_idx": null, "neon_tx_log_idx": null}, {"event_type": 300, "is_hidden": true, "address": "0x", "topic_list": [], "data": "0x01", "sol_sig": "2FSmsnCJYenPWsbrK1vFpkhgeFGKXC13gB3wDwqqyUfEnZmWpEJ6iUSjtLrtNn5QZh54bz5brWMonccG7WHA4Wp5", "idx": 2, "inner_idx": null, "total_gas_used": 15000, "is_reverted": false, "event_level": 0, "event_order": 3, "neon_sig": "0xc6a0f130f273b774b1725b058a0f9be2b2486816542cf53a7e426220f7b613d1", "block_hash": "0x4b40b04fb905d2a39070fc15cbe94d972d511090534098b43b26b51b76e3d9aa", "block_slot": 276140928, "neon_tx_idx": 3, "block_log_idx": null, "neon_tx_log_idx": null}]
}
]}

0 comments on commit 5ccc6ce

Please sign in to comment.