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  }