diff --git a/CHANGELOG.md b/CHANGELOG.md index 149d3a2c3..be52176c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ Release built: _not released yet_ > [!CAUTION] > **Breaking Changes:** +> - Manifest addresses are no longer indexed in the `/stream/transactions` endpoint for failed transactions. Affected filters: +> - `manifest_accounts_withdrawn_from_filter` +> - `manifest_accounts_deposited_into_filter` +> - `manifest_badges_presented_filter` +> - `manifest_resources_filter` +> - `accounts_with_manifest_owner_method_calls` +> - `accounts_without_manifest_owner_method_calls` > - Changed ordering of entity metadata. Entries are no longer ordered by their last modification state version but rather by their first appearance on the network, descending. Affected endpoints: > - `/state/entity/metadata` > - `/state/entity/page/metadata` diff --git a/babylon-gateway.sln.DotSettings b/babylon-gateway.sln.DotSettings index f32a80e43..553c1b634 100644 --- a/babylon-gateway.sln.DotSettings +++ b/babylon-gateway.sln.DotSettings @@ -1,4 +1,5 @@  + True True True True diff --git a/src/RadixDlt.NetworkGateway.Abstractions/EntityAddress.cs b/src/RadixDlt.NetworkGateway.Abstractions/EntityAddress.cs index 8e87f8414..912118087 100644 --- a/src/RadixDlt.NetworkGateway.Abstractions/EntityAddress.cs +++ b/src/RadixDlt.NetworkGateway.Abstractions/EntityAddress.cs @@ -62,6 +62,7 @@ * permissions under this License. */ +using RadixDlt.NetworkGateway.Abstractions.Network; using System.Diagnostics; namespace RadixDlt.NetworkGateway.Abstractions; @@ -82,6 +83,8 @@ private EntityAddress(string address) public bool IsAccount => _address.StartsWith("account_"); + public bool IsIdentity => _address.StartsWith("identity_"); + public bool IsResource => _address.StartsWith("resource_"); public static implicit operator string(EntityAddress ra) => ra._address; @@ -92,4 +95,6 @@ public override string ToString() { return _address; } + + public DecodedRadixAddress Decode() => RadixAddressCodec.DecodeEntityAddress(_address); } diff --git a/src/RadixDlt.NetworkGateway.Abstractions/Network/DecodedRadixAddress.cs b/src/RadixDlt.NetworkGateway.Abstractions/Network/DecodedRadixAddress.cs new file mode 100644 index 000000000..e18f4ef6c --- /dev/null +++ b/src/RadixDlt.NetworkGateway.Abstractions/Network/DecodedRadixAddress.cs @@ -0,0 +1,92 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +namespace RadixDlt.NetworkGateway.Abstractions.Network; + +public sealed record DecodedRadixAddress(string Hrp, byte[] Data, Bech32Codec.Variant Variant) +{ + private const byte Secp256kPreAllocatedAccountPrefix = 209; + private const byte Secp256kPreAllocatedIdentityPrefix = 210; + private const byte Ed25519PreAllocatedAccountPrefix = 81; + private const byte Ed25519PreAllocatedIdentityPrefix = 82; + + public bool IsPreAllocated() => IsPreAllocatedAccountAddress() || IsPreAllocatedIdentityAddress(); + + public bool IsSecp256k() => DiscriminatorByte is Secp256kPreAllocatedAccountPrefix or Secp256kPreAllocatedIdentityPrefix; + + public bool IsEd25519() => DiscriminatorByte is Ed25519PreAllocatedAccountPrefix or Ed25519PreAllocatedIdentityPrefix; + + public bool IsPreAllocatedAccountAddress() => DiscriminatorByte is Secp256kPreAllocatedAccountPrefix or Ed25519PreAllocatedAccountPrefix; + + public bool IsPreAllocatedIdentityAddress() => DiscriminatorByte is Secp256kPreAllocatedIdentityPrefix or Ed25519PreAllocatedIdentityPrefix; + + public byte DiscriminatorByte => Data[0]; + + public byte[] AddressBytes => Data[1..]; + + public override string ToString() + { + return RadixAddressCodec.Encode(Hrp, Data); + } +} diff --git a/src/RadixDlt.NetworkGateway.Abstractions/Network/RadixAddressCodec.cs b/src/RadixDlt.NetworkGateway.Abstractions/Network/RadixAddressCodec.cs index fa73d4a6e..d9d22e321 100644 --- a/src/RadixDlt.NetworkGateway.Abstractions/Network/RadixAddressCodec.cs +++ b/src/RadixDlt.NetworkGateway.Abstractions/Network/RadixAddressCodec.cs @@ -62,27 +62,10 @@ * permissions under this License. */ -// ReSharper disable CommentTypo -// ReSharper disable StringLiteralTypo -// ReSharper disable IdentifierTypo -/* The above is a fix for ReShaper not liking the work "Bech" */ - using System; namespace RadixDlt.NetworkGateway.Abstractions.Network; -public sealed record DecodedRadixAddress(string Hrp, byte[] Data, Bech32Codec.Variant Variant) -{ - public byte DiscriminatorByte => Data[0]; - - public byte[] AddressBytes => Data[1..]; - - public override string ToString() - { - return RadixAddressCodec.Encode(Hrp, Data); - } -} - public static class RadixAddressCodec { public static string Encode(string hrp, ReadOnlySpan addressData) @@ -90,6 +73,18 @@ public static string Encode(string hrp, ReadOnlySpan addressData) return Bech32Codec.Encode(hrp, EncodeAddressDataInBase32(addressData), Bech32Codec.Variant.Bech32M); } + public static DecodedRadixAddress DecodeEntityAddress(string encoded) + { + var decoded = Decode(encoded); + + if (decoded.Data.Length != 30) + { + throw new AddressException($"Entity address is expected to be 30 bytes in length. But was {decoded.Data.Length}"); + } + + return decoded; + } + public static DecodedRadixAddress Decode(string encoded) { var (hrp, rawBase32Data, variant) = Bech32Codec.Decode(encoded); @@ -102,7 +97,7 @@ public static DecodedRadixAddress Decode(string encoded) if (variant != Bech32Codec.Variant.Bech32M) { - throw new AddressException("Only Bech32M addresses are supported"); + throw new AddressException($"Only Bech32M addresses are supported, decoded variant: {variant}"); } return new DecodedRadixAddress(hrp, addressData, variant); diff --git a/src/RadixDlt.NetworkGateway.GatewayApi/Validators/RadixAddressValidator.cs b/src/RadixDlt.NetworkGateway.GatewayApi/Validators/RadixAddressValidator.cs index e6a18edf3..87dc32e35 100644 --- a/src/RadixDlt.NetworkGateway.GatewayApi/Validators/RadixAddressValidator.cs +++ b/src/RadixDlt.NetworkGateway.GatewayApi/Validators/RadixAddressValidator.cs @@ -63,6 +63,7 @@ */ using FluentValidation; +using RadixDlt.NetworkGateway.Abstractions; using RadixDlt.NetworkGateway.Abstractions.Network; using System; diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/IoC/GatewayApiBuilderExtensions.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/IoC/GatewayApiBuilderExtensions.cs index 29ca094c3..e5a06eed1 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/IoC/GatewayApiBuilderExtensions.cs +++ b/src/RadixDlt.NetworkGateway.PostgresIntegration/IoC/GatewayApiBuilderExtensions.cs @@ -106,7 +106,7 @@ public static GatewayApiBuilder AddPostgresPersistenceCore(this GatewayApiBuilde .AddScoped() .AddScoped() .AddScoped() - .AddScoped() + .AddScoped() .AddScoped() .AddScoped() .AddSingleton(); diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/LedgerExtension/ManifestAddressesExtractor.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/LedgerExtension/ManifestAddressesExtractor.cs index be2414ad4..3fa1d68dd 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/LedgerExtension/ManifestAddressesExtractor.cs +++ b/src/RadixDlt.NetworkGateway.PostgresIntegration/LedgerExtension/ManifestAddressesExtractor.cs @@ -114,22 +114,36 @@ public static ManifestAddresses ExtractAddresses(ToolkitModel.TransactionManifes var accountsDepositedInto = manifestSummary.accountsDepositedInto.Select(x => (EntityAddress)x.AddressString()).ToList(); var identitiesRequiringAuth = manifestSummary.identitiesRequiringAuth.Select(x => (EntityAddress)x.AddressString()).ToList(); - var packageAddresses = allAddresses.Where(x => x.Key == ToolkitModel.EntityType.GlobalPackage).SelectMany(x => x.Value.Select(y => (EntityAddress)y.AddressString())).ToList(); + var packageAddresses = allAddresses + .Where(x => x.Key == ToolkitModel.EntityType.GlobalPackage) + .SelectMany(x => x.Value.Select(y => (EntityAddress)y.AddressString())) + .ToList(); + var componentAddresses = allAddresses .Where(x => x.Key is ToolkitModel.EntityType.GlobalGenericComponent or ToolkitModel.EntityType.InternalGenericComponent) .SelectMany(x => x.Value.Select(y => (EntityAddress)y.AddressString())) .ToList(); + var resourceAddresses = allAddresses .Where(x => x.Key is ToolkitModel.EntityType.GlobalFungibleResourceManager or ToolkitModel.EntityType.GlobalNonFungibleResourceManager) .SelectMany(x => x.Value.Select(y => (EntityAddress)y.AddressString())) .ToList(); + var accountAddresses = allAddresses - .Where(x => x.Key is ToolkitModel.EntityType.GlobalAccount or ToolkitModel.EntityType.GlobalVirtualEd25519Account - or ToolkitModel.EntityType.GlobalVirtualSecp256k1Account) + .Where( + x => x.Key + is ToolkitModel.EntityType.GlobalAccount + or ToolkitModel.EntityType.GlobalVirtualEd25519Account + or ToolkitModel.EntityType.GlobalVirtualSecp256k1Account) .SelectMany(x => x.Value.Select(y => (EntityAddress)y.AddressString())) .ToList(); + var identityAddresses = allAddresses - .Where(x => x.Key is ToolkitModel.EntityType.GlobalIdentity or ToolkitModel.EntityType.GlobalVirtualEd25519Identity or ToolkitModel.EntityType.GlobalVirtualSecp256k1Identity) + .Where( + x => x.Key + is ToolkitModel.EntityType.GlobalIdentity + or ToolkitModel.EntityType.GlobalVirtualEd25519Identity + or ToolkitModel.EntityType.GlobalVirtualSecp256k1Identity) .SelectMany(x => x.Value.Select(y => (EntityAddress)y.AddressString())) .ToList(); @@ -159,18 +173,18 @@ private static List ExtractProofs(Dictionary _ledgerTransactionMarkersToAdd = new(); private readonly Dictionary _manifestExtractedAddresses = new(); private readonly Dictionary> _manifestClasses = new(); @@ -101,27 +101,30 @@ public void OnTransactionScan(CoreModel.CommittedTransaction transaction, long s using var manifestInstructions = ToolkitModel.Instructions.FromString(coreInstructions, _networkConfiguration.Id); using var toolkitManifest = new ToolkitModel.TransactionManifest(manifestInstructions, coreBlobs.Values.Select(x => x.ConvertFromHex()).ToArray()); - var extractedAddresses = ManifestAddressesExtractor.ExtractAddresses(toolkitManifest, _networkConfiguration.Id); + AnalyzeManifestClasses(toolkitManifest, stateVersion); - foreach (var address in extractedAddresses.All()) + if (transaction.Receipt.Status == CoreModel.TransactionStatus.Succeeded) { - _referencedEntities.MarkSeenAddress(address); - } + var extractedAddresses = ManifestAddressesExtractor.ExtractAddresses(toolkitManifest, _networkConfiguration.Id); - _manifestExtractedAddresses.Add(stateVersion, extractedAddresses); + foreach (var address in extractedAddresses.All()) + { + _referencedEntities.MarkSeenAddress(address); + } - AnalyzeManifestClasses(toolkitManifest, stateVersion); + _manifestExtractedAddresses.Add(stateVersion, extractedAddresses); + } } } public IEnumerable CreateTransactionMarkers() { - foreach (var stateVersion in _manifestExtractedAddresses.Keys) - { - AnalyzeAddresses(stateVersion); - } + var ledgerTransactionMarkersToAdd = new List(); - return _ledgerTransactionMarkersToAdd; + ledgerTransactionMarkersToAdd.AddRange(CreateMarkersForManifestAddresses()); + ledgerTransactionMarkersToAdd.AddRange(CreateMarkersForManifestClasses()); + + return ledgerTransactionMarkersToAdd; } public LedgerTransactionManifestClass[] GetManifestClasses(long stateVersion) @@ -129,107 +132,145 @@ public LedgerTransactionManifestClass[] GetManifestClasses(long stateVersion) return _manifestClasses.TryGetValue(stateVersion, out var mc) ? mc.ToArray() : Array.Empty(); } - public void AnalyzeManifestClasses(ToolkitModel.TransactionManifest toolkitManifest, long stateVersion) + private void AnalyzeManifestClasses(ToolkitModel.TransactionManifest toolkitManifest, long stateVersion) { var manifestSummary = toolkitManifest.Summary(_networkConfiguration.Id); - for (var i = 0; i < manifestSummary.classification.Length; ++i) + foreach (var manifestClass in manifestSummary.classification) { - var manifestClass = manifestSummary.classification[i].ToModel(); + var mapped = manifestClass.ToModel(); _manifestClasses .GetOrAdd(stateVersion, _ => new List()) - .Add(manifestClass); + .Add(mapped); + } + } - _ledgerTransactionMarkersToAdd.Add( - new ManifestClassMarker - { - Id = _context.Sequences.LedgerTransactionMarkerSequence++, - StateVersion = stateVersion, - ManifestClass = manifestClass, - IsMostSpecific = i == 0, - }); + private IEnumerable CreateMarkersForManifestClasses() + { + var ledgerTransactionMarkersToAdd = new List(); + + foreach (var stateVersion in _manifestClasses.Keys) + { + for (int i = 0; i < _manifestClasses[stateVersion].Count; ++i) + { + ledgerTransactionMarkersToAdd.Add( + new ManifestClassMarker + { + Id = _context.Sequences.LedgerTransactionMarkerSequence++, + StateVersion = stateVersion, + ManifestClass = _manifestClasses[stateVersion][i], + IsMostSpecific = i == 0, + }); + } } + + return ledgerTransactionMarkersToAdd; } - private void AnalyzeAddresses(long stateVersion) + private IEnumerable CreateMarkersForManifestAddresses() { - if (_manifestExtractedAddresses.TryGetValue(stateVersion, out var extractedAddresses)) + var ledgerTransactionMarkersToAdd = new List(); + + foreach (var stateVersion in _manifestExtractedAddresses.Keys) { + if (!_manifestExtractedAddresses.TryGetValue(stateVersion, out var extractedAddresses)) + { + return ledgerTransactionMarkersToAdd; + } + foreach (var proofResourceAddress in extractedAddresses.PresentedProofs.Select(x => x.ResourceAddress).ToHashSet()) { - if (_referencedEntities.TryGet(proofResourceAddress, out var re)) + if (!_referencedEntities.TryGet(proofResourceAddress, out var referencedEntity)) { - _ledgerTransactionMarkersToAdd.Add( - new ManifestAddressLedgerTransactionMarker - { - Id = _context.Sequences.LedgerTransactionMarkerSequence++, - StateVersion = stateVersion, - OperationType = LedgerTransactionMarkerOperationType.BadgePresented, - EntityId = re.DatabaseId, - }); + throw new UnreachableException($"Entity: {proofResourceAddress} was not present in referenced entities dictionary."); } + + ledgerTransactionMarkersToAdd.Add( + new ManifestAddressLedgerTransactionMarker + { + Id = _context.Sequences.LedgerTransactionMarkerSequence++, + StateVersion = stateVersion, + OperationType = LedgerTransactionMarkerOperationType.BadgePresented, + EntityId = referencedEntity.DatabaseId, + }); } - foreach (var address in extractedAddresses.ResourceAddresses) + foreach (var resourceAddress in extractedAddresses.ResourceAddresses) { - if (_referencedEntities.TryGet(address, out var re)) + if (!_referencedEntities.TryGet(resourceAddress, out var referencedEntity)) { - _ledgerTransactionMarkersToAdd.Add( - new ManifestAddressLedgerTransactionMarker - { - Id = _context.Sequences.LedgerTransactionMarkerSequence++, - StateVersion = stateVersion, - OperationType = LedgerTransactionMarkerOperationType.ResourceInUse, - EntityId = re.DatabaseId, - }); + throw new UnreachableException($"Entity: {resourceAddress} was not present in referenced entities dictionary."); } + + ledgerTransactionMarkersToAdd.Add( + new ManifestAddressLedgerTransactionMarker + { + Id = _context.Sequences.LedgerTransactionMarkerSequence++, + StateVersion = stateVersion, + OperationType = LedgerTransactionMarkerOperationType.ResourceInUse, + EntityId = referencedEntity.DatabaseId, + }); } - foreach (var address in extractedAddresses.AccountsRequiringAuth) + foreach (var entityAddress in extractedAddresses.AccountsRequiringAuth) { - if (_referencedEntities.TryGet(address, out var re)) + if (_referencedEntities.TryGet(entityAddress, out var referencedEntity)) { - _ledgerTransactionMarkersToAdd.Add( + ledgerTransactionMarkersToAdd.Add( new ManifestAddressLedgerTransactionMarker { Id = _context.Sequences.LedgerTransactionMarkerSequence++, StateVersion = stateVersion, OperationType = LedgerTransactionMarkerOperationType.AccountOwnerMethodCall, - EntityId = re.DatabaseId, + EntityId = referencedEntity.DatabaseId, }); } + else if (!entityAddress.Decode().IsPreAllocatedAccountAddress()) + { + throw new UnreachableException($"Entity: {entityAddress} was not present in referenced entities dictionary."); + } } - foreach (var address in extractedAddresses.AccountsDepositedInto) + foreach (var entityAddress in extractedAddresses.AccountsDepositedInto) { - if (_referencedEntities.TryGet(address, out var re)) + if (_referencedEntities.TryGet(entityAddress, out var referencedEntity)) { - _ledgerTransactionMarkersToAdd.Add( + ledgerTransactionMarkersToAdd.Add( new ManifestAddressLedgerTransactionMarker { Id = _context.Sequences.LedgerTransactionMarkerSequence++, StateVersion = stateVersion, OperationType = LedgerTransactionMarkerOperationType.AccountDepositedInto, - EntityId = re.DatabaseId, + EntityId = referencedEntity.DatabaseId, }); } + else if (!entityAddress.Decode().IsPreAllocatedAccountAddress()) + { + throw new UnreachableException($"Entity: {entityAddress} was not present in referenced entities dictionary."); + } } - foreach (var address in extractedAddresses.AccountsWithdrawnFrom) + foreach (var entityAddress in extractedAddresses.AccountsWithdrawnFrom) { - if (_referencedEntities.TryGet(address, out var re)) + if (_referencedEntities.TryGet(entityAddress, out var referencedEntity)) { - _ledgerTransactionMarkersToAdd.Add( + ledgerTransactionMarkersToAdd.Add( new ManifestAddressLedgerTransactionMarker { Id = _context.Sequences.LedgerTransactionMarkerSequence++, StateVersion = stateVersion, OperationType = LedgerTransactionMarkerOperationType.AccountWithdrawnFrom, - EntityId = re.DatabaseId, + EntityId = referencedEntity.DatabaseId, }); } + else if (!entityAddress.Decode().IsPreAllocatedAccountAddress()) + { + throw new UnreachableException($"Entity: {entityAddress} was not present in referenced entities dictionary."); } } } + + return ledgerTransactionMarkersToAdd; } +} diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/Models/Entity.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/Models/Entity.cs index a1778ec9e..57e1dd052 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/Models/Entity.cs +++ b/src/RadixDlt.NetworkGateway.PostgresIntegration/Models/Entity.cs @@ -251,9 +251,9 @@ internal class GlobalPackageEntity : ComponentEntity // This is transient model, not stored in database // "virtual" should be understood as un-instantiated, pre-allocated entity -internal class VirtualAccountComponentEntity : GlobalAccountEntity +internal class PreAllocatedAccountComponentEntity : GlobalAccountEntity { - public VirtualAccountComponentEntity(EntityAddress address) + public PreAllocatedAccountComponentEntity(EntityAddress address) { Address = address; IsGlobal = true; @@ -262,9 +262,9 @@ public VirtualAccountComponentEntity(EntityAddress address) // This is transient model, not stored in database // "virtual" should be understood as un-instantiated, pre-allocated entity -internal class VirtualIdentityEntity : GlobalIdentityEntity +internal class PreAllocatedIdentityEntity : GlobalIdentityEntity { - public VirtualIdentityEntity(EntityAddress address) + public PreAllocatedIdentityEntity(EntityAddress address) { Address = address; IsGlobal = true; diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/Queries/EntityQuerier.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/Queries/EntityQuerier.cs index 76dbf06ab..44cc48cc6 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/Queries/EntityQuerier.cs +++ b/src/RadixDlt.NetworkGateway.PostgresIntegration/Queries/EntityQuerier.cs @@ -81,7 +81,7 @@ internal interface IEntityQuerier Task GetEntity(EntityAddress address, GatewayApiSdk.Model.LedgerState ledgerState, CancellationToken token) where TEntity : Entity; - Task GetNonVirtualEntity(EntityAddress address, GatewayModel.LedgerState ledgerState, CancellationToken token) + Task GetNonPreAllocatedEntity(EntityAddress address, GatewayModel.LedgerState ledgerState, CancellationToken token) where TEntity : Entity; Task> ResolveEntityIds(List addresses, GatewayModel.LedgerState ledgerState, CancellationToken token); @@ -93,12 +93,12 @@ Task GetNonVirtualEntity(EntityAddress address, GatewayModel.L internal class EntityQuerier : IEntityQuerier { - private readonly IVirtualEntityDataProvider _virtualEntityDataProvider; + private readonly IPreAllocatedEntityDataProvider _preAllocatedEntityDataProvider; private readonly ReadOnlyDbContext _dbContext; - public EntityQuerier(IVirtualEntityDataProvider virtualEntityDataProvider, ReadOnlyDbContext dbContext) + public EntityQuerier(IPreAllocatedEntityDataProvider preAllocatedEntityDataProvider, ReadOnlyDbContext dbContext) { - _virtualEntityDataProvider = virtualEntityDataProvider; + _preAllocatedEntityDataProvider = preAllocatedEntityDataProvider; _dbContext = dbContext; } @@ -113,7 +113,7 @@ public async Task GetEntity(EntityAddress address, GatewayApiS if (entity == null) { - entity = await TryResolveAsVirtualEntity(address); + entity = TryResolveAsPreAllocatedEntity(address); if (entity == null) { @@ -130,7 +130,7 @@ public async Task GetEntity(EntityAddress address, GatewayApiS return typedEntity; } - public async Task GetNonVirtualEntity(EntityAddress address, GatewayModel.LedgerState ledgerState, CancellationToken token) + public async Task GetNonPreAllocatedEntity(EntityAddress address, GatewayModel.LedgerState ledgerState, CancellationToken token) where TEntity : Entity { var entity = await _dbContext @@ -188,27 +188,27 @@ public async Task> GetEntities(List addresses foreach (var address in addresses.Except(entities.Keys)) { - var virtualEntity = await TryResolveAsVirtualEntity(address); + var preAllocatedEntity = TryResolveAsPreAllocatedEntity(address); - if (virtualEntity != null) + if (preAllocatedEntity != null) { - entities.Add(virtualEntity.Address, virtualEntity); + entities.Add(preAllocatedEntity.Address, preAllocatedEntity); } } return entities.Values; } - private async Task TryResolveAsVirtualEntity(EntityAddress address) + private static Entity? TryResolveAsPreAllocatedEntity(EntityAddress address) { - if (await _virtualEntityDataProvider.IsVirtualAccountAddress(address)) + if (address.IsAccount && address.Decode().IsPreAllocatedAccountAddress()) { - return new VirtualAccountComponentEntity(address); + return new PreAllocatedAccountComponentEntity(address); } - if (await _virtualEntityDataProvider.IsVirtualIdentityAddress(address)) + if (address.IsIdentity && address.Decode().IsPreAllocatedIdentityAddress()) { - return new VirtualIdentityEntity(address); + return new PreAllocatedIdentityEntity(address); } return null; diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/AccountDepositSettings/AccountStateQuerier.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/AccountDepositSettings/AccountStateQuerier.cs index e38b5ce74..e622faeda 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/AccountDepositSettings/AccountStateQuerier.cs +++ b/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/AccountDepositSettings/AccountStateQuerier.cs @@ -112,7 +112,7 @@ public AccountStateQuerier(IDapperWrapper dapperWrapper, ReadOnlyDbContext dbCon int limit, CancellationToken token = default) { - var accountEntity = await _entityQuerier.GetNonVirtualEntity(accountAddress, ledgerState, token); + var accountEntity = await _entityQuerier.GetNonPreAllocatedEntity(accountAddress, ledgerState, token); var parameters = new { @@ -173,7 +173,7 @@ INNER JOIN LATERAL UNNEST(resource_preference_rules_slice) WITH ORDINALITY AS re int limit, CancellationToken token = default) { - var accountEntity = await _entityQuerier.GetNonVirtualEntity(accountAddress, ledgerState, token); + var accountEntity = await _entityQuerier.GetNonPreAllocatedEntity(accountAddress, ledgerState, token); var parameters = new { diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/AccountDepositSettings/DepositPreValidationQuerier.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/AccountDepositSettings/DepositPreValidationQuerier.cs index 27078e729..c284ac049 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/AccountDepositSettings/DepositPreValidationQuerier.cs +++ b/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/AccountDepositSettings/DepositPreValidationQuerier.cs @@ -111,7 +111,7 @@ public DepositPreValidationQuerier( { var xrdResourceAddress = (await _networkConfigurationProvider.GetNetworkConfiguration(token)).WellKnownAddresses.Xrd; var accountEntity = await _entityQuerier.GetEntity(accountAddress, ledgerState, token); - if (accountEntity is VirtualAccountComponentEntity) + if (accountEntity is PreAllocatedAccountComponentEntity) { var resourceItems = resourceAddresses .Select( diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/EntityStateQuerier.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/EntityStateQuerier.cs index 92764d7cc..2b5896905 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/EntityStateQuerier.cs +++ b/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/EntityStateQuerier.cs @@ -99,7 +99,7 @@ private class SchemaEntryViewModel : SchemaEntryDefinition private readonly INetworkConfigurationProvider _networkConfigurationProvider; private readonly IOptionsSnapshot _endpointConfiguration; private readonly ReadOnlyDbContext _dbContext; - private readonly IVirtualEntityDataProvider _virtualEntityDataProvider; + private readonly IPreAllocatedEntityDataProvider _preAllocatedEntityDataProvider; private readonly IRoleAssignmentQuerier _roleAssignmentQuerier; private readonly IDapperWrapper _dapperWrapper; private readonly IEntityQuerier _entityQuerier; @@ -108,7 +108,7 @@ public EntityStateQuerier( INetworkConfigurationProvider networkConfigurationProvider, ReadOnlyDbContext dbContext, IOptionsSnapshot endpointConfiguration, - IVirtualEntityDataProvider virtualEntityDataProvider, + IPreAllocatedEntityDataProvider preAllocatedEntityDataProvider, IRoleAssignmentQuerier roleAssignmentQuerier, IDapperWrapper dapperWrapper, IEntityQuerier entityQuerier) @@ -116,7 +116,7 @@ public EntityStateQuerier( _networkConfigurationProvider = networkConfigurationProvider; _dbContext = dbContext; _endpointConfiguration = endpointConfiguration; - _virtualEntityDataProvider = virtualEntityDataProvider; + _preAllocatedEntityDataProvider = preAllocatedEntityDataProvider; _roleAssignmentQuerier = roleAssignmentQuerier; _dapperWrapper = dapperWrapper; _entityQuerier = entityQuerier; @@ -343,12 +343,12 @@ public EntityStateQuerier( twoWayLinkedDappAddress: twoWayLinks?.OfType().FirstOrDefault()?.EntityAddress); break; - case VirtualIdentityEntity: - case VirtualAccountComponentEntity: - var virtualEntityData = await _virtualEntityDataProvider.GetVirtualEntityData(entity.Address); + case PreAllocatedIdentityEntity: + case PreAllocatedAccountComponentEntity: + var preAllocatedEntityData = await _preAllocatedEntityDataProvider.GetPreAllocatedEntityData(entity.Address); - details = virtualEntityData.Details; - metadata[entity.Id] = virtualEntityData.Metadata; + details = preAllocatedEntityData.Details; + metadata[entity.Id] = preAllocatedEntityData.Metadata; break; case InternalFungibleVaultEntity ifve: @@ -629,10 +629,10 @@ public EntityStateQuerier( var entity = await _entityQuerier.GetEntity(request.Address, ledgerState, token); GatewayModel.EntityMetadataCollection metadata; - if (entity is VirtualIdentityEntity or VirtualAccountComponentEntity) + if (entity is PreAllocatedIdentityEntity or PreAllocatedAccountComponentEntity) { - var (_, virtualEntityMetadata) = await _virtualEntityDataProvider.GetVirtualEntityData(entity.Address); - metadata = virtualEntityMetadata; + var (_, preAllocatedEntityMetadata) = await _preAllocatedEntityDataProvider.GetPreAllocatedEntityData(entity.Address); + metadata = preAllocatedEntityMetadata; } else { diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/KeyValueStoreQuerier.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/KeyValueStoreQuerier.cs index 2d29f672f..d57ca12c9 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/KeyValueStoreQuerier.cs +++ b/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/KeyValueStoreQuerier.cs @@ -106,7 +106,7 @@ public KeyValueStoreQuerier( CancellationToken token = default) { var networkId = (await _networkConfigurationProvider.GetNetworkConfiguration(token)).Id; - var keyValueStore = await _entityQuerier.GetNonVirtualEntity(keyValueStoreAddress, ledgerState, token); + var keyValueStore = await _entityQuerier.GetNonPreAllocatedEntity(keyValueStoreAddress, ledgerState, token); var keyValueStoreSchema = await KeyValueStoreQueries.KeyValueStoreSchemaLookupQuery( _dbContext, @@ -138,7 +138,7 @@ public KeyValueStoreQuerier( CancellationToken token = default) { var networkId = (await _networkConfigurationProvider.GetNetworkConfiguration(token)).Id; - var keyValueStore = await _entityQuerier.GetNonVirtualEntity(keyValueStoreAddress, ledgerState, token); + var keyValueStore = await _entityQuerier.GetNonPreAllocatedEntity(keyValueStoreAddress, ledgerState, token); var keyValueStoreSchema = await KeyValueStoreQueries.KeyValueStoreSchemaLookupQuery( _dbContext, diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/VirtualEntityDataProvider.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/PreAllocatedEntityDataProvider.cs similarity index 69% rename from src/RadixDlt.NetworkGateway.PostgresIntegration/Services/VirtualEntityDataProvider.cs rename to src/RadixDlt.NetworkGateway.PostgresIntegration/Services/PreAllocatedEntityDataProvider.cs index 4ef1b69e0..becae3acb 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/VirtualEntityDataProvider.cs +++ b/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/PreAllocatedEntityDataProvider.cs @@ -62,7 +62,6 @@ * permissions under this License. */ -using Nito.AsyncEx; using RadixDlt.NetworkGateway.Abstractions; using RadixDlt.NetworkGateway.Abstractions.Extensions; using RadixDlt.NetworkGateway.Abstractions.Network; @@ -77,74 +76,40 @@ namespace RadixDlt.NetworkGateway.PostgresIntegration.Services; -internal interface IVirtualEntityDataProvider +internal interface IPreAllocatedEntityDataProvider { - public Task IsVirtualAccountAddress(EntityAddress address); - - public Task IsVirtualIdentityAddress(EntityAddress address); - - Task<(GatewayModel.StateEntityDetailsResponseComponentDetails Details, GatewayModel.EntityMetadataCollection Metadata)> GetVirtualEntityData(EntityAddress address); + Task<(GatewayModel.StateEntityDetailsResponseComponentDetails Details, GatewayModel.EntityMetadataCollection Metadata)> GetPreAllocatedEntityData(EntityAddress address); } -internal class VirtualEntityDataProvider : IVirtualEntityDataProvider +internal class PreAllocatedEntityDataProvider : IPreAllocatedEntityDataProvider { private readonly INetworkConfigurationProvider _networkConfigurationProvider; - private readonly AsyncLazy _secp256k1VirtualAccountDiscriminator; - private readonly AsyncLazy _ed25519VirtualAccountDiscriminator; - private readonly AsyncLazy _secp256k1VirtualIdentityDiscriminator; - private readonly AsyncLazy _ed25519VirtualIdentityDiscriminator; - private readonly List _virtualAccountRoleAssignmentEntries; - private readonly List _virtualIdentityRoleAssignmentEntries; + private readonly List _preAllocatedAccountRoleAssignmentEntries; + private readonly List _preAllocatedIdentityRoleAssignmentEntries; - public VirtualEntityDataProvider(INetworkConfigurationProvider networkConfigurationProvider, IRoleAssignmentsKeyProvider roleAssignmentsKeyProvider) + public PreAllocatedEntityDataProvider(INetworkConfigurationProvider networkConfigurationProvider, IRoleAssignmentsKeyProvider roleAssignmentsKeyProvider) { - async Task GetAddressBytePrefix(AddressEntityType addressEntityType) - { - var networkConfiguration = await networkConfigurationProvider.GetNetworkConfiguration(); - - return networkConfiguration.AddressTypeDefinitions.First(atd => atd.EntityType == addressEntityType).AddressBytePrefix; - } - - AsyncLazy CreateAsyncLazy(AddressEntityType addressEntityType) - { - return new AsyncLazy(async () => await GetAddressBytePrefix(addressEntityType), AsyncLazyFlags.RetryOnFailure); - } - _networkConfigurationProvider = networkConfigurationProvider; - _secp256k1VirtualAccountDiscriminator = CreateAsyncLazy(AddressEntityType.GlobalVirtualSecp256k1Account); - _ed25519VirtualAccountDiscriminator = CreateAsyncLazy(AddressEntityType.GlobalVirtualEd25519Account); - _secp256k1VirtualIdentityDiscriminator = CreateAsyncLazy(AddressEntityType.GlobalVirtualSecp256k1Identity); - _ed25519VirtualIdentityDiscriminator = CreateAsyncLazy(AddressEntityType.GlobalVirtualEd25519Identity); - _virtualAccountRoleAssignmentEntries = GenerateVirtualAccountRoleAssignmentEntries(roleAssignmentsKeyProvider); - _virtualIdentityRoleAssignmentEntries = GenerateVirtualIdentityRoleAssignmentEntries(roleAssignmentsKeyProvider); + _preAllocatedAccountRoleAssignmentEntries = GeneratePreAllocatedAccountRoleAssignmentEntries(roleAssignmentsKeyProvider); + _preAllocatedIdentityRoleAssignmentEntries = GeneratePreAllocatedIdentityRoleAssignmentEntries(roleAssignmentsKeyProvider); } - public Task IsVirtualAccountAddress(EntityAddress address) + public async Task<(GatewayModel.StateEntityDetailsResponseComponentDetails Details, GatewayModel.EntityMetadataCollection Metadata)> GetPreAllocatedEntityData(EntityAddress address) { - return IsAccount(DecodeAddress(address, false)); - } - - public Task IsVirtualIdentityAddress(EntityAddress address) - { - return IsIdentity(DecodeAddress(address, false)); - } - - public async Task<(GatewayModel.StateEntityDetailsResponseComponentDetails Details, GatewayModel.EntityMetadataCollection Metadata)> GetVirtualEntityData(EntityAddress address) - { - var decoded = DecodeAddress(address, true); + var decoded = address.Decode(); var networkConfiguration = await _networkConfigurationProvider.GetNetworkConfiguration(); - if (await IsSecp256k1(decoded) == false && await IsEd25519(decoded) == false) + if (!decoded.IsSecp256k() && !decoded.IsEd25519()) { throw new ArgumentException("Failed to detect key algorithm (ed25519 or secp256k1)", nameof(address)); } - if (await IsAccount(decoded) == false && await IsIdentity(decoded) == false) + if (!decoded.IsPreAllocatedAccountAddress() && !decoded.IsPreAllocatedIdentityAddress()) { throw new ArgumentException("Failed to detect entity type (account or identity)", nameof(address)); } - ToolkitModel.PublicKeyHash publicKeyHash = await IsSecp256k1(decoded) + ToolkitModel.PublicKeyHash publicKeyHash = decoded.IsSecp256k() ? new ToolkitModel.PublicKeyHash.Secp256k1(decoded.AddressBytes) : new ToolkitModel.PublicKeyHash.Ed25519(decoded.AddressBytes); @@ -163,7 +128,7 @@ public Task IsVirtualIdentityAddress(EntityAddress address) simpleRep: ToolkitModel.RadixEngineToolkitUniffiMethods.NonFungibleLocalIdAsStr(new ToolkitModel.NonFungibleLocalId.Bytes(decoded.AddressBytes)), idType: CoreModel.NonFungibleIdType.Bytes, sborHex: ToolkitModel.RadixEngineToolkitUniffiMethods.NonFungibleLocalIdSborEncode(new ToolkitModel.NonFungibleLocalId.Bytes(decoded.AddressBytes)).ToArray().ToHex()); - var roleAssignmentOwnerProofGlobalId = await IsSecp256k1(decoded) + var roleAssignmentOwnerProofGlobalId = decoded.IsSecp256k() ? new CoreModel.NonFungibleGlobalId(networkConfiguration.WellKnownAddresses.Secp256k1SignatureVirtualBadge, roleAssignmentOwnerProofLocalId) : new CoreModel.NonFungibleGlobalId(networkConfiguration.WellKnownAddresses.Ed25519SignatureVirtualBadge, roleAssignmentOwnerProofLocalId); var ownerRule = new CoreModel.ProtectedAccessRule(new CoreModel.ProofAccessRuleNode(new CoreModel.RequireProofRule(new CoreModel.NonFungibleRequirement(roleAssignmentOwnerProofGlobalId)))); @@ -177,20 +142,20 @@ public Task IsVirtualIdentityAddress(EntityAddress address) new List { new("_self_", GatewayModel.ObjectModuleId.Main) }), }; - var details = await IsAccount(decoded) + var details = decoded.IsPreAllocatedAccountAddress() ? new GatewayModel.StateEntityDetailsResponseComponentDetails( packageAddress: networkConfiguration.WellKnownAddresses.AccountPackage, blueprintName: "Account", blueprintVersion: "1.0.0", state: new CoreModel.AccountFieldStateValue(CoreModel.DefaultDepositRule.Accept), - roleAssignments: new GatewayModel.ComponentEntityRoleAssignments(roleAssignmentOwner, securifyRule.Concat(_virtualAccountRoleAssignmentEntries).ToList()), + roleAssignments: new GatewayModel.ComponentEntityRoleAssignments(roleAssignmentOwner, securifyRule.Concat(_preAllocatedAccountRoleAssignmentEntries).ToList()), royaltyVaultBalance: null) : new GatewayModel.StateEntityDetailsResponseComponentDetails( packageAddress: networkConfiguration.WellKnownAddresses.IdentityPackage, blueprintName: "Identity", blueprintVersion: "1.0.0", state: null, - roleAssignments: new GatewayModel.ComponentEntityRoleAssignments(roleAssignmentOwner, securifyRule.Concat(_virtualIdentityRoleAssignmentEntries).ToList()), + roleAssignments: new GatewayModel.ComponentEntityRoleAssignments(roleAssignmentOwner, securifyRule.Concat(_preAllocatedIdentityRoleAssignmentEntries).ToList()), royaltyVaultBalance: null); var ownerKeys = new GatewayModel.EntityMetadataItemValue(ownerKeysRawHex, ownerKeysProgrammaticJson, ScryptoSborUtils.ConvertToolkitMetadataToGateway(ownedKeysItem)); @@ -211,39 +176,7 @@ public Task IsVirtualIdentityAddress(EntityAddress address) return (details, metadata); } - private DecodedRadixAddress DecodeAddress(EntityAddress address, bool strict) - { - var decodedAddress = RadixAddressCodec.Decode(address); - - if (strict && decodedAddress.Data.Length != 30) - { - throw new ArgumentException("Expected address to be 30 bytes in length.", nameof(address)); - } - - return decodedAddress; - } - - private async Task IsAccount(DecodedRadixAddress decoded) - { - return decoded.DiscriminatorByte == await _secp256k1VirtualAccountDiscriminator.Task || decoded.DiscriminatorByte == await _ed25519VirtualAccountDiscriminator.Task; - } - - private async Task IsIdentity(DecodedRadixAddress decoded) - { - return decoded.DiscriminatorByte == await _secp256k1VirtualIdentityDiscriminator.Task || decoded.DiscriminatorByte == await _ed25519VirtualIdentityDiscriminator.Task; - } - - private async Task IsSecp256k1(DecodedRadixAddress decoded) - { - return decoded.DiscriminatorByte == await _secp256k1VirtualAccountDiscriminator.Task || decoded.DiscriminatorByte == await _secp256k1VirtualIdentityDiscriminator.Task; - } - - private async Task IsEd25519(DecodedRadixAddress decoded) - { - return decoded.DiscriminatorByte == await _ed25519VirtualAccountDiscriminator.Task || decoded.DiscriminatorByte == await _ed25519VirtualIdentityDiscriminator.Task; - } - - private List GenerateVirtualAccountRoleAssignmentEntries(IRoleAssignmentsKeyProvider roleAssignmentsKeyProvider) + private List GeneratePreAllocatedAccountRoleAssignmentEntries(IRoleAssignmentsKeyProvider roleAssignmentsKeyProvider) { return roleAssignmentsKeyProvider .MetadataModulesKeys @@ -255,7 +188,7 @@ private async Task IsEd25519(DecodedRadixAddress decoded) .ToList(); } - private List GenerateVirtualIdentityRoleAssignmentEntries(IRoleAssignmentsKeyProvider roleAssignmentsKeyProvider) + private List GeneratePreAllocatedIdentityRoleAssignmentEntries(IRoleAssignmentsKeyProvider roleAssignmentsKeyProvider) { return roleAssignmentsKeyProvider .AllNativeModulesKeys