@@ -20,18 +20,30 @@ pub enum Error {
20
20
Interpreter ( InterpreterError ) ,
21
21
BadTransaction ( String ) ,
22
22
CostError ( ExecutionCost , ExecutionCost ) ,
23
- AbortedByCallback ( Option < Value > , AssetMap , Vec < StacksTransactionEvent > ) ,
23
+ AbortedByCallback {
24
+ /// What the output value of the transaction would have been.
25
+ /// This will be a Some for contract-calls, and None for contract initialization txs.
26
+ output : Option < Value > ,
27
+ /// The asset map which was evaluated by the abort callback
28
+ assets_modified : AssetMap ,
29
+ /// The events from the transaction processing
30
+ tx_events : Vec < StacksTransactionEvent > ,
31
+ /// A human-readable explanation for aborting the transaction
32
+ reason : String ,
33
+ } ,
24
34
}
25
35
26
36
impl fmt:: Display for Error {
27
37
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
28
- match * self {
38
+ match self {
29
39
Error :: CostError ( ref a, ref b) => {
30
- write ! ( f, "Cost Error: {} cost exceeded budget of {} cost" , a , b )
40
+ write ! ( f, "Cost Error: {a } cost exceeded budget of {b } cost" )
31
41
}
32
42
Error :: Analysis ( ref e) => fmt:: Display :: fmt ( e, f) ,
33
43
Error :: Parse ( ref e) => fmt:: Display :: fmt ( e, f) ,
34
- Error :: AbortedByCallback ( ..) => write ! ( f, "Post condition aborted transaction" ) ,
44
+ Error :: AbortedByCallback { reason, .. } => {
45
+ write ! ( f, "Post condition aborted transaction: {reason}" )
46
+ }
35
47
Error :: Interpreter ( ref e) => fmt:: Display :: fmt ( e, f) ,
36
48
Error :: BadTransaction ( ref s) => fmt:: Display :: fmt ( s, f) ,
37
49
}
@@ -42,7 +54,7 @@ impl std::error::Error for Error {
42
54
fn cause ( & self ) -> Option < & dyn std:: error:: Error > {
43
55
match * self {
44
56
Error :: CostError ( ref _a, ref _b) => None ,
45
- Error :: AbortedByCallback ( .. ) => None ,
57
+ Error :: AbortedByCallback { .. } => None ,
46
58
Error :: Analysis ( ref e) => Some ( e) ,
47
59
Error :: Parse ( ref e) => Some ( e) ,
48
60
Error :: Interpreter ( ref e) => Some ( e) ,
@@ -168,16 +180,17 @@ pub trait TransactionConnection: ClarityConnection {
168
180
/// * the asset changes during `to_do` in an `AssetMap`
169
181
/// * the Stacks events during the transaction
170
182
///
171
- /// and a `bool` value which is `true` if the `abort_call_back` caused the changes to abort.
183
+ /// and an optional string value which is the result of `abort_call_back`,
184
+ /// containing a human-readable reason for aborting the transaction.
172
185
///
173
186
/// If `to_do` returns an `Err` variant, then the changes are aborted.
174
187
fn with_abort_callback < F , A , R , E > (
175
188
& mut self ,
176
189
to_do : F ,
177
190
abort_call_back : A ,
178
- ) -> Result < ( R , AssetMap , Vec < StacksTransactionEvent > , bool ) , E >
191
+ ) -> Result < ( R , AssetMap , Vec < StacksTransactionEvent > , Option < String > ) , E >
179
192
where
180
- A : FnOnce ( & AssetMap , & mut ClarityDatabase ) -> bool ,
193
+ A : FnOnce ( & AssetMap , & mut ClarityDatabase ) -> Option < String > ,
181
194
F : FnOnce ( & mut OwnedEnvironment ) -> Result < ( R , AssetMap , Vec < StacksTransactionEvent > ) , E > ,
182
195
E : From < InterpreterError > ;
183
196
@@ -283,16 +296,16 @@ pub trait TransactionConnection: ClarityConnection {
283
296
. stx_transfer ( from, to, amount, memo)
284
297
. map_err ( Error :: from)
285
298
} ,
286
- |_, _| false ,
299
+ |_, _| None ,
287
300
)
288
301
. map ( |( value, assets, events, _) | ( value, assets, events) )
289
302
}
290
303
291
304
/// Execute a contract call in the current block.
292
- /// If an error occurs while processing the transaction, its modifications will be rolled back.
293
- /// abort_call_back is called with an AssetMap and a ClarityDatabase reference,
294
- /// if abort_call_back returns true , all modifications from this transaction will be rolled back.
295
- /// otherwise , they will be committed (though they may later be rolled back if the block itself is rolled back).
305
+ /// If an error occurs while processing the transaction, its modifications will be rolled back.
306
+ /// ` abort_call_back` is called with an ` AssetMap` and a ` ClarityDatabase` reference,
307
+ /// If ` abort_call_back` returns `Some(reason)` , all modifications from this transaction will be rolled back.
308
+ /// Otherwise , they will be committed (though they may later be rolled back if the block itself is rolled back).
296
309
#[ allow( clippy:: too_many_arguments) ]
297
310
fn run_contract_call < F > (
298
311
& mut self ,
@@ -305,7 +318,7 @@ pub trait TransactionConnection: ClarityConnection {
305
318
max_execution_time : Option < std:: time:: Duration > ,
306
319
) -> Result < ( Value , AssetMap , Vec < StacksTransactionEvent > ) , Error >
307
320
where
308
- F : FnOnce ( & AssetMap , & mut ClarityDatabase ) -> bool ,
321
+ F : FnOnce ( & AssetMap , & mut ClarityDatabase ) -> Option < String > ,
309
322
{
310
323
let expr_args: Vec < _ > = args
311
324
. iter ( )
@@ -331,20 +344,25 @@ pub trait TransactionConnection: ClarityConnection {
331
344
} ,
332
345
abort_call_back,
333
346
)
334
- . and_then ( |( value, assets, events, aborted) | {
335
- if aborted {
336
- Err ( Error :: AbortedByCallback ( Some ( value) , assets, events) )
347
+ . and_then ( |( value, assets_modified, tx_events, reason) | {
348
+ if let Some ( reason) = reason {
349
+ Err ( Error :: AbortedByCallback {
350
+ output : Some ( value) ,
351
+ assets_modified,
352
+ tx_events,
353
+ reason,
354
+ } )
337
355
} else {
338
- Ok ( ( value, assets , events ) )
356
+ Ok ( ( value, assets_modified , tx_events ) )
339
357
}
340
358
} )
341
359
}
342
360
343
361
/// Initialize a contract in the current block.
344
362
/// If an error occurs while processing the initialization, it's modifications will be rolled back.
345
- /// abort_call_back is called with an AssetMap and a ClarityDatabase reference,
346
- /// if abort_call_back returns true , all modifications from this transaction will be rolled back.
347
- /// otherwise , they will be committed (though they may later be rolled back if the block itself is rolled back).
363
+ /// ` abort_call_back` is called with an ` AssetMap` and a ` ClarityDatabase` reference,
364
+ /// If ` abort_call_back` returns `Some(reason)` , all modifications from this transaction will be rolled back.
365
+ /// Otherwise , they will be committed (though they may later be rolled back if the block itself is rolled back).
348
366
#[ allow( clippy:: too_many_arguments) ]
349
367
fn initialize_smart_contract < F > (
350
368
& mut self ,
@@ -357,9 +375,9 @@ pub trait TransactionConnection: ClarityConnection {
357
375
max_execution_time : Option < std:: time:: Duration > ,
358
376
) -> Result < ( AssetMap , Vec < StacksTransactionEvent > ) , Error >
359
377
where
360
- F : FnOnce ( & AssetMap , & mut ClarityDatabase ) -> bool ,
378
+ F : FnOnce ( & AssetMap , & mut ClarityDatabase ) -> Option < String > ,
361
379
{
362
- let ( _, asset_map , events , aborted ) = self . with_abort_callback (
380
+ let ( _, assets_modified , tx_events , reason ) = self . with_abort_callback (
363
381
|vm_env| {
364
382
if let Some ( max_execution_time_duration) = max_execution_time {
365
383
vm_env
@@ -378,10 +396,15 @@ pub trait TransactionConnection: ClarityConnection {
378
396
} ,
379
397
abort_call_back,
380
398
) ?;
381
- if aborted {
382
- Err ( Error :: AbortedByCallback ( None , asset_map, events) )
399
+ if let Some ( reason) = reason {
400
+ Err ( Error :: AbortedByCallback {
401
+ output : None ,
402
+ assets_modified,
403
+ tx_events,
404
+ reason,
405
+ } )
383
406
} else {
384
- Ok ( ( asset_map , events ) )
407
+ Ok ( ( assets_modified , tx_events ) )
385
408
}
386
409
}
387
410
}
0 commit comments