Skip to content

Commit

Permalink
Merge pull request #5779 from onflow/gregor/evm/event-field-tx
Browse files Browse the repository at this point in the history
[EVM] Optimize event data
  • Loading branch information
devbugging authored Apr 26, 2024
2 parents 5f128e3 + 17430c7 commit ed9f53f
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 149 deletions.
21 changes: 8 additions & 13 deletions fvm/evm/evm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ func TestEVMRun(t *testing.T) {
cadenceEvent, ok := ev.(cadence.Event)
require.True(t, ok)

event := txEventType{}
require.NoError(t, cadence.DecodeFields(cadenceEvent, &event))
require.NotEmpty(t, event.TransactionHash)
event, err := types.DecodeTransactionEventPayload(cadenceEvent)
require.NoError(t, err)
require.NotEmpty(t, event.Hash)

// append the state
snapshot = snapshot.Append(state)
Expand Down Expand Up @@ -338,9 +338,9 @@ func TestEVMRun(t *testing.T) {
cadenceEvent, ok := ev.(cadence.Event)
require.True(t, ok)

event := txEventType{}
require.NoError(t, cadence.DecodeFields(cadenceEvent, &event))
require.NotEmpty(t, event.TransactionHash)
event, err := types.DecodeTransactionEventPayload(cadenceEvent)
require.NoError(t, err)
require.NotEmpty(t, event.Hash)

encodedLogs, err := hex.DecodeString(event.Logs)
require.NoError(t, err)
Expand Down Expand Up @@ -447,8 +447,8 @@ func TestEVMBatchRun(t *testing.T) {
cadenceEvent, ok := ev.(cadence.Event)
require.True(t, ok)

event := txEventType{}
require.NoError(t, cadence.DecodeFields(cadenceEvent, &event))
event, err := types.DecodeTransactionEventPayload(cadenceEvent)
require.NoError(t, err)

encodedLogs, err := hex.DecodeString(event.Logs)
require.NoError(t, err)
Expand Down Expand Up @@ -1901,8 +1901,3 @@ func RunWithNewEnvironment(
})
})
}

