Skip to content

Commit

Permalink
precompile accepter should take logIdx (#728)
Browse files Browse the repository at this point in the history
* precompile accepter should take logIdx

* minimize mock

* copyright yr

* add comments
  • Loading branch information
darioush authored Jul 18, 2023
1 parent 484ce17 commit fca9bac
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 13 deletions.
25 changes: 12 additions & 13 deletions plugin/evm/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/ava-labs/subnet-evm/core"
"github.com/ava-labs/subnet-evm/core/rawdb"
"github.com/ava-labs/subnet-evm/core/types"
"github.com/ava-labs/subnet-evm/params"
"github.com/ava-labs/subnet-evm/precompile/precompileconfig"

"github.com/ava-labs/avalanchego/ids"
Expand Down Expand Up @@ -64,8 +65,9 @@ func (b *Block) Accept(context.Context) error {

// Call Accept for relevant precompile logs. This should apply DB operations to the VM's versionDB
// to be committed atomically with marking this block as accepted.
rules := b.vm.chainConfig.AvalancheRules(b.ethBlock.Number(), b.ethBlock.Timestamp())
sharedMemoryWriter := NewSharedMemoryWriter()
if err := b.handlePrecompileAccept(sharedMemoryWriter); err != nil {
if err := b.handlePrecompileAccept(&rules, sharedMemoryWriter); err != nil {
return err
}
if err := vm.acceptedBlockDB.Put(lastAcceptedKey, b.id[:]); err != nil {
Expand All @@ -89,8 +91,7 @@ func (b *Block) Accept(context.Context) error {
// contract.Accepter
// This function assumes that the Accept function will ONLY operate on state maintained in the VM's versiondb.
// This ensures that any DB operations are performed atomically with marking the block as accepted.
func (b *Block) handlePrecompileAccept(sharedMemoryWriter *sharedMemoryWriter) error {
rules := b.vm.chainConfig.AvalancheRules(b.ethBlock.Number(), b.ethBlock.Timestamp())
func (b *Block) handlePrecompileAccept(rules *params.Rules, sharedMemoryWriter *sharedMemoryWriter) error {
// Short circuit early if there are no precompile accepters to execute
if len(rules.AccepterPrecompiles) == 0 {
return nil
Expand All @@ -103,20 +104,18 @@ func (b *Block) handlePrecompileAccept(sharedMemoryWriter *sharedMemoryWriter) e
if len(receipts) == 0 && b.ethBlock.ReceiptHash() != types.EmptyRootHash {
return fmt.Errorf("failed to fetch receipts for accepted block with non-empty root hash (%s) (Block: %s, Height: %d)", b.ethBlock.ReceiptHash(), b.ethBlock.Hash(), b.ethBlock.NumberU64())
}

for txIndex, receipt := range receipts {
for _, log := range receipt.Logs {
acceptCtx := &precompileconfig.AcceptContext{
SnowCtx: b.vm.ctx,
SharedMemory: sharedMemoryWriter,
Warp: b.vm.warpBackend,
}
for _, receipt := range receipts {
for logIdx, log := range receipt.Logs {
accepter, ok := rules.AccepterPrecompiles[log.Address]
if !ok {
continue
}

acceptCtx := &precompileconfig.AcceptContext{
SnowCtx: b.vm.ctx,
SharedMemory: sharedMemoryWriter,
Warp: b.vm.warpBackend,
}
if err := accepter.Accept(acceptCtx, log.TxHash, txIndex, log.Topics, log.Data); err != nil {
if err := accepter.Accept(acceptCtx, log.TxHash, logIdx, log.Topics, log.Data); err != nil {
return err
}
}
Expand Down
94 changes: 94 additions & 0 deletions plugin/evm/block_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// (c) 2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package evm

import (
"math/big"
"testing"

"github.com/ava-labs/avalanchego/database/memdb"
"github.com/ava-labs/subnet-evm/core/rawdb"
"github.com/ava-labs/subnet-evm/core/types"
"github.com/ava-labs/subnet-evm/params"
"github.com/ava-labs/subnet-evm/precompile/precompileconfig"
"github.com/ava-labs/subnet-evm/trie"
"github.com/ethereum/go-ethereum/common"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
)

func TestHandlePrecompileAccept(t *testing.T) {
require := require.New(t)
ctrl := gomock.NewController(t)
defer ctrl.Finish()

db := memdb.New()
vm := &VM{
chaindb: Database{db},
chainConfig: params.TestChainConfig,
}

precompileAddr := common.Address{0x05}
otherAddr := common.Address{0x06}

// Prepare a receipt with 3 logs, two of which are from the precompile
receipt := &types.Receipt{
Logs: []*types.Log{
{
Address: precompileAddr,
Topics: []common.Hash{{0x01}, {0x02}, {0x03}},
Data: []byte("log1"),
},
{
Address: otherAddr,
Topics: []common.Hash{{0x01}, {0x02}, {0x04}},
Data: []byte("log2"),
},
{
Address: precompileAddr,
Topics: []common.Hash{{0x01}, {0x02}, {0x05}},
Data: []byte("log3"),
},
},
}
ethBlock := types.NewBlock(
&types.Header{Number: big.NewInt(1)},
[]*types.Transaction{types.NewTx(&types.LegacyTx{})},
nil,
[]*types.Receipt{receipt},
trie.NewStackTrie(nil),
)
// Write the block to the db
rawdb.WriteBlock(db, ethBlock)
rawdb.WriteReceipts(db, ethBlock.Hash(), ethBlock.NumberU64(), []*types.Receipt{receipt})

// Set up the mock with the expected calls to Accept
txIndex := 0
mockAccepter := precompileconfig.NewMockAccepter(ctrl)
gomock.InOrder(
mockAccepter.EXPECT().Accept(
gomock.Not(gomock.Nil()), // acceptCtx
ethBlock.Transactions()[txIndex].Hash(), // txHash
0, // logIndex
receipt.Logs[0].Topics, // topics
receipt.Logs[0].Data, // logData
),
mockAccepter.EXPECT().Accept(
gomock.Not(gomock.Nil()), // acceptCtx
ethBlock.Transactions()[txIndex].Hash(), // txHash
2, // logIndex
receipt.Logs[2].Topics, // topics
receipt.Logs[2].Data, // logData
),
)

// Call handlePrecompileAccept
blk := vm.newBlock(ethBlock)
rules := &params.Rules{
AccepterPrecompiles: map[common.Address]precompileconfig.Accepter{
precompileAddr: mockAccepter,
},
}
require.NoError(blk.handlePrecompileAccept(rules, nil))
}
49 changes: 49 additions & 0 deletions precompile/precompileconfig/test_config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit fca9bac

Please sign in to comment.