github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/types/events.go (about)

     1  package types
     2  
     3  import (
     4  	"encoding/hex"
     5  
     6  	"github.com/onflow/cadence/runtime/common"
     7  	gethCommon "github.com/onflow/go-ethereum/common"
     8  	"github.com/onflow/go-ethereum/rlp"
     9  
    10  	"github.com/onflow/cadence"
    11  
    12  	"github.com/onflow/flow-go/model/flow"
    13  )
    14  
    15  const (
    16  	EventTypeBlockExecuted       flow.EventType = "EVM.BlockExecuted"
    17  	EventTypeTransactionExecuted flow.EventType = "EVM.TransactionExecuted"
    18  )
    19  
    20  type EventPayload interface {
    21  	// ToCadence converts the event to Cadence event
    22  	ToCadence(location common.Location) (cadence.Event, error)
    23  }
    24  
    25  type Event struct {
    26  	Etype   flow.EventType
    27  	Payload EventPayload
    28  }
    29  
    30  // todo we might have to break this event into two (tx included /tx executed) if size becomes an issue
    31  
    32  type transactionEvent struct {
    33  	Payload     []byte  // transaction RLP-encoded payload
    34  	Result      *Result // transaction execution result
    35  	BlockHeight uint64
    36  	BlockHash   gethCommon.Hash
    37  }
    38  
    39  // NewTransactionEvent creates a new transaction event with the given parameters
    40  // - result: the result of the transaction execution
    41  // - payload: the RLP-encoded payload of the transaction
    42  // - blockHeight: the height of the block where the transaction is included
    43  // - blockHash: the hash of the block where the transaction is included
    44  func NewTransactionEvent(
    45  	result *Result,
    46  	payload []byte,
    47  	blockHeight uint64,
    48  	blockHash gethCommon.Hash,
    49  ) *Event {
    50  	return &Event{
    51  		Etype: EventTypeTransactionExecuted,
    52  		Payload: &transactionEvent{
    53  			BlockHeight: blockHeight,
    54  			BlockHash:   blockHash,
    55  			Payload:     payload,
    56  			Result:      result,
    57  		},
    58  	}
    59  }
    60  
    61  func (p *transactionEvent) ToCadence(location common.Location) (cadence.Event, error) {
    62  	var encodedLogs []byte
    63  	var err error
    64  	if len(p.Result.Logs) > 0 {
    65  		encodedLogs, err = rlp.EncodeToBytes(p.Result.Logs)
    66  		if err != nil {
    67  			return cadence.Event{}, err
    68  		}
    69  	}
    70  
    71  	deployedAddress := cadence.String("")
    72  	if p.Result.DeployedContractAddress != nil {
    73  		deployedAddress = cadence.String(p.Result.DeployedContractAddress.String())
    74  	}
    75  
    76  	eventType := cadence.NewEventType(
    77  		location,
    78  		string(EventTypeTransactionExecuted),
    79  		[]cadence.Field{
    80  			cadence.NewField("hash", cadence.StringType),
    81  			cadence.NewField("index", cadence.UInt16Type),
    82  			cadence.NewField("type", cadence.UInt8Type),
    83  			cadence.NewField("payload", cadence.StringType),
    84  			cadence.NewField("errorCode", cadence.UInt16Type),
    85  			cadence.NewField("gasConsumed", cadence.UInt64Type),
    86  			cadence.NewField("contractAddress", cadence.StringType),
    87  			cadence.NewField("logs", cadence.StringType),
    88  			cadence.NewField("blockHeight", cadence.UInt64Type),
    89  			// todo we can remove hash and just reference block by height (evm-gateway dependency)
    90  			cadence.NewField("blockHash", cadence.StringType),
    91  		},
    92  		nil,
    93  	)
    94  
    95  	return cadence.NewEvent([]cadence.Value{
    96  		cadence.String(p.Result.TxHash.String()),
    97  		cadence.NewUInt16(p.Result.Index),
    98  		cadence.NewUInt8(p.Result.TxType),
    99  		cadence.String(hex.EncodeToString(p.Payload)),
   100  		cadence.NewUInt16(uint16(p.Result.ResultSummary().ErrorCode)),
   101  		cadence.NewUInt64(p.Result.GasConsumed),
   102  		deployedAddress,
   103  		cadence.String(hex.EncodeToString(encodedLogs)),
   104  		cadence.NewUInt64(p.BlockHeight),
   105  		cadence.String(p.BlockHash.String()),
   106  	}).WithType(eventType), nil
   107  }
   108  
   109  type blockEvent struct {
   110  	*Block
   111  }
   112  
   113  // NewBlockEvent creates a new block event with the given block as payload.
   114  func NewBlockEvent(block *Block) *Event {
   115  	return &Event{
   116  		Etype:   EventTypeBlockExecuted,
   117  		Payload: &blockEvent{block},
   118  	}
   119  }
   120  
   121  func (p *blockEvent) ToCadence(location common.Location) (cadence.Event, error) {
   122  	hashes := make([]cadence.Value, len(p.TransactionHashes))
   123  	for i, hash := range p.TransactionHashes {
   124  		hashes[i] = cadence.String(hash.String())
   125  	}
   126  
   127  	blockHash, err := p.Hash()
   128  	if err != nil {
   129  		return cadence.Event{}, err
   130  	}
   131  
   132  	eventType := cadence.NewEventType(
   133  		location,
   134  		string(EventTypeBlockExecuted),
   135  		[]cadence.Field{
   136  			cadence.NewField("height", cadence.UInt64Type),
   137  			cadence.NewField("hash", cadence.StringType),
   138  			cadence.NewField("timestamp", cadence.UInt64Type),
   139  			cadence.NewField("totalSupply", cadence.IntType),
   140  			cadence.NewField("totalGasUsed", cadence.UInt64Type),
   141  			cadence.NewField("parentHash", cadence.StringType),
   142  			cadence.NewField("receiptRoot", cadence.StringType),
   143  			cadence.NewField(
   144  				"transactionHashes",
   145  				cadence.NewVariableSizedArrayType(cadence.StringType),
   146  			),
   147  		},
   148  		nil,
   149  	)
   150  
   151  	return cadence.NewEvent([]cadence.Value{
   152  		cadence.NewUInt64(p.Height),
   153  		cadence.String(blockHash.String()),
   154  		cadence.NewUInt64(p.Timestamp),
   155  		cadence.NewIntFromBig(p.TotalSupply),
   156  		cadence.NewUInt64(p.TotalGasUsed),
   157  		cadence.String(p.ParentBlockHash.String()),
   158  		cadence.String(p.ReceiptRoot.String()),
   159  		cadence.NewArray(hashes).WithType(cadence.NewVariableSizedArrayType(cadence.StringType)),
   160  	}).WithType(eventType), nil
   161  }
   162  
   163  type BlockEventPayload struct {
   164  	Height            uint64           `cadence:"height"`
   165  	Hash              string           `cadence:"hash"`
   166  	Timestamp         uint64           `cadence:"timestamp"`
   167  	TotalSupply       cadence.Int      `cadence:"totalSupply"`
   168  	TotalGasUsed      uint64           `cadence:"totalGasUsed"`
   169  	ParentBlockHash   string           `cadence:"parentHash"`
   170  	ReceiptRoot       string           `cadence:"receiptRoot"`
   171  	TransactionHashes []cadence.String `cadence:"transactionHashes"`
   172  }
   173  
   174  // DecodeBlockEventPayload decodes Cadence event into block event payload.
   175  func DecodeBlockEventPayload(event cadence.Event) (*BlockEventPayload, error) {
   176  	var block BlockEventPayload
   177  	err := cadence.DecodeFields(event, &block)
   178  	return &block, err
   179  }
   180  
   181  type TransactionEventPayload struct {
   182  	Hash            string `cadence:"hash"`
   183  	Index           uint16 `cadence:"index"`
   184  	TransactionType uint8  `cadence:"type"`
   185  	Payload         string `cadence:"payload"`
   186  	ErrorCode       uint16 `cadence:"errorCode"`
   187  	GasConsumed     uint64 `cadence:"gasConsumed"`
   188  	ContractAddress string `cadence:"contractAddress"`
   189  	Logs            string `cadence:"logs"`
   190  	BlockHeight     uint64 `cadence:"blockHeight"`
   191  	BlockHash       string `cadence:"blockHash"`
   192  }
   193  
   194  // DecodeTransactionEventPayload decodes Cadence event into transaction event payload.
   195  func DecodeTransactionEventPayload(event cadence.Event) (*TransactionEventPayload, error) {
   196  	var tx TransactionEventPayload
   197  	err := cadence.DecodeFields(event, &tx)
   198  	return &tx, err
   199  }