diff --git a/src/RadixDlt.NetworkGateway.Abstractions/EntityAddress.cs b/src/RadixDlt.NetworkGateway.Abstractions/EntityAddress.cs index 8e87f8414..24fe5985d 100644 --- a/src/RadixDlt.NetworkGateway.Abstractions/EntityAddress.cs +++ b/src/RadixDlt.NetworkGateway.Abstractions/EntityAddress.cs @@ -82,6 +82,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; diff --git a/src/RadixDlt.NetworkGateway.Abstractions/Network/RadixAddressCodec.cs b/src/RadixDlt.NetworkGateway.Abstractions/Network/RadixAddressCodec.cs index fa73d4a6e..8a684a546 100644 --- a/src/RadixDlt.NetworkGateway.Abstractions/Network/RadixAddressCodec.cs +++ b/src/RadixDlt.NetworkGateway.Abstractions/Network/RadixAddressCodec.cs @@ -73,6 +73,21 @@ 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..]; @@ -90,7 +105,7 @@ public static string Encode(string hrp, ReadOnlySpan addressData) return Bech32Codec.Encode(hrp, EncodeAddressDataInBase32(addressData), Bech32Codec.Variant.Bech32M); } - public static DecodedRadixAddress Decode(string encoded) + public static DecodedRadixAddress Decode(string encoded, bool strict = false) { var (hrp, rawBase32Data, variant) = Bech32Codec.Decode(encoded); var addressData = DecodeBase32IntoAddressData(rawBase32Data); @@ -102,7 +117,12 @@ 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}"); + } + + if (strict && addressData.Length != 30) + { + throw new AddressException($"Expected address to be 30 bytes in length. But was {addressData.Length}"); } return new DecodedRadixAddress(hrp, addressData, variant); diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/LedgerExtension/ManifestAddressesExtractor.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/LedgerExtension/ManifestAddressesExtractor.cs index 0aa6bd80f..3fa1d68dd 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/LedgerExtension/ManifestAddressesExtractor.cs +++ b/src/RadixDlt.NetworkGateway.PostgresIntegration/LedgerExtension/ManifestAddressesExtractor.cs @@ -74,30 +74,28 @@ internal static class ManifestAddressesExtractor { internal record PresentedProof(EntityAddress AccountAddress, EntityAddress ResourceAddress); - internal record AddressWithEntityType(ToolkitModel.EntityType EntityType, EntityAddress Address); - internal record ManifestAddresses( List PackageAddresses, List ComponentAddresses, List ResourceAddresses, - List AccountAddresses, - List AccountsRequiringAuth, - List AccountsWithdrawnFrom, - List AccountsDepositedInto, - List IdentityAddresses, - List IdentitiesRequiringAuth, + List AccountAddresses, + List AccountsRequiringAuth, + List AccountsWithdrawnFrom, + List AccountsDepositedInto, + List IdentityAddresses, + List IdentitiesRequiringAuth, List PresentedProofs) { public List All() => PackageAddresses .Concat(ComponentAddresses) .Concat(ResourceAddresses) - .Concat(AccountAddresses.Select(x => x.Address)) - .Concat(AccountsRequiringAuth.Select(x => x.Address)) - .Concat(AccountsWithdrawnFrom.Select(x => x.Address)) - .Concat(AccountsDepositedInto.Select(x => x.Address)) - .Concat(IdentityAddresses.Select(x => x.Address)) - .Concat(IdentitiesRequiringAuth.Select(x => x.Address)) + .Concat(AccountAddresses) + .Concat(AccountsRequiringAuth) + .Concat(AccountsWithdrawnFrom) + .Concat(AccountsDepositedInto) + .Concat(IdentityAddresses) + .Concat(IdentitiesRequiringAuth) .Concat(PresentedProofs.Select(x => x.AccountAddress)) .Concat(PresentedProofs.Select(x => x.ResourceAddress)) .Distinct() @@ -111,10 +109,10 @@ public static ManifestAddresses ExtractAddresses(ToolkitModel.TransactionManifes var manifestSummary = manifest.Summary(networkId); var presentedProofs = ExtractProofs(manifestSummary.presentedProofs); - var accountsRequiringAuth = manifestSummary.accountsRequiringAuth.Select(x => new AddressWithEntityType(x.EntityType(), (EntityAddress)x.AddressString())).ToList(); - var accountsWithdrawnFrom = manifestSummary.accountsWithdrawnFrom.Select(x => new AddressWithEntityType(x.EntityType(), (EntityAddress)x.AddressString())).ToList(); - var accountsDepositedInto = manifestSummary.accountsDepositedInto.Select(x => new AddressWithEntityType(x.EntityType(), (EntityAddress)x.AddressString())).ToList(); - var identitiesRequiringAuth = manifestSummary.identitiesRequiringAuth.Select(x => new AddressWithEntityType(x.EntityType(), (EntityAddress)x.AddressString())).ToList(); + var accountsRequiringAuth = manifestSummary.accountsRequiringAuth.Select(x => (EntityAddress)x.AddressString()).ToList(); + var accountsWithdrawnFrom = manifestSummary.accountsWithdrawnFrom.Select(x => (EntityAddress)x.AddressString()).ToList(); + 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) @@ -137,7 +135,7 @@ public static ManifestAddresses ExtractAddresses(ToolkitModel.TransactionManifes is ToolkitModel.EntityType.GlobalAccount or ToolkitModel.EntityType.GlobalVirtualEd25519Account or ToolkitModel.EntityType.GlobalVirtualSecp256k1Account) - .SelectMany(x => x.Value.Select(y => new AddressWithEntityType(y.EntityType(), (EntityAddress)y.AddressString()))) + .SelectMany(x => x.Value.Select(y => (EntityAddress)y.AddressString())) .ToList(); var identityAddresses = allAddresses @@ -146,7 +144,7 @@ or ToolkitModel.EntityType.GlobalVirtualEd25519Account is ToolkitModel.EntityType.GlobalIdentity or ToolkitModel.EntityType.GlobalVirtualEd25519Identity or ToolkitModel.EntityType.GlobalVirtualSecp256k1Identity) - .SelectMany(x => x.Value.Select(y => new AddressWithEntityType(y.EntityType(), (EntityAddress)y.AddressString()))) + .SelectMany(x => x.Value.Select(y => (EntityAddress)y.AddressString())) .ToList(); return new ManifestAddresses( diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/LedgerExtension/Processors/LedgerTransactionMarkers/ManifestProcessor.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/LedgerExtension/Processors/LedgerTransactionMarkers/ManifestProcessor.cs index 94682afe1..9e9184d3a 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/LedgerExtension/Processors/LedgerTransactionMarkers/ManifestProcessor.cs +++ b/src/RadixDlt.NetworkGateway.PostgresIntegration/LedgerExtension/Processors/LedgerTransactionMarkers/ManifestProcessor.cs @@ -213,9 +213,9 @@ private IEnumerable CreateMarkersForManifestAddresses() }); } - foreach (var addressWithEntityType in extractedAddresses.AccountsRequiringAuth) + foreach (var entityAddress in extractedAddresses.AccountsRequiringAuth) { - if (_referencedEntities.TryGet(addressWithEntityType.Address, out var referencedEntity)) + if (_referencedEntities.TryGet(entityAddress, out var referencedEntity)) { ledgerTransactionMarkersToAdd.Add( new ManifestAddressLedgerTransactionMarker @@ -226,15 +226,15 @@ private IEnumerable CreateMarkersForManifestAddresses() EntityId = referencedEntity.DatabaseId, }); } - else if (addressWithEntityType.EntityType is not (ToolkitModel.EntityType.GlobalVirtualEd25519Account or ToolkitModel.EntityType.GlobalVirtualSecp256k1Account)) + else if (!RadixAddressCodec.Decode(entityAddress).IsPreAllocatedAccountAddress()) { - throw new UnreachableException($"Entity: {addressWithEntityType.Address} was not present in referenced entities dictionary."); + throw new UnreachableException($"Entity: {entityAddress} was not present in referenced entities dictionary."); } } - foreach (var addressWithEntityType in extractedAddresses.AccountsDepositedInto) + foreach (var entityAddress in extractedAddresses.AccountsDepositedInto) { - if (_referencedEntities.TryGet(addressWithEntityType.Address, out var referencedEntity)) + if (_referencedEntities.TryGet(entityAddress, out var referencedEntity)) { ledgerTransactionMarkersToAdd.Add( new ManifestAddressLedgerTransactionMarker @@ -245,15 +245,15 @@ private IEnumerable CreateMarkersForManifestAddresses() EntityId = referencedEntity.DatabaseId, }); } - else if (addressWithEntityType.EntityType is not (ToolkitModel.EntityType.GlobalVirtualEd25519Account or ToolkitModel.EntityType.GlobalVirtualSecp256k1Account)) + else if (!RadixAddressCodec.Decode(entityAddress).IsPreAllocatedAccountAddress()) { - throw new UnreachableException($"Entity: {addressWithEntityType.Address} was not present in referenced entities dictionary."); + throw new UnreachableException($"Entity: {entityAddress} was not present in referenced entities dictionary."); } } - foreach (var addressWithEntityType in extractedAddresses.AccountsWithdrawnFrom) + foreach (var entityAddress in extractedAddresses.AccountsWithdrawnFrom) { - if (_referencedEntities.TryGet(addressWithEntityType.Address, out var referencedEntity)) + if (_referencedEntities.TryGet(entityAddress, out var referencedEntity)) { ledgerTransactionMarkersToAdd.Add( new ManifestAddressLedgerTransactionMarker @@ -264,9 +264,9 @@ private IEnumerable CreateMarkersForManifestAddresses() EntityId = referencedEntity.DatabaseId, }); } - else if (addressWithEntityType.EntityType is not (ToolkitModel.EntityType.GlobalVirtualEd25519Account or ToolkitModel.EntityType.GlobalVirtualSecp256k1Account)) + else if (!RadixAddressCodec.Decode(entityAddress).IsPreAllocatedAccountAddress()) { - throw new UnreachableException($"Entity: {addressWithEntityType.Address} was not present in referenced entities dictionary."); + throw new UnreachableException($"Entity: {entityAddress} was not present in referenced entities dictionary."); } } } diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/Queries/EntityQuerier.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/Queries/EntityQuerier.cs index ff55038ac..e14748dc5 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/Queries/EntityQuerier.cs +++ b/src/RadixDlt.NetworkGateway.PostgresIntegration/Queries/EntityQuerier.cs @@ -64,6 +64,7 @@ using Microsoft.EntityFrameworkCore; using RadixDlt.NetworkGateway.Abstractions; +using RadixDlt.NetworkGateway.Abstractions.Network; using RadixDlt.NetworkGateway.GatewayApi.Exceptions; using RadixDlt.NetworkGateway.PostgresIntegration.Models; using RadixDlt.NetworkGateway.PostgresIntegration.Services; @@ -113,7 +114,7 @@ public async Task GetEntity(EntityAddress address, GatewayApiS if (entity == null) { - entity = await TryResolveAsPreAllocatedEntity(address); + entity = TryResolveAsPreAllocatedEntity(address); if (entity == null) { @@ -188,7 +189,7 @@ public async Task> GetEntities(List addresses foreach (var address in addresses.Except(entities.Keys)) { - var preAllocatedEntity = await TryResolveAsPreAllocatedEntity(address); + var preAllocatedEntity = TryResolveAsPreAllocatedEntity(address); if (preAllocatedEntity != null) { @@ -199,14 +200,14 @@ public async Task> GetEntities(List addresses return entities.Values; } - private async Task TryResolveAsPreAllocatedEntity(EntityAddress address) + private static Entity? TryResolveAsPreAllocatedEntity(EntityAddress address) { - if (await _preAllocatedEntityDataProvider.IsPreAllocatedAccountAddress(address)) + if (address.IsAccount && RadixAddressCodec.Decode(address).IsPreAllocatedAccountAddress()) { return new PreAllocatedAccountComponentEntity(address); } - if (await _preAllocatedEntityDataProvider.IsPreAllocatedIdentityAddress(address)) + if (address.IsIdentity && RadixAddressCodec.Decode(address).IsPreAllocatedIdentityAddress()) { return new PreAllocatedIdentityEntity(address); } diff --git a/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/PreAllocatedEntityDataProvider.cs b/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/PreAllocatedEntityDataProvider.cs index f463cc0c2..f184e36ee 100644 --- a/src/RadixDlt.NetworkGateway.PostgresIntegration/Services/PreAllocatedEntityDataProvider.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; @@ -79,72 +78,38 @@ namespace RadixDlt.NetworkGateway.PostgresIntegration.Services; internal interface IPreAllocatedEntityDataProvider { - public Task IsPreAllocatedAccountAddress(EntityAddress address); - - public Task IsPreAllocatedIdentityAddress(EntityAddress address); - Task<(GatewayModel.StateEntityDetailsResponseComponentDetails Details, GatewayModel.EntityMetadataCollection Metadata)> GetPreAllocatedEntityData(EntityAddress address); } internal class PreAllocatedEntityDataProvider : IPreAllocatedEntityDataProvider { private readonly INetworkConfigurationProvider _networkConfigurationProvider; - private readonly AsyncLazy _secp256k1PreAllocatedAccountDiscriminator; - private readonly AsyncLazy _ed25519PreAllocatedAccountDiscriminator; - private readonly AsyncLazy _secp256k1PreAllocatedIdentityDiscriminator; - private readonly AsyncLazy _ed25519PreAllocatedIdentityDiscriminator; private readonly List _preAllocatedAccountRoleAssignmentEntries; private readonly List _preAllocatedIdentityRoleAssignmentEntries; 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; - _secp256k1PreAllocatedAccountDiscriminator = CreateAsyncLazy(AddressEntityType.GlobalVirtualSecp256k1Account); - _ed25519PreAllocatedAccountDiscriminator = CreateAsyncLazy(AddressEntityType.GlobalVirtualEd25519Account); - _secp256k1PreAllocatedIdentityDiscriminator = CreateAsyncLazy(AddressEntityType.GlobalVirtualSecp256k1Identity); - _ed25519PreAllocatedIdentityDiscriminator = CreateAsyncLazy(AddressEntityType.GlobalVirtualEd25519Identity); - _preAllocatedAccountRoleAssignmentEntries = GenerateVirtualAccountRoleAssignmentEntries(roleAssignmentsKeyProvider); - _preAllocatedIdentityRoleAssignmentEntries = GenerateVirtualIdentityRoleAssignmentEntries(roleAssignmentsKeyProvider); - } - - public Task IsPreAllocatedAccountAddress(EntityAddress address) - { - return IsAccount(DecodeAddress(address, false)); - } - - public Task IsPreAllocatedIdentityAddress(EntityAddress address) - { - return IsIdentity(DecodeAddress(address, false)); + _preAllocatedAccountRoleAssignmentEntries = GeneratePreAllocatedAccountRoleAssignmentEntries(roleAssignmentsKeyProvider); + _preAllocatedIdentityRoleAssignmentEntries = GeneratePreAllocatedIdentityRoleAssignmentEntries(roleAssignmentsKeyProvider); } public async Task<(GatewayModel.StateEntityDetailsResponseComponentDetails Details, GatewayModel.EntityMetadataCollection Metadata)> GetPreAllocatedEntityData(EntityAddress address) { - var decoded = DecodeAddress(address, true); + var decoded = RadixAddressCodec.Decode(address, true); 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 IsPreAllocatedIdentityAddress(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,7 +142,7 @@ public Task IsPreAllocatedIdentityAddress(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", @@ -211,39 +176,7 @@ public Task IsPreAllocatedIdentityAddress(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 _secp256k1PreAllocatedAccountDiscriminator.Task || decoded.DiscriminatorByte == await _ed25519PreAllocatedAccountDiscriminator.Task; - } - - private async Task IsIdentity(DecodedRadixAddress decoded) - { - return decoded.DiscriminatorByte == await _secp256k1PreAllocatedIdentityDiscriminator.Task || decoded.DiscriminatorByte == await _ed25519PreAllocatedIdentityDiscriminator.Task; - } - - private async Task IsSecp256k1(DecodedRadixAddress decoded) - { - return decoded.DiscriminatorByte == await _secp256k1PreAllocatedAccountDiscriminator.Task || decoded.DiscriminatorByte == await _secp256k1PreAllocatedIdentityDiscriminator.Task; - } - - private async Task IsEd25519(DecodedRadixAddress decoded) - { - return decoded.DiscriminatorByte == await _ed25519PreAllocatedAccountDiscriminator.Task || decoded.DiscriminatorByte == await _ed25519PreAllocatedIdentityDiscriminator.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