fn add_payment_with_timestamp(
        &mut self,
        memo: Memo,
        payment: Operation,
        created_at_time: Option<TimeStamp>,
        now: TimeStamp,
    ) -> Result<(BlockHeight, HashOf<EncodedBlock>), PaymentError> {
        let num_pruned = self.purge_old_transactions(now);

        let created_at_time = created_at_time.unwrap_or(now);

        if created_at_time + self.transaction_window < now {
            return Err(PaymentError::TransferError(TransferError::TxTooOld {
                allowed_window_nanos: self.transaction_window.as_nanos() as u64,
            }));
        }

        if created_at_time > now + ic_types::ingress::PERMITTED_DRIFT {
            return Err(PaymentError::TransferError(
                TransferError::TxCreatedInFuture,
            ));
        }

        // If we pruned some transactions, let this one through
        // otherwise throttle if there are too many
        if num_pruned == 0 && self.throttle(now) {
            return Err(PaymentError::Reject("Too many transactions in replay prevention window, ledger is throttling, please retry later".to_string()));
        }

        let transaction = Transaction {
            operation: payment.clone(),
            memo,
            created_at_time,
        };

        let transaction_hash = transaction.hash();

        if let Some(block_height) = self.transactions_by_hash.get(&transaction_hash) {
            return Err(PaymentError::TransferError(TransferError::TxDuplicate {
                duplicate_of: *block_height,
            }));
        }

        let block = Block::new_from_transaction(self.blockchain.last_hash, transaction, now);
        let block_timestamp = block.timestamp;

        self.balances.add_payment(&payment).map_err(|e| match e {
            BalanceError::InsufficientFunds { balance } => {
                PaymentError::TransferError(TransferError::InsufficientFunds { balance })
            }
        })?;

        let height = self
            .blockchain
            .add_block(block)
            .expect("failed to add block");

        self.transactions_by_hash.insert(transaction_hash, height);
        self.transactions_by_height.push_back(TransactionInfo {
            block_timestamp,
            transaction_hash,
        });

        let to_trim = if self.balances.store.len()
            >= self.maximum_number_of_accounts + self.accounts_overflow_trim_quantity
        {
            self.balances
                .select_accounts_to_trim(self.accounts_overflow_trim_quantity)
        } else {
            vec![]
        };

        for (balance, account) in to_trim {
            let operation = Operation::Burn {
                from: account,
                amount: balance,
            };
            self.balances
                .add_payment(&operation)
                .expect("failed to burn funds that must have existed");
            self.blockchain
                .add_block(Block::new_from_transaction(
                    self.blockchain.last_hash,
                    Transaction {
                        operation,
                        memo: Memo::default(),
                        created_at_time: now,
                    },
                    now,
                ))
                .unwrap();
        }

        Ok((height, self.blockchain.last_hash.unwrap()))
    }
/// Internal version of `add_payment` that takes a timestamp, for
/// testing.
Internal version of `add_payment` that takes a timestamp, for
testing.
Internal version of ` add_payment ` that takes a timestamp for testing .
fn add_payment_with_timestamp(
        &mut self,
        memo: Memo,
        payment: Operation,
        created_at_time: Option<TimeStamp>,
        now: TimeStamp,
    ) -> Result<(BlockHeight, HashOf<EncodedBlock>), PaymentError> {
        let num_pruned = self.purge_old_transactions(now);
        let created_at_time = created_at_time.unwrap_or(now);
        if created_at_time + self.transaction_window < now {
            return Err(PaymentError::TransferError(TransferError::TxTooOld {
                allowed_window_nanos: self.transaction_window.as_nanos() as u64,
            }));
        }
        if created_at_time > now + ic_types::ingress::PERMITTED_DRIFT {
            return Err(PaymentError::TransferError(
                TransferError::TxCreatedInFuture,
            ));
        }
        // If we pruned some transactions, let this one through
        // otherwise throttle if there are too many
        if num_pruned == 0 && self.throttle(now) {
            return Err(PaymentError::Reject("Too many transactions in replay prevention window, ledger is throttling, please retry later".to_string()));
        }
        let transaction = Transaction {
            operation: payment.clone(),
            memo,
            created_at_time,
        };
        let transaction_hash = transaction.hash();
        if let Some(block_height) = self.transactions_by_hash.get(&transaction_hash) {
            return Err(PaymentError::TransferError(TransferError::TxDuplicate {
                duplicate_of: *block_height,
            }));
        }
        let block = Block::new_from_transaction(self.blockchain.last_hash, transaction, now);
        let block_timestamp = block.timestamp;
        self.balances.add_payment(&payment).map_err(|e| match e {
            BalanceError::InsufficientFunds { balance } => {
                PaymentError::TransferError(TransferError::InsufficientFunds { balance })
            }
        })?;
        let height = self
            .blockchain
            .add_block(block)
            .expect("failed to add block");
        self.transactions_by_hash.insert(transaction_hash, height);
        self.transactions_by_height.push_back(TransactionInfo {
            block_timestamp,
            transaction_hash,
        });
        let to_trim = if self.balances.store.len()
            >= self.maximum_number_of_accounts + self.accounts_overflow_trim_quantity
        {
            self.balances
                .select_accounts_to_trim(self.accounts_overflow_trim_quantity)
        } else {
            vec![]
        };
        for (balance, account) in to_trim {
            let operation = Operation::Burn {
                from: account,
                amount: balance,
            };
            self.balances
                .add_payment(&operation)
                .expect("failed to burn funds that must have existed");
            self.blockchain
                .add_block(Block::new_from_transaction(
                    self.blockchain.last_hash,
                    Transaction {
                        operation,
                        memo: Memo::default(),
                        created_at_time: now,
                    },
                    now,
                ))
                .unwrap();
        }
        Ok((height, self.blockchain.last_hash.unwrap()))
    }
