Skip to content

Commit

Permalink
Implement error types and error handling (#26)
Browse files Browse the repository at this point in the history
* Define errors

* Implement error handling and state rollback on #endWasm

* Implement fail_with_error

* Test error types

* Test state rollback

* Set Version: 0.1.19

* Require `error type == ErrContract` in `fail_with_error`

---------

Co-authored-by: devops <[email protected]>
  • Loading branch information
bbyalcinkaya and devops authored Aug 13, 2024
1 parent 0ca53e7 commit 96a1afa
Show file tree
Hide file tree
Showing 8 changed files with 522 additions and 3 deletions.
2 changes: 1 addition & 1 deletion package/version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.18
0.1.19
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "ksoroban"
version = "0.1.18"
version = "0.1.19"
description = "K tooling for the Soroban platform"
authors = [
"Runtime Verification, Inc. <[email protected]>",
Expand Down
14 changes: 13 additions & 1 deletion src/ksoroban/kdist/soroban-semantics/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
[Documentation - Host Value Type](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0046-01.md#host-value-type)

```k
requires "errors.md"
module HOST-OBJECT-SYNTAX
imports BOOL-SYNTAX
imports INT-SYNTAX
imports BYTES-SYNTAX
imports STRING-SYNTAX
imports LIST
imports MAP
imports ERRORS
```

## ScVal
Expand Down Expand Up @@ -48,8 +51,9 @@ various contexts:

```k
syntax ScVal
::= SCBool(Bool) [symbol(SCVal:Bool)]
::= SCBool(Bool) [symbol(SCVal:Bool)]
| "Void" [symbol(SCVal:Void)]
| Error(ErrorType, Int) [symbol(SCVal:Error)]
| U32(Int) [symbol(SCVal:U32)]
| I32(Int) [symbol(SCVal:I32)]
| U64(Int) [symbol(SCVal:U64)]
Expand Down Expand Up @@ -97,10 +101,12 @@ module HOST-OBJECT
imports WASM
syntax Int ::= getMajor(HostVal) [function, total, symbol(getMajor)]
| getMinor(HostVal) [function, total, symbol(getMinor)]
| getTag(HostVal) [function, total, symbol(getTag)]
| getBody(HostVal) [function, total, symbol(getBody)]
// -----------------------------------------------------------------------
rule getMajor(HostVal(I)) => I >>Int 32
rule getMinor(HostVal(I)) => (I &Int (#pow(i32) -Int 1)) >>Int 8
rule getTag(HostVal(I)) => I &Int 255
rule getBody(HostVal(I)) => I >>Int 8
Expand Down Expand Up @@ -139,6 +145,7 @@ module HOST-OBJECT
rule getTag(SCBool(true)) => 0
rule getTag(SCBool(false)) => 1
rule getTag(Void) => 2
rule getTag(Error(_,_)) => 3
rule getTag(U32(_)) => 4
rule getTag(I32(_)) => 5
rule getTag(U64(I)) => 6 requires I <=Int #maxU64small
Expand Down Expand Up @@ -204,6 +211,10 @@ module HOST-OBJECT
rule fromSmall(VAL) => Void requires getTag(VAL) ==Int 2
rule fromSmall(VAL) => Error(Int2ErrorType(getMinor(VAL)), getMajor(VAL))
requires getTag(VAL) ==Int 3
andBool Int2ErrorTypeValid(getMinor(VAL))
rule fromSmall(VAL) => U32(getMajor(VAL)) requires getTag(VAL) ==Int 4
rule fromSmall(VAL) => I32(#signed(i32, getMajor(VAL)))
Expand Down Expand Up @@ -232,6 +243,7 @@ module HOST-OBJECT
rule toSmall(SCBool(false)) => fromMajorMinorAndTag(0, 0, 0)
rule toSmall(SCBool(true)) => fromMajorMinorAndTag(0, 0, 1)
rule toSmall(Void) => fromMajorMinorAndTag(0, 0, 2)
rule toSmall(Error(TYP, I)) => fromMajorMinorAndTag(I, ErrorType2Int(TYP), 3)
rule toSmall(U32(I)) => fromMajorMinorAndTag(I, 0, 4)
rule toSmall(I32(I)) => fromMajorMinorAndTag(#unsigned(i32, I), 0, 5)
requires definedUnsigned(i32, I)
Expand Down
73 changes: 73 additions & 0 deletions src/ksoroban/kdist/soroban-semantics/errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Errors


```k
module ERRORS
imports BOOL
imports INT
syntax ErrorType ::= "ErrContract" [symbol(ErrorType:Contract)]
| "ErrWasmVm" [symbol(ErrorType:WasmVm)]
| "ErrContext" [symbol(ErrorType:Context)]
| "ErrStorage" [symbol(ErrorType:Storage)]
| "ErrObject" [symbol(ErrorType:Object)]
| "ErrCrypto" [symbol(ErrorType:Crypto)]
| "ErrEvents" [symbol(ErrorType:Events)]
| "ErrBudget" [symbol(ErrorType:Budget)]
| "ErrValue" [symbol(ErrorType:Value)]
| "ErrAuth" [symbol(ErrorType:Auth)]
syntax Int ::= ErrorType2Int(ErrorType) [function, total, symbol(ErrorType2Int)]
// -------------------------------------------------------------------------------------
rule ErrorType2Int(ErrContract) => 0
rule ErrorType2Int(ErrWasmVm) => 1
rule ErrorType2Int(ErrContext) => 2
rule ErrorType2Int(ErrStorage) => 3
rule ErrorType2Int(ErrObject) => 4
rule ErrorType2Int(ErrCrypto) => 5
rule ErrorType2Int(ErrEvents) => 6
rule ErrorType2Int(ErrBudget) => 7
rule ErrorType2Int(ErrValue) => 8
rule ErrorType2Int(ErrAuth) => 9
syntax ErrorType ::= Int2ErrorType(Int) [function, total, symbol(Int2ErrorType)]
// ----------------------------------------------------------------------------------
rule Int2ErrorType(1) => ErrWasmVm
rule Int2ErrorType(2) => ErrContext
rule Int2ErrorType(3) => ErrStorage
rule Int2ErrorType(4) => ErrObject
rule Int2ErrorType(5) => ErrCrypto
rule Int2ErrorType(6) => ErrEvents
rule Int2ErrorType(7) => ErrBudget
rule Int2ErrorType(8) => ErrValue
rule Int2ErrorType(9) => ErrAuth
rule Int2ErrorType(_) => ErrContract [owise]
syntax Bool ::= Int2ErrorTypeValid(Int) [function, total, symbol(Int2ErrorTypeValid)]
// ---------------------------------------------------------------------------------------
rule Int2ErrorTypeValid(I) => 0 <=Int I andBool I <=Int 9
syntax Int ::= "ArithDomain" [macro]
| "IndexBounds" [macro]
| "InvalidInput" [macro]
| "MissingValue" [macro]
| "ExistingValue" [macro]
| "ExceededLimit" [macro]
| "InvalidAction" [macro]
| "InternalError" [macro]
| "UnexpectedType" [macro]
| "UnexpectedSize" [macro]
// --------------------------------------------
rule ArithDomain => 0
rule IndexBounds => 1
rule InvalidInput => 2
rule MissingValue => 3
rule ExistingValue => 4
rule ExceededLimit => 5
rule InvalidAction => 6
rule InternalError => 7
rule UnexpectedType => 8
rule UnexpectedSize => 9
endmodule
```
28 changes: 28 additions & 0 deletions src/ksoroban/kdist/soroban-semantics/host/context.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,34 @@ Return the current ledger sequence number as `U32`.
</instrs>
<locals> .Map </locals>
<ledgerSequenceNumber> SEQ_NUM </ledgerSequenceNumber>
```

## fail_with_error

```k
rule [hostfun-fail-with-error]:
<instrs> hostCall ( "x" , "5" , [ i64 .ValTypes ] -> [ i64 .ValTypes ] ) ~> _REST
=> .K
</instrs>
<k> (.K => pushStack(fromSmall(HostVal(ERR)))) ... </k>
<locals>
0 |-> < i64 > ERR
</locals>
requires fromSmallValid(HostVal(ERR))
andBool getTag(HostVal(ERR)) ==Int 3
andBool Int2ErrorType(getMinor(HostVal(ERR))) ==K ErrContract // error type must be ErrContract
rule [hostfun-fail-with-error-wrong-type]:
<instrs> hostCall ( "x" , "5" , [ i64 .ValTypes ] -> [ i64 .ValTypes ] ) ~> _REST
=> .K
</instrs>
<k> (.K => pushStack(Error(ErrContext, UnexpectedType))) ... </k>
<locals>
0 |-> < i64 > ERR
</locals>
requires fromSmallValid(HostVal(ERR))
andBool getTag(HostVal(ERR)) ==Int 3
andBool Int2ErrorType(getMinor(HostVal(ERR))) =/=K ErrContract
endmodule
```
16 changes: 16 additions & 0 deletions src/ksoroban/kdist/soroban-semantics/switch.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ module SWITCH
stack after the function execution.

```k
rule [endWasm-error]:
<k> #endWasm
=> popCallState
~> popWorldState
...
</k>
<instrs> .K </instrs>
<hostStack> (Error(_,_) #as ERR) : _ => ERR : .HostStack </hostStack>
[priority(40)]
rule [endWasm]:
<k> #endWasm
=> popCallState
Expand All @@ -44,6 +54,12 @@ module SWITCH
<instrs> .K </instrs>
<relativeObjects> RELS </relativeObjects>
<valstack> STACK </valstack>
[priority(50)]
rule [endWasm-trap]:
<k> #endWasm ... </k>
<instrs> trap => .K </instrs>
<hostStack> S => Error(ErrContext, InvalidAction) : S </hostStack>
```

Expand Down
169 changes: 169 additions & 0 deletions src/tests/integration/data/errors.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@

setExitCode(1)

uploadWasm( b"test-wasm",
;; #![no_std]
;; use soroban_sdk::{contract, contracterror, contractimpl, panic_with_error, Env};
;;
;; #[contracterror]
;; #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
;; #[repr(u32)]
;; pub enum CustomError {
;; CustomErrorCode1 = 1,
;; CustomErrorCode2 = 2,
;; }
;;
;; #[contract]
;; pub struct IncrementContract;
;;
;; #[contractimpl]
;; impl IncrementContract {
;; /// Increment increments an internal counter, and returns the value. Errors
;; /// if the value is attempted to be incremented past 5.
;; pub fn custom_fail(_env: Env, p: bool) -> Result<u32, CustomError> {
;; Err(
;; match p {
;; false => CustomError::CustomErrorCode1,
;; true => CustomError::CustomErrorCode2
;; }
;; )
;; }
;;
;; pub fn panic_fail(_env: Env) {
;; panic!()
;; }
;;
;; pub fn panic_with_error_fail(env: Env, p: bool) {
;; panic_with_error!(env, match p {
;; false => CustomError::CustomErrorCode1,
;; true => CustomError::CustomErrorCode2
;; })
;; }
;; }
;; mod test;
(module $soroban_errors_contract.wasm
(type (;0;) (func (param i64) (result i64)))
(type (;1;) (func (result i64)))
(type (;2;) (func))
(type (;3;) (func (param i64)))
(import "x" "5" (func $_ZN17soroban_env_guest5guest7context15fail_with_error17h712c0ad18a303073E (type 0)))
(func $custom_fail (type 0) (param i64) (result i64)
(local i32)
block ;; label = @1
local.get 0
i32.wrap_i64
i32.const 255
i32.and
local.tee 1
i32.const 2
i32.lt_u
br_if 0 (;@1;)
unreachable
unreachable
end
i64.const 8589934595
i64.const 4294967299
local.get 1
select)
(func $panic_fail (type 1) (result i64)
call $_ZN23soroban_errors_contract17IncrementContract10panic_fail19panic_cold_explicit17h500069efcbed89a3E
unreachable)
(func $_ZN23soroban_errors_contract17IncrementContract10panic_fail19panic_cold_explicit17h500069efcbed89a3E (type 2)
call $_ZN4core9panicking14panic_explicit17h47855c360709a39dE
unreachable)
(func $panic_with_error_fail (type 0) (param i64) (result i64)
(local i32)
block ;; label = @1
local.get 0
i32.wrap_i64
i32.const 255
i32.and
local.tee 1
i32.const 2
i32.ge_u
br_if 0 (;@1;)
i64.const 8589934595
i64.const 4294967299
local.get 1
select
call $_ZN70_$LT$soroban_sdk..env..Env$u20$as$u20$soroban_env_common..env..Env$GT$15fail_with_error17h4649cb3441ec7f31E
end
unreachable
unreachable)
(func $_ZN70_$LT$soroban_sdk..env..Env$u20$as$u20$soroban_env_common..env..Env$GT$15fail_with_error17h4649cb3441ec7f31E (type 3) (param i64)
local.get 0
call $_ZN17soroban_env_guest5guest7context15fail_with_error17h712c0ad18a303073E
drop)
(func $_ZN4core9panicking14panic_explicit17h47855c360709a39dE (type 2)
call $_ZN4core9panicking13panic_display17hbd841ae85eb3dff4E
unreachable)
(func $_ZN4core9panicking9panic_fmt17h5c7ce52813e94bcdE (type 2)
unreachable
unreachable)
(func $_ZN4core9panicking13panic_display17hbd841ae85eb3dff4E (type 2)
call $_ZN4core9panicking9panic_fmt17h5c7ce52813e94bcdE
unreachable)
(func $_ (type 2))
(memory (;0;) 16)
(global $__stack_pointer (mut i32) (i32.const 1048576))
(global (;1;) i32 (i32.const 1048576))
(global (;2;) i32 (i32.const 1048576))
(export "memory" (memory 0))
(export "custom_fail" (func $custom_fail))
(export "panic_fail" (func $panic_fail))
(export "panic_with_error_fail" (func $panic_with_error_fail))
(export "_" (func $_))
(export "__data_end" (global 1))
(export "__heap_base" (global 2)))
)

setAccount(Account(b"test-account"), 9876543210)

deployContract(
Account(b"test-account"),
Contract(b"test-sc"),
b"test-wasm",
.List
)

callTx(
Account(b"test-caller"),
Contract(b"test-sc"),
"panic_fail",
.List,
Error(ErrContext, InvalidAction)
)

callTx(
Account(b"test-caller"),
Contract(b"test-sc"),
"custom_fail",
ListItem(SCBool(false)),
Error(ErrContract, 1)
)

callTx(
Account(b"test-caller"),
Contract(b"test-sc"),
"custom_fail",
ListItem(SCBool(true)),
Error(ErrContract, 2)
)

callTx(
Account(b"test-caller"),
Contract(b"test-sc"),
"panic_with_error_fail",
ListItem(SCBool(false)),
Error(ErrContract, 1)
)

callTx(
Account(b"test-caller"),
Contract(b"test-sc"),
"panic_with_error_fail",
ListItem(SCBool(true)),
Error(ErrContract, 2)
)

setExitCode(0)
Loading

0 comments on commit 96a1afa

Please sign in to comment.