Skip to content

Commit

Permalink
fix: Compare local nonce w/ backend to detect invalidated cache
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanschneider committed Aug 21, 2024
1 parent 977b757 commit 2445525
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
5 changes: 5 additions & 0 deletions server/redisstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ func (s *RedisState) GetSenderMaxNonce(txFrom string) (senderMaxNonce uint64, fo
return senderMaxNonce, true, nil
}

func (s *RedisState) DelSenderMaxNonce(txFrom string) error {
key := RedisKeySenderMaxNonce(txFrom)
return s.RedisClient.Del(context.Background(), key).Err()
}

// Block transactions, with a specific return value (eg. "nonce too low")
func (s *RedisState) SetBlockedTxHash(txHash string, returnValue string) error {
key := RedisKeyBlockedTxHash(txHash)
Expand Down
36 changes: 33 additions & 3 deletions server/request_intercepts.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package server

import (
"encoding/json"
"fmt"
"strings"

Expand Down Expand Up @@ -179,7 +180,9 @@ func (r *RpcRequest) intercept_signed_eth_getTransactionCount() (requestFinished
return false
}

nonce, found, err := RState.GetSenderMaxNonce(addr)
// since it's possible that the user sent another tx via another provider, we need to check the nonce from
// both the backend and our cache, and return the greater of the two
cachedNonce, found, err := RState.GetSenderMaxNonce(addr)
if err != nil {
r.logger.Error("[eth_getTransactionCount] Redis:GetSenderMaxNonce error", "error", err)
return false
Expand All @@ -188,9 +191,36 @@ func (r *RpcRequest) intercept_signed_eth_getTransactionCount() (requestFinished
r.logger.Info("[eth_getTransactionCount] No nonce found")
return false
}
if !r.proxyRequestRead() {
r.logger.Info("[ProcessRequest] Proxy to node failed", "method", r.jsonReq.Method)
r.writeRpcError("internal server error", types.JsonRpcInternalError)
return true
}
r.logger.Info("[eth_getTransactionCount] intercept", "cachedNonce", cachedNonce, "addr", addr)

backendTxCount := uint64(0)
if r.jsonRes.Result != nil {
if err := json.Unmarshal(r.jsonRes.Result, &backendTxCount); err != nil {
r.logger.Info("[ProcessRequest] Proxy to node failed", "method", r.jsonReq.Method)
r.writeRpcError("internal server error", types.JsonRpcInternalError)
return true
}
r.logger.Info("[eth_getTransactionCount] intercept", "backendTxCount", backendTxCount, "addr", addr)
}

// return either the cached nonce plus one, or the backend tx count
txCount := cachedNonce + 1
if backendTxCount > txCount {
txCount = backendTxCount
// since the cached value is invalid lets remove it from redis
r.logger.Info("[eth_getTransactionCount] intercept invalidated nonce", "addr", addr)
if err := RState.DelSenderMaxNonce(addr); err != nil {
// log the error but continue
r.logger.Error("[eth_getTransactionCount] Redis:DelSenderMaxNonce error", "error", err, "addr", addr)
}
}

r.logger.Info("[eth_getTransactionCount] intercept", "nonce", nonce)
resp := fmt.Sprintf("0x%x", nonce+1)
resp := fmt.Sprintf("0x%x", txCount)
r.writeRpcResult(resp)
return true
}

0 comments on commit 2445525

Please sign in to comment.