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

use custom cache store to properly implement interfaces #46

Merged
merged 4 commits into from
Aug 20, 2024
Merged
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
cosmossdk.io/x/feegrant v0.1.0
cosmossdk.io/x/tx v0.13.3
cosmossdk.io/x/upgrade v0.1.3
github.com/allegro/bigcache/v3 v3.1.0
github.com/cometbft/cometbft v0.38.10
github.com/cosmos/cosmos-db v1.0.2
github.com/cosmos/cosmos-proto v1.0.0-beta.5
Expand Down Expand Up @@ -72,7 +73,6 @@ require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/VictoriaMetrics/fastcache v1.12.1 // indirect
github.com/allegro/bigcache/v3 v3.1.0 // indirect
github.com/avast/retry-go/v4 v4.5.1 // indirect
github.com/aws/aws-sdk-go v1.44.312 // indirect
github.com/beorn7/perks v1.0.1 // indirect
Expand Down
19 changes: 8 additions & 11 deletions indexer/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,8 @@
func (e *EVMIndexerImpl) ListenFinalizeBlock(ctx context.Context, req abci.RequestFinalizeBlock, res abci.ResponseFinalizeBlock) error {
sdkCtx := sdk.UnwrapSDKContext(ctx)

batch := e.db.NewBatch()
defer batch.Close()

// compute base fee from the opChild gas prices
baseFee, err := e.baseFee(ctx)
baseFee, err := e.baseFee(sdkCtx)

Check warning on line 33 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L33

Added line #L33 was not covered by tests
if err != nil {
e.logger.Error("failed to get base fee", "err", err)
return err
Expand Down Expand Up @@ -67,11 +64,11 @@

// index tx hash
cosmosTxHash := comettypes.Tx(txBytes).Hash()
if err := e.TxHashToCosmosTxHash.Set(ctx, ethTx.Hash().Bytes(), cosmosTxHash); err != nil {
if err := e.TxHashToCosmosTxHash.Set(sdkCtx, ethTx.Hash().Bytes(), cosmosTxHash); err != nil {

Check warning on line 67 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L67

Added line #L67 was not covered by tests
e.logger.Error("failed to store tx hash to cosmos tx hash", "err", err)
return err
}
if err := e.CosmosTxHashToTxHash.Set(ctx, cosmosTxHash, ethTx.Hash().Bytes()); err != nil {
if err := e.CosmosTxHashToTxHash.Set(sdkCtx, cosmosTxHash, ethTx.Hash().Bytes()); err != nil {

Check warning on line 71 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L71

Added line #L71 was not covered by tests
e.logger.Error("failed to store cosmos tx hash to tx hash", "err", err)
return err
}
Expand Down Expand Up @@ -147,17 +144,17 @@

// store tx
rpcTx := rpctypes.NewRPCTransaction(ethTx, blockHash, uint64(blockHeight), uint64(receipt.TransactionIndex), chainId)
if err := e.TxMap.Set(ctx, txHash.Bytes(), *rpcTx); err != nil {
if err := e.TxMap.Set(sdkCtx, txHash.Bytes(), *rpcTx); err != nil {

Check warning on line 147 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L147

Added line #L147 was not covered by tests
e.logger.Error("failed to store rpcTx", "err", err)
return err
}
if err := e.TxReceiptMap.Set(ctx, txHash.Bytes(), *receipt); err != nil {
if err := e.TxReceiptMap.Set(sdkCtx, txHash.Bytes(), *receipt); err != nil {

Check warning on line 151 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L151

Added line #L151 was not covered by tests
e.logger.Error("failed to store tx receipt", "err", err)
return err
}

// store index
if err := e.BlockAndIndexToTxHashMap.Set(ctx, collections.Join(uint64(blockHeight), uint64(receipt.TransactionIndex)), txHash.Bytes()); err != nil {
if err := e.BlockAndIndexToTxHashMap.Set(sdkCtx, collections.Join(uint64(blockHeight), uint64(receipt.TransactionIndex)), txHash.Bytes()); err != nil {

Check warning on line 157 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L157

Added line #L157 was not covered by tests
e.logger.Error("failed to store blockAndIndexToTxHash", "err", err)
return err
}
Expand All @@ -181,11 +178,11 @@
}

// index block header
if err := e.BlockHeaderMap.Set(ctx, uint64(blockHeight), blockHeader); err != nil {
if err := e.BlockHeaderMap.Set(sdkCtx, uint64(blockHeight), blockHeader); err != nil {

Check warning on line 181 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L181

Added line #L181 was not covered by tests
e.logger.Error("failed to marshal blockHeader", "err", err)
return err
}
if err := e.BlockHashToNumberMap.Set(ctx, blockHash.Bytes(), uint64(blockHeight)); err != nil {
if err := e.BlockHashToNumberMap.Set(sdkCtx, blockHash.Bytes(), uint64(blockHeight)); err != nil {

Check warning on line 185 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L185

Added line #L185 was not covered by tests
e.logger.Error("failed to store blockHashToNumber", "err", err)
return err
}
Expand Down
6 changes: 3 additions & 3 deletions indexer/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
coretypes "github.com/ethereum/go-ethereum/core/types"

opchildkeeper "github.com/initia-labs/OPinit/x/opchild/keeper"
"github.com/initia-labs/kvindexer/store"

rpctypes "github.com/initia-labs/minievm/jsonrpc/types"
evmkeeper "github.com/initia-labs/minievm/x/evm/keeper"
)
Expand Down Expand Up @@ -55,7 +55,7 @@
txConfig client.TxConfig
appCodec codec.Codec

store *store.CacheStore
store *CacheStore
evmKeeper *evmkeeper.Keeper
opChildKeeper *opchildkeeper.Keeper

Expand All @@ -82,7 +82,7 @@
opChildKeeper *opchildkeeper.Keeper,
) (EVMIndexer, error) {
// TODO make cache size configurable
store := store.NewCacheStore(dbadapter.Store{DB: db}, 100)
store := NewCacheStore(dbadapter.Store{DB: db}, 100)

Check warning on line 85 in indexer/indexer.go

View check run for this annotation

Codecov / codecov/patch

indexer/indexer.go#L85

Added line #L85 was not covered by tests
beer-1 marked this conversation as resolved.
Show resolved Hide resolved
sb := collections.NewSchemaBuilderFromAccessor(
func(ctx context.Context) corestoretypes.KVStore {
return store
Expand Down
123 changes: 123 additions & 0 deletions indexer/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package indexer

import (
"context"

corestoretypes "cosmossdk.io/core/store"
"cosmossdk.io/errors"
cachekv "cosmossdk.io/store/cachekv"
storetypes "cosmossdk.io/store/types"
bigcache "github.com/allegro/bigcache/v3"
)

var _ corestoretypes.KVStore = (*CacheStore)(nil)

type CacheStore struct {
store storetypes.CacheKVStore
cache *bigcache.BigCache
}

func NewCacheStore(store storetypes.KVStore, capacity int) *CacheStore {
// default with no eviction and custom hard max cache capacity
cacheCfg := bigcache.DefaultConfig(0)
cacheCfg.Verbose = false
cacheCfg.HardMaxCacheSize = capacity

cache, err := bigcache.New(context.Background(), cacheCfg)
if err != nil {
panic(err)

Check warning on line 28 in indexer/store.go

View check run for this annotation

Codecov / codecov/patch

indexer/store.go#L28

Added line #L28 was not covered by tests
}
beer-1 marked this conversation as resolved.
Show resolved Hide resolved

return &CacheStore{
store: cachekv.NewStore(store),
cache: cache,
}
Comment on lines +31 to +34
Copy link

Choose a reason for hiding this comment

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

Add test coverage for NewCacheStore.

The NewCacheStore function initializes a new cache store, but there is no test coverage for this functionality. Ensure that tests are added to verify the initialization process.

Would you like me to help create unit tests for this function or open a GitHub issue to track this task?

Tools
GitHub Check: codecov/patch

[warning] 31-34: indexer/store.go#L31-L34
Added lines #L31 - L34 were not covered by tests

}

// Get returns nil iff key doesn't exist. Errors on nil key.
func (c CacheStore) Get(key []byte) ([]byte, error) {
storetypes.AssertValidKey(key)

if value, err := c.cache.Get(string(key)); err == nil {
return value, nil
}

// get from store and write to cache
value := c.store.Get(key)
if value == nil {
return nil, nil
}

// ignore cache error
_ = c.cache.Set(string(key), value)

return value, nil

Check warning on line 54 in indexer/store.go

View check run for this annotation

Codecov / codecov/patch

indexer/store.go#L52-L54

Added lines #L52 - L54 were not covered by tests
beer-1 marked this conversation as resolved.
Show resolved Hide resolved
}

// Has checks if a key exists. Errors on nil key.
func (c CacheStore) Has(key []byte) (bool, error) {
_, err := c.cache.Get(string(key))
if err == nil {
return true, nil
}

value := c.store.Get(key)
if value == nil {
return false, nil
}

// ignore cache error
_ = c.cache.Set(string(key), value)
Vritra4 marked this conversation as resolved.
Show resolved Hide resolved

return true, nil

Check warning on line 72 in indexer/store.go

View check run for this annotation

Codecov / codecov/patch

indexer/store.go#L70-L72

Added lines #L70 - L72 were not covered by tests
}
Comment on lines +58 to +73
Copy link

Choose a reason for hiding this comment

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

Add test coverage for Has.

The Has method checks for key existence in the cache or store, but there is no test coverage for this functionality. Ensure that tests are added to verify the existence check.

Would you like me to help create unit tests for this method or open a GitHub issue to track this task?

Tools
GitHub Check: codecov/patch

[warning] 58-62: indexer/store.go#L58-L62
Added lines #L58 - L62 were not covered by tests


[warning] 64-67: indexer/store.go#L64-L67
Added lines #L64 - L67 were not covered by tests


[warning] 70-72: indexer/store.go#L70-L72
Added lines #L70 - L72 were not covered by tests


// Set sets the key. Errors on nil key or value.
func (c CacheStore) Set(key, value []byte) error {
storetypes.AssertValidKey(key)
storetypes.AssertValidValue(value)

err := c.cache.Set(string(key), value)
if err != nil {
return errors.Wrap(err, "failed to set cache")
}

Check warning on line 83 in indexer/store.go

View check run for this annotation

Codecov / codecov/patch

indexer/store.go#L82-L83

Added lines #L82 - L83 were not covered by tests
c.store.Set(key, value)

return nil
}
beer-1 marked this conversation as resolved.
Show resolved Hide resolved

// Delete deletes the key. Errors on nil key.
func (c CacheStore) Delete(key []byte) error {
storetypes.AssertValidKey(key)

err := c.cache.Delete(string(key))
if err != nil && errors.IsOf(err, bigcache.ErrEntryNotFound) {
return errors.Wrap(err, "failed to delete cache")
}

Check warning on line 96 in indexer/store.go

View check run for this annotation

Codecov / codecov/patch

indexer/store.go#L95-L96

Added lines #L95 - L96 were not covered by tests
c.store.Delete(key)

return nil
}
beer-1 marked this conversation as resolved.
Show resolved Hide resolved

// Iterator iterates over a domain of keys in ascending order. End is exclusive.
// Start must be less than end, or the Iterator is invalid.
// Iterator must be closed by caller.
// To iterate over entire domain, use store.Iterator(nil, nil)
// CONTRACT: No writes may happen within a domain while an iterator exists over it.
// Exceptionally allowed for cachekv.Store, safe to write in the modules.
func (c CacheStore) Iterator(start, end []byte) (storetypes.Iterator, error) {
return c.store.Iterator(start, end), nil

Check warning on line 109 in indexer/store.go

View check run for this annotation

Codecov / codecov/patch

indexer/store.go#L108-L109

Added lines #L108 - L109 were not covered by tests
beer-1 marked this conversation as resolved.
Show resolved Hide resolved
}

// ReverseIterator iterates over a domain of keys in descending order. End is exclusive.
// Start must be less than end, or the Iterator is invalid.
// Iterator must be closed by caller.
// CONTRACT: No writes may happen within a domain while an iterator exists over it.
// Exceptionally allowed for cachekv.Store, safe to write in the modules.
func (c CacheStore) ReverseIterator(start, end []byte) (storetypes.Iterator, error) {
return c.store.ReverseIterator(start, end), nil

Check warning on line 118 in indexer/store.go

View check run for this annotation

Codecov / codecov/patch

indexer/store.go#L117-L118

Added lines #L117 - L118 were not covered by tests
beer-1 marked this conversation as resolved.
Show resolved Hide resolved
}

func (c CacheStore) Write() {
c.store.Write()

Check warning on line 122 in indexer/store.go

View check run for this annotation

Codecov / codecov/patch

indexer/store.go#L121-L122

Added lines #L121 - L122 were not covered by tests
}
50 changes: 50 additions & 0 deletions indexer/store_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package indexer

import (
"testing"

"cosmossdk.io/store/dbadapter"
dbm "github.com/cosmos/cosmos-db"
"github.com/stretchr/testify/require"
)

func Test_StoreIO(t *testing.T) {
db := dbm.NewMemDB()
store := NewCacheStore(dbadapter.Store{DB: db}, 100)

key := []byte("key")
value := []byte("value")

// case 1. key not exists
ok, err := store.Has(key)
require.NoError(t, err)
require.False(t, ok)

bz, err := store.Get(key)
require.NoError(t, err)
require.Nil(t, bz)

// case 2. set key
err = store.Set(key, value)
require.NoError(t, err)

ok, err = store.Has(key)
require.NoError(t, err)
require.True(t, ok)

bz, err = store.Get(key)
require.NoError(t, err)
require.Equal(t, value, bz)

// case 3. delete key
err = store.Delete(key)
require.NoError(t, err)

ok, err = store.Has(key)
require.NoError(t, err)
require.False(t, ok)

bz, err = store.Get(key)
require.NoError(t, err)
require.Nil(t, bz)
}
7 changes: 2 additions & 5 deletions indexer/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,11 @@ func CollJsonVal[T any]() collcodec.ValueCodec[T] {
type collJsonVal[T any] struct{}

func (c collJsonVal[T]) Encode(value T) ([]byte, error) {
return json.Marshal(value)
return c.EncodeJSON(value)
beer-1 marked this conversation as resolved.
Show resolved Hide resolved
}

func (c collJsonVal[T]) Decode(b []byte) (T, error) {
var value T

err := json.Unmarshal(b, &value)
return value, err
return c.DecodeJSON(b)
beer-1 marked this conversation as resolved.
Show resolved Hide resolved
}

func (c collJsonVal[T]) EncodeJSON(value T) ([]byte, error) {
Expand Down
22 changes: 22 additions & 0 deletions indexer/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,25 @@ func Test_UnpackData(t *testing.T) {
require.NoError(t, err)
require.Equal(t, resp, respOut)
}

func Test_collJsonVal(t *testing.T) {
type s1 struct {
A string `json:"a"`
B uint64 `json:"b"`
}

codec := collJsonVal[s1]{}
bz, err := codec.Encode(s1{
A: "a",
B: 1,
})
require.NoError(t, err)
require.Equal(t, `{"a":"a","b":1}`, string(bz))

out, err := codec.Decode(bz)
require.NoError(t, err)
require.Equal(t, s1{
A: "a",
B: 1,
}, out)
}
Loading