diff --git a/cmd/loadtest/output.go b/cmd/loadtest/output.go index 6d175acf..2be17c5d 100644 --- a/cmd/loadtest/output.go +++ b/cmd/loadtest/output.go @@ -105,12 +105,15 @@ func printBlockSummary(c *ethclient.Client, bs map[uint64]blockSummary, startNon p.Printf("Transactions per sec: %v\n", number.Decimal(tps)) p.Printf("Gas Per Second: %v\n", number.Decimal(gaspersec)) p.Printf("Latencies - Min: %v\tMedian: %v\tMax: %v\n", number.Decimal(minLatency.Seconds()), number.Decimal(medianLatency.Seconds()), number.Decimal(maxLatency.Seconds())) - p.Printf("Mean Blocktime: %vs\n", number.Decimal(meanBlocktime)) - p.Printf("Median Blocktime: %vs\n", number.Decimal(medianBlocktime)) - p.Printf("Minimum Blocktime: %vs\n", number.Decimal(minBlocktime)) - p.Printf("Maximum Blocktime: %vs\n", number.Decimal(maxBlocktime)) - p.Printf("Blocktime Standard Deviation: %vs\n", number.Decimal(stddevBlocktime)) - p.Printf("Blocktime Variance: %vs\n", number.Decimal(varianceBlocktime)) + // Blocktime related metrics can only be calculated when there are at least two blocks + if len(bs) > 1 { + p.Printf("Mean Blocktime: %vs\n", number.Decimal(meanBlocktime)) + p.Printf("Median Blocktime: %vs\n", number.Decimal(medianBlocktime)) + p.Printf("Minimum Blocktime: %vs\n", number.Decimal(minBlocktime)) + p.Printf("Maximum Blocktime: %vs\n", number.Decimal(maxBlocktime)) + p.Printf("Blocktime Standard Deviation: %vs\n", number.Decimal(stddevBlocktime)) + p.Printf("Blocktime Variance: %vs\n", number.Decimal(varianceBlocktime)) + } } else if summaryOutputMode == "json" { summaryOutput := SummaryOutput{} summaryOutput.Summaries = jsonSummaryList diff --git a/util/util.go b/util/util.go index 2f3de79c..c424927c 100644 --- a/util/util.go +++ b/util/util.go @@ -161,14 +161,36 @@ func GetReceipts(ctx context.Context, rawBlocks []*json.RawMessage, c *ethrpc.Cl } break } - - err := c.BatchCallContext(ctx, blms[start:end]) - if err != nil { - log.Error().Err(err).Str("randtx", txHashes[0]).Uint64("start", start).Uint64("end", end).Msg("RPC issue fetching receipts") - return nil, err - } - start = end - if last { + // go-ethereum's BatchCallContext fails when the number of txns are over 100, because it attempts to unmarshal a single json source object into a slice if the number of txns go over 100. + // A workaround could be to implement our own unmarshal function for batch calls to unmarshal the single json object into a custom type (non-slice), but the below method has been chosen. + // When the number of txns go over 100 and forms a slice, this logic will batch call in units of 100 txns. This will successfully unmarshal the json source object. + if end <= 100 { + err := c.BatchCallContext(ctx, blms[start:end]) + if err != nil { + log.Error().Err(err).Str("randtx", txHashes[0]).Uint64("start", start).Uint64("end", end).Msg("RPC issue fetching receipts") + break + } + start = end + if last { + break + } + } else { + for index := uint64(0); index <= end; index = index + 100 { + // Check for the final section of the slice, and also check end is not equal to index, because this will send another already sent BatchCall otherwise. + if end < index+100 && end != index { + err := c.BatchCallContext(ctx, blms[index:end]) + if err != nil { + log.Error().Err(err).Str("randtx", txHashes[0]).Uint64("start", start).Uint64("end", end).Msg("RPC issue fetching receipts") + break + } + break + } + err := c.BatchCallContext(ctx, blms[index:index+100]) + if err != nil { + log.Error().Err(err).Str("randtx", txHashes[0]).Uint64("start", start).Uint64("end", end).Msg("RPC issue fetching receipts") + break + } + } break } } @@ -182,6 +204,10 @@ func GetReceipts(ctx context.Context, rawBlocks []*json.RawMessage, c *ethrpc.Cl } receipts = append(receipts, b.Result.(*json.RawMessage)) } + if len(receipts) == 0 { + log.Error().Msg("No receipts have been fetched") + return nil, nil + } log.Info().Int("hashes", len(txHashes)).Int("receipts", len(receipts)).Msg("Fetched tx receipts") return receipts, nil }