receipt fixes
This commit is contained in:
		@@ -111,12 +111,12 @@ struct NodeDialInfo {
 | 
			
		||||
##############################
 | 
			
		||||
 | 
			
		||||
struct SignalInfoHolePunch {
 | 
			
		||||
    receiptNonce            @0  :Nonce;                 # receipt to return with hole punch
 | 
			
		||||
    receipt                 @0  :Data;                  # receipt to return with hole punch
 | 
			
		||||
    peerInfo                @1  :PeerInfo;              # peer info of the signal sender for hole punch attempt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct SignalInfoReverseConnect {
 | 
			
		||||
    receiptNonce            @0  :Nonce;                 # receipt to return with reverse connect
 | 
			
		||||
    receipt                 @0  :Data;                  # receipt to return with reverse connect
 | 
			
		||||
    peerInfo                @1  :PeerInfo;              # peer info of the signal sender for reverse connect attempt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -240,15 +240,12 @@ struct OperationStatusA {
 | 
			
		||||
 | 
			
		||||
struct OperationValidateDialInfo {
 | 
			
		||||
    dialInfo                @0  :DialInfo;              # dial info to use for the receipt
 | 
			
		||||
    minVersion              @1  :UInt8;                 # minimum version for the direct receipt
 | 
			
		||||
    maxVersion              @2  :UInt8;                 # maximum version for the direct receipt
 | 
			
		||||
    receiptNonce            @3  :Nonce;                 # receipt to return to dial info to prove it is reachable
 | 
			
		||||
    redirect                @4  :Bool;                  # request a different node do the validate
 | 
			
		||||
    receipt                 @1  :Data;                  # receipt to return to dial info to prove it is reachable
 | 
			
		||||
    redirect                @2  :Bool;                  # request a different node do the validate
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct OperationReturnReceipt {
 | 
			
		||||
    receiptNonce            @0  :Nonce;                 # receipt being returned to its origin
 | 
			
		||||
    extraData               @1  :Data;                  # extra data for receipt
 | 
			
		||||
    receipt                 @0  :Data;                  # receipt being returned to its origin
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct OperationFindNodeQ {    
 | 
			
		||||
 
 | 
			
		||||
@@ -423,41 +423,53 @@ impl NetworkManager {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Generates a multi-shot/normal receipt
 | 
			
		||||
    pub fn generate_receipt(
 | 
			
		||||
    pub fn generate_receipt<D: AsRef<[u8]>>(
 | 
			
		||||
        &self,
 | 
			
		||||
        expiration_us: u64,
 | 
			
		||||
        expected_returns: u32,
 | 
			
		||||
        extra_data: D,
 | 
			
		||||
        callback: impl ReceiptCallback,
 | 
			
		||||
    ) -> Result<ReceiptNonce, String> {
 | 
			
		||||
    ) -> Result<Vec<u8>, String> {
 | 
			
		||||
        let receipt_manager = self.receipt_manager();
 | 
			
		||||
        let routing_table = self.routing_table();
 | 
			
		||||
 | 
			
		||||
        // Generate receipt nonce
 | 
			
		||||
        let receipt_nonce = Crypto::get_random_nonce();
 | 
			
		||||
        // Generate receipt and serialized form to return
 | 
			
		||||
        let nonce = Crypto::get_random_nonce();
 | 
			
		||||
        let receipt = Receipt::try_new(0, nonce, routing_table.node_id(), extra_data)?;
 | 
			
		||||
        let out = receipt
 | 
			
		||||
            .to_signed_data(&routing_table.node_id_secret())
 | 
			
		||||
            .map_err(|_| "failed to generate signed receipt".to_owned())?;
 | 
			
		||||
 | 
			
		||||
        // Record the receipt for later
 | 
			
		||||
        let exp_ts = intf::get_timestamp() + expiration_us;
 | 
			
		||||
        receipt_manager.record_receipt(receipt_nonce, exp_ts, expected_returns, callback);
 | 
			
		||||
        receipt_manager.record_receipt(receipt, exp_ts, expected_returns, callback);
 | 
			
		||||
 | 
			
		||||
        Ok(receipt_nonce)
 | 
			
		||||
        Ok(out)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Generates a single-shot/normal receipt
 | 
			
		||||
    pub fn generate_single_shot_receipt(
 | 
			
		||||
    pub fn generate_single_shot_receipt<D: AsRef<[u8]>>(
 | 
			
		||||
        &self,
 | 
			
		||||
        expiration_us: u64,
 | 
			
		||||
    ) -> Result<(ReceiptNonce, EventualValueFuture<ReceiptEvent>), String> {
 | 
			
		||||
        extra_data: D,
 | 
			
		||||
    ) -> Result<(Vec<u8>, EventualValueFuture<ReceiptEvent>), String> {
 | 
			
		||||
        let receipt_manager = self.receipt_manager();
 | 
			
		||||
        let routing_table = self.routing_table();
 | 
			
		||||
 | 
			
		||||
        // Generate receipt nonce
 | 
			
		||||
        let receipt_nonce = Crypto::get_random_nonce();
 | 
			
		||||
        // Generate receipt and serialized form to return
 | 
			
		||||
        let nonce = Crypto::get_random_nonce();
 | 
			
		||||
        let receipt = Receipt::try_new(0, nonce, routing_table.node_id(), extra_data)?;
 | 
			
		||||
        let out = receipt
 | 
			
		||||
            .to_signed_data(&routing_table.node_id_secret())
 | 
			
		||||
            .map_err(|_| "failed to generate signed receipt".to_owned())?;
 | 
			
		||||
 | 
			
		||||
        // Record the receipt for later
 | 
			
		||||
        let exp_ts = intf::get_timestamp() + expiration_us;
 | 
			
		||||
        let eventual = SingleShotEventual::new(Some(ReceiptEvent::Cancelled));
 | 
			
		||||
        let instance = eventual.instance();
 | 
			
		||||
        receipt_manager.record_single_shot_receipt(receipt_nonce, exp_ts, eventual);
 | 
			
		||||
        receipt_manager.record_single_shot_receipt(receipt, exp_ts, eventual);
 | 
			
		||||
 | 
			
		||||
        Ok((receipt_nonce, instance))
 | 
			
		||||
        Ok((out, instance))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Process a received out-of-band receipt
 | 
			
		||||
@@ -468,34 +480,31 @@ impl NetworkManager {
 | 
			
		||||
        let receipt_manager = self.receipt_manager();
 | 
			
		||||
 | 
			
		||||
        let receipt = Receipt::from_signed_data(receipt_data.as_ref())
 | 
			
		||||
            .map_err(|_| "failed to parse signed receipt".to_owned())?;
 | 
			
		||||
            .map_err(|_| "failed to parse signed out-of-band receipt".to_owned())?;
 | 
			
		||||
 | 
			
		||||
        receipt_manager
 | 
			
		||||
            .handle_receipt(receipt.get_nonce(), receipt.get_extra_data().to_vec(), None)
 | 
			
		||||
            .await
 | 
			
		||||
        receipt_manager.handle_receipt(receipt, None).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Process a received in-band receipt
 | 
			
		||||
    pub async fn handle_in_band_receipt(
 | 
			
		||||
    pub async fn handle_in_band_receipt<R: AsRef<[u8]>>(
 | 
			
		||||
        &self,
 | 
			
		||||
        receipt_nonce: ReceiptNonce,
 | 
			
		||||
        extra_data: Vec<u8>,
 | 
			
		||||
        receipt_data: R,
 | 
			
		||||
        inbound_nr: NodeRef,
 | 
			
		||||
    ) -> Result<(), String> {
 | 
			
		||||
        let receipt_manager = self.receipt_manager();
 | 
			
		||||
 | 
			
		||||
        let receipt = Receipt::from_signed_data(receipt_data.as_ref())
 | 
			
		||||
            .map_err(|_| "failed to parse signed in-band receipt".to_owned())?;
 | 
			
		||||
 | 
			
		||||
        receipt_manager
 | 
			
		||||
            .handle_receipt(receipt_nonce, extra_data, Some(inbound_nr))
 | 
			
		||||
            .handle_receipt(receipt, Some(inbound_nr))
 | 
			
		||||
            .await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Process a received signal
 | 
			
		||||
    pub async fn handle_signal(&self, signal_info: SignalInfo) -> Result<(), String> {
 | 
			
		||||
        match signal_info {
 | 
			
		||||
            SignalInfo::ReverseConnect {
 | 
			
		||||
                receipt_nonce,
 | 
			
		||||
                peer_info,
 | 
			
		||||
            } => {
 | 
			
		||||
            SignalInfo::ReverseConnect { receipt, peer_info } => {
 | 
			
		||||
                let routing_table = self.routing_table();
 | 
			
		||||
                let rpc = self.rpc_processor();
 | 
			
		||||
 | 
			
		||||
@@ -506,14 +515,11 @@ impl NetworkManager {
 | 
			
		||||
                )?;
 | 
			
		||||
 | 
			
		||||
                // Make a reverse connection to the peer and send the receipt to it
 | 
			
		||||
                rpc.rpc_call_return_receipt(Destination::Direct(peer_nr), None, receipt_nonce, [])
 | 
			
		||||
                rpc.rpc_call_return_receipt(Destination::Direct(peer_nr), None, receipt)
 | 
			
		||||
                    .await
 | 
			
		||||
                    .map_err(map_to_string)?;
 | 
			
		||||
            }
 | 
			
		||||
            SignalInfo::HolePunch {
 | 
			
		||||
                receipt_nonce,
 | 
			
		||||
                peer_info,
 | 
			
		||||
            } => {
 | 
			
		||||
            SignalInfo::HolePunch { receipt, peer_info } => {
 | 
			
		||||
                let routing_table = self.routing_table();
 | 
			
		||||
                let rpc = self.rpc_processor();
 | 
			
		||||
 | 
			
		||||
@@ -547,7 +553,7 @@ impl NetworkManager {
 | 
			
		||||
                // XXX: do we need a delay here? or another hole punch packet?
 | 
			
		||||
 | 
			
		||||
                // Return the receipt using the same dial info send the receipt to it
 | 
			
		||||
                rpc.rpc_call_return_receipt(Destination::Direct(peer_nr), None, receipt_nonce, [])
 | 
			
		||||
                rpc.rpc_call_return_receipt(Destination::Direct(peer_nr), None, receipt)
 | 
			
		||||
                    .await
 | 
			
		||||
                    .map_err(map_to_string)?;
 | 
			
		||||
            }
 | 
			
		||||
@@ -634,21 +640,16 @@ impl NetworkManager {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Called by the RPC handler when we want to issue an direct receipt
 | 
			
		||||
    pub async fn send_out_of_band_receipt<D: AsRef<[u8]>>(
 | 
			
		||||
    pub async fn send_out_of_band_receipt(
 | 
			
		||||
        &self,
 | 
			
		||||
        dial_info: DialInfo,
 | 
			
		||||
        version: u8,
 | 
			
		||||
        receipt_nonce: Nonce,
 | 
			
		||||
        extra_data: D,
 | 
			
		||||
        rcpt_data: Vec<u8>,
 | 
			
		||||
    ) -> Result<(), String> {
 | 
			
		||||
        let routing_table = self.routing_table();
 | 
			
		||||
        let node_id = routing_table.node_id();
 | 
			
		||||
        let node_id_secret = routing_table.node_id_secret();
 | 
			
		||||
 | 
			
		||||
        let receipt = Receipt::try_new(version, receipt_nonce, node_id, extra_data)?;
 | 
			
		||||
        let rcpt_data = receipt
 | 
			
		||||
            .to_signed_data(&node_id_secret)
 | 
			
		||||
            .map_err(|_| "failed to sign receipt".to_owned())?;
 | 
			
		||||
        // Do we need to validate the outgoing receipt? Probably not
 | 
			
		||||
        // because it is supposed to be opaque and the
 | 
			
		||||
        // recipient/originator does the validation
 | 
			
		||||
        // Also, in the case of an old 'version', returning the receipt
 | 
			
		||||
        // should not be subject to our ability to decode it
 | 
			
		||||
 | 
			
		||||
        // Send receipt directly
 | 
			
		||||
        self.net()
 | 
			
		||||
@@ -785,8 +786,8 @@ impl NetworkManager {
 | 
			
		||||
        // Build a return receipt for the signal
 | 
			
		||||
        let receipt_timeout =
 | 
			
		||||
            ms_to_us(self.config.get().network.reverse_connection_receipt_time_ms);
 | 
			
		||||
        let (receipt_nonce, eventual_value) = self
 | 
			
		||||
            .generate_single_shot_receipt(receipt_timeout)
 | 
			
		||||
        let (receipt, eventual_value) = self
 | 
			
		||||
            .generate_single_shot_receipt(receipt_timeout, [])
 | 
			
		||||
            .map_err(map_to_string)?;
 | 
			
		||||
 | 
			
		||||
        // Get our peer info
 | 
			
		||||
@@ -797,23 +798,17 @@ impl NetworkManager {
 | 
			
		||||
        rpc.rpc_call_signal(
 | 
			
		||||
            Destination::Relay(relay_nr.clone(), target_nr.node_id()),
 | 
			
		||||
            None,
 | 
			
		||||
            SignalInfo::ReverseConnect {
 | 
			
		||||
                receipt_nonce,
 | 
			
		||||
                peer_info,
 | 
			
		||||
            },
 | 
			
		||||
            SignalInfo::ReverseConnect { receipt, peer_info },
 | 
			
		||||
        )
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(logthru_net!("failed to send signal to {:?}", relay_nr))
 | 
			
		||||
        .map_err(map_to_string)?;
 | 
			
		||||
        // Wait for the return receipt
 | 
			
		||||
        let inbound_nr = match eventual_value.await.take_value().unwrap() {
 | 
			
		||||
            ReceiptEvent::ReturnedOutOfBand { extra_data: _ } => {
 | 
			
		||||
            ReceiptEvent::ReturnedOutOfBand => {
 | 
			
		||||
                return Err("reverse connect receipt should be returned in-band".to_owned());
 | 
			
		||||
            }
 | 
			
		||||
            ReceiptEvent::ReturnedInBand {
 | 
			
		||||
                inbound_noderef,
 | 
			
		||||
                extra_data: _,
 | 
			
		||||
            } => inbound_noderef,
 | 
			
		||||
            ReceiptEvent::ReturnedInBand { inbound_noderef } => inbound_noderef,
 | 
			
		||||
            ReceiptEvent::Expired => {
 | 
			
		||||
                return Err(format!(
 | 
			
		||||
                    "reverse connect receipt expired from {:?}",
 | 
			
		||||
@@ -871,8 +866,8 @@ impl NetworkManager {
 | 
			
		||||
        // Build a return receipt for the signal
 | 
			
		||||
        let receipt_timeout =
 | 
			
		||||
            ms_to_us(self.config.get().network.reverse_connection_receipt_time_ms);
 | 
			
		||||
        let (receipt_nonce, eventual_value) = self
 | 
			
		||||
            .generate_single_shot_receipt(receipt_timeout)
 | 
			
		||||
        let (receipt, eventual_value) = self
 | 
			
		||||
            .generate_single_shot_receipt(receipt_timeout, [])
 | 
			
		||||
            .map_err(map_to_string)?;
 | 
			
		||||
 | 
			
		||||
        // Get our peer info
 | 
			
		||||
@@ -894,10 +889,7 @@ impl NetworkManager {
 | 
			
		||||
        rpc.rpc_call_signal(
 | 
			
		||||
            Destination::Relay(relay_nr.clone(), target_nr.node_id()),
 | 
			
		||||
            None,
 | 
			
		||||
            SignalInfo::HolePunch {
 | 
			
		||||
                receipt_nonce,
 | 
			
		||||
                peer_info,
 | 
			
		||||
            },
 | 
			
		||||
            SignalInfo::HolePunch { receipt, peer_info },
 | 
			
		||||
        )
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(logthru_net!("failed to send signal to {:?}", relay_nr))
 | 
			
		||||
@@ -905,13 +897,10 @@ impl NetworkManager {
 | 
			
		||||
 | 
			
		||||
        // Wait for the return receipt
 | 
			
		||||
        let inbound_nr = match eventual_value.await.take_value().unwrap() {
 | 
			
		||||
            ReceiptEvent::ReturnedOutOfBand { extra_data: _ } => {
 | 
			
		||||
            ReceiptEvent::ReturnedOutOfBand => {
 | 
			
		||||
                return Err("hole punch receipt should be returned in-band".to_owned());
 | 
			
		||||
            }
 | 
			
		||||
            ReceiptEvent::ReturnedInBand {
 | 
			
		||||
                inbound_noderef,
 | 
			
		||||
                extra_data: _,
 | 
			
		||||
            } => inbound_noderef,
 | 
			
		||||
            ReceiptEvent::ReturnedInBand { inbound_noderef } => inbound_noderef,
 | 
			
		||||
            ReceiptEvent::Expired => {
 | 
			
		||||
                return Err(format!("hole punch receipt expired from {}", target_nr));
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -8,13 +8,8 @@ use xx::*;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug, PartialEq, Eq)]
 | 
			
		||||
pub enum ReceiptEvent {
 | 
			
		||||
    ReturnedOutOfBand {
 | 
			
		||||
        extra_data: Vec<u8>,
 | 
			
		||||
    },
 | 
			
		||||
    ReturnedInBand {
 | 
			
		||||
        inbound_noderef: NodeRef,
 | 
			
		||||
        extra_data: Vec<u8>,
 | 
			
		||||
    },
 | 
			
		||||
    ReturnedOutOfBand,
 | 
			
		||||
    ReturnedInBand { inbound_noderef: NodeRef },
 | 
			
		||||
    Expired,
 | 
			
		||||
    Cancelled,
 | 
			
		||||
}
 | 
			
		||||
@@ -25,24 +20,24 @@ cfg_if! {
 | 
			
		||||
            fn call(
 | 
			
		||||
                &self,
 | 
			
		||||
                event: ReceiptEvent,
 | 
			
		||||
                nonce: ReceiptNonce,
 | 
			
		||||
                receipt: Receipt,
 | 
			
		||||
                returns_so_far: u32,
 | 
			
		||||
                expected_returns: u32,
 | 
			
		||||
            ) -> SystemPinBoxFuture<()>;
 | 
			
		||||
        }
 | 
			
		||||
        impl<T, F> ReceiptCallback for T
 | 
			
		||||
        where
 | 
			
		||||
            T: Fn(ReceiptEvent, ReceiptNonce, u32, u32) -> F + 'static,
 | 
			
		||||
            T: Fn(ReceiptEvent, Receipt, u32, u32) -> F + 'static,
 | 
			
		||||
            F: Future<Output = ()> + 'static,
 | 
			
		||||
        {
 | 
			
		||||
            fn call(
 | 
			
		||||
                &self,
 | 
			
		||||
                event: ReceiptEvent,
 | 
			
		||||
                nonce: ReceiptNonce,
 | 
			
		||||
                receipt: Receipt,
 | 
			
		||||
                returns_so_far: u32,
 | 
			
		||||
                expected_returns: u32,
 | 
			
		||||
            ) -> SystemPinBoxFuture<()> {
 | 
			
		||||
                Box::pin(self(event, nonce, returns_so_far, expected_returns))
 | 
			
		||||
                Box::pin(self(event, receipt, returns_so_far, expected_returns))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
@@ -50,24 +45,24 @@ cfg_if! {
 | 
			
		||||
            fn call(
 | 
			
		||||
                &self,
 | 
			
		||||
                event: ReceiptEvent,
 | 
			
		||||
                nonce: ReceiptNonce,
 | 
			
		||||
                receipt: Receipt,
 | 
			
		||||
                returns_so_far: u32,
 | 
			
		||||
                expected_returns: u32,
 | 
			
		||||
            ) -> SystemPinBoxFuture<()>;
 | 
			
		||||
        }
 | 
			
		||||
        impl<F, T> ReceiptCallback for T
 | 
			
		||||
        where
 | 
			
		||||
            T: Fn(ReceiptEvent, ReceiptNonce, u32, u32) -> F + Send + 'static,
 | 
			
		||||
            T: Fn(ReceiptEvent, Receipt, u32, u32) -> F + Send + 'static,
 | 
			
		||||
            F: Future<Output = ()> + Send + 'static
 | 
			
		||||
        {
 | 
			
		||||
            fn call(
 | 
			
		||||
                &self,
 | 
			
		||||
                event: ReceiptEvent,
 | 
			
		||||
                nonce: ReceiptNonce,
 | 
			
		||||
                receipt: Receipt,
 | 
			
		||||
                returns_so_far: u32,
 | 
			
		||||
                expected_returns: u32,
 | 
			
		||||
            ) -> SystemPinBoxFuture<()> {
 | 
			
		||||
                Box::pin(self(event, nonce, returns_so_far, expected_returns))
 | 
			
		||||
                Box::pin(self(event, receipt, returns_so_far, expected_returns))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -95,7 +90,7 @@ impl fmt::Debug for ReceiptRecordCallbackType {
 | 
			
		||||
 | 
			
		||||
pub struct ReceiptRecord {
 | 
			
		||||
    expiration_ts: u64,
 | 
			
		||||
    nonce: ReceiptNonce,
 | 
			
		||||
    receipt: Receipt,
 | 
			
		||||
    expected_returns: u32,
 | 
			
		||||
    returns_so_far: u32,
 | 
			
		||||
    receipt_callback: ReceiptRecordCallbackType,
 | 
			
		||||
@@ -105,7 +100,7 @@ impl fmt::Debug for ReceiptRecord {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        f.debug_struct("ReceiptRecord")
 | 
			
		||||
            .field("expiration_ts", &self.expiration_ts)
 | 
			
		||||
            .field("nonce", &self.nonce)
 | 
			
		||||
            .field("receipt", &self.receipt)
 | 
			
		||||
            .field("expected_returns", &self.expected_returns)
 | 
			
		||||
            .field("returns_so_far", &self.returns_so_far)
 | 
			
		||||
            .field("receipt_callback", &self.receipt_callback)
 | 
			
		||||
@@ -115,14 +110,14 @@ impl fmt::Debug for ReceiptRecord {
 | 
			
		||||
 | 
			
		||||
impl ReceiptRecord {
 | 
			
		||||
    pub fn new(
 | 
			
		||||
        receipt_nonce: ReceiptNonce,
 | 
			
		||||
        receipt: Receipt,
 | 
			
		||||
        expiration_ts: u64,
 | 
			
		||||
        expected_returns: u32,
 | 
			
		||||
        receipt_callback: impl ReceiptCallback,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            expiration_ts,
 | 
			
		||||
            nonce: receipt_nonce,
 | 
			
		||||
            receipt,
 | 
			
		||||
            expected_returns,
 | 
			
		||||
            returns_so_far: 0u32,
 | 
			
		||||
            receipt_callback: ReceiptRecordCallbackType::Normal(Box::new(receipt_callback)),
 | 
			
		||||
@@ -130,13 +125,13 @@ impl ReceiptRecord {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_single_shot(
 | 
			
		||||
        receipt_nonce: ReceiptNonce,
 | 
			
		||||
        receipt: Receipt,
 | 
			
		||||
        expiration_ts: u64,
 | 
			
		||||
        eventual: ReceiptSingleShotType,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            expiration_ts,
 | 
			
		||||
            nonce: receipt_nonce,
 | 
			
		||||
            receipt,
 | 
			
		||||
            returns_so_far: 0u32,
 | 
			
		||||
            expected_returns: 1u32,
 | 
			
		||||
            receipt_callback: ReceiptRecordCallbackType::SingleShot(Some(eventual)),
 | 
			
		||||
@@ -223,7 +218,7 @@ impl ReceiptManager {
 | 
			
		||||
        match &mut record_mut.receipt_callback {
 | 
			
		||||
            ReceiptRecordCallbackType::Normal(callback) => Some(callback.call(
 | 
			
		||||
                evt,
 | 
			
		||||
                record_mut.nonce,
 | 
			
		||||
                record_mut.receipt.clone(),
 | 
			
		||||
                record_mut.returns_so_far,
 | 
			
		||||
                record_mut.expected_returns,
 | 
			
		||||
            )),
 | 
			
		||||
@@ -308,14 +303,15 @@ impl ReceiptManager {
 | 
			
		||||
 | 
			
		||||
    pub fn record_receipt(
 | 
			
		||||
        &self,
 | 
			
		||||
        receipt_nonce: ReceiptNonce,
 | 
			
		||||
        receipt: Receipt,
 | 
			
		||||
        expiration: u64,
 | 
			
		||||
        expected_returns: u32,
 | 
			
		||||
        callback: impl ReceiptCallback,
 | 
			
		||||
    ) {
 | 
			
		||||
        let receipt_nonce = receipt.get_nonce();
 | 
			
		||||
        log_rpc!(debug "== New Multiple Receipt ({}) {} ", expected_returns, receipt_nonce.encode());
 | 
			
		||||
        let record = Arc::new(Mutex::new(ReceiptRecord::new(
 | 
			
		||||
            receipt_nonce,
 | 
			
		||||
            receipt,
 | 
			
		||||
            expiration,
 | 
			
		||||
            expected_returns,
 | 
			
		||||
            callback,
 | 
			
		||||
@@ -328,16 +324,15 @@ impl ReceiptManager {
 | 
			
		||||
 | 
			
		||||
    pub fn record_single_shot_receipt(
 | 
			
		||||
        &self,
 | 
			
		||||
        receipt_nonce: ReceiptNonce,
 | 
			
		||||
        receipt: Receipt,
 | 
			
		||||
        expiration: u64,
 | 
			
		||||
        eventual: ReceiptSingleShotType,
 | 
			
		||||
    ) {
 | 
			
		||||
        let receipt_nonce = receipt.get_nonce();
 | 
			
		||||
        log_rpc!(debug "== New SingleShot Receipt {}", receipt_nonce.encode());
 | 
			
		||||
 | 
			
		||||
        let record = Arc::new(Mutex::new(ReceiptRecord::new_single_shot(
 | 
			
		||||
            receipt_nonce,
 | 
			
		||||
            expiration,
 | 
			
		||||
            eventual,
 | 
			
		||||
            receipt, expiration, eventual,
 | 
			
		||||
        )));
 | 
			
		||||
        let mut inner = self.inner.lock();
 | 
			
		||||
        inner.records_by_nonce.insert(receipt_nonce, record);
 | 
			
		||||
@@ -393,10 +388,12 @@ impl ReceiptManager {
 | 
			
		||||
 | 
			
		||||
    pub async fn handle_receipt(
 | 
			
		||||
        &self,
 | 
			
		||||
        receipt_nonce: ReceiptNonce,
 | 
			
		||||
        extra_data: Vec<u8>,
 | 
			
		||||
        receipt: Receipt,
 | 
			
		||||
        inbound_noderef: Option<NodeRef>,
 | 
			
		||||
    ) -> Result<(), String> {
 | 
			
		||||
        let receipt_nonce = receipt.get_nonce();
 | 
			
		||||
        let extra_data = receipt.get_extra_data();
 | 
			
		||||
 | 
			
		||||
        log_rpc!(debug "<<== RECEIPT {} <- {}{}",
 | 
			
		||||
            receipt_nonce.encode(),
 | 
			
		||||
            if let Some(nr) = &inbound_noderef {
 | 
			
		||||
@@ -427,12 +424,9 @@ impl ReceiptManager {
 | 
			
		||||
 | 
			
		||||
            // Get the receipt event to return
 | 
			
		||||
            let receipt_event = if let Some(inbound_noderef) = inbound_noderef {
 | 
			
		||||
                ReceiptEvent::ReturnedInBand {
 | 
			
		||||
                    inbound_noderef,
 | 
			
		||||
                    extra_data,
 | 
			
		||||
                }
 | 
			
		||||
                ReceiptEvent::ReturnedInBand { inbound_noderef }
 | 
			
		||||
            } else {
 | 
			
		||||
                ReceiptEvent::ReturnedOutOfBand { extra_data }
 | 
			
		||||
                ReceiptEvent::ReturnedOutOfBand
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let callback_future = Self::perform_callback(receipt_event, &mut record_mut);
 | 
			
		||||
 
 | 
			
		||||
@@ -6,23 +6,25 @@ pub fn encode_signal_info(
 | 
			
		||||
    builder: &mut veilid_capnp::operation_signal::Builder,
 | 
			
		||||
) -> Result<(), RPCError> {
 | 
			
		||||
    match signal_info {
 | 
			
		||||
        SignalInfo::HolePunch {
 | 
			
		||||
            receipt_nonce,
 | 
			
		||||
            peer_info,
 | 
			
		||||
        } => {
 | 
			
		||||
        SignalInfo::HolePunch { receipt, peer_info } => {
 | 
			
		||||
            let mut hp_builder = builder.reborrow().init_hole_punch();
 | 
			
		||||
            let mut rn_builder = hp_builder.reborrow().init_receipt_nonce();
 | 
			
		||||
            encode_nonce(receipt_nonce, &mut rn_builder);
 | 
			
		||||
            let r_builder = hp_builder
 | 
			
		||||
                .reborrow()
 | 
			
		||||
                .init_receipt(receipt.len().try_into().map_err(map_error_protocol!(
 | 
			
		||||
                    "invalid receipt length in encode_signal_info"
 | 
			
		||||
                ))?);
 | 
			
		||||
            r_builder.copy_from_slice(receipt);
 | 
			
		||||
            let mut pi_builder = hp_builder.init_peer_info();
 | 
			
		||||
            encode_peer_info(peer_info, &mut pi_builder)?;
 | 
			
		||||
        }
 | 
			
		||||
        SignalInfo::ReverseConnect {
 | 
			
		||||
            receipt_nonce,
 | 
			
		||||
            peer_info,
 | 
			
		||||
        } => {
 | 
			
		||||
        SignalInfo::ReverseConnect { receipt, peer_info } => {
 | 
			
		||||
            let mut rc_builder = builder.reborrow().init_reverse_connect();
 | 
			
		||||
            let mut rn_builder = rc_builder.reborrow().init_receipt_nonce();
 | 
			
		||||
            encode_nonce(receipt_nonce, &mut rn_builder);
 | 
			
		||||
            let r_builder = rc_builder
 | 
			
		||||
                .reborrow()
 | 
			
		||||
                .init_receipt(receipt.len().try_into().map_err(map_error_protocol!(
 | 
			
		||||
                    "invalid receipt length in encode_signal_info"
 | 
			
		||||
                ))?);
 | 
			
		||||
            r_builder.copy_from_slice(receipt);
 | 
			
		||||
            let mut pi_builder = rc_builder.init_peer_info();
 | 
			
		||||
            encode_peer_info(peer_info, &mut pi_builder)?;
 | 
			
		||||
        }
 | 
			
		||||
@@ -45,17 +47,18 @@ pub fn decode_signal_info(
 | 
			
		||||
                    Ok(r) => r,
 | 
			
		||||
                    Err(_) => return Err(rpc_error_internal("invalid hole punch")),
 | 
			
		||||
                };
 | 
			
		||||
                let receipt_nonce =
 | 
			
		||||
                    decode_nonce(&r.get_receipt_nonce().map_err(map_error_capnp_error!())?);
 | 
			
		||||
                let receipt = r
 | 
			
		||||
                    .get_receipt()
 | 
			
		||||
                    .map_err(map_error_protocol!(
 | 
			
		||||
                        "invalid receipt in hole punch signal info"
 | 
			
		||||
                    ))?
 | 
			
		||||
                    .to_vec();
 | 
			
		||||
                let pi_reader = r.get_peer_info().map_err(map_error_protocol!(
 | 
			
		||||
                    "invalid peer info in hole punch signal info"
 | 
			
		||||
                ))?;
 | 
			
		||||
                let peer_info = decode_peer_info(&pi_reader, true)?;
 | 
			
		||||
 | 
			
		||||
                SignalInfo::HolePunch {
 | 
			
		||||
                    receipt_nonce,
 | 
			
		||||
                    peer_info,
 | 
			
		||||
                }
 | 
			
		||||
                SignalInfo::HolePunch { receipt, peer_info }
 | 
			
		||||
            }
 | 
			
		||||
            veilid_capnp::operation_signal::ReverseConnect(r) => {
 | 
			
		||||
                // Extract reverse connect reader
 | 
			
		||||
@@ -63,17 +66,18 @@ pub fn decode_signal_info(
 | 
			
		||||
                    Ok(r) => r,
 | 
			
		||||
                    Err(_) => return Err(rpc_error_internal("invalid reverse connect")),
 | 
			
		||||
                };
 | 
			
		||||
                let receipt_nonce =
 | 
			
		||||
                    decode_nonce(&r.get_receipt_nonce().map_err(map_error_capnp_error!())?);
 | 
			
		||||
                let receipt = r
 | 
			
		||||
                    .get_receipt()
 | 
			
		||||
                    .map_err(map_error_protocol!(
 | 
			
		||||
                        "invalid receipt in hole punch signal info"
 | 
			
		||||
                    ))?
 | 
			
		||||
                    .to_vec();
 | 
			
		||||
                let pi_reader = r.get_peer_info().map_err(map_error_protocol!(
 | 
			
		||||
                    "invalid peer info in reverse connect signal info"
 | 
			
		||||
                ))?;
 | 
			
		||||
                let peer_info = decode_peer_info(&pi_reader, true)?;
 | 
			
		||||
 | 
			
		||||
                SignalInfo::ReverseConnect {
 | 
			
		||||
                    receipt_nonce,
 | 
			
		||||
                    peer_info,
 | 
			
		||||
                }
 | 
			
		||||
                SignalInfo::ReverseConnect { receipt, peer_info }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -872,7 +872,7 @@ impl RPCProcessor {
 | 
			
		||||
        rpcreader: RPCMessageReader,
 | 
			
		||||
    ) -> Result<(), RPCError> {
 | 
			
		||||
        //
 | 
			
		||||
        let (redirect, dial_info, receipt_nonce, min_version, max_version) = {
 | 
			
		||||
        let (redirect, dial_info, receipt) = {
 | 
			
		||||
            let operation = rpcreader
 | 
			
		||||
                .reader
 | 
			
		||||
                .get_root::<veilid_capnp::operation::Reader>()
 | 
			
		||||
@@ -893,20 +893,17 @@ impl RPCProcessor {
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // Parse out fields
 | 
			
		||||
            let min_version = vdi_reader.get_min_version();
 | 
			
		||||
            let max_version = vdi_reader.get_max_version();
 | 
			
		||||
            let redirect = vdi_reader.get_redirect();
 | 
			
		||||
            let dial_info = decode_dial_info(
 | 
			
		||||
                &vdi_reader
 | 
			
		||||
                    .get_dial_info()
 | 
			
		||||
                    .map_err(map_error_internal!("no valid dial info"))?,
 | 
			
		||||
                    .map_err(map_error_internal!("no valid dial info in process_validate_dial_info"))?,
 | 
			
		||||
            )?;
 | 
			
		||||
            let rn_reader = vdi_reader
 | 
			
		||||
                .get_receipt_nonce()
 | 
			
		||||
                .map_err(map_error_internal!("no valid receipt nonce"))?;
 | 
			
		||||
            let receipt_nonce = decode_nonce(&rn_reader);
 | 
			
		||||
            let receipt = vdi_reader
 | 
			
		||||
                .get_receipt()
 | 
			
		||||
                .map_err(map_error_internal!("no valid receipt in process_validate_dial_info"))?.to_vec();
 | 
			
		||||
 | 
			
		||||
            (redirect, dial_info, receipt_nonce, min_version, max_version)
 | 
			
		||||
            (redirect, dial_info, receipt)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Redirect this request if we are asked to
 | 
			
		||||
@@ -949,12 +946,12 @@ impl RPCProcessor {
 | 
			
		||||
                    let detail = question.reborrow().init_detail();
 | 
			
		||||
                    let mut vdi_builder = detail.init_validate_dial_info();
 | 
			
		||||
                    vdi_builder.set_redirect(false);
 | 
			
		||||
                    vdi_builder.set_min_version(min_version);
 | 
			
		||||
                    vdi_builder.set_max_version(max_version);
 | 
			
		||||
                    let mut di_builder = vdi_builder.reborrow().init_dial_info();
 | 
			
		||||
                    encode_dial_info(&dial_info, &mut di_builder)?;
 | 
			
		||||
                    let mut rn_builder = vdi_builder.reborrow().init_receipt_nonce();
 | 
			
		||||
                    encode_nonce(&receipt_nonce, &mut rn_builder);
 | 
			
		||||
                    let r_builder = vdi_builder.init_receipt(receipt.len().try_into().map_err(
 | 
			
		||||
                        map_error_protocol!("invalid receipt length in process_validate_dial_info"),
 | 
			
		||||
                    )?);
 | 
			
		||||
                    r_builder.copy_from_slice(&receipt);
 | 
			
		||||
                    vdi_msg.into_reader()
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
@@ -967,25 +964,13 @@ impl RPCProcessor {
 | 
			
		||||
 | 
			
		||||
        // Otherwise send a return receipt directly
 | 
			
		||||
        // Possibly from an alternate port
 | 
			
		||||
        let version = {
 | 
			
		||||
            #[allow(clippy::absurd_extreme_comparisons)]
 | 
			
		||||
            if min_version > MAX_VERSION || max_version < MIN_VERSION {
 | 
			
		||||
                return Err(rpc_error_protocol(format!(
 | 
			
		||||
                    "can't send direct receipt to {} because version is unsupported: ({},{})",
 | 
			
		||||
                    dial_info, min_version, max_version
 | 
			
		||||
                )))
 | 
			
		||||
                .map_err(
 | 
			
		||||
                    logthru_rpc!(debug)); 
 | 
			
		||||
            }
 | 
			
		||||
            cmp::min(max_version, MAX_VERSION)
 | 
			
		||||
        };
 | 
			
		||||
        let network_manager = self.network_manager();
 | 
			
		||||
        network_manager
 | 
			
		||||
            .send_out_of_band_receipt(dial_info.clone(), version, receipt_nonce, [])
 | 
			
		||||
            .send_out_of_band_receipt(dial_info.clone(), receipt)
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(map_error_string!())
 | 
			
		||||
            .map_err(
 | 
			
		||||
                logthru_net!(error "failed to send direct receipt to dial info: {}, version={}", dial_info, version),
 | 
			
		||||
                logthru_net!(error "failed to send direct receipt to dial info: {}", dial_info),
 | 
			
		||||
            )?;
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
@@ -1166,7 +1151,7 @@ impl RPCProcessor {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn process_return_receipt(&self, rpcreader: RPCMessageReader) -> Result<(), RPCError> {
 | 
			
		||||
        let (receipt_nonce, extra_data) = {
 | 
			
		||||
        let receipt = {
 | 
			
		||||
            let operation = rpcreader
 | 
			
		||||
                .reader
 | 
			
		||||
                .get_root::<veilid_capnp::operation::Reader>()
 | 
			
		||||
@@ -1186,24 +1171,16 @@ impl RPCProcessor {
 | 
			
		||||
                _ => panic!("invalid operation type in process_return_receipt"),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // Get receipt nonce
 | 
			
		||||
            let rn_reader = rr_reader
 | 
			
		||||
                .get_receipt_nonce()
 | 
			
		||||
                .map_err(map_error_internal!("no valid receipt_nonce"))?;
 | 
			
		||||
            let receipt_nonce = decode_nonce(&rn_reader);
 | 
			
		||||
 | 
			
		||||
            // Get receipt extra data
 | 
			
		||||
            let extra_data = rr_reader
 | 
			
		||||
                .get_extra_data()
 | 
			
		||||
                .map_err(map_error_internal!("no valid extra data"))?;
 | 
			
		||||
 | 
			
		||||
            (receipt_nonce, extra_data.to_vec())
 | 
			
		||||
            // Get receipt
 | 
			
		||||
            rr_reader
 | 
			
		||||
                .get_receipt()
 | 
			
		||||
                .map_err(map_error_internal!("no valid receipt in process_return_receipt"))?.to_vec()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Handle it
 | 
			
		||||
        let network_manager = self.network_manager();
 | 
			
		||||
        network_manager
 | 
			
		||||
            .handle_in_band_receipt(receipt_nonce, extra_data, rpcreader.header.peer_noderef)
 | 
			
		||||
            .handle_in_band_receipt(receipt, rpcreader.header.peer_noderef)
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(map_error_string!())
 | 
			
		||||
    }
 | 
			
		||||
@@ -1602,17 +1579,17 @@ impl RPCProcessor {
 | 
			
		||||
            let mut vdi_builder = detail.init_validate_dial_info();
 | 
			
		||||
 | 
			
		||||
            // Generate receipt and waitable eventual so we can see if we get the receipt back
 | 
			
		||||
            let (receipt_nonce, eventual_value) = network_manager
 | 
			
		||||
                .generate_single_shot_receipt(receipt_time)
 | 
			
		||||
            let (receipt, eventual_value) = network_manager
 | 
			
		||||
                .generate_single_shot_receipt(receipt_time, [])
 | 
			
		||||
                .map_err(map_error_string!())?;
 | 
			
		||||
 | 
			
		||||
            vdi_builder.set_redirect(redirect);
 | 
			
		||||
            vdi_builder.set_min_version(MIN_VERSION);
 | 
			
		||||
            vdi_builder.set_max_version(MAX_VERSION);
 | 
			
		||||
            let mut di_builder = vdi_builder.reborrow().init_dial_info();
 | 
			
		||||
            encode_dial_info(&dial_info, &mut di_builder)?;
 | 
			
		||||
            let mut rn_builder = vdi_builder.reborrow().init_receipt_nonce();
 | 
			
		||||
            encode_nonce(&receipt_nonce, &mut rn_builder);
 | 
			
		||||
            let r_builder = vdi_builder.init_receipt(receipt.len().try_into().map_err(
 | 
			
		||||
                map_error_protocol!("invalid receipt length in validate dial info"),
 | 
			
		||||
            )?);
 | 
			
		||||
            r_builder.copy_from_slice(&receipt);
 | 
			
		||||
            
 | 
			
		||||
            (vdi_msg.into_reader(), eventual_value)
 | 
			
		||||
        };
 | 
			
		||||
@@ -1627,13 +1604,10 @@ impl RPCProcessor {
 | 
			
		||||
        match eventual_value.await.take_value().unwrap() {
 | 
			
		||||
            ReceiptEvent::ReturnedInBand {
 | 
			
		||||
                inbound_noderef: _,
 | 
			
		||||
                extra_data:_
 | 
			
		||||
            } => {
 | 
			
		||||
                Err(rpc_error_internal("validate_dial_info receipt should be returned out-of-band"))
 | 
			
		||||
            }
 | 
			
		||||
            ReceiptEvent::ReturnedOutOfBand {
 | 
			
		||||
                extra_data:_
 | 
			
		||||
            } => {
 | 
			
		||||
            ReceiptEvent::ReturnedOutOfBand => {
 | 
			
		||||
                log_net!(debug "validate_dial_info receipt returned");
 | 
			
		||||
                Ok(true)
 | 
			
		||||
            }
 | 
			
		||||
@@ -1779,14 +1753,13 @@ impl RPCProcessor {
 | 
			
		||||
 | 
			
		||||
    // Sends a unidirectional in-band return receipt
 | 
			
		||||
    // Can be sent via all methods including relays and routes
 | 
			
		||||
    pub async fn rpc_call_return_receipt<B: AsRef<[u8]>>(
 | 
			
		||||
    pub async fn rpc_call_return_receipt<D: AsRef<[u8]>>(
 | 
			
		||||
        &self,
 | 
			
		||||
        dest: Destination,
 | 
			
		||||
        safety_route: Option<&SafetyRouteSpec>,
 | 
			
		||||
        receipt_nonce: Nonce,
 | 
			
		||||
        extra_data: B,
 | 
			
		||||
        receipt: D,
 | 
			
		||||
    ) -> Result<(), RPCError> {        
 | 
			
		||||
        let extra_data = extra_data.as_ref();
 | 
			
		||||
        let receipt = receipt.as_ref();
 | 
			
		||||
 | 
			
		||||
        let rr_msg = {
 | 
			
		||||
            let mut rr_msg = ::capnp::message::Builder::new_default();
 | 
			
		||||
@@ -1795,13 +1768,11 @@ impl RPCProcessor {
 | 
			
		||||
            let mut respond_to = question.reborrow().init_respond_to();
 | 
			
		||||
            respond_to.set_none(());
 | 
			
		||||
            let detail = question.reborrow().init_detail();
 | 
			
		||||
            let mut rr_builder = detail.init_return_receipt();
 | 
			
		||||
            let mut rn_builder = rr_builder.reborrow().init_receipt_nonce();
 | 
			
		||||
            encode_nonce(&receipt_nonce, &mut rn_builder);
 | 
			
		||||
            let ed_builder = rr_builder.init_extra_data(extra_data.len().try_into().map_err(
 | 
			
		||||
                map_error_protocol!("invalid extra data length in return receipt"),
 | 
			
		||||
            let rr_builder = detail.init_return_receipt();
 | 
			
		||||
            let r_builder = rr_builder.init_receipt(receipt.len().try_into().map_err(
 | 
			
		||||
                map_error_protocol!("invalid receipt length in return receipt"),
 | 
			
		||||
            )?);
 | 
			
		||||
            ed_builder.copy_from_slice(extra_data);
 | 
			
		||||
            r_builder.copy_from_slice(receipt);
 | 
			
		||||
 | 
			
		||||
            rr_msg.into_reader()
 | 
			
		||||
        };
 | 
			
		||||
 
 | 
			
		||||
@@ -1482,13 +1482,13 @@ cfg_if! {
 | 
			
		||||
pub enum SignalInfo {
 | 
			
		||||
    HolePunch {
 | 
			
		||||
        // UDP Hole Punch Request
 | 
			
		||||
        receipt_nonce: ReceiptNonce, // Receipt to be returned after the hole punch
 | 
			
		||||
        peer_info: PeerInfo,         // Sender's peer info
 | 
			
		||||
        receipt: Vec<u8>,    // Receipt to be returned after the hole punch
 | 
			
		||||
        peer_info: PeerInfo, // Sender's peer info
 | 
			
		||||
    },
 | 
			
		||||
    ReverseConnect {
 | 
			
		||||
        // Reverse Connection Request
 | 
			
		||||
        receipt_nonce: ReceiptNonce, // Receipt to be returned by the reverse connection
 | 
			
		||||
        peer_info: PeerInfo,         // Sender's peer info
 | 
			
		||||
        receipt: Vec<u8>,    // Receipt to be returned by the reverse connection
 | 
			
		||||
        peer_info: PeerInfo, // Sender's peer info
 | 
			
		||||
    },
 | 
			
		||||
    // XXX: WebRTC
 | 
			
		||||
    // XXX: App-level signalling
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user