pub async fn send_one_sided_transaction(
        &mut self,
        dest_pubkey: CommsPublicKey,
        amount: MicroTari,
        fee_per_gram: MicroTari,
        message: String,
        transaction_broadcast_join_handles: &mut FuturesUnordered<
            JoinHandle<Result<u64, TransactionServiceProtocolError>>,
        >,
    ) -> Result<TxId, TransactionServiceError> {
        if self.node_identity.public_key() == &dest_pubkey {
            warn!(target: LOG_TARGET, "One-sided spend-to-self transactions not supported");
            return Err(TransactionServiceError::OneSidedTransactionError(
                "One-sided spend-to-self transactions not supported".to_string(),
            ));
        }

        // Prepare sender part of the transaction

        let mut stp = self
            .output_manager_service
            .prepare_transaction_to_send(
                amount,
                fee_per_gram,
                None,
                message.clone(),
                script!(PushPubKey(Box::new(dest_pubkey.clone()))),
            )
            .await?;
        let tx_id = stp.get_tx_id()?;

        // This call is needed to advance the state from `SingleRoundMessageReady` to `SingleRoundMessageReady`,
        // but the returned value is not used
        let _ = stp
            .build_single_round_message()
            .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;

        self.output_manager_service
            .confirm_pending_transaction(tx_id)
            .await
            .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;

        // Prepare receiver part of the transaction

        // Diffie-Hellman shared secret `k_Ob * K_Sb = K_Ob * k_Sb` results in a public key, which is converted to
        // bytes to enable conversion into a private key to be used as the spending key
        let sender_offset_private_key = stp
            .get_recipient_sender_offset_private_key(0)
            .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;
        // TODO: Add a standardized Diffie-Hellman method to the tari_crypto library that will return a private key,
        // TODO: then come back and use it here.
        let spending_key = PrivateKey::from_bytes(
            CommsPublicKey::shared_secret(&sender_offset_private_key.clone(), &dest_pubkey.clone()).as_bytes(),
        )
        .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;

        let sender_message = TransactionSenderMessage::new_single_round_message(stp.get_single_round_message()?);
        let rewind_key = PrivateKey::from_bytes(&hash_secret_key(&spending_key))?;
        let blinding_key = PrivateKey::from_bytes(&hash_secret_key(&rewind_key))?;
        let rewind_data = RewindData {
            rewind_key: rewind_key.clone(),
            rewind_blinding_key: blinding_key.clone(),
            proof_message: [0u8; 21],
        };

        let rtp = ReceiverTransactionProtocol::new_with_rewindable_output(
            sender_message,
            PrivateKey::random(&mut OsRng),
            spending_key,
            OutputFeatures::default(),
            &self.resources.factories,
            &rewind_data,
        );

        let recipient_reply = rtp.get_signed_data()?.clone();

        // Start finalizing

        stp.add_single_recipient_info(recipient_reply, &self.resources.factories.range_proof)
            .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;

        // Finalize

        stp.finalize(KernelFeatures::empty(), &self.resources.factories)
            .map_err(|e| {
                error!(
                    target: LOG_TARGET,
                    "Transaction (TxId: {}) could not be finalized. Failure error: {:?}", tx_id, e,
                );
                TransactionServiceProtocolError::new(tx_id, e.into())
            })?;
        info!(target: LOG_TARGET, "Finalized one-side transaction TxId: {}", tx_id);

        // This event being sent is important, but not critical to the protocol being successful. Send only fails if
        // there are no subscribers.
        let _ = self
            .event_publisher
            .send(Arc::new(TransactionEvent::TransactionCompletedImmediately(tx_id)));

        // Broadcast one-sided transaction

        let tx = stp
            .get_transaction()
            .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;
        let fee = stp
            .get_fee_amount()
            .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;
        self.submit_transaction(
            transaction_broadcast_join_handles,
            CompletedTransaction::new(
                tx_id,
                self.resources.node_identity.public_key().clone(),
                dest_pubkey.clone(),
                amount,
                fee,
                tx.clone(),
                TransactionStatus::Completed,
                message.clone(),
                Utc::now().naive_utc(),
                TransactionDirection::Outbound,
                None,
            ),
        )
        .await?;

        Ok(tx_id)
    }
