Verifier test: make sure only correct transactions are generated

This commit is contained in:
Andrius Dagys 2017-08-09 12:10:33 +01:00
parent f59621ce3f
commit f69273027c
3 changed files with 42 additions and 7 deletions

View File

@ -167,7 +167,7 @@ fun <A> Generator.Companion.replicate(number: Int, generator: Generator<A>): Gen
}
fun <A> Generator.Companion.replicatePoisson(meanSize: Double, generator: Generator<A>) = Generator<List<A>> {
fun <A> Generator.Companion.replicatePoisson(meanSize: Double, generator: Generator<A>, atLeastOne: Boolean = false) = Generator<List<A>> {
val chance = (meanSize - 1) / meanSize
val result = mutableListOf<A>()
var finish = false
@ -177,7 +177,9 @@ fun <A> 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) {

View File

@ -67,7 +67,7 @@ class WiredTransactionGenerator : Generator<WireTransaction>(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,

View File

@ -50,7 +50,7 @@ data class GeneratedLedger(
}
val commandsGenerator: Generator<List<Pair<Command<*>, 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<StateAndRef<ContractState>>): Generator<Pair<WireTransaction, GeneratedLedger>> {
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<StateAndRef<ContractState>>): Generator<Pair<WireTransaction, GeneratedLedger>> {
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 <A> pickOneOrMaybeNew(from: Collection<A>, generator: Generator<A>): Generat
}
val attachmentGenerator: Generator<Attachment> = Generator.bytes(16).map(::GeneratedAttachment)
val outputsGenerator = Generator.replicatePoisson(3.0, stateGenerator)
val outputsGenerator = Generator.replicatePoisson(3.0, stateGenerator, atLeastOne = true)