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

Upgrade Kute #6366

Merged
merged 24 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
069807d
Introduce filter limits
emlautarom1 Jul 21, 2023
b5cae4f
Report progress at the start
emlautarom1 Jul 21, 2023
3f99c36
Initial response validator
emlautarom1 Jul 21, 2023
2d48013
Include more examples of filters and limits
emlautarom1 Jul 21, 2023
6ac09f0
Perform validation outside time measurement
emlautarom1 Jul 24, 2023
a32b2bb
Add 'TracerValidator'
emlautarom1 Jul 26, 2023
4af2f00
Document 'TracerValidator'
emlautarom1 Jul 26, 2023
6f333c4
Make config help text more consistent
emlautarom1 Jul 26, 2023
b0919e6
Capitalize
emlautarom1 Jul 26, 2023
77ab7bd
Change name of tracing to verbose
kamilchodola Jul 27, 2023
5842d5c
Update README.md
kamilchodola Jul 27, 2023
22d55df
Use `-r|--responses` to store responses
emlautarom1 Jul 27, 2023
112836e
Invert condition
emlautarom1 Jul 27, 2023
d10c9f8
Merge remote-tracking branch 'origin/feature/replay_rpc' into feature…
emlautarom1 Jul 27, 2023
3d902c5
Make 'IJsonRpcValidator' take also request into consideration
emlautarom1 Jul 27, 2023
d0279fb
Validate 'NewPayload' responses using custom strategy
emlautarom1 Jul 27, 2023
83fe482
Separate 'ResponseTracer' from Validator
emlautarom1 Jul 27, 2023
86d83b3
Validate and trace batch responses
emlautarom1 Jul 27, 2023
c94c018
Add TickSucceeded
kamilchodola Jul 27, 2023
ec3bc7c
Add temp sampleSize
kamilchodola Jul 27, 2023
96c46f0
Tick succeeded on batches too
emlautarom1 Jul 28, 2023
f9aca78
Use 'CompleteReservoir' for sampling
emlautarom1 Jul 28, 2023
6b8ac7b
Remove whitespace
emlautarom1 Dec 13, 2023
538d02e
Remove `IAuth` from `NullJsonRpcSubmitter`
emlautarom1 Dec 13, 2023
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
52 changes: 45 additions & 7 deletions tools/Nethermind.Tools.Kute/Application.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Text.Json;
using Nethermind.Tools.Kute.Extensions;
using Nethermind.Tools.Kute.MessageProvider;
using Nethermind.Tools.Kute.JsonRpcMethodFilter;
using Nethermind.Tools.Kute.JsonRpcSubmitter;
using Nethermind.Tools.Kute.JsonRpcValidator;
using Nethermind.Tools.Kute.MetricsConsumer;
using Nethermind.Tools.Kute.ProgressReporter;
using Nethermind.Tools.Kute.ResponseTracer;

namespace Nethermind.Tools.Kute;

Expand All @@ -16,20 +19,26 @@ class Application

private readonly IMessageProvider<JsonRpc?> _msgProvider;
private readonly IJsonRpcSubmitter _submitter;
private readonly IJsonRpcValidator _validator;
private readonly IResponseTracer _responseTracer;
private readonly IProgressReporter _progressReporter;
private readonly IMetricsConsumer _metricsConsumer;
private readonly IJsonRpcMethodFilter _methodFilter;

