@@ -944,82 +944,9 @@ where
944
944
) ?;
945
945
ProgramState :: Return ( 1 )
946
946
} else {
947
- let gas_limit;
948
- let is_empty_script;
949
- if let Some ( script) = self . transaction ( ) . as_script ( ) {
950
- gas_limit = * script. script_gas_limit ( ) ;
951
- is_empty_script = script. script ( ) . is_empty ( ) ;
952
- } else {
953
- unreachable ! (
954
- "Only `Script` transactions can be executed inside of the VM"
955
- )
956
- }
957
-
958
- // TODO set tree balance
959
-
960
947
// `Interpreter` supports only `Create` and `Script` transactions. It is not
961
948
// `Create` -> it is `Script`.
962
- let program = if !is_empty_script {
963
- self . run_program ( )
964
- } else {
965
- // Return `1` as successful execution.
966
- let return_val = 1 ;
967
- self . ret ( return_val) ?;
968
- Ok ( ProgramState :: Return ( return_val) )
969
- } ;
970
-
971
- let gas_used = gas_limit
972
- . checked_sub ( self . remaining_gas ( ) )
973
- . ok_or_else ( || Bug :: new ( BugVariant :: GlobalGasUnderflow ) ) ?;
974
-
975
- // Catch VM panic and don't propagate, generating a receipt
976
- let ( status, program) = match program {
977
- Ok ( s) => {
978
- // either a revert or success
979
- let res = if let ProgramState :: Revert ( _) = & s {
980
- ScriptExecutionResult :: Revert
981
- } else {
982
- ScriptExecutionResult :: Success
983
- } ;
984
- ( res, s)
985
- }
986
-
987
- Err ( e) => match e. instruction_result ( ) {
988
- Some ( result) => {
989
- self . append_panic_receipt ( result) ;
990
-
991
- ( ScriptExecutionResult :: Panic , ProgramState :: Revert ( 0 ) )
992
- }
993
-
994
- // This isn't a specified case of an erroneous program and should be
995
- // propagated. If applicable, OS errors will fall into this category.
996
- None => return Err ( e) ,
997
- } ,
998
- } ;
999
-
1000
- let receipt = Receipt :: script_result ( status, gas_used) ;
1001
-
1002
- self . receipts . push ( receipt) ?;
1003
-
1004
- if program. is_debug ( ) {
1005
- self . debugger_set_last_state ( program) ;
1006
- }
1007
-
1008
- let revert = matches ! ( program, ProgramState :: Revert ( _) ) ;
1009
- let gas_price = self . gas_price ( ) ;
1010
- Self :: finalize_outputs (
1011
- & mut self . tx ,
1012
- & gas_costs,
1013
- & fee_params,
1014
- & base_asset_id,
1015
- revert,
1016
- gas_used,
1017
- & self . initial_balances ,
1018
- & self . balances ,
1019
- gas_price,
1020
- ) ?;
1021
-
1022
- program
949
+ self . run_program ( ) ?
1023
950
} ;
1024
951
self . update_transaction_outputs ( ) ?;
1025
952
@@ -1029,29 +956,94 @@ where
1029
956
pub ( crate ) fn run_program (
1030
957
& mut self ,
1031
958
) -> Result < ProgramState , InterpreterError < S :: DataError > > {
1032
- loop {
1033
- // Check whether the instruction will be executed in a call context
1034
- let in_call = !self . frames . is_empty ( ) ;
1035
-
1036
- let state = self . execute ( ) ?;
1037
-
1038
- if in_call {
1039
- // Only reverts should terminate execution from a call context
1040
- match state {
1041
- ExecuteState :: Revert ( r) => return Ok ( ProgramState :: Revert ( r) ) ,
1042
- ExecuteState :: DebugEvent ( d) => return Ok ( ProgramState :: RunProgram ( d) ) ,
1043
- _ => { }
1044
- }
1045
- } else {
1046
- match state {
1047
- ExecuteState :: Return ( r) => return Ok ( ProgramState :: Return ( r) ) ,
1048
- ExecuteState :: ReturnData ( d) => return Ok ( ProgramState :: ReturnData ( d) ) ,
1049
- ExecuteState :: Revert ( r) => return Ok ( ProgramState :: Revert ( r) ) ,
1050
- ExecuteState :: DebugEvent ( d) => return Ok ( ProgramState :: RunProgram ( d) ) ,
1051
- ExecuteState :: Proceed => { }
959
+ let Some ( script) = self . transaction ( ) . as_script ( ) else {
960
+ unreachable ! ( "Only `Script` transactions can be executed inside of the VM" )
961
+ } ;
962
+ let gas_limit = * script. script_gas_limit ( ) ;
963
+
964
+ let ( result, state) = if script. script ( ) . is_empty ( ) {
965
+ // Empty script is special-cased to simply return `1` as successful execution.
966
+ let return_val = 1 ;
967
+ self . ret ( return_val) ?;
968
+ (
969
+ ScriptExecutionResult :: Success ,
970
+ ProgramState :: Return ( return_val) ,
971
+ )
972
+ } else {
973
+ // TODO set tree balance
974
+ loop {
975
+ // Check whether the instruction will be executed in a call context
976
+ let in_call = !self . frames . is_empty ( ) ;
977
+
978
+ match self . execute ( ) {
979
+ // Proceeding with the execution normally
980
+ Ok ( ExecuteState :: Proceed ) => continue ,
981
+ // Debugger events are returned directly to the caller
982
+ Ok ( ExecuteState :: DebugEvent ( d) ) => {
983
+ self . debugger_set_last_state ( ProgramState :: RunProgram ( d) ) ;
984
+ return Ok ( ProgramState :: RunProgram ( d) ) ;
985
+ }
986
+ // Reverting terminated execution immediately
987
+ Ok ( ExecuteState :: Revert ( r) ) => {
988
+ break ( ScriptExecutionResult :: Revert , ProgramState :: Revert ( r) )
989
+ }
990
+ // Returning in call context is ignored
991
+ Ok ( ExecuteState :: Return ( _) | ExecuteState :: ReturnData ( _) )
992
+ if in_call =>
993
+ {
994
+ continue
995
+ }
996
+ // In non-call context, returning terminates the execution
997
+ Ok ( ExecuteState :: Return ( r) ) => {
998
+ break ( ScriptExecutionResult :: Success , ProgramState :: Return ( r) )
999
+ }
1000
+ Ok ( ExecuteState :: ReturnData ( d) ) => {
1001
+ break (
1002
+ ScriptExecutionResult :: Success ,
1003
+ ProgramState :: ReturnData ( d) ,
1004
+ )
1005
+ }
1006
+ // Error always terminates the execution
1007
+ Err ( e) => match e. instruction_result ( ) {
1008
+ Some ( result) => {
1009
+ self . append_panic_receipt ( result) ;
1010
+ break ( ScriptExecutionResult :: Panic , ProgramState :: Revert ( 0 ) ) ;
1011
+ }
1012
+ // This isn't a specified case of an erroneous program and should
1013
+ // be propagated. If applicable, OS errors
1014
+ // will fall into this category.
1015
+ // The VM state is not finalized in this case.
1016
+ None => return Err ( e) ,
1017
+ } ,
1052
1018
}
1053
1019
}
1054
- }
1020
+ } ;
1021
+
1022
+ // Produce result receipt
1023
+ let gas_used = gas_limit
1024
+ . checked_sub ( self . remaining_gas ( ) )
1025
+ . ok_or_else ( || Bug :: new ( BugVariant :: GlobalGasUnderflow ) ) ?;
1026
+ self . receipts
1027
+ . push ( Receipt :: script_result ( result, gas_used) ) ?;
1028
+
1029
+ // Finalize the outputs
1030
+ let fee_params = * self . fee_params ( ) ;
1031
+ let base_asset_id = * self . base_asset_id ( ) ;
1032
+ let gas_costs = self . gas_costs ( ) . clone ( ) ;
1033
+ let gas_price = self . gas_price ( ) ;
1034
+ Self :: finalize_outputs (
1035
+ & mut self . tx ,
1036
+ & gas_costs,
1037
+ & fee_params,
1038
+ & base_asset_id,
1039
+ matches ! ( state, ProgramState :: Revert ( _) ) ,
1040
+ gas_used,
1041
+ & self . initial_balances ,
1042
+ & self . balances ,
1043
+ gas_price,
1044
+ ) ?;
1045
+
1046
+ Ok ( state)
1055
1047
}
1056
1048
1057
1049
/// Update tx fields after execution
0 commit comments