-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Map missing chain parameter updates (#141)
* add missing chain update types to mapping * Updated frontend * updated chain log and bumped version * fix data corruption * refactor JobRepository * factor to use common * remove unused generic * refactored health and added resilience to job * added metric * added test * use default source class enricher from serilog * Add job to migrate events * add test * add tests * fix naming and add job * update log format * add log statement * Update ImportWriteController.cs * bump version * Fix job name
- Loading branch information
Søren Schwartz
authored
Dec 1, 2023
1 parent
a34f866
commit b86260e
Showing
20 changed files
with
787 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace Application.Api.GraphQL; | ||
|
||
public readonly record struct Ratio(ulong Numerator, ulong Denominator) | ||
{ | ||
internal static Ratio From(Concordium.Sdk.Types.Ratio ratio) => new(ratio.Numerator, ratio.Denominator); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
141 changes: 141 additions & 0 deletions
141
backend/Application/Database/MigrationJobs/_01_AddMissingChainUpdateEvents.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Application.Api.GraphQL.EfCore; | ||
using Application.Api.GraphQL.Import; | ||
using Application.Api.GraphQL.Transactions; | ||
using Application.Exceptions; | ||
using Application.Import.ConcordiumNode; | ||
using Application.Observability; | ||
using Application.Resilience; | ||
using Concordium.Sdk.Types; | ||
using Dapper; | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.Extensions.Options; | ||
using Serilog.Context; | ||
|
||
namespace Application.Database.MigrationJobs; | ||
|
||
/// <summary> | ||
/// Some transaction events hasn't been mapped to the database. Those missing are | ||
/// <see cref="Concordium.Sdk.Types.UpdateType"/> of one of below values | ||
/// - <see cref="Concordium.Sdk.Types.UpdateType.GasRewardsCpv2Update"/> | ||
/// - <see cref="Concordium.Sdk.Types.UpdateType.TimeoutParametersUpdate"/> | ||
/// - <see cref="Concordium.Sdk.Types.UpdateType.MinBlockTimeUpdate"/> | ||
/// - <see cref="Concordium.Sdk.Types.UpdateType.BlockEnergyLimitUpdate"/> | ||
/// - <see cref="Concordium.Sdk.Types.UpdateType.FinalizationCommitteeParametersUpdate"/> | ||
/// | ||
/// The events are mapped to <see cref="ChainUpdateEnqueued"/>. This migration job adds missing events. | ||
/// | ||
/// Even though transaction events for these cases hasn't been mapped the event type has been set on the | ||
/// <see cref="Transaction"/> entity on property <see cref="Transaction.TransactionType"/>. The jobs starts by | ||
/// querying the transaction table for those transaction with is of one of the missing event types. | ||
/// | ||
/// The mapping between the <see cref="Transaction.TransactionType"/> and the string value stored in the database | ||
/// is present at <see cref="Application.Api.GraphQL.EfCore.Converters.EfCore.TransactionTypeToStringConverter"/>. | ||
/// | ||
/// There is an one-to-one relation between transaction and events when the transaction is of type | ||
/// <see cref="Concordium.Sdk.Types.UpdateDetails"/>. Hence the job is idempotent because it checks if any transaction | ||
/// event for the given transaction already exist, and only generates an event if none is present. | ||
/// </summary> | ||
public class _01_AddMissingChainUpdateEvents : IMainMigrationJob { | ||
/// <summary> | ||
/// WARNING - Do not change this if job already executed on environment, since it will trigger rerun of job. | ||
/// </summary> | ||
private const string JobName = "_01_AddMissingChainUpdateEvents"; | ||
|
||
/// <summary> | ||
/// The mapping between the <see cref="Transaction.TransactionType"/> and the string value stored in the database | ||
/// is present at <see cref="Application.Api.GraphQL.EfCore.Converters.EfCore.TransactionTypeToStringConverter"/>. | ||
/// </summary> | ||
private const string AffectedTransactionTypesSql = @" | ||
SELECT id as Id, block_id as BlockId, index as TransactionIndex, transaction_hash as TransactionHash | ||
FROM graphql_transactions | ||
WHERE transaction_type IN ('2.22', '2.21', '2.20', '2.19', '2.18'); | ||
"; | ||
|
||
private readonly IDbContextFactory<GraphQlDbContext> _contextFactory; | ||
private readonly IConcordiumNodeClient _client; | ||
private readonly JobHealthCheck _jobHealthCheck; | ||
private readonly ILogger _logger; | ||
private readonly MainMigrationJobOptions _mainMigrationJobOptions; | ||
|
||
public _01_AddMissingChainUpdateEvents( | ||
IDbContextFactory<GraphQlDbContext> contextFactory, | ||
IConcordiumNodeClient client, | ||
JobHealthCheck jobHealthCheck, | ||
IOptions<MainMigrationJobOptions> options | ||
) | ||
{ | ||
_contextFactory = contextFactory; | ||
_client = client; | ||
_jobHealthCheck = jobHealthCheck; | ||
_logger = Log.ForContext<_00_UpdateValidatorCommissionRates>(); | ||
_mainMigrationJobOptions = options.Value; | ||
} | ||
|
||
/// <summary> | ||
/// Start import of missing transaction events. | ||
/// </summary> | ||
/// <exception cref="JobException">If the transaction fetched from the node isn't | ||
/// <see cref="TransactionStatusFinalized"/> or the transaction isn't of type <see cref="UpdateDetails"/> | ||
/// </exception> | ||
public async Task StartImport(CancellationToken token) | ||
{ | ||
using var _ = TraceContext.StartActivity(GetUniqueIdentifier()); | ||
using var __ = LogContext.PushProperty("Job", GetUniqueIdentifier()); | ||
|
||
try | ||
{ | ||
await Policies.GetTransientPolicy(GetUniqueIdentifier(), _logger, _mainMigrationJobOptions.RetryCount, _mainMigrationJobOptions.RetryDelay) | ||
.ExecuteAsync(async () => | ||
{ | ||
await using var context = await _contextFactory.CreateDbContextAsync(token); | ||
var connection = context.Database.GetDbConnection(); | ||
|
||
var transactions = await connection.QueryAsync<Transaction>(AffectedTransactionTypesSql); | ||
|
||
foreach (var transaction in transactions) | ||
{ | ||
var count = await context.TransactionResultEvents | ||
.Where(te => te.TransactionId == transaction.Id) | ||
.CountAsync(cancellationToken: token); | ||
// If a transaction event exist the event has already been generated. | ||
if (count > 0) | ||
{ | ||
continue; | ||
} | ||
|
||
var blockItemStatus = await _client.GetBlockItemStatusAsync(TransactionHash.From(transaction.TransactionHash), token); | ||
|
||
var finalized = blockItemStatus.GetFinalizedBlockItemSummary(); | ||
|
||
if (finalized.Details is not UpdateDetails updateDetails) | ||
{ | ||
throw JobException.Create(GetUniqueIdentifier(), | ||
$"Transaction details was of wrong type {finalized.Details.GetType()}"); | ||
} | ||
|
||
var block = await context | ||
.Blocks | ||
.SingleAsync(b => b.Id == transaction.BlockId, cancellationToken: token); | ||
|
||
var chainUpdateEnqueued = ChainUpdateEnqueued.From(updateDetails, block.BlockSlotTime); | ||
|
||
var transactionRelated = new TransactionRelated<TransactionResultEvent>(transaction.Id, 0, chainUpdateEnqueued); | ||
await context.TransactionResultEvents.AddAsync(transactionRelated, token); | ||
await context.SaveChangesAsync(token); | ||
} | ||
}); | ||
} | ||
catch (Exception e) | ||
{ | ||
_jobHealthCheck.AddUnhealthyJobWithMessage(GetUniqueIdentifier(), "Job stopped due to exception."); | ||
_logger.Fatal(e, $"{GetUniqueIdentifier()} stopped due to exception."); | ||
throw; | ||
} | ||
} | ||
|
||
public string GetUniqueIdentifier() => JobName; | ||
|
||
public bool ShouldNodeImportAwait() => false; | ||
} |
7 changes: 7 additions & 0 deletions
7
backend/Application/Exceptions/ConcordiumClientWrapperException.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace Application.Exceptions; | ||
|
||
public sealed class ConcordiumClientWrapperException : Exception | ||
{ | ||
public ConcordiumClientWrapperException(string message) : base(message) | ||
{} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
namespace Application.Exceptions; | ||
|
||
internal sealed class JobException : Exception | ||
{ | ||
private JobException(string message) : base(message) | ||
{} | ||
|
||
internal static JobException Create(string identifier, string message) | ||
{ | ||
return new JobException($"Job {identifier} encountered error: {message}"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
...end/Application/Import/ConcordiumNode/ConcordiumClientWrappers/BlockItemSummaryWrapper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using Application.Exceptions; | ||
using Concordium.Sdk.Types; | ||
|
||
namespace Application.Import.ConcordiumNode.ConcordiumClientWrappers; | ||
|
||
public interface IBlockItemSummaryWrapper | ||
{ | ||
ITransactionStatus GetTransactionStatus(); | ||
BlockItemSummary GetFinalizedBlockItemSummary(); | ||
} | ||
|
||
public class BlockItemSummaryWrapper : IBlockItemSummaryWrapper | ||
{ | ||
private readonly ITransactionStatus _transactionStatus; | ||
|
||
public BlockItemSummaryWrapper(ITransactionStatus transactionStatus) | ||
{ | ||
_transactionStatus = transactionStatus; | ||
} | ||
public ITransactionStatus GetTransactionStatus() => _transactionStatus; | ||
|
||
/// <summary> | ||
/// Get block item summary for finalized transaction. | ||
/// </summary> | ||
/// <exception cref="ConcordiumClientWrapperException">Throws exception if the transaction | ||
/// it not finalized. | ||
/// </exception> | ||
public BlockItemSummary GetFinalizedBlockItemSummary() | ||
{ | ||
if (_transactionStatus is not TransactionStatusFinalized finalized) | ||
{ | ||
throw new ConcordiumClientWrapperException($"Transaction was of wrong type {_transactionStatus.GetType()}"); | ||
} | ||
|
||
return finalized.State.Summary; | ||
} | ||
} |
Oops, something went wrong.