ENT-2506 restore the attachment party signers (#4255)

* ENT-2506 restore the attachment party signers

* ENT-2506 restore the attachment party signers

* ENT-2506 restore the attachment party signers

* ENT-2675 Address code review changes.

* ENT-2675 Address code review changes.
This commit is contained in:
Tudor Malene
2018-11-22 18:35:30 +00:00
committed by GitHub
parent c41960520c
commit 4c8dabc288
21 changed files with 66 additions and 34 deletions

View File

@ -431,7 +431,9 @@ public static final class net.corda.core.contracts.AmountTransfer$Companion exte
public interface net.corda.core.contracts.Attachment extends net.corda.core.contracts.NamedByHash public interface net.corda.core.contracts.Attachment extends net.corda.core.contracts.NamedByHash
public void extractFile(String, java.io.OutputStream) public void extractFile(String, java.io.OutputStream)
@NotNull @NotNull
public abstract java.util.List<java.security.PublicKey> getSigners() public abstract java.util.List<java.security.PublicKey> getSignerKeys()
@NotNull
public abstract java.util.List<net.corda.core.identity.Party> getSigners()
public abstract int getSize() public abstract int getSize()
@NotNull @NotNull
public abstract java.io.InputStream open() public abstract java.io.InputStream open()
@ -542,7 +544,7 @@ public final class net.corda.core.contracts.ContractAttachment extends java.lang
@NotNull @NotNull
public net.corda.core.crypto.SecureHash getId() public net.corda.core.crypto.SecureHash getId()
@NotNull @NotNull
public java.util.List<java.security.PublicKey> getSigners() public java.util.List<net.corda.core.identity.Party> getSigners()
public int getSize() public int getSize()
@Nullable @Nullable
public final String getUploader() public final String getUploader()

View File

@ -234,7 +234,7 @@ class JacksonSupportTest(@Suppress("unused") private val name: String, factory:
val attachment = rigorousMock<ContractAttachment>() val attachment = rigorousMock<ContractAttachment>()
doReturn(attachment).whenever(attachmentStorage).openAttachment(attachmentId) doReturn(attachment).whenever(attachmentStorage).openAttachment(attachmentId)
doReturn(attachmentId).whenever(attachment).id doReturn(attachmentId).whenever(attachment).id
doReturn(emptyList<Party>()).whenever(attachment).signers doReturn(emptyList<Party>()).whenever(attachment).signerKeys
doReturn(setOf(DummyContract.PROGRAM_ID)).whenever(attachment).allContracts doReturn(setOf(DummyContract.PROGRAM_ID)).whenever(attachment).allContracts
doReturn("app").whenever(attachment).uploader doReturn("app").whenever(attachment).uploader

View File

@ -40,10 +40,12 @@ class AttachmentTest {
@Before @Before
fun setup() { fun setup() {
attachment = object : Attachment { attachment = object : Attachment {
override val signerKeys: List<PublicKey>
get() = listOf(ALICE_KEY)
override val id: SecureHash override val id: SecureHash
get() = SecureHash.allOnesHash get() = SecureHash.allOnesHash
override val signers: List<PublicKey> override val signers: List<Party>
get() = listOf(ALICE_KEY) get() = listOf(ALICE)
override val size: Int override val size: Int
get() = jarData.size get() = jarData.size

View File

@ -3,13 +3,19 @@ package net.corda.deterministic.verifier
import net.corda.core.contracts.Attachment import net.corda.core.contracts.Attachment
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.identity.Party
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.InputStream import java.io.InputStream
import java.security.PublicKey import java.security.PublicKey
@CordaSerializable @CordaSerializable
class MockContractAttachment(override val id: SecureHash = SecureHash.zeroHash, val contract: ContractClassName, override val signers: List<PublicKey> = emptyList()) : Attachment { class MockContractAttachment(
override val id: SecureHash = SecureHash.zeroHash,
val contract: ContractClassName,
override val signerKeys: List<PublicKey> = emptyList(),
override val signers: List<Party> = emptyList()
) : Attachment {
override fun open(): InputStream = ByteArrayInputStream(id.bytes) override fun open(): InputStream = ByteArrayInputStream(id.bytes)
override val size = id.size override val size = id.size
} }

View File

@ -1,6 +1,8 @@
package net.corda.core.contracts package net.corda.core.contracts
import net.corda.core.DoNotImplement
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.identity.Party
import net.corda.core.internal.extractFile import net.corda.core.internal.extractFile
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import java.io.FileNotFoundException import java.io.FileNotFoundException
@ -31,6 +33,7 @@ import java.util.jar.JarInputStream
*/ */
@KeepForDJVM @KeepForDJVM
@CordaSerializable @CordaSerializable
@DoNotImplement
interface Attachment : NamedByHash { interface Attachment : NamedByHash {
fun open(): InputStream fun open(): InputStream
@ -51,11 +54,20 @@ interface Attachment : NamedByHash {
@JvmDefault @JvmDefault
fun extractFile(path: String, outputTo: OutputStream) = openAsJAR().use { it.extractFile(path, outputTo) } fun extractFile(path: String, outputTo: OutputStream) = openAsJAR().use { it.extractFile(path, outputTo) }
/**
* The parties that have correctly signed the whole attachment.
* Even though this returns a list of party objects, it is not required that these parties exist on the network, but rather they are a mapping from the signing key to the X.500 name.
*
* Note: Anyone can sign attachments, not only Corda parties. It's recommended to use [signerKeys].
*/
@Deprecated("Use signerKeys. There is no requirement that attachment signers are Corda parties.")
val signers: List<Party>
/** /**
* The keys that have correctly signed the whole attachment. * The keys that have correctly signed the whole attachment.
* Can be empty, for example non-contract attachments won't be necessarily be signed. * Can be empty, for example non-contract attachments won't be necessarily be signed.
*/ */
val signers: List<PublicKey> val signerKeys: List<PublicKey>
/** /**
* Attachment size in bytes. * Attachment size in bytes.

View File

@ -72,7 +72,7 @@ interface AttachmentConstraint {
// You can transition from the WhitelistConstraint to the SignatureConstraint only if all signers of the JAR are required to sign in the future. // You can transition from the WhitelistConstraint to the SignatureConstraint only if all signers of the JAR are required to sign in the future.
input is WhitelistedByZoneAttachmentConstraint && output is SignatureAttachmentConstraint -> input is WhitelistedByZoneAttachmentConstraint && output is SignatureAttachmentConstraint ->
attachment.signers.isNotEmpty() && output.key.keys.containsAll(attachment.signers) attachment.signerKeys.isNotEmpty() && output.key.keys.containsAll(attachment.signerKeys)
else -> false else -> false
} }
@ -180,5 +180,5 @@ data class SignatureAttachmentConstraint(
val key: PublicKey val key: PublicKey
) : AttachmentConstraint { ) : AttachmentConstraint {
override fun isSatisfiedBy(attachment: Attachment): Boolean = override fun isSatisfiedBy(attachment: Attachment): Boolean =
key.isFulfilledBy(attachment.signers.map { it }) key.isFulfilledBy(attachment.signerKeys.map { it })
} }

View File

@ -18,7 +18,7 @@ class ContractAttachment @JvmOverloads constructor(
val contract: ContractClassName, val contract: ContractClassName,
val additionalContracts: Set<ContractClassName> = emptySet(), val additionalContracts: Set<ContractClassName> = emptySet(),
val uploader: String? = null, val uploader: String? = null,
override val signers: List<PublicKey> = emptyList()) : Attachment by attachment { override val signerKeys: List<PublicKey> = emptyList()) : Attachment by attachment {
val allContracts: Set<ContractClassName> get() = additionalContracts + contract val allContracts: Set<ContractClassName> get() = additionalContracts + contract

View File

@ -6,6 +6,7 @@ import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.contracts.Attachment import net.corda.core.contracts.Attachment
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.identity.Party
import net.corda.core.serialization.MissingAttachmentsException import net.corda.core.serialization.MissingAttachmentsException
import net.corda.core.serialization.SerializeAsTokenContext import net.corda.core.serialization.SerializeAsTokenContext
import java.io.FileNotFoundException import java.io.FileNotFoundException
@ -47,10 +48,15 @@ abstract class AbstractAttachment(dataLoader: () -> ByteArray) : Attachment {
override val size: Int get() = attachmentData.size override val size: Int get() = attachmentData.size
override fun open(): InputStream = attachmentData.inputStream() override fun open(): InputStream = attachmentData.inputStream()
override val signers: List<PublicKey> by lazy {
override val signerKeys: List<PublicKey> by lazy {
openAsJAR().use(JarSignatureCollector::collectSigners) openAsJAR().use(JarSignatureCollector::collectSigners)
} }
override val signers: List<Party> by lazy {
openAsJAR().use(JarSignatureCollector::collectSigningParties)
}
override fun equals(other: Any?) = other === this || other is Attachment && other.id == this.id override fun equals(other: Any?) = other === this || other is Attachment && other.id == this.id
override fun hashCode() = id.hashCode() override fun hashCode() = id.hashCode()
override fun toString() = "${javaClass.simpleName}(id=$id)" override fun toString() = "${javaClass.simpleName}(id=$id)"

View File

@ -252,7 +252,7 @@ data class ContractUpgradeLedgerTransaction(
private fun verifyConstraints() { private fun verifyConstraints() {
val attachmentForConstraintVerification = AttachmentWithContext( val attachmentForConstraintVerification = AttachmentWithContext(
legacyContractAttachment as? ContractAttachment legacyContractAttachment as? ContractAttachment
?: ContractAttachment(legacyContractAttachment, legacyContractClassName, signers = legacyContractAttachment.signers), ?: ContractAttachment(legacyContractAttachment, legacyContractClassName, signerKeys = legacyContractAttachment.signerKeys),
upgradedContract.legacyContract, upgradedContract.legacyContract,
networkParameters.whitelistedContractImplementations networkParameters.whitelistedContractImplementations
) )

View File

@ -166,7 +166,7 @@ data class LedgerTransaction private constructor(
contractsAndOwners.forEach { contract, owner -> contractsAndOwners.forEach { contract, owner ->
val attachment = contractAttachmentsByContract[contract]!! val attachment = contractAttachmentsByContract[contract]!!
if (!owner.isFulfilledBy(attachment.signers)) { if (!owner.isFulfilledBy(attachment.signerKeys)) {
throw TransactionVerificationException.ContractAttachmentNotSignedByPackageOwnerException(this.id, id, contract) throw TransactionVerificationException.ContractAttachmentNotSignedByPackageOwnerException(this.id, id, contract)
} }
} }

View File

@ -19,7 +19,6 @@ import net.corda.core.node.services.AttachmentId
import net.corda.core.node.services.KeyManagementService import net.corda.core.node.services.KeyManagementService
import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationFactory import net.corda.core.serialization.SerializationFactory
import net.corda.core.utilities.loggerFor
import net.corda.core.utilities.contextLogger import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.warnOnce import net.corda.core.utilities.warnOnce
import java.security.PublicKey import java.security.PublicKey
@ -310,7 +309,7 @@ open class TransactionBuilder @JvmOverloads constructor(
attachmentToUse: ContractAttachment, attachmentToUse: ContractAttachment,
services: ServicesForResolution): AttachmentConstraint = when { services: ServicesForResolution): AttachmentConstraint = when {
inputStates != null -> attachmentConstraintsTransition(inputStates.groupBy { it.constraint }.keys, attachmentToUse) inputStates != null -> attachmentConstraintsTransition(inputStates.groupBy { it.constraint }.keys, attachmentToUse)
attachmentToUse.signers.isNotEmpty() && services.networkParameters.minimumPlatformVersion < 4 -> { attachmentToUse.signerKeys.isNotEmpty() && services.networkParameters.minimumPlatformVersion < 4 -> {
log.warnOnce("Signature constraints not available on network requiring a minimum platform version of 4. Current is: ${services.networkParameters.minimumPlatformVersion}.") log.warnOnce("Signature constraints not available on network requiring a minimum platform version of 4. Current is: ${services.networkParameters.minimumPlatformVersion}.")
if (useWhitelistedByZoneAttachmentConstraint(contractClassName, services.networkParameters)) { if (useWhitelistedByZoneAttachmentConstraint(contractClassName, services.networkParameters)) {
log.warnOnce("Reverting back to using whitelisted zone constraints for contract $contractClassName") log.warnOnce("Reverting back to using whitelisted zone constraints for contract $contractClassName")
@ -320,7 +319,7 @@ open class TransactionBuilder @JvmOverloads constructor(
HashAttachmentConstraint(attachmentToUse.id) HashAttachmentConstraint(attachmentToUse.id)
} }
} }
attachmentToUse.signers.isNotEmpty() -> makeSignatureAttachmentConstraint(attachmentToUse.signers) attachmentToUse.signerKeys.isNotEmpty() -> makeSignatureAttachmentConstraint(attachmentToUse.signerKeys)
useWhitelistedByZoneAttachmentConstraint(contractClassName, services.networkParameters) -> WhitelistedByZoneAttachmentConstraint useWhitelistedByZoneAttachmentConstraint(contractClassName, services.networkParameters) -> WhitelistedByZoneAttachmentConstraint
else -> HashAttachmentConstraint(attachmentToUse.id) else -> HashAttachmentConstraint(attachmentToUse.id)
} }
@ -361,8 +360,8 @@ open class TransactionBuilder @JvmOverloads constructor(
constraints.any { it is SignatureAttachmentConstraint } && constraints.any { it is WhitelistedByZoneAttachmentConstraint } -> { constraints.any { it is SignatureAttachmentConstraint } && constraints.any { it is WhitelistedByZoneAttachmentConstraint } -> {
val signatureConstraint = constraints.mapNotNull { it as? SignatureAttachmentConstraint }.single() val signatureConstraint = constraints.mapNotNull { it as? SignatureAttachmentConstraint }.single()
when { when {
attachmentToUse.signers.isEmpty() -> throw IllegalArgumentException("Cannot mix a state with the WhitelistedByZoneAttachmentConstraint and a state with the SignatureAttachmentConstraint, when the latest attachment is not signed. Please contact your Zone operator.") attachmentToUse.signerKeys.isEmpty() -> throw IllegalArgumentException("Cannot mix a state with the WhitelistedByZoneAttachmentConstraint and a state with the SignatureAttachmentConstraint, when the latest attachment is not signed. Please contact your Zone operator.")
signatureConstraint.key.keys.containsAll(attachmentToUse.signers) -> signatureConstraint signatureConstraint.key.keys.containsAll(attachmentToUse.signerKeys) -> signatureConstraint
else -> throw IllegalArgumentException("Attempting to transition a WhitelistedByZoneAttachmentConstraint state backed by an attachment signed by multiple parties to a weaker SignatureConstraint that does not require all those signatures. Please contact your Zone operator.") else -> throw IllegalArgumentException("Attempting to transition a WhitelistedByZoneAttachmentConstraint state backed by an attachment signed by multiple parties to a weaker SignatureConstraint that does not require all those signatures. Please contact your Zone operator.")
} }
} }

View File

@ -7,7 +7,6 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.MissingContractAttachments
import net.corda.finance.POUNDS import net.corda.finance.POUNDS
import net.corda.finance.`issued by` import net.corda.finance.`issued by`
import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.Cash
@ -223,7 +222,7 @@ class ConstraintsPropagationTests {
fun `Attachment canBeTransitionedFrom behaves as expected`() { fun `Attachment canBeTransitionedFrom behaves as expected`() {
val attachment = mock<ContractAttachment>() val attachment = mock<ContractAttachment>()
whenever(attachment.signers).thenReturn(listOf(ALICE_PARTY.owningKey)) whenever(attachment.signerKeys).thenReturn(listOf(ALICE_PARTY.owningKey))
// Exhaustive positive check // Exhaustive positive check
assertTrue(HashAttachmentConstraint(SecureHash.randomSHA256()).canBeTransitionedFrom(SignatureAttachmentConstraint(ALICE_PUBKEY), attachment)) assertTrue(HashAttachmentConstraint(SecureHash.randomSHA256()).canBeTransitionedFrom(SignatureAttachmentConstraint(ALICE_PUBKEY), attachment))

View File

@ -3,6 +3,7 @@ package net.corda.core.contracts
import com.nhaarman.mockito_kotlin.doAnswer import com.nhaarman.mockito_kotlin.doAnswer
import com.nhaarman.mockito_kotlin.spy import com.nhaarman.mockito_kotlin.spy
import com.nhaarman.mockito_kotlin.whenever import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.identity.Party
import org.junit.Test import org.junit.Test
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.IOException import java.io.IOException
@ -30,7 +31,8 @@ class AttachmentTest {
val attachment = object : Attachment { val attachment = object : Attachment {
override val id get() = throw UnsupportedOperationException() override val id get() = throw UnsupportedOperationException()
override fun open() = inputStream override fun open() = inputStream
override val signers get() = throw UnsupportedOperationException() override val signerKeys get() = throw UnsupportedOperationException()
override val signers: List<Party> get() = throw UnsupportedOperationException()
override val size: Int = 512 override val size: Int = 512
} }
try { try {

View File

@ -111,7 +111,8 @@ class AttachmentSerializationTest {
private class CustomAttachment(override val id: SecureHash, internal val customContent: String) : Attachment { private class CustomAttachment(override val id: SecureHash, internal val customContent: String) : Attachment {
override fun open() = throw UnsupportedOperationException("Not implemented.") override fun open() = throw UnsupportedOperationException("Not implemented.")
override val signers get() = throw UnsupportedOperationException() override val signerKeys get() = throw UnsupportedOperationException()
override val signers: List<Party> get() = throw UnsupportedOperationException()
override val size get() = throw UnsupportedOperationException() override val size get() = throw UnsupportedOperationException()
} }

View File

@ -50,7 +50,7 @@ class TransactionBuilderTest {
doReturn(contractAttachmentId).whenever(attachment).id doReturn(contractAttachmentId).whenever(attachment).id
doReturn(setOf(DummyContract.PROGRAM_ID)).whenever(attachment).allContracts doReturn(setOf(DummyContract.PROGRAM_ID)).whenever(attachment).allContracts
doReturn("app").whenever(attachment).uploader doReturn("app").whenever(attachment).uploader
doReturn(emptyList<Party>()).whenever(attachment).signers doReturn(emptyList<Party>()).whenever(attachment).signerKeys
} }
@Test @Test
@ -128,12 +128,12 @@ class TransactionBuilderTest {
private val unsignedAttachment = ContractAttachment(object : AbstractAttachment({ byteArrayOf() }) { private val unsignedAttachment = ContractAttachment(object : AbstractAttachment({ byteArrayOf() }) {
override val id: SecureHash get() = throw UnsupportedOperationException() override val id: SecureHash get() = throw UnsupportedOperationException()
override val signers: List<PublicKey> get() = emptyList() override val signerKeys: List<PublicKey> get() = emptyList()
}, DummyContract.PROGRAM_ID) }, DummyContract.PROGRAM_ID)
private fun signedAttachment(vararg parties: Party) = ContractAttachment(object : AbstractAttachment({ byteArrayOf() }) { private fun signedAttachment(vararg parties: Party) = ContractAttachment(object : AbstractAttachment({ byteArrayOf() }) {
override val id: SecureHash get() = throw UnsupportedOperationException() override val id: SecureHash get() = throw UnsupportedOperationException()
override val signers: List<PublicKey> get() = parties.map { it.owningKey } override val signerKeys: List<PublicKey> get() = parties.map { it.owningKey }
}, DummyContract.PROGRAM_ID, signers = parties.map { it.owningKey }) }, DummyContract.PROGRAM_ID, signerKeys = parties.map { it.owningKey })
} }

View File

@ -7,6 +7,9 @@ release, see :doc:`upgrade-notes`.
Unreleased Unreleased
---------- ----------
* Marked the `Attachment` interface as `@DoNotImplement` because it is not meant to be extended by CorDapp developers. If you have already done so,
please get in contact on the usual communication channels.
* Added auto-acceptance of network parameters for network updates. This behaviour is available for a subset of the network parameters * Added auto-acceptance of network parameters for network updates. This behaviour is available for a subset of the network parameters
and is configurable via the node config. See :doc:`network-map` for more information. and is configurable via the node config. See :doc:`network-map` for more information.

View File

@ -87,7 +87,7 @@ class AttachmentsClassLoaderStaticContractTests {
doReturn(it.cordappProvider.getContractAttachmentID(AttachmentDummyContract.ATTACHMENT_PROGRAM_ID)).whenever(attachment).id doReturn(it.cordappProvider.getContractAttachmentID(AttachmentDummyContract.ATTACHMENT_PROGRAM_ID)).whenever(attachment).id
doReturn(setOf(AttachmentDummyContract.ATTACHMENT_PROGRAM_ID)).whenever(attachment).allContracts doReturn(setOf(AttachmentDummyContract.ATTACHMENT_PROGRAM_ID)).whenever(attachment).allContracts
doReturn("app").whenever(attachment).uploader doReturn("app").whenever(attachment).uploader
doReturn(emptyList<Party>()).whenever(attachment).signers doReturn(emptyList<Party>()).whenever(attachment).signerKeys
} }
@Test @Test

View File

@ -211,7 +211,7 @@ object DefaultKryoCustomizer {
output.writeString(obj.contract) output.writeString(obj.contract)
kryo.writeClassAndObject(output, obj.additionalContracts) kryo.writeClassAndObject(output, obj.additionalContracts)
output.writeString(obj.uploader) output.writeString(obj.uploader)
kryo.writeClassAndObject(output, obj.signers) kryo.writeClassAndObject(output, obj.signerKeys)
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")

View File

@ -91,7 +91,7 @@ class NodeAttachmentServiceTest {
val signedJar = jarAndSigner.first val signedJar = jarAndSigner.first
signedJar.inputStream().use { jarStream -> signedJar.inputStream().use { jarStream ->
val attachmentId = storage.importAttachment(jarStream, "test", null) val attachmentId = storage.importAttachment(jarStream, "test", null)
assertEquals(listOf(jarAndSigner.second.hash), storage.openAttachment(attachmentId)!!.signers.map { it.hash }) assertEquals(listOf(jarAndSigner.second.hash), storage.openAttachment(attachmentId)!!.signerKeys.map { it.hash })
} }
} }
} }
@ -102,7 +102,7 @@ class NodeAttachmentServiceTest {
val jarName = makeTestContractJar(it.path, "com.example.MyContract") val jarName = makeTestContractJar(it.path, "com.example.MyContract")
it.path.resolve(jarName).inputStream().use { jarStream -> it.path.resolve(jarName).inputStream().use { jarStream ->
val attachmentId = storage.importAttachment(jarStream, "test", null) val attachmentId = storage.importAttachment(jarStream, "test", null)
assertEquals(0, storage.openAttachment(attachmentId)!!.signers.size) assertEquals(0, storage.openAttachment(attachmentId)!!.signerKeys.size)
} }
} }
} }

View File

@ -24,7 +24,7 @@ class ContractAttachmentSerializer(factory: SerializerFactory) : CustomSerialize
} catch (e: Exception) { } catch (e: Exception) {
throw MissingAttachmentsException(listOf(obj.id)) throw MissingAttachmentsException(listOf(obj.id))
} }
return ContractAttachmentProxy(GeneratedAttachment(bytes), obj.contract, obj.additionalContracts, obj.uploader, obj.signers) return ContractAttachmentProxy(GeneratedAttachment(bytes), obj.contract, obj.additionalContracts, obj.uploader, obj.signerKeys)
} }
override fun fromProxy(proxy: ContractAttachmentProxy): ContractAttachment { override fun fromProxy(proxy: ContractAttachmentProxy): ContractAttachment {

View File

@ -61,7 +61,7 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() {
fun getAttachmentIdAndBytes(jar: InputStream): Pair<AttachmentId, ByteArray> = jar.readFully().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, override val signers: List<PublicKey>) : AbstractAttachment(dataLoader) private class MockAttachment(dataLoader: () -> ByteArray, override val id: SecureHash, override val signerKeys: List<PublicKey>) : AbstractAttachment(dataLoader)
private fun importAttachmentInternal(jar: InputStream, uploader: String, contractClassNames: List<ContractClassName>? = null, attachmentId: AttachmentId? = null, signers: List<PublicKey> = emptyList()): AttachmentId { private fun importAttachmentInternal(jar: InputStream, uploader: String, contractClassNames: List<ContractClassName>? = null, attachmentId: AttachmentId? = null, signers: List<PublicKey> = emptyList()): AttachmentId {
// 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.