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

feat: introduce cache layer for fee denom and decimals #110

Merged
merged 5 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
75 changes: 72 additions & 3 deletions jsonrpc/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import (
"context"
"fmt"
"sync"
"time"

Expand Down Expand Up @@ -39,6 +40,11 @@
txLookupCache *lru.Cache[common.Hash, *rpctypes.RPCTransaction]
receiptCache *lru.Cache[common.Hash, *coretypes.Receipt]

// fee cache
feeDenom string
feeDecimals uint8
beer-1 marked this conversation as resolved.
Show resolved Hide resolved
feeMutex sync.RWMutex

mut sync.Mutex // mutex for accMuts
accMuts map[string]*AccMut

Expand All @@ -65,6 +71,7 @@

// NewJSONRPCBackend creates a new JSONRPCBackend instance
func NewJSONRPCBackend(
ctx context.Context,
app *app.MinitiaApp,
logger log.Logger,
svrCtx *server.Context,
Expand All @@ -86,8 +93,7 @@
return nil, err
}

ctx := context.Background()
return &JSONRPCBackend{
b := &JSONRPCBackend{

Check warning on line 96 in jsonrpc/backend/backend.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/backend.go#L96

Added line #L96 was not covered by tests
app: app,
logger: logger,

Expand All @@ -113,7 +119,70 @@
svrCtx: svrCtx,
clientCtx: clientCtx,
cfg: cfg,
}, nil
}

// start fee fetcher
go b.feeFetcher()

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

Check warning on line 127 in jsonrpc/backend/backend.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/backend.go#L122-L127

Added lines #L122 - L127 were not covered by tests
}

func (b *JSONRPCBackend) feeInfo() (string, uint8, error) {
b.feeMutex.RLock()
defer b.feeMutex.RUnlock()

if b.feeDenom == "" {
return "", 0, NewInternalError("jsonrpc is not ready")
}

Check warning on line 136 in jsonrpc/backend/backend.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/backend.go#L130-L136

Added lines #L130 - L136 were not covered by tests

return b.feeDenom, b.feeDecimals, nil

Check warning on line 138 in jsonrpc/backend/backend.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/backend.go#L138

Added line #L138 was not covered by tests
}

func (b *JSONRPCBackend) feeFetcher() {
fetcher := func() (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("feeFetcher panic: %v", r)
}

Check warning on line 146 in jsonrpc/backend/backend.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/backend.go#L141-L146

Added lines #L141 - L146 were not covered by tests
}()

queryCtx, err := b.getQueryCtx()
if err != nil {
return err
}

Check warning on line 152 in jsonrpc/backend/backend.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/backend.go#L149-L152

Added lines #L149 - L152 were not covered by tests

params, err := b.app.EVMKeeper.Params.Get(queryCtx)
if err != nil {
return err
}

Check warning on line 157 in jsonrpc/backend/backend.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/backend.go#L154-L157

Added lines #L154 - L157 were not covered by tests

feeDenom := params.FeeDenom
decimals, err := b.app.EVMKeeper.ERC20Keeper().GetDecimals(queryCtx, feeDenom)
if err != nil {
return err
}

Check warning on line 163 in jsonrpc/backend/backend.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/backend.go#L159-L163

Added lines #L159 - L163 were not covered by tests

b.feeMutex.Lock()
b.feeDenom = feeDenom
b.feeDecimals = decimals
b.feeMutex.Unlock()

return nil

Check warning on line 170 in jsonrpc/backend/backend.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/backend.go#L165-L170

Added lines #L165 - L170 were not covered by tests
}

ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()

for {
select {
case <-ticker.C:
if err := fetcher(); err != nil {
b.logger.Error("failed to fetch fee", "err", err)
}
case <-b.ctx.Done():
return

Check warning on line 183 in jsonrpc/backend/backend.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/backend.go#L173-L183

Added lines #L173 - L183 were not covered by tests
}
}
}

type AccMut struct {
Expand Down
5 changes: 3 additions & 2 deletions jsonrpc/backend/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
return nil, err
}

feeDenom, decimals, err := b.feeDenomWithDecimals()
// jsonrpc is not ready for querying
feeDenom, feeDecimals, err := b.feeInfo()

Check warning on line 29 in jsonrpc/backend/eth.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/eth.go#L29

Added line #L29 was not covered by tests
if err != nil {
return nil, err
}
Expand All @@ -35,7 +36,7 @@
return nil, err
}

