Validate LedgerTransaction deserialised from AttachmentsClassLoader. (#7049) (#7052)

This commit is contained in:
Chris Rankin 2022-01-31 09:40:01 +00:00 committed by GitHub
parent 7752fc8c9d
commit 758a69f904
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 212 additions and 104 deletions

View File

@ -21,6 +21,7 @@ import net.corda.testing.internal.createWireTransaction
import net.corda.testing.internal.fakeAttachment import net.corda.testing.internal.fakeAttachment
import net.corda.coretesting.internal.rigorousMock import net.corda.coretesting.internal.rigorousMock
import net.corda.testing.internal.TestingNamedCacheFactory import net.corda.testing.internal.TestingNamedCacheFactory
import org.assertj.core.api.Assertions.fail
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -36,6 +37,7 @@ import kotlin.test.assertNotEquals
@RunWith(Parameterized::class) @RunWith(Parameterized::class)
class TransactionTests(private val digestService : DigestService) { class TransactionTests(private val digestService : DigestService) {
private companion object { private companion object {
const val ISOLATED_JAR = "isolated-4.0.jar"
val DUMMY_KEY_1 = generateKeyPair() val DUMMY_KEY_1 = generateKeyPair()
val DUMMY_KEY_2 = generateKeyPair() val DUMMY_KEY_2 = generateKeyPair()
val DUMMY_CASH_ISSUER_KEY = entropyToKeyPair(BigInteger.valueOf(10)) val DUMMY_CASH_ISSUER_KEY = entropyToKeyPair(BigInteger.valueOf(10))
@ -200,15 +202,15 @@ class TransactionTests(private val digestService : DigestService) {
val outputs = listOf(outState) val outputs = listOf(outState)
val commands = emptyList<CommandWithParties<CommandData>>() val commands = emptyList<CommandWithParties<CommandData>>()
val attachments = listOf(object : AbstractAttachment({ val attachments = listOf(ContractAttachment(object : AbstractAttachment({
AttachmentsClassLoaderTests::class.java.getResource("isolated-4.0.jar").openStream().readBytes() (AttachmentsClassLoaderTests::class.java.getResource(ISOLATED_JAR) ?: fail("Missing $ISOLATED_JAR")).openStream().readBytes()
}, TESTDSL_UPLOADER) { }, TESTDSL_UPLOADER) {
@Suppress("OverridingDeprecatedMember") @Suppress("OverridingDeprecatedMember")
override val signers: List<Party> = emptyList() override val signers: List<Party> = emptyList()
override val signerKeys: List<PublicKey> = emptyList() override val signerKeys: List<PublicKey> = emptyList()
override val size: Int = 1234 override val size: Int = 1234
override val id: SecureHash = SecureHash.zeroHash override val id: SecureHash = SecureHash.zeroHash
}) }, DummyContract.PROGRAM_ID))
val id = digestService.randomHash() val id = digestService.randomHash()
val timeWindow: TimeWindow? = null val timeWindow: TimeWindow? = null
val privacySalt = PrivacySalt(digestService.digestLength) val privacySalt = PrivacySalt(digestService.digestLength)

View File

@ -16,6 +16,7 @@ typealias Version = Int
* Attention: this value affects consensus, so it requires a minimum platform version bump in order to be changed. * Attention: this value affects consensus, so it requires a minimum platform version bump in order to be changed.
*/ */
const val MAX_NUMBER_OF_KEYS_IN_SIGNATURE_CONSTRAINT = 20 const val MAX_NUMBER_OF_KEYS_IN_SIGNATURE_CONSTRAINT = 20
private const val DJVM_SANDBOX_PREFIX = "sandbox."
private val log = loggerFor<AttachmentConstraint>() private val log = loggerFor<AttachmentConstraint>()
@ -29,10 +30,14 @@ val Attachment.contractVersion: Version get() = if (this is ContractAttachment)
val ContractState.requiredContractClassName: String? get() { val ContractState.requiredContractClassName: String? get() {
val annotation = javaClass.getAnnotation(BelongsToContract::class.java) val annotation = javaClass.getAnnotation(BelongsToContract::class.java)
if (annotation != null) { if (annotation != null) {
return annotation.value.java.typeName return annotation.value.java.typeName.removePrefix(DJVM_SANDBOX_PREFIX)
} }
val enclosingClass = javaClass.enclosingClass ?: return null val enclosingClass = javaClass.enclosingClass ?: return null
return if (Contract::class.java.isAssignableFrom(enclosingClass)) enclosingClass.typeName else null return if (Contract::class.java.isAssignableFrom(enclosingClass)) {
enclosingClass.typeName.removePrefix(DJVM_SANDBOX_PREFIX)
} else {
null
}
} }
/** /**

View File

@ -13,6 +13,7 @@ import net.corda.core.contracts.SignatureAttachmentConstraint
import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.StateRef import net.corda.core.contracts.StateRef
import net.corda.core.contracts.TransactionState import net.corda.core.contracts.TransactionState
import net.corda.core.contracts.TransactionVerificationException
import net.corda.core.contracts.TransactionVerificationException.ConflictingAttachmentsRejection import net.corda.core.contracts.TransactionVerificationException.ConflictingAttachmentsRejection
import net.corda.core.contracts.TransactionVerificationException.ConstraintPropagationRejection import net.corda.core.contracts.TransactionVerificationException.ConstraintPropagationRejection
import net.corda.core.contracts.TransactionVerificationException.ContractCreationError import net.corda.core.contracts.TransactionVerificationException.ContractCreationError
@ -33,7 +34,7 @@ import net.corda.core.crypto.CompositeKey
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.internal.rules.StateContractValidationEnforcementRule import net.corda.core.internal.rules.StateContractValidationEnforcementRule
import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.LedgerTransaction
import net.corda.core.utilities.contextLogger import net.corda.core.utilities.loggerFor
import java.util.function.Function import java.util.function.Function
import java.util.function.Supplier import java.util.function.Supplier
@ -47,16 +48,54 @@ interface TransactionVerifierServiceInternal {
*/ */
fun LedgerTransaction.prepareVerify(attachments: List<Attachment>) = internalPrepareVerify(attachments) fun LedgerTransaction.prepareVerify(attachments: List<Attachment>) = internalPrepareVerify(attachments)
interface Verifier {
/**
* Placeholder function for the verification logic.
*/
fun verify()
}
// This class allows us unit-test transaction verification more easily.
abstract class AbstractVerifier(
protected val ltx: LedgerTransaction,
protected val transactionClassLoader: ClassLoader
) : Verifier {
protected abstract val transaction: Supplier<LedgerTransaction>
protected companion object {
@JvmField
val logger = loggerFor<Verifier>()
}
/**
* Check that the transaction is internally consistent, and then check that it is
* contract-valid by running verify() for each input and output state contract.
* If any contract fails to verify, the whole transaction is considered to be invalid.
*
* Note: Reference states are not verified.
*/
final override fun verify() {
try {
TransactionVerifier(transactionClassLoader).apply(transaction)
} catch (e: TransactionVerificationException) {
logger.error("Error validating transaction ${ltx.id}.", e.cause)
throw e
}
}
}
/** /**
* Because we create a separate [LedgerTransaction] onto which we need to perform verification, it becomes important we don't verify the * Because we create a separate [LedgerTransaction] onto which we need to perform verification, it becomes important we don't verify the
* wrong object instance. This class helps avoid that. * wrong object instance. This class helps avoid that.
*/ */
abstract class Verifier(val ltx: LedgerTransaction, protected val transactionClassLoader: ClassLoader) { @KeepForDJVM
private class Validator(private val ltx: LedgerTransaction, private val transactionClassLoader: ClassLoader) {
private val inputStates: List<TransactionState<*>> = ltx.inputs.map(StateAndRef<ContractState>::state) private val inputStates: List<TransactionState<*>> = ltx.inputs.map(StateAndRef<ContractState>::state)
private val allStates: List<TransactionState<*>> = inputStates + ltx.references.map(StateAndRef<ContractState>::state) + ltx.outputs private val allStates: List<TransactionState<*>> = inputStates + ltx.references.map(StateAndRef<ContractState>::state) + ltx.outputs
companion object { private companion object {
val logger = contextLogger() private val logger = loggerFor<Validator>()
} }
/** /**
@ -66,7 +105,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla
* *
* @throws net.corda.core.contracts.TransactionVerificationException * @throws net.corda.core.contracts.TransactionVerificationException
*/ */
fun verify() { fun validate() {
// checkNoNotaryChange and checkEncumbrancesValid are called here, and not in the c'tor, as they need access to the "outputs" // checkNoNotaryChange and checkEncumbrancesValid are called here, and not in the c'tor, as they need access to the "outputs"
// list, the contents of which need to be deserialized under the correct classloader. // list, the contents of which need to be deserialized under the correct classloader.
checkNoNotaryChange() checkNoNotaryChange()
@ -93,8 +132,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla
// 4. Check that the [TransactionState] objects are correctly formed. // 4. Check that the [TransactionState] objects are correctly formed.
validateStatesAgainstContract() validateStatesAgainstContract()
// 5. Final step is to run the contract code. After the first 4 steps we are now sure that we are running the correct code. // 5. Final step will be to run the contract code.
verifyContracts()
} }
private fun checkTransactionWithTimeWindowIsNotarised() { private fun checkTransactionWithTimeWindowIsNotarised() {
@ -106,6 +144,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla
* It makes sure there is one and only one. * It makes sure there is one and only one.
* This is an important piece of the security of transactions. * This is an important piece of the security of transactions.
*/ */
@Suppress("ThrowsCount")
private fun getUniqueContractAttachmentsByContract(): Map<ContractClassName, ContractAttachment> { private fun getUniqueContractAttachmentsByContract(): Map<ContractClassName, ContractAttachment> {
val contractClasses = allStates.mapTo(LinkedHashSet(), TransactionState<*>::contract) val contractClasses = allStates.mapTo(LinkedHashSet(), TransactionState<*>::contract)
@ -210,6 +249,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla
// b -> c and c -> b // b -> c and c -> b
// c -> a b -> a // c -> a b -> a
// and form a full cycle, meaning that the bi-directionality property is satisfied. // and form a full cycle, meaning that the bi-directionality property is satisfied.
@Suppress("ThrowsCount")
private fun checkBidirectionalOutputEncumbrances(statesAndEncumbrance: List<Pair<Int, Int>>) { private fun checkBidirectionalOutputEncumbrances(statesAndEncumbrance: List<Pair<Int, Int>>) {
// [Set] of "from" (encumbered states). // [Set] of "from" (encumbered states).
val encumberedSet = mutableSetOf<Int>() val encumberedSet = mutableSetOf<Int>()
@ -306,6 +346,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla
* - Constraints should be one of the valid supported ones. * - Constraints should be one of the valid supported ones.
* - Constraints should propagate correctly if not marked otherwise (in that case it is the responsibility of the contract to ensure that the output states are created properly). * - Constraints should propagate correctly if not marked otherwise (in that case it is the responsibility of the contract to ensure that the output states are created properly).
*/ */
@Suppress("NestedBlockDepth")
private fun verifyConstraintsValidity(contractAttachmentsByContract: Map<ContractClassName, ContractAttachment>) { private fun verifyConstraintsValidity(contractAttachmentsByContract: Map<ContractClassName, ContractAttachment>) {
// First check that the constraints are valid. // First check that the constraints are valid.
@ -392,19 +433,15 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla
throw ContractConstraintRejection(ltx.id, contract) throw ContractConstraintRejection(ltx.id, contract)
} }
} }
/**
* Placeholder function for the contract verification logic.
*/
abstract fun verifyContracts()
} }
/** /**
* Verify all of the contracts on the given [LedgerTransaction]. * Verify the given [LedgerTransaction]. This includes validating
* its contents, as well as executing all of its smart contracts.
*/ */
@Suppress("TooGenericExceptionCaught") @Suppress("TooGenericExceptionCaught")
@KeepForDJVM @KeepForDJVM
class ContractVerifier(private val transactionClassLoader: ClassLoader) : Function<Supplier<LedgerTransaction>, Unit> { class TransactionVerifier(private val transactionClassLoader: ClassLoader) : Function<Supplier<LedgerTransaction>, Unit> {
// This constructor is used inside the DJVM's sandbox. // This constructor is used inside the DJVM's sandbox.
@Suppress("unused") @Suppress("unused")
constructor() : this(ClassLoader.getSystemClassLoader()) constructor() : this(ClassLoader.getSystemClassLoader())
@ -440,16 +477,33 @@ class ContractVerifier(private val transactionClassLoader: ClassLoader) : Functi
} }
} }
private fun validateTransaction(ltx: LedgerTransaction) {
Validator(ltx, transactionClassLoader).validate()
}
override fun apply(transactionFactory: Supplier<LedgerTransaction>) { override fun apply(transactionFactory: Supplier<LedgerTransaction>) {
var firstLtx: LedgerTransaction? = null var firstLtx: LedgerTransaction? = null
transactionFactory.get().let { ltx -> transactionFactory.get().let { ltx ->
firstLtx = ltx firstLtx = ltx
/**
* Check that this transaction is correctly formed.
* We only need to run these checks once.
*/
validateTransaction(ltx)
/**
* Generate the list of unique contracts
* within this transaction.
*/
generateContracts(ltx) generateContracts(ltx)
}.forEach { contract -> }.forEach { contract ->
val ltx = firstLtx ?: transactionFactory.get() val ltx = firstLtx ?: transactionFactory.get()
firstLtx = null firstLtx = null
try { try {
// Final step is to run the contract code. Having validated the
// transaction, we are now sure that we are running the correct code.
contract.verify(ltx) contract.verify(ltx)
} catch (e: Exception) { } catch (e: Exception) {
throw ContractRejection(ltx.id, contract, e) throw ContractRejection(ltx.id, contract, e)

View File

@ -18,7 +18,7 @@ import net.corda.core.crypto.DigestService
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.ContractVerifier import net.corda.core.internal.AbstractVerifier
import net.corda.core.internal.SerializedStateAndRef import net.corda.core.internal.SerializedStateAndRef
import net.corda.core.internal.Verifier import net.corda.core.internal.Verifier
import net.corda.core.internal.castIfPossible import net.corda.core.internal.castIfPossible
@ -824,7 +824,7 @@ private constructor(
private class BasicVerifier( private class BasicVerifier(
ltx: LedgerTransaction, ltx: LedgerTransaction,
private val serializationContext: SerializationContext private val serializationContext: SerializationContext
) : Verifier(ltx, serializationContext.deserializationClassLoader) { ) : AbstractVerifier(ltx, serializationContext.deserializationClassLoader) {
init { init {
// This is a sanity check: We should only instantiate this // This is a sanity check: We should only instantiate this
@ -836,9 +836,15 @@ private class BasicVerifier(
// Fetch these commands' signing parties from the database. // Fetch these commands' signing parties from the database.
// Corda forbids database access during contract verification, // Corda forbids database access during contract verification,
// and so we must load the commands here eagerly instead. // and so we must load the commands here eagerly instead.
// THIS ALSO DESERIALISES THE COMMANDS USING THE WRONG CONTEXT
// BECAUSE THAT CONTEXT WAS CHOSEN WHEN THE LAZY MAP WAS CREATED,
// AND CHANGING THE DEFAULT CONTEXT HERE DOES NOT AFFECT IT.
ltx.commands.eagerDeserialise() ltx.commands.eagerDeserialise()
} }
override val transaction: Supplier<LedgerTransaction>
get() = Supplier(::createTransaction)
private fun createTransaction(): LedgerTransaction { private fun createTransaction(): LedgerTransaction {
// Deserialize all relevant classes using the serializationContext. // Deserialize all relevant classes using the serializationContext.
return SerializationFactory.defaultFactory.withCurrentContext(serializationContext) { return SerializationFactory.defaultFactory.withCurrentContext(serializationContext) {
@ -870,21 +876,6 @@ private class BasicVerifier(
} }
} }
} }
/**
* Check the transaction is contract-valid by running verify() for each input and output state contract.
* If any contract fails to verify, the whole transaction is considered to be invalid.
*
* Note: Reference states are not verified.
*/
override fun verifyContracts() {
try {
ContractVerifier(transactionClassLoader).apply(Supplier(::createTransaction))
} catch (e: TransactionVerificationException) {
logger.error("Error validating transaction ${ltx.id}.", e.cause)
throw e
}
}
} }
/** /**
@ -892,10 +883,10 @@ private class BasicVerifier(
* *
* THIS CLASS IS NOT PUBLIC API, AND IS DELIBERATELY PRIVATE! * THIS CLASS IS NOT PUBLIC API, AND IS DELIBERATELY PRIVATE!
*/ */
@Suppress("unused_parameter")
@CordaInternal @CordaInternal
private class NoOpVerifier(ltx: LedgerTransaction, serializationContext: SerializationContext) private class NoOpVerifier(ltx: LedgerTransaction, serializationContext: SerializationContext) : Verifier {
: Verifier(ltx, serializationContext.deserializationClassLoader) {
// Invoking LedgerTransaction.verify() from Contract.verify(LedgerTransaction) // Invoking LedgerTransaction.verify() from Contract.verify(LedgerTransaction)
// will execute this function. But why would anyone do that?! // will execute this function. But why would anyone do that?!
override fun verifyContracts() {} override fun verify() {}
} }

View File

@ -5,10 +5,12 @@ import net.corda.core.crypto.DigestService
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.node.NetworkParameters import net.corda.core.node.NetworkParameters
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.internal.AttachmentsClassLoaderCache import net.corda.core.serialization.internal.AttachmentsClassLoaderCache
import net.corda.core.transactions.ComponentGroup import net.corda.core.transactions.ComponentGroup
import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
import java.util.function.Supplier
/** /**
* A set of functions in core:test that allows testing of core internal classes in the core-tests project. * A set of functions in core:test that allows testing of core internal classes in the core-tests project.
@ -38,7 +40,17 @@ fun createLedgerTransaction(
isAttachmentTrusted: (Attachment) -> Boolean, isAttachmentTrusted: (Attachment) -> Boolean,
attachmentsClassLoaderCache: AttachmentsClassLoaderCache, attachmentsClassLoaderCache: AttachmentsClassLoaderCache,
digestService: DigestService = DigestService.default digestService: DigestService = DigestService.default
): LedgerTransaction = LedgerTransaction.create(inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, networkParameters, references, componentGroups, serializedInputs, serializedReferences, isAttachmentTrusted, attachmentsClassLoaderCache, digestService) ): LedgerTransaction = LedgerTransaction.create(
inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, networkParameters, references, componentGroups, serializedInputs, serializedReferences, isAttachmentTrusted, attachmentsClassLoaderCache, digestService
).specialise(::PassthroughVerifier)
fun createContractCreationError(txId: SecureHash, contractClass: String, cause: Throwable) = TransactionVerificationException.ContractCreationError(txId, contractClass, cause) fun createContractCreationError(txId: SecureHash, contractClass: String, cause: Throwable) = TransactionVerificationException.ContractCreationError(txId, contractClass, cause)
fun createContractRejection(txId: SecureHash, contract: Contract, cause: Throwable) = TransactionVerificationException.ContractRejection(txId, contract, cause) fun createContractRejection(txId: SecureHash, contract: Contract, cause: Throwable) = TransactionVerificationException.ContractRejection(txId, contract, cause)
/**
* Verify the [LedgerTransaction] we already have.
*/
private class PassthroughVerifier(ltx: LedgerTransaction, context: SerializationContext) : AbstractVerifier(ltx, context.deserializationClassLoader) {
override val transaction: Supplier<LedgerTransaction>
get() = Supplier { ltx }
}

View File

@ -3,6 +3,7 @@ package net.corda.node.djvm
import net.corda.core.contracts.Attachment import net.corda.core.contracts.Attachment
import net.corda.core.contracts.BrokenAttachmentException import net.corda.core.contracts.BrokenAttachmentException
import net.corda.core.contracts.ContractAttachment
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.identity.Party import net.corda.core.identity.Party
import java.io.InputStream import java.io.InputStream
@ -16,6 +17,12 @@ private const val ID_IDX = 2
private const val ATTACHMENT_IDX = 3 private const val ATTACHMENT_IDX = 3
private const val STREAMER_IDX = 4 private const val STREAMER_IDX = 4
private const val CONTRACT_IDX = 5
private const val ADDITIONAL_CONTRACT_IDX = 6
private const val UPLOADER_IDX = 7
private const val CONTRACT_SIGNER_KEYS_IDX = 8
private const val VERSION_IDX = 9
class AttachmentBuilder : Function<Array<Any>?, List<Attachment>?> { class AttachmentBuilder : Function<Array<Any>?, List<Attachment>?> {
private val attachments = mutableListOf<Attachment>() private val attachments = mutableListOf<Attachment>()
@ -28,17 +35,30 @@ class AttachmentBuilder : Function<Array<Any>?, List<Attachment>?> {
} }
override fun apply(inputs: Array<Any>?): List<Attachment>? { override fun apply(inputs: Array<Any>?): List<Attachment>? {
@Suppress("unchecked_cast")
return if (inputs == null) { return if (inputs == null) {
unmodifiable(attachments) unmodifiable(attachments)
} else { } else {
@Suppress("unchecked_cast") var attachment: Attachment = SandboxAttachment(
attachments.add(SandboxAttachment(
signerKeys = inputs[SIGNER_KEYS_IDX] as List<PublicKey>, signerKeys = inputs[SIGNER_KEYS_IDX] as List<PublicKey>,
size = inputs[SIZE_IDX] as Int, size = inputs[SIZE_IDX] as Int,
id = inputs[ID_IDX] as SecureHash, id = inputs[ID_IDX] as SecureHash,
attachment = inputs[ATTACHMENT_IDX], attachment = inputs[ATTACHMENT_IDX],
streamer = inputs[STREAMER_IDX] as Function<in Any, out InputStream> streamer = inputs[STREAMER_IDX] as Function<in Any, out InputStream>
)) )
if (inputs.size > VERSION_IDX) {
attachment = ContractAttachment.create(
attachment = attachment,
contract = inputs[CONTRACT_IDX] as String,
additionalContracts = (inputs[ADDITIONAL_CONTRACT_IDX] as Array<String>).toSet(),
uploader = inputs[UPLOADER_IDX] as? String,
signerKeys = inputs[CONTRACT_SIGNER_KEYS_IDX] as List<PublicKey>,
version = inputs[VERSION_IDX] as Int
)
}
attachments.add(attachment)
null null
} }
} }
@ -47,7 +67,7 @@ class AttachmentBuilder : Function<Array<Any>?, List<Attachment>?> {
/** /**
* This represents an [Attachment] from within the sandbox. * This represents an [Attachment] from within the sandbox.
*/ */
class SandboxAttachment( private class SandboxAttachment(
override val signerKeys: List<PublicKey>, override val signerKeys: List<PublicKey>,
override val size: Int, override val size: Int,
override val id: SecureHash, override val id: SecureHash,

View File

@ -95,9 +95,11 @@ class MutatorContract : Contract {
} }
} }
private class ExtraSpecialise(ltx: LedgerTransaction, ctx: SerializationContext) private class ExtraSpecialise(private val ltx: LedgerTransaction, private val ctx: SerializationContext) : Verifier {
: Verifier(ltx, ctx.deserializationClassLoader) { override fun verify() {
override fun verifyContracts() {} ltx.inputStates.forEach(::println)
println(ctx.deserializationClassLoader)
}
} }
class MutateState(val owner: AbstractParty) : ContractState { class MutateState(val owner: AbstractParty) : ContractState {

View File

@ -30,12 +30,12 @@ class CashIssueAndPaymentTest {
private val configOverrides = mapOf(NodeConfiguration::reloadCheckpointAfterSuspend.name to true) private val configOverrides = mapOf(NodeConfiguration::reloadCheckpointAfterSuspend.name to true)
private val CASH_AMOUNT = 500.DOLLARS private val CASH_AMOUNT = 500.DOLLARS
fun parametersFor(): DriverParameters { fun parametersFor(runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
systemProperties = mapOf("co.paralleluniverse.fibers.verifyInstrumentation" to "false"), systemProperties = mapOf("co.paralleluniverse.fibers.verifyInstrumentation" to "false"),
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = false, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = false, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
notaryCustomOverrides = configOverrides, notaryCustomOverrides = configOverrides,
cordappsForAllNodes = listOf( cordappsForAllNodes = listOf(
findCordapp("net.corda.finance.contracts"), findCordapp("net.corda.finance.contracts"),

View File

@ -23,7 +23,7 @@ class ContractCannotMutateTransactionTest {
private val mutatorFlowCorDapp = cordappWithPackages("net.corda.flows.mutator").signed() private val mutatorFlowCorDapp = cordappWithPackages("net.corda.flows.mutator").signed()
private val mutatorContractCorDapp = cordappWithPackages("net.corda.contracts.mutator").signed() private val mutatorContractCorDapp = cordappWithPackages("net.corda.contracts.mutator").signed()
fun driverParameters(runInProcess: Boolean): DriverParameters { fun driverParameters(runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = runInProcess, startNodesInProcess = runInProcess,
@ -35,7 +35,7 @@ class ContractCannotMutateTransactionTest {
@Test(timeout = 300_000) @Test(timeout = 300_000)
fun testContractCannotModifyTransaction() { fun testContractCannotModifyTransaction() {
driver(driverParameters(runInProcess = false)) { driver(driverParameters()) {
val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow() val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow()
val txID = CordaRPCClient(hostAndPort = alice.rpcAddress) val txID = CordaRPCClient(hostAndPort = alice.rpcAddress)
.start(user.username, user.password) .start(user.username, user.password)

View File

@ -35,11 +35,11 @@ class ContractWithCordappFixupTest {
val dependentContractCorDapp = cordappWithPackages("net.corda.contracts.fixup.dependent").signed() val dependentContractCorDapp = cordappWithPackages("net.corda.contracts.fixup.dependent").signed()
val standaloneContractCorDapp = cordappWithPackages("net.corda.contracts.fixup.standalone").signed() val standaloneContractCorDapp = cordappWithPackages("net.corda.contracts.fixup.standalone").signed()
fun driverParameters(cordapps: List<TestCordapp>): DriverParameters { fun driverParameters(cordapps: List<TestCordapp>, runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = false, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
cordappsForAllNodes = cordapps, cordappsForAllNodes = cordapps,
systemProperties = mapOf("net.corda.transactionbuilder.missingclass.disabled" to true.toString()) systemProperties = mapOf("net.corda.transactionbuilder.missingclass.disabled" to true.toString())
) )

View File

@ -46,7 +46,7 @@ class ContractWithCustomSerializerTest(private val runInProcess: Boolean) {
driver(DriverParameters( driver(DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = runInProcess, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
cordappsForAllNodes = listOf( cordappsForAllNodes = listOf(
cordappWithPackages("net.corda.flows.serialization.custom").signed(), cordappWithPackages("net.corda.flows.serialization.custom").signed(),
cordappWithPackages("net.corda.contracts.serialization.custom").signed() cordappWithPackages("net.corda.contracts.serialization.custom").signed()

View File

@ -31,11 +31,11 @@ class ContractWithGenericTypeTest {
@JvmField @JvmField
val user = User("u", "p", setOf(Permissions.all())) val user = User("u", "p", setOf(Permissions.all()))
fun parameters(): DriverParameters { fun parameters(runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = false, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
cordappsForAllNodes = listOf( cordappsForAllNodes = listOf(
cordappWithPackages("net.corda.flows.serialization.generics").signed(), cordappWithPackages("net.corda.flows.serialization.generics").signed(),
cordappWithPackages("net.corda.contracts.serialization.generics").signed() cordappWithPackages("net.corda.contracts.serialization.generics").signed()

View File

@ -45,7 +45,7 @@ class ContractWithMissingCustomSerializerTest(private val runInProcess: Boolean)
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = runInProcess, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
cordappsForAllNodes = cordapps cordappsForAllNodes = cordapps
) )
} }

View File

@ -43,7 +43,7 @@ class ContractWithSerializationWhitelistTest(private val runInProcess: Boolean)
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = runInProcess, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
cordappsForAllNodes = listOf(contractCordapp, workflowCordapp) cordappsForAllNodes = listOf(contractCordapp, workflowCordapp)
) )
} }

View File

@ -32,11 +32,11 @@ class DeterministicCashIssueAndPaymentTest {
@JvmField @JvmField
val djvmSources = DeterministicSourcesRule() val djvmSources = DeterministicSourcesRule()
fun parametersFor(djvmSources: DeterministicSourcesRule): DriverParameters { fun parametersFor(djvmSources: DeterministicSourcesRule, runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = false, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
notaryCustomOverrides = configOverrides, notaryCustomOverrides = configOverrides,
cordappsForAllNodes = listOf( cordappsForAllNodes = listOf(
findCordapp("net.corda.finance.contracts"), findCordapp("net.corda.finance.contracts"),

View File

@ -28,7 +28,7 @@ class DeterministicContractCannotMutateTransactionTest {
@JvmField @JvmField
val djvmSources = DeterministicSourcesRule() val djvmSources = DeterministicSourcesRule()
fun driverParameters(runInProcess: Boolean): DriverParameters { fun driverParameters(runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = runInProcess, startNodesInProcess = runInProcess,
@ -42,7 +42,7 @@ class DeterministicContractCannotMutateTransactionTest {
@Test(timeout = 300_000) @Test(timeout = 300_000)
fun testContractCannotModifyTransaction() { fun testContractCannotModifyTransaction() {
driver(driverParameters(runInProcess = false)) { driver(driverParameters()) {
val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow() val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow()
val txID = CordaRPCClient(hostAndPort = alice.rpcAddress) val txID = CordaRPCClient(hostAndPort = alice.rpcAddress)
.start(user.username, user.password) .start(user.username, user.password)

View File

@ -32,11 +32,11 @@ class DeterministicContractCryptoTest {
@JvmField @JvmField
val djvmSources = DeterministicSourcesRule() val djvmSources = DeterministicSourcesRule()
fun parametersFor(djvmSources: DeterministicSourcesRule): DriverParameters { fun parametersFor(djvmSources: DeterministicSourcesRule, runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = false, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
cordappsForAllNodes = listOf( cordappsForAllNodes = listOf(
cordappWithPackages("net.corda.flows.djvm.crypto"), cordappWithPackages("net.corda.flows.djvm.crypto"),
CustomCordapp( CustomCordapp(

View File

@ -41,11 +41,11 @@ class DeterministicContractWithCustomSerializerTest {
@JvmField @JvmField
val contractCordapp = cordappWithPackages("net.corda.contracts.serialization.custom").signed() val contractCordapp = cordappWithPackages("net.corda.contracts.serialization.custom").signed()
fun parametersFor(djvmSources: DeterministicSourcesRule, vararg cordapps: TestCordapp): DriverParameters { fun parametersFor(djvmSources: DeterministicSourcesRule, cordapps: List<TestCordapp>, runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = false, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
cordappsForAllNodes = cordapps.toList(), cordappsForAllNodes = cordapps.toList(),
djvmBootstrapSource = djvmSources.bootstrap, djvmBootstrapSource = djvmSources.bootstrap,
djvmCordaSource = djvmSources.corda djvmCordaSource = djvmSources.corda
@ -61,7 +61,7 @@ class DeterministicContractWithCustomSerializerTest {
@Test(timeout=300_000) @Test(timeout=300_000)
fun `test DJVM can verify using custom serializer`() { fun `test DJVM can verify using custom serializer`() {
driver(parametersFor(djvmSources, flowCordapp, contractCordapp)) { driver(parametersFor(djvmSources, listOf(flowCordapp, contractCordapp))) {
val alice = startNode(providedName = ALICE_NAME).getOrThrow() val alice = startNode(providedName = ALICE_NAME).getOrThrow()
val txId = assertDoesNotThrow { val txId = assertDoesNotThrow {
alice.rpc.startFlow(::CustomSerializerFlow, Currantsy(GOOD_CURRANTS)) alice.rpc.startFlow(::CustomSerializerFlow, Currantsy(GOOD_CURRANTS))
@ -73,7 +73,7 @@ class DeterministicContractWithCustomSerializerTest {
@Test(timeout=300_000) @Test(timeout=300_000)
fun `test DJVM can fail verify using custom serializer`() { fun `test DJVM can fail verify using custom serializer`() {
driver(parametersFor(djvmSources, flowCordapp, contractCordapp)) { driver(parametersFor(djvmSources, listOf(flowCordapp, contractCordapp))) {
val alice = startNode(providedName = ALICE_NAME).getOrThrow() val alice = startNode(providedName = ALICE_NAME).getOrThrow()
val currantsy = Currantsy(BAD_CURRANTS) val currantsy = Currantsy(BAD_CURRANTS)
val ex = assertThrows<DeterministicVerificationException> { val ex = assertThrows<DeterministicVerificationException> {

View File

@ -36,11 +36,11 @@ class DeterministicContractWithGenericTypeTest {
@JvmField @JvmField
val djvmSources = DeterministicSourcesRule() val djvmSources = DeterministicSourcesRule()
fun parameters(): DriverParameters { fun parameters(runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = false, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
cordappsForAllNodes = listOf( cordappsForAllNodes = listOf(
cordappWithPackages("net.corda.flows.serialization.generics").signed(), cordappWithPackages("net.corda.flows.serialization.generics").signed(),
cordappWithPackages("net.corda.contracts.serialization.generics").signed() cordappWithPackages("net.corda.contracts.serialization.generics").signed()

View File

@ -41,11 +41,11 @@ class DeterministicContractWithSerializationWhitelistTest {
@JvmField @JvmField
val contractCordapp = cordappWithPackages("net.corda.contracts.djvm.whitelist").signed() val contractCordapp = cordappWithPackages("net.corda.contracts.djvm.whitelist").signed()
fun parametersFor(djvmSources: DeterministicSourcesRule, vararg cordapps: TestCordapp): DriverParameters { fun parametersFor(djvmSources: DeterministicSourcesRule, cordapps: List<TestCordapp>, runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = false, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
cordappsForAllNodes = cordapps.toList(), cordappsForAllNodes = cordapps.toList(),
djvmBootstrapSource = djvmSources.bootstrap, djvmBootstrapSource = djvmSources.bootstrap,
djvmCordaSource = djvmSources.corda djvmCordaSource = djvmSources.corda
@ -61,7 +61,7 @@ class DeterministicContractWithSerializationWhitelistTest {
@Test(timeout=300_000) @Test(timeout=300_000)
fun `test DJVM can verify using whitelist`() { fun `test DJVM can verify using whitelist`() {
driver(parametersFor(djvmSources, flowCordapp, contractCordapp)) { driver(parametersFor(djvmSources, listOf(flowCordapp, contractCordapp))) {
val alice = startNode(providedName = ALICE_NAME).getOrThrow() val alice = startNode(providedName = ALICE_NAME).getOrThrow()
val txId = assertDoesNotThrow { val txId = assertDoesNotThrow {
alice.rpc.startFlow(::DeterministicWhitelistFlow, WhitelistData(GOOD_VALUE)) alice.rpc.startFlow(::DeterministicWhitelistFlow, WhitelistData(GOOD_VALUE))
@ -73,7 +73,7 @@ class DeterministicContractWithSerializationWhitelistTest {
@Test(timeout=300_000) @Test(timeout=300_000)
fun `test DJVM can fail verify using whitelist`() { fun `test DJVM can fail verify using whitelist`() {
driver(parametersFor(djvmSources, flowCordapp, contractCordapp)) { driver(parametersFor(djvmSources, listOf(flowCordapp, contractCordapp))) {
val alice = startNode(providedName = ALICE_NAME).getOrThrow() val alice = startNode(providedName = ALICE_NAME).getOrThrow()
val badData = WhitelistData(BAD_VALUE) val badData = WhitelistData(BAD_VALUE)
val ex = assertThrows<DeterministicVerificationException> { val ex = assertThrows<DeterministicVerificationException> {

View File

@ -34,7 +34,7 @@ class DeterministicEvilContractCannotModifyStatesTest {
@JvmField @JvmField
val djvmSources = DeterministicSourcesRule() val djvmSources = DeterministicSourcesRule()
fun driverParameters(runInProcess: Boolean): DriverParameters { fun driverParameters(runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = runInProcess, startNodesInProcess = runInProcess,
@ -53,7 +53,7 @@ class DeterministicEvilContractCannotModifyStatesTest {
@Test(timeout = 300_000) @Test(timeout = 300_000)
fun testContractThatTriesToModifyStates() { fun testContractThatTriesToModifyStates() {
val evilData = MutableDataObject(5000) val evilData = MutableDataObject(5000)
driver(driverParameters(runInProcess = false)) { driver(driverParameters()) {
val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow() val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow()
val ex = assertFailsWith<DeterministicVerificationException> { val ex = assertFailsWith<DeterministicVerificationException> {
CordaRPCClient(hostAndPort = alice.rpcAddress) CordaRPCClient(hostAndPort = alice.rpcAddress)

View File

@ -35,11 +35,11 @@ class NonDeterministicContractVerifyTest {
@JvmField @JvmField
val djvmSources = DeterministicSourcesRule() val djvmSources = DeterministicSourcesRule()
fun parametersFor(djvmSources: DeterministicSourcesRule): DriverParameters { fun parametersFor(djvmSources: DeterministicSourcesRule, runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = false, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
cordappsForAllNodes = listOf( cordappsForAllNodes = listOf(
cordappWithPackages("net.corda.flows.djvm.broken"), cordappWithPackages("net.corda.flows.djvm.broken"),
CustomCordapp( CustomCordapp(

View File

@ -31,11 +31,11 @@ class SandboxAttachmentsTest {
@JvmField @JvmField
val djvmSources = DeterministicSourcesRule() val djvmSources = DeterministicSourcesRule()
fun parametersFor(djvmSources: DeterministicSourcesRule): DriverParameters { fun parametersFor(djvmSources: DeterministicSourcesRule, runInProcess: Boolean = false): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = false, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)),
cordappsForAllNodes = listOf( cordappsForAllNodes = listOf(
cordappWithPackages("net.corda.flows.djvm.attachment"), cordappWithPackages("net.corda.flows.djvm.attachment"),
CustomCordapp( CustomCordapp(

View File

@ -1,6 +1,7 @@
package net.corda.node.internal.djvm package net.corda.node.internal.djvm
import net.corda.core.contracts.Attachment import net.corda.core.contracts.Attachment
import net.corda.core.contracts.ContractAttachment
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.djvm.rewiring.SandboxClassLoader import net.corda.djvm.rewiring.SandboxClassLoader
import net.corda.node.djvm.AttachmentBuilder import net.corda.node.djvm.AttachmentBuilder
@ -19,14 +20,30 @@ class AttachmentFactory(
fun toSandbox(attachments: List<Attachment>): Any? { fun toSandbox(attachments: List<Attachment>): Any? {
val builder = taskFactory.apply(AttachmentBuilder::class.java) val builder = taskFactory.apply(AttachmentBuilder::class.java)
for (attachment in attachments) { for (attachment in attachments) {
builder.apply(arrayOf( builder.apply(generateArgsFor(attachment))
serializer.deserialize(attachment.signerKeys.serialize()),
sandboxBasicInput.apply(attachment.size),
serializer.deserialize(attachment.id.serialize()),
attachment,
sandboxOpenAttachment
))
} }
return builder.apply(null) return builder.apply(null)
} }
private fun generateArgsFor(attachment: Attachment): Array<Any?> {
val signerKeys = serializer.deserialize(attachment.signerKeys.serialize())
val id = serializer.deserialize(attachment.id.serialize())
val size = sandboxBasicInput.apply(attachment.size)
return if (attachment is ContractAttachment) {
val underlyingAttachment = attachment.attachment
arrayOf(
serializer.deserialize(underlyingAttachment.signerKeys.serialize()),
size, id,
underlyingAttachment,
sandboxOpenAttachment,
sandboxBasicInput.apply(attachment.contract),
sandboxBasicInput.apply(attachment.additionalContracts.toTypedArray()),
sandboxBasicInput.apply(attachment.uploader),
signerKeys,
sandboxBasicInput.apply(attachment.version)
)
} else {
arrayOf(signerKeys, size, id, attachment, sandboxOpenAttachment)
}
}
} }

View File

@ -7,13 +7,14 @@ import net.corda.core.contracts.ComponentGroupEnum.SIGNERS_GROUP
import net.corda.core.contracts.TransactionState import net.corda.core.contracts.TransactionState
import net.corda.core.contracts.TransactionVerificationException import net.corda.core.contracts.TransactionVerificationException
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.internal.ContractVerifier import net.corda.core.internal.TransactionVerifier
import net.corda.core.internal.Verifier import net.corda.core.internal.Verifier
import net.corda.core.internal.getNamesOfClassesImplementing import net.corda.core.internal.getNamesOfClassesImplementing
import net.corda.core.serialization.SerializationCustomSerializer import net.corda.core.serialization.SerializationCustomSerializer
import net.corda.core.serialization.SerializationWhitelist import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.LedgerTransaction
import net.corda.core.utilities.contextLogger
import net.corda.djvm.SandboxConfiguration import net.corda.djvm.SandboxConfiguration
import net.corda.djvm.execution.ExecutionSummary import net.corda.djvm.execution.ExecutionSummary
import net.corda.djvm.execution.IsolatedTask import net.corda.djvm.execution.IsolatedTask
@ -26,10 +27,14 @@ import java.util.function.Function
import kotlin.collections.LinkedHashSet import kotlin.collections.LinkedHashSet
class DeterministicVerifier( class DeterministicVerifier(
ltx: LedgerTransaction, private val ltx: LedgerTransaction,
transactionClassLoader: ClassLoader, private val transactionClassLoader: ClassLoader,
private val sandboxConfiguration: SandboxConfiguration private val sandboxConfiguration: SandboxConfiguration
) : Verifier(ltx, transactionClassLoader) { ) : Verifier {
private companion object {
private val logger = contextLogger()
}
/** /**
* Read the whitelisted classes without using the [java.util.ServiceLoader] mechanism * Read the whitelisted classes without using the [java.util.ServiceLoader] mechanism
* because the whitelists themselves are untrusted. * because the whitelists themselves are untrusted.
@ -47,7 +52,7 @@ class DeterministicVerifier(
} }
} }
override fun verifyContracts() { override fun verify() {
val customSerializerNames = getNamesOfClassesImplementing(transactionClassLoader, SerializationCustomSerializer::class.java) val customSerializerNames = getNamesOfClassesImplementing(transactionClassLoader, SerializationCustomSerializer::class.java)
val serializationWhitelistNames = getSerializationWhitelistNames(transactionClassLoader) val serializationWhitelistNames = getSerializationWhitelistNames(transactionClassLoader)
val result = IsolatedTask(ltx.id.toString(), sandboxConfiguration).run<Any>(Function { classLoader -> val result = IsolatedTask(ltx.id.toString(), sandboxConfiguration).run<Any>(Function { classLoader ->
@ -113,7 +118,7 @@ class DeterministicVerifier(
)) ))
} }
val verifier = taskFactory.apply(ContractVerifier::class.java) val verifier = taskFactory.apply(TransactionVerifier::class.java)
// Now execute the contract verifier task within the sandbox... // Now execute the contract verifier task within the sandbox...
verifier.apply(sandboxTx) verifier.apply(sandboxTx)
@ -128,7 +133,7 @@ class DeterministicVerifier(
val sandboxEx = SandboxException( val sandboxEx = SandboxException(
Message.getMessageFromException(this), Message.getMessageFromException(this),
result.identifier, result.identifier,
ClassSource.fromClassName(ContractVerifier::class.java.name), ClassSource.fromClassName(TransactionVerifier::class.java.name),
ExecutionSummary(result.costs), ExecutionSummary(result.costs),
this this
) )