From f69273027c9f39c1dc79da9065e55f5e3d22b0a5 Mon Sep 17 00:00:00 2001 From: Andrius Dagys Date: Wed, 9 Aug 2017 12:10:33 +0100 Subject: [PATCH] Verifier test: make sure only correct transactions are generated --- .../kotlin/net/corda/client/mock/Generator.kt | 6 ++- .../net/corda/contracts/testing/Generators.kt | 2 +- .../net/corda/verifier/GeneratedLedger.kt | 41 +++++++++++++++++-- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/client/mock/src/main/kotlin/net/corda/client/mock/Generator.kt b/client/mock/src/main/kotlin/net/corda/client/mock/Generator.kt index 9aec5f1b84..8da2e4e49b 100644 --- a/client/mock/src/main/kotlin/net/corda/client/mock/Generator.kt +++ b/client/mock/src/main/kotlin/net/corda/client/mock/Generator.kt @@ -167,7 +167,7 @@ fun Generator.Companion.replicate(number: Int, generator: Generator): Gen } -fun Generator.Companion.replicatePoisson(meanSize: Double, generator: Generator) = Generator> { +fun Generator.Companion.replicatePoisson(meanSize: Double, generator: Generator, atLeastOne: Boolean = false) = Generator> { val chance = (meanSize - 1) / meanSize val result = mutableListOf() var finish = false @@ -177,7 +177,9 @@ fun Generator.Companion.replicatePoisson(meanSize: Double, generator: Genera generator.generate(it).map { result.add(it) } } else { finish = true - Try.Success(Unit) + if (result.isEmpty() && atLeastOne) { + generator.generate(it).map { result.add(it) } + } else Try.Success(Unit) } } if (res is Try.Failure) { diff --git a/finance/src/test/kotlin/net/corda/contracts/testing/Generators.kt b/finance/src/test/kotlin/net/corda/contracts/testing/Generators.kt index 34e8d39f72..3d184d7760 100644 --- a/finance/src/test/kotlin/net/corda/contracts/testing/Generators.kt +++ b/finance/src/test/kotlin/net/corda/contracts/testing/Generators.kt @@ -67,7 +67,7 @@ class WiredTransactionGenerator : Generator(WireTransaction::cl override fun generate(random: SourceOfRandomness, status: GenerationStatus): WireTransaction { val commands = CommandGenerator().generateList(random, status) + listOf(CommandGenerator().generate(random, status)) return WireTransaction( - inputs = StateRefGenerator().generateList(random, status), + inputs = StateRefGenerator().generateList(random, status) + listOf(StateRefGenerator().generate(random, status)), attachments = SecureHashGenerator().generateList(random, status), outputs = TransactionStateGenerator(ContractStateGenerator()).generateList(random, status), commands = commands, diff --git a/verifier/src/integration-test/kotlin/net/corda/verifier/GeneratedLedger.kt b/verifier/src/integration-test/kotlin/net/corda/verifier/GeneratedLedger.kt index e178b25e71..a5890f8a9b 100644 --- a/verifier/src/integration-test/kotlin/net/corda/verifier/GeneratedLedger.kt +++ b/verifier/src/integration-test/kotlin/net/corda/verifier/GeneratedLedger.kt @@ -50,7 +50,7 @@ data class GeneratedLedger( } val commandsGenerator: Generator, Party>>> by lazy { - Generator.replicatePoisson(4.0, commandGenerator(identities)) + Generator.replicatePoisson(4.0, commandGenerator(identities), atLeastOne = true) } /** @@ -87,10 +87,42 @@ data class GeneratedLedger( } } + /** + * Generates an exit transaction. + * Invariants: + * * The output list must be empty + */ + fun exitTransactionGenerator(inputNotary: Party, inputsToChooseFrom: List>): Generator> { + val inputsGen = Generator.sampleBernoulli(inputsToChooseFrom) + return inputsGen.combine(attachmentsGenerator, commandsGenerator) { inputs, txAttachments, commands -> + val newTransaction = WireTransaction( + inputs.map { it.ref }, + txAttachments.map { it.id }, + emptyList(), + commands.map { it.first }, + inputNotary, + null + ) + + val availableOutputsMinusConsumed = HashMap(availableOutputs) + if (inputs.size == inputsToChooseFrom.size) { + availableOutputsMinusConsumed.remove(inputNotary) + } else { + availableOutputsMinusConsumed[inputNotary] = inputsToChooseFrom - inputs + } + val newAvailableOutputs = availableOutputsMinusConsumed + val newAttachments = attachments + txAttachments + val newIdentities = identities + commands.map { it.second } + val newLedger = GeneratedLedger(transactions + newTransaction, newAvailableOutputs, newAttachments, newIdentities) + Pair(newTransaction, newLedger) + } + } + /** * Generates a regular non-issue transaction. * Invariants: * * Input and output notaries must be one and the same. + * * There must be at least one input and output state. */ fun regularTransactionGenerator(inputNotary: Party, inputsToChooseFrom: List>): Generator> { val outputsGen = outputsGenerator.map { outputs -> @@ -136,8 +168,9 @@ data class GeneratedLedger( Generator.pickOne(availableOutputs.keys.toList()).flatMap { inputNotary -> val inputsToChooseFrom = availableOutputs[inputNotary]!! Generator.frequency( - 0.5 to issuanceGenerator, - 0.5 to regularTransactionGenerator(inputNotary, inputsToChooseFrom) + 0.3 to issuanceGenerator, + 0.3 to exitTransactionGenerator(inputNotary, inputsToChooseFrom), + 0.4 to regularTransactionGenerator(inputNotary, inputsToChooseFrom) ) } } @@ -193,4 +226,4 @@ fun pickOneOrMaybeNew(from: Collection, generator: Generator): Generat } val attachmentGenerator: Generator = Generator.bytes(16).map(::GeneratedAttachment) -val outputsGenerator = Generator.replicatePoisson(3.0, stateGenerator) +val outputsGenerator = Generator.replicatePoisson(3.0, stateGenerator, atLeastOne = true)