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

Contract Listing View #98

Merged
108 commits merged into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
d5e8afa
Made entities and import flow
Aug 17, 2023
cdf8265
Added test to aggregate which validates events are stored
Aug 18, 2023
bc505e9
Merge branch 'main' into cbw-1248/implementation-smart-contract-aggre…
Aug 18, 2023
fbf296d
Added test for other read cases
Aug 18, 2023
aa922e0
Added smart contract entity
Aug 18, 2023
81b34ab
Added Smart Contract Aggregate to Startup
Aug 18, 2023
58156e1
Added import job
Aug 21, 2023
dcb5256
Finished repository test
Aug 21, 2023
ca0522a
Fixed aggregate test
Aug 21, 2023
b73da60
Added data source
Aug 21, 2023
91b0eaf
Added awaits on jobs on node import
Aug 21, 2023
fc47cb3
Added contract version to contract initialize and update events
Aug 22, 2023
50f6167
Added tests which validates uniqueness contrains
Aug 22, 2023
293329a
Remove todos and added simple resilience in import loop
Aug 22, 2023
1cfb11c
Fixed dependency injection issue
Aug 22, 2023
aa91b17
Fix issues when testing job
Aug 22, 2023
d575289
Small updates
Aug 22, 2023
f63bf17
Updated changelog
Aug 22, 2023
ef4550d
Moved classes to own files
Aug 22, 2023
eae5cb1
Added logic to Smart Contract Repository which can fetch batch
Aug 24, 2023
bb162ca
Made batch import instead of processing single rows
Aug 24, 2023
952e48b
Clean up unused code
Aug 24, 2023
4a40b00
Fix limit on smart contract database job
Aug 24, 2023
e708617
Remove unnecessary batch
Aug 24, 2023
40e474d
Added duration- and height metrics
Aug 24, 2023
d565919
Added health states to application
Aug 25, 2023
b3cc30b
Fixed health output
Aug 25, 2023
5411768
Adding temp CI
Aug 25, 2023
ea18072
Updating change log
Aug 25, 2023
75f2851
Remove some debugging and added nugets
Aug 25, 2023
54ab1c6
Fix test
Aug 25, 2023
b71562d
Merge branch 'main' into cbw-1248/implementation-smart-contract-aggre…
Aug 25, 2023
2c26643
Merge branch 'cbw-1248/implementation-smart-contract-aggregate' into …
Aug 25, 2023
915777e
Refactor
Aug 28, 2023
9857710
Merge branch 'cbw-1248/implementation-smart-contract-aggregate' into …
Aug 28, 2023
ce21ac8
Clean up after merge
Aug 28, 2023
707c401
Added smart contract paging query
Aug 31, 2023
7e5f664
Added metrics to graphql endpoints
Sep 1, 2023
2171a83
Updated changelog
Sep 1, 2023
09d7102
Added contract address to Smart Contract query
Sep 1, 2023
160f17d
Fix increment issue when reading heights
Sep 1, 2023
9edb613
Added simple view which can list smart contracts
Sep 1, 2023
ee4acf7
Updated naming from Smart Contract to Contract
Sep 1, 2023
9ba8c24
Renamed test and tables
Sep 1, 2023
68db31f
Merge branch 'cbw-1248/implementation-smart-contract-aggregate' into …
Sep 1, 2023
bc4440a
Fix naming conflicts
Sep 1, 2023
0faea97
Merge branch 'cbw-1249/add-observability' into cbw-1261/sc-listing-en…
Sep 1, 2023
c595e17
Resolve conflicts after merge
Sep 1, 2023
c823dde
Merge branch 'cbw-1261/sc-listing-endpoints' into cbw-1260/smart-cont…
Sep 1, 2023
e6f4b82
Renamed to Contract
Sep 1, 2023
aa2f083
Updated with add and remove link entities
Sep 1, 2023
f143293
Fixed off by one error
Sep 1, 2023
4ec857d
Merge branch 'cbw-1248/implementation-smart-contract-aggregate' into …
Sep 4, 2023
8c96ed8
Merge branch 'cbw-1249/add-observability' into cbw-1261/sc-listing-en…
Sep 4, 2023
bfd3257
Merge branch 'cbw-1261/sc-listing-endpoints' into cbw-1260/smart-cont…
Sep 4, 2023
f1f8c70
Update Program.cs
Sep 4, 2023
c33b7e6
Merge branch 'cbw-1249/add-observability' into cbw-1261/sc-listing-en…
Sep 4, 2023
8441f6c
Using activity and better exception handling in diagnostic handler
Sep 4, 2023
5197ede
Enable rewind of request body
Sep 4, 2023
ffaa221
Added tracing to logs
Sep 4, 2023
c42ada0
Updated log formats
Sep 4, 2023
0944d3d
remove extra from console
Sep 4, 2023
bff53f4
Corrected naming
Sep 5, 2023
5bf501e
Made repository for contract jobs
Sep 5, 2023
5843bdc
Migrated to options for feature flags
Sep 5, 2023
37b979e
Moved interfaces to same file as classes where only one implementatio…
Sep 5, 2023
e9bc1c1
Changed to date time offset
Sep 5, 2023
152c486
Added warnings not to change job identifier
Sep 5, 2023
3c682d0
Update range function with comments
Sep 5, 2023
6769b70
Follow standards from EF regarding CS8618 compiler warning for C# 10
Sep 5, 2023
3e7126e
Refactored Contract Aggregate Node Import job to be more readable
Sep 5, 2023
8048a49
Merge branch 'cbw-1248/implementation-smart-contract-aggregate' into …
Sep 5, 2023
a30fb7c
Resolve comments after merge
Sep 5, 2023
9f028f2
Merge branch 'main' into cbw-1249/add-observability
Sep 5, 2023
05dfeb9
Resolve issues after merge
Sep 5, 2023
0c43cc3
Merge branch 'cbw-1249/add-observability' into cbw-1261/sc-listing-en…
Sep 5, 2023
77ec045
Resolve issues after merge
Sep 5, 2023
c8020b3
Merge branch 'cbw-1261/sc-listing-endpoints' into cbw-1260/smart-cont…
Sep 5, 2023
e26cb54
Resolve comments
Sep 5, 2023
de8e391
Minor refactoring after final review
Sep 5, 2023
d47a38c
Merge branch 'cbw-1249/add-observability' into cbw-1261/sc-listing-en…
Sep 5, 2023
36467a9
Merge branch 'main' into cbw-1261/sc-listing-endpoints
Sep 5, 2023
f8fa896
Updates after merge
Sep 5, 2023
bfd0d97
Merge branch 'cbw-1261/sc-listing-endpoints' into cbw-1260/smart-cont…
Sep 5, 2023
9be4c15
Change log level to information when contract job has written heights.
Sep 5, 2023
8313365
Fix wrong tracing enrichment
Sep 5, 2023
f332453
Fix compiler warning and sorted contracts when queried for listing
Sep 5, 2023
0b2264f
Fix logging of users cancel queries.
Sep 5, 2023
f483588
Fix exceptions handling in diagnostics
Sep 8, 2023
0b962a5
Fix missing events when money CCD was transferred between account
Sep 8, 2023
282839d
Remove unused exception
Sep 8, 2023
3492061
Added block slot time to all events
Sep 8, 2023
4838845
Updated graphql schema
Sep 8, 2023
bfc7795
Rejected events + Using Parallel in import job + Add Sender
Sep 8, 2023
0302c3c
Added to context, fix migration and fix serializer for reject
Sep 8, 2023
c0c8bb6
Removed wrong event_index from reject tables.
Sep 8, 2023
e9e1f09
Merge branch 'main' into cbw-1261/add-reject-events
Sep 11, 2023
b939614
Remove commented
Sep 11, 2023
4afcdd5
Added documentation to transfer event
Sep 11, 2023
b5928ff
Merge branch 'main' into cbw-1260/smart-contract-listing-view
Sep 11, 2023
842f47d
Merge branch 'cbw-1261/add-reject-events' into cbw-1260/smart-contrac…
Sep 11, 2023
542188d
Added age and module to contract list view
Sep 11, 2023
8755cd1
Validated performance and SQL on split query.
Sep 11, 2023
e9af685
Fix missing new line
Sep 13, 2023
f6c6b17
Change to Try pattern
Sep 13, 2023
fd64758
Fixed comments
Sep 13, 2023
2297fe6
Merge branch 'cbw-1261/add-reject-events' into cbw-1260/smart-contrac…
Sep 14, 2023
146666b
Merge branch 'main' into cbw-1260/smart-contract-listing-view
Sep 14, 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
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,10 @@ public void Configure(EntityTypeBuilder<Entities.Contract> builder)
.HasMany<ContractEvent>(sm => sm.ContractEvents)
.WithOne()
.HasForeignKey(sme => new { sme.ContractAddressIndex, sme.ContractAddressSubIndex });

