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

eval: add DetailedEvalErrors method to EvalTracer interface #6172

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 5 additions & 1 deletion data/pools/transactionPool.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
cond sync.Cond
expiredTxCount map[basics.Round]int
pendingBlockEvaluator BlockEvaluator
evalTracer logic.EvalTracer
numPendingWholeBlocks basics.Round
feePerByte atomic.Uint64
feeThresholdMultiplier uint64
Expand Down Expand Up @@ -140,6 +141,9 @@
log: log,
vac: vac,
}
if cfg.EnableDeveloperAPI {
pool.evalTracer = logic.EvalErrorDetailsTracer{}

Check warning on line 145 in data/pools/transactionPool.go

View check run for this annotation

Codecov / codecov/patch

data/pools/transactionPool.go#L145

Added line #L145 was not covered by tests
}
pool.cond.L = &pool.mu
pool.assemblyCond.L = &pool.assemblyMu
pool.recomputeBlockEvaluator(nil, 0)
Expand Down Expand Up @@ -732,7 +736,7 @@
if hint < 0 || int(knownCommitted) < 0 {
hint = 0
}
pool.pendingBlockEvaluator, err = pool.ledger.StartEvaluator(next.BlockHeader, hint, 0, nil)
pool.pendingBlockEvaluator, err = pool.ledger.StartEvaluator(next.BlockHeader, hint, 0, pool.evalTracer)
if err != nil {
// The pendingBlockEvaluator is an interface, and in case of an evaluator error
// we want to remove the interface itself rather then keeping an interface
Expand Down
12 changes: 10 additions & 2 deletions data/transactions/logic/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -1027,8 +1027,16 @@ func (err EvalError) Unwrap() error {
}

func (cx *EvalContext) evalError(err error) error {
pc := cx.pc
details := fmt.Sprintf("pc=%d", pc)
var pc int
var details string
if cx.Tracer != nil && cx.Tracer.DetailedEvalErrors() {
var det string
pc, det = cx.pcDetails()
details = fmt.Sprintf("pc=%d, opcodes=%s", pc, det)
} else {
pc = cx.pc
details = fmt.Sprintf("pc=%d", pc)
}

err = basics.Annotate(err,
"pc", pc,
Expand Down
3 changes: 2 additions & 1 deletion data/transactions/logic/evalStateful_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ func testApps(t *testing.T, programs []string, txgroup []transactions.SignedTxn,
}
}
ep := NewAppEvalParams(transactions.WrapSignedTxnsWithAD(txgroup), proto, &transactions.SpecialAddresses{})
ep.Tracer = EvalErrorDetailsTracer{}
if ledger == nil {
ledger = NewLedger(nil)
}
Expand Down Expand Up @@ -929,7 +930,7 @@ itxn_submit
Stack: []any{uint64(777)},
},
},
"inner-msg": "logic eval error: cannot compare (uint64 to []byte). Details: app=5000, pc=26",
"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
3 changes: 3 additions & 0 deletions data/transactions/logic/mocktracer/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ func (d *Tracer) AfterBlock(hdr *bookkeeping.BlockHeader) {
d.Events = append(d.Events, AfterBlock(hdr.Round))
}

// DetailedEvalErrors returns true, enabling detailed errors in tests.
func (d *Tracer) DetailedEvalErrors() bool { return false }

// copyDeltas makes a deep copy of the given ledgercore.StateDelta pointer, if it's not nil.
// This is inefficient, but it should only be used for testing.
func copyDeltas(deltas *ledgercore.StateDelta) *ledgercore.StateDelta {
Expand Down
13 changes: 13 additions & 0 deletions data/transactions/logic/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ type EvalTracer interface {
// AfterBlock is called after the block has finished evaluation. It will not be called in the event that an evalError
// stops evaluation of the block.
AfterBlock(hdr *bookkeeping.BlockHeader)

// DetailedEvalErrors permits the tracer to enable detailed EvalError messages (including PC with disassembled
// opcodes) by returning true.
DetailedEvalErrors() bool
}

// NullEvalTracer implements EvalTracer, but all of its hook methods do nothing
Expand Down Expand Up @@ -198,3 +202,12 @@ func (n NullEvalTracer) AfterOpcode(cx *EvalContext, evalError error) {}

// AfterBlock does nothing
func (n NullEvalTracer) AfterBlock(hdr *bookkeeping.BlockHeader) {}

// DetailedEvalErrors does nothing
func (n NullEvalTracer) DetailedEvalErrors() bool { return false }

// EvalErrorDetailsTracer enables disassembled details in EvalError messages, and nothing else.
type EvalErrorDetailsTracer struct{ NullEvalTracer }

// DetailedEvalErrors returns true.
func (EvalErrorDetailsTracer) DetailedEvalErrors() bool { return true }
2 changes: 1 addition & 1 deletion ledger/apptxn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ func TestRekeyActionCloseAccount(t *testing.T) {
// do it again, to ensure the lack of authorization is in the right
// place, by matching on the opcode that comes before the itxn_submit we
// want to know failed (it'll be in the error).
dl.txn(&useacct, "logic eval error")
dl.txn(&useacct, "itxn_field Receiver")
})
}

