ckb-sync 1.3.2

The ckb sync/relayer protocols implementation
use crate::StatusCode;
use crate::relayer::get_transactions_process::GetTransactionsProcess;
use crate::relayer::tests::helper::{MockProtocolContext, build_chain, new_transaction};
use ckb_network::{PeerIndex, SupportProtocols};
use ckb_types::packed;
use ckb_types::prelude::*;
use std::collections::HashSet;
use std::sync::Arc;

fn alternate_hash(tx_hash: &packed::Byte32) -> packed::Byte32 {
    let mut bytes = tx_hash.as_slice().to_vec();
    bytes[31] ^= 1;
    packed::Byte32::from_slice(&bytes).expect("valid transaction hash")
}

fn relay_message(tx: &ckb_types::core::TransactionView, cycles: u64) -> packed::RelayMessage {
    let relay_tx = packed::RelayTransaction::new_builder()
        .cycles(cycles)
        .transaction(tx.data())
        .build();
    packed::RelayMessage::new_builder()
        .set(
            packed::RelayTransactions::new_builder()
                .transactions(
                    packed::RelayTransactionVec::new_builder()
                        .set(vec![relay_tx])
                        .build(),
                )
                .build(),
        )
        .build()
}

#[test]
fn test_duplicate() {
    let (_chain, relayer, always_success_out_point) = build_chain(5);

    let tx = new_transaction(&relayer, 1, &always_success_out_point);
    let tx_hash = tx.hash();
    let content = packed::GetRelayTransactions::new_builder()
        .tx_hashes(vec![tx_hash.clone(), tx_hash])
        .build();
    let mock_protocol_context = MockProtocolContext::new(SupportProtocols::RelayV3);
    let nc = Arc::new(mock_protocol_context);
    let peer_index: PeerIndex = 1.into();
    let process = GetTransactionsProcess::new(content.as_reader(), &relayer, nc, peer_index);

    let rt = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap();
    assert_eq!(
        rt.block_on(process.execute()),
        StatusCode::RequestDuplicate.with_context("Request duplicate transaction")
    );
}

#[test]
fn test_fetch_transactions_by_hash() {
    let (_chain, relayer, always_success_out_point) = build_chain(5);
    let tx = new_transaction(&relayer, 1, &always_success_out_point);
    let tx_hash = tx.hash();
    let alternate_hash = alternate_hash(&tx_hash);
    assert_eq!(
        packed::ProposalShortId::from_tx_hash(&tx_hash),
        packed::ProposalShortId::from_tx_hash(&alternate_hash)
    );

    relayer
        .shared
        .shared()
        .tx_pool_controller()
        .submit_local_tx(tx.clone())
        .expect("submit request")
        .expect("resident transaction accepted");

    let content = packed::GetRelayTransactions::new_builder()
        .tx_hashes(vec![alternate_hash.clone()])
        .build();
    let nc = Arc::new(MockProtocolContext::new(SupportProtocols::RelayV3));
    let process = GetTransactionsProcess::new(
        content.as_reader(),
        &relayer,
        Arc::<MockProtocolContext>::clone(&nc),
        1.into(),
    );
    let rt = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap();

    assert_eq!(rt.block_on(process.execute()), crate::Status::ok());
    assert_eq!(nc.sent_messages_len(), 0);

    let alternate_fetched = rt
        .block_on(
            relayer
                .shared
                .shared()
                .tx_pool_controller()
                .fetch_txs_with_cycles(HashSet::from([alternate_hash.clone()])),
        )
        .expect("fetch response");
    assert!(alternate_fetched.is_empty());

    let fetched = rt
        .block_on(
            relayer
                .shared
                .shared()
                .tx_pool_controller()
                .fetch_txs_with_cycles(HashSet::from([tx_hash.clone()])),
        )
        .expect("fetch response");
    let cycles = fetched.first().expect("resident transaction returned").1;
    let expected = relay_message(&tx, cycles).as_bytes();
    let peer_index: PeerIndex = 1.into();

    for requested in [vec![tx_hash.clone()], vec![tx_hash, alternate_hash]] {
        let content = packed::GetRelayTransactions::new_builder()
            .tx_hashes(requested)
            .build();
        let nc = Arc::new(MockProtocolContext::new(SupportProtocols::RelayV3));
        let process = GetTransactionsProcess::new(
            content.as_reader(),
            &relayer,
            Arc::<MockProtocolContext>::clone(&nc),
            peer_index,
        );
        assert_eq!(rt.block_on(process.execute()), crate::Status::ok());
        assert_eq!(nc.sent_messages_len(), 1);
        assert!(nc.has_sent(
            SupportProtocols::RelayV3.protocol_id(),
            peer_index,
            expected.clone(),
        ));
    }
}