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

AVM: report structure txn failure info #5875

Merged
merged 7 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 6 additions & 18 deletions daemon/algod/api/client/restClient.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ type HTTPError struct {
StatusCode int
Status string
ErrorString string
Data map[string]any
jannotti marked this conversation as resolved.
Show resolved Hide resolved
}

// Error formats an error string.
Expand Down Expand Up @@ -120,24 +121,11 @@ func extractError(resp *http.Response) error {
decodeErr := json.Unmarshal(errorBuf, &errorJSON)

var errorString string
var data map[string]any
if decodeErr == nil {
if errorJSON.Data == nil {
// There's no additional data, so let's just use the message
errorString = errorJSON.Message
} else {
// There's additional data, so let's re-encode the JSON response to show everything.
// We do this because the original response is likely encoded with escapeHTML=true, but
// since this isn't a webpage that extra encoding is not preferred.
var buffer strings.Builder
enc := json.NewEncoder(&buffer)
enc.SetEscapeHTML(false)
encErr := enc.Encode(errorJSON)
if encErr != nil {
// This really shouldn't happen, but if it does let's default to errorBuff
errorString = string(errorBuf)
} else {
errorString = buffer.String()
}
errorString = errorJSON.Message
if errorJSON.Data != nil {
data = *errorJSON.Data
}
} else {
errorString = string(errorBuf)
Expand All @@ -149,7 +137,7 @@ func extractError(resp *http.Response) error {
return unauthorizedRequestError{errorString, apiToken, resp.Request.URL.String()}
}

return HTTPError{StatusCode: resp.StatusCode, Status: resp.Status, ErrorString: errorString}
return HTTPError{StatusCode: resp.StatusCode, Status: resp.Status, ErrorString: errorString, Data: data}
}

// stripTransaction gets a transaction of the form "tx-XXXXXXXX" and truncates the "tx-" part, if it starts with "tx-"
Expand Down
2 changes: 1 addition & 1 deletion data/transactions/logic/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,7 @@ func (cx *EvalContext) evalError(err error) error {
"group-index", cx.groupIndex,
"eval-states", cx.evalStates())
if cx.runMode == ModeApp {
details = fmt.Sprintf("app=%d %s", cx.appID, details)
details = fmt.Sprintf("app=%d, %s", cx.appID, details)
err = basics.Annotate(err, "app-index", cx.appID)
}

Expand Down
2 changes: 1 addition & 1 deletion data/transactions/logic/evalStateful_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,7 @@ itxn_submit
Stack: []any{uint64(777)},
},
},
"inner-msg": "logic eval error: cannot compare (uint64 to []byte). Details: app=5000 pc=26, opcodes=pushint 100; pushbytes 0x0201 // 0x0201; ==",
"inner-msg": "logic eval error: cannot compare (uint64 to []byte). Details: app=5000, pc=26, opcodes=pushint 100; pushbytes 0x0201 // 0x0201; ==",
"inner-attrs": map[string]any{
"pc": 26,
"group-index": 0,
Expand Down
2 changes: 1 addition & 1 deletion test/e2e-go/cli/goal/expect/goalAppAccountAddressTest.exp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ proc goalAppAccountAddress { TEST_ALGO_DIR TEST_DATA_DIR} {
--app-account $ACCOUNT_4_ADDRESS
expect {
timeout { puts timeout; ::AlgorandGoal::Abort "\n Failed to see expected output" }
"*Couldn't broadcast tx with algod: HTTP 400 Bad Request: *TransactionPool.Remember: transaction*invalid Accounts index 4*" {
"*Couldn't broadcast tx with algod: HTTP 400 Bad Request: TransactionPool.Remember: transaction*invalid Accounts index 4*" {
puts "\nError received successfully "
# wait until the eof signal is received
expect {
Expand Down
4 changes: 2 additions & 2 deletions test/e2e-go/cli/goal/expect/statefulTealAppReadTest.exp
jannotti marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ proc statefulTealAppReadTest { TEST_ALGO_DIR TEST_DATA_DIR} {
spawn goal app call --app-id $APP_ID --from $PRIMARY_ACCOUNT_ADDRESS -w $PRIMARY_WALLET_NAME -d $TEST_PRIMARY_NODE_DIR
expect {
timeout { puts timeout; ::AlgorandGoal::Abort "\n Failed to see expected output" }
"Couldn't broadcast tx with algod: HTTP 400 Bad Request: *TransactionPool.Remember: transaction*" {puts "received expected error"; close}
"Couldn't broadcast tx with algod: HTTP 400 Bad Request: TransactionPool.Remember: transaction*" {puts "received expected error"; close}
eof { close; ::AlgorandGoal::Abort "did not receive expected error" }
}

Expand All @@ -83,7 +83,7 @@ proc statefulTealAppReadTest { TEST_ALGO_DIR TEST_DATA_DIR} {
spawn goal app call --app-id $APP_ID --from $PRIMARY_ACCOUNT_ADDRESS -w $PRIMARY_WALLET_NAME --approval-prog-raw ${TEAL_PROGS_DIR}/wrongupgrade.tealc --clear-prog-raw ${TEAL_PROGS_DIR}/wrongupgrade.tealc -d $TEST_PRIMARY_NODE_DIR
expect {
timeout { puts timeout; ::AlgorandGoal::Abort "\n Failed to see expected output" }
"Couldn't broadcast tx with algod: HTTP 400 Bad Request: *TransactionPool.Remember: transaction*" {puts "received expected error"; close}
"Couldn't broadcast tx with algod: HTTP 400 Bad Request: TransactionPool.Remember: transaction*" {puts "received expected error"; close}
eof { close; ::AlgorandGoal::Abort "did not receive expected error" }
}

Expand Down
4 changes: 2 additions & 2 deletions test/e2e-go/cli/goal/expect/statefulTealCreateAppTest.exp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ proc statefulTealTest { TEST_ALGO_DIR TEST_DATA_DIR TEAL_PROGRAM} {
spawn goal app call --app-id $APP_ID --from $PRIMARY_ACCOUNT_ADDRESS -w $PRIMARY_WALLET_NAME -d $TEST_PRIMARY_NODE_DIR
expect {
timeout { puts timeout; ::AlgorandGoal::Abort "\n Failed to see expected output" }
"Couldn't broadcast tx with algod: HTTP 400 Bad Request: *TransactionPool.Remember: transaction*" {puts "received expected error"; close}
"Couldn't broadcast tx with algod: HTTP 400 Bad Request: TransactionPool.Remember: transaction*" {puts "received expected error"; close}
eof { close; ::AlgorandGoal::Abort "did not receive expected error" }
}

Expand All @@ -88,7 +88,7 @@ proc statefulTealTest { TEST_ALGO_DIR TEST_DATA_DIR TEAL_PROGRAM} {
"Please enter the password for wallet '$WALLET_1_NAME':" {send "$WALLET_1_PASSWORD\r" ; exp_continue }
"*not opted in to app*" {puts "received expected error"; close}
"*exceeds schema bytes count*" {puts "received expected error"; close}
"Couldn't broadcast tx with algod: HTTP 400 Bad Request: *TransactionPool.Remember: transaction*" {puts "received expected error"; close}
"Couldn't broadcast tx with algod: HTTP 400 Bad Request: TransactionPool.Remember: transaction*" {puts "received expected error"; close}
eof { close; ::AlgorandGoal::Abort "did not receive expected error" }
}
}
Expand Down
14 changes: 5 additions & 9 deletions test/e2e-go/restAPI/other/appsRestAPI_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import (
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/data/transactions/logic"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/test/framework/fixtures"
"github.com/algorand/go-algorand/test/partitiontest"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -319,15 +318,12 @@ end:
e := err.(client.HTTPError)
a.Equal(400, e.StatusCode)

var er *model.ErrorResponse
err = protocol.DecodeJSON([]byte(e.ErrorString), &er)
a.NoError(err)
a.Equal("Result limit exceeded", er.Message)
a.Equal(uint64(100000), ((*er.Data)["max-api-box-per-application"]).(uint64))
a.Equal(requestedMax, ((*er.Data)["max"]).(uint64))
a.Equal(expectedCount, ((*er.Data)["total-boxes"]).(uint64))
a.Equal("Result limit exceeded", e.ErrorString)
a.EqualValues(100000, e.Data["max-api-box-per-application"])
a.EqualValues(requestedMax, e.Data["max"])
a.EqualValues(expectedCount, e.Data["total-boxes"])

a.Len(*er.Data, 3, fmt.Sprintf("error response (%v) contains unverified fields. Extend test for new fields.", *er.Data))
a.Len(e.Data, 3, fmt.Sprintf("error response (%v) contains unverified fields. Extend test for new fields.", e.Data))
}

// `assertBoxCount` sanity checks that the REST API respects `expectedCount` through different queries against app ID = `createdAppID`.
Expand Down