Skip to content

Commit

Permalink
add concurrency tests
Browse files Browse the repository at this point in the history
  • Loading branch information
beer-1 committed Nov 13, 2024
1 parent 23ccbfb commit 8c4d4a5
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mytestnet
coverage.txt
profile.out
sim_log_file
testdata

# Vagrant
.vagrant/
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ contracts-gen: $(CONTRACTS_DIR)/*
benchmark:
@go test -timeout 20m -mod=readonly -bench=. ./...

fuzz:
@go test --timeout 2m -mod=readonly -fuzz=Fuzz ./x/evm/keeper

.PHONY: test test-all test-cover test-unit test-race benchmark contracts-gen

###############################################################################
Expand Down
25 changes: 23 additions & 2 deletions x/evm/contracts/counter/Counter.go

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion x/evm/contracts/counter/Counter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ contract Counter is IIBCAsyncCallback {

constructor() payable {}

function increase() external payable {
function increase_for_fuzz(uint64 num) external {
for (uint64 i = 0; i < num; i++) {
increase();
}
}

function increase() public payable {
count++;

emit increased(count - 1, count);
Expand Down
2 changes: 1 addition & 1 deletion x/evm/keeper/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func Test_Call(t *testing.T) {
res, logs, err := input.EVMKeeper.EVMCall(ctx, caller, contractAddr, inputBz, uint256.NewInt(100), nil)
require.NoError(t, err)
require.Empty(t, res)
require.NotEmpty(t, logs)
require.Len(t, logs, int(2))

// check balance
balance, err := input.EVMKeeper.ERC20Keeper().GetBalance(ctx, contractAddr.Bytes(), sdk.DefaultBondDenom)
Expand Down
92 changes: 92 additions & 0 deletions x/evm/keeper/fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package keeper_test

import (
"bytes"
"sync"
"sync/atomic"
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
coretypes "github.com/ethereum/go-ethereum/core/types"

"github.com/holiman/uint256"
"github.com/stretchr/testify/require"

"github.com/initia-labs/minievm/x/evm/contracts/counter"
"github.com/initia-labs/minievm/x/evm/types"
)

func Fuzz_Concurrent_Counter(f *testing.F) {
f.Add(uint8(100), uint8(100))
f.Fuzz(func(t *testing.T, numThread uint8, numCount uint8) {
if numThread == 0 || numCount == 0 {
t.Skip("skip invalid input")
}

ctx, input := createDefaultTestInput(t)
_, _, addr := keyPubAddr()

counterBz, err := hexutil.Decode(counter.CounterBin)
require.NoError(t, err)

caller := common.BytesToAddress(addr.Bytes())
retBz, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, caller, counterBz, nil, nil)
require.NoError(t, err)
require.NotEmpty(t, retBz)
require.Len(t, contractAddr, 20)

parsed, err := counter.CounterMetaData.GetAbi()
require.NoError(t, err)

count := getCount(t, ctx, input, contractAddr)
require.Equal(t, uint256.NewInt(0), count)

inputBz, err := parsed.Pack("increase_for_fuzz", uint64(numCount))
require.NoError(t, err)

atomicBloomBytes := atomic.Pointer[[]byte]{}
atomicBloomBytes.Store(nil)

var wg sync.WaitGroup
cacheCtxes := make([]sdk.Context, numThread)
for i := uint8(0); i < numThread; i++ {
wg.Add(1)
cacheCtx, _ := ctx.CacheContext()
cacheCtxes[i] = cacheCtx
go func(ctx sdk.Context) {
defer wg.Done()

// call with value
res, logs, err := input.EVMKeeper.EVMCall(ctx, caller, contractAddr, inputBz, nil, nil)
require.NoError(t, err)
require.Empty(t, res)
bloomBytes := coretypes.LogsBloom(logs.ToEthLogs())
prev := atomicBloomBytes.Swap(&bloomBytes)
require.True(t, prev == nil || bytes.Equal(*prev, bloomBytes))
}(cacheCtx)
}
wg.Wait()

for i := uint8(0); i < numThread; i++ {
count := getCount(t, cacheCtxes[i], input, contractAddr)
require.Equal(t, uint256.NewInt(uint64(numCount)), count)
require.NotEmpty(t, atomicBloomBytes.Load())
}
})
}

func getCount(t *testing.T, ctx sdk.Context, input TestKeepers, contractAddr common.Address) *uint256.Int {
parsed, err := counter.CounterMetaData.GetAbi()
require.NoError(t, err)

queryInputBz, err := parsed.Pack("count")
require.NoError(t, err)

queryRes, err := input.EVMKeeper.EVMStaticCall(ctx, types.StdAddress, contractAddr, queryInputBz, nil)
require.NoError(t, err)

return uint256.NewInt(0).SetBytes32(queryRes)
}

0 comments on commit 8c4d4a5

Please sign in to comment.