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  }