Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EVM] Optimize event data #5779

Merged
merged 17 commits into from
Apr 26, 2024
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
Loading