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(op-node): pre-fetch block info and transaction #110

Closed
Closed
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
12 changes: 12 additions & 0 deletions op-node/sources/caching/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ func (c *LRUCache) Get(key any) (value any, ok bool) {
return value, ok
}

func (c *LRUCache) GetOrPeek(key any, usePeek bool, recordMetrics bool) (value any, ok bool) {
if usePeek {
value, ok = c.inner.Peek(key)
} else {
value, ok = c.inner.Get(key)
}
if c.m != nil && recordMetrics {
c.m.CacheGet(c.label, ok)
}
return value, ok
}

bnoieh marked this conversation as resolved.
Show resolved Hide resolved
func (c *LRUCache) Add(key, value any) (evicted bool) {
evicted = c.inner.Add(key, value)
if c.m != nil {
Expand Down
4 changes: 2 additions & 2 deletions op-node/sources/caching/pre_fetch_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ func (v *PreFetchCache[V]) AddIfNotFull(key uint64, value V) (success bool, isFu
return true, false
}

func (v *PreFetchCache[V]) Get(key uint64) (V, bool) {
func (v *PreFetchCache[V]) Get(key uint64, recordMetrics bool) (V, bool) {
defer v.lock.Unlock()
v.lock.Lock()
value, ok := v.inner[key]
if v.m != nil {
if v.m != nil && recordMetrics {
v.m.CacheGet(v.label, ok)
}
return value, ok
Expand Down
21 changes: 15 additions & 6 deletions op-node/sources/eth_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ type EthClient struct {

// methodResetDuration defines how long we take till we reset lastMethodsReset
methodResetDuration time.Duration

// isReadOrderly Indicates whether the client often reads data in order of block height.
// If so, the process of reading the cache will be different to ensure a high cache hit rate.
isReadOrderly bool
}

func (s *EthClient) PickReceiptsMethod(txCount uint64) ReceiptsFetchingMethod {
Expand Down Expand Up @@ -160,7 +164,7 @@ func (s *EthClient) OnReceiptsMethodErr(m ReceiptsFetchingMethod, err error) {

// NewEthClient returns an [EthClient], wrapping an RPC with bindings to fetch ethereum data with added error logging,
// metric tracking, and caching. The [EthClient] uses a [LimitRPC] wrapper to limit the number of concurrent RPC requests.
func NewEthClient(client client.RPC, log log.Logger, metrics caching.Metrics, config *EthClientConfig) (*EthClient, error) {
func NewEthClient(client client.RPC, log log.Logger, metrics caching.Metrics, config *EthClientConfig, isReadOrderly bool) (*EthClient, error) {
if err := config.Check(); err != nil {
return nil, fmt.Errorf("bad config, cannot create L1 source: %w", err)
}
Expand All @@ -179,6 +183,7 @@ func NewEthClient(client client.RPC, log log.Logger, metrics caching.Metrics, co
availableReceiptMethods: AvailableReceiptsFetchingMethods(config.RPCProviderKind),
lastMethodsReset: time.Now(),
methodResetDuration: config.MethodResetDuration,
isReadOrderly: isReadOrderly,
}, nil
}

Expand Down Expand Up @@ -291,7 +296,7 @@ func (s *EthClient) ChainID(ctx context.Context) (*big.Int, error) {
}

func (s *EthClient) InfoByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, error) {
if header, ok := s.headersCache.Get(hash); ok {
if header, ok := s.headersCache.GetOrPeek(hash, s.isReadOrderly, true); ok {
return header.(eth.BlockInfo), nil
}
return s.headerCall(ctx, "eth_getBlockByHash", hashID(hash))
Expand All @@ -316,8 +321,12 @@ func (s *EthClient) BSCInfoByLabel(ctx context.Context, label eth.BlockLabel) (e
}

func (s *EthClient) InfoAndTxsByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, types.Transactions, error) {
if header, ok := s.headersCache.Get(hash); ok {
if txs, ok := s.transactionsCache.Get(hash); ok {
return s.infoAndTxsByHash(ctx, hash, true)
}

func (s *EthClient) infoAndTxsByHash(ctx context.Context, hash common.Hash, recordMetrics bool) (eth.BlockInfo, types.Transactions, error) {
if header, ok := s.headersCache.GetOrPeek(hash, s.isReadOrderly, recordMetrics); ok {
if txs, ok := s.transactionsCache.GetOrPeek(hash, s.isReadOrderly, recordMetrics); ok {
return header.(eth.BlockInfo), txs.(types.Transactions), nil
}
}
Expand Down Expand Up @@ -362,7 +371,7 @@ func (s *EthClient) FetchReceipts(ctx context.Context, blockHash common.Hash) (e
}

func (s *EthClient) fetchReceiptsInner(ctx context.Context, blockHash common.Hash, isForPreFetch bool) (eth.BlockInfo, types.Receipts, error, bool) {
info, txs, err := s.InfoAndTxsByHash(ctx, blockHash)
info, txs, err := s.infoAndTxsByHash(ctx, blockHash, !isForPreFetch)
if err != nil {
return nil, nil, err, false
}
Expand All @@ -371,7 +380,7 @@ func (s *EthClient) fetchReceiptsInner(ctx context.Context, blockHash common.Has
// The underlying fetcher uses the receipts hash to verify receipt integrity.
var job *receiptsFetchingJob
var isFull bool
v, ok := s.receiptsCache.Get(info.NumberU64())
v, ok := s.receiptsCache.Get(info.NumberU64(), !isForPreFetch)
if ok && v.blockHash == blockHash {
job = v.job
} else {
Expand Down
2 changes: 1 addition & 1 deletion op-node/sources/eth_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func TestEthClient_InfoByHash(t *testing.T) {
"eth_getBlockByHash", []any{rhdr.Hash, false}).Run(func(args mock.Arguments) {
*args[1].(**rpcHeader) = rhdr
}).Return([]error{nil})
s, err := NewEthClient(m, nil, nil, testEthClientConfig)
s, err := NewEthClient(m, nil, nil, testEthClientConfig, false)
require.NoError(t, err)
info, err := s.InfoByHash(ctx, rhdr.Hash)
require.NoError(t, err)
Expand Down
5 changes: 3 additions & 2 deletions op-node/sources/l1_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ type L1Client struct {

// NewL1Client wraps a RPC with bindings to fetch L1 data, while logging errors, tracking metrics (optional), and caching.
func NewL1Client(client client.RPC, log log.Logger, metrics caching.Metrics, config *L1ClientConfig) (*L1Client, error) {
ethClient, err := NewEthClient(client, log, metrics, &config.EthClientConfig)
ethClient, err := NewEthClient(client, log, metrics, &config.EthClientConfig, true)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -186,13 +186,13 @@ func (s *L1Client) GoOrUpdatePreFetchReceipts(ctx context.Context, l1Start uint6
case <-s.done:
return
default:
pair, ok := s.receiptsCache.Get(blockNumber)
blockInfo, err := s.L1BlockRefByNumber(ctx, blockNumber)
if err != nil {
s.log.Debug("failed to fetch block ref", "err", err, "blockNumber", blockNumber)
time.Sleep(1 * time.Second)
continue
}
pair, ok := s.receiptsCache.Get(blockNumber, false)
if ok && pair.blockHash == blockInfo.Hash {
blockInfoChan <- blockInfo
return
Expand Down Expand Up @@ -250,6 +250,7 @@ func (s *L1Client) GoOrUpdatePreFetchReceipts(ctx context.Context, l1Start uint6
}

func (s *L1Client) ClearReceiptsCacheBefore(blockNumber uint64) {
s.log.Debug("clear receipts cache before", "blockNumber", blockNumber)
s.receiptsCache.RemoveLessThan(blockNumber)
}

Expand Down
4 changes: 2 additions & 2 deletions op-node/sources/l1_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,10 @@ func TestGoOrUpdatePreFetchReceipts(t *testing.T) {
err2 := s.GoOrUpdatePreFetchReceipts(ctx, 81)
require.NoError(t, err2)
time.Sleep(1 * time.Second)
pair, ok := s.receiptsCache.Get(100)
pair, ok := s.receiptsCache.Get(100, false)
require.True(t, ok, "100 cache miss")
require.Equal(t, real100Hash, pair.blockHash, "block 100 hash is different,want:%s,but:%s", real100Hash, pair.blockHash)
_, ok2 := s.receiptsCache.Get(76)
_, ok2 := s.receiptsCache.Get(76, false)
require.True(t, ok2, "76 cache miss")
})
}
2 changes: 1 addition & 1 deletion op-node/sources/l2_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ type L2Client struct {
// for fetching and caching eth.L2BlockRef values. This includes fetching an L2BlockRef by block number, label, or hash.
// See: [L2BlockRefByLabel], [L2BlockRefByNumber], [L2BlockRefByHash]
func NewL2Client(client client.RPC, log log.Logger, metrics caching.Metrics, config *L2ClientConfig) (*L2Client, error) {
ethClient, err := NewEthClient(client, log, metrics, &config.EthClientConfig)
ethClient, err := NewEthClient(client, log, metrics, &config.EthClientConfig, false)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion op-node/sources/receipts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func (tc *ReceiptsTestCase) Run(t *testing.T) {
testCfg.MethodResetDuration = 0
}
logger := testlog.Logger(t, log.LvlError)
ethCl, err := NewEthClient(client.NewBaseRPCClient(cl), logger, nil, testCfg)
ethCl, err := NewEthClient(client.NewBaseRPCClient(cl), logger, nil, testCfg, true)
require.NoError(t, err)
defer ethCl.Close()

Expand Down
3 changes: 0 additions & 3 deletions ops-bedrock/Dockerfile.l1
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ RUN git clone https://github.com/bnb-chain/bsc.git
RUN cd bsc && git checkout v1.2.12 && make geth && go build -o ./build/bin/bootnode ./cmd/bootnode
RUN git clone https://github.com/bnb-chain/node.git
RUN cd node && git checkout v0.10.16 && make build
RUN git clone https://github.com/bnb-chain/test-crosschain-transfer.git
RUN cd test-crosschain-transfer && go build

FROM golang:1.19-alpine3.18

Expand All @@ -18,6 +16,5 @@ COPY --from=build /go/bsc/build/bin/geth /db/node-deploy/bin/geth
COPY --from=build /go/bsc/build/bin/bootnode /db/node-deploy/bin/bootnode
COPY --from=build /go/node/build/tbnbcli /db/node-deploy/bin/tbnbcli
COPY --from=build /go/node/build/bnbchaind /db/node-deploy/bin/bnbchaind
COPY --from=build /go/test-crosschain-transfer/test-crosschain-transfer /db/node-deploy/bin/test-crosschain-transfer

ENTRYPOINT ["/bin/sh", "/l1-entrypoint.sh"]
2 changes: 1 addition & 1 deletion ops-bedrock/Dockerfile.l2
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM --platform=linux/amd64 ghcr.io/bnb-chain/op-geth:latest
FROM --platform=linux/amd64 ghcr.io/bnb-chain/op-geth:develop

RUN apk add --no-cache jq

Expand Down
Loading