mirror of
https://github.com/corda/corda.git
synced 2025-01-27 14:49:35 +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) {
|
||||
throw IllegalStateException("Failed to validate signatures in command data")
|
||||
require(cryptoData.isNotEmpty() && validators.isNotEmpty() && isValid) {
|
||||
"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