return (*hexutil.Big)(types.ToEthersUint(decimals, balance.BigInt())), nil
return (*hexutil.Big)(types.ToEthersUint(feeDecimals, balance.BigInt())), nil

Check warning on line 39 in jsonrpc/backend/eth.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/eth.go#L39

Added line #L39 was not covered by tests
}

func (b *JSONRPCBackend) Call(args rpctypes.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *rpctypes.StateOverride, blockOverrides *rpctypes.BlockOverrides) (hexutil.Bytes, error) {
Expand Down
56 changes: 17 additions & 39 deletions jsonrpc/backend/gas.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
return hexutil.Uint64(0), err
}

_, decimals, err := b.feeDenomWithDecimals()
// jsonrpc is not ready for querying
_, feeDecimals, err := b.feeInfo()

Check warning on line 43 in jsonrpc/backend/gas.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/gas.go#L43

Added line #L43 was not covered by tests
if err != nil {
return hexutil.Uint64(0), err
}
Expand All @@ -49,14 +50,14 @@
sdkMsgs = append(sdkMsgs, &types.MsgCreate{
Sender: sender,
Code: hexutil.Encode(args.GetData()),
Value: math.NewIntFromBigInt(types.FromEthersUnit(decimals, args.Value.ToInt())),
Value: math.NewIntFromBigInt(types.FromEthersUnit(feeDecimals, args.Value.ToInt())),

Check warning on line 53 in jsonrpc/backend/gas.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/gas.go#L53

Added line #L53 was not covered by tests
beer-1 marked this conversation as resolved.
Show resolved Hide resolved
})
} else {
sdkMsgs = append(sdkMsgs, &types.MsgCall{
Sender: sender,
ContractAddr: args.To.Hex(),
Input: hexutil.Encode(args.GetData()),
Value: math.NewIntFromBigInt(types.FromEthersUnit(decimals, args.Value.ToInt())),
Value: math.NewIntFromBigInt(types.FromEthersUnit(feeDecimals, args.Value.ToInt())),

Check warning on line 60 in jsonrpc/backend/gas.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/gas.go#L60

Added line #L60 was not covered by tests
})
}

Expand Down Expand Up @@ -90,39 +91,6 @@
return hexutil.Uint64(gasInfo.GasUsed), nil
}

func (b *JSONRPCBackend) feeDenom() (string, error) {
queryCtx, err := b.getQueryCtx()
if err != nil {
return "", err
}

params, err := b.app.EVMKeeper.Params.Get(queryCtx)
if err != nil {
return "", err
}

return params.FeeDenom, nil
}

func (b *JSONRPCBackend) feeDenomWithDecimals() (string, uint8, error) {
feeDenom, err := b.feeDenom()
if err != nil {
return "", 0, err
}

queryCtx, err := b.getQueryCtx()
if err != nil {
return "", 0, err
}

decimals, err := b.app.EVMKeeper.ERC20Keeper().GetDecimals(queryCtx, feeDenom)
if err != nil {
return "", 0, err
}

return feeDenom, decimals, nil
}

func (b *JSONRPCBackend) GasPrice() (*hexutil.Big, error) {
queryCtx, err := b.getQueryCtx()
if err != nil {
Expand All @@ -134,17 +102,27 @@
return nil, err
}

feeDenom, decimals, err := b.feeDenomWithDecimals()
// jsonrpc is not ready for querying
feeDenom, feeDecimals, err := b.feeInfo()

Check warning on line 106 in jsonrpc/backend/gas.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/gas.go#L106

Added line #L106 was not covered by tests
if err != nil {
return nil, err
}

// Multiply by 1e9 to maintain precision during conversion
// This adds 9 decimal places to prevent truncation errors
const precisionMultiplier = 1e9

Check warning on line 114 in jsonrpc/backend/gas.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/gas.go#L113-L114

Added lines #L113 - L114 were not covered by tests
// multiply by 1e9 to prevent decimal drops
gasPrice := params.MinGasPrices.AmountOf(feeDenom).
MulTruncate(math.LegacyNewDec(1e9)).
MulTruncate(math.LegacyNewDec(precisionMultiplier)).

Check warning on line 117 in jsonrpc/backend/gas.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/gas.go#L117

Added line #L117 was not covered by tests
TruncateInt().BigInt()

return (*hexutil.Big)(types.ToEthersUint(decimals+9, gasPrice)), nil
// Verify the result is within safe bounds
if gasPrice.BitLen() > 256 {
return nil, NewInternalError("gas price overflow")
}

Check warning on line 123 in jsonrpc/backend/gas.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/gas.go#L120-L123

Added lines #L120 - L123 were not covered by tests

return (*hexutil.Big)(types.ToEthersUint(feeDecimals+9, gasPrice)), nil

Check warning on line 125 in jsonrpc/backend/gas.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/gas.go#L125

Added line #L125 was not covered by tests
}