/// Sends a one side payment transaction to a recipient
/// # Arguments
/// 'dest_pubkey': The Comms pubkey of the recipient node
/// 'amount': The amount of Tari to send to the recipient
/// 'fee_per_gram': The amount of fee per transaction gram to be included in transaction
Sends a one side payment transaction to a recipient
Sends a one side payment transaction to a recipient
pub async fn send_one_sided_transaction(
        &mut self,
        dest_pubkey: CommsPublicKey,
        amount: MicroTari,
        fee_per_gram: MicroTari,
        message: String,
        transaction_broadcast_join_handles: &mut FuturesUnordered<
            JoinHandle<Result<u64, TransactionServiceProtocolError>>,
        >,
    ) -> Result<TxId, TransactionServiceError> {
        if self.node_identity.public_key() == &dest_pubkey {
            warn!(target: LOG_TARGET, "One-sided spend-to-self transactions not supported");
            return Err(TransactionServiceError::OneSidedTransactionError(
                "One-sided spend-to-self transactions not supported".to_string(),
            ));
        }
        // Prepare sender part of the transaction
        let mut stp = self
            .output_manager_service
            .prepare_transaction_to_send(
                amount,
                fee_per_gram,
                None,
                message.clone(),
                script!(PushPubKey(Box::new(dest_pubkey.clone()))),
            )
            .await?;
        let tx_id = stp.get_tx_id()?;
        // This call is needed to advance the state from `SingleRoundMessageReady` to `SingleRoundMessageReady`,
        // but the returned value is not used
        let _ = stp
            .build_single_round_message()
            .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;
        self.output_manager_service
            .confirm_pending_transaction(tx_id)
            .await
            .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;
        // Prepare receiver part of the transaction
        // Diffie-Hellman shared secret `k_Ob * K_Sb = K_Ob * k_Sb` results in a public key, which is converted to
        // bytes to enable conversion into a private key to be used as the spending key
        let sender_offset_private_key = stp
            .get_recipient_sender_offset_private_key(0)
            .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;
        // TODO: Add a standardized Diffie-Hellman method to the tari_crypto library that will return a private key,
        // TODO: then come back and use it here.
        let spending_key = PrivateKey::from_bytes(
            CommsPublicKey::shared_secret(&sender_offset_private_key.clone(), &dest_pubkey.clone()).as_bytes(),
        )
        .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;
        let sender_message = TransactionSenderMessage::new_single_round_message(stp.get_single_round_message()?);
        let rewind_key = PrivateKey::from_bytes(&hash_secret_key(&spending_key))?;
        let blinding_key = PrivateKey::from_bytes(&hash_secret_key(&rewind_key))?;
        let rewind_data = RewindData {
            rewind_key: rewind_key.clone(),
            rewind_blinding_key: blinding_key.clone(),
            proof_message: [0u8; 21],
        };
        let rtp = ReceiverTransactionProtocol::new_with_rewindable_output(
            sender_message,
            PrivateKey::random(&mut OsRng),
            spending_key,
            OutputFeatures::default(),
            &self.resources.factories,
            &rewind_data,
        );
        let recipient_reply = rtp.get_signed_data()?.clone();
        // Start finalizing
        stp.add_single_recipient_info(recipient_reply, &self.resources.factories.range_proof)
            .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;
        // Finalize
        stp.finalize(KernelFeatures::empty(), &self.resources.factories)
            .map_err(|e| {
                error!(
                    target: LOG_TARGET,
                    "Transaction (TxId: {}) could not be finalized. Failure error: {:?}", tx_id, e,
                );
                TransactionServiceProtocolError::new(tx_id, e.into())
            })?;
        info!(target: LOG_TARGET, "Finalized one-side transaction TxId: {}", tx_id);
        // This event being sent is important, but not critical to the protocol being successful. Send only fails if
        // there are no subscribers.
        let _ = self
            .event_publisher
            .send(Arc::new(TransactionEvent::TransactionCompletedImmediately(tx_id)));
        // Broadcast one-sided transaction
        let tx = stp
            .get_transaction()
            .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;
        let fee = stp
            .get_fee_amount()
            .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;
        self.submit_transaction(
            transaction_broadcast_join_handles,
            CompletedTransaction::new(
                tx_id,
                self.resources.node_identity.public_key().clone(),
                dest_pubkey.clone(),
                amount,
                fee,
                tx.clone(),
                TransactionStatus::Completed,
                message.clone(),
                Utc::now().naive_utc(),
                TransactionDirection::Outbound,
                None,
            ),
        )
        .await?;
        Ok(tx_id)
    }
