@@ -137,24 +137,26 @@ where
137
137
}
138
138
}
139
139
140
+ // The bool in the result indicates whether execution result is a speculative abort.
140
141
fn process_execution_result < ' a > (
141
142
execution_result : & ' a ExecutionStatus < E :: Output , E :: Error > ,
142
143
read_set : & mut CapturedReads < T , ModuleId , CompiledModule , Module , AptosModuleExtension > ,
143
144
txn_idx : TxnIndex ,
144
- ) -> Result < Option < & ' a E :: Output > , PanicError > {
145
+ ) -> Result < ( Option < & ' a E :: Output > , bool ) , PanicError > {
145
146
match execution_result {
146
147
ExecutionStatus :: Success ( output) | ExecutionStatus :: SkipRest ( output) => {
147
- Ok ( Some ( output) )
148
+ Ok ( ( Some ( output) , false ) )
148
149
} ,
149
150
ExecutionStatus :: SpeculativeExecutionAbortError ( _msg) => {
150
151
// TODO(BlockSTMv2): cleaner to rename or distinguish V2 early abort
151
- // from DeltaApplicationFailure.
152
+ // from DeltaApplicationFailure. This is also why we return the bool
153
+ // separately for now instead of relying on the read set.
152
154
read_set. capture_delayed_field_read_error ( & PanicOr :: Or (
153
155
MVDelayedFieldsError :: DeltaApplicationFailure ,
154
156
) ) ;
155
- Ok ( None )
157
+ Ok ( ( None , true ) )
156
158
} ,
157
- ExecutionStatus :: Abort ( _err) => Ok ( None ) ,
159
+ ExecutionStatus :: Abort ( _err) => Ok ( ( None , false ) ) ,
158
160
ExecutionStatus :: DelayedFieldsCodeInvariantError ( msg) => {
159
161
Err ( code_invariant_error ( format ! (
160
162
"[Execution] At txn {}, failed with DelayedFieldsCodeInvariantError: {:?}" ,
@@ -365,9 +367,19 @@ where
365
367
) ) ) ;
366
368
}
367
369
368
- let maybe_output =
370
+ let ( maybe_output, is_speculative_failure ) =
369
371
Self :: process_execution_result ( & execution_result, & mut read_set, idx_to_execute) ?;
370
372
373
+ if is_speculative_failure {
374
+ // Recording in order to check the invariant that the final, committed incarnation
375
+ // of each transaction is not a speculative failure.
376
+ last_input_output. record_speculative_failure ( idx_to_execute) ;
377
+ // Ignoring module validation requirements since speculative failure
378
+ // anyway requires re-execution.
379
+ let _ = scheduler. finish_execution ( abort_manager) ?;
380
+ return Ok ( ( ) ) ;
381
+ }
382
+
371
383
Self :: process_delayed_field_output (
372
384
maybe_output,
373
385
idx_to_execute,
@@ -510,7 +522,7 @@ where
510
522
idx_to_execute, incarnation
511
523
) ) ) ;
512
524
}
513
- let processed_output =
525
+ let ( processed_output, _ ) =
514
526
Self :: process_execution_result ( & execution_result, & mut read_set, idx_to_execute) ?;
515
527
516
528
let mut prev_modified_resource_keys = last_input_output
@@ -666,29 +678,31 @@ where
666
678
// 2. The only possible time to take the read-set from txn_last_input_output
667
679
// is in prepare_and_queue_commit_ready_txn (applying module publishing output).
668
680
// However, required module validation necessarily occurs before the commit.
669
- let read_set = last_input_output. read_set ( idx_to_validate) . ok_or_else ( || {
670
- code_invariant_error ( format ! (
671
- "Prior read-set of txn {} incarnation {} not recorded for module verification" ,
672
- idx_to_validate, incarnation_to_validate
673
- ) )
674
- } ) ?;
681
+ let ( read_set, is_speculative_failure) =
682
+ last_input_output. read_set ( idx_to_validate) . ok_or_else ( || {
683
+ code_invariant_error ( format ! (
684
+ "Prior read-set of txn {} incarnation {} not recorded for module verification" ,
685
+ idx_to_validate, incarnation_to_validate
686
+ ) )
687
+ } ) ?;
675
688
// Perform invariant checks or return early based on read set's incarnation.
676
689
let blockstm_v2_incarnation = read_set. blockstm_v2_incarnation ( ) . ok_or_else ( || {
677
690
code_invariant_error (
678
691
"BlockSTMv2 must be enabled in CapturedReads when validating module reads" ,
679
692
)
680
693
} ) ?;
694
+ if blockstm_v2_incarnation > incarnation_to_validate || is_speculative_failure {
695
+ // No need to validate as a newer incarnation has already been executed
696
+ // and recorded its output, or the incarnation has resulted in a speculative
697
+ // failure, which means there will be a further re-execution.
698
+ return Ok ( true ) ;
699
+ }
681
700
if blockstm_v2_incarnation < incarnation_to_validate {
682
701
return Err ( code_invariant_error ( format ! (
683
702
"For txn_idx {}, read set incarnation {} < incarnation to validate {}" ,
684
703
idx_to_validate, blockstm_v2_incarnation, incarnation_to_validate
685
704
) ) ) ;
686
705
}
687
- if blockstm_v2_incarnation > incarnation_to_validate {
688
- // No need to validate as a newer incarnation has already been executed
689
- // and recorded its output.
690
- return Ok ( true ) ;
691
- }
692
706
693
707
if !read_set. validate_module_reads (
694
708
global_module_cache,
@@ -715,10 +729,14 @@ where
715
729
skip_module_reads_validation : bool ,
716
730
) -> bool {
717
731
let _timer = TASK_VALIDATE_SECONDS . start_timer ( ) ;
718
- let read_set = last_input_output
732
+ let ( read_set, is_speculative_failure ) = last_input_output
719
733
. read_set ( idx_to_validate)
720
734
. expect ( "[BlockSTM]: Prior read-set must be recorded" ) ;
721
735
736
+ if is_speculative_failure {
737
+ return false ;
738
+ }
739
+
722
740
assert ! (
723
741
!read_set. is_incorrect_use( ) ,
724
742
"Incorrect use must be handled after execution"
@@ -775,10 +793,14 @@ where
775
793
last_input_output : & TxnLastInputOutput < T , E :: Output , E :: Error > ,
776
794
is_v2 : bool ,
777
795
) -> Result < bool , PanicError > {
778
- let read_set = last_input_output
796
+ let ( read_set, is_speculative_failure ) = last_input_output
779
797
. read_set ( txn_idx)
780
798
. ok_or_else ( || code_invariant_error ( "Read set must be recorded" ) ) ?;
781
799
800
+ if is_speculative_failure {
801
+ return Ok ( false ) ;
802
+ }
803
+
782
804
if !read_set. validate_delayed_field_reads ( versioned_cache. delayed_fields ( ) , txn_idx) ?
783
805
|| ( is_v2
784
806
&& !read_set. validate_aggregator_v1_reads (
0 commit comments