use std::collections::HashMap;
use hex::ToHex;
use jsonrpc::simple_http::SimpleHttpTransport;
use jsonrpc::Client;
use zcash_client_backend::decrypt_transaction;
use zcash_primitives::consensus::{BlockHeight, BranchId};
use zcash_primitives::transaction::Transaction;
use zip32::AccountId;
use zebra_scan::scan::{dfvk_to_ufvk, sapling_key_to_dfvk};
use zebra_scan::{storage::Storage, Config};
#[allow(clippy::print_stdout)]
pub fn main() {
let network = zebra_chain::parameters::Network::Mainnet;
let zp_network = zebra_scan::scan::zp_network(&network);
let storage = Storage::new(&Config::default(), &network, true);
let mut prev_memo = "".to_owned();
for (key, _) in storage.sapling_keys_last_heights().iter() {
let ufvks = HashMap::from([(
AccountId::ZERO,
dfvk_to_ufvk(&sapling_key_to_dfvk(key, &network).expect("dfvk")).expect("ufvk"),
)]);
for (height, txids) in storage.sapling_results(key) {
let height = BlockHeight::from(height.0);
for txid in txids.iter() {
let tx = Transaction::read(
&hex::decode(fetch_tx_via_rpc(txid.encode_hex()))
.expect("RPC response should be decodable from hex string to bytes")[..],
BranchId::for_height(&zp_network, height),
)
.expect("TX fetched via RPC should be deserializable from raw bytes");
for output in decrypt_transaction(&zp_network, Some(height), None, &tx, &ufvks)
.sapling_outputs()
{
let memo = memo_bytes_to_string(output.memo().as_array());
if !memo.is_empty()
&& !memo.contains("LIKE:")
&& !memo.contains("VOTE:")
&& memo != prev_memo
{
println!("{memo}\n");
prev_memo = memo;
}
}
}
}
}
}
fn memo_bytes_to_string(memo: &[u8; 512]) -> String {
match memo.iter().rposition(|&byte| byte != 0) {
Some(i) => String::from_utf8_lossy(&memo[..=i]).into_owned(),
None => "".to_owned(),
}
}
fn fetch_tx_via_rpc(txid: String) -> String {
let client = Client::with_transport(
SimpleHttpTransport::builder()
.url("127.0.0.1:8232")
.expect("Zebra's URL should be valid")
.build(),
);
client
.send_request(client.build_request("getrawtransaction", Some(&jsonrpc::arg([txid]))))
.expect("Sending the `getrawtransaction` request should succeed")
.result()
.expect("Zebra's RPC response should contain a valid result")
}