Skip to content

Commit

Permalink
allow for attaching non-existant record specs to existing contract spec
Browse files Browse the repository at this point in the history
* if bootstrapping with the batch size set to 1 (or anything less than a contract's number of records + 1) could lead to a bad bootstrap if the process is interrupted between when the contract spec is created on chain and when the record specifications were created, as a subsequent run of the same code would produce the same hash, resulting in the record spec creation being skipped and subsequent operations using a session of that contract spec could fail due to missing record specs
* The bootstrapping process is now smarter and checks for contract spec existence, creates it if it doesn't exist, but also checks for record spec existence and will create any non-existent record specs even if the parent contract spec does exist
  • Loading branch information
celloman committed Aug 2, 2022
1 parent f082935 commit 4dfdb7d
Showing 1 changed file with 39 additions and 26 deletions.
65 changes: 39 additions & 26 deletions src/main/kotlin/io/provenance/p8e/plugin/Bootstrapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -258,34 +258,42 @@ internal class Bootstrapper(
}

// write brand new contract specifications
contractSpecifications.filter { spec ->
contractSpecifications.map { spec ->
val existingSpec = client.contractSpecification(
ContractSpecificationRequest.newBuilder()
.setSpecificationId(spec.uuid().toString())
.setIncludeRecordSpecs(true)
.build()
)
// at this time we only post contract specifications when it doesn't already exist
// but we can still write record specifications for them
val specDoesNotExist = existingSpec.contractSpecification.specification.className.isEmpty()

// at this time we only post scope specifications when it doesn't already exist
existingSpec.contractSpecification.specification.className.isEmpty()
}.map { spec ->
val recordSpecifications = mutableListOf<RecordSpecification>()
val id = MetadataAddress.forContractSpecification(spec.uuid()).bytes

val contractSpecification = ContractSpecification.newBuilder()
.setSpecificationId(ByteString.copyFrom(id))
.setDescription(
Description.newBuilder()
.setDescription(spec.definition.resourceLocation.classname)
.setName(spec.definition.name)
.build()
)
.addOwnerAddresses(pbAddress)
.addAllPartiesInvolvedValue(spec.partiesInvolvedValueList)
.setHash(spec.hashString())
.setClassName(spec.definition.resourceLocation.classname)
.build()
val contractSpecification = if (specDoesNotExist) {
ContractSpecification.newBuilder()
.setSpecificationId(ByteString.copyFrom(id))
.setDescription(
Description.newBuilder()
.setDescription(spec.definition.resourceLocation.classname)
.setName(spec.definition.name)
.build()
)
.addOwnerAddresses(pbAddress)
.addAllPartiesInvolvedValue(spec.partiesInvolvedValueList)
.setHash(spec.hashString())
.setClassName(spec.definition.resourceLocation.classname)
.build()
} else null

val existingRecordSpecs = existingSpec.recordSpecificationsList.map { it.specification.name }.toHashSet()

spec.functionSpecsList.forEach { functionSpec ->
spec.functionSpecsList.filterNot { functionSpec ->
// filter out specifications that already exist
existingRecordSpecs.contains(functionSpec.outputSpec.spec.name)
}.forEach { functionSpec ->
val id =
MetadataAddress.forRecordSpecification(spec.uuid(), functionSpec.outputSpec.spec.name).bytes

Expand All @@ -307,19 +315,24 @@ internal class Bootstrapper(
recordSpecifications.add(recordSpec)
}

Pair(contractSpecification, recordSpecifications)
Pair(contractSpecification, recordSpecifications.toList())
}.also { specs ->
project.logger.info("Adding ${specs.size} contract specification(s) to batch for provenance")
val (numContractSpecsToAdd, numRecordSpecsToAdd) = specs.fold(0 to 0) { acc, curr ->
acc.first + (curr.first?.let { 1 } ?: 0) to acc.second + curr.second.size
}
project.logger.info("Adding $numContractSpecsToAdd contract specification(s) and $numRecordSpecsToAdd record specification(s) to batch for provenance")

val messages = mutableListOf<Message>()

specs.map { (contractSpecification, recordSpecifications) ->
messages.add(
MsgWriteContractSpecificationRequest.newBuilder()
.addSigners(pbAddress)
.setSpecification(contractSpecification)
.build()
)
if (contractSpecification != null) {
messages.add(
MsgWriteContractSpecificationRequest.newBuilder()
.addSigners(pbAddress)
.setSpecification(contractSpecification)
.build()
)
}

messages.addAll(recordSpecifications.map { spec ->
val contractSpecAddress = MetadataAddress.fromBytes(spec.specificationId.toByteArray())
Expand Down

0 comments on commit 4dfdb7d

Please sign in to comment.