builder
.HasMany<ModuleReferenceContractLinkEvent>(c => c.ModuleReferenceContractLinkEvents)
.WithOne()
.HasForeignKey(link => new { link.ContractAddressIndex, link.ContractAddressSubIndex });
}
}
33 changes: 31 additions & 2 deletions backend/Application/Aggregates/Contract/Entities/Contract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public sealed class Contract
public ImportSource Source { get; init; }
public DateTimeOffset BlockSlotTime { get; init; }
public DateTimeOffset CreatedAt { get; init; } = DateTime.UtcNow;
public ICollection<ContractEvent> ContractEvents { get; set; }
public ICollection<ContractEvent> ContractEvents { get; set; } = null!;
public ICollection<ModuleReferenceContractLinkEvent> ModuleReferenceContractLinkEvents { get; set; } = null!;

/// <summary>
/// Needed for EF Core
Expand Down Expand Up @@ -58,13 +59,27 @@ internal Contract(
[ExtendObjectType(typeof(Query))]
public class ContractQuery
{
/// <summary>
/// Get contracts with pagination support.
///
/// Currently contracts module reference are not updated for the lifetime of the contract. Hence often there will
/// be only one module link event for each contract.
///
/// Because of this we are currently not using <see cref="Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.AsSplitQuery"/>.
/// If performance issues on this query is seen and module reference links increases then look into using above splitting technique.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-split-queries">EF Core split queries</see> for more information.
/// </remarks>
[UsePaging]
public IQueryable<Contract> GetContracts(
GraphQlDbContext context)
{
return context.Contract
.AsNoTracking()
.Include(s => s.ContractEvents);
.Include(s => s.ContractEvents)
.Include(s => s.ModuleReferenceContractLinkEvents)
.OrderByDescending(c => c.ContractAddressIndex);
}
}

Expand All @@ -77,6 +92,20 @@ public sealed class ContractExtensions
public ContractAddress GetContractAddress([Parent] Contract contract) =>
new(contract.ContractAddressIndex, contract.ContractAddressSubIndex);

/// <summary>
/// Returns the current linked module reference which is the latest added <see cref="ModuleReferenceContractLinkEvent"/>.
/// </summary>
public string GetModuleReference([Parent] Contract contract)
{
var link = contract.ModuleReferenceContractLinkEvents
.Where(link => link.LinkAction == ModuleReferenceContractLinkEvent.ModuleReferenceContractLinkAction.Added)
.OrderByDescending(link => link.BlockHeight)
.ThenByDescending(link => link.TransactionIndex)
.ThenByDescending(link => link.EventIndex)
.First();
return link.ModuleReference;
}

/// <summary>
/// Returns aggregated amount from events on contract.
/// </summary>
Expand Down
6 changes: 3 additions & 3 deletions backend/Application/Common/Logging/TraceEnricher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
}

logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(Id, Activity.Current.Id));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(TraceId, Activity.Current.Id));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(SpanId, Activity.Current.Id));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(TraceId, Activity.Current.TraceId));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(SpanId, Activity.Current.SpanId));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,4 @@ private static bool TryGetQuery(IHasContextData context, out string? query)

return false;
}
}
}
85 changes: 85 additions & 0 deletions backend/Tests/Aggregates/Contract/Entities/ContractTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System.Collections.Generic;
using Application.Aggregates.Contract.Entities;
using Application.Api.GraphQL;
using Application.Api.GraphQL.Transactions;
using FluentAssertions;
using Tests.TestUtilities.Builders;

namespace Tests.Aggregates.Contract.Entities;

public sealed class ContractTests
{
private readonly Application.Aggregates.Contract.Entities.Contract.ContractExtensions _contractExtensions;

public ContractTests()
{
_contractExtensions = new Application.Aggregates.Contract.Entities.Contract.ContractExtensions();
}

[Fact]
public void WhenGetModuleReference_ThenReturnLatestAdded()
{
// Arrange
const string expectedModuleReference = "foobar";
var a = ModuleReferenceContractLinkEventBuilder.Create()
.WithBlockHeight(6)
.WithTransactionIndex(5)
.WithEventIndex(4)
.WithModuleReference(expectedModuleReference)
.WithLinkAction(ModuleReferenceContractLinkEvent.ModuleReferenceContractLinkAction.Added)
.Build();
var b = ModuleReferenceContractLinkEventBuilder.Create()
.WithBlockHeight(7)
.WithTransactionIndex(5)
.WithEventIndex(4)
.WithLinkAction(ModuleReferenceContractLinkEvent.ModuleReferenceContractLinkAction.Removed)
.Build();
var c = ModuleReferenceContractLinkEventBuilder.Create()
.WithBlockHeight(6)
.WithTransactionIndex(4)
.WithLinkAction(ModuleReferenceContractLinkEvent.ModuleReferenceContractLinkAction.Added)
.Build();
var d = ModuleReferenceContractLinkEventBuilder.Create()
.WithBlockHeight(5)
.WithLinkAction(ModuleReferenceContractLinkEvent.ModuleReferenceContractLinkAction.Added)
.Build();
var contract = ContractBuilder
.Create()
.WithModuleReferenceContractLinkEvents(new List<ModuleReferenceContractLinkEvent>
{
a, b, c, d
})
.Build();

// Act
var moduleReference = _contractExtensions.GetModuleReference(contract);

// Assert
moduleReference.Should().Be(expectedModuleReference);
}

[Fact]
public void WhenGetAmount_ThenReturnCorrectAmount()
{
// Arrange
var from = new ContractAddress(1, 1);
var to = new ContractAddress(2, 1);
var contractEvents = new List<ContractEvent>{
ContractEventBuilder.Create().WithEvent(new Transferred(42, from, to)).Build(),
ContractEventBuilder.Create().WithEvent(new Transferred(2, to, from)).Build(),
ContractEventBuilder.Create().WithEvent(new ContractInitialized("", new ContractAddress(1,0), 10, "", ContractVersion.V0, Array.Empty<string>())).Build(),
ContractEventBuilder.Create().WithEvent(new ContractUpdated(new ContractAddress(1,0), new ContractAddress(1,0), 7, "", "", ContractVersion.V0, Array.Empty<string>())).Build()
};
var contract = ContractBuilder
.Create()
.WithContractAddress(to)
.WithContractEvents(contractEvents)
.Build();

// Act
var amount = _contractExtensions.GetAmount(contract);

// Assert
amount.Should().Be(57);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,9 @@ type Contract {
blockSlotTime: DateTime!
createdAt: DateTime!
contractEvents: [ContractEvent!]!
moduleReferenceContractLinkEvents: [ModuleReferenceContractLinkEvent!]!
contractAddress: ContractAddress!
moduleReference: String!
amount: Float!
}

Expand Down Expand Up @@ -1193,6 +1195,21 @@ type ModuleNotWf {
_: Boolean! @deprecated(reason: "Don't use! This field is only in the schema to make sure reject reasons without any fields are valid types in GraphQL (which does not allow types without any fields)")
}

type ModuleReferenceContractLinkEvent {
blockHeight: UnsignedLong!
transactionHash: String!
transactionIndex: UnsignedLong!
eventIndex: UnsignedInt!
moduleReference: String!
contractAddressIndex: UnsignedLong!
contractAddressSubIndex: UnsignedLong!
sender: AccountAddress!
source: ImportSource!
linkAction: ModuleReferenceContractLinkAction!
blockSlotTime: DateTime!
createdAt: DateTime!
}

type NewEncryptedAmount {
accountAddress: AccountAddress!
newIndex: UnsignedLong!
Expand Down Expand Up @@ -1939,6 +1956,11 @@ enum MetricsPeriod {
LAST_YEAR
}

enum ModuleReferenceContractLinkAction {
ADDED
REMOVED
}

enum NodeSortDirection {
ASC
DSC
Expand Down
65 changes: 65 additions & 0 deletions backend/Tests/TestUtilities/Builders/ContractBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System.Collections.Generic;
using Application.Aggregates.Contract.Entities;
using Application.Aggregates.Contract.Types;
using Application.Api.GraphQL;
using Application.Api.GraphQL.Accounts;

namespace Tests.TestUtilities.Builders;

internal sealed class ContractBuilder
{
private readonly ulong _blockHeight = 1;
private readonly string _transactionHash = "";
private readonly ulong _transactionIndex = 1;
private readonly uint _eventIndex = 1;
private ContractAddress _contractAddress = new(1, 0);
private readonly AccountAddress _accountAddress = new("");
private readonly ImportSource _source = ImportSource.DatabaseImport;
private readonly DateTimeOffset _dateTimeOffset = DateTimeOffset.UtcNow;
private IList<ModuleReferenceContractLinkEvent> _moduleReferenceContractLinkEvents = new List<ModuleReferenceContractLinkEvent>();
private IList<ContractEvent> _contractEvents = new List<ContractEvent>();

private ContractBuilder() {}

internal static ContractBuilder Create()
{
return new ContractBuilder();
}

internal Contract Build()
{
return new Contract(
_blockHeight,
_transactionHash,
_transactionIndex,
_eventIndex,
_contractAddress,
_accountAddress,
_source,
_dateTimeOffset
)
{
ModuleReferenceContractLinkEvents = _moduleReferenceContractLinkEvents,
ContractEvents = _contractEvents
};
}

internal ContractBuilder WithContractEvents(IList<ContractEvent> events)
{
_contractEvents = events;
return this;
}

internal ContractBuilder WithModuleReferenceContractLinkEvents(IList<ModuleReferenceContractLinkEvent> events)
{
_moduleReferenceContractLinkEvents = events;
return this;
}

internal ContractBuilder WithContractAddress(ContractAddress contractAddress)
{
_contractAddress = contractAddress;
return this;
}

}
53 changes: 53 additions & 0 deletions backend/Tests/TestUtilities/Builders/ContractEventBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Application.Aggregates.Contract.Entities;
using Application.Aggregates.Contract.Types;
using Application.Api.GraphQL;
using Application.Api.GraphQL.Accounts;
using Application.Api.GraphQL.Transactions;

namespace Tests.TestUtilities.Builders;

internal sealed class ContractEventBuilder
{
private readonly ulong _blockHeight = 1;
private readonly string _transactionHash = "";
private readonly ulong _transactionIndex = 1;
private readonly uint _eventIndex = 1;
private readonly ContractAddress _contractAddress = new(1, 0);
private readonly AccountAddress _accountAddress = new("");
private TransactionResultEvent _event =
new Transferred(1, new ContractAddress(1, 0), new ContractAddress(2, 0));

private readonly ImportSource _source = ImportSource.DatabaseImport;
private readonly DateTimeOffset _dateTimeOffset = DateTimeOffset.UtcNow;

private ContractEventBuilder()
{
}

internal static ContractEventBuilder Create()
{
return new ContractEventBuilder();
}

internal ContractEvent Build()
{
return new ContractEvent(
_blockHeight,
_transactionHash,
_transactionIndex,
_eventIndex,
_contractAddress,
_accountAddress,
_event,
_source,
_dateTimeOffset
);
}

internal ContractEventBuilder WithEvent(TransactionResultEvent @event)
{
_event = @event;
return this;
}

}
Loading
Loading