Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARC-65: AVM Run Time Errors based on program bytecode #315

Merged
merged 24 commits into from
Dec 9, 2024
Merged
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions ARCs/arc-0065.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
---
arc: 65
title: AVM Run Time Errors In Program
description: Informative AVM run time errors based on program bytecode
author: Cosimo Bassi (@cusma), Tasos Bitsios (@tasosbit), Steve Ferrigno (@nullun)
discussions-to: https://github.com/algorandfoundation/ARCs/issues/315
status: Draft
type: Standards Track
category: ARC
created: 2024-10-09
---

## Abstract

This document introduces a convention for rising informative run time errors on
the Algorand Virtual Machine (AVM) directly from the program bytecode.

## Motivation

The AVM does not offer native opcodes to catch and raise run time errors.

The lack of native error handling semantics could lead to fragmentation of tooling
and frictions for AVM clients, who are unable to retrieve informative and useful
hints about the occurred run time failures.

This ARC formalizes a convention to rise AVM run time errors based just on the program
bytecode.

## Specification

The keywords "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL NOT**",
"**SHOULD**", "**SHOULD NOT**", "**RECOMMENDED**", "**MAY**", and "**OPTIONAL**"
in this document are to be interpreted as described in <a href="https://datatracker.ietf.org/doc/html/rfc2119">RFC 2119</a>.

> Notes like this are non-normative.

### In Program Errors

When a program wants to emit informative run time errors, contained in the bytecode,
it **MUST**:

1. Push to the stack the bytes string containing the error;
1. Execute the `log` opcode to use the bytes from the top of the stack;
1. Execute the `err` opcode to immediately terminate the program.

Upon a program run time failure, the Algod API returns both the failed *program
counter* (`pc`) and the `log` content.

### Error format

> The AVM programs bytecode have limited sized. In this convention, the errors are
> part of the bytecode, therefore it is good to mind errors' formatting and sizing.

> Errors consist of a _code_ and an optional _short message_.

Errors **MUST** statisfy the regexp: `ERR:(\w*)(?:\s?-\s?(.*))?`.

It is **RECOMMENDED** to use `UTF-8` for the error encoding.

It is **RECOMMENDED** to use fixed length error codes and _short_ error messages.

### Error examples

Error with a _numeric code_: `ERR:042`.

Error with an _alphanumeric code_: `ERR:BadRequest`.

Error with a _numeric code_ and _short message_: `ERR:042 - A Funny Error`.

### Program example

The program example raises the error `ERR:001 - Invalid Method` for any application
call to methods different from `m1()void`.

```teal
#pragma version 10

txn ApplicationID
bz end

method "m1()void"
txn ApplicationArgs 0
match method1
byte "ERR:001 - Invalid Method"
log
err

method1:
b end

end:
int 1
```

Full Algod API response of a failed execution:

```json
{
"data": {
"app-index":1004,
"eval-states": [
{
"logs": ["RVJSOiBJbnZhbGlkIE1ldGhvZA=="]
}
],
"group-index":0,
"pc":41
},
"message":"TransactionPool.Remember: transaction ESI4GHAZY46MCUCLPBSB5HBRZPGO6V7DDUM5XKMNVPIRJK6DDAGQ: logic eval error: err opcode executed. Details: app=1004, pc=41, opcodes=pushbytes 0x4552523a20496e76616c6964204d6574686f64 // \"ERR:001 - Invalid Method\"; log; err; label2:"
}
```

The `message` field contains the error `ERR:001 - Invalid Method`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, I think changing it to rely on the logs array would be better. Just decode each value and compare against the regex.
Here's an example I did via the command line with an application that attempts to use ABI methods first, then falls back to non-ABI methods. It resulted in two logged errors before failing.

curl -s -X POST http://127.0.0.1:4001/v2/transactions --data-binary @appl_call.stxn | jq -r '."data"."eval-states"[0]."logs"[] | @base64d' | grep -E "ERR:(\w*)(?:\s?-\s?(.*))?"
ERR:01 - Invalid Method
ERR:02 - No arguments supplied

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC the SDKs (e.g. JS) currently only throw the error message, e.g. when you do sendRawTransaction in JS/TS.

To me, including the error code in the surfaced message makes it significantly more useful


## Rationale

This convention for AVM run time errors presents the following PROS and CONS.

### PROS

- No additional artifacts required to bind the failed *program counter* (`pc`) to
the informative _error_;
- Errors are returned directly in the Algod API response, no additional client operation
needed.

### CONS

- Errors consume program bytecode size.

## Security Considerations

> Not applicable.

## Copyright

Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CCO</a>.
Loading