• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

input-output-hk / atala-prism-building-blocks / 6174691072

13 Sep 2023 03:35PM UTC coverage: 29.221% (+0.04%) from 29.185%
6174691072

Pull #715

antonbaliasnikov
docs: update readme with latest release 1.12.0

Signed-off-by: Anton Baliasnikov <anton.baliasnikov@iohk.io>
Pull Request #715: docs: update readme with latest release 1.12.0

3470 of 11875 relevant lines covered (29.22%)

0.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

28.33
/castor/lib/core/src/main/scala/io/iohk/atala/castor/core/service/DIDService.scala
1
package io.iohk.atala.castor.core.service
2

3
import io.iohk.atala.castor.core.model.ProtoModelHelper
4
import io.iohk.atala.castor.core.model.did.{
5
  CanonicalPrismDID,
6
  DIDData,
7
  DIDMetadata,
8
  InternalPublicKey,
9
  LongFormPrismDID,
10
  PrismDID,
11
  PublicKey,
12
  ScheduleDIDOperationOutcome,
13
  ScheduledDIDOperationDetail,
14
  SignedPrismDIDOperation
15
}
16
import io.iohk.atala.castor.core.model.error.OperationValidationError
17
import io.iohk.atala.castor.core.model.error.{DIDOperationError, DIDResolutionError}
18
import io.iohk.atala.castor.core.util.DIDOperationValidator
19
import io.iohk.atala.prism.protos.node_api.NodeServiceGrpc.NodeService
20
import io.iohk.atala.prism.protos.node_models.OperationOutput.OperationMaybe
21
import io.iohk.atala.prism.protos.{node_api, node_models}
22
import io.iohk.atala.shared.models.HexString
23
import java.time.Instant
24
import scala.collection.immutable.ArraySeq
25
import zio.*
26

27
trait DIDService {
28
  def scheduleOperation(operation: SignedPrismDIDOperation): IO[DIDOperationError, ScheduleDIDOperationOutcome]
29
  def getScheduledDIDOperationDetail(
30
      operationId: Array[Byte]
31
  ): IO[DIDOperationError, Option[ScheduledDIDOperationDetail]]
32
  def resolveDID(did: PrismDID): IO[DIDResolutionError, Option[(DIDMetadata, DIDData)]]
33
}
34

35
object DIDServiceImpl {
36
  val layer: URLayer[NodeService & DIDOperationValidator, DIDService] =
1✔
37
    ZLayer.fromFunction(DIDServiceImpl(_, _))
38
}
39

40
private class DIDServiceImpl(didOpValidator: DIDOperationValidator, nodeClient: NodeService)
41
    extends DIDService,
