mirror of
https://github.com/corda/corda.git
synced 2025-02-05 18:49:14 +00:00
Test examining attachments within DJVM sandbox.
This commit is contained in:
parent
ceeb170f6c
commit
210f10f6be
@ -0,0 +1,38 @@
|
|||||||
|
package net.corda.contracts.djvm.attachment
|
||||||
|
|
||||||
|
import net.corda.core.contracts.CommandData
|
||||||
|
import net.corda.core.contracts.Contract
|
||||||
|
import net.corda.core.contracts.ContractState
|
||||||
|
import net.corda.core.identity.AbstractParty
|
||||||
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
|
||||||
|
class SandboxAttachmentContract : Contract {
|
||||||
|
override fun verify(tx: LedgerTransaction) {
|
||||||
|
val attachments = tx.attachments
|
||||||
|
require(attachments.isNotEmpty()) { "Attachments are missing for TX=${tx.id}" }
|
||||||
|
|
||||||
|
require(attachments.size == 1) { "Did not expect to find ${attachments.size} attachments for TX${tx.id}" }
|
||||||
|
val attachment = attachments[0]
|
||||||
|
require(attachment.size > 0) { "Attachment ${attachment.id} has no contents for TX=${tx.id}" }
|
||||||
|
|
||||||
|
val keyCount = attachment.signerKeys.size
|
||||||
|
require(keyCount == 1) { "Attachment ${attachment.id} has $keyCount signing keys for TX=${tx.id}" }
|
||||||
|
|
||||||
|
tx.commandsOfType(ExtractFile::class.java).forEach { extract ->
|
||||||
|
val fileName = extract.value.fileName
|
||||||
|
val contents = ByteArrayOutputStream().use {
|
||||||
|
attachment.extractFile(fileName, it)
|
||||||
|
it
|
||||||
|
}.toByteArray()
|
||||||
|
require(contents.isNotEmpty()) { "File $fileName has no contents for TX=${tx.id}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("CanBeParameter", "MemberVisibilityCanBePrivate")
|
||||||
|
class State(val issuer: AbstractParty) : ContractState {
|
||||||
|
override val participants: List<AbstractParty> = listOf(issuer)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExtractFile(val fileName: String) : CommandData
|
||||||
|
}
|
@ -22,8 +22,8 @@ class DeterministicCryptoContract : Contract {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cryptoData.isEmpty() || validators.isEmpty() || !isValid) {
|
require(cryptoData.isNotEmpty() && validators.isNotEmpty() && isValid) {
|
||||||
throw IllegalStateException("Failed to validate signatures in command data")
|
"Failed to validate signatures in command data"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package net.corda.flows.djvm.attachment
|
||||||
|
|
||||||
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
|
import net.corda.contracts.djvm.attachment.SandboxAttachmentContract
|
||||||
|
import net.corda.core.contracts.Command
|
||||||
|
import net.corda.core.contracts.CommandData
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.flows.FlowLogic
|
||||||
|
import net.corda.core.flows.InitiatingFlow
|
||||||
|
import net.corda.core.flows.StartableByRPC
|
||||||
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
|
|
||||||
|
@InitiatingFlow
|
||||||
|
@StartableByRPC
|
||||||
|
class SandboxAttachmentFlow(private val command: CommandData) : FlowLogic<SecureHash>() {
|
||||||
|
@Suspendable
|
||||||
|
override fun call(): SecureHash {
|
||||||
|
val notary = serviceHub.networkMapCache.notaryIdentities[0]
|
||||||
|
val stx = serviceHub.signInitialTransaction(
|
||||||
|
TransactionBuilder(notary)
|
||||||
|
.addOutputState(SandboxAttachmentContract.State(ourIdentity))
|
||||||
|
.addCommand(Command(command, ourIdentity.owningKey))
|
||||||
|
)
|
||||||
|
stx.verify(serviceHub, checkSufficientSignatures = false)
|
||||||
|
return stx.id
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
package net.corda.node.services
|
||||||
|
|
||||||
|
import net.corda.contracts.djvm.attachment.SandboxAttachmentContract
|
||||||
|
import net.corda.contracts.djvm.attachment.SandboxAttachmentContract.*
|
||||||
|
import net.corda.core.messaging.startFlow
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.core.utilities.loggerFor
|
||||||
|
import net.corda.djvm.code.asResourcePath
|
||||||
|
import net.corda.flows.djvm.attachment.SandboxAttachmentFlow
|
||||||
|
import net.corda.node.DeterministicSourcesRule
|
||||||
|
import net.corda.node.internal.djvm.DeterministicVerificationException
|
||||||
|
import net.corda.testing.core.ALICE_NAME
|
||||||
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
|
import net.corda.testing.driver.DriverParameters
|
||||||
|
import net.corda.testing.driver.driver
|
||||||
|
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||||
|
import net.corda.testing.node.NotarySpec
|
||||||
|
import net.corda.testing.node.internal.CustomCordapp
|
||||||
|
import net.corda.testing.node.internal.cordappWithPackages
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.junit.ClassRule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.jupiter.api.assertDoesNotThrow
|
||||||
|
import org.junit.jupiter.api.assertThrows
|
||||||
|
|
||||||
|
class SandboxAttachmentsTest {
|
||||||
|
companion object {
|
||||||
|
val logger = loggerFor<SandboxAttachmentsTest>()
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
@JvmField
|
||||||
|
val djvmSources = DeterministicSourcesRule()
|
||||||
|
|
||||||
|
fun parametersFor(djvmSources: DeterministicSourcesRule): DriverParameters {
|
||||||
|
return DriverParameters(
|
||||||
|
portAllocation = incrementalPortAllocation(),
|
||||||
|
startNodesInProcess = false,
|
||||||
|
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)),
|
||||||
|
cordappsForAllNodes = listOf(
|
||||||
|
cordappWithPackages("net.corda.flows.djvm.attachment"),
|
||||||
|
CustomCordapp(
|
||||||
|
packages = setOf("net.corda.contracts.djvm.attachment"),
|
||||||
|
name = "sandbox-attachment-contract",
|
||||||
|
signingInfo = CustomCordapp.SigningInfo()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
djvmBootstrapSource = djvmSources.bootstrap,
|
||||||
|
djvmCordaSource = djvmSources.corda
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test attachment accessible within sandbox`() {
|
||||||
|
val extractFile = ExtractFile(SandboxAttachmentContract::class.java.name.asResourcePath + ".class")
|
||||||
|
driver(parametersFor(djvmSources)) {
|
||||||
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
|
val txId = assertDoesNotThrow {
|
||||||
|
alice.rpc.startFlow(::SandboxAttachmentFlow, extractFile)
|
||||||
|
.returnValue.getOrThrow()
|
||||||
|
}
|
||||||
|
logger.info("TX-ID: {}", txId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test attachment file not found within sandbox`() {
|
||||||
|
val extractFile = ExtractFile("does/not/Exist.class")
|
||||||
|
driver(parametersFor(djvmSources)) {
|
||||||
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
|
val ex = assertThrows<DeterministicVerificationException> {
|
||||||
|
alice.rpc.startFlow(::SandboxAttachmentFlow, extractFile)
|
||||||
|
.returnValue.getOrThrow()
|
||||||
|
}
|
||||||
|
assertThat(ex)
|
||||||
|
.hasMessageStartingWith("sandbox.net.corda.core.contracts.TransactionVerificationException\$ContractRejection -> ")
|
||||||
|
.hasMessageContaining(" Contract verification failed: does/not/Exist.class, " )
|
||||||
|
.hasMessageContaining(" contract: sandbox.net.corda.contracts.djvm.attachment.SandboxAttachmentContract, ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user