From c24d991a7e87d60e4966583d0254607b9e49aa7c Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Thu, 25 Feb 2016 19:23:00 +0100 Subject: [PATCH] Introduce a NamedByHash interface, for things that are identified via secure hash. --- core/src/main/kotlin/core/Structures.kt | 25 ++++++++++++++++++++++- core/src/main/kotlin/core/Transactions.kt | 10 +++++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/core/src/main/kotlin/core/Structures.kt b/core/src/main/kotlin/core/Structures.kt index 498e4ea4ef..73aa3d45c4 100644 --- a/core/src/main/kotlin/core/Structures.kt +++ b/core/src/main/kotlin/core/Structures.kt @@ -12,9 +12,16 @@ import core.crypto.SecureHash import core.crypto.toStringShort import core.serialization.OpaqueBytes import core.serialization.serialize +import java.io.InputStream import java.security.PublicKey import java.time.Duration import java.time.Instant +import java.util.jar.JarInputStream + +/** Implemented by anything that can be named by a secure hash value (e.g. transactions, attachments). */ +interface NamedByHash { + val id: SecureHash +} /** * A contract state (or just "state") contains opaque data used by a contract program. It can be thought of as a disk @@ -146,4 +153,20 @@ interface ContractFactory { operator fun get(hash: SecureHash): T } -class UnknownContractException : Exception() \ No newline at end of file +class UnknownContractException : Exception() + +/** + * An attachment is a ZIP (or an optionally signed JAR) that contains one or more files. Attachments are meant to + * contain public static data which can be referenced from transactions and utilised from contracts. Good examples + * of how attachments are meant to be used include: + * + * - Calendar data + * - Fixes (e.g. LIBOR) + * - Smart contract code + * - Legal documents + * - Facts generated by oracles which might be reused a lot + */ +interface Attachment : NamedByHash { + fun open(): InputStream + fun openAsJAR() = JarInputStream(open()) +} \ No newline at end of file diff --git a/core/src/main/kotlin/core/Transactions.kt b/core/src/main/kotlin/core/Transactions.kt index 54ac529403..35eb09f975 100644 --- a/core/src/main/kotlin/core/Transactions.kt +++ b/core/src/main/kotlin/core/Transactions.kt @@ -57,12 +57,13 @@ import java.util.* /** Transaction ready for serialisation, without any signatures attached. */ data class WireTransaction(val inputs: List, val outputs: List, - val commands: List) { + val commands: List) : NamedByHash { // Cache the serialised form of the transaction and its hash to give us fast access to it. @Volatile @Transient private var cachedBits: SerializedBytes? = null val serialized: SerializedBytes get() = cachedBits ?: serialize().apply { cachedBits = this } - val id: SecureHash get() = serialized.hash + override val id: SecureHash get() = serialized.hash + companion object { fun deserialize(bits: SerializedBytes): WireTransaction { val wtx = bits.deserialize() @@ -98,14 +99,15 @@ data class WireTransaction(val inputs: List, } /** Container for a [WireTransaction] and attached signatures. */ -data class SignedTransaction(val txBits: SerializedBytes, val sigs: List) { +data class SignedTransaction(val txBits: SerializedBytes, + val sigs: List) : NamedByHash { init { check(sigs.isNotEmpty()) } /** Lazily calculated access to the deserialised/hashed transaction data. */ val tx: WireTransaction by lazy { WireTransaction.deserialize(txBits) } /** A transaction ID is the hash of the [WireTransaction]. Thus adding or removing a signature does not change it. */ - val id: SecureHash get() = txBits.hash + override val id: SecureHash get() = txBits.hash /** * Verifies the given signatures against the serialized transaction data. Does NOT deserialise or check the contents