42
      ProtoModelHelper {
43

×
44
  override def scheduleOperation(
45
      signedOperation: SignedPrismDIDOperation
46
  ): IO[DIDOperationError, ScheduleDIDOperationOutcome] = {
×
47
    val operationRequest = node_api.ScheduleOperationsRequest(
×
48
      signedOperations = Seq(signedOperation.toProto)
49
    )
×
50
    for {
×
51
      _ <- ZIO
×
52
        .fromEither(didOpValidator.validate(signedOperation.operation))
53
        .mapError(DIDOperationError.ValidationError.apply)
×
54
      operationOutput <- ZIO
×
55
        .fromFuture(_ => nodeClient.scheduleOperations(operationRequest))
×
56
        .mapBoth(DIDOperationError.DLTProxyError.apply, _.outputs.toList)
57
        .map {
×
58
          case output :: Nil => Right(output)
×
59
          case _ => Left(DIDOperationError.UnexpectedDLTResult("operation result is expected to have exactly 1 output"))
60
        }
61
        .absolve
×
62
      operationId <- ZIO.fromEither {
63
        operationOutput.operationMaybe match {
×
64
          case OperationMaybe.OperationId(id) => Right(id.toByteArray)
×
65
          case OperationMaybe.Empty =>
×
66
            Left(DIDOperationError.UnexpectedDLTResult("operation result does not contain operation detail"))
×
67
          case OperationMaybe.Error(e) =>
×
68
            Left(DIDOperationError.UnexpectedDLTResult(s"operation result was not successful: $e"))
69
        }
70
      }
71
    } yield ScheduleDIDOperationOutcome(
×
72
      did = signedOperation.operation.did,
73
      operation = signedOperation.operation,
×
74
      operationId = ArraySeq.from(operationId)
75
    )
76
  }
77

×
78
  override def getScheduledDIDOperationDetail(
79
      operationId: Array[Byte]
80
  ): IO[DIDOperationError, Option[ScheduledDIDOperationDetail]] = {
×
81
    for {
×
82
      result <- ZIO
×
83
        .fromFuture(_ => nodeClient.getOperationInfo(node_api.GetOperationInfoRequest(operationId.toProto)))
84
        .mapError(DIDOperationError.DLTProxyError.apply)
×
85
      detail <- ZIO
×
86
        .fromEither(result.toDomain)
87
        .mapError(DIDOperationError.UnexpectedDLTResult.apply)
88
    } yield detail
89
  }
90

1✔
91
  override def resolveDID(did: PrismDID): IO[DIDResolutionError, Option[(DIDMetadata, DIDData)]] = {
1✔
92
    val canonicalDID = did.asCanonical
1✔
93
    val request = node_api.GetDidDocumentRequest(did = canonicalDID.toString)
1✔
94
    for {
95
      unpublishedDidData <- did match {
×
96
        case _: CanonicalPrismDID => ZIO.none
×
97
        case d: LongFormPrismDID  => extractUnpublishedDIDData(d).asSome
98
      }
×
99
      result <- ZIO
×
100
        .fromFuture(_ => nodeClient.getDidDocument(request))
101
        .mapError(DIDResolutionError.DLTProxyError.apply)
1✔
102
      publishedDidData <- ZIO
103
        .fromOption(result.document)
104
        .foldZIO(
105
          _ => ZIO.none,
106
          didDataProto =>
×
107
            didDataProto.filterRevokedKeysAndServices
×
108
              .flatMap(didData => ZIO.fromEither(didData.toDomain))
109
              .mapError(DIDResolutionError.UnexpectedDLTResult.apply)
110
              .map { didData =>
×
111
                val (created, updated) = getMinMaxLedgerTime(didDataProto)
112
                val metadata = DIDMetadata(
×
113
                  lastOperationHash = ArraySeq.from(result.lastUpdateOperation.toByteArray),
114
                  canonicalId =
×
115
                    unpublishedDidData.map(_ => canonicalDID), // only shows canonicalId if long-form and published
×
116
                  deactivated = didData.internalKeys.isEmpty && didData.publicKeys.isEmpty,
117
                  created = created,
118
                  updated = updated
119
                )
×
120
                metadata -> didData
121
              }
122
              .asSome
123
        )
1✔
124
    } yield publishedDidData.orElse(unpublishedDidData)
125
  }
126

127
  // FIXME: This doesn't play well detecting timestamp context and revoked service due to
128
  // the response from Node missing the ledger data for those items.
1✔
129
  private def getMinMaxLedgerTime(didData: node_models.DIDData): (Option[Instant], Option[Instant]) = {
×
130
    val ledgerTimes = didData.publicKeys.flatMap(_.addedOn) ++
×
131
      didData.publicKeys.flatMap(_.revokedOn) ++
×
132
      didData.services.flatMap(_.addedOn) ++
1✔
133
      didData.services.flatMap(_.deletedOn)
1✔
134
    val instants = ledgerTimes.flatMap(_.toInstant)
1✔
135
    (instants.minOption, instants.maxOption)
136
  }
137

1✔
138
  private def extractUnpublishedDIDData(did: LongFormPrismDID): IO[DIDResolutionError, (DIDMetadata, DIDData)] = {
×
139
    ZIO
×
140
      .fromEither(did.createOperation)
141
      .mapError(e => DIDResolutionError.ValidationError(OperationValidationError.InvalidArgument(e)))
142
      .flatMap { op =>
143
        // unpublished CreateOperation (if exists) must be validated before the resolution
×
144
        ZIO
×
145
          .fromEither(didOpValidator.validate(op))
146
          .mapError(DIDResolutionError.ValidationError.apply)
147
          .as(op)
148
      }
149
      .map { op =>
150
        val metadata =
151
          DIDMetadata(
1✔
152
            lastOperationHash = ArraySeq.from(did.stateHash.toByteArray),
153
            canonicalId = None, // unpublished DID must not contain canonicalId
154
            deactivated = false, // unpublished DID cannot be deactivated
155
            created = None, // unpublished DID cannot have timestamp
156
            updated = None // unpublished DID cannot have timestamp
157
          )
158
        val didData = DIDData(
1✔
159
          id = did.asCanonical,
1✔
160
          publicKeys = op.publicKeys.collect { case pk: PublicKey => pk },
161
          services = op.services,
1✔
162
          internalKeys = op.publicKeys.collect { case pk: InternalPublicKey => pk },
163
          context = op.context
164
        )
1✔
165
        metadata -> didData
166
      }
167
  }
168

169
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc