Skip to content

Commit

Permalink
Instantiate Contract classes outside of LedgerTransaction.verify() (c…
Browse files Browse the repository at this point in the history
…orda#1770)

* Load the contract classes when we create the LedgerTransaction.
* Fix Verifier tests by making ContractResult serialisable.
* Use named parameters to create ContractResult.
* Make the @JvmStatic function private.
* Refactor ContractResult to use Try.on{} instead.
  • Loading branch information
chrisr3 authored Oct 5, 2017
1 parent cf83328 commit 248c898
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import net.corda.core.internal.UpgradeCommand
import net.corda.core.internal.castIfPossible
import net.corda.core.internal.uncheckedCast
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.Try
import java.security.PublicKey
import java.util.*
import java.util.function.Predicate
Expand Down Expand Up @@ -48,6 +49,16 @@ data class LedgerTransaction(
checkEncumbrancesValid()
}

private companion object {
@JvmStatic
private fun createContractFor(className: ContractClassName): Try<Contract> {
return Try.on { this::class.java.classLoader.loadClass(className).asSubclass(Contract::class.java).getConstructor().newInstance() }
}
}

private val contracts: Map<ContractClassName, Try<Contract>> = (inputs.map { it.state.contract } + outputs.map { it.contract })
.toSet().map { it to createContractFor(it) }.toMap()

val inputStates: List<ContractState> get() = inputs.map { it.state.data }

/**
Expand Down Expand Up @@ -98,19 +109,18 @@ data class LedgerTransaction(
* If any contract fails to verify, the whole transaction is considered to be invalid.
*/
private fun verifyContracts() {
val contracts = (inputs.map { it.state.contract } + outputs.map { it.contract }).toSet()
for (contractClassName in contracts) {
val contract = try {
assert(javaClass.classLoader == ClassLoader.getSystemClassLoader())
javaClass.classLoader.loadClass(contractClassName).asSubclass(Contract::class.java).getConstructor().newInstance()
} catch (e: ClassNotFoundException) {
throw TransactionVerificationException.ContractCreationError(id, contractClassName, e)
}

try {
contract.verify(this)
} catch (e: Throwable) {
throw TransactionVerificationException.ContractRejection(id, contract, e)
for (contractEntry in contracts.entries) {
val result = contractEntry.value
when (result) {
is Try.Failure -> throw TransactionVerificationException.ContractCreationError(id, contractEntry.key, result.exception)
is Try.Success -> {
val contract = result.value
try {
contract.verify(this)
} catch (e: Throwable) {
throw TransactionVerificationException.ContractRejection(id, contract, e)
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import java.util.concurrent.atomic.AtomicInteger
class VerifierTests {
private fun generateTransactions(number: Int): List<LedgerTransaction> {
var currentLedger = GeneratedLedger.empty
val transactions = ArrayList<WireTransaction>()
val transactions = arrayListOf<WireTransaction>()
val random = SplittableRandom()
for (i in 0 until number) {
val (tx, ledger) = currentLedger.transactionGenerator.generateOrFail(random)
Expand Down

0 comments on commit 248c898

Please sign in to comment.