mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
Introduced a few helper methods around InputStream.readBytes (#2928)
This commit is contained in:
parent
54db391e3c
commit
53a0aae489
@ -3,6 +3,7 @@ package net.corda.core.flows
|
|||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.internal.FetchDataFlow
|
import net.corda.core.internal.FetchDataFlow
|
||||||
|
import net.corda.core.internal.readFully
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
|
|
||||||
@ -60,7 +61,7 @@ open class DataVendingFlow(val otherSideSession: FlowSession, val payload: Any)
|
|||||||
serviceHub.validatedTransactions.getTransaction(it) ?: throw FetchDataFlow.HashNotFound(it)
|
serviceHub.validatedTransactions.getTransaction(it) ?: throw FetchDataFlow.HashNotFound(it)
|
||||||
}
|
}
|
||||||
FetchDataFlow.DataType.ATTACHMENT -> dataRequest.hashes.map {
|
FetchDataFlow.DataType.ATTACHMENT -> dataRequest.hashes.map {
|
||||||
serviceHub.attachments.openAttachment(it)?.open()?.readBytes() ?: throw FetchDataFlow.HashNotFound(it)
|
serviceHub.attachments.openAttachment(it)?.open()?.readFully() ?: throw FetchDataFlow.HashNotFound(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ abstract class AbstractAttachment(dataLoader: () -> ByteArray) : Attachment {
|
|||||||
fun SerializeAsTokenContext.attachmentDataLoader(id: SecureHash): () -> ByteArray {
|
fun SerializeAsTokenContext.attachmentDataLoader(id: SecureHash): () -> ByteArray {
|
||||||
return {
|
return {
|
||||||
val a = serviceHub.attachments.openAttachment(id) ?: throw MissingAttachmentsException(listOf(id))
|
val a = serviceHub.attachments.openAttachment(id) ?: throw MissingAttachmentsException(listOf(id))
|
||||||
(a as? AbstractAttachment)?.attachmentData ?: a.open().use { it.readBytes() }
|
(a as? AbstractAttachment)?.attachmentData ?: a.open().readFully()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
package net.corda.core.internal
|
package net.corda.core.internal
|
||||||
|
|
||||||
|
import com.google.common.hash.Hashing
|
||||||
|
import com.google.common.hash.HashingInputStream
|
||||||
import net.corda.core.cordapp.Cordapp
|
import net.corda.core.cordapp.Cordapp
|
||||||
import net.corda.core.cordapp.CordappConfig
|
import net.corda.core.cordapp.CordappConfig
|
||||||
import net.corda.core.cordapp.CordappContext
|
import net.corda.core.cordapp.CordappContext
|
||||||
@ -150,8 +152,31 @@ fun Path.writeLines(lines: Iterable<CharSequence>, charset: Charset = UTF_8, var
|
|||||||
|
|
||||||
inline fun <reified T : Any> Path.readObject(): T = readAll().deserialize()
|
inline fun <reified T : Any> Path.readObject(): T = readAll().deserialize()
|
||||||
|
|
||||||
|
/** Calculate the hash of the contents of this file. */
|
||||||
|
val Path.hash: SecureHash get() = read { it.hash() }
|
||||||
|
|
||||||
fun InputStream.copyTo(target: Path, vararg options: CopyOption): Long = Files.copy(this, target, *options)
|
fun InputStream.copyTo(target: Path, vararg options: CopyOption): Long = Files.copy(this, target, *options)
|
||||||
|
|
||||||
|
/** Same as [InputStream.readBytes] but also closes the stream. */
|
||||||
|
fun InputStream.readFully(): ByteArray = use { it.readBytes() }
|
||||||
|
|
||||||
|
/** Calculate the hash of the remaining bytes in this input stream. The stream is closed at the end. */
|
||||||
|
fun InputStream.hash(): SecureHash {
|
||||||
|
return use {
|
||||||
|
val his = HashingInputStream(Hashing.sha256(), it)
|
||||||
|
his.copyTo(NullOutputStream) // To avoid reading in the entire stream into memory just write out the bytes to /dev/null
|
||||||
|
SecureHash.SHA256(his.hash().asBytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Any> InputStream.readObject(): T = readFully().deserialize()
|
||||||
|
|
||||||
|
object NullOutputStream : OutputStream() {
|
||||||
|
override fun write(b: Int) = Unit
|
||||||
|
override fun write(b: ByteArray) = Unit
|
||||||
|
override fun write(b: ByteArray, off: Int, len: Int) = Unit
|
||||||
|
}
|
||||||
|
|
||||||
fun String.abbreviate(maxWidth: Int): String = if (length <= maxWidth) this else take(maxWidth - 1) + "…"
|
fun String.abbreviate(maxWidth: Int): String = if (length <= maxWidth) this else take(maxWidth - 1) + "…"
|
||||||
|
|
||||||
/** Return the sum of an Iterable of [BigDecimal]s. */
|
/** Return the sum of an Iterable of [BigDecimal]s. */
|
||||||
@ -333,7 +358,7 @@ fun URL.post(serializedData: OpaqueBytes): ByteArray {
|
|||||||
setRequestProperty("Content-Type", "application/octet-stream")
|
setRequestProperty("Content-Type", "application/octet-stream")
|
||||||
outputStream.use { serializedData.open().copyTo(it) }
|
outputStream.use { serializedData.open().copyTo(it) }
|
||||||
checkOkResponse()
|
checkOkResponse()
|
||||||
inputStream.use { it.readBytes() }
|
inputStream.readFully()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,7 +371,7 @@ fun HttpURLConnection.checkOkResponse() {
|
|||||||
|
|
||||||
inline fun <reified T : Any> HttpURLConnection.responseAs(): T {
|
inline fun <reified T : Any> HttpURLConnection.responseAs(): T {
|
||||||
checkOkResponse()
|
checkOkResponse()
|
||||||
return inputStream.use { it.readBytes() }.deserialize()
|
return inputStream.readObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Analogous to [Thread.join]. */
|
/** Analogous to [Thread.join]. */
|
||||||
|
@ -7,6 +7,7 @@ import net.corda.core.crypto.sha256
|
|||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FetchAttachmentsFlow
|
import net.corda.core.internal.FetchAttachmentsFlow
|
||||||
import net.corda.core.internal.FetchDataFlow
|
import net.corda.core.internal.FetchDataFlow
|
||||||
|
import net.corda.core.internal.hash
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.node.internal.StartedNode
|
import net.corda.node.internal.StartedNode
|
||||||
import net.corda.node.services.persistence.NodeAttachmentService
|
import net.corda.node.services.persistence.NodeAttachmentService
|
||||||
@ -72,7 +73,7 @@ class AttachmentTests {
|
|||||||
bobNode.attachments.openAttachment(id)!!
|
bobNode.attachments.openAttachment(id)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(id, attachment.open().readBytes().sha256())
|
assertEquals(id, attachment.open().hash())
|
||||||
|
|
||||||
// Shut down node zero and ensure node one can still resolve the attachment.
|
// Shut down node zero and ensure node one can still resolve the attachment.
|
||||||
aliceNode.dispose()
|
aliceNode.dispose()
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
package net.corda.nodeapi.internal.network
|
package net.corda.nodeapi.internal.network
|
||||||
|
|
||||||
import com.google.common.hash.Hashing
|
|
||||||
import com.google.common.hash.HashingInputStream
|
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import net.corda.cordform.CordformNode
|
import net.corda.cordform.CordformNode
|
||||||
import net.corda.core.contracts.ContractClassName
|
|
||||||
import net.corda.core.crypto.SecureHash
|
|
||||||
import net.corda.core.crypto.SecureHash.Companion.parse
|
import net.corda.core.crypto.SecureHash.Companion.parse
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
@ -27,7 +23,6 @@ import net.corda.nodeapi.internal.serialization.SerializationFactoryImpl
|
|||||||
import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme
|
import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme
|
||||||
import net.corda.nodeapi.internal.serialization.kryo.AbstractKryoSerializationScheme
|
import net.corda.nodeapi.internal.serialization.kryo.AbstractKryoSerializationScheme
|
||||||
import net.corda.nodeapi.internal.serialization.kryo.kryoMagic
|
import net.corda.nodeapi.internal.serialization.kryo.kryoMagic
|
||||||
import java.io.File
|
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
@ -191,7 +186,7 @@ class NetworkBootstrapper {
|
|||||||
private fun generateWhitelist(whitelistFile: Path, excludeWhitelistFile: Path, cordapps: List<String>?): Map<String, List<AttachmentId>> {
|
private fun generateWhitelist(whitelistFile: Path, excludeWhitelistFile: Path, cordapps: List<String>?): Map<String, List<AttachmentId>> {
|
||||||
val existingWhitelist = if (whitelistFile.exists()) readContractWhitelist(whitelistFile) else emptyMap()
|
val existingWhitelist = if (whitelistFile.exists()) readContractWhitelist(whitelistFile) else emptyMap()
|
||||||
|
|
||||||
println(if (existingWhitelist.isEmpty()) "No existing whitelist file found." else "Found existing whitelist: ${whitelistFile}")
|
println(if (existingWhitelist.isEmpty()) "No existing whitelist file found." else "Found existing whitelist: $whitelistFile")
|
||||||
|
|
||||||
val excludeContracts = if (excludeWhitelistFile.exists()) readExcludeWhitelist(excludeWhitelistFile) else emptyList()
|
val excludeContracts = if (excludeWhitelistFile.exists()) readExcludeWhitelist(excludeWhitelistFile) else emptyList()
|
||||||
if (excludeContracts.isNotEmpty()) {
|
if (excludeContracts.isNotEmpty()) {
|
||||||
@ -199,7 +194,7 @@ class NetworkBootstrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val newWhiteList = cordapps?.flatMap { cordappJarPath ->
|
val newWhiteList = cordapps?.flatMap { cordappJarPath ->
|
||||||
val jarHash = getJarHash(cordappJarPath)
|
val jarHash = Paths.get(cordappJarPath).hash
|
||||||
scanJarForContracts(cordappJarPath).map { contract ->
|
scanJarForContracts(cordappJarPath).map { contract ->
|
||||||
contract to jarHash
|
contract to jarHash
|
||||||
}
|
}
|
||||||
@ -213,30 +208,26 @@ class NetworkBootstrapper {
|
|||||||
contractClassName to (if (newHash == null || newHash in existing) existing else existing + newHash)
|
contractClassName to (if (newHash == null || newHash in existing) existing else existing + newHash)
|
||||||
}.toMap()
|
}.toMap()
|
||||||
|
|
||||||
println("CorDapp whitelist " + (if (existingWhitelist.isEmpty()) "generated" else "updated") + " in ${whitelistFile}")
|
println("CorDapp whitelist " + (if (existingWhitelist.isEmpty()) "generated" else "updated") + " in $whitelistFile")
|
||||||
return merged
|
return merged
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun overwriteWhitelist(whitelistFile: Path, mergedWhiteList: Map<String, List<AttachmentId>>) {
|
private fun overwriteWhitelist(whitelistFile: Path, mergedWhiteList: Map<String, List<AttachmentId>>) {
|
||||||
PrintStream(whitelistFile.toFile().outputStream()).use { out ->
|
PrintStream(whitelistFile.toFile().outputStream()).use { out ->
|
||||||
mergedWhiteList.forEach { (contract, attachments) ->
|
mergedWhiteList.forEach { (contract, attachments) ->
|
||||||
out.println("${contract}:${attachments.joinToString(",")}")
|
out.println("$contract:${attachments.joinToString(",")}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getJarHash(cordappPath: String): AttachmentId = File(cordappPath).inputStream().use { jar ->
|
private fun readContractWhitelist(file: Path): Map<String, List<AttachmentId>> {
|
||||||
val hs = HashingInputStream(Hashing.sha256(), jar)
|
return file.readAllLines()
|
||||||
hs.readBytes()
|
.map { line -> line.split(":") }
|
||||||
SecureHash.SHA256(hs.hash().asBytes())
|
.map { (contract, attachmentIds) ->
|
||||||
|
contract to (attachmentIds.split(",").map(::parse))
|
||||||
|
}.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readContractWhitelist(file: Path): Map<String, List<AttachmentId>> = file.readAllLines()
|
|
||||||
.map { line -> line.split(":") }
|
|
||||||
.map { (contract, attachmentIds) ->
|
|
||||||
contract to (attachmentIds.split(",").map(::parse))
|
|
||||||
}.toMap()
|
|
||||||
|
|
||||||
private fun readExcludeWhitelist(file: Path): List<String> = file.readAllLines().map(String::trim)
|
private fun readExcludeWhitelist(file: Path): List<String> = file.readAllLines().map(String::trim)
|
||||||
|
|
||||||
private fun NotaryInfo.prettyPrint(): String = "${identity.name} (${if (validating) "" else "non-"}validating)"
|
private fun NotaryInfo.prettyPrint(): String = "${identity.name} (${if (validating) "" else "non-"}validating)"
|
||||||
|
@ -3,6 +3,7 @@ package net.corda.nodeapi.internal.serialization.amqp.custom
|
|||||||
import net.corda.core.contracts.Attachment
|
import net.corda.core.contracts.Attachment
|
||||||
import net.corda.core.contracts.ContractAttachment
|
import net.corda.core.contracts.ContractAttachment
|
||||||
import net.corda.core.contracts.ContractClassName
|
import net.corda.core.contracts.ContractClassName
|
||||||
|
import net.corda.core.internal.readFully
|
||||||
import net.corda.core.serialization.MissingAttachmentsException
|
import net.corda.core.serialization.MissingAttachmentsException
|
||||||
import net.corda.nodeapi.internal.serialization.GeneratedAttachment
|
import net.corda.nodeapi.internal.serialization.GeneratedAttachment
|
||||||
import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer
|
import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer
|
||||||
@ -17,7 +18,7 @@ class ContractAttachmentSerializer(factory: SerializerFactory) : CustomSerialize
|
|||||||
ContractAttachmentProxy::class.java, factory) {
|
ContractAttachmentProxy::class.java, factory) {
|
||||||
override fun toProxy(obj: ContractAttachment): ContractAttachmentProxy {
|
override fun toProxy(obj: ContractAttachment): ContractAttachmentProxy {
|
||||||
val bytes = try {
|
val bytes = try {
|
||||||
obj.attachment.open().readBytes()
|
obj.attachment.open().readFully()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
throw MissingAttachmentsException(listOf(obj.id))
|
throw MissingAttachmentsException(listOf(obj.id))
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import net.corda.core.crypto.CompositeKey
|
|||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.identity.PartyAndCertificate
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.internal.AbstractAttachment
|
import net.corda.core.internal.AbstractAttachment
|
||||||
|
import net.corda.core.internal.readFully
|
||||||
import net.corda.core.serialization.MissingAttachmentsException
|
import net.corda.core.serialization.MissingAttachmentsException
|
||||||
import net.corda.core.serialization.SerializationWhitelist
|
import net.corda.core.serialization.SerializationWhitelist
|
||||||
import net.corda.core.serialization.SerializeAsToken
|
import net.corda.core.serialization.SerializeAsToken
|
||||||
@ -223,7 +224,7 @@ object DefaultKryoCustomizer {
|
|||||||
val lazyAttachment = object : AbstractAttachment({
|
val lazyAttachment = object : AbstractAttachment({
|
||||||
val attachment = attachmentStorage.openAttachment(attachmentHash)
|
val attachment = attachmentStorage.openAttachment(attachmentHash)
|
||||||
?: throw MissingAttachmentsException(listOf(attachmentHash))
|
?: throw MissingAttachmentsException(listOf(attachmentHash))
|
||||||
attachment.open().readBytes()
|
attachment.open().readFully()
|
||||||
}) {
|
}) {
|
||||||
override val id = attachmentHash
|
override val id = attachmentHash
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package net.corda.node.utilities.registration
|
|||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.concurrent.transpose
|
import net.corda.core.internal.concurrent.transpose
|
||||||
import net.corda.core.internal.logElapsedTime
|
import net.corda.core.internal.logElapsedTime
|
||||||
|
import net.corda.core.internal.readFully
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.utilities.*
|
import net.corda.core.utilities.*
|
||||||
import net.corda.finance.DOLLARS
|
import net.corda.finance.DOLLARS
|
||||||
@ -130,7 +131,7 @@ class RegistrationHandler(private val rootCertAndKeyPair: CertificateAndKeyPair)
|
|||||||
@Produces(MediaType.TEXT_PLAIN)
|
@Produces(MediaType.TEXT_PLAIN)
|
||||||
fun registration(input: InputStream): Response {
|
fun registration(input: InputStream): Response {
|
||||||
return log.logElapsedTime("Registration") {
|
return log.logElapsedTime("Registration") {
|
||||||
val certificationRequest = input.use { JcaPKCS10CertificationRequest(it.readBytes()) }
|
val certificationRequest = JcaPKCS10CertificationRequest(input.readFully())
|
||||||
val (certPath, name) = createSignedClientCertificate(
|
val (certPath, name) = createSignedClientCertificate(
|
||||||
certificationRequest,
|
certificationRequest,
|
||||||
rootCertAndKeyPair.keyPair,
|
rootCertAndKeyPair.keyPair,
|
||||||
|
@ -11,9 +11,11 @@ import net.corda.core.contracts.Attachment
|
|||||||
import net.corda.core.contracts.ContractAttachment
|
import net.corda.core.contracts.ContractAttachment
|
||||||
import net.corda.core.contracts.ContractClassName
|
import net.corda.core.contracts.ContractClassName
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.internal.AbstractAttachment
|
import net.corda.core.internal.AbstractAttachment
|
||||||
import net.corda.core.internal.UNKNOWN_UPLOADER
|
import net.corda.core.internal.UNKNOWN_UPLOADER
|
||||||
import net.corda.core.internal.VisibleForTesting
|
import net.corda.core.internal.VisibleForTesting
|
||||||
|
import net.corda.core.internal.readFully
|
||||||
import net.corda.core.node.services.AttachmentId
|
import net.corda.core.node.services.AttachmentId
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
import net.corda.core.node.services.AttachmentStorage
|
||||||
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
||||||
@ -27,7 +29,10 @@ import net.corda.node.utilities.NonInvalidatingWeightBasedCache
|
|||||||
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
|
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
|
||||||
import net.corda.nodeapi.internal.persistence.currentDBSession
|
import net.corda.nodeapi.internal.persistence.currentDBSession
|
||||||
import net.corda.nodeapi.internal.withContractsInJar
|
import net.corda.nodeapi.internal.withContractsInJar
|
||||||
import java.io.*
|
import java.io.FilterInputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.Serializable
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -262,14 +267,6 @@ class NodeAttachmentService(
|
|||||||
return import(jar, uploader, filename)
|
return import(jar, uploader, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAttachmentIdAndBytes(jar: InputStream): Pair<AttachmentId, ByteArray> {
|
|
||||||
val hs = HashingInputStream(Hashing.sha256(), jar)
|
|
||||||
val bytes = hs.readBytes()
|
|
||||||
checkIsAValidJAR(ByteArrayInputStream(bytes))
|
|
||||||
val id = SecureHash.SHA256(hs.hash().asBytes())
|
|
||||||
return Pair(id, bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasAttachment(attachmentId: AttachmentId): Boolean =
|
override fun hasAttachment(attachmentId: AttachmentId): Boolean =
|
||||||
currentDBSession().find(NodeAttachmentService.DBAttachment::class.java, attachmentId.toString()) != null
|
currentDBSession().find(NodeAttachmentService.DBAttachment::class.java, attachmentId.toString()) != null
|
||||||
|
|
||||||
@ -278,15 +275,16 @@ class NodeAttachmentService(
|
|||||||
return withContractsInJar(jar) { contractClassNames, inputStream ->
|
return withContractsInJar(jar) { contractClassNames, inputStream ->
|
||||||
require(inputStream !is JarInputStream)
|
require(inputStream !is JarInputStream)
|
||||||
|
|
||||||
// Read the file into RAM, hashing it to find the ID as we go. The attachment must fit into memory.
|
// Read the file into RAM and then calculate its hash. The attachment must fit into memory.
|
||||||
// TODO: Switch to a two-phase insert so we can handle attachments larger than RAM.
|
// TODO: Switch to a two-phase insert so we can handle attachments larger than RAM.
|
||||||
// To do this we must pipe stream into the database without knowing its hash, which we will learn only once
|
// To do this we must pipe stream into the database without knowing its hash, which we will learn only once
|
||||||
// the insert/upload is complete. We can then query to see if it's a duplicate and if so, erase, and if not
|
// the insert/upload is complete. We can then query to see if it's a duplicate and if so, erase, and if not
|
||||||
// set the hash field of the new attachment record.
|
// set the hash field of the new attachment record.
|
||||||
|
|
||||||
val (id, bytes) = getAttachmentIdAndBytes(inputStream)
|
val bytes = inputStream.readFully()
|
||||||
|
val id = bytes.sha256()
|
||||||
if (!hasAttachment(id)) {
|
if (!hasAttachment(id)) {
|
||||||
checkIsAValidJAR(ByteArrayInputStream(bytes))
|
checkIsAValidJAR(bytes.inputStream())
|
||||||
val session = currentDBSession()
|
val session = currentDBSession()
|
||||||
val attachment = NodeAttachmentService.DBAttachment(attId = id.toString(), content = bytes, uploader = uploader, filename = filename, contractClassNames = contractClassNames)
|
val attachment = NodeAttachmentService.DBAttachment(attId = id.toString(), content = bytes, uploader = uploader, filename = filename, contractClassNames = contractClassNames)
|
||||||
session.save(attachment)
|
session.save(attachment)
|
||||||
|
@ -5,10 +5,7 @@ import com.google.common.jimfs.Configuration
|
|||||||
import com.google.common.jimfs.Jimfs
|
import com.google.common.jimfs.Jimfs
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.internal.read
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.internal.readAll
|
|
||||||
import net.corda.core.internal.write
|
|
||||||
import net.corda.core.internal.writeLines
|
|
||||||
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
||||||
import net.corda.core.node.services.vault.AttachmentSort
|
import net.corda.core.node.services.vault.AttachmentSort
|
||||||
import net.corda.core.node.services.vault.Builder
|
import net.corda.core.node.services.vault.Builder
|
||||||
@ -230,7 +227,7 @@ class NodeAttachmentStorageTest {
|
|||||||
database.transaction {
|
database.transaction {
|
||||||
val storage = NodeAttachmentService(MetricRegistry())
|
val storage = NodeAttachmentService(MetricRegistry())
|
||||||
val e = assertFailsWith<NodeAttachmentService.HashMismatchException> {
|
val e = assertFailsWith<NodeAttachmentService.HashMismatchException> {
|
||||||
storage.openAttachment(id)!!.open().use { it.readBytes() }
|
storage.openAttachment(id)!!.open().readFully()
|
||||||
}
|
}
|
||||||
assertEquals(e.expected, id)
|
assertEquals(e.expected, id)
|
||||||
|
|
||||||
|
@ -2,14 +2,14 @@ package net.corda.testing.node.internal.network
|
|||||||
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.SignedData
|
import net.corda.core.crypto.SignedData
|
||||||
|
import net.corda.core.internal.readObject
|
||||||
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.serialization.deserialize
|
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||||
import net.corda.core.node.NetworkParameters
|
|
||||||
import net.corda.nodeapi.internal.network.NetworkMap
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
import net.corda.nodeapi.internal.network.ParametersUpdate
|
import net.corda.nodeapi.internal.network.ParametersUpdate
|
||||||
import org.eclipse.jetty.server.Server
|
import org.eclipse.jetty.server.Server
|
||||||
@ -110,7 +110,7 @@ class NetworkMapServer(private val pollInterval: Duration,
|
|||||||
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
fun publishNodeInfo(input: InputStream): Response {
|
fun publishNodeInfo(input: InputStream): Response {
|
||||||
return try {
|
return try {
|
||||||
val signedNodeInfo = input.readBytes().deserialize<SignedNodeInfo>()
|
val signedNodeInfo = input.readObject<SignedNodeInfo>()
|
||||||
signedNodeInfo.verified()
|
signedNodeInfo.verified()
|
||||||
nodeInfoMap[signedNodeInfo.raw.hash] = signedNodeInfo
|
nodeInfoMap[signedNodeInfo.raw.hash] = signedNodeInfo
|
||||||
ok()
|
ok()
|
||||||
@ -126,7 +126,7 @@ class NetworkMapServer(private val pollInterval: Duration,
|
|||||||
@Path("ack-parameters")
|
@Path("ack-parameters")
|
||||||
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
fun ackNetworkParameters(input: InputStream): Response {
|
fun ackNetworkParameters(input: InputStream): Response {
|
||||||
val signedParametersHash = input.readBytes().deserialize<SignedData<SecureHash>>()
|
val signedParametersHash = input.readObject<SignedData<SecureHash>>()
|
||||||
val hash = signedParametersHash.verified()
|
val hash = signedParametersHash.verified()
|
||||||
latestAcceptedParametersMap[signedParametersHash.sig.by] = hash
|
latestAcceptedParametersMap[signedParametersHash.sig.by] = hash
|
||||||
return ok().build()
|
return ok().build()
|
||||||
|
@ -7,13 +7,13 @@ import net.corda.core.crypto.SecureHash
|
|||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.internal.AbstractAttachment
|
import net.corda.core.internal.AbstractAttachment
|
||||||
import net.corda.core.internal.UNKNOWN_UPLOADER
|
import net.corda.core.internal.UNKNOWN_UPLOADER
|
||||||
|
import net.corda.core.internal.readFully
|
||||||
import net.corda.core.node.services.AttachmentId
|
import net.corda.core.node.services.AttachmentId
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
import net.corda.core.node.services.AttachmentStorage
|
||||||
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
||||||
import net.corda.core.node.services.vault.AttachmentSort
|
import net.corda.core.node.services.vault.AttachmentSort
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.nodeapi.internal.withContractsInJar
|
import net.corda.nodeapi.internal.withContractsInJar
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.jar.JarInputStream
|
import java.util.jar.JarInputStream
|
||||||
@ -53,7 +53,7 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() {
|
|||||||
|
|
||||||
fun importContractAttachment(contractClassNames: List<ContractClassName>, uploader: String, jar: InputStream): AttachmentId = importAttachmentInternal(jar, uploader, null, contractClassNames)
|
fun importContractAttachment(contractClassNames: List<ContractClassName>, uploader: String, jar: InputStream): AttachmentId = importAttachmentInternal(jar, uploader, null, contractClassNames)
|
||||||
|
|
||||||
fun getAttachmentIdAndBytes(jar: InputStream): Pair<AttachmentId, ByteArray> = jar.readBytes().let { bytes -> Pair(bytes.sha256(), bytes) }
|
fun getAttachmentIdAndBytes(jar: InputStream): Pair<AttachmentId, ByteArray> = jar.readFully().let { bytes -> Pair(bytes.sha256(), bytes) }
|
||||||
|
|
||||||
private class MockAttachment(dataLoader: () -> ByteArray, override val id: SecureHash) : AbstractAttachment(dataLoader)
|
private class MockAttachment(dataLoader: () -> ByteArray, override val id: SecureHash) : AbstractAttachment(dataLoader)
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() {
|
|||||||
// JIS makes read()/readBytes() return bytes of the current file, but we want to hash the entire container here.
|
// JIS makes read()/readBytes() return bytes of the current file, but we want to hash the entire container here.
|
||||||
require(jar !is JarInputStream)
|
require(jar !is JarInputStream)
|
||||||
|
|
||||||
val bytes = jar.readBytes()
|
val bytes = jar.readFully()
|
||||||
|
|
||||||
val sha256 = bytes.sha256()
|
val sha256 = bytes.sha256()
|
||||||
if (sha256 !in files.keys) {
|
if (sha256 !in files.keys) {
|
||||||
|
Loading…
Reference in New Issue
Block a user