pub async fn send_one_sided_transaction ( & mut self , dest_pubkey : CommsPublicKey , amount : MicroTari , fee_per_gram : MicroTari , message : String , transaction_broadcast_join_handles : & mut FuturesUnordered < JoinHandle < Result < u64 , TransactionServiceProtocolError > > , > , ) -> Result < TxId , TransactionServiceError > { if self . node_identity . public_key ( ) == & dest_pubkey { warn ! ( target LOG_TARGET " " ) ; return Err ( TransactionServiceError :: OneSidedTransactionError ( " " . to_string ( ) , ) ) ; } // Prepare sender part of the transaction let mut stp = self . output_manager_service . prepare_transaction_to_send ( amount , fee_per_gram , None , message . clone ( ) , script ! ( PushPubKey ( Box new ( dest_pubkey clone ( ) ) ) ) , ) . await ? ; let tx_id = stp . get_tx_id ( ) ? ; // This call is needed to advance the state from `SingleRoundMessageReady` to `SingleRoundMessageReady`, // but the returned value is not used let _ = stp . build_single_round_message ( ) . map_err ( | e | TransactionServiceProtocolError :: new ( tx_id , e . into ( ) ) ) ? ; self . output_manager_service . confirm_pending_transaction ( tx_id ) . await . map_err ( | e | TransactionServiceProtocolError :: new ( tx_id , e . into ( ) ) ) ? ; // Prepare receiver part of the transaction // Diffie-Hellman shared secret `k_Ob * K_Sb = K_Ob * k_Sb` results in a public key, which is converted to // bytes to enable conversion into a private key to be used as the spending key let sender_offset_private_key = stp . get_recipient_sender_offset_private_key ( 0 ) . map_err ( | e | TransactionServiceProtocolError :: new ( tx_id , e . into ( ) ) ) ? ; // TODO: Add a standardized Diffie-Hellman method to the tari_crypto library that will return a private key, // TODO: then come back and use it here. let spending_key = PrivateKey :: from_bytes ( CommsPublicKey :: shared_secret ( & sender_offset_private_key . clone ( ) , & dest_pubkey . clone ( ) ) . as_bytes ( ) , ) . map_err ( | e | TransactionServiceProtocolError :: new ( tx_id , e . into ( ) ) ) ? ; let sender_message = TransactionSenderMessage :: new_single_round_message ( stp . get_single_round_message ( ) ? ) ; let rewind_key = PrivateKey :: from_bytes ( & hash_secret_key ( & spending_key ) ) ? ; let blinding_key = PrivateKey :: from_bytes ( & hash_secret_key ( & rewind_key ) ) ? ; let rewind_data = RewindData { rewind_key : rewind_key . clone ( ) , rewind_blinding_key : blinding_key . clone ( ) , proof_message : [ 0u8 ; 21 ] , } ; let rtp = ReceiverTransactionProtocol :: new_with_rewindable_output ( sender_message , PrivateKey :: random ( & mut OsRng ) , spending_key , OutputFeatures :: default ( ) , & self . resources . factories , & rewind_data , ) ; let recipient_reply = rtp . get_signed_data ( ) ? . clone ( ) ; // Start finalizing stp . add_single_recipient_info ( recipient_reply , & self . resources . factories . range_proof ) . map_err ( | e | TransactionServiceProtocolError :: new ( tx_id , e . into ( ) ) ) ? ; // Finalize stp . finalize ( KernelFeatures :: empty ( ) , & self . resources . factories ) . map_err ( | e | { error ! ( target LOG_TARGET " " tx_id e ) ; TransactionServiceProtocolError :: new ( tx_id , e . into ( ) ) } ) ? ; info ! ( target LOG_TARGET " " tx_id ) ; // This event being sent is important, but not critical to the protocol being successful. Send only fails if // there are no subscribers. let _ = self . event_publisher . send ( Arc :: new ( TransactionEvent :: TransactionCompletedImmediately ( tx_id ) ) ) ; // Broadcast one-sided transaction let tx = stp . get_transaction ( ) . map_err ( | e | TransactionServiceProtocolError :: new ( tx_id , e . into ( ) ) ) ? ; let fee = stp . get_fee_amount ( ) . map_err ( | e | TransactionServiceProtocolError :: new ( tx_id , e . into ( ) ) ) ? ; self . submit_transaction ( transaction_broadcast_join_handles , CompletedTransaction :: new ( tx_id , self . resources . node_identity . public_key ( ) . clone ( ) , dest_pubkey . clone ( ) , amount , fee , tx . clone ( ) , TransactionStatus :: Completed , message . clone ( ) , Utc :: now ( ) . naive_utc ( ) , TransactionDirection :: Outbound , None , ) , ) . await ? ; Ok ( tx_id ) }
Sends a one side payment transaction to a recipient
Sends a one side payment transaction to a recipient
&mut self
dest_pubkey
CommsPublicKey
amount
MicroTari
fee_per_gram
MicroTari
message
String
transaction_broadcast_join_handles
&mut FuturesUnordered<
            JoinHandle<Result<u64, TransactionServiceProtocolError>>,
        >
&mut self
dest_pubkey
CommsPublicKey
amount
MicroTari
fee_per_gram
MicroTari
message
String
transaction_broadcast_join_handles
&mut FuturesUnordered<
            JoinHandle<Result<u64, TransactionServiceProtocolError>>,
        >