func (b *JSONRPCBackend) MaxPriorityFeePerGas() (*hexutil.Big, error) {
Expand Down
14 changes: 7 additions & 7 deletions jsonrpc/jsonrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
rpcServer := rpc.NewServer()
rpcServer.SetBatchLimits(jsonRPCConfig.BatchRequestLimit, jsonRPCConfig.BatchResponseMaxSize)

bkd, err := backend.NewJSONRPCBackend(app, logger, svrCtx, clientCtx, jsonRPCConfig)
bkd, err := backend.NewJSONRPCBackend(ctx, app, logger, svrCtx, clientCtx, jsonRPCConfig)

Check warning on line 67 in jsonrpc/jsonrpc.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/jsonrpc.go#L67

Added line #L67 was not covered by tests
if err != nil {
return err
}
Expand All @@ -73,37 +73,37 @@
{
Namespace: EthNamespace,
Version: apiVersion,
Service: ethns.NewEthAPI(logger, bkd),
Service: ethns.NewEthAPI(ctx, logger, bkd),

Check warning on line 76 in jsonrpc/jsonrpc.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/jsonrpc.go#L76

Added line #L76 was not covered by tests
Public: true,
},
{
Namespace: EthNamespace,
Version: apiVersion,
Service: filters.NewFilterAPI(app, bkd, logger),
Service: filters.NewFilterAPI(ctx, app, bkd, logger),

Check warning on line 82 in jsonrpc/jsonrpc.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/jsonrpc.go#L82

Added line #L82 was not covered by tests
Public: true,
},
{
Namespace: NetNamespace,
Version: apiVersion,
Service: netns.NewNetAPI(logger, bkd),
Service: netns.NewNetAPI(ctx, logger, bkd),

Check warning on line 88 in jsonrpc/jsonrpc.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/jsonrpc.go#L88

Added line #L88 was not covered by tests
Public: true,
},
{
Namespace: Web3Namespace,
Version: apiVersion,
Service: web3ns.NewWeb3API(logger, bkd),
Service: web3ns.NewWeb3API(ctx, logger, bkd),

Check warning on line 94 in jsonrpc/jsonrpc.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/jsonrpc.go#L94

Added line #L94 was not covered by tests
Public: true,
},
{
Namespace: TxPoolNamespace,
Version: apiVersion,
Service: txpoolns.NewTxPoolAPI(logger, bkd),
Service: txpoolns.NewTxPoolAPI(ctx, logger, bkd),

Check warning on line 100 in jsonrpc/jsonrpc.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/jsonrpc.go#L100

Added line #L100 was not covered by tests
Public: true,
},
{
Namespace: CosmosNamespace,
Version: apiVersion,
Service: cosmosns.NewCosmosAPI(logger, bkd),
Service: cosmosns.NewCosmosAPI(ctx, logger, bkd),

Check warning on line 106 in jsonrpc/jsonrpc.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/jsonrpc.go#L106

Added line #L106 was not covered by tests
Public: true,
},
}
Expand Down
4 changes: 2 additions & 2 deletions jsonrpc/namespaces/cosmos/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
}