type txEventType struct {
TransactionHash string `cadence:"transactionHash"`
Logs string `cadence:"logs"`
}
34 changes: 11 additions & 23 deletions fvm/evm/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,19 +215,18 @@ func (h *ContractHandler) batchRun(rlpEncodedTxs [][]byte, coinbase types.Addres
if r.Invalid() { // don't emit events for invalid tx
continue
}
err = h.emitEvent(types.NewTransactionExecutedEvent(
bp.Height,
err = h.emitEvent(types.NewTransactionEvent(
r,
rlpEncodedTxs[i],
bp.Height,
blockHash,
r.TxHash,
r,
))
if err != nil {
return nil, err
}
}

err = h.emitEvent(types.NewBlockExecutedEvent(bp))
err = h.emitEvent(types.NewBlockEvent(bp))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -295,27 +294,22 @@ func (h *ContractHandler) run(

bp.AppendTxHash(res.TxHash)

// Populate receipt root
// populate receipt root
bp.PopulateReceiptRoot([]*types.Result{res})
bp.CalculateGasUsage([]types.Result{*res})

blockHash, err := bp.Hash()
if err != nil {
return nil, err
}

// step 4 - emit events
err = h.emitEvent(types.NewTransactionExecutedEvent(
bp.Height,
rlpEncodedTx,
blockHash,
res.TxHash,
res,
))
err = h.emitEvent(types.NewTransactionEvent(res, rlpEncodedTx, bp.Height, blockHash))
if err != nil {
return nil, err
}

err = h.emitEvent(types.NewBlockExecutedEvent(bp))
err = h.emitEvent(types.NewBlockEvent(bp))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -357,7 +351,7 @@ func (h *ContractHandler) meterGasUsage(res *types.Result) error {
}

func (h *ContractHandler) emitEvent(event *types.Event) error {
ev, err := event.Payload.CadenceEvent()
ev, err := event.Payload.ToCadence()
if err != nil {
return err
}
Expand Down Expand Up @@ -458,19 +452,13 @@ func (h *ContractHandler) executeAndHandleCall(
}

err = h.emitEvent(
types.NewTransactionExecutedEvent(
bp.Height,
encoded,
blockHash,
res.TxHash,
res,
),
types.NewTransactionEvent(res, encoded, bp.Height, blockHash),
)
if err != nil {
return nil, err
}

err = h.emitEvent(types.NewBlockExecutedEvent(bp))
err = h.emitEvent(types.NewBlockEvent(bp))
if err != nil {
return nil, err
}
Expand Down
10 changes: 10 additions & 0 deletions fvm/evm/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ type Block struct {

// transaction hashes
TransactionHashes []gethCommon.Hash

// stores gas used by all transactions included in the block.
TotalGasUsed uint64
}

// ToBytes encodes the block into bytes
Expand Down Expand Up @@ -65,6 +68,13 @@ func (b *Block) PopulateReceiptRoot(results []*Result) {
b.ReceiptRoot = gethTypes.DeriveSha(receipts, gethTrie.NewStackTrie(nil))
}

// CalculateGasUsage sums up all the gas transactions in the block used
func (b *Block) CalculateGasUsage(results []Result) {
for _, res := range results {
b.TotalGasUsed += res.GasConsumed
}
}

// AppendTxHash appends a transaction hash to the list of transaction hashes of the block
func (b *Block) AppendTxHash(txHash gethCommon.Hash) {
b.TransactionHashes = append(b.TransactionHashes, txHash)
Expand Down
1 change: 1 addition & 0 deletions fvm/evm/types/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func Test_BlockHash(t *testing.T) {
Height: 1,
TotalSupply: big.NewInt(1000),
ReceiptRoot: gethCommon.Hash{0x2, 0x3, 0x4},
TotalGasUsed: 135,
TransactionHashes: []gethCommon.Hash{
gethCommon.HexToHash("0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
},
Expand Down
2 changes: 1 addition & 1 deletion fvm/evm/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"fmt"
)

type ErrorCode uint64
type ErrorCode uint16

// internal error codes
const ( // code reserved for no error
Expand Down
136 changes: 88 additions & 48 deletions fvm/evm/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,46 @@ const (
)

type EventPayload interface {
// CadenceEvent creates a Cadence event type
CadenceEvent() (cadence.Event, error)
// ToCadence converts the event to Cadence event
ToCadence() (cadence.Event, error)
}

type BlockEventPayload struct {
Height uint64 `cadence:"height"`
Hash string `cadence:"hash"`
Timestamp uint64 `cadence:"timestamp"`
TotalSupply cadence.Int `cadence:"totalSupply"`
TotalGasUsed uint64 `cadence:"totalGasUsed"`
ParentBlockHash string `cadence:"parentHash"`
ReceiptRoot string `cadence:"receiptRoot"`
TransactionHashes []cadence.String `cadence:"transactionHashes"`
}

// DecodeBlockEventPayload decodes Cadence event into block event payload.
func DecodeBlockEventPayload(event cadence.Event) (*BlockEventPayload, error) {
var block BlockEventPayload
err := cadence.DecodeFields(event, &block)
return &block, err
}

type TransactionEventPayload struct {
Hash string `cadence:"hash"`
Index uint16 `cadence:"index"`
TransactionType uint8 `cadence:"type"`
Payload string `cadence:"payload"`
ErrorCode uint16 `cadence:"errorCode"`
GasConsumed uint64 `cadence:"gasConsumed"`
ContractAddress string `cadence:"contractAddress"`
Logs string `cadence:"logs"`
BlockHeight uint64 `cadence:"blockHeight"`
BlockHash string `cadence:"blockHash"`
}

// DecodeTransactionEventPayload decodes Cadence event into transaction event payload.
func DecodeTransactionEventPayload(event cadence.Event) (*TransactionEventPayload, error) {
var tx TransactionEventPayload
err := cadence.DecodeFields(event, &tx)
return &tx, err
}

type Event struct {
Expand Down Expand Up @@ -98,15 +136,14 @@ func init() {

// todo we might have to break this event into two (tx included /tx executed) if size becomes an issue

type TransactionExecutedPayload struct {
type transactionEvent struct {
Payload []byte // transaction RLP-encoded payload
Result *Result // transaction execution result
BlockHeight uint64
TxEncoded []byte
BlockHash gethCommon.Hash
TxHash gethCommon.Hash
Result *Result
}

func (p *TransactionExecutedPayload) CadenceEvent() (cadence.Event, error) {
func (p *transactionEvent) ToCadence() (cadence.Event, error) {
var encodedLogs []byte
var err error
if len(p.Result.Logs) > 0 {
Expand All @@ -126,50 +163,52 @@ func (p *TransactionExecutedPayload) CadenceEvent() (cadence.Event, error) {
EVMLocation{},
string(EventTypeTransactionExecuted),
[]cadence.Field{
cadence.NewField("blockHeight", cadence.UInt64Type{}),
cadence.NewField("blockHash", cadence.StringType{}),
cadence.NewField("transactionHash", cadence.StringType{}),
cadence.NewField("transaction", cadence.StringType{}),
cadence.NewField("failed", cadence.BoolType{}),
cadence.NewField("vmError", cadence.StringType{}),
cadence.NewField("transactionType", cadence.UInt8Type{}),
cadence.NewField("hash", cadence.StringType{}),
cadence.NewField("index", cadence.UInt16Type{}),
cadence.NewField("type", cadence.UInt8Type{}),
cadence.NewField("payload", cadence.StringType{}),
cadence.NewField("errorCode", cadence.UInt16Type{}),
cadence.NewField("gasConsumed", cadence.UInt64Type{}),
cadence.NewField("deployedContractAddress", cadence.StringType{}),
cadence.NewField("returnedValue", cadence.StringType{}),
cadence.NewField("contractAddress", cadence.StringType{}),
cadence.NewField("logs", cadence.StringType{}),
cadence.NewField("blockHeight", cadence.UInt64Type{}),
// todo we can remove hash and just reference block by height (evm-gateway dependency)
cadence.NewField("blockHash", cadence.StringType{}),
},
nil,
),
Fields: []cadence.Value{
cadence.NewUInt64(p.BlockHeight),
cadence.String(p.BlockHash.String()),
cadence.String(p.TxHash.String()),
cadence.String(hex.EncodeToString(p.TxEncoded)),
cadence.Bool(p.Result.Failed()),
cadence.String(p.Result.VMErrorString()),
cadence.String(p.Result.TxHash.String()),
cadence.NewUInt16(p.Result.Index),
cadence.NewUInt8(p.Result.TxType),
cadence.String(hex.EncodeToString(p.Payload)),
cadence.NewUInt16(uint16(p.Result.ResultSummary().ErrorCode)),
cadence.NewUInt64(p.Result.GasConsumed),
deployedAddress,
cadence.String(hex.EncodeToString(p.Result.ReturnedValue)),
cadence.String(hex.EncodeToString(encodedLogs)),
cadence.NewUInt64(p.BlockHeight),
cadence.String(p.BlockHash.String()),
},
}, nil
}

func NewTransactionExecutedEvent(
height uint64,
txEncoded []byte,
blockHash gethCommon.Hash,
txHash gethCommon.Hash,
// NewTransactionEvent creates a new transaction event with the given parameters
// - result: the result of the transaction execution
// - payload: the RLP-encoded payload of the transaction
// - blockHeight: the height of the block where the transaction is included
// - blockHash: the hash of the block where the transaction is included
func NewTransactionEvent(
result *Result,
payload []byte,
blockHeight uint64,
blockHash gethCommon.Hash,
) *Event {
return &Event{
Etype: EventTypeTransactionExecuted,
Payload: &TransactionExecutedPayload{
BlockHeight: height,
Payload: &transactionEvent{
BlockHeight: blockHeight,
BlockHash: blockHash,
TxEncoded: txEncoded,
TxHash: txHash,
Payload: payload,
Result: result,
},
}
Expand All @@ -183,6 +222,7 @@ var blockExecutedEventCadenceType = &cadence.EventType{
cadence.NewField("hash", cadence.StringType{}),
cadence.NewField("timestamp", cadence.UInt64Type{}),
cadence.NewField("totalSupply", cadence.IntType{}),
cadence.NewField("totalGasUsed", cadence.UInt64Type{}),
cadence.NewField("parentHash", cadence.StringType{}),
cadence.NewField("receiptRoot", cadence.StringType{}),
cadence.NewField(
Expand All @@ -192,28 +232,29 @@ var blockExecutedEventCadenceType = &cadence.EventType{
},
}

type BlockExecutedEventPayload struct {
Block *Block
type blockEvent struct {
*Block
}

func (p *BlockExecutedEventPayload) CadenceEvent() (cadence.Event, error) {
hashes := make([]cadence.Value, len(p.Block.TransactionHashes))
for i, hash := range p.Block.TransactionHashes {
func (p *blockEvent) ToCadence() (cadence.Event, error) {
hashes := make([]cadence.Value, len(p.TransactionHashes))
for i, hash := range p.TransactionHashes {
hashes[i] = cadence.String(hash.String())
}

blockHash, err := p.Block.Hash()
blockHash, err := p.Hash()
if err != nil {
return cadence.Event{}, err
}

fields := []cadence.Value{
cadence.NewUInt64(p.Block.Height),
cadence.NewUInt64(p.Height),
cadence.String(blockHash.String()),
cadence.NewUInt64(p.Block.Timestamp),
cadence.NewIntFromBig(p.Block.TotalSupply),
cadence.String(p.Block.ParentBlockHash.String()),
cadence.String(p.Block.ReceiptRoot.String()),
cadence.NewUInt64(p.Timestamp),
cadence.NewIntFromBig(p.TotalSupply),
cadence.NewUInt64(p.TotalGasUsed),
cadence.String(p.ParentBlockHash.String()),
cadence.String(p.ReceiptRoot.String()),
cadence.NewArray(hashes).WithType(cadence.NewVariableSizedArrayType(cadence.StringType{})),
}

Expand All @@ -222,11 +263,10 @@ func (p *BlockExecutedEventPayload) CadenceEvent() (cadence.Event, error) {
WithType(blockExecutedEventCadenceType), nil
}

func NewBlockExecutedEvent(block *Block) *Event {
// NewBlockEvent creates a new block event with the given block as payload.
func NewBlockEvent(block *Block) *Event {
return &Event{
Etype: EventTypeBlockExecuted,
Payload: &BlockExecutedEventPayload{
Block: block,
},
Etype: EventTypeBlockExecuted,
Payload: &blockEvent{block},
}
}
Loading

0 comments on commit ed9f53f

Please sign in to comment.