From 9f7e95c5159bf603fb49863cba87e2b804717299 Mon Sep 17 00:00:00 2001 From: benbierens Date: Mon, 8 Apr 2024 13:36:55 +0200 Subject: [PATCH 1/3] Applies async/await to getbalance and mint commands --- Tools/BiblioTech/Commands/GetBalanceCommand.cs | 10 ++++++++-- Tools/BiblioTech/Commands/MintCommand.cs | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Tools/BiblioTech/Commands/GetBalanceCommand.cs b/Tools/BiblioTech/Commands/GetBalanceCommand.cs index 964d7c2..3c98335 100644 --- a/Tools/BiblioTech/Commands/GetBalanceCommand.cs +++ b/Tools/BiblioTech/Commands/GetBalanceCommand.cs @@ -31,8 +31,14 @@ namespace BiblioTech.Commands return; } - var eth = gethNode.GetEthBalance(addr); - var testTokens = contracts.GetTestTokenBalance(addr); + var eth = 0.Eth(); + var testTokens = 0.TestTokens(); + + await Task.Run(() => + { + eth = gethNode.GetEthBalance(addr); + testTokens = contracts.GetTestTokenBalance(addr); + }); await context.Followup($"{context.Command.User.Username} has {eth} and {testTokens}."); } diff --git a/Tools/BiblioTech/Commands/MintCommand.cs b/Tools/BiblioTech/Commands/MintCommand.cs index faf62c8..a017ee2 100644 --- a/Tools/BiblioTech/Commands/MintCommand.cs +++ b/Tools/BiblioTech/Commands/MintCommand.cs @@ -33,8 +33,14 @@ namespace BiblioTech.Commands var report = new List(); - var sentEth = ProcessEth(gethNode, addr, report); - var mintedTokens = ProcessTokens(contracts, addr, report); + Transaction? sentEth = null; + Transaction? mintedTokens = null; + + await Task.Run(() => + { + sentEth = ProcessEth(gethNode, addr, report); + mintedTokens = ProcessTokens(contracts, addr, report); + }); Program.UserRepo.AddMintEventForUser(userId, addr, sentEth, mintedTokens); From 0b2dcef57e05331600ec5d42121950aa0d2d6980 Mon Sep 17 00:00:00 2001 From: benbierens Date: Mon, 8 Apr 2024 13:55:39 +0200 Subject: [PATCH 2/3] Sets up showing of chain events in discord bot --- .../DiscordRewards/GiveRewardsCommand.cs | 1 + Tools/BiblioTech/Configuration.cs | 3 +++ Tools/BiblioTech/Rewards/RoleDriver.cs | 23 +++++++++++++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Framework/DiscordRewards/GiveRewardsCommand.cs b/Framework/DiscordRewards/GiveRewardsCommand.cs index 0fd7a0f..9617633 100644 --- a/Framework/DiscordRewards/GiveRewardsCommand.cs +++ b/Framework/DiscordRewards/GiveRewardsCommand.cs @@ -4,6 +4,7 @@ { public RewardUsersCommand[] Rewards { get; set; } = Array.Empty(); public MarketAverage[] Averages { get; set; } = Array.Empty(); + public string[] EventsOverview { get; set; } = Array.Empty(); } public class RewardUsersCommand diff --git a/Tools/BiblioTech/Configuration.cs b/Tools/BiblioTech/Configuration.cs index 2183a54..37e1cc3 100644 --- a/Tools/BiblioTech/Configuration.cs +++ b/Tools/BiblioTech/Configuration.cs @@ -22,6 +22,9 @@ namespace BiblioTech [Uniform("rewards-channel-name", "rc", "REWARDSCHANNELNAME", false, "Name of the Discord server channel where participation rewards will be announced.")] public string RewardsChannelName { get; set; } = ""; + [Uniform("chain-events-channel-name", "cc", "CHAINEVENTSCHANNELNAME", false, "Name of the Discord server channel where chain events will be posted.")] + public string ChainEventsChannelName { get; set; } = ""; + [Uniform("reward-api-port", "rp", "REWARDAPIPORT", false, "TCP listen port for the reward API.")] public int RewardApiPort { get; set; } = 31080; diff --git a/Tools/BiblioTech/Rewards/RoleDriver.cs b/Tools/BiblioTech/Rewards/RoleDriver.cs index 182dbf8..2afff6e 100644 --- a/Tools/BiblioTech/Rewards/RoleDriver.cs +++ b/Tools/BiblioTech/Rewards/RoleDriver.cs @@ -9,16 +9,15 @@ namespace BiblioTech.Rewards { private readonly DiscordSocketClient client; private readonly SocketTextChannel? rewardsChannel; + private readonly SocketTextChannel? eventsChannel; private readonly RewardRepo repo = new RewardRepo(); public RoleDriver(DiscordSocketClient client) { this.client = client; - if (!string.IsNullOrEmpty(Program.Config.RewardsChannelName)) - { - rewardsChannel = GetGuild().TextChannels.SingleOrDefault(c => c.Name == Program.Config.RewardsChannelName); - } + rewardsChannel = GetChannel(Program.Config.RewardsChannelName); + eventsChannel = GetChannel(Program.Config.ChainEventsChannelName); } public async Task GiveRewards(GiveRewardsCommand rewards) @@ -34,6 +33,22 @@ namespace BiblioTech.Rewards rewardsChannel); await context.ProcessGiveRewardsCommand(LookUpUsers(rewards)); + await ProcessChainEvents(rewards.EventsOverview); + } + + private SocketTextChannel? GetChannel(string name) + { + if (string.IsNullOrEmpty(name)) return null; + return GetGuild().TextChannels.SingleOrDefault(c => c.Name == name); + } + + private async Task ProcessChainEvents(string[] eventsOverview) + { + if (eventsChannel == null || eventsOverview == null || !eventsOverview.Any()) return; + foreach (var e in eventsOverview) + { + await eventsChannel.SendMessageAsync(e); + } } private async Task> LoadAllUsers(SocketGuild guild) From bbc975141fc90cb15238ea6a5d1fc89c330120aa Mon Sep 17 00:00:00 2001 From: benbierens Date: Mon, 8 Apr 2024 16:07:52 +0200 Subject: [PATCH 3/3] Creates events overview in rewarder bot --- .../Marketplace/Customizations.cs | 6 ++ Tools/TestNetRewarder/ChainState.cs | 72 +++++++++++++++++++ Tools/TestNetRewarder/Configuration.cs | 3 + Tools/TestNetRewarder/HistoricState.cs | 41 ++++++++++- Tools/TestNetRewarder/Processor.cs | 13 +++- 5 files changed, 131 insertions(+), 4 deletions(-) diff --git a/ProjectPlugins/CodexContractsPlugin/Marketplace/Customizations.cs b/ProjectPlugins/CodexContractsPlugin/Marketplace/Customizations.cs index 96490b7..8e8edb2 100644 --- a/ProjectPlugins/CodexContractsPlugin/Marketplace/Customizations.cs +++ b/ProjectPlugins/CodexContractsPlugin/Marketplace/Customizations.cs @@ -1,10 +1,12 @@ #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. using GethPlugin; +using Newtonsoft.Json; namespace CodexContractsPlugin.Marketplace { public partial class Request : RequestBase { + [JsonIgnore] public ulong BlockNumber { get; set; } public byte[] RequestId { get; set; } @@ -13,22 +15,26 @@ namespace CodexContractsPlugin.Marketplace public partial class RequestFulfilledEventDTO { + [JsonIgnore] public ulong BlockNumber { get; set; } } public partial class RequestCancelledEventDTO { + [JsonIgnore] public ulong BlockNumber { get; set; } } public partial class SlotFilledEventDTO { + [JsonIgnore] public ulong BlockNumber { get; set; } public EthAddress Host { get; set; } } public partial class SlotFreedEventDTO { + [JsonIgnore] public ulong BlockNumber { get; set; } } } diff --git a/Tools/TestNetRewarder/ChainState.cs b/Tools/TestNetRewarder/ChainState.cs index b57c39b..ce7f850 100644 --- a/Tools/TestNetRewarder/ChainState.cs +++ b/Tools/TestNetRewarder/ChainState.cs @@ -1,5 +1,6 @@ using CodexContractsPlugin; using CodexContractsPlugin.Marketplace; +using Newtonsoft.Json; using Utils; namespace TestNetRewarder @@ -11,11 +12,13 @@ namespace TestNetRewarder public ChainState(HistoricState historicState, ICodexContracts contracts, BlockInterval blockRange) { NewRequests = contracts.GetStorageRequests(blockRange); + historicState.CleanUpOldRequests(); historicState.ProcessNewRequests(NewRequests); historicState.UpdateStorageRequests(contracts); StartedRequests = historicState.StorageRequests.Where(r => r.RecentlyStarted).ToArray(); FinishedRequests = historicState.StorageRequests.Where(r => r.RecentlyFinished).ToArray(); + ChangedRequests = historicState.StorageRequests.Where(r => r.RecentlyChanged).ToArray(); RequestFulfilledEvents = contracts.GetRequestFulfilledEvents(blockRange); RequestCancelledEvents = contracts.GetRequestCancelledEvents(blockRange); SlotFilledEvents = contracts.GetSlotFilledEvents(blockRange); @@ -27,9 +30,78 @@ namespace TestNetRewarder public StorageRequest[] AllRequests => historicState.StorageRequests; public StorageRequest[] StartedRequests { get; private set; } public StorageRequest[] FinishedRequests { get; private set; } + public StorageRequest[] ChangedRequests { get; private set; } public RequestFulfilledEventDTO[] RequestFulfilledEvents { get; } public RequestCancelledEventDTO[] RequestCancelledEvents { get; } public SlotFilledEventDTO[] SlotFilledEvents { get; } public SlotFreedEventDTO[] SlotFreedEvents { get; } + + public string[] GenerateOverview() + { + var entries = new List(); + + entries.AddRange(ChangedRequests.Select(ToPair)); + entries.AddRange(RequestFulfilledEvents.Select(ToPair)); + entries.AddRange(RequestCancelledEvents.Select(ToPair)); + entries.AddRange(SlotFilledEvents.Select(ToPair)); + entries.AddRange(SlotFreedEvents.Select(ToPair)); + + entries.Sort(new StringUtcComparer()); + + return entries.Select(ToLine).ToArray(); + } + + private StringBlockNumberPair ToPair(StorageRequest r) + { + return new StringBlockNumberPair(JsonConvert.SerializeObject(r), r.Request.BlockNumber); + } + + private StringBlockNumberPair ToPair(RequestFulfilledEventDTO r) + { + return new StringBlockNumberPair(JsonConvert.SerializeObject(r), r.BlockNumber); + } + + private StringBlockNumberPair ToPair(RequestCancelledEventDTO r) + { + return new StringBlockNumberPair(JsonConvert.SerializeObject(r), r.BlockNumber); + } + + private StringBlockNumberPair ToPair(SlotFilledEventDTO r) + { + return new StringBlockNumberPair(JsonConvert.SerializeObject(r), r.BlockNumber); + } + + private StringBlockNumberPair ToPair(SlotFreedEventDTO r) + { + return new StringBlockNumberPair(JsonConvert.SerializeObject(r), r.BlockNumber); + } + + private string ToLine(StringBlockNumberPair pair) + { + return $"[{pair.Number}] {pair.Str}"; + } + + public class StringBlockNumberPair + { + public StringBlockNumberPair(string str, ulong number) + { + Str = str; + Number = number; + } + + public string Str { get; } + public ulong Number { get; } + } + + public class StringUtcComparer : IComparer + { + public int Compare(StringBlockNumberPair? x, StringBlockNumberPair? y) + { + if (x == null && y == null) return 0; + if (x == null) return 1; + if (y == null) return -1; + return x.Number.CompareTo(y.Number); + } + } } } diff --git a/Tools/TestNetRewarder/Configuration.cs b/Tools/TestNetRewarder/Configuration.cs index ed885d1..c180648 100644 --- a/Tools/TestNetRewarder/Configuration.cs +++ b/Tools/TestNetRewarder/Configuration.cs @@ -22,6 +22,9 @@ namespace TestNetRewarder [Uniform("market-insights", "mi", "MARKETINSIGHTS", false, "Semi-colon separated integers. Each represents a multiple of intervals, for which a market insights average will be generated.")] public string MarketInsights { get; set; } = "1;96"; + [Uniform("events-overview", "eo", "EVENTSOVERVIEW", false, "When greater than zero, chain event summary will be generated. (default 1)")] + public int CreateChainEventsOverview { get; set; } = 1; + public string LogPath { get diff --git a/Tools/TestNetRewarder/HistoricState.cs b/Tools/TestNetRewarder/HistoricState.cs index 53fd1ba..316a80e 100644 --- a/Tools/TestNetRewarder/HistoricState.cs +++ b/Tools/TestNetRewarder/HistoricState.cs @@ -1,6 +1,7 @@ using CodexContractsPlugin; using CodexContractsPlugin.Marketplace; using GethPlugin; +using Newtonsoft.Json; namespace TestNetRewarder { @@ -19,6 +20,17 @@ namespace TestNetRewarder { foreach (var r in storageRequests) r.Update(contracts); } + + public void CleanUpOldRequests() + { + storageRequests.RemoveAll(r => + r.State == RequestState.Cancelled || + r.State == RequestState.Finished || + r.State == RequestState.Failed + ); + + foreach (var r in storageRequests) r.IsNew = false; + } } public class StorageRequest @@ -27,17 +39,26 @@ namespace TestNetRewarder { Request = request; Hosts = Array.Empty(); + IsNew = true; } public Request Request { get; } public EthAddress[] Hosts { get; private set; } public RequestState State { get; private set; } + public bool IsNew { get; set; } + + [JsonIgnore] public bool RecentlyStarted { get; private set; } + + [JsonIgnore] public bool RecentlyFinished { get; private set; } + [JsonIgnore] + public bool RecentlyChanged { get; private set; } + public void Update(ICodexContracts contracts) { - Hosts = GetHosts(contracts); + var newHosts = GetHosts(contracts); var newState = contracts.GetRequestState(Request); @@ -49,7 +70,25 @@ namespace TestNetRewarder State == RequestState.Started && newState == RequestState.Finished; + RecentlyChanged = + IsNew || + State != newState || + HostsChanged(newHosts); + State = newState; + Hosts = newHosts; + } + + private bool HostsChanged(EthAddress[] newHosts) + { + if (newHosts.Length != Hosts.Length) return true; + + foreach (var newHost in newHosts) + { + if (!Hosts.Contains(newHost)) return true; + } + + return false; } private EthAddress[] GetHosts(ICodexContracts contracts) diff --git a/Tools/TestNetRewarder/Processor.cs b/Tools/TestNetRewarder/Processor.cs index 8530330..a293495 100644 --- a/Tools/TestNetRewarder/Processor.cs +++ b/Tools/TestNetRewarder/Processor.cs @@ -65,29 +65,36 @@ namespace TestNetRewarder } var marketAverages = GetMarketAverages(chainState); + var eventsOverview = GenerateEventsOverview(chainState); log.Log($"Found {outgoingRewards.Count} rewards to send. Found {marketAverages.Length} market averages."); if (outgoingRewards.Any()) { - if (!await SendRewardsCommand(outgoingRewards, marketAverages)) + if (!await SendRewardsCommand(outgoingRewards, marketAverages, eventsOverview)) { log.Error("Failed to send reward command."); } } } + private string[] GenerateEventsOverview(ChainState chainState) + { + return chainState.GenerateOverview(); + } + private MarketAverage[] GetMarketAverages(ChainState chainState) { return marketTracker.ProcessChainState(chainState); } - private async Task SendRewardsCommand(List outgoingRewards, MarketAverage[] marketAverages) + private async Task SendRewardsCommand(List outgoingRewards, MarketAverage[] marketAverages, string[] eventsOverview) { var cmd = new GiveRewardsCommand { Rewards = outgoingRewards.ToArray(), - Averages = marketAverages.ToArray() + Averages = marketAverages.ToArray(), + EventsOverview = eventsOverview }; log.Debug("Sending rewards: " + JsonConvert.SerializeObject(cmd));