Merge branch 'release/os/4.10' into merge-release/os/4.9-release/os/4.10-2024-11-25-422

This commit is contained in:
Chris Cochrane 2024-11-25 16:49:21 +00:00 committed by GitHub
commit 2ed9753f87
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
118 changed files with 3710 additions and 512 deletions

View File

@ -157,6 +157,8 @@ public final class net.corda.core.context.InvocationContext extends java.lang.Ob
public <init>(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, int, kotlin.jvm.internal.DefaultConstructorMarker) public <init>(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, String) public <init>(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, String)
public <init>(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List, String, int, kotlin.jvm.internal.DefaultConstructorMarker) public <init>(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List, String, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, String, net.corda.core.internal.telemetry.SerializedTelemetry)
public <init>(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List, String, net.corda.core.internal.telemetry.SerializedTelemetry, int, kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull @NotNull
public final net.corda.core.context.InvocationOrigin component1() public final net.corda.core.context.InvocationOrigin component1()
@NotNull @NotNull
@ -171,10 +173,14 @@ public final class net.corda.core.context.InvocationContext extends java.lang.Ob
public final java.util.List<Object> component6() public final java.util.List<Object> component6()
@Nullable @Nullable
public final String component7() public final String component7()
@Nullable
public final net.corda.core.internal.telemetry.SerializedTelemetry component8()
@NotNull @NotNull
public final net.corda.core.context.InvocationContext copy(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor) public final net.corda.core.context.InvocationContext copy(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor)
@NotNull @NotNull
public final net.corda.core.context.InvocationContext copy(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, String) public final net.corda.core.context.InvocationContext copy(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, String)
@NotNull
public final net.corda.core.context.InvocationContext copy(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, String, net.corda.core.internal.telemetry.SerializedTelemetry)
public boolean equals(Object) public boolean equals(Object)
@Nullable @Nullable
public final net.corda.core.context.Actor getActor() public final net.corda.core.context.Actor getActor()
@ -188,6 +194,8 @@ public final class net.corda.core.context.InvocationContext extends java.lang.Ob
public final net.corda.core.context.Actor getImpersonatedActor() public final net.corda.core.context.Actor getImpersonatedActor()
@NotNull @NotNull
public final net.corda.core.context.InvocationOrigin getOrigin() public final net.corda.core.context.InvocationOrigin getOrigin()
@Nullable
public final net.corda.core.internal.telemetry.SerializedTelemetry getSerializedTelemetry()
@NotNull @NotNull
public final net.corda.core.context.Trace getTrace() public final net.corda.core.context.Trace getTrace()
public int hashCode() public int hashCode()
@ -206,6 +214,8 @@ public final class net.corda.core.context.InvocationContext extends java.lang.Ob
@NotNull @NotNull
public static final net.corda.core.context.InvocationContext newInstance(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, String) public static final net.corda.core.context.InvocationContext newInstance(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, String)
@NotNull @NotNull
public static final net.corda.core.context.InvocationContext newInstance(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, String, net.corda.core.internal.telemetry.SerializedTelemetry)
@NotNull
public static final net.corda.core.context.InvocationContext peer(net.corda.core.identity.CordaX500Name, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor) public static final net.corda.core.context.InvocationContext peer(net.corda.core.identity.CordaX500Name, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor)
@NotNull @NotNull
public final java.security.Principal principal() public final java.security.Principal principal()
@ -220,6 +230,8 @@ public final class net.corda.core.context.InvocationContext extends java.lang.Ob
@NotNull @NotNull
public static final net.corda.core.context.InvocationContext rpc(net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>) public static final net.corda.core.context.InvocationContext rpc(net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>)
@NotNull @NotNull
public static final net.corda.core.context.InvocationContext rpc(net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, net.corda.core.internal.telemetry.SerializedTelemetry)
@NotNull
public static final net.corda.core.context.InvocationContext scheduled(net.corda.core.contracts.ScheduledStateRef, net.corda.core.context.Trace, net.corda.core.context.Trace) public static final net.corda.core.context.InvocationContext scheduled(net.corda.core.contracts.ScheduledStateRef, net.corda.core.context.Trace, net.corda.core.context.Trace)
@NotNull @NotNull
public static final net.corda.core.context.InvocationContext service(String, net.corda.core.identity.CordaX500Name, net.corda.core.context.Trace, net.corda.core.context.Trace) public static final net.corda.core.context.InvocationContext service(String, net.corda.core.identity.CordaX500Name, net.corda.core.context.Trace, net.corda.core.context.Trace)
@ -246,6 +258,8 @@ public static final class net.corda.core.context.InvocationContext$Companion ext
@NotNull @NotNull
public final net.corda.core.context.InvocationContext newInstance(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, String) public final net.corda.core.context.InvocationContext newInstance(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, String)
@NotNull @NotNull
public final net.corda.core.context.InvocationContext newInstance(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, String, net.corda.core.internal.telemetry.SerializedTelemetry)
@NotNull
public final net.corda.core.context.InvocationContext peer(net.corda.core.identity.CordaX500Name, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor) public final net.corda.core.context.InvocationContext peer(net.corda.core.identity.CordaX500Name, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor)
@NotNull @NotNull
public final net.corda.core.context.InvocationContext rpc(net.corda.core.context.Actor) public final net.corda.core.context.InvocationContext rpc(net.corda.core.context.Actor)
@ -258,6 +272,8 @@ public static final class net.corda.core.context.InvocationContext$Companion ext
@NotNull @NotNull
public final net.corda.core.context.InvocationContext rpc(net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>) public final net.corda.core.context.InvocationContext rpc(net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>)
@NotNull @NotNull
public final net.corda.core.context.InvocationContext rpc(net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor, java.util.List<?>, net.corda.core.internal.telemetry.SerializedTelemetry)
@NotNull
public final net.corda.core.context.InvocationContext scheduled(net.corda.core.contracts.ScheduledStateRef, net.corda.core.context.Trace, net.corda.core.context.Trace) public final net.corda.core.context.InvocationContext scheduled(net.corda.core.contracts.ScheduledStateRef, net.corda.core.context.Trace, net.corda.core.context.Trace)
@NotNull @NotNull
public final net.corda.core.context.InvocationContext service(String, net.corda.core.identity.CordaX500Name, net.corda.core.context.Trace, net.corda.core.context.Trace) public final net.corda.core.context.InvocationContext service(String, net.corda.core.identity.CordaX500Name, net.corda.core.context.Trace, net.corda.core.context.Trace)
@ -804,7 +820,16 @@ public final class net.corda.core.contracts.PartyAndReference extends java.lang.
@CordaSerializable @CordaSerializable
public final class net.corda.core.contracts.PrivacySalt extends net.corda.core.utilities.OpaqueBytes public final class net.corda.core.contracts.PrivacySalt extends net.corda.core.utilities.OpaqueBytes
public <init>() public <init>()
public <init>(int)
public <init>(byte[]) public <init>(byte[])
@NotNull
public static final net.corda.core.contracts.PrivacySalt createFor(String)
public static final net.corda.core.contracts.PrivacySalt$Companion Companion
##
public static final class net.corda.core.contracts.PrivacySalt$Companion extends java.lang.Object
public <init>(kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull
public final net.corda.core.contracts.PrivacySalt createFor(String)
## ##
public final class net.corda.core.contracts.ReferencedStateAndRef extends java.lang.Object public final class net.corda.core.contracts.ReferencedStateAndRef extends java.lang.Object
public <init>(net.corda.core.contracts.StateAndRef<? extends T>) public <init>(net.corda.core.contracts.StateAndRef<? extends T>)
@ -882,6 +907,14 @@ public final class net.corda.core.contracts.SignatureAttachmentConstraint extend
public boolean isSatisfiedBy(net.corda.core.contracts.Attachment) public boolean isSatisfiedBy(net.corda.core.contracts.Attachment)
@NotNull @NotNull
public String toString() public String toString()
public static final net.corda.core.contracts.SignatureAttachmentConstraint$Companion Companion
##
public static final class net.corda.core.contracts.SignatureAttachmentConstraint$Companion extends java.lang.Object implements net.corda.core.internal.utilities.Internable
public <init>(kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull
public final net.corda.core.contracts.SignatureAttachmentConstraint create(java.security.PublicKey)
@NotNull
public net.corda.core.internal.utilities.PrivateInterner<net.corda.core.contracts.SignatureAttachmentConstraint> getInterner()
## ##
public final class net.corda.core.contracts.SourceAndAmount extends java.lang.Object public final class net.corda.core.contracts.SourceAndAmount extends java.lang.Object
public <init>(P, net.corda.core.contracts.Amount<T>, Object) public <init>(P, net.corda.core.contracts.Amount<T>, Object)
@ -999,6 +1032,8 @@ public final class net.corda.core.contracts.Structures extends java.lang.Object
@NotNull @NotNull
public static final net.corda.core.crypto.SecureHash hash(net.corda.core.contracts.ContractState) public static final net.corda.core.crypto.SecureHash hash(net.corda.core.contracts.ContractState)
@NotNull @NotNull
public static final net.corda.core.crypto.SecureHash hash(net.corda.core.contracts.ContractState, String)
@NotNull
public static final net.corda.core.contracts.Amount<T> withoutIssuer(net.corda.core.contracts.Amount<net.corda.core.contracts.Issued<T>>) public static final net.corda.core.contracts.Amount<T> withoutIssuer(net.corda.core.contracts.Amount<net.corda.core.contracts.Issued<T>>)
public static final int MAX_ISSUER_REF_SIZE = 512 public static final int MAX_ISSUER_REF_SIZE = 512
## ##
@ -1099,6 +1134,10 @@ public abstract class net.corda.core.contracts.TransactionVerificationException
public final net.corda.core.crypto.SecureHash getTxId() public final net.corda.core.crypto.SecureHash getTxId()
## ##
@CordaSerializable @CordaSerializable
public static final class net.corda.core.contracts.TransactionVerificationException$AttachmentTooBigException extends net.corda.core.contracts.TransactionVerificationException
public <init>(net.corda.core.crypto.SecureHash)
##
@CordaSerializable
public static final class net.corda.core.contracts.TransactionVerificationException$BrokenTransactionException extends net.corda.core.contracts.TransactionVerificationException public static final class net.corda.core.contracts.TransactionVerificationException$BrokenTransactionException extends net.corda.core.contracts.TransactionVerificationException
public <init>(net.corda.core.crypto.SecureHash, String) public <init>(net.corda.core.crypto.SecureHash, String)
## ##
@ -1257,6 +1296,10 @@ public static final class net.corda.core.contracts.TransactionVerificationExcept
public <init>(net.corda.core.crypto.SecureHash, String, Throwable) public <init>(net.corda.core.crypto.SecureHash, String, Throwable)
## ##
@CordaSerializable @CordaSerializable
public static final class net.corda.core.contracts.TransactionVerificationException$UnsupportedHashTypeException extends net.corda.core.contracts.TransactionVerificationException
public <init>(net.corda.core.crypto.SecureHash)
##
@CordaSerializable
public static final class net.corda.core.contracts.TransactionVerificationException$UntrustedAttachmentsException extends net.corda.core.CordaException public static final class net.corda.core.contracts.TransactionVerificationException$UntrustedAttachmentsException extends net.corda.core.CordaException
public <init>(net.corda.core.crypto.SecureHash, java.util.List<? extends net.corda.core.crypto.SecureHash>) public <init>(net.corda.core.crypto.SecureHash, java.util.List<? extends net.corda.core.crypto.SecureHash>)
@NotNull @NotNull
@ -1352,6 +1395,8 @@ public interface net.corda.core.cordapp.Cordapp
@NotNull @NotNull
public abstract java.util.List<Class<? extends net.corda.core.serialization.SerializeAsToken>> getServices() public abstract java.util.List<Class<? extends net.corda.core.serialization.SerializeAsToken>> getServices()
public abstract int getTargetPlatformVersion() public abstract int getTargetPlatformVersion()
@NotNull
public abstract java.util.List<Class<? extends net.corda.core.internal.telemetry.TelemetryComponent>> getTelemetryComponents()
## ##
@DoNotImplement @DoNotImplement
public static interface net.corda.core.cordapp.Cordapp$Info public static interface net.corda.core.cordapp.Cordapp$Info
@ -1861,6 +1906,53 @@ public interface net.corda.core.crypto.DigestAlgorithm
public abstract byte[] nonceDigest(byte[]) public abstract byte[] nonceDigest(byte[])
## ##
@CordaSerializable @CordaSerializable
public final class net.corda.core.crypto.DigestService extends java.lang.Object
public <init>(String)
@NotNull
public final String component1()
@NotNull
public final net.corda.core.crypto.SecureHash componentHash(net.corda.core.crypto.SecureHash, net.corda.core.utilities.OpaqueBytes)
@NotNull
public final net.corda.core.crypto.SecureHash componentHash(net.corda.core.utilities.OpaqueBytes, net.corda.core.contracts.PrivacySalt, int, int)
@NotNull
public final net.corda.core.crypto.SecureHash computeNonce(net.corda.core.contracts.PrivacySalt, int, int)
@NotNull
public final net.corda.core.crypto.DigestService copy(String)
public boolean equals(Object)
@NotNull
public final net.corda.core.crypto.SecureHash getAllOnesHash()
public final int getDigestLength()
@NotNull
public final String getHashAlgorithm()
@NotNull
public final net.corda.core.crypto.SecureHash getZeroHash()
@NotNull
public final net.corda.core.crypto.SecureHash hash(String)
@NotNull
public final net.corda.core.crypto.SecureHash hash(byte[])
public int hashCode()
@NotNull
public final net.corda.core.crypto.SecureHash serializedHash(T)
@NotNull
public String toString()
public static final net.corda.core.crypto.DigestService$Companion Companion
##
public static final class net.corda.core.crypto.DigestService$Companion extends java.lang.Object
public <init>(kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull
public final net.corda.core.crypto.DigestService getDefault()
@NotNull
public final net.corda.core.crypto.DigestService getSha2_256()
@NotNull
public final net.corda.core.crypto.DigestService getSha2_384()
@NotNull
public final net.corda.core.crypto.DigestService getSha2_512()
##
public final class net.corda.core.crypto.DigestServiceKt extends java.lang.Object
@NotNull
public static final net.corda.core.crypto.SecureHash randomHash(net.corda.core.crypto.DigestService)
##
@CordaSerializable
public class net.corda.core.crypto.DigitalSignature extends net.corda.core.utilities.OpaqueBytes public class net.corda.core.crypto.DigitalSignature extends net.corda.core.utilities.OpaqueBytes
public <init>(byte[]) public <init>(byte[])
## ##
@ -1888,6 +1980,8 @@ public static final class net.corda.core.crypto.MerkleTree$Companion extends jav
public <init>(kotlin.jvm.internal.DefaultConstructorMarker) public <init>(kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull @NotNull
public final net.corda.core.crypto.MerkleTree getMerkleTree(java.util.List<? extends net.corda.core.crypto.SecureHash>) public final net.corda.core.crypto.MerkleTree getMerkleTree(java.util.List<? extends net.corda.core.crypto.SecureHash>)
@NotNull
public final net.corda.core.crypto.MerkleTree getMerkleTree(java.util.List<? extends net.corda.core.crypto.SecureHash>, net.corda.core.crypto.DigestService)
## ##
public static final class net.corda.core.crypto.MerkleTree$Leaf extends net.corda.core.crypto.MerkleTree public static final class net.corda.core.crypto.MerkleTree$Leaf extends net.corda.core.crypto.MerkleTree
public <init>(net.corda.core.crypto.SecureHash) public <init>(net.corda.core.crypto.SecureHash)
@ -1997,14 +2091,23 @@ public static final class net.corda.core.crypto.PartialMerkleTree$PartialTree$Le
## ##
@CordaSerializable @CordaSerializable
public static final class net.corda.core.crypto.PartialMerkleTree$PartialTree$Node extends net.corda.core.crypto.PartialMerkleTree$PartialTree public static final class net.corda.core.crypto.PartialMerkleTree$PartialTree$Node extends net.corda.core.crypto.PartialMerkleTree$PartialTree
@DeprecatedConstructorForDeserialization
public <init>(net.corda.core.crypto.PartialMerkleTree$PartialTree, net.corda.core.crypto.PartialMerkleTree$PartialTree) public <init>(net.corda.core.crypto.PartialMerkleTree$PartialTree, net.corda.core.crypto.PartialMerkleTree$PartialTree)
public <init>(net.corda.core.crypto.PartialMerkleTree$PartialTree, net.corda.core.crypto.PartialMerkleTree$PartialTree, String)
public <init>(net.corda.core.crypto.PartialMerkleTree$PartialTree, net.corda.core.crypto.PartialMerkleTree$PartialTree, String, int, kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull @NotNull
public final net.corda.core.crypto.PartialMerkleTree$PartialTree component1() public final net.corda.core.crypto.PartialMerkleTree$PartialTree component1()
@NotNull @NotNull
public final net.corda.core.crypto.PartialMerkleTree$PartialTree component2() public final net.corda.core.crypto.PartialMerkleTree$PartialTree component2()
@Nullable
public final String component3()
@NotNull @NotNull
public final net.corda.core.crypto.PartialMerkleTree$PartialTree$Node copy(net.corda.core.crypto.PartialMerkleTree$PartialTree, net.corda.core.crypto.PartialMerkleTree$PartialTree) public final net.corda.core.crypto.PartialMerkleTree$PartialTree$Node copy(net.corda.core.crypto.PartialMerkleTree$PartialTree, net.corda.core.crypto.PartialMerkleTree$PartialTree)
@NotNull
public final net.corda.core.crypto.PartialMerkleTree$PartialTree$Node copy(net.corda.core.crypto.PartialMerkleTree$PartialTree, net.corda.core.crypto.PartialMerkleTree$PartialTree, String)
public boolean equals(Object) public boolean equals(Object)
@Nullable
public final String getHashAlgorithm()
@NotNull @NotNull
public final net.corda.core.crypto.PartialMerkleTree$PartialTree getLeft() public final net.corda.core.crypto.PartialMerkleTree$PartialTree getLeft()
@NotNull @NotNull
@ -2017,36 +2120,86 @@ public static final class net.corda.core.crypto.PartialMerkleTree$PartialTree$No
public abstract class net.corda.core.crypto.SecureHash extends net.corda.core.utilities.OpaqueBytes public abstract class net.corda.core.crypto.SecureHash extends net.corda.core.utilities.OpaqueBytes
public <init>(byte[], kotlin.jvm.internal.DefaultConstructorMarker) public <init>(byte[], kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull @NotNull
public static final net.corda.core.crypto.SecureHash allOnesHashFor(String)
@NotNull
public static final net.corda.core.crypto.SecureHash componentHashAs(String, byte[])
@NotNull
public final net.corda.core.crypto.SecureHash concatenate(net.corda.core.crypto.SecureHash)
@NotNull
public final net.corda.core.crypto.SecureHash concatenateAs(String, net.corda.core.crypto.SecureHash)
@NotNull
public static final net.corda.core.crypto.SecureHash create(String)
@NotNull
public static final net.corda.core.crypto.SecureHash$SHA256 createSHA256(byte[])
@NotNull
protected net.corda.core.crypto.SecureHash generate(byte[])
@NotNull
public static final net.corda.core.crypto.SecureHash hashAs(String, byte[])
@NotNull
public final net.corda.core.crypto.SecureHash$SHA256 hashConcat(net.corda.core.crypto.SecureHash) public final net.corda.core.crypto.SecureHash$SHA256 hashConcat(net.corda.core.crypto.SecureHash)
@NotNull @NotNull
public static final net.corda.core.crypto.SecureHash nonceHashAs(String, byte[])
@NotNull
public static final net.corda.core.crypto.SecureHash$SHA256 parse(String) public static final net.corda.core.crypto.SecureHash$SHA256 parse(String)
@NotNull @NotNull
public final String prefixChars(int) public final String prefixChars(int)
@NotNull @NotNull
public static final net.corda.core.crypto.SecureHash random(String)
@NotNull
public static final net.corda.core.crypto.SecureHash$SHA256 randomSHA256() public static final net.corda.core.crypto.SecureHash$SHA256 randomSHA256()
@NotNull @NotNull
public final net.corda.core.crypto.SecureHash reHash()
@NotNull
public static final net.corda.core.crypto.SecureHash$SHA256 sha256(String) public static final net.corda.core.crypto.SecureHash$SHA256 sha256(String)
@NotNull @NotNull
public static final net.corda.core.crypto.SecureHash$SHA256 sha256(byte[]) public static final net.corda.core.crypto.SecureHash$SHA256 sha256(byte[])
@NotNull @NotNull
public static final net.corda.core.crypto.SecureHash$SHA256 sha256Twice(byte[]) public static final net.corda.core.crypto.SecureHash$SHA256 sha256Twice(byte[])
@NotNull @NotNull
public final String toHexString()
@NotNull
public String toString() public String toString()
@NotNull
public static final net.corda.core.crypto.SecureHash zeroHashFor(String)
public static final net.corda.core.crypto.SecureHash$Companion Companion public static final net.corda.core.crypto.SecureHash$Companion Companion
public static final char DELIMITER = ':'
@NotNull
public static final String SHA2_256 = "SHA-256"
@NotNull
public static final String SHA2_384 = "SHA-384"
@NotNull
public static final String SHA2_512 = "SHA-512"
@NotNull @NotNull
public static final net.corda.core.crypto.SecureHash$SHA256 allOnesHash public static final net.corda.core.crypto.SecureHash$SHA256 allOnesHash
@NotNull @NotNull
public static final net.corda.core.crypto.SecureHash$SHA256 zeroHash public static final net.corda.core.crypto.SecureHash$SHA256 zeroHash
## ##
public static final class net.corda.core.crypto.SecureHash$Companion extends java.lang.Object public static final class net.corda.core.crypto.SecureHash$Companion extends java.lang.Object implements net.corda.core.internal.utilities.Internable
public <init>(kotlin.jvm.internal.DefaultConstructorMarker) public <init>(kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull @NotNull
public final net.corda.core.crypto.SecureHash allOnesHashFor(String)
@NotNull
public final net.corda.core.crypto.SecureHash componentHashAs(String, byte[])
@NotNull
public final net.corda.core.crypto.SecureHash create(String)
@NotNull
public final net.corda.core.crypto.SecureHash$SHA256 createSHA256(byte[])
public final int digestLengthFor(String)
@NotNull
public final net.corda.core.crypto.SecureHash$SHA256 getAllOnesHash() public final net.corda.core.crypto.SecureHash$SHA256 getAllOnesHash()
@NotNull @NotNull
public net.corda.core.internal.utilities.PrivateInterner<net.corda.core.crypto.SecureHash> getInterner()
@NotNull
public final net.corda.core.crypto.SecureHash$SHA256 getZeroHash() public final net.corda.core.crypto.SecureHash$SHA256 getZeroHash()
@NotNull @NotNull
public final net.corda.core.crypto.SecureHash hashAs(String, byte[])
@NotNull
public final net.corda.core.crypto.SecureHash nonceHashAs(String, byte[])
@NotNull
public final net.corda.core.crypto.SecureHash$SHA256 parse(String) public final net.corda.core.crypto.SecureHash$SHA256 parse(String)
@NotNull @NotNull
public final net.corda.core.crypto.SecureHash random(String)
@NotNull
public final net.corda.core.crypto.SecureHash$SHA256 randomSHA256() public final net.corda.core.crypto.SecureHash$SHA256 randomSHA256()
@NotNull @NotNull
public final net.corda.core.crypto.SecureHash$SHA256 sha256(String) public final net.corda.core.crypto.SecureHash$SHA256 sha256(String)
@ -2054,14 +2207,39 @@ public static final class net.corda.core.crypto.SecureHash$Companion extends jav
public final net.corda.core.crypto.SecureHash$SHA256 sha256(byte[]) public final net.corda.core.crypto.SecureHash$SHA256 sha256(byte[])
@NotNull @NotNull
public final net.corda.core.crypto.SecureHash$SHA256 sha256Twice(byte[]) public final net.corda.core.crypto.SecureHash$SHA256 sha256Twice(byte[])
@NotNull
public final net.corda.core.crypto.SecureHash zeroHashFor(String)
##
@CordaSerializable
public static final class net.corda.core.crypto.SecureHash$HASH extends net.corda.core.crypto.SecureHash
public <init>(String, byte[])
public boolean equals(Object)
@NotNull
protected net.corda.core.crypto.SecureHash generate(byte[])
@NotNull
public final String getAlgorithm()
public int hashCode()
@NotNull
public String toString()
## ##
@CordaSerializable @CordaSerializable
public static final class net.corda.core.crypto.SecureHash$SHA256 extends net.corda.core.crypto.SecureHash public static final class net.corda.core.crypto.SecureHash$SHA256 extends net.corda.core.crypto.SecureHash
public <init>(byte[]) public <init>(byte[])
public boolean equals(Object) public boolean equals(Object)
@NotNull
protected net.corda.core.crypto.SecureHash generate(byte[])
public int hashCode() public int hashCode()
@NotNull
public String toString()
## ##
public final class net.corda.core.crypto.SecureHashKt extends java.lang.Object public final class net.corda.core.crypto.SecureHashKt extends java.lang.Object
@NotNull
public static final String getAlgorithm(net.corda.core.crypto.SecureHash)
@NotNull
public static final net.corda.core.crypto.SecureHash hashAs(net.corda.core.utilities.OpaqueBytes, String)
@NotNull
public static final net.corda.core.crypto.SecureHash hashAs(byte[], String)
public static final boolean isZero(net.corda.core.utilities.OpaqueBytes)
@NotNull @NotNull
public static final net.corda.core.crypto.SecureHash$SHA256 sha256(net.corda.core.utilities.OpaqueBytes) public static final net.corda.core.crypto.SecureHash$SHA256 sha256(net.corda.core.utilities.OpaqueBytes)
@NotNull @NotNull
@ -3157,6 +3335,24 @@ public static final class net.corda.core.flows.WithReferencedStatesFlow$Companio
public static final class net.corda.core.flows.WithReferencedStatesFlow$Companion$SUCCESS extends net.corda.core.utilities.ProgressTracker$Step public static final class net.corda.core.flows.WithReferencedStatesFlow$Companion$SUCCESS extends net.corda.core.utilities.ProgressTracker$Step
public static final net.corda.core.flows.WithReferencedStatesFlow$Companion$SUCCESS INSTANCE public static final net.corda.core.flows.WithReferencedStatesFlow$Companion$SUCCESS INSTANCE
## ##
@CordaSerializable
public final class net.corda.core.flows.WrappedFlowExternalAsyncOperation extends java.lang.Object implements net.corda.core.internal.FlowAsyncOperation
public <init>(net.corda.core.flows.FlowExternalAsyncOperation<R>)
@NotNull
public net.corda.core.concurrent.CordaFuture<R> execute(String)
@NotNull
public final net.corda.core.flows.FlowExternalAsyncOperation<R> getOperation()
##
@CordaSerializable
public final class net.corda.core.flows.WrappedFlowExternalOperation extends java.lang.Object implements net.corda.core.internal.FlowAsyncOperation
public <init>(net.corda.core.internal.ServiceHubCoreInternal, net.corda.core.flows.FlowExternalOperation<R>)
@NotNull
public net.corda.core.concurrent.CordaFuture<R> execute(String)
@NotNull
public final net.corda.core.flows.FlowExternalOperation<R> getOperation()
@NotNull
public final net.corda.core.internal.ServiceHubCoreInternal getServiceHub()
##
@DoNotImplement @DoNotImplement
@CordaSerializable @CordaSerializable
public abstract class net.corda.core.identity.AbstractParty extends java.lang.Object implements net.corda.core.flows.Destination public abstract class net.corda.core.identity.AbstractParty extends java.lang.Object implements net.corda.core.flows.Destination
@ -3171,6 +3367,7 @@ public abstract class net.corda.core.identity.AbstractParty extends java.lang.Ob
public abstract net.corda.core.contracts.PartyAndReference ref(net.corda.core.utilities.OpaqueBytes) public abstract net.corda.core.contracts.PartyAndReference ref(net.corda.core.utilities.OpaqueBytes)
@NotNull @NotNull
public final net.corda.core.contracts.PartyAndReference ref(byte...) public final net.corda.core.contracts.PartyAndReference ref(byte...)
public static final net.corda.core.identity.AbstractParty$Companion Companion
## ##
@DoNotImplement @DoNotImplement
@CordaSerializable @CordaSerializable
@ -3182,6 +3379,12 @@ public final class net.corda.core.identity.AnonymousParty extends net.corda.core
public net.corda.core.contracts.PartyAndReference ref(net.corda.core.utilities.OpaqueBytes) public net.corda.core.contracts.PartyAndReference ref(net.corda.core.utilities.OpaqueBytes)
@NotNull @NotNull
public String toString() public String toString()
public static final net.corda.core.identity.AnonymousParty$Companion Companion
##
public static final class net.corda.core.identity.AnonymousParty$Companion extends java.lang.Object
public <init>(kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull
public final net.corda.core.identity.AnonymousParty create(java.security.PublicKey)
## ##
@CordaSerializable @CordaSerializable
public final class net.corda.core.identity.CordaX500Name extends java.lang.Object public final class net.corda.core.identity.CordaX500Name extends java.lang.Object
@ -3232,11 +3435,13 @@ public final class net.corda.core.identity.CordaX500Name extends java.lang.Objec
public static final int MAX_LENGTH_ORGANISATION_UNIT = 64 public static final int MAX_LENGTH_ORGANISATION_UNIT = 64
public static final int MAX_LENGTH_STATE = 64 public static final int MAX_LENGTH_STATE = 64
## ##
public static final class net.corda.core.identity.CordaX500Name$Companion extends java.lang.Object public static final class net.corda.core.identity.CordaX500Name$Companion extends java.lang.Object implements net.corda.core.internal.utilities.Internable
public <init>(kotlin.jvm.internal.DefaultConstructorMarker) public <init>(kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull @NotNull
public final net.corda.core.identity.CordaX500Name build(javax.security.auth.x500.X500Principal) public final net.corda.core.identity.CordaX500Name build(javax.security.auth.x500.X500Principal)
@NotNull @NotNull
public net.corda.core.internal.utilities.PrivateInterner<net.corda.core.identity.CordaX500Name> getInterner()
@NotNull
public final net.corda.core.identity.CordaX500Name parse(String) public final net.corda.core.identity.CordaX500Name parse(String)
## ##
public final class net.corda.core.identity.IdentityUtils extends java.lang.Object public final class net.corda.core.identity.IdentityUtils extends java.lang.Object
@ -3262,6 +3467,8 @@ public final class net.corda.core.identity.Party extends net.corda.core.identity
@NotNull @NotNull
public final net.corda.core.identity.AnonymousParty anonymise() public final net.corda.core.identity.AnonymousParty anonymise()
@NotNull @NotNull
public final String description()
@NotNull
public final net.corda.core.identity.CordaX500Name getName() public final net.corda.core.identity.CordaX500Name getName()
@NotNull @NotNull
public net.corda.core.identity.CordaX500Name nameOrNull() public net.corda.core.identity.CordaX500Name nameOrNull()
@ -3269,6 +3476,14 @@ public final class net.corda.core.identity.Party extends net.corda.core.identity
public net.corda.core.contracts.PartyAndReference ref(net.corda.core.utilities.OpaqueBytes) public net.corda.core.contracts.PartyAndReference ref(net.corda.core.utilities.OpaqueBytes)
@NotNull @NotNull
public String toString() public String toString()
public static final net.corda.core.identity.Party$Companion Companion
##
public static final class net.corda.core.identity.Party$Companion extends java.lang.Object
public <init>(kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull
public final net.corda.core.identity.Party create(java.security.cert.X509Certificate)
@NotNull
public final net.corda.core.identity.Party create(net.corda.core.identity.CordaX500Name, java.security.PublicKey)
## ##
@CordaSerializable @CordaSerializable
public final class net.corda.core.identity.PartyAndCertificate extends java.lang.Object public final class net.corda.core.identity.PartyAndCertificate extends java.lang.Object
@ -3293,6 +3508,8 @@ public final class net.corda.core.identity.PartyAndCertificate extends java.lang
public String toString() public String toString()
@NotNull @NotNull
public final java.security.cert.PKIXCertPathValidatorResult verify(java.security.cert.TrustAnchor) public final java.security.cert.PKIXCertPathValidatorResult verify(java.security.cert.TrustAnchor)
@NotNull
public final java.security.cert.PKIXCertPathValidatorResult verify(java.util.Set<? extends java.security.cert.TrustAnchor>)
## ##
@CordaSerializable @CordaSerializable
public interface net.corda.core.messaging.AllPossibleRecipients extends net.corda.core.messaging.MessageRecipients public interface net.corda.core.messaging.AllPossibleRecipients extends net.corda.core.messaging.MessageRecipients
@ -3330,6 +3547,8 @@ public interface net.corda.core.messaging.CordaRPCOps extends net.corda.core.mes
@NotNull @NotNull
public abstract java.util.Map<String, Boolean> finishedFlowsWithClientIds() public abstract java.util.Map<String, Boolean> finishedFlowsWithClientIds()
@NotNull @NotNull
public abstract java.util.Map<String, Boolean> finishedFlowsWithClientIdsAsAdmin()
@NotNull
public abstract net.corda.core.node.NetworkParameters getNetworkParameters() public abstract net.corda.core.node.NetworkParameters getNetworkParameters()
@NotNull @NotNull
public abstract Iterable<String> getVaultTransactionNotes(net.corda.core.crypto.SecureHash) public abstract Iterable<String> getVaultTransactionNotes(net.corda.core.crypto.SecureHash)
@ -3374,6 +3593,7 @@ public interface net.corda.core.messaging.CordaRPCOps extends net.corda.core.mes
@NotNull @NotNull
public abstract java.util.List<String> registeredFlows() public abstract java.util.List<String> registeredFlows()
public abstract boolean removeClientId(String) public abstract boolean removeClientId(String)
public abstract boolean removeClientIdAsAdmin(String)
public abstract void setFlowsDrainingModeEnabled(boolean) public abstract void setFlowsDrainingModeEnabled(boolean)
public abstract void shutdown() public abstract void shutdown()
@RPCReturnsObservables @RPCReturnsObservables
@ -3691,6 +3911,11 @@ public static final class net.corda.core.messaging.StateMachineUpdate$Removed ex
public String toString() public String toString()
## ##
@DoNotImplement @DoNotImplement
public interface net.corda.core.messaging.flows.FlowManagerRPCOps extends net.corda.core.messaging.RPCOps
public abstract void debugCheckpoints()
public abstract void dumpCheckpoints()
##
@DoNotImplement
public interface net.corda.core.node.AppServiceHub extends net.corda.core.node.ServiceHub public interface net.corda.core.node.AppServiceHub extends net.corda.core.node.ServiceHub
@NotNull @NotNull
public abstract net.corda.core.node.services.vault.CordaTransactionSupport getDatabase() public abstract net.corda.core.node.services.vault.CordaTransactionSupport getDatabase()
@ -3756,8 +3981,12 @@ public final class net.corda.core.node.NetworkParameters extends java.lang.Objec
public final java.util.Map<String, java.util.List<net.corda.core.crypto.SecureHash>> getWhitelistedContractImplementations() public final java.util.Map<String, java.util.List<net.corda.core.crypto.SecureHash>> getWhitelistedContractImplementations()
public int hashCode() public int hashCode()
@NotNull @NotNull
public final net.corda.core.node.NetworkParameters toImmutable()
@NotNull
public String toString() public String toString()
## ##
public final class net.corda.core.node.NetworkParametersKt extends java.lang.Object
##
@CordaSerializable @CordaSerializable
public final class net.corda.core.node.NodeDiagnosticInfo extends java.lang.Object public final class net.corda.core.node.NodeDiagnosticInfo extends java.lang.Object
public <init>(String, String, int, String, java.util.List<net.corda.core.cordapp.CordappInfo>) public <init>(String, String, int, String, java.util.List<net.corda.core.cordapp.CordappInfo>)
@ -3841,6 +4070,8 @@ public interface net.corda.core.node.ServiceHub extends net.corda.core.node.Serv
@NotNull @NotNull
public abstract T cordaService(Class<T>) public abstract T cordaService(Class<T>)
@NotNull @NotNull
public abstract T cordaTelemetryComponent(Class<T>)
@NotNull
public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction) public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction)
@NotNull @NotNull
public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction, java.security.PublicKey) public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction, java.security.PublicKey)
@ -3863,6 +4094,8 @@ public interface net.corda.core.node.ServiceHub extends net.corda.core.node.Serv
@NotNull @NotNull
public abstract net.corda.core.node.services.NetworkMapCache getNetworkMapCache() public abstract net.corda.core.node.services.NetworkMapCache getNetworkMapCache()
@NotNull @NotNull
public abstract net.corda.core.node.services.TelemetryService getTelemetryService()
@NotNull
public abstract net.corda.core.node.services.TransactionVerifierService getTransactionVerifierService() public abstract net.corda.core.node.services.TransactionVerifierService getTransactionVerifierService()
@NotNull @NotNull
public abstract net.corda.core.node.services.TransactionStorage getValidatedTransactions() public abstract net.corda.core.node.services.TransactionStorage getValidatedTransactions()
@ -4162,6 +4395,11 @@ public final class net.corda.core.node.services.StatesNotAvailableException exte
@NotNull @NotNull
public String toString() public String toString()
## ##
@DoNotImplement
public interface net.corda.core.node.services.TelemetryService
@Nullable
public abstract T getTelemetryHandle(Class<T>)
##
public final class net.corda.core.node.services.TimeWindowChecker extends java.lang.Object public final class net.corda.core.node.services.TimeWindowChecker extends java.lang.Object
public <init>() public <init>()
public <init>(java.time.Clock) public <init>(java.time.Clock)
@ -5990,6 +6228,11 @@ public final class net.corda.core.serialization.SerializationAPIKt extends java.
public static final net.corda.core.serialization.SerializedBytes<T> serialize(T, net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext) public static final net.corda.core.serialization.SerializedBytes<T> serialize(T, net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext)
@NotNull @NotNull
public static final net.corda.core.serialization.SerializationContext withWhitelist(net.corda.core.serialization.SerializationContext, java.util.List<? extends Class<?>>) public static final net.corda.core.serialization.SerializationContext withWhitelist(net.corda.core.serialization.SerializationContext, java.util.List<? extends Class<?>>)
public static final int AMQP_ENVELOPE_CACHE_INITIAL_CAPACITY = 256
@NotNull
public static final String AMQP_ENVELOPE_CACHE_PROPERTY = "AMQP_ENVELOPE_CACHE"
@NotNull
public static final String DESERIALIZATION_CACHE_PROPERTY = "DESERIALIZATION_CACHE"
## ##
@DoNotImplement @DoNotImplement
public interface net.corda.core.serialization.SerializationContext public interface net.corda.core.serialization.SerializationContext
@ -6030,6 +6273,8 @@ public interface net.corda.core.serialization.SerializationContext
@NotNull @NotNull
public abstract net.corda.core.serialization.SerializationContext withPreventDataLoss() public abstract net.corda.core.serialization.SerializationContext withPreventDataLoss()
@NotNull @NotNull
public abstract net.corda.core.serialization.SerializationContext withProperties(java.util.Map<Object, ?>)
@NotNull
public abstract net.corda.core.serialization.SerializationContext withProperty(Object, Object) public abstract net.corda.core.serialization.SerializationContext withProperty(Object, Object)
@NotNull @NotNull
public abstract net.corda.core.serialization.SerializationContext withWhitelisted(Class<?>) public abstract net.corda.core.serialization.SerializationContext withWhitelisted(Class<?>)
@ -6090,6 +6335,8 @@ public interface net.corda.core.serialization.SerializationSchemeContext
@NotNull @NotNull
public abstract ClassLoader getDeserializationClassLoader() public abstract ClassLoader getDeserializationClassLoader()
@NotNull @NotNull
public abstract java.util.Map<Object, Object> getProperties()
@NotNull
public abstract net.corda.core.serialization.ClassWhitelist getWhitelist() public abstract net.corda.core.serialization.ClassWhitelist getWhitelist()
## ##
public interface net.corda.core.serialization.SerializationToken public interface net.corda.core.serialization.SerializationToken
@ -6206,15 +6453,23 @@ public final class net.corda.core.transactions.ComponentVisibilityException exte
@DoNotImplement @DoNotImplement
@CordaSerializable @CordaSerializable
public final class net.corda.core.transactions.ContractUpgradeFilteredTransaction extends net.corda.core.transactions.CoreTransaction public final class net.corda.core.transactions.ContractUpgradeFilteredTransaction extends net.corda.core.transactions.CoreTransaction
@DeprecatedConstructorForDeserialization
public <init>(java.util.Map<Integer, net.corda.core.transactions.ContractUpgradeFilteredTransaction$FilteredComponent>, java.util.Map<Integer, ? extends net.corda.core.crypto.SecureHash>) public <init>(java.util.Map<Integer, net.corda.core.transactions.ContractUpgradeFilteredTransaction$FilteredComponent>, java.util.Map<Integer, ? extends net.corda.core.crypto.SecureHash>)
public <init>(java.util.Map<Integer, net.corda.core.transactions.ContractUpgradeFilteredTransaction$FilteredComponent>, java.util.Map<Integer, ? extends net.corda.core.crypto.SecureHash>, net.corda.core.crypto.DigestService)
@NotNull @NotNull
public final java.util.Map<Integer, net.corda.core.transactions.ContractUpgradeFilteredTransaction$FilteredComponent> component1() public final java.util.Map<Integer, net.corda.core.transactions.ContractUpgradeFilteredTransaction$FilteredComponent> component1()
@NotNull @NotNull
public final java.util.Map<Integer, net.corda.core.crypto.SecureHash> component2() public final java.util.Map<Integer, net.corda.core.crypto.SecureHash> component2()
@NotNull @NotNull
public final net.corda.core.crypto.DigestService component3()
@NotNull
public final net.corda.core.transactions.ContractUpgradeFilteredTransaction copy(java.util.Map<Integer, net.corda.core.transactions.ContractUpgradeFilteredTransaction$FilteredComponent>, java.util.Map<Integer, ? extends net.corda.core.crypto.SecureHash>) public final net.corda.core.transactions.ContractUpgradeFilteredTransaction copy(java.util.Map<Integer, net.corda.core.transactions.ContractUpgradeFilteredTransaction$FilteredComponent>, java.util.Map<Integer, ? extends net.corda.core.crypto.SecureHash>)
@NotNull
public final net.corda.core.transactions.ContractUpgradeFilteredTransaction copy(java.util.Map<Integer, net.corda.core.transactions.ContractUpgradeFilteredTransaction$FilteredComponent>, java.util.Map<Integer, ? extends net.corda.core.crypto.SecureHash>, net.corda.core.crypto.DigestService)
public boolean equals(Object) public boolean equals(Object)
@NotNull @NotNull
public final net.corda.core.crypto.DigestService getDigestService()
@NotNull
public final java.util.Map<Integer, net.corda.core.crypto.SecureHash> getHiddenComponents() public final java.util.Map<Integer, net.corda.core.crypto.SecureHash> getHiddenComponents()
@NotNull @NotNull
public net.corda.core.crypto.SecureHash getId() public net.corda.core.crypto.SecureHash getId()
@ -6304,8 +6559,11 @@ public static final class net.corda.core.transactions.ContractUpgradeLedgerTrans
@DoNotImplement @DoNotImplement
@CordaSerializable @CordaSerializable
public final class net.corda.core.transactions.ContractUpgradeWireTransaction extends net.corda.core.transactions.CoreTransaction public final class net.corda.core.transactions.ContractUpgradeWireTransaction extends net.corda.core.transactions.CoreTransaction
@DeprecatedConstructorForDeserialization
public <init>(java.util.List<? extends net.corda.core.utilities.OpaqueBytes>, net.corda.core.contracts.PrivacySalt) public <init>(java.util.List<? extends net.corda.core.utilities.OpaqueBytes>, net.corda.core.contracts.PrivacySalt)
@DeprecatedConstructorForDeserialization
public <init>(java.util.List, net.corda.core.contracts.PrivacySalt, int, kotlin.jvm.internal.DefaultConstructorMarker) public <init>(java.util.List, net.corda.core.contracts.PrivacySalt, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(java.util.List<? extends net.corda.core.utilities.OpaqueBytes>, net.corda.core.contracts.PrivacySalt, net.corda.core.crypto.DigestService)
@NotNull @NotNull
public final net.corda.core.transactions.ContractUpgradeFilteredTransaction buildFilteredTransaction() public final net.corda.core.transactions.ContractUpgradeFilteredTransaction buildFilteredTransaction()
@NotNull @NotNull
@ -6313,9 +6571,15 @@ public final class net.corda.core.transactions.ContractUpgradeWireTransaction ex
@NotNull @NotNull
public final net.corda.core.contracts.PrivacySalt component2() public final net.corda.core.contracts.PrivacySalt component2()
@NotNull @NotNull
public final net.corda.core.crypto.DigestService component3()
@NotNull
public final net.corda.core.transactions.ContractUpgradeWireTransaction copy(java.util.List<? extends net.corda.core.utilities.OpaqueBytes>, net.corda.core.contracts.PrivacySalt) public final net.corda.core.transactions.ContractUpgradeWireTransaction copy(java.util.List<? extends net.corda.core.utilities.OpaqueBytes>, net.corda.core.contracts.PrivacySalt)
@NotNull
public final net.corda.core.transactions.ContractUpgradeWireTransaction copy(java.util.List<? extends net.corda.core.utilities.OpaqueBytes>, net.corda.core.contracts.PrivacySalt, net.corda.core.crypto.DigestService)
public boolean equals(Object) public boolean equals(Object)
@NotNull @NotNull
public final net.corda.core.crypto.DigestService getDigestService()
@NotNull
public net.corda.core.crypto.SecureHash getId() public net.corda.core.crypto.SecureHash getId()
@NotNull @NotNull
public java.util.List<net.corda.core.contracts.StateRef> getInputs() public java.util.List<net.corda.core.contracts.StateRef> getInputs()
@ -6389,7 +6653,9 @@ public final class net.corda.core.transactions.FilteredComponentGroup extends ne
@DoNotImplement @DoNotImplement
@CordaSerializable @CordaSerializable
public final class net.corda.core.transactions.FilteredTransaction extends net.corda.core.transactions.TraversableTransaction public final class net.corda.core.transactions.FilteredTransaction extends net.corda.core.transactions.TraversableTransaction
@DeprecatedConstructorForDeserialization
public <init>(net.corda.core.crypto.SecureHash, java.util.List<net.corda.core.transactions.FilteredComponentGroup>, java.util.List<? extends net.corda.core.crypto.SecureHash>) public <init>(net.corda.core.crypto.SecureHash, java.util.List<net.corda.core.transactions.FilteredComponentGroup>, java.util.List<? extends net.corda.core.crypto.SecureHash>)
public <init>(net.corda.core.crypto.SecureHash, java.util.List<net.corda.core.transactions.FilteredComponentGroup>, java.util.List<? extends net.corda.core.crypto.SecureHash>, net.corda.core.crypto.DigestService)
@NotNull @NotNull
public static final net.corda.core.transactions.FilteredTransaction buildFilteredTransaction(net.corda.core.transactions.WireTransaction, java.util.function.Predicate<Object>) public static final net.corda.core.transactions.FilteredTransaction buildFilteredTransaction(net.corda.core.transactions.WireTransaction, java.util.function.Predicate<Object>)
public final void checkAllComponentsVisible(net.corda.core.contracts.ComponentGroupEnum) public final void checkAllComponentsVisible(net.corda.core.contracts.ComponentGroupEnum)
@ -6433,6 +6699,7 @@ public abstract class net.corda.core.transactions.FullTransaction extends net.co
public final class net.corda.core.transactions.LedgerTransaction extends net.corda.core.transactions.FullTransaction public final class net.corda.core.transactions.LedgerTransaction extends net.corda.core.transactions.FullTransaction
public <init>(java.util.List<? extends net.corda.core.contracts.StateAndRef<? extends net.corda.core.contracts.ContractState>>, java.util.List<? extends net.corda.core.contracts.TransactionState<? extends net.corda.core.contracts.ContractState>>, java.util.List<? extends net.corda.core.contracts.CommandWithParties<? extends net.corda.core.contracts.CommandData>>, java.util.List<? extends net.corda.core.contracts.Attachment>, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt) public <init>(java.util.List<? extends net.corda.core.contracts.StateAndRef<? extends net.corda.core.contracts.ContractState>>, java.util.List<? extends net.corda.core.contracts.TransactionState<? extends net.corda.core.contracts.ContractState>>, java.util.List<? extends net.corda.core.contracts.CommandWithParties<? extends net.corda.core.contracts.CommandData>>, java.util.List<? extends net.corda.core.contracts.Attachment>, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt)
public <init>(java.util.List<? extends net.corda.core.contracts.StateAndRef<? extends net.corda.core.contracts.ContractState>>, java.util.List<? extends net.corda.core.contracts.TransactionState<? extends net.corda.core.contracts.ContractState>>, java.util.List<? extends net.corda.core.contracts.CommandWithParties<? extends net.corda.core.contracts.CommandData>>, java.util.List<? extends net.corda.core.contracts.Attachment>, 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 <init>(java.util.List<? extends net.corda.core.contracts.StateAndRef<? extends net.corda.core.contracts.ContractState>>, java.util.List<? extends net.corda.core.contracts.TransactionState<? extends net.corda.core.contracts.ContractState>>, java.util.List<? extends net.corda.core.contracts.CommandWithParties<? extends net.corda.core.contracts.CommandData>>, java.util.List<? extends net.corda.core.contracts.Attachment>, 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 <init>(java.util.List, java.util.List, java.util.List, java.util.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, java.util.List, java.util.List, java.util.List, java.util.List, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function2, net.corda.core.serialization.internal.AttachmentsClassLoaderCache, net.corda.core.crypto.DigestService, kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull @NotNull
public final java.util.List<net.corda.core.contracts.Command<T>> commandsOfType(Class<T>) public final java.util.List<net.corda.core.contracts.Command<T>> commandsOfType(Class<T>)
@NotNull @NotNull
@ -6491,6 +6758,8 @@ public final class net.corda.core.transactions.LedgerTransaction extends net.cor
@NotNull @NotNull
public final java.util.List<net.corda.core.contracts.CommandWithParties<net.corda.core.contracts.CommandData>> getCommands() public final java.util.List<net.corda.core.contracts.CommandWithParties<net.corda.core.contracts.CommandData>> getCommands()
@NotNull @NotNull
public final net.corda.core.crypto.DigestService getDigestService()
@NotNull
public net.corda.core.crypto.SecureHash getId() public net.corda.core.crypto.SecureHash getId()
@NotNull @NotNull
public final net.corda.core.contracts.ContractState getInput(int) public final net.corda.core.contracts.ContractState getInput(int)
@ -6629,14 +6898,22 @@ public static final class net.corda.core.transactions.NotaryChangeLedgerTransact
@DoNotImplement @DoNotImplement
@CordaSerializable @CordaSerializable
public final class net.corda.core.transactions.NotaryChangeWireTransaction extends net.corda.core.transactions.CoreTransaction public final class net.corda.core.transactions.NotaryChangeWireTransaction extends net.corda.core.transactions.CoreTransaction
@DeprecatedConstructorForDeserialization
public <init>(java.util.List<? extends net.corda.core.utilities.OpaqueBytes>) public <init>(java.util.List<? extends net.corda.core.utilities.OpaqueBytes>)
public <init>(java.util.List<? extends net.corda.core.utilities.OpaqueBytes>, net.corda.core.crypto.DigestService)
public <init>(java.util.List<net.corda.core.contracts.StateRef>, net.corda.core.identity.Party, net.corda.core.identity.Party) public <init>(java.util.List<net.corda.core.contracts.StateRef>, net.corda.core.identity.Party, net.corda.core.identity.Party)
@NotNull @NotNull
public final java.util.List<net.corda.core.utilities.OpaqueBytes> component1() public final java.util.List<net.corda.core.utilities.OpaqueBytes> component1()
@NotNull @NotNull
public final net.corda.core.crypto.DigestService component2()
@NotNull
public final net.corda.core.transactions.NotaryChangeWireTransaction copy(java.util.List<? extends net.corda.core.utilities.OpaqueBytes>) public final net.corda.core.transactions.NotaryChangeWireTransaction copy(java.util.List<? extends net.corda.core.utilities.OpaqueBytes>)
@NotNull
public final net.corda.core.transactions.NotaryChangeWireTransaction copy(java.util.List<? extends net.corda.core.utilities.OpaqueBytes>, net.corda.core.crypto.DigestService)
public boolean equals(Object) public boolean equals(Object)
@NotNull @NotNull
public final net.corda.core.crypto.DigestService getDigestService()
@NotNull
public net.corda.core.crypto.SecureHash getId() public net.corda.core.crypto.SecureHash getId()
@NotNull @NotNull
public java.util.List<net.corda.core.contracts.StateRef> getInputs() public java.util.List<net.corda.core.contracts.StateRef> getInputs()
@ -6851,6 +7128,10 @@ public class net.corda.core.transactions.TransactionBuilder extends java.lang.Ob
public final net.corda.core.transactions.SignedTransaction toSignedTransaction(net.corda.core.node.services.KeyManagementService, java.security.PublicKey, net.corda.core.crypto.SignatureMetadata, net.corda.core.node.ServicesForResolution) public final net.corda.core.transactions.SignedTransaction toSignedTransaction(net.corda.core.node.services.KeyManagementService, java.security.PublicKey, net.corda.core.crypto.SignatureMetadata, net.corda.core.node.ServicesForResolution)
@NotNull @NotNull
public final net.corda.core.transactions.WireTransaction toWireTransaction(net.corda.core.node.ServicesForResolution) public final net.corda.core.transactions.WireTransaction toWireTransaction(net.corda.core.node.ServicesForResolution)
@NotNull
public final net.corda.core.transactions.WireTransaction toWireTransaction(net.corda.core.node.ServicesForResolution, int)
@NotNull
public final net.corda.core.transactions.WireTransaction toWireTransaction(net.corda.core.node.ServicesForResolution, int, java.util.Map<Object, ?>)
public final void verify(net.corda.core.node.ServiceHub) public final void verify(net.corda.core.node.ServiceHub)
@NotNull @NotNull
public final net.corda.core.transactions.TransactionBuilder withItems(Object...) public final net.corda.core.transactions.TransactionBuilder withItems(Object...)
@ -6874,7 +7155,9 @@ public interface net.corda.core.transactions.TransactionWithSignatures extends n
@DoNotImplement @DoNotImplement
@CordaSerializable @CordaSerializable
public abstract class net.corda.core.transactions.TraversableTransaction extends net.corda.core.transactions.CoreTransaction public abstract class net.corda.core.transactions.TraversableTransaction extends net.corda.core.transactions.CoreTransaction
@DeprecatedConstructorForDeserialization
public <init>(java.util.List<? extends net.corda.core.transactions.ComponentGroup>) public <init>(java.util.List<? extends net.corda.core.transactions.ComponentGroup>)
public <init>(java.util.List<? extends net.corda.core.transactions.ComponentGroup>, net.corda.core.crypto.DigestService)
@NotNull @NotNull
public final java.util.List<net.corda.core.crypto.SecureHash> getAttachments() public final java.util.List<net.corda.core.crypto.SecureHash> getAttachments()
@NotNull @NotNull
@ -6884,6 +7167,8 @@ public abstract class net.corda.core.transactions.TraversableTransaction extends
@NotNull @NotNull
public java.util.List<net.corda.core.transactions.ComponentGroup> getComponentGroups() public java.util.List<net.corda.core.transactions.ComponentGroup> getComponentGroups()
@NotNull @NotNull
public final net.corda.core.crypto.DigestService getDigestService()
@NotNull
public java.util.List<net.corda.core.contracts.StateRef> getInputs() public java.util.List<net.corda.core.contracts.StateRef> getInputs()
@Nullable @Nullable
public net.corda.core.crypto.SecureHash getNetworkParametersHash() public net.corda.core.crypto.SecureHash getNetworkParametersHash()
@ -6903,8 +7188,11 @@ public final class net.corda.core.transactions.WireTransaction extends net.corda
public <init>(java.util.List<net.corda.core.contracts.StateRef>, java.util.List<? extends net.corda.core.crypto.SecureHash>, java.util.List<? extends net.corda.core.contracts.TransactionState<? extends net.corda.core.contracts.ContractState>>, java.util.List<? extends net.corda.core.contracts.Command<?>>, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow) public <init>(java.util.List<net.corda.core.contracts.StateRef>, java.util.List<? extends net.corda.core.crypto.SecureHash>, java.util.List<? extends net.corda.core.contracts.TransactionState<? extends net.corda.core.contracts.ContractState>>, java.util.List<? extends net.corda.core.contracts.Command<?>>, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow)
public <init>(java.util.List<net.corda.core.contracts.StateRef>, java.util.List<? extends net.corda.core.crypto.SecureHash>, java.util.List<? extends net.corda.core.contracts.TransactionState<? extends net.corda.core.contracts.ContractState>>, java.util.List<? extends net.corda.core.contracts.Command<?>>, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt) public <init>(java.util.List<net.corda.core.contracts.StateRef>, java.util.List<? extends net.corda.core.crypto.SecureHash>, java.util.List<? extends net.corda.core.contracts.TransactionState<? extends net.corda.core.contracts.ContractState>>, java.util.List<? extends net.corda.core.contracts.Command<?>>, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt)
public <init>(java.util.List, java.util.List, java.util.List, java.util.List, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt, int, kotlin.jvm.internal.DefaultConstructorMarker) public <init>(java.util.List, java.util.List, java.util.List, java.util.List, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt, int, kotlin.jvm.internal.DefaultConstructorMarker)
@DeprecatedConstructorForDeserialization
public <init>(java.util.List<? extends net.corda.core.transactions.ComponentGroup>, net.corda.core.contracts.PrivacySalt) public <init>(java.util.List<? extends net.corda.core.transactions.ComponentGroup>, net.corda.core.contracts.PrivacySalt)
@DeprecatedConstructorForDeserialization
public <init>(java.util.List, net.corda.core.contracts.PrivacySalt, int, kotlin.jvm.internal.DefaultConstructorMarker) public <init>(java.util.List, net.corda.core.contracts.PrivacySalt, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(java.util.List<? extends net.corda.core.transactions.ComponentGroup>, net.corda.core.contracts.PrivacySalt, net.corda.core.crypto.DigestService)
@NotNull @NotNull
public final net.corda.core.transactions.FilteredTransaction buildFilteredTransaction(java.util.function.Predicate<Object>) public final net.corda.core.transactions.FilteredTransaction buildFilteredTransaction(java.util.function.Predicate<Object>)
public final void checkSignature(net.corda.core.crypto.TransactionSignature) public final void checkSignature(net.corda.core.crypto.TransactionSignature)
@ -7290,6 +7578,12 @@ public final class net.corda.core.utilities.SgxSupport extends java.lang.Object
public static final boolean isInsideEnclave() public static final boolean isInsideEnclave()
public static final net.corda.core.utilities.SgxSupport INSTANCE public static final net.corda.core.utilities.SgxSupport INSTANCE
## ##
public final class net.corda.core.utilities.ThreadDumpUtilsKt extends java.lang.Object
@NotNull
public static final String asString(management.ThreadInfo, int)
@NotNull
public static final String threadDumpAsString()
##
@CordaSerializable @CordaSerializable
public abstract class net.corda.core.utilities.Try extends java.lang.Object public abstract class net.corda.core.utilities.Try extends java.lang.Object
public <init>(kotlin.jvm.internal.DefaultConstructorMarker) public <init>(kotlin.jvm.internal.DefaultConstructorMarker)
@ -7709,6 +8003,8 @@ public final class net.corda.testing.core.TestConstants extends java.lang.Object
@NotNull @NotNull
public static final net.corda.core.identity.CordaX500Name CHARLIE_NAME public static final net.corda.core.identity.CordaX500Name CHARLIE_NAME
@NotNull @NotNull
public static final net.corda.core.identity.CordaX500Name DAVE_NAME
@NotNull
public static final net.corda.core.identity.CordaX500Name DUMMY_BANK_A_NAME public static final net.corda.core.identity.CordaX500Name DUMMY_BANK_A_NAME
@NotNull @NotNull
public static final net.corda.core.identity.CordaX500Name DUMMY_BANK_B_NAME public static final net.corda.core.identity.CordaX500Name DUMMY_BANK_B_NAME
@ -7752,6 +8048,7 @@ public static final class net.corda.testing.core.TestIdentity$Companion extends
public final net.corda.testing.core.TestIdentity fresh(String, net.corda.core.crypto.SignatureScheme) public final net.corda.testing.core.TestIdentity fresh(String, net.corda.core.crypto.SignatureScheme)
## ##
public final class net.corda.testing.core.TestUtils extends java.lang.Object public final class net.corda.testing.core.TestUtils extends java.lang.Object
public static final T executeTest(java.time.Duration, kotlin.jvm.functions.Function0<kotlin.Unit>, java.time.Duration, kotlin.jvm.functions.Function0<? extends T>)
@NotNull @NotNull
public static final net.corda.core.utilities.NetworkHostAndPort freeLocalHostAndPort() public static final net.corda.core.utilities.NetworkHostAndPort freeLocalHostAndPort()
public static final int freePort() public static final int freePort()
@ -8085,6 +8382,8 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map, boolean, java.util.Collection, int, kotlin.jvm.internal.DefaultConstructorMarker) public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map, boolean, java.util.Collection, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.nio.file.Path, java.util.List<? extends java.nio.file.Path>, java.util.Map<String, String>, boolean) public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.nio.file.Path, java.util.List<? extends java.nio.file.Path>, java.util.Map<String, String>, boolean)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map, boolean, java.util.Collection, java.nio.file.Path, java.util.List, java.util.Map, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map, boolean, java.util.Collection, java.nio.file.Path, java.util.List, java.util.Map, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.nio.file.Path, java.util.List<? extends java.nio.file.Path>, java.util.Map<String, String>, boolean, boolean)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map, boolean, java.util.Collection, java.nio.file.Path, java.util.List, java.util.Map, boolean, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, boolean) public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, boolean)
public final boolean component1() public final boolean component1()
@NotNull @NotNull
@ -8107,6 +8406,7 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
public final boolean component19() public final boolean component19()
@NotNull @NotNull
public final java.nio.file.Path component2() public final java.nio.file.Path component2()
public final boolean component20()
@NotNull @NotNull
public final net.corda.testing.driver.PortAllocation component3() public final net.corda.testing.driver.PortAllocation component3()
@NotNull @NotNull
@ -8125,6 +8425,8 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
@NotNull @NotNull
public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.nio.file.Path, java.util.List<? extends java.nio.file.Path>, java.util.Map<String, String>, boolean) public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.nio.file.Path, java.util.List<? extends java.nio.file.Path>, java.util.Map<String, String>, boolean)
@NotNull @NotNull
public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.nio.file.Path, java.util.List<? extends java.nio.file.Path>, java.util.Map<String, String>, boolean, boolean)
@NotNull
public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Set<? extends net.corda.testing.node.TestCordapp>) public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Set<? extends net.corda.testing.node.TestCordapp>)
public boolean equals(Object) public boolean equals(Object)
public final boolean getAllowHibernateToManageAppSchema() public final boolean getAllowHibernateToManageAppSchema()
@ -8153,6 +8455,7 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
public final java.util.List<net.corda.testing.node.NotarySpec> getNotarySpecs() public final java.util.List<net.corda.testing.node.NotarySpec> getNotarySpecs()
@NotNull @NotNull
public final net.corda.testing.driver.PortAllocation getPortAllocation() public final net.corda.testing.driver.PortAllocation getPortAllocation()
public final boolean getPremigrateH2Database()
public final boolean getStartNodesInProcess() public final boolean getStartNodesInProcess()
@NotNull @NotNull
public final java.util.Map<String, String> getSystemProperties() public final java.util.Map<String, String> getSystemProperties()
@ -8265,6 +8568,8 @@ public final class net.corda.testing.driver.NodeParameters extends java.lang.Obj
public <init>(net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String, java.util.Collection, java.util.Map, String, net.corda.core.utilities.NetworkHostAndPort, int, kotlin.jvm.internal.DefaultConstructorMarker) public <init>(net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String, java.util.Collection, java.util.Map, String, net.corda.core.utilities.NetworkHostAndPort, int, kotlin.jvm.internal.DefaultConstructorMarker)
@Nullable @Nullable
public final net.corda.core.identity.CordaX500Name component1() public final net.corda.core.identity.CordaX500Name component1()
@Nullable
public final net.corda.core.utilities.NetworkHostAndPort component10()
@NotNull @NotNull
public final java.util.List<net.corda.testing.node.User> component2() public final java.util.List<net.corda.testing.node.User> component2()
@NotNull @NotNull
@ -8300,6 +8605,8 @@ public final class net.corda.testing.driver.NodeParameters extends java.lang.Obj
public final String getMaximumHeapSize() public final String getMaximumHeapSize()
@Nullable @Nullable
public final net.corda.core.identity.CordaX500Name getProvidedName() public final net.corda.core.identity.CordaX500Name getProvidedName()
@Nullable
public final net.corda.core.utilities.NetworkHostAndPort getRpcAddress()
@NotNull @NotNull
public final java.util.List<net.corda.testing.node.User> getRpcUsers() public final java.util.List<net.corda.testing.node.User> getRpcUsers()
@Nullable @Nullable
@ -8435,6 +8742,11 @@ public static final class net.corda.testing.node.ClusterSpec$Raft extends net.co
@NotNull @NotNull
public String toString() public String toString()
## ##
public final class net.corda.testing.node.DatabaseSnapshot extends java.lang.Object
public final void copyDatabaseSnapshot(java.nio.file.Path)
public final java.nio.file.Path databaseFilename(java.nio.file.Path)
public static final net.corda.testing.node.DatabaseSnapshot INSTANCE
##
@ThreadSafe @ThreadSafe
public final class net.corda.testing.node.InMemoryMessagingNetwork extends net.corda.core.serialization.SingletonSerializeAsToken public final class net.corda.testing.node.InMemoryMessagingNetwork extends net.corda.core.serialization.SingletonSerializeAsToken
public <init>(boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, org.apache.activemq.artemis.utils.ReusableLatch, kotlin.jvm.internal.DefaultConstructorMarker) public <init>(boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, org.apache.activemq.artemis.utils.ReusableLatch, kotlin.jvm.internal.DefaultConstructorMarker)
@ -8767,6 +9079,8 @@ public class net.corda.testing.node.MockServices extends java.lang.Object implem
@NotNull @NotNull
public T cordaService(Class<T>) public T cordaService(Class<T>)
@NotNull @NotNull
public T cordaTelemetryComponent(Class<T>)
@NotNull
public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction) public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction)
@NotNull @NotNull
public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction, java.security.PublicKey) public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction, java.security.PublicKey)
@ -8803,6 +9117,8 @@ public class net.corda.testing.node.MockServices extends java.lang.Object implem
@NotNull @NotNull
protected final net.corda.core.node.ServicesForResolution getServicesForResolution() protected final net.corda.core.node.ServicesForResolution getServicesForResolution()
@NotNull @NotNull
public net.corda.core.internal.telemetry.TelemetryServiceImpl getTelemetryService()
@NotNull
public net.corda.core.node.services.TransactionVerifierService getTransactionVerifierService() public net.corda.core.node.services.TransactionVerifierService getTransactionVerifierService()
@NotNull @NotNull
public net.corda.core.node.services.TransactionStorage getValidatedTransactions() public net.corda.core.node.services.TransactionStorage getValidatedTransactions()
@ -9072,7 +9388,11 @@ public class net.corda.client.rpc.CordaRPCClientConfiguration extends java.lang.
public <init>(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int) public <init>(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int)
public <init>(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int) public <init>(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int)
public <init>(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int, java.time.Duration) public <init>(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int, java.time.Duration)
public <init>(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int, java.time.Duration, int, kotlin.jvm.internal.DefaultConstructorMarker) public <init>(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int, java.time.Duration, boolean)
public <init>(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int, java.time.Duration, boolean, boolean)
public <init>(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int, java.time.Duration, boolean, boolean, boolean)
public <init>(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int, java.time.Duration, boolean, boolean, boolean, boolean)
public <init>(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int, java.time.Duration, boolean, boolean, boolean, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker)
@NotNull @NotNull
public final java.time.Duration component1() public final java.time.Duration component1()
@NotNull @NotNull
@ -9099,6 +9419,8 @@ public class net.corda.client.rpc.CordaRPCClientConfiguration extends java.lang.
public final net.corda.client.rpc.CordaRPCClientConfiguration copy(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int) public final net.corda.client.rpc.CordaRPCClientConfiguration copy(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int)
@NotNull @NotNull
public final net.corda.client.rpc.CordaRPCClientConfiguration copy(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int, java.time.Duration) public final net.corda.client.rpc.CordaRPCClientConfiguration copy(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int, java.time.Duration)
@NotNull
public final net.corda.client.rpc.CordaRPCClientConfiguration copy(java.time.Duration, int, boolean, java.time.Duration, int, int, java.time.Duration, double, int, int, java.time.Duration, boolean, boolean, boolean, boolean)
public boolean equals(Object) public boolean equals(Object)
public int getCacheConcurrencyLevel() public int getCacheConcurrencyLevel()
@NotNull @NotNull
@ -9106,14 +9428,18 @@ public class net.corda.client.rpc.CordaRPCClientConfiguration extends java.lang.
@NotNull @NotNull
public java.time.Duration getConnectionRetryInterval() public java.time.Duration getConnectionRetryInterval()
public double getConnectionRetryIntervalMultiplier() public double getConnectionRetryIntervalMultiplier()
public boolean getCopyBaggageToTags()
@NotNull @NotNull
public java.time.Duration getDeduplicationCacheExpiry() public java.time.Duration getDeduplicationCacheExpiry()
public int getMaxFileSize() public int getMaxFileSize()
public int getMaxReconnectAttempts() public int getMaxReconnectAttempts()
public int getMinimumServerProtocolVersion() public int getMinimumServerProtocolVersion()
public int getObservationExecutorPoolSize() public int getObservationExecutorPoolSize()
public boolean getOpenTelemetryEnabled()
@NotNull @NotNull
public java.time.Duration getReapInterval() public java.time.Duration getReapInterval()
public boolean getSimpleLogTelemetryEnabled()
public boolean getSpanStartEndEventsEnabled()
public boolean getTrackRpcCallSites() public boolean getTrackRpcCallSites()
public int hashCode() public int hashCode()
@NotNull @NotNull
@ -9134,6 +9460,8 @@ public final class net.corda.client.rpc.CordaRPCConnection extends java.lang.Obj
@NotNull @NotNull
public net.corda.core.messaging.CordaRPCOps getProxy() public net.corda.core.messaging.CordaRPCOps getProxy()
public int getServerProtocolVersion() public int getServerProtocolVersion()
@Nullable
public T getTelemetryHandle(Class<T>)
public void notifyServerAndClose() public void notifyServerAndClose()
public static final net.corda.client.rpc.CordaRPCConnection$Companion Companion public static final net.corda.client.rpc.CordaRPCConnection$Companion Companion
## ##
@ -9168,6 +9496,8 @@ public interface net.corda.client.rpc.RPCConnection extends java.io.Closeable
@NotNull @NotNull
public abstract I getProxy() public abstract I getProxy()
public abstract int getServerProtocolVersion() public abstract int getServerProtocolVersion()
@Nullable
public abstract T getTelemetryHandle(Class<T>)
public abstract void notifyServerAndClose() public abstract void notifyServerAndClose()
## ##
public class net.corda.client.rpc.RPCException extends net.corda.core.CordaRuntimeException public class net.corda.client.rpc.RPCException extends net.corda.core.CordaRuntimeException

View File

@ -13,13 +13,13 @@
* the branch name of origin branch, it should match the current branch * the branch name of origin branch, it should match the current branch
* and it acts as a fail-safe inside {@code forwardMerger} pipeline * and it acts as a fail-safe inside {@code forwardMerger} pipeline
*/ */
String originBranch = 'release/os/4.9' String originBranch = 'release/os/4.10'
/** /**
* the branch name of target branch, it should be the branch with the next version * the branch name of target branch, it should be the branch with the next version
* after the one in current branch. * after the one in current branch.
*/ */
String targetBranch = 'release/os/4.10' String targetBranch = 'release/os/4.11'
/** /**
* Forward merge any changes between #originBranch and #targetBranch * Forward merge any changes between #originBranch and #targetBranch

View File

@ -11,7 +11,6 @@ jobs:
- name: Close - name: Close
uses: corda/jira-sync-closed-action@master uses: corda/jira-sync-closed-action@master
with: with:
project: CORDA
jiraBaseUrl: https://r3-cev.atlassian.net jiraBaseUrl: https://r3-cev.atlassian.net
jiraEmail: ${{ secrets.JIRA_USER_EMAIL }} jiraEmail: ${{ secrets.JIRA_USER_EMAIL }}
jiraToken: ${{ secrets.JIRA_API_TOKEN }} jiraToken: ${{ secrets.JIRA_API_TOKEN }}

View File

@ -14,9 +14,8 @@
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS"> <option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value> <value>
<package name="java.util" withSubpackages="false" static="false" /> <package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
<package name="kotlinx.android.synthetic" withSubpackages="true" static="false" /> <package name="tornadofx" alias="false" withSubpackages="false" />
<package name="tornadofx" withSubpackages="false" static="false" />
</value> </value>
</option> </option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />

View File

@ -1,6 +1,5 @@
<component name="ProjectCodeStyleConfiguration"> <component name="ProjectCodeStyleConfiguration">
<state> <state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" /> <option name="USE_PER_PROJECT_SETTINGS" value="true" />
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state> </state>
</component> </component>

279
.snyk Normal file → Executable file
View File

@ -8,7 +8,7 @@ ignore:
Guavas Files.createTempDir() is used during integration tests only. Guavas Files.createTempDir() is used during integration tests only.
Users of Corda are advised not to use Guavas Files.createTempDir() Users of Corda are advised not to use Guavas Files.createTempDir()
when building applications on Corda. when building applications on Corda.
expires: 2023-09-01T11:38:11.478Z expires: 2023-07-21T11:38:11.478Z
created: 2022-12-29T11:38:11.489Z created: 2022-12-29T11:38:11.489Z
SNYK-JAVA-COMH2DATABASE-31685: SNYK-JAVA-COMH2DATABASE-31685:
- '*': - '*':
@ -17,7 +17,7 @@ ignore:
When it comes to DB connectivity parameters, we do not allow changing When it comes to DB connectivity parameters, we do not allow changing
them as they are supplied by Corda Node configuration file. them as they are supplied by Corda Node configuration file.
expires: 2023-09-01T11:39:26.763Z expires: 2023-07-21T11:39:26.763Z
created: 2022-12-29T11:39:26.775Z created: 2022-12-29T11:39:26.775Z
SNYK-JAVA-COMH2DATABASE-2331071: SNYK-JAVA-COMH2DATABASE-2331071:
- '*': - '*':
@ -26,7 +26,7 @@ ignore:
When it comes to DB connectivity parameters, we do not allow changing When it comes to DB connectivity parameters, we do not allow changing
them as they are supplied by Corda Node configuration file. them as they are supplied by Corda Node configuration file.
expires: 2023-09-01T11:41:05.707Z expires: 2023-07-21T11:41:05.707Z
created: 2022-12-29T11:41:05.723Z created: 2022-12-29T11:41:05.723Z
SNYK-JAVA-COMSQUAREUPOKHTTP3-2958044: SNYK-JAVA-COMSQUAREUPOKHTTP3-2958044:
- '*': - '*':
@ -34,7 +34,7 @@ ignore:
The vulnerability in okhttps error handling is only exploitable in The vulnerability in okhttps error handling is only exploitable in
services that receive and parse HTTP requests. Corda does not receive services that receive and parse HTTP requests. Corda does not receive
HTTP requests and thus is not exposed to this issue. HTTP requests and thus is not exposed to this issue.
expires: 2023-09-01T11:42:55.546Z expires: 2023-07-21T11:42:55.546Z
created: 2022-12-29T11:42:55.556Z created: 2022-12-29T11:42:55.556Z
SNYK-JAVA-IONETTY-1042268: SNYK-JAVA-IONETTY-1042268:
- '*': - '*':
@ -47,7 +47,7 @@ ignore:
RPC SSL client connections Artemis is used which calls into netty. The RPC SSL client connections Artemis is used which calls into netty. The
default value for verifyHost is true for Artemis client connectors so default value for verifyHost is true for Artemis client connectors so
verification of the host name in netty does occur. verification of the host name in netty does occur.
expires: 2023-09-01T11:45:42.976Z expires: 2023-07-21T11:45:42.976Z
created: 2022-12-29T11:45:42.981Z created: 2022-12-29T11:45:42.981Z
SNYK-JAVA-ORGJETBRAINSKOTLIN-2628385: SNYK-JAVA-ORGJETBRAINSKOTLIN-2628385:
- '*': - '*':
@ -57,7 +57,7 @@ ignore:
time for Corda we do not use Multiplatform Gradle Projects so are not time for Corda we do not use Multiplatform Gradle Projects so are not
affected by this vulnerability. In addition as it is a build time affected by this vulnerability. In addition as it is a build time
vulnerability released artifacts are not affected. vulnerability released artifacts are not affected.
expires: 2023-09-01T11:52:35.855Z expires: 2023-07-21T11:52:35.855Z
created: 2022-12-29T11:52:35.870Z created: 2022-12-29T11:52:35.870Z
SNYK-JAVA-ORGJETBRAINSKOTLIN-2393744: SNYK-JAVA-ORGJETBRAINSKOTLIN-2393744:
- '*': - '*':
@ -66,8 +66,35 @@ ignore:
temporary files (via Kotlin functions) with insecure permissions. temporary files (via Kotlin functions) with insecure permissions.
Corda does not use any of the vulnerable functions so it not Corda does not use any of the vulnerable functions so it not
susceptible to this vulnerability. susceptible to this vulnerability.
expires: 2023-09-01T13:39:03.244Z expires: 2023-07-21T13:39:03.244Z
created: 2022-12-29T13:39:03.262Z created: 2022-12-29T13:39:03.262Z
SNYK-JAVA-ORGYAML-3016888:
- '*':
reason: >-
Snakeyaml is being used by Jackson and liquidbase. Corda does not use
Jackson for deserialization except in the optional shell which we
recommend using standalone. The Corda node itself is not exposed.
Corda does however provide mappings of Corda types to allow CorDapps
to use Jackson, and CorDapps using Jackson should make their own
assessment. Liquibase is used to apply the database migration changes.
XML files are used here to define the changes not YAML and therefore
the Corda node itself is not exposed to this deserialisation
vulnerability.
expires: 2023-07-21T13:39:49.450Z
created: 2022-12-29T13:39:49.470Z
SNYK-JAVA-ORGYAML-2806360:
- '*':
reason: >-
Snakeyaml is being used by Jackson and liquidbase. Corda does not use
Jackson except in the optional shell which we recommend using
standalone. The Corda node itself is not exposed. Corda does however
provide mappings of Corda types to allow CorDapps to use Jackson, and
CorDapps using Jackson should make their own assessment. Liquibase is
used to apply the database migration changes. XML files are used here
to define the changes not YAML and therefore the Corda node itself is
not exposed to this DOS vulnerability.
expires: 2023-07-21T13:40:55.262Z
created: 2022-12-29T13:40:55.279Z
SNYK-JAVA-ORGLIQUIBASE-2419059: SNYK-JAVA-ORGLIQUIBASE-2419059:
- '*': - '*':
reason: >- reason: >-
@ -81,139 +108,8 @@ ignore:
exploit this vulnerability would need access to the server with the exploit this vulnerability would need access to the server with the
XML input files, and specifically the access and ability to change JAR XML input files, and specifically the access and ability to change JAR
files on the file system that make up the Corda installation. files on the file system that make up the Corda installation.
expires: 2023-09-01T13:42:11.552Z expires: 2023-07-21T13:42:11.552Z
created: 2022-12-29T13:42:11.570Z created: 2022-12-29T13:42:11.570Z
SNYK-JAVA-COMH2DATABASE-2348247:
- '*':
reason: >-
H2 console is not enabled for any of the applications we are running.
When it comes to DB connectivity parameters, we do not allow changing
them as they are supplied by Corda Node configuration file.
expires: 2023-09-01T11:36:39.068Z
created: 2022-12-29T11:36:39.089Z
SNYK-JAVA-COMH2DATABASE-1769238:
- '*':
reason: >-
H2 is not invoked by Corda unless the node deployment configures an H2
database. This is not a supported configuration in Production and so
this vulnerability should be irrelevant except during development on
Corda. Corda itself does not store XML data within the database so
Corda is not susceptible to this vulnerability. If CorDapp developers
store XML data to the database they need to ascertain themselves that
they are not susceptible.
expires: 2023-09-01T11:40:29.871Z
created: 2022-12-29T11:40:29.896Z
SNYK-JAVA-ORGYAML-3152153:
- '*':
reason: >-
There is a transitive dependency on snakeyaml from the third party
components jackson-dataformat-yaml and liquidbase-core. The
jackson-dataformat-yaml component does not use the snakeyaml
databinding layer. For liquidbase we use xml in the changelog files
not yaml. So given this Corda is not susceptible to this
vulnerability.Cordapp authors should exercise their own judgment if
using this library directly in their cordapp.
expires: 2023-09-01T11:35:04.385Z
created: 2023-01-04T11:35:04.414Z
SNYK-JAVA-COMH2DATABASE-3146851:
- '*':
reason: >-
Corda does not make use of the H2 web admin console, so it not
susceptible to this reported vulnerability
expires: 2023-09-01T11:45:11.295Z
created: 2023-01-04T11:45:11.322Z
SNYK-JAVA-ORGBOUNCYCASTLE-2841508:
- '*':
reason: >-
This vulnerability relates to weak key-hash message authentication
code due to an error within the BKS version 1 keystore files. Corda
does not use BKS-V1 for its keystore files so is not susceptible to
this vulnerability.
expires: 2023-09-01T11:32:38.120Z
created: 2022-09-21T11:32:38.125Z
SNYK-JAVA-COMFASTERXMLJACKSONCORE-3038424:
- '*':
reason: >-
Corda does not set the non-default UNWRAP_SINGLE_VALUE_ARRAYS required
for this vulnerability. In addition Corda does not use Jackson for
deserialization except in the optional shell which we recommend using
standalone. The Corda node itself is not exposed. Corda does however
provide mappings of Corda types to allow CorDapps to use Jackson, and
CorDapps using Jackson should make their own assessment. This
vulnerability relates to deeply nested untyped Object or Array values
(3000 levels deep). Only CorDapps with these types at this level of
nesting are potentially susceptible.
expires: 2023-09-01T12:04:40.180Z
created: 2023-02-09T12:04:40.209Z
SNYK-JAVA-COMFASTERXMLJACKSONCORE-3038426:
- '*':
reason: >-
Corda does not set the non-default UNWRAP_SINGLE_VALUE_ARRAYS required
for this vulnerability. In addition Corda does not use Jackson for
deserialization except in the optional shell which we recommend using
standalone. The Corda node itself is not exposed. Corda does however
provide mappings of Corda types to allow CorDapps to use Jackson, and
CorDapps using Jackson should make their own assessment. This
vulnerability relates to deeply nested untyped Object or Array values
(3000 levels deep). Only CorDapps with these types at this level of
nesting are potentially susceptible.
expires: 2023-09-01T12:05:03.931Z
created: 2023-02-09T12:05:03.962Z
SNYK-JAVA-ORGYAML-2806360:
- '*':
reason: >-
Snakeyaml is being used by Jackson and liquidbase. Corda does not use
Jackson except in the optional shell which we recommend using
standalone. The Corda node itself is not exposed. Corda does however
provide mappings of Corda types to allow CorDapps to use Jackson, and
CorDapps using Jackson should make their own assessment. Liquibase is
used to apply the database migration changes. XML files are used here
to define the changes not YAML and therefore the Corda node itself is
not exposed to this DOS vulnerability.
expires: 2023-09-01T13:40:55.262Z
created: 2022-09-21T13:40:55.279Z
SNYK-JAVA-ORGYAML-3016891:
- '*':
reason: >-
Snakeyaml is being used by Jackson and liquidbase. Corda does not use
Jackson for deserialization except in the optional shell which we
recommend using standalone. The Corda node itself is not exposed.
Corda does however provide mappings of Corda types to allow CorDapps
to use Jackson, and CorDapps using Jackson should make their own
assessment. Liquibase is used to apply the database migration changes.
XML files are used here to define the changes not YAML and therefore
the Corda node itself is not exposed to this deserialisation
vulnerability.
expires: 2023-09-01T16:37:28.911Z
created: 2023-02-06T16:37:28.933Z
SNYK-JAVA-ORGYAML-3016888:
- '*':
reason: >-
Snakeyaml is being used by Jackson and liquidbase. Corda does not use
Jackson for deserialization except in the optional shell which we
recommend using standalone. The Corda node itself is not exposed.
Corda does however provide mappings of Corda types to allow CorDapps
to use Jackson, and CorDapps using Jackson should make their own
assessment. Liquibase is used to apply the database migration changes.
XML files are used here to define the changes not YAML and therefore
the Corda node itself is not exposed to this deserialisation
vulnerability.
expires: 2023-09-01T13:39:49.450Z
created: 2022-09-21T13:39:49.470Z
SNYK-JAVA-ORGYAML-3016889:
- '*':
reason: >-
Snakeyaml is being used by Jackson and liquidbase. Corda does not use
Jackson for deserialization except in the optional shell which we
recommend using standalone. The Corda node itself is not exposed.
Corda does however provide mappings of Corda types to allow CorDapps
to use Jackson, and CorDapps using Jackson should make their own
assessment. Liquibase is used to apply the database migration changes.
XML files are used here to define the changes not YAML and therefore
the Corda node itself is not exposed to this deserialisation
vulnerability.
expires: 2023-09-01T16:35:13.840Z
created: 2023-02-06T16:35:13.875Z
SNYK-JAVA-ORGYAML-3113851: SNYK-JAVA-ORGYAML-3113851:
- '*': - '*':
reason: >- reason: >-
@ -226,6 +122,107 @@ ignore:
XML files are used here to define the changes not YAML and therefore XML files are used here to define the changes not YAML and therefore
the Corda node itself is not exposed to this deserialisation the Corda node itself is not exposed to this deserialisation
vulnerability. vulnerability.
expires: 2024-04-01T00:00:00.000Z expires: 2024-04-30T00:00:00.000Z
created: 2022-11-29T14:55:03.623Z created: 2022-12-29T14:55:03.623Z
SNYK-JAVA-COMFASTERXMLJACKSONCORE-3038426:
- '*':
reason: >-
Corda does not use Jackson for deserialization except in the optional
shell which we recommend using standalone. The Corda node itself is
not exposed. Corda does however provide mappings of Corda types to
allow CorDapps to use Jackson, and CorDapps using Jackson should make
their own assessment. This vulnerability relates to deeply nested
untyped Object or Array values (3000 levels deep). Only CorDapps with
these types at this level of nesting are potentially susceptible.
expires: 2023-07-12T16:50:57.921Z
created: 2022-12-29T16:50:57.943Z
SNYK-JAVA-COMFASTERXMLJACKSONCORE-3038424:
- '*':
reason: >-
Corda does not use Jackson for deserialization except in the optional
shell which we recommend using standalone. The Corda node itself is
not exposed. Corda does however provide mappings of Corda types to
allow CorDapps to use Jackson, and CorDapps using Jackson should make
their own assessment. This vulnerability relates to deeply nested
untyped Object or Array values (3000 levels deep). Only CorDapps with
these types at this level of nesting are potentially susceptible.
expires: 2023-07-12T16:52:30.722Z
created: 2022-12-29T16:52:30.747Z
SNYK-JAVA-ORGYAML-3016891:
- '*':
reason: >-
Snakeyaml is being used by Jackson and liquidbase. Corda does not use
Jackson for deserialization except in the optional shell which we
recommend using standalone. The Corda node itself is not exposed.
Corda does however provide mappings of Corda types to allow CorDapps
to use Jackson, and CorDapps using Jackson should make their own
assessment. Liquibase is used to apply the database migration changes.
XML files are used here to define the changes not YAML and therefore
the Corda node itself is not exposed to this deserialisation
vulnerability.
expires: 2023-07-12T17:00:51.957Z
created: 2022-12-29T17:00:51.970Z
SNYK-JAVA-ORGYAML-3016889:
- '*':
reason: >-
Snakeyaml is being used by Jackson and liquidbase. Corda does not use
Jackson for deserialization except in the optional shell which we
recommend using standalone. The Corda node itself is not exposed.
Corda does however provide mappings of Corda types to allow CorDapps
to use Jackson, and CorDapps using Jackson should make their own
assessment. Liquibase is used to apply the database migration changes.
XML files are used here to define the changes not YAML and therefore
the Corda node itself is not exposed to this deserialisation
vulnerability.
expires: 2023-07-12T17:02:02.538Z
created: 2022-12-29T17:02:02.564Z
SNYK-JAVA-COMH2DATABASE-2348247:
- '*':
reason: >-
H2 console is not enabled for any of the applications we are running.
When it comes to DB connectivity parameters, we do not allow changing
them as they are supplied by Corda Node configuration file.
expires: 2023-07-28T11:36:39.068Z
created: 2022-12-29T11:36:39.089Z
SNYK-JAVA-COMH2DATABASE-1769238:
- '*':
reason: >-
H2 is not invoked by Corda unless the node deployment configures an H2
database. This is not a supported configuration in Production and so
this vulnerability should be irrelevant except during development on
Corda. Corda itself does not store XML data within the database so
Corda is not susceptible to this vulnerability. If CorDapp developers
store XML data to the database they need to ascertain themselves that
they are not susceptible.
expires: 2023-07-28T11:40:29.871Z
created: 2022-12-29T11:40:29.896Z
SNYK-JAVA-ORGYAML-3152153:
- '*':
reason: >-
There is a transitive dependency on snakeyaml from the third party
components jackson-dataformat-yaml and liquidbase-core. The
jackson-dataformat-yaml component does not use the snakeyaml
databinding layer. For liquidbase we use xml in the changelog files
not yaml. So given this Corda is not susceptible to this
vulnerability.Cordapp authors should exercise their own judgment if
using this library directly in their cordapp.
expires: 2023-07-03T11:35:04.385Z
created: 2023-01-04T11:35:04.414Z
SNYK-JAVA-IONETTY-3167773:
- '*':
reason: >-
Corda does not use Netty HTTP (and does not use HTTP in the P2P
protocol) . This is a transitive dependency of Netty comms library,
but it is not used in Corda, which uses a custom binary protocol
secured by mutually authenticated TLS. The vulnerability relating to
HTTP Response splitting is not exposed.
expires: 2023-07-03T11:40:51.456Z
created: 2023-01-04T11:40:51.467Z
SNYK-JAVA-COMH2DATABASE-3146851:
- '*':
reason: >-
Corda does not make use of the H2 web admin console, so it not
susceptible to this reported vulnerability
expires: 2023-07-03T11:45:11.295Z
created: 2023-01-04T11:45:11.322Z
patch: {} patch: {}

View File

@ -8,6 +8,12 @@
Corda is an open source blockchain project, designed for business from the start. Only Corda allows you to build interoperable blockchain networks that transact in strict privacy. Corda's smart contract technology allows businesses to transact directly, with value. Corda is an open source blockchain project, designed for business from the start. Only Corda allows you to build interoperable blockchain networks that transact in strict privacy. Corda's smart contract technology allows businesses to transact directly, with value.
## Architecture Evolution
The code present in this repository reflects the first version of the implementation of the Corda model for DLT technology. This first architecture version covers Corda versions 1 through 4 and continues to deliver on the promise of DLT for both the open source community and industry as a whole.
However, like all things, Corda must evolve to serve the more stringent needs of today. This is why the second (and current) version of the Corda Architecture can be found [here](https://github.com/corda/corda-runtime-os) and will form the basis of the Corda 5 release.
## Features ## Features
* Smart contracts that can be written in Java and other JVM languages * Smart contracts that can be written in Java and other JVM languages
@ -31,7 +37,7 @@ Corda is an open source blockchain project, designed for business from the start
* [Documentation](https://docs.corda.net) * [Documentation](https://docs.corda.net)
* [Stack Overflow Tag](https://stackoverflow.com/questions/tagged/corda) * [Stack Overflow Tag](https://stackoverflow.com/questions/tagged/corda)
* [Slack Channel](https://slack.corda.net/) * [Slack Channel](https://slack.corda.net/)
* [Twitter](https://twitter.com/cordadlt) * [Twitter](https://twitter.com/Cordablockchain)
* [Meetups](https://www.meetup.com/pro/corda/) * [Meetups](https://www.meetup.com/pro/corda/)
* [Training Courses](https://www.corda.net/corda-training/) * [Training Courses](https://www.corda.net/corda-training/)

View File

@ -56,21 +56,20 @@ buildscript {
'org.opentest4j**' 'org.opentest4j**'
] ]
// gradle-capsule-plugin:1.0.2 contains capsule:1.0.1 by default.
// We must configure it manually to use the latest capsule version.
ext.capsule_version = '1.0.3'
ext.asm_version = '7.1' ext.capsule_version = constants.getProperty("capsuleVersion")
ext.artemis_version = '2.19.1' ext.open_telemetry_version = constants.getProperty("openTelemetryVersion")
// TODO Upgrade Jackson only when corda is using kotlin 1.3.10 ext.open_telemetry_sem_conv_version = constants.getProperty("openTelemetrySemConvVersion")
ext.jackson_version = '2.13.5' ext.asm_version = constants.getProperty("asmVersion")
ext.jackson_kotlin_version = '2.9.7' ext.artemis_version = constants.getProperty("artemisVersion")
ext.jetty_version = '9.4.56.v20240826' ext.jackson_version = constants.getProperty("jacksonVersion")
ext.jersey_version = '2.25' ext.jackson_kotlin_version = constants.getProperty("jacksonKotlinVersion")
ext.servlet_version = '4.0.1' ext.jetty_version = constants.getProperty("jettyVersion")
ext.assertj_version = '3.12.2' ext.jersey_version = constants.getProperty("jerseyVersion")
ext.slf4j_version = '1.7.30' ext.servlet_version = constants.getProperty("servletVersion")
ext.log4j_version = '2.17.1' ext.assertj_version = constants.getProperty("assertjVersion")
ext.slf4j_version = constants.getProperty("slf4JVersion")
ext.log4j_version = constants.getProperty("log4JVersion")
ext.bouncycastle_version = constants.getProperty("bouncycastleVersion") ext.bouncycastle_version = constants.getProperty("bouncycastleVersion")
ext.guava_version = constants.getProperty("guavaVersion") ext.guava_version = constants.getProperty("guavaVersion")
ext.caffeine_version = constants.getProperty("caffeineVersion") ext.caffeine_version = constants.getProperty("caffeineVersion")
@ -79,66 +78,61 @@ buildscript {
ext.metrics_new_relic_version = constants.getProperty("metricsNewRelicVersion") ext.metrics_new_relic_version = constants.getProperty("metricsNewRelicVersion")
ext.djvm_version = constants.getProperty("djvmVersion") ext.djvm_version = constants.getProperty("djvmVersion")
ext.deterministic_rt_version = constants.getProperty('deterministicRtVersion') ext.deterministic_rt_version = constants.getProperty('deterministicRtVersion')
ext.okhttp_version = '3.14.2' ext.okhttp_version = constants.getProperty("okhttpVersion")
ext.netty_version = '4.1.77.Final' ext.netty_version = constants.getProperty("nettyVersion")
ext.tcnative_version = constants.getProperty("tcnativeVersion") ext.tcnative_version = constants.getProperty("tcnativeVersion")
ext.typesafe_config_version = constants.getProperty("typesafeConfigVersion") ext.typesafe_config_version = constants.getProperty("typesafeConfigVersion")
ext.fileupload_version = '1.4' ext.fileupload_version = constants.getProperty("fileuploadVersion")
ext.kryo_version = '4.0.2' ext.kryo_version = constants.getProperty("kryoVersion")
ext.kryo_serializer_version = '0.43' ext.kryo_serializer_version = constants.getProperty("kryoSerializerVersion")
// Legacy JUnit 4 version ext.junit_version = constants.getProperty("junitVersion")
ext.junit_version = '4.12' ext.junit_vintage_version = constants.getProperty("junitVintageVersion")
// Need this version to access classpath scanning error handling fix - ext.junit_jupiter_version = constants.getProperty("junitJupiterVersion")
// see https://github.com/junit-team/junit5/commit/389de48c2a18c5a93a7203ef424aa47a8a835a74 ext.junit_platform_version = constants.getProperty("junitPlatformVersion")
// Upgrade to 5.5.x when GA release is available. ext.mockito_version = constants.getProperty("mockitoVersion")
ext.junit_vintage_version = '5.5.0-RC1' ext.mockito_kotlin_version = constants.getProperty("mockitoKotlinVersion")
ext.junit_jupiter_version = '5.5.0-RC1' ext.hamkrest_version = constants.getProperty("hamkrestVersion")
ext.junit_platform_version = '1.5.0-RC1' ext.jopt_simple_version = constants.getProperty("joptSimpleVersion")
ext.mockito_version = '2.28.2' ext.jansi_version = constants.getProperty("jansiVersion")
ext.mockito_kotlin_version = '1.6.0' ext.hibernate_version = constants.getProperty("hibernateVersion")
ext.hamkrest_version = '1.7.0.0' ext.h2_version = constants.getProperty("h2Version")
ext.jopt_simple_version = '5.0.2' ext.rxjava_version = constants.getProperty("rxjavaVersion")
ext.jansi_version = '1.18' ext.dokka_version = constants.getProperty("dokkaVersion")
ext.hibernate_version = '5.4.32.Final' ext.eddsa_version = constants.getProperty("eddsaVersion")
ext.h2_version = '1.4.199' // Update docs if renamed or removed. ext.dependency_checker_version = constants.getProperty("dependencyCheckerVersion")
ext.rxjava_version = '1.3.8' ext.commons_collections_version = constants.getProperty("commonsCollectionsVersion")
ext.dokka_version = '0.10.1' ext.beanutils_version = constants.getProperty("beanutilsVersion")
ext.eddsa_version = '0.3.0'
ext.dependency_checker_version = '5.2.0'
ext.commons_collections_version = '4.3'
ext.beanutils_version = '1.9.4'
ext.jsr305_version = constants.getProperty("jsr305Version") ext.jsr305_version = constants.getProperty("jsr305Version")
ext.shiro_version = '1.10.0' ext.shiro_version = constants.getProperty("shiroVersion")
ext.artifactory_plugin_version = constants.getProperty('artifactoryPluginVersion') ext.artifactory_plugin_version = constants.getProperty('artifactoryPluginVersion')
ext.hikari_version = '4.0.3' ext.hikari_version = constants.getProperty("hikariVersion")
ext.liquibase_version = '3.6.3' ext.liquibase_version = constants.getProperty("liquibaseVersion")
ext.artifactory_contextUrl = 'https://software.r3.com/artifactory' ext.artifactory_contextUrl = 'https://software.r3.com/artifactory'
ext.publicArtifactURL = 'https://download.corda.net/maven' ext.publicArtifactURL = 'https://download.corda.net/maven'
ext.snake_yaml_version = constants.getProperty('snakeYamlVersion') ext.docker_compose_rule_version = constants.getProperty("dockerComposeRuleVersion")
ext.docker_compose_rule_version = '1.5.0' ext.selenium_version = constants.getProperty("seleniumVersion")
ext.selenium_version = '3.141.59' ext.ghostdriver_version = constants.getProperty("ghostdriverVersion")
ext.ghostdriver_version = '2.1.0'
ext.proguard_version = constants.getProperty('proguardVersion') ext.proguard_version = constants.getProperty('proguardVersion')
ext.jsch_version = '0.1.55' ext.jsch_version = constants.getProperty("jschVersion")
ext.protonj_version = '0.33.0' // Overide Artemis version ext.protonj_version = constants.getProperty("protonjVersion")
ext.snappy_version = '0.5' ext.snappy_version = constants.getProperty("snappyVersion")
ext.class_graph_version = constants.getProperty('classgraphVersion') ext.class_graph_version = constants.getProperty('classgraphVersion')
ext.jcabi_manifests_version = '1.1' ext.jcabi_manifests_version = constants.getProperty("jcabiManifestsVersion")
ext.picocli_version = '3.9.6' ext.picocli_version = constants.getProperty("picocliVersion")
ext.commons_lang_version = '3.9' ext.commons_lang_version = constants.getProperty("commonsLangVersion")
ext.commons_io_version = '2.17.0' ext.commons_io_version = constants.getProperty("commonsIoVersion")
ext.controlsfx_version = '8.40.15' ext.controlsfx_version = constants.getProperty("controlsfxVersion")
ext.detekt_version = constants.getProperty('detektVersion') ext.detekt_version = constants.getProperty('detektVersion')
ext.docker_java_version = constants.getProperty("dockerJavaVersion") ext.docker_java_version = constants.getProperty("dockerJavaVersion")
ext.commons_configuration2_version = "2.10.1" ext.commons_configuration2_version = constants.getProperty("commonsConfiguration2Version")
ext.commons_text_version = "1.10.0" ext.commons_text_version = constants.getProperty("commonsTextVersion")
ext.snake_yaml_version = constants.getProperty("snakeYamlVersion")
if (JavaVersion.current().isJava8()) { if (JavaVersion.current().isJava8()) {
ext.fontawesomefx_commons_version = '8.15' ext.fontawesomefx_commons_version = constants.getProperty("fontawesomefxCommonsJava8Version")
ext.fontawesomefx_fontawesome_version = '4.7.0-5' ext.fontawesomefx_fontawesome_version = constants.getProperty("fontawesomefxFontawesomeJava8Version")
} else { } else {
// has been compiled by a more recent version of the Java Runtime (class file version 55.0) ext.fontawesomefx_commons_version = constants.getProperty("fontawesomefxCommonsVersion")
ext.fontawesomefx_commons_version = '11.0' ext.fontawesomefx_fontawesome_version = constants.getProperty("fontawesomefxFontawesomeVersion")
ext.fontawesomefx_fontawesome_version = '4.7.0-11'
} }
// Name of the IntelliJ SDK created for the deterministic Java rt.jar. // Name of the IntelliJ SDK created for the deterministic Java rt.jar.
@ -222,7 +216,8 @@ buildscript {
classpath "com.gradle:common-custom-user-data-gradle-plugin:$customUserDataGradlePlugin" classpath "com.gradle:common-custom-user-data-gradle-plugin:$customUserDataGradlePlugin"
} }
configurations.all { configurations.classpath {
// FORCE Gradle to use latest SNAPSHOT plugins.
resolutionStrategy.cacheChangingModulesFor 0, 'seconds' resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
} }
} }
@ -492,7 +487,7 @@ allprojects {
// * Apache commons-configuration2 // * Apache commons-configuration2
eachDependency { details -> eachDependency { details ->
if (details.requested.group == 'io.netty' && details.requested.name.startsWith('netty-')) { if (details.requested.group == 'io.netty' && details.requested.name.startsWith('netty-')) {
if (details.requested.name.startsWith('netty-tcnative')){ if (details.requested.name.startsWith('netty-tcnative')) {
details.useVersion tcnative_version details.useVersion tcnative_version
} else { } else {
details.useVersion netty_version details.useVersion netty_version
@ -510,25 +505,48 @@ allprojects {
details.useVersion snake_yaml_version details.useVersion snake_yaml_version
} }
} }
dependencySubstitution {
// We want to use SLF4J's version of these bindings: jcl-over-slf4j
// Remove any transitive dependency on Apache's version.
substitute module('commons-logging:commons-logging') with module("org.slf4j:jcl-over-slf4j:$slf4j_version")
// Remove any transitive dependency on Logback (e.g. Liquibase 3.6 introduces this dependency)
substitute module('ch.qos.logback:logback-classic') with module("org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version")
// Netty-All is an uber-jar which contains every Netty module.
// Exclude it to force us to use the individual Netty modules instead.
substitute module('io.netty:netty-all') with module("io.netty:netty-common:$netty_version")
// Force dependencies to use the same version of Guava as Corda.
substitute module('com.google.guava:guava') with module("com.google.guava:guava:$guava_version")
// Effectively delete this unused and unwanted transitive dependency of Artemis.
substitute module('org.jgroups:jgroups') with module("org.apache.activemq:artemis-commons:$artemis_version")
}
} }
} }
compile {
// We want to use SLF4J's version of these bindings: jcl-over-slf4j
// Remove any transitive dependency on Apache's version.
exclude group: 'commons-logging', module: 'commons-logging'
// Remove any transitive dependency on Logback (e.g. Liquibase 3.6 introduces this dependency)
exclude group: 'ch.qos.logback'
// Netty-All is an uber-jar which contains every Netty module. // Select all of the compileClasspath and runtimeClasspath etc configurations,
// Exclude it to force us to use the individual Netty modules instead. // but NOT the "classpath" configuration, as that is used by the Gradle plugins.
exclude group: 'io.netty', module: 'netty-all' matching { it.name.endsWith("Classpath") }.configureEach { cfg ->
} cfg.resolutionStrategy {
runtime { dependencySubstitution {
// We never want isolated.jar on classPath, since we want to test jar being dynamically loaded as an attachment // Force dependencies to use the same version of Kotlin as Corda.
exclude module: 'isolated' substitute module('org.jetbrains.kotlin:kotlin-stdlib-jdk8') with module("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version")
substitute module('org.jetbrains.kotlin:kotlin-stdlib-jdk7') with module("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version")
substitute module('org.jetbrains.kotlin:kotlin-stdlib-common') with module("org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version")
substitute module('org.jetbrains.kotlin:kotlin-stdlib') with module("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
substitute module('org.jetbrains.kotlin:kotlin-reflect') with module("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")
}
// FORCE Gradle to use latest SNAPSHOT dependencies.
cacheChangingModulesFor 0, 'seconds'
}
} }
} }
} }
sonarqube { sonarqube {
properties { properties {
property "sonar.projectName", "Corda" property "sonar.projectName", "Corda"
@ -666,6 +684,8 @@ bintrayConfig {
gpgSign = true gpgSign = true
gpgPassphrase = System.getenv('CORDA_BINTRAY_GPG_PASSPHRASE') gpgPassphrase = System.getenv('CORDA_BINTRAY_GPG_PASSPHRASE')
publications = [ publications = [
'corda-opentelemetry',
'corda-opentelemetry-driver',
'corda-jfx', 'corda-jfx',
'corda-mock', 'corda-mock',
'corda-rpc', 'corda-rpc',

View File

@ -78,6 +78,10 @@ class CordaRPCConnection private constructor(
override fun forceClose() = doCloseLogic { actualConnection.forceClose() } override fun forceClose() = doCloseLogic { actualConnection.forceClose() }
override fun <T> getTelemetryHandle(telemetryClass: Class<T>): T? {
return actualConnection.getTelemetryHandle(telemetryClass)
}
private inline fun doCloseLogic(close: () -> Unit) { private inline fun doCloseLogic(close: () -> Unit) {
try { try {
close.invoke() close.invoke()
@ -170,8 +174,15 @@ open class CordaRPCClientConfiguration @JvmOverloads constructor(
/** /**
* The cache expiry of a deduplication watermark per client. Default is 1 day. * The cache expiry of a deduplication watermark per client. Default is 1 day.
*/ */
open val deduplicationCacheExpiry: Duration = 1.days open val deduplicationCacheExpiry: Duration = 1.days,
open val openTelemetryEnabled: Boolean = true,
open val simpleLogTelemetryEnabled: Boolean = false,
open val spanStartEndEventsEnabled: Boolean = false,
open val copyBaggageToTags: Boolean = false
) { ) {
companion object { companion object {
@ -215,7 +226,49 @@ open class CordaRPCClientConfiguration @JvmOverloads constructor(
connectionRetryIntervalMultiplier, connectionRetryIntervalMultiplier,
maxReconnectAttempts, maxReconnectAttempts,
maxFileSize, maxFileSize,
deduplicationCacheExpiry deduplicationCacheExpiry,
openTelemetryEnabled,
simpleLogTelemetryEnabled,
spanStartEndEventsEnabled,
copyBaggageToTags
)
}
@Suppress("LongParameterList")
fun copy(
connectionMaxRetryInterval: Duration = this.connectionMaxRetryInterval,
minimumServerProtocolVersion: Int = this.minimumServerProtocolVersion,
trackRpcCallSites: Boolean = this.trackRpcCallSites,
reapInterval: Duration = this.reapInterval,
observationExecutorPoolSize: Int = this.observationExecutorPoolSize,
@Suppress("DEPRECATION")
cacheConcurrencyLevel: Int = this.cacheConcurrencyLevel,
connectionRetryInterval: Duration = this.connectionRetryInterval,
connectionRetryIntervalMultiplier: Double = this.connectionRetryIntervalMultiplier,
maxReconnectAttempts: Int = this.maxReconnectAttempts,
maxFileSize: Int = this.maxFileSize,
deduplicationCacheExpiry: Duration = this.deduplicationCacheExpiry,
openTelemetryEnabled: Boolean = this.openTelemetryEnabled,
simpleLogTelemetryEnabled: Boolean = this.simpleLogTelemetryEnabled,
spanStartEndEventsEnabled: Boolean = this.spanStartEndEventsEnabled,
copyBaggageToTags: Boolean = this.copyBaggageToTags
): CordaRPCClientConfiguration {
return CordaRPCClientConfiguration(
connectionMaxRetryInterval,
minimumServerProtocolVersion,
trackRpcCallSites,
reapInterval,
observationExecutorPoolSize,
cacheConcurrencyLevel,
connectionRetryInterval,
connectionRetryIntervalMultiplier,
maxReconnectAttempts,
maxFileSize,
deduplicationCacheExpiry,
openTelemetryEnabled,
simpleLogTelemetryEnabled,
spanStartEndEventsEnabled,
copyBaggageToTags
) )
} }
@ -236,6 +289,10 @@ open class CordaRPCClientConfiguration @JvmOverloads constructor(
if (maxReconnectAttempts != other.maxReconnectAttempts) return false if (maxReconnectAttempts != other.maxReconnectAttempts) return false
if (maxFileSize != other.maxFileSize) return false if (maxFileSize != other.maxFileSize) return false
if (deduplicationCacheExpiry != other.deduplicationCacheExpiry) return false if (deduplicationCacheExpiry != other.deduplicationCacheExpiry) return false
if (openTelemetryEnabled != other.openTelemetryEnabled) return false
if (simpleLogTelemetryEnabled != other.simpleLogTelemetryEnabled) return false
if (spanStartEndEventsEnabled != other.spanStartEndEventsEnabled) return false
if (copyBaggageToTags != other.copyBaggageToTags) return false
return true return true
} }
@ -253,6 +310,10 @@ open class CordaRPCClientConfiguration @JvmOverloads constructor(
result = 31 * result + maxReconnectAttempts result = 31 * result + maxReconnectAttempts
result = 31 * result + maxFileSize result = 31 * result + maxFileSize
result = 31 * result + deduplicationCacheExpiry.hashCode() result = 31 * result + deduplicationCacheExpiry.hashCode()
result = 31 * result + openTelemetryEnabled.hashCode()
result = 31 * result + simpleLogTelemetryEnabled.hashCode()
result = 31 * result + spanStartEndEventsEnabled.hashCode()
result = 31 * result + copyBaggageToTags.hashCode()
return result return result
} }
@ -265,7 +326,11 @@ open class CordaRPCClientConfiguration @JvmOverloads constructor(
"cacheConcurrencyLevel=$cacheConcurrencyLevel, connectionRetryInterval=$connectionRetryInterval, " + "cacheConcurrencyLevel=$cacheConcurrencyLevel, connectionRetryInterval=$connectionRetryInterval, " +
"connectionRetryIntervalMultiplier=$connectionRetryIntervalMultiplier, " + "connectionRetryIntervalMultiplier=$connectionRetryIntervalMultiplier, " +
"maxReconnectAttempts=$maxReconnectAttempts, maxFileSize=$maxFileSize, " + "maxReconnectAttempts=$maxReconnectAttempts, maxFileSize=$maxFileSize, " +
"deduplicationCacheExpiry=$deduplicationCacheExpiry)" "deduplicationCacheExpiry=$deduplicationCacheExpiry, " +
"openTelemetryEnabled=$openTelemetryEnabled, " +
"simpleLogTelemetryEnabled=$simpleLogTelemetryEnabled, " +
"spanStartEndEventsEnabled=$spanStartEndEventsEnabled, " +
"copyBaggageToTags=$copyBaggageToTags )"
} }
// Left in for backwards compatibility with version 3.1 // Left in for backwards compatibility with version 3.1

View File

@ -21,6 +21,12 @@ interface RPCConnection<out I : RPCOps> : Closeable {
/** The RPC protocol version reported by the server. */ /** The RPC protocol version reported by the server. */
val serverProtocolVersion: Int val serverProtocolVersion: Int
/**
* Returns the configured openTelemetry global. Returns null if opentelemetry has not been configured.
*/
fun <T> getTelemetryHandle(telemetryClass: Class<T>): T?
/** /**
* Closes this client gracefully by sending a notification to the server, so it can immediately clean up resources. * Closes this client gracefully by sending a notification to the server, so it can immediately clean up resources.
* If the server is not available this method may block for a short period until it's clear the server is not * If the server is not available this method may block for a short period until it's clear the server is not

View File

@ -22,6 +22,7 @@ import net.corda.nodeapi.internal.RoundRobinConnectionPolicy
import net.corda.nodeapi.internal.config.SslConfiguration import net.corda.nodeapi.internal.config.SslConfiguration
import org.apache.activemq.artemis.api.core.TransportConfiguration import org.apache.activemq.artemis.api.core.TransportConfiguration
import org.apache.activemq.artemis.api.core.client.ActiveMQClient import org.apache.activemq.artemis.api.core.client.ActiveMQClient
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants
import java.lang.reflect.Proxy import java.lang.reflect.Proxy
import java.util.concurrent.CopyOnWriteArraySet import java.util.concurrent.CopyOnWriteArraySet
@ -101,10 +102,15 @@ class RPCClient<I : RPCOps>(
// Without this any type of "send" time failures will not be delivered back to the client // Without this any type of "send" time failures will not be delivered back to the client
isBlockOnNonDurableSend = true isBlockOnNonDurableSend = true
} }
val targetString = "${transport.params[TransportConstants.HOST_PROP_NAME]}:${transport.params[TransportConstants.PORT_PROP_NAME]}"
val rpcClientTelemetry = RPCClientTelemetry("rpcClient-$targetString", rpcConfiguration.openTelemetryEnabled,
rpcConfiguration.simpleLogTelemetryEnabled, rpcConfiguration.spanStartEndEventsEnabled, rpcConfiguration.copyBaggageToTags)
val sessionId = Trace.SessionId.newInstance() val sessionId = Trace.SessionId.newInstance()
val distributionMux = DistributionMux(listeners, username) val distributionMux = DistributionMux(listeners, username)
val proxyHandler = RPCClientProxyHandler(rpcConfiguration, username, password, serverLocator, val proxyHandler = RPCClientProxyHandler(rpcConfiguration, username, password, serverLocator,
rpcOpsClass, serializationContext, sessionId, externalTrace, impersonatedActor, targetLegalIdentity, distributionMux) rpcOpsClass, serializationContext, sessionId, externalTrace, impersonatedActor, targetLegalIdentity, distributionMux,
rpcClientTelemetry)
try { try {
proxyHandler.start() proxyHandler.start()
val ops: I = uncheckedCast(Proxy.newProxyInstance(rpcOpsClass.classLoader, arrayOf(rpcOpsClass), proxyHandler)) val ops: I = uncheckedCast(Proxy.newProxyInstance(rpcOpsClass.classLoader, arrayOf(rpcOpsClass), proxyHandler))
@ -121,6 +127,10 @@ class RPCClient<I : RPCOps>(
override val proxy = ops override val proxy = ops
override val serverProtocolVersion = serverProtocolVersion override val serverProtocolVersion = serverProtocolVersion
override fun <T> getTelemetryHandle(telemetryClass: Class<T>): T? {
return rpcClientTelemetry.getTelemetryHandle(telemetryClass)
}
private fun close(notify: Boolean) { private fun close(notify: Boolean) {
if (notify) { if (notify) {
proxyHandler.notifyServerAndClose() proxyHandler.notifyServerAndClose()
@ -128,6 +138,7 @@ class RPCClient<I : RPCOps>(
proxyHandler.forceClose() proxyHandler.forceClose()
} }
serverLocator.close() serverLocator.close()
rpcClientTelemetry.telemetryService.shutdownTelemetry()
} }
override fun notifyServerAndClose() { override fun notifyServerAndClose() {

View File

@ -20,6 +20,7 @@ import net.corda.core.internal.LazyStickyPool
import net.corda.core.internal.LifeCycle import net.corda.core.internal.LifeCycle
import net.corda.core.internal.NamedCacheFactory import net.corda.core.internal.NamedCacheFactory
import net.corda.core.internal.ThreadBox import net.corda.core.internal.ThreadBox
import net.corda.core.internal.telemetry.TelemetryStatusCode
import net.corda.core.internal.times import net.corda.core.internal.times
import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.RPCOps import net.corda.core.messaging.RPCOps
@ -110,6 +111,7 @@ internal class RPCClientProxyHandler(
private val impersonatedActor: Actor?, private val impersonatedActor: Actor?,
private val targetLegalIdentity: CordaX500Name?, private val targetLegalIdentity: CordaX500Name?,
private val notificationDistributionMux: DistributionMux<out RPCOps>, private val notificationDistributionMux: DistributionMux<out RPCOps>,
private val rpcClientTelemetry: RPCClientTelemetry,
private val cacheFactory: NamedCacheFactory = ClientCacheFactory() private val cacheFactory: NamedCacheFactory = ClientCacheFactory()
) : InvocationHandler { ) : InvocationHandler {
@ -330,6 +332,8 @@ internal class RPCClientProxyHandler(
val replyId = InvocationId.newInstance() val replyId = InvocationId.newInstance()
val methodFqn = produceMethodFullyQualifiedName(method) val methodFqn = produceMethodFullyQualifiedName(method)
callSiteMap?.set(replyId, CallSite(methodFqn)) callSiteMap?.set(replyId, CallSite(methodFqn))
val telemetryId = rpcClientTelemetry.telemetryService.startSpanForFlow("client-$methodFqn", emptyMap())
try { try {
val serialisedArguments = (arguments?.toList() ?: emptyList()).serialize(context = serializationContextWithObservableContext) val serialisedArguments = (arguments?.toList() ?: emptyList()).serialize(context = serializationContextWithObservableContext)
val request = RPCApi.ClientToServer.RpcRequest( val request = RPCApi.ClientToServer.RpcRequest(
@ -339,7 +343,8 @@ internal class RPCClientProxyHandler(
replyId, replyId,
sessionId, sessionId,
externalTrace, externalTrace,
impersonatedActor impersonatedActor,
rpcClientTelemetry.telemetryService.getCurrentTelemetryData()
) )
val replyFuture = SettableFuture.create<Any>() val replyFuture = SettableFuture.create<Any>()
require(rpcReplyMap.put(replyId, replyFuture) == null) { require(rpcReplyMap.put(replyId, replyFuture) == null) {
@ -353,13 +358,18 @@ internal class RPCClientProxyHandler(
sendMessage(request) sendMessage(request)
return replyFuture.getOrThrow() return replyFuture.getOrThrow()
} catch (e: RuntimeException) { } catch (e: RuntimeException) {
rpcClientTelemetry.telemetryService.recordException(telemetryId, e)
rpcClientTelemetry.telemetryService.setStatus(telemetryId, TelemetryStatusCode.ERROR, e.message ?: "RuntimeException occurred")
// Already an unchecked exception, so just rethrow it // Already an unchecked exception, so just rethrow it
throw e throw e
} catch (e: Exception) { } catch (e: Exception) {
rpcClientTelemetry.telemetryService.recordException(telemetryId, e)
rpcClientTelemetry.telemetryService.setStatus(telemetryId, TelemetryStatusCode.ERROR, e.message ?: "Exception occurred")
// This must be a checked exception, so wrap it // This must be a checked exception, so wrap it
throw RPCException(e.message ?: "", e) throw RPCException(e.message ?: "", e)
} finally { } finally {
callSiteMap?.remove(replyId) callSiteMap?.remove(replyId)
rpcClientTelemetry.telemetryService.endSpanForFlow(telemetryId)
} }
} }

View File

@ -0,0 +1,42 @@
package net.corda.client.rpc.internal
import net.corda.core.internal.telemetry.OpenTelemetryComponent
import net.corda.core.internal.telemetry.SimpleLogTelemetryComponent
import net.corda.core.internal.telemetry.TelemetryServiceImpl
import net.corda.core.utilities.contextLogger
class RPCClientTelemetry(val serviceName: String, val openTelemetryEnabled: Boolean,
val simpleLogTelemetryEnabled: Boolean, val spanStartEndEventsEnabled: Boolean,
val copyBaggageToTags: Boolean) {
companion object {
private val log = contextLogger()
}
val telemetryService = TelemetryServiceImpl()
init {
if (openTelemetryEnabled) {
try {
val openTelemetryComponent = OpenTelemetryComponent(serviceName, spanStartEndEventsEnabled, copyBaggageToTags)
if (openTelemetryComponent.isEnabled()) {
telemetryService.addTelemetryComponent(openTelemetryComponent)
log.debug("OpenTelemetry enabled")
}
}
catch (ex: NoClassDefFoundError) {
// Do nothing api or sdk not available on classpath
log.debug("OpenTelemetry not enabled, api or sdk not found on classpath")
}
}
if (simpleLogTelemetryEnabled) {
val simpleLogTelemetryComponent = SimpleLogTelemetryComponent()
telemetryService.addTelemetryComponent(simpleLogTelemetryComponent)
log.debug("SimpleLogTelemetry enabled")
}
}
fun <T> getTelemetryHandle(telemetryClass: Class<T>): T? {
return telemetryService.getTelemetryHandle(telemetryClass)
}
}

View File

@ -299,6 +299,9 @@ class ReconnectingCordaRPCOps private constructor(
currentRPCConnection?.forceClose() currentRPCConnection?.forceClose()
} }
} }
override fun <T> getTelemetryHandle(telemetryClass: Class<T>): T? {
return currentRPCConnection?.getTelemetryHandle(telemetryClass)
}
fun isClosed(): Boolean = currentState == CLOSED fun isClosed(): Boolean = currentState == CLOSED
} }
private class ErrorInterceptingHandler(val reconnectingRPCConnection: ReconnectingRPCConnection) : InvocationHandler { private class ErrorInterceptingHandler(val reconnectingRPCConnection: ReconnectingRPCConnection) : InvocationHandler {

View File

@ -118,7 +118,7 @@ class StandaloneCordaRPClientTest {
val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use { it -> val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use { it ->
it.copyTo(NULL_OUTPUT_STREAM) it.copyTo(NULL_OUTPUT_STREAM)
SecureHash.SHA256(it.hash().asBytes()) SecureHash.createSHA256(it.hash().asBytes())
} }
assertEquals(attachment.sha256, hash) assertEquals(attachment.sha256, hash)
} }
@ -133,7 +133,7 @@ class StandaloneCordaRPClientTest {
val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use { it -> val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use { it ->
it.copyTo(NULL_OUTPUT_STREAM) it.copyTo(NULL_OUTPUT_STREAM)
SecureHash.SHA256(it.hash().asBytes()) SecureHash.createSHA256(it.hash().asBytes())
} }
assertEquals(attachment.sha256, hash) assertEquals(attachment.sha256, hash)
} }

View File

@ -0,0 +1,109 @@
package net.corda.client.rpc
import net.corda.core.crypto.random63BitValue
import net.corda.core.internal.concurrent.fork
import net.corda.core.messaging.RPCOps
import net.corda.core.utilities.millis
import net.corda.coretesting.internal.testThreadFactory
import net.corda.node.services.rpc.RPCServerConfiguration
import net.corda.testing.node.internal.RPCDriverDSL
import net.corda.testing.node.internal.rpcDriver
import org.junit.After
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executors
import kotlin.test.assertTrue
@RunWith(Parameterized::class)
class QuickRPCRequestTests : AbstractRPCTest() {
companion object {
// indicate when all RPC threads are busy
val threadBusyLatches = ConcurrentHashMap<Long, CountDownLatch>()
val numRpcThreads = 4
}
interface TestOps : RPCOps {
fun newLatch(numberOfDowns: Int): Long
fun waitLatch(id: Long)
fun downLatch(id: Long)
}
class TestOpsImpl : TestOps {
private val latches = ConcurrentHashMap<Long, CountDownLatch>()
override val protocolVersion = 1000
override fun newLatch(numberOfDowns: Int): Long {
val id = random63BitValue()
val latch = CountDownLatch(numberOfDowns)
latches[id] = latch
return id
}
override fun waitLatch(id: Long) {
threadBusyLatches[id]!!.countDown()
latches[id]!!.await()
}
override fun downLatch(id: Long) {
latches[id]!!.countDown()
}
}
private fun RPCDriverDSL.testProxy(): TestProxy<TestOps> {
return testProxy<TestOps>(
TestOpsImpl(),
clientConfiguration = CordaRPCClientConfiguration.DEFAULT.copy(
reapInterval = 100.millis
),
serverConfiguration = RPCServerConfiguration.DEFAULT.copy(
rpcThreadPoolSize = numRpcThreads
)
)
}
private val pool = Executors.newFixedThreadPool(10, testThreadFactory())
@After
fun shutdown() {
pool.shutdown()
}
@Test(timeout=300_000)
fun `quick RPCs by-pass the standard RPC thread pool`() {
/*
1. Set up a node with N RPC threads
2. Send a call to a blocking RPC on each thread
3. When all RPC threads are blocked, call a quick RPC
4. Check the quick RPC returns, whilst the RPC threads are still blocked
*/
rpcDriver {
val proxy = testProxy()
val numberOfDownsRequired = 1
val id = proxy.ops.newLatch(numberOfDownsRequired)
val newThreadLatch = CountDownLatch(numRpcThreads)
threadBusyLatches[id] = newThreadLatch
// Flood the RPC threads with blocking calls
for (n in 1..numRpcThreads) {
pool.fork {
proxy.ops.waitLatch(id)
}
}
// wait until all the RPC threads are blocked
threadBusyLatches[id]!!.await()
// try a quick RPC - getProtocolVersion() is always quick
val quickResult = proxy.ops.protocolVersion.toString()
// the fact that a result is returned is proof enough that the quick-RPC has by-passed the
// flooded RPC thread pool
assertTrue(quickResult.isNotEmpty())
// The failure condition is that the test times out.
}
}
}

View File

@ -9,4 +9,4 @@ package net.corda.common.logging
* (originally added to source control for ease of use) * (originally added to source control for ease of use)
*/ */
internal const val CURRENT_MAJOR_RELEASE = "4.9-SNAPSHOT" internal const val CURRENT_MAJOR_RELEASE = "4.10-SNAPSHOT"

View File

@ -203,11 +203,14 @@
<AppenderRef ref="RollingFile-ErrorCode-Appender"/> <AppenderRef ref="RollingFile-ErrorCode-Appender"/>
</Logger> </Logger>
<Logger name="org.apache.activemq.artemis.core.server" level="warn" additivity="false"> <Logger name="org.apache.activemq.artemis.core.server" level="warn" additivity="false">
<Filters> <AppenderRef ref="Console-ErrorCode-Selector">
<RegexFilter regex=".*AMQ222165.*" onMatch="DENY" onMismatch="NEUTRAL"/> <Filters>
<RegexFilter regex=".*AMQ222166.*" onMatch="DENY" onMismatch="NEUTRAL"/> <RegexFilter regex=".*AMQ222061.*" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters> <RegexFilter regex=".*AMQ222107.*" onMatch="DENY" onMismatch="NEUTRAL"/>
<AppenderRef ref="Console-ErrorCode-Selector"/> <RegexFilter regex=".*AMQ222165.*" onMatch="DENY" onMismatch="NEUTRAL"/>
<RegexFilter regex=".*AMQ222166.*" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
</AppenderRef>
<AppenderRef ref="RollingFile-ErrorCode-Appender"/> <AppenderRef ref="RollingFile-ErrorCode-Appender"/>
</Logger> </Logger>
<Logger name="org.apache.activemq.audit" level="error" additivity="false"> <Logger name="org.apache.activemq.audit" level="error" additivity="false">

View File

@ -1,8 +1,9 @@
# This file is parsed from Python in the docs/source/conf.py file # This file is parsed from Python in the docs/source/conf.py file
# because some versions here need to be matched by app authors in # because some versions here need to be matched by app authors in
# their own projects. So don't get fancy with syntax! # their own projects. So don't get fancy with syntax!
# Fancy syntax - multi pass ${whatever} replacement
cordaVersion=4.9 cordaVersion=4.10
versionSuffix=SNAPSHOT versionSuffix=SNAPSHOT
gradlePluginsVersion=5.0.12 gradlePluginsVersion=5.0.12
kotlinVersion=1.2.71 kotlinVersion=1.2.71
@ -11,7 +12,9 @@ java8MinUpdateVersion=171
# When incrementing platformVersion make sure to update # # When incrementing platformVersion make sure to update #
# net.corda.core.internal.CordaUtilsKt.PLATFORM_VERSION as well. # # net.corda.core.internal.CordaUtilsKt.PLATFORM_VERSION as well. #
# ***************************************************************# # ***************************************************************#
platformVersion=11 platformVersion=12
openTelemetryVersion=1.20.1
openTelemetrySemConvVersion=1.20.1-alpha
guavaVersion=28.0-jre guavaVersion=28.0-jre
# Quasar version to use with Java 8: # Quasar version to use with Java 8:
quasarVersion=0.7.15_r3 quasarVersion=0.7.15_r3
@ -37,3 +40,70 @@ openSourceSamplesBranch=https://github.com/corda/samples/blob/release-V4
jolokiaAgentVersion=1.6.1 jolokiaAgentVersion=1.6.1
detektVersion=1.0.1 detektVersion=1.0.1
tcnativeVersion=2.0.48.Final tcnativeVersion=2.0.48.Final
commonsConfiguration2Version=2.11.0
commonsTextVersion=1.10.0
# ENT-6607 all third party version in here now
# gradle-capsule-plugin:1.0.2 contains capsule:1.0.1 by default.
# We must configure it manually to use the latest capsule version.
capsuleVersion=1.0.3
asmVersion=7.1
artemisVersion=2.19.1
# TODO Upgrade Jackson only when corda is using kotlin 1.3.10
jacksonVersion=2.17.2
jacksonKotlinVersion=2.9.7
jettyVersion=9.4.56.v20240826
jerseyVersion=2.25
servletVersion=4.0.1
assertjVersion=3.12.2
slf4JVersion=1.7.30
log4JVersion=2.17.1
okhttpVersion=3.14.9
nettyVersion=4.1.77.Final
fileuploadVersion=1.4
kryoVersion=4.0.2
kryoSerializerVersion=0.43
# Legacy JUnit 4 version
junitVersion=4.12
# Need this version to access classpath scanning error handling fix -
# see https://github.com/junit-team/junit5/commit/389de48c2a18c5a93a7203ef424aa47a8a835a74
# Upgrade to 5.5.x when GA release is available.
junitVintageVersion=5.5.0-RC1
junitJupiterVersion=5.5.0-RC1
junitPlatformVersion=1.5.0-RC1
mockitoVersion=2.28.2
mockitoKotlinVersion=1.6.0
hamkrestVersion=1.7.0.0
joptSimpleVersion=5.0.2
jansiVersion=1.18
hibernateVersion=5.4.32.Final
# h2Version - Update docs if renamed or removed.
h2Version=1.4.199
rxjavaVersion=1.3.8
dokkaVersion=0.10.1
eddsaVersion=0.3.0
dependencyCheckerVersion=5.2.0
commonsCollectionsVersion=4.3
beanutilsVersion=1.9.4
shiroVersion=1.10.0
hikariVersion=4.0.3
liquibaseVersion=3.6.3
dockerComposeRuleVersion=1.5.0
seleniumVersion=3.141.59
ghostdriverVersion=2.1.0
jschVersion=0.1.55
# Override Artemis version
protonjVersion=0.33.0
snappyVersion=0.5
jcabiManifestsVersion=1.1
picocliVersion=3.9.6
commonsLangVersion=3.9
commonsIoVersion=2.17.0
controlsfxVersion=8.40.15
# FontAwesomeFX for Java8
fontawesomefxCommonsJava8Version=8.15
fontawesomefxFontawesomeJava8Version=4.7.0-5
# FontAwesomeFX for a more recent version of the Java Runtime (class file version 55.0)
fontawesomefxCommonsVersion=11.0
fontawesomefxFontawesomeVersion=4.7.0-11

View File

@ -1,6 +1,7 @@
import net.corda.gradle.jarfilter.JarFilterTask import net.corda.gradle.jarfilter.JarFilterTask
import net.corda.gradle.jarfilter.MetaFixerTask import net.corda.gradle.jarfilter.MetaFixerTask
import proguard.gradle.ProGuardTask import proguard.gradle.ProGuardTask
import static org.gradle.api.JavaVersion.VERSION_1_8 import static org.gradle.api.JavaVersion.VERSION_1_8
plugins { plugins {
@ -43,6 +44,9 @@ dependencies {
api "com.google.code.findbugs:jsr305:$jsr305_version" api "com.google.code.findbugs:jsr305:$jsr305_version"
api "org.slf4j:slf4j-api:$slf4j_version" api "org.slf4j:slf4j-api:$slf4j_version"
compileOnly "io.opentelemetry:opentelemetry-api:${open_telemetry_version}"
compileOnly project(':opentelemetry')
// These dependencies will become "runtime" scoped in our published POM. // These dependencies will become "runtime" scoped in our published POM.
// See publish.dependenciesFrom.defaultScope. // See publish.dependenciesFrom.defaultScope.
deterministicLibraries "org.bouncycastle:bcprov-jdk18on:$bouncycastle_version" deterministicLibraries "org.bouncycastle:bcprov-jdk18on:$bouncycastle_version"
@ -80,6 +84,7 @@ def patchCore = tasks.register('patchCore', Zip) {
exclude 'net/corda/core/contracts/CordaRotatedKeys.class' exclude 'net/corda/core/contracts/CordaRotatedKeys.class'
exclude 'net/corda/core/contracts/RotatedKeysKt.class' exclude 'net/corda/core/contracts/RotatedKeysKt.class'
exclude 'net/corda/core/contracts/RotatedKeys.class' exclude 'net/corda/core/contracts/RotatedKeys.class'
exclude 'net/corda/core/internal/utilities/PrivateInterner*.class'
} }
reproducibleFileOrder = true reproducibleFileOrder = true

View File

@ -0,0 +1,16 @@
package net.corda.core.internal.utilities
import net.corda.core.KeepForDJVM
@KeepForDJVM
class PrivateInterner<T>(val verifier: IternabilityVerifier<T> = AlwaysInternableVerifier()) {
// DJVM implementation does not intern and does not use Guava
fun <S : T> intern(sample: S): S = sample
@KeepForDJVM
companion object {
@Suppress("UNUSED_PARAMETER")
fun findFor(clazz: Class<*>?): PrivateInterner<Any>? = null
}
}

View File

@ -27,7 +27,8 @@ configurations {
dependencies { dependencies {
obfuscatorImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" obfuscatorImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compileOnly "io.opentelemetry:opentelemetry-api:${open_telemetry_version}"
compileOnly project(':opentelemetry')
testImplementation sourceSets.obfuscator.output testImplementation sourceSets.obfuscator.output
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
testImplementation "junit:junit:$junit_version" testImplementation "junit:junit:$junit_version"
@ -58,7 +59,7 @@ dependencies {
testCompile "org.assertj:assertj-core:${assertj_version}" testCompile "org.assertj:assertj-core:${assertj_version}"
// Guava: Google utilities library. // Guava: Google utilities library.
testCompile "com.google.guava:guava:$guava_version" compile "com.google.guava:guava:$guava_version"
// For caches rather than guava // For caches rather than guava
compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version" compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version"
@ -161,7 +162,8 @@ quasar {
"org.w3c.**", "org.w3c.**",
"org.xml**", "org.xml**",
"org.yaml**", "org.yaml**",
"rx**") "rx**",
"io.opentelemetry.**")
} }
artifacts { artifacts {

View File

@ -4,6 +4,7 @@ import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.contracts.ScheduledStateRef import net.corda.core.contracts.ScheduledStateRef
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.telemetry.SerializedTelemetry
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import java.security.Principal import java.security.Principal
@ -25,7 +26,8 @@ data class InvocationContext(
val externalTrace: Trace? = null, val externalTrace: Trace? = null,
val impersonatedActor: Actor? = null, val impersonatedActor: Actor? = null,
val arguments: List<Any?>? = emptyList(), // 'arguments' is nullable so that a - >= 4.6 version - RPC client can be backwards compatible against - < 4.6 version - nodes val arguments: List<Any?>? = emptyList(), // 'arguments' is nullable so that a - >= 4.6 version - RPC client can be backwards compatible against - < 4.6 version - nodes
val clientId: String? = null val clientId: String? = null,
val serializedTelemetry: SerializedTelemetry? = null
) { ) {
constructor( constructor(
@ -36,6 +38,16 @@ data class InvocationContext(
impersonatedActor: Actor? = null impersonatedActor: Actor? = null
) : this(origin, trace, actor, externalTrace, impersonatedActor, emptyList()) ) : this(origin, trace, actor, externalTrace, impersonatedActor, emptyList())
constructor(
origin: InvocationOrigin,
trace: Trace,
actor: Actor?,
externalTrace: Trace? = null,
impersonatedActor: Actor? = null,
arguments: List<Any?>? = emptyList(),
clientId: String? = null
) : this(origin, trace, actor, externalTrace, impersonatedActor, arguments, clientId, serializedTelemetry = null)
companion object { companion object {
/** /**
* Creates an [InvocationContext] with a [Trace] that defaults to a [java.util.UUID] as value and [java.time.Instant.now] timestamp. * Creates an [InvocationContext] with a [Trace] that defaults to a [java.util.UUID] as value and [java.time.Instant.now] timestamp.
@ -51,8 +63,9 @@ data class InvocationContext(
externalTrace: Trace? = null, externalTrace: Trace? = null,
impersonatedActor: Actor? = null, impersonatedActor: Actor? = null,
arguments: List<Any?> = emptyList(), arguments: List<Any?> = emptyList(),
clientId: String? = null clientId: String? = null,
) = InvocationContext(origin, trace, actor, externalTrace, impersonatedActor, arguments, clientId) serializedTelemetry: SerializedTelemetry? = null
) = InvocationContext(origin, trace, actor, externalTrace, impersonatedActor, arguments, clientId, serializedTelemetry)
/** /**
* Creates an [InvocationContext] with [InvocationOrigin.RPC] origin. * Creates an [InvocationContext] with [InvocationOrigin.RPC] origin.
@ -60,13 +73,15 @@ data class InvocationContext(
@DeleteForDJVM @DeleteForDJVM
@JvmStatic @JvmStatic
@JvmOverloads @JvmOverloads
@Suppress("LongParameterList")
fun rpc( fun rpc(
actor: Actor, actor: Actor,
trace: Trace = Trace.newInstance(), trace: Trace = Trace.newInstance(),
externalTrace: Trace? = null, externalTrace: Trace? = null,
impersonatedActor: Actor? = null, impersonatedActor: Actor? = null,
arguments: List<Any?> = emptyList() arguments: List<Any?> = emptyList(),
): InvocationContext = newInstance(InvocationOrigin.RPC(actor), trace, actor, externalTrace, impersonatedActor, arguments) serializedTelemetry: SerializedTelemetry? = null
): InvocationContext = newInstance(InvocationOrigin.RPC(actor), trace, actor, externalTrace, impersonatedActor, arguments, serializedTelemetry = serializedTelemetry)
/** /**
* Creates an [InvocationContext] with [InvocationOrigin.Peer] origin. * Creates an [InvocationContext] with [InvocationOrigin.Peer] origin.
@ -119,6 +134,28 @@ data class InvocationContext(
clientId = clientId clientId = clientId
) )
} }
@Suppress("LongParameterList")
fun copy(
origin: InvocationOrigin = this.origin,
trace: Trace = this.trace,
actor: Actor? = this.actor,
externalTrace: Trace? = this.externalTrace,
impersonatedActor: Actor? = this.impersonatedActor,
arguments: List<Any?>? = this.arguments,
clientId: String? = this.clientId
): InvocationContext {
return copy(
origin = origin,
trace = trace,
actor = actor,
externalTrace = externalTrace,
impersonatedActor = impersonatedActor,
arguments = arguments,
clientId = clientId,
serializedTelemetry = serializedTelemetry
)
}
} }
/** /**

View File

@ -1,5 +1,6 @@
package net.corda.core.contracts package net.corda.core.contracts
import net.corda.core.CordaInternal
import net.corda.core.DoNotImplement import net.corda.core.DoNotImplement
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint.isSatisfiedBy import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint.isSatisfiedBy
@ -7,6 +8,8 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.isFulfilledBy import net.corda.core.crypto.isFulfilledBy
import net.corda.core.internal.AttachmentWithContext import net.corda.core.internal.AttachmentWithContext
import net.corda.core.internal.isUploaderTrusted import net.corda.core.internal.isUploaderTrusted
import net.corda.core.internal.utilities.Internable
import net.corda.core.internal.utilities.PrivateInterner
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
@ -120,8 +123,17 @@ data class SignatureAttachmentConstraint(val key: PublicKey) : AttachmentConstra
return if (!key.isFulfilledBy(attachment.signerKeys.map { it })) { return if (!key.isFulfilledBy(attachment.signerKeys.map { it })) {
if (!disableWarnings) log.warn("Untrusted signing key: expected $key. but contract attachment contains ${attachment.signerKeys}") if (!disableWarnings) log.warn("Untrusted signing key: expected $key. but contract attachment contains ${attachment.signerKeys}")
false false
} } else true
else true }
companion object : Internable<SignatureAttachmentConstraint> {
@CordaInternal
override val interner = PrivateInterner<SignatureAttachmentConstraint>()
/**
* Factory method to be used in preference to the constructor.
*/
fun create(key: PublicKey) = interner.intern(SignatureAttachmentConstraint(key))
} }
} }

View File

@ -6,6 +6,7 @@ import net.corda.core.cordapp.Cordapp.Info.*
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.internal.cordapp.CordappImpl.Companion.UNKNOWN_VALUE import net.corda.core.internal.cordapp.CordappImpl.Companion.UNKNOWN_VALUE
import net.corda.core.internal.telemetry.TelemetryComponent
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
import net.corda.core.serialization.CheckpointCustomSerializer import net.corda.core.serialization.CheckpointCustomSerializer
import net.corda.core.serialization.SerializationCustomSerializer import net.corda.core.serialization.SerializationCustomSerializer
@ -49,6 +50,7 @@ interface Cordapp {
val serviceFlows: List<Class<out FlowLogic<*>>> val serviceFlows: List<Class<out FlowLogic<*>>>
val schedulableFlows: List<Class<out FlowLogic<*>>> val schedulableFlows: List<Class<out FlowLogic<*>>>
val services: List<Class<out SerializeAsToken>> val services: List<Class<out SerializeAsToken>>
val telemetryComponents: List<Class<out TelemetryComponent>>
val serializationWhitelists: List<SerializationWhitelist> val serializationWhitelists: List<SerializationWhitelist>
val serializationCustomSerializers: List<SerializationCustomSerializer<*, *>> val serializationCustomSerializers: List<SerializationCustomSerializer<*, *>>
val checkpointCustomSerializers: List<CheckpointCustomSerializer<*, *>> val checkpointCustomSerializers: List<CheckpointCustomSerializer<*, *>>

View File

@ -3,7 +3,13 @@ package net.corda.core.crypto
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.serialization.deserialize import net.corda.core.serialization.deserialize
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.security.* import java.security.InvalidAlgorithmParameterException
import java.security.InvalidKeyException
import java.security.PrivateKey
import java.security.Provider
import java.security.PublicKey
import java.security.Signature
import java.security.SignatureException
import java.security.spec.AlgorithmParameterSpec import java.security.spec.AlgorithmParameterSpec
/** /**
@ -80,7 +86,7 @@ class CompositeSignature : Signature(SIGNATURE_ALGORITHM) {
fun engineVerify(sigBytes: ByteArray): Boolean { fun engineVerify(sigBytes: ByteArray): Boolean {
val sig = sigBytes.deserialize<CompositeSignaturesWithKeys>() val sig = sigBytes.deserialize<CompositeSignaturesWithKeys>()
return if (verifyKey.isFulfilledBy(sig.sigs.map { it.by })) { return if (verifyKey.isFulfilledBy(sig.sigs.map { it.by })) {
val clearData = SecureHash.SHA256(buffer.toByteArray()) val clearData = SecureHash.createSHA256(buffer.toByteArray())
sig.sigs.all { it.isValid(clearData) } sig.sigs.all { it.isValid(clearData) }
} else { } else {
false false

View File

@ -5,11 +5,12 @@ import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.crypto.internal.AliasPrivateKey import net.corda.core.crypto.internal.AliasPrivateKey
import net.corda.core.crypto.internal.Instances.withSignature import net.corda.core.crypto.internal.Instances.withSignature
import net.corda.core.crypto.internal.`id-Curve25519ph`
import net.corda.core.crypto.internal.bouncyCastlePQCProvider import net.corda.core.crypto.internal.bouncyCastlePQCProvider
import net.corda.core.crypto.internal.cordaBouncyCastleProvider import net.corda.core.crypto.internal.cordaBouncyCastleProvider
import net.corda.core.crypto.internal.cordaSecurityProvider import net.corda.core.crypto.internal.cordaSecurityProvider
import net.corda.core.crypto.internal.`id-Curve25519ph`
import net.corda.core.crypto.internal.providerMap import net.corda.core.crypto.internal.providerMap
import net.corda.core.internal.utilities.PrivateInterner
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.i2p.crypto.eddsa.EdDSAEngine import net.i2p.crypto.eddsa.EdDSAEngine
import net.i2p.crypto.eddsa.EdDSAPrivateKey import net.i2p.crypto.eddsa.EdDSAPrivateKey
@ -710,7 +711,8 @@ object Crypto {
keyPairGenerator.initialize(signatureScheme.algSpec, newSecureRandom()) keyPairGenerator.initialize(signatureScheme.algSpec, newSecureRandom())
else else
keyPairGenerator.initialize(signatureScheme.keySize!!, newSecureRandom()) keyPairGenerator.initialize(signatureScheme.keySize!!, newSecureRandom())
return keyPairGenerator.generateKeyPair() val newKeyPair = keyPairGenerator.generateKeyPair()
return KeyPair(internPublicKey(newKeyPair.public), newKeyPair.private)
} }
/** /**
@ -840,7 +842,7 @@ object Crypto {
val publicKeySpec = ECPublicKeySpec(pointQ, parameterSpec) val publicKeySpec = ECPublicKeySpec(pointQ, parameterSpec)
val publicKeyD = BCECPublicKey(privateKey.algorithm, publicKeySpec, BouncyCastleProvider.CONFIGURATION) val publicKeyD = BCECPublicKey(privateKey.algorithm, publicKeySpec, BouncyCastleProvider.CONFIGURATION)
return KeyPair(publicKeyD, privateKeyD) return KeyPair(internPublicKey(publicKeyD), privateKeyD)
} }
// Deterministically generate an EdDSA key. // Deterministically generate an EdDSA key.
@ -853,7 +855,7 @@ object Crypto {
val bytes = macBytes.copyOf(params.curve.field.getb() / 8) // Need to pad the entropy to the valid seed length. val bytes = macBytes.copyOf(params.curve.field.getb() / 8) // Need to pad the entropy to the valid seed length.
val privateKeyD = EdDSAPrivateKeySpec(bytes, params) val privateKeyD = EdDSAPrivateKeySpec(bytes, params)
val publicKeyD = EdDSAPublicKeySpec(privateKeyD.a, params) val publicKeyD = EdDSAPublicKeySpec(privateKeyD.a, params)
return KeyPair(EdDSAPublicKey(publicKeyD), EdDSAPrivateKey(privateKeyD)) return KeyPair(internPublicKey(EdDSAPublicKey(publicKeyD)), EdDSAPrivateKey(privateKeyD))
} }
/** /**
@ -892,7 +894,7 @@ object Crypto {
val bytes = entropy.toByteArray().copyOf(params.curve.field.getb() / 8) // Need to pad the entropy to the valid seed length. val bytes = entropy.toByteArray().copyOf(params.curve.field.getb() / 8) // Need to pad the entropy to the valid seed length.
val priv = EdDSAPrivateKeySpec(bytes, params) val priv = EdDSAPrivateKeySpec(bytes, params)
val pub = EdDSAPublicKeySpec(priv.a, params) val pub = EdDSAPublicKeySpec(priv.a, params)
return KeyPair(EdDSAPublicKey(pub), EdDSAPrivateKey(priv)) return KeyPair(internPublicKey(EdDSAPublicKey(pub)), EdDSAPrivateKey(priv))
} }
// Custom key pair generator from an entropy required for various tests. It is similar to deriveKeyPairECDSA, // Custom key pair generator from an entropy required for various tests. It is similar to deriveKeyPairECDSA,
@ -918,7 +920,7 @@ object Crypto {
val publicKeySpec = ECPublicKeySpec(pointQ, parameterSpec) val publicKeySpec = ECPublicKeySpec(pointQ, parameterSpec)
val pub = BCECPublicKey("EC", publicKeySpec, BouncyCastleProvider.CONFIGURATION) val pub = BCECPublicKey("EC", publicKeySpec, BouncyCastleProvider.CONFIGURATION)
return KeyPair(pub, priv) return KeyPair(internPublicKey(pub), priv)
} }
// Compute the HMAC-SHA512 using a privateKey as the MAC_key and a seed ByteArray. // Compute the HMAC-SHA512 using a privateKey as the MAC_key and a seed ByteArray.
@ -990,11 +992,14 @@ object Crypto {
} }
} }
private val interner = PrivateInterner<PublicKey>()
private fun internPublicKey(key: PublicKey): PublicKey = interner.intern(key)
private fun convertIfBCEdDSAPublicKey(key: PublicKey): PublicKey { private fun convertIfBCEdDSAPublicKey(key: PublicKey): PublicKey {
return when (key) { return internPublicKey(when (key) {
is BCEdDSAPublicKey -> EdDSAPublicKey(X509EncodedKeySpec(key.encoded)) is BCEdDSAPublicKey -> EdDSAPublicKey(X509EncodedKeySpec(key.encoded))
else -> key else -> key
} })
} }
private fun convertIfBCEdDSAPrivateKey(key: PrivateKey): PrivateKey { private fun convertIfBCEdDSAPrivateKey(key: PrivateKey): PrivateKey {
@ -1026,11 +1031,11 @@ object Crypto {
@JvmStatic @JvmStatic
fun toSupportedPublicKey(key: PublicKey): PublicKey { fun toSupportedPublicKey(key: PublicKey): PublicKey {
return when (key) { return when (key) {
is BCECPublicKey -> key is BCECPublicKey -> internPublicKey(key)
is BCRSAPublicKey -> key is BCRSAPublicKey -> internPublicKey(key)
is BCSphincs256PublicKey -> key is BCSphincs256PublicKey -> internPublicKey(key)
is EdDSAPublicKey -> key is EdDSAPublicKey -> internPublicKey(key)
is CompositeKey -> key is CompositeKey -> internPublicKey(key)
is BCEdDSAPublicKey -> convertIfBCEdDSAPublicKey(key) is BCEdDSAPublicKey -> convertIfBCEdDSAPublicKey(key)
else -> decodePublicKey(key.encoded) else -> decodePublicKey(key.encoded)
} }

View File

@ -3,9 +3,12 @@
package net.corda.core.crypto package net.corda.core.crypto
import io.netty.util.concurrent.FastThreadLocal import io.netty.util.concurrent.FastThreadLocal
import net.corda.core.CordaInternal
import net.corda.core.DeleteForDJVM import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.crypto.internal.DigestAlgorithmFactory import net.corda.core.crypto.internal.DigestAlgorithmFactory
import net.corda.core.internal.utilities.Internable
import net.corda.core.internal.utilities.PrivateInterner
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.parseAsHex import net.corda.core.utilities.parseAsHex
@ -66,7 +69,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
} }
override fun generate(data: ByteArray): SecureHash { override fun generate(data: ByteArray): SecureHash {
return HASH(algorithm, digestAs(algorithm, data)) return interner.intern(HASH(algorithm, digestAs(algorithm, data)))
} }
} }
@ -110,7 +113,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
return if(concatAlgorithm == SHA2_256) { return if(concatAlgorithm == SHA2_256) {
concatBytes.sha256() concatBytes.sha256()
} else { } else {
HASH(concatAlgorithm, digestAs(concatAlgorithm, concatBytes)) interner.intern(HASH(concatAlgorithm, digestAs(concatAlgorithm, concatBytes)))
} }
} }
@ -121,12 +124,15 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
fun reHash() : SecureHash = hashAs(algorithm, bytes) fun reHash() : SecureHash = hashAs(algorithm, bytes)
// Like static methods in Java, except the 'companion' is a singleton that can have state. // Like static methods in Java, except the 'companion' is a singleton that can have state.
companion object { companion object : Internable<SecureHash> {
const val SHA2_256 = "SHA-256" const val SHA2_256 = "SHA-256"
const val SHA2_384 = "SHA-384" const val SHA2_384 = "SHA-384"
const val SHA2_512 = "SHA-512" const val SHA2_512 = "SHA-512"
const val DELIMITER = ':' const val DELIMITER = ':'
@CordaInternal
override val interner = PrivateInterner<SecureHash>()
/** /**
* Converts a SecureHash hash value represented as a {algorithm:}hexadecimal [String] into a [SecureHash]. * Converts a SecureHash hash value represented as a {algorithm:}hexadecimal [String] into a [SecureHash].
* @param str An optional algorithm id followed by a delimiter and the sequence of hexadecimal digits that represents a hash value. * @param str An optional algorithm id followed by a delimiter and the sequence of hexadecimal digits that represents a hash value.
@ -149,6 +155,14 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
} }
} }
@JvmStatic
internal fun deintern(hash: SecureHash): SecureHash {
return when (hash) {
is SHA256 -> SHA256(hash.bytes)
else -> HASH(hash.algorithm, hash.bytes)
}
}
/** /**
* @param algorithm [MessageDigest] algorithm name, in uppercase. * @param algorithm [MessageDigest] algorithm name, in uppercase.
* @param value Hash value as a hexadecimal string. * @param value Hash value as a hexadecimal string.
@ -157,7 +171,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
val digestLength = digestFor(algorithm).digestLength val digestLength = digestFor(algorithm).digestLength
val data = value.parseAsHex() val data = value.parseAsHex()
return when (data.size) { return when (data.size) {
digestLength -> HASH(algorithm, data) digestLength -> interner.intern(HASH(algorithm, data))
else -> throw IllegalArgumentException("Provided string is ${data.size} bytes not $digestLength bytes in hex: $value") else -> throw IllegalArgumentException("Provided string is ${data.size} bytes not $digestLength bytes in hex: $value")
} }
} }
@ -171,12 +185,18 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
fun parse(str: String?): SHA256 { fun parse(str: String?): SHA256 {
return str?.toUpperCase()?.parseAsHex()?.let { return str?.toUpperCase()?.parseAsHex()?.let {
when (it.size) { when (it.size) {
32 -> SHA256(it) 32 -> interner.intern(SHA256(it))
else -> throw IllegalArgumentException("Provided string is ${it.size} bytes not 32 bytes in hex: $str") else -> throw IllegalArgumentException("Provided string is ${it.size} bytes not 32 bytes in hex: $str")
} }
} ?: throw IllegalArgumentException("Provided string is null") } ?: throw IllegalArgumentException("Provided string is null")
} }
/**
* Factory method for SHA256 to be used in preference to the constructor.
*/
@JvmStatic
fun createSHA256(bytes: ByteArray): SHA256 = interner.intern(SHA256(bytes))
private val messageDigests: ConcurrentMap<String, DigestSupplier> = ConcurrentHashMap() private val messageDigests: ConcurrentMap<String, DigestSupplier> = ConcurrentHashMap()
private fun digestFor(algorithm: String): DigestSupplier { private fun digestFor(algorithm: String): DigestSupplier {
@ -202,9 +222,9 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
fun hashAs(algorithm: String, bytes: ByteArray): SecureHash { fun hashAs(algorithm: String, bytes: ByteArray): SecureHash {
val hashBytes = digestAs(algorithm, bytes) val hashBytes = digestAs(algorithm, bytes)
return if (algorithm == SHA2_256) { return if (algorithm == SHA2_256) {
SHA256(hashBytes) interner.intern(SHA256(hashBytes))
} else { } else {
HASH(algorithm, hashBytes) interner.intern(HASH(algorithm, hashBytes))
} }
} }
@ -222,7 +242,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
} else { } else {
val digest = digestFor(algorithm).get() val digest = digestFor(algorithm).get()
val hash = digest.componentDigest(bytes) val hash = digest.componentDigest(bytes)
HASH(algorithm, hash) interner.intern(HASH(algorithm, hash))
} }
} }
@ -240,7 +260,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
} else { } else {
val digest = digestFor(algorithm).get() val digest = digestFor(algorithm).get()
val hash = digest.nonceDigest(bytes) val hash = digest.nonceDigest(bytes)
HASH(algorithm, hash) interner.intern(HASH(algorithm, hash))
} }
} }
@ -249,7 +269,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
* @param bytes The [ByteArray] to hash. * @param bytes The [ByteArray] to hash.
*/ */
@JvmStatic @JvmStatic
fun sha256(bytes: ByteArray) = SHA256(digestAs(SHA2_256, bytes)) fun sha256(bytes: ByteArray) = interner.intern(SHA256(digestAs(SHA2_256, bytes)))
/** /**
* Computes the SHA-256 hash of the [ByteArray], and then computes the SHA-256 hash of the hash. * Computes the SHA-256 hash of the [ByteArray], and then computes the SHA-256 hash of the hash.
@ -282,7 +302,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
randomSHA256() randomSHA256()
} else { } else {
val digest = digestFor(algorithm) val digest = digestFor(algorithm)
HASH(algorithm, digest.get().digest(secureRandomBytes(digest.digestLength))) interner.intern(HASH(algorithm, digest.get().digest(secureRandomBytes(digest.digestLength))))
} }
} }
@ -291,7 +311,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
* This field provides more intuitive access from Java. * This field provides more intuitive access from Java.
*/ */
@JvmField @JvmField
val zeroHash: SHA256 = SHA256(ByteArray(32) { 0.toByte() }) val zeroHash: SHA256 = interner.intern(SHA256(ByteArray(32) { 0.toByte() }))
/** /**
* A SHA-256 hash value consisting of 32 0x00 bytes. * A SHA-256 hash value consisting of 32 0x00 bytes.
@ -305,7 +325,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
* This field provides more intuitive access from Java. * This field provides more intuitive access from Java.
*/ */
@JvmField @JvmField
val allOnesHash: SHA256 = SHA256(ByteArray(32) { 255.toByte() }) val allOnesHash: SHA256 = interner.intern(SHA256(ByteArray(32) { 255.toByte() }))
/** /**
* A SHA-256 hash value consisting of 32 0xFF bytes. * A SHA-256 hash value consisting of 32 0xFF bytes.
@ -323,8 +343,8 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
return hashConstants.getOrPut(algorithm) { return hashConstants.getOrPut(algorithm) {
val digestLength = digestFor(algorithm).digestLength val digestLength = digestFor(algorithm).digestLength
HashConstants( HashConstants(
zero = HASH(algorithm, ByteArray(digestLength)), zero = interner.intern(HASH(algorithm, ByteArray(digestLength))),
allOnes = HASH(algorithm, ByteArray(digestLength) { 255.toByte() }) allOnes = interner.intern(HASH(algorithm, ByteArray(digestLength) { 255.toByte() }))
) )
} }
} }

View File

@ -7,6 +7,7 @@ import net.corda.core.crypto.isFulfilledBy
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.groupAbstractPartyByWellKnownParty import net.corda.core.identity.groupAbstractPartyByWellKnownParty
import net.corda.core.internal.pushToLoggingContext import net.corda.core.internal.pushToLoggingContext
import net.corda.core.internal.telemetry.telemetryServiceInternal
import net.corda.core.internal.warnOnce import net.corda.core.internal.warnOnce
import net.corda.core.node.StatesToRecord import net.corda.core.node.StatesToRecord
import net.corda.core.node.StatesToRecord.ONLY_RELEVANT import net.corda.core.node.StatesToRecord.ONLY_RELEVANT
@ -221,18 +222,22 @@ class FinalityFlow private constructor(val transaction: SignedTransaction,
@Suspendable @Suspendable
private fun notariseAndRecord(): SignedTransaction { private fun notariseAndRecord(): SignedTransaction {
val notarised = if (needsNotarySignature(transaction)) { serviceHub.telemetryServiceInternal.span("${this::class.java.name}#notariseAndRecord", flowLogic = this) {
progressTracker.currentStep = NOTARISING val notarised = if (needsNotarySignature(transaction)) {
val notarySignatures = subFlow(NotaryFlow.Client(transaction, skipVerification = true)) progressTracker.currentStep = NOTARISING
transaction + notarySignatures val notarySignatures = subFlow(NotaryFlow.Client(transaction, skipVerification = true))
} else { transaction + notarySignatures
logger.info("No need to notarise this transaction.") } else {
transaction logger.info("No need to notarise this transaction.")
transaction
}
serviceHub.telemetryServiceInternal.span("${this::class.java.name}#notariseAndRecord:recordTransactions", flowLogic = this) {
logger.info("Recording transaction locally.")
serviceHub.recordTransactions(statesToRecord, listOf(notarised))
logger.info("Recorded transaction locally successfully.")
}
return notarised
} }
logger.info("Recording transaction locally.")
serviceHub.recordTransactions(statesToRecord, listOf(notarised))
logger.info("Recorded transaction locally successfully.")
return notarised
} }
private fun needsNotarySignature(stx: SignedTransaction): Boolean { private fun needsNotarySignature(stx: SignedTransaction): Boolean {

View File

@ -16,6 +16,7 @@ import net.corda.core.internal.ServiceHubCoreInternal
import net.corda.core.internal.WaitForStateConsumption import net.corda.core.internal.WaitForStateConsumption
import net.corda.core.internal.abbreviate import net.corda.core.internal.abbreviate
import net.corda.core.internal.checkPayloadIs import net.corda.core.internal.checkPayloadIs
import net.corda.core.internal.telemetry.telemetryServiceInternal
import net.corda.core.internal.uncheckedCast import net.corda.core.internal.uncheckedCast
import net.corda.core.messaging.DataFeed import net.corda.core.messaging.DataFeed
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
@ -157,7 +158,7 @@ abstract class FlowLogic<out T> {
fun initiateFlow(destination: Destination): FlowSession { fun initiateFlow(destination: Destination): FlowSession {
require(destination is Party || destination is AnonymousParty) { "Unsupported destination type ${destination.javaClass.name}" } require(destination is Party || destination is AnonymousParty) { "Unsupported destination type ${destination.javaClass.name}" }
return stateMachine.initiateFlow(destination, serviceHub.identityService.wellKnownPartyFromAnonymous(destination as AbstractParty) return stateMachine.initiateFlow(destination, serviceHub.identityService.wellKnownPartyFromAnonymous(destination as AbstractParty)
?: throw IllegalArgumentException("Could not resolve destination: $destination")) ?: throw IllegalArgumentException("Could not resolve destination: $destination"), serviceHub.telemetryServiceInternal.getCurrentTelemetryData())
} }
/** /**
@ -165,7 +166,7 @@ abstract class FlowLogic<out T> {
* that this function does not communicate in itself, the counter-flow will be kicked off by the first send/receive. * that this function does not communicate in itself, the counter-flow will be kicked off by the first send/receive.
*/ */
@Suspendable @Suspendable
fun initiateFlow(party: Party): FlowSession = stateMachine.initiateFlow(party, party) fun initiateFlow(party: Party): FlowSession = stateMachine.initiateFlow(party, party, serviceHub.telemetryServiceInternal.getCurrentTelemetryData())
/** /**
* Specifies the identity, with certificate, to use for this flow. This will be one of the multiple identities that * Specifies the identity, with certificate, to use for this flow. This will be one of the multiple identities that
@ -285,11 +286,13 @@ abstract class FlowLogic<out T> {
@Suspendable @Suspendable
internal fun <R : Any> FlowSession.sendAndReceiveWithRetry(receiveType: Class<R>, payload: Any): UntrustworthyData<R> { internal fun <R : Any> FlowSession.sendAndReceiveWithRetry(receiveType: Class<R>, payload: Any): UntrustworthyData<R> {
val request = FlowIORequest.SendAndReceive( serviceHub.telemetryServiceInternal.span("${this::class.java.name}#sendAndReceiveWithRetry", mapOf("destination" to destination.toString())) {
sessionToMessage = stateMachine.serialize(mapOf(this to payload)), val request = FlowIORequest.SendAndReceive(
shouldRetrySend = true sessionToMessage = stateMachine.serialize(mapOf(this to payload)),
) shouldRetrySend = true
return stateMachine.suspend(request, maySkipCheckpoint = false)[this]!!.checkPayloadIs(receiveType) )
return stateMachine.suspend(request, maySkipCheckpoint = false)[this]!!.checkPayloadIs(receiveType)
}
} }
@Suspendable @Suspendable
@ -310,12 +313,14 @@ abstract class FlowLogic<out T> {
@Suspendable @Suspendable
@JvmOverloads @JvmOverloads
open fun receiveAllMap(sessions: Map<FlowSession, Class<out Any>>, maySkipCheckpoint: Boolean = false): Map<FlowSession, UntrustworthyData<Any>> { open fun receiveAllMap(sessions: Map<FlowSession, Class<out Any>>, maySkipCheckpoint: Boolean = false): Map<FlowSession, UntrustworthyData<Any>> {
enforceNoPrimitiveInReceive(sessions.values) serviceHub.telemetryServiceInternal.span("${this::class.java.name}#receiveAllMap") {
val replies = stateMachine.suspend( enforceNoPrimitiveInReceive(sessions.values)
ioRequest = FlowIORequest.Receive(sessions.keys.toNonEmptySet()), val replies = stateMachine.suspend(
maySkipCheckpoint = maySkipCheckpoint ioRequest = FlowIORequest.Receive(sessions.keys.toNonEmptySet()),
) maySkipCheckpoint = maySkipCheckpoint
return replies.mapValues { (session, payload) -> payload.checkPayloadIs(sessions[session]!!) } )
return replies.mapValues { (session, payload) -> payload.checkPayloadIs(sessions[session]!!) }
}
} }
/** /**
@ -332,9 +337,11 @@ abstract class FlowLogic<out T> {
@Suspendable @Suspendable
@JvmOverloads @JvmOverloads
open fun <R : Any> receiveAll(receiveType: Class<R>, sessions: List<FlowSession>, maySkipCheckpoint: Boolean = false): List<UntrustworthyData<R>> { open fun <R : Any> receiveAll(receiveType: Class<R>, sessions: List<FlowSession>, maySkipCheckpoint: Boolean = false): List<UntrustworthyData<R>> {
enforceNoPrimitiveInReceive(listOf(receiveType)) serviceHub.telemetryServiceInternal.span("${this::class.java.name}#receiveAll") {
enforceNoDuplicates(sessions) enforceNoPrimitiveInReceive(listOf(receiveType))
return castMapValuesToKnownType(receiveAllMap(associateSessionsToReceiveType(receiveType, sessions))) enforceNoDuplicates(sessions)
return castMapValuesToKnownType(receiveAllMap(associateSessionsToReceiveType(receiveType, sessions)))
}
} }
/** /**
@ -351,8 +358,10 @@ abstract class FlowLogic<out T> {
@Suspendable @Suspendable
@JvmOverloads @JvmOverloads
fun sendAll(payload: Any, sessions: Set<FlowSession>, maySkipCheckpoint: Boolean = false) { fun sendAll(payload: Any, sessions: Set<FlowSession>, maySkipCheckpoint: Boolean = false) {
val sessionToPayload = sessions.map { it to payload }.toMap() serviceHub.telemetryServiceInternal.span("${this::class.java.name}#sendAll") {
return sendAllMap(sessionToPayload, maySkipCheckpoint) val sessionToPayload = sessions.map { it to payload }.toMap()
return sendAllMap(sessionToPayload, maySkipCheckpoint)
}
} }
/** /**
@ -368,10 +377,12 @@ abstract class FlowLogic<out T> {
@Suspendable @Suspendable
@JvmOverloads @JvmOverloads
fun sendAllMap(payloadsPerSession: Map<FlowSession, Any>, maySkipCheckpoint: Boolean = false) { fun sendAllMap(payloadsPerSession: Map<FlowSession, Any>, maySkipCheckpoint: Boolean = false) {
val request = FlowIORequest.Send( serviceHub.telemetryServiceInternal.span("${this::class.java.name}#sendAllMap") {
sessionToMessage = stateMachine.serialize(payloadsPerSession) val request = FlowIORequest.Send(
) sessionToMessage = stateMachine.serialize(payloadsPerSession)
stateMachine.suspend(request, maySkipCheckpoint) )
stateMachine.suspend(request, maySkipCheckpoint)
}
} }
/** /**

View File

@ -5,7 +5,6 @@ import net.corda.core.CordaInternal
import net.corda.core.DoNotImplement import net.corda.core.DoNotImplement
import net.corda.core.contracts.StateRef import net.corda.core.contracts.StateRef
import net.corda.core.contracts.TimeWindow import net.corda.core.contracts.TimeWindow
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.TransactionSignature import net.corda.core.crypto.TransactionSignature
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.BackpressureAwareTimedFlow import net.corda.core.internal.BackpressureAwareTimedFlow
@ -174,8 +173,7 @@ class NotaryFlow {
* same transaction. * same transaction.
*/ */
private fun generateRequestSignature(): NotarisationRequestSignature { private fun generateRequestSignature(): NotarisationRequestSignature {
// TODO: This is not required any more once our AMQP serialization supports turning off object referencing. val notarisationRequest = NotarisationRequest(stx.inputs, stx.id)
val notarisationRequest = NotarisationRequest(stx.inputs.map { it.copy(txhash = SecureHash.create(it.txhash.toString())) }, stx.id)
return notarisationRequest.generateSignature(serviceHub) return notarisationRequest.generateSignature(serviceHub)
} }
} }

View File

@ -34,7 +34,9 @@ class NotarisationRequest(statesToConsume: List<StateRef>, val transactionId: Se
private val stateRefComparator = compareBy<StateRef>({ it.txhash }, { it.index }) private val stateRefComparator = compareBy<StateRef>({ it.txhash }, { it.index })
} }
// For compatibility reasons, each SecureHash has to be distinct, even if for same value.
private val _statesToConsumeSorted = statesToConsume.sortedWith(stateRefComparator) private val _statesToConsumeSorted = statesToConsume.sortedWith(stateRefComparator)
.map { StateRef(SecureHash.deintern(it.txhash), it.index) }
/** States this request specifies to be consumed. Sorted to ensure the serialized form does not get affected by the state order. */ /** States this request specifies to be consumed. Sorted to ensure the serialized form does not get affected by the state order. */
val statesToConsume: List<StateRef> get() = _statesToConsumeSorted // Getter required for AMQP serialization val statesToConsume: List<StateRef> get() = _statesToConsumeSorted // Getter required for AMQP serialization

View File

@ -1,8 +1,12 @@
package net.corda.core.identity package net.corda.core.identity
import net.corda.core.CordaInternal
import net.corda.core.DoNotImplement import net.corda.core.DoNotImplement
import net.corda.core.contracts.PartyAndReference import net.corda.core.contracts.PartyAndReference
import net.corda.core.flows.Destination import net.corda.core.flows.Destination
import net.corda.core.internal.utilities.Internable
import net.corda.core.internal.utilities.IternabilityVerifier
import net.corda.core.internal.utilities.PrivateInterner
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import java.security.PublicKey import java.security.PublicKey
@ -31,4 +35,15 @@ abstract class AbstractParty(val owningKey: PublicKey): Destination {
* ledger. * ledger.
*/ */
fun ref(vararg bytes: Byte) = ref(OpaqueBytes.of(*bytes)) fun ref(vararg bytes: Byte) = ref(OpaqueBytes.of(*bytes))
@CordaInternal
companion object : Internable<AbstractParty> {
@CordaInternal
override val interner = PrivateInterner<AbstractParty>(object : IternabilityVerifier<AbstractParty> {
override fun choose(original: AbstractParty, interned: AbstractParty): AbstractParty {
// Because Party does not compare name in equals(), don't intern if there's a clash
return if (original.nameOrNull() != interned.nameOrNull()) original else interned
}
})
}
} }

View File

@ -22,4 +22,11 @@ class AnonymousParty(owningKey: PublicKey) : Destination, AbstractParty(owningKe
override fun nameOrNull(): CordaX500Name? = null override fun nameOrNull(): CordaX500Name? = null
override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this, bytes) override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this, bytes)
override fun toString() = "Anonymous(${owningKey.toStringShort()})" override fun toString() = "Anonymous(${owningKey.toStringShort()})"
companion object {
/**
* Factory method to be used in preference to the constructor.
*/
fun create(owningKey: PublicKey): AnonymousParty = interner.intern(AnonymousParty(owningKey))
}
} }

View File

@ -1,10 +1,13 @@
package net.corda.core.identity package net.corda.core.identity
import net.corda.core.CordaInternal
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.internal.LegalNameValidator import net.corda.core.internal.LegalNameValidator
import net.corda.core.internal.toAttributesMap import net.corda.core.internal.toAttributesMap
import net.corda.core.internal.toX500Name import net.corda.core.internal.toX500Name
import net.corda.core.internal.unspecifiedCountry import net.corda.core.internal.unspecifiedCountry
import net.corda.core.internal.utilities.Internable
import net.corda.core.internal.utilities.PrivateInterner
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import org.bouncycastle.asn1.x500.style.BCStyle import org.bouncycastle.asn1.x500.style.BCStyle
import java.util.* import java.util.*
@ -68,7 +71,7 @@ data class CordaX500Name(val commonName: String?,
} }
} }
companion object { companion object : Internable<CordaX500Name> {
@Deprecated("Not Used") @Deprecated("Not Used")
const val LENGTH_COUNTRY = 2 const val LENGTH_COUNTRY = 2
const val MAX_LENGTH_ORGANISATION = 128 const val MAX_LENGTH_ORGANISATION = 128
@ -80,6 +83,9 @@ data class CordaX500Name(val commonName: String?,
private val supportedAttributes = setOf(BCStyle.O, BCStyle.C, BCStyle.L, BCStyle.CN, BCStyle.ST, BCStyle.OU) private val supportedAttributes = setOf(BCStyle.O, BCStyle.C, BCStyle.L, BCStyle.CN, BCStyle.ST, BCStyle.OU)
private val countryCodes: Set<String> = setOf(*Locale.getISOCountries(), unspecifiedCountry) private val countryCodes: Set<String> = setOf(*Locale.getISOCountries(), unspecifiedCountry)
@CordaInternal
override val interner = PrivateInterner<CordaX500Name>()
@JvmStatic @JvmStatic
fun build(principal: X500Principal): CordaX500Name { fun build(principal: X500Principal): CordaX500Name {
val attrsMap = principal.toAttributesMap(supportedAttributes) val attrsMap = principal.toAttributesMap(supportedAttributes)
@ -89,7 +95,7 @@ data class CordaX500Name(val commonName: String?,
val L = requireNotNull(attrsMap[BCStyle.L]) { "Corda X.500 names must include an L attribute" } val L = requireNotNull(attrsMap[BCStyle.L]) { "Corda X.500 names must include an L attribute" }
val ST = attrsMap[BCStyle.ST] val ST = attrsMap[BCStyle.ST]
val C = requireNotNull(attrsMap[BCStyle.C]) { "Corda X.500 names must include an C attribute" } val C = requireNotNull(attrsMap[BCStyle.C]) { "Corda X.500 names must include an C attribute" }
return CordaX500Name(CN, OU, O, L, ST, C) return interner.intern(CordaX500Name(CN, OU, O, L, ST, C))
} }
@JvmStatic @JvmStatic

View File

@ -45,4 +45,16 @@ class Party(val name: CordaX500Name, owningKey: PublicKey) : Destination, Abstra
override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this, bytes) override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this, bytes)
override fun toString() = name.toString() override fun toString() = name.toString()
fun description() = "$name (owningKey = ${owningKey.toStringShort()})" fun description() = "$name (owningKey = ${owningKey.toStringShort()})"
companion object {
/**
* Factory method to be used in preference to the constructor.
*/
fun create(name: CordaX500Name, owningKey: PublicKey): Party = interner.intern(Party(name, owningKey))
/**
* Factory method to be used in preference to the constructor.
*/
fun create(certificate: X509Certificate): Party = interner.intern(Party(certificate))
}
} }

View File

@ -6,7 +6,11 @@ import net.corda.core.internal.uncheckedCast
import net.corda.core.internal.validate import net.corda.core.internal.validate
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import java.security.PublicKey import java.security.PublicKey
import java.security.cert.* import java.security.cert.CertPath
import java.security.cert.CertPathValidatorException
import java.security.cert.PKIXCertPathValidatorResult
import java.security.cert.TrustAnchor
import java.security.cert.X509Certificate
/** /**
* A full party plus the X.509 certificate and path linking the party back to a trust root. Equality of * A full party plus the X.509 certificate and path linking the party back to a trust root. Equality of
@ -29,7 +33,7 @@ class PartyAndCertificate(val certPath: CertPath) {
} }
@Transient @Transient
val party: Party = Party(certificate) val party: Party = Party.create(certificate)
val owningKey: PublicKey get() = party.owningKey val owningKey: PublicKey get() = party.owningKey
val name: CordaX500Name get() = party.name val name: CordaX500Name get() = party.name

View File

@ -30,7 +30,7 @@ import java.util.jar.JarInputStream
// When incrementing platformVersion make sure to update PLATFORM_VERSION in constants.properties as well. // When incrementing platformVersion make sure to update PLATFORM_VERSION in constants.properties as well.
const val PLATFORM_VERSION = 11 const val PLATFORM_VERSION = 12
fun ServicesForResolution.ensureMinimumPlatformVersion(requiredMinPlatformVersion: Int, feature: String) { fun ServicesForResolution.ensureMinimumPlatformVersion(requiredMinPlatformVersion: Int, feature: String) {
checkMinimumPlatformVersion(networkParameters.minimumPlatformVersion, requiredMinPlatformVersion, feature) checkMinimumPlatformVersion(networkParameters.minimumPlatformVersion, requiredMinPlatformVersion, feature)

View File

@ -8,6 +8,7 @@ import net.corda.core.context.InvocationContext
import net.corda.core.flows.* import net.corda.core.flows.*
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.node.ServiceHub import net.corda.core.node.ServiceHub
import net.corda.core.internal.telemetry.SerializedTelemetry
import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.SerializedBytes
import org.slf4j.Logger import org.slf4j.Logger
@ -30,7 +31,7 @@ interface FlowStateMachine<FLOWRETURN> : FlowStateMachineHandle<FLOWRETURN> {
fun serialize(payloads: Map<FlowSession, Any>): Map<FlowSession, SerializedBytes<Any>> fun serialize(payloads: Map<FlowSession, Any>): Map<FlowSession, SerializedBytes<Any>>
@Suspendable @Suspendable
fun initiateFlow(destination: Destination, wellKnownParty: Party): FlowSession fun initiateFlow(destination: Destination, wellKnownParty: Party, serializedTelemetry: SerializedTelemetry?): FlowSession
fun checkFlowPermission(permissionName: String, extraAuditData: Map<String, String>) fun checkFlowPermission(permissionName: String, extraAuditData: Map<String, String>)

View File

@ -77,7 +77,6 @@ import java.util.stream.StreamSupport
import java.util.zip.Deflater import java.util.zip.Deflater
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
import kotlin.collections.LinkedHashSet
import kotlin.math.roundToLong import kotlin.math.roundToLong
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance import kotlin.reflect.full.createInstance
@ -165,7 +164,7 @@ fun InputStream.hash(): SecureHash {
} }
md.update(buffer, 0, count) md.update(buffer, 0, count)
} }
SecureHash.SHA256(md.digest()) SecureHash.createSHA256(md.digest())
} }
} }

View File

@ -8,6 +8,7 @@ import net.corda.core.internal.PLATFORM_VERSION
import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.VisibleForTesting
import net.corda.core.internal.notary.NotaryService import net.corda.core.internal.notary.NotaryService
import net.corda.core.internal.toPath import net.corda.core.internal.toPath
import net.corda.core.internal.telemetry.TelemetryComponent
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
import net.corda.core.serialization.CheckpointCustomSerializer import net.corda.core.serialization.CheckpointCustomSerializer
import net.corda.core.serialization.SerializationCustomSerializer import net.corda.core.serialization.SerializationCustomSerializer
@ -24,6 +25,7 @@ data class CordappImpl(
override val serviceFlows: List<Class<out FlowLogic<*>>>, override val serviceFlows: List<Class<out FlowLogic<*>>>,
override val schedulableFlows: List<Class<out FlowLogic<*>>>, override val schedulableFlows: List<Class<out FlowLogic<*>>>,
override val services: List<Class<out SerializeAsToken>>, override val services: List<Class<out SerializeAsToken>>,
override val telemetryComponents: List<Class<out TelemetryComponent>>,
override val serializationWhitelists: List<SerializationWhitelist>, override val serializationWhitelists: List<SerializationWhitelist>,
override val serializationCustomSerializers: List<SerializationCustomSerializer<*, *>>, override val serializationCustomSerializers: List<SerializationCustomSerializer<*, *>>,
override val checkpointCustomSerializers: List<CheckpointCustomSerializer<*, *>>, override val checkpointCustomSerializers: List<CheckpointCustomSerializer<*, *>>,
@ -79,6 +81,7 @@ data class CordappImpl(
serviceFlows = emptyList(), serviceFlows = emptyList(),
schedulableFlows = emptyList(), schedulableFlows = emptyList(),
services = emptyList(), services = emptyList(),
telemetryComponents = emptyList(),
serializationWhitelists = emptyList(), serializationWhitelists = emptyList(),
serializationCustomSerializers = emptyList(), serializationCustomSerializers = emptyList(),
checkpointCustomSerializers = emptyList(), checkpointCustomSerializers = emptyList(),

View File

@ -10,6 +10,7 @@ import net.corda.core.flows.*
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.PlatformVersionSwitches import net.corda.core.internal.PlatformVersionSwitches
import net.corda.core.internal.checkParameterHash import net.corda.core.internal.checkParameterHash
import net.corda.core.internal.telemetry.telemetryServiceInternal
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
import java.lang.IllegalStateException import java.lang.IllegalStateException
@ -74,14 +75,15 @@ abstract class NotaryServiceFlow(
sleep(Duration.ZERO) sleep(Duration.ZERO)
} }
} }
serviceHub.telemetryServiceInternal.span("${this::class.java.name}#call:commitInputStates", flowLogic = this) {
service.commitInputStates( service.commitInputStates(
tx.inputs, tx.inputs,
tx.id, tx.id,
otherSideSession.counterparty, otherSideSession.counterparty,
requestPayload.requestSignature, requestPayload.requestSignature,
tx.timeWindow, tx.timeWindow,
tx.references) tx.references)
}
} catch (e: NotaryInternalException) { } catch (e: NotaryInternalException) {
logError(e.error) logError(e.error)
// Any exception that's not a NotaryInternalException is assumed to be an unexpected internal error // Any exception that's not a NotaryInternalException is assumed to be an unexpected internal error

View File

@ -0,0 +1,374 @@
package net.corda.core.internal.telemetry
import io.opentelemetry.api.GlobalOpenTelemetry
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.baggage.Baggage
import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.api.common.Attributes
import io.opentelemetry.api.common.AttributesBuilder
import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.context.Context
import io.opentelemetry.context.Scope
import net.corda.core.flows.FlowLogic
import net.corda.core.serialization.CordaSerializable
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import net.corda.opentelemetrydriver.OpenTelemetryDriver
import io.opentelemetry.context.propagation.TextMapGetter
import java.util.concurrent.ConcurrentLinkedDeque
@CordaSerializable
data class SpanEventContexts(val child: Context, val parent: Context)
@CordaSerializable
data class ContextCarrier(val context: MutableMap<String,String>)
@CordaSerializable
data class OpenTelemetryContext(val context: ContextCarrier, val spanEventChildContext: ContextCarrier, val spanEventParentContext: ContextCarrier, val baggage: Map<String,String>): TelemetryDataItem
data class SpanInfo(val name: String, val span: Span, val spanScope: Scope,
val spanEventContext: SpanEventContexts? = null,
val spanEventContextQueue: ConcurrentLinkedDeque<SpanEventContexts>? = null)
class TracerSetup(serviceName: String) {
private var openTelemetryDriver: Any? = null
val openTelemetry: OpenTelemetry by lazy {
try {
openTelemetryDriver = OpenTelemetryDriver(serviceName)
(openTelemetryDriver as OpenTelemetryDriver).openTelemetry
}
catch (ex: NoClassDefFoundError) {
GlobalOpenTelemetry.get()
}
}
fun getTracer(): Tracer {
return openTelemetry.tracerProvider.get(OpenTelemetryComponent::class.java.name)
}
fun shutdown() {
(openTelemetryDriver as? OpenTelemetryDriver)?.shutdown()
}
}
@Suppress("TooManyFunctions")
class OpenTelemetryComponent(val serviceName: String, val spanStartEndEventsEnabled: Boolean, val copyBaggageToTags: Boolean) : TelemetryComponent {
val tracerSetup = TracerSetup(serviceName)
val tracer: Tracer = tracerSetup.getTracer()
companion object {
private val log: Logger = LoggerFactory.getLogger(OpenTelemetryComponent::class.java)
const val OPENTELEMETRY_COMPONENT_NAME = "OpenTelemetry"
}
val rootSpans = ConcurrentHashMap<UUID, SpanInfo>()
val spans = ConcurrentHashMap<UUID, SpanInfo>()
val baggages = ConcurrentHashMap<UUID, Scope>()
override fun isEnabled(): Boolean {
// DefaultTracer is the NoOp tracer in the OT API
return tracerSetup.getTracer().javaClass.name != "io.opentelemetry.api.trace.DefaultTracer"
}
override fun name(): String = OPENTELEMETRY_COMPONENT_NAME
override fun onTelemetryEvent(event: TelemetryEvent) {
when (event) {
is StartSpanForFlowEvent -> startSpanForFlow(event.name, event.attributes, event.telemetryId, event.flowLogic, event.telemetryDataItem)
is EndSpanForFlowEvent -> endSpanForFlow(event.telemetryId)
is StartSpanEvent -> startSpan(event.name, event.attributes, event.telemetryId, event.flowLogic)
is EndSpanEvent -> endSpan(event.telemetryId)
is SetStatusEvent -> setStatus(event.telemetryId, event.telemetryStatusCode, event.message)
is RecordExceptionEvent -> recordException(event.telemetryId, event.throwable)
is ShutdownTelemetryEvent -> shutdownTelemetry()
}
}
private fun shutdownTelemetry() {
tracerSetup.shutdown()
}
private fun extractContext(carrier: ContextCarrier): Context {
val getter = object : TextMapGetter<ContextCarrier?> {
override fun get(carrier: ContextCarrier?, key: String): String? {
return if (carrier?.context?.containsKey(key) == true) {
val value = carrier.context[key]
value
} else null
}
override fun keys(carrier: ContextCarrier?): MutableIterable<String> {
return carrier?.context?.keys ?: mutableListOf()
}
}
return carrier.let {
tracerSetup.openTelemetry.propagators.textMapPropagator.extract(Context.current(), it, getter)
}
}
@Suppress("LongParameterList")
private fun startSpanForFlow(name: String, attributes: Map<String, String>, telemetryId: UUID, flowLogic: FlowLogic<*>?,
telemetryDataItem: TelemetryDataItem?) {
val openTelemetryContext = telemetryDataItem as? OpenTelemetryContext
val extractedContext = openTelemetryContext?.let { extractContext(it.context) }
val spanEventContexts = openTelemetryContext?.let { SpanEventContexts(extractContext(it.spanEventChildContext), extractContext(it.spanEventParentContext)) }
val baggageAttributes = openTelemetryContext?.baggage?.let {
val baggageBuilder = it.toList().fold(Baggage.current().toBuilder()) {builder, attribute -> builder.put(attribute.first, attribute.second)}
baggages[telemetryId] = baggageBuilder.build().makeCurrent()
it
} ?: emptyMap()
val allAttributes = if (copyBaggageToTags) {
attributes + baggageAttributes
}
else {
attributes
}
val attributesMap = allAttributes.toList()
.fold(Attributes.builder()) { builder, attribute -> builder.put(attribute.first, attribute.second) }.also {
populateWithFlowAttributes(it, flowLogic)
}.build()
if (extractedContext != null && spanEventContexts != null) {
startSpanForFlowWithRemoteParent(name, attributesMap, telemetryId, extractedContext, spanEventContexts)
}
else {
startSpanForFlowWithNoParent(name, attributesMap, telemetryId)
}
}
private fun startSpanForFlowWithRemoteParent(name: String, attributesMap: Attributes, telemetryId: UUID, parentContext: Context, spanEventContexts: SpanEventContexts) {
val span = tracer.spanBuilder(name).setParent(parentContext).setAllAttributes(attributesMap).startSpan()
val spanScope = span.makeCurrent()
val contextAndQueue = startEndEventForFlowWithRemoteParent(name, attributesMap, spanEventContexts)
spans[telemetryId] = SpanInfo(name, span, spanScope, contextAndQueue?.first, contextAndQueue?.second)
}
private fun startEndEventForFlowWithRemoteParent(name: String, attributesMap: Attributes, spanEventContexts: SpanEventContexts): Pair<SpanEventContexts, ConcurrentLinkedDeque<SpanEventContexts>>? {
if (spanStartEndEventsEnabled) {
val contexts = createSpanToCaptureStartedSpanEventWithRemoteParent(name, spanEventContexts, attributesMap)
return Pair( contexts, ConcurrentLinkedDeque<SpanEventContexts>().also { it.add(contexts) })
}
return null
}
private fun startSpanForFlowWithNoParent(name: String, attributesMap: Attributes, telemetryId: UUID) {
val rootSpan = tracer.spanBuilder(name).setAllAttributes(attributesMap).setAllAttributes(Attributes.of(AttributeKey.stringKey("root.flow"), "true")).startSpan()
val rootSpanScope = rootSpan.makeCurrent()
if (spanStartEndEventsEnabled) {
val startedSpanContexts = createSpanToCaptureStartedSpanEvent(name, rootSpan, attributesMap)
val span = tracer.spanBuilder("Child Spans").setParent(Context.current().with(rootSpan)).startSpan()
val spanScope = span.makeCurrent()
rootSpans[telemetryId] = SpanInfo(name, rootSpan, rootSpanScope)
val spanEventContextStack = ConcurrentLinkedDeque<SpanEventContexts>().also { it.add(startedSpanContexts) }
spans[telemetryId] = SpanInfo(name, span, spanScope, startedSpanContexts, spanEventContextStack)
}
else {
spans[telemetryId] = SpanInfo(name, rootSpan, rootSpanScope)
}
}
private fun createSpanToCaptureStartedSpanEvent(name: String, rootSpan: Span, attributesMap: Attributes): SpanEventContexts {
val startedSpan = tracer.spanBuilder("Started Events").setAllAttributes(attributesMap).setAllAttributes(Attributes.of(AttributeKey.stringKey("root.startend.events"), "true")).setParent(Context.current().with(rootSpan)).startSpan()
val parentContext = Context.current().with(startedSpan)
startedSpan.end()
val startedSpanChild = tracer.spanBuilder("${name}-start").setAllAttributes(attributesMap)
.setParent(parentContext).startSpan()
val childContext = Context.current().with(startedSpanChild)
startedSpanChild.end()
return SpanEventContexts(childContext, parentContext)
}
private fun createSpanToCaptureStartedSpanEventWithRemoteParent(name: String, spanEventContexts: SpanEventContexts, attributesMap: Attributes ): SpanEventContexts {
val startedSpanChild = tracer.spanBuilder("${name}-start").setAllAttributes(attributesMap)
.setParent(spanEventContexts.child).startSpan()
val grandChildContext = Context.current().with(startedSpanChild)
startedSpanChild.end()
return SpanEventContexts(grandChildContext, spanEventContexts.child)
}
private fun endSpanForFlow(telemetryId: UUID){
val spanInfo = spans[telemetryId]
val rootSpanInfo = rootSpans[telemetryId]
if (spanStartEndEventsEnabled) {
createSpanToCaptureEndSpanEvent(spanInfo)
}
spanInfo?.spanScope?.close()
spanInfo?.span?.end()
rootSpanInfo?.spanScope?.close()
rootSpanInfo?.span?.end()
spans.remove(telemetryId)
rootSpans.remove(telemetryId)
val baggageScope = baggages[telemetryId]
baggageScope?.close()
baggages.remove(telemetryId)
}
private fun createSpanToCaptureEndSpanEvent(spanInfo: SpanInfo?) {
spanInfo?.spanEventContext?.parent?.let {
val startedSpanChild = tracer.spanBuilder("${spanInfo.name}-end").setParent(it).startSpan()
startedSpanChild.end()
}
val spanEventContextStack = spanInfo?.spanEventContextQueue
val filteredSpanEventContexts = spanEventContextStack?.filter { it == spanInfo.spanEventContext }
filteredSpanEventContexts?.forEach { spanEventContextStack.remove(it) }
}
private fun startSpan(name: String, attributes: Map<String, String>, telemetryId: UUID, flowLogic: FlowLogic<*>?) {
val currentBaggage = Baggage.current()
val baggageAttributes = mutableMapOf<String,String>()
if (copyBaggageToTags) {
currentBaggage.forEach { t, u -> baggageAttributes[t] = u.value }
}
val parentSpan = Span.current()
val attributesMap = (attributes+baggageAttributes).toList().fold(Attributes.builder()) { builder, attribute -> builder.put(attribute.first, attribute.second) }.also {
populateWithFlowAttributes(it, flowLogic)
}.build()
val span = tracer.spanBuilder(name).setAllAttributes(attributesMap).startSpan()
val spanScope = span.makeCurrent()
val spanEventContexts = createStartedEventSpan(name, attributesMap, parentSpan)
spans[telemetryId] = SpanInfo(name, span, spanScope, spanEventContexts?.peekLast(), spanEventContexts)
}
private fun populateWithFlowAttributes(attributesBuilder: AttributesBuilder, flowLogic: FlowLogic<*>?) {
flowLogic?.let {
attributesBuilder.put("flow.id", flowLogic.runId.uuid.toString())
attributesBuilder.put("creation.time", flowLogic.stateMachine.creationTime)
attributesBuilder.put("class.name", flowLogic.javaClass.name)
}
}
private fun createStartedEventSpan(name: String, attributesMap: Attributes, parentSpan: Span): ConcurrentLinkedDeque<SpanEventContexts>? {
return if (spanStartEndEventsEnabled) {
val filteredSpans = spans.filter { it.value.span == parentSpan }.toList()
val (startEventParentContext, spanEventContextQueue) = getStartEventParentContext(filteredSpans, parentSpan)
val startedSpanChild = tracer.spanBuilder("${name}-start").setAllAttributes(attributesMap)
.setParent(startEventParentContext).startSpan()
val childContext = Context.current().with(startedSpanChild)
startedSpanChild.end()
spanEventContextQueue?.offer(SpanEventContexts(childContext, startEventParentContext))
spanEventContextQueue
}
else {
null
}
}
private fun getStartEventParentContext(filteredSpans: List<Pair<UUID, SpanInfo>>, parentSpan: Span): Pair<Context, ConcurrentLinkedDeque<SpanEventContexts>?> {
return if (filteredSpans.isNotEmpty()) {
Pair(filteredSpans[0].second.spanEventContext?.child ?: Context.current(), filteredSpans[0].second.spanEventContextQueue)
}
else {
// Copes with case where user has created their own span. So we just use the most
// recent span we know about on the stack.
val altFilteredSpans = spans.filter { it.value.span.spanContext.traceId == parentSpan.spanContext.traceId }.toList()
val spanEventContexts = altFilteredSpans[0].second.spanEventContextQueue
Pair(spanEventContexts?.peekLast()?.child ?: Context.current(), spanEventContexts)
}
}
private fun endSpan(telemetryId: UUID){
val spanInfo = spans[telemetryId]
createSpanToCaptureEndSpanEvent(spanInfo)
spanInfo?.spanScope?.close()
spanInfo?.span?.end()
spans.remove(telemetryId)
}
override fun getCurrentTelemetryData(): TelemetryDataItem {
val currentSpan = Span.current()
val currentContextCarrier = inject(tracerSetup, Context.current())
val filteredSpans = spans.filter { it.value.span == currentSpan }.toList()
val childContext = if (filteredSpans.isNotEmpty()) {
filteredSpans.getOrNull(0)?.second?.spanEventContext?.child
}
else {
val altFilteredSpans = spans.filter { it.value.span.spanContext.traceId == currentSpan.spanContext.traceId }.toList()
if (altFilteredSpans.isNotEmpty()) {
altFilteredSpans[0].second.spanEventContextQueue?.peekLast()?.child
}
else {
null
}
}
val childContextCarrier = inject(tracerSetup, childContext)
val parentContext = if (filteredSpans.isNotEmpty()) {
filteredSpans.getOrNull(0)?.second?.spanEventContext?.parent
}
else {
val altFilteredSpans = spans.filter { it.value.span.spanContext.traceId == currentSpan.spanContext.traceId }.toList()
if (altFilteredSpans.isNotEmpty()) {
altFilteredSpans[0].second.spanEventContextQueue?.peekLast()?.parent
}
else {
null
}
}
val parentContextCarrier = inject(tracerSetup, parentContext)
return OpenTelemetryContext(currentContextCarrier, childContextCarrier, parentContextCarrier, Baggage.current().asMap().mapValues { it.value.value })
}
private fun inject(tracerSetup: TracerSetup, context: Context?) : ContextCarrier {
val contextCarrier = ContextCarrier(mutableMapOf())
context?.let { tracerSetup.openTelemetry.propagators.textMapPropagator.inject(it, contextCarrier) { carrier, key, value -> carrier?.context?.put(key, value) }}
return contextCarrier
}
override fun getCurrentTelemetryId(): UUID {
val currentSpan = Span.current()
val filteredSpans = spans.filter { it.value.span == currentSpan }.toList()
if (filteredSpans.isEmpty()) {
return UUID(0, 0)
}
return filteredSpans[0].first // return UUID associated with current span
}
override fun setCurrentTelemetryId(id: UUID) {
val spanInfo = spans[id]
spanInfo?.let {
it.spanScope.close() // close the old scope
val childSpanScope = it.span.makeCurrent()
val newSpanInfo = spanInfo.copy(spanScope = childSpanScope)
spans[id] = newSpanInfo
}
}
override fun getCurrentSpanId(): String {
return Span.current().spanContext.spanId
}
override fun getCurrentTraceId(): String {
return Span.current().spanContext.traceId
}
override fun getCurrentBaggage(): Map<String, String> {
return Baggage.current().asMap().mapValues { it.value.value }
}
override fun getTelemetryHandles(): List<Any> {
return listOf(tracerSetup.openTelemetry)
}
private fun setStatus(telemetryId: UUID, telemetryStatusCode: TelemetryStatusCode, message: String) {
val spanInfo = spans[telemetryId]
spanInfo?.span?.setStatus(toOpenTelemetryStatus(telemetryStatusCode), message)
}
private fun toOpenTelemetryStatus(telemetryStatusCode: TelemetryStatusCode): StatusCode {
return when(telemetryStatusCode) {
TelemetryStatusCode.ERROR -> StatusCode.ERROR
TelemetryStatusCode.OK -> StatusCode.OK
TelemetryStatusCode.UNSET -> StatusCode.UNSET
}
}
private fun recordException(telemetryId: UUID, throwable: Throwable) {
val spanInfo = spans[telemetryId]
spanInfo?.span?.recordException(throwable)
}
}

View File

@ -0,0 +1,129 @@
package net.corda.core.internal.telemetry
import net.corda.core.flows.FlowLogic
import net.corda.core.serialization.CordaSerializable
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.slf4j.MDC
import java.lang.IllegalStateException
import java.util.*
import java.util.concurrent.ConcurrentHashMap
@CordaSerializable
data class SimpleLogContext(val traceId: UUID, val baggage: Map<String, String>): TelemetryDataItem
const val CLIENT_ID = "client.id"
const val TRACE_ID = "trace.id"
// Simple telemetry class that creates a single UUID and uses this for the trace id. When the flow starts we use the trace is passed in. After this
// though we must use the trace id propagated to us (if remote), or the trace id associated with thread local.
@Suppress("TooManyFunctions")
class SimpleLogTelemetryComponent : TelemetryComponent {
companion object {
private val log: Logger = LoggerFactory.getLogger(SimpleLogTelemetryComponent::class.java)
}
private val traces: InheritableThreadLocal<UUID> = InheritableThreadLocal()
private val logContexts = ConcurrentHashMap<UUID, SimpleLogContext>()
override fun isEnabled(): Boolean {
return true
}
override fun name(): String = "SimpleLogTelemetry"
override fun onTelemetryEvent(event: TelemetryEvent) {
when (event) {
is StartSpanForFlowEvent -> startSpanForFlow(event.name, event.attributes, event.telemetryId, event.flowLogic, event.telemetryDataItem)
is EndSpanForFlowEvent -> endSpanForFlow(event.telemetryId)
is StartSpanEvent -> startSpan(event.name, event.attributes, event.telemetryId, event.flowLogic)
is EndSpanEvent -> endSpan(event.telemetryId)
is SetStatusEvent -> setStatus(event.telemetryId, event.telemetryStatusCode, event.message)
is RecordExceptionEvent -> recordException(event.telemetryId, event.throwable)
}
}
@Suppress("LongParameterList")
private fun startSpanForFlow(name: String, attributes: Map<String, String>, telemetryId: UUID, flowLogic: FlowLogic<*>?, telemetryDataItem: TelemetryDataItem?) {
val simpleLogTelemetryDataItem = telemetryDataItem?.let {(telemetryDataItem as? SimpleLogContext) ?:
throw IllegalStateException("Type of telemetryDataItem no a SimpleLogContext, actual class is ${telemetryDataItem::class.java.name}")}
val traceId = simpleLogTelemetryDataItem?.traceId ?: telemetryId
val flowId = flowLogic?.runId
val clientId = simpleLogTelemetryDataItem?.baggage?.get(CLIENT_ID) ?: flowLogic?.stateMachine?.clientId
traces.set(traceId)
val baggageAttributes = simpleLogTelemetryDataItem?.baggage ?: emptyMap()
logContexts[traceId] = SimpleLogContext(traceId, baggageAttributes)
clientId?.let { MDC.put(CLIENT_ID, it) }
MDC.put(TRACE_ID, traceId.toString())
log.info("startSpanForFlow: name: $name, traceId: $traceId, flowId: $flowId, clientId: $clientId, attributes: ${attributes+baggageAttributes}")
}
// Check when you start a top level flow the startSpanForFlow appears just once, and so the endSpanForFlow also appears just once
// So its valid to do the MDC clear here. For remotes nodes as well
private fun endSpanForFlow(telemetryId: UUID) {
log.info("endSpanForFlow: traceId: ${traces.get()}")
logContexts.remove(telemetryId)
MDC.clear()
}
@Suppress("UNUSED_PARAMETER")
private fun startSpan(name: String, attributes: Map<String, String>, telemetryId: UUID, flowLogic: FlowLogic<*>?) {
val flowId = flowLogic?.runId
val clientId = flowLogic?.stateMachine?.clientId
val traceId = traces.get()
log.info("startSpan: name: $name, traceId: $traceId, flowId: $flowId, clientId: $clientId, attributes: $attributes")
}
@Suppress("UNUSED_PARAMETER")
private fun endSpan(telemetryId: UUID) {
log.info("endSpan: traceId: ${traces.get()}")
}
override fun getCurrentTelemetryData(): SimpleLogContext {
traces.get()?.let {
logContexts[it]?.let { simpleLogContext ->
return simpleLogContext
}
}
return SimpleLogContext(UUID(0, 0), emptyMap())
}
override fun getCurrentTelemetryId(): UUID {
return traces.get() ?: UUID(0,0)
}
override fun setCurrentTelemetryId(id: UUID) {
traces.set(id)
}
override fun getCurrentSpanId(): String {
return traces.get()?.toString() ?: ""
}
override fun getCurrentTraceId(): String {
return traces.get()?.toString() ?: ""
}
override fun getCurrentBaggage(): Map<String, String> {
val uuid = traces.get()
return logContexts[uuid]?.baggage ?: emptyMap()
}
override fun getTelemetryHandles(): List<Any> {
return emptyList()
}
@Suppress("UNUSED_PARAMETER")
private fun setStatus(telemetryId: UUID, telemetryStatusCode: TelemetryStatusCode, message: String) {
when(telemetryStatusCode) {
TelemetryStatusCode.ERROR -> log.error("setStatus: traceId: ${traces.get()}, statusCode: ${telemetryStatusCode}, message: message")
TelemetryStatusCode.OK, TelemetryStatusCode.UNSET -> log.info("setStatus: traceId: ${traces.get()}, statusCode: ${telemetryStatusCode}, message: message")
}
}
@Suppress("UNUSED_PARAMETER")
private fun recordException(telemetryId: UUID, throwable: Throwable) {
log.error("recordException: traceId: ${traces.get()}, throwable: ${throwable}}")
}
}

View File

@ -0,0 +1,266 @@
package net.corda.core.internal.telemetry
import net.corda.core.CordaInternal
import net.corda.core.DeleteForDJVM
import net.corda.core.flows.FlowLogic
import net.corda.core.internal.uncheckedCast
import net.corda.core.node.ServiceHub
import net.corda.core.node.services.TelemetryService
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializationFactory
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.serialization.serialize
import net.corda.core.utilities.OpaqueBytes
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.util.*
@CordaSerializable
interface TelemetryDataItem
@CordaSerializable
data class SerializedTelemetry(val serializedTelemetryData: Map<String, OpaqueBytes>)
enum class TelemetryStatusCode {
/** The default status. */
UNSET,
/**
* The operation has been validated by an Application developers or Operator to have completed
* successfully.
*/
OK,
/** The operation contains an error. */
ERROR
}
@DeleteForDJVM
@CordaSerializable
data class TelemetryId(private val telemetryService: TelemetryServiceImpl) {
val id: UUID = UUID.randomUUID()
fun setStatus(telemetryStatusCode: TelemetryStatusCode, message: String) {
telemetryService.setStatus(this, telemetryStatusCode, message)
}
fun recordException(throwable: Throwable) {
telemetryService.recordException( this, throwable)
}
fun close() {
telemetryService.endSpan(this)
}
}
@CordaSerializable
data class ComponentTelemetryIds(val componentTelemetryIds: Map<String, UUID>)
interface TelemetryEvent
@DeleteForDJVM
class StartSpanForFlowEvent(val name: String,
val attributes: Map<String, String>,
val telemetryId: UUID, val flowLogic: FlowLogic<*>?,
val telemetryDataItem: TelemetryDataItem?): TelemetryEvent
@DeleteForDJVM
class EndSpanForFlowEvent(val telemetryId: UUID): TelemetryEvent
@DeleteForDJVM
class StartSpanEvent(val name: String, val attributes: Map<String, String>, val telemetryId: UUID, val flowLogic: FlowLogic<*>?): TelemetryEvent
class EndSpanEvent(val telemetryId: UUID): TelemetryEvent
class SetStatusEvent(val telemetryId: UUID, val telemetryStatusCode: TelemetryStatusCode, val message: String): TelemetryEvent
class RecordExceptionEvent(val telemetryId: UUID, val throwable: Throwable): TelemetryEvent
class InitialiseTelemetryEvent: TelemetryEvent
class ShutdownTelemetryEvent: TelemetryEvent
interface TelemetryComponent {
fun name(): String
fun isEnabled(): Boolean
fun onTelemetryEvent(event: TelemetryEvent)
fun getCurrentTelemetryData(): TelemetryDataItem
fun getCurrentTelemetryId(): UUID
fun setCurrentTelemetryId(id: UUID)
fun getCurrentSpanId(): String
fun getCurrentTraceId(): String
fun getCurrentBaggage(): Map<String, String>
fun getTelemetryHandles(): List<Any>
}
interface TelemetryComponentId {
fun name(): String
}
@Suppress("TooManyFunctions")
@DeleteForDJVM
class TelemetryServiceImpl : SingletonSerializeAsToken(), TelemetryService {
companion object {
private val log: Logger = LoggerFactory.getLogger(TelemetryServiceImpl::class.java)
}
fun getCurrentSpanId(telemetryComponentName: String): String? {
return telemetryComponents[telemetryComponentName]?.getCurrentSpanId()
}
fun getCurrentTraceId(telemetryComponentName: String): String? {
return telemetryComponents[telemetryComponentName]?.getCurrentTraceId()
}
fun getCurrentBaggage(telemetryComponentName: String): Map<String, String>? {
return telemetryComponents[telemetryComponentName]?.getCurrentBaggage()
}
fun setStatus(telemetryId: TelemetryId, telemetryStatusCode: TelemetryStatusCode, message: String) {
telemetryComponents.values.forEach {
it.onTelemetryEvent(SetStatusEvent(telemetryId.id, telemetryStatusCode, message))
}
}
fun recordException(telemetryId: TelemetryId, throwable: Throwable) {
telemetryComponents.values.forEach {
it.onTelemetryEvent(RecordExceptionEvent(telemetryId.id, throwable))
}
}
@CordaInternal
fun deserialize(data: OpaqueBytes): TelemetryDataItem {
return SerializationFactory.defaultFactory.deserialize(data, TelemetryDataItem::class.java, SerializationFactory.defaultFactory.defaultContext)
}
private val telemetryComponents: MutableMap<String, TelemetryComponent> = mutableMapOf()
@CordaInternal
fun initialiseTelemetry() {
telemetryComponents.values.forEach {
it.onTelemetryEvent(InitialiseTelemetryEvent())
}
}
@CordaInternal
fun shutdownTelemetry() {
telemetryComponents.values.forEach {
it.onTelemetryEvent(ShutdownTelemetryEvent())
}
telemetryComponents.clear()
}
@CordaInternal
fun addTelemetryComponent(telemetryComponent: TelemetryComponent) {
telemetryComponents[telemetryComponent.name()] = telemetryComponent
}
@CordaInternal
fun startSpanForFlow(name: String, attributes: Map<String, String>, flowLogic: FlowLogic<*>? = null, remoteSerializedTelemetry: SerializedTelemetry? = null): TelemetryId {
val telemetryId = TelemetryId(this)
telemetryComponents.values.forEach {
val bytes = remoteSerializedTelemetry?.serializedTelemetryData?.get(it.name())
val telemetryDataItem = bytes?.let { deserialize(bytes) }
it.onTelemetryEvent(StartSpanForFlowEvent(name, attributes, telemetryId.id, flowLogic, telemetryDataItem))
}
return telemetryId
}
@CordaInternal
fun endSpanForFlow(telemetryId: TelemetryId) {
telemetryComponents.values.forEach {
it.onTelemetryEvent(EndSpanForFlowEvent(telemetryId.id))
}
}
fun startSpan(name: String, attributes: Map<String, String> = emptyMap(), flowLogic: FlowLogic<*>? = null): TelemetryId {
val telemetryId = TelemetryId(this)
telemetryComponents.values.forEach {
it.onTelemetryEvent(StartSpanEvent(name, attributes, telemetryId.id, flowLogic))
}
return telemetryId
}
fun endSpan(telemetryId: TelemetryId) {
telemetryComponents.values.forEach {
it.onTelemetryEvent(EndSpanEvent(telemetryId.id))
}
}
@Suppress("TooGenericExceptionCaught")
inline fun <R> span(name: String, attributes: Map<String, String> = emptyMap(), flowLogic: FlowLogic<*>? = null, block: () -> R): R {
val telemetryId = startSpan(name, attributes, flowLogic)
try {
return block()
}
catch(ex: Throwable) {
recordException(telemetryId, ex)
setStatus(telemetryId, TelemetryStatusCode.ERROR, "Exception raised: ${ex.message}")
throw ex
}
finally {
endSpan(telemetryId)
}
}
@CordaInternal
@Suppress("LongParameterList", "TooGenericExceptionCaught")
inline fun <R> spanForFlow(name: String, attributes: Map<String, String>, flowLogic: FlowLogic<*>? = null, remoteSerializedTelemetry: SerializedTelemetry? = null, block: () -> R): R {
val telemetryId = startSpanForFlow(name, attributes, flowLogic, remoteSerializedTelemetry)
try {
return block()
}
catch(ex: Throwable) {
recordException(telemetryId, ex)
setStatus(telemetryId, TelemetryStatusCode.ERROR, "Exception raised: ${ex.message}")
throw ex
}
finally {
endSpanForFlow(telemetryId)
}
}
@CordaInternal
fun getCurrentTelemetryData(): SerializedTelemetry? {
if (telemetryComponents.isEmpty()) {
return null
}
val serializedTelemetryData = mutableMapOf<String, OpaqueBytes>()
telemetryComponents.values.forEach {
val currentTelemetryData = it.getCurrentTelemetryData()
serializedTelemetryData[it.name()] = currentTelemetryData.serialize()
}
return SerializedTelemetry(serializedTelemetryData)
}
@CordaInternal
fun getCurrentTelemetryIds(): ComponentTelemetryIds? {
if (telemetryComponents.isEmpty()) {
return null
}
val telemetryIds = mutableMapOf<String, UUID>()
telemetryComponents.values.forEach {
telemetryIds[it.name()] = it.getCurrentTelemetryId()
}
return ComponentTelemetryIds(telemetryIds)
}
@CordaInternal
fun setCurrentTelemetryId(telemetryIds: ComponentTelemetryIds) {
telemetryComponents.values.forEach {
it.setCurrentTelemetryId(telemetryIds.componentTelemetryIds[it.name()]!!)
}
}
private fun getTelemetryHandles(): List<Any> {
return telemetryComponents.values.map { it.getTelemetryHandles() }.flatten()
}
override fun <T> getTelemetryHandle(telemetryClass: Class<T>): T? {
getTelemetryHandles().forEach {
if (telemetryClass.isInstance(it))
@Suppress("UNCHECKED_CAST")
return uncheckedCast(it as T)
}
return null
}
}
val ServiceHub.telemetryServiceInternal
get() = this.telemetryService as TelemetryServiceImpl

View File

@ -0,0 +1,24 @@
package net.corda.core.internal.utilities
import net.corda.core.CordaInternal
import net.corda.core.KeepForDJVM
@KeepForDJVM
interface Internable<T> {
@CordaInternal
val interner: PrivateInterner<T>
}
@KeepForDJVM
@CordaInternal
interface IternabilityVerifier<T> {
// If a type being interned has a slightly dodgy equality check, the more strict rules you probably
// want to apply to interning can be enforced here.
fun choose(original: T, interned: T): T
}
@KeepForDJVM
@CordaInternal
class AlwaysInternableVerifier<T> : IternabilityVerifier<T> {
override fun choose(original: T, interned: T): T = interned
}

View File

@ -0,0 +1,69 @@
package net.corda.core.internal.utilities
import com.google.common.collect.Interners
import net.corda.core.CordaInternal
import net.corda.core.internal.packageNameOrNull
import net.corda.core.internal.uncheckedCast
import net.corda.core.serialization.CordaSerializable
import kotlin.reflect.full.companionObjectInstance
/**
* This class converts instances supplied to [intern] to a common instance within the JVM, amongst all those
* instances that have been submitted. It uses weak references to avoid memory leaks.
*
* NOTE: the Guava interners are Beta, so upgrading Guava may result in us having to adapt this code.
*
* System properties allow disabling, in the event an issue is uncovered in a live environment. The
* correct default for the concurrency setting is the result of performance evaluation.
*/
@CordaInternal
class PrivateInterner<T>(val verifier: IternabilityVerifier<T> = AlwaysInternableVerifier()) {
companion object {
// This value is the default in Guava, and performance testing didn't reveal a need to change
private const val DEFAULT_CONCURRENCY_LEVEL = 4
private val CONCURRENCY_LEVEL = Integer.getInteger("net.corda.core.intern.concurrency", DEFAULT_CONCURRENCY_LEVEL).toInt()
private val DISABLE = java.lang.Boolean.getBoolean("net.corda.core.intern.disable")
/**
* This will look at the companion object of a class, and on the super class companion object,
* to see if they implement [Internable], in which case there is a [PrivateInterner] instance
* available to do interning. Tolerant of null class references and a lack of companion objects.
*/
@Suppress("ComplexMethod")
fun findFor(clazz: Class<*>?): PrivateInterner<Any>? {
fun hasCordaSerializable(type: Class<*>): Boolean {
return type.isAnnotationPresent(CordaSerializable::class.java)
|| type.interfaces.any(::hasCordaSerializable)
|| (type.superclass != null && hasCordaSerializable(type.superclass))
}
fun isSerializableCore(clazz: Class<*>): Boolean {
if (!(clazz.packageNameOrNull?.startsWith("net.corda.core") ?: false)) return false
return hasCordaSerializable(clazz)
}
fun findInterner(clazz: Class<*>?): PrivateInterner<Any>? {
// Kotlin reflection has a habit of throwing exceptions, so protect just in case.
try {
return clazz?.kotlin?.companionObjectInstance?.let {
(it as? Internable<*>)?.let {
uncheckedCast(it.interner)
}
}
} catch (_: Throwable) {
return null
}
}
return if (clazz != null) {
// We try not to ruffle the feathers of kotlin reflection by avoiding throwing all types at it.
if (!isSerializableCore(clazz)) return null
findInterner(clazz) ?: findInterner(clazz.superclass)
} else null
}
}
private val interner = Interners.newBuilder().weak().concurrencyLevel(CONCURRENCY_LEVEL).build<T>()
fun <S : T> intern(sample: S): S = if (DISABLE) sample else uncheckedCast(verifier.choose(sample, interner.intern(sample)))
}

View File

@ -392,7 +392,11 @@ interface CordaRPCOps : RPCOps {
/** Queries attachments metadata */ /** Queries attachments metadata */
fun queryAttachments(query: AttachmentQueryCriteria, sorting: AttachmentSort?): List<AttachmentId> fun queryAttachments(query: AttachmentQueryCriteria, sorting: AttachmentSort?): List<AttachmentId>
/** Returns the node's current time. */ /** Returns the node's current time.
*
* Is a quick RPC, meaning that it is handled outside the node's standard thread pool in order to provide a
* quick response even when the node is dealing with a high volume of RPC calls.
*/
fun currentNodeTime(): Instant fun currentNodeTime(): Instant
/** /**

View File

@ -8,6 +8,10 @@ import net.corda.core.DoNotImplement
*/ */
@DoNotImplement @DoNotImplement
interface RPCOps { interface RPCOps {
/** Returns the RPC protocol version. Exists since version 0 so guaranteed to be present. */ /** Returns the RPC protocol version. Exists since version 0 so guaranteed to be present.
*
* Getting this property is handled as a quick RPC, meaning that it is handled outside the node's standard
* thread pool in order to provide a quick response even when the node is dealing with a high volume of RPC calls.
*/
val protocolVersion: Int val protocolVersion: Int
} }

View File

@ -12,6 +12,7 @@ import net.corda.core.crypto.TransactionSignature
import net.corda.core.flows.ContractUpgradeFlow import net.corda.core.flows.ContractUpgradeFlow
import net.corda.core.node.services.* import net.corda.core.node.services.*
import net.corda.core.node.services.diagnostics.DiagnosticsService import net.corda.core.node.services.diagnostics.DiagnosticsService
import net.corda.core.internal.telemetry.TelemetryComponent
import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsToken
import net.corda.core.transactions.FilteredTransaction import net.corda.core.transactions.FilteredTransaction
import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.LedgerTransaction
@ -165,6 +166,11 @@ interface ServiceHub : ServicesForResolution {
*/ */
val diagnosticsService: DiagnosticsService val diagnosticsService: DiagnosticsService
/**
* Provides operations to support telemetry and telemetry data between nodes.
*/
val telemetryService: TelemetryService
/** /**
* INTERNAL. DO NOT USE. * INTERNAL. DO NOT USE.
* @suppress * @suppress
@ -187,6 +193,13 @@ interface ServiceHub : ServicesForResolution {
*/ */
fun <T : SerializeAsToken> cordaService(type: Class<T>): T fun <T : SerializeAsToken> cordaService(type: Class<T>): T
/**
* Return the singleton instance of the given Corda telemetry component type. This is a class that implements TelemetryComponent
* and will have automatically been registered by the node.
* @throws IllegalArgumentException If the instance is not found.
*/
fun <T : TelemetryComponent> cordaTelemetryComponent(type: Class<T>): T
/** /**
* Stores the given [SignedTransaction]s in the local transaction storage and then sends them to the vault for * Stores the given [SignedTransaction]s in the local transaction storage and then sends them to the vault for
* further processing if [notifyVault] is true. This is expected to be run within a database transaction. * further processing if [notifyVault] is true. This is expected to be run within a database transaction.

View File

@ -17,6 +17,18 @@ interface ServiceLifecycleObserver {
} }
enum class ServiceLifecycleEvent { enum class ServiceLifecycleEvent {
/**
* This event is dispatched when the node is about to start the State Machine. The State Machine will not be started until
* all handlers return from processing this event.
* Handlers can delay the node start-up, and the processing of flows, by not returning from handling this event until their
* CorDapp is ready for flows to be started/resumed.
*
* If a handler for this event throws [CordaServiceCriticalFailureException] - this is the way to flag that it will not make
* sense for Corda node to continue its operation. The lifecycle events dispatcher will endeavor to terminate node's JVM as soon
* as practically possible.
*/
BEFORE_STATE_MACHINE_START,
/** /**
* This event is dispatched when State Machine is fully started such that [net.corda.core.node.AppServiceHub] available * This event is dispatched when State Machine is fully started such that [net.corda.core.node.AppServiceHub] available
* for [CordaService] to be use. * for [CordaService] to be use.

View File

@ -0,0 +1,9 @@
package net.corda.core.node.services
import net.corda.core.DoNotImplement
@DoNotImplement
interface TelemetryService {
fun <T> getTelemetryHandle(telemetryClass: Class<T>): T?
}

View File

@ -178,7 +178,7 @@ class Vault<out T : ContractState>(val states: Iterable<StateAndRef<T>>) {
Type.ALWAYS_ACCEPT -> ConstraintInfo(AlwaysAcceptAttachmentConstraint) Type.ALWAYS_ACCEPT -> ConstraintInfo(AlwaysAcceptAttachmentConstraint)
Type.HASH -> ConstraintInfo(HashAttachmentConstraint(SecureHash.create(data!!.toHexString()))) Type.HASH -> ConstraintInfo(HashAttachmentConstraint(SecureHash.create(data!!.toHexString())))
Type.CZ_WHITELISTED -> ConstraintInfo(WhitelistedByZoneAttachmentConstraint) Type.CZ_WHITELISTED -> ConstraintInfo(WhitelistedByZoneAttachmentConstraint)
Type.SIGNATURE -> ConstraintInfo(SignatureAttachmentConstraint(Crypto.decodePublicKey(data!!))) Type.SIGNATURE -> ConstraintInfo(SignatureAttachmentConstraint.create(Crypto.decodePublicKey(data!!)))
} }
} }
} }

View File

@ -51,6 +51,9 @@ import java.util.WeakHashMap
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.atomic.AtomicLong
import java.util.function.Function import java.util.function.Function
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.set
/** /**
* A custom ClassLoader that knows how to load classes from a set of attachments. The attachments themselves only * A custom ClassLoader that knows how to load classes from a set of attachments. The attachments themselves only
@ -168,7 +171,7 @@ class AttachmentsClassLoader(attachments: List<Attachment>,
if(read <= 0) break if(read <= 0) break
md.update(ctx.buffer, 0, read) md.update(ctx.buffer, 0, read)
} }
return SecureHash.SHA256(md.digest()) return SecureHash.createSHA256(md.digest())
} }
private fun isZipOrJar(attachment: Attachment) = attachment.openAsJAR().use { jar -> private fun isZipOrJar(attachment: Attachment) = attachment.openAsJAR().use { jar ->

View File

@ -692,7 +692,8 @@ open class TransactionBuilder(
} }
private fun makeSignatureAttachmentConstraint(attachmentSigners: List<PublicKey>) = private fun makeSignatureAttachmentConstraint(attachmentSigners: List<PublicKey>) =
SignatureAttachmentConstraint(CompositeKey.Builder().addKeys(attachmentSigners).build()) SignatureAttachmentConstraint.create(CompositeKey.Builder().addKeys(attachmentSigners)
.build())
private fun getInstalledContractAttachmentId( private fun getInstalledContractAttachmentId(
contractClassName: String, contractClassName: String,

View File

@ -26,7 +26,7 @@ results in
If no image variant is specified, all available image variants will be built. If no image variant is specified, all available image variants will be built.
The default repository for all images is `corda/corda` and you will need official R3 credentials The default repository for all images is `corda/corda` and you will need official R3 credentials
for Artifactory to push there. [Ross Nicoll](ross.nicoll@r3.com) (or other Artifactory administrators) can assist with this if needed, for Artifactory to push there. R3's Artifactory administrators can assist with this if needed,
otherwise you can override the repository name using the `docker.image.repository` Gradle property. otherwise you can override the repository name using the `docker.image.repository` Gradle property.
e.g. e.g.

View File

@ -1,8 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
NODE_LIST=("dockerNode1" "dockerNode2" "dockerNode3") NODE_LIST=("dockerNode1" "dockerNode2" "dockerNode3")
NETWORK_NAME=mininet NETWORK_NAME=mininet
CORDAPP_VERSION="4.9-SNAPSHOT" CORDAPP_VERSION="4.10-SNAPSHOT"
DOCKER_IMAGE_VERSION="corda-zulu-4.9-snapshot" DOCKER_IMAGE_VERSION="corda-zulu-4.10-snapshot"
mkdir cordapps mkdir cordapps
rm -f cordapps/* rm -f cordapps/*

View File

@ -6,7 +6,9 @@ import net.corda.core.context.Trace
import net.corda.core.context.Trace.InvocationId import net.corda.core.context.Trace.InvocationId
import net.corda.core.context.Trace.SessionId import net.corda.core.context.Trace.SessionId
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.telemetry.SerializedTelemetry
import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializedBytes
import net.corda.core.serialization.deserialize import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.utilities.Id import net.corda.core.utilities.Id
@ -116,7 +118,8 @@ object RPCApi {
val replyId: InvocationId, val replyId: InvocationId,
val sessionId: SessionId, val sessionId: SessionId,
val externalTrace: Trace? = null, val externalTrace: Trace? = null,
val impersonatedActor: Actor? = null val impersonatedActor: Actor? = null,
val serializedTelemetry: SerializedTelemetry? = null
) : ClientToServer() { ) : ClientToServer() {
override fun writeToClientMessage(message: ClientMessage) { override fun writeToClientMessage(message: ClientMessage) {
MessageUtil.setJMSReplyTo(message, clientAddress) MessageUtil.setJMSReplyTo(message, clientAddress)
@ -130,6 +133,8 @@ object RPCApi {
message.putStringProperty(METHOD_NAME_FIELD_NAME, methodName) message.putStringProperty(METHOD_NAME_FIELD_NAME, methodName)
message.bodyBuffer.writeBytes(serialisedArguments.bytes) message.bodyBuffer.writeBytes(serialisedArguments.bytes)
val telemetryBytes: SerializedBytes<SerializedTelemetry>? = serializedTelemetry?.serialize()
telemetryBytes?.let { message.putBytesProperty(TELEMETRY_PROPERTY, it.bytes) }
} }
} }
@ -148,15 +153,20 @@ object RPCApi {
fun fromClientMessage(message: ClientMessage): ClientToServer { fun fromClientMessage(message: ClientMessage): ClientToServer {
val tag = Tag.values()[message.getIntProperty(TAG_FIELD_NAME)] val tag = Tag.values()[message.getIntProperty(TAG_FIELD_NAME)]
return when (tag) { return when (tag) {
RPCApi.ClientToServer.Tag.RPC_REQUEST -> RpcRequest( RPCApi.ClientToServer.Tag.RPC_REQUEST -> {
clientAddress = MessageUtil.getJMSReplyTo(message), val telemetryBytes = message.getBytesProperty(TELEMETRY_PROPERTY)
methodName = message.getStringProperty(METHOD_NAME_FIELD_NAME), val serializedTelemetry: SerializedTelemetry? = telemetryBytes?.let {OpaqueBytes(it).deserialize()}
serialisedArguments = OpaqueBytes(message.getBodyAsByteArray()), RpcRequest(
replyId = message.replyId(), clientAddress = MessageUtil.getJMSReplyTo(message),
sessionId = message.sessionId(), methodName = message.getStringProperty(METHOD_NAME_FIELD_NAME),
externalTrace = message.externalTrace(), serialisedArguments = OpaqueBytes(message.getBodyAsByteArray()),
impersonatedActor = message.impersonatedActor() replyId = message.replyId(),
) sessionId = message.sessionId(),
externalTrace = message.externalTrace(),
impersonatedActor = message.impersonatedActor(),
serializedTelemetry = serializedTelemetry
)
}
RPCApi.ClientToServer.Tag.OBSERVABLES_CLOSED -> { RPCApi.ClientToServer.Tag.OBSERVABLES_CLOSED -> {
val ids = ArrayList<InvocationId>() val ids = ArrayList<InvocationId>()
val buffer = message.bodyBuffer val buffer = message.bodyBuffer
@ -279,6 +289,7 @@ private const val DEDUPLICATION_IDENTITY_FIELD_NAME = "deduplication-identity"
private const val OBSERVABLE_ID_FIELD_NAME = "observable-id" private const val OBSERVABLE_ID_FIELD_NAME = "observable-id"
private const val OBSERVABLE_ID_TIMESTAMP_FIELD_NAME = "observable-id-timestamp" private const val OBSERVABLE_ID_TIMESTAMP_FIELD_NAME = "observable-id-timestamp"
private const val METHOD_NAME_FIELD_NAME = "method-name" private const val METHOD_NAME_FIELD_NAME = "method-name"
private const val TELEMETRY_PROPERTY = "telemetry-data"
fun ClientMessage.replyId(): InvocationId { fun ClientMessage.replyId(): InvocationId {
@ -301,6 +312,11 @@ fun ClientMessage.externalTrace(): Trace? {
} }
} }
fun ClientMessage.serializedTelemetry(): SerializedTelemetry? {
val telemetryBytes = this.getBytesProperty(TELEMETRY_PROPERTY)
return telemetryBytes?.let { OpaqueBytes(it).deserialize() }
}
fun ClientMessage.impersonatedActor(): Actor? { fun ClientMessage.impersonatedActor(): Actor? {
return getStringProperty(RPC_IMPERSONATED_ACTOR_ID)?.let { return getStringProperty(RPC_IMPERSONATED_ACTOR_ID)?.let {

View File

@ -0,0 +1,8 @@
package net.corda.nodeapi.internal
enum class NodeStatus {
WAITING_TO_START,
STARTING,
STARTED,
STOPPING
}

View File

@ -49,6 +49,7 @@ interface NodeLifecycleObserver {
sealed class NodeLifecycleEvent(val reversedPriority: Boolean = false) { sealed class NodeLifecycleEvent(val reversedPriority: Boolean = false) {
class BeforeNodeStart(val nodeInitialContext: NodeInitialContext) : NodeLifecycleEvent() class BeforeNodeStart(val nodeInitialContext: NodeInitialContext) : NodeLifecycleEvent()
class AfterNodeStart<out T : NodeServicesContext>(val nodeServicesContext: T) : NodeLifecycleEvent() class AfterNodeStart<out T : NodeServicesContext>(val nodeServicesContext: T) : NodeLifecycleEvent()
class BeforeStateMachineStart<out T : NodeServicesContext>(val nodeServicesContext: T) : NodeLifecycleEvent()
class StateMachineStarted<out T : NodeServicesContext>(val nodeServicesContext: T) : NodeLifecycleEvent() class StateMachineStarted<out T : NodeServicesContext>(val nodeServicesContext: T) : NodeLifecycleEvent()
class StateMachineStopped<out T : NodeServicesContext>(val nodeServicesContext: T) : NodeLifecycleEvent(reversedPriority = true) class StateMachineStopped<out T : NodeServicesContext>(val nodeServicesContext: T) : NodeLifecycleEvent(reversedPriority = true)
class BeforeNodeStop<out T : NodeServicesContext>(val nodeServicesContext: T) : NodeLifecycleEvent(reversedPriority = true) class BeforeNodeStop<out T : NodeServicesContext>(val nodeServicesContext: T) : NodeLifecycleEvent(reversedPriority = true)

View File

@ -58,7 +58,7 @@ internal class AMQPChannelHandler(private val serverMode: Boolean,
private var remoteCert: X509Certificate? = null private var remoteCert: X509Certificate? = null
private var eventProcessor: EventProcessor? = null private var eventProcessor: EventProcessor? = null
private var suppressClose: Boolean = false private var suppressClose: Boolean = false
private var badCert: Boolean = false private var connectionResult: ConnectionResult = ConnectionResult.NO_ERROR
private var localCert: X509Certificate? = null private var localCert: X509Certificate? = null
private var requestedServerName: String? = null private var requestedServerName: String? = null
@ -130,7 +130,7 @@ internal class AMQPChannelHandler(private val serverMode: Boolean,
val ch = ctx.channel() val ch = ctx.channel()
logInfoWithMDC { "Closed client connection ${ch.id()} from $remoteAddress to ${ch.localAddress()}" } logInfoWithMDC { "Closed client connection ${ch.id()} from $remoteAddress to ${ch.localAddress()}" }
if (!suppressClose) { if (!suppressClose) {
onClose(ch as SocketChannel, ConnectionChange(remoteAddress, remoteCert, false, badCert)) onClose(ch as SocketChannel, ConnectionChange(remoteAddress, remoteCert, false, connectionResult))
} }
eventProcessor?.close() eventProcessor?.close()
ctx.fireChannelInactive() ctx.fireChannelInactive()
@ -273,13 +273,13 @@ internal class AMQPChannelHandler(private val serverMode: Boolean,
val remoteX500Name = try { val remoteX500Name = try {
CordaX500Name.build(remoteCert!!.subjectX500Principal) CordaX500Name.build(remoteCert!!.subjectX500Principal)
} catch (ex: IllegalArgumentException) { } catch (ex: IllegalArgumentException) {
badCert = true connectionResult = ConnectionResult.HANDSHAKE_FAILURE
logErrorWithMDC("Certificate subject not a valid CordaX500Name", ex) logErrorWithMDC("Certificate subject not a valid CordaX500Name", ex)
ctx.close() ctx.close()
return return
} }
if (allowedRemoteLegalNames != null && remoteX500Name !in allowedRemoteLegalNames) { if (allowedRemoteLegalNames != null && remoteX500Name !in allowedRemoteLegalNames) {
badCert = true connectionResult = ConnectionResult.HANDSHAKE_FAILURE
logErrorWithMDC("Provided certificate subject $remoteX500Name not in expected set $allowedRemoteLegalNames") logErrorWithMDC("Provided certificate subject $remoteX500Name not in expected set $allowedRemoteLegalNames")
ctx.close() ctx.close()
return return
@ -287,7 +287,7 @@ internal class AMQPChannelHandler(private val serverMode: Boolean,
logInfoWithMDC { "Handshake completed with subject: $remoteX500Name, requested server name: ${sslHandler.getRequestedServerName()}." } logInfoWithMDC { "Handshake completed with subject: $remoteX500Name, requested server name: ${sslHandler.getRequestedServerName()}." }
createAMQPEngine(ctx) createAMQPEngine(ctx)
onOpen(ctx.channel() as SocketChannel, ConnectionChange(remoteAddress, remoteCert, connected = true, badCert = false)) onOpen(ctx.channel() as SocketChannel, ConnectionChange(remoteAddress, remoteCert, connected = true, connectionResult = ConnectionResult.NO_ERROR))
} }
private fun handleFailedHandshake(ctx: ChannelHandlerContext, evt: SslHandshakeCompletionEvent) { private fun handleFailedHandshake(ctx: ChannelHandlerContext, evt: SslHandshakeCompletionEvent) {
@ -301,7 +301,7 @@ internal class AMQPChannelHandler(private val serverMode: Boolean,
// io.netty.handler.ssl.SslHandler.setHandshakeFailureTransportFailure() // io.netty.handler.ssl.SslHandler.setHandshakeFailureTransportFailure()
cause is SSLException && (cause.message?.contains("writing TLS control frames") == true) -> logWarnWithMDC(cause.message!!) cause is SSLException && (cause.message?.contains("writing TLS control frames") == true) -> logWarnWithMDC(cause.message!!)
cause is SSLException && (cause.message?.contains("internal_error") == true) -> logWarnWithMDC("Received internal_error during handshake") cause is SSLException && (cause.message?.contains("internal_error") == true) -> logWarnWithMDC("Received internal_error during handshake")
else -> badCert = true else -> connectionResult = ConnectionResult.HANDSHAKE_FAILURE
} }
if (log.isTraceEnabled) { if (log.isTraceEnabled) {
withMDC { log.trace("Handshake failure", cause) } withMDC { log.trace("Handshake failure", cause) }

View File

@ -35,6 +35,7 @@ import java.net.InetSocketAddress
import java.util.concurrent.Executor import java.util.concurrent.Executor
import java.util.concurrent.ExecutorService import java.util.concurrent.ExecutorService
import java.util.concurrent.ThreadPoolExecutor import java.util.concurrent.ThreadPoolExecutor
import java.time.Duration
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock import kotlin.concurrent.withLock
@ -78,6 +79,7 @@ class AMQPClient(private val targets: List<NetworkHostAndPort>,
private const val MAX_RETRY_INTERVAL = 60000L private const val MAX_RETRY_INTERVAL = 60000L
private const val BACKOFF_MULTIPLIER = 2L private const val BACKOFF_MULTIPLIER = 2L
private val NUM_CLIENT_THREADS = Integer.getInteger(CORDA_AMQP_NUM_CLIENT_THREAD_PROP_NAME, 2) private val NUM_CLIENT_THREADS = Integer.getInteger(CORDA_AMQP_NUM_CLIENT_THREAD_PROP_NAME, 2)
private val handshakeRetryIntervals = List(5) { Duration.ofMinutes(5) }
} }
private val lock = ReentrantLock() private val lock = ReentrantLock()
@ -89,7 +91,9 @@ class AMQPClient(private val targets: List<NetworkHostAndPort>,
private var targetIndex = 0 private var targetIndex = 0
private var currentTarget: NetworkHostAndPort = targets.first() private var currentTarget: NetworkHostAndPort = targets.first()
private var retryInterval = MIN_RETRY_INTERVAL private var retryInterval = MIN_RETRY_INTERVAL
private val badCertTargets = mutableSetOf<NetworkHostAndPort>() private val handshakeFailureRetryTargets = mutableSetOf<NetworkHostAndPort>()
private var retryingHandshakeFailures = false
private var retryOffset = 0
@Volatile @Volatile
private var amqpActive = false private var amqpActive = false
@Volatile @Volatile
@ -98,22 +102,67 @@ class AMQPClient(private val targets: List<NetworkHostAndPort>,
val localAddressString: String val localAddressString: String
get() = clientChannel?.localAddress()?.toString() ?: "<unknownLocalAddress>" get() = clientChannel?.localAddress()?.toString() ?: "<unknownLocalAddress>"
private fun nextTarget() { /*
Figure out the index of the next address to try to connect to
*/
private fun setTargetIndex() {
val origIndex = targetIndex val origIndex = targetIndex
targetIndex = -1 targetIndex = -1
for (offset in 1..targets.size) { for (offset in 1..targets.size) {
val newTargetIndex = (origIndex + offset).rem(targets.size) val newTargetIndex = (origIndex + offset).rem(targets.size)
if (targets[newTargetIndex] !in badCertTargets) { if (targets[newTargetIndex] !in handshakeFailureRetryTargets ) {
targetIndex = newTargetIndex targetIndex = newTargetIndex
break break
} }
} }
if (targetIndex == -1) { }
log.error("No targets have presented acceptable certificates for $allowedRemoteLegalNames. Halting retries")
return /*
Set how long to wait until trying to connect to the next address
*/
private fun setTargetRetryInterval() {
retryInterval = if (retryingHandshakeFailures) {
if (retryOffset < handshakeRetryIntervals.size) {
handshakeRetryIntervals[retryOffset++].toMillis()
} else {
Duration.ofDays(1).toMillis()
}
} else {
min(MAX_RETRY_INTERVAL, retryInterval * BACKOFF_MULTIPLIER)
} }
log.info("Retry connect to ${targets[targetIndex]}") }
retryInterval = min(MAX_RETRY_INTERVAL, retryInterval * BACKOFF_MULTIPLIER)
/*
Once a connection is made, reset all the retry-connection info so if there is another connection failure
then this node tries to reconnect quickly.
*/
private fun successfullyConnected() {
log.info("Successfully connected to [${targets[targetIndex]}]; resetting the target connection-retry interval")
retryingHandshakeFailures = false
retryInterval = MIN_RETRY_INTERVAL
retryOffset = 0
}
/*
Set the next target to connect to
*/
private fun nextTarget() {
setTargetIndex()
if (targetIndex == -1) {
if (handshakeFailureRetryTargets.isNotEmpty()) {
log.info("Failed to connect to any targets. Retrying targets that previously failed to handshake.")
handshakeFailureRetryTargets.clear()
retryingHandshakeFailures = true
setTargetIndex()
} else {
log.error("Attempted connection to targets: $targets, but none of them have presented acceptable certificates" +
" for $allowedRemoteLegalNames. Halting retries.")
return
}
}
setTargetRetryInterval()
log.info("Retry connect to ${targets[targetIndex]} in [$retryInterval] ms")
} }
private val connectListener = ChannelFutureListener { future -> private val connectListener = ChannelFutureListener { future ->
@ -238,7 +287,7 @@ class AMQPClient(private val targets: List<NetworkHostAndPort>,
private fun onChannelOpen(change: ConnectionChange) { private fun onChannelOpen(change: ConnectionChange) {
parent.run { parent.run {
amqpActive = true amqpActive = true
retryInterval = MIN_RETRY_INTERVAL // reset to fast reconnect if we connect properly successfullyConnected()
_onConnection.onNext(change) _onConnection.onNext(change)
} }
} }
@ -247,9 +296,9 @@ class AMQPClient(private val targets: List<NetworkHostAndPort>,
if (parent.amqpChannelHandler != amqpChannelHandler) return if (parent.amqpChannelHandler != amqpChannelHandler) return
parent.run { parent.run {
_onConnection.onNext(change) _onConnection.onNext(change)
if (change.badCert) { if (change.connectionResult == ConnectionResult.HANDSHAKE_FAILURE) {
log.error("Blocking future connection attempts to $target due to bad certificate on endpoint") log.warn("Handshake failure with $target target; will retry later")
badCertTargets += target handshakeFailureRetryTargets += target
} }
if (started && amqpActive) { if (started && amqpActive) {

View File

@ -3,8 +3,8 @@ package net.corda.nodeapi.internal.protonwrapper.netty
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
data class ConnectionChange(val remoteAddress: InetSocketAddress, val remoteCert: X509Certificate?, val connected: Boolean, val badCert: Boolean) { data class ConnectionChange(val remoteAddress: InetSocketAddress, val remoteCert: X509Certificate?, val connected: Boolean, val connectionResult: ConnectionResult) {
override fun toString(): String { override fun toString(): String {
return "ConnectionChange remoteAddress: $remoteAddress connected state: $connected cert subject: ${remoteCert?.subjectDN} cert ok: ${!badCert}" return "ConnectionChange remoteAddress: $remoteAddress connected state: $connected cert subject: ${remoteCert?.subjectDN} result: ${connectionResult}"
} }
} }

View File

@ -0,0 +1,6 @@
package net.corda.nodeapi.internal.protonwrapper.netty
enum class ConnectionResult {
NO_ERROR,
HANDSHAKE_FAILURE
}

View File

@ -24,7 +24,7 @@ import net.corda.nodeapi.internal.namedThreadPoolExecutor
import net.corda.nodeapi.internal.revocation.CordaRevocationChecker import net.corda.nodeapi.internal.revocation.CordaRevocationChecker
import org.bouncycastle.asn1.ASN1InputStream import org.bouncycastle.asn1.ASN1InputStream
import org.bouncycastle.asn1.ASN1Primitive import org.bouncycastle.asn1.ASN1Primitive
import org.bouncycastle.asn1.DERIA5String import org.bouncycastle.asn1.ASN1IA5String
import org.bouncycastle.asn1.DEROctetString import org.bouncycastle.asn1.DEROctetString
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x509.CRLDistPoint import org.bouncycastle.asn1.x509.CRLDistPoint
@ -96,7 +96,7 @@ fun X509Certificate.distributionPoints(): Map<URI, List<X500Principal>?> {
} }
for (generalName in GeneralNames.getInstance(distributionPointName.name).names) { for (generalName in GeneralNames.getInstance(distributionPointName.name).names) {
if (generalName.tagNo == GeneralName.uniformResourceIdentifier) { if (generalName.tagNo == GeneralName.uniformResourceIdentifier) {
val uri = URI(DERIA5String.getInstance(generalName.name).string) val uri = URI(ASN1IA5String.getInstance(generalName.name).string)
dpMap[uri] = issuerNames dpMap[uri] = issuerNames
} }
} }

View File

@ -1,17 +1,23 @@
package net.corda.nodeapi.internal.serialization.kryo package net.corda.nodeapi.internal.serialization.kryo
import com.esotericsoftware.kryo.* import com.esotericsoftware.kryo.DefaultSerializer
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.KryoException
import com.esotericsoftware.kryo.KryoSerializable
import com.esotericsoftware.kryo.Registration
import com.esotericsoftware.kryo.Serializer
import com.esotericsoftware.kryo.io.Input import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output import com.esotericsoftware.kryo.io.Output
import com.esotericsoftware.kryo.serializers.FieldSerializer import com.esotericsoftware.kryo.serializers.FieldSerializer
import com.esotericsoftware.kryo.util.DefaultClassResolver import com.esotericsoftware.kryo.util.DefaultClassResolver
import com.esotericsoftware.kryo.util.Util import com.esotericsoftware.kryo.util.Util
import net.corda.core.internal.kotlinObjectInstance import net.corda.core.internal.kotlinObjectInstance
import net.corda.core.internal.utilities.PrivateInterner
import net.corda.core.internal.writer import net.corda.core.internal.writer
import net.corda.core.serialization.internal.CheckpointSerializationContext
import net.corda.core.serialization.ClassWhitelist import net.corda.core.serialization.ClassWhitelist
import net.corda.core.utilities.contextLogger
import net.corda.core.serialization.internal.AttachmentsClassLoader import net.corda.core.serialization.internal.AttachmentsClassLoader
import net.corda.core.serialization.internal.CheckpointSerializationContext
import net.corda.core.utilities.contextLogger
import net.corda.serialization.internal.MutableClassWhitelist import net.corda.serialization.internal.MutableClassWhitelist
import net.corda.serialization.internal.TransientClassWhiteList import net.corda.serialization.internal.TransientClassWhiteList
import net.corda.serialization.internal.amqp.hasCordaSerializable import net.corda.serialization.internal.amqp.hasCordaSerializable
@ -19,8 +25,11 @@ import java.io.PrintWriter
import java.lang.reflect.Modifier.isAbstract import java.lang.reflect.Modifier.isAbstract
import java.nio.charset.StandardCharsets.UTF_8 import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.Paths import java.nio.file.Paths
import java.nio.file.StandardOpenOption.* import java.nio.file.StandardOpenOption.APPEND
import java.util.* import java.nio.file.StandardOpenOption.CREATE
import java.nio.file.StandardOpenOption.WRITE
import java.util.ArrayList
import java.util.Collections
/** /**
* Corda specific class resolver which enables extra customisation for the purposes of serialization using Kryo * Corda specific class resolver which enables extra customisation for the purposes of serialization using Kryo
@ -86,7 +95,7 @@ class CordaClassResolver(serializationContext: CheckpointSerializationContext) :
kotlin.jvm.internal.Lambda::class.java.isAssignableFrom(targetType) -> // Kotlin lambdas extend this class and any captured variables are stored in synthetic fields kotlin.jvm.internal.Lambda::class.java.isAssignableFrom(targetType) -> // Kotlin lambdas extend this class and any captured variables are stored in synthetic fields
FieldSerializer<Any>(kryo, targetType).apply { setIgnoreSyntheticFields(false) } FieldSerializer<Any>(kryo, targetType).apply { setIgnoreSyntheticFields(false) }
Throwable::class.java.isAssignableFrom(targetType) -> ThrowableSerializer(kryo, targetType) Throwable::class.java.isAssignableFrom(targetType) -> ThrowableSerializer(kryo, targetType)
else -> kryo.getDefaultSerializer(targetType) else -> maybeWrapForInterning(kryo.getDefaultSerializer(targetType), targetType)
} }
return register(Registration(targetType, serializer, NAME.toInt())) return register(Registration(targetType, serializer, NAME.toInt()))
} finally { } finally {
@ -94,6 +103,11 @@ class CordaClassResolver(serializationContext: CheckpointSerializationContext) :
} }
} }
private fun maybeWrapForInterning(serializer: Serializer<Any>, targetType: Class<*>): Serializer<Any> {
val interner = PrivateInterner.findFor(targetType)
return if (interner != null) InterningSerializer(serializer, interner) else serializer
}
override fun writeName(output: Output, type: Class<*>, registration: Registration) { override fun writeName(output: Output, type: Class<*>, registration: Registration) {
super.writeName(output, registration.type ?: type, registration) super.writeName(output, registration.type ?: type, registration)
} }
@ -104,6 +118,11 @@ class CordaClassResolver(serializationContext: CheckpointSerializationContext) :
override fun write(kryo: Kryo, output: Output, obj: Any) = Unit override fun write(kryo: Kryo, output: Output, obj: Any) = Unit
} }
private class InterningSerializer(private val delegate: Serializer<Any>, private val interner: PrivateInterner<Any>) : Serializer<Any>() {
override fun read(kryo: Kryo, input: Input, type: Class<Any>): Any = interner.intern(delegate.read(kryo, input, type))
override fun write(kryo: Kryo, output: Output, obj: Any) = delegate.write(kryo, output, obj)
}
// We don't allow the annotation for classes in attachments for now. The class will be on the main classpath if we have the CorDapp installed. // We don't allow the annotation for classes in attachments for now. The class will be on the main classpath if we have the CorDapp installed.
// We also do not allow extension of KryoSerializable for annotated classes, or combination with @DefaultSerializer for custom serialisation. // We also do not allow extension of KryoSerializable for annotated classes, or combination with @DefaultSerializer for custom serialisation.
// TODO: Later we can support annotations on attachment classes and spin up a proxy via bytecode that we know is harmless. // TODO: Later we can support annotations on attachment classes and spin up a proxy via bytecode that we know is harmless.

View File

@ -59,9 +59,8 @@ import java.security.PrivateKey
import java.security.PublicKey import java.security.PublicKey
import java.security.cert.CertPath import java.security.cert.CertPath
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import java.util.Arrays import java.util.*
import java.util.BitSet import kotlin.collections.ArrayList
import java.util.ServiceLoader
object DefaultKryoCustomizer { object DefaultKryoCustomizer {
private val serializationWhitelists: List<SerializationWhitelist> by lazy { private val serializationWhitelists: List<SerializationWhitelist> by lazy {
@ -233,7 +232,7 @@ object DefaultKryoCustomizer {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
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.createSHA256(input.readBytes(32))
val contract = input.readString() val contract = input.readString()
val additionalContracts = kryo.readClassAndObject(input) as Set<ContractClassName> val additionalContracts = kryo.readClassAndObject(input) as Set<ContractClassName>
val uploader = input.readString() val uploader = input.readString()

View File

@ -9,22 +9,38 @@ import com.google.common.primitives.Ints
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.contracts.PrivacySalt import net.corda.core.contracts.PrivacySalt
import net.corda.core.crypto.* import net.corda.core.contracts.SignatureAttachmentConstraint
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignableData
import net.corda.core.crypto.SignatureMetadata
import net.corda.core.crypto.generateKeyPair
import net.corda.core.crypto.sha256
import net.corda.core.crypto.sign
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.internal.FetchDataFlow import net.corda.core.internal.FetchDataFlow
import net.corda.core.serialization.* import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.EncodingWhitelist
import net.corda.core.serialization.internal.CheckpointSerializationContext import net.corda.core.serialization.internal.CheckpointSerializationContext
import net.corda.core.serialization.internal.checkpointDeserialize import net.corda.core.serialization.internal.checkpointDeserialize
import net.corda.core.serialization.internal.checkpointSerialize import net.corda.core.serialization.internal.checkpointSerialize
import net.corda.core.utilities.ByteSequence import net.corda.core.utilities.ByteSequence
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.sequence import net.corda.core.utilities.sequence
import net.corda.serialization.internal.* import net.corda.coretesting.internal.rigorousMock
import net.corda.serialization.internal.AllWhitelist
import net.corda.serialization.internal.CheckpointSerializationContextImpl
import net.corda.serialization.internal.CordaSerializationEncoding
import net.corda.serialization.internal.encodingNotPermittedFormat
import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.TestIdentity import net.corda.testing.core.TestIdentity
import net.corda.testing.core.internal.CheckpointSerializationEnvironmentRule import net.corda.testing.core.internal.CheckpointSerializationEnvironmentRule
import net.corda.coretesting.internal.rigorousMock
import org.apache.commons.lang3.SystemUtils import org.apache.commons.lang3.SystemUtils
import org.assertj.core.api.Assertions.* import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.assertj.core.api.Assertions.catchThrowable
import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
@ -36,9 +52,13 @@ import org.junit.runners.Parameterized.Parameters
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.InputStream import java.io.InputStream
import java.time.Instant import java.time.Instant
import java.util.* import java.util.Collections
import kotlin.collections.ArrayList import java.util.Random
import kotlin.test.* import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertSame
import kotlin.test.assertTrue
@RunWith(Parameterized::class) @RunWith(Parameterized::class)
class KryoTests(private val compression: CordaSerializationEncoding?) { class KryoTests(private val compression: CordaSerializationEncoding?) {
@ -129,6 +149,7 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
val deserialisedSignature = deserialisedKeyPair.sign(bitsToSign) val deserialisedSignature = deserialisedKeyPair.sign(bitsToSign)
deserialisedSignature.verify(bitsToSign) deserialisedSignature.verify(bitsToSign)
assertThatThrownBy { deserialisedSignature.verify(wrongBits) } assertThatThrownBy { deserialisedSignature.verify(wrongBits) }
assertSame(keyPair.public, deserialisedKeyPair.public)
} }
@Test(timeout=300_000) @Test(timeout=300_000)
@ -178,7 +199,7 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
} }
@Test(timeout=300_000) @Test(timeout=300_000)
fun `serialize - deserialize SignableData`() { fun `serialize - deserialize SignableData`() {
val testString = "Hello World" val testString = "Hello World"
val testBytes = testString.toByteArray() val testBytes = testString.toByteArray()
@ -186,15 +207,33 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
val serializedMetaData = meta.checkpointSerialize(context).bytes val serializedMetaData = meta.checkpointSerialize(context).bytes
val meta2 = serializedMetaData.checkpointDeserialize<SignableData>(context) val meta2 = serializedMetaData.checkpointDeserialize<SignableData>(context)
assertEquals(meta2, meta) assertEquals(meta2, meta)
assertSame(meta.txId, meta2.txId)
} }
@Test(timeout=300_000) @Test(timeout = 300_000)
fun `serialize - deserialize Logger`() { fun `serialize - deserialize internables`() {
val list: List<Any> = listOf(
SecureHash.randomSHA256(),
CordaX500Name.parse("O=bank A, L=New York, C=DE, OU=Org Unit, CN=Service Name"),
Party.create(CordaX500Name.parse("O=bank A, L=New York, C=DE, OU=Org Unit, CN=Service Name"), Crypto.generateKeyPair().public),
AnonymousParty.create(Crypto.generateKeyPair().public),
SignatureAttachmentConstraint.create(Crypto.generateKeyPair().public)
)
val serializedList = list.checkpointSerialize(context).bytes
val list2 = serializedList.checkpointDeserialize<List<Any>>(context)
list.zip(list2).forEach { (original, deserialized) ->
assertSame(original, deserialized, "${original.javaClass} not interned")
}
}
@Test(timeout = 300_000)
fun `serialize - deserialize Logger`() {
val storageContext: CheckpointSerializationContext = context val storageContext: CheckpointSerializationContext = context
val logger = LoggerFactory.getLogger("aName") val logger = LoggerFactory.getLogger("aName")
val logger2 = logger.checkpointSerialize(storageContext).checkpointDeserialize(storageContext) val logger2 = logger.checkpointSerialize(storageContext).checkpointDeserialize(storageContext)
assertEquals(logger.name, logger2.name) assertEquals(logger.name, logger2.name)
assertTrue(logger === logger2) assertSame(logger, logger2)
} }
@CordaSerializable @CordaSerializable

View File

@ -100,6 +100,7 @@ dependencies {
compile project(':common-configuration-parsing') compile project(':common-configuration-parsing')
compile project(':common-logging') compile project(':common-logging')
implementation "io.opentelemetry:opentelemetry-api:${open_telemetry_version}"
// Backwards compatibility goo: Apps expect confidential-identities to be loaded by default. // Backwards compatibility goo: Apps expect confidential-identities to be loaded by default.
// We could eventually gate this on a target-version check. // We could eventually gate this on a target-version check.
compile project(':confidential-identities') compile project(':confidential-identities')
@ -309,7 +310,8 @@ quasar {
"org.w3c.**", "org.w3c.**",
"org.xml**", "org.xml**",
"org.yaml**", "org.yaml**",
"rx**") "rx**",
"io.opentelemetry.**")
} }
jar { jar {

View File

@ -96,7 +96,7 @@ task buildCordaJAR(type: FatCapsule, dependsOn: [
applicationVersion = corda_release_version applicationVersion = corda_release_version
applicationId = "net.corda.node.Corda" applicationId = "net.corda.node.Corda"
// See experimental/quasar-hook/README.md for how to generate. // See experimental/quasar-hook/README.md for how to generate.
def quasarExcludeExpression = "x(antlr**;bftsmart**;co.paralleluniverse**;com.codahale**;com.esotericsoftware**;com.fasterxml**;com.google**;com.ibm**;com.intellij**;com.jcabi**;com.nhaarman**;com.opengamma**;com.typesafe**;com.zaxxer**;de.javakaffee**;groovy**;groovyjarjarantlr**;groovyjarjarasm**;io.atomix**;io.github**;io.netty**;jdk**;kotlin**;net.corda.djvm**;djvm**;net.bytebuddy**;net.i2p**;org.apache**;org.bouncycastle**;org.codehaus**;org.crsh**;org.dom4j**;org.fusesource**;org.h2**;org.hibernate**;org.jboss**;org.jcp**;org.joda**;org.objectweb**;org.objenesis**;org.slf4j**;org.w3c**;org.xml**;org.yaml**;reflectasm**;rx**;org.jolokia**;com.lmax**;picocli**;liquibase**;com.github.benmanes**;org.json**;org.postgresql**;nonapi.io.github.classgraph**)" def quasarExcludeExpression = "x(antlr**;bftsmart**;co.paralleluniverse**;com.codahale**;com.esotericsoftware**;com.fasterxml**;com.google**;com.ibm**;com.intellij**;com.jcabi**;com.nhaarman**;com.opengamma**;com.typesafe**;com.zaxxer**;de.javakaffee**;groovy**;groovyjarjarantlr**;groovyjarjarasm**;io.atomix**;io.github**;io.netty**;jdk**;kotlin**;net.corda.djvm**;djvm**;net.bytebuddy**;net.i2p**;org.apache**;org.bouncycastle**;org.codehaus**;org.crsh**;org.dom4j**;org.fusesource**;org.h2**;org.hibernate**;org.jboss**;org.jcp**;org.joda**;org.objectweb**;org.objenesis**;org.slf4j**;org.w3c**;org.xml**;org.yaml**;reflectasm**;rx**;org.jolokia**;com.lmax**;picocli**;liquibase**;com.github.benmanes**;org.json**;org.postgresql**;nonapi.io.github.classgraph**;io.opentelemetry**)"
def quasarClassLoaderExclusion = "l(net.corda.djvm.**;net.corda.core.serialization.internal.**)" def quasarClassLoaderExclusion = "l(net.corda.djvm.**;net.corda.core.serialization.internal.**)"
javaAgents = quasar_classifier ? ["quasar-core-${quasar_version}-${quasar_classifier}.jar=${quasarExcludeExpression}${quasarClassLoaderExclusion}"] : ["quasar-core-${quasar_version}.jar=${quasarExcludeExpression}${quasarClassLoaderExclusion}"] javaAgents = quasar_classifier ? ["quasar-core-${quasar_version}-${quasar_classifier}.jar=${quasarExcludeExpression}${quasarClassLoaderExclusion}"] : ["quasar-core-${quasar_version}.jar=${quasarExcludeExpression}${quasarClassLoaderExclusion}"]
systemProperties['visualvm.display.name'] = 'Corda' systemProperties['visualvm.display.name'] = 'Corda'

View File

@ -14,6 +14,7 @@ import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.configureWithDevSSLCertificate import net.corda.node.services.config.configureWithDevSSLCertificate
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPClient import net.corda.nodeapi.internal.protonwrapper.netty.AMQPClient
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPConfiguration import net.corda.nodeapi.internal.protonwrapper.netty.AMQPConfiguration
import net.corda.nodeapi.internal.protonwrapper.netty.ConnectionResult
import net.corda.nodeapi.internal.protonwrapper.netty.RevocationConfig import net.corda.nodeapi.internal.protonwrapper.netty.RevocationConfig
import net.corda.nodeapi.internal.protonwrapper.netty.RevocationConfigImpl import net.corda.nodeapi.internal.protonwrapper.netty.RevocationConfigImpl
import net.corda.nodeapi.internal.protonwrapper.netty.keyManagerFactory import net.corda.nodeapi.internal.protonwrapper.netty.keyManagerFactory
@ -33,6 +34,7 @@ import org.junit.runners.Parameterized
import java.time.Duration import java.time.Duration
import javax.net.ssl.KeyManagerFactory import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.TrustManagerFactory import javax.net.ssl.TrustManagerFactory
import kotlin.test.assertEquals
import kotlin.test.assertFalse import kotlin.test.assertFalse
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -219,7 +221,7 @@ class AMQPClientSslErrorsTest(@Suppress("unused") private val iteration: Int) {
val clientConnect = clientConnected.get() val clientConnect = clientConnected.get()
assertFalse(clientConnect.connected) assertFalse(clientConnect.connected)
// Not a badCert, but a timeout during handshake // Not a badCert, but a timeout during handshake
assertFalse(clientConnect.badCert) assertEquals(ConnectionResult.NO_ERROR, clientConnect.connectionResult)
} }
} }
assertFalse(serverThread.isActive) assertFalse(serverThread.isActive)

View File

@ -26,6 +26,7 @@ import net.corda.nodeapi.internal.protonwrapper.messages.MessageStatus
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPClient import net.corda.nodeapi.internal.protonwrapper.netty.AMQPClient
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPConfiguration import net.corda.nodeapi.internal.protonwrapper.netty.AMQPConfiguration
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPServer import net.corda.nodeapi.internal.protonwrapper.netty.AMQPServer
import net.corda.nodeapi.internal.protonwrapper.netty.init
import net.corda.nodeapi.internal.protonwrapper.netty.keyManagerFactory import net.corda.nodeapi.internal.protonwrapper.netty.keyManagerFactory
import net.corda.nodeapi.internal.protonwrapper.netty.toRevocationConfig import net.corda.nodeapi.internal.protonwrapper.netty.toRevocationConfig
import net.corda.nodeapi.internal.protonwrapper.netty.trustManagerFactory import net.corda.nodeapi.internal.protonwrapper.netty.trustManagerFactory
@ -38,6 +39,7 @@ import net.corda.testing.driver.internal.incrementalPortAllocation
import net.corda.testing.internal.createDevIntermediateCaCertPath import net.corda.testing.internal.createDevIntermediateCaCertPath
import org.apache.activemq.artemis.api.core.QueueConfiguration import org.apache.activemq.artemis.api.core.QueueConfiguration
import org.apache.activemq.artemis.api.core.RoutingType import org.apache.activemq.artemis.api.core.RoutingType
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertArrayEquals
import org.junit.Rule import org.junit.Rule
@ -45,11 +47,14 @@ import org.junit.Test
import org.junit.rules.TemporaryFolder import org.junit.rules.TemporaryFolder
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext import javax.net.ssl.SSLContext
import javax.net.ssl.SSLException
import javax.net.ssl.SSLHandshakeException import javax.net.ssl.SSLHandshakeException
import javax.net.ssl.SSLParameters import javax.net.ssl.SSLParameters
import javax.net.ssl.SSLServerSocket import javax.net.ssl.SSLServerSocket
import javax.net.ssl.SSLSocket import javax.net.ssl.SSLSocket
import javax.net.ssl.TrustManagerFactory
import kotlin.concurrent.thread import kotlin.concurrent.thread
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -208,6 +213,103 @@ class ProtonWrapperTests {
assertTrue(done) assertTrue(done)
} }
@Suppress("TooGenericExceptionCaught") // Too generic exception thrown!
@Test(timeout=300_000)
fun `AMPQClient that fails to handshake with a server will retry the server`() {
/*
This test has been modelled on `Test AMQP Client with invalid root certificate`, above.
The aim is to set up a server with an invalid root cert so that the TLS handshake will fail.
The test allows the AMQPClient to retry the connection (which it should do).
*/
val certificatesDirectory = temporaryFolder.root.toPath()
val signingCertificateStore = CertificateStoreStubs.Signing.withCertificatesDirectory(certificatesDirectory, "serverstorepass")
val sslConfig = CertificateStoreStubs.P2P.withCertificatesDirectory(certificatesDirectory, keyStorePassword = "serverstorepass")
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
// Generate server cert and private key and populate another keystore suitable for SSL
signingCertificateStore.get(true).also { it.installDevNodeCaCertPath(ALICE_NAME, rootCa.certificate, intermediateCa) }
sslConfig.keyStore.get(true).also { it.registerDevP2pCertificates(ALICE_NAME, rootCa.certificate, intermediateCa) }
sslConfig.createTrustStore(rootCa.certificate)
val keyStore = sslConfig.keyStore.get()
val trustStore = sslConfig.trustStore.get()
val context = SSLContext.getInstance("TLS")
val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
keyManagerFactory.init(keyStore)
val keyManagers = keyManagerFactory.keyManagers
val trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
trustMgrFactory.init(trustStore.value.internal)
val trustManagers = trustMgrFactory.trustManagers
context.init(keyManagers, trustManagers, newSecureRandom())
val serverSocketFactory = context.serverSocketFactory
val serverSocket = serverSocketFactory.createServerSocket(serverPort) as SSLServerSocket
val serverParams = SSLParameters(ArtemisTcpTransport.CIPHER_SUITES.toTypedArray(),
arrayOf("TLSv1.2"))
serverParams.wantClientAuth = true
serverParams.needClientAuth = true
serverParams.endpointIdentificationAlgorithm = null // Reconfirm default no server name indication, use our own validator.
serverSocket.sslParameters = serverParams
serverSocket.useClientMode = false
var done = false
var handshakeErrorCount = 0
//
// This is the thread that acts as the server-side endpoint for the AMQPClient to connect to.
//
val serverThread = thread {
//
// The server thread will keep making itself available for SSL connections until
// the 'done' flag is set by the client thread, later on.
//
while (!done) {
try {
val sslServerSocket = serverSocket.accept() as SSLSocket
sslServerSocket.addHandshakeCompletedListener {
done = true
}
sslServerSocket.startHandshake()
} catch (ex: SSLException) {
++handshakeErrorCount
} catch (e: Throwable) {
println(e)
}
}
}
//
// Create the AMQPClient but only specify one server endpoint to connect to.
//
val amqpClient = createClient(serverAddressList = listOf(NetworkHostAndPort("localhost", serverPort)))
amqpClient.use {
amqpClient.start()
//
// Waiting for the number of handshake errors to get to at least 2.
// This happens when the AMQPClient has made it's first retry attempt, which is
// what this test is interested in.
//
while (handshakeErrorCount < 2) {
Thread.sleep(2)
}
done = true
}
serverThread.join(1000)
//
// check that there was at least one retry i.e. > 1 handshake error.
//
Assertions.assertThat(handshakeErrorCount > 1).isTrue()
serverSocket.close()
assertTrue(done)
}
@Test(timeout=300_000) @Test(timeout=300_000)
fun `Client Failover for multiple IP`() { fun `Client Failover for multiple IP`() {
@ -451,7 +553,11 @@ class ProtonWrapperTests {
return Pair(server, client) return Pair(server, client)
} }
private fun createClient(maxMessageSize: Int = MAX_MESSAGE_SIZE): AMQPClient { private fun createClient(maxMessageSize: Int = MAX_MESSAGE_SIZE,
serverAddressList: List<NetworkHostAndPort> = listOf(
NetworkHostAndPort("localhost", serverPort),
NetworkHostAndPort("localhost", serverPort2),
NetworkHostAndPort("localhost", artemisPort))): AMQPClient {
val baseDirectory = temporaryFolder.root.toPath() / "client" val baseDirectory = temporaryFolder.root.toPath() / "client"
val certificatesDirectory = baseDirectory / "certificates" val certificatesDirectory = baseDirectory / "certificates"
val signingCertificateStore = CertificateStoreStubs.Signing.withCertificatesDirectory(certificatesDirectory) val signingCertificateStore = CertificateStoreStubs.Signing.withCertificatesDirectory(certificatesDirectory)
@ -475,9 +581,7 @@ class ProtonWrapperTests {
override val maxMessageSize: Int = maxMessageSize override val maxMessageSize: Int = maxMessageSize
} }
return AMQPClient( return AMQPClient(
listOf(NetworkHostAndPort("localhost", serverPort), serverAddressList,
NetworkHostAndPort("localhost", serverPort2),
NetworkHostAndPort("localhost", artemisPort)),
setOf(ALICE_NAME, CHARLIE_NAME), setOf(ALICE_NAME, CHARLIE_NAME),
amqpConfig) amqpConfig)
} }

View File

@ -16,6 +16,7 @@ import net.corda.core.internal.concurrent.transpose
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
import net.corda.core.node.AppServiceHub import net.corda.core.node.AppServiceHub
import net.corda.core.node.services.CordaService import net.corda.core.node.services.CordaService
import net.corda.core.node.services.ServiceLifecycleEvent
import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
@ -854,19 +855,25 @@ class FlowEntityManagerTest : AbstractFlowEntityManagerTest() {
init { init {
if (includeRawUpdates) { if (includeRawUpdates) {
services.register { services.register {
services.vaultService.rawUpdates.subscribe { processEvent(it)
if (insertionType == InsertionType.ENTITY_MANAGER) { }
services.withEntityManager { }
persist(entityWithIdOne) }
persist(entityWithIdTwo)
persist(entityWithIdThree) private fun processEvent(event : ServiceLifecycleEvent) {
} if (event == ServiceLifecycleEvent.STATE_MACHINE_STARTED) {
} else { services.vaultService.rawUpdates.subscribe {
services.jdbcSession().run { if (insertionType == InsertionType.ENTITY_MANAGER) {
insert(entityWithIdOne) services.withEntityManager {
insert(entityWithIdTwo) persist(entityWithIdOne)
insert(entityWithIdThree) persist(entityWithIdTwo)
} persist(entityWithIdThree)
}
} else {
services.jdbcSession().run {
insert(entityWithIdOne)
insert(entityWithIdTwo)
insert(entityWithIdThree)
} }
} }
} }

View File

@ -0,0 +1,42 @@
package net.corda.node.jmx
import com.fasterxml.jackson.databind.ObjectMapper
import net.corda.nodeapi.internal.NodeStatus
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.JmxPolicy
import net.corda.testing.driver.driver
import org.junit.Test
import java.net.HttpURLConnection
import java.net.HttpURLConnection.HTTP_OK
import java.net.URL
import java.util.stream.Collectors
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class NodeStatusTest {
@Test(timeout=300_000)
fun `node status is published via JMX`() {
driver(DriverParameters(notarySpecs = emptyList(), jmxPolicy = JmxPolicy.defaultEnabled())) {
val jmxAddress = startNode().get().jmxAddress.toString()
val nodeStatusURL = URL("http://$jmxAddress/jolokia/read/net.corda:name=Status,type=Node")
val jmxInfo = with(nodeStatusURL.openConnection() as HttpURLConnection) {
requestMethod = "GET"
inputStream.bufferedReader().use {
it.lines().collect(Collectors.toList()).joinToString()
}
}
assertTrue {
jmxInfo.isNotEmpty()
}
val jsonTree = ObjectMapper().readTree(jmxInfo)
val httpStatus = jsonTree.get("status").asInt()
val nodeStatus = jsonTree.get("value").get("Value").asText()
assertEquals(httpStatus, HTTP_OK)
assertEquals(nodeStatus, NodeStatus.STARTED.toString())
}
}
}

View File

@ -0,0 +1,28 @@
package net.corda.node.jmx
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.JmxPolicy
import net.corda.testing.driver.driver
import org.junit.Test
import java.net.HttpURLConnection
import java.net.URL
import kotlin.test.assertTrue
class PublishTest {
@Test(timeout=300_000)
fun `node publishes node information via JMX when configured to do so`() {
driver(DriverParameters(notarySpecs = emptyList(), jmxPolicy = JmxPolicy.defaultEnabled())) {
val jmxAddress = startNode().get().jmxAddress.toString()
val nodeStatusURL = URL("http://$jmxAddress/jolokia/read/net.corda:*")
val httpResponse = with(nodeStatusURL.openConnection() as HttpURLConnection) {
requestMethod = "GET"
responseCode
}
assertTrue {
httpResponse == HttpURLConnection.HTTP_OK
}
}
}
}

View File

@ -51,12 +51,14 @@ class CordaServiceLifecycleFatalTests {
object FailingObserver : ServiceLifecycleObserver { object FailingObserver : ServiceLifecycleObserver {
override fun onServiceLifecycleEvent(event: ServiceLifecycleEvent) { override fun onServiceLifecycleEvent(event: ServiceLifecycleEvent) {
val tmpFile = File(System.getProperty(tempFilePropertyName)) if (event == ServiceLifecycleEvent.STATE_MACHINE_STARTED) {
tmpFile.appendText("\n" + readyToThrowMarker) val tmpFile = File(System.getProperty(tempFilePropertyName))
eventually(duration = 30.seconds) { tmpFile.appendText("\n" + readyToThrowMarker)
assertEquals(goodToThrowMarker, tmpFile.readLines().last()) eventually(duration = 30.seconds) {
assertEquals(goodToThrowMarker, tmpFile.readLines().last())
}
throw CordaServiceCriticalFailureException("controlled failure")
} }
throw CordaServiceCriticalFailureException("controlled failure")
} }
} }
} }

View File

@ -3,18 +3,23 @@ package net.corda.node.services
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StartableByRPC import net.corda.core.flows.StartableByRPC
import net.corda.core.flows.StartableByService
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
import net.corda.core.node.AppServiceHub import net.corda.core.node.AppServiceHub
import net.corda.core.node.services.CordaService import net.corda.core.node.services.CordaService
import net.corda.core.node.services.ServiceLifecycleEvent import net.corda.core.node.services.ServiceLifecycleEvent
import net.corda.core.node.services.ServiceLifecycleEvent.BEFORE_STATE_MACHINE_START
import net.corda.core.node.services.ServiceLifecycleEvent.STATE_MACHINE_STARTED import net.corda.core.node.services.ServiceLifecycleEvent.STATE_MACHINE_STARTED
import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.ALICE_NAME
import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.InProcess
import net.corda.testing.driver.driver import net.corda.testing.driver.driver
import net.corda.testing.node.internal.enclosedCordapp import net.corda.testing.node.internal.enclosedCordapp
import org.junit.Before
import org.junit.Test import org.junit.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class CordaServiceLifecycleTests { class CordaServiceLifecycleTests {
@ -22,23 +27,70 @@ class CordaServiceLifecycleTests {
private companion object { private companion object {
const val TEST_PHRASE = "testPhrase" const val TEST_PHRASE = "testPhrase"
// the number of times to register a service callback
private var numServiceCallbacks = 0
// the set of events a test wants to capture
private var eventsToBeCaptured: MutableSet<ServiceLifecycleEvent> = mutableSetOf()
// the events that were actually captured in a test
private val eventsCaptured: MutableList<ServiceLifecycleEvent> = mutableListOf() private val eventsCaptured: MutableList<ServiceLifecycleEvent> = mutableListOf()
}
@Before
fun setup() {
numServiceCallbacks = 1
eventsCaptured.clear()
eventsToBeCaptured = setOf(BEFORE_STATE_MACHINE_START, STATE_MACHINE_STARTED).toMutableSet()
} }
@Test(timeout=300_000) @Test(timeout=300_000)
fun `corda service receives events`() { fun `corda service receives events`() {
eventsCaptured.clear()
val result = driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = listOf(enclosedCordapp()), val result = driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = listOf(enclosedCordapp()),
notarySpecs = emptyList())) { notarySpecs = emptyList())) {
val node = startNode(providedName = ALICE_NAME).getOrThrow() val node = startNode(providedName = ALICE_NAME).getOrThrow()
node.rpc.startFlow(::ComputeTextLengthThroughCordaService, TEST_PHRASE).returnValue.getOrThrow() node.rpc.startFlow(::ComputeTextLengthThroughCordaService, TEST_PHRASE).returnValue.getOrThrow()
} }
val expectedEventsAndTheOrderTheyOccurIn = listOf(BEFORE_STATE_MACHINE_START, STATE_MACHINE_STARTED)
assertEquals(TEST_PHRASE.length, result) assertEquals(TEST_PHRASE.length, result)
assertEquals(1, eventsCaptured.size) assertEquals(numServiceCallbacks * 2, eventsCaptured.size)
assertEquals(listOf(STATE_MACHINE_STARTED), eventsCaptured) assertEquals(expectedEventsAndTheOrderTheyOccurIn, eventsCaptured)
}
@Test(timeout=300_000)
fun `corda service receives BEFORE_STATE_MACHINE_START before the state machine is started`() {
testStateMachineManagerStatusWhenServiceEventOccurs(
event = BEFORE_STATE_MACHINE_START,
expectedResult = TestSmmStateService.STATE_MACHINE_MANAGER_WAS_NOT_STARTED
)
}
@Test(timeout=300_000)
fun `corda service receives STATE_MACHINE_STARTED after the state machine is started`() {
testStateMachineManagerStatusWhenServiceEventOccurs(
event = STATE_MACHINE_STARTED,
expectedResult = TestSmmStateService.STATE_MACHINE_MANAGER_WAS_STARTED
)
}
/**
* Commonised
*/
private fun testStateMachineManagerStatusWhenServiceEventOccurs(event: ServiceLifecycleEvent, expectedResult : Int) {
val result = driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = listOf(enclosedCordapp()),
notarySpecs = emptyList())) {
val node = startNode(providedName = ALICE_NAME).getOrThrow()
if (node is InProcess) { // assuming the node-handle is always one of these
val svc = node.services.cordaService(TestSmmStateService::class.java)
svc.getSmmStartedForEvent(event)
} else {
TestSmmStateService.STATE_MACHINE_MANAGER_UNKNOWN_STATUS
}
}
assertEquals(expectedResult, result)
} }
@StartableByRPC @StartableByRPC
@StartableByService
class ComputeTextLengthThroughCordaService(private val text: String) : FlowLogic<Int>() { class ComputeTextLengthThroughCordaService(private val text: String) : FlowLogic<Int>() {
@Suspendable @Suspendable
override fun call(): Int { override fun call(): Int {
@ -52,17 +104,14 @@ class CordaServiceLifecycleTests {
class TextLengthComputingService(services: AppServiceHub) : SingletonSerializeAsToken() { class TextLengthComputingService(services: AppServiceHub) : SingletonSerializeAsToken() {
init { init {
services.register { addEvent(it) } for (n in 1..numServiceCallbacks) {
services.register { addEvent(it) }
}
} }
private fun addEvent(event: ServiceLifecycleEvent) { private fun addEvent(event: ServiceLifecycleEvent) {
when (event) { if (event in eventsToBeCaptured) {
STATE_MACHINE_STARTED -> { eventsCaptured.add(event)
eventsCaptured.add(event)
}
else -> {
eventsCaptured.add(event)
}
} }
} }
@ -71,4 +120,42 @@ class CordaServiceLifecycleTests {
return text.length return text.length
} }
} }
/**
* Service that checks the State Machine Manager state (started, not started) when service events are received.
*/
@CordaService
class TestSmmStateService(private val services: AppServiceHub) : SingletonSerializeAsToken() {
companion object {
const val STATE_MACHINE_MANAGER_UNKNOWN_STATUS = -1
const val STATE_MACHINE_MANAGER_WAS_NOT_STARTED = 0
const val STATE_MACHINE_MANAGER_WAS_STARTED = 1
}
var smmStateAtEvent = mutableMapOf<ServiceLifecycleEvent, Int>()
init {
services.register { addEvent(it) }
}
private fun addEvent(event: ServiceLifecycleEvent) {
smmStateAtEvent[event] = checkSmmStarted()
}
private fun checkSmmStarted() : Int {
// try to start a flow; success == SMM started
try {
services.startFlow(ComputeTextLengthThroughCordaService(TEST_PHRASE)).returnValue.getOrThrow()
return STATE_MACHINE_MANAGER_WAS_STARTED
} catch (ex : UninitializedPropertyAccessException) {
return STATE_MACHINE_MANAGER_WAS_NOT_STARTED
}
}
/**
* Given an event, was the SMM started when the event was received?
*/
fun getSmmStartedForEvent(event: ServiceLifecycleEvent) : Int = smmStateAtEvent.getOrDefault(event, STATE_MACHINE_MANAGER_UNKNOWN_STATUS)
}
} }

View File

@ -0,0 +1,133 @@
package net.corda.node.services
import net.corda.core.node.AppServiceHub
import net.corda.core.node.AppServiceHub.Companion.SERVICE_PRIORITY_HIGH
import net.corda.core.node.AppServiceHub.Companion.SERVICE_PRIORITY_LOW
import net.corda.core.node.AppServiceHub.Companion.SERVICE_PRIORITY_NORMAL
import net.corda.core.node.services.CordaService
import net.corda.core.node.services.ServiceLifecycleEvent
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.utilities.getOrThrow
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.driver
import net.corda.testing.node.internal.enclosedCordapp
import org.junit.Before
import org.junit.Test
import kotlin.test.assertEquals
/**
* Test the priorities of Corda services when distributing/handlimg service events.
* Services register themselves with a priority - an integer whereby higher numbers == higher priority.
* There are a few pre-defined priorities provided by Corda:
* SERVICE_PRIORITY_HIGH
* SERVICE_PRIORITY_NORMAL
* SERVICE_PRIORITY_LOW
*
* but actually the priority can be ANY integer the Corda service desires.
*/
/**
* This base class commonizes code for the subsequent real test classes, further down.
*/
open class CordaServicePriorityTests {
companion object {
val eventsCaptured: MutableMap<ServiceLifecycleEvent, MutableList<String>> = mutableMapOf()
}
/**
* Services loaded by the node
*/
open class PriorityService(private val services: AppServiceHub, private val priority : Int, private val name : String) : SingletonSerializeAsToken() {
init {
services.register(priority = priority) { addEvent(it) }
}
private fun addEvent(event: ServiceLifecycleEvent) {
eventsCaptured.getOrPut(event) {
mutableListOf()
}.add(name)
}
}
@Before
fun startUp() {
eventsCaptured.clear()
driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = listOf(enclosedCordapp()),
notarySpecs = emptyList())) {
startNode(providedName = ALICE_NAME).getOrThrow()
}
}
}
/**
* Test the priorities of Corda services when distributing/handlimg service events where services have different priorities.
*
* The expectation is that service events BEFORE_STATE_MACHINE_START and STATE_MACHINE_STARTED are delivered to Corda Services
* in priority order. That is, services registered with a higher priority value are sent the events first.
*/
class CordaServiceDifferentPriorityTests : CordaServicePriorityTests() {
@Test(timeout=300_000)
@Suppress("unused")
fun `startup service events are delivered to Corda Services in priority order`() {
// expect events to be delivered to these Corda Services in this order
val expectedCallList = listOf("John", "Paul", "George", "Ringo")
assertEquals(expectedCallList, eventsCaptured[ServiceLifecycleEvent.BEFORE_STATE_MACHINE_START]?.toList())
assertEquals(expectedCallList, eventsCaptured[ServiceLifecycleEvent.STATE_MACHINE_STARTED]?.toList())
}
/*
These are the services with different priorities.
*/
@CordaService
class John(val services: AppServiceHub) : PriorityService(services, priority = SERVICE_PRIORITY_HIGH, name = "John")
@CordaService
class Paul(val services: AppServiceHub) : PriorityService(services, priority = SERVICE_PRIORITY_HIGH - 1, name = "Paul")
@CordaService
class George(val services: AppServiceHub) : PriorityService(services, priority = SERVICE_PRIORITY_NORMAL, name = "George")
@CordaService
class Ringo(val services: AppServiceHub) : PriorityService(services, priority = SERVICE_PRIORITY_LOW, name = "Ringo")
}
/**
* Test the priorities of Corda services when distributing/handlimg service events where services have the same priorities.
*
* The expectation is that service events BEFORE_STATE_MACHINE_START and STATE_MACHINE_STARTED are delivered to all Corda Services
* but the order of delivery is not defined, and may differ from run to run.
*/
class CordaServiceSamePriorityTests : CordaServicePriorityTests() {
@Test(timeout=300_000)
@Suppress("unused")
fun `startup service events are delivered to all equal-priority services, the ordering is not fixed`() {
// expect the service events to be delivered to these Corda Services, but don;t care about the order.
val expectedCallList = listOf("Pete", "Roger", "John", "Keith")
assertEquals(expectedCallList.sorted(), eventsCaptured[ServiceLifecycleEvent.BEFORE_STATE_MACHINE_START]?.toList()?.sorted())
assertEquals(expectedCallList.sorted(), eventsCaptured[ServiceLifecycleEvent.STATE_MACHINE_STARTED]?.toList()?.sorted())
}
/*
These are the services with all the same priority.
*/
@CordaService
class Pete(val services: AppServiceHub) : PriorityService(services, priority = SERVICE_PRIORITY_NORMAL, name = "Pete")
@CordaService
class Roger(val services: AppServiceHub) : PriorityService(services, priority = SERVICE_PRIORITY_NORMAL, name = "Roger")
@CordaService
class John(val services: AppServiceHub) : PriorityService(services, priority = SERVICE_PRIORITY_NORMAL, name = "John")
@CordaService
class Keith(val services: AppServiceHub) : PriorityService(services, priority = SERVICE_PRIORITY_NORMAL, name = "Keith")
}

View File

@ -1,6 +1,7 @@
package net.corda.node.internal package net.corda.node.internal
import co.paralleluniverse.fibers.instrument.Retransform import co.paralleluniverse.fibers.instrument.Retransform
import com.codahale.metrics.Gauge
import com.codahale.metrics.MetricRegistry import com.codahale.metrics.MetricRegistry
import com.google.common.collect.MutableClassToInstanceMap import com.google.common.collect.MutableClassToInstanceMap
import com.google.common.util.concurrent.MoreExecutors import com.google.common.util.concurrent.MoreExecutors
@ -56,6 +57,11 @@ import net.corda.core.node.services.ContractUpgradeService
import net.corda.core.node.services.CordaService import net.corda.core.node.services.CordaService
import net.corda.core.node.services.IdentityService import net.corda.core.node.services.IdentityService
import net.corda.core.node.services.KeyManagementService import net.corda.core.node.services.KeyManagementService
import net.corda.core.internal.telemetry.SimpleLogTelemetryComponent
import net.corda.core.internal.telemetry.TelemetryComponent
import net.corda.core.internal.telemetry.OpenTelemetryComponent
import net.corda.core.internal.telemetry.TelemetryServiceImpl
import net.corda.core.node.services.TelemetryService
import net.corda.core.node.services.TransactionVerifierService import net.corda.core.node.services.TransactionVerifierService
import net.corda.core.node.services.diagnostics.DiagnosticsService import net.corda.core.node.services.diagnostics.DiagnosticsService
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
@ -148,6 +154,7 @@ import net.corda.node.utilities.BindableNamedCacheFactory
import net.corda.node.utilities.NamedThreadFactory import net.corda.node.utilities.NamedThreadFactory
import net.corda.node.utilities.NotaryLoader import net.corda.node.utilities.NotaryLoader
import net.corda.nodeapi.internal.NodeInfoAndSigned import net.corda.nodeapi.internal.NodeInfoAndSigned
import net.corda.nodeapi.internal.NodeStatus
import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.cordapp.CordappLoader import net.corda.nodeapi.internal.cordapp.CordappLoader
import net.corda.nodeapi.internal.cryptoservice.CryptoService import net.corda.nodeapi.internal.cryptoservice.CryptoService
@ -249,6 +256,16 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
} }
val rotatedKeys = makeRotatedKeysService(configuration).tokenize() val rotatedKeys = makeRotatedKeysService(configuration).tokenize()
val cordappLoader: CordappLoader = makeCordappLoader(configuration, versionInfo, rotatedKeys).closeOnStop(false) val cordappLoader: CordappLoader = makeCordappLoader(configuration, versionInfo, rotatedKeys).closeOnStop(false)
val telemetryService: TelemetryServiceImpl = TelemetryServiceImpl().also {
val openTelemetryComponent = OpenTelemetryComponent(configuration.myLegalName.toString(), configuration.telemetry.spanStartEndEventsEnabled, configuration.telemetry.copyBaggageToTags)
if (configuration.telemetry.openTelemetryEnabled && openTelemetryComponent.isEnabled()) {
it.addTelemetryComponent(openTelemetryComponent)
}
if (configuration.telemetry.simpleLogTelemetryEnabled) {
it.addTelemetryComponent(SimpleLogTelemetryComponent())
}
runOnStop += { it.shutdownTelemetry() }
}.tokenize()
val schemaService = NodeSchemaService(cordappLoader.cordappSchemas).tokenize() val schemaService = NodeSchemaService(cordappLoader.cordappSchemas).tokenize()
val identityService = PersistentIdentityService(cacheFactory).tokenize() val identityService = PersistentIdentityService(cacheFactory).tokenize()
val database: CordaPersistence = createCordaPersistence( val database: CordaPersistence = createCordaPersistence(
@ -336,6 +353,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
private val schedulerService = makeNodeSchedulerService() private val schedulerService = makeNodeSchedulerService()
private val cordappServices = MutableClassToInstanceMap.create<SerializeAsToken>() private val cordappServices = MutableClassToInstanceMap.create<SerializeAsToken>()
private val cordappTelemetryComponents = MutableClassToInstanceMap.create<TelemetryComponent>()
private val shutdownExecutor = Executors.newSingleThreadExecutor(DefaultThreadFactory("Shutdown")) private val shutdownExecutor = Executors.newSingleThreadExecutor(DefaultThreadFactory("Shutdown"))
protected abstract val transactionVerifierWorkerCount: Int protected abstract val transactionVerifierWorkerCount: Int
@ -384,6 +402,9 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
protected val keyStoreHandler = KeyStoreHandler(configuration, cryptoService) protected val keyStoreHandler = KeyStoreHandler(configuration, cryptoService)
@Volatile
private var nodeStatus = NodeStatus.WAITING_TO_START
private fun <T : Any> T.tokenize(): T { private fun <T : Any> T.tokenize(): T {
tokenizableServices?.add(this as? SerializeAsToken ?: tokenizableServices?.add(this as? SerializeAsToken ?:
throw IllegalStateException("${this::class.java} is expected to be extending from SerializeAsToken")) throw IllegalStateException("${this::class.java} is expected to be extending from SerializeAsToken"))
@ -525,6 +546,12 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
Node.printBasicNodeInfo("CorDapp schemas synchronised") Node.printBasicNodeInfo("CorDapp schemas synchronised")
} }
private fun setNodeStatus(st : NodeStatus) {
log.info("Node status update: [$nodeStatus] -> [$st]")
nodeStatus = st
}
@Suppress("ComplexMethod") @Suppress("ComplexMethod")
open fun start(): S { open fun start(): S {
check(started == null) { "Node has already been started" } check(started == null) { "Node has already been started" }
@ -534,9 +561,12 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
} }
nodeLifecycleEventsDistributor.distributeEvent(NodeLifecycleEvent.BeforeNodeStart(nodeServicesContext)) nodeLifecycleEventsDistributor.distributeEvent(NodeLifecycleEvent.BeforeNodeStart(nodeServicesContext))
log.info("Node starting up ...") log.info("Node starting up ...")
setNodeStatus(NodeStatus.STARTING)
initialiseJolokia()
monitoringService.metrics.register(MetricRegistry.name("Node", "Status"), Gauge { nodeStatus })
val trustRoots = initKeyStores() val trustRoots = initKeyStores()
initialiseJolokia()
schemaService.mappedSchemasWarnings().forEach { schemaService.mappedSchemasWarnings().forEach {
val warning = it.toWarning() val warning = it.toWarning()
@ -616,6 +646,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
// the KMS is meant for derived temporary keys used in transactions, and we're not supposed to sign things with // the KMS is meant for derived temporary keys used in transactions, and we're not supposed to sign things with
// the identity key. But the infrastructure to make that easy isn't here yet. // the identity key. But the infrastructure to make that easy isn't here yet.
keyManagementService.start(keyStoreHandler.signingKeys.map { it.key to it.alias }) keyManagementService.start(keyStoreHandler.signingKeys.map { it.key to it.alias })
installTelemetryComponents()
installCordaServices() installCordaServices()
notaryService = maybeStartNotaryService(keyStoreHandler.notaryIdentity) notaryService = maybeStartNotaryService(keyStoreHandler.notaryIdentity)
contractUpgradeService.start() contractUpgradeService.start()
@ -626,6 +657,11 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
tokenizableServices = null tokenizableServices = null
verifyCheckpointsCompatible(frozenTokenizableServices) verifyCheckpointsCompatible(frozenTokenizableServices)
/* Note the .get() at the end of the distributeEvent call, below.
This will block until all Corda Services have returned from processing the event, allowing a service to prevent the
state machine manager from starting (just below this) until the service is ready.
*/
nodeLifecycleEventsDistributor.distributeEvent(NodeLifecycleEvent.BeforeStateMachineStart(nodeServicesContext)).get()
val callback = smm.start(frozenTokenizableServices) val callback = smm.start(frozenTokenizableServices)
val smmStartedFuture = rootFuture.map { callback() } val smmStartedFuture = rootFuture.map { callback() }
// Shut down the SMM so no Fibers are scheduled. // Shut down the SMM so no Fibers are scheduled.
@ -659,6 +695,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
log.warn("Not distributing events as NetworkMap is not ready") log.warn("Not distributing events as NetworkMap is not ready")
} }
} }
setNodeStatus(NodeStatus.STARTED)
return resultingNodeInfo return resultingNodeInfo
} }
@ -961,6 +998,62 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
return service return service
} }
private class TelemetryComponentInstantiationException(cause: Throwable?) : CordaException("Service Instantiation Error", cause)
@Suppress("ThrowsCount", "ComplexMethod", "NestedBlockDepth")
private fun installTelemetryComponents() {
val loadedTelemetryComponents: List<Class<out TelemetryComponent>> = cordappLoader.cordapps.flatMap { it.telemetryComponents }.filterNot {
it.name == OpenTelemetryComponent::class.java.name ||
it.name == SimpleLogTelemetryComponent::class.java.name }
// This sets the Cordapp classloader on the contextClassLoader of the current thread, prior to initializing telemetry components
// Needed because of bug CORDA-2653 - some telemetry components can utilise third-party libraries that require access to
// the Thread context class loader. (Same as installCordaServices).
val oldContextClassLoader: ClassLoader? = Thread.currentThread().contextClassLoader
try {
Thread.currentThread().contextClassLoader = cordappLoader.appClassLoader
loadedTelemetryComponents.forEach {
try {
installTelemetryComponent(it)
} catch (e: NoSuchMethodException) {
log.error("Missing no arg ctor for ${it.name}")
throw e
} catch (e: TelemetryComponentInstantiationException) {
if (e.cause != null) {
log.error("Corda telemetry component ${it.name} failed to instantiate. Reason was: ${e.cause?.rootMessage}", e.cause)
} else {
log.error("Corda telemetry component ${it.name} failed to instantiate", e)
}
throw e
} catch (e: Exception) {
log.error("Unable to install Corda telemetry component ${it.name}", e)
throw e
}
}
} finally {
Thread.currentThread().contextClassLoader = oldContextClassLoader
}
}
private fun <T : TelemetryComponent> installTelemetryComponent(telemetryComponentClass: Class<T>) {
val telemetryComponent = try {
val extendedTelemetryComponentConstructor = telemetryComponentClass.getDeclaredConstructor().apply { isAccessible = true }
val telemetryComponent = extendedTelemetryComponentConstructor.newInstance()
telemetryComponent
} catch (e: InvocationTargetException) {
throw TelemetryComponentInstantiationException(e.cause)
}
cordappTelemetryComponents.putInstance(telemetryComponentClass, telemetryComponent)
if (telemetryComponent.isEnabled()) {
telemetryService.addTelemetryComponent(telemetryComponent)
log.info("Installed ${telemetryComponentClass.name} Telemetry component")
}
else {
log.info("${telemetryComponentClass.name} not enabled so not installing")
}
}
private fun registerCordappFlows() { private fun registerCordappFlows() {
cordappLoader.cordapps.forEach { cordapp -> cordappLoader.cordapps.forEach { cordapp ->
cordapp.initiatedFlows.groupBy { it.requireAnnotation<InitiatedBy>().value.java }.forEach { initiator, responders -> cordapp.initiatedFlows.groupBy { it.requireAnnotation<InitiatedBy>().value.java }.forEach { initiator, responders ->
@ -1054,11 +1147,13 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
// Place the long term identity key in the KMS. Eventually, this is likely going to be separated again because // Place the long term identity key in the KMS. Eventually, this is likely going to be separated again because
// the KMS is meant for derived temporary keys used in transactions, and we're not supposed to sign things with // the KMS is meant for derived temporary keys used in transactions, and we're not supposed to sign things with
// the identity key. But the infrastructure to make that easy isn't here yet. // the identity key. But the infrastructure to make that easy isn't here yet.
return BasicHSMKeyManagementService(cacheFactory, identityService, database, cryptoService) return BasicHSMKeyManagementService(cacheFactory, identityService, database, cryptoService, telemetryService)
} }
open fun stop() { open fun stop() {
setNodeStatus(NodeStatus.STOPPING)
nodeLifecycleEventsDistributor.distributeEvent(NodeLifecycleEvent.StateMachineStopped(nodeServicesContext)) nodeLifecycleEventsDistributor.distributeEvent(NodeLifecycleEvent.StateMachineStopped(nodeServicesContext))
nodeLifecycleEventsDistributor.distributeEvent(NodeLifecycleEvent.BeforeNodeStop(nodeServicesContext)) nodeLifecycleEventsDistributor.distributeEvent(NodeLifecycleEvent.BeforeNodeStop(nodeServicesContext))
@ -1134,6 +1229,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
override val externalOperationExecutor: ExecutorService get() = this@AbstractNode.externalOperationExecutor override val externalOperationExecutor: ExecutorService get() = this@AbstractNode.externalOperationExecutor
override val notaryService: NotaryService? get() = this@AbstractNode.notaryService override val notaryService: NotaryService? get() = this@AbstractNode.notaryService
override val rotatedKeys: RotatedKeys get() = this@AbstractNode.rotatedKeys override val rotatedKeys: RotatedKeys get() = this@AbstractNode.rotatedKeys
override val telemetryService: TelemetryService get() = this@AbstractNode.telemetryService
private lateinit var _myInfo: NodeInfo private lateinit var _myInfo: NodeInfo
override val myInfo: NodeInfo get() = _myInfo override val myInfo: NodeInfo get() = _myInfo
@ -1155,6 +1251,11 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
?: throw IllegalArgumentException("Corda service ${type.name} does not exist") ?: throw IllegalArgumentException("Corda service ${type.name} does not exist")
} }
override fun <T : TelemetryComponent> cordaTelemetryComponent(type: Class<T>): T {
return cordappTelemetryComponents.getInstance(type)
?: throw IllegalArgumentException("Corda telemetry component ${type.name} does not exist")
}
override fun getFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>): InitiatedFlowFactory<*>? { override fun getFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>): InitiatedFlowFactory<*>? {
return flowManager.getFlowFactoryForInitiatingFlow(initiatingFlowClass) return flowManager.getFlowFactoryForInitiatingFlow(initiatingFlowClass)
} }

View File

@ -45,6 +45,10 @@ internal class AppServiceHubImpl<T : SerializeAsToken>(private val serviceHub: S
observer.onServiceLifecycleEvent(ServiceLifecycleEvent.STATE_MACHINE_STARTED) observer.onServiceLifecycleEvent(ServiceLifecycleEvent.STATE_MACHINE_STARTED)
reportSuccess(nodeLifecycleEvent) reportSuccess(nodeLifecycleEvent)
} }
is NodeLifecycleEvent.BeforeStateMachineStart<*> -> Try.on {
observer.onServiceLifecycleEvent(ServiceLifecycleEvent.BEFORE_STATE_MACHINE_START)
reportSuccess(nodeLifecycleEvent)
}
else -> super.update(nodeLifecycleEvent) else -> super.update(nodeLifecycleEvent)
} }
} }

View File

@ -582,14 +582,12 @@ open class Node(configuration: NodeConfiguration,
} }
override fun start(): NodeInfo { override fun start(): NodeInfo {
registerJmxReporter(services.monitoringService.metrics)
registerDefaultExceptionHandler() registerDefaultExceptionHandler()
initialiseSerialization() initialiseSerialization()
val nodeInfo: NodeInfo = super.start() val nodeInfo: NodeInfo = super.start()
nodeReadyFuture.thenMatch({ nodeReadyFuture.thenMatch({
serverThread.execute { serverThread.execute {
registerJmxReporter(services.monitoringService.metrics)
_startupComplete.set(Unit) _startupComplete.set(Unit)
} }
}, },

View File

@ -19,6 +19,7 @@ import net.corda.core.internal.cordapp.get
import net.corda.core.internal.notary.NotaryService import net.corda.core.internal.notary.NotaryService
import net.corda.core.internal.notary.SinglePartyNotaryService import net.corda.core.internal.notary.SinglePartyNotaryService
import net.corda.core.node.services.CordaService import net.corda.core.node.services.CordaService
import net.corda.core.internal.telemetry.TelemetryComponent
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
import net.corda.core.serialization.CheckpointCustomSerializer import net.corda.core.serialization.CheckpointCustomSerializer
import net.corda.core.serialization.SerializationCustomSerializer import net.corda.core.serialization.SerializationCustomSerializer
@ -188,6 +189,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
findServiceFlows(this), findServiceFlows(this),
findSchedulableFlows(this), findSchedulableFlows(this),
findServices(this), findServices(this),
findTelemetryComponents(this),
findWhitelists(url), findWhitelists(url),
findSerializers(this), findSerializers(this),
findCheckpointSerializers(this), findCheckpointSerializers(this),
@ -285,6 +287,10 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
return scanResult.getClassesWithAnnotation(SerializeAsToken::class, CordaService::class) return scanResult.getClassesWithAnnotation(SerializeAsToken::class, CordaService::class)
} }
private fun findTelemetryComponents(scanResult: RestrictedScanResult): List<Class<out TelemetryComponent>> {
return scanResult.getClassesImplementing(TelemetryComponent::class)
}
private fun findInitiatedFlows(scanResult: RestrictedScanResult): List<Class<out FlowLogic<*>>> { private fun findInitiatedFlows(scanResult: RestrictedScanResult): List<Class<out FlowLogic<*>>> {
return scanResult.getClassesWithAnnotation(FlowLogic::class, InitiatedBy::class) return scanResult.getClassesWithAnnotation(FlowLogic::class, InitiatedBy::class)
} }
@ -418,6 +424,15 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
.map { it.kotlin.objectOrNewInstance() } .map { it.kotlin.objectOrNewInstance() }
} }
fun <T : Any> getClassesImplementing(type: KClass<T>): List<Class<out T>> {
return scanResult
.getClassesImplementing(type.java.name)
.filter { it.name.startsWith(qualifiedNamePrefix) }
.mapNotNull {
loadClass(it.name, type) }
.filterNot { it.isAbstractClass }
}
fun <T : Any> getClassesWithAnnotation(type: KClass<T>, annotation: KClass<out Annotation>): List<Class<out T>> { fun <T : Any> getClassesWithAnnotation(type: KClass<T>, annotation: KClass<out Annotation>): List<Class<out T>> {
return scanResult return scanResult
.getClassesWithAnnotation(annotation.java.name) .getClassesWithAnnotation(annotation.java.name)

View File

@ -30,6 +30,7 @@ internal object VirtualCordapp {
serviceFlows = listOf(), serviceFlows = listOf(),
schedulableFlows = listOf(), schedulableFlows = listOf(),
services = listOf(), services = listOf(),
telemetryComponents = listOf(),
serializationWhitelists = listOf(), serializationWhitelists = listOf(),
serializationCustomSerializers = listOf(), serializationCustomSerializers = listOf(),
checkpointCustomSerializers = listOf(), checkpointCustomSerializers = listOf(),
@ -54,6 +55,7 @@ internal object VirtualCordapp {
serviceFlows = listOf(), serviceFlows = listOf(),
schedulableFlows = listOf(), schedulableFlows = listOf(),
services = listOf(), services = listOf(),
telemetryComponents = listOf(),
serializationWhitelists = listOf(), serializationWhitelists = listOf(),
serializationCustomSerializers = listOf(), serializationCustomSerializers = listOf(),
checkpointCustomSerializers = listOf(), checkpointCustomSerializers = listOf(),
@ -79,6 +81,7 @@ internal object VirtualCordapp {
serviceFlows = listOf(), serviceFlows = listOf(),
schedulableFlows = listOf(), schedulableFlows = listOf(),
services = listOf(), services = listOf(),
telemetryComponents = listOf(),
serializationWhitelists = listOf(), serializationWhitelists = listOf(),
serializationCustomSerializers = listOf(), serializationCustomSerializers = listOf(),
checkpointCustomSerializers = listOf(), checkpointCustomSerializers = listOf(),
@ -103,6 +106,7 @@ internal object VirtualCordapp {
serviceFlows = listOf(), serviceFlows = listOf(),
schedulableFlows = listOf(), schedulableFlows = listOf(),
services = listOf(), services = listOf(),
telemetryComponents = listOf(),
serializationWhitelists = listOf(), serializationWhitelists = listOf(),
serializationCustomSerializers = listOf(), serializationCustomSerializers = listOf(),
checkpointCustomSerializers = listOf(), checkpointCustomSerializers = listOf(),

View File

@ -43,6 +43,7 @@ interface NodeConfiguration : ConfigurationWithOptionsContainer {
val certificateChainCheckPolicies: List<CertChainPolicyConfig> val certificateChainCheckPolicies: List<CertChainPolicyConfig>
val verifierType: VerifierType val verifierType: VerifierType
val flowTimeout: FlowTimeoutConfiguration val flowTimeout: FlowTimeoutConfiguration
val telemetry: TelemetryConfiguration
val notary: NotaryConfig? val notary: NotaryConfig?
val additionalNodeInfoPollingFrequencyMsec: Long val additionalNodeInfoPollingFrequencyMsec: Long
val p2pAddress: NetworkHostAndPort val p2pAddress: NetworkHostAndPort
@ -234,6 +235,13 @@ data class FlowTimeoutConfiguration(
*/ */
data class RotatedCorDappSignerKeyConfiguration(val rotatedKeys: List<String>) data class RotatedCorDappSignerKeyConfiguration(val rotatedKeys: List<String>)
data class TelemetryConfiguration(
val openTelemetryEnabled: Boolean,
val simpleLogTelemetryEnabled: Boolean,
val spanStartEndEventsEnabled: Boolean,
val copyBaggageToTags: Boolean
)
internal typealias Valid<TARGET> = Validated<TARGET, Configuration.Validation.Error> internal typealias Valid<TARGET> = Validated<TARGET, Configuration.Validation.Error>
fun Config.parseAsNodeConfiguration(options: Configuration.Options = Configuration.Options(strict = true)): Valid<NodeConfiguration> = V1NodeConfigurationSpec.parse(this, options) fun Config.parseAsNodeConfiguration(options: Configuration.Options = Configuration.Options(strict = true)): Valid<NodeConfiguration> = V1NodeConfigurationSpec.parse(this, options)

View File

@ -42,6 +42,7 @@ data class NodeConfigurationImpl(
override val security: SecurityConfiguration? = Defaults.security, override val security: SecurityConfiguration? = Defaults.security,
override val verifierType: VerifierType, override val verifierType: VerifierType,
override val flowTimeout: FlowTimeoutConfiguration, override val flowTimeout: FlowTimeoutConfiguration,
override val telemetry: TelemetryConfiguration = Defaults.telemetry,
override val p2pAddress: NetworkHostAndPort, override val p2pAddress: NetworkHostAndPort,
override val additionalP2PAddresses: List<NetworkHostAndPort> = Defaults.additionalP2PAddresses, override val additionalP2PAddresses: List<NetworkHostAndPort> = Defaults.additionalP2PAddresses,
private val rpcAddress: NetworkHostAndPort? = Defaults.rpcAddress, private val rpcAddress: NetworkHostAndPort? = Defaults.rpcAddress,
@ -135,6 +136,7 @@ data class NodeConfigurationImpl(
fun database(devMode: Boolean) = DatabaseConfig( fun database(devMode: Boolean) = DatabaseConfig(
exportHibernateJMXStatistics = devMode exportHibernateJMXStatistics = devMode
) )
val telemetry = TelemetryConfiguration(openTelemetryEnabled = true, simpleLogTelemetryEnabled = false, spanStartEndEventsEnabled = false, copyBaggageToTags = false)
} }
companion object { companion object {

View File

@ -31,6 +31,7 @@ import net.corda.node.services.config.PasswordEncryption
import net.corda.node.services.config.RotatedCorDappSignerKeyConfiguration import net.corda.node.services.config.RotatedCorDappSignerKeyConfiguration
import net.corda.node.services.config.SecurityConfiguration import net.corda.node.services.config.SecurityConfiguration
import net.corda.node.services.config.SecurityConfiguration.AuthService.Companion.defaultAuthServiceId import net.corda.node.services.config.SecurityConfiguration.AuthService.Companion.defaultAuthServiceId
import net.corda.node.services.config.TelemetryConfiguration
import net.corda.node.services.config.Valid import net.corda.node.services.config.Valid
import net.corda.node.services.config.schema.parsers.attempt import net.corda.node.services.config.schema.parsers.attempt
import net.corda.node.services.config.schema.parsers.badValue import net.corda.node.services.config.schema.parsers.badValue
@ -233,6 +234,18 @@ internal object RotatedSignerKeySpec : Configuration.Specification<RotatedCorDap
} }
} }
internal object TelemetryConfigurationSpec : Configuration.Specification<TelemetryConfiguration>("TelemetryConfiguration") {
private val openTelemetryEnabled by boolean()
private val simpleLogTelemetryEnabled by boolean()
private val spanStartEndEventsEnabled by boolean()
private val copyBaggageToTags by boolean()
override fun parseValid(configuration: Config, options: Configuration.Options): Valid<TelemetryConfiguration> {
val config = configuration.withOptions(options)
return valid(TelemetryConfiguration(config[openTelemetryEnabled], config[simpleLogTelemetryEnabled], config[spanStartEndEventsEnabled], config[copyBaggageToTags]))
}
}
internal object NotaryConfigSpec : Configuration.Specification<NotaryConfig>("NotaryConfig") { internal object NotaryConfigSpec : Configuration.Specification<NotaryConfig>("NotaryConfig") {
private val validating by boolean() private val validating by boolean()
private val serviceLegalName by string().mapValid(::toCordaX500Name).optional() private val serviceLegalName by string().mapValid(::toCordaX500Name).optional()

View File

@ -25,6 +25,7 @@ internal object V1NodeConfigurationSpec : Configuration.Specification<NodeConfig
private val certificateChainCheckPolicies by nested(CertChainPolicyConfigSpec).list().optional().withDefaultValue(Defaults.certificateChainCheckPolicies) private val certificateChainCheckPolicies by nested(CertChainPolicyConfigSpec).list().optional().withDefaultValue(Defaults.certificateChainCheckPolicies)
private val verifierType by enum(VerifierType::class) private val verifierType by enum(VerifierType::class)
private val flowTimeout by nested(FlowTimeoutConfigurationSpec) private val flowTimeout by nested(FlowTimeoutConfigurationSpec)
private val telemetry by nested(TelemetryConfigurationSpec).optional().withDefaultValue(Defaults.telemetry)
private val notary by nested(NotaryConfigSpec).optional() private val notary by nested(NotaryConfigSpec).optional()
private val additionalNodeInfoPollingFrequencyMsec by long().optional().withDefaultValue(Defaults.additionalNodeInfoPollingFrequencyMsec) private val additionalNodeInfoPollingFrequencyMsec by long().optional().withDefaultValue(Defaults.additionalNodeInfoPollingFrequencyMsec)
private val p2pAddress by string().mapValid(::toNetworkHostAndPort) private val p2pAddress by string().mapValid(::toNetworkHostAndPort)
@ -96,6 +97,7 @@ internal object V1NodeConfigurationSpec : Configuration.Specification<NodeConfig
rpcUsers = config[rpcUsers], rpcUsers = config[rpcUsers],
verifierType = config[verifierType], verifierType = config[verifierType],
flowTimeout = config[flowTimeout], flowTimeout = config[flowTimeout],
telemetry = config[telemetry],
rpcSettings = config[rpcSettings], rpcSettings = config[rpcSettings],
messagingServerAddress = config[messagingServerAddress], messagingServerAddress = config[messagingServerAddress],
notary = config[notary], notary = config[notary],

View File

@ -2,6 +2,7 @@ package net.corda.node.services.keys
import net.corda.core.crypto.* import net.corda.core.crypto.*
import net.corda.core.internal.NamedCacheFactory import net.corda.core.internal.NamedCacheFactory
import net.corda.core.internal.telemetry.TelemetryServiceImpl
import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.utilities.MAX_HASH_HEX_SIZE import net.corda.core.utilities.MAX_HASH_HEX_SIZE
@ -31,7 +32,8 @@ class BasicHSMKeyManagementService(
cacheFactory: NamedCacheFactory, cacheFactory: NamedCacheFactory,
override val identityService: PersistentIdentityService, override val identityService: PersistentIdentityService,
private val database: CordaPersistence, private val database: CordaPersistence,
private val cryptoService: SignOnlyCryptoService private val cryptoService: SignOnlyCryptoService,
val telemetryService: TelemetryServiceImpl
) : SingletonSerializeAsToken(), KeyManagementServiceInternal { ) : SingletonSerializeAsToken(), KeyManagementServiceInternal {
@Entity @Entity
@ -134,12 +136,14 @@ class BasicHSMKeyManagementService(
} }
override fun sign(bytes: ByteArray, publicKey: PublicKey): DigitalSignature.WithKey { override fun sign(bytes: ByteArray, publicKey: PublicKey): DigitalSignature.WithKey {
val signingPublicKey = getSigningPublicKey(publicKey) telemetryService.span("${this::class.java.name}#sign") {
return if (signingPublicKey in originalKeysMap) { val signingPublicKey = getSigningPublicKey(publicKey)
DigitalSignature.WithKey(signingPublicKey, cryptoService.sign(originalKeysMap[signingPublicKey]!!, bytes)) return if (signingPublicKey in originalKeysMap) {
} else { DigitalSignature.WithKey(signingPublicKey, cryptoService.sign(originalKeysMap[signingPublicKey]!!, bytes))
val keyPair = getSigningKeyPair(signingPublicKey) } else {
keyPair.sign(bytes) val keyPair = getSigningKeyPair(signingPublicKey)
keyPair.sign(bytes)
}
} }
} }

View File

@ -12,10 +12,21 @@ import net.corda.core.contracts.ContractAttachment
import net.corda.core.contracts.ContractClassName import net.corda.core.contracts.ContractClassName
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.sha256 import net.corda.core.crypto.sha256
import net.corda.core.internal.* import net.corda.core.internal.AbstractAttachment
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
import net.corda.core.internal.FetchAttachmentsFlow
import net.corda.core.internal.JarSignatureCollector
import net.corda.core.internal.NamedCacheFactory
import net.corda.core.internal.P2P_UPLOADER
import net.corda.core.internal.RPC_UPLOADER
import net.corda.core.internal.TRUSTED_UPLOADERS
import net.corda.core.internal.UNKNOWN_UPLOADER
import net.corda.core.internal.Version import net.corda.core.internal.Version
import net.corda.core.internal.VisibleForTesting
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_VERSION import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_VERSION
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
import net.corda.core.internal.isUploaderTrusted
import net.corda.core.internal.readFully
import net.corda.core.internal.utilities.ZipBombDetector import net.corda.core.internal.utilities.ZipBombDetector
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
@ -23,7 +34,11 @@ import net.corda.core.node.services.vault.AttachmentQueryCriteria
import net.corda.core.node.services.vault.AttachmentSort import net.corda.core.node.services.vault.AttachmentSort
import net.corda.core.node.services.vault.Builder import net.corda.core.node.services.vault.Builder
import net.corda.core.node.services.vault.Sort import net.corda.core.node.services.vault.Sort
import net.corda.core.serialization.* import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializationToken
import net.corda.core.serialization.SerializeAsToken
import net.corda.core.serialization.SerializeAsTokenContext
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.utilities.contextLogger import net.corda.core.utilities.contextLogger
import net.corda.node.services.vault.HibernateAttachmentQueryCriteriaParser import net.corda.node.services.vault.HibernateAttachmentQueryCriteriaParser
import net.corda.node.utilities.InfrequentlyMutatedCache import net.corda.node.utilities.InfrequentlyMutatedCache
@ -46,7 +61,17 @@ import java.util.jar.JarEntry
import java.util.jar.JarInputStream import java.util.jar.JarInputStream
import java.util.stream.Stream import java.util.stream.Stream
import javax.annotation.concurrent.ThreadSafe import javax.annotation.concurrent.ThreadSafe
import javax.persistence.* import javax.persistence.CollectionTable
import javax.persistence.Column
import javax.persistence.ElementCollection
import javax.persistence.Entity
import javax.persistence.FetchType
import javax.persistence.ForeignKey
import javax.persistence.Id
import javax.persistence.Index
import javax.persistence.JoinColumn
import javax.persistence.Lob
import javax.persistence.Table
/** /**
* Stores attachments using Hibernate to database. * Stores attachments using Hibernate to database.
@ -211,7 +236,7 @@ class NodeAttachmentService @JvmOverloads constructor(
private fun validate() { private fun validate() {
if (counter.count != expectedSize.toLong()) return if (counter.count != expectedSize.toLong()) return
val actual = SecureHash.SHA256(hash.asBytes()) val actual = SecureHash.createSHA256(hash.asBytes())
if (actual != expected) if (actual != expected)
throw HashMismatchException(expected, actual) throw HashMismatchException(expected, actual)
} }

View File

@ -40,6 +40,7 @@ import net.corda.nodeapi.internal.persistence.contextDatabaseOrNull
import net.corda.nodeapi.internal.rpc.ObservableContextInterface import net.corda.nodeapi.internal.rpc.ObservableContextInterface
import net.corda.nodeapi.internal.rpc.ObservableSubscription import net.corda.nodeapi.internal.rpc.ObservableSubscription
import net.corda.nodeapi.internal.serialization.amqp.RpcServerObservableSerializer import net.corda.nodeapi.internal.serialization.amqp.RpcServerObservableSerializer
import net.corda.nodeapi.serializedTelemetry
import org.apache.activemq.artemis.api.core.Message import org.apache.activemq.artemis.api.core.Message
import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.SimpleString
import org.apache.activemq.artemis.api.core.client.ActiveMQClient.DEFAULT_ACK_BATCH_SIZE import org.apache.activemq.artemis.api.core.client.ActiveMQClient.DEFAULT_ACK_BATCH_SIZE
@ -63,6 +64,7 @@ import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.ScheduledFuture import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.function.Predicate
import kotlin.concurrent.thread import kotlin.concurrent.thread
private typealias ObservableSubscriptionMap = Cache<InvocationId, ObservableSubscription> private typealias ObservableSubscriptionMap = Cache<InvocationId, ObservableSubscription>
@ -359,6 +361,22 @@ class RPCServer(
} }
private fun clientArtemisMessageHandler(artemisMessage: ClientMessage) { private fun clientArtemisMessageHandler(artemisMessage: ClientMessage) {
/*
Local function for actually executing an RPC, either directly or through the thread pool
*/
fun executeRpc(context : RpcAuthContext, clientToServer : RPCApi.ClientToServer.RpcRequest, arguments : Try.Success<List<Any?>>, isQuickRpc : Boolean) {
if (isQuickRpc) {
val result = invokeRpc(context, clientToServer.methodName, arguments.value)
sendReply(clientToServer.replyId, clientToServer.clientAddress, result)
} else {
rpcExecutor!!.submit {
val result = invokeRpc(context, clientToServer.methodName, arguments.value)
sendReply(clientToServer.replyId, clientToServer.clientAddress, result)
}
}
}
lifeCycle.requireState(State.STARTED) lifeCycle.requireState(State.STARTED)
val clientToServer = RPCApi.ClientToServer.fromClientMessage(artemisMessage) val clientToServer = RPCApi.ClientToServer.fromClientMessage(artemisMessage)
if (log.isDebugEnabled) { if (log.isDebugEnabled) {
@ -387,16 +405,45 @@ class RPCServer(
val arguments = Try.on { val arguments = Try.on {
clientToServer.serialisedArguments.deserialize<List<Any?>>(context = RPC_SERVER_CONTEXT) clientToServer.serialisedArguments.deserialize<List<Any?>>(context = RPC_SERVER_CONTEXT)
} }
log.debug("Received RPC request for [${clientToServer.methodName}]")
/*
The supplied method name may consist of <class>#<method>.
If just a method name is supplied then it is a call made via CordaRPCOps because a quirk of the
stored method names is that CordaRPCOps methods are stored without their class name.
The list of predicates below describes how to match quick RPC methods.
If at least one predicate returns true for the supplied method then it is treated as
a quick RPC.
*/
val quickRpcsList = listOf<Predicate<RPCApi.ClientToServer.RpcRequest>>(
// getProtocolVersion for any class
Predicate() { req ->
req.methodName.substringAfter(CLASS_METHOD_DIVIDER) == "getProtocolVersion"
},
// currentNodeTime for CordaRPCOps
Predicate() { req ->
req.methodName == "currentNodeTime"
}
// Add more predicates as and when needed
)
val isQuickRpc = if (quickRpcsList.any {
it.test(clientToServer)
}) {
log.debug("Handling [${clientToServer.methodName}] as a quick RPC")
true
} else {
false
}
val context: RpcAuthContext val context: RpcAuthContext
when (arguments) { when (arguments) {
is Try.Success -> { is Try.Success -> {
context = artemisMessage.context(clientToServer.sessionId, arguments.value) context = artemisMessage.context(clientToServer.sessionId, arguments.value)
context.invocation.pushToLoggingContext() context.invocation.pushToLoggingContext()
log.debug { "Arguments: ${arguments.value.toTypedArray().contentDeepToString()}" } log.debug { "Arguments: ${arguments.value.toTypedArray().contentDeepToString()}" }
rpcExecutor!!.submit { executeRpc(context, clientToServer, arguments, isQuickRpc)
val result = invokeRpc(context, clientToServer.methodName, arguments.value)
sendReply(clientToServer.replyId, clientToServer.clientAddress, result)
}
} }
is Try.Failure -> { is Try.Failure -> {
context = artemisMessage.context(clientToServer.sessionId, emptyList()) context = artemisMessage.context(clientToServer.sessionId, emptyList())
@ -483,7 +530,8 @@ class RPCServer(
val externalTrace = externalTrace() val externalTrace = externalTrace()
val rpcActor = actorFrom(this) val rpcActor = actorFrom(this)
val impersonatedActor = impersonatedActor() val impersonatedActor = impersonatedActor()
return RpcAuthContext(InvocationContext.rpc(rpcActor.first, trace, externalTrace, impersonatedActor, arguments), rpcActor.second) val serializedTelemetry = serializedTelemetry()
return RpcAuthContext(InvocationContext.rpc(rpcActor.first, trace, externalTrace, impersonatedActor, arguments, serializedTelemetry), rpcActor.second)
} }
private fun actorFrom(message: ClientMessage): Pair<Actor, AuthorizingSubject> { private fun actorFrom(message: ClientMessage): Pair<Actor, AuthorizingSubject> {

View File

@ -4,6 +4,7 @@ import net.corda.core.flows.Destination
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.FlowIORequest import net.corda.core.internal.FlowIORequest
import net.corda.core.internal.telemetry.SerializedTelemetry
import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.SerializedBytes
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
@ -72,7 +73,7 @@ sealed class Event {
* Initiate a flow. This causes a new session object to be created and returned to the flow. Note that no actual * Initiate a flow. This causes a new session object to be created and returned to the flow. Note that no actual
* communication takes place at this time, only on the first send/receive operation on the session. * communication takes place at this time, only on the first send/receive operation on the session.
*/ */
data class InitiateFlow(val destination: Destination, val wellKnownParty: Party) : Event() data class InitiateFlow(val destination: Destination, val wellKnownParty: Party, val serializedTelemetry: SerializedTelemetry?) : Event()
/** /**
* Signal the entering into a subflow. * Signal the entering into a subflow.

View File

@ -142,7 +142,7 @@ class FlowCreator(
senderUUID: String?): Flow<A> { senderUUID: String?): Flow<A> {
// Before we construct the state machine state by freezing the FlowLogic we need to make sure that lazy properties // Before we construct the state machine state by freezing the FlowLogic we need to make sure that lazy properties
// have access to the fiber (and thereby the service hub) // have access to the fiber (and thereby the service hub)
val flowStateMachineImpl = FlowStateMachineImpl(flowId, flowLogic, scheduler) val flowStateMachineImpl = FlowStateMachineImpl(flowId, flowLogic, scheduler, serializedTelemetry = (flowStart as? FlowStart.Initiated)?.initiatingMessage?.serializedTelemetry)
val resultFuture = openFuture<Any?>() val resultFuture = openFuture<Any?>()
flowStateMachineImpl.transientValues = createTransientValues(flowId, resultFuture) flowStateMachineImpl.transientValues = createTransientValues(flowId, resultFuture)
flowLogic.stateMachine = flowStateMachineImpl flowLogic.stateMachine = flowStateMachineImpl
@ -180,7 +180,7 @@ class FlowCreator(
return when(flowState) { return when(flowState) {
is FlowState.Unstarted -> { is FlowState.Unstarted -> {
val logic = deserializeFlowState(flowState.frozenFlowLogic) val logic = deserializeFlowState(flowState.frozenFlowLogic)
FlowStateMachineImpl(runId, logic, scheduler) FlowStateMachineImpl(runId, logic, scheduler, serializedTelemetry = null)
} }
is FlowState.Started -> deserializeFlowState(flowState.frozenFiber) is FlowState.Started -> deserializeFlowState(flowState.frozenFiber)
// Places calling this function is rely on it to return null if the flow cannot be created from the checkpoint. // Places calling this function is rely on it to return null if the flow cannot be created from the checkpoint.

View File

@ -9,6 +9,8 @@ import net.corda.core.identity.Party
import net.corda.core.internal.FlowIORequest import net.corda.core.internal.FlowIORequest
import net.corda.core.internal.FlowStateMachine import net.corda.core.internal.FlowStateMachine
import net.corda.core.internal.checkPayloadIs import net.corda.core.internal.checkPayloadIs
import net.corda.core.internal.telemetry.SerializedTelemetry
import net.corda.core.internal.telemetry.telemetryServiceInternal
import net.corda.core.serialization.SerializationDefaults import net.corda.core.serialization.SerializationDefaults
import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.SerializedBytes
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
@ -18,7 +20,8 @@ import net.corda.core.utilities.UntrustworthyData
class FlowSessionImpl( class FlowSessionImpl(
override val destination: Destination, override val destination: Destination,
private val wellKnownParty: Party, private val wellKnownParty: Party,
val sourceSessionId: SessionId val sourceSessionId: SessionId,
val serializedTelemetry: SerializedTelemetry?
) : FlowSession() { ) : FlowSession() {
override val counterparty: Party get() = wellKnownParty override val counterparty: Party get() = wellKnownParty
@ -30,6 +33,7 @@ class FlowSessionImpl(
override fun hashCode(): Int = sourceSessionId.hashCode() override fun hashCode(): Int = sourceSessionId.hashCode()
private val flowStateMachine: FlowStateMachine<*> get() = Fiber.currentFiber() as FlowStateMachine<*> private val flowStateMachine: FlowStateMachine<*> get() = Fiber.currentFiber() as FlowStateMachine<*>
private val telemetryMap = mapOf("destination" to destination.toString())
@Suspendable @Suspendable
override fun getCounterpartyFlowInfo(maySkipCheckpoint: Boolean): FlowInfo { override fun getCounterpartyFlowInfo(maySkipCheckpoint: Boolean): FlowInfo {
@ -46,15 +50,16 @@ class FlowSessionImpl(
payload: Any, payload: Any,
maySkipCheckpoint: Boolean maySkipCheckpoint: Boolean
): UntrustworthyData<R> { ): UntrustworthyData<R> {
enforceNotPrimitive(receiveType) flowStateMachine.serviceHub.telemetryServiceInternal.span("${this::class.java.name}#sendAndReceive", telemetryMap, flowLogic = flowStateMachine.logic) {
val request = FlowIORequest.SendAndReceive( enforceNotPrimitive(receiveType)
sessionToMessage = mapOf(this to payload.serialize(context = SerializationDefaults.P2P_CONTEXT)), val request = FlowIORequest.SendAndReceive(
shouldRetrySend = false sessionToMessage = mapOf(this to payload.serialize(context = SerializationDefaults.P2P_CONTEXT)),
) shouldRetrySend = false
val responseValues: Map<FlowSession, SerializedBytes<Any>> = flowStateMachine.suspend(request, maySkipCheckpoint) )
val responseForCurrentSession = responseValues.getValue(this) val responseValues: Map<FlowSession, SerializedBytes<Any>> = flowStateMachine.suspend(request, maySkipCheckpoint)
val responseForCurrentSession = responseValues.getValue(this)
return responseForCurrentSession.checkPayloadIs(receiveType) return responseForCurrentSession.checkPayloadIs(receiveType)
}
} }
@Suspendable @Suspendable
@ -62,9 +67,11 @@ class FlowSessionImpl(
@Suspendable @Suspendable
override fun <R : Any> receive(receiveType: Class<R>, maySkipCheckpoint: Boolean): UntrustworthyData<R> { override fun <R : Any> receive(receiveType: Class<R>, maySkipCheckpoint: Boolean): UntrustworthyData<R> {
enforceNotPrimitive(receiveType) flowStateMachine.serviceHub.telemetryServiceInternal.span("${this::class.java.name}#receive", telemetryMap, flowStateMachine.logic ) {
val request = FlowIORequest.Receive(NonEmptySet.of(this)) enforceNotPrimitive(receiveType)
return flowStateMachine.suspend(request, maySkipCheckpoint).getValue(this).checkPayloadIs(receiveType) val request = FlowIORequest.Receive(NonEmptySet.of(this))
return flowStateMachine.suspend(request, maySkipCheckpoint).getValue(this).checkPayloadIs(receiveType)
}
} }
@Suspendable @Suspendable
@ -72,10 +79,12 @@ class FlowSessionImpl(
@Suspendable @Suspendable
override fun send(payload: Any, maySkipCheckpoint: Boolean) { override fun send(payload: Any, maySkipCheckpoint: Boolean) {
val request = FlowIORequest.Send( flowStateMachine.serviceHub.telemetryServiceInternal.span("${this::class.java.name}#send", telemetryMap, flowStateMachine.logic) {
sessionToMessage = mapOf(this to payload.serialize(context = SerializationDefaults.P2P_CONTEXT)) val request = FlowIORequest.Send(
) sessionToMessage = mapOf(this to payload.serialize(context = SerializationDefaults.P2P_CONTEXT))
return flowStateMachine.suspend(request, maySkipCheckpoint) )
return flowStateMachine.suspend(request, maySkipCheckpoint)
}
} }
@Suspendable @Suspendable

View File

@ -36,6 +36,9 @@ import net.corda.core.internal.isRegularFile
import net.corda.core.internal.location import net.corda.core.internal.location
import net.corda.core.internal.toPath import net.corda.core.internal.toPath
import net.corda.core.internal.uncheckedCast import net.corda.core.internal.uncheckedCast
import net.corda.core.internal.telemetry.ComponentTelemetryIds
import net.corda.core.internal.telemetry.SerializedTelemetry
import net.corda.core.internal.telemetry.telemetryServiceInternal
import net.corda.core.serialization.SerializationDefaults import net.corda.core.serialization.SerializationDefaults
import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.SerializedBytes
import net.corda.core.serialization.internal.CheckpointSerializationContext import net.corda.core.serialization.internal.CheckpointSerializationContext
@ -71,7 +74,8 @@ class TransientReference<out A>(@Transient val value: A)
class FlowStateMachineImpl<R>(override val id: StateMachineRunId, class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
override val logic: FlowLogic<R>, override val logic: FlowLogic<R>,
scheduler: FiberScheduler, scheduler: FiberScheduler,
override val creationTime: Long = System.currentTimeMillis() override val creationTime: Long = System.currentTimeMillis(),
val serializedTelemetry: SerializedTelemetry? = null
) : Fiber<Unit>(id.toString(), scheduler), FlowStateMachine<R>, FlowFiber { ) : Fiber<Unit>(id.toString(), scheduler), FlowStateMachine<R>, FlowFiber {
companion object { companion object {
/** /**
@ -316,6 +320,9 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
} }
private fun openThreadLocalWormhole() { private fun openThreadLocalWormhole() {
// This sets the Cordapp classloader on the contextClassLoader of the current thread.
// Needed because in previous versions of the finance app we used Thread.contextClassLoader to resolve services defined in cordapps.
Thread.currentThread().contextClassLoader = (serviceHub.cordappProvider as CordappProviderImpl).cordappLoader.appClassLoader
val threadLocal = transientValues.database.hikariPoolThreadLocal val threadLocal = transientValues.database.hikariPoolThreadLocal
if (threadLocal != null) { if (threadLocal != null) {
val valueFromThread = swappedOutThreadLocalValue(threadLocal) val valueFromThread = swappedOutThreadLocalValue(threadLocal)
@ -346,8 +353,14 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
// Needed because in previous versions of the finance app we used Thread.contextClassLoader to resolve services defined in cordapps. // Needed because in previous versions of the finance app we used Thread.contextClassLoader to resolve services defined in cordapps.
Thread.currentThread().contextClassLoader = (serviceHub.cordappProvider as CordappProviderImpl).cordappLoader.appClassLoader Thread.currentThread().contextClassLoader = (serviceHub.cordappProvider as CordappProviderImpl).cordappLoader.appClassLoader
val result = logic.call() // context.serializedTelemetry is from an rpc client, serializedTelemetry is from a peer, otherwise nothing
suspend(FlowIORequest.WaitForSessionConfirmations(), maySkipCheckpoint = true) val serializedTelemetrySrc = context.serializedTelemetry ?: serializedTelemetry
val result = serviceHub.telemetryServiceInternal.spanForFlow(logic.javaClass.name, emptyMap(), logic, serializedTelemetrySrc) {
val ret = logic.call()
// Note suspend stores the telemetry ids back in the components from checkpoint, so must be done, before we end the span
suspend(FlowIORequest.WaitForSessionConfirmations(), maySkipCheckpoint = true)
ret
}
Try.Success(result) Try.Success(result)
} catch (t: Throwable) { } catch (t: Throwable) {
if(t.isUnrecoverable()) { if(t.isUnrecoverable()) {
@ -417,8 +430,11 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
isDbTransactionOpenOnExit = true isDbTransactionOpenOnExit = true
) )
return try { return try {
subFlow.call() serviceHub.telemetryServiceInternal.span(subFlow.javaClass.name, emptyMap(), subFlow) {
} finally { subFlow.call()
}
}
finally {
processEventImmediately( processEventImmediately(
Event.LeaveSubFlow, Event.LeaveSubFlow,
isDbTransactionOpenOnEntry = true, isDbTransactionOpenOnEntry = true,
@ -457,10 +473,10 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
} }
@Suspendable @Suspendable
override fun initiateFlow(destination: Destination, wellKnownParty: Party): FlowSession { override fun initiateFlow(destination: Destination, wellKnownParty: Party, serializedTelemetry: SerializedTelemetry?): FlowSession {
require(destination is Party || destination is AnonymousParty) { "Unsupported destination type ${destination.javaClass.name}" } require(destination is Party || destination is AnonymousParty) { "Unsupported destination type ${destination.javaClass.name}" }
val resume = processEventImmediately( val resume = processEventImmediately(
Event.InitiateFlow(destination, wellKnownParty), Event.InitiateFlow(destination, wellKnownParty, serializedTelemetry),
isDbTransactionOpenOnEntry = true, isDbTransactionOpenOnEntry = true,
isDbTransactionOpenOnExit = true isDbTransactionOpenOnExit = true
) as FlowContinuation.Resume ) as FlowContinuation.Resume
@ -527,6 +543,7 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
override fun <R : Any> suspend(ioRequest: FlowIORequest<R>, maySkipCheckpoint: Boolean): R { override fun <R : Any> suspend(ioRequest: FlowIORequest<R>, maySkipCheckpoint: Boolean): R {
val serializationContext = TransientReference(transientValues.checkpointSerializationContext) val serializationContext = TransientReference(transientValues.checkpointSerializationContext)
val transaction = extractThreadLocalTransaction() val transaction = extractThreadLocalTransaction()
val telemetryIds = retrieveTelemetryIds()
parkAndSerialize { _, _ -> parkAndSerialize { _, _ ->
setLoggingContext() setLoggingContext()
logger.trace { "Suspended on $ioRequest" } logger.trace { "Suspended on $ioRequest" }
@ -563,6 +580,7 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
} }
} }
storeTelemetryIds(telemetryIds)
transientState.reloadCheckpointAfterSuspendCount?.let { count -> transientState.reloadCheckpointAfterSuspendCount?.let { count ->
if (count < transientState.checkpoint.checkpointState.numberOfSuspends) { if (count < transientState.checkpoint.checkpointState.numberOfSuspends) {
onReloadFlowFromCheckpoint?.invoke(id) onReloadFlowFromCheckpoint?.invoke(id)
@ -580,6 +598,16 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
)) ))
} }
private fun retrieveTelemetryIds(): ComponentTelemetryIds? {
return serviceHub.telemetryServiceInternal.getCurrentTelemetryIds()
}
private fun storeTelemetryIds(telemetryIds: ComponentTelemetryIds?) {
telemetryIds?.let {
serviceHub.telemetryServiceInternal.setCurrentTelemetryId(it)
}
}
private fun containsIdempotentFlows(): Boolean { private fun containsIdempotentFlows(): Boolean {
val subFlowStack = snapshot().checkpoint.checkpointState.subFlowStack val subFlowStack = snapshot().checkpoint.checkpointState.subFlowStack
return subFlowStack.any { IdempotentFlow::class.java.isAssignableFrom(it.flowClass) } return subFlowStack.any { IdempotentFlow::class.java.isAssignableFrom(it.flowClass) }

View File

@ -2,6 +2,7 @@ package net.corda.node.services.statemachine
import net.corda.core.flows.FlowException import net.corda.core.flows.FlowException
import net.corda.core.flows.FlowInfo import net.corda.core.flows.FlowInfo
import net.corda.core.internal.telemetry.SerializedTelemetry
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.SerializedBytes
import java.security.SecureRandom import java.security.SecureRandom
@ -38,6 +39,7 @@ data class SessionId(val toLong: Long) {
* @param flowVersion the version of the initiating flow. * @param flowVersion the version of the initiating flow.
* @param appName the name of the cordapp defining the initiating flow, or "corda" if it's a core flow. * @param appName the name of the cordapp defining the initiating flow, or "corda" if it's a core flow.
* @param firstPayload the optional first payload. * @param firstPayload the optional first payload.
* @param serializedTelemetry the telemetry data
*/ */
data class InitialSessionMessage( data class InitialSessionMessage(
val initiatorSessionId: SessionId, val initiatorSessionId: SessionId,
@ -45,7 +47,8 @@ data class InitialSessionMessage(
val initiatorFlowClassName: String, val initiatorFlowClassName: String,
val flowVersion: Int, val flowVersion: Int,
val appName: String, val appName: String,
val firstPayload: SerializedBytes<Any>? val firstPayload: SerializedBytes<Any>?,
val serializedTelemetry: SerializedTelemetry?
) : SessionMessage() { ) : SessionMessage() {
override fun toString() = "InitialSessionMessage(" + override fun toString() = "InitialSessionMessage(" +
"initiatorSessionId=$initiatorSessionId, " + "initiatorSessionId=$initiatorSessionId, " +
@ -53,6 +56,7 @@ data class InitialSessionMessage(
"initiatorFlowClassName=$initiatorFlowClassName, " + "initiatorFlowClassName=$initiatorFlowClassName, " +
"appName=$appName, " + "appName=$appName, " +
"firstPayload=${firstPayload?.javaClass}" + "firstPayload=${firstPayload?.javaClass}" +
"telemetryContext=$serializedTelemetry" +
")" ")"
} }

View File

@ -863,7 +863,7 @@ internal class SingleThreadedStateMachineManager(
try { try {
val initiatedFlowFactory = getInitiatedFlowFactory(sessionMessage) val initiatedFlowFactory = getInitiatedFlowFactory(sessionMessage)
val initiatedSessionId = SessionId.createRandom(secureRandom) val initiatedSessionId = SessionId.createRandom(secureRandom)
val senderSession = FlowSessionImpl(sender, sender, initiatedSessionId) val senderSession = FlowSessionImpl(sender, sender, initiatedSessionId, sessionMessage.serializedTelemetry)
val flowLogic = initiatedFlowFactory.createFlow(senderSession) val flowLogic = initiatedFlowFactory.createFlow(senderSession)
val initiatedFlowInfo = when (initiatedFlowFactory) { val initiatedFlowInfo = when (initiatedFlowFactory) {
is InitiatedFlowFactory.Core -> FlowInfo(serviceHub.myInfo.platformVersion, "corda") is InitiatedFlowFactory.Core -> FlowInfo(serviceHub.myInfo.platformVersion, "corda")

View File

@ -7,6 +7,7 @@ import net.corda.core.flows.UnexpectedFlowEndException
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.DeclaredField import net.corda.core.internal.DeclaredField
import net.corda.core.internal.FlowIORequest import net.corda.core.internal.FlowIORequest
import net.corda.core.internal.telemetry.SerializedTelemetry
import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.SerializedBytes
import net.corda.core.utilities.contextLogger import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.toNonEmptySet import net.corda.core.utilities.toNonEmptySet
@ -74,7 +75,7 @@ class StartedFlowTransition(
return builder { return builder {
// Initialise uninitialised sessions in order to receive the associated FlowInfo. Some or all sessions may // Initialise uninitialised sessions in order to receive the associated FlowInfo. Some or all sessions may
// not be initialised yet. // not be initialised yet.
sendInitialSessionMessagesIfNeeded(sessionIdToSession.keys) sendInitialSessionMessagesIfNeeded(sessionIdToSession)
val flowInfoMap = getFlowInfoFromSessions(sessionIdToSession) val flowInfoMap = getFlowInfoFromSessions(sessionIdToSession)
if (flowInfoMap == null) { if (flowInfoMap == null) {
FlowContinuation.ProcessEvents FlowContinuation.ProcessEvents
@ -140,7 +141,7 @@ class StartedFlowTransition(
sessionIdToSession[sessionId] = session sessionIdToSession[sessionId] = session
} }
return builder { return builder {
sendToSessionsTransition(sessionIdToMessage) sendToSessionsTransition(sessionIdToMessage, sessionIdToSession)
if (isErrored()) { if (isErrored()) {
FlowContinuation.ProcessEvents FlowContinuation.ProcessEvents
} else { } else {
@ -202,7 +203,7 @@ class StartedFlowTransition(
sessionIdToSession[(session as FlowSessionImpl).sourceSessionId] = session sessionIdToSession[(session as FlowSessionImpl).sourceSessionId] = session
} }
// send initialises to uninitialised sessions // send initialises to uninitialised sessions
sendInitialSessionMessagesIfNeeded(sessionIdToSession.keys) sendInitialSessionMessagesIfNeeded(sessionIdToSession)
try { try {
val receivedMap = receiveFromSessionsTransition(sessionIdToSession) val receivedMap = receiveFromSessionsTransition(sessionIdToSession)
if (receivedMap == null) { if (receivedMap == null) {
@ -272,11 +273,11 @@ class StartedFlowTransition(
} }
} }
private fun TransitionBuilder.sendInitialSessionMessagesIfNeeded(sourceSessions: Set<SessionId>) { private fun TransitionBuilder.sendInitialSessionMessagesIfNeeded(sessionIdToSession: Map<SessionId, FlowSessionImpl>) {
val checkpoint = startingState.checkpoint val checkpoint = startingState.checkpoint
val newSessions = LinkedHashMap<SessionId, SessionState>(checkpoint.checkpointState.sessions) val newSessions = LinkedHashMap<SessionId, SessionState>(checkpoint.checkpointState.sessions)
var index = 0 var index = 0
for (sourceSessionId in sourceSessions) { for (sourceSessionId in sessionIdToSession.keys) {
val sessionState = checkpoint.checkpointState.sessions[sourceSessionId] val sessionState = checkpoint.checkpointState.sessions[sourceSessionId]
if (sessionState == null) { if (sessionState == null) {
return freshErrorTransition(CannotFindSessionException(sourceSessionId)) return freshErrorTransition(CannotFindSessionException(sourceSessionId))
@ -284,7 +285,8 @@ class StartedFlowTransition(
if (sessionState !is SessionState.Uninitiated) { if (sessionState !is SessionState.Uninitiated) {
continue continue
} }
val initialMessage = createInitialSessionMessage(sessionState.initiatingSubFlow, sourceSessionId, sessionState.additionalEntropy, null) val telemetryData = sessionIdToSession[sourceSessionId]?.serializedTelemetry
val initialMessage = createInitialSessionMessage(sessionState.initiatingSubFlow, sourceSessionId, sessionState.additionalEntropy, null, telemetryData)
val newSessionState = SessionState.Initiating( val newSessionState = SessionState.Initiating(
bufferedMessages = arrayListOf(), bufferedMessages = arrayListOf(),
rejectionError = null, rejectionError = null,
@ -302,7 +304,8 @@ class StartedFlowTransition(
val sessionIdToMessage = flowIORequest.sessionToMessage.mapKeys { val sessionIdToMessage = flowIORequest.sessionToMessage.mapKeys {
sessionToSessionId(it.key) sessionToSessionId(it.key)
} }
sendToSessionsTransition(sessionIdToMessage) val sessionIdToSession = flowIORequest.sessionToMessage.map { sessionToSessionId(it.key) to it.key as FlowSessionImpl}.toMap()
sendToSessionsTransition(sessionIdToMessage, sessionIdToSession)
if (isErrored()) { if (isErrored()) {
FlowContinuation.ProcessEvents FlowContinuation.ProcessEvents
} else { } else {
@ -311,7 +314,8 @@ class StartedFlowTransition(
} }
} }
private fun TransitionBuilder.sendToSessionsTransition(sourceSessionIdToMessage: Map<SessionId, SerializedBytes<Any>>) { private fun TransitionBuilder.sendToSessionsTransition(sourceSessionIdToMessage: Map<SessionId, SerializedBytes<Any>>, sourceSessionIdToSession: Map<SessionId, FlowSessionImpl
>) {
val checkpoint = startingState.checkpoint val checkpoint = startingState.checkpoint
val newSessions = LinkedHashMap(checkpoint.checkpointState.sessions) val newSessions = LinkedHashMap(checkpoint.checkpointState.sessions)
var index = 0 var index = 0
@ -323,7 +327,8 @@ class StartedFlowTransition(
val sendInitialActions = messagesByType[SessionState.Uninitiated::class]?.map { (sourceSessionId, sessionState, message) -> val sendInitialActions = messagesByType[SessionState.Uninitiated::class]?.map { (sourceSessionId, sessionState, message) ->
val uninitiatedSessionState = sessionState as SessionState.Uninitiated val uninitiatedSessionState = sessionState as SessionState.Uninitiated
val deduplicationId = DeduplicationId.createForNormal(checkpoint, index++, sessionState) val deduplicationId = DeduplicationId.createForNormal(checkpoint, index++, sessionState)
val initialMessage = createInitialSessionMessage(uninitiatedSessionState.initiatingSubFlow, sourceSessionId, uninitiatedSessionState.additionalEntropy, message) val serializedTelemetry: SerializedTelemetry? = sourceSessionIdToSession[sourceSessionId]?.serializedTelemetry
val initialMessage = createInitialSessionMessage(uninitiatedSessionState.initiatingSubFlow, sourceSessionId, uninitiatedSessionState.additionalEntropy, message, serializedTelemetry)
newSessions[sourceSessionId] = SessionState.Initiating( newSessions[sourceSessionId] = SessionState.Initiating(
bufferedMessages = arrayListOf(), bufferedMessages = arrayListOf(),
rejectionError = null, rejectionError = null,
@ -495,7 +500,8 @@ class StartedFlowTransition(
initiatingSubFlow: SubFlow.Initiating, initiatingSubFlow: SubFlow.Initiating,
sourceSessionId: SessionId, sourceSessionId: SessionId,
additionalEntropy: Long, additionalEntropy: Long,
payload: SerializedBytes<Any>? payload: SerializedBytes<Any>?,
serializedTelemetry: SerializedTelemetry?
): InitialSessionMessage { ): InitialSessionMessage {
return InitialSessionMessage( return InitialSessionMessage(
initiatorSessionId = sourceSessionId, initiatorSessionId = sourceSessionId,
@ -504,7 +510,8 @@ class StartedFlowTransition(
initiatorFlowClassName = initiatingSubFlow.classToInitiateWith.name, initiatorFlowClassName = initiatingSubFlow.classToInitiateWith.name,
flowVersion = initiatingSubFlow.flowInfo.flowVersion, flowVersion = initiatingSubFlow.flowInfo.flowVersion,
appName = initiatingSubFlow.flowInfo.appName, appName = initiatingSubFlow.flowInfo.appName,
firstPayload = payload firstPayload = payload,
serializedTelemetry = serializedTelemetry
) )
} }

View File

@ -305,7 +305,7 @@ class TopLevelTransition(
return@builder FlowContinuation.ProcessEvents return@builder FlowContinuation.ProcessEvents
} }
val sourceSessionId = SessionId.createRandom(context.secureRandom) val sourceSessionId = SessionId.createRandom(context.secureRandom)
val sessionImpl = FlowSessionImpl(event.destination, event.wellKnownParty, sourceSessionId) val sessionImpl = FlowSessionImpl(event.destination, event.wellKnownParty, sourceSessionId, event.serializedTelemetry)
val newSessions = checkpoint.checkpointState.sessions + (sourceSessionId to SessionState.Uninitiated(event.destination, initiatingSubFlow, sourceSessionId, context.secureRandom.nextLong())) val newSessions = checkpoint.checkpointState.sessions + (sourceSessionId to SessionState.Uninitiated(event.destination, initiatingSubFlow, sourceSessionId, context.secureRandom.nextLong()))
currentState = currentState.copy(checkpoint = checkpoint.setSessions(newSessions)) currentState = currentState.copy(checkpoint = checkpoint.setSessions(newSessions))
actions.add(Action.AddSessionBinding(context.id, sourceSessionId)) actions.add(Action.AddSessionBinding(context.id, sourceSessionId))

View File

@ -25,3 +25,9 @@ rpcSettings = {
trustStorePassword = "trustpass" trustStorePassword = "trustpass"
useTestClock = false useTestClock = false
verifierType = InMemory verifierType = InMemory
telemetry {
openTelemetryEnabled = true,
simpleLogTelemetryEnabled = false,
spanStartEndEventsEnabled = false,
copyBaggageToTags = false
}

View File

@ -4,6 +4,7 @@ import com.nhaarman.mockito_kotlin.atLeast
import com.nhaarman.mockito_kotlin.mock import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.verify import com.nhaarman.mockito_kotlin.verify
import com.nhaarman.mockito_kotlin.whenever import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.identity.CordaX500Name
import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsToken
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.VersionInfo import net.corda.node.VersionInfo
@ -134,6 +135,8 @@ class NodeH2SecurityTests {
whenever(config.dataSourceProperties).thenReturn(hikaryProperties) whenever(config.dataSourceProperties).thenReturn(hikaryProperties)
whenever(config.baseDirectory).thenReturn(mock()) whenever(config.baseDirectory).thenReturn(mock())
whenever(config.effectiveH2Settings).thenAnswer { NodeH2Settings(address) } whenever(config.effectiveH2Settings).thenAnswer { NodeH2Settings(address) }
whenever(config.telemetry).thenReturn(mock())
whenever(config.myLegalName).thenReturn(CordaX500Name(null, "client-${address.toString()}", "Corda", "London", null, "GB"))
} }
private inner class MockNode: Node(config, VersionInfo.UNKNOWN, false) { private inner class MockNode: Node(config, VersionInfo.UNKNOWN, false) {

Some files were not shown because too many files have changed in this diff Show More