public Application(
IMessageProvider<JsonRpc?> msgProvider,
IJsonRpcSubmitter submitter,
IJsonRpcValidator validator,
IResponseTracer responseTracer,
IProgressReporter progressReporter,
IMetricsConsumer metricsConsumer,
IJsonRpcMethodFilter methodFilter
)
{
_msgProvider = msgProvider;
_submitter = submitter;
_validator = validator;
_responseTracer = responseTracer;
_progressReporter = progressReporter;
_metricsConsumer = metricsConsumer;
_methodFilter = methodFilter;
Expand All @@ -43,24 +52,41 @@ public async Task Run()
{
await foreach (var (jsonRpc, n) in _msgProvider.Messages.Indexed(startingFrom: 1))
{
_progressReporter.ReportProgress(n);

_metrics.TickMessages();

switch (jsonRpc)
{
case null:
{
_metrics.TickFailed();

break;

}
case JsonRpc.BatchJsonRpc batch:
{
JsonDocument? result;
using (_metrics.TimeBatch())
{
await _submitter.Submit(batch);
result = await _submitter.Submit(batch);
}

break;
if (_validator.IsInvalid(batch, result))
{
_metrics.TickFailed();
}
else
{
_metrics.TickSucceeded();
}

await _responseTracer.TraceResponse(result);

break;
}
case JsonRpc.SingleJsonRpc single:
{
if (single.IsResponse)
{
_metrics.TickResponses();
Expand All @@ -79,18 +105,30 @@ public async Task Run()
continue;
}

JsonDocument? result;
using (_metrics.TimeMethod(single.MethodName))
{
await _submitter.Submit(single);
result = await _submitter.Submit(single);
}

break;
if (_validator.IsInvalid(single, result))
{
_metrics.TickFailed();
}
else
{
_metrics.TickSucceeded();
}

await _responseTracer.TraceResponse(result);

break;
}
default:
{
throw new ArgumentOutOfRangeException(nameof(jsonRpc));
}
}

_progressReporter.ReportProgress(n);
}
}

Expand Down
20 changes: 15 additions & 5 deletions tools/Nethermind.Tools.Kute/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ public class Config
longName: "address",
Required = false,
Default = "http://localhost:8551",
HelpText = "Address where to send JSON RPC calls"
HelpText = "Address where to send JSON RPC requests"
)]
public string HostAddress { get; }

[Option(
shortName: 's',
longName: "secret",
Required = true,
HelpText = "Path to file with hex encoded secret for JWT authentication"
HelpText = "Path to File with hex encoded secret for JWT authentication"
)]
public string JwtSecretFilePath { get; }

Expand Down Expand Up @@ -75,10 +75,19 @@ public class Config
Separator = ',',
Required = false,
Default = new string[] { },
HelpText = "A comma separated List of regexes of methods to be executed"
HelpText = "A comma separated List of regexes of methods to be executed with optional limits"
)]
public IEnumerable<string> MethodFilters { get; }

[Option(
shortName: 'r',
longName: "responses",
Required = false,
Default = null,
HelpText = "Path to File to store JSON-RPC responses"
)]
public string? ResponsesTraceFile { get; }

public Config(
string messagesFilePath,
string hostAddress,
Expand All @@ -87,7 +96,8 @@ public Config(
bool dryRun,
bool showProgress,
MetricsOutputFormatter metricsOutputFormatter,
IEnumerable<string> methodFilters
IEnumerable<string> methodFilters,
string? responsesTraceFile
)
{
MessagesFilePath = messagesFilePath;
Expand All @@ -98,6 +108,6 @@ IEnumerable<string> methodFilters
ShowProgress = showProgress;
MetricsOutputFormatter = metricsOutputFormatter;
MethodFilters = methodFilters;
ShowProgress = showProgress;
ResponsesTraceFile = responsesTraceFile;
}
}
45 changes: 45 additions & 0 deletions tools/Nethermind.Tools.Kute/Extensions/CompleteReservoir.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using App.Metrics;
using App.Metrics.ReservoirSampling;
using App.Metrics.ReservoirSampling.Uniform;

namespace Nethermind.Tools.Kute.Extensions;

