Skip to content

Commit

Permalink
add DetailedEvalErrors method to EvalTracer interface
Browse files Browse the repository at this point in the history
  • Loading branch information
cce committed Nov 16, 2024
1 parent 64dc085 commit 8219abb
Show file tree
Hide file tree
Showing 9 changed files with 43 additions and 11 deletions.
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 @@ type TransactionPool struct {
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 @@ func MakeTransactionPool(ledger *ledger.Ledger, cfg config.Local, log logging.Lo
log: log,
vac: vac,
}
if cfg.EnableDeveloperAPI {
pool.evalTracer = logic.EvalErrorDetailsTracer{}
}
pool.cond.L = &pool.mu
pool.assemblyCond.L = &pool.assemblyMu
pool.recomputeBlockEvaluator(nil, 0)
Expand Down Expand Up @@ -732,7 +736,7 @@ func (pool *TransactionPool) recomputeBlockEvaluator(committedTxIDs map[transact
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
2 changes: 2 additions & 0 deletions data/transactions/logic/mocktracer/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ func (d *Tracer) AfterBlock(hdr *bookkeeping.BlockHeader) {
d.Events = append(d.Events, AfterBlock(hdr.Round))
}

func (d *Tracer) DisassembleEvalError() 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 }

0 comments on commit 8219abb

Please sign in to comment.