summaryrefslogtreecommitdiff
path: root/data/transactions/logic/tracer.go
blob: 37603c79442c01193ec6a6a7e4644b54cab64cbe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// Copyright (C) 2019-2023 Algorand, Inc.
// This file is part of go-algorand
//
// go-algorand is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// go-algorand is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with go-algorand.  If not, see <https://www.gnu.org/licenses/>.

package logic

import (
	"github.com/algorand/go-algorand/data/bookkeeping"
	"github.com/algorand/go-algorand/data/transactions"
	"github.com/algorand/go-algorand/ledger/ledgercore"
)

// EvalTracer functions are called by eval function during AVM program execution, if a tracer
// is provided.
//
// Refer to the lifecycle graph below for the sequence in which hooks are called.
//
// NOTE: Arguments given to Tracer hooks (EvalParams and EvalContext) are passed by reference,
// they are not copies. It is therefore the responsibility of the tracer implementation to NOT
// modify the state of the structs passed to them. Additionally, hooks are responsible for copying
// the information they need from the argument structs. No guarantees are made that the referenced
// state will not change between hook calls. This decision was made in an effort to reduce the
// performance impact of tracers.
//
//	LOGICSIG LIFECYCLE GRAPH
//	┌─────────────────────────┐
//	│ LogicSig Evaluation     │
//	├─────────────────────────┤
//	│ > BeforeProgram         │
//	│                         │
//	│  ┌───────────────────┐  │
//	│  │ Teal Operation    │  │
//	│  ├───────────────────┤  │
//	│  │ > BeforeOpcode    │  │
//	│  │                   │  │
//	│  │ > AfterOpcode     │  │
//	│  └───────────────────┘  │
//	|   ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞   │
//	│                         │
//	│ > AfterProgram          │
//	└─────────────────────────┘
//
//	APP LIFECYCLE GRAPH
//	┌──────────────────────────────────────────────────────┐
//	│ Transaction Evaluation                               │
//	├──────────────────────────────────────────────────────┤
//	│ > BeforeTxnGroup                                     │
//	│                                                      │
//	│  ┌────────────────────────────────────────────────┐  │
//	│  │ > BeforeTxn                                    │  │
//	│  │                                                │  │
//	│  │  ┌──────────────────────────────────────────┐  │  │
//	│  │  │ ? App Call                               │  │  │
//	│  │  ├──────────────────────────────────────────┤  │  │
//	│  │  │ > BeforeProgram                          │  │  │
//	│  │  │                                          │  │  │
//	│  │  │  ┌────────────────────────────────────┐  │  │  │
//	│  │  │  │ Teal Operation                     │  │  │  │
//	│  │  │  ├────────────────────────────────────┤  │  │  │
//	│  │  │  │ > BeforeOpcode                     │  │  │  │
//	│  │  │  │  ┌──────────────────────────────┐  │  │  │  │
//	│  │  │  │  │ ? Inner Transaction Group    │  │  │  │  │
//	│  │  │  │  ├──────────────────────────────┤  │  │  │  │
//	│  │  │  │  │ > BeforeTxnGroup             │  │  │  │  │
//	│  │  │  │  │  ┌────────────────────────┐  │  │  │  │  │
//	│  │  │  │  │  │ Transaction Evaluation │  │  │  │  │  │
//	│  │  │  │  │  ├────────────────────────┤  │  │  │  │  │
//	│  │  │  │  │  │ ...                    │  │  │  │  │  │
//	│  │  │  │  │  └────────────────────────┘  │  │  │  │  │
//	│  │  │  │  │    ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞    │  │  │  │  │
//	│  │  │  │  │                              │  │  │  │  │
//	│  │  │  │  │ > AfterTxnGroup              │  │  │  │  │
//	│  │  │  │  └──────────────────────────────┘  │  │  │  │
//	│  │  │  │ > AfterOpcode                      │  │  │  │
//	│  │  │  └────────────────────────────────────┘  │  │  │
//	│  │  │    ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞    │  │  │
//	│  │  │                                          │  │  │
//	│  │  │ > AfterProgram                           │  │  │
//	│  │  └──────────────────────────────────────────┘  │  │
//	|  |    ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞    │  |
//	│  │                                                │  │
//	│  │ > AfterTxn                                     │  │
//	│  └────────────────────────────────────────────────┘  │
//	|    ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞  ⁞    |
//	│                                                      │
//	│ > AfterTxnGroup                                      │
//	└──────────────────────────────────────────────────────┘
//
//	Block Lifecycle Graph
//	┌──────────────────────────────────────────────────────┐
//	│ Block Evaluation                                     │
//	│  ┌────────────────────────────────────────────────┐  │
//	│  │ > BeforeBlock                                  │  │
//	│  │                                                │  │
//	│  │  ┌──────────────────────────────────────────┐  │  │
//	│  │  │ > Transaction/LogicSig Lifecycle         │  │  │
//	│  │  ├──────────────────────────────────────────┤  │  │
//	│  │  │  ┌────────────────────────────────────┐  │  │  │
//	│  │  │  │ ...                                │  │  │  │
//	│  │  │  └────────────────────────────────────┘  │  │  │
//	│  │  └──────────────────────────────────────────┘  │  │
//	│  ├────────────────────────────────────────────────│  │
//	│  │ > AfterBlock                                   │  │
//	│  └────────────────────────────────────────────────┘  │
//	└──────────────────────────────────────────────────────┘
type EvalTracer interface {
	// BeforeBlock is called once at the beginning of block evaluation. It is passed the block header.
	BeforeBlock(hdr *bookkeeping.BlockHeader)

	// BeforeTxnGroup is called before a transaction group is executed. This includes both top-level
	// and inner transaction groups. The argument ep is the EvalParams object for the group; if the
	// group is an inner group, this is the EvalParams object for the inner group.
	//
	// Each transaction within the group calls BeforeTxn and subsequent hooks, as described in the
	// lifecycle diagram.
	BeforeTxnGroup(ep *EvalParams)

	// AfterTxnGroup is called after a transaction group has been executed. This includes both
	// top-level and inner transaction groups. The argument ep is the EvalParams object for the
	// group; if the group is an inner group, this is the EvalParams object for the inner group.
	// For top-level transaction groups, the deltas argument is the ledgercore.StateDelta changes
	// that occurred because of this transaction group. For inner transaction groups, this argument
	// is nil.
	AfterTxnGroup(ep *EvalParams, deltas *ledgercore.StateDelta, evalError error)

	// BeforeTxn is called before a transaction is executed.
	//
	// groupIndex refers to the index of the transaction in the transaction group that will be executed.
	BeforeTxn(ep *EvalParams, groupIndex int)

	// AfterTxn is called after a transaction has been executed.
	//
	// groupIndex refers to the index of the transaction in the transaction group that was just executed.
	// ad is the ApplyData result of the transaction; prefer using this instead of
	// ep.TxnGroup[groupIndex].ApplyData, since it may not be populated at this point.
	AfterTxn(ep *EvalParams, groupIndex int, ad transactions.ApplyData, evalError error)

	// BeforeProgram is called before an app or LogicSig program is evaluated.
	BeforeProgram(cx *EvalContext)

	// AfterProgram is called after an app or LogicSig program is evaluated.
	AfterProgram(cx *EvalContext, pass bool, evalError error)

	// BeforeOpcode is called before the op is evaluated
	BeforeOpcode(cx *EvalContext)

	// AfterOpcode is called after the op has been evaluated
	AfterOpcode(cx *EvalContext, evalError error)

	// 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)
}

// NullEvalTracer implements EvalTracer, but all of its hook methods do nothing
type NullEvalTracer struct{}

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

// BeforeTxnGroup does nothing
func (n NullEvalTracer) BeforeTxnGroup(ep *EvalParams) {}

// AfterTxnGroup does nothing
func (n NullEvalTracer) AfterTxnGroup(ep *EvalParams, deltas *ledgercore.StateDelta, evalError error) {
}

// BeforeTxn does nothing
func (n NullEvalTracer) BeforeTxn(ep *EvalParams, groupIndex int) {}

// AfterTxn does nothing
func (n NullEvalTracer) AfterTxn(ep *EvalParams, groupIndex int, ad transactions.ApplyData, evalError error) {
}

// BeforeProgram does nothing
func (n NullEvalTracer) BeforeProgram(cx *EvalContext) {}

// AfterProgram does nothing
func (n NullEvalTracer) AfterProgram(cx *EvalContext, pass bool, evalError error) {}

// BeforeOpcode does nothing
func (n NullEvalTracer) BeforeOpcode(cx *EvalContext) {}

// AfterOpcode does nothing
func (n NullEvalTracer) AfterOpcode(cx *EvalContext, evalError error) {}

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