From dd34eae675c849d4c87a38e52793c3d3d03d10eb Mon Sep 17 00:00:00 2001 From: EzequielPostan Date: Sun, 14 Apr 2024 22:58:19 -0300 Subject: [PATCH] ATL-6668: Delete more files related to VCs This commit deletes even more files related to VC operations. It also removes some dependencies on the old SDK --- build.sbt | 19 +- node/src/main/protobuf/common_models.proto | 122 ++++++ node/src/main/protobuf/health.proto | 63 ++++ node/src/main/protobuf/node_api.proto | 354 ++++++++++++++++++ node/src/main/protobuf/node_internal.proto | 27 ++ node/src/main/protobuf/node_models.proto | 291 ++++++++++++++ node/src/main/protobuf/status.proto | 47 +++ .../io/iohk/atala/prism/node/NodeApp.scala | 3 - .../prism/node/NodeGrpcServiceImpl.scala | 60 --- .../atala/prism/node/errors/PrismError.scala | 2 +- .../atala/prism/node/interop/implicits.scala | 8 - .../logging/GeneralLoggableInstances.scala | 13 - .../atala/prism/node/models/package.scala | 30 +- .../CredentialBatchesRepository.scala | 94 ----- .../node/repositories/daos/BaseDAO.scala | 9 - .../daos/CredentialBatchesDAO.scala | 125 ------- .../node/repositories/daos/package.scala | 81 +--- .../CredentialBatchesRepositoryLogs.scala | 55 --- .../CredentialBatchesRepositoryMetrics.scala | 33 -- .../prism/node/services/NodeService.scala | 91 +---- .../services/logs/NodeServiceLogging.scala | 25 -- .../atala/prism/node/DataPreparation.scala | 56 +-- .../atala/prism/node/NodeServiceSpec.scala | 275 +------------- .../prism/node/nonce/ClientHelperSpec.scala | 4 +- .../CredentialBatchesRepositorySpec.scala | 278 -------------- .../prism/node/repositories/package.scala | 5 - .../prism/node/utils/NodeClientUtils.scala | 52 --- 27 files changed, 923 insertions(+), 1299 deletions(-) create mode 100644 node/src/main/protobuf/common_models.proto create mode 100644 node/src/main/protobuf/health.proto create mode 100644 node/src/main/protobuf/node_api.proto create mode 100644 node/src/main/protobuf/node_internal.proto create mode 100644 node/src/main/protobuf/node_models.proto create mode 100644 node/src/main/protobuf/status.proto delete mode 100644 node/src/main/scala/io/iohk/atala/prism/node/repositories/CredentialBatchesRepository.scala delete mode 100644 node/src/main/scala/io/iohk/atala/prism/node/repositories/daos/CredentialBatchesDAO.scala delete mode 100644 node/src/main/scala/io/iohk/atala/prism/node/repositories/logs/CredentialBatchesRepositoryLogs.scala delete mode 100644 node/src/main/scala/io/iohk/atala/prism/node/repositories/metrics/CredentialBatchesRepositoryMetrics.scala delete mode 100644 node/src/test/scala/io/iohk/atala/prism/node/repositories/CredentialBatchesRepositorySpec.scala delete mode 100644 node/src/test/scala/io/iohk/atala/prism/node/utils/NodeClientUtils.scala diff --git a/build.sbt b/build.sbt index ea61acbfd5..b7648d673d 100644 --- a/build.sbt +++ b/build.sbt @@ -108,19 +108,10 @@ lazy val Dependencies = new { // We have to exclude bouncycastle since for some reason bitcoinj depends on bouncycastle jdk15to18 // (i.e. JDK 1.5 to 1.8), but we are using JDK 11 - val prismCredentials = - "io.iohk.atala" % "prism-credentials-jvm" % versions.prismSdk excludeAll ExclusionRule( - organization = "org.bouncycastle" - ) - val prismProtos = - "io.iohk.atala" % "prism-protos-jvm" % versions.prismSdk % "protobuf-src" intransitive () - val vaultProtos = - "io.iohk.atala" % "vault-api-jvm" % versions.vaultSdk % "protobuf-src" intransitive () - // Can be used only in tests! - val prismApi = - "io.iohk.atala" % "prism-api-jvm" % versions.prismSdk % Test excludeAll ExclusionRule( - organization = "org.bouncycastle" - ) + val prismCrypto = + "io.iohk.atala" % "prism-crypto-jvm" % versions.prismSdk + val prismIdentity = + "io.iohk.atala" % "prism-identity-jvm" % versions.prismSdk // Test dependencies val catsScalatest = @@ -163,7 +154,7 @@ lazy val Dependencies = new { val sttpDependencies = Seq(sttpCore, sttpCE2) val tofuDependencies = Seq(tofu, tofuLogging, tofuDerevoTagless) val prismDependencies = - Seq(prismCredentials, prismProtos, prismApi, vaultProtos) + Seq(prismCrypto, prismIdentity) val scalapbDependencies = Seq( "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf", "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion diff --git a/node/src/main/protobuf/common_models.proto b/node/src/main/protobuf/common_models.proto new file mode 100644 index 0000000000..fc95d169c5 --- /dev/null +++ b/node/src/main/protobuf/common_models.proto @@ -0,0 +1,122 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +package io.iohk.atala.prism.protos; + +import "status.proto"; +import "google/protobuf/timestamp.proto"; + +/** + * A request that can be used to check service health. + * All PRISM services expose an RPC that accepts this message as request. + */ +message HealthCheckRequest {} + +/** + * A response that represents service health. + * Status code 0 with empty response represents a healthy and reachable service, + * while all other status codes represent issues with the service. + */ +message HealthCheckResponse {} + +/** + * Represents a date by its parts (day, month, year). + */ +message Date { + int32 year = 1; // A positive value. + int32 month = 2; // A value in the [1, 12] range. + int32 day = 3; // A value in the [1, 31] range (depending on the month, the maximum value might be 28). +} + +/** + * Represents a time interval between two given timestamps. + * The message represents a closed interval (i.e. both ends are inclusive and mandatory). + */ +message TimeInterval { + /** + * The starting timestamp. + * start_timestamp must be before or equal to end_timestamp. + */ + google.protobuf.Timestamp start_timestamp = 1; + /** + * The ending timestamp. + * end_timestamp must be after or equal to start_timestamp. + */ + google.protobuf.Timestamp end_timestamp = 2; +} + +/** + * This enum provides a way for some RPC requests to specify the direction so that the response values are sorted + * the way you want them to. + * Note that it specifies the direction only and doesn't say anything about a comparator + * (e.g. natural order, some RPC-specific order etc). + */ +enum SortByDirection { + SORT_BY_DIRECTION_UNKNOWN = 0; // Nothing provided, each API can define whether to fail or take a default value (commonly ASCENDING). + SORT_BY_DIRECTION_ASCENDING = 1; // Sort the results in ascending order. + SORT_BY_DIRECTION_DESCENDING = 2; // Sort the results in descending order. +} + +/** + * The supported ledger types. Specifies which chain is used for storing transactions. + */ +enum Ledger { + reserved 2; // Removed BITCOIN_TESTNET + reserved "BITCOIN_TESTNET"; + reserved 3; // Removed BITCOIN_MAINNET + reserved "BITCOIN_MAINNET"; + + UNKNOWN_LEDGER = 0; // Invalid default value. + IN_MEMORY = 1; // Store transactions in memory instead of blockchain, used only for development. + CARDANO_TESTNET = 4; // Cardano testnet, used for testing. + CARDANO_MAINNET = 5; // Cardano mainnet, used in production. +} + +/** + * Information about a ledger block. + * See Ledger documentation for details on which ledgers are possible. + */ +message BlockInfo { + reserved 2; // Removed timestamp_deprecated field + reserved "timestamp_deprecated"; + + int32 number = 1; // Number of the block in the ledger. + int32 index = 3; // Index of the transaction within the block. + google.protobuf.Timestamp timestamp = 4; // Timestamp when the block was created. +} + +/** + * Information about a ledger transaction and the block that the transaction is included in. + */ +message TransactionInfo { + string transaction_id = 1; // Transaction ID. + Ledger ledger = 2; // Ledger the transaction was published to. + BlockInfo block = 3; // Block the transaction was included in. +} + +/** + * The status of an Atala operation. + */ +enum OperationStatus { + UNKNOWN_OPERATION = 0; // The operation hasn't been received by the node service yet. + PENDING_SUBMISSION = 1; // The transaction containing this operation hasn't been published to the chain yet. + AWAIT_CONFIRMATION = 2; // The transaction containing this operation has been published to the chain, but hasn't been processed by PRISM yet. + CONFIRMED_AND_APPLIED = 3; // The operation has been successfully applied to the PRISM. + CONFIRMED_AND_REJECTED = 4; // The operation has been processed by PRISM, but rejected because of some error. +} + +message AtalaErrorMessage { + google.rpc.Status status = 1; +} + +message AtalaMessage { + oneof message { + AtalaErrorMessage atala_error_message = 9; + } +} + +message ConnectionsStatusRequest { + repeated string connection_tokens = 1; +} diff --git a/node/src/main/protobuf/health.proto b/node/src/main/protobuf/health.proto new file mode 100644 index 0000000000..53e6e03259 --- /dev/null +++ b/node/src/main/protobuf/health.proto @@ -0,0 +1,63 @@ +// Copyright 2015 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The canonical version of this proto can be found at +// https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto + +syntax = "proto3"; + +package grpc.health.v1; + +option csharp_namespace = "Grpc.Health.V1"; +option go_package = "google.golang.org/grpc/health/grpc_health_v1"; +//option java_multiple_files = true; +//option java_outer_classname = "HealthProto"; +//option java_package = "io.grpc.health.v1"; + +message HealthCheckRequest { + string service = 1; +} + +message HealthCheckResponse { + enum ServingStatus { + UNKNOWN = 0; + SERVING = 1; + NOT_SERVING = 2; + SERVICE_UNKNOWN = 3; // Used only by the Watch method. + } + ServingStatus status = 1; +} + +service Health { + // If the requested service is unknown, the call will fail with status + // NOT_FOUND. + rpc Check(HealthCheckRequest) returns (HealthCheckResponse); + + // Performs a watch for the serving status of the requested service. + // The server will immediately send back a message indicating the current + // serving status. It will then subsequently send a new message whenever + // the service's serving status changes. + // + // If the requested service is unknown when the call is received, the + // server will send a message setting the serving status to + // SERVICE_UNKNOWN but will *not* terminate the call. If at some + // future point, the serving status of the service becomes known, the + // server will send a new message with the service's serving status. + // + // If the call terminates with status UNIMPLEMENTED, then clients + // should assume this method is not supported and should not retry the + // call. If the call terminates with any other status (including OK), + // clients should retry the call with appropriate exponential backoff. + rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse); +} diff --git a/node/src/main/protobuf/node_api.proto b/node/src/main/protobuf/node_api.proto new file mode 100644 index 0000000000..ddf434b2af --- /dev/null +++ b/node/src/main/protobuf/node_api.proto @@ -0,0 +1,354 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +package io.iohk.atala.prism.protos; + +import "common_models.proto"; +import "node_models.proto"; + +import "google/protobuf/timestamp.proto"; + +/** + * Service for PRISM Node API. Provides a way to store, retrieve and update + * Decentralized identifiers (DIDs), and Credentials' commitments into/from the underlying blockchain. + */ +service NodeService { + /** + * PUBLIC + * + * Sends a request that can be used to check service health. + * All PRISM services expose an RPC that accepts this message as request. + */ + rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse) {} + + /** + * PUBLIC + * + * Retrieves a DID Document associated to a DID. + * + * Errors: + * - Invalid long form DID (INVALID_ARGUMENT) + * - DID format not supported (INVALID_ARGUMENT) + * - Invalid DID (INVALID_ARGUMENT) + * - Unknown DID (INVALID_ARGUMENT) + */ + rpc GetDidDocument(GetDidDocumentRequest) returns (GetDidDocumentResponse) {} + + /** + * PUBLIC + * + * Retrieves the Node version info. + */ + rpc GetNodeBuildInfo(GetNodeBuildInfoRequest) returns (GetNodeBuildInfoResponse) {} + + /** + * PUBLIC + * + * Retrieves the Node version info. + */ + rpc GetNodeNetworkProtocolInfo(GetNodeNetworkProtocolInfoRequest) returns (GetNodeNetworkProtocolInfoResponse) {} + + /** + * PUBLIC + * + * Retrieves the status of an operation. + */ + rpc GetOperationInfo(GetOperationInfoRequest) returns (GetOperationInfoResponse) {} + + /** + * PUBLIC + * + * Timestamp of the latest block processed by PRISM Node. + */ + rpc GetLastSyncedBlockTimestamp(GetLastSyncedBlockTimestampRequest) returns (GetLastSyncedBlockTimestampResponse) {} + + /** + * PUBLIC + * + * Schedules a list of operations for further publication. + */ + rpc ScheduleOperations(ScheduleOperationsRequest) returns (ScheduleOperationsResponse) {} +} + +service NodeExplorerService { + /** + * WHITELISTED_DID + * + * Return a list of scheduled but unconfirmed operations. + */ + rpc GetScheduledOperations(GetScheduledOperationsRequest) returns (GetScheduledOperationsResponse) {} + + /** + * WHITELISTED_DID + * + * Return a list of wallet transactions. + */ + rpc GetWalletTransactionsPaginated(GetWalletTransactionsRequest) returns (GetWalletTransactionsResponse) {} + + /** + * WHITELISTED_DID + * + * Return the Node Wallet Balance + */ + rpc GetWalletBalance(GetWalletBalanceRequest) returns (GetWalletBalanceResponse) {} + + /** + * WHITELISTED_DID + * + * Retrieves list of available metrics. + */ + rpc GetAvailableMetrics(GetAvailableMetricsRequest) returns (GetAvailableMetricsResponse) {} + + /** + * WHITELISTED_DID + * + * Get statistics + */ + rpc GetNodeStatistics(GetNodeStatisticsRequest) returns (GetNodeStatisticsResponse) {} +} + +/** + * Retrieve statistics from the Node. + */ +message GetNodeStatisticsRequest { + repeated string metrics = 1; +} + +/** + * Statistics from the Node. + */ +message GetNodeStatisticsResponse { + repeated double metrics = 1; +} + +/** + * Request to find metrics exposed by Node. + * See NodeService.GetAvailableMetrics for more information. + */ +message GetAvailableMetricsRequest {} + +/** + * Response with a list of metrics exposed by Node. + * See NodeService.GetAvailableMetrics for more information. + */ +message GetAvailableMetricsResponse { + repeated string metrics = 1; +} + +/** + * Request to find a DID Document. + * See NodeService.GetDidDocument for more information. + */ +message GetDidDocumentRequest { + string did = 1; // The DID. +} +/** + * Response to a DID Document query. + * See NodeService.GetDidDocument for more information. + */ +message GetDidDocumentResponse { + DIDData document = 1; // The DID Document. + google.protobuf.Timestamp last_synced_block_timestamp = 5; // Timestamp of the latest synchronized block. + bytes last_update_operation = 6; // The hash of the last did update operation. +} + +/** + * Request to get the Node version info. + * See NodeService.GetNodeBuildInfo for more information. + */ +message GetNodeBuildInfoRequest { +} +/** + * Response with the Node version info. + * See NodeService.GetNodeBuildInfo for more information. + */ +message GetNodeBuildInfoResponse { + reserved 4; + + string version = 1; // The actual version. + string scala_version = 2; // The Scala version used to compile the app. + string sbt_version = 3; // The SBT version used to compile the app. +} + +/** + * Request to get the Node version info. + * See NodeService.GetNodeBuildInfo for more information. + */ +message GetNodeNetworkProtocolInfoRequest { +} +/** + * Response with the Node Protocol version info. + * See NodeService.GetNodeProtocolVersionInfo for more information. + */ +message GetNodeNetworkProtocolInfoResponse { + ProtocolVersion supported_network_protocol_version = 5; // Network protocol version number supported by Node. + ProtocolVersion current_network_protocol_version = 6; // Current network protocol version number. +} + +/** + * Request to get the credential's batch state. + * See NodeService.GetBatchState for more information. + */ +message GetBatchStateRequest { + string batch_id = 1; // The batch ID. +} +/** + * Response with the credential's batch state. + * See NodeService.GetBatchState for more information. + */ +message GetBatchStateResponse { + /** + * DID suffix used to sign the IssueCredentialBatch operation. + */ + string issuer_did = 1; + + /** + * The Merkle root used for the IssueCredential operation. + */ + bytes merkle_root = 2; + + /** + * Underlying blockchain data that refers to the transaction that + * contains the IssueCredential operation associated with the credential. + */ + LedgerData publication_ledger_data = 3; + + /** + * Underlying blockchain data that refers to the transaction that + * contains the RevokeCredential operation associated with the credential. + * This is optional. + */ + LedgerData revocation_ledger_data = 4; + + /** + * Timestamp of the latest synchronized block. + */ + google.protobuf.Timestamp last_synced_block_timestamp = 5; + + /** + * The hash of the credential to query about. + */ + bytes issuance_hash = 6; +} + +/** + * Request to get the credential's revocation time. + * See NodeService.GetCredentialRevocationTime for more information. + */ +message GetCredentialRevocationTimeRequest { + string batch_id = 1; // The ID corresponding to the credential to query about. + bytes credential_hash = 2; // The hash of the credential to query about. +} +/** + * Response with the credential's revocation time. + * See NodeService.GetCredentialRevocationTime for more information. + */ +message GetCredentialRevocationTimeResponse { + LedgerData revocation_ledger_data = 1; // The ledger data when the credential was revoked. This is optional. + google.protobuf.Timestamp last_synced_block_timestamp = 2; // Timestamp of the latest synchronized block. +} + +/** + * Request to get the operation status. + * See NodeService.GetOperationInfo for more information. + */ +message GetOperationInfoRequest { + bytes operation_id = 1; // Operation identifier. The identifier is returned to the corresponding operation request. +} +/** + * Response with the current operation status. + * See NodeService.GetOperationInfo for more information. + */ +message GetOperationInfoResponse { + OperationStatus operation_status = 1; // Contains the status of this operation. + string transaction_id = 3; // Transaction identifier containing the operation. Presented only when operation was approved by the ledger. + google.protobuf.Timestamp last_synced_block_timestamp = 2; // Timestamp of the latest synchronized block. + string details = 4; // Contains additional information about the operation state. For example, error descriptions. Can be empty. +} + +/** + * Request to retrieve the timestamp of the latest synchronized (processed by PRISM Node) block. + * See NodeService.GetLastSyncedBlockTimestampRequest for more information. + */ +message GetLastSyncedBlockTimestampRequest { +} +/** + * Response with the timestamp of the latest synchronized (processed by PRISM Node) block. + * See NodeService.GetLastSyncedBlockTimestampResponse for more information. + */ +message GetLastSyncedBlockTimestampResponse { + /** + * Timestamp of the latest synchronized (processed by PRISM Node) block. + */ + google.protobuf.Timestamp last_synced_block_timestamp = 1; +} + +/** + * Request to retrieve transaction info and operations outputs. + */ +message ScheduleOperationsRequest { + /** + * List of signed operations to apply. The operations will be applied in the order specified here. + */ + repeated SignedAtalaOperation signed_operations = 1; // a list of signed operations +} + +/** + * Response with the transaction info and operations outputs. + */ +message ScheduleOperationsResponse { + /** + * The responses for scheduled operations, ordered the same as the operations sent in ScheduleOperationsRequest. + */ + repeated OperationOutput outputs = 1; +} + +/** + * Request to retrieve all scheduled but not confirmed Atala operations. + */ +message GetScheduledOperationsRequest { + /** + * Operations of which type should be returned. + */ + OperationType operationsType = 1; + + enum OperationType { + AnyOperationType = 0; // Any operation + CreateDidOperationOperationType = 1; + UpdateDidOperationOperationType = 2; + IssueCredentialBatchOperationType = 3; + RevokeCredentialsOperationType = 4; + ProtocolVersionUpdateOperationType = 5; + } +} + +message GetScheduledOperationsResponse { + repeated SignedAtalaOperation scheduled_operations = 1; // a list of scheduled operations +} + +/** + * Request to retrieve wallet transactions, either ongoing or confirmed. + * Pagination included. + */ +message GetWalletTransactionsRequest { + TransactionState state = 1; // Transaction state: either ongoing or confirmed + string last_seen_transaction_id = 2; // Last seen transaction id + int32 limit = 3; // The maximum number of transactions to return; must be greater than 0. + + enum TransactionState { + Ongoing = 0; // Transactions which hasn't been confirmed by Prism Node + Confirmed = 1; // Transactions which ahs been confirmed by Prism Node + } +} + +message GetWalletTransactionsResponse { + repeated TransactionInfo transactions = 1; +} + +message GetWalletBalanceRequest { +} +message GetWalletBalanceResponse { + bytes balance = 1; +} diff --git a/node/src/main/protobuf/node_internal.proto b/node/src/main/protobuf/node_internal.proto new file mode 100644 index 0000000000..d100519ae7 --- /dev/null +++ b/node/src/main/protobuf/node_internal.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +import "node_models.proto"; + +package io.iohk.atala.prism.protos; + +/** + * Represent a block that holds operations. + * @exclude Intended for internal usage inside. Not publicly accessible from gRPC. + */ +message AtalaBlock { + reserved 1; // Represents the version of the block. Deprecated + repeated SignedAtalaOperation operations = 2; // A signed operation, necessary to post anything on the blockchain. +} + +/** + * Wraps an AtalaBlock and its metadata. + * @exclude Intended for internal usage inside. Not publicly accessible from gRPC. + */ +message AtalaObject { + reserved 1, 2, 3; // Removed block_hash field. + reserved "block_hash", "block_operation_count", "block_byte_length"; + AtalaBlock block_content = 4; // The block content. +} diff --git a/node/src/main/protobuf/node_models.proto b/node/src/main/protobuf/node_models.proto new file mode 100644 index 0000000000..8c2358269c --- /dev/null +++ b/node/src/main/protobuf/node_models.proto @@ -0,0 +1,291 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +package io.iohk.atala.prism.protos; + +import "common_models.proto"; +import "google/protobuf/timestamp.proto"; + +// Includes timestamping details about a blockchain's block. +message TimestampInfo { + reserved 1; // Removed blockTimestamp_deprecated field + reserved "blockTimestamp_deprecated"; + + uint32 block_sequence_number = 2; // The transaction index inside the underlying block. + uint32 operation_sequence_number = 3; // The operation index inside the AtalaBlock. + google.protobuf.Timestamp block_timestamp = 4; // The timestamp provided from the underlying blockchain. +} + +// Every key has a single purpose: +enum KeyUsage { + // UNKNOWN_KEY is an invalid value - Protobuf uses 0 if no value is provided and we want the user to explicitly choose the usage. + UNKNOWN_KEY = 0; + + // This is the most privileged key-type, when any other key is lost, you could use this to recover the others. + MASTER_KEY = 1; + + // This key-type is used for issuing credentials only, it should be kept in a safe place + // to avoid malicious credentials being issued. + ISSUING_KEY = 2; + + // This key-type is used to establish a shared symmetric key for secure end-to end communication + // use this key-type to encrypt the content. + KEY_AGREEMENT_KEY = 3; + + // This key-type is used to authenticate requests or logging into services. + AUTHENTICATION_KEY = 4; + + // This key-type is used for revoking credentials only, it should be kept in a safe place + // to avoid malicious credentials being issued. + REVOCATION_KEY = 5; + + // This key-type is used to specify a verification method that might be used by the DID subject to invoke a cryptographic capability, + // such as the authorization to update the DID Document. + CAPABILITY_INVOCATION_KEY = 6; + + // This is used to specify a mechanism that might be used by the DID subject to delegate a cryptographic capability to another party, + // such as delegating the authority to access a specific HTTP API to a subordinate. + CAPABILITY_DELEGATION_KEY = 7; +} + +/** + * Holds the necessary data to recover an Elliptic Curve (EC)'s public key. + * @exclude TODO: Consider renaming this to ECPublicKeyData. + */ +message ECKeyData { + string curve = 1; // The curve name, like secp256k1. + bytes x = 2; // The x coordinate, represented as bytes. + bytes y = 3; // The y coordinate, represented as bytes. +} + +/** + * Holds the compressed representation of data needed to recover Elliptic Curve (EC)'s public key. + * @exclude TODO: Consider renaming this to CompressedECPublicKeyData. + */ +message CompressedECKeyData { + string curve = 1; // The curve name, like secp256k1. + bytes data = 2; // compressed Elliptic Curve (EC) public key data. +} + +/** + * Represents a public key with metadata, necessary for a DID document. + * @exclude TODO: Consider renaming this to something more specific, like DIDPublicKey. + */ +message PublicKey { + reserved 3, 4; + string id = 1; // The key identifier within the DID Document. + KeyUsage usage = 2; // The key's purpose. + LedgerData added_on = 5; // The ledger details related to the event that added the key to the DID Document. + LedgerData revoked_on = 6; // The ledger details related to the event that revoked the key to the DID Document. + + // The key's representation. + oneof key_data { + ECKeyData ec_key_data = 8; // The Elliptic Curve (EC) key. + CompressedECKeyData compressed_ec_key_data = 9; // Compressed Elliptic Curve (EC) key. + }; +} + +// The DID Document's data. +message DIDData { + string id = 1; // The DID suffix, where DID is in form did:prism:[DID suffix] + repeated PublicKey public_keys = 2; // The keys that belong to this DID Document. + repeated Service services = 3; // The list of services that belong to this DID Document. + repeated string context = 4; // The list of @context values to consider on JSON-LD representations +} + +// The operation to create a public DID. +message CreateDIDOperation { + DIDCreationData did_data = 1; // DIDCreationData with public keys and services + + // The data necessary to create a DID. + message DIDCreationData { + reserved 1; // Removed DID id field which is empty on creation + repeated PublicKey public_keys = 2; // The keys that belong to this DID Document. + repeated Service services = 3; // The list of services that belong to this DID Document. + repeated string context = 4; // The list of @context values to consider on JSON-LD representations + } +} + +// The necessary data to add a key to a DID. +message AddKeyAction { + PublicKey key = 1; // The key to include. +} + +// The necessary data to remove a key from a DID. +message RemoveKeyAction { + string keyId = 1; // the key id to remove +} + +message AddServiceAction { + Service service = 1; +} + +message RemoveServiceAction { + string serviceId = 1; +} + +message UpdateServiceAction { + string serviceId = 1; // scoped to the did, unique per did + string type = 2; // new type if provided + // Will replace all existing service endpoints of the service with provided ones + string service_endpoints = 3; +} + +message PatchContextAction { + repeated string context = 1; // The list of strings to use by resolvers during resolution when producing a JSON-LD output +} + +// The potential details that can be updated in a DID. +message UpdateDIDAction { + + // The action to perform. + oneof action { + AddKeyAction add_key = 1; // Used to add a new key to the DID. + RemoveKeyAction remove_key = 2; // Used to remove a key from the DID. + AddServiceAction add_service = 3; // Used to add a new service to a DID, + RemoveServiceAction remove_service = 4; // Used to remove an existing service from a DID, + UpdateServiceAction update_service = 5; // Used to Update a list of service endpoints of a given service on a given DID. + PatchContextAction patch_context = 6; // Used to Update a list of `@context` strings used during resolution for a given DID. + } +} + +// Specifies the necessary data to update a public DID. +message UpdateDIDOperation { + bytes previous_operation_hash = 1; // The hash of the operation that issued the DID. + string id = 2; // @exclude TODO: To be redefined after we start using this operation. + repeated UpdateDIDAction actions = 3; // The actual updates to perform on the DID. +} + +// Represents a credential's batch. +// +// Check the protocol docs to understand it. +message CredentialBatchData { + string issuer_did = 1; // The DID suffix that issues the credential's batch. + bytes merkle_root = 2; // The Merkle root for the credential's batch. +} + +// Specifies the data to issue a credential batch. +message IssueCredentialBatchOperation { + CredentialBatchData credential_batch_data = 1; // The actual credential batch data. +} + +// Specifies the credentials to revoke (the whole batch, or just a subset of it). +message RevokeCredentialsOperation { + bytes previous_operation_hash = 1; // The hash of the operation that issued the batch. + string credential_batch_id = 2; // The corresponding batch ID, as returned in IssueCredentialBatchResponse. + repeated bytes credentials_to_revoke = 3; // The hashes of the credentials to revoke. If empty, the full batch is revoked. +} + +// Specifies the protocol version update +message ProtocolVersionUpdateOperation { + string proposer_did = 1; // The DID suffix that proposes the protocol update. + ProtocolVersionInfo version = 2; // Information of the new version +} + + +message ProtocolVersion { + // Represent the major version + int32 major_version = 1; + // Represent the minor version + int32 minor_version = 2; +} + +message ProtocolVersionInfo { + reserved 2, 3; + string version_name = 1; // (optional) name of the version + int32 effective_since = 4; // Cardano block number that tells since which block the update is enforced + + // New major and minor version to be announced, + // If major value changes, the node MUST stop issuing and reading operations, and upgrade before `effective_since` because the new protocol version. + // If minor value changes, the node can opt to not update. All events _published_ by this node would be also + // understood by other nodes with the same major version. However, there may be new events that this node won't _read_ + ProtocolVersion protocol_version = 5; +} + +message DeactivateDIDOperation { + bytes previous_operation_hash = 1; // The hash of the operation that issued the DID. + string id = 2; // DID Suffix of the DID to be deactivated +} + +// The possible operations affecting the blockchain. +message AtalaOperation { + // The actual operation. + oneof operation { + // Used to create a public DID. + CreateDIDOperation create_did = 1; + + // Used to update an existing public DID. + UpdateDIDOperation update_did = 2; + + // Used to issue a batch of credentials. + IssueCredentialBatchOperation issue_credential_batch = 3; + + // Used to revoke a credential batch. + RevokeCredentialsOperation revoke_credentials = 4; + + // Used to announce new protocol update + ProtocolVersionUpdateOperation protocol_version_update = 5; + + // Used to deactivate DID + DeactivateDIDOperation deactivate_did = 6; + }; +} + +// A signed operation, necessary to post anything on the blockchain. +message SignedAtalaOperation { + string signed_with = 1; // The key ID used to sign the operation, it must belong to the DID that signs the operation. + bytes signature = 2; // The actual signature. + AtalaOperation operation = 3; // The operation that was signed. +} + +// Ledger data associated to a protocol event. +// Note that the difference with TransactionInfo is that this message contains a full +// timestamp, and there is no expectation for it to be optional. +message LedgerData { + string transaction_id = 1; // ID of the transaction. + Ledger ledger = 2; // Ledger the transaction was published to. + TimestampInfo timestamp_info = 3; // The timestamp of the protocol event. +} + +// Used to encode the responses of the operations issued in an AtalaBlock. +message OperationOutput { + oneof result { + // Represents the response provided by IssueCredentialBatchOperation. + IssueCredentialBatchOutput batch_output = 1; + // Represents the response provided by CreateDIDOperation. + CreateDIDOutput create_did_output = 2; + // Represents the response provided by UpdateDIDOperation. + UpdateDIDOutput update_did_output = 3; + // Represents the response provided by RevokeCredentialOperation. + RevokeCredentialsOutput revoke_credentials_output = 4; + // Represents the response provided by ProtocolVersionUpdateOperation. + ProtocolVersionUpdateOutput protocol_version_update_output = 7; + DeactivateDIDOutput deactivate_did_output = 8; + } + oneof operation_maybe { + bytes operation_id = 5; // Operation identifier. + string error = 6; // Error description if PRISM Node service haven't scheduled the operation. + } +} + +message IssueCredentialBatchOutput { + string batch_id = 1; +} +message CreateDIDOutput { + string did_suffix = 1; +} +message UpdateDIDOutput {} +message RevokeCredentialsOutput {} +message ProtocolVersionUpdateOutput {} +message DeactivateDIDOutput {} + +message Service { + string id = 1; + string type = 2; + + string service_endpoint = 3; // can be one URI, JSON object, or array of either URIs of objects + LedgerData added_on = 4; // (when present) The ledger details related to the event that added the service. + LedgerData deleted_on = 5; // (when present) The ledger details related to the event that revoked the service. +} diff --git a/node/src/main/protobuf/status.proto b/node/src/main/protobuf/status.proto new file mode 100644 index 0000000000..5bd51aa2f3 --- /dev/null +++ b/node/src/main/protobuf/status.proto @@ -0,0 +1,47 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.rpc; + +import "google/protobuf/any.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/rpc/status;status"; +option java_multiple_files = true; +option java_outer_classname = "StatusProto"; +option java_package = "com.google.rpc"; +option objc_class_prefix = "RPC"; + +// The `Status` type defines a logical error model that is suitable for +// different programming environments, including REST APIs and RPC APIs. It is +// used by [gRPC](https://github.com/grpc). Each `Status` message contains +// three pieces of data: error code, error message, and error details. +// +// You can find out more about this error model and how to work with it in the +// [API Design Guide](https://cloud.google.com/apis/design/errors). +message Status { + // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + int32 code = 1; + + // A developer-facing error message, which should be in English. Any + // user-facing error message should be localized and sent in the + // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + string message = 2; + + // A list of messages that carry the error details. There is a common set of + // message types for APIs to use. + repeated google.protobuf.Any details = 3; +} \ No newline at end of file diff --git a/node/src/main/scala/io/iohk/atala/prism/node/NodeApp.scala b/node/src/main/scala/io/iohk/atala/prism/node/NodeApp.scala index 573f6cb244..1b39bf1577 100644 --- a/node/src/main/scala/io/iohk/atala/prism/node/NodeApp.scala +++ b/node/src/main/scala/io/iohk/atala/prism/node/NodeApp.scala @@ -125,13 +125,10 @@ class NodeApp(executionContext: ExecutionContext) { self => ), submissionService ) - credentialBatchesRepository <- - CredentialBatchesRepository.resource(liftedTransactor, logs) metricsCountersRepository <- MetricsCountersRepository.resource(liftedTransactor, logs) nodeService <- NodeService.resource( didDataRepository, objectManagementService, - credentialBatchesRepository, logs ) nodeStatisticsService <- StatisticsService.resource(atalaOperationsRepository, metricsCountersRepository, logs) diff --git a/node/src/main/scala/io/iohk/atala/prism/node/NodeGrpcServiceImpl.scala b/node/src/main/scala/io/iohk/atala/prism/node/NodeGrpcServiceImpl.scala index 9e86cb8f86..262b11b9fb 100644 --- a/node/src/main/scala/io/iohk/atala/prism/node/NodeGrpcServiceImpl.scala +++ b/node/src/main/scala/io/iohk/atala/prism/node/NodeGrpcServiceImpl.scala @@ -9,7 +9,6 @@ import io.iohk.atala.prism.node.logging.TraceId.IOWithTraceIdContext import io.iohk.atala.prism.node.metrics.RequestMeasureUtil import io.iohk.atala.prism.node.metrics.RequestMeasureUtil.measureRequestFuture import io.iohk.atala.prism.node.errors.NodeError -import io.iohk.atala.prism.node.grpc.ProtoCodecs import io.iohk.atala.prism.node.models.AtalaObjectTransactionSubmissionStatus.InLedger import io.iohk.atala.prism.node.models.{ AtalaObjectTransactionSubmissionStatus, @@ -56,48 +55,6 @@ class NodeGrpcServiceImpl( } - override def getBatchState( - request: GetBatchStateRequest - ): Future[GetBatchStateResponse] = { - val methodName = "getBatchState" - - measureRequestFuture(serviceName, methodName) { - trace { traceId => - val query = for { - batchState <- nodeService.getBatchState(request.batchId) - } yield batchState.fold( - countAndThrowNodeError(methodName, _), - toGetBatchResponse - ) - query.run(traceId).unsafeToFuture() - } - } - } - - override def getCredentialRevocationTime( - request: GetCredentialRevocationTimeRequest - ): Future[GetCredentialRevocationTimeResponse] = { - val methodName = "getCredentialRevocationTime" - - measureRequestFuture(serviceName, methodName) { - trace { traceId => - for { - revocationTimeEither <- - nodeService - .getCredentialRevocationData(request.batchId, request.credentialHash) - .run(traceId) - .unsafeToFuture() - } yield revocationTimeEither match { - case Left(error) => countAndThrowNodeError(methodName, error) - case Right(ledgerData) => - GetCredentialRevocationTimeResponse( - revocationLedgerData = ledgerData.maybeLedgerData.map(ProtoCodecs.toLedgerData) - ).withLastSyncedBlockTimestamp(ledgerData.lastSyncedTimestamp.toProtoTimestamp) - } - } - } - } - override def scheduleOperations( request: node_api.ScheduleOperationsRequest ): Future[node_api.ScheduleOperationsResponse] = { @@ -281,23 +238,6 @@ object NodeGrpcServiceImpl { def countAndThrowNodeError(methodName: String, error: NodeError): Nothing = RequestMeasureUtil.countAndThrowNodeError(serviceName)(methodName, error.toStatus) - private def toGetBatchResponse( - in: BatchData - ) = { - val response = in.maybeBatchState.fold(GetBatchStateResponse()) { state => - val revocationLedgerData = state.revokedOn.map(ProtoCodecs.toLedgerData) - val responseBase = GetBatchStateResponse() - .withIssuerDid(state.issuerDIDSuffix.getValue) - .withMerkleRoot(ByteString.copyFrom(state.merkleRoot.getHash.getValue)) - .withIssuanceHash(ByteString.copyFrom(state.lastOperation.getValue)) - .withPublicationLedgerData(ProtoCodecs.toLedgerData(state.issuedOn)) - revocationLedgerData.fold(responseBase)( - responseBase.withRevocationLedgerData - ) - } - response.withLastSyncedBlockTimestamp(in.lastSyncedTimestamp.toProtoTimestamp) - } - private def countAndThrowGetDidDocumentError[I]( methodName: String, didRequestStr: String, diff --git a/node/src/main/scala/io/iohk/atala/prism/node/errors/PrismError.scala b/node/src/main/scala/io/iohk/atala/prism/node/errors/PrismError.scala index f8d6e29693..37d027671d 100644 --- a/node/src/main/scala/io/iohk/atala/prism/node/errors/PrismError.scala +++ b/node/src/main/scala/io/iohk/atala/prism/node/errors/PrismError.scala @@ -2,7 +2,7 @@ package io.iohk.atala.prism.node.errors import com.google.rpc.status.{Status => StatusProto} import io.grpc.Status -import io.iohk.atala.prism.protos.credential_models.{AtalaErrorMessage, AtalaMessage} +import io.iohk.atala.prism.protos.common_models.{AtalaErrorMessage, AtalaMessage} trait PrismError { def toStatus: Status diff --git a/node/src/main/scala/io/iohk/atala/prism/node/interop/implicits.scala b/node/src/main/scala/io/iohk/atala/prism/node/interop/implicits.scala index 80731a0a2b..70e57648b6 100644 --- a/node/src/main/scala/io/iohk/atala/prism/node/interop/implicits.scala +++ b/node/src/main/scala/io/iohk/atala/prism/node/interop/implicits.scala @@ -2,7 +2,6 @@ package io.iohk.atala.prism.node.interop import cats.data.NonEmptyList import doobie.{Get, Meta, Read, Write} -import io.iohk.atala.prism.credentials.CredentialBatchId import io.iohk.atala.prism.crypto.{MerkleRoot, Sha256Digest} import doobie.implicits.legacy.instant._ import io.iohk.atala.prism.protos.models.TimestampInfo @@ -37,13 +36,6 @@ object implicits { implicit val ledgerRead: Read[Ledger] = Read[String].map { Ledger.withNameInsensitive } - implicit val credentialBatchIdRead: Read[CredentialBatchId] = - Read[String].map { CredentialBatchId.fromString } - implicit val credentialBatchIdGet: Get[CredentialBatchId] = - Get[String].map { CredentialBatchId.fromString } - implicit val credentialBatchIdWrite: Write[CredentialBatchId] = - Write[String].contramap(_.getId) - implicit val Sha256DigestWrite: Write[Sha256Digest] = Write[Array[Byte]].contramap(_.getValue) implicit val Sha256DigestRead: Read[Sha256Digest] = diff --git a/node/src/main/scala/io/iohk/atala/prism/node/logging/GeneralLoggableInstances.scala b/node/src/main/scala/io/iohk/atala/prism/node/logging/GeneralLoggableInstances.scala index 90bf70f666..8640fa5b56 100644 --- a/node/src/main/scala/io/iohk/atala/prism/node/logging/GeneralLoggableInstances.scala +++ b/node/src/main/scala/io/iohk/atala/prism/node/logging/GeneralLoggableInstances.scala @@ -1,7 +1,6 @@ package io.iohk.atala.prism.node.logging import io.grpc.Status -import io.iohk.atala.prism.credentials.CredentialBatchId import io.iohk.atala.prism.identity.{PrismDid => DID} import io.iohk.atala.prism.node.models.DidSuffix import io.iohk.atala.prism.crypto.keys.ECPublicKey @@ -45,18 +44,6 @@ object GeneralLoggableInstances { override def logShow(a: DidSuffix): String = s"{DIDSuffix=${a.value}}" } - implicit val credentialBatchIdLoggable: DictLoggable[CredentialBatchId] = - new DictLoggable[CredentialBatchId] { - override def fields[I, V, R, S](a: CredentialBatchId, i: I)(implicit - r: LogRenderer[I, V, R, S] - ): R = { - r.addString("CredentialBatchId", a.getId, i) - } - - override def logShow(a: CredentialBatchId): String = - s"{CredentialBatchId=$a}" - } - implicit val ecPublicKeyLoggable: DictLoggable[ECPublicKey] = new DictLoggable[ECPublicKey] { override def fields[I, V, R, S](a: ECPublicKey, i: I)(implicit diff --git a/node/src/main/scala/io/iohk/atala/prism/node/models/package.scala b/node/src/main/scala/io/iohk/atala/prism/node/models/package.scala index f712af042f..049257f913 100644 --- a/node/src/main/scala/io/iohk/atala/prism/node/models/package.scala +++ b/node/src/main/scala/io/iohk/atala/prism/node/models/package.scala @@ -3,15 +3,13 @@ package io.iohk.atala.prism.node import derevo.derive import enumeratum.EnumEntry.UpperSnakecase import enumeratum._ -import io.iohk.atala.prism.credentials.CredentialBatchId -import io.iohk.atala.prism.crypto.{MerkleRoot, Sha256Digest} +import io.iohk.atala.prism.crypto.Sha256Digest import io.iohk.atala.prism.crypto.keys.ECPublicKey import io.iohk.atala.prism.protos.models.TimestampInfo import io.iohk.atala.prism.protos.node_models import tofu.logging.derivation.loggable import java.time.Instant -import scala.util.matching.Regex package object models { sealed trait KeyUsage extends EnumEntry with UpperSnakecase { @@ -66,23 +64,6 @@ package object models { lastOperation: Sha256Digest ) - class CredentialId private (val id: String) extends AnyVal - - object CredentialId { - def apply(id: String): CredentialId = { - require( - CREDENTIAL_ID_RE.pattern.matcher(id).matches(), - s"invalid credential id: $id" - ) - - new CredentialId(id) - } - - def apply(digest: Sha256Digest): CredentialId = apply(digest.getHexValue) - - val CREDENTIAL_ID_RE: Regex = "^[0-9a-f]{64}$".r - } - @derive(loggable) case class AtalaOperationInfo( operationId: AtalaOperationId, @@ -138,15 +119,6 @@ package object models { object nodeState { - case class CredentialBatchState( - batchId: CredentialBatchId, - issuerDIDSuffix: DidSuffix, - merkleRoot: MerkleRoot, - issuedOn: LedgerData, - revokedOn: Option[LedgerData] = None, - lastOperation: Sha256Digest - ) - case class DIDPublicKeyState( didSuffix: DidSuffix, keyId: String, diff --git a/node/src/main/scala/io/iohk/atala/prism/node/repositories/CredentialBatchesRepository.scala b/node/src/main/scala/io/iohk/atala/prism/node/repositories/CredentialBatchesRepository.scala deleted file mode 100644 index 3d830d2593..0000000000 --- a/node/src/main/scala/io/iohk/atala/prism/node/repositories/CredentialBatchesRepository.scala +++ /dev/null @@ -1,94 +0,0 @@ -package io.iohk.atala.prism.node.repositories - -import cats.{Applicative, Comonad, Functor} -import cats.data.EitherT -import cats.effect.Resource -import cats.syntax.comonad._ -import cats.syntax.functor._ -import derevo.derive -import derevo.tagless.applyK -import doobie.implicits._ -import doobie.util.transactor.Transactor -import io.iohk.atala.prism.credentials.CredentialBatchId -import io.iohk.atala.prism.crypto.Sha256Digest -import io.iohk.atala.prism.node.errors.NodeError -import io.iohk.atala.prism.node.models.nodeState.{CredentialBatchState, LedgerData} -import io.iohk.atala.prism.node.repositories.daos.CredentialBatchesDAO -import io.iohk.atala.prism.node.metrics.TimeMeasureMetric -import io.iohk.atala.prism.node.repositories.logs.CredentialBatchesRepositoryLogs -import io.iohk.atala.prism.node.repositories.metrics.CredentialBatchesRepositoryMetrics -import io.iohk.atala.prism.node.utils.syntax.DBConnectionOps -import tofu.higherKind.Mid -import tofu.logging.{Logs, ServiceLogging} -import tofu.syntax.monoid.TofuSemigroupOps -import cats.effect.MonadCancelThrow - -@derive(applyK) -trait CredentialBatchesRepository[F[_]] { - def getBatchState( - batchId: CredentialBatchId - ): F[Either[NodeError, Option[CredentialBatchState]]] - def getCredentialRevocationTime( - batchId: CredentialBatchId, - credentialHash: Sha256Digest - ): F[Either[NodeError, Option[LedgerData]]] -} - -object CredentialBatchesRepository { - def apply[F[_]: MonadCancelThrow: TimeMeasureMetric, R[_]: Functor]( - transactor: Transactor[F], - logs: Logs[R, F] - ): R[CredentialBatchesRepository[F]] = - for { - serviceLogs <- logs.service[CredentialBatchesRepository[F]] - } yield { - implicit val implicitLogs: ServiceLogging[F, CredentialBatchesRepository[F]] = serviceLogs - val metrics: CredentialBatchesRepository[Mid[F, *]] = - new CredentialBatchesRepositoryMetrics[F]() - val logs: CredentialBatchesRepository[Mid[F, *]] = - new CredentialBatchesRepositoryLogs[F] - val mid = metrics |+| logs - mid attach new CredentialBatchesRepositoryImpl[F](transactor) - } - - def resource[F[_]: MonadCancelThrow: TimeMeasureMetric, R[ - _ - ]: Applicative: Functor]( - transactor: Transactor[F], - logs: Logs[R, F] - ): Resource[R, CredentialBatchesRepository[F]] = - Resource.eval(CredentialBatchesRepository(transactor, logs)) - - def unsafe[F[_]: MonadCancelThrow: TimeMeasureMetric, R[_]: Comonad]( - transactor: Transactor[F], - logs: Logs[R, F] - ): CredentialBatchesRepository[F] = - CredentialBatchesRepository(transactor, logs).extract -} - -private final class CredentialBatchesRepositoryImpl[F[_]: MonadCancelThrow]( - xa: Transactor[F] -) extends CredentialBatchesRepository[F] { - - def getBatchState( - batchId: CredentialBatchId - ): F[Either[NodeError, Option[CredentialBatchState]]] = - EitherT - .right[NodeError](CredentialBatchesDAO.findBatch(batchId)) - .value - .logSQLErrorsV2("getting batch state") - .transact(xa) - - def getCredentialRevocationTime( - batchId: CredentialBatchId, - credentialHash: Sha256Digest - ): F[Either[NodeError, Option[LedgerData]]] = - EitherT - .right[NodeError]( - CredentialBatchesDAO - .findRevokedCredentialLedgerData(batchId, credentialHash) - ) - .value - .logSQLErrorsV2("getting credential revocation time") - .transact(xa) -} diff --git a/node/src/main/scala/io/iohk/atala/prism/node/repositories/daos/BaseDAO.scala b/node/src/main/scala/io/iohk/atala/prism/node/repositories/daos/BaseDAO.scala index 7973007798..d40a55f333 100644 --- a/node/src/main/scala/io/iohk/atala/prism/node/repositories/daos/BaseDAO.scala +++ b/node/src/main/scala/io/iohk/atala/prism/node/repositories/daos/BaseDAO.scala @@ -3,7 +3,6 @@ package io.iohk.atala.prism.node.repositories.daos import doobie.util.invariant.InvalidEnum import doobie.{Get, Meta, Put} import io.circe.Json -import io.iohk.atala.prism.credentials.CredentialBatchId import io.iohk.atala.prism.crypto.EC.{INSTANCE => EC} import io.iohk.atala.prism.crypto.keys.ECPublicKey import io.iohk.atala.prism.crypto.{Sha256Digest => SHA256Digest} @@ -63,14 +62,6 @@ trait BaseDAO { ): Meta[T] = { Meta[UUID].timap(builder.apply)(_.uuid) } - - implicit val credentialBatchId: Meta[CredentialBatchId] = - Meta[String].timap(x => - Option( - CredentialBatchId - .fromString(x) - ).getOrElse(throw new RuntimeException(s"Invalid batch id: $x")) - )(_.getId) } object BaseDAO extends BaseDAO diff --git a/node/src/main/scala/io/iohk/atala/prism/node/repositories/daos/CredentialBatchesDAO.scala b/node/src/main/scala/io/iohk/atala/prism/node/repositories/daos/CredentialBatchesDAO.scala deleted file mode 100644 index 45e3e15ddb..0000000000 --- a/node/src/main/scala/io/iohk/atala/prism/node/repositories/daos/CredentialBatchesDAO.scala +++ /dev/null @@ -1,125 +0,0 @@ -package io.iohk.atala.prism.node.repositories.daos - -import java.time.Instant -import cats.syntax.functor._ -import doobie.Update -import doobie.free.connection.ConnectionIO -import doobie.implicits._ -import doobie.implicits.legacy.instant._ -import io.iohk.atala.prism.credentials.CredentialBatchId -import io.iohk.atala.prism.crypto.MerkleRoot -import io.iohk.atala.prism.crypto.Sha256Digest -import io.iohk.atala.prism.node.models._ -import io.iohk.atala.prism.node.models.nodeState.{CredentialBatchState, LedgerData} -import io.iohk.atala.prism.node.repositories.daos._ -import io.iohk.atala.prism.node.interop.implicits._ -import io.iohk.atala.prism.node.utils.syntax._ - -object CredentialBatchesDAO { - case class CreateCredentialBatchData( - batchId: CredentialBatchId, - lastOperation: Sha256Digest, - issuerDIDSuffix: DidSuffix, - merkleRoot: MerkleRoot, - ledgerData: LedgerData - ) - - def insert( - data: CreateCredentialBatchData - ): ConnectionIO[Unit] = { - val issuedOn = data.ledgerData.timestampInfo - sql""" - |INSERT INTO credential_batches (batch_id, last_operation, issuer_did_suffix, merkle_root, issued_on, issued_on_absn, issued_on_osn, ledger, issued_on_transaction_id) - |VALUES (${data.batchId}, ${data.lastOperation}, ${data.issuerDIDSuffix}, ${data.merkleRoot}, ${Instant - .ofEpochMilli(issuedOn.getAtalaBlockTimestamp)}, - | ${issuedOn.getAtalaBlockSequenceNumber}, ${issuedOn.getOperationSequenceNumber}, ${data.ledgerData.ledger}, ${data.ledgerData.transactionId}) - """.stripMargin.update.run.void - } - - def findBatch( - credentialBatchId: CredentialBatchId - ): ConnectionIO[Option[CredentialBatchState]] = { - sql""" - |SELECT batch_id, issuer_did_suffix, merkle_root, issued_on_transaction_id, ledger, - | issued_on, issued_on_absn, issued_on_osn, revoked_on_transaction_id, ledger, - | revoked_on, revoked_on_absn, revoked_on_osn, last_operation - |FROM credential_batches - |WHERE batch_id = ${credentialBatchId.getId} - """.stripMargin.query[CredentialBatchState].option - } - - def revokeEntireBatch( - credentialBatchId: CredentialBatchId, - ledgerData: LedgerData - ): ConnectionIO[Boolean] = { - val revocationTimestamp = ledgerData.timestampInfo - sql""" - |UPDATE credential_batches - |SET revoked_on = ${revocationTimestamp.getAtalaBlockTimestamp.toInstant}, - | revoked_on_absn = ${revocationTimestamp.getAtalaBlockSequenceNumber}, - | revoked_on_osn = ${revocationTimestamp.getOperationSequenceNumber}, - | revoked_on_transaction_id = ${ledgerData.transactionId} - |WHERE batch_id = ${credentialBatchId.getId} AND - | revoked_on IS NULL - """.stripMargin.update.run.map(_ > 0) - } - - def revokeCredentials( - credentialBatchId: CredentialBatchId, - credentials: List[Sha256Digest], - ledgerData: LedgerData - ): ConnectionIO[Unit] = { - val revocationTimestamp = ledgerData.timestampInfo - val sql = - """INSERT INTO revoked_credentials (batch_id, credential_id, revoked_on, revoked_on_absn, revoked_on_osn, ledger, transaction_id) - |VALUES (?, ?, ?, ?, ?, ?, ?) - |ON CONFLICT (batch_id, credential_id) DO NOTHING - |""".stripMargin - Update[ - ( - CredentialBatchId, - Sha256Digest, - Instant, - Int, - Int, - Ledger, - TransactionId - ) - ](sql) - .updateMany( - credentials.map(credentialHash => - ( - credentialBatchId, - credentialHash, - revocationTimestamp.getAtalaBlockTimestamp.toInstant, - revocationTimestamp.getAtalaBlockSequenceNumber, - revocationTimestamp.getOperationSequenceNumber, - ledgerData.ledger, - ledgerData.transactionId - ) - ) - ) - .void - } - - def findRevokedCredentialLedgerData( - batchId: CredentialBatchId, - credentialHash: Sha256Digest - ): ConnectionIO[Option[LedgerData]] = { - sql"""SELECT transaction_id, ledger, revoked_on, revoked_on_absn, revoked_on_osn - |FROM revoked_credentials - |WHERE batch_id = $batchId AND - | credential_id = $credentialHash::CREDENTIAL_HASH - |""".stripMargin.query[LedgerData].option - } - - // only for testing - def findRevokedCredentials( - batchId: CredentialBatchId - ): ConnectionIO[List[(Sha256Digest, LedgerData)]] = { - sql"""SELECT credential_id, transaction_id, ledger, revoked_on, revoked_on_absn, revoked_on_osn - |FROM revoked_credentials - |WHERE batch_id = $batchId - |""".stripMargin.query[(Sha256Digest, LedgerData)].to[List] - } -} diff --git a/node/src/main/scala/io/iohk/atala/prism/node/repositories/daos/package.scala b/node/src/main/scala/io/iohk/atala/prism/node/repositories/daos/package.scala index 2384ea413d..1b39c8cc26 100644 --- a/node/src/main/scala/io/iohk/atala/prism/node/repositories/daos/package.scala +++ b/node/src/main/scala/io/iohk/atala/prism/node/repositories/daos/package.scala @@ -4,13 +4,11 @@ import cats.data.NonEmptyList import doobie._ import doobie.postgres.implicits._ import doobie.util.invariant.InvalidEnum -import io.iohk.atala.prism.credentials.CredentialBatchId import io.iohk.atala.prism.crypto.EC.{INSTANCE => EC} import io.iohk.atala.prism.crypto.ECConfig.{INSTANCE => ECConfig} import io.iohk.atala.prism.crypto.keys.ECPublicKey -import io.iohk.atala.prism.crypto.{MerkleRoot, Sha256Digest} import io.iohk.atala.prism.node.models._ -import io.iohk.atala.prism.node.models.nodeState.{CredentialBatchState, DIDPublicKeyState, DIDServiceState, LedgerData} +import io.iohk.atala.prism.node.models.nodeState.{DIDPublicKeyState, DIDServiceState, LedgerData} import io.iohk.atala.prism.protos.models.TimestampInfo import io.iohk.atala.prism.node.utils.syntax._ @@ -62,13 +60,6 @@ package object daos extends BaseDAO { implicit val IdTypePut: Put[IdType] = Put[String].contramap(_.getValue) implicit val IdTypeGet: Get[IdType] = Get[String].map(IdType.apply) - implicit val credentialIdPut: Put[CredentialId] = Put[String].contramap(_.id) - implicit val credentialIdGet: Get[CredentialId] = - Get[String].map(CredentialId(_)) - - implicit val credentialBatchIdMeta: Meta[CredentialBatchId] = - Meta[String].timap(CredentialBatchId.fromString)(_.getId) - implicit val didPublicKeyWrite: Write[DIDPublicKeyState] = { Write[ ( @@ -344,76 +335,6 @@ package object daos extends BaseDAO { ) } - implicit val CredentialBatchStateRead: Read[CredentialBatchState] = { - Read[ - ( - String, - String, - Array[Byte], - Array[Byte], - String, - Instant, - Int, - Int, - Option[Array[Byte]], - Option[String], - Option[Instant], - Option[Int], - Option[Int], - Array[Byte] - ) - ].map { - case ( - batchId, - suffix, - root, - issTxId, - issLedger, - issABT, - issABSN, - issOSN, - revTxIdOp, - revLedgerOp, - revABTOp, - revABSNOp, - revOSNOp, - sha - ) => - val issuedOn = LedgerData( - TransactionId.from(issTxId).get, - Ledger.withNameInsensitive(issLedger), - new TimestampInfo(issABT.toEpochMilli, issABSN, issOSN) - ) - val revokedOn = { - (revTxIdOp, revLedgerOp, revABTOp, revABSNOp, revOSNOp) match { - case ( - Some(rTrId), - Some(rLedger), - Some(rAbt), - Some(rAbsn), - Some(rOsn) - ) => - Some( - LedgerData( - TransactionId.from(rTrId).get, - Ledger.withNameInsensitive(rLedger), - new TimestampInfo(rAbt.toEpochMilli, rAbsn, rOsn) - ) - ) - case _ => None - } - } - CredentialBatchState( - CredentialBatchId.fromString(batchId), - DidSuffix(suffix), - new MerkleRoot(Sha256Digest.fromBytes(root)), - issuedOn, - revokedOn, - Sha256Digest.fromBytes(sha) - ) - } - } - implicit val protocolVersionRead: Read[ProtocolVersion] = Read[(Int, Int)] .map { case (major, minor) => diff --git a/node/src/main/scala/io/iohk/atala/prism/node/repositories/logs/CredentialBatchesRepositoryLogs.scala b/node/src/main/scala/io/iohk/atala/prism/node/repositories/logs/CredentialBatchesRepositoryLogs.scala deleted file mode 100644 index 514056e202..0000000000 --- a/node/src/main/scala/io/iohk/atala/prism/node/repositories/logs/CredentialBatchesRepositoryLogs.scala +++ /dev/null @@ -1,55 +0,0 @@ -package io.iohk.atala.prism.node.repositories.logs - -import cats.syntax.apply._ -import cats.syntax.applicativeError._ -import cats.syntax.flatMap._ -import io.iohk.atala.prism.credentials.CredentialBatchId -import io.iohk.atala.prism.crypto.Sha256Digest -import io.iohk.atala.prism.node.errors -import io.iohk.atala.prism.node.models.nodeState -import io.iohk.atala.prism.node.repositories.CredentialBatchesRepository -import io.iohk.atala.prism.node.logging.GeneralLoggableInstances._ -import tofu.higherKind.Mid -import tofu.logging.ServiceLogging -import tofu.syntax.logging._ -import cats.MonadThrow - -private[repositories] final class CredentialBatchesRepositoryLogs[F[ - _ -]: MonadThrow: ServiceLogging[*[ - _ -], CredentialBatchesRepository[F]]] - extends CredentialBatchesRepository[Mid[F, *]] { - override def getBatchState( - batchId: CredentialBatchId - ): Mid[F, Either[errors.NodeError, Option[nodeState.CredentialBatchState]]] = - in => - info"getting batch state $batchId" *> in - .flatTap( - _.fold( - err => error"Encountered an error while getting batch state $batchId: $err", - res => info"getting batch state $batchId - successfully done, state found - ${res.isDefined}" - ) - ) - .onError(errorCause"Encountered an error while getting batch state $batchId" (_)) - - override def getCredentialRevocationTime( - batchId: CredentialBatchId, - credentialHash: Sha256Digest - ): Mid[F, Either[errors.NodeError, Option[nodeState.LedgerData]]] = - in => - info"getting credential revocation time for $batchId" *> in - .flatTap( - _.fold( - err => error"Encountered an error while getting credential revocation time: $err", - res => - info"getting credential revocation time for $batchId - successfully done ${res - .map(_.transactionId)}" - ) - ) - .onError( - errorCause"Encountered an error while getting credential revocation time for $batchId" ( - _ - ) - ) -} diff --git a/node/src/main/scala/io/iohk/atala/prism/node/repositories/metrics/CredentialBatchesRepositoryMetrics.scala b/node/src/main/scala/io/iohk/atala/prism/node/repositories/metrics/CredentialBatchesRepositoryMetrics.scala deleted file mode 100644 index cdf3f6f3e2..0000000000 --- a/node/src/main/scala/io/iohk/atala/prism/node/repositories/metrics/CredentialBatchesRepositoryMetrics.scala +++ /dev/null @@ -1,33 +0,0 @@ -package io.iohk.atala.prism.node.repositories.metrics - -import io.iohk.atala.prism.credentials.CredentialBatchId -import io.iohk.atala.prism.crypto.Sha256Digest -import io.iohk.atala.prism.node.metrics.TimeMeasureUtil.MeasureOps -import io.iohk.atala.prism.node.metrics.{TimeMeasureMetric, TimeMeasureUtil} -import io.iohk.atala.prism.node.errors.NodeError -import io.iohk.atala.prism.node.models.nodeState.{CredentialBatchState, LedgerData} -import io.iohk.atala.prism.node.repositories.CredentialBatchesRepository -import tofu.higherKind.Mid -import cats.effect.MonadCancelThrow - -private[repositories] final class CredentialBatchesRepositoryMetrics[F[ - _ -]: TimeMeasureMetric: MonadCancelThrow] - extends CredentialBatchesRepository[Mid[F, *]] { - - private val repoName = "CredentialBatchesRepository" - private lazy val getBatchStateTimer = - TimeMeasureUtil.createDBQueryTimer(repoName, "getBatchState") - private lazy val getCredentialRevocationTimeTimer = - TimeMeasureUtil.createDBQueryTimer(repoName, "getCredentialRevocationTime") - - override def getBatchState( - batchId: CredentialBatchId - ): Mid[F, Either[NodeError, Option[CredentialBatchState]]] = - _.measureOperationTime(getBatchStateTimer) - override def getCredentialRevocationTime( - batchId: CredentialBatchId, - credentialHash: Sha256Digest - ): Mid[F, Either[NodeError, Option[LedgerData]]] = - _.measureOperationTime(getCredentialRevocationTimeTimer) -} diff --git a/node/src/main/scala/io/iohk/atala/prism/node/services/NodeService.scala b/node/src/main/scala/io/iohk/atala/prism/node/services/NodeService.scala index 90e972b0e3..cf792fddd8 100644 --- a/node/src/main/scala/io/iohk/atala/prism/node/services/NodeService.scala +++ b/node/src/main/scala/io/iohk/atala/prism/node/services/NodeService.scala @@ -6,15 +6,14 @@ import cats.{Applicative, Comonad, Functor, MonadThrow} import com.google.protobuf.ByteString import derevo.derive import derevo.tagless.applyK -import io.iohk.atala.prism.credentials.CredentialBatchId import io.iohk.atala.prism.crypto.Sha256Digest import io.iohk.atala.prism.identity.{CanonicalPrismDid, PrismDid} import io.iohk.atala.prism.node.models.AtalaOperationId import io.iohk.atala.prism.node.errors.NodeError import io.iohk.atala.prism.node.grpc.ProtoCodecs -import io.iohk.atala.prism.node.models.nodeState.{CredentialBatchState, DIDDataState, LedgerData} +import io.iohk.atala.prism.node.models.nodeState.DIDDataState import io.iohk.atala.prism.node.models.{AtalaOperationInfo, ProtocolVersion} -import io.iohk.atala.prism.node.repositories.{CredentialBatchesRepository, DIDDataRepository} +import io.iohk.atala.prism.node.repositories.DIDDataRepository import io.iohk.atala.prism.node.services.logs.NodeServiceLogging import io.iohk.atala.prism.node.services.models.{getOperationOutput, validateScheduleOperationsRequest} import io.iohk.atala.prism.protos.node_models @@ -38,26 +37,6 @@ trait NodeService[F[_]] { */ def getDidDocumentByDid(didStr: String): F[Either[GettingDidError, DidDocument]] - /** Get information about credentials batch identified by `batchId`. See `BatchData` for the details. - * - * @param batchId - * identifier of the credentials batch. - */ - def getBatchState(batchId: String): F[Either[NodeError, BatchData]] - - /** Retrieves information on credential revocation. - * - * @param batchId - * batch containing the credential. - * @param credentialHash - * hash represents the credential inside the batch. - * @return - */ - def getCredentialRevocationData( - batchId: String, - credentialHash: ByteString - ): F[Either[NodeError, CredentialRevocationTime]] - /** Schedules a list of operations for further publication to the underlying ledger. * * @param ops @@ -89,8 +68,7 @@ trait NodeService[F[_]] { private final class NodeServiceImpl[F[_]: MonadThrow]( didDataRepository: DIDDataRepository[F], - objectManagement: ObjectManagementService[F], - credentialBatchesRepository: CredentialBatchesRepository[F] + objectManagement: ObjectManagementService[F] ) extends NodeService[F] { override def getDidDocumentByDid(didStr: String): F[Either[GettingDidError, DidDocument]] = Try(PrismDid.canonicalFromString(didStr)).fold( @@ -114,56 +92,6 @@ private final class NodeServiceImpl[F[_]: MonadThrow]( private def toDidDataProto(in: Option[DIDDataState], canon: CanonicalPrismDid): Option[(DIDData, Sha256Digest)] = in.map(didDataState => (ProtoCodecs.toDIDDataProto(canon.getSuffix, didDataState), didDataState.lastOperation)) - override def getBatchState(batchIdStr: String): F[Either[NodeError, BatchData]] = { - // NOTE: CredentialBatchId.fromString returns null and doesn't throw an error when string wasn't successfully parsed - Option(CredentialBatchId.fromString(batchIdStr)) - .fold( - Applicative[F].pure((NodeError.InvalidArgument(s"Invalid batch id: $batchIdStr"): NodeError).asLeft[BatchData]) - )(batchId => getBatchState(batchId)) - } - - private def getBatchState(batchId: CredentialBatchId): F[Either[NodeError, BatchData]] = - for { - lastSyncedTimestamp <- objectManagement.getLastSyncedTimestamp - maybeBatchStateE <- credentialBatchesRepository.getBatchState(batchId) - batchData = maybeBatchStateE.map(BatchData(_, lastSyncedTimestamp)) - } yield batchData - - override def getCredentialRevocationData( - batchIdStr: String, - credentialHashBS: ByteString - ): F[Either[NodeError, CredentialRevocationTime]] = { - // NOTE: CredentialBatchId.fromString returns null and doesn't throw an error when string wasn't successfully parsed - Option(CredentialBatchId.fromString(batchIdStr)) - .fold( - Applicative[F].pure( - (NodeError.InvalidArgument(s"Invalid batch id: $batchIdStr"): NodeError).asLeft[CredentialRevocationTime] - ) - )(batchId => - Try(Sha256Digest.fromBytes(credentialHashBS.toByteArray)).fold( - _ => - Applicative[F].pure( - NodeError - .InvalidArgument( - s"The given byte array does not correspond to a SHA256 hash. It must have exactly 32 bytes: ${credentialHashBS.toByteArray.map("%02X" format _).mkString}" - ) - .asLeft - ), - credentialHash => getCredentialRevocationData(batchId, credentialHash) - ) - ) - } - - private def getCredentialRevocationData( - batchId: CredentialBatchId, - credentialHash: Sha256Digest - ): F[Either[NodeError, CredentialRevocationTime]] = - for { - lastSyncedTimestamp <- objectManagement.getLastSyncedTimestamp - maybeTime <- credentialBatchesRepository.getCredentialRevocationTime(batchId, credentialHash) - credentialRevocationTime = maybeTime.map(CredentialRevocationTime(_, lastSyncedTimestamp)) - } yield credentialRevocationTime - override def parseOperations(ops: Seq[SignedAtalaOperation]): F[Either[NodeError, List[OperationOutput]]] = Applicative[F].pure { for { @@ -210,7 +138,6 @@ object NodeService { def make[I[_]: Functor, F[_]: MonadThrow]( didDataRepository: DIDDataRepository[F], objectManagement: ObjectManagementService[F], - credentialBatchesRepository: CredentialBatchesRepository[F], logs: Logs[I, F] ): I[NodeService[F]] = { for { @@ -221,8 +148,7 @@ object NodeService { val mid: NodeService[Mid[F, *]] = logs mid attach new NodeServiceImpl[F]( didDataRepository, - objectManagement, - credentialBatchesRepository + objectManagement ) } } @@ -230,31 +156,24 @@ object NodeService { def resource[I[_]: Comonad, F[_]: MonadThrow]( didDataRepository: DIDDataRepository[F], objectManagement: ObjectManagementService[F], - credentialBatchesRepository: CredentialBatchesRepository[F], logs: Logs[I, F] ): Resource[I, NodeService[F]] = Resource.eval( - make(didDataRepository, objectManagement, credentialBatchesRepository, logs) + make(didDataRepository, objectManagement, logs) ) def unsafe[I[_]: Comonad, F[_]: MonadThrow]( didDataRepository: DIDDataRepository[F], objectManagement: ObjectManagementService[F], - credentialBatchesRepository: CredentialBatchesRepository[F], logs: Logs[I, F] ): NodeService[F] = make( didDataRepository, objectManagement, - credentialBatchesRepository, logs ).extract } -final case class BatchData(maybeBatchState: Option[CredentialBatchState], lastSyncedTimestamp: Instant) - -final case class CredentialRevocationTime(maybeLedgerData: Option[LedgerData], lastSyncedTimestamp: Instant) - final case class DidDocument( maybeData: Option[DIDData], maybeOperation: Option[Sha256Digest], diff --git a/node/src/main/scala/io/iohk/atala/prism/node/services/logs/NodeServiceLogging.scala b/node/src/main/scala/io/iohk/atala/prism/node/services/logs/NodeServiceLogging.scala index 322a254aad..683040b622 100644 --- a/node/src/main/scala/io/iohk/atala/prism/node/services/logs/NodeServiceLogging.scala +++ b/node/src/main/scala/io/iohk/atala/prism/node/services/logs/NodeServiceLogging.scala @@ -31,31 +31,6 @@ class NodeServiceLogging[F[_]: ServiceLogging[*[_], NodeService[F]]: MonadThrow] .onError(errorCause"encountered an error while $description" (_)) } - override def getBatchState(batchId: String): Mid[F, Either[errors.NodeError, BatchData]] = in => - info"getting batch state $batchId" *> in - .flatTap( - _.fold( - err => error"encountered an error while getting batch $batchId state: $err", - _ => info"getting batch $batchId state - successfully done" - ) - ) - .onError(errorCause"encountered an error while getting batch state" (_)) - - override def getCredentialRevocationData( - batchIdStr: String, - credentialHashBS: ByteString - ): Mid[F, Either[errors.NodeError, CredentialRevocationTime]] = { in => - val credentialHashHex = credentialHashBS.toByteArray.map("%02X" format _).mkString - info"getting credential revocation data [batchId=$batchIdStr, credentialHash=$credentialHashHex]" *> in - .flatTap( - _.fold( - err => error"encountered an error while getting credential revocation data for $credentialHashHex: $err", - _ => info"getting credential revocation data for $credentialHashHex - successfully done" - ) - ) - .onError(errorCause"encountered an error while getting credential revocation data " (_)) - } - override def scheduleAtalaOperations( ops: SignedAtalaOperation* ): Mid[F, List[Either[errors.NodeError, AtalaOperationId]]] = in => diff --git a/node/src/test/scala/io/iohk/atala/prism/node/DataPreparation.scala b/node/src/test/scala/io/iohk/atala/prism/node/DataPreparation.scala index ce34e740bf..ffcc542487 100644 --- a/node/src/test/scala/io/iohk/atala/prism/node/DataPreparation.scala +++ b/node/src/test/scala/io/iohk/atala/prism/node/DataPreparation.scala @@ -6,8 +6,7 @@ import cats.implicits._ import com.google.protobuf.ByteString import doobie.implicits._ import doobie.util.transactor.Transactor -import io.iohk.atala.prism.credentials.CredentialBatchId -import io.iohk.atala.prism.crypto.{MerkleRoot, Sha256, Sha256Digest} +import io.iohk.atala.prism.crypto.Sha256 import io.iohk.atala.prism.node.logging.TraceId import io.iohk.atala.prism.node.logging.TraceId.IOWithTraceIdContext import io.iohk.atala.prism.node.cardano.{LAST_SYNCED_BLOCK_NO, LAST_SYNCED_BLOCK_TIMESTAMP} @@ -18,13 +17,11 @@ import io.iohk.atala.prism.node.models._ import io.iohk.atala.prism.node.operations.ApplyOperationConfig import io.iohk.atala.prism.node.operations.CreateDIDOperationSpec.{issuingEcKeyData, masterEcKeyData} import io.iohk.atala.prism.node.repositories.daos.AtalaObjectsDAO.AtalaObjectCreateData -import io.iohk.atala.prism.node.repositories.daos.CredentialBatchesDAO.CreateCredentialBatchData import io.iohk.atala.prism.node.repositories.daos.{ AtalaObjectTransactionSubmissionsDAO, AtalaObjectsDAO, AtalaOperationsDAO, ContextDAO, - CredentialBatchesDAO, DIDDataDAO, KeyValuesDAO, PublicKeysDAO, @@ -207,57 +204,6 @@ object DataPreparation { .unsafeRunSync() } - // *************************************** - // Credential batches (slayer 0.3) - // *************************************** - - def createBatch( - batchId: CredentialBatchId, - lastOperation: Sha256Digest, - issuerDIDSuffix: DidSuffix, - merkleRoot: MerkleRoot, - issuedOn: LedgerData - )(implicit database: Transactor[IO]): Unit = { - CredentialBatchesDAO - .insert( - CreateCredentialBatchData( - batchId = batchId, - lastOperation = lastOperation, - issuerDIDSuffix = issuerDIDSuffix, - merkleRoot = merkleRoot, - ledgerData = issuedOn - ) - ) - .transact(database) - .unsafeRunSync() - } - - def revokeCredentialBatch( - batchId: CredentialBatchId, - revocationLedgerData: LedgerData - )(implicit database: Transactor[IO]): Unit = { - CredentialBatchesDAO - .revokeEntireBatch(batchId, revocationLedgerData) - .transact(database) - .unsafeRunSync() - () - } - - def revokeCredentials( - batchId: CredentialBatchId, - credentialHashes: List[Sha256Digest], - revocationLedgerData: LedgerData - )(implicit database: Transactor[IO]): Unit = { - CredentialBatchesDAO - .revokeCredentials( - batchId, - credentialHashes, - revocationLedgerData - ) - .transact(database) - .unsafeRunSync() - } - // *************************************** // Other useful methods // *************************************** diff --git a/node/src/test/scala/io/iohk/atala/prism/node/NodeServiceSpec.scala b/node/src/test/scala/io/iohk/atala/prism/node/NodeServiceSpec.scala index 21e48d811d..49ed2e376f 100644 --- a/node/src/test/scala/io/iohk/atala/prism/node/NodeServiceSpec.scala +++ b/node/src/test/scala/io/iohk/atala/prism/node/NodeServiceSpec.scala @@ -9,8 +9,7 @@ import doobie.implicits._ import io.grpc.inprocess.{InProcessChannelBuilder, InProcessServerBuilder} import io.grpc.{ManagedChannel, Server, Status, StatusRuntimeException} import io.iohk.atala.prism.node.AtalaWithPostgresSpec -import io.iohk.atala.prism.credentials.CredentialBatchId -import io.iohk.atala.prism.crypto.{MerkleRoot, Sha256} +import io.iohk.atala.prism.crypto.Sha256 import io.iohk.atala.prism.identity.{PrismDid => DID} import io.iohk.atala.prism.node.logging.TraceId import io.iohk.atala.prism.node.logging.TraceId.IOWithTraceIdContext @@ -18,11 +17,11 @@ import io.iohk.atala.prism.node.models.{AtalaOperationId, DidSuffix, Ledger, Tra import io.iohk.atala.prism.node.errors.NodeError import io.iohk.atala.prism.node.grpc.ProtoCodecs import io.iohk.atala.prism.node.models._ -import io.iohk.atala.prism.node.models.nodeState.{CredentialBatchState, LedgerData} +import io.iohk.atala.prism.node.models.nodeState.LedgerData import io.iohk.atala.prism.node.operations._ import io.iohk.atala.prism.node.operations.path.{Path, ValueAtPath} import io.iohk.atala.prism.node.repositories.daos.{DIDDataDAO, PublicKeysDAO} -import io.iohk.atala.prism.node.repositories.{CredentialBatchesRepository, DIDDataRepository} +import io.iohk.atala.prism.node.repositories.DIDDataRepository import io.iohk.atala.prism.node.services.{BlockProcessingServiceSpec, NodeService, ObjectManagementService} import io.iohk.atala.prism.protos.models.TimestampInfo import io.iohk.atala.prism.protos.node_api._ @@ -51,8 +50,6 @@ class NodeServiceSpec private val logs = Logs.withContext[IO, IOWithTraceIdContext] private val objectManagementService = mock[ObjectManagementService[IOWithTraceIdContext]] - private val credentialBatchesRepository = - mock[CredentialBatchesRepository[IOWithTraceIdContext]] def fake[T](a: T): ReaderT[IO, TraceId, T] = ReaderT.apply[IO, TraceId, T](_ => IO.pure(a)) @@ -74,7 +71,6 @@ class NodeServiceSpec NodeService.unsafe( didDataRepository, objectManagementService, - credentialBatchesRepository, logs ) ), @@ -448,271 +444,6 @@ class NodeServiceSpec } } - "NodeService.getBatchState" should { - "fail when batchId is not valid" in { - val invalidBatchId = "invalid@_?" - val requestWithInvalidId = GetBatchStateRequest(batchId = invalidBatchId) - val expectedMessage = s"INVALID_ARGUMENT: Invalid batch id: $invalidBatchId" - - doReturn(fake[Instant](dummySyncTimestamp)) - .when(objectManagementService) - .getLastSyncedTimestamp - - val error = intercept[RuntimeException] { - service.getBatchState(requestWithInvalidId) - } - error.getMessage must be(expectedMessage) - } - - "return an error when the CredentialBatchesRepository fails" in { - val validBatchId = - CredentialBatchId.fromDigest(Sha256.compute("valid".getBytes())) - val requestWithValidId = - GetBatchStateRequest(batchId = validBatchId.getId) - - val errorMsg = "an unexpected error" - val repositoryError = - ReaderT.liftF( - IO.raiseError[Either[NodeError, Option[CredentialBatchState]]]( - new RuntimeException(errorMsg) - ) - ) - - doReturn(repositoryError) - .when(credentialBatchesRepository) - .getBatchState(validBatchId) - doReturn(fake[Instant](dummySyncTimestamp)) - .when(objectManagementService) - .getLastSyncedTimestamp - - val err = intercept[RuntimeException]( - service.getBatchState(requestWithValidId) - ) - err.getMessage.endsWith(errorMsg) must be(true) - } - - "return empty response when the CredentialBatchesRepository reports no results" in { - val validBatchId = - CredentialBatchId.fromDigest(Sha256.compute("valid".getBytes())) - val requestWithValidId = - GetBatchStateRequest(batchId = validBatchId.getId) - - val repositoryError = ReaderT.liftF( - IO.pure[Either[NodeError, Option[CredentialBatchState]]](Right(None)) - ) - - doReturn(repositoryError) - .when(credentialBatchesRepository) - .getBatchState(validBatchId) - doReturn(fake[Instant](dummySyncTimestamp)) - .when(objectManagementService) - .getLastSyncedTimestamp - - val response = service.getBatchState(requestWithValidId) - response.issuerDid must be("") - response.merkleRoot must be(empty) - response.publicationLedgerData must be(empty) - response.lastSyncedBlockTimestamp must be( - Some(dummySyncTimestamp.toProtoTimestamp) - ) - } - - "return batch state when CredentialBatchesRepository succeeds" in { - val validBatchId = - CredentialBatchId.fromDigest(Sha256.compute("valid".getBytes())) - val requestWithValidId = - GetBatchStateRequest(batchId = validBatchId.getId) - - val issuerDIDSuffix: DidSuffix = - DidSuffix(Sha256.compute("testDID".getBytes()).getHexValue) - val issuedOnLedgerData = dummyLedgerData - val merkleRoot = new MerkleRoot(Sha256.compute("content".getBytes())) - val credState = - CredentialBatchState( - merkleRoot = merkleRoot, - batchId = validBatchId, - issuerDIDSuffix = issuerDIDSuffix, - issuedOn = issuedOnLedgerData, - revokedOn = None, - lastOperation = Sha256.compute("lastOp".getBytes()) - ) - - val repositoryResponse = - ReaderT.liftF( - IO.pure[Either[NodeError, Option[CredentialBatchState]]]( - Right(Some(credState)) - ) - ) - - val ledgerDataProto = node_models - .LedgerData() - .withTransactionId(dummyLedgerData.transactionId.toString) - .withLedger(common_models.Ledger.IN_MEMORY) - .withTimestampInfo( - node_models - .TimestampInfo() - .withBlockTimestamp( - Instant - .ofEpochMilli( - issuedOnLedgerData.timestampInfo.getAtalaBlockTimestamp - ) - .toProtoTimestamp - ) - .withBlockSequenceNumber( - issuedOnLedgerData.timestampInfo.getAtalaBlockSequenceNumber - ) - .withOperationSequenceNumber( - issuedOnLedgerData.timestampInfo.getOperationSequenceNumber - ) - ) - - doReturn( - fake[Instant](dummySyncTimestamp) - ).when(objectManagementService).getLastSyncedTimestamp - doReturn(repositoryResponse) - .when(credentialBatchesRepository) - .getBatchState(validBatchId) - - val response = service.getBatchState(requestWithValidId) - response.issuerDid must be(issuerDIDSuffix.getValue) - response.merkleRoot.toByteArray.toVector must be( - merkleRoot.getHash.getValue - ) - response.publicationLedgerData must be(Some(ledgerDataProto)) - response.revocationLedgerData must be(empty) - response.lastSyncedBlockTimestamp must be( - Some(dummySyncTimestamp.toProtoTimestamp) - ) - } - } - - "NodeService.getCredentialRevocationTime" should { - "fail when batchId is not valid" in { - val invalidBatchId = "invalid@_?" - val validCredentialHash = Sha256.compute("random".getBytes()) - val requestWithInvalidId = - GetCredentialRevocationTimeRequest( - batchId = invalidBatchId, - credentialHash = ByteString.copyFrom(validCredentialHash.getValue) - ) - val expectedMessage = s"INVALID_ARGUMENT: Invalid batch id: $invalidBatchId" - - doReturn(fake[Instant](dummySyncTimestamp)) - .when(objectManagementService) - .getLastSyncedTimestamp - val error = intercept[RuntimeException] { - service.getCredentialRevocationTime(requestWithInvalidId) - } - error.getMessage must be(expectedMessage) - } - - "fail when credentialHash is not valid" in { - val validBatchId = - CredentialBatchId.fromDigest(Sha256.compute("random".getBytes())) - val requestWithInvalidCredentialHash = - GetCredentialRevocationTimeRequest( - batchId = validBatchId.getId, - credentialHash = ByteString.copyFrom(Array[Byte](0x4a)) - ) - - val expectedMessage = - "INVALID_ARGUMENT: The given byte array does not correspond to a SHA256 hash. It must have exactly 32 bytes: 4A" - - doReturn( - fake[Instant](dummySyncTimestamp) - ).when(objectManagementService).getLastSyncedTimestamp - - val error = intercept[RuntimeException] { - service.getCredentialRevocationTime(requestWithInvalidCredentialHash) - } - - error.getMessage must be(expectedMessage) - } - - "return empty timestamp when CredentialBatchesRepository succeeds returning None" in { - val validBatchId = - CredentialBatchId.fromDigest(Sha256.compute("valid".getBytes())) - val validCredentialHash = Sha256.compute("random".getBytes()) - val validRequest = GetCredentialRevocationTimeRequest( - batchId = validBatchId.getId, - credentialHash = ByteString.copyFrom(validCredentialHash.getValue) - ) - - val repositoryResponse = ReaderT.liftF( - IO.pure[Either[NodeError, Option[LedgerData]]](Right(None)) - ) - - doReturn( - fake[Instant](dummySyncTimestamp) - ).when(objectManagementService).getLastSyncedTimestamp - - doReturn(repositoryResponse) - .when(credentialBatchesRepository) - .getCredentialRevocationTime(validBatchId, validCredentialHash) - - val response = service.getCredentialRevocationTime(validRequest) - response.revocationLedgerData must be(empty) - response.lastSyncedBlockTimestamp must be( - Some(dummySyncTimestamp.toProtoTimestamp) - ) - } - - "return correct timestamp when CredentialBatchesRepository succeeds returning a time" in { - val validBatchId = - CredentialBatchId.fromDigest(Sha256.compute("valid".getBytes())) - val validCredentialHash = Sha256.compute("random".getBytes()) - val validRequest = GetCredentialRevocationTimeRequest( - batchId = validBatchId.getId, - credentialHash = ByteString.copyFrom(validCredentialHash.getValue) - ) - val revocationDate = new TimestampInfo(Instant.now().toEpochMilli, 1, 1) - val revocationLedgerData = LedgerData( - TransactionId - .from(Array.fill[Byte](TransactionId.config.size.toBytes.toInt)(1)) - .value, - Ledger.InMemory, - revocationDate - ) - - val repositoryResponse = - ReaderT.liftF( - IO.pure[Either[NodeError, Option[LedgerData]]]( - Right(Some(revocationLedgerData)) - ) - ) - - val timestampInfoProto = node_models - .TimestampInfo() - .withBlockTimestamp( - Instant - .ofEpochMilli(revocationDate.getAtalaBlockTimestamp) - .toProtoTimestamp - ) - .withBlockSequenceNumber(revocationDate.getAtalaBlockSequenceNumber) - .withOperationSequenceNumber(revocationDate.getOperationSequenceNumber) - - val revocationLedgerDataProto = node_models - .LedgerData() - .withTransactionId(revocationLedgerData.transactionId.toString) - .withLedger(common_models.Ledger.IN_MEMORY) - .withTimestampInfo(timestampInfoProto) - - doReturn( - fake[Instant](dummySyncTimestamp) - ).when(objectManagementService).getLastSyncedTimestamp - - doReturn(repositoryResponse) - .when(credentialBatchesRepository) - .getCredentialRevocationTime(validBatchId, validCredentialHash) - - val response = service.getCredentialRevocationTime(validRequest) - response.revocationLedgerData must be(Some(revocationLedgerDataProto)) - response.lastSyncedBlockTimestamp must be( - Some(dummySyncTimestamp.toProtoTimestamp) - ) - } - } - "NodeService.scheduleOperations" should { "fail when called with an empty sequence of operations" in { val error = intercept[StatusRuntimeException] { diff --git a/node/src/test/scala/io/iohk/atala/prism/node/nonce/ClientHelperSpec.scala b/node/src/test/scala/io/iohk/atala/prism/node/nonce/ClientHelperSpec.scala index b677ea54ef..ef9c14d05e 100644 --- a/node/src/test/scala/io/iohk/atala/prism/node/nonce/ClientHelperSpec.scala +++ b/node/src/test/scala/io/iohk/atala/prism/node/nonce/ClientHelperSpec.scala @@ -3,7 +3,7 @@ package io.iohk.atala.prism.node.nonce import io.iohk.atala.prism.node.DIDUtil import io.iohk.atala.prism.node.auth.utils.DIDUtils import io.iohk.atala.prism.crypto.EC.{INSTANCE => EC} -import io.iohk.atala.prism.protos.connector_api +import io.iohk.atala.prism.protos.common_models import org.scalatest.OptionValues._ import org.scalatest.concurrent.ScalaFutures._ import org.scalatest.matchers.must.Matchers._ @@ -21,7 +21,7 @@ class ClientHelperSpec extends AnyWordSpec { did, keyPair.getPrivateKey ) - val request = connector_api + val request = common_models .ConnectionsStatusRequest() .withConnectionTokens("a b c".split(" ").toList) val header = requestSigner(request) diff --git a/node/src/test/scala/io/iohk/atala/prism/node/repositories/CredentialBatchesRepositorySpec.scala b/node/src/test/scala/io/iohk/atala/prism/node/repositories/CredentialBatchesRepositorySpec.scala deleted file mode 100644 index d368883c3e..0000000000 --- a/node/src/test/scala/io/iohk/atala/prism/node/repositories/CredentialBatchesRepositorySpec.scala +++ /dev/null @@ -1,278 +0,0 @@ -package io.iohk.atala.prism.node.repositories - -import io.iohk.atala.prism.credentials.CredentialBatchId -import io.iohk.atala.prism.crypto.{MerkleRoot, Sha256, Sha256Digest} -import io.iohk.atala.prism.node.models.{DidSuffix, Ledger, TransactionId} -import io.iohk.atala.prism.node.models.nodeState.{CredentialBatchState, LedgerData} -import org.scalatest.OptionValues._ -import java.time.Instant -import cats.effect.IO -import cats.effect.unsafe.implicits.global -import doobie.util.transactor.Transactor -import io.iohk.atala.prism.protos.models.TimestampInfo -import io.iohk.atala.prism.node.{AtalaWithPostgresSpec, DataPreparation} -import io.iohk.atala.prism.node.models.DIDData -import tofu.logging.Logging - -class CredentialBatchesRepositorySpec extends AtalaWithPostgresSpec { - - import CredentialBatchesRepositorySpec._ - - private val logs = Logging.Make.plain[IO] - - private lazy implicit val repository: CredentialBatchesRepository[IO] = - CredentialBatchesRepository.unsafe(database, logs) - - private val dummyTimestampInfo = - new TimestampInfo(Instant.ofEpochMilli(0).toEpochMilli, 1, 0) - private val dummyLedgerData = LedgerData( - TransactionId - .from(Array.fill[Byte](TransactionId.config.size.toBytes.toInt)(0)) - .value, - Ledger.InMemory, - dummyTimestampInfo - ) - - "CredentialsRepository.getCredentialRevocationTime" should { - "return empty timestamp when there is no data associated to the credential and batch" in { - val randomBatchId = CredentialBatchId.random() - val randomCredentialHash = Sha256.compute("random".getBytes()) - - revocationTime(randomBatchId, randomCredentialHash) must be(None) - } - - "return proper timestamp when there is data associated to the credential and batch" in { - val randomBatchId = CredentialBatchId.random() - val randomCredentialHash1 = Sha256.compute("random".getBytes()) - val randomCredentialHash2 = Sha256.compute("another random".getBytes()) - val randomRevocationTime = - new TimestampInfo(Instant.now().toEpochMilli, 10, 100) - val randomRevocationLedgerData = LedgerData( - TransactionId - .from(Array.fill[Byte](TransactionId.config.size.toBytes.toInt)(0)) - .value, - Ledger.InMemory, - randomRevocationTime - ) - - val randomIssuerDIDSuffix = - DidSuffix(Sha256.compute("did".getBytes()).getHexValue) - val randomLastOperation = Sha256.compute("lastOperation".getBytes()) - val randomMerkleRoot = - new MerkleRoot(Sha256.compute("merkleRoot".getBytes())) - val randomIssuedOnTime = LedgerData( - TransactionId - .from(Array.fill[Byte](TransactionId.config.size.toBytes.toInt)(0)) - .value, - Ledger.InMemory, - dummyTimestampInfo - ) - - registerDID(randomIssuerDIDSuffix) - - DataPreparation.createBatch( - randomBatchId, - randomLastOperation, - randomIssuerDIDSuffix, - randomMerkleRoot, - randomIssuedOnTime - ) - - DataPreparation.revokeCredentials( - randomBatchId, - List(randomCredentialHash1, randomCredentialHash2), - randomRevocationLedgerData - ) - - revocationTime(randomBatchId, randomCredentialHash1) must be( - Some(randomRevocationLedgerData) - ) - revocationTime(randomBatchId, randomCredentialHash2) must be( - Some(randomRevocationLedgerData) - ) - } - } - - "CredentialsRepository.getBatchState" should { - "return empty when the batch is unknown" in { - val randomBatchId = CredentialBatchId.random() - - val response = repository - .getBatchState(randomBatchId) - .unsafeRunSync() - .toOption - .flatten - - response must be(empty) - } - - "return proper data when there is non-revoked batch data" in { - val randomBatchId = CredentialBatchId.random() - val randomIssuerDIDSuffix = - DidSuffix(Sha256.compute("did".getBytes()).getHexValue) - val randomLastOperation = Sha256.compute("lastOperation".getBytes()) - val randomMerkleRoot = - new MerkleRoot(Sha256.compute("merkleRoot".getBytes())) - val randomIssuedOnLedgerData = LedgerData( - TransactionId - .from(Array.fill[Byte](TransactionId.config.size.toBytes.toInt)(0)) - .value, - Ledger.InMemory, - dummyTimestampInfo - ) - - registerDID(randomIssuerDIDSuffix) - - DataPreparation.createBatch( - randomBatchId, - randomLastOperation, - randomIssuerDIDSuffix, - randomMerkleRoot, - randomIssuedOnLedgerData - ) - - val expectedState = CredentialBatchState( - batchId = randomBatchId, - issuerDIDSuffix = randomIssuerDIDSuffix, - merkleRoot = randomMerkleRoot, - issuedOn = randomIssuedOnLedgerData, - revokedOn = None, - lastOperation = randomLastOperation - ) - - repository - .getBatchState(randomBatchId) - .unsafeRunSync() - .toOption - .flatten must be(Some(expectedState)) - } - - "return proper data when the batch was revoked" in { - val randomBatchId = CredentialBatchId.random() - val randomIssuerDIDSuffix = - DidSuffix(Sha256.compute("did".getBytes()).getHexValue) - val randomLastOperation = Sha256.compute("lastOperation".getBytes()) - val randomMerkleRoot = - new MerkleRoot(Sha256.compute("merkleRoot".getBytes())) - val randomIssuedOnLedgerData = dummyLedgerData - - val randomRevocationTime = - new TimestampInfo(Instant.now().toEpochMilli, 10, 100) - val randomRevocationLedgerData = LedgerData( - TransactionId - .from(Array.fill[Byte](TransactionId.config.size.toBytes.toInt)(0)) - .value, - Ledger.InMemory, - randomRevocationTime - ) - - registerDID(randomIssuerDIDSuffix) - - DataPreparation.createBatch( - randomBatchId, - randomLastOperation, - randomIssuerDIDSuffix, - randomMerkleRoot, - randomIssuedOnLedgerData - ) - - DataPreparation.revokeCredentialBatch( - randomBatchId, - randomRevocationLedgerData - ) - - val expectedState = CredentialBatchState( - batchId = randomBatchId, - issuerDIDSuffix = randomIssuerDIDSuffix, - merkleRoot = randomMerkleRoot, - issuedOn = randomIssuedOnLedgerData, - revokedOn = Some(randomRevocationLedgerData), - lastOperation = randomLastOperation - ) - - repository - .getBatchState(randomBatchId) - .unsafeRunSync() - .toOption - .flatten must be(Some(expectedState)) - } - - "revocation of previously revoked credential doesn't throw any errors" in { - val randomBatchId = CredentialBatchId.random() - val randomIssuerDIDSuffix = DidSuffix(Sha256.compute("did".getBytes()).getHexValue) - val randomLastOperation = Sha256.compute("lastOperation".getBytes()) - val randomMerkleRoot = new MerkleRoot(Sha256.compute("merkleRoot".getBytes())) - val randomCredentialId1 = Sha256.compute("randomCredential1".getBytes()) - val randomCredentialId2 = Sha256.compute("randomCredential2".getBytes()) - val randomCredentialId3 = Sha256.compute("randomCredential3".getBytes()) - val randomIssuedOnLedgerData = dummyLedgerData - - val randomRevocationTime = - new TimestampInfo(Instant.now().toEpochMilli, 10, 100) - val randomRevocationLedgerData = LedgerData( - TransactionId - .from(Array.fill[Byte](TransactionId.config.size.toBytes.toInt)(0)) - .value, - Ledger.InMemory, - randomRevocationTime - ) - - registerDID(randomIssuerDIDSuffix) - - DataPreparation.createBatch( - randomBatchId, - randomLastOperation, - randomIssuerDIDSuffix, - randomMerkleRoot, - randomIssuedOnLedgerData - ) - - DataPreparation.revokeCredentials( - randomBatchId, - List(randomCredentialId1, randomCredentialId2), - randomRevocationLedgerData - ) - - DataPreparation.revokeCredentials( - randomBatchId, - List(randomCredentialId2, randomCredentialId3), - randomRevocationLedgerData - ) - } - } -} - -object CredentialBatchesRepositorySpec { - private def registerDID( - didSuffix: DidSuffix - )(implicit database: Transactor[IO]): Unit = { - val lastOperation = - Sha256.compute("a random did create operation".getBytes()) - val dummyTimestampInfo = - new TimestampInfo(Instant.ofEpochMilli(0).toEpochMilli, 1, 0) - val dummyLedgerData = LedgerData( - TransactionId - .from(Array.fill[Byte](TransactionId.config.size.toBytes.toInt)(0)) - .value, - Ledger.InMemory, - dummyTimestampInfo - ) - DataPreparation.createDID( - DIDData(didSuffix, keys = Nil, Nil, Nil, lastOperation), - dummyLedgerData - ) - } - - private def revocationTime( - batchId: CredentialBatchId, - credentialHash: Sha256Digest - )(implicit - repository: CredentialBatchesRepository[IO] - ): Option[LedgerData] = { - repository - .getCredentialRevocationTime(batchId, credentialHash) - .unsafeRunSync() - .toOption - .flatten - } -} diff --git a/node/src/test/scala/io/iohk/atala/prism/node/repositories/package.scala b/node/src/test/scala/io/iohk/atala/prism/node/repositories/package.scala index fb8a58cb36..25dd9fe69c 100644 --- a/node/src/test/scala/io/iohk/atala/prism/node/repositories/package.scala +++ b/node/src/test/scala/io/iohk/atala/prism/node/repositories/package.scala @@ -2,7 +2,6 @@ package io.iohk.atala.prism.node import io.iohk.atala.prism.crypto.Sha256Digest import io.iohk.atala.prism.node.models.DidSuffix -import io.iohk.atala.prism.node.models.CredentialId package object repositories { @@ -13,8 +12,4 @@ package object repositories { digest.getHexValue ) - def credentialIdFromDigest(digest: Sha256Digest): CredentialId = CredentialId( - digest.getHexValue - ) - } diff --git a/node/src/test/scala/io/iohk/atala/prism/node/utils/NodeClientUtils.scala b/node/src/test/scala/io/iohk/atala/prism/node/utils/NodeClientUtils.scala deleted file mode 100644 index 8c5ce3048b..0000000000 --- a/node/src/test/scala/io/iohk/atala/prism/node/utils/NodeClientUtils.scala +++ /dev/null @@ -1,52 +0,0 @@ -package io.iohk.atala.prism.node.utils - -import com.google.protobuf.ByteString -import io.iohk.atala.prism.credentials.CredentialBatchId -import io.iohk.atala.prism.crypto.{MerkleRoot, Sha256Digest} -import io.iohk.atala.prism.protos.node_models -import io.iohk.atala.prism.identity.{PrismDid => DID} - -object NodeClientUtils { - - def issueBatchOperation( - issuerDID: DID, - merkleRoot: MerkleRoot - ): node_models.AtalaOperation = { - node_models - .AtalaOperation( - operation = node_models.AtalaOperation.Operation.IssueCredentialBatch( - value = node_models - .IssueCredentialBatchOperation( - credentialBatchData = Some( - node_models.CredentialBatchData( - issuerDid = issuerDID.getSuffix, - merkleRoot = toByteString(merkleRoot.getHash) - ) - ) - ) - ) - ) - } - - def revokeCredentialsOperation( - previousOperationHash: Sha256Digest, - batchId: CredentialBatchId, - credentialsToRevoke: Seq[Sha256Digest] = Nil - ): node_models.AtalaOperation = { - node_models - .AtalaOperation( - operation = node_models.AtalaOperation.Operation.RevokeCredentials( - value = node_models - .RevokeCredentialsOperation( - previousOperationHash = toByteString(previousOperationHash), - credentialBatchId = batchId.getId, - credentialsToRevoke = credentialsToRevoke.map(toByteString) - ) - ) - ) - } - - def toByteString(hash: Sha256Digest): ByteString = - ByteString.copyFrom(hash.getValue) - -}