mirror of
https://github.com/trezor/blockbook.git
synced 2026-02-20 00:51:39 +01:00
avoid parallelization that provokes backend rate limitting
This commit is contained in:
@@ -946,13 +946,15 @@ func (b *EthereumRPC) processCallTrace(call *rpcCallTrace, d *bchain.EthereumInt
|
|||||||
return contracts
|
return contracts
|
||||||
}
|
}
|
||||||
|
|
||||||
// getInternalDataForBlock fetches debug trace using callTracer, extracts internal transfers/creations/destructions; ctx controls cancellation.
|
// getInternalDataForBlock fetches debug trace using callTracer, extracts internal transfers and creations and destructions of contracts
|
||||||
func (b *EthereumRPC) getInternalDataForBlock(ctx context.Context, blockHash string, blockHeight uint32, transactions []bchain.RpcTransaction) ([]bchain.EthereumInternalData, []bchain.ContractInfo, error) {
|
func (b *EthereumRPC) getInternalDataForBlock(blockHash string, blockHeight uint32, transactions []bchain.RpcTransaction) ([]bchain.EthereumInternalData, []bchain.ContractInfo, error) {
|
||||||
data := make([]bchain.EthereumInternalData, len(transactions))
|
data := make([]bchain.EthereumInternalData, len(transactions))
|
||||||
contracts := make([]bchain.ContractInfo, 0)
|
contracts := make([]bchain.ContractInfo, 0)
|
||||||
if ProcessInternalTransactions {
|
if ProcessInternalTransactions {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||||
|
defer cancel()
|
||||||
var trace []rpcTraceResult
|
var trace []rpcTraceResult
|
||||||
err := b.RPC.CallContext(ctx, &trace, "debug_traceBlockByHash", blockHash, map[string]interface{}{"tracer": "callTracer"}) // Use caller-provided ctx for timeout/cancel.
|
err := b.RPC.CallContext(ctx, &trace, "debug_traceBlockByHash", blockHash, map[string]interface{}{"tracer": "callTracer"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("debug_traceBlockByHash block ", blockHash, ", error ", err)
|
glog.Error("debug_traceBlockByHash block ", blockHash, ", error ", err)
|
||||||
return data, contracts, err
|
return data, contracts, err
|
||||||
@@ -1039,49 +1041,21 @@ func (b *EthereumRPC) GetBlock(hash string, height uint32) (*bchain.Block, error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "hash %v, height %v", hash, height)
|
return nil, errors.Annotatef(err, "hash %v, height %v", hash, height)
|
||||||
}
|
}
|
||||||
// Run event/log processing and internal data extraction in parallel; allow early return on log failure.
|
// get block events
|
||||||
ctxInternal, cancelInternal := context.WithTimeout(context.Background(), b.Timeout) // Cancel trace RPC on log error or timeout.
|
// TODO - could be possibly done in parallel to getInternalDataForBlock
|
||||||
defer cancelInternal() // Ensure timer resources are released on any return path.
|
logs, ens, err := b.processEventsForBlock(head.Number)
|
||||||
type logsResult struct { // Bundles processEventsForBlock outputs for channel return.
|
if err != nil {
|
||||||
logs map[string][]*bchain.RpcLog
|
return nil, err
|
||||||
ens []bchain.AddressAliasRecord
|
|
||||||
err error
|
|
||||||
}
|
}
|
||||||
type internalResult struct { // Bundles getInternalDataForBlock outputs for channel return.
|
|
||||||
data []bchain.EthereumInternalData
|
|
||||||
contracts []bchain.ContractInfo
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
logsCh := make(chan logsResult, 1) // Buffered so send won't block if we return early.
|
|
||||||
internalCh := make(chan internalResult, 1) // Buffered to avoid goroutine leak on early return.
|
|
||||||
go func() {
|
|
||||||
logs, ens, err := b.processEventsForBlock(head.Number)
|
|
||||||
logsCh <- logsResult{logs: logs, ens: ens, err: err} // Send result without shared state.
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
data, contracts, err := b.getInternalDataForBlock(ctxInternal, head.Hash, bbh.Height, body.Transactions) // ctxInternal allows cancellation on log errors.
|
|
||||||
internalCh <- internalResult{data: data, contracts: contracts, err: err} // Send result without shared state.
|
|
||||||
}()
|
|
||||||
logsRes := <-logsCh
|
|
||||||
if logsRes.err != nil {
|
|
||||||
// Short-circuit on log failure to preserve existing error behavior.
|
|
||||||
return nil, logsRes.err
|
|
||||||
}
|
|
||||||
internalRes := <-internalCh
|
|
||||||
// Rebind results to keep downstream logic unchanged.
|
|
||||||
logs := logsRes.logs
|
|
||||||
ens := logsRes.ens
|
|
||||||
internalData := internalRes.data
|
|
||||||
contracts := internalRes.contracts
|
|
||||||
internalErr := internalRes.err
|
|
||||||
// error fetching internal data does not stop the block processing
|
// error fetching internal data does not stop the block processing
|
||||||
var blockSpecificData *bchain.EthereumBlockSpecificData
|
var blockSpecificData *bchain.EthereumBlockSpecificData
|
||||||
|
internalData, contracts, err := b.getInternalDataForBlock(head.Hash, bbh.Height, body.Transactions)
|
||||||
// pass internalData error and ENS records in blockSpecificData to be stored
|
// pass internalData error and ENS records in blockSpecificData to be stored
|
||||||
if internalErr != nil || len(ens) > 0 || len(contracts) > 0 {
|
if err != nil || len(ens) > 0 || len(contracts) > 0 {
|
||||||
blockSpecificData = &bchain.EthereumBlockSpecificData{}
|
blockSpecificData = &bchain.EthereumBlockSpecificData{}
|
||||||
if internalErr != nil {
|
if err != nil {
|
||||||
blockSpecificData.InternalDataError = internalErr.Error()
|
blockSpecificData.InternalDataError = err.Error()
|
||||||
// glog.Info("InternalDataError ", bbh.Height, ": ", internalErr.Error())
|
// glog.Info("InternalDataError ", bbh.Height, ": ", err.Error())
|
||||||
}
|
}
|
||||||
if len(ens) > 0 {
|
if len(ens) > 0 {
|
||||||
blockSpecificData.AddressAliasRecords = ens
|
blockSpecificData.AddressAliasRecords = ens
|
||||||
|
|||||||
Reference in New Issue
Block a user