Revert design changes to attachment demo (#540)

Restructure attachment demo

Restructure attachment demo to pass the attachment hash in the transaction outputs,
rather than trying to use shared memory. Also remove 1kb test for attachments as there's little value in having a smaller test case.
This commit is contained in:
Ross Nicoll 2017-04-19 10:12:01 +01:00 committed by GitHub
parent 8e0a0ba8fb
commit 022b38b7dc
2 changed files with 33 additions and 34 deletions

View File

@ -13,18 +13,9 @@ import org.junit.Test
import java.util.concurrent.CompletableFuture
class AttachmentDemoTest {
// run with the default 1K bytes in-memory zip file.
@Test fun `attachment demo`() {
attachmentDemo()
}
// run with a 10,000,000 bytes in-memory zip file. In practice, a slightly bigger file will be used (~10,002,000 bytes).
@Test fun `attachment demo using a 10MB zip file`() {
attachmentDemo(10000000)
}
// An in-memory zip file will be used as InputStream, with a size slightly bigger than numOfExpectedBytes.
private fun attachmentDemo(numOfExpectedBytes: Int = 1024) {
val numOfExpectedBytes = 10_000_000
driver(dsl = {
val demoUser = listOf(User("demo", "demo", setOf("StartFlow.net.corda.flows.FinalityFlow")))
val (nodeA, nodeB) = Futures.allAsList(

View File

@ -3,21 +3,22 @@ package net.corda.attachmentdemo
import com.google.common.net.HostAndPort
import joptsimple.OptionParser
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.contracts.Contract
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.TransactionForContract
import net.corda.core.contracts.TransactionType
import net.corda.core.crypto.Party
import net.corda.core.crypto.SecureHash
import net.corda.core.div
import net.corda.core.getOrThrow
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow
import net.corda.core.sizedInputStreamAndHash
import net.corda.core.utilities.ALICE_KEY
import net.corda.core.utilities.DUMMY_NOTARY
import net.corda.core.utilities.DUMMY_NOTARY_KEY
import net.corda.core.utilities.Emoji
import net.corda.flows.FinalityFlow
import net.corda.nodeapi.config.SSLConfiguration
import java.io.InputStream
import java.nio.file.Path
import java.nio.file.Paths
import java.security.PublicKey
import kotlin.system.exitProcess
import kotlin.test.assertEquals
@ -57,8 +58,6 @@ fun main(args: Array<String>) {
}
}
var EXPECTED_HASH = SecureHash.zeroHash // Note: We could use another random default value to initialize it.
/** An in memory test zip attachment of at least numOfClearBytes size, will be used. */
fun sender(rpc: CordaRPCOps, numOfClearBytes: Int = 1024) { // default size 1K.
val (inputStream, hash) = sizedInputStreamAndHash(numOfClearBytes)
@ -66,7 +65,6 @@ fun sender(rpc: CordaRPCOps, numOfClearBytes: Int = 1024) { // default size 1K.
}
fun sender(rpc: CordaRPCOps, inputStream: InputStream, hash: SecureHash.SHA256) {
EXPECTED_HASH = hash
// Get the identity key of the other side (the recipient).
val otherSide: Party = rpc.partyFromName("Bank B")!!
@ -78,15 +76,14 @@ fun sender(rpc: CordaRPCOps, inputStream: InputStream, hash: SecureHash.SHA256)
}
}
// Create a trivial transaction that just passes across the attachment - in normal cases there would be
// inputs, outputs and commands that refer to this attachment.
val ptx = TransactionType.General.Builder(notary = null)
// Create a trivial transaction with an output that describes the attachment, and the attachment itself
val ptx = TransactionType.General.Builder(notary = DUMMY_NOTARY)
require(rpc.attachmentExists(hash))
ptx.addOutputState(AttachmentContract.State(hash))
ptx.addAttachment(hash)
// TODO: Add a dummy state and specify a notary, so that the tx hash is randomised each time and the demo can be repeated.
// Despite not having any states, we have to have at least one signature on the transaction
ptx.signWith(ALICE_KEY)
// Sign with the notary key
ptx.signWith(DUMMY_NOTARY_KEY)
// Send the transaction to the other recipient
val stx = ptx.toSignedTransaction()
@ -101,9 +98,13 @@ fun recipient(rpc: CordaRPCOps) {
val stx = rpc.verifiedTransactions().second.toBlocking().first()
val wtx = stx.tx
if (wtx.attachments.isNotEmpty()) {
assertEquals(EXPECTED_HASH, wtx.attachments.first())
require(rpc.attachmentExists(EXPECTED_HASH))
println("File received - we're happy!\n\nFinal transaction is:\n\n${Emoji.renderIfSupported(wtx)}")
if (wtx.outputs.isNotEmpty()) {
val state = wtx.outputs.map { it.data }.filterIsInstance<AttachmentContract.State>().single()
require(rpc.attachmentExists(state.hash))
println("File received - we're happy!\n\nFinal transaction is:\n\n${Emoji.renderIfSupported(wtx)}")
} else {
println("Error: no output state found in ${wtx.id}")
}
} else {
println("Error: no attachments found in ${wtx.id}")
}
@ -118,11 +119,18 @@ private fun printHelp(parser: OptionParser) {
parser.printHelpOn(System.out)
}
// TODO: Take this out once we have a dedicated RPC port and allow SSL on it to be optional.
private fun sslConfigFor(nodename: String, certsPath: String?): SSLConfiguration {
return object : SSLConfiguration {
override val keyStorePassword: String = "cordacadevpass"
override val trustStorePassword: String = "trustpass"
override val certificatesDirectory: Path = if (certsPath != null) Paths.get(certsPath) else Paths.get("build") / "nodes" / nodename / "certificates"
class AttachmentContract : Contract {
override val legalContractReference: SecureHash
get() = TODO("not implemented")
override fun verify(tx: TransactionForContract) {
val state = tx.outputs.filterIsInstance<AttachmentContract.State>().single()
val attachment = tx.attachments.single()
require(state.hash == attachment.id)
}
}
data class State(val hash: SecureHash.SHA256) : ContractState {
override val contract: Contract = AttachmentContract()
override val participants: List<PublicKey> = emptyList()
}
}