Skip to content

Enhancement: goal Error UX Improvement#4951

Merged
algorandskiy merged 19 commits intoalgorand:masterfrom
tzaffi:improve-some-goal-errors
Jan 13, 2023
Merged

Enhancement: goal Error UX Improvement#4951
algorandskiy merged 19 commits intoalgorand:masterfrom
tzaffi:improve-some-goal-errors

Conversation

@tzaffi
Copy link
Copy Markdown
Contributor

@tzaffi tzaffi commented Dec 28, 2022

Summary

Changing assembler functionality so that data/transactions/logic/assembler.go::assemble() errors when receiving empty input.

For example, here's what occurs when the clear program is empty (but approval is fine):

❯ goal app create --creator $ADDR_CREATOR \
                --approval-prog "$TEAL_APPROVAL_PROG" \
                --clear-prog "$TEAL_CLEAR_PROG" \
                --global-byteslices $GLOBAL_BYTESLICES \
                --global-ints $GLOBAL_INTS \
                --local-byteslices $LOCAL_BYTESLICES \
                --local-ints $LOCAL_INTS -d /Users/zeph/networks/niftynetwork/Primary
clear_state_program.teal: 1 error 0: Cannot assemble empty program text
clear_state_program.teal: 0: Cannot assemble empty program text

Question for Consideration

  • Is this the right approach? Is there a reason to allow empty programs to be assembled?

Related, to this. Consider the following empty'ish program:

#pragma version 7