// NewCosmosAPI creates an instance of the public ETH Web3 API.
func NewCosmosAPI(logger log.Logger, backend *backend.JSONRPCBackend) *CosmosAPI {
func NewCosmosAPI(ctx context.Context, logger log.Logger, backend *backend.JSONRPCBackend) *CosmosAPI {

Check warning on line 20 in jsonrpc/namespaces/cosmos/api.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/namespaces/cosmos/api.go#L20

Added line #L20 was not covered by tests
api := &CosmosAPI{
ctx: context.TODO(),
ctx: ctx,

Check warning on line 22 in jsonrpc/namespaces/cosmos/api.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/namespaces/cosmos/api.go#L22

Added line #L22 was not covered by tests
logger: logger.With("client", "json-rpc"),
backend: backend,
}
Expand Down
4 changes: 2 additions & 2 deletions jsonrpc/namespaces/eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@
}

// NewEthAPI creates an instance of the public ETH Web3 API.
func NewEthAPI(logger log.Logger, backend *backend.JSONRPCBackend) *EthAPI {
func NewEthAPI(ctx context.Context, logger log.Logger, backend *backend.JSONRPCBackend) *EthAPI {

Check warning on line 110 in jsonrpc/namespaces/eth/api.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/namespaces/eth/api.go#L110

Added line #L110 was not covered by tests
api := &EthAPI{
ctx: context.TODO(),
ctx: ctx,

Check warning on line 112 in jsonrpc/namespaces/eth/api.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/namespaces/eth/api.go#L112

Added line #L112 was not covered by tests
logger: logger.With("client", "json-rpc"),
backend: backend,
}
Expand Down
40 changes: 25 additions & 15 deletions jsonrpc/namespaces/eth/filters/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@

// FilterAPI is the eth_ filter namespace API
type FilterAPI struct {
ctx context.Context

app *app.MinitiaApp
backend *backend.JSONRPCBackend

Expand All @@ -63,9 +65,11 @@
}

// NewFiltersAPI returns a new instance
func NewFilterAPI(app *app.MinitiaApp, backend *backend.JSONRPCBackend, logger log.Logger) *FilterAPI {
func NewFilterAPI(ctx context.Context, app *app.MinitiaApp, backend *backend.JSONRPCBackend, logger log.Logger) *FilterAPI {

Check warning on line 68 in jsonrpc/namespaces/eth/filters/api.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/namespaces/eth/filters/api.go#L68

Added line #L68 was not covered by tests
logger = logger.With("api", "filter")
api := &FilterAPI{
ctx: ctx,

Check warning on line 72 in jsonrpc/namespaces/eth/filters/api.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/namespaces/eth/filters/api.go#L71-L72

Added lines #L71 - L72 were not covered by tests
app: app,
backend: backend,

Expand Down Expand Up @@ -98,23 +102,27 @@

var toUninstall []*subscription
for {
<-ticker.C
api.filtersMut.Lock()
for id, f := range api.filters {
if time.Since(f.lastUsed) > timeout {
toUninstall = append(toUninstall, f.s)
delete(api.filters, id)
select {
case <-ticker.C:
api.filtersMut.Lock()
for id, f := range api.filters {
if time.Since(f.lastUsed) > timeout {
toUninstall = append(toUninstall, f.s)
delete(api.filters, id)
}

Check warning on line 112 in jsonrpc/namespaces/eth/filters/api.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/namespaces/eth/filters/api.go#L105-L112

Added lines #L105 - L112 were not covered by tests
}
}
api.filtersMut.Unlock()
api.filtersMut.Unlock()

Check warning on line 114 in jsonrpc/namespaces/eth/filters/api.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/namespaces/eth/filters/api.go#L114

Added line #L114 was not covered by tests

// Unsubscribes are processed outside the lock to avoid the following scenario:
// event loop attempts broadcasting events to still active filters while
// Unsubscribe is waiting for it to process the uninstall request.
for _, s := range toUninstall {
api.uninstallSubscription(s)
// Unsubscribes are processed outside the lock to avoid the following scenario:
// event loop attempts broadcasting events to still active filters while
// Unsubscribe is waiting for it to process the uninstall request.
for _, s := range toUninstall {
api.uninstallSubscription(s)
}
toUninstall = nil
case <-api.ctx.Done():
return

Check warning on line 124 in jsonrpc/namespaces/eth/filters/api.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/namespaces/eth/filters/api.go#L116-L124

Added lines #L116 - L124 were not covered by tests
}
toUninstall = nil
}
}

Expand Down Expand Up @@ -155,6 +163,8 @@
case s := <-api.uninstall:
delete(api.subscriptions, s.id)
close(s.err)
case <-api.ctx.Done():
return

Check warning on line 167 in jsonrpc/namespaces/eth/filters/api.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/namespaces/eth/filters/api.go#L166-L167

Added lines #L166 - L167 were not covered by tests
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions jsonrpc/namespaces/net/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
}

// NewNetAPI creates a new net API instance
func NewNetAPI(logger log.Logger, backend *backend.JSONRPCBackend) *NetAPI {
func NewNetAPI(ctx context.Context, logger log.Logger, backend *backend.JSONRPCBackend) *NetAPI {

Check warning on line 27 in jsonrpc/namespaces/net/api.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/namespaces/net/api.go#L27

Added line #L27 was not covered by tests
return &NetAPI{
ctx: context.TODO(),
ctx: ctx,

Check warning on line 29 in jsonrpc/namespaces/net/api.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/namespaces/net/api.go#L29

Added line #L29 was not covered by tests
logger: logger,
backend: backend,
}
Expand Down
Loading
Loading