fn add_payment_with_timestamp ( & mut self , memo : Memo , payment : Operation , created_at_time : Option < TimeStamp > , now : TimeStamp , ) -> Result < ( BlockHeight , HashOf < EncodedBlock > ) , PaymentError > { let num_pruned = self . purge_old_transactions ( now ) ; let created_at_time = created_at_time . unwrap_or ( now ) ; if created_at_time + self . transaction_window < now { return Err ( PaymentError :: TransferError ( TransferError :: TxTooOld { allowed_window_nanos : self . transaction_window . as_nanos ( ) as u64 , } ) ) ; } if created_at_time > now + ic_types :: ingress :: PERMITTED_DRIFT { return Err ( PaymentError :: TransferError ( TransferError :: TxCreatedInFuture , ) ) ; } // If we pruned some transactions, let this one through // otherwise throttle if there are too many if num_pruned == 0 && self . throttle ( now ) { return Err ( PaymentError :: Reject ( " " . to_string ( ) ) ) ; } let transaction = Transaction { operation : payment . clone ( ) , memo , created_at_time , } ; let transaction_hash = transaction . hash ( ) ; if let Some ( block_height ) = self . transactions_by_hash . get ( & transaction_hash ) { return Err ( PaymentError :: TransferError ( TransferError :: TxDuplicate { duplicate_of : * block_height , } ) ) ; } let block = Block :: new_from_transaction ( self . blockchain . last_hash , transaction , now ) ; let block_timestamp = block . timestamp ; self . balances . add_payment ( & payment ) . map_err ( | e | match e { BalanceError :: InsufficientFunds { balance } => { PaymentError :: TransferError ( TransferError :: InsufficientFunds { balance } ) } } ) ? ; let height = self . blockchain . add_block ( block ) . expect ( " " ) ; self . transactions_by_hash . insert ( transaction_hash , height ) ; self . transactions_by_height . push_back ( TransactionInfo { block_timestamp , transaction_hash , } ) ; let to_trim = if self . balances . store . len ( ) >= self . maximum_number_of_accounts + self . accounts_overflow_trim_quantity { self . balances . select_accounts_to_trim ( self . accounts_overflow_trim_quantity ) } else { vec ! [ ] } ; for ( balance , account ) in to_trim { let operation = Operation :: Burn { from : account , amount : balance , } ; self . balances . add_payment ( & operation ) . expect ( " " ) ; self . blockchain . add_block ( Block :: new_from_transaction ( self . blockchain . last_hash , Transaction { operation , memo : Memo :: default ( ) , created_at_time : now , } , now , ) ) . unwrap ( ) ; } Ok ( ( height , self . blockchain . last_hash . unwrap ( ) ) ) }
Internal version of `add_payment` that takes a timestamp, for
testing.
Internal version of ` add_payment ` that takes a timestamp for testing .
&mut self
memo
Memo
payment
Operation
created_at_time
Option<TimeStamp>
now
TimeStamp
&mut self
memo
Memo
payment
Operation
created_at_time
Option<TimeStamp>
now
TimeStamp