Expand Down
12 changes: 6 additions & 6 deletions ledger/boxtxn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,28 +169,28 @@ func TestBoxCreate(t *testing.T) {
}

dl.txn(adam.Args("check", "adam", "\x00\x00"))
dl.txgroup("logic eval error: assert failed", adam.Noted("one"), adam.Noted("two"))
dl.txgroup("box_create; assert", adam.Noted("one"), adam.Noted("two"))

bobo := call.Args("create", "bobo")
dl.txn(bobo, fmt.Sprintf("invalid Box reference %#x", "bobo"))
bobo.Boxes = []transactions.BoxRef{{Index: 0, Name: []byte("bobo")}}
dl.txn(bobo)
dl.txgroup("logic eval error: assert failed", bobo.Noted("one"), bobo.Noted("two"))
dl.txgroup("box_create; assert", bobo.Noted("one"), bobo.Noted("two"))

dl.beginBlock()
chaz := call.Args("create", "chaz")
chaz.Boxes = []transactions.BoxRef{{Index: 0, Name: []byte("chaz")}}
dl.txn(chaz)
dl.txn(chaz.Noted("again"), "logic eval error: assert failed")
dl.txn(chaz.Noted("again"), "box_create; assert")
dl.endBlock()

// new block
dl.txn(chaz.Noted("again"), "logic eval error: assert failed")
dl.txn(chaz.Noted("again"), "box_create; assert")
dogg := call.Args("create", "dogg")
dogg.Boxes = []transactions.BoxRef{{Index: 0, Name: []byte("dogg")}}
dl.txn(dogg, "below min")
dl.txn(chaz.Args("delete", "chaz"))
dl.txn(chaz.Args("delete", "chaz").Noted("again"), "logic eval error: assert failed")
dl.txn(chaz.Args("delete", "chaz").Noted("again"), "box_del; assert")
dl.txn(dogg)
dl.txn(bobo.Args("delete", "bobo"))

Expand Down Expand Up @@ -229,7 +229,7 @@ func TestBoxRecreate(t *testing.T) {
create := call.Args("create", "adam", "\x04") // box value size is 4 bytes
recreate := call.Args("recreate", "adam", "\x04")

dl.txn(recreate, "logic eval error: assert failed")
dl.txn(recreate, "box_create; !; assert")
dl.txn(create)
dl.txn(recreate)
dl.txn(call.Args("set", "adam", "\x01\x02\x03\x04"))
Expand Down
2 changes: 2 additions & 0 deletions ledger/simple_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/data/committee"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/data/transactions/logic"
"github.com/algorand/go-algorand/data/transactions/verify"
"github.com/algorand/go-algorand/data/txntest"
"github.com/algorand/go-algorand/ledger/eval"
Expand Down Expand Up @@ -91,6 +92,7 @@ func nextBlock(t testing.TB, ledger *Ledger) *eval.BlockEvaluator {
eval, err := eval.StartEvaluator(ledger, nextHdr, eval.EvaluatorOptions{
Generate: true,
Validate: true, // Do the complete checks that a new txn would be subject to
Tracer: logic.EvalErrorDetailsTracer{},
})
require.NoError(t, err)
return eval
Expand Down
2 changes: 2 additions & 0 deletions ledger/simulation/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -555,3 +555,5 @@ func (tracer *evalTracer) AfterProgram(cx *logic.EvalContext, pass bool, evalErr
}
}
}

func (tracer *evalTracer) DetailedEvalErrors() bool { return true }
Loading