mirror of
https://github.com/corda/corda.git
synced 2025-06-05 09:00:53 +00:00
[CORDA-941]: Add NetworkParameters contract implementation whitelist. (#2580)
This commit is contained in:
parent
977836f4eb
commit
5be0e4b39e
@ -14,8 +14,6 @@
|
|||||||
public void setMessage(String)
|
public void setMessage(String)
|
||||||
public void setOriginalExceptionClassName(String)
|
public void setOriginalExceptionClassName(String)
|
||||||
##
|
##
|
||||||
public @interface net.corda.core.CordaInternal
|
|
||||||
##
|
|
||||||
public final class net.corda.core.CordaOID extends java.lang.Object
|
public final class net.corda.core.CordaOID extends java.lang.Object
|
||||||
@org.jetbrains.annotations.NotNull public static final String CORDA_PLATFORM = "1.3.6.1.4.1.50530.1"
|
@org.jetbrains.annotations.NotNull public static final String CORDA_PLATFORM = "1.3.6.1.4.1.50530.1"
|
||||||
public static final net.corda.core.CordaOID INSTANCE
|
public static final net.corda.core.CordaOID INSTANCE
|
||||||
@ -209,7 +207,7 @@ public static final class net.corda.core.context.Trace$InvocationId$Companion ex
|
|||||||
public static final class net.corda.core.context.Trace$SessionId$Companion extends java.lang.Object
|
public static final class net.corda.core.context.Trace$SessionId$Companion extends java.lang.Object
|
||||||
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public final net.corda.core.context.Trace$SessionId newInstance(String, java.time.Instant)
|
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public final net.corda.core.context.Trace$SessionId newInstance(String, java.time.Instant)
|
||||||
##
|
##
|
||||||
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.contracts.AlwaysAcceptAttachmentConstraint extends java.lang.Object implements net.corda.core.contracts.AttachmentConstraint
|
@net.corda.core.serialization.CordaSerializable @net.corda.core.DoNotImplement public final class net.corda.core.contracts.AlwaysAcceptAttachmentConstraint extends java.lang.Object implements net.corda.core.contracts.AttachmentConstraint
|
||||||
public boolean isSatisfiedBy(net.corda.core.contracts.Attachment)
|
public boolean isSatisfiedBy(net.corda.core.contracts.Attachment)
|
||||||
public static final net.corda.core.contracts.AlwaysAcceptAttachmentConstraint INSTANCE
|
public static final net.corda.core.contracts.AlwaysAcceptAttachmentConstraint INSTANCE
|
||||||
##
|
##
|
||||||
@ -284,14 +282,14 @@ public static final class net.corda.core.contracts.AmountTransfer$Companion exte
|
|||||||
@org.jetbrains.annotations.NotNull public abstract java.io.InputStream open()
|
@org.jetbrains.annotations.NotNull public abstract java.io.InputStream open()
|
||||||
@org.jetbrains.annotations.NotNull public abstract jar.JarInputStream openAsJAR()
|
@org.jetbrains.annotations.NotNull public abstract jar.JarInputStream openAsJAR()
|
||||||
##
|
##
|
||||||
@net.corda.core.serialization.CordaSerializable public interface net.corda.core.contracts.AttachmentConstraint
|
@net.corda.core.serialization.CordaSerializable @net.corda.core.DoNotImplement public interface net.corda.core.contracts.AttachmentConstraint
|
||||||
public abstract boolean isSatisfiedBy(net.corda.core.contracts.Attachment)
|
public abstract boolean isSatisfiedBy(net.corda.core.contracts.Attachment)
|
||||||
##
|
##
|
||||||
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.contracts.AttachmentResolutionException extends net.corda.core.flows.FlowException
|
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.contracts.AttachmentResolutionException extends net.corda.core.flows.FlowException
|
||||||
public <init>(net.corda.core.crypto.SecureHash)
|
public <init>(net.corda.core.crypto.SecureHash)
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash getHash()
|
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash getHash()
|
||||||
##
|
##
|
||||||
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.contracts.AutomaticHashConstraint extends java.lang.Object implements net.corda.core.contracts.AttachmentConstraint
|
@net.corda.core.serialization.CordaSerializable @net.corda.core.DoNotImplement public final class net.corda.core.contracts.AutomaticHashConstraint extends java.lang.Object implements net.corda.core.contracts.AttachmentConstraint
|
||||||
public boolean isSatisfiedBy(net.corda.core.contracts.Attachment)
|
public boolean isSatisfiedBy(net.corda.core.contracts.Attachment)
|
||||||
public static final net.corda.core.contracts.AutomaticHashConstraint INSTANCE
|
public static final net.corda.core.contracts.AutomaticHashConstraint INSTANCE
|
||||||
##
|
##
|
||||||
@ -343,14 +341,20 @@ public final class net.corda.core.contracts.ComponentGroupEnum extends java.lang
|
|||||||
##
|
##
|
||||||
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.contracts.ContractAttachment extends java.lang.Object implements net.corda.core.contracts.Attachment
|
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.contracts.ContractAttachment extends java.lang.Object implements net.corda.core.contracts.Attachment
|
||||||
public <init>(net.corda.core.contracts.Attachment, String)
|
public <init>(net.corda.core.contracts.Attachment, String)
|
||||||
|
public <init>(net.corda.core.contracts.Attachment, String, Set)
|
||||||
|
public <init>(net.corda.core.contracts.Attachment, String, Set, String)
|
||||||
public void extractFile(String, java.io.OutputStream)
|
public void extractFile(String, java.io.OutputStream)
|
||||||
|
@org.jetbrains.annotations.NotNull public final Set getAdditionalContracts()
|
||||||
|
@org.jetbrains.annotations.NotNull public final Set getAllContracts()
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.core.contracts.Attachment getAttachment()
|
@org.jetbrains.annotations.NotNull public final net.corda.core.contracts.Attachment getAttachment()
|
||||||
@org.jetbrains.annotations.NotNull public final String getContract()
|
@org.jetbrains.annotations.NotNull public final String getContract()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.SecureHash getId()
|
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.SecureHash getId()
|
||||||
@org.jetbrains.annotations.NotNull public List getSigners()
|
@org.jetbrains.annotations.NotNull public List getSigners()
|
||||||
public int getSize()
|
public int getSize()
|
||||||
|
@org.jetbrains.annotations.Nullable public final String getUploader()
|
||||||
@org.jetbrains.annotations.NotNull public java.io.InputStream open()
|
@org.jetbrains.annotations.NotNull public java.io.InputStream open()
|
||||||
@org.jetbrains.annotations.NotNull public jar.JarInputStream openAsJAR()
|
@org.jetbrains.annotations.NotNull public jar.JarInputStream openAsJAR()
|
||||||
|
@org.jetbrains.annotations.NotNull public String toString()
|
||||||
##
|
##
|
||||||
@net.corda.core.serialization.CordaSerializable public interface net.corda.core.contracts.ContractState
|
@net.corda.core.serialization.CordaSerializable public interface net.corda.core.contracts.ContractState
|
||||||
@org.jetbrains.annotations.NotNull public abstract List getParticipants()
|
@org.jetbrains.annotations.NotNull public abstract List getParticipants()
|
||||||
@ -366,7 +370,7 @@ public final class net.corda.core.contracts.ContractsDSL extends java.lang.Objec
|
|||||||
@org.jetbrains.annotations.NotNull public abstract Collection getExitKeys()
|
@org.jetbrains.annotations.NotNull public abstract Collection getExitKeys()
|
||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.contracts.FungibleAsset withNewOwnerAndAmount(net.corda.core.contracts.Amount, net.corda.core.identity.AbstractParty)
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.contracts.FungibleAsset withNewOwnerAndAmount(net.corda.core.contracts.Amount, net.corda.core.identity.AbstractParty)
|
||||||
##
|
##
|
||||||
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.contracts.HashAttachmentConstraint extends java.lang.Object implements net.corda.core.contracts.AttachmentConstraint
|
@net.corda.core.serialization.CordaSerializable @net.corda.core.DoNotImplement public final class net.corda.core.contracts.HashAttachmentConstraint extends java.lang.Object implements net.corda.core.contracts.AttachmentConstraint
|
||||||
public <init>(net.corda.core.crypto.SecureHash)
|
public <init>(net.corda.core.crypto.SecureHash)
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash component1()
|
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash component1()
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.core.contracts.HashAttachmentConstraint copy(net.corda.core.crypto.SecureHash)
|
@org.jetbrains.annotations.NotNull public final net.corda.core.contracts.HashAttachmentConstraint copy(net.corda.core.crypto.SecureHash)
|
||||||
@ -557,6 +561,9 @@ public final class net.corda.core.contracts.TransactionStateKt extends java.lang
|
|||||||
@net.corda.core.serialization.CordaSerializable public abstract class net.corda.core.contracts.TransactionVerificationException extends net.corda.core.flows.FlowException
|
@net.corda.core.serialization.CordaSerializable public abstract class net.corda.core.contracts.TransactionVerificationException extends net.corda.core.flows.FlowException
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash getTxId()
|
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash getTxId()
|
||||||
##
|
##
|
||||||
|
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$ConflictingAttachmentsRejection extends net.corda.core.contracts.TransactionVerificationException
|
||||||
|
public <init>(net.corda.core.crypto.SecureHash, String)
|
||||||
|
##
|
||||||
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$ContractConstraintRejection extends net.corda.core.contracts.TransactionVerificationException
|
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$ContractConstraintRejection extends net.corda.core.contracts.TransactionVerificationException
|
||||||
public <init>(net.corda.core.crypto.SecureHash, String)
|
public <init>(net.corda.core.crypto.SecureHash, String)
|
||||||
##
|
##
|
||||||
@ -620,6 +627,10 @@ public static final class net.corda.core.contracts.UniqueIdentifier$Companion ex
|
|||||||
@org.jetbrains.annotations.NotNull public abstract String getLegacyContract()
|
@org.jetbrains.annotations.NotNull public abstract String getLegacyContract()
|
||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.contracts.ContractState upgrade(net.corda.core.contracts.ContractState)
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.contracts.ContractState upgrade(net.corda.core.contracts.ContractState)
|
||||||
##
|
##
|
||||||
|
@net.corda.core.serialization.CordaSerializable @net.corda.core.DoNotImplement public final class net.corda.core.contracts.WhitelistedByZoneAttachmentConstraint extends java.lang.Object implements net.corda.core.contracts.AttachmentConstraint
|
||||||
|
public boolean isSatisfiedBy(net.corda.core.contracts.Attachment)
|
||||||
|
public static final net.corda.core.contracts.WhitelistedByZoneAttachmentConstraint INSTANCE
|
||||||
|
##
|
||||||
@net.corda.core.DoNotImplement public interface net.corda.core.cordapp.Cordapp
|
@net.corda.core.DoNotImplement public interface net.corda.core.cordapp.Cordapp
|
||||||
@org.jetbrains.annotations.NotNull public abstract List getContractClassNames()
|
@org.jetbrains.annotations.NotNull public abstract List getContractClassNames()
|
||||||
@org.jetbrains.annotations.NotNull public abstract List getCordappClasses()
|
@org.jetbrains.annotations.NotNull public abstract List getCordappClasses()
|
||||||
@ -634,10 +645,25 @@ public static final class net.corda.core.contracts.UniqueIdentifier$Companion ex
|
|||||||
@org.jetbrains.annotations.NotNull public abstract List getServiceFlows()
|
@org.jetbrains.annotations.NotNull public abstract List getServiceFlows()
|
||||||
@org.jetbrains.annotations.NotNull public abstract List getServices()
|
@org.jetbrains.annotations.NotNull public abstract List getServices()
|
||||||
##
|
##
|
||||||
|
@net.corda.core.DoNotImplement public interface net.corda.core.cordapp.CordappConfig
|
||||||
|
public abstract boolean exists(String)
|
||||||
|
@org.jetbrains.annotations.NotNull public abstract Object get(String)
|
||||||
|
public abstract boolean getBoolean(String)
|
||||||
|
public abstract double getDouble(String)
|
||||||
|
public abstract float getFloat(String)
|
||||||
|
public abstract int getInt(String)
|
||||||
|
public abstract long getLong(String)
|
||||||
|
@org.jetbrains.annotations.NotNull public abstract Number getNumber(String)
|
||||||
|
@org.jetbrains.annotations.NotNull public abstract String getString(String)
|
||||||
|
##
|
||||||
|
public final class net.corda.core.cordapp.CordappConfigException extends java.lang.Exception
|
||||||
|
public <init>(String, Throwable)
|
||||||
|
##
|
||||||
public final class net.corda.core.cordapp.CordappContext extends java.lang.Object
|
public final class net.corda.core.cordapp.CordappContext extends java.lang.Object
|
||||||
public <init>(net.corda.core.cordapp.Cordapp, net.corda.core.crypto.SecureHash, ClassLoader, net.corda.core.cordapp.CordappConfig)
|
public <init>(net.corda.core.cordapp.Cordapp, net.corda.core.crypto.SecureHash, ClassLoader, net.corda.core.cordapp.CordappConfig)
|
||||||
@org.jetbrains.annotations.Nullable public final net.corda.core.crypto.SecureHash getAttachmentId()
|
@org.jetbrains.annotations.Nullable public final net.corda.core.crypto.SecureHash getAttachmentId()
|
||||||
@org.jetbrains.annotations.NotNull public final ClassLoader getClassLoader()
|
@org.jetbrains.annotations.NotNull public final ClassLoader getClassLoader()
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.cordapp.CordappConfig getConfig()
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.core.cordapp.Cordapp getCordapp()
|
@org.jetbrains.annotations.NotNull public final net.corda.core.cordapp.Cordapp getCordapp()
|
||||||
##
|
##
|
||||||
@net.corda.core.DoNotImplement public interface net.corda.core.cordapp.CordappProvider
|
@net.corda.core.DoNotImplement public interface net.corda.core.cordapp.CordappProvider
|
||||||
@ -1305,6 +1331,39 @@ public @interface net.corda.core.flows.InitiatedBy
|
|||||||
public @interface net.corda.core.flows.InitiatingFlow
|
public @interface net.corda.core.flows.InitiatingFlow
|
||||||
public abstract int version()
|
public abstract int version()
|
||||||
##
|
##
|
||||||
|
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.flows.NotarisationPayload extends java.lang.Object
|
||||||
|
public <init>(Object, net.corda.core.flows.NotarisationRequestSignature)
|
||||||
|
@org.jetbrains.annotations.NotNull public final Object component1()
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.flows.NotarisationRequestSignature component2()
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.flows.NotarisationPayload copy(Object, net.corda.core.flows.NotarisationRequestSignature)
|
||||||
|
public boolean equals(Object)
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.transactions.CoreTransaction getCoreTransaction()
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.flows.NotarisationRequestSignature getRequestSignature()
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.transactions.SignedTransaction getSignedTransaction()
|
||||||
|
@org.jetbrains.annotations.NotNull public final Object getTransaction()
|
||||||
|
public int hashCode()
|
||||||
|
public String toString()
|
||||||
|
##
|
||||||
|
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.flows.NotarisationRequest extends java.lang.Object
|
||||||
|
public <init>(List, net.corda.core.crypto.SecureHash)
|
||||||
|
@org.jetbrains.annotations.NotNull public final List getStatesToConsume()
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash getTransactionId()
|
||||||
|
public final void verifySignature(net.corda.core.flows.NotarisationRequestSignature, net.corda.core.identity.Party)
|
||||||
|
public static final net.corda.core.flows.NotarisationRequest$Companion Companion
|
||||||
|
##
|
||||||
|
public static final class net.corda.core.flows.NotarisationRequest$Companion extends java.lang.Object
|
||||||
|
##
|
||||||
|
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.flows.NotarisationRequestSignature extends java.lang.Object
|
||||||
|
public <init>(net.corda.core.crypto.DigitalSignature$WithKey, int)
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.DigitalSignature$WithKey component1()
|
||||||
|
public final int component2()
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.flows.NotarisationRequestSignature copy(net.corda.core.crypto.DigitalSignature$WithKey, int)
|
||||||
|
public boolean equals(Object)
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.DigitalSignature$WithKey getDigitalSignature()
|
||||||
|
public final int getPlatformVersion()
|
||||||
|
public int hashCode()
|
||||||
|
public String toString()
|
||||||
|
##
|
||||||
@net.corda.core.flows.InitiatingFlow public final class net.corda.core.flows.NotaryChangeFlow extends net.corda.core.flows.AbstractStateReplacementFlow$Instigator
|
@net.corda.core.flows.InitiatingFlow public final class net.corda.core.flows.NotaryChangeFlow extends net.corda.core.flows.AbstractStateReplacementFlow$Instigator
|
||||||
public <init>(net.corda.core.contracts.StateAndRef, net.corda.core.identity.Party, net.corda.core.utilities.ProgressTracker)
|
public <init>(net.corda.core.contracts.StateAndRef, net.corda.core.identity.Party, net.corda.core.utilities.ProgressTracker)
|
||||||
@org.jetbrains.annotations.NotNull protected net.corda.core.flows.AbstractStateReplacementFlow$UpgradeTx assembleTx()
|
@org.jetbrains.annotations.NotNull protected net.corda.core.flows.AbstractStateReplacementFlow$UpgradeTx assembleTx()
|
||||||
@ -1331,6 +1390,15 @@ public @interface net.corda.core.flows.InitiatingFlow
|
|||||||
public int hashCode()
|
public int hashCode()
|
||||||
@org.jetbrains.annotations.NotNull public String toString()
|
@org.jetbrains.annotations.NotNull public String toString()
|
||||||
##
|
##
|
||||||
|
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.flows.NotaryError$RequestSignatureInvalid extends net.corda.core.flows.NotaryError
|
||||||
|
public <init>(Throwable)
|
||||||
|
@org.jetbrains.annotations.NotNull public final Throwable component1()
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.flows.NotaryError$RequestSignatureInvalid copy(Throwable)
|
||||||
|
public boolean equals(Object)
|
||||||
|
@org.jetbrains.annotations.NotNull public final Throwable getCause()
|
||||||
|
public int hashCode()
|
||||||
|
@org.jetbrains.annotations.NotNull public String toString()
|
||||||
|
##
|
||||||
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.flows.NotaryError$TimeWindowInvalid extends net.corda.core.flows.NotaryError
|
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.flows.NotaryError$TimeWindowInvalid extends net.corda.core.flows.NotaryError
|
||||||
public <init>(java.time.Instant, net.corda.core.contracts.TimeWindow)
|
public <init>(java.time.Instant, net.corda.core.contracts.TimeWindow)
|
||||||
@org.jetbrains.annotations.NotNull public final java.time.Instant component1()
|
@org.jetbrains.annotations.NotNull public final java.time.Instant component1()
|
||||||
@ -1369,6 +1437,7 @@ public final class net.corda.core.flows.NotaryFlow extends java.lang.Object
|
|||||||
public <init>(net.corda.core.transactions.SignedTransaction)
|
public <init>(net.corda.core.transactions.SignedTransaction)
|
||||||
public <init>(net.corda.core.transactions.SignedTransaction, net.corda.core.utilities.ProgressTracker)
|
public <init>(net.corda.core.transactions.SignedTransaction, net.corda.core.utilities.ProgressTracker)
|
||||||
@co.paralleluniverse.fibers.Suspendable @org.jetbrains.annotations.NotNull public List call()
|
@co.paralleluniverse.fibers.Suspendable @org.jetbrains.annotations.NotNull public List call()
|
||||||
|
@org.jetbrains.annotations.NotNull protected final net.corda.core.identity.Party checkTransaction()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.utilities.ProgressTracker getProgressTracker()
|
@org.jetbrains.annotations.NotNull public net.corda.core.utilities.ProgressTracker getProgressTracker()
|
||||||
@co.paralleluniverse.fibers.Suspendable @org.jetbrains.annotations.NotNull protected final net.corda.core.utilities.UntrustworthyData notarise(net.corda.core.identity.Party)
|
@co.paralleluniverse.fibers.Suspendable @org.jetbrains.annotations.NotNull protected final net.corda.core.utilities.UntrustworthyData notarise(net.corda.core.identity.Party)
|
||||||
@org.jetbrains.annotations.NotNull protected final List validateResponse(net.corda.core.utilities.UntrustworthyData, net.corda.core.identity.Party)
|
@org.jetbrains.annotations.NotNull protected final List validateResponse(net.corda.core.utilities.UntrustworthyData, net.corda.core.identity.Party)
|
||||||
@ -1748,14 +1817,15 @@ public @interface net.corda.core.messaging.RPCReturnsObservables
|
|||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.messaging.FlowProgressHandle startTrackedFlow(net.corda.core.flows.FlowLogic)
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.messaging.FlowProgressHandle startTrackedFlow(net.corda.core.flows.FlowLogic)
|
||||||
##
|
##
|
||||||
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.node.NetworkParameters extends java.lang.Object
|
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.node.NetworkParameters extends java.lang.Object
|
||||||
public <init>(int, List, int, int, java.time.Instant, int)
|
public <init>(int, List, int, int, java.time.Instant, int, Map)
|
||||||
public final int component1()
|
public final int component1()
|
||||||
@org.jetbrains.annotations.NotNull public final List component2()
|
@org.jetbrains.annotations.NotNull public final List component2()
|
||||||
public final int component3()
|
public final int component3()
|
||||||
public final int component4()
|
public final int component4()
|
||||||
@org.jetbrains.annotations.NotNull public final java.time.Instant component5()
|
@org.jetbrains.annotations.NotNull public final java.time.Instant component5()
|
||||||
public final int component6()
|
public final int component6()
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.core.node.NetworkParameters copy(int, List, int, int, java.time.Instant, int)
|
@org.jetbrains.annotations.NotNull public final Map component7()
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.node.NetworkParameters copy(int, List, int, int, java.time.Instant, int, Map)
|
||||||
public boolean equals(Object)
|
public boolean equals(Object)
|
||||||
public final int getEpoch()
|
public final int getEpoch()
|
||||||
public final int getMaxMessageSize()
|
public final int getMaxMessageSize()
|
||||||
@ -1763,6 +1833,7 @@ public @interface net.corda.core.messaging.RPCReturnsObservables
|
|||||||
public final int getMinimumPlatformVersion()
|
public final int getMinimumPlatformVersion()
|
||||||
@org.jetbrains.annotations.NotNull public final java.time.Instant getModifiedTime()
|
@org.jetbrains.annotations.NotNull public final java.time.Instant getModifiedTime()
|
||||||
@org.jetbrains.annotations.NotNull public final List getNotaries()
|
@org.jetbrains.annotations.NotNull public final List getNotaries()
|
||||||
|
@org.jetbrains.annotations.NotNull public final Map getWhitelistedContractImplementations()
|
||||||
public int hashCode()
|
public int hashCode()
|
||||||
public String toString()
|
public String toString()
|
||||||
##
|
##
|
||||||
@ -1804,6 +1875,7 @@ public @interface net.corda.core.messaging.RPCReturnsObservables
|
|||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction, java.security.PublicKey)
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction, java.security.PublicKey)
|
||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction)
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction)
|
||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction, java.security.PublicKey)
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction, java.security.PublicKey)
|
||||||
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.cordapp.CordappContext getAppContext()
|
||||||
@org.jetbrains.annotations.NotNull public abstract java.time.Clock getClock()
|
@org.jetbrains.annotations.NotNull public abstract java.time.Clock getClock()
|
||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.node.services.ContractUpgradeService getContractUpgradeService()
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.node.services.ContractUpgradeService getContractUpgradeService()
|
||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.node.services.KeyManagementService getKeyManagementService()
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.node.services.KeyManagementService getKeyManagementService()
|
||||||
@ -1826,6 +1898,7 @@ public @interface net.corda.core.messaging.RPCReturnsObservables
|
|||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.node.services.AttachmentStorage getAttachments()
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.node.services.AttachmentStorage getAttachments()
|
||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.cordapp.CordappProvider getCordappProvider()
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.cordapp.CordappProvider getCordappProvider()
|
||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.node.services.IdentityService getIdentityService()
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.node.services.IdentityService getIdentityService()
|
||||||
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.node.NetworkParameters getNetworkParameters()
|
||||||
##
|
##
|
||||||
@net.corda.core.DoNotImplement public interface net.corda.core.node.StateLoader
|
@net.corda.core.DoNotImplement public interface net.corda.core.node.StateLoader
|
||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.contracts.TransactionState loadState(net.corda.core.contracts.StateRef)
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.contracts.TransactionState loadState(net.corda.core.contracts.StateRef)
|
||||||
@ -1838,9 +1911,9 @@ public final class net.corda.core.node.StatesToRecord extends java.lang.Enum
|
|||||||
##
|
##
|
||||||
@net.corda.core.DoNotImplement public interface net.corda.core.node.services.AttachmentStorage
|
@net.corda.core.DoNotImplement public interface net.corda.core.node.services.AttachmentStorage
|
||||||
public abstract boolean hasAttachment(net.corda.core.crypto.SecureHash)
|
public abstract boolean hasAttachment(net.corda.core.crypto.SecureHash)
|
||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.crypto.SecureHash importAttachment(java.io.InputStream)
|
@kotlin.Deprecated @org.jetbrains.annotations.NotNull public abstract net.corda.core.crypto.SecureHash importAttachment(java.io.InputStream)
|
||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.crypto.SecureHash importAttachment(java.io.InputStream, String, String)
|
@org.jetbrains.annotations.NotNull public abstract net.corda.core.crypto.SecureHash importAttachment(java.io.InputStream, String, String)
|
||||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.crypto.SecureHash importOrGetAttachment(java.io.InputStream)
|
@kotlin.Deprecated @org.jetbrains.annotations.NotNull public abstract net.corda.core.crypto.SecureHash importOrGetAttachment(java.io.InputStream)
|
||||||
@org.jetbrains.annotations.Nullable public abstract net.corda.core.contracts.Attachment openAttachment(net.corda.core.crypto.SecureHash)
|
@org.jetbrains.annotations.Nullable public abstract net.corda.core.contracts.Attachment openAttachment(net.corda.core.crypto.SecureHash)
|
||||||
@org.jetbrains.annotations.NotNull public abstract List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria, net.corda.core.node.services.vault.AttachmentSort)
|
@org.jetbrains.annotations.NotNull public abstract List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria, net.corda.core.node.services.vault.AttachmentSort)
|
||||||
##
|
##
|
||||||
@ -2968,6 +3041,7 @@ public static final class net.corda.core.transactions.FilteredTransaction$Compan
|
|||||||
##
|
##
|
||||||
@net.corda.core.serialization.CordaSerializable @net.corda.core.DoNotImplement public final class net.corda.core.transactions.LedgerTransaction extends net.corda.core.transactions.FullTransaction
|
@net.corda.core.serialization.CordaSerializable @net.corda.core.DoNotImplement public final class net.corda.core.transactions.LedgerTransaction extends net.corda.core.transactions.FullTransaction
|
||||||
public <init>(List, List, List, List, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt)
|
public <init>(List, List, List, List, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt)
|
||||||
|
public <init>(List, List, List, List, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt, net.corda.core.node.NetworkParameters)
|
||||||
@org.jetbrains.annotations.NotNull public final List commandsOfType(Class)
|
@org.jetbrains.annotations.NotNull public final List commandsOfType(Class)
|
||||||
@org.jetbrains.annotations.NotNull public final List component1()
|
@org.jetbrains.annotations.NotNull public final List component1()
|
||||||
@org.jetbrains.annotations.NotNull public final List component2()
|
@org.jetbrains.annotations.NotNull public final List component2()
|
||||||
@ -2978,6 +3052,7 @@ public static final class net.corda.core.transactions.FilteredTransaction$Compan
|
|||||||
@org.jetbrains.annotations.Nullable public final net.corda.core.contracts.TimeWindow component7()
|
@org.jetbrains.annotations.Nullable public final net.corda.core.contracts.TimeWindow component7()
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.core.contracts.PrivacySalt component8()
|
@org.jetbrains.annotations.NotNull public final net.corda.core.contracts.PrivacySalt component8()
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.core.transactions.LedgerTransaction copy(List, List, List, List, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt)
|
@org.jetbrains.annotations.NotNull public final net.corda.core.transactions.LedgerTransaction copy(List, List, List, List, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt)
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.transactions.LedgerTransaction copy(List, List, List, List, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt, net.corda.core.node.NetworkParameters)
|
||||||
public boolean equals(Object)
|
public boolean equals(Object)
|
||||||
@org.jetbrains.annotations.NotNull public final List filterCommands(Class, function.Predicate)
|
@org.jetbrains.annotations.NotNull public final List filterCommands(Class, function.Predicate)
|
||||||
@org.jetbrains.annotations.NotNull public final List filterInRefs(Class, function.Predicate)
|
@org.jetbrains.annotations.NotNull public final List filterInRefs(Class, function.Predicate)
|
||||||
@ -3690,6 +3765,7 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
|
|||||||
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withExtraCordappPackagesToScan(List)
|
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withExtraCordappPackagesToScan(List)
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withIsDebug(boolean)
|
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withIsDebug(boolean)
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withJmxPolicy(net.corda.testing.driver.JmxPolicy)
|
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withJmxPolicy(net.corda.testing.driver.JmxPolicy)
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withNetworkParameters(net.corda.core.node.NetworkParameters)
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withNotarySpecs(List)
|
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withNotarySpecs(List)
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withPortAllocation(net.corda.testing.driver.PortAllocation)
|
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withPortAllocation(net.corda.testing.driver.PortAllocation)
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withStartNodesInProcess(boolean)
|
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters withStartNodesInProcess(boolean)
|
||||||
@ -4014,6 +4090,7 @@ public class net.corda.testing.node.MockServices extends java.lang.Object implem
|
|||||||
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction, java.security.PublicKey)
|
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction, java.security.PublicKey)
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction)
|
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction)
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction, java.security.PublicKey)
|
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction, java.security.PublicKey)
|
||||||
|
@org.jetbrains.annotations.NotNull public net.corda.core.cordapp.CordappContext getAppContext()
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.testing.services.MockAttachmentStorage getAttachments()
|
@org.jetbrains.annotations.NotNull public final net.corda.testing.services.MockAttachmentStorage getAttachments()
|
||||||
@org.jetbrains.annotations.NotNull public java.time.Clock getClock()
|
@org.jetbrains.annotations.NotNull public java.time.Clock getClock()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.ContractUpgradeService getContractUpgradeService()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.ContractUpgradeService getContractUpgradeService()
|
||||||
@ -4024,6 +4101,7 @@ public class net.corda.testing.node.MockServices extends java.lang.Object implem
|
|||||||
@org.jetbrains.annotations.NotNull public static final net.corda.node.VersionInfo getMOCK_VERSION_INFO()
|
@org.jetbrains.annotations.NotNull public static final net.corda.node.VersionInfo getMOCK_VERSION_INFO()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.NodeInfo getMyInfo()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.NodeInfo getMyInfo()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.NetworkMapCache getNetworkMapCache()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.NetworkMapCache getNetworkMapCache()
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.node.NetworkParameters getNetworkParameters()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.TransactionVerifierService getTransactionVerifierService()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.TransactionVerifierService getTransactionVerifierService()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.node.services.api.WritableTransactionStorage getValidatedTransactions()
|
@org.jetbrains.annotations.NotNull public net.corda.node.services.api.WritableTransactionStorage getValidatedTransactions()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.VaultService getVaultService()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.VaultService getVaultService()
|
||||||
@ -4062,6 +4140,7 @@ public static final class net.corda.testing.node.MockServicesKt$createMockCordaS
|
|||||||
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction, java.security.PublicKey)
|
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction, java.security.PublicKey)
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction)
|
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction)
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction, java.security.PublicKey)
|
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction, java.security.PublicKey)
|
||||||
|
@org.jetbrains.annotations.NotNull public net.corda.core.cordapp.CordappContext getAppContext()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.AttachmentStorage getAttachments()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.AttachmentStorage getAttachments()
|
||||||
@org.jetbrains.annotations.NotNull public java.time.Clock getClock()
|
@org.jetbrains.annotations.NotNull public java.time.Clock getClock()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.ContractUpgradeService getContractUpgradeService()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.ContractUpgradeService getContractUpgradeService()
|
||||||
@ -4070,6 +4149,7 @@ public static final class net.corda.testing.node.MockServicesKt$createMockCordaS
|
|||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.KeyManagementService getKeyManagementService()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.KeyManagementService getKeyManagementService()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.NodeInfo getMyInfo()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.NodeInfo getMyInfo()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.NetworkMapCache getNetworkMapCache()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.NetworkMapCache getNetworkMapCache()
|
||||||
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.NetworkParameters getNetworkParameters()
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.testing.node.MockServices getServiceHub()
|
@org.jetbrains.annotations.NotNull public final net.corda.testing.node.MockServices getServiceHub()
|
||||||
@org.jetbrains.annotations.NotNull public final net.corda.core.serialization.SerializeAsToken getServiceInstance()
|
@org.jetbrains.annotations.NotNull public final net.corda.core.serialization.SerializeAsToken getServiceInstance()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.TransactionVerifierService getTransactionVerifierService()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.TransactionVerifierService getTransactionVerifierService()
|
||||||
@ -4135,6 +4215,7 @@ public final class net.corda.testing.node.StartedMockNode extends java.lang.Obje
|
|||||||
@org.jetbrains.annotations.NotNull public final rx.Observable registerInitiatedFlow(Class)
|
@org.jetbrains.annotations.NotNull public final rx.Observable registerInitiatedFlow(Class)
|
||||||
public final void setMessagingServiceSpy(net.corda.testing.node.MessagingServiceSpy)
|
public final void setMessagingServiceSpy(net.corda.testing.node.MessagingServiceSpy)
|
||||||
public final void stop()
|
public final void stop()
|
||||||
|
public final Object transaction(kotlin.jvm.functions.Function0)
|
||||||
public static final net.corda.testing.node.StartedMockNode$Companion Companion
|
public static final net.corda.testing.node.StartedMockNode$Companion Companion
|
||||||
##
|
##
|
||||||
public static final class net.corda.testing.node.StartedMockNode$Companion extends java.lang.Object
|
public static final class net.corda.testing.node.StartedMockNode$Companion extends java.lang.Object
|
||||||
@ -4553,6 +4634,7 @@ public static final class net.corda.testing.dsl.TestTransactionDSLInterpreter$se
|
|||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.AttachmentStorage getAttachments()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.AttachmentStorage getAttachments()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.cordapp.CordappProvider getCordappProvider()
|
@org.jetbrains.annotations.NotNull public net.corda.core.cordapp.CordappProvider getCordappProvider()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.IdentityService getIdentityService()
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.services.IdentityService getIdentityService()
|
||||||
|
@org.jetbrains.annotations.NotNull public net.corda.core.node.NetworkParameters getNetworkParameters()
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.contracts.TransactionState loadState(net.corda.core.contracts.StateRef)
|
@org.jetbrains.annotations.NotNull public net.corda.core.contracts.TransactionState loadState(net.corda.core.contracts.StateRef)
|
||||||
@org.jetbrains.annotations.NotNull public Set loadStates(Set)
|
@org.jetbrains.annotations.NotNull public Set loadStates(Set)
|
||||||
##
|
##
|
||||||
@ -4640,6 +4722,7 @@ public final class net.corda.testing.services.MockAttachmentStorage extends net.
|
|||||||
public boolean hasAttachment(net.corda.core.crypto.SecureHash)
|
public boolean hasAttachment(net.corda.core.crypto.SecureHash)
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.SecureHash importAttachment(java.io.InputStream)
|
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.SecureHash importAttachment(java.io.InputStream)
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.SecureHash importAttachment(java.io.InputStream, String, String)
|
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.SecureHash importAttachment(java.io.InputStream, String, String)
|
||||||
|
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash importContractAttachment(List, String, java.io.InputStream)
|
||||||
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.SecureHash importOrGetAttachment(java.io.InputStream)
|
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.SecureHash importOrGetAttachment(java.io.InputStream)
|
||||||
@org.jetbrains.annotations.Nullable public net.corda.core.contracts.Attachment openAttachment(net.corda.core.crypto.SecureHash)
|
@org.jetbrains.annotations.Nullable public net.corda.core.contracts.Attachment openAttachment(net.corda.core.crypto.SecureHash)
|
||||||
@org.jetbrains.annotations.NotNull public List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria, net.corda.core.node.services.vault.AttachmentSort)
|
@org.jetbrains.annotations.NotNull public List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria, net.corda.core.node.services.vault.AttachmentSort)
|
||||||
|
31
build.gradle
31
build.gradle
@ -116,7 +116,6 @@ ext {
|
|||||||
apply plugin: 'project-report'
|
apply plugin: 'project-report'
|
||||||
apply plugin: 'com.github.ben-manes.versions'
|
apply plugin: 'com.github.ben-manes.versions'
|
||||||
apply plugin: 'net.corda.plugins.publish-utils'
|
apply plugin: 'net.corda.plugins.publish-utils'
|
||||||
apply plugin: 'net.corda.plugins.cordformation'
|
|
||||||
apply plugin: 'maven-publish'
|
apply plugin: 'maven-publish'
|
||||||
apply plugin: 'com.jfrog.artifactory'
|
apply plugin: 'com.jfrog.artifactory'
|
||||||
|
|
||||||
@ -262,36 +261,6 @@ tasks.withType(Test) {
|
|||||||
reports.html.destination = file("${reporting.baseDir}/${name}")
|
reports.html.destination = file("${reporting.baseDir}/${name}")
|
||||||
}
|
}
|
||||||
|
|
||||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|
||||||
directory "./build/nodes"
|
|
||||||
node {
|
|
||||||
name "O=Controller,OU=corda,L=London,C=GB"
|
|
||||||
notary = [validating : true]
|
|
||||||
p2pPort 10002
|
|
||||||
cordapps = []
|
|
||||||
}
|
|
||||||
node {
|
|
||||||
name "O=Bank A,OU=corda,L=London,C=GB"
|
|
||||||
p2pPort 10012
|
|
||||||
rpcSettings {
|
|
||||||
address "localhost:10013"
|
|
||||||
adminAddress "localhost:10023"
|
|
||||||
}
|
|
||||||
webPort 10014
|
|
||||||
cordapps = []
|
|
||||||
}
|
|
||||||
node {
|
|
||||||
name "O=Bank B,OU=corda,L=London,C=GB"
|
|
||||||
p2pAddress "localhost:10007"
|
|
||||||
rpcSettings {
|
|
||||||
address "localhost:10018"
|
|
||||||
adminAddress "localhost:10028"
|
|
||||||
}
|
|
||||||
webAddress "localhost:10009"
|
|
||||||
cordapps = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bintrayConfig {
|
bintrayConfig {
|
||||||
user = System.getenv('CORDA_BINTRAY_USER')
|
user = System.getenv('CORDA_BINTRAY_USER')
|
||||||
key = System.getenv('CORDA_BINTRAY_KEY')
|
key = System.getenv('CORDA_BINTRAY_KEY')
|
||||||
|
@ -10,6 +10,7 @@ import net.corda.core.identity.CordaX500Name
|
|||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.finance.USD
|
import net.corda.finance.USD
|
||||||
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.contracts.DummyContract
|
import net.corda.testing.contracts.DummyContract
|
||||||
import net.corda.testing.core.ALICE_NAME
|
import net.corda.testing.core.ALICE_NAME
|
||||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
@ -101,6 +102,7 @@ class JacksonSupportTest {
|
|||||||
fun writeTransaction() {
|
fun writeTransaction() {
|
||||||
val attachmentRef = SecureHash.randomSHA256()
|
val attachmentRef = SecureHash.randomSHA256()
|
||||||
doReturn(attachmentRef).whenever(cordappProvider).getContractAttachmentID(DummyContract.PROGRAM_ID)
|
doReturn(attachmentRef).whenever(cordappProvider).getContractAttachmentID(DummyContract.PROGRAM_ID)
|
||||||
|
doReturn(testNetworkParameters()).whenever(services).networkParameters
|
||||||
fun makeDummyTx(): SignedTransaction {
|
fun makeDummyTx(): SignedTransaction {
|
||||||
val wtx = DummyContract.generateInitial(1, DUMMY_NOTARY, MINI_CORP.ref(1))
|
val wtx = DummyContract.generateInitial(1, DUMMY_NOTARY, MINI_CORP.ref(1))
|
||||||
.toWireTransaction(services)
|
.toWireTransaction(services)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
gradlePluginsVersion=4.0.0
|
gradlePluginsVersion=4.0.2
|
||||||
kotlinVersion=1.2.20
|
kotlinVersion=1.2.20
|
||||||
platformVersion=2
|
platformVersion=2
|
||||||
guavaVersion=21.0
|
guavaVersion=21.0
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package net.corda.core.contracts
|
package net.corda.core.contracts
|
||||||
|
|
||||||
|
import net.corda.core.DoNotImplement
|
||||||
|
import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint.isSatisfiedBy
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.internal.AttachmentWithContext
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
|
|
||||||
/** Constrain which contract-code-containing attachment can be used with a [ContractState]. */
|
/** Constrain which contract-code-containing attachment can be used with a [ContractState]. */
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
|
@DoNotImplement
|
||||||
interface AttachmentConstraint {
|
interface AttachmentConstraint {
|
||||||
/** Returns whether the given contract attachment can be used with the [ContractState] associated with this constraint object. */
|
/** Returns whether the given contract attachment can be used with the [ContractState] associated with this constraint object. */
|
||||||
fun isSatisfiedBy(attachment: Attachment): Boolean
|
fun isSatisfiedBy(attachment: Attachment): Boolean
|
||||||
@ -20,6 +24,20 @@ data class HashAttachmentConstraint(val attachmentId: SecureHash) : AttachmentCo
|
|||||||
override fun isSatisfiedBy(attachment: Attachment) = attachment.id == attachmentId
|
override fun isSatisfiedBy(attachment: Attachment) = attachment.id == attachmentId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An [AttachmentConstraint] that verifies that the hash of the attachment is in the network parameters whitelist.
|
||||||
|
* See: [net.corda.core.node.NetworkParameters.whitelistedContractImplementations]
|
||||||
|
* It allows for centralized control over the cordapps that can be used.
|
||||||
|
*/
|
||||||
|
object WhitelistedByZoneAttachmentConstraint : AttachmentConstraint {
|
||||||
|
override fun isSatisfiedBy(attachment: Attachment): Boolean {
|
||||||
|
return if (attachment is AttachmentWithContext) {
|
||||||
|
val whitelist = attachment.whitelistedContractImplementations ?: throw IllegalStateException("Unable to verify WhitelistedByZoneAttachmentConstraint - whitelist not specified")
|
||||||
|
attachment.id in (whitelist[attachment.stateContract] ?: emptyList())
|
||||||
|
} else false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This [AttachmentConstraint] is a convenience class that will be automatically resolved to a [HashAttachmentConstraint].
|
* This [AttachmentConstraint] is a convenience class that will be automatically resolved to a [HashAttachmentConstraint].
|
||||||
* The resolution occurs in [TransactionBuilder.toWireTransaction] and uses the [TransactionState.contract] value
|
* The resolution occurs in [TransactionBuilder.toWireTransaction] and uses the [TransactionState.contract] value
|
||||||
|
@ -6,7 +6,15 @@ import net.corda.core.serialization.CordaSerializable
|
|||||||
* Wrap an attachment in this if it is to be used as an executable contract attachment
|
* Wrap an attachment in this if it is to be used as an executable contract attachment
|
||||||
*
|
*
|
||||||
* @property attachment The attachment representing the contract JAR
|
* @property attachment The attachment representing the contract JAR
|
||||||
* @property contract The contract name contained within the JAR
|
* @property contract The contract name contained within the JAR. A Contract attachment has to contain at least 1 contract.
|
||||||
|
* @property additionalContracts Additional contract names contained within the JAR.
|
||||||
*/
|
*/
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
class ContractAttachment(val attachment: Attachment, val contract: ContractClassName) : Attachment by attachment
|
class ContractAttachment @JvmOverloads constructor (val attachment: Attachment, val contract: ContractClassName, val additionalContracts: Set<ContractClassName> = emptySet(), val uploader: String? = null) : Attachment by attachment {
|
||||||
|
|
||||||
|
val allContracts: Set<ContractClassName> get() = additionalContracts + contract
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ContractAttachment(attachment=${attachment.id}, contracts='${allContracts}', uploader='${uploader}')"
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,9 @@ sealed class TransactionVerificationException(val txId: SecureHash, message: Str
|
|||||||
class MissingAttachmentRejection(txId: SecureHash, val contractClass: String)
|
class MissingAttachmentRejection(txId: SecureHash, val contractClass: String)
|
||||||
: TransactionVerificationException(txId, "Contract constraints failed, could not find attachment for: $contractClass", null)
|
: TransactionVerificationException(txId, "Contract constraints failed, could not find attachment for: $contractClass", null)
|
||||||
|
|
||||||
|
class ConflictingAttachmentsRejection(txId: SecureHash, contractClass: String)
|
||||||
|
: TransactionVerificationException(txId, "Contract constraints failed for: $contractClass, because multiple attachments providing this contract were attached.", null)
|
||||||
|
|
||||||
class ContractCreationError(txId: SecureHash, contractClass: String, cause: Throwable)
|
class ContractCreationError(txId: SecureHash, contractClass: String, cause: Throwable)
|
||||||
: TransactionVerificationException(txId, "Contract verification failed: ${cause.message}, could not create contract class: $contractClass", cause)
|
: TransactionVerificationException(txId, "Contract verification failed: ${cause.message}, could not create contract class: $contractClass", cause)
|
||||||
|
|
||||||
|
@ -13,6 +13,13 @@ import java.security.CodeSigner
|
|||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.util.jar.JarInputStream
|
import java.util.jar.JarInputStream
|
||||||
|
|
||||||
|
// Possible attachment uploaders
|
||||||
|
const val DEPLOYED_CORDAPP_UPLOADER = "app"
|
||||||
|
const val RPC_UPLOADER = "rpc"
|
||||||
|
const val TEST_UPLOADER = "test"
|
||||||
|
const val P2P_UPLOADER = "p2p"
|
||||||
|
const val UNKNOWN_UPLOADER = "unknown"
|
||||||
|
|
||||||
abstract class AbstractAttachment(dataLoader: () -> ByteArray) : Attachment {
|
abstract class AbstractAttachment(dataLoader: () -> ByteArray) : Attachment {
|
||||||
companion object {
|
companion object {
|
||||||
fun SerializeAsTokenContext.attachmentDataLoader(id: SecureHash): () -> ByteArray {
|
fun SerializeAsTokenContext.attachmentDataLoader(id: SecureHash): () -> ByteArray {
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package net.corda.core.internal
|
||||||
|
|
||||||
|
import net.corda.core.contracts.Attachment
|
||||||
|
import net.corda.core.contracts.ContractAttachment
|
||||||
|
import net.corda.core.contracts.ContractClassName
|
||||||
|
import net.corda.core.node.services.AttachmentId
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used only for passing to the Attachment constraint verification.
|
||||||
|
*/
|
||||||
|
class AttachmentWithContext(
|
||||||
|
val contractAttachment: ContractAttachment,
|
||||||
|
val stateContract: ContractClassName,
|
||||||
|
/** Required for verifying [WhitelistedByZoneAttachmentConstraint] */
|
||||||
|
val whitelistedContractImplementations: Map<String, List<AttachmentId>>?
|
||||||
|
) : Attachment by contractAttachment {
|
||||||
|
init {
|
||||||
|
require(stateContract in contractAttachment.allContracts) {
|
||||||
|
"This AttachmentWithContext was not initialised properly"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -147,7 +147,7 @@ class FetchAttachmentsFlow(requests: Set<SecureHash>,
|
|||||||
|
|
||||||
override fun maybeWriteToDisk(downloaded: List<Attachment>) {
|
override fun maybeWriteToDisk(downloaded: List<Attachment>) {
|
||||||
for (attachment in downloaded) {
|
for (attachment in downloaded) {
|
||||||
serviceHub.attachments.importAttachment(attachment.open())
|
serviceHub.attachments.importAttachment(attachment.open(), "$P2P_UPLOADER:${otherSideSession.counterparty.name}", null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,8 +306,8 @@ fun <T, U : T> uncheckedCast(obj: T) = obj as U
|
|||||||
fun <K, V> Iterable<Pair<K, V>>.toMultiMap(): Map<K, List<V>> = this.groupBy({ it.first }) { it.second }
|
fun <K, V> Iterable<Pair<K, V>>.toMultiMap(): Map<K, List<V>> = this.groupBy({ it.first }) { it.second }
|
||||||
|
|
||||||
/** Provide access to internal method for AttachmentClassLoaderTests */
|
/** Provide access to internal method for AttachmentClassLoaderTests */
|
||||||
fun TransactionBuilder.toWireTransaction(cordappProvider: CordappProvider, serializationContext: SerializationContext): WireTransaction {
|
fun TransactionBuilder.toWireTransaction(services: ServicesForResolution, serializationContext: SerializationContext): WireTransaction {
|
||||||
return toWireTransactionWithContext(cordappProvider, serializationContext)
|
return toWireTransactionWithContext(services, serializationContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Provide access to internal method for AttachmentClassLoaderTests */
|
/** Provide access to internal method for AttachmentClassLoaderTests */
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.corda.core.node
|
package net.corda.core.node
|
||||||
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.node.services.AttachmentId
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
@ -9,11 +10,13 @@ import java.time.Instant
|
|||||||
* correctly interoperate with each other.
|
* correctly interoperate with each other.
|
||||||
* @property minimumPlatformVersion Minimum version of Corda platform that is required for nodes in the network.
|
* @property minimumPlatformVersion Minimum version of Corda platform that is required for nodes in the network.
|
||||||
* @property notaries List of well known and trusted notary identities with information on validation type.
|
* @property notaries List of well known and trusted notary identities with information on validation type.
|
||||||
* @property maxMessageSize Maximum P2P message sent over the wire in bytes.
|
* @property maxMessageSize This is currently ignored. However, it will be wired up in a future release.
|
||||||
* @property maxTransactionSize Maximum permitted transaction size in bytes.
|
* @property maxTransactionSize Maximum permitted transaction size in bytes.
|
||||||
* @property modifiedTime Last modification time of network parameters set.
|
* @property modifiedTime Last modification time of network parameters set.
|
||||||
* @property epoch Version number of the network parameters. Starting from 1, this will always increment on each new set
|
* @property epoch Version number of the network parameters. Starting from 1, this will always increment on each new set
|
||||||
* of parameters.
|
* of parameters.
|
||||||
|
* @property whitelistedContractImplementations List of whitelisted jars containing contract code for each contract class.
|
||||||
|
* This will be used by [net.corda.core.contracts.WhitelistedByZoneAttachmentConstraint]. Read more about contract constraints here: <https://docs.corda.net/api-contract-constraints.html>
|
||||||
*/
|
*/
|
||||||
// TODO Add eventHorizon - how many days a node can be offline before being automatically ejected from the network.
|
// TODO Add eventHorizon - how many days a node can be offline before being automatically ejected from the network.
|
||||||
// It needs separate design.
|
// It needs separate design.
|
||||||
@ -24,7 +27,8 @@ data class NetworkParameters(
|
|||||||
val maxMessageSize: Int,
|
val maxMessageSize: Int,
|
||||||
val maxTransactionSize: Int,
|
val maxTransactionSize: Int,
|
||||||
val modifiedTime: Instant,
|
val modifiedTime: Instant,
|
||||||
val epoch: Int
|
val epoch: Int,
|
||||||
|
val whitelistedContractImplementations: Map<String, List<AttachmentId>>
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
require(minimumPlatformVersion > 0) { "minimumPlatformVersion must be at least 1" }
|
require(minimumPlatformVersion > 0) { "minimumPlatformVersion must be at least 1" }
|
||||||
|
@ -33,6 +33,7 @@ interface AttachmentStorage {
|
|||||||
* @throws IllegalArgumentException if the given byte stream is empty or a [java.util.jar.JarInputStream].
|
* @throws IllegalArgumentException if the given byte stream is empty or a [java.util.jar.JarInputStream].
|
||||||
* @throws IOException if something went wrong.
|
* @throws IOException if something went wrong.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("More attachment information is required", replaceWith = ReplaceWith("importAttachment(jar, uploader, filename)"))
|
||||||
@Throws(FileAlreadyExistsException::class, IOException::class)
|
@Throws(FileAlreadyExistsException::class, IOException::class)
|
||||||
fun importAttachment(jar: InputStream): AttachmentId
|
fun importAttachment(jar: InputStream): AttachmentId
|
||||||
|
|
||||||
@ -43,13 +44,14 @@ interface AttachmentStorage {
|
|||||||
* @param filename Name of the file
|
* @param filename Name of the file
|
||||||
*/
|
*/
|
||||||
@Throws(FileAlreadyExistsException::class, IOException::class)
|
@Throws(FileAlreadyExistsException::class, IOException::class)
|
||||||
fun importAttachment(jar: InputStream, uploader: String, filename: String): AttachmentId
|
fun importAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts or returns Attachment Id of attachment. Does not throw an exception if already uploaded.
|
* Inserts or returns Attachment Id of attachment. Does not throw an exception if already uploaded.
|
||||||
* @param jar [InputStream] of Jar file
|
* @param jar [InputStream] of Jar file
|
||||||
* @return [AttachmentId] of uploaded attachment
|
* @return [AttachmentId] of uploaded attachment
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("More attachment information is required", replaceWith = ReplaceWith("importAttachment(jar, uploader, filename)"))
|
||||||
fun importOrGetAttachment(jar: InputStream): AttachmentId
|
fun importOrGetAttachment(jar: InputStream): AttachmentId
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,9 +3,11 @@ package net.corda.core.transactions
|
|||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.internal.AttachmentWithContext
|
||||||
import net.corda.core.internal.UpgradeCommand
|
import net.corda.core.internal.UpgradeCommand
|
||||||
import net.corda.core.internal.castIfPossible
|
import net.corda.core.internal.castIfPossible
|
||||||
import net.corda.core.internal.uncheckedCast
|
import net.corda.core.internal.uncheckedCast
|
||||||
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.utilities.Try
|
import net.corda.core.utilities.Try
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
@ -27,7 +29,7 @@ import java.util.function.Predicate
|
|||||||
// currently sends this across to out-of-process verifiers. We'll need to change that first.
|
// currently sends this across to out-of-process verifiers. We'll need to change that first.
|
||||||
// DOCSTART 1
|
// DOCSTART 1
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
data class LedgerTransaction(
|
data class LedgerTransaction @JvmOverloads constructor(
|
||||||
/** The resolved input states which will be consumed/invalidated by the execution of this transaction. */
|
/** The resolved input states which will be consumed/invalidated by the execution of this transaction. */
|
||||||
override val inputs: List<StateAndRef<ContractState>>,
|
override val inputs: List<StateAndRef<ContractState>>,
|
||||||
override val outputs: List<TransactionState<ContractState>>,
|
override val outputs: List<TransactionState<ContractState>>,
|
||||||
@ -39,7 +41,8 @@ data class LedgerTransaction(
|
|||||||
override val id: SecureHash,
|
override val id: SecureHash,
|
||||||
override val notary: Party?,
|
override val notary: Party?,
|
||||||
val timeWindow: TimeWindow?,
|
val timeWindow: TimeWindow?,
|
||||||
val privacySalt: PrivacySalt
|
val privacySalt: PrivacySalt,
|
||||||
|
private val networkParameters: NetworkParameters? = null
|
||||||
) : FullTransaction() {
|
) : FullTransaction() {
|
||||||
//DOCEND 1
|
//DOCEND 1
|
||||||
init {
|
init {
|
||||||
@ -87,17 +90,29 @@ data class LedgerTransaction(
|
|||||||
/**
|
/**
|
||||||
* Verify that all contract constraints are valid for each state before running any contract code
|
* Verify that all contract constraints are valid for each state before running any contract code
|
||||||
*
|
*
|
||||||
|
* In case the transaction was created on this node then the attachments will contain the hash of the current cordapp jars.
|
||||||
|
* In case this verifies an older transaction or one originated on a different node, then this verifies that the attachments
|
||||||
|
* are valid.
|
||||||
|
*
|
||||||
* @throws TransactionVerificationException if the constraints fail to verify
|
* @throws TransactionVerificationException if the constraints fail to verify
|
||||||
*/
|
*/
|
||||||
private fun verifyConstraints() {
|
private fun verifyConstraints() {
|
||||||
val contractAttachments = attachments.filterIsInstance<ContractAttachment>()
|
val contractAttachments = attachments.filterIsInstance<ContractAttachment>()
|
||||||
(inputs.map { it.state } + outputs).forEach { state ->
|
(inputs.map { it.state } + outputs).forEach { state ->
|
||||||
// Ordering of attachments matters - if two attachments contain the same named contract then the second
|
val stateAttachments = contractAttachments.filter { state.contract in it.allContracts }
|
||||||
// will be shadowed by the first.
|
if (stateAttachments.isEmpty()) throw TransactionVerificationException.MissingAttachmentRejection(id, state.contract)
|
||||||
val contractAttachment = contractAttachments.find { it.contract == state.contract }
|
|
||||||
?: throw TransactionVerificationException.MissingAttachmentRejection(id, state.contract)
|
|
||||||
|
|
||||||
if (!state.constraint.isSatisfiedBy(contractAttachment)) {
|
val uniqueAttachmentsForStateContract = stateAttachments.distinctBy { it.id }
|
||||||
|
|
||||||
|
// In case multiple attachments have been added for the same contract, fail because this transaction will not be able to be verified
|
||||||
|
// because it will break the no-overlap rule that we have implemented in our Classloaders
|
||||||
|
if (uniqueAttachmentsForStateContract.size > 1) {
|
||||||
|
throw TransactionVerificationException.ConflictingAttachmentsRejection(id, state.contract)
|
||||||
|
}
|
||||||
|
|
||||||
|
val contractAttachment = uniqueAttachmentsForStateContract.first()
|
||||||
|
val constraintAttachment = AttachmentWithContext(contractAttachment, state.contract, networkParameters?.whitelistedContractImplementations)
|
||||||
|
if (!state.constraint.isSatisfiedBy(constraintAttachment)) {
|
||||||
throw TransactionVerificationException.ContractConstraintRejection(id, state.contract)
|
throw TransactionVerificationException.ContractConstraintRejection(id, state.contract)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -403,5 +418,14 @@ data class LedgerTransaction(
|
|||||||
* @throws IllegalArgumentException if no item matches the id.
|
* @throws IllegalArgumentException if no item matches the id.
|
||||||
*/
|
*/
|
||||||
fun getAttachment(id: SecureHash): Attachment = attachments.first { it.id == id }
|
fun getAttachment(id: SecureHash): Attachment = attachments.first { it.id == id }
|
||||||
}
|
|
||||||
|
|
||||||
|
fun copy(inputs: List<StateAndRef<ContractState>>,
|
||||||
|
outputs: List<TransactionState<ContractState>>,
|
||||||
|
commands: List<CommandWithParties<CommandData>>,
|
||||||
|
attachments: List<Attachment>,
|
||||||
|
id: SecureHash,
|
||||||
|
notary: Party?,
|
||||||
|
timeWindow: TimeWindow?,
|
||||||
|
privacySalt: PrivacySalt
|
||||||
|
) = copy(inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, null)
|
||||||
|
}
|
||||||
|
@ -8,8 +8,10 @@ import net.corda.core.crypto.SignableData
|
|||||||
import net.corda.core.crypto.SignatureMetadata
|
import net.corda.core.crypto.SignatureMetadata
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FlowStateMachine
|
import net.corda.core.internal.FlowStateMachine
|
||||||
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.ServicesForResolution
|
import net.corda.core.node.ServicesForResolution
|
||||||
|
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
|
||||||
@ -17,6 +19,7 @@ import java.security.PublicKey
|
|||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A TransactionBuilder is a transaction class that's mutable (unlike the others which are all immutable). It is
|
* A TransactionBuilder is a transaction class that's mutable (unlike the others which are all immutable). It is
|
||||||
@ -42,18 +45,24 @@ open class TransactionBuilder(
|
|||||||
) {
|
) {
|
||||||
constructor(notary: Party) : this(notary, (Strand.currentStrand() as? FlowStateMachine<*>)?.id?.uuid ?: UUID.randomUUID())
|
constructor(notary: Party) : this(notary, (Strand.currentStrand() as? FlowStateMachine<*>)?.id?.uuid ?: UUID.randomUUID())
|
||||||
|
|
||||||
|
private val inputsWithTransactionState = arrayListOf<TransactionState<ContractState>>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a copy of the builder.
|
* Creates a copy of the builder.
|
||||||
*/
|
*/
|
||||||
fun copy() = TransactionBuilder(
|
fun copy(): TransactionBuilder {
|
||||||
notary = notary,
|
val t = TransactionBuilder(
|
||||||
inputs = ArrayList(inputs),
|
notary = notary,
|
||||||
attachments = ArrayList(attachments),
|
inputs = ArrayList(inputs),
|
||||||
outputs = ArrayList(outputs),
|
attachments = ArrayList(attachments),
|
||||||
commands = ArrayList(commands),
|
outputs = ArrayList(outputs),
|
||||||
window = window,
|
commands = ArrayList(commands),
|
||||||
privacySalt = privacySalt
|
window = window,
|
||||||
)
|
privacySalt = privacySalt
|
||||||
|
)
|
||||||
|
t.inputsWithTransactionState.addAll(this.inputsWithTransactionState)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
// DOCSTART 1
|
// DOCSTART 1
|
||||||
/** A more convenient way to add items to this transaction that calls the add* methods for you based on type */
|
/** A more convenient way to add items to this transaction that calls the add* methods for you based on type */
|
||||||
@ -83,31 +92,52 @@ open class TransactionBuilder(
|
|||||||
* @returns A new [WireTransaction] that will be unaffected by further changes to this [TransactionBuilder].
|
* @returns A new [WireTransaction] that will be unaffected by further changes to this [TransactionBuilder].
|
||||||
*/
|
*/
|
||||||
@Throws(MissingContractAttachments::class)
|
@Throws(MissingContractAttachments::class)
|
||||||
fun toWireTransaction(services: ServicesForResolution): WireTransaction = toWireTransactionWithContext(services.cordappProvider)
|
fun toWireTransaction(services: ServicesForResolution): WireTransaction = toWireTransactionWithContext(services)
|
||||||
|
|
||||||
internal fun toWireTransactionWithContext(cordappProvider: CordappProvider, serializationContext: SerializationContext? = null): WireTransaction {
|
internal fun toWireTransactionWithContext(services: ServicesForResolution, serializationContext: SerializationContext? = null): WireTransaction {
|
||||||
// Resolves the AutomaticHashConstraints to HashAttachmentConstraints for convenience. The AutomaticHashConstraint
|
|
||||||
// allows for less boiler plate when constructing transactions since for the typical case the named contract
|
// Resolves the AutomaticHashConstraints to HashAttachmentConstraints or WhitelistedByZoneAttachmentConstraint based on a global parameter.
|
||||||
|
// The AutomaticHashConstraint allows for less boiler plate when constructing transactions since for the typical case the named contract
|
||||||
// will be available when building the transaction. In exceptional cases the TransactionStates must be created
|
// will be available when building the transaction. In exceptional cases the TransactionStates must be created
|
||||||
// with an explicit [AttachmentConstraint]
|
// with an explicit [AttachmentConstraint]
|
||||||
val resolvedOutputs = outputs.map { state ->
|
val resolvedOutputs = outputs.map { state ->
|
||||||
if (state.constraint is AutomaticHashConstraint) {
|
when {
|
||||||
cordappProvider.getContractAttachmentID(state.contract)?.let {
|
state.constraint !is AutomaticHashConstraint -> state
|
||||||
|
useWhitelistedByZoneAttachmentConstraint(state.contract, services.networkParameters) -> state.copy(constraint = WhitelistedByZoneAttachmentConstraint)
|
||||||
|
else -> services.cordappProvider.getContractAttachmentID(state.contract)?.let {
|
||||||
state.copy(constraint = HashAttachmentConstraint(it))
|
state.copy(constraint = HashAttachmentConstraint(it))
|
||||||
} ?: throw MissingContractAttachments(listOf(state))
|
} ?: throw MissingContractAttachments(listOf(state))
|
||||||
} else {
|
|
||||||
state
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SerializationFactory.defaultFactory.withCurrentContext(serializationContext) {
|
return SerializationFactory.defaultFactory.withCurrentContext(serializationContext) {
|
||||||
WireTransaction(WireTransaction.createComponentGroups(inputs, resolvedOutputs, commands, attachments, notary, window), privacySalt)
|
WireTransaction(WireTransaction.createComponentGroups(inputStates(), resolvedOutputs, commands, attachments + makeContractAttachments(services.cordappProvider), notary, window), privacySalt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun useWhitelistedByZoneAttachmentConstraint(contractClassName: ContractClassName, networkParameters: NetworkParameters): Boolean {
|
||||||
|
return contractClassName in networkParameters.whitelistedContractImplementations.keys
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attachments added to the current transaction contain only the hashes of the current cordapps.
|
||||||
|
* NOT the hashes of the cordapps that were used when the input states were created ( in case they changed in the meantime)
|
||||||
|
* TODO - review this logic
|
||||||
|
*/
|
||||||
|
private fun makeContractAttachments(cordappProvider: CordappProvider): List<AttachmentId> {
|
||||||
|
return (inputsWithTransactionState + outputs).map { state ->
|
||||||
|
cordappProvider.getContractAttachmentID(state.contract)
|
||||||
|
?: throw MissingContractAttachments(listOf(state))
|
||||||
|
}.distinct()
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class)
|
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class)
|
||||||
fun toLedgerTransaction(services: ServiceHub) = toWireTransaction(services).toLedgerTransaction(services)
|
fun toLedgerTransaction(services: ServiceHub) = toWireTransaction(services).toLedgerTransaction(services)
|
||||||
|
|
||||||
internal fun toLedgerTransactionWithContext(services: ServicesForResolution, serializationContext: SerializationContext) = toWireTransactionWithContext(services.cordappProvider, serializationContext).toLedgerTransaction(services)
|
internal fun toLedgerTransactionWithContext(services: ServicesForResolution, serializationContext: SerializationContext): LedgerTransaction {
|
||||||
|
return toWireTransactionWithContext(services, serializationContext).toLedgerTransaction(services)
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class, TransactionVerificationException::class)
|
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class, TransactionVerificationException::class)
|
||||||
fun verify(services: ServiceHub) {
|
fun verify(services: ServiceHub) {
|
||||||
toLedgerTransaction(services).verify()
|
toLedgerTransaction(services).verify()
|
||||||
@ -117,6 +147,7 @@ open class TransactionBuilder(
|
|||||||
val notary = stateAndRef.state.notary
|
val notary = stateAndRef.state.notary
|
||||||
require(notary == this.notary) { "Input state requires notary \"$notary\" which does not match the transaction notary \"${this.notary}\"." }
|
require(notary == this.notary) { "Input state requires notary \"$notary\" which does not match the transaction notary \"${this.notary}\"." }
|
||||||
inputs.add(stateAndRef.ref)
|
inputs.add(stateAndRef.ref)
|
||||||
|
inputsWithTransactionState.add(stateAndRef.state)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import net.corda.core.contracts.ComponentGroupEnum.*
|
|||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.Emoji
|
import net.corda.core.internal.Emoji
|
||||||
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.node.ServicesForResolution
|
import net.corda.core.node.ServicesForResolution
|
||||||
import net.corda.core.node.services.AttachmentId
|
import net.corda.core.node.services.AttachmentId
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
@ -88,8 +89,7 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
|||||||
resolveIdentity = { services.identityService.partyFromKey(it) },
|
resolveIdentity = { services.identityService.partyFromKey(it) },
|
||||||
resolveAttachment = { services.attachments.openAttachment(it) },
|
resolveAttachment = { services.attachments.openAttachment(it) },
|
||||||
resolveStateRef = { services.loadState(it) },
|
resolveStateRef = { services.loadState(it) },
|
||||||
resolveContractAttachment = { services.cordappProvider.getContractAttachmentID(it.contract) },
|
networkParameters = services.networkParameters
|
||||||
maxTransactionSize = services.networkParameters.maxTransactionSize
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,17 +108,16 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
|||||||
resolveStateRef: (StateRef) -> TransactionState<*>?,
|
resolveStateRef: (StateRef) -> TransactionState<*>?,
|
||||||
resolveContractAttachment: (TransactionState<ContractState>) -> AttachmentId?
|
resolveContractAttachment: (TransactionState<ContractState>) -> AttachmentId?
|
||||||
): LedgerTransaction {
|
): LedgerTransaction {
|
||||||
return toLedgerTransactionInternal(resolveIdentity, resolveAttachment, resolveStateRef, resolveContractAttachment, 10485760)
|
return toLedgerTransactionInternal(resolveIdentity, resolveAttachment, resolveStateRef, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toLedgerTransactionInternal(
|
private fun toLedgerTransactionInternal(
|
||||||
resolveIdentity: (PublicKey) -> Party?,
|
resolveIdentity: (PublicKey) -> Party?,
|
||||||
resolveAttachment: (SecureHash) -> Attachment?,
|
resolveAttachment: (SecureHash) -> Attachment?,
|
||||||
resolveStateRef: (StateRef) -> TransactionState<*>?,
|
resolveStateRef: (StateRef) -> TransactionState<*>?,
|
||||||
resolveContractAttachment: (TransactionState<ContractState>) -> AttachmentId?,
|
networkParameters: NetworkParameters?
|
||||||
maxTransactionSize: Int
|
|
||||||
): LedgerTransaction {
|
): LedgerTransaction {
|
||||||
// Look up public keys to authenticated identities. This is just a stub placeholder and will all change in future.
|
// Look up public keys to authenticated identities.
|
||||||
val authenticatedArgs = commands.map {
|
val authenticatedArgs = commands.map {
|
||||||
val parties = it.signers.mapNotNull { pk -> resolveIdentity(pk) }
|
val parties = it.signers.mapNotNull { pk -> resolveIdentity(pk) }
|
||||||
CommandWithParties(it.signers, parties, it.value)
|
CommandWithParties(it.signers, parties, it.value)
|
||||||
@ -126,12 +125,9 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
|||||||
val resolvedInputs = inputs.map { ref ->
|
val resolvedInputs = inputs.map { ref ->
|
||||||
resolveStateRef(ref)?.let { StateAndRef(it, ref) } ?: throw TransactionResolutionException(ref.txhash)
|
resolveStateRef(ref)?.let { StateAndRef(it, ref) } ?: throw TransactionResolutionException(ref.txhash)
|
||||||
}
|
}
|
||||||
// Open attachments specified in this transaction. If we haven't downloaded them, we fail.
|
val attachments = attachments.map { resolveAttachment(it) ?: throw AttachmentResolutionException(it) }
|
||||||
val contractAttachments = findAttachmentContracts(resolvedInputs, resolveContractAttachment, resolveAttachment)
|
val ltx = LedgerTransaction(resolvedInputs, outputs, authenticatedArgs, attachments, id, notary, timeWindow, privacySalt, networkParameters)
|
||||||
// Order of attachments is important since contracts may refer to indexes so only append automatic attachments
|
checkTransactionSize(ltx, networkParameters?.maxTransactionSize ?: 10485760)
|
||||||
val attachments = (attachments.map { resolveAttachment(it) ?: throw AttachmentResolutionException(it) } + contractAttachments).distinct()
|
|
||||||
val ltx = LedgerTransaction(resolvedInputs, outputs, authenticatedArgs, attachments, id, notary, timeWindow, privacySalt)
|
|
||||||
checkTransactionSize(ltx, maxTransactionSize)
|
|
||||||
return ltx
|
return ltx
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,19 +262,6 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
|||||||
return buf.toString()
|
return buf.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findAttachmentContracts(resolvedInputs: List<StateAndRef<ContractState>>,
|
|
||||||
resolveContractAttachment: (TransactionState<ContractState>) -> AttachmentId?,
|
|
||||||
resolveAttachment: (SecureHash) -> Attachment?
|
|
||||||
): List<Attachment> {
|
|
||||||
val contractAttachments = (outputs + resolvedInputs.map { it.state }).map { Pair(it, resolveContractAttachment(it)) }
|
|
||||||
val missingAttachments = contractAttachments.filter { it.second == null }
|
|
||||||
return if (missingAttachments.isEmpty()) {
|
|
||||||
contractAttachments.map { ContractAttachment(resolveAttachment(it.second!!) ?: throw AttachmentResolutionException(it.second!!), it.first.contract) }
|
|
||||||
} else {
|
|
||||||
throw MissingContractAttachments(missingAttachments.map { it.first })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other is WireTransaction) {
|
if (other is WireTransaction) {
|
||||||
return (this.id == other.id)
|
return (this.id == other.id)
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package net.corda.core.contracts
|
package net.corda.core.contracts
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.any
|
||||||
import com.nhaarman.mockito_kotlin.doReturn
|
import com.nhaarman.mockito_kotlin.doReturn
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
import net.corda.core.cordapp.CordappProvider
|
import net.corda.core.cordapp.CordappProvider
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.crypto.SecureHash.Companion.allOnesHash
|
||||||
import net.corda.core.internal.UpgradeCommand
|
import net.corda.core.internal.UpgradeCommand
|
||||||
import net.corda.core.node.ServicesForResolution
|
import net.corda.core.node.ServicesForResolution
|
||||||
import net.corda.testing.contracts.DummyContract
|
import net.corda.testing.contracts.DummyContract
|
||||||
@ -34,7 +36,9 @@ class DummyContractV2Tests {
|
|||||||
@Test
|
@Test
|
||||||
fun `upgrade from v1`() {
|
fun `upgrade from v1`() {
|
||||||
val services = rigorousMock<ServicesForResolution>().also {
|
val services = rigorousMock<ServicesForResolution>().also {
|
||||||
doReturn(rigorousMock<CordappProvider>()).whenever(it).cordappProvider
|
doReturn(rigorousMock<CordappProvider>().also {
|
||||||
|
doReturn(allOnesHash).whenever(it).getContractAttachmentID(any())
|
||||||
|
}).whenever(it).cordappProvider
|
||||||
}
|
}
|
||||||
val contractUpgrade = DummyContractV2()
|
val contractUpgrade = DummyContractV2()
|
||||||
val v1State = TransactionState(DummyContract.SingleOwnerState(0, ALICE), DummyContract.PROGRAM_ID, DUMMY_NOTARY, constraint = AlwaysAcceptAttachmentConstraint)
|
val v1State = TransactionState(DummyContract.SingleOwnerState(0, ALICE), DummyContract.PROGRAM_ID, DUMMY_NOTARY, constraint = AlwaysAcceptAttachmentConstraint)
|
||||||
|
@ -10,7 +10,6 @@ import net.corda.core.identity.Party
|
|||||||
import net.corda.node.services.api.IdentityServiceInternal
|
import net.corda.node.services.api.IdentityServiceInternal
|
||||||
import net.corda.testing.contracts.DummyContract
|
import net.corda.testing.contracts.DummyContract
|
||||||
import net.corda.testing.core.*
|
import net.corda.testing.core.*
|
||||||
import net.corda.testing.internal.MockCordappProvider
|
|
||||||
import net.corda.testing.internal.rigorousMock
|
import net.corda.testing.internal.rigorousMock
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
@ -30,7 +29,7 @@ class LedgerTransactionQueryTests {
|
|||||||
@JvmField
|
@JvmField
|
||||||
val testSerialization = SerializationEnvironmentRule()
|
val testSerialization = SerializationEnvironmentRule()
|
||||||
private val keyPair = generateKeyPair()
|
private val keyPair = generateKeyPair()
|
||||||
private val services = MockServices(emptyList(), CordaX500Name("MegaCorp", "London", "GB"),
|
private val services = MockServices(listOf("net.corda.testing.contracts"), CordaX500Name("MegaCorp", "London", "GB"),
|
||||||
rigorousMock<IdentityServiceInternal>().also {
|
rigorousMock<IdentityServiceInternal>().also {
|
||||||
doReturn(null).whenever(it).partyFromKey(keyPair.public)
|
doReturn(null).whenever(it).partyFromKey(keyPair.public)
|
||||||
}, keyPair)
|
}, keyPair)
|
||||||
|
@ -65,7 +65,7 @@ class TransactionEncumbranceTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ledgerServices = MockServices(emptyList(), MEGA_CORP.name,
|
private val ledgerServices = MockServices(listOf("net.corda.core.transactions", "net.corda.finance.contracts.asset"), MEGA_CORP.name,
|
||||||
rigorousMock<IdentityServiceInternal>().also {
|
rigorousMock<IdentityServiceInternal>().also {
|
||||||
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
|
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package net.corda.core.transactions
|
package net.corda.core.transactions
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.doReturn
|
||||||
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.CompositeKey
|
||||||
@ -112,7 +114,9 @@ class TransactionTests {
|
|||||||
val inputs = emptyList<StateAndRef<*>>()
|
val inputs = emptyList<StateAndRef<*>>()
|
||||||
val outputs = listOf(baseOutState, baseOutState.copy(notary = ALICE), baseOutState.copy(notary = BOB))
|
val outputs = listOf(baseOutState, baseOutState.copy(notary = ALICE), baseOutState.copy(notary = BOB))
|
||||||
val commands = emptyList<CommandWithParties<CommandData>>()
|
val commands = emptyList<CommandWithParties<CommandData>>()
|
||||||
val attachments = listOf<Attachment>(ContractAttachment(rigorousMock(), DummyContract.PROGRAM_ID))
|
val attachments = listOf<Attachment>(ContractAttachment(rigorousMock<Attachment>().also {
|
||||||
|
doReturn(SecureHash.zeroHash).whenever(it).id
|
||||||
|
}, DummyContract.PROGRAM_ID))
|
||||||
val id = SecureHash.randomSHA256()
|
val id = SecureHash.randomSHA256()
|
||||||
val timeWindow: TimeWindow? = null
|
val timeWindow: TimeWindow? = null
|
||||||
val privacySalt: PrivacySalt = PrivacySalt()
|
val privacySalt: PrivacySalt = PrivacySalt()
|
||||||
|
@ -7,46 +7,48 @@ import net.corda.core.identity.CordaX500Name;
|
|||||||
import net.corda.finance.contracts.ICommercialPaperState;
|
import net.corda.finance.contracts.ICommercialPaperState;
|
||||||
import net.corda.finance.contracts.JavaCommercialPaper;
|
import net.corda.finance.contracts.JavaCommercialPaper;
|
||||||
import net.corda.finance.contracts.asset.Cash;
|
import net.corda.finance.contracts.asset.Cash;
|
||||||
import net.corda.testing.node.MockServices;
|
|
||||||
import net.corda.testing.core.TestIdentity;
|
import net.corda.testing.core.TestIdentity;
|
||||||
|
import net.corda.testing.node.MockServices;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.singletonList;
|
||||||
import static net.corda.core.crypto.Crypto.generateKeyPair;
|
|
||||||
import static net.corda.finance.Currencies.DOLLARS;
|
import static net.corda.finance.Currencies.DOLLARS;
|
||||||
import static net.corda.finance.Currencies.issuedBy;
|
import static net.corda.finance.Currencies.issuedBy;
|
||||||
import static net.corda.finance.contracts.JavaCommercialPaper.JCP_PROGRAM_ID;
|
import static net.corda.finance.contracts.JavaCommercialPaper.JCP_PROGRAM_ID;
|
||||||
|
import static net.corda.testing.core.TestConstants.*;
|
||||||
import static net.corda.testing.node.MockServicesKt.makeTestIdentityService;
|
import static net.corda.testing.node.MockServicesKt.makeTestIdentityService;
|
||||||
import static net.corda.testing.node.NodeTestUtils.ledger;
|
import static net.corda.testing.node.NodeTestUtils.ledger;
|
||||||
import static net.corda.testing.node.NodeTestUtils.transaction;
|
import static net.corda.testing.node.NodeTestUtils.transaction;
|
||||||
import static net.corda.testing.core.TestConstants.ALICE_NAME;
|
|
||||||
import static net.corda.testing.core.TestConstants.BOB_NAME;
|
|
||||||
import static net.corda.testing.core.TestConstants.TEST_TX_TIME;
|
|
||||||
|
|
||||||
public class CommercialPaperTest {
|
public class CommercialPaperTest {
|
||||||
|
|
||||||
private static final TestIdentity alice = new TestIdentity(ALICE_NAME, 70L);
|
private static final TestIdentity alice = new TestIdentity(ALICE_NAME, 70L);
|
||||||
private static final TestIdentity bigCorp = new TestIdentity(new CordaX500Name("BigCorp", "New York", "GB"));
|
private static final TestIdentity bigCorp = new TestIdentity(new CordaX500Name("BigCorp", "New York", "GB"));
|
||||||
private static final TestIdentity bob = new TestIdentity(BOB_NAME, 80L);
|
private static final TestIdentity bob = new TestIdentity(BOB_NAME, 80L);
|
||||||
private static final TestIdentity megaCorp = new TestIdentity(new CordaX500Name("MegaCorp", "London", "GB"));
|
private static final TestIdentity megaCorp = new TestIdentity(new CordaX500Name("MegaCorp", "London", "GB"));
|
||||||
private final byte[] defaultRef = {123};
|
private final byte[] defaultRef = {123};
|
||||||
|
private MockServices ledgerServices;
|
||||||
|
|
||||||
// DOCSTART 11
|
@Before
|
||||||
private final MockServices ledgerServices = new MockServices(
|
public void setUp() {
|
||||||
// A list of packages to scan for cordapps
|
// DOCSTART 11
|
||||||
emptyList(),
|
ledgerServices = new MockServices(
|
||||||
// The identity represented by this set of mock services. Defaults to a test identity.
|
// A list of packages to scan for cordapps
|
||||||
// You can also use the alternative parameter initialIdentityName which accepts a
|
singletonList("net.corda.finance.contracts"),
|
||||||
// [CordaX500Name]
|
// The identity represented by this set of mock services. Defaults to a test identity.
|
||||||
megaCorp,
|
// You can also use the alternative parameter initialIdentityName which accepts a
|
||||||
// An implementation of [IdentityService], which contains a list of all identities known
|
// [CordaX500Name]
|
||||||
// to the node. Use [makeTestIdentityService] which returns an implementation of
|
megaCorp,
|
||||||
// [InMemoryIdentityService] with the given identities
|
// An implementation of [IdentityService], which contains a list of all identities known
|
||||||
makeTestIdentityService(megaCorp.getIdentity())
|
// to the node. Use [makeTestIdentityService] which returns an implementation of
|
||||||
|
// [InMemoryIdentityService] with the given identities
|
||||||
|
makeTestIdentityService(megaCorp.getIdentity())
|
||||||
);
|
);
|
||||||
// DOCEND 11
|
// DOCEND 11
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
// DOCSTART 12
|
// DOCSTART 12
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package net.corda.docs.tutorial.testdsl
|
package net.corda.docs.tutorial.testdsl
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.doReturn
|
||||||
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
import net.corda.core.contracts.TransactionVerificationException
|
import net.corda.core.contracts.TransactionVerificationException
|
||||||
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
|
import net.corda.core.node.services.IdentityService
|
||||||
import net.corda.core.utilities.days
|
import net.corda.core.utilities.days
|
||||||
import net.corda.finance.DOLLARS
|
import net.corda.finance.DOLLARS
|
||||||
import net.corda.finance.`issued by`
|
import net.corda.finance.`issued by`
|
||||||
@ -11,6 +15,7 @@ import net.corda.finance.contracts.ICommercialPaperState
|
|||||||
import net.corda.finance.contracts.asset.CASH
|
import net.corda.finance.contracts.asset.CASH
|
||||||
import net.corda.finance.contracts.asset.Cash
|
import net.corda.finance.contracts.asset.Cash
|
||||||
import net.corda.testing.core.*
|
import net.corda.testing.core.*
|
||||||
|
import net.corda.testing.internal.rigorousMock
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import net.corda.testing.node.ledger
|
import net.corda.testing.node.ledger
|
||||||
import net.corda.testing.node.makeTestIdentityService
|
import net.corda.testing.node.makeTestIdentityService
|
||||||
@ -33,20 +38,20 @@ class CommercialPaperTest {
|
|||||||
// DOCSTART 11
|
// DOCSTART 11
|
||||||
private val ledgerServices = MockServices(
|
private val ledgerServices = MockServices(
|
||||||
// A list of packages to scan for cordapps
|
// A list of packages to scan for cordapps
|
||||||
cordappPackages = emptyList(),
|
listOf("net.corda.finance.contracts"),
|
||||||
// The identity represented by this set of mock services. Defaults to a test identity.
|
// The identity represented by this set of mock services. Defaults to a test identity.
|
||||||
// You can also use the alternative parameter initialIdentityName which accepts a
|
// You can also use the alternative parameter initialIdentityName which accepts a
|
||||||
// [CordaX500Name]
|
// [CordaX500Name]
|
||||||
initialIdentity = megaCorp,
|
megaCorp,
|
||||||
// An implementation of IdentityService, which contains a list of all identities known
|
rigorousMock<IdentityService>().also {
|
||||||
// to the node. Use [makeTestIdentityService] which returns an implementation of
|
doReturn(megaCorp.party).whenever(it).partyFromKey(megaCorp.publicKey)
|
||||||
// [InMemoryIdentityService] with the given identities
|
doReturn(null).whenever(it).partyFromKey(bigCorp.publicKey)
|
||||||
identityService = makeTestIdentityService(megaCorp.identity)
|
doReturn(null).whenever(it).partyFromKey(alice.publicKey)
|
||||||
)
|
})
|
||||||
// DOCEND 11
|
// DOCEND 11
|
||||||
|
|
||||||
@Suppress("unused")
|
|
||||||
// DOCSTART 12
|
// DOCSTART 12
|
||||||
|
@Suppress("unused")
|
||||||
private val simpleLedgerServices = MockServices(
|
private val simpleLedgerServices = MockServices(
|
||||||
// This is the identity of the node
|
// This is the identity of the node
|
||||||
megaCorp,
|
megaCorp,
|
||||||
|
@ -88,7 +88,7 @@ class ObligationTests {
|
|||||||
doReturn(MINI_CORP).whenever(it).partyFromKey(MINI_CORP_PUBKEY)
|
doReturn(MINI_CORP).whenever(it).partyFromKey(MINI_CORP_PUBKEY)
|
||||||
}
|
}
|
||||||
private val mockService = MockServices(listOf("net.corda.finance.contracts.asset"), MEGA_CORP.name, identityService)
|
private val mockService = MockServices(listOf("net.corda.finance.contracts.asset"), MEGA_CORP.name, identityService)
|
||||||
private val ledgerServices get() = MockServices(emptyList(), MEGA_CORP.name, identityService)
|
private val ledgerServices get() = MockServices(listOf("net.corda.finance.contracts.asset", "net.corda.testing.contracts"), MEGA_CORP.name, identityService)
|
||||||
private fun cashObligationTestRoots(
|
private fun cashObligationTestRoots(
|
||||||
group: LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>
|
group: LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>
|
||||||
) = group.apply {
|
) = group.apply {
|
||||||
|
@ -34,6 +34,9 @@ dependencies {
|
|||||||
// For AMQP serialisation.
|
// For AMQP serialisation.
|
||||||
compile "org.apache.qpid:proton-j:0.21.0"
|
compile "org.apache.qpid:proton-j:0.21.0"
|
||||||
|
|
||||||
|
// FastClasspathScanner: classpath scanning - needed for the NetworkBootstraper
|
||||||
|
compile 'io.github.lukehutch:fast-classpath-scanner:2.0.21'
|
||||||
|
|
||||||
// Pure-Java Snappy compression
|
// Pure-Java Snappy compression
|
||||||
compile 'org.iq80.snappy:snappy:0.4'
|
compile 'org.iq80.snappy:snappy:0.4'
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package net.corda.nodeapi.internal
|
package net.corda.nodeapi.internal
|
||||||
|
|
||||||
import net.corda.core.contracts.Attachment
|
import net.corda.core.contracts.Attachment
|
||||||
|
import net.corda.core.contracts.ContractAttachment
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
@ -31,6 +33,10 @@ class AttachmentsClassLoader(attachments: List<Attachment>, parent: ClassLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
require(attachments.mapNotNull { it as? ContractAttachment }.none { it.uploader != DEPLOYED_CORDAPP_UPLOADER }) {
|
||||||
|
"Attempting to load Contract Attachments downloaded from the network"
|
||||||
|
}
|
||||||
|
|
||||||
for (attachment in attachments) {
|
for (attachment in attachments) {
|
||||||
attachment.openAsJAR().use { jar ->
|
attachment.openAsJAR().use { jar ->
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
package net.corda.nodeapi.internal
|
||||||
|
|
||||||
|
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||||
|
import net.corda.core.contracts.Contract
|
||||||
|
import net.corda.core.contracts.ContractClassName
|
||||||
|
import net.corda.core.internal.copyTo
|
||||||
|
import net.corda.core.internal.deleteIfExists
|
||||||
|
import net.corda.core.internal.read
|
||||||
|
import java.io.File
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.lang.reflect.Modifier
|
||||||
|
import java.net.URLClassLoader
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Paths
|
||||||
|
import java.nio.file.StandardCopyOption
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans the jar for contracts.
|
||||||
|
* @returns: found contract class names or null if none found
|
||||||
|
*/
|
||||||
|
fun scanJarForContracts(cordappJarPath: String): List<ContractClassName> {
|
||||||
|
val currentClassLoader = Contract::class.java.classLoader
|
||||||
|
val scanResult = FastClasspathScanner().addClassLoader(currentClassLoader).overrideClasspath(cordappJarPath, Paths.get(Contract::class.java.protectionDomain.codeSource.location.toURI()).toString()).scan()
|
||||||
|
val contracts = (scanResult.getNamesOfClassesImplementing(Contract::class.qualifiedName) ).distinct()
|
||||||
|
|
||||||
|
// Only keep instantiable contracts
|
||||||
|
val classLoader = URLClassLoader(arrayOf(File(cordappJarPath).toURL()), currentClassLoader)
|
||||||
|
val concreteContracts = contracts.map(classLoader::loadClass).filter { !it.isInterface && !Modifier.isAbstract(it.modifiers) }
|
||||||
|
return concreteContracts.map { it.name }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> withContractsInJar(jarInputStream: InputStream, withContracts: (List<ContractClassName>, InputStream) -> T): T {
|
||||||
|
val tempFile = Files.createTempFile("attachment", ".jar")
|
||||||
|
try {
|
||||||
|
jarInputStream.copyTo(tempFile, StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
val contracts = scanJarForContracts(tempFile.toAbsolutePath().toString())
|
||||||
|
return tempFile.read { withContracts(contracts, it) }
|
||||||
|
} finally {
|
||||||
|
tempFile.deleteIfExists()
|
||||||
|
}
|
||||||
|
}
|
@ -1,25 +1,33 @@
|
|||||||
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.crypto.SecureHash
|
||||||
|
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.*
|
||||||
import net.corda.core.internal.concurrent.fork
|
import net.corda.core.internal.concurrent.fork
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.node.NotaryInfo
|
import net.corda.core.node.NotaryInfo
|
||||||
|
import net.corda.core.node.services.AttachmentId
|
||||||
import net.corda.core.serialization.SerializationContext
|
import net.corda.core.serialization.SerializationContext
|
||||||
import net.corda.core.serialization.internal.SerializationEnvironmentImpl
|
import net.corda.core.serialization.internal.SerializationEnvironmentImpl
|
||||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
|
import net.corda.nodeapi.internal.scanJarForContracts
|
||||||
import net.corda.nodeapi.internal.serialization.AMQP_P2P_CONTEXT
|
import net.corda.nodeapi.internal.serialization.AMQP_P2P_CONTEXT
|
||||||
import net.corda.nodeapi.internal.serialization.CordaSerializationMagic
|
import net.corda.nodeapi.internal.serialization.CordaSerializationMagic
|
||||||
import net.corda.nodeapi.internal.serialization.SerializationFactoryImpl
|
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.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
@ -43,15 +51,17 @@ class NetworkBootstrapper {
|
|||||||
)
|
)
|
||||||
|
|
||||||
private const val LOGS_DIR_NAME = "logs"
|
private const val LOGS_DIR_NAME = "logs"
|
||||||
|
private const val WHITELIST_FILE_NAME = "whitelist.txt"
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val arg = args.singleOrNull() ?: throw IllegalArgumentException("Expecting single argument which is the nodes' parent directory")
|
val baseNodeDirectory = args.firstOrNull() ?: throw IllegalArgumentException("Expecting first argument which is the nodes' parent directory")
|
||||||
NetworkBootstrapper().bootstrap(Paths.get(arg).toAbsolutePath().normalize())
|
val cordapps = if (args.size > 1) args.toList().drop(1) else null
|
||||||
|
NetworkBootstrapper().bootstrap(Paths.get(baseNodeDirectory).toAbsolutePath().normalize(), cordapps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bootstrap(directory: Path) {
|
fun bootstrap(directory: Path, cordapps: List<String>?) {
|
||||||
directory.createDirectories()
|
directory.createDirectories()
|
||||||
println("Bootstrapping local network in $directory")
|
println("Bootstrapping local network in $directory")
|
||||||
generateDirectoriesIfNeeded(directory)
|
generateDirectoriesIfNeeded(directory)
|
||||||
@ -68,7 +78,10 @@ class NetworkBootstrapper {
|
|||||||
println("Gathering notary identities")
|
println("Gathering notary identities")
|
||||||
val notaryInfos = gatherNotaryInfos(nodeInfoFiles)
|
val notaryInfos = gatherNotaryInfos(nodeInfoFiles)
|
||||||
println("Notary identities to be used in network-parameters file: ${notaryInfos.joinToString("; ") { it.prettyPrint() }}")
|
println("Notary identities to be used in network-parameters file: ${notaryInfos.joinToString("; ") { it.prettyPrint() }}")
|
||||||
installNetworkParameters(notaryInfos, nodeDirs)
|
val mergedWhiteList = generateWhitelist(directory / WHITELIST_FILE_NAME, cordapps?.distinct())
|
||||||
|
println("Updating whitelist.")
|
||||||
|
overwriteWhitelist(directory / WHITELIST_FILE_NAME, mergedWhiteList)
|
||||||
|
installNetworkParameters(notaryInfos, nodeDirs, mergedWhiteList)
|
||||||
println("Bootstrapping complete!")
|
println("Bootstrapping complete!")
|
||||||
} finally {
|
} finally {
|
||||||
_contextSerializationEnv.set(null)
|
_contextSerializationEnv.set(null)
|
||||||
@ -84,8 +97,7 @@ class NetworkBootstrapper {
|
|||||||
for (confFile in confFiles) {
|
for (confFile in confFiles) {
|
||||||
val nodeName = confFile.fileName.toString().removeSuffix(".conf")
|
val nodeName = confFile.fileName.toString().removeSuffix(".conf")
|
||||||
println("Generating directory for $nodeName")
|
println("Generating directory for $nodeName")
|
||||||
val nodeDir = (directory / nodeName)
|
val nodeDir = (directory / nodeName).createDirectories()
|
||||||
if (!nodeDir.exists()) { nodeDir.createDirectory() }
|
|
||||||
confFile.moveTo(nodeDir / "node.conf", StandardCopyOption.REPLACE_EXISTING)
|
confFile.moveTo(nodeDir / "node.conf", StandardCopyOption.REPLACE_EXISTING)
|
||||||
Files.copy(cordaJar, (nodeDir / "corda.jar"), StandardCopyOption.REPLACE_EXISTING)
|
Files.copy(cordaJar, (nodeDir / "corda.jar"), StandardCopyOption.REPLACE_EXISTING)
|
||||||
}
|
}
|
||||||
@ -157,7 +169,7 @@ class NetworkBootstrapper {
|
|||||||
}.distinct() // We need distinct as nodes part of a distributed notary share the same notary identity
|
}.distinct() // We need distinct as nodes part of a distributed notary share the same notary identity
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun installNetworkParameters(notaryInfos: List<NotaryInfo>, nodeDirs: List<Path>) {
|
private fun installNetworkParameters(notaryInfos: List<NotaryInfo>, nodeDirs: List<Path>, whitelist: Map<String, List<AttachmentId>>) {
|
||||||
// TODO Add config for minimumPlatformVersion, maxMessageSize and maxTransactionSize
|
// TODO Add config for minimumPlatformVersion, maxMessageSize and maxTransactionSize
|
||||||
val copier = NetworkParametersCopier(NetworkParameters(
|
val copier = NetworkParametersCopier(NetworkParameters(
|
||||||
minimumPlatformVersion = 1,
|
minimumPlatformVersion = 1,
|
||||||
@ -165,12 +177,58 @@ class NetworkBootstrapper {
|
|||||||
modifiedTime = Instant.now(),
|
modifiedTime = Instant.now(),
|
||||||
maxMessageSize = 10485760,
|
maxMessageSize = 10485760,
|
||||||
maxTransactionSize = Int.MAX_VALUE,
|
maxTransactionSize = Int.MAX_VALUE,
|
||||||
epoch = 1
|
epoch = 1,
|
||||||
|
whitelistedContractImplementations = whitelist
|
||||||
), overwriteFile = true)
|
), overwriteFile = true)
|
||||||
|
|
||||||
nodeDirs.forEach { copier.install(it) }
|
nodeDirs.forEach { copier.install(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun generateWhitelist(whitelistFile: Path, cordapps: List<String>?): Map<String, List<AttachmentId>> {
|
||||||
|
val existingWhitelist = if (whitelistFile.exists()) readContractWhitelist(whitelistFile) else emptyMap()
|
||||||
|
|
||||||
|
println("Found existing whitelist: $existingWhitelist")
|
||||||
|
|
||||||
|
val newWhiteList = cordapps?.flatMap { cordappJarPath ->
|
||||||
|
val jarHash = getJarHash(cordappJarPath)
|
||||||
|
scanJarForContracts(cordappJarPath).map { contract ->
|
||||||
|
contract to jarHash
|
||||||
|
}
|
||||||
|
}?.toMap() ?: emptyMap()
|
||||||
|
|
||||||
|
println("Calculating whitelist for current cordapps: $newWhiteList")
|
||||||
|
|
||||||
|
val merged = (newWhiteList.keys + existingWhitelist.keys).map { contractClassName ->
|
||||||
|
val existing = existingWhitelist[contractClassName] ?: emptyList()
|
||||||
|
val newHash = newWhiteList[contractClassName]
|
||||||
|
contractClassName to (if (newHash == null || newHash in existing) existing else existing + newHash)
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
|
println("Final whitelist: $merged")
|
||||||
|
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun overwriteWhitelist(whitelistFile: Path, mergedWhiteList: Map<String, List<AttachmentId>>) {
|
||||||
|
PrintStream(whitelistFile.toFile().outputStream()).use { out ->
|
||||||
|
mergedWhiteList.forEach { (contract, attachments )->
|
||||||
|
out.println("${contract}:${attachments.joinToString(",")}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getJarHash(cordappPath: String): AttachmentId = File(cordappPath).inputStream().use { jar ->
|
||||||
|
val hs = HashingInputStream(Hashing.sha256(), jar)
|
||||||
|
hs.readBytes()
|
||||||
|
SecureHash.SHA256(hs.hash().asBytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readContractWhitelist(file: Path): Map<String, List<AttachmentId>> = file.toFile().readLines()
|
||||||
|
.map { line -> line.split(":") }
|
||||||
|
.map { (contract, attachmentIds) ->
|
||||||
|
contract to (attachmentIds.split(",").map(::parse))
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
private fun NotaryInfo.prettyPrint(): String = "${identity.name} (${if (validating) "" else "non-"}validating)"
|
private fun NotaryInfo.prettyPrint(): String = "${identity.name} (${if (validating) "" else "non-"}validating)"
|
||||||
|
|
||||||
private fun NodeInfo.notaryIdentity(): Party {
|
private fun NodeInfo.notaryIdentity(): Party {
|
||||||
|
@ -21,12 +21,12 @@ 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)
|
return ContractAttachmentProxy(GeneratedAttachment(bytes), obj.contract, obj.additionalContracts, obj.uploader)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromProxy(proxy: ContractAttachmentProxy): ContractAttachment {
|
override fun fromProxy(proxy: ContractAttachmentProxy): ContractAttachment {
|
||||||
return ContractAttachment(proxy.attachment, proxy.contract)
|
return ContractAttachment(proxy.attachment, proxy.contract, proxy.contracts, proxy.uploader)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ContractAttachmentProxy(val attachment: Attachment, val contract: ContractClassName)
|
data class ContractAttachmentProxy(val attachment: Attachment, val contract: ContractClassName, val contracts: Set<ContractClassName>, val uploader: String?)
|
||||||
}
|
}
|
@ -12,6 +12,7 @@ import de.javakaffee.kryoserializers.BitSetSerializer
|
|||||||
import de.javakaffee.kryoserializers.UnmodifiableCollectionsSerializer
|
import de.javakaffee.kryoserializers.UnmodifiableCollectionsSerializer
|
||||||
import de.javakaffee.kryoserializers.guava.*
|
import de.javakaffee.kryoserializers.guava.*
|
||||||
import net.corda.core.contracts.ContractAttachment
|
import net.corda.core.contracts.ContractAttachment
|
||||||
|
import net.corda.core.contracts.ContractClassName
|
||||||
import net.corda.core.contracts.PrivacySalt
|
import net.corda.core.contracts.PrivacySalt
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.CompositeKey
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
@ -206,29 +207,34 @@ object DefaultKryoCustomizer {
|
|||||||
output.writeBytesWithLength(buffer.toByteArray())
|
output.writeBytesWithLength(buffer.toByteArray())
|
||||||
}
|
}
|
||||||
output.writeString(obj.contract)
|
output.writeString(obj.contract)
|
||||||
|
kryo.writeClassAndObject(output, obj.additionalContracts)
|
||||||
|
output.writeString(obj.uploader)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun read(kryo: Kryo, input: Input, type: Class<ContractAttachment>): ContractAttachment {
|
override fun read(kryo: Kryo, input: Input, type: Class<ContractAttachment>): ContractAttachment {
|
||||||
if (kryo.serializationContext() != null) {
|
if (kryo.serializationContext() != null) {
|
||||||
val attachmentHash = SecureHash.SHA256(input.readBytes(32))
|
val attachmentHash = SecureHash.SHA256(input.readBytes(32))
|
||||||
val contract = input.readString()
|
val contract = input.readString()
|
||||||
|
val additionalContracts = kryo.readClassAndObject(input) as Set<ContractClassName>
|
||||||
|
val uploader = input.readString()
|
||||||
val context = kryo.serializationContext()!!
|
val context = kryo.serializationContext()!!
|
||||||
val attachmentStorage = context.serviceHub.attachments
|
val attachmentStorage = context.serviceHub.attachments
|
||||||
|
|
||||||
val lazyAttachment = object : AbstractAttachment({
|
val lazyAttachment = object : AbstractAttachment({
|
||||||
val attachment = attachmentStorage.openAttachment(attachmentHash) ?: throw MissingAttachmentsException(listOf(attachmentHash))
|
val attachment = attachmentStorage.openAttachment(attachmentHash)
|
||||||
|
?: throw MissingAttachmentsException(listOf(attachmentHash))
|
||||||
attachment.open().readBytes()
|
attachment.open().readBytes()
|
||||||
}) {
|
}) {
|
||||||
override val id = attachmentHash
|
override val id = attachmentHash
|
||||||
}
|
}
|
||||||
|
|
||||||
return ContractAttachment(lazyAttachment, contract)
|
return ContractAttachment(lazyAttachment, contract, additionalContracts, uploader)
|
||||||
} else {
|
} else {
|
||||||
val attachment = GeneratedAttachment(input.readBytesWithLength())
|
val attachment = GeneratedAttachment(input.readBytesWithLength())
|
||||||
val contract = input.readString()
|
val contract = input.readString()
|
||||||
|
val additionalContracts = kryo.readClassAndObject(input) as Set<ContractClassName>
|
||||||
return ContractAttachment(attachment, contract)
|
val uploader = input.readString()
|
||||||
|
return ContractAttachment(attachment, contract, additionalContracts, uploader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import net.corda.core.transactions.LedgerTransaction
|
|||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.node.internal.cordapp.CordappLoader
|
import net.corda.node.internal.cordapp.CordappLoader
|
||||||
import net.corda.node.internal.cordapp.CordappProviderImpl
|
import net.corda.node.internal.cordapp.CordappProviderImpl
|
||||||
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
import net.corda.testing.core.SerializationEnvironmentRule
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
import net.corda.testing.core.TestIdentity
|
import net.corda.testing.core.TestIdentity
|
||||||
@ -59,7 +60,8 @@ class AttachmentsClassLoaderStaticContractTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val serviceHub = rigorousMock<ServicesForResolution>().also {
|
private val serviceHub = rigorousMock<ServicesForResolution>().also {
|
||||||
doReturn(CordappProviderImpl(CordappLoader.createWithTestPackages(listOf("net.corda.nodeapi.internal")), MockCordappConfigProvider(), MockAttachmentStorage())).whenever(it).cordappProvider
|
doReturn(CordappProviderImpl(CordappLoader.createWithTestPackages(listOf("net.corda.nodeapi.internal")), MockCordappConfigProvider(), MockAttachmentStorage(), testNetworkParameters().whitelistedContractImplementations)).whenever(it).cordappProvider
|
||||||
|
doReturn(testNetworkParameters()).whenever(it).networkParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -18,6 +18,7 @@ import net.corda.nodeapi.DummyContractBackdoor
|
|||||||
import net.corda.nodeapi.internal.serialization.SerializeAsTokenContextImpl
|
import net.corda.nodeapi.internal.serialization.SerializeAsTokenContextImpl
|
||||||
import net.corda.nodeapi.internal.serialization.attachmentsClassLoaderEnabledPropertyName
|
import net.corda.nodeapi.internal.serialization.attachmentsClassLoaderEnabledPropertyName
|
||||||
import net.corda.nodeapi.internal.serialization.withTokenContext
|
import net.corda.nodeapi.internal.serialization.withTokenContext
|
||||||
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
import net.corda.testing.core.SerializationEnvironmentRule
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
import net.corda.testing.core.TestIdentity
|
import net.corda.testing.core.TestIdentity
|
||||||
@ -58,12 +59,15 @@ class AttachmentsClassLoaderTests {
|
|||||||
@JvmField
|
@JvmField
|
||||||
val testSerialization = SerializationEnvironmentRule()
|
val testSerialization = SerializationEnvironmentRule()
|
||||||
private val attachments = MockAttachmentStorage()
|
private val attachments = MockAttachmentStorage()
|
||||||
private val cordappProvider = CordappProviderImpl(CordappLoader.createDevMode(listOf(ISOLATED_CONTRACTS_JAR_PATH)), MockCordappConfigProvider(), attachments)
|
private val networkParameters = testNetworkParameters()
|
||||||
|
private val cordappProvider = CordappProviderImpl(CordappLoader.createDevMode(listOf(ISOLATED_CONTRACTS_JAR_PATH)), MockCordappConfigProvider(), attachments, networkParameters.whitelistedContractImplementations)
|
||||||
private val cordapp get() = cordappProvider.cordapps.first()
|
private val cordapp get() = cordappProvider.cordapps.first()
|
||||||
private val attachmentId get() = cordappProvider.getCordappAttachmentId(cordapp)!!
|
private val attachmentId get() = cordappProvider.getCordappAttachmentId(cordapp)!!
|
||||||
private val appContext get() = cordappProvider.getAppContext(cordapp)
|
private val appContext get() = cordappProvider.getAppContext(cordapp)
|
||||||
private val serviceHub = rigorousMock<ServiceHub>().also {
|
private val serviceHub = rigorousMock<ServiceHub>().also {
|
||||||
doReturn(attachments).whenever(it).attachments
|
doReturn(attachments).whenever(it).attachments
|
||||||
|
doReturn(cordappProvider).whenever(it).cordappProvider
|
||||||
|
doReturn(networkParameters).whenever(it).networkParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
// These ClassLoaders work together to load 'AnotherDummyContract' in a disposable way, such that even though
|
// These ClassLoaders work together to load 'AnotherDummyContract' in a disposable way, such that even though
|
||||||
@ -279,7 +283,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
.withClassLoader(child)
|
.withClassLoader(child)
|
||||||
|
|
||||||
val bytes = run {
|
val bytes = run {
|
||||||
val wireTransaction = tx.toWireTransaction(cordappProvider, context)
|
val wireTransaction = tx.toWireTransaction(serviceHub, context)
|
||||||
wireTransaction.serialize(context = context)
|
wireTransaction.serialize(context = context)
|
||||||
}
|
}
|
||||||
val copiedWireTransaction = bytes.deserialize(context = context)
|
val copiedWireTransaction = bytes.deserialize(context = context)
|
||||||
@ -303,7 +307,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
val outboundContext = SerializationFactory.defaultFactory.defaultContext
|
val outboundContext = SerializationFactory.defaultFactory.defaultContext
|
||||||
.withServiceHub(serviceHub)
|
.withServiceHub(serviceHub)
|
||||||
.withClassLoader(child)
|
.withClassLoader(child)
|
||||||
val wireTransaction = tx.toWireTransaction(cordappProvider, outboundContext)
|
val wireTransaction = tx.toWireTransaction(serviceHub, outboundContext)
|
||||||
wireTransaction.serialize(context = outboundContext)
|
wireTransaction.serialize(context = outboundContext)
|
||||||
}
|
}
|
||||||
// use empty attachmentStorage
|
// use empty attachmentStorage
|
||||||
|
@ -43,6 +43,7 @@ class ContractAttachmentSerializerTest {
|
|||||||
|
|
||||||
assertEquals(contractAttachment.id, deserialized.attachment.id)
|
assertEquals(contractAttachment.id, deserialized.attachment.id)
|
||||||
assertEquals(contractAttachment.contract, deserialized.contract)
|
assertEquals(contractAttachment.contract, deserialized.contract)
|
||||||
|
assertEquals(contractAttachment.additionalContracts, deserialized.additionalContracts)
|
||||||
assertArrayEquals(contractAttachment.open().readBytes(), deserialized.open().readBytes())
|
assertArrayEquals(contractAttachment.open().readBytes(), deserialized.open().readBytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +59,7 @@ class ContractAttachmentSerializerTest {
|
|||||||
|
|
||||||
assertEquals(contractAttachment.id, deserialized.attachment.id)
|
assertEquals(contractAttachment.id, deserialized.attachment.id)
|
||||||
assertEquals(contractAttachment.contract, deserialized.contract)
|
assertEquals(contractAttachment.contract, deserialized.contract)
|
||||||
|
assertEquals(contractAttachment.additionalContracts, deserialized.additionalContracts)
|
||||||
assertArrayEquals(contractAttachment.open().readBytes(), deserialized.open().readBytes())
|
assertArrayEquals(contractAttachment.open().readBytes(), deserialized.open().readBytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import com.esotericsoftware.kryo.io.Output
|
|||||||
import com.esotericsoftware.kryo.util.DefaultClassResolver
|
import com.esotericsoftware.kryo.util.DefaultClassResolver
|
||||||
import com.esotericsoftware.kryo.util.MapReferenceResolver
|
import com.esotericsoftware.kryo.util.MapReferenceResolver
|
||||||
import com.nhaarman.mockito_kotlin.*
|
import com.nhaarman.mockito_kotlin.*
|
||||||
|
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
import net.corda.core.node.services.AttachmentStorage
|
||||||
import net.corda.core.serialization.*
|
import net.corda.core.serialization.*
|
||||||
import net.corda.nodeapi.internal.AttachmentsClassLoader
|
import net.corda.nodeapi.internal.AttachmentsClassLoader
|
||||||
@ -195,7 +196,7 @@ class CordaClassResolverTests {
|
|||||||
CordaClassResolver(emptyWhitelistContext).getRegistration(DefaultSerializable::class.java)
|
CordaClassResolver(emptyWhitelistContext).getRegistration(DefaultSerializable::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun importJar(storage: AttachmentStorage) = AttachmentsClassLoaderTests.ISOLATED_CONTRACTS_JAR_PATH.openStream().use { storage.importAttachment(it) }
|
private fun importJar(storage: AttachmentStorage, uploader: String = DEPLOYED_CORDAPP_UPLOADER) = AttachmentsClassLoaderTests.ISOLATED_CONTRACTS_JAR_PATH.openStream().use { storage.importAttachment(it, uploader, "") }
|
||||||
|
|
||||||
@Test(expected = KryoException::class)
|
@Test(expected = KryoException::class)
|
||||||
fun `Annotation does not work in conjunction with AttachmentClassLoader annotation`() {
|
fun `Annotation does not work in conjunction with AttachmentClassLoader annotation`() {
|
||||||
@ -206,6 +207,15 @@ class CordaClassResolverTests {
|
|||||||
CordaClassResolver(emptyWhitelistContext).getRegistration(attachedClass)
|
CordaClassResolver(emptyWhitelistContext).getRegistration(attachedClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun `Attempt to load contract attachment with the incorrect uploader should fails with IAE`() {
|
||||||
|
val storage = MockAttachmentStorage()
|
||||||
|
val attachmentHash = importJar(storage, "some_uploader")
|
||||||
|
val classLoader = AttachmentsClassLoader(arrayOf(attachmentHash).map { storage.openAttachment(it)!! })
|
||||||
|
val attachedClass = Class.forName("net.corda.finance.contracts.isolated.AnotherDummyContract", true, classLoader)
|
||||||
|
CordaClassResolver(emptyWhitelistContext).getRegistration(attachedClass)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Annotation is inherited from interfaces`() {
|
fun `Annotation is inherited from interfaces`() {
|
||||||
CordaClassResolver(emptyWhitelistContext).getRegistration(SerializableViaInterface::class.java)
|
CordaClassResolver(emptyWhitelistContext).getRegistration(SerializableViaInterface::class.java)
|
||||||
|
@ -523,7 +523,7 @@ class EvolvabilityTests {
|
|||||||
val resource = "networkParams.<corda version>.<commit sha>"
|
val resource = "networkParams.<corda version>.<commit sha>"
|
||||||
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
|
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
|
||||||
val networkParameters = NetworkParameters(
|
val networkParameters = NetworkParameters(
|
||||||
3, listOf(NotaryInfo(DUMMY_NOTARY, false)),1000, 1000, Instant.EPOCH, 1 )
|
3, listOf(NotaryInfo(DUMMY_NOTARY, false)),1000, 1000, Instant.EPOCH, 1, emptyMap())
|
||||||
|
|
||||||
val sf = testDefaultFactory()
|
val sf = testDefaultFactory()
|
||||||
sf.register(net.corda.nodeapi.internal.serialization.amqp.custom.InstantSerializer(sf))
|
sf.register(net.corda.nodeapi.internal.serialization.amqp.custom.InstantSerializer(sf))
|
||||||
|
@ -1071,6 +1071,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi
|
|||||||
val obj2 = serdes(obj, factory, factory2, expectedEqual = false, expectDeserializedEqual = false)
|
val obj2 = serdes(obj, factory, factory2, expectedEqual = false, expectDeserializedEqual = false)
|
||||||
assertEquals(obj.id, obj2.attachment.id)
|
assertEquals(obj.id, obj2.attachment.id)
|
||||||
assertEquals(obj.contract, obj2.contract)
|
assertEquals(obj.contract, obj2.contract)
|
||||||
|
assertEquals(obj.additionalContracts, obj2.additionalContracts)
|
||||||
assertArrayEquals(obj.open().readBytes(), obj2.open().readBytes())
|
assertArrayEquals(obj.open().readBytes(), obj2.open().readBytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,9 +167,6 @@ dependencies {
|
|||||||
compile 'commons-codec:commons-codec:1.10'
|
compile 'commons-codec:commons-codec:1.10'
|
||||||
compile 'com.github.bft-smart:library:master-v1.1-beta-g6215ec8-87'
|
compile 'com.github.bft-smart:library:master-v1.1-beta-g6215ec8-87'
|
||||||
|
|
||||||
// FastClasspathScanner: classpath scanning
|
|
||||||
compile 'io.github.lukehutch:fast-classpath-scanner:2.0.21'
|
|
||||||
|
|
||||||
// Apache Shiro: authentication, authorization and session management.
|
// Apache Shiro: authentication, authorization and session management.
|
||||||
compile "org.apache.shiro:shiro-core:${shiro_version}"
|
compile "org.apache.shiro:shiro-core:${shiro_version}"
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ class AttachmentLoadingTests {
|
|||||||
@JvmField
|
@JvmField
|
||||||
val testSerialization = SerializationEnvironmentRule()
|
val testSerialization = SerializationEnvironmentRule()
|
||||||
private val attachments = MockAttachmentStorage()
|
private val attachments = MockAttachmentStorage()
|
||||||
private val provider = CordappProviderImpl(CordappLoader.createDevMode(listOf(isolatedJAR)), MockCordappConfigProvider(), attachments)
|
private val provider = CordappProviderImpl(CordappLoader.createDevMode(listOf(isolatedJAR)), MockCordappConfigProvider(), attachments, testNetworkParameters().whitelistedContractImplementations)
|
||||||
private val cordapp get() = provider.cordapps.first()
|
private val cordapp get() = provider.cordapps.first()
|
||||||
private val attachmentId get() = provider.getCordappAttachmentId(cordapp)!!
|
private val attachmentId get() = provider.getCordappAttachmentId(cordapp)!!
|
||||||
private val appContext get() = provider.getAppContext(cordapp)
|
private val appContext get() = provider.getAppContext(cordapp)
|
||||||
|
@ -48,7 +48,7 @@ class BFTNotaryServiceTests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun before() {
|
fun before() {
|
||||||
mockNet = InternalMockNetwork(emptyList())
|
mockNet = InternalMockNetwork(listOf("net.corda.testing.contracts"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
@ -556,7 +556,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
|||||||
checkpointStorage = DBCheckpointStorage()
|
checkpointStorage = DBCheckpointStorage()
|
||||||
val metrics = MetricRegistry()
|
val metrics = MetricRegistry()
|
||||||
attachments = NodeAttachmentService(metrics, configuration.attachmentContentCacheSizeBytes, configuration.attachmentCacheBound)
|
attachments = NodeAttachmentService(metrics, configuration.attachmentContentCacheSizeBytes, configuration.attachmentCacheBound)
|
||||||
val cordappProvider = CordappProviderImpl(cordappLoader, CordappConfigFileProvider(), attachments)
|
val cordappProvider = CordappProviderImpl(cordappLoader, CordappConfigFileProvider(), attachments, networkParameters.whitelistedContractImplementations)
|
||||||
val keyManagementService = makeKeyManagementService(identityService, keyPairs)
|
val keyManagementService = makeKeyManagementService(identityService, keyPairs)
|
||||||
_services = ServiceHubInternalImpl(
|
_services = ServiceHubInternalImpl(
|
||||||
identityService,
|
identityService,
|
||||||
|
@ -13,6 +13,7 @@ import net.corda.core.identity.AbstractParty
|
|||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FlowStateMachine
|
import net.corda.core.internal.FlowStateMachine
|
||||||
|
import net.corda.core.internal.RPC_UPLOADER
|
||||||
import net.corda.core.internal.sign
|
import net.corda.core.internal.sign
|
||||||
import net.corda.core.messaging.*
|
import net.corda.core.messaging.*
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
@ -189,7 +190,7 @@ internal class CordaRPCOpsImpl(
|
|||||||
override fun uploadAttachment(jar: InputStream): SecureHash {
|
override fun uploadAttachment(jar: InputStream): SecureHash {
|
||||||
// TODO: this operation should not require an explicit transaction
|
// TODO: this operation should not require an explicit transaction
|
||||||
return database.transaction {
|
return database.transaction {
|
||||||
services.attachments.importAttachment(jar)
|
services.attachments.importAttachment(jar, RPC_UPLOADER, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package net.corda.node.internal.cordapp
|
package net.corda.node.internal.cordapp
|
||||||
|
|
||||||
import com.google.common.collect.HashBiMap
|
import com.google.common.collect.HashBiMap
|
||||||
|
import net.corda.core.contracts.ContractAttachment
|
||||||
import net.corda.core.contracts.ContractClassName
|
import net.corda.core.contracts.ContractClassName
|
||||||
import net.corda.core.cordapp.Cordapp
|
import net.corda.core.cordapp.Cordapp
|
||||||
import net.corda.core.cordapp.CordappContext
|
import net.corda.core.cordapp.CordappContext
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
|
||||||
import net.corda.core.internal.cordapp.CordappConfigProvider
|
import net.corda.core.internal.cordapp.CordappConfigProvider
|
||||||
import net.corda.core.internal.createCordappContext
|
import net.corda.core.internal.createCordappContext
|
||||||
import net.corda.core.node.services.AttachmentId
|
import net.corda.core.node.services.AttachmentId
|
||||||
@ -17,7 +19,10 @@ import java.util.concurrent.ConcurrentHashMap
|
|||||||
/**
|
/**
|
||||||
* Cordapp provider and store. For querying CorDapps for their attachment and vice versa.
|
* Cordapp provider and store. For querying CorDapps for their attachment and vice versa.
|
||||||
*/
|
*/
|
||||||
open class CordappProviderImpl(private val cordappLoader: CordappLoader, private val cordappConfigProvider: CordappConfigProvider, attachmentStorage: AttachmentStorage) : SingletonSerializeAsToken(), CordappProviderInternal {
|
open class CordappProviderImpl(private val cordappLoader: CordappLoader,
|
||||||
|
private val cordappConfigProvider: CordappConfigProvider,
|
||||||
|
attachmentStorage: AttachmentStorage,
|
||||||
|
private val whitelistedContractImplementations: Map<String, List<AttachmentId>>) : SingletonSerializeAsToken(), CordappProviderInternal {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = loggerFor<CordappProviderImpl>()
|
private val log = loggerFor<CordappProviderImpl>()
|
||||||
@ -25,6 +30,34 @@ open class CordappProviderImpl(private val cordappLoader: CordappLoader, private
|
|||||||
|
|
||||||
private val contextCache = ConcurrentHashMap<Cordapp, CordappContext>()
|
private val contextCache = ConcurrentHashMap<Cordapp, CordappContext>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current known CorDapps loaded on this node
|
||||||
|
*/
|
||||||
|
override val cordapps get() = cordappLoader.cordapps
|
||||||
|
private val cordappAttachments = HashBiMap.create(loadContractsIntoAttachmentStore(attachmentStorage))
|
||||||
|
|
||||||
|
init {
|
||||||
|
verifyInstalledCordapps(attachmentStorage)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun verifyInstalledCordapps(attachmentStorage: AttachmentStorage) {
|
||||||
|
|
||||||
|
if (whitelistedContractImplementations.isEmpty()) {
|
||||||
|
log.warn("The network parameters don't specify any whitelisted contract implementations. Please contact your zone operator. See https://docs.corda.net/network-map.html")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that the installed contract classes correspond with the whitelist hash
|
||||||
|
// And warn if node is not using latest CorDapp
|
||||||
|
cordappAttachments.keys.map(attachmentStorage::openAttachment).mapNotNull { it as? ContractAttachment }.forEach { attch ->
|
||||||
|
(attch.allContracts intersect whitelistedContractImplementations.keys).forEach { contractClassName ->
|
||||||
|
when {
|
||||||
|
attch.id !in whitelistedContractImplementations[contractClassName]!! -> log.error("Contract $contractClassName found in attachment ${attch.id} is not whitelisted in the network parameters. If this is a production node contact your zone operator. See https://docs.corda.net/network-map.html")
|
||||||
|
attch.id != whitelistedContractImplementations[contractClassName]!!.last() -> log.warn("You are not using the latest CorDapp version for contract: $contractClassName. Please contact your zone operator.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun getAppContext(): CordappContext {
|
override fun getAppContext(): CordappContext {
|
||||||
// TODO: Use better supported APIs in Java 9
|
// TODO: Use better supported APIs in Java 9
|
||||||
@ -42,11 +75,6 @@ open class CordappProviderImpl(private val cordappLoader: CordappLoader, private
|
|||||||
return getCordappForClass(contractClassName)?.let(this::getCordappAttachmentId)
|
return getCordappForClass(contractClassName)?.let(this::getCordappAttachmentId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Current known CorDapps loaded on this node
|
|
||||||
*/
|
|
||||||
override val cordapps get() = cordappLoader.cordapps
|
|
||||||
private val cordappAttachments = HashBiMap.create(loadContractsIntoAttachmentStore(attachmentStorage))
|
|
||||||
/**
|
/**
|
||||||
* Gets the attachment ID of this CorDapp. Only CorDapps with contracts have an attachment ID
|
* Gets the attachment ID of this CorDapp. Only CorDapps with contracts have an attachment ID
|
||||||
*
|
*
|
||||||
@ -55,11 +83,16 @@ open class CordappProviderImpl(private val cordappLoader: CordappLoader, private
|
|||||||
*/
|
*/
|
||||||
fun getCordappAttachmentId(cordapp: Cordapp): SecureHash? = cordappAttachments.inverse().get(cordapp.jarPath)
|
fun getCordappAttachmentId(cordapp: Cordapp): SecureHash? = cordappAttachments.inverse().get(cordapp.jarPath)
|
||||||
|
|
||||||
private fun loadContractsIntoAttachmentStore(attachmentStorage: AttachmentStorage): Map<SecureHash, URL> {
|
private fun loadContractsIntoAttachmentStore(attachmentStorage: AttachmentStorage): Map<SecureHash, URL> =
|
||||||
val cordappsWithAttachments = cordapps.filter { !it.contractClassNames.isEmpty() }.map { it.jarPath }
|
cordapps.filter { !it.contractClassNames.isEmpty() }.map {
|
||||||
val attachmentIds = cordappsWithAttachments.map { it.openStream().use { attachmentStorage.importOrGetAttachment(it) } }
|
it.jarPath.openStream().use { stream ->
|
||||||
return attachmentIds.zip(cordappsWithAttachments).toMap()
|
try {
|
||||||
}
|
attachmentStorage.importAttachment(stream, DEPLOYED_CORDAPP_UPLOADER, null)
|
||||||
|
} catch (faee: java.nio.file.FileAlreadyExistsException) {
|
||||||
|
AttachmentId.parse(faee.message!!)
|
||||||
|
}
|
||||||
|
} to it.jarPath
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current cordapp context for the given CorDapp
|
* Get the current cordapp context for the given CorDapp
|
||||||
|
@ -8,8 +8,11 @@ import com.google.common.hash.HashingInputStream
|
|||||||
import com.google.common.io.CountingInputStream
|
import com.google.common.io.CountingInputStream
|
||||||
import net.corda.core.CordaRuntimeException
|
import net.corda.core.CordaRuntimeException
|
||||||
import net.corda.core.contracts.Attachment
|
import net.corda.core.contracts.Attachment
|
||||||
|
import net.corda.core.contracts.ContractAttachment
|
||||||
|
import net.corda.core.contracts.ContractClassName
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.internal.AbstractAttachment
|
import net.corda.core.internal.AbstractAttachment
|
||||||
|
import net.corda.core.internal.UNKNOWN_UPLOADER
|
||||||
import net.corda.core.internal.VisibleForTesting
|
import net.corda.core.internal.VisibleForTesting
|
||||||
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
|
||||||
@ -24,6 +27,7 @@ import net.corda.node.utilities.NonInvalidatingWeightBasedCache
|
|||||||
import net.corda.node.utilities.defaultCordaCacheConcurrencyLevel
|
import net.corda.node.utilities.defaultCordaCacheConcurrencyLevel
|
||||||
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 java.io.*
|
import java.io.*
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@ -85,7 +89,14 @@ class NodeAttachmentService(
|
|||||||
var uploader: String? = null,
|
var uploader: String? = null,
|
||||||
|
|
||||||
@Column(name = "filename", updatable = false)
|
@Column(name = "filename", updatable = false)
|
||||||
var filename: String? = null
|
var filename: String? = null,
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@Column(name = "contract_class_name")
|
||||||
|
@CollectionTable(name = "node_attachments_contract_class_name", joinColumns = arrayOf(
|
||||||
|
JoinColumn(name = "att_id", referencedColumnName = "att_id")),
|
||||||
|
foreignKey = ForeignKey(name = "FK__ctr_class__attachments"))
|
||||||
|
var contractClassNames: List<ContractClassName>? = null
|
||||||
) : Serializable
|
) : Serializable
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@ -196,23 +207,31 @@ class NodeAttachmentService(
|
|||||||
// If repeatedly looking for non-existing attachments becomes a performance issue, this is either indicating a
|
// If repeatedly looking for non-existing attachments becomes a performance issue, this is either indicating a
|
||||||
// a problem somewhere else or this needs to be revisited.
|
// a problem somewhere else or this needs to be revisited.
|
||||||
|
|
||||||
private val attachmentContentCache = NonInvalidatingWeightBasedCache<SecureHash, Optional<ByteArray>>(
|
private val attachmentContentCache = NonInvalidatingWeightBasedCache<SecureHash, Optional<Pair<Attachment, ByteArray>>>(
|
||||||
maxWeight = attachmentContentCacheSize,
|
maxWeight = attachmentContentCacheSize,
|
||||||
concurrencyLevel = defaultCordaCacheConcurrencyLevel,
|
concurrencyLevel = defaultCordaCacheConcurrencyLevel,
|
||||||
weigher = object : Weigher<SecureHash, Optional<ByteArray>> {
|
weigher = object : Weigher<SecureHash, Optional<Pair<Attachment, ByteArray>>> {
|
||||||
override fun weigh(key: SecureHash, value: Optional<ByteArray>): Int {
|
override fun weigh(key: SecureHash, value: Optional<Pair<Attachment, ByteArray>>): Int {
|
||||||
return key.size + if (value.isPresent) value.get().size else 0
|
return key.size + if (value.isPresent) value.get().second.size else 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
loadFunction = { Optional.ofNullable(loadAttachmentContent(it)) }
|
loadFunction = { Optional.ofNullable(loadAttachmentContent(it)) }
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun loadAttachmentContent(id: SecureHash): ByteArray? {
|
private fun loadAttachmentContent(id: SecureHash): Pair<Attachment, ByteArray>? {
|
||||||
val attachment = currentDBSession().get(NodeAttachmentService.DBAttachment::class.java, id.toString())
|
val attachment = currentDBSession().get(NodeAttachmentService.DBAttachment::class.java, id.toString())
|
||||||
return attachment?.content
|
?: return null
|
||||||
|
val attachmentImpl = AttachmentImpl(id, { attachment.content }, checkAttachmentsOnLoad).let {
|
||||||
|
val contracts = attachment.contractClassNames
|
||||||
|
if (contracts != null && contracts.isNotEmpty()) {
|
||||||
|
ContractAttachment(it, contracts.first(), contracts.drop(1).toSet(), attachment.uploader)
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Pair(attachmentImpl, attachment.content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val attachmentCache = NonInvalidatingCache<SecureHash, Optional<Attachment>>(
|
private val attachmentCache = NonInvalidatingCache<SecureHash, Optional<Attachment>>(
|
||||||
attachmentCacheBound,
|
attachmentCacheBound,
|
||||||
defaultCordaCacheConcurrencyLevel,
|
defaultCordaCacheConcurrencyLevel,
|
||||||
@ -222,16 +241,7 @@ class NodeAttachmentService(
|
|||||||
private fun createAttachment(key: SecureHash): Attachment? {
|
private fun createAttachment(key: SecureHash): Attachment? {
|
||||||
val content = attachmentContentCache.get(key)
|
val content = attachmentContentCache.get(key)
|
||||||
if (content.isPresent) {
|
if (content.isPresent) {
|
||||||
return AttachmentImpl(
|
return content.get().first
|
||||||
key,
|
|
||||||
{
|
|
||||||
attachmentContentCache
|
|
||||||
.get(key)
|
|
||||||
.orElseThrow {
|
|
||||||
IllegalArgumentException("No attachement impl should have been created for non existent content")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
checkAttachmentsOnLoad)
|
|
||||||
}
|
}
|
||||||
// if no attachement has been found, we don't want to cache that - it might arrive later
|
// if no attachement has been found, we don't want to cache that - it might arrive later
|
||||||
attachmentContentCache.invalidate(key)
|
attachmentContentCache.invalidate(key)
|
||||||
@ -248,10 +258,10 @@ class NodeAttachmentService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun importAttachment(jar: InputStream): AttachmentId {
|
override fun importAttachment(jar: InputStream): AttachmentId {
|
||||||
return import(jar, null, null)
|
return import(jar, UNKNOWN_UPLOADER, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun importAttachment(jar: InputStream, uploader: String, filename: String): AttachmentId {
|
override fun importAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId {
|
||||||
return import(jar, uploader, filename)
|
return import(jar, uploader, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,47 +273,39 @@ class NodeAttachmentService(
|
|||||||
return Pair(id, bytes)
|
return Pair(id, bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hasAttachment(attachmentId: AttachmentId): Boolean {
|
override fun hasAttachment(attachmentId: AttachmentId): Boolean =
|
||||||
val session = currentDBSession()
|
currentDBSession().find(NodeAttachmentService.DBAttachment::class.java, attachmentId.toString()) != null
|
||||||
val criteriaBuilder = session.criteriaBuilder
|
|
||||||
val criteriaQuery = criteriaBuilder.createQuery(Long::class.java)
|
|
||||||
val attachments = criteriaQuery.from(NodeAttachmentService.DBAttachment::class.java)
|
|
||||||
criteriaQuery.select(criteriaBuilder.count(criteriaQuery.from(NodeAttachmentService.DBAttachment::class.java)))
|
|
||||||
criteriaQuery.where(criteriaBuilder.equal(attachments.get<String>(DBAttachment::attId.name), attachmentId.toString()))
|
|
||||||
return (session.createQuery(criteriaQuery).singleResult > 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: PLT-147: The attachment should be randomised to prevent brute force guessing and thus privacy leaks.
|
// TODO: PLT-147: The attachment should be randomised to prevent brute force guessing and thus privacy leaks.
|
||||||
private fun import(jar: InputStream, uploader: String?, filename: String?): AttachmentId {
|
private fun import(jar: InputStream, uploader: String?, filename: String?): AttachmentId {
|
||||||
require(jar !is JarInputStream)
|
return withContractsInJar(jar) { contractClassNames, inputStream ->
|
||||||
|
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, hashing it to find the ID as we go. 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(jar)
|
val (id, bytes) = getAttachmentIdAndBytes(inputStream)
|
||||||
if (!hasAttachment(id)) {
|
if (!hasAttachment(id)) {
|
||||||
checkIsAValidJAR(ByteArrayInputStream(bytes))
|
checkIsAValidJAR(ByteArrayInputStream(bytes))
|
||||||
val session = currentDBSession()
|
val session = currentDBSession()
|
||||||
val attachment = NodeAttachmentService.DBAttachment(attId = id.toString(), content = bytes, uploader = uploader, filename = filename)
|
val attachment = NodeAttachmentService.DBAttachment(attId = id.toString(), content = bytes, uploader = uploader, filename = filename, contractClassNames = contractClassNames)
|
||||||
session.save(attachment)
|
session.save(attachment)
|
||||||
attachmentCount.inc()
|
attachmentCount.inc()
|
||||||
log.info("Stored new attachment $id")
|
log.info("Stored new attachment $id")
|
||||||
return id
|
id
|
||||||
} else {
|
} else {
|
||||||
throw java.nio.file.FileAlreadyExistsException(id.toString())
|
throw java.nio.file.FileAlreadyExistsException(id.toString())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun importOrGetAttachment(jar: InputStream): AttachmentId {
|
override fun importOrGetAttachment(jar: InputStream): AttachmentId = try {
|
||||||
try {
|
importAttachment(jar)
|
||||||
return importAttachment(jar)
|
} catch (faee: java.nio.file.FileAlreadyExistsException) {
|
||||||
}
|
AttachmentId.parse(faee.message!!)
|
||||||
catch (faee: java.nio.file.FileAlreadyExistsException) {
|
|
||||||
return AttachmentId.parse(faee.message!!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun queryAttachments(criteria: AttachmentQueryCriteria, sorting: AttachmentSort?): List<AttachmentId> {
|
override fun queryAttachments(criteria: AttachmentQueryCriteria, sorting: AttachmentSort?): List<AttachmentId> {
|
||||||
@ -328,5 +330,4 @@ class NodeAttachmentService(
|
|||||||
return results.map { AttachmentId.parse(it.attId) }
|
return results.map { AttachmentId.parse(it.attId) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,18 @@ package net.corda.node.internal.cordapp
|
|||||||
|
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
|
import junit.framework.Assert.assertNull
|
||||||
import net.corda.core.internal.cordapp.CordappConfigProvider
|
import net.corda.core.internal.cordapp.CordappConfigProvider
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
import net.corda.core.node.services.AttachmentStorage
|
||||||
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.internal.MockCordappConfigProvider
|
import net.corda.testing.internal.MockCordappConfigProvider
|
||||||
import net.corda.testing.services.MockAttachmentStorage
|
import net.corda.testing.services.MockAttachmentStorage
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Assert
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNotNull
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
class CordappProviderImplTests {
|
class CordappProviderImplTests {
|
||||||
private companion object {
|
private companion object {
|
||||||
@ -25,6 +29,7 @@ class CordappProviderImplTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var attachmentStore: AttachmentStorage
|
private lateinit var attachmentStore: AttachmentStorage
|
||||||
|
private val whitelistedContractImplementations = testNetworkParameters().whitelistedContractImplementations
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
@ -33,44 +38,40 @@ class CordappProviderImplTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `isolated jar is loaded into the attachment store`() {
|
fun `isolated jar is loaded into the attachment store`() {
|
||||||
val loader = CordappLoader.createDevMode(listOf(isolatedJAR))
|
val provider = newCordappProvider(isolatedJAR)
|
||||||
val provider = CordappProviderImpl(loader, stubConfigProvider, attachmentStore)
|
|
||||||
val maybeAttachmentId = provider.getCordappAttachmentId(provider.cordapps.first())
|
val maybeAttachmentId = provider.getCordappAttachmentId(provider.cordapps.first())
|
||||||
|
|
||||||
Assert.assertNotNull(maybeAttachmentId)
|
assertNotNull(maybeAttachmentId)
|
||||||
Assert.assertNotNull(attachmentStore.openAttachment(maybeAttachmentId!!))
|
assertNotNull(attachmentStore.openAttachment(maybeAttachmentId!!))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `empty jar is not loaded into the attachment store`() {
|
fun `empty jar is not loaded into the attachment store`() {
|
||||||
val loader = CordappLoader.createDevMode(listOf(emptyJAR))
|
val provider = newCordappProvider(emptyJAR)
|
||||||
val provider = CordappProviderImpl(loader, stubConfigProvider, attachmentStore)
|
assertNull(provider.getCordappAttachmentId(provider.cordapps.first()))
|
||||||
Assert.assertNull(provider.getCordappAttachmentId(provider.cordapps.first()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test that we find a cordapp class that is loaded into the store`() {
|
fun `test that we find a cordapp class that is loaded into the store`() {
|
||||||
val loader = CordappLoader.createDevMode(listOf(isolatedJAR))
|
val provider = newCordappProvider(isolatedJAR)
|
||||||
val provider = CordappProviderImpl(loader, stubConfigProvider, attachmentStore)
|
|
||||||
val className = "net.corda.finance.contracts.isolated.AnotherDummyContract"
|
val className = "net.corda.finance.contracts.isolated.AnotherDummyContract"
|
||||||
|
|
||||||
val expected = provider.cordapps.first()
|
val expected = provider.cordapps.first()
|
||||||
val actual = provider.getCordappForClass(className)
|
val actual = provider.getCordappForClass(className)
|
||||||
|
|
||||||
Assert.assertNotNull(actual)
|
assertNotNull(actual)
|
||||||
Assert.assertEquals(expected, actual)
|
assertEquals(expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test that we find an attachment for a cordapp contract class`() {
|
fun `test that we find an attachment for a cordapp contrat class`() {
|
||||||
val loader = CordappLoader.createDevMode(listOf(isolatedJAR))
|
val provider = newCordappProvider(isolatedJAR)
|
||||||
val provider = CordappProviderImpl(loader, stubConfigProvider, attachmentStore)
|
|
||||||
val className = "net.corda.finance.contracts.isolated.AnotherDummyContract"
|
val className = "net.corda.finance.contracts.isolated.AnotherDummyContract"
|
||||||
val expected = provider.getAppContext(provider.cordapps.first()).attachmentId
|
val expected = provider.getAppContext(provider.cordapps.first()).attachmentId
|
||||||
val actual = provider.getContractAttachmentID(className)
|
val actual = provider.getContractAttachmentID(className)
|
||||||
|
|
||||||
Assert.assertNotNull(actual)
|
assertNotNull(actual)
|
||||||
Assert.assertEquals(actual!!, expected)
|
assertEquals(actual!!, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -78,10 +79,15 @@ class CordappProviderImplTests {
|
|||||||
val configProvider = MockCordappConfigProvider()
|
val configProvider = MockCordappConfigProvider()
|
||||||
configProvider.cordappConfigs.put(isolatedCordappName, validConfig)
|
configProvider.cordappConfigs.put(isolatedCordappName, validConfig)
|
||||||
val loader = CordappLoader.createDevMode(listOf(isolatedJAR))
|
val loader = CordappLoader.createDevMode(listOf(isolatedJAR))
|
||||||
val provider = CordappProviderImpl(loader, configProvider, attachmentStore)
|
val provider = CordappProviderImpl(loader, configProvider, attachmentStore, whitelistedContractImplementations)
|
||||||
|
|
||||||
val expected = provider.getAppContext(provider.cordapps.first()).config
|
val expected = provider.getAppContext(provider.cordapps.first()).config
|
||||||
|
|
||||||
assertThat(expected.getString("key")).isEqualTo("value")
|
assertThat(expected.getString("key")).isEqualTo("value")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun newCordappProvider(vararg urls: URL): CordappProviderImpl {
|
||||||
|
val loader = CordappLoader.createDevMode(urls.toList())
|
||||||
|
return CordappProviderImpl(loader, stubConfigProvider, attachmentStore, whitelistedContractImplementations)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ open class MockServices private constructor(
|
|||||||
cordappLoader: CordappLoader,
|
cordappLoader: CordappLoader,
|
||||||
override val validatedTransactions: WritableTransactionStorage,
|
override val validatedTransactions: WritableTransactionStorage,
|
||||||
override val identityService: IdentityService,
|
override val identityService: IdentityService,
|
||||||
override val networkParameters: NetworkParameters,
|
final override val networkParameters: NetworkParameters,
|
||||||
private val initialIdentity: TestIdentity,
|
private val initialIdentity: TestIdentity,
|
||||||
private val moreKeys: Array<out KeyPair>
|
private val moreKeys: Array<out KeyPair>
|
||||||
) : ServiceHub, StateLoader by validatedTransactions {
|
) : ServiceHub, StateLoader by validatedTransactions {
|
||||||
@ -226,7 +226,7 @@ open class MockServices private constructor(
|
|||||||
return NodeInfo(listOf(NetworkHostAndPort("mock.node.services", 10000)), listOf(initialIdentity.identity), 1, serial = 1L)
|
return NodeInfo(listOf(NetworkHostAndPort("mock.node.services", 10000)), listOf(initialIdentity.identity), 1, serial = 1L)
|
||||||
}
|
}
|
||||||
override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(2)
|
override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(2)
|
||||||
private val mockCordappProvider: MockCordappProvider = MockCordappProvider(cordappLoader, attachments)
|
private val mockCordappProvider: MockCordappProvider = MockCordappProvider(cordappLoader, attachments, networkParameters.whitelistedContractImplementations)
|
||||||
override val cordappProvider: CordappProvider get() = mockCordappProvider
|
override val cordappProvider: CordappProvider get() = mockCordappProvider
|
||||||
|
|
||||||
internal fun makeVaultService(hibernateConfig: HibernateConfiguration, schemaService: SchemaService): VaultServiceInternal {
|
internal fun makeVaultService(hibernateConfig: HibernateConfiguration, schemaService: SchemaService): VaultServiceInternal {
|
||||||
|
@ -39,7 +39,7 @@ class NetworkMapServer(private val cacheTimeout: Duration,
|
|||||||
private val myHostNameValue: String = "test.host.name",
|
private val myHostNameValue: String = "test.host.name",
|
||||||
vararg additionalServices: Any) : Closeable {
|
vararg additionalServices: Any) : Closeable {
|
||||||
companion object {
|
companion object {
|
||||||
private val stubNetworkParameters = NetworkParameters(1, emptyList(), 10485760, Int.MAX_VALUE, Instant.now(), 10)
|
private val stubNetworkParameters = NetworkParameters(1, emptyList(), 10485760, Int.MAX_VALUE, Instant.now(), 10, emptyMap())
|
||||||
}
|
}
|
||||||
|
|
||||||
private val server: Server
|
private val server: Server
|
||||||
|
@ -19,6 +19,7 @@ fun testNetworkParameters(
|
|||||||
modifiedTime = modifiedTime,
|
modifiedTime = modifiedTime,
|
||||||
maxMessageSize = maxMessageSize,
|
maxMessageSize = maxMessageSize,
|
||||||
maxTransactionSize = maxTransactionSize,
|
maxTransactionSize = maxTransactionSize,
|
||||||
epoch = epoch
|
epoch = epoch,
|
||||||
|
whitelistedContractImplementations = emptyMap()
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ package net.corda.testing.internal
|
|||||||
|
|
||||||
import net.corda.core.contracts.ContractClassName
|
import net.corda.core.contracts.ContractClassName
|
||||||
import net.corda.core.cordapp.Cordapp
|
import net.corda.core.cordapp.Cordapp
|
||||||
|
import net.corda.core.internal.TEST_UPLOADER
|
||||||
import net.corda.core.internal.cordapp.CordappImpl
|
import net.corda.core.internal.cordapp.CordappImpl
|
||||||
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
|
||||||
@ -14,9 +15,10 @@ import java.util.*
|
|||||||
class MockCordappProvider(
|
class MockCordappProvider(
|
||||||
cordappLoader: CordappLoader,
|
cordappLoader: CordappLoader,
|
||||||
attachmentStorage: AttachmentStorage,
|
attachmentStorage: AttachmentStorage,
|
||||||
val cordappConfigProvider: MockCordappConfigProvider = MockCordappConfigProvider()
|
whitelistedContractImplementations: Map<String, List<AttachmentId>>,
|
||||||
) : CordappProviderImpl(cordappLoader, cordappConfigProvider, attachmentStorage) {
|
cordappConfigProvider: MockCordappConfigProvider = MockCordappConfigProvider()
|
||||||
constructor(cordappLoader: CordappLoader, attachmentStorage: AttachmentStorage) : this(cordappLoader, attachmentStorage, MockCordappConfigProvider())
|
) : CordappProviderImpl(cordappLoader, cordappConfigProvider, attachmentStorage, whitelistedContractImplementations) {
|
||||||
|
constructor(cordappLoader: CordappLoader, attachmentStorage: AttachmentStorage, whitelistedContractImplementations: Map<String, List<AttachmentId>>) : this(cordappLoader, attachmentStorage, whitelistedContractImplementations, MockCordappConfigProvider())
|
||||||
|
|
||||||
val cordappRegistry = mutableListOf<Pair<Cordapp, AttachmentId>>()
|
val cordappRegistry = mutableListOf<Pair<Cordapp, AttachmentId>>()
|
||||||
|
|
||||||
@ -33,20 +35,21 @@ class MockCordappProvider(
|
|||||||
customSchemas = emptySet(),
|
customSchemas = emptySet(),
|
||||||
jarPath = Paths.get("").toUri().toURL())
|
jarPath = Paths.get("").toUri().toURL())
|
||||||
if (cordappRegistry.none { it.first.contractClassNames.contains(contractClassName) }) {
|
if (cordappRegistry.none { it.first.contractClassNames.contains(contractClassName) }) {
|
||||||
cordappRegistry.add(Pair(cordapp, findOrImportAttachment(contractClassName.toByteArray(), attachments)))
|
cordappRegistry.add(Pair(cordapp, findOrImportAttachment(listOf(contractClassName), contractClassName.toByteArray(), attachments)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getContractAttachmentID(contractClassName: ContractClassName): AttachmentId? = cordappRegistry.find { it.first.contractClassNames.contains(contractClassName) }?.second ?: super.getContractAttachmentID(contractClassName)
|
override fun getContractAttachmentID(contractClassName: ContractClassName): AttachmentId? = cordappRegistry.find { it.first.contractClassNames.contains(contractClassName) }?.second
|
||||||
|
?: super.getContractAttachmentID(contractClassName)
|
||||||
|
|
||||||
private fun findOrImportAttachment(data: ByteArray, attachments: MockAttachmentStorage): AttachmentId {
|
private fun findOrImportAttachment(contractClassNames: List<ContractClassName>, data: ByteArray, attachments: MockAttachmentStorage): AttachmentId {
|
||||||
val existingAttachment = attachments.files.filter {
|
val existingAttachment = attachments.files.filter {
|
||||||
Arrays.equals(it.value, data)
|
Arrays.equals(it.value.second, data)
|
||||||
}
|
}
|
||||||
return if (!existingAttachment.isEmpty()) {
|
return if (!existingAttachment.isEmpty()) {
|
||||||
existingAttachment.keys.first()
|
existingAttachment.keys.first()
|
||||||
} else {
|
} else {
|
||||||
attachments.importAttachment(data.inputStream())
|
attachments.importContractAttachment(contractClassNames, TEST_UPLOADER, data.inputStream())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
package net.corda.testing.services
|
package net.corda.testing.services
|
||||||
|
|
||||||
import net.corda.core.contracts.Attachment
|
import net.corda.core.contracts.Attachment
|
||||||
|
import net.corda.core.contracts.ContractAttachment
|
||||||
|
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.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.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 java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -24,31 +28,17 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun importAttachment(jar: InputStream): AttachmentId {
|
val files = HashMap<SecureHash, Pair<Attachment, ByteArray>>()
|
||||||
// JIS makes read()/readBytes() return bytes of the current file, but we want to hash the entire container here.
|
|
||||||
require(jar !is JarInputStream)
|
|
||||||
|
|
||||||
val bytes = getBytes(jar)
|
override fun importAttachment(jar: InputStream): AttachmentId = importAttachment(jar, UNKNOWN_UPLOADER, null)
|
||||||
|
|
||||||
val sha256 = bytes.sha256()
|
override fun importAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId {
|
||||||
if (!files.containsKey(sha256)) {
|
return withContractsInJar(jar) { contractClassNames, inputStream ->
|
||||||
files[sha256] = bytes
|
importAttachmentInternal(inputStream, uploader, filename, contractClassNames)
|
||||||
}
|
}
|
||||||
return sha256
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun importAttachment(jar: InputStream, uploader: String, filename: String): AttachmentId {
|
override fun openAttachment(id: SecureHash): Attachment? = files[id]?.first
|
||||||
return importAttachment(jar)
|
|
||||||
}
|
|
||||||
|
|
||||||
val files = HashMap<SecureHash, ByteArray>()
|
|
||||||
|
|
||||||
private class MockAttachment(dataLoader: () -> ByteArray, override val id: SecureHash) : AbstractAttachment(dataLoader)
|
|
||||||
|
|
||||||
override fun openAttachment(id: SecureHash): Attachment? {
|
|
||||||
val f = files[id] ?: return null
|
|
||||||
return MockAttachment({ f }, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun queryAttachments(criteria: AttachmentQueryCriteria, sorting: AttachmentSort?): List<AttachmentId> {
|
override fun queryAttachments(criteria: AttachmentQueryCriteria, sorting: AttachmentSort?): List<AttachmentId> {
|
||||||
throw NotImplementedError("Querying for attachments not implemented")
|
throw NotImplementedError("Querying for attachments not implemented")
|
||||||
@ -56,11 +46,6 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() {
|
|||||||
|
|
||||||
override fun hasAttachment(attachmentId: AttachmentId) = files.containsKey(attachmentId)
|
override fun hasAttachment(attachmentId: AttachmentId) = files.containsKey(attachmentId)
|
||||||
|
|
||||||
fun getAttachmentIdAndBytes(jar: InputStream): Pair<AttachmentId, ByteArray> {
|
|
||||||
val bytes = getBytes(jar)
|
|
||||||
return Pair(bytes.sha256(), bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun importOrGetAttachment(jar: InputStream): AttachmentId {
|
override fun importOrGetAttachment(jar: InputStream): AttachmentId {
|
||||||
try {
|
try {
|
||||||
return importAttachment(jar)
|
return importAttachment(jar)
|
||||||
@ -68,4 +53,25 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() {
|
|||||||
return AttachmentId.parse(faee.message!!)
|
return AttachmentId.parse(faee.message!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun importContractAttachment(contractClassNames: List<ContractClassName>, uploader: String, jar: InputStream): AttachmentId = importAttachmentInternal(jar, uploader, null, contractClassNames)
|
||||||
|
|
||||||
|
fun getAttachmentIdAndBytes(jar: InputStream): Pair<AttachmentId, ByteArray> = getBytes(jar).let { bytes -> Pair(bytes.sha256(), bytes) }
|
||||||
|
|
||||||
|
private class MockAttachment(dataLoader: () -> ByteArray, override val id: SecureHash) : AbstractAttachment(dataLoader)
|
||||||
|
|
||||||
|
private fun importAttachmentInternal(jar: InputStream, uploader: String, filename: String?, contractClassNames: List<ContractClassName>? = null): AttachmentId {
|
||||||
|
// JIS makes read()/readBytes() return bytes of the current file, but we want to hash the entire container here.
|
||||||
|
require(jar !is JarInputStream)
|
||||||
|
|
||||||
|
val bytes = getBytes(jar)
|
||||||
|
|
||||||
|
val sha256 = bytes.sha256()
|
||||||
|
if (sha256 !in files.keys) {
|
||||||
|
val baseAttachment = MockAttachment({ bytes }, sha256)
|
||||||
|
val attachment = if (contractClassNames == null || contractClassNames.isEmpty()) baseAttachment else ContractAttachment(baseAttachment, contractClassNames.first(), contractClassNames.toSet(), uploader)
|
||||||
|
files[sha256] = Pair(attachment, bytes)
|
||||||
|
}
|
||||||
|
return sha256
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,8 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() {
|
|||||||
modifiedTime = Instant.now(),
|
modifiedTime = Instant.now(),
|
||||||
maxMessageSize = 10485760,
|
maxMessageSize = 10485760,
|
||||||
maxTransactionSize = Int.MAX_VALUE,
|
maxTransactionSize = Int.MAX_VALUE,
|
||||||
epoch = 1
|
epoch = 1,
|
||||||
|
whitelistedContractImplementations = emptyMap()
|
||||||
))
|
))
|
||||||
notaryIdentity = identity
|
notaryIdentity = identity
|
||||||
networkParametersCopier = parametersCopier
|
networkParametersCopier = parametersCopier
|
||||||
|
@ -43,7 +43,7 @@ data class GeneratedLedger(
|
|||||||
private val attachmentMap: Map<SecureHash, Attachment> by lazy { attachments.associateBy(Attachment::id) }
|
private val attachmentMap: Map<SecureHash, Attachment> by lazy { attachments.associateBy(Attachment::id) }
|
||||||
private val identityMap: Map<PublicKey, Party> by lazy { identities.associateBy(Party::owningKey) }
|
private val identityMap: Map<PublicKey, Party> by lazy { identities.associateBy(Party::owningKey) }
|
||||||
private val contractAttachmentMap: Map<String, ContractAttachment> by lazy {
|
private val contractAttachmentMap: Map<String, ContractAttachment> by lazy {
|
||||||
attachments.mapNotNull { it as? ContractAttachment }.associateBy { it.contract }
|
attachments.mapNotNull { it as? ContractAttachment }.flatMap { attch-> attch.allContracts.map { it to attch } }.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val services = object : ServicesForResolution {
|
private val services = object : ServicesForResolution {
|
||||||
|
@ -17,6 +17,7 @@ import net.corda.testing.core.DUMMY_NOTARY_NAME
|
|||||||
import net.corda.testing.core.SerializationEnvironmentRule
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
import net.corda.testing.driver.internal.NodeHandleInternal
|
import net.corda.testing.driver.internal.NodeHandleInternal
|
||||||
import net.corda.testing.node.NotarySpec
|
import net.corda.testing.node.NotarySpec
|
||||||
|
import org.junit.Ignore
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -133,6 +134,7 @@ class VerifierTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore("CORDA-1022")
|
||||||
@Test
|
@Test
|
||||||
fun `single verifier works with a node`() {
|
fun `single verifier works with a node`() {
|
||||||
verifierDriver(
|
verifierDriver(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user