github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/execution/exec/tx_execution.go (about) 1 package exec 2 3 import ( 4 "fmt" 5 "reflect" 6 7 "github.com/hyperledger/burrow/binary" 8 9 "github.com/hyperledger/burrow/crypto" 10 "github.com/hyperledger/burrow/event" 11 "github.com/hyperledger/burrow/event/query" 12 "github.com/hyperledger/burrow/execution/errors" 13 "github.com/hyperledger/burrow/execution/names" 14 "github.com/hyperledger/burrow/permission" 15 "github.com/hyperledger/burrow/txs" 16 ) 17 18 func EventStringAccountInput(addr crypto.Address) string { return fmt.Sprintf("Acc/%s/Input", addr) } 19 func EventStringAccountOutput(addr crypto.Address) string { return fmt.Sprintf("Acc/%s/Output", addr) } 20 21 func EventStringAccountCall(addr crypto.Address) string { return fmt.Sprintf("Acc/%s/Call", addr) } 22 func EventStringLogEvent(addr crypto.Address) string { return fmt.Sprintf("Log/%s", addr) } 23 func EventStringTxExecution(txHash []byte) string { return fmt.Sprintf("Execution/Tx/%X", txHash) } 24 func EventStringGovernAccount(addr *crypto.Address) string { return fmt.Sprintf("Govern/Acc/%v", addr) } 25 26 func NewTxExecution(txEnv *txs.Envelope) *TxExecution { 27 return &TxExecution{ 28 TxHeader: &TxHeader{ 29 TxHash: txEnv.Tx.Hash(), 30 TxType: txEnv.Tx.Type(), 31 }, 32 Envelope: txEnv, 33 Receipt: txEnv.Tx.GenerateReceipt(), 34 } 35 } 36 37 func (txe *TxExecution) StreamEvents() []*StreamEvent { 38 var ses []*StreamEvent 39 ses = append(ses, 40 &StreamEvent{ 41 BeginTx: &BeginTx{ 42 TxHeader: txe.TxHeader, 43 NumEvents: uint64(len(txe.Events)), 44 Exception: txe.Exception, 45 Result: txe.Result, 46 }, 47 }, 48 &StreamEvent{ 49 Envelope: txe.Envelope, 50 }, 51 ) 52 for _, ev := range txe.Events { 53 ses = append(ses, &StreamEvent{ 54 Event: ev, 55 }) 56 } 57 for _, txeNested := range txe.TxExecutions { 58 ses = append(ses, txeNested.StreamEvents()...) 59 } 60 return append(ses, &StreamEvent{ 61 EndTx: &EndTx{ 62 TxHash: txe.TxHash, 63 }, 64 }) 65 } 66 67 func (*TxExecution) EventType() EventType { 68 return TypeTxExecution 69 } 70 71 func (txe *TxExecution) GetTxHash() binary.HexBytes { 72 if txe == nil || txe.TxHeader == nil { 73 return nil 74 } 75 return txe.TxHeader.TxHash 76 } 77 78 func (txe *TxExecution) Header(eventType EventType, eventID string, exception *errors.Exception) *Header { 79 return &Header{ 80 TxType: txe.GetTxType(), 81 TxHash: txe.GetTxHash(), 82 Height: txe.GetHeight(), 83 EventType: eventType, 84 EventID: eventID, 85 Exception: exception, 86 } 87 } 88 89 // Emit events 90 func (txe *TxExecution) Input(address crypto.Address, exception *errors.Exception) { 91 txe.Append(&Event{ 92 Header: txe.Header(TypeAccountInput, EventStringAccountInput(address), exception), 93 Input: &InputEvent{ 94 Address: address, 95 }, 96 }) 97 } 98 99 func (txe *TxExecution) Output(address crypto.Address, exception *errors.Exception) { 100 txe.Append(&Event{ 101 Header: txe.Header(TypeAccountOutput, EventStringAccountOutput(address), exception), 102 Output: &OutputEvent{ 103 Address: address, 104 }, 105 }) 106 } 107 108 func (txe *TxExecution) Log(log *LogEvent) error { 109 txe.Append(&Event{ 110 Header: txe.Header(TypeLog, EventStringLogEvent(log.Address), nil), 111 Log: log, 112 }) 113 return nil 114 } 115 116 func (txe *TxExecution) Call(call *CallEvent, exception *errors.Exception) error { 117 txe.Append(&Event{ 118 Header: txe.Header(TypeCall, EventStringAccountCall(call.CallData.Callee), exception), 119 Call: call, 120 }) 121 return nil 122 } 123 124 func (txe *TxExecution) GovernAccount(governAccount *GovernAccountEvent, exception *errors.Exception) { 125 txe.Append(&Event{ 126 Header: txe.Header(TypeGovernAccount, EventStringGovernAccount(governAccount.AccountUpdate.Address), exception), 127 GovernAccount: governAccount, 128 }) 129 } 130 131 func (txe *TxExecution) Print(print *PrintEvent) error { 132 txe.Append(&Event{ 133 Header: txe.Header(TypePrint, EventStringLogEvent(print.Address), nil), 134 Print: print, 135 }) 136 return nil 137 } 138 139 // Errors pushed to TxExecutions end up in merkle state so it is essential that they are deterministic and independent 140 // of the code path taken to execution (e.g. replay takes a different path to that of normal consensus reactor so stack 141 // traces may differ - as they may across architectures) 142 func (txe *TxExecution) PushError(err error) bool { 143 if err == nil { 144 return false 145 } 146 if txe.Exception == nil { 147 // Don't forget the nil jig 148 ex := errors.AsException(err) 149 if ex != nil { 150 txe.Exception = ex 151 } 152 } 153 return true 154 } 155 156 func (txe *TxExecution) CallTrace() string { 157 return Events(txe.Events).CallTrace() 158 } 159 160 func (txe *TxExecution) ExceptionalCalls() []*Event { 161 return Events(txe.Events).ExceptionalCalls() 162 } 163 164 func (txe *TxExecution) CallError() *errors.CallError { 165 if txe.Exception == nil { 166 return nil 167 } 168 return &errors.CallError{ 169 CodedError: txe.Exception, 170 NestedErrors: Events(txe.Events).NestedCallErrors(), 171 } 172 } 173 174 func (txe *TxExecution) TaggedEvents() Events { 175 return txe.Events 176 } 177 178 // Set result 179 func (txe *TxExecution) Return(returnValue []byte, gasUsed uint64) { 180 if txe.Result == nil { 181 txe.Result = &Result{} 182 } 183 txe.Result.Return = returnValue 184 txe.Result.GasUsed = gasUsed 185 } 186 187 func (txe *TxExecution) Name(entry *names.Entry) { 188 if txe.Result == nil { 189 txe.Result = &Result{} 190 } 191 txe.Result.NameEntry = entry 192 } 193 194 func (txe *TxExecution) Permission(permArgs *permission.PermArgs) { 195 if txe.Result == nil { 196 txe.Result = &Result{} 197 } 198 txe.Result.PermArgs = permArgs 199 } 200 201 func (txe *TxExecution) Append(tail ...*Event) { 202 for i, ev := range tail { 203 if ev != nil && ev.Header != nil { 204 ev.Header.Index = uint64(len(txe.Events) + i) 205 ev.Header.Height = txe.GetHeight() 206 } 207 } 208 txe.Events = append(txe.Events, tail...) 209 } 210 211 // Tags 212 func (txe *TxExecution) Get(key string) (interface{}, bool) { 213 switch key { 214 case event.EventIDKey: 215 return EventStringTxExecution(txe.TxHash), true 216 case event.EventTypeKey: 217 return txe.EventType(), true 218 } 219 return query.GetReflect(reflect.ValueOf(txe), key) 220 } 221 222 func QueryForTxExecution(txHash []byte) query.Queryable { 223 return event.QueryForEventID(EventStringTxExecution(txHash)) 224 }