[rpc] Fix cache lead to inconsistent result (#3733)

* Fix cache lead to inconsistent result

* update

* Add latest block real number to cache

* Fix cache
pull/3739/head
MathxH Chen 4 years ago committed by GitHub
parent 73ab26cf4e
commit c005b3b002
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      rpc/blockchain.go

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"math/big" "math/big"
"strconv"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -160,16 +161,6 @@ func (s *PublicBlockchainService) GetBlockByNumber(
ctx context.Context, blockNumber BlockNumber, opts interface{}, ctx context.Context, blockNumber BlockNumber, opts interface{},
) (response StructuredResponse, err error) { ) (response StructuredResponse, err error) {
blockNum := blockNumber.EthBlockNumber()
if block, ok := s.blockCache.Get(uint64(blockNum)); ok {
return block.(StructuredResponse), nil
}
err = s.wait(ctx)
if err != nil {
return nil, err
}
// Process arguments based on version // Process arguments based on version
var blockArgs *rpc_common.BlockArgs var blockArgs *rpc_common.BlockArgs
blockArgs, ok := opts.(*rpc_common.BlockArgs) blockArgs, ok := opts.(*rpc_common.BlockArgs)
@ -181,6 +172,19 @@ func (s *PublicBlockchainService) GetBlockByNumber(
} }
blockArgs.InclTx = true blockArgs.InclTx = true
blockNum := blockNumber.EthBlockNumber()
if blockNum != rpc.LatestBlockNumber && blockNum != rpc.PendingBlockNumber {
cacheKey := combineCacheKey(uint64(blockNum), s.version, blockArgs)
if block, ok := s.blockCache.Get(cacheKey); ok {
return block.(StructuredResponse), nil
}
}
err = s.wait(ctx)
if err != nil {
return nil, err
}
// Some Ethereum tools (such as Truffle) rely on being able to query for future blocks without the chain returning errors. // Some Ethereum tools (such as Truffle) rely on being able to query for future blocks without the chain returning errors.
// These tools implement retry mechanisms that will query & retry for a given block until it has been finalized. // These tools implement retry mechanisms that will query & retry for a given block until it has been finalized.
// Throwing an error like "requested block number greater than current block number" breaks this retry functionality. // Throwing an error like "requested block number greater than current block number" breaks this retry functionality.
@ -227,7 +231,10 @@ func (s *PublicBlockchainService) GetBlockByNumber(
} }
} }
s.blockCache.Add(uint64(blockNum), response) if blockNum != rpc.PendingBlockNumber {
cacheKey := combineCacheKey(blk.NumberU64(), s.version, blockArgs)
s.blockCache.Add(cacheKey, response)
}
return response, err return response, err
} }
@ -812,3 +819,9 @@ func isBlockGreaterThanLatest(hmy *hmy.Harmony, blockNum rpc.BlockNumber) bool {
} }
return uint64(blockNum) > hmy.CurrentBlock().NumberU64() return uint64(blockNum) > hmy.CurrentBlock().NumberU64()
} }
func combineCacheKey(number uint64, version Version, blockArgs *rpc_common.BlockArgs) string {
// no need format blockArgs.Signers[] as a part of cache key
// because it's not input from rpc caller, it's caculate with blockArgs.WithSigners
return strconv.FormatUint(number, 10) + strconv.FormatInt(int64(version), 10) + strconv.FormatBool(blockArgs.WithSigners) + strconv.FormatBool(blockArgs.InclTx) + strconv.FormatBool(blockArgs.FullTx) + strconv.FormatBool(blockArgs.InclStaking)
}

Loading…
Cancel
Save