public class CompleteReservoir : IReservoir
{
private const int DefaultSize = 10_000;

private readonly List<UserValueWrapper> _values;

public CompleteReservoir() : this(DefaultSize) { }

public CompleteReservoir(int size)
{
_values = new List<UserValueWrapper>(size);
}

public IReservoirSnapshot GetSnapshot(bool resetReservoir)
{
long count = _values.Count;
double sum = _values.Sum(v => v.Value);
IEnumerable<long> values = _values.Select(v => v.Value);

if (resetReservoir)
{
_values.Clear();
}

return new UniformSnapshot(count, sum, values);
}

public IReservoirSnapshot GetSnapshot() => GetSnapshot(false);

public void Reset() => _values.Clear();

public void Update(long value, string userValue) => _values.Add(new UserValueWrapper(value, userValue));

public void Update(long value) => _values.Add(new UserValueWrapper(value));

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

namespace Nethermind.Tools.Kute.JsonRpcMethodFilter;

class LimitedJsonRpcMethodFilter : IJsonRpcMethodFilter
{
private readonly IJsonRpcMethodFilter _filter;

private int _usagesLeft;

public LimitedJsonRpcMethodFilter(IJsonRpcMethodFilter filter, int limit)
{
_filter = filter;
_usagesLeft = limit;
}

public bool ShouldSubmit(string methodName)
{
if (_filter.ShouldSubmit(methodName))
{
if (_usagesLeft == 0)
{
return false;
}

_usagesLeft--;
return true;
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Text.RegularExpressions;

namespace Nethermind.Tools.Kute.JsonRpcMethodFilter;

class PatternJsonRpcMethodFilter : IJsonRpcMethodFilter
public class PatternJsonRpcMethodFilter : IJsonRpcMethodFilter
{
private readonly Regex _pattern;
private const char PatternSeparator = '=';

private readonly IJsonRpcMethodFilter _filter;
public PatternJsonRpcMethodFilter(string pattern)
{
_pattern = new Regex(pattern);
var splitted = pattern.Split(PatternSeparator);

var regex = new RegexJsonRpcMethodFilter(splitted[0]);
_filter = splitted.Length switch
{
1 => regex,
2 => new LimitedJsonRpcMethodFilter(regex, int.Parse(splitted[1])),
_ => throw new ArgumentException($"Unexpected pattern: {pattern}"),
};
}

public bool ShouldSubmit(string methodName) => _pattern.IsMatch(methodName);
public bool ShouldSubmit(string methodName) => _filter.ShouldSubmit(methodName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Text.RegularExpressions;

namespace Nethermind.Tools.Kute.JsonRpcMethodFilter;

class RegexJsonRpcMethodFilter : IJsonRpcMethodFilter
{
private readonly Regex _pattern;

public RegexJsonRpcMethodFilter(string pattern)
{
_pattern = new Regex(pattern);
}

public bool ShouldSubmit(string methodName) => _pattern.IsMatch(methodName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Text;
using System.Text.Json;
using Nethermind.Tools.Kute.Auth;

namespace Nethermind.Tools.Kute.JsonRpcSubmitter;
Expand All @@ -22,7 +23,7 @@ public HttpJsonRpcSubmitter(HttpClient httpClient, IAuth auth, string hostAddres
_uri = new Uri(hostAddress);
}

public async Task Submit(JsonRpc rpc)
public async Task<JsonDocument?> Submit(JsonRpc rpc)
{
var request = new HttpRequestMessage(HttpMethod.Post, _uri)
{
Expand All @@ -32,7 +33,9 @@ public async Task Submit(JsonRpc rpc)
var response = await _httpClient.SendAsync(request);
if (response.StatusCode != HttpStatusCode.OK)
{
throw new HttpRequestException($"Expected {HttpStatusCode.OK}, got {response.StatusCode}");
return null;
}
var content = await response.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync<JsonDocument>(content);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Text.Json;

namespace Nethermind.Tools.Kute.JsonRpcSubmitter;

interface IJsonRpcSubmitter
{
Task Submit(JsonRpc rpc);
Task<JsonDocument?> Submit(JsonRpc rpc);
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using Nethermind.Tools.Kute.Auth;
using System.Text.Json;

namespace Nethermind.Tools.Kute.JsonRpcSubmitter;

class NullJsonRpcSubmitter : IJsonRpcSubmitter
{
private readonly IAuth _auth;

public NullJsonRpcSubmitter(IAuth auth)
{
_auth = auth;
}

public Task Submit(JsonRpc rpc)
{
_ = _auth.AuthToken;
return Task.CompletedTask;
}
public Task<JsonDocument?> Submit(JsonRpc rpc) => Task.FromResult<JsonDocument?>(null);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Text.Json;

namespace Nethermind.Tools.Kute.JsonRpcValidator;

public class ComposedJsonRpcValidator : IJsonRpcValidator
{
private readonly IEnumerable<IJsonRpcValidator> _validators;

public ComposedJsonRpcValidator(IEnumerable<IJsonRpcValidator> validators)
{
_validators = validators;
}

public bool IsValid(JsonRpc request, JsonDocument? document) => _validators.All(validator => validator.IsValid(request, document));
}
Loading