Skip to content

Commit b768bfd

Browse files
committed
Fix two bugs in revalidate
1. Rewrite revalidate to enhance readability 2. Fix two similar issues originating from confusion between previous variable names `t` and `t'` ("Account no longer has permission to send" and "Current account nonce precedes first nonce in queue") 3. Fix the issue #16397 by ensuring removal from `applicable_by_fee` is done only for the previous head of queue.
1 parent 0790709 commit b768bfd

File tree

1 file changed

+60
-54
lines changed

1 file changed

+60
-54
lines changed

src/lib/network_pool/indexed_pool.ml

+60-54
Original file line numberDiff line numberDiff line change
@@ -682,29 +682,24 @@ let revalidate :
682682
-> [ `Entire_pool | `Subset of Account_id.Set.t ]
683683
-> (Account_id.t -> Account.t)
684684
-> t * Transaction_hash.User_command_with_valid_signature.t Sequence.t =
685-
fun t ~logger scope get_account_by_id ->
685+
fun t_initial ~logger scope get_account_by_id ->
686686
let requires_revalidation =
687687
match scope with
688688
| `Entire_pool ->
689-
t.all_by_sender
689+
t_initial.all_by_sender
690690
| `Subset subset ->
691691
(* intersection of scope and all_by_sender *)
692-
Account_id.Map.merge t.all_by_sender
692+
Account_id.Map.merge t_initial.all_by_sender
693693
(Account_id.Set.to_map subset ~f:(const ()))
694694
~f:(fun ~key:_ -> function `Both (v, ()) -> Some v | _ -> None)
695695
in
696-
Map.fold requires_revalidation ~init:(t, Sequence.empty)
697-
~f:(fun
698-
~key:sender
699-
~data:(queue, currency_reserved)
700-
((t', dropped_acc) as acc)
701-
->
696+
let global_slot = global_slot_since_genesis t_initial.config in
697+
Map.fold requires_revalidation ~init:(t_initial, Sequence.empty)
698+
~f:(fun ~key:sender ~data:(queue, currency_reserved) (t, dropped_acc) ->
702699
let account : Account.t = get_account_by_id sender in
703700
let current_balance =
704701
Currency.Balance.to_amount
705-
(Account.liquid_balance_at_slot
706-
~global_slot:(global_slot_since_genesis t.config)
707-
account )
702+
(Account.liquid_balance_at_slot ~global_slot account)
708703
in
709704
[%log debug]
710705
"Revalidating account $account in transaction pool ($account_nonce, \
@@ -726,13 +721,13 @@ let revalidate :
726721
&& Account.has_permission_to_increment_nonce account )
727722
then (
728723
[%log debug] "Account no longer has permission to send; dropping queue" ;
729-
let dropped, t'' = remove_with_dependents_exn' t first_cmd in
730-
(t'', Sequence.append dropped_acc dropped) )
724+
let dropped, t_updated = remove_with_dependents_exn' t first_cmd in
725+
(t_updated, Sequence.append dropped_acc dropped) )
731726
else if Account_nonce.(account.nonce < first_nonce) then (
732727
[%log debug]
733728
"Current account nonce precedes first nonce in queue; dropping queue" ;
734-
let dropped, t'' = remove_with_dependents_exn' t first_cmd in
735-
(t'', Sequence.append dropped_acc dropped) )
729+
let dropped, t_updated = remove_with_dependents_exn' t first_cmd in
730+
(t_updated, Sequence.append dropped_acc dropped) )
736731
else
737732
(* current_nonce >= first_nonce *)
738733
let first_applicable_nonce_index =
@@ -759,52 +754,63 @@ let revalidate :
759754
)
760755
currency_reserved drop_queue
761756
in
757+
(* NB: dropped_for_balance is ordered by nonce *)
762758
let keep_queue', currency_reserved'', dropped_for_balance =
763759
drop_until_sufficient_balance
764760
(keep_queue, currency_reserved')
765761
current_balance
766762
in
767-
(* NB: to_drop is ordered by nonce *)
768763
let to_drop =
769764
Sequence.append (F_sequence.to_seq drop_queue) dropped_for_balance
770765
in
771-
match Sequence.next to_drop with
772-
| None ->
773-
acc
774-
| Some (head, tail) ->
775-
let t'' =
776-
Sequence.fold tail
777-
~init:
778-
(remove_all_by_fee_and_hash_and_expiration_exn
779-
(remove_applicable_exn t' head)
780-
head )
781-
~f:remove_all_by_fee_and_hash_and_expiration_exn
782-
in
783-
let t''' =
784-
match F_sequence.uncons keep_queue' with
785-
| None ->
786-
{ t'' with
787-
all_by_sender = Map.remove t''.all_by_sender sender
788-
}
789-
| Some (first_kept, _) ->
790-
let first_kept_unchecked =
791-
Transaction_hash.User_command_with_valid_signature.command
792-
first_kept
793-
in
794-
{ t'' with
795-
all_by_sender =
796-
Map.set t''.all_by_sender ~key:sender
797-
~data:(keep_queue', currency_reserved'')
798-
; applicable_by_fee =
799-
Map_set.insert
800-
( module Transaction_hash
801-
.User_command_with_valid_signature )
802-
t''.applicable_by_fee
803-
(User_command.fee_per_wu first_kept_unchecked)
804-
first_kept
805-
}
806-
in
807-
(t''', Sequence.append dropped_acc to_drop) )
766+
(* t with all_by_sender and applicable_by_fee fields updated *)
767+
let t_partially_updated =
768+
match
769+
( F_sequence.uncons drop_queue
770+
, Sequence.hd dropped_for_balance
771+
, F_sequence.uncons keep_queue' )
772+
with
773+
| None, None, _ ->
774+
(* Nothing dropped, nothing needs to be updated *)
775+
t
776+
| Some (first_dropped, _), _, None | None, Some first_dropped, None ->
777+
(* We drop the entire queue, first element needs to be removed from
778+
applicable_by_fee *)
779+
let t' = remove_applicable_exn t first_dropped in
780+
{ t' with all_by_sender = Map.remove t'.all_by_sender sender }
781+
| None, _, Some _ ->
782+
(* We drop only some transactions from the end of queue, keeping
783+
the head untouched, no need to update applicable_by_fee *)
784+
{ t with
785+
all_by_sender =
786+
Map.set t.all_by_sender ~key:sender
787+
~data:(keep_queue', currency_reserved'')
788+
}
789+
| Some (first_dropped, _), _, Some (first_kept, _) ->
790+
(* We need to replace old queue head with the new queue head
791+
in applicable_by_fee *)
792+
let first_kept_unchecked =
793+
Transaction_hash.User_command_with_valid_signature.command
794+
first_kept
795+
in
796+
let t' = remove_applicable_exn t first_dropped in
797+
{ t' with
798+
all_by_sender =
799+
Map.set t'.all_by_sender ~key:sender
800+
~data:(keep_queue', currency_reserved'')
801+
; applicable_by_fee =
802+
Map_set.insert
803+
(module Transaction_hash.User_command_with_valid_signature)
804+
t'.applicable_by_fee
805+
(User_command.fee_per_wu first_kept_unchecked)
806+
first_kept
807+
}
808+
in
809+
let t_updated =
810+
Sequence.fold ~init:t_partially_updated
811+
~f:remove_all_by_fee_and_hash_and_expiration_exn to_drop
812+
in
813+
(t_updated, Sequence.append dropped_acc to_drop) )
808814

809815
let expired_by_global_slot (t : t) :
810816
Transaction_hash.User_command_with_valid_signature.t Sequence.t =

0 commit comments

Comments
 (0)