Skip to content

Commit

Permalink
Merge pull request #240
Browse files Browse the repository at this point in the history
feat-performance
  • Loading branch information
waltkb authored Mar 20, 2023
2 parents 76f2ca6 + 6a21bb8 commit 74e98ad
Show file tree
Hide file tree
Showing 52 changed files with 1,295 additions and 125 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ fun main() {
val issuerDid = DidService.create(DidMethod.ebsi)
val holderDid = DidService.create(DidMethod.key)

// Issue VC in JSON-LD and JWT format (for show-casing both formats)
// Issue VC with LD_PROOF and JWT format (for show-casing both formats)
val vcJson = Signatory.getService().issue(
templateId = "VerifiableId",
templateIdOrFilename = "VerifiableId",
config = ProofConfig(issuerDid = issuerDid, subjectDid = holderDid, proofType = ProofType.LD_PROOF)
)
val vcJwt = Signatory.getService().issue(
templateId = "Europass",
templateIdOrFilename = "Europass",
config = ProofConfig(issuerDid = issuerDid, subjectDid = holderDid, proofType = ProofType.JWT)
)

Expand Down
17 changes: 9 additions & 8 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ dependencies {
implementation("com.github.multiformats:java-multibase:v1.1.0")
implementation("com.microsoft.azure:azure-keyvault:1.2.6")
implementation("com.microsoft.azure:azure-client-authentication:1.7.14")
implementation("com.nimbusds:nimbus-jose-jwt:9.30.1")
implementation("com.nimbusds:oauth2-oidc-sdk:10.5.1")
implementation("com.nimbusds:nimbus-jose-jwt:9.30.2")
implementation("com.nimbusds:oauth2-oidc-sdk:10.7")

implementation("org.bouncycastle:bcprov-jdk15to18:1.72")
implementation("org.bouncycastle:bcpkix-jdk15to18:1.72")
Expand All @@ -52,22 +52,23 @@ dependencies {
implementation("com.beust:klaxon:5.6")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.0")
implementation("com.jayway.jsonpath:json-path:2.7.0")
implementation("com.networknt:json-schema-validator:1.0.77")
implementation("com.networknt:json-schema-validator:1.0.78")
implementation("net.pwall.json:json-kotlin-schema:0.39")

implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1")

// DB
implementation("org.xerial:sqlite-jdbc:3.39.4.1")
implementation("org.xerial:sqlite-jdbc:3.40.1.0")
implementation("com.zaxxer:HikariCP:5.0.1")

// CLI
implementation("com.github.ajalt.clikt:clikt-jvm:3.5.0")
implementation("com.github.ajalt.clikt:clikt-jvm:3.5.2")
implementation("com.github.ajalt.clikt:clikt:3.5.0")

// Misc
implementation("commons-io:commons-io:2.11.0")
implementation("io.minio:minio:8.4.6")
implementation("com.github.ben-manes.caffeine:caffeine:3.1.5")

// HTTP
implementation("io.ktor:ktor-client-jackson-jvm:2.2.4")
Expand Down Expand Up @@ -107,9 +108,9 @@ dependencies {
//testImplementation(kotlin("test-junit"))
testImplementation("io.mockk:mockk:1.13.2")

testImplementation("io.kotest:kotest-runner-junit5:5.5.4")
testImplementation("io.kotest:kotest-assertions-core:5.5.4")
testImplementation("io.kotest:kotest-assertions-json:5.5.4")
testImplementation("io.kotest:kotest-runner-junit5:5.5.5")
testImplementation("io.kotest:kotest-assertions-core:5.5.5")
testImplementation("io.kotest:kotest-assertions-json:5.5.5")

}

Expand Down
12 changes: 0 additions & 12 deletions src/main/kotlin/id/walt/DidCheqdTest.kt

This file was deleted.

43 changes: 43 additions & 0 deletions src/main/kotlin/id/walt/PerformanceRun.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package id.walt

import id.walt.credentials.w3c.VerifiableCredential
import id.walt.credentials.w3c.W3CIssuer
import id.walt.model.DidMethod
import id.walt.servicematrix.ServiceMatrix
import id.walt.services.did.DidService
import id.walt.signatory.ProofConfig
import id.walt.signatory.ProofType
import id.walt.signatory.Signatory
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import java.io.File
import kotlin.system.measureTimeMillis

val RESOURCES_PATH: String = "src/test/resources"

fun getTemplate(name: String): VerifiableCredential =
VerifiableCredential.fromString(File("$RESOURCES_PATH/verifiable-credentials/vc-template-default.json").readText(Charsets.UTF_8))

suspend fun main() {
ServiceMatrix("service-matrix.properties")
val issuerWebDid: String = DidService.create(DidMethod.web)

//val credentialService: JwtCredentialService = JwtCredentialService.getService()
val signatory = Signatory.getService()
val template = getTemplate("ebsi-attestation")

template.issuer = W3CIssuer(issuerWebDid)
template.credentialSubject!!.id = issuerWebDid // self signed

println("" + measureTimeMillis {
val jobs = ArrayList<Job>()
repeat(500000) {
jobs.add(GlobalScope.launch {
signatory.issue("VerifiableId", ProofConfig(issuerDid = issuerWebDid, proofType = ProofType.JWT))
})
}

jobs.forEach { it.join() }
} + " ms overall")
}
29 changes: 13 additions & 16 deletions src/main/kotlin/id/walt/credentials/w3c/JsonConverter.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package id.walt.credentials.w3c

import kotlinx.serialization.json.*
import kotlin.reflect.jvm.jvmName

object JsonConverter {

Expand All @@ -9,34 +10,30 @@ object JsonConverter {
is Number -> JsonPrimitive(value)
is String -> JsonPrimitive(value)
is Boolean -> JsonPrimitive(value)
is List<*> -> buildJsonArray {
value.forEach { add(toJsonElement(it)) }
}
null -> JsonNull

is Map<*, *> -> buildJsonObject {
value.keys.forEach { key ->
put(key.toString(), toJsonElement(value[key]))
}
}
is List<*> -> buildJsonArray { value.forEach { add(toJsonElement(it)) } }
is Map<*, *> -> buildJsonObject { value.keys.forEach { put(it.toString(), toJsonElement(value[it])) } }

is JsonElement -> value
null -> JsonNull
else -> throw Exception("Json values can only be Number, String, List or Map")

//else -> JsonNull
else -> throw Exception("Json values can only be Number, String, Boolean, Null, List or Map, not \"${value::class.jvmName}\": toString = $value")
}
}

fun fromJsonElement(element: JsonElement): Any? {
return when (element) {
is JsonPrimitive -> if (element.isString) {
element.contentOrNull
} else {
element.booleanOrNull ?: element.longOrNull ?: element.doubleOrNull
is JsonPrimitive -> when {
element.isString -> element.contentOrNull
else -> element.booleanOrNull ?: element.longOrNull ?: element.doubleOrNull
}

is JsonArray -> element.map { fromJsonElement(it) }.toList()
is JsonObject -> element.keys.associateWith {
fromJsonElement(element[it] ?: JsonNull)
}
fromJsonElement(element[it] ?: JsonNull)
}
else -> throw IllegalArgumentException("Invalid JSON element \"${element::class.jvmName}\": $element")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ open class VerifiableCredential internal constructor(
}
}

fun toJson() = toJsonObject().toString()
fun toJson(): String {
println("To JSON Object: $type $id")
return toJsonObject().toString()
}

fun toJsonElement() = jwt?.let { JsonPrimitive(it) } ?: toJsonObject()
override fun toString(): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ open class W3CCredentialSubject(var id: String? = null, override val properties:
id?.let { put("id", it) }
properties.let { props ->
props.keys.forEach { key ->
println("Properties key: $key => ${props[key]}")
put(key, JsonConverter.toJsonElement(props[key]))
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package id.walt.credentials.w3c.templates

import id.walt.common.SingleVCObject
import id.walt.credentials.w3c.VerifiableCredential

data class VcTemplate(
val name: String,
val template: VerifiableCredential? = null,
@SingleVCObject val template: VerifiableCredential? = null,
val mutable: Boolean
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package id.walt.credentials.w3c.templates

import com.github.benmanes.caffeine.cache.Caffeine
import id.walt.credentials.w3c.VerifiableCredential
import id.walt.credentials.w3c.W3CIssuer
import id.walt.credentials.w3c.toVerifiableCredential
Expand All @@ -9,6 +10,7 @@ import mu.KotlinLogging
import java.io.File
import java.nio.file.FileSystems
import java.nio.file.Files
import java.time.Duration
import kotlin.io.path.isRegularFile
import kotlin.io.path.nameWithoutExtension

Expand All @@ -25,19 +27,60 @@ object VcTemplateManager {
return VcTemplate(name, template, true)
}

val templateCache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(Duration.ofMinutes(10))
.build<String, VcTemplate>()

private fun String?.toVcTemplate(name: String, populateTemplate: Boolean, isMutable: Boolean) =
this?.let { VcTemplate(name, if (populateTemplate && it.isNotBlank()) it.toVerifiableCredential() else null, isMutable) }

fun loadTemplateFromHkvStore(name: String, loadTemplate: Boolean) =
ContextManager.hkvStore.getAsString(HKVKey(SAVED_VC_TEMPLATES_KEY, name))
.toVcTemplate(name, loadTemplate, true)

fun loadTemplateFromResources(name: String, populateTemplate: Boolean) =
object {}.javaClass.getResource("/vc-templates/$name.json")?.readText()
.toVcTemplate(name, populateTemplate, false)

fun loadTemplateFromFile(name: String, populateTemplate: Boolean, runtimeTemplateFolder: String) =
File("$runtimeTemplateFolder/$name.json").let {
if (it.exists()) it.readText() else null
}.toVcTemplate(name, populateTemplate, false)

fun loadTemplate(name: String, populateTemplate: Boolean, runtimeTemplateFolder: String) = loadTemplateFromHkvStore(name, populateTemplate)
?: loadTemplateFromResources(name, populateTemplate)
?: loadTemplateFromFile(name, populateTemplate, runtimeTemplateFolder)
?: throw IllegalArgumentException("No template found with name: $name")

fun retrieveOrLoadCachedTemplate(
name: String,
populateTemplate: Boolean = true,
runtimeTemplateFolder: String = "/vc-templates-runtime"
) = if(populateTemplate) {
// only add to cache, if template is populated
templateCache.get(name) {
loadTemplate(name, true, runtimeTemplateFolder)
}
} else {
// try to get from cache or load unpopulated template
(templateCache.getIfPresent(name) ?: loadTemplate(name, false, runtimeTemplateFolder)).let {
// reset populated template, in case it was loaded from cache
VcTemplate(it.name, null, it.mutable)
}
}

fun getTemplate(
name: String,
loadTemplate: Boolean = true,
populateTemplate: Boolean = true,
runtimeTemplateFolder: String = "/vc-templates-runtime"
): VcTemplate {
return ContextManager.hkvStore.getAsString(HKVKey(SAVED_VC_TEMPLATES_KEY, name))
?.let { VcTemplate(name, if (loadTemplate) it.toVerifiableCredential() else null, true) }
?: object {}.javaClass.getResource("/vc-templates/$name.json")?.readText()
?.let { VcTemplate(name, if (loadTemplate) it.toVerifiableCredential() else null, false) }
?: File("$runtimeTemplateFolder/$name.json").let {
if (it.exists()) it.readText() else null
}?.let { VcTemplate(name, if (loadTemplate) it.toVerifiableCredential() else null, false) }
?: throw IllegalArgumentException("No template found, with name $name")
val cachedTemplate = retrieveOrLoadCachedTemplate(name, populateTemplate, runtimeTemplateFolder)

return if (cachedTemplate.template == null && populateTemplate) {
templateCache.invalidate(name)
retrieveOrLoadCachedTemplate(name, true, runtimeTemplateFolder)
} else cachedTemplate
}

private val resourceWalk = lazy {
Expand Down
19 changes: 15 additions & 4 deletions src/main/kotlin/id/walt/services/did/DidService.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package id.walt.services.did

import com.beust.klaxon.Klaxon
import com.github.benmanes.caffeine.cache.Caffeine
import com.nimbusds.jose.jwk.Curve
import com.nimbusds.jose.jwk.JWK
import com.nimbusds.jose.util.Base64URL
Expand Down Expand Up @@ -39,6 +40,7 @@ import java.nio.charset.StandardCharsets
import java.security.KeyFactory
import java.security.KeyPair
import java.security.spec.X509EncodedKeySpec
import java.time.Duration
import java.util.*


Expand Down Expand Up @@ -116,10 +118,18 @@ object DidService {
}
}

private val didCache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(Duration.ofMinutes(10))
.build<DidUrl, Did>()

fun load(did: String): Did = load(DidUrl.from(did))
fun load(didUrl: DidUrl): Did = Did.decode(
loadDid(didUrl.did) ?: throw IllegalArgumentException("DID $didUrl not found.")
) ?: throw IllegalArgumentException("DID $didUrl not found.")
fun load(didUrl: DidUrl): Did =
didCache.get(didUrl) {
Did.decode(
loadDid(didUrl.did) ?: throw IllegalArgumentException("DID $didUrl could not be loaded/found.")
) ?: throw IllegalArgumentException("DID $didUrl could not be decoded.")
}

fun resolveDidEbsiRaw(did: String): String = runBlocking {
log.debug { "Resolving DID $did" }
Expand Down Expand Up @@ -192,7 +202,7 @@ object DidService {
}

fun loadDidEbsi(did: String): DidEbsi = loadDidEbsi(DidUrl.from(did))
fun loadDidEbsi(didUrl: DidUrl): DidEbsi = Did.decode(loadDid(didUrl.did)!!)!! as DidEbsi
fun loadDidEbsi(didUrl: DidUrl): DidEbsi = load(didUrl.did) as DidEbsi

fun updateDidEbsi(did: DidEbsi) = storeDid(did.id, did.encode())

Expand Down Expand Up @@ -648,6 +658,7 @@ object DidService {

fun deleteDid(didUrl: String) {
loadOrResolveAnyDid(didUrl)?.let { did ->
didCache.invalidate(DidUrl.from(didUrl))
ContextManager.hkvStore.delete(HKVKey("did", "created", didUrl), recursive = true)
did.verificationMethod?.forEach {
ContextManager.keyStore.delete(it.id)
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/id/walt/services/jwt/WaltIdJwtService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,17 @@ open class WaltIdJwtService : JwtService() {

private fun createSignedJwt(jwsAlgorithm: JWSAlgorithm, keyAlias: String, claimsSet: JWTClaimsSet, includeJwk: JWK?) =
SignedJWT(
/* header = */ JWSHeader
JWSHeader
.Builder(jwsAlgorithm)
.keyID(keyAlias)
.type(JOSEObjectType.JWT)
.apply {
includeJwk?.let { jwk(it) }
}.build(),
/* claimsSet = */ claimsSet
).also {
claimsSet
)/*.also {
// log.debug { "Created signable JWT object: $it." }
}
}*/


override fun sign(
Expand Down
Loading

0 comments on commit 74e98ad

Please sign in to comment.