github.com/datachainlab/burrow@v0.25.0/execution/exec/tx_execution.go (about) 1 package exec 2 3 import ( 4 "fmt" 5 "strings" 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 DecodeTxExecution(bs []byte) (*TxExecution, error) { 38 txe := new(TxExecution) 39 err := cdc.UnmarshalBinaryBare(bs, txe) 40 if err != nil { 41 return nil, err 42 } 43 return txe, nil 44 } 45 46 func (txe *TxExecution) StreamEvents() StreamEvents { 47 var ses StreamEvents 48 ses = append(ses, &StreamEvent{ 49 BeginTx: &BeginTx{ 50 TxHeader: txe.TxHeader, 51 Exception: txe.Exception, 52 Result: txe.Result, 53 }, 54 }) 55 for _, ev := range txe.Events { 56 ses = append(ses, &StreamEvent{ 57 Event: ev, 58 }) 59 } 60 for _, txeNested := range txe.TxExecutions { 61 ses = append(ses, txeNested.StreamEvents()...) 62 } 63 return append(ses, &StreamEvent{ 64 EndTx: &EndTx{ 65 TxHash: txe.TxHash, 66 }, 67 }) 68 } 69 70 func (txe *TxExecution) Encode() ([]byte, error) { 71 return cdc.MarshalBinaryBare(txe) 72 } 73 74 func (*TxExecution) EventType() EventType { 75 return TypeTxExecution 76 } 77 78 func (txe *TxExecution) GetTxHash() binary.HexBytes { 79 if txe == nil || txe.TxHeader == nil { 80 return nil 81 } 82 return txe.TxHeader.TxHash 83 } 84 85 func (txe *TxExecution) Header(eventType EventType, eventID string, exception *errors.Exception) *Header { 86 return &Header{ 87 TxType: txe.GetTxType(), 88 TxHash: txe.GetTxHash(), 89 Height: txe.GetHeight(), 90 EventType: eventType, 91 EventID: eventID, 92 Exception: exception, 93 } 94 } 95 96 // Emit events 97 func (txe *TxExecution) Input(address crypto.Address, exception *errors.Exception) { 98 txe.Append(&Event{ 99 Header: txe.Header(TypeAccountInput, EventStringAccountInput(address), exception), 100 Input: &InputEvent{ 101 Address: address, 102 }, 103 }) 104 } 105 106 func (txe *TxExecution) Output(address crypto.Address, exception *errors.Exception) { 107 txe.Append(&Event{ 108 Header: txe.Header(TypeAccountOutput, EventStringAccountOutput(address), exception), 109 Output: &OutputEvent{ 110 Address: address, 111 }, 112 }) 113 } 114 115 func (txe *TxExecution) Log(log *LogEvent) error { 116 txe.Append(&Event{ 117 Header: txe.Header(TypeLog, EventStringLogEvent(log.Address), nil), 118 Log: log, 119 }) 120 return nil 121 } 122 123 func (txe *TxExecution) Call(call *CallEvent, exception *errors.Exception) error { 124 txe.Append(&Event{ 125 Header: txe.Header(TypeCall, EventStringAccountCall(call.CallData.Callee), exception), 126 Call: call, 127 }) 128 return nil 129 } 130 131 func (txe *TxExecution) GovernAccount(governAccount *GovernAccountEvent, exception *errors.Exception) { 132 txe.Append(&Event{ 133 Header: txe.Header(TypeGovernAccount, EventStringGovernAccount(governAccount.AccountUpdate.Address), exception), 134 GovernAccount: governAccount, 135 }) 136 } 137 138 // Errors pushed to TxExecutions end up in merkle state so it is essential that they are deterministic and independent 139 // of the code path taken to execution (e.g. replay takes a different path to that of normal consensus reactor so stack 140 // traces may differ - as they may across architectures) 141 func (txe *TxExecution) PushError(err error) { 142 if txe.Exception == nil { 143 // Don't forget the nil jig 144 ex := errors.AsException(err) 145 if ex != nil { 146 txe.Exception = ex 147 } 148 } 149 } 150 151 func (txe *TxExecution) CallTrace() string { 152 var calls []string 153 for _, ev := range txe.Events { 154 if ev.Call != nil { 155 ex := "" 156 if ev.Header.Exception != nil { 157 ex = fmt.Sprintf(" [%v]", ev.Header.Exception) 158 } 159 calls = append(calls, fmt.Sprintf("%v: %v -> %v: %v%s", 160 ev.Call.CallType, ev.Call.CallData.Caller, ev.Call.CallData.Callee, ev.Call.Return, ex)) 161 } 162 } 163 return strings.Join(calls, "\n") 164 } 165 166 func (txe *TxExecution) ExceptionalCalls() []*Event { 167 var exCalls []*Event 168 for _, ev := range txe.Events { 169 if ev.Call != nil && ev.Header.Exception != nil { 170 exCalls = append(exCalls, ev) 171 } 172 } 173 return exCalls 174 } 175 176 func (txe *TxExecution) CallError() *errors.CallError { 177 if txe.Exception == nil { 178 return nil 179 } 180 var nestedErrors []errors.NestedCallError 181 for _, ev := range txe.Events { 182 if ev.Call != nil && ev.Header.Exception != nil { 183 nestedErrors = append(nestedErrors, errors.NestedCallError{ 184 CodedError: ev.Header.Exception, 185 Caller: ev.Call.CallData.Caller, 186 Callee: ev.Call.CallData.Callee, 187 StackDepth: ev.Call.StackDepth, 188 }) 189 } 190 } 191 return &errors.CallError{ 192 CodedError: txe.Exception, 193 NestedErrors: nestedErrors, 194 } 195 } 196 197 // Set result 198 func (txe *TxExecution) Return(returnValue []byte, gasUsed uint64) { 199 if txe.Result == nil { 200 txe.Result = &Result{} 201 } 202 txe.Result.Return = returnValue 203 txe.Result.GasUsed = gasUsed 204 } 205 206 func (txe *TxExecution) Name(entry *names.Entry) { 207 if txe.Result == nil { 208 txe.Result = &Result{} 209 } 210 txe.Result.NameEntry = entry 211 } 212 213 func (txe *TxExecution) Permission(permArgs *permission.PermArgs) { 214 if txe.Result == nil { 215 txe.Result = &Result{} 216 } 217 txe.Result.PermArgs = permArgs 218 } 219 220 func (txe *TxExecution) Append(tail ...*Event) { 221 for i, ev := range tail { 222 if ev != nil && ev.Header != nil { 223 ev.Header.Index = uint64(len(txe.Events) + i) 224 ev.Header.Height = txe.GetHeight() 225 } 226 } 227 txe.Events = append(txe.Events, tail...) 228 } 229 230 // Tags 231 type TaggedTxExecution struct { 232 query.Tagged 233 *TxExecution 234 } 235 236 func (txe *TxExecution) Tagged() *TaggedTxExecution { 237 var tagged query.Tagged = query.TagMap{} 238 if txe != nil { 239 tagged = query.MergeTags( 240 query.TagMap{ 241 event.EventIDKey: EventStringTxExecution(txe.TxHash), 242 event.EventTypeKey: txe.EventType()}, 243 query.MustReflectTags(txe), 244 query.MustReflectTags(txe.TxHeader), 245 txe.Envelope.Tagged(), 246 ) 247 } 248 return &TaggedTxExecution{ 249 Tagged: tagged, 250 TxExecution: txe, 251 } 252 } 253 254 func (txe *TxExecution) TaggedEvents() TaggedEvents { 255 tevs := make(TaggedEvents, len(txe.Events)) 256 for i, ev := range txe.Events { 257 tevs[i] = ev.Tagged() 258 } 259 return tevs 260 } 261 262 func QueryForTxExecution(txHash []byte) query.Queryable { 263 return event.QueryForEventID(EventStringTxExecution(txHash)) 264 }