Currently (and this PR doesn't change the behavior) we get the following error when attempting to run goal app create:

Couldn't broadcast tx with algod: HTTP 400 Bad Request: TransactionPool.Remember: transaction VTYB432J3J6XBZX2FPU5J3KWMN6OTEM5PRJLXIEY5ATAREZI66BA: logic eval error: stack len is 0 instead of 1. Details: pc=1, opcodes=

So we're perfectly happy to start the evaluator and immediately stop it, then declare a rejection. The PR here doesn't adhere to this pattern.

Even if the answer to the above is "yes, it is good to allow empty programs to be assembled because ..." there is still the counterargument that we want to fail as fast as possible and not create extra work for the node to evaluate guaranteed-to-fail transactions.

Issues

Test Plan

@tzaffi tzaffi changed the title Improveme Some goal Error UX Improve Some goal Error UX Dec 28, 2022
@tzaffi tzaffi added duplicate This issue or pull request already exists Enhancement labels Dec 28, 2022
@tzaffi tzaffi changed the title Improve Some goal Error UX Enhancement: Improve Some goal Error UX Dec 28, 2022
@tzaffi tzaffi changed the title Enhancement: Improve Some goal Error UX Enhancement: goal Error UX Improvements Dec 28, 2022
@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 28, 2022

Codecov Report

Merging #4951 (5e4f0ea) into master (5d38a15) will increase coverage by 0.02%.
The diff coverage is 75.00%.

@@            Coverage Diff             @@
##           master    #4951      +/-   ##
==========================================
+ Coverage   53.62%   53.65%   +0.02%     
==========================================
  Files         432      432              
  Lines       54060    54068       +8     
==========================================
+ Hits        28991    29011      +20     
+ Misses      22824    22810      -14     
- Partials     2245     2247       +2     
Impacted Files Coverage Δ
cmd/goal/clerk.go 8.77% <0.00%> (ø)
cmd/goal/multisig.go 10.00% <0.00%> (ø)
daemon/algod/api/server/v2/handlers.go 0.82% <0.00%> (ø)
data/transactions/logic/assembler.go 87.25% <100.00%> (+0.74%) ⬆️
util/rateLimit.go 81.37% <0.00%> (-0.99%) ⬇️
cmd/tealdbg/debugger.go 72.69% <0.00%> (-0.81%) ⬇️
ledger/acctupdates.go 68.99% <0.00%> (-0.25%) ⬇️
network/wsNetwork.go 64.74% <0.00%> (-0.18%) ⬇️
catchup/service.go 69.80% <0.00%> (+1.20%) ⬆️
... and 1 more

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@tzaffi tzaffi changed the title Enhancement: goal Error UX Improvements Enhancement: goal Error UX Improvement Dec 28, 2022
Comment thread daemon/algod/api/server/v2/test/handlers_test.go
@tzaffi tzaffi marked this pull request as ready for review December 29, 2022 04:53
Copy link
Copy Markdown
Contributor

@algochoi algochoi left a comment

Choose a reason for hiding this comment

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

Looking good, I agree that returning a clearer error for an empty program seems better from a UX perspective 👍

Comment thread cmd/goal/application.go Outdated
Comment thread cmd/goal/application.go Outdated
Comment thread data/transactions/logic/assembler.go Outdated
// assemble reads text from an input and accumulates the program
func (ops *OpStream) assemble(text string) error {
if strings.TrimSpace(text) == "" {
ops.errorf("Cannot assemble empty program text")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

return here?

Copy link
Copy Markdown
Contributor Author

@tzaffi tzaffi Dec 29, 2022

Choose a reason for hiding this comment

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

I didn't want to return right away because I want to let the assembler do it's thing and report number of errors. I.e., if I return right away instead of getting the following message:

clear_state_program.teal: 0: Cannot assemble empty program text
clear_state_program.teal: 1 error

I would get the following:

clear_state_program.teal: 0: Cannot assemble empty program text
clear_state_program.teal: 0: Cannot assemble empty program text

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It should be ok to:
return ops.errorf("Cannot assemble empty program text")
since that's how the Version check works a couple lines lower.
return ops.errorf("Can not assemble version %d", ops.Version)
That must show the same problem in the context you're looking at.

Perhaps we can change ops.ReportProblems to only report the underlying errors if there's more than 1? Rename to ops.MultpleErrors?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This worked with the following error goal messages:

clear_state_program.teal: 1 error
clear_state_program.teal: 0: Cannot assemble empty program text

Copy link
Copy Markdown
Contributor Author

@tzaffi tzaffi Jan 2, 2023

Choose a reason for hiding this comment

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

After modifying as above, test/scripts/e2e_subs/e2e-teal.sh started failing as the original error wasn't reported for goal clerk compile a logic sig (bad compiler version). So I modified ops.MultipleErrors() to also report the original unique error along with the count in the same line (only in the case of exactly 1 error and no warnings). Now the error looks like:

clear_state_program.teal: 1 error: 0: Cannot assemble empty program text
clear_state_program.teal: 0: Cannot assemble empty program text

… 1 error to _not_ report the actual errors, but "1 error" instead
}

func TestMultipleErrors(t *testing.T) {
func TestSeveralErrors(t *testing.T) {
Copy link
Copy Markdown
Contributor Author

@tzaffi tzaffi Jan 2, 2023

Choose a reason for hiding this comment

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

Renaming as the natural name of a new unit test for renamed function func(ops *OpStream) MultipleErrors is this one.

Comment thread test/scripts/e2e_subs/e2e-app-simple.sh Outdated
Comment thread test/scripts/e2e_subs/e2e-app-simple.sh Outdated
Comment thread data/transactions/logic/assembler.go Outdated
Comment on lines +1860 to +1862
if strings.TrimSpace(text) == "" {
return ops.errorf("Cannot assemble empty program text")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
if strings.TrimSpace(text) == "" {
return ops.errorf("Cannot assemble empty program text")
}
// version check
...
trimmed := strings.TrimSpace(text)
if trimmed == "" {
return ops.errorf("Cannot assemble empty program text")
}
fin := strings.NewReader(trimmed)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Implemented suggestion in 5f7de10

Copy link
Copy Markdown
Contributor Author

@tzaffi tzaffi Jan 11, 2023

Choose a reason for hiding this comment

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

I am reverting this change. Though I agree that passing on trimmed seems sensible, it is breaking tests, and the asserted behavior is there for a reason. For example, when providing this TEAL input:


int 1
#pragma version 2

This test case is failing:

This is because it is expecting the error:

{l: 3, s: "#pragma version is only allowed before instructions"}

but now, since we removed the empty line, it becomes

{l: 2, s: "#pragma version is only allowed before instructions"}

From a user's perspective, I believe the original error is more correct.

Comment thread data/transactions/logic/assembler.go Outdated
algorandskiy
algorandskiy previously approved these changes Jan 11, 2023
@tzaffi
Copy link
Copy Markdown
Contributor Author

tzaffi commented Jan 11, 2023

Update: The recent changes are causing test failures. I will investigate further.

emptyExpect := Expect{0, "Cannot assemble empty program text"}
emptyPrograms := []string{
"",
" ",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What about "label:" or " //"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The goal of the PR was to address the original concern (see #2585 ) which is when someone basically accidentally puts in a blank program for assembly. I expanded the definition to include any program that consists of all whitespace. We can expand even further, but it does seem to me to be a can of worms that I am inclined to push back against... However, I'm more than happy to test this out experimentally in our pair programming project.

@algorandskiy algorandskiy merged commit 4631571 into algorand:master Jan 13, 2023
winder pushed a commit to winder/go-algorand that referenced this pull request Jan 18, 2023
Changed assembler functionality so that logic.assemble errors when receiving empty input
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

duplicate This issue or pull request already exists Enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants