@@ -733,42 +733,108 @@ send_payment_core(struct lightningd *ld,
733733 struct short_channel_id * route_channels TAKES ,
734734 struct secret * path_secrets )
735735{
736- struct wallet_payment * payment ;
736+ const struct wallet_payment * * payments , * old_payment = NULL ;
737737 struct channel * channel ;
738738 enum onion_type failcode ;
739739 struct htlc_out * hout ;
740740 struct routing_failure * fail ;
741+ struct amount_msat msat_already_pending = AMOUNT_MSAT (0 );
742+
743+ /* Now, do we already have one or more payments? */
744+ payments = wallet_payment_list (tmpctx , ld -> wallet , rhash );
745+ for (size_t i = 0 ; i < tal_count (payments ); i ++ ) {
746+ log_debug (ld -> log , "Payment %zu/%zu: %s %s" ,
747+ i , tal_count (payments ),
748+ type_to_string (tmpctx , struct amount_msat ,
749+ & payments [i ]-> msatoshi ),
750+ payments [i ]-> status == PAYMENT_COMPLETE ? "COMPLETE"
751+ : payments [i ]-> status == PAYMENT_PENDING ? "PENDING"
752+ : "FAILED" );
753+
754+ switch (payments [i ]-> status ) {
755+ case PAYMENT_COMPLETE :
756+ if (payments [i ]-> parallel_id != parallel_id )
757+ continue ;
741758
742- /* Now, do we already have a payment? */
743- payment = wallet_payment_by_hash (tmpctx , ld -> wallet , rhash , parallel_id );
744- if (payment ) {
745- /* FIXME: We should really do something smarter here! */
746- if (payment -> status == PAYMENT_PENDING ) {
747- log_debug (ld -> log , "send_payment: previous still in progress" );
748- return json_sendpay_in_progress (cmd , payment );
749- }
750- if (payment -> status == PAYMENT_COMPLETE ) {
751- log_debug (ld -> log , "send_payment: previous succeeded" );
752759 /* Must match successful payment parameters. */
753- if (!amount_msat_eq (payment -> msatoshi , msat )) {
760+ if (!amount_msat_eq (payments [ i ] -> msatoshi , msat )) {
754761 return command_fail (cmd , PAY_RHASH_ALREADY_USED ,
755762 "Already succeeded "
756763 "with amount %s" ,
757764 type_to_string (tmpctx ,
758765 struct amount_msat ,
759- & payment -> msatoshi ));
766+ & payments [ i ] -> msatoshi ));
760767 }
761- if (payment -> destination && destination
762- && !node_id_eq (payment -> destination , destination )) {
768+ if (payments [i ]-> destination && destination
769+ && !node_id_eq (payments [i ]-> destination ,
770+ destination )) {
763771 return command_fail (cmd , PAY_RHASH_ALREADY_USED ,
764772 "Already succeeded to %s" ,
765773 type_to_string (tmpctx ,
766774 struct node_id ,
767- payment -> destination ));
775+ payments [ i ] -> destination ));
768776 }
769- return sendpay_success (cmd , payment );
770- }
771- log_debug (ld -> log , "send_payment: found previous, retrying" );
777+ return sendpay_success (cmd , payments [i ]);
778+
779+ case PAYMENT_PENDING :
780+ /* Can't mix non-parallel and parallel payments! */
781+ if (!payments [i ]-> parallel_id != !parallel_id ) {
782+ return command_fail (cmd , PAY_IN_PROGRESS ,
783+ "Already have %s payment in progress" ,
784+ payments [i ]-> parallel_id ? "parallel" : "non-parallel" );
785+ }
786+ if (payments [i ]-> parallel_id == parallel_id )
787+ return json_sendpay_in_progress (cmd , payments [i ]);
788+ /* You shouldn't change your mind about amount being
789+ * sent, since we'll use it in onion! */
790+ else if (!amount_msat_eq (payments [i ]-> msatoshi_total ,
791+ msat_total ))
792+ return command_fail (cmd , JSONRPC2_INVALID_PARAMS ,
793+ "msatoshi was previously %s, now %s" ,
794+ type_to_string (tmpctx ,
795+ struct amount_msat ,
796+ & payments [i ]-> msatoshi_total ),
797+ type_to_string (tmpctx ,
798+ struct amount_msat ,
799+ & msat_total ));
800+
801+
802+ if (!amount_msat_add (& msat_already_pending ,
803+ msat_already_pending ,
804+ payments [i ]-> msatoshi )) {
805+ return command_fail (cmd , LIGHTNINGD ,
806+ "Internal amount overflow!"
807+ " %s + %s in %zu/%zu" ,
808+ type_to_string (tmpctx ,
809+ struct amount_msat ,
810+ & msat_already_pending ),
811+ type_to_string (tmpctx ,
812+ struct amount_msat ,
813+ & payments [i ]-> msatoshi ),
814+ i , tal_count (payments ));
815+ }
816+ break ;
817+
818+ case PAYMENT_FAILED :
819+ if (payments [i ]-> parallel_id == parallel_id )
820+ old_payment = payments [i ];
821+ }
822+ }
823+
824+ /* BOLT-3a09bc54f8443c4757b47541a5310aff6377ee21 #4:
825+ *
826+ * - MUST NOT send another HTLC if the total `amount_msat` of the HTLC
827+ * set is already greater or equal to `total_msat`.
828+ */
829+ /* We don't do this for single 0-value payments (sendonion does this) */
830+ if (!amount_msat_eq (msat_total , AMOUNT_MSAT (0 ))
831+ && amount_msat_greater_eq (msat_already_pending , msat_total )) {
832+ return command_fail (cmd , PAY_IN_PROGRESS ,
833+ "Already have %s of %s payments in progress" ,
834+ type_to_string (tmpctx , struct amount_msat ,
835+ & msat_already_pending ),
836+ type_to_string (tmpctx , struct amount_msat ,
837+ & msat_total ));
772838 }
773839
774840 channel = active_channel_by_id (ld , & first_hop -> nodeid , NULL );
@@ -795,7 +861,7 @@ send_payment_core(struct lightningd *ld,
795861 & first_hop -> channel_id ,
796862 & channel -> peer -> id );
797863
798- return sendpay_fail (cmd , payment , PAY_TRY_OTHER_ROUTE ,
864+ return sendpay_fail (cmd , old_payment , PAY_TRY_OTHER_ROUTE ,
799865 NULL , fail , "First peer not ready" );
800866 }
801867
@@ -804,14 +870,14 @@ send_payment_core(struct lightningd *ld,
804870 * a possibility, and we end up in handle_missing_htlc_output->
805871 * onchain_failed_our_htlc->payment_failed with no payment.
806872 */
807- if (payment ) {
808- wallet_payment_delete (ld -> wallet , rhash , payment -> parallel_id );
873+ if (old_payment ) {
874+ wallet_payment_delete (ld -> wallet , rhash , parallel_id );
809875 wallet_local_htlc_out_delete (ld -> wallet , channel , rhash ,
810- payment -> parallel_id );
876+ parallel_id );
811877 }
812878
813879 /* If hout fails, payment should be freed too. */
814- payment = tal (hout , struct wallet_payment );
880+ struct wallet_payment * payment = tal (hout , struct wallet_payment );
815881 payment -> id = 0 ;
816882 payment -> payment_hash = * rhash ;
817883 payment -> parallel_id = parallel_id ;
0 commit comments