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

Aggregate and expose EVM-related event payloads #628

Open
wants to merge 1 commit into
base: feature/local-tx-reexecution
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions models/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ func (b *Block) Hash() (gethCommon.Hash, error) {

// decodeBlockEvent takes a cadence event that contains executed block payload and
// decodes it into the Block type.
func decodeBlockEvent(event cadence.Event) (*Block, error) {
func decodeBlockEvent(event cadence.Event) (*Block, *events.BlockEventPayload, error) {
payload, err := events.DecodeBlockEventPayload(event)
if err != nil {
return nil, fmt.Errorf(
return nil, nil, fmt.Errorf(
"failed to Cadence-decode EVM block event [%s]: %w",
event.String(),
err,
Expand Down Expand Up @@ -102,7 +102,7 @@ func decodeBlockEvent(event cadence.Event) (*Block, error) {
PrevRandao: payload.PrevRandao,
},
FixedHash: fixedHash,
}, nil
}, payload, nil
}

// blockV0 is the block format, prior to adding the PrevRandao field.
Expand Down
4 changes: 2 additions & 2 deletions models/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func Test_DecodeBlockExecutedEvent(t *testing.T) {
encEv, err := ev.Payload.ToCadence(flowGo.Previewnet)
require.NoError(t, err)

decBlock, err := decodeBlockEvent(encEv)
decBlock, _, err := decodeBlockEvent(encEv)
require.NoError(t, err)

assert.Equal(t, decBlock, block)
Expand Down Expand Up @@ -150,7 +150,7 @@ func Test_DecodingLegacyBlockExecutedEvent(t *testing.T) {
hashToCadenceArrayValue(block.TransactionHashRoot),
}).WithType(eventType)

b, err := decodeBlockEvent(legacyEvent)
b, _, err := decodeBlockEvent(legacyEvent)
require.NoError(t, err)

require.Equal(t, block.ParentBlockHash, b.ParentBlockHash)
Expand Down
29 changes: 23 additions & 6 deletions models/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ func isTransactionExecutedEvent(event cadence.Event) bool {
// CadenceEvents contains Flow emitted events containing one or zero evm block executed event,
// and multiple or zero evm transaction events.
type CadenceEvents struct {
events flow.BlockEvents // Flow events for a specific flow block
block *Block // EVM block (at most one per Flow block)
transactions []Transaction // transactions in the EVM block
receipts []*Receipt // receipts for transactions
events flow.BlockEvents // Flow events for a specific flow block
block *Block // EVM block (at most one per Flow block)
blockEventPayload *events.BlockEventPayload // EVM.BlockExecuted event payload (at most one per Flow block)
transactions []Transaction // transactions in the EVM block
txEventPayloads []events.TransactionEventPayload // EVM.TransactionExecuted event payloads
receipts []*Receipt // receipts for transactions
}

// NewCadenceEvents decodes the events into evm types.
Expand Down Expand Up @@ -111,22 +113,24 @@ func decodeCadenceEvents(events flow.BlockEvents) (*CadenceEvents, error) {
return nil, fmt.Errorf("EVM block was already set for Flow block: %d", events.Height)
}

block, err := decodeBlockEvent(val)
block, blockEventPayload, err := decodeBlockEvent(val)
if err != nil {
return nil, err
}

e.block = block
e.blockEventPayload = blockEventPayload
continue
}

if isTransactionExecutedEvent(val) {
tx, receipt, err := decodeTransactionEvent(val)
tx, receipt, txEventPayload, err := decodeTransactionEvent(val)
if err != nil {
return nil, err
}

e.transactions = append(e.transactions, tx)
e.txEventPayloads = append(e.txEventPayloads, *txEventPayload)
Comment on lines +127 to +133
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add nil check for txEventPayload.

Consider adding a nil check before dereferencing txEventPayload to prevent potential panic.

-			e.txEventPayloads = append(e.txEventPayloads, *txEventPayload)
+			if txEventPayload != nil {
+				e.txEventPayloads = append(e.txEventPayloads, *txEventPayload)
+			}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tx, receipt, txEventPayload, err := decodeTransactionEvent(val)
if err != nil {
return nil, err
}
e.transactions = append(e.transactions, tx)
e.txEventPayloads = append(e.txEventPayloads, *txEventPayload)
tx, receipt, txEventPayload, err := decodeTransactionEvent(val)
if err != nil {
return nil, err
}
e.transactions = append(e.transactions, tx)
if txEventPayload != nil {
e.txEventPayloads = append(e.txEventPayloads, *txEventPayload)
}

e.receipts = append(e.receipts, receipt)
}
}
Expand Down Expand Up @@ -162,12 +166,25 @@ func (c *CadenceEvents) Block() *Block {
return c.block
}

// BlockEventPayload returns the EVM.BlockExecuted event payload. If the Flow block
// events do not contain an EVM block, the return value is nil.
func (c *CadenceEvents) BlockEventPayload() *events.BlockEventPayload {
return c.blockEventPayload
}

// Transactions included in the EVM block, if event doesn't
// contain EVM transactions the return value is nil.
func (c *CadenceEvents) Transactions() []Transaction {
return c.transactions
}

// TxEventPayloads returns the EVM.TransactionExecuted event payloads for the
// current EVM block. If the Flow block events do not contain any EVM transactions
// the return value is nil.
func (c *CadenceEvents) TxEventPayloads() []events.TransactionEventPayload {
return c.txEventPayloads
}

// Receipts included in the EVM block, if event doesn't
// contain EVM transactions the return value is nil.
func (c *CadenceEvents) Receipts() []*Receipt {
Expand Down
14 changes: 13 additions & 1 deletion models/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func TestCadenceEvents_Block(t *testing.T) {
}

// generate single block
_, blockEvent, err := newBlock(1, hashes)
block, blockEvent, err := newBlock(1, hashes)
require.NoError(t, err)
blockEvent.TransactionIndex = 4
blockEvent.EventIndex = 0
Expand All @@ -216,13 +216,25 @@ func TestCadenceEvents_Block(t *testing.T) {
cdcEvents.events.Events,
)

// assert we have collected the EVM.BlockExecuted event payload
blockEventPayload := cdcEvents.BlockEventPayload()
blockHash, err := block.Hash()
require.NoError(t, err)
assert.Equal(t, blockHash, blockEventPayload.Hash)

// assert that EVM transactions & receipts are sorted by their
// TransactionIndex field
for i := 0; i < txCount; i++ {
tx := cdcEvents.transactions[i]
receipt := cdcEvents.receipts[i]
assert.Equal(t, tx.Hash(), receipt.TxHash)
assert.Equal(t, uint(i), receipt.TransactionIndex)

// assert we have collected the EVM.TransactionExecuted event payloads
// in their correct order.
txEventPayload := cdcEvents.TxEventPayloads()[i]
assert.Equal(t, tx.Hash(), txEventPayload.Hash)
assert.Equal(t, blockEventPayload.Height, txEventPayload.BlockHeight)
}
})
}
Expand Down
2 changes: 1 addition & 1 deletion models/receipt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
func Test_DecodeReceipts(t *testing.T) {
cdcEv, rec := createTestEvent(t, evmTxBinary)

_, receipt, err := decodeTransactionEvent(cdcEv)
_, receipt, _, err := decodeTransactionEvent(cdcEv)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consider testing the new event payload.

The test ignores the newly added event payload return value, which is a key part of the PR's objective to aggregate EVM event payloads. Consider adding assertions to verify the correctness of this payload.

Here's a suggested improvement:

-	_, receipt, _, err := decodeTransactionEvent(cdcEv)
+	_, receipt, payload, err := decodeTransactionEvent(cdcEv)
 	require.NoError(t, err)
+	// Verify the event payload
+	assert.NotNil(t, payload, "event payload should not be nil")
+	// Add specific assertions for payload fields based on test event data

Committable suggestion was skipped due to low confidence.

require.NoError(t, err)

for i, l := range rec.Logs {
Expand Down
29 changes: 23 additions & 6 deletions models/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,19 @@ func (tc TransactionCall) MarshalBinary() ([]byte, error) {
// decodeTransactionEvent takes a cadence event for transaction executed
// and decodes its payload into a Transaction interface and a Receipt.
// The concrete type will be either a TransactionCall or a DirectCall.
func decodeTransactionEvent(event cadence.Event) (Transaction, *Receipt, error) {
func decodeTransactionEvent(event cadence.Event) (
Transaction,
*Receipt,
*events.TransactionEventPayload,
error,
) {
txEvent, err := events.DecodeTransactionEventPayload(event)
if err != nil {
return nil, nil, fmt.Errorf("failed to Cadence decode transaction event [%s]: %w", event.String(), err)
return nil, nil, nil, fmt.Errorf(
"failed to Cadence decode transaction event [%s]: %w",
event.String(),
err,
)
}

gethReceipt := &gethTypes.Receipt{
Expand All @@ -186,7 +195,7 @@ func decodeTransactionEvent(event cadence.Event) (Transaction, *Receipt, error)
if len(txEvent.Logs) > 0 {
err = rlp.Decode(bytes.NewReader(txEvent.Logs), &gethReceipt.Logs)
if err != nil {
return nil, nil, fmt.Errorf("failed to RLP-decode logs: %w", err)
return nil, nil, nil, fmt.Errorf("failed to RLP-decode logs: %w", err)
}
}

Expand All @@ -211,19 +220,27 @@ func decodeTransactionEvent(event cadence.Event) (Transaction, *Receipt, error)
if txEvent.TransactionType == types.DirectCallTxType {
directCall, err := types.DirectCallFromEncoded(txEvent.Payload)
if err != nil {
return nil, nil, fmt.Errorf("failed to RLP-decode direct call [%x]: %w", txEvent.Payload, err)
return nil, nil, nil, fmt.Errorf(
"failed to RLP-decode direct call [%x]: %w",
txEvent.Payload,
err,
)
}
tx = DirectCall{DirectCall: directCall}
} else {
gethTx := &gethTypes.Transaction{}
if err := gethTx.UnmarshalBinary(txEvent.Payload); err != nil {
return nil, nil, fmt.Errorf("failed to RLP-decode transaction [%x]: %w", txEvent.Payload, err)
return nil, nil, nil, fmt.Errorf(
"failed to RLP-decode transaction [%x]: %w",
txEvent.Payload,
err,
)
}
receipt.EffectiveGasPrice = gethTx.EffectiveGasTipValue(nil)
tx = TransactionCall{Transaction: gethTx}
}

return tx, receipt, nil
return tx, receipt, txEvent, nil
}

func UnmarshalTransaction(value []byte) (Transaction, error) {
Expand Down
8 changes: 4 additions & 4 deletions models/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func createTestEvent(t *testing.T, txBinary string) (cadence.Event, *types.Resul
func Test_DecodeEVMTransaction(t *testing.T) {
cdcEv, _ := createTestEvent(t, evmTxBinary)

decTx, _, err := decodeTransactionEvent(cdcEv)
decTx, _, _, err := decodeTransactionEvent(cdcEv)
require.NoError(t, err)
require.IsType(t, TransactionCall{}, decTx)

Expand Down Expand Up @@ -131,7 +131,7 @@ func Test_DecodeEVMTransaction(t *testing.T) {
func Test_DecodeDirectCall(t *testing.T) {
cdcEv, _ := createTestEvent(t, directCallBinary)

decTx, _, err := decodeTransactionEvent(cdcEv)
decTx, _, _, err := decodeTransactionEvent(cdcEv)
require.NoError(t, err)
require.IsType(t, DirectCall{}, decTx)

Expand Down Expand Up @@ -179,7 +179,7 @@ func Test_UnmarshalTransaction(t *testing.T) {

cdcEv, _ := createTestEvent(t, evmTxBinary)

tx, _, err := decodeTransactionEvent(cdcEv)
tx, _, _, err := decodeTransactionEvent(cdcEv)
require.NoError(t, err)

encodedTx, err := tx.MarshalBinary()
Expand Down Expand Up @@ -233,7 +233,7 @@ func Test_UnmarshalTransaction(t *testing.T) {

cdcEv, _ := createTestEvent(t, directCallBinary)

tx, _, err := decodeTransactionEvent(cdcEv)
tx, _, _, err := decodeTransactionEvent(cdcEv)
require.NoError(t, err)

encodedTx, err := tx.MarshalBinary()
Expand Down
Loading