diff --git a/.ci/api-current.txt b/.ci/api-current.txt index 79812632d4..4815aaeb79 100644 --- a/.ci/api-current.txt +++ b/.ci/api-current.txt @@ -28,6 +28,7 @@ public final class net.corda.core.CordaOID extends java.lang.Object public static final String ALIAS_PRIVATE_KEY = "1.3.6.1.4.1.50530.1.2" @NotNull public static final String CORDA_PLATFORM = "1.3.6.1.4.1.50530.1" + @NotNull public static final net.corda.core.CordaOID INSTANCE @NotNull public static final String R3_ROOT = "1.3.6.1.4.1.50530" @@ -69,29 +70,25 @@ public @interface net.corda.core.DoNotImplement ## public final class net.corda.core.Utils extends java.lang.Object @NotNull - public static final net.corda.core.messaging.DataFeed doOnError(net.corda.core.messaging.DataFeed, kotlin.jvm.functions.Function1) + public static final net.corda.core.messaging.DataFeed doOnError(net.corda.core.messaging.DataFeed, kotlin.jvm.functions.Function1) @NotNull - public static final net.corda.core.messaging.DataFeed mapErrors(net.corda.core.messaging.DataFeed, kotlin.jvm.functions.Function1) + public static final net.corda.core.messaging.DataFeed mapErrors(net.corda.core.messaging.DataFeed, kotlin.jvm.functions.Function1) @NotNull - public static final rx.Observable mapErrors(rx.Observable, kotlin.jvm.functions.Function1) + public static final rx.Observable mapErrors(rx.Observable, kotlin.jvm.functions.Function1) @NotNull - public static final net.corda.core.concurrent.CordaFuture toFuture(rx.Observable) + public static final net.corda.core.concurrent.CordaFuture toFuture(rx.Observable) @NotNull - public static final rx.Observable toObservable(net.corda.core.concurrent.CordaFuture) + public static final rx.Observable toObservable(net.corda.core.concurrent.CordaFuture) ## public final class net.corda.core.concurrent.ConcurrencyUtils extends java.lang.Object @NotNull - public static final net.corda.core.concurrent.CordaFuture firstOf(net.corda.core.concurrent.CordaFuture[], kotlin.jvm.functions.Function1, ? extends W>) - @NotNull - public static final net.corda.core.concurrent.CordaFuture firstOf(net.corda.core.concurrent.CordaFuture[], org.slf4j.Logger, kotlin.jvm.functions.Function1, ? extends W>) - public static final W match(java.util.concurrent.Future, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1) - @NotNull - public static final String shortCircuitedTaskFailedMessage = "Short-circuited task failed:" + public static final net.corda.core.concurrent.CordaFuture firstOf(net.corda.core.concurrent.CordaFuture[], kotlin.jvm.functions.Function1) + public static final W match(java.util.concurrent.Future, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1) ## public interface net.corda.core.concurrent.CordaFuture extends java.util.concurrent.Future - public abstract void then(kotlin.jvm.functions.Function1, ? extends W>) + public abstract void then(kotlin.jvm.functions.Function1) @NotNull - public abstract java.util.concurrent.CompletableFuture toCompletableFuture() + public abstract java.util.concurrent.CompletableFuture toCompletableFuture() ## @CordaSerializable public final class net.corda.core.context.Actor extends java.lang.Object @@ -116,6 +113,7 @@ public final class net.corda.core.context.Actor extends java.lang.Object public static final net.corda.core.context.Actor service(String, net.corda.core.identity.CordaX500Name) @NotNull public String toString() + @NotNull public static final net.corda.core.context.Actor$Companion Companion ## public static final class net.corda.core.context.Actor$Companion extends java.lang.Object @@ -155,9 +153,9 @@ public final class net.corda.core.context.AuthServiceId extends java.lang.Object public final class net.corda.core.context.InvocationContext extends java.lang.Object public (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 (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 (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 (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 (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 (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 (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 (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 public final net.corda.core.context.InvocationOrigin component1() @@ -170,7 +168,7 @@ public final class net.corda.core.context.InvocationContext extends java.lang.Ob @Nullable public final net.corda.core.context.Actor component5() @Nullable - public final java.util.List component6() + public final java.util.List component6() @Nullable public final String component7() @Nullable @@ -178,14 +176,14 @@ public final class net.corda.core.context.InvocationContext extends java.lang.Ob @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) @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 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) @Nullable public final net.corda.core.context.Actor getActor() @Nullable - public final java.util.List getArguments() + public final java.util.List getArguments() @Nullable public final String getClientId() @Nullable @@ -210,11 +208,11 @@ public final class net.corda.core.context.InvocationContext extends java.lang.Ob @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) @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) + 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) @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 - 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) + 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) @NotNull @@ -228,9 +226,9 @@ public final class net.corda.core.context.InvocationContext extends java.lang.Ob @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) @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 - 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) + 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) @NotNull @@ -239,6 +237,7 @@ public final class net.corda.core.context.InvocationContext extends java.lang.Ob public static final net.corda.core.context.InvocationContext shell(net.corda.core.context.Trace, net.corda.core.context.Trace) @NotNull public String toString() + @NotNull public static final net.corda.core.context.InvocationContext$Companion Companion ## public static final class net.corda.core.context.InvocationContext$Companion extends java.lang.Object @@ -254,11 +253,11 @@ public static final class net.corda.core.context.InvocationContext$Companion ext @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) @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) + 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) @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 - 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) + 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) @NotNull @@ -270,9 +269,9 @@ public static final class net.corda.core.context.InvocationContext$Companion ext @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) @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 - 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) + 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) @NotNull @@ -358,6 +357,7 @@ public static final class net.corda.core.context.InvocationOrigin$Service extend public static final class net.corda.core.context.InvocationOrigin$Shell extends net.corda.core.context.InvocationOrigin @NotNull public java.security.Principal principal() + @NotNull public static final net.corda.core.context.InvocationOrigin$Shell INSTANCE ## @CordaSerializable @@ -379,6 +379,7 @@ public final class net.corda.core.context.Trace extends java.lang.Object public static final net.corda.core.context.Trace newInstance(net.corda.core.context.Trace$InvocationId, net.corda.core.context.Trace$SessionId) @NotNull public String toString() + @NotNull public static final net.corda.core.context.Trace$Companion Companion ## public static final class net.corda.core.context.Trace$Companion extends java.lang.Object @@ -391,6 +392,7 @@ public static final class net.corda.core.context.Trace$InvocationId extends net. public (String, java.time.Instant) @NotNull public static final net.corda.core.context.Trace$InvocationId newInstance(String, java.time.Instant) + @NotNull public static final net.corda.core.context.Trace$InvocationId$Companion Companion ## public static final class net.corda.core.context.Trace$InvocationId$Companion extends java.lang.Object @@ -403,6 +405,7 @@ public static final class net.corda.core.context.Trace$SessionId extends net.cor public (String, java.time.Instant) @NotNull public static final net.corda.core.context.Trace$SessionId newInstance(String, java.time.Instant) + @NotNull public static final net.corda.core.context.Trace$SessionId$Companion Companion ## public static final class net.corda.core.context.Trace$SessionId$Companion extends java.lang.Object @@ -414,25 +417,26 @@ public static final class net.corda.core.context.Trace$SessionId$Companion exten @CordaSerializable public final class net.corda.core.contracts.AlwaysAcceptAttachmentConstraint extends java.lang.Object implements net.corda.core.contracts.AttachmentConstraint public boolean isSatisfiedBy(net.corda.core.contracts.Attachment) + @NotNull public static final net.corda.core.contracts.AlwaysAcceptAttachmentConstraint INSTANCE ## @CordaSerializable public final class net.corda.core.contracts.Amount extends java.lang.Object implements java.lang.Comparable public (long, T) public (long, java.math.BigDecimal, T) - public int compareTo(net.corda.core.contracts.Amount) + public int compareTo(net.corda.core.contracts.Amount) public final long component1() @NotNull public final java.math.BigDecimal component2() @NotNull public final T component3() @NotNull - public final net.corda.core.contracts.Amount copy(long, java.math.BigDecimal, T) + public final net.corda.core.contracts.Amount copy(long, java.math.BigDecimal, T) public boolean equals(Object) @NotNull - public static final net.corda.core.contracts.Amount fromDecimal(java.math.BigDecimal, T) + public static final net.corda.core.contracts.Amount fromDecimal(java.math.BigDecimal, T) @NotNull - public static final net.corda.core.contracts.Amount fromDecimal(java.math.BigDecimal, T, java.math.RoundingMode) + public static final net.corda.core.contracts.Amount fromDecimal(java.math.BigDecimal, T, java.math.RoundingMode) @NotNull public final java.math.BigDecimal getDisplayTokenSize() @NotNull @@ -442,62 +446,63 @@ public final class net.corda.core.contracts.Amount extends java.lang.Object impl public final T getToken() public int hashCode() @NotNull - public final net.corda.core.contracts.Amount minus(net.corda.core.contracts.Amount) + public final net.corda.core.contracts.Amount minus(net.corda.core.contracts.Amount) @NotNull - public static final net.corda.core.contracts.Amount parseCurrency(String) + public static final net.corda.core.contracts.Amount parseCurrency(String) @NotNull - public final net.corda.core.contracts.Amount plus(net.corda.core.contracts.Amount) + public final net.corda.core.contracts.Amount plus(net.corda.core.contracts.Amount) @NotNull - public final java.util.List> splitEvenly(int) + public final java.util.List splitEvenly(int) @Nullable - public static final net.corda.core.contracts.Amount sumOrNull(Iterable>) + public static final net.corda.core.contracts.Amount sumOrNull(Iterable) @NotNull - public static final net.corda.core.contracts.Amount sumOrThrow(Iterable>) + public static final net.corda.core.contracts.Amount sumOrThrow(Iterable) @NotNull - public static final net.corda.core.contracts.Amount sumOrZero(Iterable>, T) + public static final net.corda.core.contracts.Amount sumOrZero(Iterable, T) @NotNull - public final net.corda.core.contracts.Amount times(int) + public final net.corda.core.contracts.Amount times(int) @NotNull - public final net.corda.core.contracts.Amount times(long) + public final net.corda.core.contracts.Amount times(long) @NotNull public final java.math.BigDecimal toDecimal() @NotNull public String toString() @NotNull - public static final net.corda.core.contracts.Amount zero(T) + public static final net.corda.core.contracts.Amount zero(T) + @NotNull public static final net.corda.core.contracts.Amount$Companion Companion ## public static final class net.corda.core.contracts.Amount$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.contracts.Amount fromDecimal(java.math.BigDecimal, T) + public final net.corda.core.contracts.Amount fromDecimal(java.math.BigDecimal, T) @NotNull - public final net.corda.core.contracts.Amount fromDecimal(java.math.BigDecimal, T, java.math.RoundingMode) + public final net.corda.core.contracts.Amount fromDecimal(java.math.BigDecimal, T, java.math.RoundingMode) @NotNull public final java.math.BigDecimal getDisplayTokenSize(Object) @NotNull - public final net.corda.core.contracts.Amount parseCurrency(String) + public final net.corda.core.contracts.Amount parseCurrency(String) @Nullable - public final net.corda.core.contracts.Amount sumOrNull(Iterable>) + public final net.corda.core.contracts.Amount sumOrNull(Iterable) @NotNull - public final net.corda.core.contracts.Amount sumOrThrow(Iterable>) + public final net.corda.core.contracts.Amount sumOrThrow(Iterable) @NotNull - public final net.corda.core.contracts.Amount sumOrZero(Iterable>, T) + public final net.corda.core.contracts.Amount sumOrZero(Iterable, T) @NotNull - public final net.corda.core.contracts.Amount zero(T) + public final net.corda.core.contracts.Amount zero(T) ## @CordaSerializable public final class net.corda.core.contracts.AmountTransfer extends java.lang.Object public (long, T, P, P) @NotNull - public final java.util.List> apply(java.util.List>, Object) + public final java.util.List apply(java.util.List, Object) @NotNull - public final net.corda.core.contracts.AmountTransfer copy(long, T, P, P) + public final net.corda.core.contracts.AmountTransfer copy(long, T, P, P) public boolean equals(Object) @NotNull - public static final net.corda.core.contracts.AmountTransfer fromDecimal(java.math.BigDecimal, T, P, P) + public static final net.corda.core.contracts.AmountTransfer fromDecimal(java.math.BigDecimal, T, P, P) @NotNull - public static final net.corda.core.contracts.AmountTransfer fromDecimal(java.math.BigDecimal, T, P, P, java.math.RoundingMode) + public static final net.corda.core.contracts.AmountTransfer fromDecimal(java.math.BigDecimal, T, P, P, java.math.RoundingMode) @NotNull public final P getDestination() public final long getQuantityDelta() @@ -507,34 +512,35 @@ public final class net.corda.core.contracts.AmountTransfer extends java.lang.Obj public final T getToken() public int hashCode() @NotNull - public final java.util.List> novate(P) + public final java.util.List novate(P) @NotNull - public final net.corda.core.contracts.AmountTransfer plus(net.corda.core.contracts.AmountTransfer) + public final net.corda.core.contracts.AmountTransfer plus(net.corda.core.contracts.AmountTransfer) @NotNull public final java.math.BigDecimal toDecimal() @NotNull public String toString() @NotNull - public static final net.corda.core.contracts.AmountTransfer zero(T, P, P) + public static final net.corda.core.contracts.AmountTransfer zero(T, P, P) + @NotNull public static final net.corda.core.contracts.AmountTransfer$Companion Companion ## public static final class net.corda.core.contracts.AmountTransfer$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.contracts.AmountTransfer fromDecimal(java.math.BigDecimal, T, P, P) + public final net.corda.core.contracts.AmountTransfer fromDecimal(java.math.BigDecimal, T, P, P) @NotNull - public final net.corda.core.contracts.AmountTransfer fromDecimal(java.math.BigDecimal, T, P, P, java.math.RoundingMode) + public final net.corda.core.contracts.AmountTransfer fromDecimal(java.math.BigDecimal, T, P, P, java.math.RoundingMode) @NotNull - public final net.corda.core.contracts.AmountTransfer zero(T, P, P) + public final net.corda.core.contracts.AmountTransfer zero(T, P, P) ## @DoNotImplement @CordaSerializable public interface net.corda.core.contracts.Attachment extends net.corda.core.contracts.NamedByHash public void extractFile(String, java.io.OutputStream) @NotNull - public abstract java.util.List getSignerKeys() + public abstract java.util.List getSignerKeys() @NotNull - public abstract java.util.List getSigners() + public abstract java.util.List getSigners() public abstract int getSize() @NotNull public abstract java.io.InputStream open() @@ -546,8 +552,6 @@ public interface net.corda.core.contracts.Attachment extends net.corda.core.cont public interface net.corda.core.contracts.AttachmentConstraint public abstract boolean isSatisfiedBy(net.corda.core.contracts.Attachment) ## -public final class net.corda.core.contracts.AttachmentConstraintKt extends java.lang.Object -## @CordaSerializable public final class net.corda.core.contracts.AttachmentResolutionException extends net.corda.core.flows.FlowException public (net.corda.core.crypto.SecureHash) @@ -558,16 +562,18 @@ public final class net.corda.core.contracts.AttachmentResolutionException extend @CordaSerializable public final class net.corda.core.contracts.AutomaticHashConstraint extends java.lang.Object implements net.corda.core.contracts.AttachmentConstraint public boolean isSatisfiedBy(net.corda.core.contracts.Attachment) + @NotNull public static final net.corda.core.contracts.AutomaticHashConstraint INSTANCE ## @DoNotImplement @CordaSerializable public final class net.corda.core.contracts.AutomaticPlaceholderConstraint extends java.lang.Object implements net.corda.core.contracts.AttachmentConstraint public boolean isSatisfiedBy(net.corda.core.contracts.Attachment) + @NotNull public static final net.corda.core.contracts.AutomaticPlaceholderConstraint INSTANCE ## public @interface net.corda.core.contracts.BelongsToContract - public abstract Class value() + public abstract Class value() ## @CordaSerializable public final class net.corda.core.contracts.BrokenAttachmentException extends net.corda.core.flows.FlowException @@ -578,16 +584,16 @@ public final class net.corda.core.contracts.BrokenAttachmentException extends ne @CordaSerializable public final class net.corda.core.contracts.Command extends java.lang.Object public (T, java.security.PublicKey) - public (T, java.util.List) + public (T, java.util.List) @NotNull public final T component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() @NotNull - public final net.corda.core.contracts.Command copy(T, java.util.List) + public final net.corda.core.contracts.Command copy(T, java.util.List) public boolean equals(Object) @NotNull - public final java.util.List getSigners() + public final java.util.List getSigners() @NotNull public final T getValue() public int hashCode() @@ -616,20 +622,20 @@ public interface net.corda.core.contracts.CommandData ## @CordaSerializable public final class net.corda.core.contracts.CommandWithParties extends java.lang.Object - public (java.util.List, java.util.List, T) + public (java.util.List, java.util.List, T) @NotNull - public final java.util.List component1() + public final java.util.List component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() @NotNull public final T component3() @NotNull - public final net.corda.core.contracts.CommandWithParties copy(java.util.List, java.util.List, T) + public final net.corda.core.contracts.CommandWithParties copy(java.util.List, java.util.List, T) public boolean equals(Object) @NotNull - public final java.util.List getSigners() + public final java.util.List getSigners() @NotNull - public final java.util.List getSigningParties() + public final java.util.List getSigningParties() @NotNull public final T getValue() public int hashCode() @@ -637,6 +643,8 @@ public final class net.corda.core.contracts.CommandWithParties extends java.lang public String toString() ## public final class net.corda.core.contracts.ComponentGroupEnum extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.contracts.ComponentGroupEnum valueOf(String) public static net.corda.core.contracts.ComponentGroupEnum[] values() ## @@ -648,14 +656,15 @@ public interface net.corda.core.contracts.Contract @CordaSerializable public final class net.corda.core.contracts.ContractAttachment extends java.lang.Object implements net.corda.core.contracts.Attachment public (net.corda.core.contracts.Attachment, String) - public (net.corda.core.contracts.Attachment, String, java.util.Set) - public (net.corda.core.contracts.Attachment, String, java.util.Set, String) + public (net.corda.core.contracts.Attachment, String, java.util.Set) + public (net.corda.core.contracts.Attachment, String, java.util.Set, String) public (net.corda.core.contracts.Attachment, String, java.util.Set, String, int, kotlin.jvm.internal.DefaultConstructorMarker) public (net.corda.core.contracts.Attachment, String, java.util.Set, String, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) + public void extractFile(String, java.io.OutputStream) @NotNull - public final java.util.Set getAdditionalContracts() + public final java.util.Set getAdditionalContracts() @NotNull - public final java.util.Set getAllContracts() + public final java.util.Set getAllContracts() @NotNull public final net.corda.core.contracts.Attachment getAttachment() @NotNull @@ -663,9 +672,9 @@ public final class net.corda.core.contracts.ContractAttachment extends java.lang @NotNull public net.corda.core.crypto.SecureHash getId() @NotNull - public java.util.List getSignerKeys() + public java.util.List getSignerKeys() @NotNull - public java.util.List getSigners() + public java.util.List getSigners() public int getSize() @Nullable public final String getUploader() @@ -674,7 +683,10 @@ public final class net.corda.core.contracts.ContractAttachment extends java.lang @NotNull public java.io.InputStream open() @NotNull + public java.util.jar.JarInputStream openAsJAR() + @NotNull public String toString() + @NotNull public static final net.corda.core.contracts.ContractAttachment$Companion Companion ## public static final class net.corda.core.contracts.ContractAttachment$Companion extends java.lang.Object @@ -683,31 +695,35 @@ public static final class net.corda.core.contracts.ContractAttachment$Companion @CordaSerializable public interface net.corda.core.contracts.ContractState @NotNull - public abstract java.util.List getParticipants() + public abstract java.util.List getParticipants() ## public final class net.corda.core.contracts.ContractsDSL extends java.lang.Object + public static final net.corda.core.contracts.CommandWithParties requireSingleCommand(java.util.Collection) @NotNull - public static final net.corda.core.contracts.CommandWithParties requireSingleCommand(java.util.Collection>, Class) - public static final R requireThat(kotlin.jvm.functions.Function1) + public static final net.corda.core.contracts.CommandWithParties requireSingleCommand(java.util.Collection, Class) + public static final R requireThat(kotlin.jvm.functions.Function1) @NotNull - public static final java.util.List> select(java.util.Collection>, Class, java.security.PublicKey, net.corda.core.identity.AbstractParty) + public static final java.util.List select(java.util.Collection, Class, java.security.PublicKey, net.corda.core.identity.AbstractParty) @NotNull - public static final java.util.List> select(java.util.Collection>, Class, java.util.Collection, java.util.Collection) + public static final java.util.List select(java.util.Collection, Class, java.util.Collection, java.util.Collection) + public static final java.util.List select(java.util.Collection, java.security.PublicKey, net.corda.core.identity.AbstractParty) + public static final java.util.List select(java.util.Collection, java.util.Collection, java.util.Collection) + public static final net.corda.core.contracts.MoveCommand verifyMoveCommand(java.util.List, java.util.List) ## @CordaSerializable public interface net.corda.core.contracts.FungibleAsset extends net.corda.core.contracts.FungibleState, net.corda.core.contracts.OwnableState @NotNull - public abstract net.corda.core.contracts.Amount> getAmount() + public abstract net.corda.core.contracts.Amount getAmount() @SerializableCalculatedProperty @NotNull - public abstract java.util.Collection getExitKeys() + public abstract java.util.Collection getExitKeys() @NotNull - public abstract net.corda.core.contracts.FungibleAsset withNewOwnerAndAmount(net.corda.core.contracts.Amount>, net.corda.core.identity.AbstractParty) + public abstract net.corda.core.contracts.FungibleAsset withNewOwnerAndAmount(net.corda.core.contracts.Amount, net.corda.core.identity.AbstractParty) ## @CordaSerializable public interface net.corda.core.contracts.FungibleState extends net.corda.core.contracts.ContractState @NotNull - public abstract net.corda.core.contracts.Amount getAmount() + public abstract net.corda.core.contracts.Amount getAmount() ## @DoNotImplement @CordaSerializable @@ -724,6 +740,7 @@ public final class net.corda.core.contracts.HashAttachmentConstraint extends jav public boolean isSatisfiedBy(net.corda.core.contracts.Attachment) @NotNull public String toString() + @NotNull public static final net.corda.core.contracts.HashAttachmentConstraint$Companion Companion ## public static final class net.corda.core.contracts.HashAttachmentConstraint$Companion extends java.lang.Object @@ -732,9 +749,9 @@ public static final class net.corda.core.contracts.HashAttachmentConstraint$Comp ## @CordaSerializable public final class net.corda.core.contracts.InsufficientBalanceException extends net.corda.core.flows.FlowException - public (net.corda.core.contracts.Amount) + public (net.corda.core.contracts.Amount) @NotNull - public final net.corda.core.contracts.Amount getAmountMissing() + public final net.corda.core.contracts.Amount getAmountMissing() ## @CordaSerializable public final class net.corda.core.contracts.Issued extends java.lang.Object @@ -744,7 +761,7 @@ public final class net.corda.core.contracts.Issued extends java.lang.Object @NotNull public final P component2() @NotNull - public final net.corda.core.contracts.Issued

copy(net.corda.core.contracts.PartyAndReference, P) + public final net.corda.core.contracts.Issued copy(net.corda.core.contracts.PartyAndReference, P) public boolean equals(Object) @NotNull public final net.corda.core.contracts.PartyAndReference getIssuer() @@ -761,20 +778,20 @@ public @interface net.corda.core.contracts.LegalProseReference @CordaSerializable public final class net.corda.core.contracts.LinearPointer extends net.corda.core.contracts.StatePointer @DeprecatedConstructorForDeserialization - public (net.corda.core.contracts.UniqueIdentifier, Class) - public (net.corda.core.contracts.UniqueIdentifier, Class, boolean) + public (net.corda.core.contracts.UniqueIdentifier, Class) + public (net.corda.core.contracts.UniqueIdentifier, Class, boolean) public (net.corda.core.contracts.UniqueIdentifier, Class, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) public boolean equals(Object) @NotNull public net.corda.core.contracts.UniqueIdentifier getPointer() @NotNull - public Class getType() + public Class getType() public int hashCode() public boolean isResolved() @NotNull - public net.corda.core.contracts.StateAndRef resolve(net.corda.core.node.ServiceHub) + public net.corda.core.contracts.StateAndRef resolve(net.corda.core.node.ServiceHub) @NotNull - public net.corda.core.contracts.StateAndRef resolve(net.corda.core.transactions.LedgerTransaction) + public net.corda.core.contracts.StateAndRef resolve(net.corda.core.transactions.LedgerTransaction) ## @CordaSerializable public interface net.corda.core.contracts.LinearState extends net.corda.core.contracts.ContractState @@ -784,7 +801,7 @@ public interface net.corda.core.contracts.LinearState extends net.corda.core.con @CordaSerializable public interface net.corda.core.contracts.MoveCommand extends net.corda.core.contracts.CommandData @Nullable - public abstract Class getContract() + public abstract Class getContract() ## public interface net.corda.core.contracts.NamedByHash @NotNull @@ -824,6 +841,7 @@ public final class net.corda.core.contracts.PrivacySalt extends net.corda.core.u public (byte[]) @NotNull public static final net.corda.core.contracts.PrivacySalt createFor(String) + @NotNull public static final net.corda.core.contracts.PrivacySalt$Companion Companion ## public static final class net.corda.core.contracts.PrivacySalt$Companion extends java.lang.Object @@ -832,20 +850,21 @@ public static final class net.corda.core.contracts.PrivacySalt$Companion extends public final net.corda.core.contracts.PrivacySalt createFor(String) ## public final class net.corda.core.contracts.ReferencedStateAndRef extends java.lang.Object - public (net.corda.core.contracts.StateAndRef) + public (net.corda.core.contracts.StateAndRef) @NotNull - public final net.corda.core.contracts.StateAndRef component1() + public final net.corda.core.contracts.StateAndRef component1() @NotNull - public final net.corda.core.contracts.ReferencedStateAndRef copy(net.corda.core.contracts.StateAndRef) + public final net.corda.core.contracts.ReferencedStateAndRef copy(net.corda.core.contracts.StateAndRef) public boolean equals(Object) @NotNull - public final net.corda.core.contracts.StateAndRef getStateAndRef() + public final net.corda.core.contracts.StateAndRef getStateAndRef() public int hashCode() @NotNull public String toString() ## public final class net.corda.core.contracts.Requirements extends java.lang.Object public final void using(String, boolean) + @NotNull public static final net.corda.core.contracts.Requirements INSTANCE ## @CordaSerializable @@ -907,6 +926,7 @@ public final class net.corda.core.contracts.SignatureAttachmentConstraint extend public boolean isSatisfiedBy(net.corda.core.contracts.Attachment) @NotNull public String toString() + @NotNull 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 @@ -914,22 +934,22 @@ public static final class net.corda.core.contracts.SignatureAttachmentConstraint @NotNull public final net.corda.core.contracts.SignatureAttachmentConstraint create(java.security.PublicKey) @NotNull - public net.corda.core.internal.utilities.PrivateInterner getInterner() + public net.corda.core.internal.utilities.PrivateInterner getInterner() ## public final class net.corda.core.contracts.SourceAndAmount extends java.lang.Object - public (P, net.corda.core.contracts.Amount, Object) + public (P, net.corda.core.contracts.Amount, Object) public (Object, net.corda.core.contracts.Amount, Object, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull public final P component1() @NotNull - public final net.corda.core.contracts.Amount component2() + public final net.corda.core.contracts.Amount component2() @Nullable public final Object component3() @NotNull - public final net.corda.core.contracts.SourceAndAmount copy(P, net.corda.core.contracts.Amount, Object) + public final net.corda.core.contracts.SourceAndAmount copy(P, net.corda.core.contracts.Amount, Object) public boolean equals(Object) @NotNull - public final net.corda.core.contracts.Amount getAmount() + public final net.corda.core.contracts.Amount getAmount() @Nullable public final Object getRef() @NotNull @@ -957,21 +977,21 @@ public final class net.corda.core.contracts.StateAndContract extends java.lang.O ## @CordaSerializable public final class net.corda.core.contracts.StateAndRef extends java.lang.Object - public (net.corda.core.contracts.TransactionState, net.corda.core.contracts.StateRef) + public (net.corda.core.contracts.TransactionState, net.corda.core.contracts.StateRef) @NotNull - public final net.corda.core.contracts.TransactionState component1() + public final net.corda.core.contracts.TransactionState component1() @NotNull public final net.corda.core.contracts.StateRef component2() @NotNull - public final net.corda.core.contracts.StateAndRef copy(net.corda.core.contracts.TransactionState, net.corda.core.contracts.StateRef) + public final net.corda.core.contracts.StateAndRef copy(net.corda.core.contracts.TransactionState, net.corda.core.contracts.StateRef) public boolean equals(Object) @NotNull public final net.corda.core.contracts.StateRef getRef() @NotNull - public final net.corda.core.contracts.TransactionState getState() + public final net.corda.core.contracts.TransactionState getState() public int hashCode() @NotNull - public final net.corda.core.contracts.ReferencedStateAndRef referenced() + public final net.corda.core.contracts.ReferencedStateAndRef referenced() @NotNull public String toString() ## @@ -982,16 +1002,19 @@ public abstract class net.corda.core.contracts.StatePointer extends java.lang.Ob @NotNull public abstract Object getPointer() @NotNull - public abstract Class getType() + public abstract Class getType() public abstract boolean isResolved() @NotNull - public abstract net.corda.core.contracts.StateAndRef resolve(net.corda.core.node.ServiceHub) + public abstract net.corda.core.contracts.StateAndRef resolve(net.corda.core.node.ServiceHub) + @NotNull + public abstract net.corda.core.contracts.StateAndRef resolve(net.corda.core.transactions.LedgerTransaction) @NotNull - public abstract net.corda.core.contracts.StateAndRef resolve(net.corda.core.transactions.LedgerTransaction) public static final net.corda.core.contracts.StatePointer$Companion Companion ## public static final class net.corda.core.contracts.StatePointer$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) + public final net.corda.core.contracts.LinearPointer linearPointer(T, boolean) + public final net.corda.core.contracts.StaticPointer staticPointer(net.corda.core.contracts.StateAndRef, boolean) ## @CordaSerializable public final class net.corda.core.contracts.StateRef extends java.lang.Object @@ -1013,28 +1036,29 @@ public final class net.corda.core.contracts.StateRef extends java.lang.Object @CordaSerializable public final class net.corda.core.contracts.StaticPointer extends net.corda.core.contracts.StatePointer @DeprecatedConstructorForDeserialization - public (net.corda.core.contracts.StateRef, Class) - public (net.corda.core.contracts.StateRef, Class, boolean) + public (net.corda.core.contracts.StateRef, Class) + public (net.corda.core.contracts.StateRef, Class, boolean) public (net.corda.core.contracts.StateRef, Class, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) public boolean equals(Object) @NotNull public net.corda.core.contracts.StateRef getPointer() @NotNull - public Class getType() + public Class getType() public int hashCode() public boolean isResolved() @NotNull - public net.corda.core.contracts.StateAndRef resolve(net.corda.core.node.ServiceHub) + public net.corda.core.contracts.StateAndRef resolve(net.corda.core.node.ServiceHub) @NotNull - public net.corda.core.contracts.StateAndRef resolve(net.corda.core.transactions.LedgerTransaction) + public net.corda.core.contracts.StateAndRef resolve(net.corda.core.transactions.LedgerTransaction) ## public final class net.corda.core.contracts.Structures extends java.lang.Object + public static final java.util.List filterStatesOfType(Iterable) @NotNull public static final net.corda.core.crypto.SecureHash hash(net.corda.core.contracts.ContractState) @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 withoutIssuer(net.corda.core.contracts.Amount>) + public static final net.corda.core.contracts.Amount withoutIssuer(net.corda.core.contracts.Amount) public static final int MAX_ISSUER_REF_SIZE = 512 ## @CordaSerializable @@ -1059,6 +1083,7 @@ public abstract class net.corda.core.contracts.TimeWindow extends java.lang.Obje public static final net.corda.core.contracts.TimeWindow untilOnly(java.time.Instant) @NotNull public static final net.corda.core.contracts.TimeWindow withTolerance(java.time.Instant, java.time.Duration) + @NotNull public static final net.corda.core.contracts.TimeWindow$Companion Companion ## public static final class net.corda.core.contracts.TimeWindow$Companion extends java.lang.Object @@ -1108,7 +1133,7 @@ public final class net.corda.core.contracts.TransactionState extends java.lang.O @NotNull public final net.corda.core.contracts.AttachmentConstraint component5() @NotNull - public final net.corda.core.contracts.TransactionState copy(T, String, net.corda.core.identity.Party, Integer, net.corda.core.contracts.AttachmentConstraint) + public final net.corda.core.contracts.TransactionState copy(T, String, net.corda.core.identity.Party, Integer, net.corda.core.contracts.AttachmentConstraint) public boolean equals(Object) @NotNull public final net.corda.core.contracts.AttachmentConstraint getConstraint() @@ -1123,7 +1148,6 @@ public final class net.corda.core.contracts.TransactionState extends java.lang.O public int hashCode() @NotNull public String toString() - public static final net.corda.core.contracts.TransactionState$Companion Companion ## public final class net.corda.core.contracts.TransactionStateKt extends java.lang.Object ## @@ -1176,8 +1200,10 @@ public static final class net.corda.core.contracts.TransactionVerificationExcept ## @CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$Direction extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.contracts.TransactionVerificationException$Direction valueOf(String) - public static net.corda.core.contracts.TransactionVerificationException$Direction[] values() + public static net.corda.core.contracts.TransactionVerificationException.Direction[] values() ## @CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$DuplicateAttachmentsRejection extends net.corda.core.contracts.TransactionVerificationException @@ -1187,9 +1213,9 @@ public static final class net.corda.core.contracts.TransactionVerificationExcept ## @CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$DuplicateInputStates extends net.corda.core.contracts.TransactionVerificationException - public (net.corda.core.crypto.SecureHash, net.corda.core.utilities.NonEmptySet) + public (net.corda.core.crypto.SecureHash, net.corda.core.utilities.NonEmptySet) @NotNull - public final net.corda.core.utilities.NonEmptySet getDuplicates() + public final net.corda.core.utilities.NonEmptySet getDuplicates() ## @CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$InvalidAttachmentException extends net.corda.core.contracts.TransactionVerificationException @@ -1250,14 +1276,14 @@ public static final class net.corda.core.contracts.TransactionVerificationExcept ## @CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$SignersMissing extends net.corda.core.contracts.TransactionVerificationException - public (net.corda.core.crypto.SecureHash, java.util.List) + public (net.corda.core.crypto.SecureHash, java.util.List) @NotNull - public final java.util.List getMissing() + public final java.util.List getMissing() ## @CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$TransactionContractConflictException extends net.corda.core.contracts.TransactionVerificationException public (net.corda.core.crypto.SecureHash, String) - public (net.corda.core.crypto.SecureHash, net.corda.core.contracts.TransactionState, String) + public (net.corda.core.crypto.SecureHash, net.corda.core.contracts.TransactionState, String) ## @CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$TransactionDuplicateEncumbranceException extends net.corda.core.contracts.TransactionVerificationException @@ -1279,7 +1305,7 @@ public static final class net.corda.core.contracts.TransactionVerificationExcept @CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$TransactionNonMatchingEncumbranceException extends net.corda.core.contracts.TransactionVerificationException public (net.corda.core.crypto.SecureHash, String) - public (net.corda.core.crypto.SecureHash, java.util.Collection) + public (net.corda.core.crypto.SecureHash, java.util.Collection) ## @CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$TransactionNotaryMismatchEncumbranceException extends net.corda.core.contracts.TransactionVerificationException @@ -1289,7 +1315,7 @@ public static final class net.corda.core.contracts.TransactionVerificationExcept @CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$TransactionRequiredContractUnspecifiedException extends net.corda.core.contracts.TransactionVerificationException public (net.corda.core.crypto.SecureHash, String) - public (net.corda.core.crypto.SecureHash, net.corda.core.contracts.TransactionState) + public (net.corda.core.crypto.SecureHash, net.corda.core.contracts.TransactionState) ## @CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$UnsupportedClassVersionError extends net.corda.core.contracts.TransactionVerificationException @@ -1301,9 +1327,9 @@ public static final class net.corda.core.contracts.TransactionVerificationExcept ## @CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$UntrustedAttachmentsException extends net.corda.core.CordaException - public (net.corda.core.crypto.SecureHash, java.util.List) + public (net.corda.core.crypto.SecureHash, java.util.List) @NotNull - public final java.util.List getIds() + public final java.util.List getIds() @NotNull public final net.corda.core.crypto.SecureHash getTxId() ## @@ -1334,6 +1360,7 @@ public final class net.corda.core.contracts.UniqueIdentifier extends java.lang.O public int hashCode() @NotNull public String toString() + @NotNull public static final net.corda.core.contracts.UniqueIdentifier$Companion Companion ## public static final class net.corda.core.contracts.UniqueIdentifier$Companion extends java.lang.Object @@ -1357,24 +1384,25 @@ public interface net.corda.core.contracts.UpgradedContractWithLegacyConstraint e @CordaSerializable public final class net.corda.core.contracts.WhitelistedByZoneAttachmentConstraint extends java.lang.Object implements net.corda.core.contracts.AttachmentConstraint public boolean isSatisfiedBy(net.corda.core.contracts.Attachment) + @NotNull public static final net.corda.core.contracts.WhitelistedByZoneAttachmentConstraint INSTANCE ## @DoNotImplement public interface net.corda.core.cordapp.Cordapp @NotNull - public abstract java.util.List>> getAllFlows() + public abstract java.util.List getAllFlows() @NotNull - public abstract java.util.List> getCheckpointCustomSerializers() + public abstract java.util.List getCheckpointCustomSerializers() @NotNull - public abstract java.util.List getContractClassNames() + public abstract java.util.List getContractClassNames() @NotNull - public abstract java.util.List getCordappClasses() + public abstract java.util.List getCordappClasses() @NotNull - public abstract java.util.Set getCustomSchemas() + public abstract java.util.Set getCustomSchemas() @NotNull public abstract net.corda.core.cordapp.Cordapp$Info getInfo() @NotNull - public abstract java.util.List>> getInitiatedFlows() + public abstract java.util.List getInitiatedFlows() @NotNull public abstract net.corda.core.crypto.SecureHash$SHA256 getJarHash() @NotNull @@ -1383,20 +1411,20 @@ public interface net.corda.core.cordapp.Cordapp @NotNull public abstract String getName() @NotNull - public abstract java.util.List>> getRpcFlows() + public abstract java.util.List getRpcFlows() @NotNull - public abstract java.util.List>> getSchedulableFlows() + public abstract java.util.List getSchedulableFlows() @NotNull - public abstract java.util.List> getSerializationCustomSerializers() + public abstract java.util.List getSerializationCustomSerializers() @NotNull - public abstract java.util.List getSerializationWhitelists() + public abstract java.util.List getSerializationWhitelists() @NotNull - public abstract java.util.List>> getServiceFlows() + public abstract java.util.List getServiceFlows() @NotNull - public abstract java.util.List> getServices() + public abstract java.util.List getServices() public abstract int getTargetPlatformVersion() @NotNull - public abstract java.util.List> getTelemetryComponents() + public abstract java.util.List getTelemetryComponents() ## @DoNotImplement public static interface net.corda.core.cordapp.Cordapp$Info @@ -1547,6 +1575,7 @@ public final class net.corda.core.cordapp.CordappContext extends java.lang.Objec public final net.corda.core.cordapp.CordappConfig getConfig() @NotNull public final net.corda.core.cordapp.Cordapp getCordapp() + @NotNull public static final net.corda.core.cordapp.CordappContext$Companion Companion ## public static final class net.corda.core.cordapp.CordappContext$Companion extends java.lang.Object @@ -1619,19 +1648,20 @@ public final class net.corda.core.crypto.CompositeKey extends java.lang.Object i @NotNull public String getAlgorithm() @NotNull - public final java.util.List getChildren() + public final java.util.List getChildren() @NotNull public byte[] getEncoded() @NotNull public String getFormat() @NotNull - public final java.util.Set getLeafKeys() + public final java.util.Set getLeafKeys() public final int getThreshold() public int hashCode() - public final boolean isFulfilledBy(Iterable) + public final boolean isFulfilledBy(Iterable) public final boolean isFulfilledBy(java.security.PublicKey) @NotNull public String toString() + @NotNull public static final net.corda.core.crypto.CompositeKey$Companion Companion @NotNull public static final String KEY_ALGORITHM = "COMPOSITE" @@ -1641,7 +1671,7 @@ public static final class net.corda.core.crypto.CompositeKey$Builder extends jav @NotNull public final net.corda.core.crypto.CompositeKey$Builder addKey(java.security.PublicKey, int) @NotNull - public final net.corda.core.crypto.CompositeKey$Builder addKeys(java.util.List) + public final net.corda.core.crypto.CompositeKey$Builder addKeys(java.util.List) @NotNull public final net.corda.core.crypto.CompositeKey$Builder addKeys(java.security.PublicKey...) @NotNull @@ -1680,7 +1710,7 @@ public final class net.corda.core.crypto.CompositeKeyFactory extends java.securi @Nullable protected java.security.PublicKey engineGeneratePublic(java.security.spec.KeySpec) @NotNull - protected T engineGetKeySpec(java.security.Key, Class) + protected T engineGetKeySpec(java.security.Key, Class) @NotNull protected java.security.Key engineTranslateKey(java.security.Key) ## @@ -1699,6 +1729,7 @@ public final class net.corda.core.crypto.CompositeSignature extends java.securit protected boolean engineVerify(byte[]) @NotNull public static final java.security.Provider$Service getService(java.security.Provider) + @NotNull public static final net.corda.core.crypto.CompositeSignature$Companion Companion @NotNull public static final String SIGNATURE_ALGORITHM = "COMPOSITESIG" @@ -1728,17 +1759,18 @@ public static final class net.corda.core.crypto.CompositeSignature$State extends ## @CordaSerializable public final class net.corda.core.crypto.CompositeSignaturesWithKeys extends java.lang.Object - public (java.util.List) + public (java.util.List) @NotNull - public final java.util.List component1() + public final java.util.List component1() @NotNull - public final net.corda.core.crypto.CompositeSignaturesWithKeys copy(java.util.List) + public final net.corda.core.crypto.CompositeSignaturesWithKeys copy(java.util.List) public boolean equals(Object) @NotNull - public final java.util.List getSigs() + public final java.util.List getSigs() public int hashCode() @NotNull public String toString() + @NotNull public static final net.corda.core.crypto.CompositeSignaturesWithKeys$Companion Companion ## public static final class net.corda.core.crypto.CompositeSignaturesWithKeys$Companion extends java.lang.Object @@ -1751,12 +1783,14 @@ public final class net.corda.core.crypto.CordaObjectIdentifier extends java.lang public static final org.bouncycastle.asn1.ASN1ObjectIdentifier COMPOSITE_KEY @NotNull public static final org.bouncycastle.asn1.ASN1ObjectIdentifier COMPOSITE_SIGNATURE + @NotNull public static final net.corda.core.crypto.CordaObjectIdentifier INSTANCE ## public final class net.corda.core.crypto.CordaSecurityProvider extends java.security.Provider public () @Nullable public java.security.Provider$Service getService(String, String) + @NotNull public static final net.corda.core.crypto.CordaSecurityProvider$Companion Companion @NotNull public static final String PROVIDER_NAME = "Corda" @@ -1798,6 +1832,8 @@ public final class net.corda.core.crypto.Crypto extends java.lang.Object public static final boolean doVerify(net.corda.core.crypto.SecureHash, net.corda.core.crypto.TransactionSignature) public static final boolean doVerify(net.corda.core.crypto.SignatureScheme, java.security.PublicKey, byte[], byte[]) @NotNull + public static final byte[] encodePublicKey(java.security.PublicKey) + @NotNull public static final java.security.Provider findProvider(String) @NotNull public static final net.corda.core.crypto.SignatureScheme findSignatureScheme(int) @@ -1822,7 +1858,7 @@ public final class net.corda.core.crypto.Crypto extends java.lang.Object public static final boolean publicKeyOnCurve(net.corda.core.crypto.SignatureScheme, java.security.PublicKey) public static final void registerProviders() @NotNull - public static final java.util.List supportedSignatureSchemes() + public static final java.util.List supportedSignatureSchemes() @NotNull public static final java.security.PrivateKey toSupportedPrivateKey(java.security.PrivateKey) @NotNull @@ -1840,17 +1876,16 @@ public final class net.corda.core.crypto.Crypto extends java.lang.Object public static final net.corda.core.crypto.SignatureScheme ECDSA_SECP256R1_SHA256 @NotNull public static final net.corda.core.crypto.SignatureScheme EDDSA_ED25519_SHA512 + @NotNull public static final net.corda.core.crypto.Crypto INSTANCE @NotNull public static final net.corda.core.crypto.SignatureScheme RSA_SHA256 @NotNull public static final org.bouncycastle.asn1.DLSequence SHA512_256 - @NotNull - public static final net.corda.core.crypto.SignatureScheme SPHINCS256_SHA256 ## public final class net.corda.core.crypto.CryptoUtils extends java.lang.Object @NotNull - public static final java.util.Set byKeys(Iterable) + public static final java.util.Set byKeys(Iterable) @NotNull public static final java.security.PrivateKey component1(java.security.KeyPair) @NotNull @@ -1861,14 +1896,14 @@ public final class net.corda.core.crypto.CryptoUtils extends java.lang.Object public static final net.corda.core.crypto.SecureHash componentHash(net.corda.core.utilities.OpaqueBytes, net.corda.core.contracts.PrivacySalt, int, int) @NotNull public static final net.corda.core.crypto.SecureHash$SHA256 computeNonce(net.corda.core.contracts.PrivacySalt, int, int) - public static final boolean containsAny(java.security.PublicKey, Iterable) + public static final boolean containsAny(java.security.PublicKey, Iterable) @NotNull public static final java.security.KeyPair entropyToKeyPair(java.math.BigInteger) @NotNull public static final java.security.KeyPair generateKeyPair() @NotNull - public static final java.util.Set getKeys(java.security.PublicKey) - public static final boolean isFulfilledBy(java.security.PublicKey, Iterable) + public static final java.util.Set getKeys(java.security.PublicKey) + public static final boolean isFulfilledBy(java.security.PublicKey, Iterable) public static final boolean isFulfilledBy(java.security.PublicKey, java.security.PublicKey) public static final boolean isValid(java.security.PublicKey, byte[], net.corda.core.crypto.DigitalSignature) @NotNull @@ -1896,14 +1931,14 @@ public final class net.corda.core.crypto.CryptoUtils extends java.lang.Object ## public interface net.corda.core.crypto.DigestAlgorithm @NotNull - public abstract byte[] componentDigest(byte[]) + public byte[] componentDigest(byte[]) @NotNull public abstract byte[] digest(byte[]) @NotNull public abstract String getAlgorithm() public abstract int getDigestLength() @NotNull - public abstract byte[] nonceDigest(byte[]) + public byte[] nonceDigest(byte[]) ## @CordaSerializable public final class net.corda.core.crypto.DigestService extends java.lang.Object @@ -1935,6 +1970,7 @@ public final class net.corda.core.crypto.DigestService extends java.lang.Object public final net.corda.core.crypto.SecureHash serializedHash(T) @NotNull public String toString() + @NotNull public static final net.corda.core.crypto.DigestService$Companion Companion ## public static final class net.corda.core.crypto.DigestService$Companion extends java.lang.Object @@ -1968,20 +2004,22 @@ public static class net.corda.core.crypto.DigitalSignature$WithKey extends net.c public final net.corda.core.crypto.DigitalSignature withoutKey() ## public final class net.corda.core.crypto.DummySecureRandom extends java.security.SecureRandom + @NotNull public static final net.corda.core.crypto.DummySecureRandom INSTANCE ## public abstract class net.corda.core.crypto.MerkleTree extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull public abstract net.corda.core.crypto.SecureHash getHash() + @NotNull public static final net.corda.core.crypto.MerkleTree$Companion Companion ## public static final class net.corda.core.crypto.MerkleTree$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.crypto.MerkleTree getMerkleTree(java.util.List) + public final net.corda.core.crypto.MerkleTree getMerkleTree(java.util.List) @NotNull - public final net.corda.core.crypto.MerkleTree getMerkleTree(java.util.List, net.corda.core.crypto.DigestService) + public final net.corda.core.crypto.MerkleTree getMerkleTree(java.util.List, net.corda.core.crypto.DigestService) ## public static final class net.corda.core.crypto.MerkleTree$Leaf extends net.corda.core.crypto.MerkleTree public (net.corda.core.crypto.SecureHash) @@ -2028,6 +2066,7 @@ public final class net.corda.core.crypto.NullKeys extends java.lang.Object public final net.corda.core.identity.AnonymousParty getNULL_PARTY() @NotNull public final net.corda.core.crypto.TransactionSignature getNULL_SIGNATURE() + @NotNull public static final net.corda.core.crypto.NullKeys INSTANCE ## public static final class net.corda.core.crypto.NullKeys$NullPublicKey extends java.lang.Object implements java.lang.Comparable, java.security.PublicKey @@ -2040,6 +2079,7 @@ public static final class net.corda.core.crypto.NullKeys$NullPublicKey extends j public String getFormat() @NotNull public String toString() + @NotNull public static final net.corda.core.crypto.NullKeys$NullPublicKey INSTANCE ## @CordaSerializable @@ -2047,15 +2087,16 @@ public final class net.corda.core.crypto.PartialMerkleTree extends java.lang.Obj public (net.corda.core.crypto.PartialMerkleTree$PartialTree) @NotNull public final net.corda.core.crypto.PartialMerkleTree$PartialTree getRoot() - public final boolean verify(net.corda.core.crypto.SecureHash, java.util.List) + public final boolean verify(net.corda.core.crypto.SecureHash, java.util.List) + @NotNull public static final net.corda.core.crypto.PartialMerkleTree$Companion Companion ## public static final class net.corda.core.crypto.PartialMerkleTree$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.crypto.PartialMerkleTree build(net.corda.core.crypto.MerkleTree, java.util.List) + public final net.corda.core.crypto.PartialMerkleTree build(net.corda.core.crypto.MerkleTree, java.util.List) @NotNull - public final net.corda.core.crypto.SecureHash rootAndUsedHashes(net.corda.core.crypto.PartialMerkleTree$PartialTree, java.util.List) + public final net.corda.core.crypto.SecureHash rootAndUsedHashes(net.corda.core.crypto.PartialMerkleTree$PartialTree, java.util.List) ## @CordaSerializable public abstract static class net.corda.core.crypto.PartialMerkleTree$PartialTree extends java.lang.Object @@ -2161,6 +2202,7 @@ public abstract class net.corda.core.crypto.SecureHash extends net.corda.core.ut public String toString() @NotNull public static final net.corda.core.crypto.SecureHash zeroHashFor(String) + @NotNull public static final net.corda.core.crypto.SecureHash$Companion Companion public static final char DELIMITER = ':' @NotNull @@ -2188,7 +2230,7 @@ public static final class net.corda.core.crypto.SecureHash$Companion extends jav @NotNull public final net.corda.core.crypto.SecureHash$SHA256 getAllOnesHash() @NotNull - public net.corda.core.internal.utilities.PrivateInterner getInterner() + public net.corda.core.internal.utilities.PrivateInterner getInterner() @NotNull public final net.corda.core.crypto.SecureHash$SHA256 getZeroHash() @NotNull @@ -2278,7 +2320,7 @@ public final class net.corda.core.crypto.SignatureMetadata extends java.lang.Obj public String toString() ## public final class net.corda.core.crypto.SignatureScheme extends java.lang.Object - public (int, String, org.bouncycastle.asn1.x509.AlgorithmIdentifier, java.util.List, String, String, String, java.security.spec.AlgorithmParameterSpec, Integer, String) + public (int, String, org.bouncycastle.asn1.x509.AlgorithmIdentifier, java.util.List, String, String, String, java.security.spec.AlgorithmParameterSpec, Integer, String) public final int component1() @NotNull public final String component10() @@ -2287,7 +2329,7 @@ public final class net.corda.core.crypto.SignatureScheme extends java.lang.Objec @NotNull public final org.bouncycastle.asn1.x509.AlgorithmIdentifier component3() @NotNull - public final java.util.List component4() + public final java.util.List component4() @NotNull public final String component5() @NotNull @@ -2299,14 +2341,14 @@ public final class net.corda.core.crypto.SignatureScheme extends java.lang.Objec @Nullable public final Integer component9() @NotNull - public final net.corda.core.crypto.SignatureScheme copy(int, String, org.bouncycastle.asn1.x509.AlgorithmIdentifier, java.util.List, String, String, String, java.security.spec.AlgorithmParameterSpec, Integer, String) + public final net.corda.core.crypto.SignatureScheme copy(int, String, org.bouncycastle.asn1.x509.AlgorithmIdentifier, java.util.List, String, String, String, java.security.spec.AlgorithmParameterSpec, Integer, String) public boolean equals(Object) @Nullable public final java.security.spec.AlgorithmParameterSpec getAlgSpec() @NotNull public final String getAlgorithmName() @NotNull - public final java.util.List getAlternativeOIDs() + public final java.util.List getAlternativeOIDs() @NotNull public final String getDesc() @Nullable @@ -2326,9 +2368,9 @@ public final class net.corda.core.crypto.SignatureScheme extends java.lang.Objec ## @CordaSerializable public class net.corda.core.crypto.SignedData extends java.lang.Object - public (net.corda.core.serialization.SerializedBytes, net.corda.core.crypto.DigitalSignature$WithKey) + public (net.corda.core.serialization.SerializedBytes, net.corda.core.crypto.DigitalSignature$WithKey) @NotNull - public final net.corda.core.serialization.SerializedBytes getRaw() + public final net.corda.core.serialization.SerializedBytes getRaw() @NotNull public final net.corda.core.crypto.DigitalSignature$WithKey getSig() @NotNull @@ -2364,7 +2406,8 @@ public abstract static class net.corda.core.flows.AbstractStateReplacementFlow$A public final net.corda.core.flows.FlowSession getInitiatingSession() @NotNull public net.corda.core.utilities.ProgressTracker getProgressTracker() - protected abstract void verifyProposal(net.corda.core.transactions.SignedTransaction, net.corda.core.flows.AbstractStateReplacementFlow$Proposal) + protected abstract void verifyProposal(net.corda.core.transactions.SignedTransaction, net.corda.core.flows.AbstractStateReplacementFlow$Proposal) + @NotNull public static final net.corda.core.flows.AbstractStateReplacementFlow$Acceptor$Companion Companion ## public static final class net.corda.core.flows.AbstractStateReplacementFlow$Acceptor$Companion extends java.lang.Object @@ -2374,27 +2417,30 @@ public static final class net.corda.core.flows.AbstractStateReplacementFlow$Acce ## @CordaSerializable public static final class net.corda.core.flows.AbstractStateReplacementFlow$Acceptor$Companion$APPROVING extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.AbstractStateReplacementFlow$Acceptor$Companion$APPROVING INSTANCE ## @CordaSerializable public static final class net.corda.core.flows.AbstractStateReplacementFlow$Acceptor$Companion$VERIFYING extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.AbstractStateReplacementFlow$Acceptor$Companion$VERIFYING INSTANCE ## public abstract static class net.corda.core.flows.AbstractStateReplacementFlow$Instigator extends net.corda.core.flows.FlowLogic - public (net.corda.core.contracts.StateAndRef, M, net.corda.core.utilities.ProgressTracker) + public (net.corda.core.contracts.StateAndRef, M, net.corda.core.utilities.ProgressTracker) public (net.corda.core.contracts.StateAndRef, Object, net.corda.core.utilities.ProgressTracker, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull protected abstract net.corda.core.flows.AbstractStateReplacementFlow$UpgradeTx assembleTx() @Suspendable @NotNull - public net.corda.core.contracts.StateAndRef call() + public net.corda.core.contracts.StateAndRef call() public final M getModification() @NotNull - public final net.corda.core.contracts.StateAndRef getOriginalState() + public final net.corda.core.contracts.StateAndRef getOriginalState() @NotNull - public java.util.List>> getParticipantSessions() + public java.util.List getParticipantSessions() @NotNull public net.corda.core.utilities.ProgressTracker getProgressTracker() + @NotNull public static final net.corda.core.flows.AbstractStateReplacementFlow$Instigator$Companion Companion ## public static final class net.corda.core.flows.AbstractStateReplacementFlow$Instigator$Companion extends java.lang.Object @@ -2404,10 +2450,12 @@ public static final class net.corda.core.flows.AbstractStateReplacementFlow$Inst ## @CordaSerializable public static final class net.corda.core.flows.AbstractStateReplacementFlow$Instigator$Companion$NOTARY extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.AbstractStateReplacementFlow$Instigator$Companion$NOTARY INSTANCE ## @CordaSerializable public static final class net.corda.core.flows.AbstractStateReplacementFlow$Instigator$Companion$SIGNING extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.AbstractStateReplacementFlow$Instigator$Companion$SIGNING INSTANCE ## @CordaSerializable @@ -2417,7 +2465,7 @@ public static final class net.corda.core.flows.AbstractStateReplacementFlow$Prop public final net.corda.core.contracts.StateRef component1() public final M component2() @NotNull - public final net.corda.core.flows.AbstractStateReplacementFlow$Proposal copy(net.corda.core.contracts.StateRef, M) + public final net.corda.core.flows.AbstractStateReplacementFlow$Proposal copy(net.corda.core.contracts.StateRef, M) public boolean equals(Object) public final M getModification() @NotNull @@ -2441,38 +2489,39 @@ public static final class net.corda.core.flows.AbstractStateReplacementFlow$Upgr ## @Suspendable public final class net.corda.core.flows.CollectSignatureFlow extends net.corda.core.flows.FlowLogic - public (net.corda.core.transactions.SignedTransaction, net.corda.core.flows.FlowSession, java.util.List) + public (net.corda.core.transactions.SignedTransaction, net.corda.core.flows.FlowSession, java.util.List) public (net.corda.core.transactions.SignedTransaction, net.corda.core.flows.FlowSession, java.security.PublicKey...) @Suspendable @NotNull - public java.util.List call() + public java.util.List call() @NotNull public final net.corda.core.transactions.SignedTransaction getPartiallySignedTx() @NotNull public final net.corda.core.flows.FlowSession getSession() @NotNull - public final java.util.List getSigningKeys() + public final java.util.List getSigningKeys() ## public final class net.corda.core.flows.CollectSignaturesFlow extends net.corda.core.flows.FlowLogic - public (net.corda.core.transactions.SignedTransaction, java.util.Collection) - public (net.corda.core.transactions.SignedTransaction, java.util.Collection, Iterable) - public (net.corda.core.transactions.SignedTransaction, java.util.Collection, Iterable, net.corda.core.utilities.ProgressTracker) + public (net.corda.core.transactions.SignedTransaction, java.util.Collection) + public (net.corda.core.transactions.SignedTransaction, java.util.Collection, Iterable) + public (net.corda.core.transactions.SignedTransaction, java.util.Collection, Iterable, net.corda.core.utilities.ProgressTracker) public (net.corda.core.transactions.SignedTransaction, java.util.Collection, Iterable, net.corda.core.utilities.ProgressTracker, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.transactions.SignedTransaction, java.util.Collection, net.corda.core.utilities.ProgressTracker) + public (net.corda.core.transactions.SignedTransaction, java.util.Collection, net.corda.core.utilities.ProgressTracker) public (net.corda.core.transactions.SignedTransaction, java.util.Collection, net.corda.core.utilities.ProgressTracker, int, kotlin.jvm.internal.DefaultConstructorMarker) @Suspendable @NotNull public net.corda.core.transactions.SignedTransaction call() @Nullable - public final Iterable getMyOptionalKeys() + public final Iterable getMyOptionalKeys() @NotNull public final net.corda.core.transactions.SignedTransaction getPartiallySignedTx() @NotNull public net.corda.core.utilities.ProgressTracker getProgressTracker() @NotNull - public final java.util.Collection getSessionsToCollectFrom() + public final java.util.Collection getSessionsToCollectFrom() @NotNull public static final net.corda.core.utilities.ProgressTracker tracker() + @NotNull public static final net.corda.core.flows.CollectSignaturesFlow$Companion Companion ## public static final class net.corda.core.flows.CollectSignaturesFlow$Companion extends java.lang.Object @@ -2482,23 +2531,55 @@ public static final class net.corda.core.flows.CollectSignaturesFlow$Companion e ## @CordaSerializable public static final class net.corda.core.flows.CollectSignaturesFlow$Companion$COLLECTING extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.CollectSignaturesFlow$Companion$COLLECTING INSTANCE ## @CordaSerializable public static final class net.corda.core.flows.CollectSignaturesFlow$Companion$VERIFYING extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.CollectSignaturesFlow$Companion$VERIFYING INSTANCE ## +@CordaSerializable +public final class net.corda.core.flows.ComparableRecoveryTimeWindow extends java.lang.Object + public (java.time.Instant, int, java.time.Instant, int) + @NotNull + public final java.time.Instant component1() + public final int component2() + @NotNull + public final java.time.Instant component3() + public final int component4() + @NotNull + public final net.corda.core.flows.ComparableRecoveryTimeWindow copy(java.time.Instant, int, java.time.Instant, int) + public boolean equals(Object) + @NotNull + public final java.time.Instant getFromTime() + public final int getFromTimestampDiscriminator() + @NotNull + public final java.time.Instant getUntilTime() + public final int getUntilTimestampDiscriminator() + public int hashCode() + @NotNull + public String toString() + @NotNull + public static final net.corda.core.flows.ComparableRecoveryTimeWindow$Companion Companion +## +public static final class net.corda.core.flows.ComparableRecoveryTimeWindow$Companion extends java.lang.Object + public (kotlin.jvm.internal.DefaultConstructorMarker) + @NotNull + public final net.corda.core.flows.ComparableRecoveryTimeWindow from(net.corda.core.flows.RecoveryTimeWindow) +## public final class net.corda.core.flows.ContractUpgradeFlow extends java.lang.Object + @NotNull public static final net.corda.core.flows.ContractUpgradeFlow INSTANCE ## @StartableByRPC public static final class net.corda.core.flows.ContractUpgradeFlow$Authorise extends net.corda.core.flows.FlowLogic - public (net.corda.core.contracts.StateAndRef, Class>) + public (net.corda.core.contracts.StateAndRef, Class) @Suspendable @Nullable public Void call() @NotNull - public final net.corda.core.contracts.StateAndRef getStateAndRef() + public final net.corda.core.contracts.StateAndRef getStateAndRef() ## @StartableByRPC public static final class net.corda.core.flows.ContractUpgradeFlow$Deauthorise extends net.corda.core.flows.FlowLogic @@ -2512,43 +2593,142 @@ public static final class net.corda.core.flows.ContractUpgradeFlow$Deauthorise e @InitiatingFlow @StartableByRPC public static final class net.corda.core.flows.ContractUpgradeFlow$Initiate extends net.corda.core.flows.AbstractStateReplacementFlow$Instigator - public (net.corda.core.contracts.StateAndRef, Class>) + public (net.corda.core.contracts.StateAndRef, Class) @Suspendable @NotNull protected net.corda.core.flows.AbstractStateReplacementFlow$UpgradeTx assembleTx() ## public class net.corda.core.flows.DataVendingFlow extends net.corda.core.flows.FlowLogic + public (java.util.Set, Object, net.corda.core.flows.TransactionMetadata) + public (java.util.Set, Object, net.corda.core.flows.TransactionMetadata, int, kotlin.jvm.internal.DefaultConstructorMarker) public (net.corda.core.flows.FlowSession, Object) + public (net.corda.core.flows.FlowSession, Object, net.corda.core.flows.TransactionMetadata) + public (net.corda.core.flows.FlowSession, Object, net.corda.core.flows.TransactionMetadata, int, kotlin.jvm.internal.DefaultConstructorMarker) @Suspendable @Nullable public Void call() @NotNull - public final java.util.Set getOtherSessions() + public final java.util.Set getOtherSessions() @NotNull public final net.corda.core.flows.FlowSession getOtherSideSession() @NotNull public final Object getPayload() + protected boolean isFinality() @Suspendable @NotNull - protected net.corda.core.utilities.UntrustworthyData sendPayloadAndReceiveDataRequest(net.corda.core.flows.FlowSession, Object) + protected net.corda.core.utilities.UntrustworthyData sendPayloadAndReceiveDataRequest(net.corda.core.flows.FlowSession, Object) @Suspendable protected void verifyDataRequest(net.corda.core.internal.FetchDataFlow$Request$Data) ## @DoNotImplement public interface net.corda.core.flows.Destination ## +@DoNotImplement +@CordaSerializable +public abstract class net.corda.core.flows.DistributionList extends java.lang.Object + public (kotlin.jvm.internal.DefaultConstructorMarker) +## +@DoNotImplement +@CordaSerializable +public static final class net.corda.core.flows.DistributionList$ReceiverDistributionList extends net.corda.core.flows.DistributionList + public (byte[], net.corda.core.node.StatesToRecord) + @NotNull + public final byte[] component1() + @NotNull + public final net.corda.core.node.StatesToRecord component2() + @NotNull + public final net.corda.core.flows.DistributionList$ReceiverDistributionList copy(byte[], net.corda.core.node.StatesToRecord) + public boolean equals(Object) + @NotNull + public final byte[] getOpaqueData() + @NotNull + public final net.corda.core.node.StatesToRecord getReceiverStatesToRecord() + public int hashCode() + @NotNull + public String toString() +## +@DoNotImplement +@CordaSerializable +public static final class net.corda.core.flows.DistributionList$SenderDistributionList extends net.corda.core.flows.DistributionList + public (net.corda.core.node.StatesToRecord, java.util.Map) + @NotNull + public final net.corda.core.node.StatesToRecord component1() + @NotNull + public final java.util.Map component2() + @NotNull + public final net.corda.core.flows.DistributionList$SenderDistributionList copy(net.corda.core.node.StatesToRecord, java.util.Map) + public boolean equals(Object) + @NotNull + public final java.util.Map getPeersToStatesToRecord() + @NotNull + public final net.corda.core.node.StatesToRecord getSenderStatesToRecord() + public int hashCode() + @NotNull + public String toString() +## +@DoNotImplement +@CordaSerializable +public abstract class net.corda.core.flows.DistributionRecord extends java.lang.Object implements net.corda.core.contracts.NamedByHash + public () + @NotNull + public abstract net.corda.core.crypto.SecureHash getPeerPartyId() + @NotNull + public abstract java.time.Instant getTimestamp() + public abstract int getTimestampDiscriminator() + @NotNull + public abstract net.corda.core.crypto.SecureHash getTxId() +## +@CordaSerializable +public final class net.corda.core.flows.DistributionRecordKey extends java.lang.Object + public (net.corda.core.crypto.SecureHash, java.time.Instant, int) + @NotNull + public final net.corda.core.crypto.SecureHash component1() + @NotNull + public final java.time.Instant component2() + public final int component3() + @NotNull + public final net.corda.core.flows.DistributionRecordKey copy(net.corda.core.crypto.SecureHash, java.time.Instant, int) + public boolean equals(Object) + @NotNull + public final java.time.Instant getTimestamp() + public final int getTimestampDiscriminator() + @NotNull + public final net.corda.core.crypto.SecureHash getTxnId() + public int hashCode() + @NotNull + public String toString() +## +@CordaSerializable +public final class net.corda.core.flows.DistributionRecordType extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() + public static net.corda.core.flows.DistributionRecordType valueOf(String) + public static net.corda.core.flows.DistributionRecordType[] values() +## +@CordaSerializable +public final class net.corda.core.flows.DistributionRecords extends java.lang.Object + public () + public (java.util.List, java.util.List) + public (java.util.List, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) + @NotNull + public final java.util.List getReceiverRecords() + @NotNull + public final java.util.List getSenderRecords() + public final int getSize() +## @InitiatingFlow public final class net.corda.core.flows.FinalityFlow extends net.corda.core.flows.FlowLogic public (net.corda.core.transactions.SignedTransaction) - public (net.corda.core.transactions.SignedTransaction, java.util.Collection) - public (net.corda.core.transactions.SignedTransaction, java.util.Collection, java.util.Collection, net.corda.core.utilities.ProgressTracker) - public (net.corda.core.transactions.SignedTransaction, java.util.Collection, net.corda.core.node.StatesToRecord) - public (net.corda.core.transactions.SignedTransaction, java.util.Collection, net.corda.core.node.StatesToRecord, net.corda.core.utilities.ProgressTracker) + public (net.corda.core.transactions.SignedTransaction, java.util.Collection) + public (net.corda.core.transactions.SignedTransaction, java.util.Collection, java.util.Collection) + public (net.corda.core.transactions.SignedTransaction, java.util.Collection, java.util.Collection, net.corda.core.utilities.ProgressTracker) + public (net.corda.core.transactions.SignedTransaction, java.util.Collection, net.corda.core.node.StatesToRecord) + public (net.corda.core.transactions.SignedTransaction, java.util.Collection, net.corda.core.node.StatesToRecord, net.corda.core.utilities.ProgressTracker) public (net.corda.core.transactions.SignedTransaction, java.util.Collection, net.corda.core.node.StatesToRecord, net.corda.core.utilities.ProgressTracker, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.transactions.SignedTransaction, java.util.Collection, net.corda.core.utilities.ProgressTracker) + public (net.corda.core.transactions.SignedTransaction, java.util.Collection, net.corda.core.utilities.ProgressTracker) public (net.corda.core.transactions.SignedTransaction, java.util.Collection, net.corda.core.utilities.ProgressTracker, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.transactions.SignedTransaction, java.util.Set) - public (net.corda.core.transactions.SignedTransaction, java.util.Set, net.corda.core.utilities.ProgressTracker) + public (net.corda.core.transactions.SignedTransaction, java.util.Set) + public (net.corda.core.transactions.SignedTransaction, java.util.Set, net.corda.core.utilities.ProgressTracker) public (net.corda.core.transactions.SignedTransaction, net.corda.core.flows.FlowSession, net.corda.core.flows.FlowSession...) public (net.corda.core.transactions.SignedTransaction, net.corda.core.utilities.ProgressTracker) @Suspendable @@ -2560,6 +2740,7 @@ public final class net.corda.core.flows.FinalityFlow extends net.corda.core.flow public final net.corda.core.transactions.SignedTransaction getTransaction() @NotNull public static final net.corda.core.utilities.ProgressTracker tracker() + @NotNull public static final net.corda.core.flows.FinalityFlow$Companion Companion ## public static final class net.corda.core.flows.FinalityFlow$Companion extends java.lang.Object @@ -2569,15 +2750,66 @@ public static final class net.corda.core.flows.FinalityFlow$Companion extends ja ## @CordaSerializable public static final class net.corda.core.flows.FinalityFlow$Companion$BROADCASTING extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.FinalityFlow$Companion$BROADCASTING INSTANCE ## @CordaSerializable +public static final class net.corda.core.flows.FinalityFlow$Companion$BROADCASTING_NOTARY_ERROR extends net.corda.core.utilities.ProgressTracker$Step + @NotNull + public static final net.corda.core.flows.FinalityFlow$Companion$BROADCASTING_NOTARY_ERROR INSTANCE +## +@CordaSerializable +public static final class net.corda.core.flows.FinalityFlow$Companion$BROADCASTING_POST_NOTARISATION extends net.corda.core.utilities.ProgressTracker$Step + @NotNull + public static final net.corda.core.flows.FinalityFlow$Companion$BROADCASTING_POST_NOTARISATION INSTANCE +## +@CordaSerializable +public static final class net.corda.core.flows.FinalityFlow$Companion$BROADCASTING_PRE_NOTARISATION extends net.corda.core.utilities.ProgressTracker$Step + @NotNull + public static final net.corda.core.flows.FinalityFlow$Companion$BROADCASTING_PRE_NOTARISATION INSTANCE +## +@CordaSerializable +public static final class net.corda.core.flows.FinalityFlow$Companion$FINALISING_TRANSACTION extends net.corda.core.utilities.ProgressTracker$Step + @NotNull + public static final net.corda.core.flows.FinalityFlow$Companion$FINALISING_TRANSACTION INSTANCE +## +@CordaSerializable public static final class net.corda.core.flows.FinalityFlow$Companion$NOTARISING extends net.corda.core.utilities.ProgressTracker$Step @NotNull public net.corda.core.utilities.ProgressTracker childProgressTracker() + @NotNull public static final net.corda.core.flows.FinalityFlow$Companion$NOTARISING INSTANCE ## @CordaSerializable +public static final class net.corda.core.flows.FinalityFlow$Companion$RECORD_UNNOTARISED extends net.corda.core.utilities.ProgressTracker$Step + @NotNull + public static final net.corda.core.flows.FinalityFlow$Companion$RECORD_UNNOTARISED INSTANCE +## +@InitiatingFlow +@StartableByRPC +public final class net.corda.core.flows.FinalityRecoveryFlow extends net.corda.core.flows.FlowLogic + public () + public (java.util.Collection, java.util.Collection, net.corda.core.flows.FlowRecoveryQuery, boolean, boolean, java.util.Collection, net.corda.core.utilities.ProgressTracker) + public (java.util.Collection, java.util.Collection, net.corda.core.flows.FlowRecoveryQuery, boolean, boolean, java.util.Collection, net.corda.core.utilities.ProgressTracker, int, kotlin.jvm.internal.DefaultConstructorMarker) + public (java.util.Collection, boolean) + public (java.util.Collection, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) + public (java.util.Collection, boolean, boolean) + public (java.util.Collection, boolean, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) + public (net.corda.core.crypto.SecureHash, boolean) + public (net.corda.core.crypto.SecureHash, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) + public (net.corda.core.flows.FlowRecoveryQuery, boolean) + public (net.corda.core.flows.FlowRecoveryQuery, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) + public (net.corda.core.flows.StateMachineRunId, boolean) + public (net.corda.core.flows.StateMachineRunId, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) + public (boolean, boolean) + public (boolean, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) + @Suspendable + @NotNull + public java.util.Map call() + @NotNull + public net.corda.core.utilities.ProgressTracker getProgressTracker() +## +@CordaSerializable public class net.corda.core.flows.FlowException extends net.corda.core.CordaException implements net.corda.core.flows.IdentifiableException public () public (String) @@ -2593,7 +2825,7 @@ public class net.corda.core.flows.FlowException extends net.corda.core.CordaExce ## public interface net.corda.core.flows.FlowExternalAsyncOperation @NotNull - public abstract java.util.concurrent.CompletableFuture execute(String) + public abstract java.util.concurrent.CompletableFuture execute(String) ## public interface net.corda.core.flows.FlowExternalOperation @NotNull @@ -2689,28 +2921,29 @@ public static final class net.corda.core.flows.FlowInitiator$Service extends net public static final class net.corda.core.flows.FlowInitiator$Shell extends net.corda.core.flows.FlowInitiator @NotNull public String getName() + @NotNull public static final net.corda.core.flows.FlowInitiator$Shell INSTANCE ## public abstract class net.corda.core.flows.FlowLogic extends java.lang.Object public () @Suspendable @NotNull - public final R await(net.corda.core.flows.FlowExternalAsyncOperation) + public final R await(net.corda.core.flows.FlowExternalAsyncOperation) @Suspendable @NotNull - public final R await(net.corda.core.flows.FlowExternalOperation) + public final R await(net.corda.core.flows.FlowExternalOperation) @Suspendable public abstract T call() public final void checkFlowIsNotKilled() - public final void checkFlowIsNotKilled(kotlin.jvm.functions.Function0) - public final void checkFlowPermission(String, java.util.Map) + public final void checkFlowIsNotKilled(kotlin.jvm.functions.Function0) + public final void checkFlowPermission(String, java.util.Map) @Suspendable - public final void close(net.corda.core.utilities.NonEmptySet) + public final void close(net.corda.core.utilities.NonEmptySet) @Suspendable @Nullable public final net.corda.core.flows.FlowStackSnapshot flowStackSnapshot() @Nullable - public static final net.corda.core.flows.FlowLogic getCurrentTopLevel() + public static final net.corda.core.flows.FlowLogic getCurrentTopLevel() @Suspendable @NotNull public final net.corda.core.flows.FlowInfo getFlowInfo(net.corda.core.identity.Party) @@ -2737,45 +2970,47 @@ public abstract class net.corda.core.flows.FlowLogic extends java.lang.Object public final void persistFlowStackSnapshot() @Suspendable @NotNull - public net.corda.core.utilities.UntrustworthyData receive(Class, net.corda.core.identity.Party) + public net.corda.core.utilities.UntrustworthyData receive(Class, net.corda.core.identity.Party) + public final net.corda.core.utilities.UntrustworthyData receive(net.corda.core.identity.Party) @Suspendable @NotNull - public java.util.List> receiveAll(Class, java.util.List) + public final java.util.List receiveAll(Class, java.util.List) @Suspendable @NotNull - public java.util.List> receiveAll(Class, java.util.List, boolean) + public java.util.List receiveAll(Class, java.util.List, boolean) @Suspendable @NotNull - public java.util.Map> receiveAllMap(java.util.Map>) + public final java.util.Map receiveAllMap(java.util.Map) @Suspendable @NotNull - public java.util.Map> receiveAllMap(java.util.Map>, boolean) - public final void recordAuditEvent(String, String, java.util.Map) + public java.util.Map receiveAllMap(java.util.Map, boolean) + public final void recordAuditEvent(String, String, java.util.Map) @Suspendable public void send(net.corda.core.identity.Party, Object) @Suspendable - public final void sendAll(Object, java.util.Set) + public final void sendAll(Object, java.util.Set) @Suspendable - public final void sendAll(Object, java.util.Set, boolean) + public final void sendAll(Object, java.util.Set, boolean) @Suspendable - public final void sendAllMap(java.util.Map) + public final void sendAllMap(java.util.Map) @Suspendable - public final void sendAllMap(java.util.Map, boolean) + public final void sendAllMap(java.util.Map, boolean) @Suspendable @NotNull - public net.corda.core.utilities.UntrustworthyData sendAndReceive(Class, net.corda.core.identity.Party, Object) + public net.corda.core.utilities.UntrustworthyData sendAndReceive(Class, net.corda.core.identity.Party, Object) + public final net.corda.core.utilities.UntrustworthyData sendAndReceive(net.corda.core.identity.Party, Object) @Suspendable public static final void sleep(java.time.Duration) @Suspendable public static final void sleep(java.time.Duration, boolean) @Suspendable - public R subFlow(net.corda.core.flows.FlowLogic) + public R subFlow(net.corda.core.flows.FlowLogic) @Nullable - public final net.corda.core.messaging.DataFeed track() + public final net.corda.core.messaging.DataFeed track() @Nullable - public final net.corda.core.messaging.DataFeed>, java.util.List>> trackStepsTree() + public final net.corda.core.messaging.DataFeed trackStepsTree() @Nullable - public final net.corda.core.messaging.DataFeed trackStepsTreeIndex() + public final net.corda.core.messaging.DataFeed trackStepsTreeIndex() @Suspendable @NotNull public final net.corda.core.transactions.SignedTransaction waitForLedgerCommit(net.corda.core.crypto.SecureHash) @@ -2783,13 +3018,14 @@ public abstract class net.corda.core.flows.FlowLogic extends java.lang.Object @NotNull public final net.corda.core.transactions.SignedTransaction waitForLedgerCommit(net.corda.core.crypto.SecureHash, boolean) @Suspendable - public final void waitForStateConsumption(java.util.Set) + public final void waitForStateConsumption(java.util.Set) + @NotNull public static final net.corda.core.flows.FlowLogic$Companion Companion ## public static final class net.corda.core.flows.FlowLogic$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @Nullable - public final net.corda.core.flows.FlowLogic getCurrentTopLevel() + public final net.corda.core.flows.FlowLogic getCurrentTopLevel() @Suspendable public final void sleep(java.time.Duration) @Suspendable @@ -2802,11 +3038,42 @@ public interface net.corda.core.flows.FlowLogicRef @DoNotImplement public interface net.corda.core.flows.FlowLogicRefFactory @NotNull - public abstract net.corda.core.flows.FlowLogicRef create(Class>, Object...) + public abstract net.corda.core.flows.FlowLogicRef create(Class, Object...) @NotNull public abstract net.corda.core.flows.FlowLogicRef create(String, Object...) @NotNull - public abstract net.corda.core.flows.FlowLogic toFlowLogic(net.corda.core.flows.FlowLogicRef) + public abstract net.corda.core.flows.FlowLogic toFlowLogic(net.corda.core.flows.FlowLogicRef) +## +@CordaSerializable +public final class net.corda.core.flows.FlowRecoveryException extends net.corda.core.flows.FlowException + public (String, Throwable) + public (String, Throwable, int, kotlin.jvm.internal.DefaultConstructorMarker) + public (net.corda.core.crypto.SecureHash, String, Throwable) + public (net.corda.core.crypto.SecureHash, String, Throwable, int, kotlin.jvm.internal.DefaultConstructorMarker) +## +@CordaSerializable +public final class net.corda.core.flows.FlowRecoveryQuery extends java.lang.Object + public () + public (net.corda.core.flows.FlowTimeWindow, java.util.List, java.util.List) + public (net.corda.core.flows.FlowTimeWindow, java.util.List, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) + @Nullable + public final net.corda.core.flows.FlowTimeWindow component1() + @Nullable + public final java.util.List component2() + @Nullable + public final java.util.List component3() + @NotNull + public final net.corda.core.flows.FlowRecoveryQuery copy(net.corda.core.flows.FlowTimeWindow, java.util.List, java.util.List) + public boolean equals(Object) + @Nullable + public final java.util.List getCounterParties() + @Nullable + public final java.util.List getInitiatedBy() + @Nullable + public final net.corda.core.flows.FlowTimeWindow getTimeframe() + public int hashCode() + @NotNull + public String toString() ## @DoNotImplement public abstract class net.corda.core.flows.FlowSession extends java.lang.Object @@ -2824,37 +3091,41 @@ public abstract class net.corda.core.flows.FlowSession extends java.lang.Object @NotNull public abstract net.corda.core.flows.Destination getDestination() @Suspendable - @NotNull - public abstract net.corda.core.utilities.UntrustworthyData receive(Class) + public final net.corda.core.utilities.UntrustworthyData receive() @Suspendable @NotNull - public abstract net.corda.core.utilities.UntrustworthyData receive(Class, boolean) + public abstract net.corda.core.utilities.UntrustworthyData receive(Class) + @Suspendable + @NotNull + public abstract net.corda.core.utilities.UntrustworthyData receive(Class, boolean) @Suspendable public abstract void send(Object) @Suspendable public abstract void send(Object, boolean) @Suspendable @NotNull - public abstract net.corda.core.utilities.UntrustworthyData sendAndReceive(Class, Object) + public abstract net.corda.core.utilities.UntrustworthyData sendAndReceive(Class, Object) @Suspendable @NotNull - public abstract net.corda.core.utilities.UntrustworthyData sendAndReceive(Class, Object, boolean) + public abstract net.corda.core.utilities.UntrustworthyData sendAndReceive(Class, Object, boolean) + @Suspendable + public final net.corda.core.utilities.UntrustworthyData sendAndReceive(Object) ## public final class net.corda.core.flows.FlowStackSnapshot extends java.lang.Object - public (java.time.Instant, String, java.util.List) + public (java.time.Instant, String, java.util.List) @NotNull public final java.time.Instant component1() @NotNull public final String component2() @NotNull - public final java.util.List component3() + public final java.util.List component3() @NotNull - public final net.corda.core.flows.FlowStackSnapshot copy(java.time.Instant, String, java.util.List) + public final net.corda.core.flows.FlowStackSnapshot copy(java.time.Instant, String, java.util.List) public boolean equals(Object) @NotNull public final String getFlowClass() @NotNull - public final java.util.List getStackFrames() + public final java.util.List getStackFrames() @NotNull public final java.time.Instant getTime() public int hashCode() @@ -2862,16 +3133,16 @@ public final class net.corda.core.flows.FlowStackSnapshot extends java.lang.Obje public String toString() ## public static final class net.corda.core.flows.FlowStackSnapshot$Frame extends java.lang.Object - public (StackTraceElement, java.util.List) + public (StackTraceElement, java.util.List) @NotNull public final StackTraceElement component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() @NotNull - public final net.corda.core.flows.FlowStackSnapshot$Frame copy(StackTraceElement, java.util.List) + public final net.corda.core.flows.FlowStackSnapshot$Frame copy(StackTraceElement, java.util.List) public boolean equals(Object) @NotNull - public final java.util.List getStackObjects() + public final java.util.List getStackObjects() @NotNull public final StackTraceElement getStackTraceElement() public int hashCode() @@ -2879,6 +3150,74 @@ public static final class net.corda.core.flows.FlowStackSnapshot$Frame extends j public String toString() ## @CordaSerializable +public final class net.corda.core.flows.FlowTimeWindow extends java.lang.Object + public () + public (java.time.Instant, java.time.Instant) + public (java.time.Instant, java.time.Instant, int, kotlin.jvm.internal.DefaultConstructorMarker) + @NotNull + public static final net.corda.core.flows.FlowTimeWindow between(java.time.Instant, java.time.Instant) + @Nullable + public final java.time.Instant component1() + @Nullable + public final java.time.Instant component2() + @NotNull + public final net.corda.core.flows.FlowTimeWindow copy(java.time.Instant, java.time.Instant) + public boolean equals(Object) + @NotNull + public static final net.corda.core.flows.FlowTimeWindow fromOnly(java.time.Instant) + @Nullable + public final java.time.Instant getFromTime() + @Nullable + public final java.time.Instant getUntilTime() + public int hashCode() + @NotNull + public String toString() + @NotNull + public static final net.corda.core.flows.FlowTimeWindow untilOnly(java.time.Instant) + @NotNull + public static final net.corda.core.flows.FlowTimeWindow$Companion Companion +## +public static final class net.corda.core.flows.FlowTimeWindow$Companion extends java.lang.Object + public (kotlin.jvm.internal.DefaultConstructorMarker) + @NotNull + public final net.corda.core.flows.FlowTimeWindow between(java.time.Instant, java.time.Instant) + @NotNull + public final net.corda.core.flows.FlowTimeWindow fromOnly(java.time.Instant) + @NotNull + public final net.corda.core.flows.FlowTimeWindow untilOnly(java.time.Instant) +## +@CordaSerializable +public final class net.corda.core.flows.FlowTransactionInfo extends java.lang.Object + public (net.corda.core.flows.StateMachineRunId, String, net.corda.core.node.services.TransactionStatus, java.time.Instant, net.corda.core.flows.TransactionMetadata) + @NotNull + public final net.corda.core.flows.StateMachineRunId component1() + @NotNull + public final String component2() + @NotNull + public final net.corda.core.node.services.TransactionStatus component3() + @NotNull + public final java.time.Instant component4() + @Nullable + public final net.corda.core.flows.TransactionMetadata component5() + @NotNull + public final net.corda.core.flows.FlowTransactionInfo copy(net.corda.core.flows.StateMachineRunId, String, net.corda.core.node.services.TransactionStatus, java.time.Instant, net.corda.core.flows.TransactionMetadata) + public boolean equals(Object) + @Nullable + public final net.corda.core.flows.TransactionMetadata getMetadata() + @NotNull + public final net.corda.core.flows.StateMachineRunId getStateMachineRunId() + @NotNull + public final net.corda.core.node.services.TransactionStatus getStatus() + @NotNull + public final java.time.Instant getTimestamp() + @NotNull + public final String getTxId() + public int hashCode() + public final boolean isInitiator(net.corda.core.identity.CordaX500Name) + @NotNull + public String toString() +## +@CordaSerializable public class net.corda.core.flows.HospitalizeFlowException extends net.corda.core.CordaRuntimeException public () public (String) @@ -2890,13 +3229,13 @@ public interface net.corda.core.flows.IdentifiableException public Long getErrorId() ## public final class net.corda.core.flows.IllegalFlowLogicException extends java.lang.IllegalArgumentException - public (Class, String) + public (Class, String) public (String, String) @NotNull public final String getType() ## public @interface net.corda.core.flows.InitiatedBy - public abstract Class> value() + public abstract Class value() ## public @interface net.corda.core.flows.InitiatingFlow public abstract int version() @@ -2909,16 +3248,99 @@ public final class net.corda.core.flows.KilledFlowException extends net.corda.co public final net.corda.core.flows.StateMachineRunId getId() ## @CordaSerializable +public final class net.corda.core.flows.LedgerRecoveryException extends net.corda.core.flows.FlowException + public (String) +## +@StartableByRPC +public final class net.corda.core.flows.LedgerRecoveryFlow extends net.corda.core.flows.FlowLogic + public (java.util.Collection) + public (java.util.Collection, net.corda.core.flows.RecoveryTimeWindow) + public (java.util.Collection, net.corda.core.flows.RecoveryTimeWindow, boolean) + public (java.util.Collection, net.corda.core.flows.RecoveryTimeWindow, boolean, boolean) + public (java.util.Collection, net.corda.core.flows.RecoveryTimeWindow, boolean, boolean, boolean) + public (java.util.Collection, net.corda.core.flows.RecoveryTimeWindow, boolean, boolean, boolean, boolean, int) + public (net.corda.core.flows.LedgerRecoveryParameters, net.corda.core.utilities.ProgressTracker) + public (net.corda.core.flows.LedgerRecoveryParameters, net.corda.core.utilities.ProgressTracker, int, kotlin.jvm.internal.DefaultConstructorMarker) + public (net.corda.core.identity.Party) + public (net.corda.core.identity.Party, net.corda.core.flows.RecoveryTimeWindow) + public (net.corda.core.identity.Party, net.corda.core.flows.RecoveryTimeWindow, boolean) + public (net.corda.core.identity.Party, net.corda.core.flows.RecoveryTimeWindow, boolean, boolean) + public (net.corda.core.identity.Party, net.corda.core.flows.RecoveryTimeWindow, boolean, boolean, boolean) + public (boolean) + public (boolean, net.corda.core.flows.RecoveryTimeWindow) + public (boolean, net.corda.core.flows.RecoveryTimeWindow, boolean) + public (boolean, net.corda.core.flows.RecoveryTimeWindow, boolean, boolean) + public (boolean, net.corda.core.flows.RecoveryTimeWindow, boolean, boolean, int) + public (boolean, net.corda.core.flows.RecoveryTimeWindow, boolean, boolean, int, boolean) + @Suspendable + @NotNull + public net.corda.core.flows.LedgerRecoveryResult call() + @NotNull + public net.corda.core.utilities.ProgressTracker getProgressTracker() +## +@CordaSerializable +public final class net.corda.core.flows.LedgerRecoveryParameters extends java.lang.Object + public (java.util.Collection, net.corda.core.flows.RecoveryTimeWindow, boolean, boolean, boolean, boolean, int, boolean) + public (java.util.Collection, net.corda.core.flows.RecoveryTimeWindow, boolean, boolean, boolean, boolean, int, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) + @NotNull + public final java.util.Collection component1() + @Nullable + public final net.corda.core.flows.RecoveryTimeWindow component2() + public final boolean component3() + public final boolean component4() + public final boolean component5() + public final boolean component6() + public final int component7() + public final boolean component8() + @NotNull + public final net.corda.core.flows.LedgerRecoveryParameters copy(java.util.Collection, net.corda.core.flows.RecoveryTimeWindow, boolean, boolean, boolean, boolean, int, boolean) + public boolean equals(Object) + public final boolean getAlsoFinalize() + public final boolean getDryRun() + public final int getRecoveryBatchSize() + @NotNull + public final java.util.Collection getRecoveryPeers() + @Nullable + public final net.corda.core.flows.RecoveryTimeWindow getTimeWindow() + public final boolean getUseAllNetworkNodes() + public final boolean getUseTimeWindowNarrowing() + public final boolean getVerboseLogging() + public int hashCode() + @NotNull + public String toString() +## +@CordaSerializable +public final class net.corda.core.flows.LedgerRecoveryResult extends java.lang.Object + public (long, long, long, long) + public final long component1() + public final long component2() + public final long component3() + public final long component4() + @NotNull + public final net.corda.core.flows.LedgerRecoveryResult copy(long, long, long, long) + public boolean equals(Object) + public final long getTotalErrors() + public final long getTotalRecoveredInFlightTransactions() + public final long getTotalRecoveredRecords() + public final long getTotalRecoveredTransactions() + public int hashCode() + @NotNull + public String toString() +## +@CordaSerializable public final class net.corda.core.flows.MaybeSerializedSignedTransaction extends java.lang.Object implements net.corda.core.contracts.NamedByHash - public (net.corda.core.crypto.SecureHash, net.corda.core.serialization.SerializedBytes, net.corda.core.transactions.SignedTransaction) + @DeprecatedConstructorForDeserialization + public (net.corda.core.crypto.SecureHash, net.corda.core.serialization.SerializedBytes, net.corda.core.transactions.SignedTransaction) + public (net.corda.core.crypto.SecureHash, net.corda.core.serialization.SerializedBytes, net.corda.core.transactions.SignedTransaction, boolean) @Nullable public final net.corda.core.transactions.SignedTransaction get() @NotNull public net.corda.core.crypto.SecureHash getId() + public final boolean getInFlight() @Nullable public final net.corda.core.transactions.SignedTransaction getNonSerialised() @Nullable - public final net.corda.core.serialization.SerializedBytes getSerialized() + public final net.corda.core.serialization.SerializedBytes getSerialized() public final boolean isNull() @NotNull public final String payloadContentDescription() @@ -2948,11 +3370,12 @@ public final class net.corda.core.flows.NotarisationPayload extends java.lang.Ob ## @CordaSerializable public final class net.corda.core.flows.NotarisationRequest extends java.lang.Object - public (java.util.List, net.corda.core.crypto.SecureHash) + public (java.util.List, net.corda.core.crypto.SecureHash) @NotNull - public final java.util.List getStatesToConsume() + public final java.util.List getStatesToConsume() @NotNull public final net.corda.core.crypto.SecureHash getTransactionId() + @NotNull public static final net.corda.core.flows.NotarisationRequest$Companion Companion ## public static final class net.corda.core.flows.NotarisationRequest$Companion extends java.lang.Object @@ -2976,21 +3399,21 @@ public final class net.corda.core.flows.NotarisationRequestSignature extends jav ## @CordaSerializable public final class net.corda.core.flows.NotarisationResponse extends java.lang.Object - public (java.util.List) + public (java.util.List) @NotNull - public final java.util.List component1() + public final java.util.List component1() @NotNull - public final net.corda.core.flows.NotarisationResponse copy(java.util.List) + public final net.corda.core.flows.NotarisationResponse copy(java.util.List) public boolean equals(Object) @NotNull - public final java.util.List getSignatures() + public final java.util.List getSignatures() public int hashCode() @NotNull public String toString() ## @InitiatingFlow public final class net.corda.core.flows.NotaryChangeFlow extends net.corda.core.flows.AbstractStateReplacementFlow$Instigator - public (net.corda.core.contracts.StateAndRef, net.corda.core.identity.Party, net.corda.core.utilities.ProgressTracker) + public (net.corda.core.contracts.StateAndRef, net.corda.core.identity.Party, net.corda.core.utilities.ProgressTracker) public (net.corda.core.contracts.StateAndRef, net.corda.core.identity.Party, net.corda.core.utilities.ProgressTracker, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull protected net.corda.core.flows.AbstractStateReplacementFlow$UpgradeTx assembleTx() @@ -2998,6 +3421,7 @@ public final class net.corda.core.flows.NotaryChangeFlow extends net.corda.core. @CordaSerializable public abstract class net.corda.core.flows.NotaryError extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) + @NotNull public static final net.corda.core.flows.NotaryError$Companion Companion public static final int NUM_STATES = 5 ## @@ -3006,16 +3430,16 @@ public static final class net.corda.core.flows.NotaryError$Companion extends jav ## @CordaSerializable public static final class net.corda.core.flows.NotaryError$Conflict extends net.corda.core.flows.NotaryError - public (net.corda.core.crypto.SecureHash, java.util.Map) + public (net.corda.core.crypto.SecureHash, java.util.Map) @NotNull public final net.corda.core.crypto.SecureHash component1() @NotNull - public final java.util.Map component2() + public final java.util.Map component2() @NotNull - public final net.corda.core.flows.NotaryError$Conflict copy(net.corda.core.crypto.SecureHash, java.util.Map) + public final net.corda.core.flows.NotaryError$Conflict copy(net.corda.core.crypto.SecureHash, java.util.Map) public boolean equals(Object) @NotNull - public final java.util.Map getConsumedStates() + public final java.util.Map getConsumedStates() @NotNull public final net.corda.core.crypto.SecureHash getTxId() public int hashCode() @@ -3067,6 +3491,7 @@ public static final class net.corda.core.flows.NotaryError$TimeWindowInvalid ext public int hashCode() @NotNull public String toString() + @NotNull public static final net.corda.core.flows.NotaryError$TimeWindowInvalid$Companion Companion @NotNull public static final net.corda.core.flows.NotaryError$TimeWindowInvalid INSTANCE @@ -3090,6 +3515,7 @@ public static final class net.corda.core.flows.NotaryError$TransactionInvalid ex ## @CordaSerializable public static final class net.corda.core.flows.NotaryError$WrongNotary extends net.corda.core.flows.NotaryError + @NotNull public static final net.corda.core.flows.NotaryError$WrongNotary INSTANCE ## @CordaSerializable @@ -3115,16 +3541,17 @@ public static class net.corda.core.flows.NotaryFlow$Client extends net.corda.cor public (net.corda.core.transactions.SignedTransaction, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) @Suspendable @NotNull - public java.util.List call() + public java.util.List call() @NotNull protected final net.corda.core.identity.Party checkTransaction() @NotNull public net.corda.core.utilities.ProgressTracker getProgressTracker() @Suspendable @NotNull - protected final net.corda.core.utilities.UntrustworthyData notarise(net.corda.core.identity.Party) + protected final net.corda.core.utilities.UntrustworthyData notarise(net.corda.core.identity.Party) + @NotNull + protected final java.util.List validateResponse(net.corda.core.utilities.UntrustworthyData, net.corda.core.identity.Party) @NotNull - protected final java.util.List validateResponse(net.corda.core.utilities.UntrustworthyData, net.corda.core.identity.Party) public static final net.corda.core.flows.NotaryFlow$Client$Companion Companion ## public static final class net.corda.core.flows.NotaryFlow$Client$Companion extends java.lang.Object @@ -3134,17 +3561,29 @@ public static final class net.corda.core.flows.NotaryFlow$Client$Companion exten ## @CordaSerializable public static final class net.corda.core.flows.NotaryFlow$Client$Companion$REQUESTING extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.NotaryFlow$Client$Companion$REQUESTING INSTANCE ## @CordaSerializable public static final class net.corda.core.flows.NotaryFlow$Client$Companion$VALIDATING extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.NotaryFlow$Client$Companion$VALIDATING INSTANCE ## +public final class net.corda.core.flows.NotarySigCheck extends java.lang.Object + public final boolean needsNotarySignature(net.corda.core.transactions.SignedTransaction) + @NotNull + public static final net.corda.core.flows.NotarySigCheck INSTANCE +## public final class net.corda.core.flows.ReceiveFinalityFlow extends net.corda.core.flows.FlowLogic + @DeprecatedConstructorForDeserialization public (net.corda.core.flows.FlowSession) + @DeprecatedConstructorForDeserialization public (net.corda.core.flows.FlowSession, net.corda.core.crypto.SecureHash) + @DeprecatedConstructorForDeserialization public (net.corda.core.flows.FlowSession, net.corda.core.crypto.SecureHash, net.corda.core.node.StatesToRecord) public (net.corda.core.flows.FlowSession, net.corda.core.crypto.SecureHash, net.corda.core.node.StatesToRecord, int, kotlin.jvm.internal.DefaultConstructorMarker) + public (net.corda.core.flows.FlowSession, net.corda.core.crypto.SecureHash, net.corda.core.node.StatesToRecord, Boolean) + public (net.corda.core.flows.FlowSession, net.corda.core.crypto.SecureHash, net.corda.core.node.StatesToRecord, Boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) @Suspendable @NotNull public net.corda.core.transactions.SignedTransaction call() @@ -3153,18 +3592,93 @@ public final class net.corda.core.flows.ReceiveStateAndRefFlow extends net.corda public (net.corda.core.flows.FlowSession) @Suspendable @NotNull - public java.util.List> call() + public java.util.List call() ## public class net.corda.core.flows.ReceiveTransactionFlow extends net.corda.core.flows.FlowLogic public (net.corda.core.flows.FlowSession) public (net.corda.core.flows.FlowSession, boolean) public (net.corda.core.flows.FlowSession, boolean, net.corda.core.node.StatesToRecord) public (net.corda.core.flows.FlowSession, boolean, net.corda.core.node.StatesToRecord, int, kotlin.jvm.internal.DefaultConstructorMarker) + public (net.corda.core.flows.FlowSession, boolean, net.corda.core.node.StatesToRecord, Boolean) + public (net.corda.core.flows.FlowSession, boolean, net.corda.core.node.StatesToRecord, Boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) @Suspendable @NotNull public net.corda.core.transactions.SignedTransaction call() @Suspendable protected void checkBeforeRecording(net.corda.core.transactions.SignedTransaction) + @NotNull + public net.corda.core.transactions.SignedTransaction resolvePayload(Object) +## +@DoNotImplement +@CordaSerializable +public final class net.corda.core.flows.ReceiverDistributionRecord extends net.corda.core.flows.DistributionRecord + public (net.corda.core.crypto.SecureHash, net.corda.core.crypto.SecureHash, java.time.Instant, int, net.corda.core.utilities.OpaqueBytes, net.corda.core.node.StatesToRecord) + @NotNull + public final net.corda.core.crypto.SecureHash component1() + @NotNull + public final net.corda.core.crypto.SecureHash component2() + @NotNull + public final java.time.Instant component3() + public final int component4() + @NotNull + public final net.corda.core.utilities.OpaqueBytes component5() + @NotNull + public final net.corda.core.node.StatesToRecord component6() + @NotNull + public final net.corda.core.flows.ReceiverDistributionRecord copy(net.corda.core.crypto.SecureHash, net.corda.core.crypto.SecureHash, java.time.Instant, int, net.corda.core.utilities.OpaqueBytes, net.corda.core.node.StatesToRecord) + public boolean equals(Object) + @NotNull + public final net.corda.core.utilities.OpaqueBytes getEncryptedDistributionList() + @NotNull + public net.corda.core.crypto.SecureHash getId() + @NotNull + public net.corda.core.crypto.SecureHash getPeerPartyId() + @NotNull + public final net.corda.core.node.StatesToRecord getReceiverStatesToRecord() + @NotNull + public java.time.Instant getTimestamp() + public int getTimestampDiscriminator() + @NotNull + public net.corda.core.crypto.SecureHash getTxId() + public int hashCode() + @NotNull + public String toString() +## +@CordaSerializable +public final class net.corda.core.flows.RecoveryTimeWindow extends java.lang.Object + public (java.time.Instant, java.time.Instant) + public (java.time.Instant, java.time.Instant, int, kotlin.jvm.internal.DefaultConstructorMarker) + @NotNull + public static final net.corda.core.flows.RecoveryTimeWindow between(java.time.Instant, java.time.Instant) + @NotNull + public final java.time.Instant component1() + @NotNull + public final java.time.Instant component2() + @NotNull + public final net.corda.core.flows.RecoveryTimeWindow copy(java.time.Instant, java.time.Instant) + public boolean equals(Object) + @NotNull + public static final net.corda.core.flows.RecoveryTimeWindow fromOnly(java.time.Instant) + @NotNull + public final java.time.Instant getFromTime() + @NotNull + public final java.time.Instant getUntilTime() + public int hashCode() + @NotNull + public String toString() + @NotNull + public static final net.corda.core.flows.RecoveryTimeWindow untilOnly(java.time.Instant) + @NotNull + public static final net.corda.core.flows.RecoveryTimeWindow$Companion Companion +## +public static final class net.corda.core.flows.RecoveryTimeWindow$Companion extends java.lang.Object + public (kotlin.jvm.internal.DefaultConstructorMarker) + @NotNull + public final net.corda.core.flows.RecoveryTimeWindow between(java.time.Instant, java.time.Instant) + @NotNull + public final net.corda.core.flows.RecoveryTimeWindow fromOnly(java.time.Instant) + @NotNull + public final net.corda.core.flows.RecoveryTimeWindow untilOnly(java.time.Instant) ## @CordaSerializable public final class net.corda.core.flows.ResultSerializationException extends net.corda.core.CordaRuntimeException @@ -3173,10 +3687,64 @@ public final class net.corda.core.flows.ResultSerializationException extends net public @interface net.corda.core.flows.SchedulableFlow ## public class net.corda.core.flows.SendStateAndRefFlow extends net.corda.core.flows.DataVendingFlow - public (net.corda.core.flows.FlowSession, java.util.List>) + public (net.corda.core.flows.FlowSession, java.util.List) ## public class net.corda.core.flows.SendTransactionFlow extends net.corda.core.flows.DataVendingFlow public (net.corda.core.flows.FlowSession, net.corda.core.transactions.SignedTransaction) + public (net.corda.core.transactions.SignedTransaction, java.util.Set, java.util.Set, net.corda.core.node.StatesToRecord, boolean) + public (net.corda.core.transactions.SignedTransaction, java.util.Set, java.util.Set, net.corda.core.node.StatesToRecord, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) + @NotNull + public final java.util.Set getObserverSessions() + @NotNull + public final java.util.Set getParticipantSessions() + @NotNull + public final net.corda.core.node.StatesToRecord getSenderStatesToRecord() + @NotNull + public final net.corda.core.transactions.SignedTransaction getStx() + @NotNull + public static final net.corda.core.flows.SendTransactionFlow$Companion Companion +## +public static final class net.corda.core.flows.SendTransactionFlow$Companion extends java.lang.Object + public (kotlin.jvm.internal.DefaultConstructorMarker) + @NotNull + public final net.corda.core.identity.CordaX500Name getDUMMY_PARTICIPANT_NAME() + @Nullable + public final net.corda.core.flows.TransactionMetadata makeMetaData(net.corda.core.transactions.SignedTransaction, boolean, net.corda.core.node.StatesToRecord, java.util.Set, java.util.Set) +## +@DoNotImplement +@CordaSerializable +public final class net.corda.core.flows.SenderDistributionRecord extends net.corda.core.flows.DistributionRecord + public (net.corda.core.crypto.SecureHash, net.corda.core.crypto.SecureHash, java.time.Instant, int, net.corda.core.node.StatesToRecord, net.corda.core.node.StatesToRecord) + @NotNull + public final net.corda.core.crypto.SecureHash component1() + @NotNull + public final net.corda.core.crypto.SecureHash component2() + @NotNull + public final java.time.Instant component3() + public final int component4() + @NotNull + public final net.corda.core.node.StatesToRecord component5() + @NotNull + public final net.corda.core.node.StatesToRecord component6() + @NotNull + public final net.corda.core.flows.SenderDistributionRecord copy(net.corda.core.crypto.SecureHash, net.corda.core.crypto.SecureHash, java.time.Instant, int, net.corda.core.node.StatesToRecord, net.corda.core.node.StatesToRecord) + public boolean equals(Object) + @NotNull + public net.corda.core.crypto.SecureHash getId() + @NotNull + public net.corda.core.crypto.SecureHash getPeerPartyId() + @NotNull + public final net.corda.core.node.StatesToRecord getReceiverStatesToRecord() + @NotNull + public final net.corda.core.node.StatesToRecord getSenderStatesToRecord() + @NotNull + public java.time.Instant getTimestamp() + public int getTimestampDiscriminator() + @NotNull + public net.corda.core.crypto.SecureHash getTxId() + public int hashCode() + @NotNull + public String toString() ## public abstract class net.corda.core.flows.SignTransactionFlow extends net.corda.core.flows.FlowLogic public (net.corda.core.flows.FlowSession) @@ -3193,6 +3761,7 @@ public abstract class net.corda.core.flows.SignTransactionFlow extends net.corda public net.corda.core.utilities.ProgressTracker getProgressTracker() @NotNull public static final net.corda.core.utilities.ProgressTracker tracker() + @NotNull public static final net.corda.core.flows.SignTransactionFlow$Companion Companion ## public static final class net.corda.core.flows.SignTransactionFlow$Companion extends java.lang.Object @@ -3202,16 +3771,39 @@ public static final class net.corda.core.flows.SignTransactionFlow$Companion ext ## @CordaSerializable public static final class net.corda.core.flows.SignTransactionFlow$Companion$RECEIVING extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.SignTransactionFlow$Companion$RECEIVING INSTANCE ## @CordaSerializable public static final class net.corda.core.flows.SignTransactionFlow$Companion$SIGNING extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.SignTransactionFlow$Companion$SIGNING INSTANCE ## @CordaSerializable public static final class net.corda.core.flows.SignTransactionFlow$Companion$VERIFYING extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.SignTransactionFlow$Companion$VERIFYING INSTANCE ## +@CordaSerializable +public final class net.corda.core.flows.SignedTransactionWithDistributionList extends java.lang.Object + public (net.corda.core.transactions.SignedTransaction, byte[], boolean) + @NotNull + public final net.corda.core.transactions.SignedTransaction component1() + @NotNull + public final byte[] component2() + public final boolean component3() + @NotNull + public final net.corda.core.flows.SignedTransactionWithDistributionList copy(net.corda.core.transactions.SignedTransaction, byte[], boolean) + public boolean equals(Object) + @NotNull + public final byte[] getDistributionList() + @NotNull + public final net.corda.core.transactions.SignedTransaction getStx() + public int hashCode() + public final boolean isFinality() + @NotNull + public String toString() +## public final class net.corda.core.flows.StackFrameDataToken extends java.lang.Object public (String) @NotNull @@ -3253,8 +3845,10 @@ public final class net.corda.core.flows.StateConsumptionDetails extends java.lan ## @CordaSerializable public static final class net.corda.core.flows.StateConsumptionDetails$ConsumedStateType extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.flows.StateConsumptionDetails$ConsumedStateType valueOf(String) - public static net.corda.core.flows.StateConsumptionDetails$ConsumedStateType[] values() + public static net.corda.core.flows.StateConsumptionDetails.ConsumedStateType[] values() ## @CordaSerializable public final class net.corda.core.flows.StateMachineRunId extends java.lang.Object @@ -3269,6 +3863,7 @@ public final class net.corda.core.flows.StateMachineRunId extends java.lang.Obje public int hashCode() @NotNull public String toString() + @NotNull public static final net.corda.core.flows.StateMachineRunId$Companion Companion ## public static final class net.corda.core.flows.StateMachineRunId$Companion extends java.lang.Object @@ -3284,6 +3879,24 @@ public class net.corda.core.flows.StateReplacementException extends net.corda.co public (String, Throwable, int, kotlin.jvm.internal.DefaultConstructorMarker) ## @CordaSerializable +public final class net.corda.core.flows.TransactionMetadata extends java.lang.Object + public (net.corda.core.identity.CordaX500Name, net.corda.core.flows.DistributionList) + @NotNull + public final net.corda.core.identity.CordaX500Name component1() + @NotNull + public final net.corda.core.flows.DistributionList component2() + @NotNull + public final net.corda.core.flows.TransactionMetadata copy(net.corda.core.identity.CordaX500Name, net.corda.core.flows.DistributionList) + public boolean equals(Object) + @NotNull + public final net.corda.core.flows.DistributionList getDistributionList() + @NotNull + public final net.corda.core.identity.CordaX500Name getInitiator() + public int hashCode() + @NotNull + public String toString() +## +@CordaSerializable public final class net.corda.core.flows.UnexpectedFlowEndException extends net.corda.core.CordaRuntimeException implements net.corda.core.flows.IdentifiableException public (String) public (String, Throwable) @@ -3308,8 +3921,8 @@ public final class net.corda.core.flows.WaitTimeUpdate extends java.lang.Object public String toString() ## public final class net.corda.core.flows.WithReferencedStatesFlow extends net.corda.core.flows.FlowLogic - public (kotlin.jvm.functions.Function0>) - public (net.corda.core.utilities.ProgressTracker, kotlin.jvm.functions.Function0>) + public (kotlin.jvm.functions.Function0) + public (net.corda.core.utilities.ProgressTracker, kotlin.jvm.functions.Function0) public (net.corda.core.utilities.ProgressTracker, kotlin.jvm.functions.Function0, int, kotlin.jvm.internal.DefaultConstructorMarker) @Suspendable @NotNull @@ -3318,6 +3931,7 @@ public final class net.corda.core.flows.WithReferencedStatesFlow extends net.cor public net.corda.core.utilities.ProgressTracker getProgressTracker() @NotNull public static final net.corda.core.utilities.ProgressTracker tracker() + @NotNull public static final net.corda.core.flows.WithReferencedStatesFlow$Companion Companion ## public static final class net.corda.core.flows.WithReferencedStatesFlow$Companion extends java.lang.Object @@ -3327,31 +3941,34 @@ public static final class net.corda.core.flows.WithReferencedStatesFlow$Companio ## @CordaSerializable public static final class net.corda.core.flows.WithReferencedStatesFlow$Companion$ATTEMPT extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.WithReferencedStatesFlow$Companion$ATTEMPT INSTANCE ## @CordaSerializable public static final class net.corda.core.flows.WithReferencedStatesFlow$Companion$RETRYING extends net.corda.core.utilities.ProgressTracker$Step + @NotNull public static final net.corda.core.flows.WithReferencedStatesFlow$Companion$RETRYING INSTANCE ## @CordaSerializable public static final class net.corda.core.flows.WithReferencedStatesFlow$Companion$SUCCESS extends net.corda.core.utilities.ProgressTracker$Step + @NotNull 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 (net.corda.core.flows.FlowExternalAsyncOperation) + public (net.corda.core.flows.FlowExternalAsyncOperation) @NotNull - public net.corda.core.concurrent.CordaFuture execute(String) + public net.corda.core.concurrent.CordaFuture execute(String) @NotNull - public final net.corda.core.flows.FlowExternalAsyncOperation getOperation() + public final net.corda.core.flows.FlowExternalAsyncOperation getOperation() ## @CordaSerializable public final class net.corda.core.flows.WrappedFlowExternalOperation extends java.lang.Object implements net.corda.core.internal.FlowAsyncOperation - public (net.corda.core.internal.ServiceHubCoreInternal, net.corda.core.flows.FlowExternalOperation) + public (net.corda.core.internal.ServiceHubCoreInternal, net.corda.core.flows.FlowExternalOperation) @NotNull - public net.corda.core.concurrent.CordaFuture execute(String) + public net.corda.core.concurrent.CordaFuture execute(String) @NotNull - public final net.corda.core.flows.FlowExternalOperation getOperation() + public final net.corda.core.flows.FlowExternalOperation getOperation() @NotNull public final net.corda.core.internal.ServiceHubCoreInternal getServiceHub() ## @@ -3369,6 +3986,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) @NotNull public final net.corda.core.contracts.PartyAndReference ref(byte...) + @NotNull public static final net.corda.core.identity.AbstractParty$Companion Companion ## @DoNotImplement @@ -3381,6 +3999,7 @@ public final class net.corda.core.identity.AnonymousParty extends net.corda.core public net.corda.core.contracts.PartyAndReference ref(net.corda.core.utilities.OpaqueBytes) @NotNull public String toString() + @NotNull public static final net.corda.core.identity.AnonymousParty$Companion Companion ## public static final class net.corda.core.identity.AnonymousParty$Companion extends java.lang.Object @@ -3429,6 +4048,7 @@ public final class net.corda.core.identity.CordaX500Name extends java.lang.Objec public static final net.corda.core.identity.CordaX500Name parse(String) @NotNull public String toString() + @NotNull public static final net.corda.core.identity.CordaX500Name$Companion Companion public static final int LENGTH_COUNTRY = 2 public static final int MAX_LENGTH_COMMON_NAME = 64 @@ -3442,23 +4062,23 @@ public static final class net.corda.core.identity.CordaX500Name$Companion extend @NotNull public final net.corda.core.identity.CordaX500Name build(javax.security.auth.x500.X500Principal) @NotNull - public net.corda.core.internal.utilities.PrivateInterner getInterner() + public net.corda.core.internal.utilities.PrivateInterner getInterner() @NotNull public final net.corda.core.identity.CordaX500Name parse(String) ## public final class net.corda.core.identity.IdentityUtils extends java.lang.Object @NotNull - public static final java.util.Map excludeHostNode(net.corda.core.node.ServiceHub, java.util.Map) + public static final java.util.Map excludeHostNode(net.corda.core.node.ServiceHub, java.util.Map) @NotNull - public static final java.util.Map excludeNotary(java.util.Map, net.corda.core.transactions.SignedTransaction) + public static final java.util.Map excludeNotary(java.util.Map, net.corda.core.transactions.SignedTransaction) @NotNull - public static final java.util.Map> groupAbstractPartyByWellKnownParty(net.corda.core.node.ServiceHub, java.util.Collection) + public static final java.util.Map groupAbstractPartyByWellKnownParty(net.corda.core.node.ServiceHub, java.util.Collection) @NotNull - public static final java.util.Map> groupAbstractPartyByWellKnownParty(net.corda.core.node.ServiceHub, java.util.Collection, boolean) + public static final java.util.Map groupAbstractPartyByWellKnownParty(net.corda.core.node.ServiceHub, java.util.Collection, boolean) @NotNull - public static final java.util.Map> groupPublicKeysByWellKnownParty(net.corda.core.node.ServiceHub, java.util.Collection) + public static final java.util.Map groupPublicKeysByWellKnownParty(net.corda.core.node.ServiceHub, java.util.Collection) @NotNull - public static final java.util.Map> groupPublicKeysByWellKnownParty(net.corda.core.node.ServiceHub, java.util.Collection, boolean) + public static final java.util.Map groupPublicKeysByWellKnownParty(net.corda.core.node.ServiceHub, java.util.Collection, boolean) public static final boolean x500Matches(String, boolean, net.corda.core.identity.CordaX500Name) ## @DoNotImplement @@ -3478,6 +4098,7 @@ 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) @NotNull public String toString() + @NotNull public static final net.corda.core.identity.Party$Companion Companion ## public static final class net.corda.core.identity.Party$Companion extends java.lang.Object @@ -3511,7 +4132,7 @@ public final class net.corda.core.identity.PartyAndCertificate extends java.lang @NotNull public final java.security.cert.PKIXCertPathValidatorResult verify(java.security.cert.TrustAnchor) @NotNull - public final java.security.cert.PKIXCertPathValidatorResult verify(java.util.Set) + public final java.security.cert.PKIXCertPathValidatorResult verify(java.util.Set) ## @CordaSerializable public interface net.corda.core.messaging.AllPossibleRecipients extends net.corda.core.messaging.MessageRecipients @@ -3547,29 +4168,29 @@ public interface net.corda.core.messaging.CordaRPCOps extends net.corda.core.mes @NotNull public abstract java.time.Instant currentNodeTime() @NotNull - public abstract java.util.Map finishedFlowsWithClientIds() + public abstract java.util.Map finishedFlowsWithClientIds() @NotNull - public abstract java.util.Map finishedFlowsWithClientIdsAsAdmin() + public abstract java.util.Map finishedFlowsWithClientIdsAsAdmin() @NotNull public abstract net.corda.core.node.NetworkParameters getNetworkParameters() @NotNull - public abstract Iterable getVaultTransactionNotes(net.corda.core.crypto.SecureHash) + public abstract Iterable getVaultTransactionNotes(net.corda.core.crypto.SecureHash) @RPCReturnsObservables @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.transactions.SignedTransaction> internalVerifiedTransactionsFeed() + public abstract net.corda.core.messaging.DataFeed internalVerifiedTransactionsFeed() @NotNull - public abstract java.util.List internalVerifiedTransactionsSnapshot() + public abstract java.util.List internalVerifiedTransactionsSnapshot() public abstract boolean isFlowsDrainingModeEnabled() public abstract boolean isWaitingForShutdown() public abstract boolean killFlow(net.corda.core.flows.StateMachineRunId) @RPCReturnsObservables @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.NetworkMapCache$MapChange> networkMapFeed() + public abstract net.corda.core.messaging.DataFeed networkMapFeed() @NotNull - public abstract java.util.List networkMapSnapshot() + public abstract java.util.List networkMapSnapshot() @RPCReturnsObservables @NotNull - public abstract net.corda.core.messaging.DataFeed networkParametersFeed() + public abstract net.corda.core.messaging.DataFeed networkParametersFeed() @NotNull public abstract net.corda.core.node.NodeDiagnosticInfo nodeDiagnosticInfo() @NotNull @@ -3577,76 +4198,76 @@ public interface net.corda.core.messaging.CordaRPCOps extends net.corda.core.mes @Nullable public abstract net.corda.core.node.NodeInfo nodeInfoFromParty(net.corda.core.identity.AbstractParty) @NotNull - public abstract java.util.List notaryIdentities() + public abstract java.util.List notaryIdentities() @Nullable public abstract net.corda.core.identity.Party notaryPartyFromX500Name(net.corda.core.identity.CordaX500Name) @NotNull public abstract java.io.InputStream openAttachment(net.corda.core.crypto.SecureHash) @NotNull - public abstract java.util.Set partiesFromName(String, boolean) + public abstract java.util.Set partiesFromName(String, boolean) @Nullable public abstract net.corda.core.identity.Party partyFromKey(java.security.PublicKey) @NotNull - public abstract java.util.List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria, net.corda.core.node.services.vault.AttachmentSort) + public abstract java.util.List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria, net.corda.core.node.services.vault.AttachmentSort) @RPCReturnsObservables @Nullable - public abstract net.corda.core.messaging.FlowHandleWithClientId reattachFlowWithClientId(String) + public abstract net.corda.core.messaging.FlowHandleWithClientId reattachFlowWithClientId(String) public abstract void refreshNetworkMapCache() @NotNull - public abstract java.util.List registeredFlows() + public abstract java.util.List registeredFlows() public abstract boolean removeClientId(String) public abstract boolean removeClientIdAsAdmin(String) public abstract void setFlowsDrainingModeEnabled(boolean) public abstract void shutdown() @RPCReturnsObservables @NotNull - public abstract net.corda.core.messaging.FlowHandle startFlowDynamic(Class>, Object...) + public abstract net.corda.core.messaging.FlowHandle startFlowDynamic(Class, Object...) @RPCReturnsObservables @NotNull - public abstract net.corda.core.messaging.FlowHandleWithClientId startFlowDynamicWithClientId(String, Class>, Object...) + public abstract net.corda.core.messaging.FlowHandleWithClientId startFlowDynamicWithClientId(String, Class, Object...) @RPCReturnsObservables @NotNull - public abstract net.corda.core.messaging.FlowProgressHandle startTrackedFlowDynamic(Class>, Object...) + public abstract net.corda.core.messaging.FlowProgressHandle startTrackedFlowDynamic(Class, Object...) @RPCReturnsObservables @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.messaging.StateMachineTransactionMapping> stateMachineRecordedTransactionMappingFeed() + public abstract net.corda.core.messaging.DataFeed stateMachineRecordedTransactionMappingFeed() @NotNull - public abstract java.util.List stateMachineRecordedTransactionMappingSnapshot() + public abstract java.util.List stateMachineRecordedTransactionMappingSnapshot() @RPCReturnsObservables @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.messaging.StateMachineUpdate> stateMachinesFeed() + public abstract net.corda.core.messaging.DataFeed stateMachinesFeed() @NotNull - public abstract java.util.List stateMachinesSnapshot() + public abstract java.util.List stateMachinesSnapshot() public abstract void terminate(boolean) @NotNull public abstract net.corda.core.crypto.SecureHash uploadAttachment(java.io.InputStream) @NotNull public abstract net.corda.core.crypto.SecureHash uploadAttachmentWithMetadata(java.io.InputStream, String, String) @NotNull - public abstract net.corda.core.node.services.Vault$Page vaultQuery(Class) + public abstract net.corda.core.node.services.Vault$Page vaultQuery(Class) @RPCReturnsObservables @NotNull - public abstract net.corda.core.node.services.Vault$Page vaultQueryBy(net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort, Class) + public abstract net.corda.core.node.services.Vault$Page vaultQueryBy(net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort, Class) @NotNull - public abstract net.corda.core.node.services.Vault$Page vaultQueryByCriteria(net.corda.core.node.services.vault.QueryCriteria, Class) + public abstract net.corda.core.node.services.Vault$Page vaultQueryByCriteria(net.corda.core.node.services.vault.QueryCriteria, Class) @NotNull - public abstract net.corda.core.node.services.Vault$Page vaultQueryByWithPagingSpec(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification) + public abstract net.corda.core.node.services.Vault$Page vaultQueryByWithPagingSpec(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification) @NotNull - public abstract net.corda.core.node.services.Vault$Page vaultQueryByWithSorting(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.Sort) + public abstract net.corda.core.node.services.Vault$Page vaultQueryByWithSorting(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.Sort) @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.Vault$Update> vaultTrack(Class) + public abstract net.corda.core.messaging.DataFeed vaultTrack(Class) @RPCReturnsObservables @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.Vault$Update> vaultTrackBy(net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort, Class) + public abstract net.corda.core.messaging.DataFeed vaultTrackBy(net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort, Class) @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.Vault$Update> vaultTrackByCriteria(Class, net.corda.core.node.services.vault.QueryCriteria) + public abstract net.corda.core.messaging.DataFeed vaultTrackByCriteria(Class, net.corda.core.node.services.vault.QueryCriteria) @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.Vault$Update> vaultTrackByWithPagingSpec(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification) + public abstract net.corda.core.messaging.DataFeed vaultTrackByWithPagingSpec(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification) @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.Vault$Update> vaultTrackByWithSorting(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.Sort) + public abstract net.corda.core.messaging.DataFeed vaultTrackByWithSorting(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.Sort) @RPCReturnsObservables @NotNull - public abstract net.corda.core.concurrent.CordaFuture waitUntilNetworkReady() + public abstract net.corda.core.concurrent.CordaFuture waitUntilNetworkReady() @Nullable public abstract net.corda.core.identity.Party wellKnownPartyFromAnonymous(net.corda.core.identity.AbstractParty) @Nullable @@ -3654,20 +4275,43 @@ public interface net.corda.core.messaging.CordaRPCOps extends net.corda.core.mes ## public final class net.corda.core.messaging.CordaRPCOpsKt extends java.lang.Object @NotNull - public static final net.corda.core.messaging.DataFeed> pendingFlowsCount(net.corda.core.messaging.CordaRPCOps) + public static final net.corda.core.messaging.DataFeed pendingFlowsCount(net.corda.core.messaging.CordaRPCOps) + public static final net.corda.core.messaging.FlowHandle startFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function0) + public static final net.corda.core.messaging.FlowHandle startFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function1, A) + public static final net.corda.core.messaging.FlowHandle startFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function2, A, B) + public static final net.corda.core.messaging.FlowHandle startFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function3, A, B, C) + public static final net.corda.core.messaging.FlowHandle startFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function4, A, B, C, D) + public static final net.corda.core.messaging.FlowHandle startFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function5, A, B, C, D, E) + public static final net.corda.core.messaging.FlowHandle startFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function6, A, B, C, D, E, F) + public static final net.corda.core.messaging.FlowHandleWithClientId startFlowWithClientId(net.corda.core.messaging.CordaRPCOps, String, kotlin.jvm.functions.Function0) + public static final net.corda.core.messaging.FlowHandleWithClientId startFlowWithClientId(net.corda.core.messaging.CordaRPCOps, String, kotlin.jvm.functions.Function1, A) + public static final net.corda.core.messaging.FlowHandleWithClientId startFlowWithClientId(net.corda.core.messaging.CordaRPCOps, String, kotlin.jvm.functions.Function2, A, B) + public static final net.corda.core.messaging.FlowHandleWithClientId startFlowWithClientId(net.corda.core.messaging.CordaRPCOps, String, kotlin.jvm.functions.Function3, A, B, C) + public static final net.corda.core.messaging.FlowHandleWithClientId startFlowWithClientId(net.corda.core.messaging.CordaRPCOps, String, kotlin.jvm.functions.Function4, A, B, C, D) + public static final net.corda.core.messaging.FlowHandleWithClientId startFlowWithClientId(net.corda.core.messaging.CordaRPCOps, String, kotlin.jvm.functions.Function5, A, B, C, D, E) + public static final net.corda.core.messaging.FlowHandleWithClientId startFlowWithClientId(net.corda.core.messaging.CordaRPCOps, String, kotlin.jvm.functions.Function6, A, B, C, D, E, F) + public static final net.corda.core.messaging.FlowProgressHandle startTrackedFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function0) + public static final net.corda.core.messaging.FlowProgressHandle startTrackedFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function1, A) + public static final net.corda.core.messaging.FlowProgressHandle startTrackedFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function2, A, B) + public static final net.corda.core.messaging.FlowProgressHandle startTrackedFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function3, A, B, C) + public static final net.corda.core.messaging.FlowProgressHandle startTrackedFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function4, A, B, C, D) + public static final net.corda.core.messaging.FlowProgressHandle startTrackedFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function5, A, B, C, D, E) + public static final net.corda.core.messaging.FlowProgressHandle startTrackedFlow(net.corda.core.messaging.CordaRPCOps, kotlin.jvm.functions.Function6, A, B, C, D, E, F) + public static final net.corda.core.node.services.Vault$Page vaultQueryBy(net.corda.core.messaging.CordaRPCOps, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort) + public static final net.corda.core.messaging.DataFeed vaultTrackBy(net.corda.core.messaging.CordaRPCOps, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort) ## @CordaSerializable public final class net.corda.core.messaging.DataFeed extends java.lang.Object - public (A, rx.Observable) + public (A, rx.Observable) public final A component1() @NotNull - public final rx.Observable component2() + public final rx.Observable component2() @NotNull - public final net.corda.core.messaging.DataFeed copy(A, rx.Observable) + public final net.corda.core.messaging.DataFeed copy(A, rx.Observable) public boolean equals(Object) public final A getSnapshot() @NotNull - public final rx.Observable getUpdates() + public final rx.Observable getUpdates() public int hashCode() @NotNull public String toString() @@ -3679,24 +4323,24 @@ public interface net.corda.core.messaging.FlowHandle extends java.lang.AutoClose @NotNull public abstract net.corda.core.flows.StateMachineRunId getId() @NotNull - public abstract net.corda.core.concurrent.CordaFuture getReturnValue() + public abstract net.corda.core.concurrent.CordaFuture getReturnValue() ## @DoNotImplement @CordaSerializable public final class net.corda.core.messaging.FlowHandleImpl extends java.lang.Object implements net.corda.core.messaging.FlowHandle - public (net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture) + public (net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture) public void close() @NotNull public final net.corda.core.flows.StateMachineRunId component1() @NotNull - public final net.corda.core.concurrent.CordaFuture component2() + public final net.corda.core.concurrent.CordaFuture component2() @NotNull - public final net.corda.core.messaging.FlowHandleImpl copy(net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture) + public final net.corda.core.messaging.FlowHandleImpl copy(net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture) public boolean equals(Object) @NotNull public net.corda.core.flows.StateMachineRunId getId() @NotNull - public net.corda.core.concurrent.CordaFuture getReturnValue() + public net.corda.core.concurrent.CordaFuture getReturnValue() public int hashCode() @NotNull public String toString() @@ -3710,23 +4354,23 @@ public interface net.corda.core.messaging.FlowHandleWithClientId extends net.cor @DoNotImplement @CordaSerializable public final class net.corda.core.messaging.FlowHandleWithClientIdImpl extends java.lang.Object implements net.corda.core.messaging.FlowHandleWithClientId - public (net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, String) + public (net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, String) public void close() @NotNull public final net.corda.core.flows.StateMachineRunId component1() @NotNull - public final net.corda.core.concurrent.CordaFuture component2() + public final net.corda.core.concurrent.CordaFuture component2() @NotNull public final String component3() @NotNull - public final net.corda.core.messaging.FlowHandleWithClientIdImpl copy(net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, String) + public final net.corda.core.messaging.FlowHandleWithClientIdImpl copy(net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, String) public boolean equals(Object) @NotNull public String getClientId() @NotNull public net.corda.core.flows.StateMachineRunId getId() @NotNull - public net.corda.core.concurrent.CordaFuture getReturnValue() + public net.corda.core.concurrent.CordaFuture getReturnValue() public int hashCode() @NotNull public String toString() @@ -3736,45 +4380,45 @@ public final class net.corda.core.messaging.FlowHandleWithClientIdImpl extends j public interface net.corda.core.messaging.FlowProgressHandle extends net.corda.core.messaging.FlowHandle public abstract void close() @NotNull - public abstract rx.Observable getProgress() + public abstract rx.Observable getProgress() @Nullable - public abstract net.corda.core.messaging.DataFeed>, java.util.List>> getStepsTreeFeed() + public abstract net.corda.core.messaging.DataFeed getStepsTreeFeed() @Nullable - public abstract net.corda.core.messaging.DataFeed getStepsTreeIndexFeed() + public abstract net.corda.core.messaging.DataFeed getStepsTreeIndexFeed() ## @DoNotImplement @CordaSerializable public final class net.corda.core.messaging.FlowProgressHandleImpl extends java.lang.Object implements net.corda.core.messaging.FlowProgressHandle - public (net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, rx.Observable) - public (net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, rx.Observable, net.corda.core.messaging.DataFeed) - public (net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, rx.Observable, net.corda.core.messaging.DataFeed, net.corda.core.messaging.DataFeed>, java.util.List>>) + public (net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, rx.Observable) + public (net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, rx.Observable, net.corda.core.messaging.DataFeed) + public (net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, rx.Observable, net.corda.core.messaging.DataFeed, net.corda.core.messaging.DataFeed) public (net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, rx.Observable, net.corda.core.messaging.DataFeed, net.corda.core.messaging.DataFeed, int, kotlin.jvm.internal.DefaultConstructorMarker) public void close() @NotNull public final net.corda.core.flows.StateMachineRunId component1() @NotNull - public final net.corda.core.concurrent.CordaFuture component2() + public final net.corda.core.concurrent.CordaFuture component2() @NotNull - public final rx.Observable component3() + public final rx.Observable component3() @Nullable - public final net.corda.core.messaging.DataFeed component4() + public final net.corda.core.messaging.DataFeed component4() @Nullable - public final net.corda.core.messaging.DataFeed>, java.util.List>> component5() + public final net.corda.core.messaging.DataFeed component5() @NotNull - public final net.corda.core.messaging.FlowProgressHandleImpl copy(net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, rx.Observable) + public final net.corda.core.messaging.FlowProgressHandleImpl copy(net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, rx.Observable) @NotNull - public final net.corda.core.messaging.FlowProgressHandleImpl copy(net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, rx.Observable, net.corda.core.messaging.DataFeed, net.corda.core.messaging.DataFeed>, java.util.List>>) + public final net.corda.core.messaging.FlowProgressHandleImpl copy(net.corda.core.flows.StateMachineRunId, net.corda.core.concurrent.CordaFuture, rx.Observable, net.corda.core.messaging.DataFeed, net.corda.core.messaging.DataFeed) public boolean equals(Object) @NotNull public net.corda.core.flows.StateMachineRunId getId() @NotNull - public rx.Observable getProgress() + public rx.Observable getProgress() @NotNull - public net.corda.core.concurrent.CordaFuture getReturnValue() + public net.corda.core.concurrent.CordaFuture getReturnValue() @Nullable - public net.corda.core.messaging.DataFeed>, java.util.List>> getStepsTreeFeed() + public net.corda.core.messaging.DataFeed getStepsTreeFeed() @Nullable - public net.corda.core.messaging.DataFeed getStepsTreeIndexFeed() + public net.corda.core.messaging.DataFeed getStepsTreeIndexFeed() public int hashCode() @NotNull public String toString() @@ -3822,8 +4466,8 @@ public interface net.corda.core.messaging.SingleMessageRecipient extends net.cor ## @CordaSerializable public final class net.corda.core.messaging.StateMachineInfo extends java.lang.Object - public (net.corda.core.flows.StateMachineRunId, String, net.corda.core.flows.FlowInitiator, net.corda.core.messaging.DataFeed) - public (net.corda.core.flows.StateMachineRunId, String, net.corda.core.flows.FlowInitiator, net.corda.core.messaging.DataFeed, net.corda.core.context.InvocationContext) + public (net.corda.core.flows.StateMachineRunId, String, net.corda.core.flows.FlowInitiator, net.corda.core.messaging.DataFeed) + public (net.corda.core.flows.StateMachineRunId, String, net.corda.core.flows.FlowInitiator, net.corda.core.messaging.DataFeed, net.corda.core.context.InvocationContext) public (net.corda.core.flows.StateMachineRunId, String, net.corda.core.flows.FlowInitiator, net.corda.core.messaging.DataFeed, net.corda.core.context.InvocationContext, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull public final net.corda.core.flows.StateMachineRunId component1() @@ -3832,13 +4476,13 @@ public final class net.corda.core.messaging.StateMachineInfo extends java.lang.O @NotNull public final net.corda.core.flows.FlowInitiator component3() @Nullable - public final net.corda.core.messaging.DataFeed component4() + public final net.corda.core.messaging.DataFeed component4() @NotNull public final net.corda.core.context.InvocationContext component5() @NotNull - public final net.corda.core.messaging.StateMachineInfo copy(net.corda.core.flows.StateMachineRunId, String, net.corda.core.flows.FlowInitiator, net.corda.core.messaging.DataFeed) + public final net.corda.core.messaging.StateMachineInfo copy(net.corda.core.flows.StateMachineRunId, String, net.corda.core.flows.FlowInitiator, net.corda.core.messaging.DataFeed) @NotNull - public final net.corda.core.messaging.StateMachineInfo copy(net.corda.core.flows.StateMachineRunId, String, net.corda.core.flows.FlowInitiator, net.corda.core.messaging.DataFeed, net.corda.core.context.InvocationContext) + public final net.corda.core.messaging.StateMachineInfo copy(net.corda.core.flows.StateMachineRunId, String, net.corda.core.flows.FlowInitiator, net.corda.core.messaging.DataFeed, net.corda.core.context.InvocationContext) public boolean equals(Object) @NotNull public final String getFlowLogicClassName() @@ -3849,7 +4493,7 @@ public final class net.corda.core.messaging.StateMachineInfo extends java.lang.O @NotNull public final net.corda.core.context.InvocationContext getInvocationContext() @Nullable - public final net.corda.core.messaging.DataFeed getProgressTrackerStepAndUpdates() + public final net.corda.core.messaging.DataFeed getProgressTrackerStepAndUpdates() public int hashCode() @NotNull public String toString() @@ -3896,18 +4540,18 @@ public static final class net.corda.core.messaging.StateMachineUpdate$Added exte ## @CordaSerializable public static final class net.corda.core.messaging.StateMachineUpdate$Removed extends net.corda.core.messaging.StateMachineUpdate - public (net.corda.core.flows.StateMachineRunId, net.corda.core.utilities.Try) + public (net.corda.core.flows.StateMachineRunId, net.corda.core.utilities.Try) @NotNull public final net.corda.core.flows.StateMachineRunId component1() @NotNull - public final net.corda.core.utilities.Try component2() + public final net.corda.core.utilities.Try component2() @NotNull - public final net.corda.core.messaging.StateMachineUpdate$Removed copy(net.corda.core.flows.StateMachineRunId, net.corda.core.utilities.Try) + public final net.corda.core.messaging.StateMachineUpdate$Removed copy(net.corda.core.flows.StateMachineRunId, net.corda.core.utilities.Try) public boolean equals(Object) @NotNull public net.corda.core.flows.StateMachineRunId getId() @NotNull - public final net.corda.core.utilities.Try getResult() + public final net.corda.core.utilities.Try getResult() public int hashCode() @NotNull public String toString() @@ -3921,12 +4565,13 @@ public interface net.corda.core.messaging.flows.FlowManagerRPCOps extends net.co public interface net.corda.core.node.AppServiceHub extends net.corda.core.node.ServiceHub @NotNull public abstract net.corda.core.node.services.vault.CordaTransactionSupport getDatabase() - public abstract void register(int, kotlin.jvm.functions.Function1) + public void register(int, kotlin.jvm.functions.Function1) public abstract void register(int, net.corda.core.node.services.ServiceLifecycleObserver) @NotNull - public abstract net.corda.core.messaging.FlowHandle startFlow(net.corda.core.flows.FlowLogic) + public abstract net.corda.core.messaging.FlowHandle startFlow(net.corda.core.flows.FlowLogic) + @NotNull + public abstract net.corda.core.messaging.FlowProgressHandle startTrackedFlow(net.corda.core.flows.FlowLogic) @NotNull - public abstract net.corda.core.messaging.FlowProgressHandle startTrackedFlow(net.corda.core.flows.FlowLogic) public static final net.corda.core.node.AppServiceHub$Companion Companion public static final int SERVICE_PRIORITY_HIGH = 200 public static final int SERVICE_PRIORITY_LOW = 20 @@ -3942,31 +4587,42 @@ public @interface net.corda.core.node.AutoAcceptable @CordaSerializable public final class net.corda.core.node.NetworkParameters extends java.lang.Object @DeprecatedConstructorForDeserialization - public (int, java.util.List, int, int, java.time.Instant, int, java.util.Map>) + public (int, java.util.List, int, int, java.time.Instant, int, java.util.Map) @DeprecatedConstructorForDeserialization - public (int, java.util.List, int, int, java.time.Instant, int, java.util.Map>, java.time.Duration) - public (int, java.util.List, int, int, java.time.Instant, int, java.util.Map>, java.time.Duration, java.util.Map) + public (int, java.util.List, int, int, java.time.Instant, int, java.util.Map, java.time.Duration) + @DeprecatedConstructorForDeserialization + public (int, java.util.List, int, int, java.time.Instant, int, java.util.Map, java.time.Duration, java.util.Map) + public (int, java.util.List, int, int, java.time.Instant, int, java.util.Map, java.time.Duration, java.util.Map, java.time.Duration, java.time.Duration) + public (int, java.util.List, int, int, java.time.Instant, int, java.util.Map, java.time.Duration, java.util.Map, java.time.Duration, java.time.Duration, int, kotlin.jvm.internal.DefaultConstructorMarker) public final int component1() + @Nullable + public final java.time.Duration component10() + @Nullable + public final java.time.Duration component11() @NotNull - public final java.util.List component2() + public final java.util.List component2() public final int component3() public final int component4() @NotNull public final java.time.Instant component5() public final int component6() @NotNull - public final java.util.Map> component7() + public final java.util.Map component7() @NotNull public final java.time.Duration component8() @NotNull - public final java.util.Map component9() + public final java.util.Map component9() @NotNull - public final net.corda.core.node.NetworkParameters copy(int, java.util.List, int, int, java.time.Instant, int, java.util.Map>) + public final net.corda.core.node.NetworkParameters copy(int, java.util.List, int, int, java.time.Instant, int, java.util.Map) @NotNull - public final net.corda.core.node.NetworkParameters copy(int, java.util.List, int, int, java.time.Instant, int, java.util.Map>, java.time.Duration) + public final net.corda.core.node.NetworkParameters copy(int, java.util.List, int, int, java.time.Instant, int, java.util.Map, java.time.Duration) @NotNull - public final net.corda.core.node.NetworkParameters copy(int, java.util.List, int, int, java.time.Instant, int, java.util.Map>, java.time.Duration, java.util.Map) + public final net.corda.core.node.NetworkParameters copy(int, java.util.List, int, int, java.time.Instant, int, java.util.Map, java.time.Duration, java.util.Map) + @NotNull + public final net.corda.core.node.NetworkParameters copy(int, java.util.List, int, int, java.time.Instant, int, java.util.Map, java.time.Duration, java.util.Map, java.time.Duration, java.time.Duration) public boolean equals(Object) + @Nullable + public final java.time.Duration getConfidentialIdentityMinimumBackupInterval() public final int getEpoch() @NotNull public final java.time.Duration getEventHorizon() @@ -3976,11 +4632,13 @@ public final class net.corda.core.node.NetworkParameters extends java.lang.Objec @NotNull public final java.time.Instant getModifiedTime() @NotNull - public final java.util.List getNotaries() + public final java.util.List getNotaries() @NotNull - public final java.util.Map getPackageOwnership() + public final java.util.Map getPackageOwnership() + @Nullable + public final java.time.Duration getRecoveryMaximumBackupInterval() @NotNull - public final java.util.Map> getWhitelistedContractImplementations() + public final java.util.Map getWhitelistedContractImplementations() public int hashCode() @NotNull public final net.corda.core.node.NetworkParameters toImmutable() @@ -3991,7 +4649,7 @@ public final class net.corda.core.node.NetworkParametersKt extends java.lang.Obj ## @CordaSerializable public final class net.corda.core.node.NodeDiagnosticInfo extends java.lang.Object - public (String, String, int, String, java.util.List) + public (String, String, int, String, java.util.List) @NotNull public final String component1() @NotNull @@ -4000,12 +4658,12 @@ public final class net.corda.core.node.NodeDiagnosticInfo extends java.lang.Obje @NotNull public final String component4() @NotNull - public final java.util.List component5() + public final java.util.List component5() @NotNull - public final net.corda.core.node.NodeDiagnosticInfo copy(String, String, int, String, java.util.List) + public final net.corda.core.node.NodeDiagnosticInfo copy(String, String, int, String, java.util.List) public boolean equals(Object) @NotNull - public final java.util.List getCordapps() + public final java.util.List getCordapps() public final int getPlatformVersion() @NotNull public final String getRevision() @@ -4019,22 +4677,22 @@ public final class net.corda.core.node.NodeDiagnosticInfo extends java.lang.Obje ## @CordaSerializable public final class net.corda.core.node.NodeInfo extends java.lang.Object - public (java.util.List, java.util.List, int, long) + public (java.util.List, java.util.List, int, long) @NotNull - public final java.util.List component1() + public final java.util.List component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() public final int component3() public final long component4() @NotNull - public final net.corda.core.node.NodeInfo copy(java.util.List, java.util.List, int, long) + public final net.corda.core.node.NodeInfo copy(java.util.List, java.util.List, int, long) public boolean equals(Object) @NotNull - public final java.util.List getAddresses() + public final java.util.List getAddresses() @NotNull - public final java.util.List getLegalIdentities() + public final java.util.List getLegalIdentities() @NotNull - public final java.util.List getLegalIdentitiesAndCerts() + public final java.util.List getLegalIdentitiesAndCerts() public final int getPlatformVersion() public final long getSerial() public int hashCode() @@ -4066,23 +4724,23 @@ public final class net.corda.core.node.NotaryInfo extends java.lang.Object @DoNotImplement public interface net.corda.core.node.ServiceHub extends net.corda.core.node.ServicesForResolution @NotNull - public abstract net.corda.core.transactions.SignedTransaction addSignature(net.corda.core.transactions.SignedTransaction) + public net.corda.core.transactions.SignedTransaction addSignature(net.corda.core.transactions.SignedTransaction) @NotNull - public abstract net.corda.core.transactions.SignedTransaction addSignature(net.corda.core.transactions.SignedTransaction, java.security.PublicKey) + public net.corda.core.transactions.SignedTransaction addSignature(net.corda.core.transactions.SignedTransaction, java.security.PublicKey) @NotNull - public abstract T cordaService(Class) + public abstract T cordaService(Class) @NotNull - public abstract T cordaTelemetryComponent(Class) + public abstract T cordaTelemetryComponent(Class) @NotNull - public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction) + public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction) @NotNull - public abstract 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) @NotNull - public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction) + public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction) @NotNull - public abstract net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction, java.security.PublicKey) + public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction, java.security.PublicKey) @NotNull - public abstract net.corda.core.cordapp.CordappContext getAppContext() + public net.corda.core.cordapp.CordappContext getAppContext() @NotNull public abstract java.time.Clock getClock() @NotNull @@ -4098,29 +4756,27 @@ public interface net.corda.core.node.ServiceHub extends net.corda.core.node.Serv @NotNull public abstract net.corda.core.node.services.TelemetryService getTelemetryService() @NotNull - public abstract net.corda.core.node.services.TransactionVerifierService getTransactionVerifierService() - @NotNull public abstract net.corda.core.node.services.TransactionStorage getValidatedTransactions() @NotNull public abstract net.corda.core.node.services.VaultService getVaultService() @NotNull public abstract java.sql.Connection jdbcSession() - public abstract void recordTransactions(Iterable) - public abstract void recordTransactions(net.corda.core.node.StatesToRecord, Iterable) - public abstract void recordTransactions(net.corda.core.transactions.SignedTransaction, net.corda.core.transactions.SignedTransaction...) - public abstract void recordTransactions(boolean, Iterable) - public abstract void recordTransactions(boolean, net.corda.core.transactions.SignedTransaction, net.corda.core.transactions.SignedTransaction...) - public abstract void registerUnloadHandler(kotlin.jvm.functions.Function0) + public void recordTransactions(Iterable) + public abstract void recordTransactions(net.corda.core.node.StatesToRecord, Iterable) + public void recordTransactions(net.corda.core.transactions.SignedTransaction, net.corda.core.transactions.SignedTransaction...) + public void recordTransactions(boolean, Iterable) + public void recordTransactions(boolean, net.corda.core.transactions.SignedTransaction, net.corda.core.transactions.SignedTransaction...) + public abstract void registerUnloadHandler(kotlin.jvm.functions.Function0) @NotNull - public abstract net.corda.core.transactions.SignedTransaction signInitialTransaction(net.corda.core.transactions.TransactionBuilder) + public net.corda.core.transactions.SignedTransaction signInitialTransaction(net.corda.core.transactions.TransactionBuilder) @NotNull - public abstract net.corda.core.transactions.SignedTransaction signInitialTransaction(net.corda.core.transactions.TransactionBuilder, Iterable) + public net.corda.core.transactions.SignedTransaction signInitialTransaction(net.corda.core.transactions.TransactionBuilder, Iterable) @NotNull - public abstract net.corda.core.transactions.SignedTransaction signInitialTransaction(net.corda.core.transactions.TransactionBuilder, java.security.PublicKey) + public net.corda.core.transactions.SignedTransaction signInitialTransaction(net.corda.core.transactions.TransactionBuilder, java.security.PublicKey) @NotNull - public abstract net.corda.core.contracts.StateAndRef toStateAndRef(net.corda.core.contracts.StateRef) - public abstract void withEntityManager(java.util.function.Consumer) - public abstract T withEntityManager(kotlin.jvm.functions.Function1) + public net.corda.core.contracts.StateAndRef toStateAndRef(net.corda.core.contracts.StateRef) + public abstract void withEntityManager(java.util.function.Consumer) + public abstract T withEntityManager(kotlin.jvm.functions.Function1) ## @DoNotImplement public interface net.corda.core.node.ServicesForResolution @@ -4137,13 +4793,16 @@ public interface net.corda.core.node.ServicesForResolution @NotNull public abstract net.corda.core.contracts.Attachment loadContractAttachment(net.corda.core.contracts.StateRef) @NotNull - public abstract net.corda.core.contracts.TransactionState loadState(net.corda.core.contracts.StateRef) + public abstract net.corda.core.contracts.TransactionState loadState(net.corda.core.contracts.StateRef) @NotNull - public abstract java.util.Set> loadStates(java.util.Set) + public abstract java.util.Set loadStates(java.util.Set) @NotNull public net.corda.core.transactions.LedgerTransaction specialise(net.corda.core.transactions.LedgerTransaction) ## +@CordaSerializable public final class net.corda.core.node.StatesToRecord extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.StatesToRecord valueOf(String) public static net.corda.core.node.StatesToRecord[] values() ## @@ -4154,7 +4813,7 @@ public final class net.corda.core.node.ZoneVersionTooLowException extends net.co @DoNotImplement public interface net.corda.core.node.services.AttachmentStorage @NotNull - public abstract java.util.List getLatestContractAttachments(String, int) + public abstract java.util.List getLatestContractAttachments(String, int) public abstract boolean hasAttachment(net.corda.core.crypto.SecureHash) @NotNull public abstract net.corda.core.crypto.SecureHash importAttachment(java.io.InputStream) @@ -4165,9 +4824,9 @@ public interface net.corda.core.node.services.AttachmentStorage @Nullable public abstract net.corda.core.contracts.Attachment openAttachment(net.corda.core.crypto.SecureHash) @NotNull - public abstract java.util.List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria) + public java.util.List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria) @NotNull - public abstract java.util.List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria, net.corda.core.node.services.vault.AttachmentSort) + public abstract java.util.List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria, net.corda.core.node.services.vault.AttachmentSort) ## public final class net.corda.core.node.services.AttachmentStorageKt extends java.lang.Object ## @@ -4176,7 +4835,7 @@ public interface net.corda.core.node.services.ContractUpgradeService @Nullable public abstract String getAuthorisedContractUpgrade(net.corda.core.contracts.StateRef) public abstract void removeAuthorisedContractUpgrade(net.corda.core.contracts.StateRef) - public abstract void storeAuthorisedContractUpgrade(net.corda.core.contracts.StateRef, Class>) + public abstract void storeAuthorisedContractUpgrade(net.corda.core.contracts.StateRef, Class) ## public @interface net.corda.core.node.services.CordaService ## @@ -4186,14 +4845,14 @@ public final class net.corda.core.node.services.CordaServiceCriticalFailureExcep ## @DoNotImplement public interface net.corda.core.node.services.IdentityService - public abstract void assertOwnership(net.corda.core.identity.Party, net.corda.core.identity.AnonymousParty) + public void assertOwnership(net.corda.core.identity.Party, net.corda.core.identity.AnonymousParty) @Nullable public abstract net.corda.core.identity.PartyAndCertificate certificateFromKey(java.security.PublicKey) @Suspendable @Nullable public abstract java.util.UUID externalIdForPublicKey(java.security.PublicKey) @NotNull - public abstract Iterable getAllIdentities() + public abstract Iterable getAllIdentities() @NotNull public abstract java.security.cert.CertStore getCaCertStore() @NotNull @@ -4201,22 +4860,23 @@ public interface net.corda.core.node.services.IdentityService @NotNull public abstract java.security.cert.X509Certificate getTrustRoot() @NotNull - public abstract java.util.Set partiesFromName(String, boolean) + public abstract java.util.Set partiesFromName(String, boolean) @Nullable public abstract net.corda.core.identity.Party partyFromKey(java.security.PublicKey) @NotNull - public abstract Iterable publicKeysForExternalId(java.util.UUID) + public abstract Iterable publicKeysForExternalId(java.util.UUID) public abstract void registerKey(java.security.PublicKey, net.corda.core.identity.Party, java.util.UUID) @NotNull - public abstract net.corda.core.identity.Party requireWellKnownPartyFromAnonymous(net.corda.core.identity.AbstractParty) + public net.corda.core.identity.Party requireWellKnownPartyFromAnonymous(net.corda.core.identity.AbstractParty) @Nullable public abstract net.corda.core.identity.PartyAndCertificate verifyAndRegisterIdentity(net.corda.core.identity.PartyAndCertificate) @Nullable - public abstract net.corda.core.identity.Party wellKnownPartyFromAnonymous(net.corda.core.contracts.PartyAndReference) + public net.corda.core.identity.Party wellKnownPartyFromAnonymous(net.corda.core.contracts.PartyAndReference) @Nullable - public abstract net.corda.core.identity.Party wellKnownPartyFromAnonymous(net.corda.core.identity.AbstractParty) + public net.corda.core.identity.Party wellKnownPartyFromAnonymous(net.corda.core.identity.AbstractParty) @Nullable public abstract net.corda.core.identity.Party wellKnownPartyFromX500Name(net.corda.core.identity.CordaX500Name) + @NotNull public static final net.corda.core.node.services.IdentityService$Companion Companion ## public static final class net.corda.core.node.services.IdentityService$Companion extends java.lang.Object @@ -4224,7 +4884,7 @@ public static final class net.corda.core.node.services.IdentityService$Companion @DoNotImplement public interface net.corda.core.node.services.KeyManagementService @NotNull - public abstract Iterable filterMyKeys(Iterable) + public abstract Iterable filterMyKeys(Iterable) @Suspendable @NotNull public abstract java.security.PublicKey freshKey() @@ -4238,7 +4898,7 @@ public interface net.corda.core.node.services.KeyManagementService @NotNull public abstract net.corda.core.identity.PartyAndCertificate freshKeyAndCert(net.corda.core.identity.PartyAndCertificate, boolean, java.util.UUID) @NotNull - public abstract java.util.Set getKeys() + public abstract java.util.Set getKeys() @Suspendable @NotNull public abstract net.corda.core.crypto.TransactionSignature sign(net.corda.core.crypto.SignableData, java.security.PublicKey) @@ -4307,33 +4967,33 @@ public static final class net.corda.core.node.services.NetworkMapCache$MapChange public interface net.corda.core.node.services.NetworkMapCacheBase public abstract void clearNetworkMapCache() @NotNull - public abstract java.util.List getAllNodes() + public abstract java.util.List getAllNodes() @NotNull - public abstract rx.Observable getChanged() + public abstract rx.Observable getChanged() @Nullable public abstract net.corda.core.node.NodeInfo getNodeByAddress(net.corda.core.utilities.NetworkHostAndPort) @Nullable public abstract net.corda.core.node.NodeInfo getNodeByLegalName(net.corda.core.identity.CordaX500Name) @NotNull - public abstract net.corda.core.concurrent.CordaFuture getNodeReady() + public abstract net.corda.core.concurrent.CordaFuture getNodeReady() @NotNull - public abstract java.util.List getNodesByLegalIdentityKey(java.security.PublicKey) + public abstract java.util.List getNodesByLegalIdentityKey(java.security.PublicKey) @NotNull - public abstract java.util.List getNodesByLegalName(net.corda.core.identity.CordaX500Name) + public abstract java.util.List getNodesByLegalName(net.corda.core.identity.CordaX500Name) @Nullable - public abstract net.corda.core.identity.Party getNotary(net.corda.core.identity.CordaX500Name) + public net.corda.core.identity.Party getNotary(net.corda.core.identity.CordaX500Name) @NotNull - public abstract java.util.List getNotaryIdentities() + public abstract java.util.List getNotaryIdentities() @Nullable public abstract net.corda.core.node.services.PartyInfo getPartyInfo(net.corda.core.identity.Party) @Nullable - public abstract net.corda.core.identity.Party getPeerByLegalName(net.corda.core.identity.CordaX500Name) + public net.corda.core.identity.Party getPeerByLegalName(net.corda.core.identity.CordaX500Name) @Nullable public abstract net.corda.core.identity.PartyAndCertificate getPeerCertificateByLegalName(net.corda.core.identity.CordaX500Name) public abstract boolean isNotary(net.corda.core.identity.Party) public abstract boolean isValidatingNotary(net.corda.core.identity.Party) @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.NetworkMapCache$MapChange> track() + public abstract net.corda.core.messaging.DataFeed track() ## @DoNotImplement public interface net.corda.core.node.services.NetworkParametersService @@ -4363,16 +5023,16 @@ public static final class net.corda.core.node.services.PartyInfo$DistributedNode public String toString() ## public static final class net.corda.core.node.services.PartyInfo$SingleNode extends net.corda.core.node.services.PartyInfo - public (net.corda.core.identity.Party, java.util.List) + public (net.corda.core.identity.Party, java.util.List) @NotNull public final net.corda.core.identity.Party component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() @NotNull - public final net.corda.core.node.services.PartyInfo$SingleNode copy(net.corda.core.identity.Party, java.util.List) + public final net.corda.core.node.services.PartyInfo$SingleNode copy(net.corda.core.identity.Party, java.util.List) public boolean equals(Object) @NotNull - public final java.util.List getAddresses() + public final java.util.List getAddresses() @NotNull public net.corda.core.identity.Party getParty() public int hashCode() @@ -4380,6 +5040,8 @@ public static final class net.corda.core.node.services.PartyInfo$SingleNode exte public String toString() ## public final class net.corda.core.node.services.ServiceLifecycleEvent extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.ServiceLifecycleEvent valueOf(String) public static net.corda.core.node.services.ServiceLifecycleEvent[] values() ## @@ -4387,6 +5049,26 @@ public interface net.corda.core.node.services.ServiceLifecycleObserver public abstract void onServiceLifecycleEvent(net.corda.core.node.services.ServiceLifecycleEvent) ## @CordaSerializable +public final class net.corda.core.node.services.SignedTransactionWithStatus extends java.lang.Object implements net.corda.core.contracts.NamedByHash + public (net.corda.core.transactions.SignedTransaction, net.corda.core.node.services.TransactionStatus) + @NotNull + public final net.corda.core.transactions.SignedTransaction component1() + @NotNull + public final net.corda.core.node.services.TransactionStatus component2() + @NotNull + public final net.corda.core.node.services.SignedTransactionWithStatus copy(net.corda.core.transactions.SignedTransaction, net.corda.core.node.services.TransactionStatus) + public boolean equals(Object) + @NotNull + public net.corda.core.crypto.SecureHash getId() + @NotNull + public final net.corda.core.node.services.TransactionStatus getStatus() + @NotNull + public final net.corda.core.transactions.SignedTransaction getStx() + public int hashCode() + @NotNull + public String toString() +## +@CordaSerializable public final class net.corda.core.node.services.StatesNotAvailableException extends net.corda.core.flows.FlowException public (String, Throwable) public (String, Throwable, int, kotlin.jvm.internal.DefaultConstructorMarker) @@ -4400,7 +5082,7 @@ public final class net.corda.core.node.services.StatesNotAvailableException exte @DoNotImplement public interface net.corda.core.node.services.TelemetryService @Nullable - public abstract T getTelemetryHandle(Class) + public abstract T getTelemetryHandle(Class) ## public final class net.corda.core.node.services.TimeWindowChecker extends java.lang.Object public () @@ -4410,21 +5092,25 @@ public final class net.corda.core.node.services.TimeWindowChecker extends java.l public final java.time.Clock getClock() public final boolean isValid(net.corda.core.contracts.TimeWindow) ## +@CordaSerializable +public final class net.corda.core.node.services.TransactionStatus extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() + public static net.corda.core.node.services.TransactionStatus valueOf(String) + public static net.corda.core.node.services.TransactionStatus[] values() +## @DoNotImplement public interface net.corda.core.node.services.TransactionStorage @Nullable public abstract net.corda.core.transactions.SignedTransaction getTransaction(net.corda.core.crypto.SecureHash) + @Nullable + public abstract net.corda.core.node.services.SignedTransactionWithStatus getTransactionWithStatus(net.corda.core.crypto.SecureHash) @NotNull - public abstract rx.Observable getUpdates() + public abstract rx.Observable getUpdates() @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.transactions.SignedTransaction> track() + public abstract net.corda.core.messaging.DataFeed track() @NotNull - public abstract net.corda.core.concurrent.CordaFuture trackTransaction(net.corda.core.crypto.SecureHash) -## -@DoNotImplement -public interface net.corda.core.node.services.TransactionVerifierService - @NotNull - public abstract net.corda.core.concurrent.CordaFuture verify(net.corda.core.transactions.LedgerTransaction) + public abstract net.corda.core.concurrent.CordaFuture trackTransaction(net.corda.core.crypto.SecureHash) ## @CordaSerializable public final class net.corda.core.node.services.UnknownAnonymousPartyException extends net.corda.core.CordaException @@ -4432,17 +5118,18 @@ public final class net.corda.core.node.services.UnknownAnonymousPartyException e ## @CordaSerializable public final class net.corda.core.node.services.Vault extends java.lang.Object - public (Iterable>) + public (Iterable) + @NotNull + public final Iterable getStates() @NotNull - public final Iterable> getStates() public static final net.corda.core.node.services.Vault$Companion Companion ## public static final class net.corda.core.node.services.Vault$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.node.services.Vault$Update getNoNotaryUpdate() + public final net.corda.core.node.services.Vault$Update getNoNotaryUpdate() @NotNull - public final net.corda.core.node.services.Vault$Update getNoUpdate() + public final net.corda.core.node.services.Vault$Update getNoUpdate() ## @CordaSerializable public static final class net.corda.core.node.services.Vault$ConstraintInfo extends java.lang.Object @@ -4461,6 +5148,7 @@ public static final class net.corda.core.node.services.Vault$ConstraintInfo exte public String toString() @NotNull public final net.corda.core.node.services.Vault$ConstraintInfo$Type type() + @NotNull public static final net.corda.core.node.services.Vault$ConstraintInfo$Companion Companion ## public static final class net.corda.core.node.services.Vault$ConstraintInfo$Companion extends java.lang.Object @@ -4470,32 +5158,42 @@ public static final class net.corda.core.node.services.Vault$ConstraintInfo$Comp ## @CordaSerializable public static final class net.corda.core.node.services.Vault$ConstraintInfo$Type extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.Vault$ConstraintInfo$Type valueOf(String) - public static net.corda.core.node.services.Vault$ConstraintInfo$Type[] values() + public static net.corda.core.node.services.Vault.ConstraintInfo.Type[] values() ## @CordaSerializable public static final class net.corda.core.node.services.Vault$Page extends java.lang.Object - public (java.util.List>, java.util.List, long, net.corda.core.node.services.Vault$StateStatus, java.util.List) + public (java.util.List, java.util.List, long, net.corda.core.node.services.Vault$StateStatus, java.util.List) + public (java.util.List, java.util.List, long, net.corda.core.node.services.Vault$StateStatus, java.util.List, net.corda.core.contracts.StateRef) + public (java.util.List, java.util.List, long, net.corda.core.node.services.Vault$StateStatus, java.util.List, net.corda.core.contracts.StateRef, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final java.util.List> component1() + public final java.util.List component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() public final long component3() @NotNull public final net.corda.core.node.services.Vault$StateStatus component4() @NotNull - public final java.util.List component5() + public final java.util.List component5() + @Nullable + public final net.corda.core.contracts.StateRef component6() @NotNull - public final net.corda.core.node.services.Vault$Page copy(java.util.List>, java.util.List, long, net.corda.core.node.services.Vault$StateStatus, java.util.List) + public final net.corda.core.node.services.Vault$Page copy(java.util.List, java.util.List, long, net.corda.core.node.services.Vault$StateStatus, java.util.List) + @NotNull + public final net.corda.core.node.services.Vault$Page copy(java.util.List, java.util.List, long, net.corda.core.node.services.Vault$StateStatus, java.util.List, net.corda.core.contracts.StateRef) public boolean equals(Object) @NotNull - public final java.util.List getOtherResults() + public final java.util.List getOtherResults() + @Nullable + public final net.corda.core.contracts.StateRef getPreviousPageAnchor() @NotNull public final net.corda.core.node.services.Vault$StateStatus getStateTypes() @NotNull - public final java.util.List> getStates() + public final java.util.List getStates() @NotNull - public final java.util.List getStatesMetadata() + public final java.util.List getStatesMetadata() public final long getTotalStatesAvailable() public int hashCode() @NotNull @@ -4503,8 +5201,10 @@ public static final class net.corda.core.node.services.Vault$Page extends java.l ## @CordaSerializable public static final class net.corda.core.node.services.Vault$RelevancyStatus extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.Vault$RelevancyStatus valueOf(String) - public static net.corda.core.node.services.Vault$RelevancyStatus[] values() + public static net.corda.core.node.services.Vault.RelevancyStatus[] values() ## @CordaSerializable public static final class net.corda.core.node.services.Vault$StateMetadata extends java.lang.Object @@ -4565,53 +5265,70 @@ public static final class net.corda.core.node.services.Vault$StateMetadata exten ## @CordaSerializable public static final class net.corda.core.node.services.Vault$StateStatus extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.Vault$StateStatus valueOf(String) - public static net.corda.core.node.services.Vault$StateStatus[] values() + public static net.corda.core.node.services.Vault.StateStatus[] values() ## @CordaSerializable public static final class net.corda.core.node.services.Vault$Update extends java.lang.Object - public (java.util.Set>, java.util.Set>) - public (java.util.Set>, java.util.Set>, java.util.UUID) - public (java.util.Set>, java.util.Set>, java.util.UUID, net.corda.core.node.services.Vault$UpdateType) - public (java.util.Set>, java.util.Set>, java.util.UUID, net.corda.core.node.services.Vault$UpdateType, java.util.Set>) + @DeprecatedConstructorForDeserialization + public (java.util.Set, java.util.Set) + @DeprecatedConstructorForDeserialization + public (java.util.Set, java.util.Set, java.util.UUID) + @DeprecatedConstructorForDeserialization + public (java.util.Set, java.util.Set, java.util.UUID, net.corda.core.node.services.Vault$UpdateType) + @DeprecatedConstructorForDeserialization + public (java.util.Set, java.util.Set, java.util.UUID, net.corda.core.node.services.Vault$UpdateType, java.util.Set) public (java.util.Set, java.util.Set, java.util.UUID, net.corda.core.node.services.Vault$UpdateType, java.util.Set, int, kotlin.jvm.internal.DefaultConstructorMarker) + public (java.util.Set, java.util.Set, java.util.UUID, net.corda.core.node.services.Vault$UpdateType, java.util.Set, java.util.Map) + public (java.util.Set, java.util.Set, java.util.UUID, net.corda.core.node.services.Vault$UpdateType, java.util.Set, java.util.Map, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final java.util.Set> component1() + public final java.util.Set component1() @NotNull - public final java.util.Set> component2() + public final java.util.Set component2() @Nullable public final java.util.UUID component3() @NotNull public final net.corda.core.node.services.Vault$UpdateType component4() @NotNull - public final java.util.Set> component5() - public final boolean containsType(Class, net.corda.core.node.services.Vault$StateStatus) + public final java.util.Set component5() @NotNull - public final net.corda.core.node.services.Vault$Update copy(java.util.Set>, java.util.Set>, java.util.UUID, net.corda.core.node.services.Vault$UpdateType) + public final java.util.Map component6() + public final boolean containsType() + public final boolean containsType(Class, net.corda.core.node.services.Vault$StateStatus) @NotNull - public final net.corda.core.node.services.Vault$Update copy(java.util.Set>, java.util.Set>, java.util.UUID, net.corda.core.node.services.Vault$UpdateType, java.util.Set>) + public final net.corda.core.node.services.Vault$Update copy(java.util.Set, java.util.Set, java.util.UUID, net.corda.core.node.services.Vault$UpdateType) + @NotNull + public final net.corda.core.node.services.Vault$Update copy(java.util.Set, java.util.Set, java.util.UUID, net.corda.core.node.services.Vault$UpdateType, java.util.Set) + @NotNull + public final net.corda.core.node.services.Vault$Update copy(java.util.Set, java.util.Set, java.util.UUID, net.corda.core.node.services.Vault$UpdateType, java.util.Set, java.util.Map) public boolean equals(Object) @NotNull - public final java.util.Set> getConsumed() + public final java.util.Set getConsumed() + @NotNull + public final java.util.Map getConsumingTxIds() @Nullable public final java.util.UUID getFlowId() @NotNull - public final java.util.Set> getProduced() + public final java.util.Set getProduced() @NotNull - public final java.util.Set> getReferences() + public final java.util.Set getReferences() @NotNull public final net.corda.core.node.services.Vault$UpdateType getType() public int hashCode() public final boolean isEmpty() @NotNull - public final net.corda.core.node.services.Vault$Update plus(net.corda.core.node.services.Vault$Update) + public final net.corda.core.node.services.Vault$Update plus(net.corda.core.node.services.Vault$Update) @NotNull public String toString() ## @CordaSerializable public static final class net.corda.core.node.services.Vault$UpdateType extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.Vault$UpdateType valueOf(String) - public static net.corda.core.node.services.Vault$UpdateType[] values() + public static net.corda.core.node.services.Vault.UpdateType[] values() ## @CordaSerializable public final class net.corda.core.node.services.VaultQueryException extends net.corda.core.flows.FlowException @@ -4622,49 +5339,61 @@ public final class net.corda.core.node.services.VaultQueryException extends net. @DoNotImplement public interface net.corda.core.node.services.VaultService @NotNull - public abstract net.corda.core.node.services.Vault$Page _queryBy(net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort, Class) + public abstract net.corda.core.node.services.Vault$Page _queryBy(net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort, Class) @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.Vault$Update> _trackBy(net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort, Class) + public abstract net.corda.core.messaging.DataFeed _trackBy(net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort, Class) public abstract void addNoteToTransaction(net.corda.core.crypto.SecureHash, String) @NotNull - public abstract rx.Observable> getRawUpdates() + public abstract rx.Observable getRawUpdates() @NotNull - public abstract Iterable getTransactionNotes(net.corda.core.crypto.SecureHash) + public abstract Iterable getTransactionNotes(net.corda.core.crypto.SecureHash) @NotNull - public abstract rx.Observable> getUpdates() + public abstract rx.Observable getUpdates() @NotNull - public abstract net.corda.core.node.services.Vault$Page queryBy(Class) + public net.corda.core.node.services.Vault$Page queryBy(Class) @NotNull - public abstract net.corda.core.node.services.Vault$Page queryBy(Class, net.corda.core.node.services.vault.PageSpecification) + public net.corda.core.node.services.Vault$Page queryBy(Class, net.corda.core.node.services.vault.PageSpecification) @NotNull - public abstract net.corda.core.node.services.Vault$Page queryBy(Class, net.corda.core.node.services.vault.QueryCriteria) + public net.corda.core.node.services.Vault$Page queryBy(Class, net.corda.core.node.services.vault.QueryCriteria) @NotNull - public abstract net.corda.core.node.services.Vault$Page queryBy(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification) + public net.corda.core.node.services.Vault$Page queryBy(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification) @NotNull - public abstract net.corda.core.node.services.Vault$Page queryBy(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort) + public net.corda.core.node.services.Vault$Page queryBy(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort) @NotNull - public abstract net.corda.core.node.services.Vault$Page queryBy(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.Sort) - public abstract void softLockRelease(java.util.UUID, net.corda.core.utilities.NonEmptySet) - public abstract void softLockReserve(java.util.UUID, net.corda.core.utilities.NonEmptySet) + public net.corda.core.node.services.Vault$Page queryBy(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.Sort) + public abstract void softLockRelease(java.util.UUID, net.corda.core.utilities.NonEmptySet) + public abstract void softLockReserve(java.util.UUID, net.corda.core.utilities.NonEmptySet) @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.Vault$Update> trackBy(Class) + public net.corda.core.messaging.DataFeed trackBy(Class) @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.Vault$Update> trackBy(Class, net.corda.core.node.services.vault.PageSpecification) + public net.corda.core.messaging.DataFeed trackBy(Class, net.corda.core.node.services.vault.PageSpecification) @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.Vault$Update> trackBy(Class, net.corda.core.node.services.vault.QueryCriteria) + public net.corda.core.messaging.DataFeed trackBy(Class, net.corda.core.node.services.vault.QueryCriteria) @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.Vault$Update> trackBy(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification) + public net.corda.core.messaging.DataFeed trackBy(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification) @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.Vault$Update> trackBy(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort) + public net.corda.core.messaging.DataFeed trackBy(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort) @NotNull - public abstract net.corda.core.messaging.DataFeed, net.corda.core.node.services.Vault$Update> trackBy(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.Sort) + public net.corda.core.messaging.DataFeed trackBy(Class, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.Sort) @Suspendable @NotNull - public abstract java.util.List> tryLockFungibleStatesForSpending(java.util.UUID, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.contracts.Amount, Class) + public abstract java.util.List tryLockFungibleStatesForSpending(java.util.UUID, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.contracts.Amount, Class) @NotNull - public abstract net.corda.core.concurrent.CordaFuture> whenConsumed(net.corda.core.contracts.StateRef) + public net.corda.core.concurrent.CordaFuture whenConsumed(net.corda.core.contracts.StateRef) ## public final class net.corda.core.node.services.VaultServiceKt extends java.lang.Object + public static final net.corda.core.node.services.Vault$Page queryBy(net.corda.core.node.services.VaultService) + public static final net.corda.core.node.services.Vault$Page queryBy(net.corda.core.node.services.VaultService, net.corda.core.node.services.vault.PageSpecification) + public static final net.corda.core.node.services.Vault$Page queryBy(net.corda.core.node.services.VaultService, net.corda.core.node.services.vault.QueryCriteria) + public static final net.corda.core.node.services.Vault$Page queryBy(net.corda.core.node.services.VaultService, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification) + public static final net.corda.core.node.services.Vault$Page queryBy(net.corda.core.node.services.VaultService, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort) + public static final net.corda.core.node.services.Vault$Page queryBy(net.corda.core.node.services.VaultService, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.Sort) + public static final net.corda.core.messaging.DataFeed trackBy(net.corda.core.node.services.VaultService) + public static final net.corda.core.messaging.DataFeed trackBy(net.corda.core.node.services.VaultService, net.corda.core.node.services.vault.PageSpecification) + public static final net.corda.core.messaging.DataFeed trackBy(net.corda.core.node.services.VaultService, net.corda.core.node.services.vault.QueryCriteria) + public static final net.corda.core.messaging.DataFeed trackBy(net.corda.core.node.services.VaultService, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification) + public static final net.corda.core.messaging.DataFeed trackBy(net.corda.core.node.services.VaultService, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.PageSpecification, net.corda.core.node.services.vault.Sort) + public static final net.corda.core.messaging.DataFeed trackBy(net.corda.core.node.services.VaultService, net.corda.core.node.services.vault.QueryCriteria, net.corda.core.node.services.vault.Sort) public static final int MAX_CONSTRAINT_DATA_SIZE = 20000 ## @DoNotImplement @@ -4697,6 +5426,8 @@ public final class net.corda.core.node.services.diagnostics.NodeVersionInfo exte ## @CordaSerializable public final class net.corda.core.node.services.vault.AggregateFunctionType extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.AggregateFunctionType valueOf(String) public static net.corda.core.node.services.vault.AggregateFunctionType[] values() ## @@ -4715,74 +5446,71 @@ public static final class net.corda.core.node.services.vault.AttachmentQueryCrit public net.corda.core.node.services.vault.AttachmentQueryCriteria getA() @NotNull public net.corda.core.node.services.vault.AttachmentQueryCriteria getB() - @NotNull - public java.util.Collection visit(net.corda.core.node.services.vault.AttachmentsQueryCriteriaParser) ## @CordaSerializable public static final class net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria extends net.corda.core.node.services.vault.AttachmentQueryCriteria public () @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.vault.ColumnPredicate) + public (net.corda.core.node.services.vault.ColumnPredicate) @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate) - @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate) + public (net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate) @DeprecatedConstructorForDeserialization + public (net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate) public (net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate>, net.corda.core.node.services.vault.ColumnPredicate>, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate) + public (net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate) public (net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, int, kotlin.jvm.internal.DefaultConstructorMarker) @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate component1() + public final net.corda.core.node.services.vault.ColumnPredicate component1() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate component2() + public final net.corda.core.node.services.vault.ColumnPredicate component2() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate component3() + public final net.corda.core.node.services.vault.ColumnPredicate component3() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate> component4() + public final net.corda.core.node.services.vault.ColumnPredicate component4() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate> component5() + public final net.corda.core.node.services.vault.ColumnPredicate component5() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate component6() + public final net.corda.core.node.services.vault.ColumnPredicate component6() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate component7() + public final net.corda.core.node.services.vault.ColumnPredicate component7() @NotNull - public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria copy(net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria copy(net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate) @NotNull - public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria copy(net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate>, net.corda.core.node.services.vault.ColumnPredicate>, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria copy(net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.vault.ColumnPredicate) public boolean equals(Object) @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate> getContractClassNamesCondition() + public final net.corda.core.node.services.vault.ColumnPredicate getContractClassNamesCondition() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate getFilenameCondition() + public final net.corda.core.node.services.vault.ColumnPredicate getFilenameCondition() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate> getSignersCondition() + public final net.corda.core.node.services.vault.ColumnPredicate getSignersCondition() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate getUploadDateCondition() + public final net.corda.core.node.services.vault.ColumnPredicate getUploadDateCondition() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate getUploaderCondition() + public final net.corda.core.node.services.vault.ColumnPredicate getUploaderCondition() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate getVersionCondition() + public final net.corda.core.node.services.vault.ColumnPredicate getVersionCondition() public int hashCode() @NotNull - public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria isSigned(net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria isSigned(net.corda.core.node.services.vault.ColumnPredicate) @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate isSignedCondition() + public final net.corda.core.node.services.vault.ColumnPredicate isSignedCondition() @NotNull public String toString() @NotNull - public java.util.Collection visit(net.corda.core.node.services.vault.AttachmentsQueryCriteriaParser) + public java.util.Collection visit(net.corda.core.node.services.vault.AttachmentsQueryCriteriaParser) @NotNull - public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria withContractClassNames(net.corda.core.node.services.vault.ColumnPredicate>) + public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria withContractClassNames(net.corda.core.node.services.vault.ColumnPredicate) @NotNull - public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria withFilename(net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria withFilename(net.corda.core.node.services.vault.ColumnPredicate) @NotNull - public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria withSigners(net.corda.core.node.services.vault.ColumnPredicate>) + public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria withSigners(net.corda.core.node.services.vault.ColumnPredicate) @NotNull - public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria withUploadDate(net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria withUploadDate(net.corda.core.node.services.vault.ColumnPredicate) @NotNull - public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria withUploader(net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria withUploader(net.corda.core.node.services.vault.ColumnPredicate) @NotNull - public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria withVersion(net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria withVersion(net.corda.core.node.services.vault.ColumnPredicate) ## @CordaSerializable public static final class net.corda.core.node.services.vault.AttachmentQueryCriteria$OrComposition extends net.corda.core.node.services.vault.AttachmentQueryCriteria implements net.corda.core.node.services.vault.GenericQueryCriteria$ChainableQueryCriteria$OrVisitor @@ -4791,19 +5519,17 @@ public static final class net.corda.core.node.services.vault.AttachmentQueryCrit public net.corda.core.node.services.vault.AttachmentQueryCriteria getA() @NotNull public net.corda.core.node.services.vault.AttachmentQueryCriteria getB() - @NotNull - public java.util.Collection visit(net.corda.core.node.services.vault.AttachmentsQueryCriteriaParser) ## @CordaSerializable public final class net.corda.core.node.services.vault.AttachmentSort extends net.corda.core.node.services.vault.BaseSort - public (java.util.Collection) + public (java.util.Collection) @NotNull - public final java.util.Collection component1() + public final java.util.Collection component1() @NotNull - public final net.corda.core.node.services.vault.AttachmentSort copy(java.util.Collection) + public final net.corda.core.node.services.vault.AttachmentSort copy(java.util.Collection) public boolean equals(Object) @NotNull - public final java.util.Collection getColumns() + public final java.util.Collection getColumns() public int hashCode() @NotNull public String toString() @@ -4811,8 +5537,10 @@ public final class net.corda.core.node.services.vault.AttachmentSort extends net public static final class net.corda.core.node.services.vault.AttachmentSort$AttachmentSortAttribute extends java.lang.Enum @NotNull public final String getColumnName() + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.AttachmentSort$AttachmentSortAttribute valueOf(String) - public static net.corda.core.node.services.vault.AttachmentSort$AttachmentSortAttribute[] values() + public static net.corda.core.node.services.vault.AttachmentSort.AttachmentSortAttribute[] values() ## @CordaSerializable public static final class net.corda.core.node.services.vault.AttachmentSort$AttachmentSortColumn extends java.lang.Object @@ -4835,15 +5563,15 @@ public static final class net.corda.core.node.services.vault.AttachmentSort$Atta ## public interface net.corda.core.node.services.vault.AttachmentsQueryCriteriaParser extends net.corda.core.node.services.vault.BaseQueryCriteriaParser @NotNull - public abstract java.util.Collection parseCriteria(net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria) + public abstract java.util.Collection parseCriteria(net.corda.core.node.services.vault.AttachmentQueryCriteria$AttachmentsQueryCriteria) ## public interface net.corda.core.node.services.vault.BaseQueryCriteriaParser @NotNull - public abstract java.util.Collection parse(Q, S) + public abstract java.util.Collection parse(Q, S) @NotNull - public abstract java.util.Collection parseAnd(Q, Q) + public abstract java.util.Collection parseAnd(Q, Q) @NotNull - public abstract java.util.Collection parseOr(Q, Q) + public abstract java.util.Collection parseOr(Q, Q) ## public abstract class net.corda.core.node.services.vault.BaseSort extends java.lang.Object public () @@ -4851,270 +5579,276 @@ public abstract class net.corda.core.node.services.vault.BaseSort extends java.l @DoNotImplement @CordaSerializable public final class net.corda.core.node.services.vault.BinaryComparisonOperator extends java.lang.Enum implements net.corda.core.node.services.vault.Operator + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.BinaryComparisonOperator valueOf(String) public static net.corda.core.node.services.vault.BinaryComparisonOperator[] values() ## @DoNotImplement @CordaSerializable public final class net.corda.core.node.services.vault.BinaryLogicalOperator extends java.lang.Enum implements net.corda.core.node.services.vault.Operator + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.BinaryLogicalOperator valueOf(String) public static net.corda.core.node.services.vault.BinaryLogicalOperator[] values() ## @CordaSerializable public final class net.corda.core.node.services.vault.Builder extends java.lang.Object @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(reflect.Field) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(reflect.Field) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(reflect.Field, java.util.List) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(reflect.Field, java.util.List) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(reflect.Field, java.util.List, net.corda.core.node.services.vault.Sort$Direction) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(reflect.Field, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(kotlin.reflect.KProperty1, java.util.List>, net.corda.core.node.services.vault.Sort$Direction) + public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(kotlin.reflect.KProperty1, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(net.corda.core.node.services.vault.FieldInfo) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(net.corda.core.node.services.vault.FieldInfo) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(net.corda.core.node.services.vault.FieldInfo, java.util.List) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(net.corda.core.node.services.vault.FieldInfo, java.util.List) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(net.corda.core.node.services.vault.FieldInfo, java.util.List, net.corda.core.node.services.vault.Sort$Direction) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression avg(net.corda.core.node.services.vault.FieldInfo, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$Between between(R, R) + public final net.corda.core.node.services.vault.ColumnPredicate$Between between(R, R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression between(reflect.Field, R, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression between(reflect.Field, R, R) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression between(kotlin.reflect.KProperty1, R, R) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression between(kotlin.reflect.KProperty1, R, R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression between(net.corda.core.node.services.vault.FieldInfo, R, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression between(net.corda.core.node.services.vault.FieldInfo, R, R) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$BinaryComparison compare(net.corda.core.node.services.vault.BinaryComparisonOperator, R) + public final net.corda.core.node.services.vault.ColumnPredicate$BinaryComparison compare(net.corda.core.node.services.vault.BinaryComparisonOperator, R) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression comparePredicate(reflect.Field, net.corda.core.node.services.vault.BinaryComparisonOperator, R) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression comparePredicate(reflect.Field, net.corda.core.node.services.vault.BinaryComparisonOperator, R) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression comparePredicate(kotlin.reflect.KProperty1, net.corda.core.node.services.vault.BinaryComparisonOperator, R) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression comparePredicate(kotlin.reflect.KProperty1, net.corda.core.node.services.vault.BinaryComparisonOperator, R) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression comparePredicate(net.corda.core.node.services.vault.FieldInfo, net.corda.core.node.services.vault.BinaryComparisonOperator, R) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression comparePredicate(net.corda.core.node.services.vault.FieldInfo, net.corda.core.node.services.vault.BinaryComparisonOperator, R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression count(reflect.Field) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression count(reflect.Field) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression count(kotlin.reflect.KProperty1) + public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression count(kotlin.reflect.KProperty1) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression count(net.corda.core.node.services.vault.FieldInfo) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression count(net.corda.core.node.services.vault.FieldInfo) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$EqualityComparison equal(R) + public final net.corda.core.node.services.vault.ColumnPredicate$EqualityComparison equal(R) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$EqualityComparison equal(R, boolean) + public final net.corda.core.node.services.vault.ColumnPredicate$EqualityComparison equal(R, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression equal(reflect.Field, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression equal(reflect.Field, R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression equal(reflect.Field, R, boolean) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression equal(reflect.Field, R, boolean) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression equal(kotlin.reflect.KProperty1, R) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression equal(kotlin.reflect.KProperty1, R) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression equal(kotlin.reflect.KProperty1, R, boolean) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression equal(kotlin.reflect.KProperty1, R, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression equal(net.corda.core.node.services.vault.FieldInfo, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression equal(net.corda.core.node.services.vault.FieldInfo, R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression equal(net.corda.core.node.services.vault.FieldInfo, R, boolean) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression equal(net.corda.core.node.services.vault.FieldInfo, R, boolean) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression functionPredicate(reflect.Field, net.corda.core.node.services.vault.ColumnPredicate, java.util.List>, net.corda.core.node.services.vault.Sort$Direction) + public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression functionPredicate(reflect.Field, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression functionPredicate(kotlin.reflect.KProperty1, net.corda.core.node.services.vault.ColumnPredicate, java.util.List>, net.corda.core.node.services.vault.Sort$Direction) + public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression functionPredicate(kotlin.reflect.KProperty1, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression functionPredicate(net.corda.core.node.services.vault.FieldInfo, net.corda.core.node.services.vault.ColumnPredicate, java.util.List>, net.corda.core.node.services.vault.Sort$Direction) + public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression functionPredicate(net.corda.core.node.services.vault.FieldInfo, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$BinaryComparison greaterThan(R) + public final net.corda.core.node.services.vault.ColumnPredicate$BinaryComparison greaterThan(R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression greaterThan(reflect.Field, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression greaterThan(reflect.Field, R) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression greaterThan(kotlin.reflect.KProperty1, R) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression greaterThan(kotlin.reflect.KProperty1, R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression greaterThan(net.corda.core.node.services.vault.FieldInfo, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression greaterThan(net.corda.core.node.services.vault.FieldInfo, R) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$BinaryComparison greaterThanOrEqual(R) + public final net.corda.core.node.services.vault.ColumnPredicate$BinaryComparison greaterThanOrEqual(R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression greaterThanOrEqual(reflect.Field, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression greaterThanOrEqual(reflect.Field, R) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression greaterThanOrEqual(kotlin.reflect.KProperty1, R) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression greaterThanOrEqual(kotlin.reflect.KProperty1, R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression greaterThanOrEqual(net.corda.core.node.services.vault.FieldInfo, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression greaterThanOrEqual(net.corda.core.node.services.vault.FieldInfo, R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression in(reflect.Field, java.util.Collection) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression in(reflect.Field, java.util.Collection) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression in(reflect.Field, java.util.Collection, boolean) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression in(reflect.Field, java.util.Collection, boolean) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$CollectionExpression in(java.util.Collection) + public final net.corda.core.node.services.vault.ColumnPredicate$CollectionExpression in(java.util.Collection) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$CollectionExpression in(java.util.Collection, boolean) + public final net.corda.core.node.services.vault.ColumnPredicate$CollectionExpression in(java.util.Collection, boolean) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression in(kotlin.reflect.KProperty1, java.util.Collection) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression in(kotlin.reflect.KProperty1, java.util.Collection) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression in(kotlin.reflect.KProperty1, java.util.Collection, boolean) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression in(kotlin.reflect.KProperty1, java.util.Collection, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression in(net.corda.core.node.services.vault.FieldInfo, java.util.Collection) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression in(net.corda.core.node.services.vault.FieldInfo, java.util.Collection) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression in(net.corda.core.node.services.vault.FieldInfo, java.util.Collection, boolean) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression in(net.corda.core.node.services.vault.FieldInfo, java.util.Collection, boolean) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$NullExpression isNotNull() + public final net.corda.core.node.services.vault.ColumnPredicate$NullExpression isNotNull() @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$NullExpression isNull() + public final net.corda.core.node.services.vault.ColumnPredicate$NullExpression isNull() @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression isNull(reflect.Field) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression isNull(reflect.Field) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression isNull(kotlin.reflect.KProperty1) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression isNull(kotlin.reflect.KProperty1) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression isNull(net.corda.core.node.services.vault.FieldInfo) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression isNull(net.corda.core.node.services.vault.FieldInfo) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$BinaryComparison lessThan(R) + public final net.corda.core.node.services.vault.ColumnPredicate$BinaryComparison lessThan(R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression lessThan(reflect.Field, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression lessThan(reflect.Field, R) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression lessThan(kotlin.reflect.KProperty1, R) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression lessThan(kotlin.reflect.KProperty1, R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression lessThan(net.corda.core.node.services.vault.FieldInfo, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression lessThan(net.corda.core.node.services.vault.FieldInfo, R) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$BinaryComparison lessThanOrEqual(R) + public final net.corda.core.node.services.vault.ColumnPredicate$BinaryComparison lessThanOrEqual(R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression lessThanOrEqual(reflect.Field, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression lessThanOrEqual(reflect.Field, R) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression lessThanOrEqual(kotlin.reflect.KProperty1, R) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression lessThanOrEqual(kotlin.reflect.KProperty1, R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression lessThanOrEqual(net.corda.core.node.services.vault.FieldInfo, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression lessThanOrEqual(net.corda.core.node.services.vault.FieldInfo, R) @NotNull public final net.corda.core.node.services.vault.ColumnPredicate$Likeness like(String) @NotNull public final net.corda.core.node.services.vault.ColumnPredicate$Likeness like(String, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression like(reflect.Field, String) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression like(reflect.Field, String) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression like(reflect.Field, String, boolean) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression like(reflect.Field, String, boolean) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression like(kotlin.reflect.KProperty1, String) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression like(kotlin.reflect.KProperty1, String) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression like(kotlin.reflect.KProperty1, String, boolean) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression like(kotlin.reflect.KProperty1, String, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression like(net.corda.core.node.services.vault.FieldInfo, String) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression like(net.corda.core.node.services.vault.FieldInfo, String) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression like(net.corda.core.node.services.vault.FieldInfo, String, boolean) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression like(net.corda.core.node.services.vault.FieldInfo, String, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(reflect.Field) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(reflect.Field) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(reflect.Field, java.util.List) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(reflect.Field, java.util.List) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(reflect.Field, java.util.List, net.corda.core.node.services.vault.Sort$Direction) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(reflect.Field, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(kotlin.reflect.KProperty1, java.util.List>, net.corda.core.node.services.vault.Sort$Direction) + public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(kotlin.reflect.KProperty1, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(net.corda.core.node.services.vault.FieldInfo) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(net.corda.core.node.services.vault.FieldInfo) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(net.corda.core.node.services.vault.FieldInfo, java.util.List) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(net.corda.core.node.services.vault.FieldInfo, java.util.List) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(net.corda.core.node.services.vault.FieldInfo, java.util.List, net.corda.core.node.services.vault.Sort$Direction) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression max(net.corda.core.node.services.vault.FieldInfo, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(reflect.Field) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(reflect.Field) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(reflect.Field, java.util.List) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(reflect.Field, java.util.List) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(reflect.Field, java.util.List, net.corda.core.node.services.vault.Sort$Direction) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(reflect.Field, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(kotlin.reflect.KProperty1, java.util.List>, net.corda.core.node.services.vault.Sort$Direction) + public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(kotlin.reflect.KProperty1, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(net.corda.core.node.services.vault.FieldInfo) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(net.corda.core.node.services.vault.FieldInfo) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(net.corda.core.node.services.vault.FieldInfo, java.util.List) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(net.corda.core.node.services.vault.FieldInfo, java.util.List) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(net.corda.core.node.services.vault.FieldInfo, java.util.List, net.corda.core.node.services.vault.Sort$Direction) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression min(net.corda.core.node.services.vault.FieldInfo, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$EqualityComparison notEqual(R) + public final net.corda.core.node.services.vault.ColumnPredicate$EqualityComparison notEqual(R) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$EqualityComparison notEqual(R, boolean) + public final net.corda.core.node.services.vault.ColumnPredicate$EqualityComparison notEqual(R, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notEqual(reflect.Field, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notEqual(reflect.Field, R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notEqual(reflect.Field, R, boolean) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notEqual(reflect.Field, R, boolean) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notEqual(kotlin.reflect.KProperty1, R) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notEqual(kotlin.reflect.KProperty1, R) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notEqual(kotlin.reflect.KProperty1, R, boolean) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notEqual(kotlin.reflect.KProperty1, R, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notEqual(net.corda.core.node.services.vault.FieldInfo, R) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notEqual(net.corda.core.node.services.vault.FieldInfo, R) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notEqual(net.corda.core.node.services.vault.FieldInfo, R, boolean) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notEqual(net.corda.core.node.services.vault.FieldInfo, R, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notIn(reflect.Field, java.util.Collection) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notIn(reflect.Field, java.util.Collection) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notIn(reflect.Field, java.util.Collection, boolean) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notIn(reflect.Field, java.util.Collection, boolean) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$CollectionExpression notIn(java.util.Collection) + public final net.corda.core.node.services.vault.ColumnPredicate$CollectionExpression notIn(java.util.Collection) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$CollectionExpression notIn(java.util.Collection, boolean) + public final net.corda.core.node.services.vault.ColumnPredicate$CollectionExpression notIn(java.util.Collection, boolean) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notIn(kotlin.reflect.KProperty1, java.util.Collection) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notIn(kotlin.reflect.KProperty1, java.util.Collection) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notIn(kotlin.reflect.KProperty1, java.util.Collection, boolean) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notIn(kotlin.reflect.KProperty1, java.util.Collection, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notIn(net.corda.core.node.services.vault.FieldInfo, java.util.Collection) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notIn(net.corda.core.node.services.vault.FieldInfo, java.util.Collection) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notIn(net.corda.core.node.services.vault.FieldInfo, java.util.Collection, boolean) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notIn(net.corda.core.node.services.vault.FieldInfo, java.util.Collection, boolean) @NotNull public final net.corda.core.node.services.vault.ColumnPredicate$Likeness notLike(String) @NotNull public final net.corda.core.node.services.vault.ColumnPredicate$Likeness notLike(String, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notLike(reflect.Field, String) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notLike(reflect.Field, String) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notLike(reflect.Field, String, boolean) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notLike(reflect.Field, String, boolean) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notLike(kotlin.reflect.KProperty1, String) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notLike(kotlin.reflect.KProperty1, String) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notLike(kotlin.reflect.KProperty1, String, boolean) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notLike(kotlin.reflect.KProperty1, String, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notLike(net.corda.core.node.services.vault.FieldInfo, String) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notLike(net.corda.core.node.services.vault.FieldInfo, String) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notLike(net.corda.core.node.services.vault.FieldInfo, String, boolean) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notLike(net.corda.core.node.services.vault.FieldInfo, String, boolean) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notNull(reflect.Field) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notNull(reflect.Field) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notNull(kotlin.reflect.KProperty1) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notNull(kotlin.reflect.KProperty1) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notNull(net.corda.core.node.services.vault.FieldInfo) + public static final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression notNull(net.corda.core.node.services.vault.FieldInfo) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression predicate(reflect.Field, net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression predicate(reflect.Field, net.corda.core.node.services.vault.ColumnPredicate) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression predicate(kotlin.reflect.KProperty1, net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression predicate(kotlin.reflect.KProperty1, net.corda.core.node.services.vault.ColumnPredicate) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression predicate(net.corda.core.node.services.vault.FieldInfo, net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression predicate(net.corda.core.node.services.vault.FieldInfo, net.corda.core.node.services.vault.ColumnPredicate) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(reflect.Field) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(reflect.Field) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(reflect.Field, java.util.List) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(reflect.Field, java.util.List) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(reflect.Field, java.util.List, net.corda.core.node.services.vault.Sort$Direction) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(reflect.Field, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(kotlin.reflect.KProperty1, java.util.List>, net.corda.core.node.services.vault.Sort$Direction) + public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(kotlin.reflect.KProperty1, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(net.corda.core.node.services.vault.FieldInfo) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(net.corda.core.node.services.vault.FieldInfo) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(net.corda.core.node.services.vault.FieldInfo, java.util.List) + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(net.corda.core.node.services.vault.FieldInfo, java.util.List) + @NotNull + public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(net.corda.core.node.services.vault.FieldInfo, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public static final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression sum(net.corda.core.node.services.vault.FieldInfo, java.util.List, net.corda.core.node.services.vault.Sort$Direction) public static final net.corda.core.node.services.vault.Builder INSTANCE ## @DoNotImplement @CordaSerializable public final class net.corda.core.node.services.vault.CollectionOperator extends java.lang.Enum implements net.corda.core.node.services.vault.Operator + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.CollectionOperator valueOf(String) public static net.corda.core.node.services.vault.CollectionOperator[] values() ## @CordaSerializable public final class net.corda.core.node.services.vault.Column extends java.lang.Object - public (String, Class) + public (String, Class) public (reflect.Field) - public (kotlin.reflect.KProperty1) + public (kotlin.reflect.KProperty1) public (net.corda.core.node.services.vault.FieldInfo) @NotNull - public final Class getDeclaringClass() + public final Class getDeclaringClass() @NotNull public final String getName() - public static final net.corda.core.node.services.vault.Column$Companion Companion ## @CordaSerializable public abstract class net.corda.core.node.services.vault.ColumnPredicate extends java.lang.Object @@ -5126,7 +5860,7 @@ public static final class net.corda.core.node.services.vault.ColumnPredicate$Agg @NotNull public final net.corda.core.node.services.vault.AggregateFunctionType component1() @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$AggregateFunction copy(net.corda.core.node.services.vault.AggregateFunctionType) + public final net.corda.core.node.services.vault.ColumnPredicate$AggregateFunction copy(net.corda.core.node.services.vault.AggregateFunctionType) public boolean equals(Object) @NotNull public final net.corda.core.node.services.vault.AggregateFunctionType getType() @@ -5142,7 +5876,7 @@ public static final class net.corda.core.node.services.vault.ColumnPredicate$Bet @NotNull public final C component2() @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$Between copy(C, C) + public final net.corda.core.node.services.vault.ColumnPredicate$Between copy(C, C) public boolean equals(Object) @NotNull public final C getRightFromLiteral() @@ -5160,7 +5894,7 @@ public static final class net.corda.core.node.services.vault.ColumnPredicate$Bin @NotNull public final C component2() @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$BinaryComparison copy(net.corda.core.node.services.vault.BinaryComparisonOperator, C) + public final net.corda.core.node.services.vault.ColumnPredicate$BinaryComparison copy(net.corda.core.node.services.vault.BinaryComparisonOperator, C) public boolean equals(Object) @NotNull public final net.corda.core.node.services.vault.BinaryComparisonOperator getOperator() @@ -5172,18 +5906,18 @@ public static final class net.corda.core.node.services.vault.ColumnPredicate$Bin ## @CordaSerializable public static final class net.corda.core.node.services.vault.ColumnPredicate$CollectionExpression extends net.corda.core.node.services.vault.ColumnPredicate - public (net.corda.core.node.services.vault.CollectionOperator, java.util.Collection) + public (net.corda.core.node.services.vault.CollectionOperator, java.util.Collection) @NotNull public final net.corda.core.node.services.vault.CollectionOperator component1() @NotNull - public final java.util.Collection component2() + public final java.util.Collection component2() @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$CollectionExpression copy(net.corda.core.node.services.vault.CollectionOperator, java.util.Collection) + public final net.corda.core.node.services.vault.ColumnPredicate$CollectionExpression copy(net.corda.core.node.services.vault.CollectionOperator, java.util.Collection) public boolean equals(Object) @NotNull public final net.corda.core.node.services.vault.CollectionOperator getOperator() @NotNull - public final java.util.Collection getRightLiteral() + public final java.util.Collection getRightLiteral() public int hashCode() @NotNull public String toString() @@ -5195,7 +5929,7 @@ public static final class net.corda.core.node.services.vault.ColumnPredicate$Equ public final net.corda.core.node.services.vault.EqualityComparisonOperator component1() public final C component2() @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$EqualityComparison copy(net.corda.core.node.services.vault.EqualityComparisonOperator, C) + public final net.corda.core.node.services.vault.ColumnPredicate$EqualityComparison copy(net.corda.core.node.services.vault.EqualityComparisonOperator, C) public boolean equals(Object) @NotNull public final net.corda.core.node.services.vault.EqualityComparisonOperator getOperator() @@ -5228,7 +5962,7 @@ public static final class net.corda.core.node.services.vault.ColumnPredicate$Nul @NotNull public final net.corda.core.node.services.vault.NullOperator component1() @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate$NullExpression copy(net.corda.core.node.services.vault.NullOperator) + public final net.corda.core.node.services.vault.ColumnPredicate$NullExpression copy(net.corda.core.node.services.vault.NullOperator) public boolean equals(Object) @NotNull public final net.corda.core.node.services.vault.NullOperator getOperator() @@ -5238,7 +5972,7 @@ public static final class net.corda.core.node.services.vault.ColumnPredicate$Nul ## @DoNotImplement public interface net.corda.core.node.services.vault.CordaTransactionSupport - public abstract T transaction(kotlin.jvm.functions.Function1) + public abstract T transaction(kotlin.jvm.functions.Function1) ## @CordaSerializable public abstract class net.corda.core.node.services.vault.CriteriaExpression extends java.lang.Object @@ -5246,80 +5980,80 @@ public abstract class net.corda.core.node.services.vault.CriteriaExpression exte ## @CordaSerializable public static final class net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression extends net.corda.core.node.services.vault.CriteriaExpression - public (net.corda.core.node.services.vault.Column, net.corda.core.node.services.vault.ColumnPredicate, java.util.List>, net.corda.core.node.services.vault.Sort$Direction) + public (net.corda.core.node.services.vault.Column, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, net.corda.core.node.services.vault.Sort$Direction) @NotNull - public final net.corda.core.node.services.vault.Column component1() + public final net.corda.core.node.services.vault.Column component1() @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate component2() + public final net.corda.core.node.services.vault.ColumnPredicate component2() @Nullable - public final java.util.List> component3() + public final java.util.List component3() @Nullable public final net.corda.core.node.services.vault.Sort$Direction component4() @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression copy(net.corda.core.node.services.vault.Column, net.corda.core.node.services.vault.ColumnPredicate, java.util.List>, net.corda.core.node.services.vault.Sort$Direction) + public final net.corda.core.node.services.vault.CriteriaExpression$AggregateFunctionExpression copy(net.corda.core.node.services.vault.Column, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, net.corda.core.node.services.vault.Sort$Direction) public boolean equals(Object) @NotNull - public final net.corda.core.node.services.vault.Column getColumn() + public final net.corda.core.node.services.vault.Column getColumn() @Nullable - public final java.util.List> getGroupByColumns() + public final java.util.List getGroupByColumns() @Nullable public final net.corda.core.node.services.vault.Sort$Direction getOrderBy() @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate getPredicate() + public final net.corda.core.node.services.vault.ColumnPredicate getPredicate() public int hashCode() @NotNull public String toString() ## @CordaSerializable public static final class net.corda.core.node.services.vault.CriteriaExpression$BinaryLogical extends net.corda.core.node.services.vault.CriteriaExpression - public (net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.vault.BinaryLogicalOperator) + public (net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.vault.BinaryLogicalOperator) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression component1() + public final net.corda.core.node.services.vault.CriteriaExpression component1() @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression component2() + public final net.corda.core.node.services.vault.CriteriaExpression component2() @NotNull public final net.corda.core.node.services.vault.BinaryLogicalOperator component3() @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$BinaryLogical copy(net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.vault.BinaryLogicalOperator) + public final net.corda.core.node.services.vault.CriteriaExpression$BinaryLogical copy(net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.vault.BinaryLogicalOperator) public boolean equals(Object) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression getLeft() + public final net.corda.core.node.services.vault.CriteriaExpression getLeft() @NotNull public final net.corda.core.node.services.vault.BinaryLogicalOperator getOperator() @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression getRight() + public final net.corda.core.node.services.vault.CriteriaExpression getRight() public int hashCode() @NotNull public String toString() ## @CordaSerializable public static final class net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression extends net.corda.core.node.services.vault.CriteriaExpression - public (net.corda.core.node.services.vault.Column, net.corda.core.node.services.vault.ColumnPredicate) + public (net.corda.core.node.services.vault.Column, net.corda.core.node.services.vault.ColumnPredicate) @NotNull - public final net.corda.core.node.services.vault.Column component1() + public final net.corda.core.node.services.vault.Column component1() @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate component2() + public final net.corda.core.node.services.vault.ColumnPredicate component2() @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression copy(net.corda.core.node.services.vault.Column, net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.CriteriaExpression$ColumnPredicateExpression copy(net.corda.core.node.services.vault.Column, net.corda.core.node.services.vault.ColumnPredicate) public boolean equals(Object) @NotNull - public final net.corda.core.node.services.vault.Column getColumn() + public final net.corda.core.node.services.vault.Column getColumn() @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate getPredicate() + public final net.corda.core.node.services.vault.ColumnPredicate getPredicate() public int hashCode() @NotNull public String toString() ## @CordaSerializable public static final class net.corda.core.node.services.vault.CriteriaExpression$Not extends net.corda.core.node.services.vault.CriteriaExpression - public (net.corda.core.node.services.vault.CriteriaExpression) + public (net.corda.core.node.services.vault.CriteriaExpression) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression component1() + public final net.corda.core.node.services.vault.CriteriaExpression component1() @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression$Not copy(net.corda.core.node.services.vault.CriteriaExpression) + public final net.corda.core.node.services.vault.CriteriaExpression$Not copy(net.corda.core.node.services.vault.CriteriaExpression) public boolean equals(Object) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression getExpression() + public final net.corda.core.node.services.vault.CriteriaExpression getExpression() public int hashCode() @NotNull public String toString() @@ -5327,19 +6061,21 @@ public static final class net.corda.core.node.services.vault.CriteriaExpression$ @DoNotImplement @CordaSerializable public final class net.corda.core.node.services.vault.EqualityComparisonOperator extends java.lang.Enum implements net.corda.core.node.services.vault.Operator + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.EqualityComparisonOperator valueOf(String) public static net.corda.core.node.services.vault.EqualityComparisonOperator[] values() ## public final class net.corda.core.node.services.vault.FieldInfo extends java.lang.Object - public (String, Class) + public (String, Class) @NotNull - public final Class getEntityClass() + public final Class getEntityClass() @NotNull public final String getName() ## public interface net.corda.core.node.services.vault.GenericQueryCriteria @NotNull - public abstract java.util.Collection visit(P) + public abstract java.util.Collection visit(P) ## public static interface net.corda.core.node.services.vault.GenericQueryCriteria$ChainableQueryCriteria @NotNull @@ -5353,7 +6089,7 @@ public static interface net.corda.core.node.services.vault.GenericQueryCriteria$ @NotNull public abstract Q getB() @NotNull - public abstract java.util.Collection visit(P) + public java.util.Collection visit(P) ## public static interface net.corda.core.node.services.vault.GenericQueryCriteria$ChainableQueryCriteria$OrVisitor extends net.corda.core.node.services.vault.GenericQueryCriteria @NotNull @@ -5361,30 +6097,34 @@ public static interface net.corda.core.node.services.vault.GenericQueryCriteria$ @NotNull public abstract Q getB() @NotNull - public abstract java.util.Collection visit(P) + public java.util.Collection visit(P) ## @DoNotImplement public interface net.corda.core.node.services.vault.IQueryCriteriaParser extends net.corda.core.node.services.vault.BaseQueryCriteriaParser @NotNull - public abstract java.util.Collection parseCriteria(net.corda.core.node.services.vault.QueryCriteria$CommonQueryCriteria) + public abstract java.util.Collection parseCriteria(net.corda.core.node.services.vault.QueryCriteria$CommonQueryCriteria) @NotNull - public abstract java.util.Collection parseCriteria(net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria) + public abstract java.util.Collection parseCriteria(net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria) @NotNull - public abstract java.util.Collection parseCriteria(net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria) + public abstract java.util.Collection parseCriteria(net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria) @NotNull - public abstract java.util.Collection parseCriteria(net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria) + public abstract java.util.Collection parseCriteria(net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria) @NotNull - public abstract java.util.Collection parseCriteria(net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria) + public abstract java.util.Collection parseCriteria(net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria) ## @DoNotImplement @CordaSerializable public final class net.corda.core.node.services.vault.LikenessOperator extends java.lang.Enum implements net.corda.core.node.services.vault.Operator + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.LikenessOperator valueOf(String) public static net.corda.core.node.services.vault.LikenessOperator[] values() ## @DoNotImplement @CordaSerializable public final class net.corda.core.node.services.vault.NullOperator extends java.lang.Enum implements net.corda.core.node.services.vault.Operator + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.NullOperator valueOf(String) public static net.corda.core.node.services.vault.NullOperator[] values() ## @@ -5424,96 +6164,92 @@ public static final class net.corda.core.node.services.vault.QueryCriteria$AndCo public net.corda.core.node.services.vault.QueryCriteria getA() @NotNull public net.corda.core.node.services.vault.QueryCriteria getB() - @NotNull - public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) ## @CordaSerializable public abstract static class net.corda.core.node.services.vault.QueryCriteria$CommonQueryCriteria extends net.corda.core.node.services.vault.QueryCriteria public () @NotNull - public java.util.Set getConstraintTypes() + public java.util.Set getConstraintTypes() @NotNull - public java.util.Set getConstraints() + public java.util.Set getConstraints() @Nullable - public abstract java.util.Set> getContractStateTypes() + public abstract java.util.Set getContractStateTypes() @Nullable - public java.util.List getExactParticipants() + public java.util.List getExactParticipants() @NotNull - public java.util.List getExternalIds() + public java.util.List getExternalIds() @Nullable - public java.util.List getParticipants() + public java.util.List getParticipants() @NotNull public net.corda.core.node.services.Vault$RelevancyStatus getRelevancyStatus() @NotNull public abstract net.corda.core.node.services.Vault$StateStatus getStatus() @NotNull - public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) + public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) ## @CordaSerializable public static final class net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria extends net.corda.core.node.services.vault.QueryCriteria$CommonQueryCriteria @DeprecatedConstructorForDeserialization public () @DeprecatedConstructorForDeserialization - public (java.util.List) + public (java.util.List) @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List) + public (java.util.List, java.util.List) @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate) + public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate) @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List) + public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List) @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List) + public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List) @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus) - @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>) + public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus) @DeprecatedConstructorForDeserialization + public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set) public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, int, kotlin.jvm.internal.DefaultConstructorMarker) @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus) - @DeprecatedConstructorForDeserialization + public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus) public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus, java.util.List) + public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus, java.util.List) public (java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) @Nullable - public final java.util.List component1() + public final java.util.List component1() @Nullable - public final java.util.List component2() + public final java.util.List component2() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate component3() + public final net.corda.core.node.services.vault.ColumnPredicate component3() @Nullable - public final java.util.List component4() + public final java.util.List component4() @Nullable - public final java.util.List component5() + public final java.util.List component5() @NotNull public final net.corda.core.node.services.Vault$StateStatus component6() @Nullable - public final java.util.Set> component7() + public final java.util.Set component7() @NotNull public final net.corda.core.node.services.Vault$RelevancyStatus component8() @Nullable - public final java.util.List component9() + public final java.util.List component9() @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria copy(java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria copy(java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria copy(java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria copy(java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria copy(java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus, java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria copy(java.util.List, java.util.List, net.corda.core.node.services.vault.ColumnPredicate, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus, java.util.List) public boolean equals(Object) @Nullable - public java.util.Set> getContractStateTypes() + public java.util.Set getContractStateTypes() @Nullable - public java.util.List getExactParticipants() + public java.util.List getExactParticipants() @Nullable - public final java.util.List getIssuer() + public final java.util.List getIssuer() @Nullable - public final java.util.List getIssuerRef() + public final java.util.List getIssuerRef() @Nullable - public final java.util.List getOwner() + public final java.util.List getOwner() @Nullable - public java.util.List getParticipants() + public java.util.List getParticipants() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate getQuantity() + public final net.corda.core.node.services.vault.ColumnPredicate getQuantity() @NotNull public net.corda.core.node.services.Vault$RelevancyStatus getRelevancyStatus() @NotNull @@ -5522,50 +6258,50 @@ public static final class net.corda.core.node.services.vault.QueryCriteria$Fungi @NotNull public String toString() @NotNull - public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) + public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withContractStateTypes(java.util.Set>) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withContractStateTypes(java.util.Set) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withExactParticipants(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withExactParticipants(java.util.List) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withIssuer(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withIssuer(java.util.List) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withOwner(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withOwner(java.util.List) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withParticipants(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withParticipants(java.util.List) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withQuantity(net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withQuantity(net.corda.core.node.services.vault.ColumnPredicate) @NotNull public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withRelevancyStatus(net.corda.core.node.services.Vault$RelevancyStatus) @NotNull public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withStatus(net.corda.core.node.services.Vault$StateStatus) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withissuerRef(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleAssetQueryCriteria withissuerRef(java.util.List) ## @CordaSerializable public static final class net.corda.core.node.services.vault.QueryCriteria$FungibleStateQueryCriteria extends net.corda.core.node.services.vault.QueryCriteria$CommonQueryCriteria public () - public (java.util.List, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus) + public (java.util.List, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus) public (java.util.List, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus, int, kotlin.jvm.internal.DefaultConstructorMarker) @Nullable - public final java.util.List component1() + public final java.util.List component1() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate component2() + public final net.corda.core.node.services.vault.ColumnPredicate component2() @NotNull public final net.corda.core.node.services.Vault$StateStatus component3() @Nullable - public final java.util.Set> component4() + public final java.util.Set component4() @NotNull public final net.corda.core.node.services.Vault$RelevancyStatus component5() @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleStateQueryCriteria copy(java.util.List, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleStateQueryCriteria copy(java.util.List, net.corda.core.node.services.vault.ColumnPredicate, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus) public boolean equals(Object) @Nullable - public java.util.Set> getContractStateTypes() + public java.util.Set getContractStateTypes() @Nullable - public java.util.List getParticipants() + public java.util.List getParticipants() @Nullable - public final net.corda.core.node.services.vault.ColumnPredicate getQuantity() + public final net.corda.core.node.services.vault.ColumnPredicate getQuantity() @NotNull public net.corda.core.node.services.Vault$RelevancyStatus getRelevancyStatus() @NotNull @@ -5574,13 +6310,13 @@ public static final class net.corda.core.node.services.vault.QueryCriteria$Fungi @NotNull public String toString() @NotNull - public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) + public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleStateQueryCriteria withContractStateTypes(java.util.Set>) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleStateQueryCriteria withContractStateTypes(java.util.Set) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleStateQueryCriteria withParticipants(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleStateQueryCriteria withParticipants(java.util.List) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$FungibleStateQueryCriteria withQuantity(net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.QueryCriteria$FungibleStateQueryCriteria withQuantity(net.corda.core.node.services.vault.ColumnPredicate) @NotNull public final net.corda.core.node.services.vault.QueryCriteria$FungibleStateQueryCriteria withRelevancyStatus(net.corda.core.node.services.Vault$RelevancyStatus) @NotNull @@ -5591,85 +6327,81 @@ public static final class net.corda.core.node.services.vault.QueryCriteria$Linea @DeprecatedConstructorForDeserialization public () @DeprecatedConstructorForDeserialization - public (java.util.List) + public (java.util.List) @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List) + public (java.util.List, java.util.List) @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List, java.util.List) + public (java.util.List, java.util.List, java.util.List) @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus) - @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>) + public (java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus) @DeprecatedConstructorForDeserialization + public (java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set) public (java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, int, kotlin.jvm.internal.DefaultConstructorMarker) @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus) - @DeprecatedConstructorForDeserialization + public (java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus) public (java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus, java.util.List) + public (java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus, java.util.List) public (java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>) - @DeprecatedConstructorForDeserialization + public (java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set) public (java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, int, kotlin.jvm.internal.DefaultConstructorMarker) @DeprecatedConstructorForDeserialization - public (java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus) - @DeprecatedConstructorForDeserialization + public (java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus) public (java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus, int, kotlin.jvm.internal.DefaultConstructorMarker) @Nullable - public final java.util.List component1() + public final java.util.List component1() @Nullable - public final java.util.List component2() + public final java.util.List component2() @Nullable - public final java.util.List component3() + public final java.util.List component3() @NotNull public final net.corda.core.node.services.Vault$StateStatus component4() @Nullable - public final java.util.Set> component5() + public final java.util.Set component5() @NotNull public final net.corda.core.node.services.Vault$RelevancyStatus component6() @Nullable - public final java.util.List component7() + public final java.util.List component7() @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria copy(java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>) + public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria copy(java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria copy(java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus) + public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria copy(java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria copy(java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus, java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria copy(java.util.List, java.util.List, java.util.List, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus, java.util.List) public boolean equals(Object) @Nullable - public java.util.Set> getContractStateTypes() + public java.util.Set getContractStateTypes() @Nullable - public java.util.List getExactParticipants() + public java.util.List getExactParticipants() @Nullable - public final java.util.List getExternalId() + public final java.util.List getExternalId() @Nullable - public java.util.List getParticipants() + public java.util.List getParticipants() @NotNull public net.corda.core.node.services.Vault$RelevancyStatus getRelevancyStatus() @NotNull public net.corda.core.node.services.Vault$StateStatus getStatus() @Nullable - public final java.util.List getUuid() + public final java.util.List getUuid() public int hashCode() @NotNull public String toString() @NotNull - public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) + public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria withContractStateTypes(java.util.Set>) + public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria withContractStateTypes(java.util.Set) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria withExactParticipants(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria withExactParticipants(java.util.List) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria withExternalId(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria withExternalId(java.util.List) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria withParticipants(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria withParticipants(java.util.List) @NotNull public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria withRelevancyStatus(net.corda.core.node.services.Vault$RelevancyStatus) @NotNull public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria withStatus(net.corda.core.node.services.Vault$StateStatus) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria withUuid(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$LinearStateQueryCriteria withUuid(java.util.List) ## @CordaSerializable public static final class net.corda.core.node.services.vault.QueryCriteria$OrComposition extends net.corda.core.node.services.vault.QueryCriteria implements net.corda.core.node.services.vault.GenericQueryCriteria$ChainableQueryCriteria$OrVisitor @@ -5678,22 +6410,20 @@ public static final class net.corda.core.node.services.vault.QueryCriteria$OrCom public net.corda.core.node.services.vault.QueryCriteria getA() @NotNull public net.corda.core.node.services.vault.QueryCriteria getB() - @NotNull - public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) ## @CordaSerializable public static final class net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition extends java.lang.Object - public (net.corda.core.node.services.vault.QueryCriteria$SoftLockingType, java.util.List) + public (net.corda.core.node.services.vault.QueryCriteria$SoftLockingType, java.util.List) public (net.corda.core.node.services.vault.QueryCriteria$SoftLockingType, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull public final net.corda.core.node.services.vault.QueryCriteria$SoftLockingType component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition copy(net.corda.core.node.services.vault.QueryCriteria$SoftLockingType, java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition copy(net.corda.core.node.services.vault.QueryCriteria$SoftLockingType, java.util.List) public boolean equals(Object) @NotNull - public final java.util.List getLockIds() + public final java.util.List getLockIds() @NotNull public final net.corda.core.node.services.vault.QueryCriteria$SoftLockingType getType() public int hashCode() @@ -5702,21 +6432,23 @@ public static final class net.corda.core.node.services.vault.QueryCriteria$SoftL ## @CordaSerializable public static final class net.corda.core.node.services.vault.QueryCriteria$SoftLockingType extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.QueryCriteria$SoftLockingType valueOf(String) - public static net.corda.core.node.services.vault.QueryCriteria$SoftLockingType[] values() + public static net.corda.core.node.services.vault.QueryCriteria.SoftLockingType[] values() ## @CordaSerializable public static final class net.corda.core.node.services.vault.QueryCriteria$TimeCondition extends java.lang.Object - public (net.corda.core.node.services.vault.QueryCriteria$TimeInstantType, net.corda.core.node.services.vault.ColumnPredicate) + public (net.corda.core.node.services.vault.QueryCriteria$TimeInstantType, net.corda.core.node.services.vault.ColumnPredicate) @NotNull public final net.corda.core.node.services.vault.QueryCriteria$TimeInstantType component1() @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate component2() + public final net.corda.core.node.services.vault.ColumnPredicate component2() @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$TimeCondition copy(net.corda.core.node.services.vault.QueryCriteria$TimeInstantType, net.corda.core.node.services.vault.ColumnPredicate) + public final net.corda.core.node.services.vault.QueryCriteria$TimeCondition copy(net.corda.core.node.services.vault.QueryCriteria$TimeInstantType, net.corda.core.node.services.vault.ColumnPredicate) public boolean equals(Object) @NotNull - public final net.corda.core.node.services.vault.ColumnPredicate getPredicate() + public final net.corda.core.node.services.vault.ColumnPredicate getPredicate() @NotNull public final net.corda.core.node.services.vault.QueryCriteria$TimeInstantType getType() public int hashCode() @@ -5725,38 +6457,39 @@ public static final class net.corda.core.node.services.vault.QueryCriteria$TimeC ## @CordaSerializable public static final class net.corda.core.node.services.vault.QueryCriteria$TimeInstantType extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.QueryCriteria$TimeInstantType valueOf(String) - public static net.corda.core.node.services.vault.QueryCriteria$TimeInstantType[] values() + public static net.corda.core.node.services.vault.QueryCriteria.TimeInstantType[] values() ## @CordaSerializable public static final class net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria extends net.corda.core.node.services.vault.QueryCriteria$CommonQueryCriteria @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.vault.CriteriaExpression) + public (net.corda.core.node.services.vault.CriteriaExpression) @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.Vault$StateStatus) - @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.Vault$StateStatus, java.util.Set>) + public (net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.Vault$StateStatus) @DeprecatedConstructorForDeserialization + public (net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.Vault$StateStatus, java.util.Set) public (net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.Vault$StateStatus, java.util.Set, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus) + public (net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus) public (net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression component1() + public final net.corda.core.node.services.vault.CriteriaExpression component1() @NotNull public final net.corda.core.node.services.Vault$StateStatus component2() @Nullable - public final java.util.Set> component3() + public final java.util.Set component3() @NotNull public final net.corda.core.node.services.Vault$RelevancyStatus component4() @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria copy(net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.Vault$StateStatus, java.util.Set>) + public final net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria copy(net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.Vault$StateStatus, java.util.Set) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria copy(net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.Vault$StateStatus, java.util.Set>, net.corda.core.node.services.Vault$RelevancyStatus) + public final net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria copy(net.corda.core.node.services.vault.CriteriaExpression, net.corda.core.node.services.Vault$StateStatus, java.util.Set, net.corda.core.node.services.Vault$RelevancyStatus) public boolean equals(Object) @Nullable - public java.util.Set> getContractStateTypes() + public java.util.Set getContractStateTypes() @NotNull - public final net.corda.core.node.services.vault.CriteriaExpression getExpression() + public final net.corda.core.node.services.vault.CriteriaExpression getExpression() @NotNull public net.corda.core.node.services.Vault$RelevancyStatus getRelevancyStatus() @NotNull @@ -5765,15 +6498,15 @@ public static final class net.corda.core.node.services.vault.QueryCriteria$Vault @NotNull public String toString() @NotNull - public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) + public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria withContractStateTypes(java.util.Set>) + public final net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria withContractStateTypes(java.util.Set) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria withExpression(net.corda.core.node.services.vault.CriteriaExpression) + public final net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria withExpression(net.corda.core.node.services.vault.CriteriaExpression) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria withRelevancyStatus(net.corda.core.node.services.Vault$RelevancyStatus) + public final net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria withRelevancyStatus(net.corda.core.node.services.Vault$RelevancyStatus) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria withStatus(net.corda.core.node.services.Vault$StateStatus) + public final net.corda.core.node.services.vault.QueryCriteria$VaultCustomQueryCriteria withStatus(net.corda.core.node.services.Vault$StateStatus) ## @CordaSerializable public static final class net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria extends net.corda.core.node.services.vault.QueryCriteria$CommonQueryCriteria @@ -5781,41 +6514,38 @@ public static final class net.corda.core.node.services.vault.QueryCriteria$Vault @DeprecatedConstructorForDeserialization public (net.corda.core.node.services.Vault$StateStatus) @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.Vault$StateStatus, java.util.Set>) + public (net.corda.core.node.services.Vault$StateStatus, java.util.Set) @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.Vault$StateStatus, java.util.Set>, java.util.List) + public (net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List) @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.Vault$StateStatus, java.util.Set>, java.util.List, java.util.List) + public (net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List) @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.Vault$StateStatus, java.util.Set>, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition) - @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.Vault$StateStatus, java.util.Set>, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition) + public (net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition) @DeprecatedConstructorForDeserialization + public (net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition) public (net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, int, kotlin.jvm.internal.DefaultConstructorMarker) @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.Vault$StateStatus, java.util.Set>, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List) - @DeprecatedConstructorForDeserialization + public (net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List) public (net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) @DeprecatedConstructorForDeserialization - public (net.corda.core.node.services.Vault$StateStatus, java.util.Set>, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List, java.util.List) - @DeprecatedConstructorForDeserialization + public (net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List, java.util.List) public (net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.node.services.Vault$StateStatus, java.util.Set>, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List, java.util.List, java.util.List) + public (net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List, java.util.List, java.util.List) public (net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List, java.util.List, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull public final net.corda.core.node.services.Vault$StateStatus component1() @Nullable - public final java.util.List component10() + public final java.util.List component10() @NotNull - public final java.util.List component11() + public final java.util.List component11() @Nullable - public final java.util.List component12() + public final java.util.List component12() @Nullable - public final java.util.Set> component2() + public final java.util.Set component2() @Nullable - public final java.util.List component3() + public final java.util.List component3() @Nullable - public final java.util.List component4() + public final java.util.List component4() @Nullable public final net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition component5() @Nullable @@ -5823,38 +6553,38 @@ public static final class net.corda.core.node.services.vault.QueryCriteria$Vault @NotNull public final net.corda.core.node.services.Vault$RelevancyStatus component7() @NotNull - public final java.util.Set component8() + public final java.util.Set component8() @NotNull - public final java.util.Set component9() + public final java.util.Set component9() @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria copy(net.corda.core.node.services.Vault$StateStatus, java.util.Set>, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition) + public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria copy(net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria copy(net.corda.core.node.services.Vault$StateStatus, java.util.Set>, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria copy(net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria copy(net.corda.core.node.services.Vault$StateStatus, java.util.Set>, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List, java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria copy(net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List, java.util.List) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria copy(net.corda.core.node.services.Vault$StateStatus, java.util.Set>, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List, java.util.List, java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria copy(net.corda.core.node.services.Vault$StateStatus, java.util.Set, java.util.List, java.util.List, net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition, net.corda.core.node.services.vault.QueryCriteria$TimeCondition, net.corda.core.node.services.Vault$RelevancyStatus, java.util.Set, java.util.Set, java.util.List, java.util.List, java.util.List) public boolean equals(Object) @NotNull - public java.util.Set getConstraintTypes() + public java.util.Set getConstraintTypes() @NotNull - public java.util.Set getConstraints() + public java.util.Set getConstraints() @Nullable - public java.util.Set> getContractStateTypes() + public java.util.Set getContractStateTypes() @Nullable - public java.util.List getExactParticipants() + public java.util.List getExactParticipants() @NotNull - public java.util.List getExternalIds() + public java.util.List getExternalIds() @Nullable - public final java.util.List getNotary() + public final java.util.List getNotary() @Nullable - public java.util.List getParticipants() + public java.util.List getParticipants() @NotNull public net.corda.core.node.services.Vault$RelevancyStatus getRelevancyStatus() @Nullable public final net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition getSoftLockingCondition() @Nullable - public final java.util.List getStateRefs() + public final java.util.List getStateRefs() @NotNull public net.corda.core.node.services.Vault$StateStatus getStatus() @Nullable @@ -5863,42 +6593,42 @@ public static final class net.corda.core.node.services.vault.QueryCriteria$Vault @NotNull public String toString() @NotNull - public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) + public java.util.Collection visit(net.corda.core.node.services.vault.IQueryCriteriaParser) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withConstraintTypes(java.util.Set) + public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withConstraintTypes(java.util.Set) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withConstraints(java.util.Set) + public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withConstraints(java.util.Set) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withContractStateTypes(java.util.Set>) + public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withContractStateTypes(java.util.Set) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withExactParticipants(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withExactParticipants(java.util.List) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withExternalIds(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withExternalIds(java.util.List) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withNotary(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withNotary(java.util.List) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withParticipants(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withParticipants(java.util.List) @NotNull public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withRelevancyStatus(net.corda.core.node.services.Vault$RelevancyStatus) @NotNull public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withSoftLockingCondition(net.corda.core.node.services.vault.QueryCriteria$SoftLockingCondition) @NotNull - public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withStateRefs(java.util.List) + public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withStateRefs(java.util.List) @NotNull public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withStatus(net.corda.core.node.services.Vault$StateStatus) @NotNull public final net.corda.core.node.services.vault.QueryCriteria$VaultQueryCriteria withTimeCondition(net.corda.core.node.services.vault.QueryCriteria$TimeCondition) ## public final class net.corda.core.node.services.vault.QueryCriteriaUtils extends java.lang.Object - public static final A builder(kotlin.jvm.functions.Function1) + public static final A builder(kotlin.jvm.functions.Function1) @NotNull - public static final String getColumnName(net.corda.core.node.services.vault.Column) + public static final String getColumnName(net.corda.core.node.services.vault.Column) @NotNull - public static final net.corda.core.node.services.vault.FieldInfo getField(String, Class) + public static final net.corda.core.node.services.vault.FieldInfo getField(String, Class) @NotNull - public static final Class resolveEnclosingObjectFromColumn(net.corda.core.node.services.vault.Column) + public static final Class resolveEnclosingObjectFromColumn(net.corda.core.node.services.vault.Column) @NotNull - public static final Class resolveEnclosingObjectFromExpression(net.corda.core.node.services.vault.CriteriaExpression) + public static final Class resolveEnclosingObjectFromExpression(net.corda.core.node.services.vault.CriteriaExpression) public static final int DEFAULT_PAGE_NUM = 1 public static final int DEFAULT_PAGE_SIZE = 200 public static final int MAX_PAGE_SIZE = 2147483646 @@ -5910,14 +6640,14 @@ public interface net.corda.core.node.services.vault.SessionScope ## @CordaSerializable public final class net.corda.core.node.services.vault.Sort extends net.corda.core.node.services.vault.BaseSort - public (java.util.Collection) + public (java.util.Collection) @NotNull - public final java.util.Collection component1() + public final java.util.Collection component1() @NotNull - public final net.corda.core.node.services.vault.Sort copy(java.util.Collection) + public final net.corda.core.node.services.vault.Sort copy(java.util.Collection) public boolean equals(Object) @NotNull - public final java.util.Collection getColumns() + public final java.util.Collection getColumns() public int hashCode() @NotNull public String toString() @@ -5933,29 +6663,37 @@ public static final class net.corda.core.node.services.vault.Sort$CommonStateAtt public final String getAttributeChild() @NotNull public final String getAttributeParent() + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.Sort$CommonStateAttribute valueOf(String) - public static net.corda.core.node.services.vault.Sort$CommonStateAttribute[] values() + public static net.corda.core.node.services.vault.Sort.CommonStateAttribute[] values() ## @CordaSerializable public static final class net.corda.core.node.services.vault.Sort$Direction extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.Sort$Direction valueOf(String) - public static net.corda.core.node.services.vault.Sort$Direction[] values() + public static net.corda.core.node.services.vault.Sort.Direction[] values() ## @DoNotImplement @CordaSerializable public static final class net.corda.core.node.services.vault.Sort$FungibleStateAttribute extends java.lang.Enum implements net.corda.core.node.services.vault.Sort$Attribute @NotNull public final String getAttributeName() + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.Sort$FungibleStateAttribute valueOf(String) - public static net.corda.core.node.services.vault.Sort$FungibleStateAttribute[] values() + public static net.corda.core.node.services.vault.Sort.FungibleStateAttribute[] values() ## @DoNotImplement @CordaSerializable public static final class net.corda.core.node.services.vault.Sort$LinearStateAttribute extends java.lang.Enum implements net.corda.core.node.services.vault.Sort$Attribute @NotNull public final String getAttributeName() + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.Sort$LinearStateAttribute valueOf(String) - public static net.corda.core.node.services.vault.Sort$LinearStateAttribute[] values() + public static net.corda.core.node.services.vault.Sort.LinearStateAttribute[] values() ## @CordaSerializable public static final class net.corda.core.node.services.vault.Sort$SortColumn extends java.lang.Object @@ -5981,8 +6719,10 @@ public static final class net.corda.core.node.services.vault.Sort$SortColumn ext public static final class net.corda.core.node.services.vault.Sort$VaultStateAttribute extends java.lang.Enum implements net.corda.core.node.services.vault.Sort$Attribute @NotNull public final String getAttributeName() + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.node.services.vault.Sort$VaultStateAttribute valueOf(String) - public static net.corda.core.node.services.vault.Sort$VaultStateAttribute[] values() + public static net.corda.core.node.services.vault.Sort.VaultStateAttribute[] values() ## @CordaSerializable public abstract class net.corda.core.node.services.vault.SortAttribute extends java.lang.Object @@ -5990,16 +6730,16 @@ public abstract class net.corda.core.node.services.vault.SortAttribute extends j ## @CordaSerializable public static final class net.corda.core.node.services.vault.SortAttribute$Custom extends net.corda.core.node.services.vault.SortAttribute - public (Class, String) + public (Class, String) @NotNull - public final Class component1() + public final Class component1() @NotNull public final String component2() @NotNull - public final net.corda.core.node.services.vault.SortAttribute$Custom copy(Class, String) + public final net.corda.core.node.services.vault.SortAttribute$Custom copy(Class, String) public boolean equals(Object) @NotNull - public final Class getEntityStateClass() + public final Class getEntityStateClass() @NotNull public final String getEntityStateColumnName() public int hashCode() @@ -6022,21 +6762,23 @@ public static final class net.corda.core.node.services.vault.SortAttribute$Stand ## public final class net.corda.core.observable.Observables extends java.lang.Object @NotNull - public static final rx.Observable continueOnError(rx.Observable) + public static final rx.Observable continueOnError(rx.Observable) ## public final class net.corda.core.schemas.CommonSchema extends java.lang.Object + @NotNull public static final net.corda.core.schemas.CommonSchema INSTANCE ## public final class net.corda.core.schemas.CommonSchemaV1 extends net.corda.core.schemas.MappedSchema @NotNull public String getMigrationResource() + @NotNull public static final net.corda.core.schemas.CommonSchemaV1 INSTANCE ## @MappedSuperclass @CordaSerializable public static class net.corda.core.schemas.CommonSchemaV1$FungibleState extends net.corda.core.schemas.PersistentState public () - public (java.util.Set, net.corda.core.identity.AbstractParty, long, net.corda.core.identity.AbstractParty, byte[]) + public (java.util.Set, net.corda.core.identity.AbstractParty, long, net.corda.core.identity.AbstractParty, byte[]) public (java.util.Set, net.corda.core.identity.AbstractParty, long, net.corda.core.identity.AbstractParty, byte[], int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull public net.corda.core.identity.AbstractParty getIssuer() @@ -6045,29 +6787,29 @@ public static class net.corda.core.schemas.CommonSchemaV1$FungibleState extends @NotNull public net.corda.core.identity.AbstractParty getOwner() @Nullable - public java.util.Set getParticipants() + public java.util.Set getParticipants() public long getQuantity() public void setIssuer(net.corda.core.identity.AbstractParty) public void setIssuerRef(byte[]) public void setOwner(net.corda.core.identity.AbstractParty) - public void setParticipants(java.util.Set) + public void setParticipants(java.util.Set) public void setQuantity(long) ## @MappedSuperclass @CordaSerializable public static class net.corda.core.schemas.CommonSchemaV1$LinearState extends net.corda.core.schemas.PersistentState public () - public (java.util.Set, String, java.util.UUID) + public (java.util.Set, String, java.util.UUID) public (java.util.Set, String, java.util.UUID, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.contracts.UniqueIdentifier, java.util.Set) + public (net.corda.core.contracts.UniqueIdentifier, java.util.Set) @Nullable public String getExternalId() @Nullable - public java.util.Set getParticipants() + public java.util.Set getParticipants() @NotNull public java.util.UUID getUuid() public void setExternalId(String) - public void setParticipants(java.util.Set) + public void setParticipants(java.util.Set) public void setUuid(java.util.UUID) ## public interface net.corda.core.schemas.DirectStatePersistable extends net.corda.core.schemas.StatePersistable @@ -6079,10 +6821,10 @@ public interface net.corda.core.schemas.IndirectStatePersistable extends net.cor public abstract T getCompositeKey() ## public class net.corda.core.schemas.MappedSchema extends java.lang.Object - public (Class, int, Iterable>) + public (Class, int, Iterable) public boolean equals(Object) @NotNull - public final Iterable> getMappedTypes() + public final Iterable getMappedTypes() @Nullable public String getMigrationResource() @NotNull @@ -6094,11 +6836,12 @@ public class net.corda.core.schemas.MappedSchema extends java.lang.Object ## public final class net.corda.core.schemas.MappedSchemaValidator extends java.lang.Object @NotNull - public final java.util.List crossReferencesToOtherMappedSchema(net.corda.core.schemas.MappedSchema) + public final java.util.List crossReferencesToOtherMappedSchema(net.corda.core.schemas.MappedSchema) @NotNull - public final java.util.List fieldsFromOtherMappedSchema(net.corda.core.schemas.MappedSchema) + public final java.util.List fieldsFromOtherMappedSchema(net.corda.core.schemas.MappedSchema) + @NotNull + public final java.util.List methodsFromOtherMappedSchema(net.corda.core.schemas.MappedSchema) @NotNull - public final java.util.List methodsFromOtherMappedSchema(net.corda.core.schemas.MappedSchema) public static final net.corda.core.schemas.MappedSchemaValidator INSTANCE ## public static final class net.corda.core.schemas.MappedSchemaValidator$SchemaCrossReferenceReport extends java.lang.Object @@ -6144,7 +6887,7 @@ public interface net.corda.core.schemas.QueryableState extends net.corda.core.co @NotNull public abstract net.corda.core.schemas.PersistentState generateMappedObject(net.corda.core.schemas.MappedSchema) @NotNull - public abstract Iterable supportedSchemas() + public abstract Iterable supportedSchemas() ## public interface net.corda.core.schemas.StatePersistable ## @@ -6153,11 +6896,13 @@ public interface net.corda.core.serialization.CheckpointCustomSerializer public abstract PROXY toProxy(OBJ) ## public interface net.corda.core.serialization.ClassWhitelist - public abstract boolean hasListed(Class) + public abstract boolean hasListed(Class) ## public @interface net.corda.core.serialization.ConstructorForDeserialization ## public final class net.corda.core.serialization.ContextPropertyKeys extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.serialization.ContextPropertyKeys valueOf(String) public static net.corda.core.serialization.ContextPropertyKeys[] values() ## @@ -6179,7 +6924,7 @@ public @interface net.corda.core.serialization.CordaSerializationTransformRename ## public interface net.corda.core.serialization.CustomSerializationScheme @NotNull - public abstract T deserialize(net.corda.core.utilities.ByteSequence, Class, net.corda.core.serialization.SerializationSchemeContext) + public abstract T deserialize(net.corda.core.utilities.ByteSequence, Class, net.corda.core.serialization.SerializationSchemeContext) public abstract int getSchemeId() @NotNull public abstract net.corda.core.utilities.ByteSequence serialize(T, net.corda.core.serialization.SerializationSchemeContext) @@ -6193,18 +6938,18 @@ public interface net.corda.core.serialization.EncodingWhitelist ## @CordaSerializable public final class net.corda.core.serialization.MissingAttachmentsException extends net.corda.core.CordaException - public (java.util.List) - public (java.util.List, String) + public (java.util.List) + public (java.util.List, String) @NotNull - public final java.util.List getIds() + public final java.util.List getIds() ## @CordaSerializable public final class net.corda.core.serialization.MissingAttachmentsRuntimeException extends net.corda.core.CordaRuntimeException - public (java.util.List) - public (java.util.List, String) - public (java.util.List, String, Throwable) + public (java.util.List) + public (java.util.List, String) + public (java.util.List, String, Throwable) @NotNull - public final java.util.List getIds() + public final java.util.List getIds() ## public final class net.corda.core.serialization.ObjectWithCompatibleContext extends java.lang.Object public (T, net.corda.core.serialization.SerializationContext) @@ -6213,7 +6958,7 @@ public final class net.corda.core.serialization.ObjectWithCompatibleContext exte @NotNull public final net.corda.core.serialization.SerializationContext component2() @NotNull - public final net.corda.core.serialization.ObjectWithCompatibleContext copy(T, net.corda.core.serialization.SerializationContext) + public final net.corda.core.serialization.ObjectWithCompatibleContext copy(T, net.corda.core.serialization.SerializationContext) public boolean equals(Object) @NotNull public final net.corda.core.serialization.SerializationContext getContext() @@ -6226,10 +6971,15 @@ public final class net.corda.core.serialization.ObjectWithCompatibleContext exte public @interface net.corda.core.serialization.SerializableCalculatedProperty ## public final class net.corda.core.serialization.SerializationAPIKt extends java.lang.Object + public static final T deserialize(java.sql.Blob, net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext) + public static final T deserialize(net.corda.core.serialization.SerializedBytes, net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext) + public static final T deserialize(net.corda.core.utilities.ByteSequence, net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext) + public static final T deserialize(byte[], net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext) + public static final net.corda.core.serialization.ObjectWithCompatibleContext deserializeWithCompatibleContext(net.corda.core.utilities.ByteSequence, net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext) @NotNull - public static final net.corda.core.serialization.SerializedBytes serialize(T, net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext) + public static final net.corda.core.serialization.SerializedBytes serialize(T, net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext) @NotNull - public static final net.corda.core.serialization.SerializationContext withWhitelist(net.corda.core.serialization.SerializationContext, java.util.List>) + public static final net.corda.core.serialization.SerializationContext withWhitelist(net.corda.core.serialization.SerializationContext, java.util.List) public static final int AMQP_ENVELOPE_CACHE_INITIAL_CAPACITY = 256 @NotNull public static final String AMQP_ENVELOPE_CACHE_PROPERTY = "AMQP_ENVELOPE_CACHE" @@ -6240,7 +6990,7 @@ public final class net.corda.core.serialization.SerializationAPIKt extends java. public interface net.corda.core.serialization.SerializationContext public abstract boolean getCarpenterDisabled() @NotNull - public abstract java.util.Set> getCustomSerializers() + public abstract java.util.Set getCustomSerializers() @NotNull public abstract ClassLoader getDeserializationClassLoader() @Nullable @@ -6253,17 +7003,17 @@ public interface net.corda.core.serialization.SerializationContext public abstract net.corda.core.utilities.ByteSequence getPreferredSerializationVersion() public abstract boolean getPreventDataLoss() @NotNull - public abstract java.util.Map getProperties() + public abstract java.util.Map getProperties() @NotNull public abstract net.corda.core.serialization.SerializationContext$UseCase getUseCase() @NotNull public abstract net.corda.core.serialization.ClassWhitelist getWhitelist() @NotNull - public abstract net.corda.core.serialization.SerializationContext withAttachmentsClassLoader(java.util.List) + public abstract net.corda.core.serialization.SerializationContext withAttachmentsClassLoader(java.util.List) @NotNull public abstract net.corda.core.serialization.SerializationContext withClassLoader(ClassLoader) @NotNull - public abstract net.corda.core.serialization.SerializationContext withCustomSerializers(java.util.Set>) + public abstract net.corda.core.serialization.SerializationContext withCustomSerializers(java.util.Set) @NotNull public abstract net.corda.core.serialization.SerializationContext withEncoding(net.corda.core.serialization.SerializationEncoding) @NotNull @@ -6275,19 +7025,21 @@ public interface net.corda.core.serialization.SerializationContext @NotNull public abstract net.corda.core.serialization.SerializationContext withPreventDataLoss() @NotNull - public abstract net.corda.core.serialization.SerializationContext withProperties(java.util.Map) + public abstract net.corda.core.serialization.SerializationContext withProperties(java.util.Map) @NotNull public abstract net.corda.core.serialization.SerializationContext withProperty(Object, Object) @NotNull - public abstract net.corda.core.serialization.SerializationContext withWhitelisted(Class) + public abstract net.corda.core.serialization.SerializationContext withWhitelisted(Class) @NotNull public abstract net.corda.core.serialization.SerializationContext withoutCarpenter() @NotNull public abstract net.corda.core.serialization.SerializationContext withoutReferences() ## public static final class net.corda.core.serialization.SerializationContext$UseCase extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.serialization.SerializationContext$UseCase valueOf(String) - public static net.corda.core.serialization.SerializationContext$UseCase[] values() + public static net.corda.core.serialization.SerializationContext.UseCase[] values() ## public interface net.corda.core.serialization.SerializationCustomSerializer public abstract OBJ fromProxy(PROXY) @@ -6304,6 +7056,7 @@ public final class net.corda.core.serialization.SerializationDefaults extends ja public final net.corda.core.serialization.SerializationFactory getSERIALIZATION_FACTORY() @NotNull public final net.corda.core.serialization.SerializationContext getSTORAGE_CONTEXT() + @NotNull public static final net.corda.core.serialization.SerializationDefaults INSTANCE ## @DoNotImplement @@ -6311,18 +7064,19 @@ public interface net.corda.core.serialization.SerializationEncoding ## public abstract class net.corda.core.serialization.SerializationFactory extends java.lang.Object public () - public final T asCurrent(kotlin.jvm.functions.Function1) + public final T asCurrent(kotlin.jvm.functions.Function1) @NotNull - public abstract T deserialize(net.corda.core.utilities.ByteSequence, Class, net.corda.core.serialization.SerializationContext) + public abstract T deserialize(net.corda.core.utilities.ByteSequence, Class, net.corda.core.serialization.SerializationContext) @NotNull - public abstract net.corda.core.serialization.ObjectWithCompatibleContext deserializeWithCompatibleContext(net.corda.core.utilities.ByteSequence, Class, net.corda.core.serialization.SerializationContext) + public abstract net.corda.core.serialization.ObjectWithCompatibleContext deserializeWithCompatibleContext(net.corda.core.utilities.ByteSequence, Class, net.corda.core.serialization.SerializationContext) @Nullable public final net.corda.core.serialization.SerializationContext getCurrentContext() @NotNull public final net.corda.core.serialization.SerializationContext getDefaultContext() @NotNull - public abstract net.corda.core.serialization.SerializedBytes serialize(T, net.corda.core.serialization.SerializationContext) - public final T withCurrentContext(net.corda.core.serialization.SerializationContext, kotlin.jvm.functions.Function0) + public abstract net.corda.core.serialization.SerializedBytes serialize(T, net.corda.core.serialization.SerializationContext) + public final T withCurrentContext(net.corda.core.serialization.SerializationContext, kotlin.jvm.functions.Function0) + @NotNull public static final net.corda.core.serialization.SerializationFactory$Companion Companion ## public static final class net.corda.core.serialization.SerializationFactory$Companion extends java.lang.Object @@ -6337,7 +7091,7 @@ public interface net.corda.core.serialization.SerializationSchemeContext @NotNull public abstract ClassLoader getDeserializationClassLoader() @NotNull - public abstract java.util.Map getProperties() + public abstract java.util.Map getProperties() @NotNull public abstract net.corda.core.serialization.ClassWhitelist getWhitelist() ## @@ -6347,7 +7101,7 @@ public interface net.corda.core.serialization.SerializationToken ## public interface net.corda.core.serialization.SerializationWhitelist @NotNull - public abstract java.util.List> getWhitelist() + public abstract java.util.List getWhitelist() ## @CordaSerializable public interface net.corda.core.serialization.SerializeAsToken @@ -6365,23 +7119,24 @@ public interface net.corda.core.serialization.SerializeAsTokenContext public final class net.corda.core.serialization.SerializedBytes extends net.corda.core.utilities.OpaqueBytes public (byte[]) @NotNull - public static final net.corda.core.serialization.SerializedBytes from(T) + public static final net.corda.core.serialization.SerializedBytes from(T) @NotNull - public static final net.corda.core.serialization.SerializedBytes from(T, net.corda.core.serialization.SerializationFactory) + public static final net.corda.core.serialization.SerializedBytes from(T, net.corda.core.serialization.SerializationFactory) @NotNull - public static final net.corda.core.serialization.SerializedBytes from(T, net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext) + public static final net.corda.core.serialization.SerializedBytes from(T, net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext) @NotNull public final net.corda.core.crypto.SecureHash getHash() + @NotNull public static final net.corda.core.serialization.SerializedBytes$Companion Companion ## public static final class net.corda.core.serialization.SerializedBytes$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.serialization.SerializedBytes from(T) + public final net.corda.core.serialization.SerializedBytes from(T) @NotNull - public final net.corda.core.serialization.SerializedBytes from(T, net.corda.core.serialization.SerializationFactory) + public final net.corda.core.serialization.SerializedBytes from(T, net.corda.core.serialization.SerializationFactory) @NotNull - public final net.corda.core.serialization.SerializedBytes from(T, net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext) + public final net.corda.core.serialization.SerializedBytes from(T, net.corda.core.serialization.SerializationFactory, net.corda.core.serialization.SerializationContext) ## public final class net.corda.core.serialization.SingletonSerializationToken extends java.lang.Object implements net.corda.core.serialization.SerializationToken public (String, kotlin.jvm.internal.DefaultConstructorMarker) @@ -6389,12 +7144,13 @@ public final class net.corda.core.serialization.SingletonSerializationToken exte public net.corda.core.serialization.SerializeAsToken fromToken(net.corda.core.serialization.SerializeAsTokenContext) @NotNull public final net.corda.core.serialization.SingletonSerializationToken registerWithContext(net.corda.core.serialization.SerializeAsTokenContext, net.corda.core.serialization.SerializeAsToken) + @NotNull public static final net.corda.core.serialization.SingletonSerializationToken$Companion Companion ## public static final class net.corda.core.serialization.SingletonSerializationToken$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.serialization.SingletonSerializationToken singletonSerializationToken(Class) + public final net.corda.core.serialization.SingletonSerializationToken singletonSerializationToken(Class) ## @CordaSerializable public abstract class net.corda.core.serialization.SingletonSerializeAsToken extends java.lang.Object implements net.corda.core.serialization.SerializeAsToken @@ -6407,41 +7163,47 @@ public abstract class net.corda.core.transactions.BaseTransaction extends java.l public () protected void checkBaseInvariants() @NotNull - public final java.util.List> filterOutRefs(Class, java.util.function.Predicate) + public final java.util.List filterOutRefs(Class, java.util.function.Predicate) + public final java.util.List filterOutRefs(kotlin.jvm.functions.Function1) @NotNull - public final java.util.List filterOutputs(Class, java.util.function.Predicate) + public final java.util.List filterOutputs(Class, java.util.function.Predicate) + public final java.util.List filterOutputs(kotlin.jvm.functions.Function1) @NotNull - public final net.corda.core.contracts.StateAndRef findOutRef(Class, java.util.function.Predicate) + public final net.corda.core.contracts.StateAndRef findOutRef(Class, java.util.function.Predicate) + public final net.corda.core.contracts.StateAndRef findOutRef(kotlin.jvm.functions.Function1) @NotNull - public final T findOutput(Class, java.util.function.Predicate) + public final T findOutput(Class, java.util.function.Predicate) + public final T findOutput(kotlin.jvm.functions.Function1) @NotNull - public abstract java.util.List getInputs() + public abstract java.util.List getInputs() @Nullable public abstract net.corda.core.identity.Party getNotary() @NotNull public final net.corda.core.contracts.ContractState getOutput(int) @NotNull - public final java.util.List getOutputStates() + public final java.util.List getOutputStates() @NotNull - public abstract java.util.List> getOutputs() + public abstract java.util.List getOutputs() @NotNull - public abstract java.util.List getReferences() + public abstract java.util.List getReferences() @NotNull - public final net.corda.core.contracts.StateAndRef outRef(int) + public final net.corda.core.contracts.StateAndRef outRef(int) @NotNull - public final net.corda.core.contracts.StateAndRef outRef(net.corda.core.contracts.ContractState) + public final net.corda.core.contracts.StateAndRef outRef(net.corda.core.contracts.ContractState) + public final java.util.List outRefsOfType() @NotNull - public final java.util.List> outRefsOfType(Class) + public final java.util.List outRefsOfType(Class) + public final java.util.List outputsOfType() @NotNull - public final java.util.List outputsOfType(Class) + public final java.util.List outputsOfType(Class) @NotNull public String toString() ## @CordaSerializable public class net.corda.core.transactions.ComponentGroup extends java.lang.Object - public (int, java.util.List) + public (int, java.util.List) @NotNull - public java.util.List getComponents() + public java.util.List getComponents() public int getGroupIndex() ## @CordaSerializable @@ -6456,37 +7218,37 @@ public final class net.corda.core.transactions.ComponentVisibilityException exte @CordaSerializable public final class net.corda.core.transactions.ContractUpgradeFilteredTransaction extends net.corda.core.transactions.CoreTransaction @DeprecatedConstructorForDeserialization - public (java.util.Map, java.util.Map) - public (java.util.Map, java.util.Map, net.corda.core.crypto.DigestService) + public (java.util.Map, java.util.Map) + public (java.util.Map, java.util.Map, net.corda.core.crypto.DigestService) @NotNull - public final java.util.Map component1() + public final java.util.Map component1() @NotNull - public final java.util.Map component2() + public final java.util.Map component2() @NotNull public final net.corda.core.crypto.DigestService component3() @NotNull - public final net.corda.core.transactions.ContractUpgradeFilteredTransaction copy(java.util.Map, java.util.Map) + public final net.corda.core.transactions.ContractUpgradeFilteredTransaction copy(java.util.Map, java.util.Map) @NotNull - public final net.corda.core.transactions.ContractUpgradeFilteredTransaction copy(java.util.Map, java.util.Map, net.corda.core.crypto.DigestService) + public final net.corda.core.transactions.ContractUpgradeFilteredTransaction copy(java.util.Map, java.util.Map, net.corda.core.crypto.DigestService) public boolean equals(Object) @NotNull public final net.corda.core.crypto.DigestService getDigestService() @NotNull - public final java.util.Map getHiddenComponents() + public final java.util.Map getHiddenComponents() @NotNull public net.corda.core.crypto.SecureHash getId() @NotNull - public java.util.List getInputs() + public java.util.List getInputs() @Nullable public net.corda.core.crypto.SecureHash getNetworkParametersHash() @NotNull public net.corda.core.identity.Party getNotary() @NotNull - public java.util.List> getOutputs() + public java.util.List getOutputs() @NotNull - public java.util.List getReferences() + public java.util.List getReferences() @NotNull - public final java.util.Map getVisibleComponents() + public final java.util.Map getVisibleComponents() public int hashCode() @NotNull public String toString() @@ -6501,10 +7263,10 @@ public static final class net.corda.core.transactions.ContractUpgradeFilteredTra ## @DoNotImplement public final class net.corda.core.transactions.ContractUpgradeLedgerTransaction extends net.corda.core.transactions.FullTransaction implements net.corda.core.transactions.TransactionWithSignatures - public (java.util.List>, net.corda.core.identity.Party, net.corda.core.contracts.Attachment, String, net.corda.core.contracts.Attachment, net.corda.core.crypto.SecureHash, net.corda.core.contracts.PrivacySalt, java.util.List, net.corda.core.node.NetworkParameters) + public (java.util.List, net.corda.core.identity.Party, net.corda.core.contracts.Attachment, String, net.corda.core.contracts.Attachment, net.corda.core.crypto.SecureHash, net.corda.core.contracts.PrivacySalt, java.util.List, net.corda.core.node.NetworkParameters) public (java.util.List, net.corda.core.identity.Party, net.corda.core.contracts.Attachment, net.corda.core.contracts.Attachment, net.corda.core.crypto.SecureHash, net.corda.core.contracts.PrivacySalt, java.util.List, net.corda.core.node.NetworkParameters, net.corda.core.contracts.UpgradedContract, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final java.util.List> component1() + public final java.util.List component1() @NotNull public final net.corda.core.identity.Party component2() @NotNull @@ -6518,18 +7280,18 @@ public final class net.corda.core.transactions.ContractUpgradeLedgerTransaction @NotNull public final net.corda.core.contracts.PrivacySalt component7() @NotNull - public final java.util.List component8() + public final java.util.List component8() @NotNull public final net.corda.core.node.NetworkParameters component9() @NotNull - public final net.corda.core.transactions.ContractUpgradeLedgerTransaction copy(java.util.List>, net.corda.core.identity.Party, net.corda.core.contracts.Attachment, String, net.corda.core.contracts.Attachment, net.corda.core.crypto.SecureHash, net.corda.core.contracts.PrivacySalt, java.util.List, net.corda.core.node.NetworkParameters) + public final net.corda.core.transactions.ContractUpgradeLedgerTransaction copy(java.util.List, net.corda.core.identity.Party, net.corda.core.contracts.Attachment, String, net.corda.core.contracts.Attachment, net.corda.core.crypto.SecureHash, net.corda.core.contracts.PrivacySalt, java.util.List, net.corda.core.node.NetworkParameters) public boolean equals(Object) @NotNull public net.corda.core.crypto.SecureHash getId() @NotNull - public java.util.List> getInputs() + public java.util.List getInputs() @NotNull - public java.util.List getKeyDescriptions(java.util.Set) + public java.util.List getKeyDescriptions(java.util.Set) @NotNull public final net.corda.core.contracts.Attachment getLegacyContractAttachment() @NotNull @@ -6537,15 +7299,15 @@ public final class net.corda.core.transactions.ContractUpgradeLedgerTransaction @NotNull public net.corda.core.identity.Party getNotary() @NotNull - public java.util.List> getOutputs() + public java.util.List getOutputs() @NotNull public final net.corda.core.contracts.PrivacySalt getPrivacySalt() @NotNull - public java.util.List> getReferences() + public java.util.List getReferences() @NotNull - public java.util.Set getRequiredSigningKeys() + public java.util.Set getRequiredSigningKeys() @NotNull - public java.util.List getSigs() + public java.util.List getSigs() @NotNull public final net.corda.core.contracts.Attachment getUpgradedContractAttachment() @NotNull @@ -6553,6 +7315,7 @@ public final class net.corda.core.transactions.ContractUpgradeLedgerTransaction public int hashCode() @NotNull public String toString() + @NotNull public static final net.corda.core.transactions.ContractUpgradeLedgerTransaction$Companion Companion ## public static final class net.corda.core.transactions.ContractUpgradeLedgerTransaction$Companion extends java.lang.Object @@ -6562,29 +7325,28 @@ public static final class net.corda.core.transactions.ContractUpgradeLedgerTrans @CordaSerializable public final class net.corda.core.transactions.ContractUpgradeWireTransaction extends net.corda.core.transactions.CoreTransaction @DeprecatedConstructorForDeserialization - public (java.util.List, net.corda.core.contracts.PrivacySalt) - @DeprecatedConstructorForDeserialization + public (java.util.List, net.corda.core.contracts.PrivacySalt) public (java.util.List, net.corda.core.contracts.PrivacySalt, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (java.util.List, net.corda.core.contracts.PrivacySalt, net.corda.core.crypto.DigestService) + public (java.util.List, net.corda.core.contracts.PrivacySalt, net.corda.core.crypto.DigestService) @NotNull public final net.corda.core.transactions.ContractUpgradeFilteredTransaction buildFilteredTransaction() @NotNull - public final java.util.List component1() + public final java.util.List component1() @NotNull public final net.corda.core.contracts.PrivacySalt component2() @NotNull public final net.corda.core.crypto.DigestService component3() @NotNull - public final net.corda.core.transactions.ContractUpgradeWireTransaction copy(java.util.List, net.corda.core.contracts.PrivacySalt) + public final net.corda.core.transactions.ContractUpgradeWireTransaction copy(java.util.List, net.corda.core.contracts.PrivacySalt) @NotNull - public final net.corda.core.transactions.ContractUpgradeWireTransaction copy(java.util.List, net.corda.core.contracts.PrivacySalt, net.corda.core.crypto.DigestService) + public final net.corda.core.transactions.ContractUpgradeWireTransaction copy(java.util.List, net.corda.core.contracts.PrivacySalt, net.corda.core.crypto.DigestService) public boolean equals(Object) @NotNull public final net.corda.core.crypto.DigestService getDigestService() @NotNull public net.corda.core.crypto.SecureHash getId() @NotNull - public java.util.List getInputs() + public java.util.List getInputs() @NotNull public final net.corda.core.crypto.SecureHash getLegacyContractAttachmentId() @Nullable @@ -6592,60 +7354,63 @@ public final class net.corda.core.transactions.ContractUpgradeWireTransaction ex @NotNull public net.corda.core.identity.Party getNotary() @NotNull - public java.util.List> getOutputs() + public java.util.List getOutputs() @NotNull public final net.corda.core.contracts.PrivacySalt getPrivacySalt() @NotNull - public java.util.List getReferences() + public java.util.List getReferences() @NotNull - public final java.util.List getSerializedComponents() + public final java.util.List getSerializedComponents() @NotNull public final net.corda.core.crypto.SecureHash getUpgradedContractAttachmentId() @NotNull public final String getUpgradedContractClassName() public int hashCode() @NotNull - public final net.corda.core.transactions.ContractUpgradeLedgerTransaction resolve(net.corda.core.node.ServicesForResolution, java.util.List) + public final net.corda.core.transactions.ContractUpgradeLedgerTransaction resolve(net.corda.core.node.ServicesForResolution, java.util.List) @NotNull public String toString() + @NotNull public static final net.corda.core.transactions.ContractUpgradeWireTransaction$Companion Companion ## public static final class net.corda.core.transactions.ContractUpgradeWireTransaction$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) ## public static final class net.corda.core.transactions.ContractUpgradeWireTransaction$Component extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.transactions.ContractUpgradeWireTransaction$Component valueOf(String) - public static net.corda.core.transactions.ContractUpgradeWireTransaction$Component[] values() + public static net.corda.core.transactions.ContractUpgradeWireTransaction.Component[] values() ## @DoNotImplement @CordaSerializable public abstract class net.corda.core.transactions.CoreTransaction extends net.corda.core.transactions.BaseTransaction public () @NotNull - public abstract java.util.List getInputs() + public abstract java.util.List getInputs() @Nullable public abstract net.corda.core.crypto.SecureHash getNetworkParametersHash() @NotNull - public abstract java.util.List getReferences() + public abstract java.util.List getReferences() ## @CordaSerializable public final class net.corda.core.transactions.FilteredComponentGroup extends net.corda.core.transactions.ComponentGroup - public (int, java.util.List, java.util.List, net.corda.core.crypto.PartialMerkleTree) + public (int, java.util.List, java.util.List, net.corda.core.crypto.PartialMerkleTree) public final int component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() @NotNull - public final java.util.List component3() + public final java.util.List component3() @NotNull public final net.corda.core.crypto.PartialMerkleTree component4() @NotNull - public final net.corda.core.transactions.FilteredComponentGroup copy(int, java.util.List, java.util.List, net.corda.core.crypto.PartialMerkleTree) + public final net.corda.core.transactions.FilteredComponentGroup copy(int, java.util.List, java.util.List, net.corda.core.crypto.PartialMerkleTree) public boolean equals(Object) @NotNull - public java.util.List getComponents() + public java.util.List getComponents() public int getGroupIndex() @NotNull - public final java.util.List getNonces() + public final java.util.List getNonces() @NotNull public final net.corda.core.crypto.PartialMerkleTree getPartialMerkleTree() public int hashCode() @@ -6656,26 +7421,27 @@ public final class net.corda.core.transactions.FilteredComponentGroup extends ne @CordaSerializable public final class net.corda.core.transactions.FilteredTransaction extends net.corda.core.transactions.TraversableTransaction @DeprecatedConstructorForDeserialization - public (net.corda.core.crypto.SecureHash, java.util.List, java.util.List) - public (net.corda.core.crypto.SecureHash, java.util.List, java.util.List, net.corda.core.crypto.DigestService) + public (net.corda.core.crypto.SecureHash, java.util.List, java.util.List) + public (net.corda.core.crypto.SecureHash, java.util.List, java.util.List, net.corda.core.crypto.DigestService) @NotNull - public static final net.corda.core.transactions.FilteredTransaction buildFilteredTransaction(net.corda.core.transactions.WireTransaction, java.util.function.Predicate) + public static final net.corda.core.transactions.FilteredTransaction buildFilteredTransaction(net.corda.core.transactions.WireTransaction, java.util.function.Predicate) public final void checkAllComponentsVisible(net.corda.core.contracts.ComponentGroupEnum) public final void checkCommandVisibility(java.security.PublicKey) - public final boolean checkWithFun(kotlin.jvm.functions.Function1) + public final boolean checkWithFun(kotlin.jvm.functions.Function1) @NotNull - public final java.util.List getFilteredComponentGroups() + public final java.util.List getFilteredComponentGroups() @NotNull - public final java.util.List getGroupHashes() + public final java.util.List getGroupHashes() @NotNull public net.corda.core.crypto.SecureHash getId() public final void verify() + @NotNull public static final net.corda.core.transactions.FilteredTransaction$Companion Companion ## public static final class net.corda.core.transactions.FilteredTransaction$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.transactions.FilteredTransaction buildFilteredTransaction(net.corda.core.transactions.WireTransaction, java.util.function.Predicate) + public final net.corda.core.transactions.FilteredTransaction buildFilteredTransaction(net.corda.core.transactions.WireTransaction, java.util.function.Predicate) ## @CordaSerializable public final class net.corda.core.transactions.FilteredTransactionVerificationException extends net.corda.core.CordaException @@ -6691,29 +7457,30 @@ public abstract class net.corda.core.transactions.FullTransaction extends net.co protected void checkBaseInvariants() protected final void checkNotaryWhitelisted() @NotNull - public abstract java.util.List> getInputs() + public abstract java.util.List getInputs() @Nullable public abstract net.corda.core.node.NetworkParameters getNetworkParameters() @NotNull - public abstract java.util.List> getReferences() + public abstract java.util.List getReferences() ## @DoNotImplement public final class net.corda.core.transactions.LedgerTransaction extends net.corda.core.transactions.FullTransaction - public (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) - public (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) + public (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) + public (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) public (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) + public final java.util.List commandsOfType() @NotNull - public final java.util.List> commandsOfType(Class) + public final java.util.List commandsOfType(Class) @NotNull - public final java.util.List> component1() + public final java.util.List component1() @NotNull - public final java.util.List> component10() + public final java.util.List component10() @NotNull - public final java.util.List> component2() + public final java.util.List component2() @NotNull - public final java.util.List> component3() + public final java.util.List component3() @NotNull - public final java.util.List component4() + public final java.util.List component4() @NotNull public final net.corda.core.crypto.SecureHash component5() @Nullable @@ -6725,40 +7492,50 @@ public final class net.corda.core.transactions.LedgerTransaction extends net.cor @Nullable public final net.corda.core.node.NetworkParameters component9() @NotNull - public final net.corda.core.transactions.LedgerTransaction copy(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) + public final net.corda.core.transactions.LedgerTransaction copy(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) @NotNull - public final net.corda.core.transactions.LedgerTransaction copy(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) + public final net.corda.core.transactions.LedgerTransaction copy(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) public boolean equals(Object) @NotNull - public final java.util.List> filterCommands(Class, java.util.function.Predicate) + public final java.util.List filterCommands(Class, java.util.function.Predicate) + public final java.util.List filterCommands(kotlin.jvm.functions.Function1) @NotNull - public final java.util.List> filterInRefs(Class, java.util.function.Predicate) + public final java.util.List filterInRefs(Class, java.util.function.Predicate) + public final java.util.List filterInRefs(kotlin.jvm.functions.Function1) @NotNull - public final java.util.List filterInputs(Class, java.util.function.Predicate) + public final java.util.List filterInputs(Class, java.util.function.Predicate) + public final java.util.List filterInputs(kotlin.jvm.functions.Function1) @NotNull - public final java.util.List> filterReferenceInputRefs(Class, java.util.function.Predicate) + public final java.util.List filterReferenceInputRefs(Class, java.util.function.Predicate) + public final java.util.List filterReferenceInputRefs(kotlin.jvm.functions.Function1) @NotNull - public final java.util.List filterReferenceInputs(Class, java.util.function.Predicate) + public final java.util.List filterReferenceInputs(Class, java.util.function.Predicate) + public final java.util.List filterReferenceInputs(kotlin.jvm.functions.Function1) @NotNull - public final net.corda.core.contracts.Command findCommand(Class, java.util.function.Predicate) + public final net.corda.core.contracts.Command findCommand(Class, java.util.function.Predicate) + public final net.corda.core.contracts.Command findCommand(kotlin.jvm.functions.Function1) @NotNull - public final net.corda.core.contracts.StateAndRef findInRef(Class, java.util.function.Predicate) + public final net.corda.core.contracts.StateAndRef findInRef(Class, java.util.function.Predicate) + public final net.corda.core.contracts.StateAndRef findInRef(kotlin.jvm.functions.Function1) @NotNull - public final T findInput(Class, java.util.function.Predicate) + public final T findInput(Class, java.util.function.Predicate) + public final T findInput(kotlin.jvm.functions.Function1) @NotNull - public final T findReference(Class, java.util.function.Predicate) + public final T findReference(Class, java.util.function.Predicate) + public final T findReference(kotlin.jvm.functions.Function1) @NotNull - public final net.corda.core.contracts.StateAndRef findReferenceInputRef(Class, java.util.function.Predicate) + public final net.corda.core.contracts.StateAndRef findReferenceInputRef(Class, java.util.function.Predicate) + public final net.corda.core.contracts.StateAndRef findReferenceInputRef(kotlin.jvm.functions.Function1) @NotNull public final net.corda.core.contracts.Attachment getAttachment(int) @NotNull public final net.corda.core.contracts.Attachment getAttachment(net.corda.core.crypto.SecureHash) @NotNull - public final java.util.List getAttachments() + public final java.util.List getAttachments() @NotNull - public final net.corda.core.contracts.Command getCommand(int) + public final net.corda.core.contracts.Command getCommand(int) @NotNull - public final java.util.List> getCommands() + public final java.util.List getCommands() @NotNull public final net.corda.core.crypto.DigestService getDigestService() @NotNull @@ -6766,75 +7543,83 @@ public final class net.corda.core.transactions.LedgerTransaction extends net.cor @NotNull public final net.corda.core.contracts.ContractState getInput(int) @NotNull - public final java.util.List getInputStates() + public final java.util.List getInputStates() @NotNull - public java.util.List> getInputs() + public java.util.List getInputs() @Nullable public net.corda.core.node.NetworkParameters getNetworkParameters() @Nullable public net.corda.core.identity.Party getNotary() @NotNull - public java.util.List> getOutputs() + public java.util.List getOutputs() @NotNull public final net.corda.core.contracts.PrivacySalt getPrivacySalt() @NotNull public final net.corda.core.contracts.ContractState getReferenceInput(int) @NotNull - public final java.util.List getReferenceStates() + public final java.util.List getReferenceStates() @NotNull - public java.util.List> getReferences() + public java.util.List getReferences() @Nullable public final net.corda.core.contracts.TimeWindow getTimeWindow() @NotNull - public final java.util.List> groupStates(Class, kotlin.jvm.functions.Function1) + public final java.util.List groupStates(Class, kotlin.jvm.functions.Function1) + public final java.util.List groupStates(kotlin.jvm.functions.Function1) public int hashCode() @NotNull - public final net.corda.core.contracts.StateAndRef inRef(int) + public final net.corda.core.contracts.StateAndRef inRef(int) + public final java.util.List inRefsOfType() @NotNull - public final java.util.List> inRefsOfType(Class) + public final java.util.List inRefsOfType(Class) + public final java.util.List inputsOfType() @NotNull - public final java.util.List inputsOfType(Class) + public final java.util.List inputsOfType(Class) + public final java.util.List referenceInputRefsOfType() @NotNull - public final java.util.List> referenceInputRefsOfType(Class) + public final java.util.List referenceInputRefsOfType(Class) + public final java.util.List referenceInputsOfType() @NotNull - public final java.util.List referenceInputsOfType(Class) + public final java.util.List referenceInputsOfType(Class) @NotNull public String toString() public final void verify() + @NotNull public static final net.corda.core.transactions.LedgerTransaction$Companion Companion ## public static final class net.corda.core.transactions.LedgerTransaction$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) ## public static final class net.corda.core.transactions.LedgerTransaction$InOutGroup extends java.lang.Object - public (java.util.List, java.util.List, K) + public (java.util.List, java.util.List, K) @NotNull - public final java.util.List component1() + public final java.util.List component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() @NotNull public final K component3() @NotNull - public final net.corda.core.transactions.LedgerTransaction$InOutGroup copy(java.util.List, java.util.List, K) + public final net.corda.core.transactions.LedgerTransaction$InOutGroup copy(java.util.List, java.util.List, K) public boolean equals(Object) @NotNull public final K getGroupingKey() @NotNull - public final java.util.List getInputs() + public final java.util.List getInputs() @NotNull - public final java.util.List getOutputs() + public final java.util.List getOutputs() public int hashCode() @NotNull public String toString() ## +public final class net.corda.core.transactions.LedgerTransactionKt extends java.lang.Object +## @CordaSerializable public final class net.corda.core.transactions.MissingContractAttachments extends net.corda.core.flows.FlowException - public (java.util.List>) - public (java.util.List>, String) - public (java.util.List>, String, Integer) + public (java.util.List) + public (java.util.List, String) + public (java.util.List, String, Integer) public (java.util.List, String, Integer, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final java.util.List> getStates() + public final java.util.List getStates() ## @CordaSerializable public final class net.corda.core.transactions.NetworkParametersHash extends java.lang.Object @@ -6852,10 +7637,10 @@ public final class net.corda.core.transactions.NetworkParametersHash extends jav ## @DoNotImplement public final class net.corda.core.transactions.NotaryChangeLedgerTransaction extends net.corda.core.transactions.FullTransaction implements net.corda.core.transactions.TransactionWithSignatures - public (java.util.List>, net.corda.core.identity.Party, net.corda.core.identity.Party, net.corda.core.crypto.SecureHash, java.util.List) + public (java.util.List, net.corda.core.identity.Party, net.corda.core.identity.Party, net.corda.core.crypto.SecureHash, java.util.List) public (java.util.List, net.corda.core.identity.Party, net.corda.core.identity.Party, net.corda.core.crypto.SecureHash, java.util.List, net.corda.core.node.NetworkParameters, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final java.util.List> component1() + public final java.util.List component1() @NotNull public final net.corda.core.identity.Party component2() @NotNull @@ -6863,18 +7648,18 @@ public final class net.corda.core.transactions.NotaryChangeLedgerTransaction ext @NotNull public final net.corda.core.crypto.SecureHash component4() @NotNull - public final java.util.List component5() + public final java.util.List component5() @Nullable public final net.corda.core.node.NetworkParameters component6() @NotNull - public final net.corda.core.transactions.NotaryChangeLedgerTransaction copy(java.util.List>, net.corda.core.identity.Party, net.corda.core.identity.Party, net.corda.core.crypto.SecureHash, java.util.List) + public final net.corda.core.transactions.NotaryChangeLedgerTransaction copy(java.util.List, net.corda.core.identity.Party, net.corda.core.identity.Party, net.corda.core.crypto.SecureHash, java.util.List) public boolean equals(Object) @NotNull public net.corda.core.crypto.SecureHash getId() @NotNull - public java.util.List> getInputs() + public java.util.List getInputs() @NotNull - public java.util.List getKeyDescriptions(java.util.Set) + public java.util.List getKeyDescriptions(java.util.Set) @Nullable public net.corda.core.node.NetworkParameters getNetworkParameters() @NotNull @@ -6882,16 +7667,17 @@ public final class net.corda.core.transactions.NotaryChangeLedgerTransaction ext @NotNull public net.corda.core.identity.Party getNotary() @NotNull - public java.util.List> getOutputs() + public java.util.List getOutputs() @NotNull - public java.util.List> getReferences() + public java.util.List getReferences() @NotNull - public java.util.Set getRequiredSigningKeys() + public java.util.Set getRequiredSigningKeys() @NotNull - public java.util.List getSigs() + public java.util.List getSigs() public int hashCode() @NotNull public String toString() + @NotNull public static final net.corda.core.transactions.NotaryChangeLedgerTransaction$Companion Companion ## public static final class net.corda.core.transactions.NotaryChangeLedgerTransaction$Companion extends java.lang.Object @@ -6901,24 +7687,24 @@ public static final class net.corda.core.transactions.NotaryChangeLedgerTransact @CordaSerializable public final class net.corda.core.transactions.NotaryChangeWireTransaction extends net.corda.core.transactions.CoreTransaction @DeprecatedConstructorForDeserialization - public (java.util.List) - public (java.util.List, net.corda.core.crypto.DigestService) - public (java.util.List, net.corda.core.identity.Party, net.corda.core.identity.Party) + public (java.util.List) + public (java.util.List, net.corda.core.crypto.DigestService) + public (java.util.List, net.corda.core.identity.Party, net.corda.core.identity.Party) @NotNull - public final java.util.List component1() + public final java.util.List component1() @NotNull public final net.corda.core.crypto.DigestService component2() @NotNull - public final net.corda.core.transactions.NotaryChangeWireTransaction copy(java.util.List) + public final net.corda.core.transactions.NotaryChangeWireTransaction copy(java.util.List) @NotNull - public final net.corda.core.transactions.NotaryChangeWireTransaction copy(java.util.List, net.corda.core.crypto.DigestService) + public final net.corda.core.transactions.NotaryChangeWireTransaction copy(java.util.List, net.corda.core.crypto.DigestService) public boolean equals(Object) @NotNull public final net.corda.core.crypto.DigestService getDigestService() @NotNull public net.corda.core.crypto.SecureHash getId() @NotNull - public java.util.List getInputs() + public java.util.List getInputs() @Nullable public net.corda.core.crypto.SecureHash getNetworkParametersHash() @NotNull @@ -6926,22 +7712,24 @@ public final class net.corda.core.transactions.NotaryChangeWireTransaction exten @NotNull public net.corda.core.identity.Party getNotary() @NotNull - public java.util.List> getOutputs() + public java.util.List getOutputs() @NotNull - public java.util.List getReferences() + public java.util.List getReferences() @NotNull - public final java.util.List getSerializedComponents() + public final java.util.List getSerializedComponents() public int hashCode() @NotNull - public final net.corda.core.transactions.NotaryChangeLedgerTransaction resolve(net.corda.core.node.ServiceHub, java.util.List) + public final net.corda.core.transactions.NotaryChangeLedgerTransaction resolve(net.corda.core.node.ServiceHub, java.util.List) @NotNull - public final net.corda.core.transactions.NotaryChangeLedgerTransaction resolve(net.corda.core.node.ServicesForResolution, java.util.List) + public final net.corda.core.transactions.NotaryChangeLedgerTransaction resolve(net.corda.core.node.ServicesForResolution, java.util.List) @NotNull public String toString() ## public static final class net.corda.core.transactions.NotaryChangeWireTransaction$Component extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.core.transactions.NotaryChangeWireTransaction$Component valueOf(String) - public static net.corda.core.transactions.NotaryChangeWireTransaction$Component[] values() + public static net.corda.core.transactions.NotaryChangeWireTransaction.Component[] values() ## @CordaSerializable public final class net.corda.core.transactions.ReferenceStateRef extends java.lang.Object @@ -6960,25 +7748,25 @@ public final class net.corda.core.transactions.ReferenceStateRef extends java.la @DoNotImplement @CordaSerializable public final class net.corda.core.transactions.SignedTransaction extends java.lang.Object implements net.corda.core.transactions.TransactionWithSignatures - public (net.corda.core.serialization.SerializedBytes, java.util.List) - public (net.corda.core.transactions.CoreTransaction, java.util.List) + public (net.corda.core.serialization.SerializedBytes, java.util.List) + public (net.corda.core.transactions.CoreTransaction, java.util.List) @NotNull - public final net.corda.core.transactions.FilteredTransaction buildFilteredTransaction(java.util.function.Predicate) + public final net.corda.core.transactions.FilteredTransaction buildFilteredTransaction(java.util.function.Predicate) @NotNull - public final net.corda.core.serialization.SerializedBytes component1() + public final net.corda.core.serialization.SerializedBytes component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() @NotNull - public final net.corda.core.transactions.SignedTransaction copy(net.corda.core.serialization.SerializedBytes, java.util.List) + public final net.corda.core.transactions.SignedTransaction copy(net.corda.core.serialization.SerializedBytes, java.util.List) public boolean equals(Object) @NotNull public final net.corda.core.transactions.CoreTransaction getCoreTransaction() @NotNull public net.corda.core.crypto.SecureHash getId() @NotNull - public final java.util.List getInputs() + public final java.util.List getInputs() @NotNull - public java.util.ArrayList getKeyDescriptions(java.util.Set) + public java.util.ArrayList getKeyDescriptions(java.util.Set) @Nullable public final net.corda.core.crypto.SecureHash getNetworkParametersHash() @Nullable @@ -6986,19 +7774,19 @@ public final class net.corda.core.transactions.SignedTransaction extends java.la @NotNull public final net.corda.core.transactions.NotaryChangeWireTransaction getNotaryChangeTx() @NotNull - public final java.util.List getReferences() + public final java.util.List getReferences() @NotNull - public java.util.Set getRequiredSigningKeys() + public java.util.Set getRequiredSigningKeys() @NotNull - public java.util.List getSigs() + public java.util.List getSigs() @NotNull public final net.corda.core.transactions.WireTransaction getTx() @NotNull - public final net.corda.core.serialization.SerializedBytes getTxBits() + public final net.corda.core.serialization.SerializedBytes getTxBits() public int hashCode() public final boolean isNotaryChangeTransaction() @NotNull - public final net.corda.core.transactions.SignedTransaction plus(java.util.Collection) + public final net.corda.core.transactions.SignedTransaction plus(java.util.Collection) @NotNull public final net.corda.core.transactions.SignedTransaction plus(net.corda.core.crypto.TransactionSignature) @NotNull @@ -7024,19 +7812,18 @@ public final class net.corda.core.transactions.SignedTransaction extends java.la @NotNull public final net.corda.core.transactions.SignedTransaction withAdditionalSignature(net.corda.core.crypto.TransactionSignature) @NotNull - public final net.corda.core.transactions.SignedTransaction withAdditionalSignatures(Iterable) - public static final net.corda.core.transactions.SignedTransaction$Companion Companion + public final net.corda.core.transactions.SignedTransaction withAdditionalSignatures(Iterable) ## @CordaSerializable public static final class net.corda.core.transactions.SignedTransaction$SignaturesMissingException extends java.security.SignatureException implements net.corda.core.CordaThrowable, net.corda.core.contracts.NamedByHash - public (java.util.Set, java.util.List, net.corda.core.crypto.SecureHash) + public (java.util.Set, java.util.List, net.corda.core.crypto.SecureHash) public void addSuppressed(Throwable[]) @NotNull - public final java.util.List getDescriptions() + public final java.util.List getDescriptions() @NotNull public net.corda.core.crypto.SecureHash getId() @NotNull - public final java.util.Set getMissing() + public final java.util.Set getMissing() @Nullable public String getOriginalExceptionClassName() @Nullable @@ -7048,20 +7835,20 @@ public static final class net.corda.core.transactions.SignedTransaction$Signatur public class net.corda.core.transactions.TransactionBuilder extends java.lang.Object public () public (net.corda.core.identity.Party) - public (net.corda.core.identity.Party, java.util.UUID, java.util.List, java.util.List, java.util.List>, java.util.List>, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt) + public (net.corda.core.identity.Party, java.util.UUID, java.util.List, java.util.List, java.util.List, java.util.List, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt) public (net.corda.core.identity.Party, java.util.UUID, java.util.List, java.util.List, java.util.List, java.util.List, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.identity.Party, java.util.UUID, java.util.List, java.util.List, java.util.List>, java.util.List>, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt, java.util.List, net.corda.core.node.ServiceHub) + public (net.corda.core.identity.Party, java.util.UUID, java.util.List, java.util.List, java.util.List, java.util.List, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt, java.util.List, net.corda.core.node.ServiceHub) public (net.corda.core.identity.Party, java.util.UUID, java.util.List, java.util.List, java.util.List, java.util.List, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt, java.util.List, net.corda.core.node.ServiceHub, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull public final net.corda.core.transactions.TransactionBuilder addAttachment(net.corda.core.crypto.SecureHash) @NotNull - public final net.corda.core.transactions.TransactionBuilder addCommand(net.corda.core.contracts.Command) + public final net.corda.core.transactions.TransactionBuilder addCommand(net.corda.core.contracts.Command) @NotNull - public final net.corda.core.transactions.TransactionBuilder addCommand(net.corda.core.contracts.CommandData, java.util.List) + public final net.corda.core.transactions.TransactionBuilder addCommand(net.corda.core.contracts.CommandData, java.util.List) @NotNull public final net.corda.core.transactions.TransactionBuilder addCommand(net.corda.core.contracts.CommandData, java.security.PublicKey...) @NotNull - public net.corda.core.transactions.TransactionBuilder addInputState(net.corda.core.contracts.StateAndRef) + public net.corda.core.transactions.TransactionBuilder addInputState(net.corda.core.contracts.StateAndRef) @NotNull public final net.corda.core.transactions.TransactionBuilder addOutputState(net.corda.core.contracts.ContractState) @NotNull @@ -7079,41 +7866,41 @@ public class net.corda.core.transactions.TransactionBuilder extends java.lang.Ob @NotNull public final net.corda.core.transactions.TransactionBuilder addOutputState(net.corda.core.contracts.ContractState, net.corda.core.identity.Party) @NotNull - public final net.corda.core.transactions.TransactionBuilder addOutputState(net.corda.core.contracts.TransactionState) + public final net.corda.core.transactions.TransactionBuilder addOutputState(net.corda.core.contracts.TransactionState) @NotNull - public net.corda.core.transactions.TransactionBuilder addReferenceState(net.corda.core.contracts.ReferencedStateAndRef) + public net.corda.core.transactions.TransactionBuilder addReferenceState(net.corda.core.contracts.ReferencedStateAndRef) @NotNull - public final java.util.List attachments() + public final java.util.List attachments() @NotNull - public final java.util.List> commands() + public final java.util.List commands() @NotNull public final net.corda.core.transactions.TransactionBuilder copy() @NotNull - protected final java.util.List getAttachments() + protected final java.util.List getAttachments() @NotNull - protected final java.util.List> getCommands() + protected final java.util.List getCommands() @NotNull - protected final java.util.List getInputs() + protected final java.util.List getInputs() @NotNull public final java.util.UUID getLockId() @Nullable public final net.corda.core.identity.Party getNotary() @NotNull - protected final java.util.List> getOutputs() + protected final java.util.List getOutputs() @NotNull protected final net.corda.core.contracts.PrivacySalt getPrivacySalt() @NotNull - protected final java.util.List getReferences() + protected final java.util.List getReferences() @Nullable protected final net.corda.core.node.ServiceHub getServiceHub() @Nullable protected final net.corda.core.contracts.TimeWindow getWindow() @NotNull - public final java.util.List inputStates() + public final java.util.List inputStates() @NotNull - public final java.util.List> outputStates() + public final java.util.List outputStates() @NotNull - public final java.util.List referenceStates() + public final java.util.List referenceStates() public final void setLockId(java.util.UUID) public final void setNotary(net.corda.core.identity.Party) @NotNull @@ -7133,70 +7920,70 @@ public class net.corda.core.transactions.TransactionBuilder extends java.lang.Ob @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) + public final net.corda.core.transactions.WireTransaction toWireTransaction(net.corda.core.node.ServicesForResolution, int, java.util.Map) public final void verify(net.corda.core.node.ServiceHub) @NotNull public final net.corda.core.transactions.TransactionBuilder withItems(Object...) - public static final net.corda.core.transactions.TransactionBuilder$Companion Companion ## @DoNotImplement public interface net.corda.core.transactions.TransactionWithSignatures extends net.corda.core.contracts.NamedByHash public void checkSignaturesAreValid() @NotNull - public abstract java.util.List getKeyDescriptions(java.util.Set) + public abstract java.util.List getKeyDescriptions(java.util.Set) @NotNull - public java.util.Set getMissingSigners() + public java.util.Set getMissingSigners() @NotNull - public abstract java.util.Set getRequiredSigningKeys() + public abstract java.util.Set getRequiredSigningKeys() @NotNull - public abstract java.util.List getSigs() + public abstract java.util.List getSigs() public void verifyRequiredSignatures() - public void verifySignaturesExcept(java.util.Collection) + public void verifySignaturesExcept(java.util.Collection) public void verifySignaturesExcept(java.security.PublicKey...) ## @DoNotImplement @CordaSerializable public abstract class net.corda.core.transactions.TraversableTransaction extends net.corda.core.transactions.CoreTransaction @DeprecatedConstructorForDeserialization - public (java.util.List) - public (java.util.List, net.corda.core.crypto.DigestService) + public (java.util.List) + public (java.util.List, net.corda.core.crypto.DigestService) @NotNull - public final java.util.List getAttachments() + public final java.util.List getAttachments() @NotNull - public final java.util.List> getAvailableComponentGroups() + public final java.util.List getAvailableComponentGroups() @NotNull - public final java.util.List> getCommands() + public final java.util.List getCommands() @NotNull - public java.util.List getComponentGroups() + public java.util.List getComponentGroups() @NotNull public final net.corda.core.crypto.DigestService getDigestService() @NotNull - public java.util.List getInputs() + public java.util.List getInputs() + @NotNull + public final java.util.List getLegacyAttachments() @Nullable public net.corda.core.crypto.SecureHash getNetworkParametersHash() @Nullable public net.corda.core.identity.Party getNotary() @NotNull - public java.util.List> getOutputs() + public java.util.List getOutputs() @NotNull - public java.util.List getReferences() + public java.util.List getReferences() @Nullable public final net.corda.core.contracts.TimeWindow getTimeWindow() ## @DoNotImplement @CordaSerializable public final class net.corda.core.transactions.WireTransaction extends net.corda.core.transactions.TraversableTransaction - public (java.util.List) - public (java.util.List, java.util.List, java.util.List>, java.util.List>, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow) - public (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) + public (java.util.List) + public (java.util.List, java.util.List, java.util.List, java.util.List, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow) + public (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) public (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 (java.util.List, net.corda.core.contracts.PrivacySalt) - @DeprecatedConstructorForDeserialization + public (java.util.List, net.corda.core.contracts.PrivacySalt) public (java.util.List, net.corda.core.contracts.PrivacySalt, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (java.util.List, net.corda.core.contracts.PrivacySalt, net.corda.core.crypto.DigestService) + public (java.util.List, net.corda.core.contracts.PrivacySalt, net.corda.core.crypto.DigestService) @NotNull - public final net.corda.core.transactions.FilteredTransaction buildFilteredTransaction(java.util.function.Predicate) + public final net.corda.core.transactions.FilteredTransaction buildFilteredTransaction(java.util.function.Predicate) public final void checkSignature(net.corda.core.crypto.TransactionSignature) public boolean equals(Object) @NotNull @@ -7206,18 +7993,14 @@ public final class net.corda.core.transactions.WireTransaction extends net.corda @NotNull public final net.corda.core.contracts.PrivacySalt getPrivacySalt() @NotNull - public final java.util.Set getRequiredSigningKeys() + public final java.util.Set getRequiredSigningKeys() public int hashCode() @NotNull - public final net.corda.core.transactions.LedgerTransaction toLedgerTransaction(kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1>, kotlin.jvm.functions.Function1, ? extends net.corda.core.crypto.SecureHash>) + public final net.corda.core.transactions.LedgerTransaction toLedgerTransaction(kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1) @NotNull public final net.corda.core.transactions.LedgerTransaction toLedgerTransaction(net.corda.core.node.ServicesForResolution) @NotNull public String toString() - public static final net.corda.core.transactions.WireTransaction$Companion Companion -## -public static final class net.corda.core.transactions.WireTransaction$Companion extends java.lang.Object - public (kotlin.jvm.internal.DefaultConstructorMarker) ## public final class net.corda.core.utilities.ByteArrays extends java.lang.Object @NotNull @@ -7259,6 +8042,7 @@ public abstract class net.corda.core.utilities.ByteSequence extends java.lang.Ob @NotNull public String toString() public final void writeTo(java.io.OutputStream) + @NotNull public static final net.corda.core.utilities.ByteSequence$Companion Companion ## public static final class net.corda.core.utilities.ByteSequence$Companion extends java.lang.Object @@ -7320,20 +8104,21 @@ public class net.corda.core.utilities.Id extends java.lang.Object public final VALUE getValue() public final int hashCode() @NotNull - public static final net.corda.core.utilities.Id newInstance(V, String, java.time.Instant) + public static final net.corda.core.utilities.Id newInstance(V, String, java.time.Instant) @NotNull public final String toString() + @NotNull public static final net.corda.core.utilities.Id$Companion Companion ## public static final class net.corda.core.utilities.Id$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.utilities.Id newInstance(V, String, java.time.Instant) + public final net.corda.core.utilities.Id newInstance(V, String, java.time.Instant) ## public final class net.corda.core.utilities.KotlinUtilsKt extends java.lang.Object @NotNull public static final org.slf4j.Logger contextLogger(Object) - public static final void debug(org.slf4j.Logger, kotlin.jvm.functions.Function0) + public static final void debug(org.slf4j.Logger, kotlin.jvm.functions.Function0) @NotNull public static final org.slf4j.Logger detailedLogger() public static final int exactAdd(int, int) @@ -7346,14 +8131,15 @@ public final class net.corda.core.utilities.KotlinUtilsKt extends java.lang.Obje public static final java.time.Duration getMillis(int) @NotNull public static final java.time.Duration getMinutes(int) - public static final V getOrThrow(java.util.concurrent.Future, java.time.Duration) + public static final V getOrThrow(java.util.concurrent.Future, java.time.Duration) @NotNull public static final java.time.Duration getSeconds(int) + public static final org.slf4j.Logger loggerFor() @NotNull - public static final net.corda.core.utilities.NonEmptySet toNonEmptySet(java.util.Collection) - public static final void trace(org.slf4j.Logger, kotlin.jvm.functions.Function0) + public static final net.corda.core.utilities.NonEmptySet toNonEmptySet(java.util.Collection) + public static final void trace(org.slf4j.Logger, kotlin.jvm.functions.Function0) @NotNull - public static final net.corda.core.utilities.PropertyDelegate transient(kotlin.jvm.functions.Function0) + public static final net.corda.core.utilities.PropertyDelegate transient(kotlin.jvm.functions.Function0) ## @CordaSerializable public final class net.corda.core.utilities.NetworkHostAndPort extends java.lang.Object @@ -7372,6 +8158,7 @@ public final class net.corda.core.utilities.NetworkHostAndPort extends java.lang public static final net.corda.core.utilities.NetworkHostAndPort parse(String) @NotNull public String toString() + @NotNull public static final net.corda.core.utilities.NetworkHostAndPort$Companion Companion @NotNull public static final String INVALID_PORT_FORMAT = "Invalid port: %s" @@ -7388,47 +8175,48 @@ public static final class net.corda.core.utilities.NetworkHostAndPort$Companion public final class net.corda.core.utilities.NonEmptySet extends java.lang.Object implements java.util.Set, kotlin.jvm.internal.markers.KMappedMarker public (java.util.Set, kotlin.jvm.internal.DefaultConstructorMarker) public boolean add(T) - public boolean addAll(java.util.Collection) + public boolean addAll(java.util.Collection) public void clear() public boolean contains(Object) - public boolean containsAll(java.util.Collection) + public boolean containsAll(java.util.Collection) @NotNull - public static final net.corda.core.utilities.NonEmptySet copyOf(java.util.Collection) + public static final net.corda.core.utilities.NonEmptySet copyOf(java.util.Collection) public boolean equals(Object) - public void forEach(java.util.function.Consumer) + public void forEach(java.util.function.Consumer) public int getSize() public int hashCode() public final T head() public boolean isEmpty() @NotNull - public java.util.Iterator iterator() + public java.util.Iterator iterator() @NotNull - public static final net.corda.core.utilities.NonEmptySet of(T) + public static final net.corda.core.utilities.NonEmptySet of(T) @NotNull - public static final net.corda.core.utilities.NonEmptySet of(T, T, T...) + public static final net.corda.core.utilities.NonEmptySet of(T, T, T...) @NotNull - public java.util.stream.Stream parallelStream() + public java.util.stream.Stream parallelStream() public boolean remove(Object) - public boolean removeAll(java.util.Collection) - public boolean retainAll(java.util.Collection) + public boolean removeAll(java.util.Collection) + public boolean retainAll(java.util.Collection) @NotNull - public java.util.Spliterator spliterator() + public java.util.Spliterator spliterator() @NotNull - public java.util.stream.Stream stream() + public java.util.stream.Stream stream() public Object[] toArray() public T[] toArray(T[]) @NotNull public String toString() + @NotNull public static final net.corda.core.utilities.NonEmptySet$Companion Companion ## public static final class net.corda.core.utilities.NonEmptySet$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.utilities.NonEmptySet copyOf(java.util.Collection) + public final net.corda.core.utilities.NonEmptySet copyOf(java.util.Collection) @NotNull - public final net.corda.core.utilities.NonEmptySet of(T) + public final net.corda.core.utilities.NonEmptySet of(T) @NotNull - public final net.corda.core.utilities.NonEmptySet of(T, T, T...) + public final net.corda.core.utilities.NonEmptySet of(T, T, T...) ## @CordaSerializable public class net.corda.core.utilities.OpaqueBytes extends net.corda.core.utilities.ByteSequence @@ -7437,6 +8225,7 @@ public class net.corda.core.utilities.OpaqueBytes extends net.corda.core.utiliti public final byte[] getBytes() @NotNull public static final net.corda.core.utilities.OpaqueBytes of(byte...) + @NotNull public static final net.corda.core.utilities.OpaqueBytes$Companion Companion ## public static final class net.corda.core.utilities.OpaqueBytes$Companion extends java.lang.Object @@ -7451,14 +8240,14 @@ public final class net.corda.core.utilities.OpaqueBytesSubSequence extends net.c ## @CordaSerializable public final class net.corda.core.utilities.ProgressTracker extends java.lang.Object - public (net.corda.core.utilities.ProgressTracker$Step...) + public (net.corda.core.utilities.ProgressTracker.Step...) public final void endWithError(Throwable) @NotNull - public final java.util.List> getAllSteps() + public final java.util.List getAllSteps() @NotNull - public final java.util.List> getAllStepsLabels() + public final java.util.List getAllStepsLabels() @NotNull - public final rx.Observable getChanges() + public final rx.Observable getChanges() @Nullable public final net.corda.core.utilities.ProgressTracker getChildProgressTracker(net.corda.core.utilities.ProgressTracker$Step) @NotNull @@ -7470,19 +8259,18 @@ public final class net.corda.core.utilities.ProgressTracker extends java.lang.Ob public final net.corda.core.utilities.ProgressTracker getParent() public final int getStepIndex() @NotNull - public final net.corda.core.utilities.ProgressTracker$Step[] getSteps() + public final net.corda.core.utilities.ProgressTracker.Step[] getSteps() @NotNull - public final rx.Observable>> getStepsTreeChanges() + public final rx.Observable getStepsTreeChanges() public final int getStepsTreeIndex() @NotNull - public final rx.Observable getStepsTreeIndexChanges() + public final rx.Observable getStepsTreeIndexChanges() @NotNull public final net.corda.core.utilities.ProgressTracker getTopLevelTracker() @NotNull public final net.corda.core.utilities.ProgressTracker$Step nextStep() public final void setChildProgressTracker(net.corda.core.utilities.ProgressTracker$Step, net.corda.core.utilities.ProgressTracker) public final void setCurrentStep(net.corda.core.utilities.ProgressTracker$Step) - public static final net.corda.core.utilities.ProgressTracker$Companion Companion ## @CordaSerializable public abstract static class net.corda.core.utilities.ProgressTracker$Change extends java.lang.Object @@ -7547,11 +8335,13 @@ public static final class net.corda.core.utilities.ProgressTracker$Change$Struct @CordaSerializable public static final class net.corda.core.utilities.ProgressTracker$DONE extends net.corda.core.utilities.ProgressTracker$Step public boolean equals(Object) + @NotNull public static final net.corda.core.utilities.ProgressTracker$DONE INSTANCE ## @CordaSerializable public static final class net.corda.core.utilities.ProgressTracker$STARTING extends net.corda.core.utilities.ProgressTracker$Step public boolean equals(Object) + @NotNull public static final net.corda.core.utilities.ProgressTracker$STARTING INSTANCE ## @CordaSerializable @@ -7561,9 +8351,9 @@ public static class net.corda.core.utilities.ProgressTracker$Step extends java.l public net.corda.core.utilities.ProgressTracker childProgressTracker() public boolean equals(Object) @NotNull - public rx.Observable getChanges() + public rx.Observable getChanges() @NotNull - public java.util.Map getExtraAuditData() + public java.util.Map getExtraAuditData() @NotNull public String getLabel() public int hashCode() @@ -7571,14 +8361,11 @@ public static class net.corda.core.utilities.ProgressTracker$Step extends java.l @CordaSerializable public static final class net.corda.core.utilities.ProgressTracker$UNSTARTED extends net.corda.core.utilities.ProgressTracker$Step public boolean equals(Object) + @NotNull public static final net.corda.core.utilities.ProgressTracker$UNSTARTED INSTANCE ## public interface net.corda.core.utilities.PropertyDelegate - public abstract T getValue(Object, kotlin.reflect.KProperty) -## -public final class net.corda.core.utilities.SgxSupport extends java.lang.Object - public static final boolean isInsideEnclave() - public static final net.corda.core.utilities.SgxSupport INSTANCE + public abstract T getValue(Object, kotlin.reflect.KProperty) ## public final class net.corda.core.utilities.ThreadDumpUtilsKt extends java.lang.Object @NotNull @@ -7590,28 +8377,29 @@ public final class net.corda.core.utilities.ThreadDumpUtilsKt extends java.lang. public abstract class net.corda.core.utilities.Try extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.utilities.Try combine(net.corda.core.utilities.Try, kotlin.jvm.functions.Function2) + public final net.corda.core.utilities.Try combine(net.corda.core.utilities.Try, kotlin.jvm.functions.Function2) @NotNull - public final net.corda.core.utilities.Try doOnFailure(java.util.function.Consumer) + public final net.corda.core.utilities.Try doOnFailure(java.util.function.Consumer) @NotNull - public final net.corda.core.utilities.Try doOnSuccess(java.util.function.Consumer) + public final net.corda.core.utilities.Try doOnSuccess(java.util.function.Consumer) @NotNull - public final net.corda.core.utilities.Try flatMap(kotlin.jvm.functions.Function1>) + public final net.corda.core.utilities.Try flatMap(kotlin.jvm.functions.Function1) public abstract A getOrThrow() public abstract boolean isFailure() public abstract boolean isSuccess() @NotNull - public final net.corda.core.utilities.Try map(kotlin.jvm.functions.Function1) + public final net.corda.core.utilities.Try map(kotlin.jvm.functions.Function1) @NotNull - public static final net.corda.core.utilities.Try on(kotlin.jvm.functions.Function0) + public static final net.corda.core.utilities.Try on(kotlin.jvm.functions.Function0) + @NotNull + public final net.corda.core.utilities.Try throwError() @NotNull - public final net.corda.core.utilities.Try throwError() public static final net.corda.core.utilities.Try$Companion Companion ## public static final class net.corda.core.utilities.Try$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.utilities.Try on(kotlin.jvm.functions.Function0) + public final net.corda.core.utilities.Try on(kotlin.jvm.functions.Function0) ## @CordaSerializable public static final class net.corda.core.utilities.Try$Failure extends net.corda.core.utilities.Try @@ -7619,7 +8407,7 @@ public static final class net.corda.core.utilities.Try$Failure extends net.corda @NotNull public final Throwable component1() @NotNull - public final net.corda.core.utilities.Try$Failure copy(Throwable) + public final net.corda.core.utilities.Try$Failure copy(Throwable) public boolean equals(Object) @NotNull public final Throwable getException() @@ -7635,7 +8423,7 @@ public static final class net.corda.core.utilities.Try$Success extends net.corda public (A) public final A component1() @NotNull - public final net.corda.core.utilities.Try$Success copy(A) + public final net.corda.core.utilities.Try$Success copy(A) public boolean equals(Object) public A getOrThrow() public final A getValue() @@ -7649,17 +8437,18 @@ public final class net.corda.core.utilities.UntrustworthyData extends java.lang. public (T) public final T getFromUntrustedWorld() @Suspendable - public final R unwrap(net.corda.core.utilities.UntrustworthyData$Validator) + public final R unwrap(net.corda.core.utilities.UntrustworthyData$Validator) ## public static interface net.corda.core.utilities.UntrustworthyData$Validator extends java.io.Serializable @Suspendable public abstract R validate(T) ## public final class net.corda.core.utilities.UntrustworthyDataKt extends java.lang.Object - public static final R unwrap(net.corda.core.utilities.UntrustworthyData, kotlin.jvm.functions.Function1) + public static final R unwrap(net.corda.core.utilities.UntrustworthyData, kotlin.jvm.functions.Function1) ## public final class net.corda.core.utilities.UuidGenerator extends java.lang.Object public () + @NotNull public static final net.corda.core.utilities.UuidGenerator$Companion Companion ## public static final class net.corda.core.utilities.UuidGenerator$Companion extends java.lang.Object @@ -7668,7 +8457,7 @@ public static final class net.corda.core.utilities.UuidGenerator$Companion exten public final java.util.UUID next() ## public interface net.corda.core.utilities.VariablePropertyDelegate extends net.corda.core.utilities.PropertyDelegate - public abstract void setValue(Object, kotlin.reflect.KProperty, T) + public abstract void setValue(Object, kotlin.reflect.KProperty, T) ## public final class net.corda.testing.contracts.DummyContract extends java.lang.Object implements net.corda.core.contracts.Contract public () @@ -7687,12 +8476,13 @@ public final class net.corda.testing.contracts.DummyContract extends java.lang.O public final String getPROGRAM_ID() public int hashCode() @NotNull - public static final net.corda.core.transactions.TransactionBuilder move(java.util.List>, net.corda.core.identity.AbstractParty) + public static final net.corda.core.transactions.TransactionBuilder move(java.util.List, net.corda.core.identity.AbstractParty) @NotNull - public static final net.corda.core.transactions.TransactionBuilder move(net.corda.core.contracts.StateAndRef, net.corda.core.identity.AbstractParty) + public static final net.corda.core.transactions.TransactionBuilder move(net.corda.core.contracts.StateAndRef, net.corda.core.identity.AbstractParty) @NotNull public String toString() public void verify(net.corda.core.transactions.LedgerTransaction) + @NotNull public static final net.corda.testing.contracts.DummyContract$Companion Companion @NotNull public static final String PROGRAM_ID = "net.corda.testing.contracts.DummyContract" @@ -7710,25 +8500,25 @@ public static final class net.corda.testing.contracts.DummyContract$Companion ex @NotNull public final net.corda.core.transactions.TransactionBuilder generateInitial(int, net.corda.core.identity.Party, net.corda.core.contracts.PartyAndReference, net.corda.core.contracts.PartyAndReference...) @NotNull - public final net.corda.core.transactions.TransactionBuilder move(java.util.List>, net.corda.core.identity.AbstractParty) + public final net.corda.core.transactions.TransactionBuilder move(java.util.List, net.corda.core.identity.AbstractParty) @NotNull - public final net.corda.core.transactions.TransactionBuilder move(net.corda.core.contracts.StateAndRef, net.corda.core.identity.AbstractParty) + public final net.corda.core.transactions.TransactionBuilder move(net.corda.core.contracts.StateAndRef, net.corda.core.identity.AbstractParty) ## @DoNotImplement public static final class net.corda.testing.contracts.DummyContract$MultiOwnerState extends java.lang.Object implements net.corda.testing.contracts.DummyContract$State - public (int, java.util.List) + public (int, java.util.List) public (int, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) public final int component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() @NotNull - public final net.corda.testing.contracts.DummyContract$MultiOwnerState copy(int, java.util.List) + public final net.corda.testing.contracts.DummyContract$MultiOwnerState copy(int, java.util.List) public boolean equals(Object) public int getMagicNumber() @NotNull - public final java.util.List getOwners() + public final java.util.List getOwners() @NotNull - public java.util.List getParticipants() + public java.util.List getParticipants() public int hashCode() @NotNull public String toString() @@ -7747,7 +8537,7 @@ public static final class net.corda.testing.contracts.DummyContract$SingleOwnerS @NotNull public net.corda.core.identity.AbstractParty getOwner() @NotNull - public java.util.List getParticipants() + public java.util.List getParticipants() public int hashCode() @NotNull public String toString() @@ -7765,12 +8555,13 @@ public final class net.corda.testing.contracts.DummyContractV2 extends java.lang @NotNull public net.corda.core.contracts.AttachmentConstraint getLegacyContractConstraint() @NotNull - public static final net.corda.core.transactions.TransactionBuilder move(java.util.List>, net.corda.core.identity.AbstractParty) + public static final net.corda.core.transactions.TransactionBuilder move(java.util.List, net.corda.core.identity.AbstractParty) @NotNull - public static final net.corda.core.transactions.TransactionBuilder move(net.corda.core.contracts.StateAndRef, net.corda.core.identity.AbstractParty) + public static final net.corda.core.transactions.TransactionBuilder move(net.corda.core.contracts.StateAndRef, net.corda.core.identity.AbstractParty) @NotNull public net.corda.testing.contracts.DummyContractV2$State upgrade(net.corda.testing.contracts.DummyContract$State) public void verify(net.corda.core.transactions.LedgerTransaction) + @NotNull public static final net.corda.testing.contracts.DummyContractV2$Companion Companion @NotNull public static final String PROGRAM_ID = "net.corda.testing.contracts.DummyContractV2" @@ -7786,29 +8577,29 @@ public static final class net.corda.testing.contracts.DummyContractV2$Commands$M public static final class net.corda.testing.contracts.DummyContractV2$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.core.transactions.TransactionBuilder move(java.util.List>, net.corda.core.identity.AbstractParty) + public final net.corda.core.transactions.TransactionBuilder move(java.util.List, net.corda.core.identity.AbstractParty) @NotNull - public final net.corda.core.transactions.TransactionBuilder move(net.corda.core.contracts.StateAndRef, net.corda.core.identity.AbstractParty) + public final net.corda.core.transactions.TransactionBuilder move(net.corda.core.contracts.StateAndRef, net.corda.core.identity.AbstractParty) ## public static final class net.corda.testing.contracts.DummyContractV2$State extends java.lang.Object implements net.corda.core.contracts.ContractState - public (int, java.util.List) + public (int, java.util.List) public (int, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) public final int component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() @NotNull - public final net.corda.testing.contracts.DummyContractV2$State copy(int, java.util.List) + public final net.corda.testing.contracts.DummyContractV2$State copy(int, java.util.List) public boolean equals(Object) public final int getMagicNumber() @NotNull - public final java.util.List getOwners() + public final java.util.List getOwners() @NotNull - public java.util.List getParticipants() + public java.util.List getParticipants() public int hashCode() @NotNull public String toString() @NotNull - public final kotlin.Pair withNewOwner(net.corda.core.identity.AbstractParty) + public final kotlin.Pair withNewOwner(net.corda.core.identity.AbstractParty) ## public final class net.corda.testing.contracts.DummyContractV3 extends java.lang.Object implements net.corda.core.contracts.UpgradedContractWithLegacyConstraint public () @@ -7819,6 +8610,7 @@ public final class net.corda.testing.contracts.DummyContractV3 extends java.lang @NotNull public net.corda.testing.contracts.DummyContractV3$State upgrade(net.corda.testing.contracts.DummyContractV2$State) public void verify(net.corda.core.transactions.LedgerTransaction) + @NotNull public static final net.corda.testing.contracts.DummyContractV3$Companion Companion @NotNull public static final String PROGRAM_ID = "net.corda.testing.contracts.DummyContractV3" @@ -7835,19 +8627,19 @@ public static final class net.corda.testing.contracts.DummyContractV3$Companion public (kotlin.jvm.internal.DefaultConstructorMarker) ## public static final class net.corda.testing.contracts.DummyContractV3$State extends java.lang.Object implements net.corda.core.contracts.ContractState - public (int, java.util.List) + public (int, java.util.List) public (int, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) public final int component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() @NotNull - public final net.corda.testing.contracts.DummyContractV3$State copy(int, java.util.List) + public final net.corda.testing.contracts.DummyContractV3$State copy(int, java.util.List) public boolean equals(Object) public final int getMagicNumber() @NotNull - public final java.util.List getOwners() + public final java.util.List getOwners() @NotNull - public java.util.List getParticipants() + public java.util.List getParticipants() public int hashCode() @NotNull public String toString() @@ -7856,43 +8648,44 @@ public static final class net.corda.testing.contracts.DummyContractV3$State exte public final class net.corda.testing.contracts.DummyState extends java.lang.Object implements net.corda.core.contracts.ContractState public () public (int) - public (int, java.util.List) + public (int, java.util.List) public (int, java.util.List, int, kotlin.jvm.internal.DefaultConstructorMarker) public final int component1() @NotNull - public final java.util.List component2() + public final java.util.List component2() @NotNull public final net.corda.testing.contracts.DummyState copy(int) @NotNull - public final net.corda.testing.contracts.DummyState copy(int, java.util.List) + public final net.corda.testing.contracts.DummyState copy(int, java.util.List) public boolean equals(Object) public final int getMagicNumber() @NotNull - public java.util.List getParticipants() + public java.util.List getParticipants() public int hashCode() @NotNull public String toString() ## public final class net.corda.testing.core.DummyCommandData extends net.corda.core.contracts.TypeOnlyCommandData + @NotNull public static final net.corda.testing.core.DummyCommandData INSTANCE ## public final class net.corda.testing.core.Expect extends java.lang.Object - public (Class, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1) + public (Class, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1) @NotNull - public final Class component1() + public final Class component1() @NotNull - public final kotlin.jvm.functions.Function1 component2() + public final kotlin.jvm.functions.Function1 component2() @NotNull - public final kotlin.jvm.functions.Function1 component3() + public final kotlin.jvm.functions.Function1 component3() @NotNull - public final net.corda.testing.core.Expect copy(Class, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1) + public final net.corda.testing.core.Expect copy(Class, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1) public boolean equals(Object) @NotNull - public final Class getClazz() + public final Class getClazz() @NotNull - public final kotlin.jvm.functions.Function1 getExpectClosure() + public final kotlin.jvm.functions.Function1 getExpectClosure() @NotNull - public final kotlin.jvm.functions.Function1 getMatch() + public final kotlin.jvm.functions.Function1 getMatch() public int hashCode() @NotNull public String toString() @@ -7903,82 +8696,84 @@ public abstract class net.corda.testing.core.ExpectCompose extends java.lang.Obj ## @DoNotImplement public static final class net.corda.testing.core.ExpectCompose$Parallel extends net.corda.testing.core.ExpectCompose - public (java.util.List>) + public (java.util.List) @NotNull - public final java.util.List> getParallel() + public final java.util.List getParallel() ## @DoNotImplement public static final class net.corda.testing.core.ExpectCompose$Sequential extends net.corda.testing.core.ExpectCompose - public (java.util.List>) + public (java.util.List) @NotNull - public final java.util.List> getSequence() + public final java.util.List getSequence() ## @DoNotImplement public static final class net.corda.testing.core.ExpectCompose$Single extends net.corda.testing.core.ExpectCompose - public (net.corda.testing.core.Expect) + public (net.corda.testing.core.Expect) @NotNull - public final net.corda.testing.core.Expect getExpect() + public final net.corda.testing.core.Expect getExpect() ## public static final class net.corda.testing.core.ExpectComposeState$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final net.corda.testing.core.ExpectComposeState fromExpectCompose(net.corda.testing.core.ExpectCompose) + public final net.corda.testing.core.ExpectComposeState fromExpectCompose(net.corda.testing.core.ExpectCompose) ## public static final class net.corda.testing.core.ExpectComposeState$Finished extends net.corda.testing.core.ExpectComposeState public () @NotNull - public java.util.List> getExpectedEvents() + public java.util.List getExpectedEvents() @Nullable public Void nextState(E) ## public static final class net.corda.testing.core.ExpectComposeState$Parallel extends net.corda.testing.core.ExpectComposeState - public (net.corda.testing.core.ExpectCompose$Parallel, java.util.List>) + public (net.corda.testing.core.ExpectCompose$Parallel, java.util.List) @NotNull - public java.util.List> getExpectedEvents() + public java.util.List getExpectedEvents() @NotNull - public final net.corda.testing.core.ExpectCompose$Parallel getParallel() + public final net.corda.testing.core.ExpectCompose$Parallel getParallel() @NotNull - public final java.util.List> getStates() + public final java.util.List getStates() @Nullable - public kotlin.Pair, net.corda.testing.core.ExpectComposeState> nextState(E) + public kotlin.Pair nextState(E) ## public static final class net.corda.testing.core.ExpectComposeState$Sequential extends net.corda.testing.core.ExpectComposeState - public (net.corda.testing.core.ExpectCompose$Sequential, int, net.corda.testing.core.ExpectComposeState) + public (net.corda.testing.core.ExpectCompose$Sequential, int, net.corda.testing.core.ExpectComposeState) @NotNull - public java.util.List> getExpectedEvents() + public java.util.List getExpectedEvents() public final int getIndex() @NotNull - public final net.corda.testing.core.ExpectCompose$Sequential getSequential() + public final net.corda.testing.core.ExpectCompose$Sequential getSequential() @NotNull - public final net.corda.testing.core.ExpectComposeState getState() + public final net.corda.testing.core.ExpectComposeState getState() @Nullable - public kotlin.Pair, net.corda.testing.core.ExpectComposeState> nextState(E) + public kotlin.Pair nextState(E) ## public static final class net.corda.testing.core.ExpectComposeState$Single extends net.corda.testing.core.ExpectComposeState - public (net.corda.testing.core.ExpectCompose$Single) + public (net.corda.testing.core.ExpectCompose$Single) @NotNull - public java.util.List> getExpectedEvents() + public java.util.List getExpectedEvents() @NotNull - public final net.corda.testing.core.ExpectCompose$Single getSingle() + public final net.corda.testing.core.ExpectCompose$Single getSingle() @Nullable - public kotlin.Pair, net.corda.testing.core.ExpectComposeState> nextState(E) + public kotlin.Pair nextState(E) ## public final class net.corda.testing.core.ExpectKt extends java.lang.Object @NotNull - public static final net.corda.testing.core.ExpectCompose expect(Class, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1) - public static final void expectEvents(Iterable, boolean, kotlin.jvm.functions.Function0>) - public static final void expectEvents(rx.Observable, boolean, kotlin.jvm.functions.Function0>) - public static final void genericExpectEvents(S, boolean, kotlin.jvm.functions.Function2, kotlin.Unit>, kotlin.jvm.functions.Function0>) + public static final net.corda.testing.core.ExpectCompose expect(Class, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1) + public static final net.corda.testing.core.ExpectCompose expect(E, kotlin.jvm.functions.Function1) + public static final net.corda.testing.core.ExpectCompose expect(kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1) + public static final void expectEvents(Iterable, boolean, kotlin.jvm.functions.Function0) + public static final void expectEvents(rx.Observable, boolean, kotlin.jvm.functions.Function0) + public static final void genericExpectEvents(S, boolean, kotlin.jvm.functions.Function2, kotlin.jvm.functions.Function0) @NotNull - public static final net.corda.testing.core.ExpectCompose parallel(java.util.List>) + public static final net.corda.testing.core.ExpectCompose parallel(java.util.List) @NotNull - public static final net.corda.testing.core.ExpectCompose parallel(net.corda.testing.core.ExpectCompose...) + public static final net.corda.testing.core.ExpectCompose parallel(net.corda.testing.core.ExpectCompose...) @NotNull - public static final net.corda.testing.core.ExpectCompose replicate(int, kotlin.jvm.functions.Function1>) + public static final net.corda.testing.core.ExpectCompose replicate(int, kotlin.jvm.functions.Function1) @NotNull - public static final net.corda.testing.core.ExpectCompose sequence(java.util.List>) + public static final net.corda.testing.core.ExpectCompose sequence(java.util.List) @NotNull - public static final net.corda.testing.core.ExpectCompose sequence(net.corda.testing.core.ExpectCompose...) + public static final net.corda.testing.core.ExpectCompose sequence(net.corda.testing.core.ExpectCompose...) ## public final class net.corda.testing.core.SerializationEnvironmentRule extends java.lang.Object implements org.junit.rules.TestRule public () @@ -7988,6 +8783,7 @@ public final class net.corda.testing.core.SerializationEnvironmentRule extends j public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement, org.junit.runner.Description) @NotNull public final net.corda.core.serialization.SerializationFactory getSerializationFactory() + @NotNull public static final net.corda.testing.core.SerializationEnvironmentRule$Companion Companion ## public static final class net.corda.testing.core.SerializationEnvironmentRule$Companion extends java.lang.Object @@ -7995,7 +8791,7 @@ public static final class net.corda.testing.core.SerializationEnvironmentRule$Co ## public final class net.corda.testing.core.TestConstants extends java.lang.Object @NotNull - public static final net.corda.core.contracts.Command dummyCommand(java.security.PublicKey...) + public static final net.corda.core.contracts.Command dummyCommand(java.security.PublicKey...) @NotNull public static final net.corda.core.identity.CordaX500Name ALICE_NAME @NotNull @@ -8040,6 +8836,7 @@ public final class net.corda.testing.core.TestIdentity extends java.lang.Object public final java.security.PublicKey getPublicKey() @NotNull public final net.corda.core.contracts.PartyAndReference ref(byte...) + @NotNull public static final net.corda.testing.core.TestIdentity$Companion Companion ## public static final class net.corda.testing.core.TestIdentity$Companion extends java.lang.Object @@ -8051,15 +8848,15 @@ public static final class net.corda.testing.core.TestIdentity$Companion extends ## public final class net.corda.testing.core.TestUtils extends java.lang.Object @NotNull - public static final java.security.cert.X509CRL createCRL(net.corda.nodeapi.internal.crypto.CertificateAndKeyPair, java.util.List, java.net.URI, java.time.Instant, java.time.Instant, boolean, java.time.Instant, int, String) - public static final T executeTest(java.time.Duration, kotlin.jvm.functions.Function0, java.time.Duration, kotlin.jvm.functions.Function0) + public static final java.security.cert.X509CRL createCRL(net.corda.nodeapi.internal.crypto.CertificateAndKeyPair, java.util.List, java.net.URI, java.time.Instant, java.time.Instant, boolean, java.time.Instant, int, String) + public static final T executeTest(java.time.Duration, kotlin.jvm.functions.Function0, java.time.Duration, kotlin.jvm.functions.Function0) @NotNull public static final net.corda.core.utilities.NetworkHostAndPort freeLocalHostAndPort() public static final int freePort() @NotNull public static final net.corda.core.contracts.StateRef generateStateRef() @NotNull - public static final java.util.List getFreeLocalPorts(String, int) + public static final java.util.List getFreeLocalPorts(String, int) @NotNull public static final net.corda.core.identity.PartyAndCertificate getTestPartyAndCertificate(net.corda.core.identity.CordaX500Name, java.security.PublicKey) @NotNull @@ -8096,33 +8893,40 @@ public final class net.corda.client.jackson.JacksonSupport extends java.lang.Obj public static final com.fasterxml.jackson.databind.ObjectMapper createNonRpcMapper(com.fasterxml.jackson.core.JsonFactory, boolean) @NotNull public final com.fasterxml.jackson.databind.Module getCordaModule() + @NotNull public static final net.corda.client.jackson.JacksonSupport INSTANCE ## public static final class net.corda.client.jackson.JacksonSupport$AmountDeserializer extends com.fasterxml.jackson.databind.JsonDeserializer @NotNull - public net.corda.core.contracts.Amount deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext) + public net.corda.core.contracts.Amount deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext) + @NotNull public static final net.corda.client.jackson.JacksonSupport$AmountDeserializer INSTANCE ## public static final class net.corda.client.jackson.JacksonSupport$AmountSerializer extends com.fasterxml.jackson.databind.JsonSerializer - public void serialize(net.corda.core.contracts.Amount, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) + public void serialize(net.corda.core.contracts.Amount, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) + @NotNull public static final net.corda.client.jackson.JacksonSupport$AmountSerializer INSTANCE ## public static final class net.corda.client.jackson.JacksonSupport$AnonymousPartyDeserializer extends com.fasterxml.jackson.databind.JsonDeserializer @NotNull public net.corda.core.identity.AnonymousParty deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext) + @NotNull public static final net.corda.client.jackson.JacksonSupport$AnonymousPartyDeserializer INSTANCE ## public static final class net.corda.client.jackson.JacksonSupport$AnonymousPartySerializer extends com.fasterxml.jackson.databind.JsonSerializer public void serialize(net.corda.core.identity.AnonymousParty, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) + @NotNull public static final net.corda.client.jackson.JacksonSupport$AnonymousPartySerializer INSTANCE ## public static final class net.corda.client.jackson.JacksonSupport$CordaX500NameDeserializer extends com.fasterxml.jackson.databind.JsonDeserializer @NotNull public net.corda.core.identity.CordaX500Name deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext) + @NotNull public static final net.corda.client.jackson.JacksonSupport$CordaX500NameDeserializer INSTANCE ## public static final class net.corda.client.jackson.JacksonSupport$CordaX500NameSerializer extends com.fasterxml.jackson.databind.JsonSerializer public void serialize(net.corda.core.identity.CordaX500Name, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) + @NotNull public static final net.corda.client.jackson.JacksonSupport$CordaX500NameSerializer INSTANCE ## @DoNotImplement @@ -8137,7 +8941,7 @@ public static final class net.corda.client.jackson.JacksonSupport$IdentityObject @Nullable public net.corda.core.node.NodeInfo nodeInfoFromParty(net.corda.core.identity.AbstractParty) @NotNull - public java.util.Set partiesFromName(String) + public java.util.Set partiesFromName(String) @Nullable public net.corda.core.identity.Party partyFromKey(java.security.PublicKey) @Nullable @@ -8152,7 +8956,7 @@ public static final class net.corda.client.jackson.JacksonSupport$NoPartyObjectM @Nullable public net.corda.core.node.NodeInfo nodeInfoFromParty(net.corda.core.identity.AbstractParty) @NotNull - public java.util.Set partiesFromName(String) + public java.util.Set partiesFromName(String) @Nullable public net.corda.core.identity.Party partyFromKey(java.security.PublicKey) @Nullable @@ -8161,24 +8965,29 @@ public static final class net.corda.client.jackson.JacksonSupport$NoPartyObjectM public static final class net.corda.client.jackson.JacksonSupport$NodeInfoDeserializer extends com.fasterxml.jackson.databind.JsonDeserializer @NotNull public net.corda.core.node.NodeInfo deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext) + @NotNull public static final net.corda.client.jackson.JacksonSupport$NodeInfoDeserializer INSTANCE ## public static final class net.corda.client.jackson.JacksonSupport$NodeInfoSerializer extends com.fasterxml.jackson.databind.JsonSerializer public void serialize(net.corda.core.node.NodeInfo, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) + @NotNull public static final net.corda.client.jackson.JacksonSupport$NodeInfoSerializer INSTANCE ## public static final class net.corda.client.jackson.JacksonSupport$OpaqueBytesDeserializer extends com.fasterxml.jackson.databind.JsonDeserializer @NotNull public net.corda.core.utilities.OpaqueBytes deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext) + @NotNull public static final net.corda.client.jackson.JacksonSupport$OpaqueBytesDeserializer INSTANCE ## public static final class net.corda.client.jackson.JacksonSupport$OpaqueBytesSerializer extends com.fasterxml.jackson.databind.JsonSerializer public void serialize(net.corda.core.utilities.OpaqueBytes, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) + @NotNull public static final net.corda.client.jackson.JacksonSupport$OpaqueBytesSerializer INSTANCE ## public static final class net.corda.client.jackson.JacksonSupport$PartyDeserializer extends com.fasterxml.jackson.databind.JsonDeserializer @NotNull public net.corda.core.identity.Party deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext) + @NotNull public static final net.corda.client.jackson.JacksonSupport$PartyDeserializer INSTANCE ## @DoNotImplement @@ -8187,7 +8996,7 @@ public static interface net.corda.client.jackson.JacksonSupport$PartyObjectMappe @Nullable public abstract net.corda.core.node.NodeInfo nodeInfoFromParty(net.corda.core.identity.AbstractParty) @NotNull - public abstract java.util.Set partiesFromName(String) + public abstract java.util.Set partiesFromName(String) @Nullable public abstract net.corda.core.identity.Party partyFromKey(java.security.PublicKey) @Nullable @@ -8195,15 +9004,18 @@ public static interface net.corda.client.jackson.JacksonSupport$PartyObjectMappe ## public static final class net.corda.client.jackson.JacksonSupport$PartySerializer extends com.fasterxml.jackson.databind.JsonSerializer public void serialize(net.corda.core.identity.Party, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) + @NotNull public static final net.corda.client.jackson.JacksonSupport$PartySerializer INSTANCE ## public static final class net.corda.client.jackson.JacksonSupport$PublicKeyDeserializer extends com.fasterxml.jackson.databind.JsonDeserializer @NotNull public java.security.PublicKey deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext) + @NotNull public static final net.corda.client.jackson.JacksonSupport$PublicKeyDeserializer INSTANCE ## public static final class net.corda.client.jackson.JacksonSupport$PublicKeySerializer extends com.fasterxml.jackson.databind.JsonSerializer public void serialize(java.security.PublicKey, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) + @NotNull public static final net.corda.client.jackson.JacksonSupport$PublicKeySerializer INSTANCE ## @DoNotImplement @@ -8218,7 +9030,7 @@ public static final class net.corda.client.jackson.JacksonSupport$RpcObjectMappe @Nullable public net.corda.core.node.NodeInfo nodeInfoFromParty(net.corda.core.identity.AbstractParty) @NotNull - public java.util.Set partiesFromName(String) + public java.util.Set partiesFromName(String) @Nullable public net.corda.core.identity.Party partyFromKey(java.security.PublicKey) @Nullable @@ -8231,6 +9043,7 @@ public static final class net.corda.client.jackson.JacksonSupport$SecureHashDese ## public static final class net.corda.client.jackson.JacksonSupport$SecureHashSerializer extends com.fasterxml.jackson.databind.JsonSerializer public void serialize(net.corda.core.crypto.SecureHash, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) + @NotNull public static final net.corda.client.jackson.JacksonSupport$SecureHashSerializer INSTANCE ## public abstract static class net.corda.client.jackson.JacksonSupport$SignedTransactionMixin extends java.lang.Object @@ -8240,7 +9053,7 @@ public abstract static class net.corda.client.jackson.JacksonSupport$SignedTrans public abstract net.corda.core.crypto.SecureHash getId() @JsonIgnore @NotNull - public abstract java.util.List getInputs() + public abstract java.util.List getInputs() @JsonIgnore @Nullable public abstract net.corda.core.identity.Party getNotary() @@ -8249,10 +9062,10 @@ public abstract static class net.corda.client.jackson.JacksonSupport$SignedTrans public abstract net.corda.core.transactions.NotaryChangeWireTransaction getNotaryChangeTx() @JsonIgnore @NotNull - public abstract java.util.Set getRequiredSigningKeys() + public abstract java.util.Set getRequiredSigningKeys() @JsonProperty @NotNull - protected abstract java.util.List getSigs() + protected abstract java.util.List getSigs() @JsonProperty @NotNull protected abstract net.corda.core.transactions.CoreTransaction getTransaction() @@ -8261,48 +9074,50 @@ public abstract static class net.corda.client.jackson.JacksonSupport$SignedTrans public abstract net.corda.core.transactions.WireTransaction getTx() @JsonIgnore @NotNull - public abstract net.corda.core.serialization.SerializedBytes getTxBits() + public abstract net.corda.core.serialization.SerializedBytes getTxBits() ## public static final class net.corda.client.jackson.JacksonSupport$ToStringSerializer extends com.fasterxml.jackson.databind.JsonSerializer public void serialize(Object, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) + @NotNull public static final net.corda.client.jackson.JacksonSupport$ToStringSerializer INSTANCE ## public abstract static class net.corda.client.jackson.JacksonSupport$WireTransactionMixin extends java.lang.Object public () @JsonIgnore @NotNull - public abstract java.util.List getAvailableComponentHashes() + public abstract java.util.List getAvailableComponentHashes() @JsonIgnore @NotNull - public abstract java.util.List getAvailableComponents() + public abstract java.util.List getAvailableComponents() @JsonIgnore @NotNull public abstract net.corda.core.crypto.MerkleTree getMerkleTree() @JsonIgnore @NotNull - public abstract java.util.List getOutputStates() + public abstract java.util.List getOutputStates() ## @ThreadSafe public class net.corda.client.jackson.StringToMethodCallParser extends java.lang.Object - public (Class) - public (Class, com.fasterxml.jackson.databind.ObjectMapper) + public (Class) + public (Class, com.fasterxml.jackson.databind.ObjectMapper) public (Class, com.fasterxml.jackson.databind.ObjectMapper, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (kotlin.reflect.KClass) + public (kotlin.reflect.KClass) @NotNull - public final java.util.Map getAvailableCommands() + public final java.util.Map getAvailableCommands() @NotNull - protected final com.google.common.collect.Multimap getMethodMap() + protected final com.google.common.collect.Multimap getMethodMap() @NotNull - public final java.util.Map> getMethodParamNames() + public final java.util.Map getMethodParamNames() @NotNull - public java.util.List paramNamesFromConstructor(reflect.Constructor) + public java.util.List paramNamesFromConstructor(reflect.Constructor) @NotNull - public java.util.List paramNamesFromMethod(reflect.Method) + public java.util.List paramNamesFromMethod(reflect.Method) @NotNull - public final net.corda.client.jackson.StringToMethodCallParser.ParsedMethodCall parse(T, String) + public final net.corda.client.jackson.StringToMethodCallParser$ParsedMethodCall parse(T, String) + @NotNull + public final Object[] parseArguments(String, java.util.List, String) + public final void validateIsMatchingCtor(String, java.util.List, String) @NotNull - public final Object[] parseArguments(String, java.util.List>, String) - public final void validateIsMatchingCtor(String, java.util.List>, String) public static final net.corda.client.jackson.StringToMethodCallParser$Companion Companion ## public static final class net.corda.client.jackson.StringToMethodCallParser$Companion extends java.lang.Object @@ -8346,7 +9161,7 @@ public static final class net.corda.client.jackson.StringToMethodCallParser$Unpa public final String getMethodName() ## public final class net.corda.testing.driver.Driver extends java.lang.Object - public static final A driver(net.corda.testing.driver.DriverParameters, kotlin.jvm.functions.Function1) + public static final A driver(net.corda.testing.driver.DriverParameters, kotlin.jvm.functions.Function1) @NotNull public static final java.io.File logFile(net.corda.testing.driver.NodeHandle) ## @@ -8355,56 +9170,56 @@ public interface net.corda.testing.driver.DriverDSL @NotNull public abstract java.nio.file.Path baseDirectory(net.corda.core.identity.CordaX500Name) @NotNull - public abstract net.corda.testing.driver.NotaryHandle getDefaultNotaryHandle() + public net.corda.testing.driver.NotaryHandle getDefaultNotaryHandle() @NotNull - public abstract net.corda.core.identity.Party getDefaultNotaryIdentity() + public net.corda.core.identity.Party getDefaultNotaryIdentity() @NotNull - public abstract net.corda.core.concurrent.CordaFuture getDefaultNotaryNode() + public net.corda.core.concurrent.CordaFuture getDefaultNotaryNode() @NotNull - public abstract java.util.List getNotaryHandles() - public abstract int nextPort() + public abstract java.util.List getNotaryHandles() + public int nextPort() @NotNull - public abstract net.corda.core.concurrent.CordaFuture startNode() + public net.corda.core.concurrent.CordaFuture startNode() @NotNull - public abstract net.corda.core.concurrent.CordaFuture startNode(net.corda.testing.driver.NodeParameters) + public abstract net.corda.core.concurrent.CordaFuture startNode(net.corda.testing.driver.NodeParameters) @NotNull - public abstract net.corda.core.concurrent.CordaFuture startNode(net.corda.testing.driver.NodeParameters, net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String) + public net.corda.core.concurrent.CordaFuture startNode(net.corda.testing.driver.NodeParameters, net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String) @NotNull - public abstract net.corda.core.concurrent.CordaFuture startNode(net.corda.testing.driver.NodeParameters, net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String, String) + public net.corda.core.concurrent.CordaFuture startNode(net.corda.testing.driver.NodeParameters, net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String, String) @NotNull - public abstract net.corda.core.concurrent.CordaFuture startWebserver(net.corda.testing.driver.NodeHandle) + public net.corda.core.concurrent.CordaFuture startWebserver(net.corda.testing.driver.NodeHandle) @NotNull - public abstract net.corda.core.concurrent.CordaFuture startWebserver(net.corda.testing.driver.NodeHandle, String) + public abstract net.corda.core.concurrent.CordaFuture startWebserver(net.corda.testing.driver.NodeHandle, String) ## public final class net.corda.testing.driver.DriverParameters extends java.lang.Object public () - public (java.util.Collection) - public (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) - public (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) + public (java.util.Collection) + public (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) + public (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) public (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, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (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) + public (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) public (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 (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.util.Map, boolean) + public (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.util.Map, boolean) public (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.util.Map, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (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.util.Map, boolean, boolean) + public (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.util.Map, boolean, boolean) public (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.util.Map, boolean, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (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.util.Map, boolean, boolean, java.time.Duration) + public (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.util.Map, boolean, boolean, java.time.Duration) public (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.util.Map, boolean, boolean, java.time.Duration, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (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, boolean) + public (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, boolean) public final boolean component1() @NotNull - public final java.util.List component10() + public final java.util.List component10() @NotNull public final net.corda.testing.driver.JmxPolicy component11() @NotNull public final net.corda.core.node.NetworkParameters component12() @NotNull - public final java.util.Map component13() + public final java.util.Map component13() public final boolean component14() @Nullable - public final java.util.Collection component15() + public final java.util.Collection component15() @NotNull - public final java.util.Map component16() + public final java.util.Map component16() public final boolean component17() public final boolean component18() @NotNull @@ -8416,53 +9231,53 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O @NotNull public final net.corda.testing.driver.PortAllocation component4() @NotNull - public final java.util.Map component5() + public final java.util.Map component5() public final boolean component6() public final boolean component7() public final boolean component8() @NotNull - public final java.util.List component9() + public final java.util.List component9() @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, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters) + 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, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters) @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, 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) + 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, 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) @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, 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.util.Map, 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, 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.util.Map, 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, 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.util.Map, boolean, 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, 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.util.Map, 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, 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.util.Map, boolean, boolean, java.time.Duration) + 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, 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.util.Map, boolean, boolean, java.time.Duration) @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, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Set) + 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, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Set) public boolean equals(Object) public final boolean getAllowHibernateToManageAppSchema() @Nullable - public final java.util.Collection getCordappsForAllNodes() + public final java.util.Collection getCordappsForAllNodes() @NotNull public final net.corda.testing.driver.PortAllocation getDebugPortAllocation() @NotNull public final java.nio.file.Path getDriverDirectory() @NotNull - public final java.util.Map getEnvironmentVariables() + public final java.util.Map getEnvironmentVariables() @NotNull - public final java.util.List getExtraCordappPackagesToScan() + public final java.util.List getExtraCordappPackagesToScan() public final boolean getInMemoryDB() @NotNull public final net.corda.testing.driver.JmxPolicy getJmxPolicy() @NotNull public final net.corda.core.node.NetworkParameters getNetworkParameters() @NotNull - public final java.util.Map getNotaryCustomOverrides() + public final java.util.Map getNotaryCustomOverrides() @NotNull public final java.time.Duration getNotaryHandleTimeout() @NotNull - public final java.util.List getNotarySpecs() + public final java.util.List getNotarySpecs() @NotNull public final net.corda.testing.driver.PortAllocation getPortAllocation() public final boolean getPremigrateH2Database() public final boolean getStartNodesInProcess() @NotNull - public final java.util.Map getSystemProperties() + public final java.util.Map getSystemProperties() public final boolean getUseTestClock() public final boolean getWaitForAllNodesToFinish() public int hashCode() @@ -8472,15 +9287,15 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O @NotNull public final net.corda.testing.driver.DriverParameters withAllowHibernateToManageAppSchema(boolean) @NotNull - public final net.corda.testing.driver.DriverParameters withCordappsForAllNodes(java.util.Collection) + public final net.corda.testing.driver.DriverParameters withCordappsForAllNodes(java.util.Collection) @NotNull public final net.corda.testing.driver.DriverParameters withDebugPortAllocation(net.corda.testing.driver.PortAllocation) @NotNull public final net.corda.testing.driver.DriverParameters withDriverDirectory(java.nio.file.Path) @NotNull - public final net.corda.testing.driver.DriverParameters withEnvironmentVariables(java.util.Map) + public final net.corda.testing.driver.DriverParameters withEnvironmentVariables(java.util.Map) @NotNull - public final net.corda.testing.driver.DriverParameters withExtraCordappPackagesToScan(java.util.List) + public final net.corda.testing.driver.DriverParameters withExtraCordappPackagesToScan(java.util.List) @NotNull public final net.corda.testing.driver.DriverParameters withInMemoryDB(boolean) @NotNull @@ -8490,17 +9305,17 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O @NotNull public final net.corda.testing.driver.DriverParameters withNetworkParameters(net.corda.core.node.NetworkParameters) @NotNull - public final net.corda.testing.driver.DriverParameters withNotaryCustomOverrides(java.util.Map) + public final net.corda.testing.driver.DriverParameters withNotaryCustomOverrides(java.util.Map) @NotNull public final net.corda.testing.driver.DriverParameters withNotaryHandleTimeout(java.time.Duration) @NotNull - public final net.corda.testing.driver.DriverParameters withNotarySpecs(java.util.List) + public final net.corda.testing.driver.DriverParameters withNotarySpecs(java.util.List) @NotNull public final net.corda.testing.driver.DriverParameters withPortAllocation(net.corda.testing.driver.PortAllocation) @NotNull public final net.corda.testing.driver.DriverParameters withStartNodesInProcess(boolean) @NotNull - public final net.corda.testing.driver.DriverParameters withSystemProperties(java.util.Map) + public final net.corda.testing.driver.DriverParameters withSystemProperties(java.util.Map) @NotNull public final net.corda.testing.driver.DriverParameters withUseTestClock(boolean) @NotNull @@ -8511,9 +9326,9 @@ public interface net.corda.testing.driver.InProcess extends net.corda.testing.dr @NotNull public abstract net.corda.core.node.ServiceHub getServices() @NotNull - public abstract rx.Observable registerInitiatedFlow(Class) + public abstract rx.Observable registerInitiatedFlow(Class) @NotNull - public abstract net.corda.core.concurrent.CordaFuture startFlow(net.corda.core.flows.FlowLogic) + public net.corda.core.concurrent.CordaFuture startFlow(net.corda.core.flows.FlowLogic) ## public final class net.corda.testing.driver.JmxPolicy extends java.lang.Object public () @@ -8534,6 +9349,7 @@ public final class net.corda.testing.driver.JmxPolicy extends java.lang.Object public int hashCode() @NotNull public String toString() + @NotNull public static final net.corda.testing.driver.JmxPolicy$Companion Companion ## public static final class net.corda.testing.driver.JmxPolicy$Companion extends java.lang.Object @@ -8558,49 +9374,59 @@ public interface net.corda.testing.driver.NodeHandle extends java.lang.AutoClose @NotNull public abstract net.corda.core.utilities.NetworkHostAndPort getRpcAdminAddress() @NotNull - public abstract java.util.List getRpcUsers() + public abstract java.util.List getRpcUsers() public abstract void stop() ## public final class net.corda.testing.driver.NodeParameters extends java.lang.Object public () - public (net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String) - public (net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String, java.util.Collection, java.util.Map>, ? extends Class>>) + public (net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String) + public (net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String, java.util.Collection, java.util.Map) public (net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String, java.util.Collection, java.util.Map, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String, java.util.Collection, java.util.Map>, ? extends Class>>, String, net.corda.core.utilities.NetworkHostAndPort) + public (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) + public (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, int, kotlin.jvm.internal.DefaultConstructorMarker) + public (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) public (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 (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, java.util.Map) + public (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, java.util.Map, int, kotlin.jvm.internal.DefaultConstructorMarker) @Nullable public final net.corda.core.identity.CordaX500Name component1() @Nullable public final net.corda.core.utilities.NetworkHostAndPort component10() @NotNull - public final java.util.List component2() + public final java.util.Map component11() + @NotNull + public final java.util.List component2() @NotNull public final net.corda.testing.driver.VerifierType component3() @NotNull - public final java.util.Map component4() + public final java.util.Map component4() @Nullable public final Boolean component5() @NotNull public final String component6() @NotNull - public final java.util.Collection component7() + public final java.util.Collection component7() @NotNull - public final java.util.Map>, Class>> component8() + public final java.util.Map component8() @Nullable public final String component9() @NotNull - public final net.corda.testing.driver.NodeParameters copy(net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String) + public final net.corda.testing.driver.NodeParameters copy(net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String) @NotNull - public final net.corda.testing.driver.NodeParameters copy(net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String, java.util.Collection, java.util.Map>, ? extends Class>>) + public final net.corda.testing.driver.NodeParameters copy(net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String, java.util.Collection, java.util.Map) @NotNull - public final net.corda.testing.driver.NodeParameters copy(net.corda.core.identity.CordaX500Name, java.util.List, net.corda.testing.driver.VerifierType, java.util.Map, Boolean, String, java.util.Collection, java.util.Map>, ? extends Class>>, String, net.corda.core.utilities.NetworkHostAndPort) + public final net.corda.testing.driver.NodeParameters copy(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) + @NotNull + public final net.corda.testing.driver.NodeParameters copy(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) + @NotNull + public final net.corda.testing.driver.NodeParameters copy(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, java.util.Map) public boolean equals(Object) @NotNull - public final java.util.Collection getAdditionalCordapps() + public final java.util.Collection getAdditionalCordapps() @NotNull - public final java.util.Map getCustomOverrides() + public final java.util.Map getCustomOverrides() @NotNull - public final java.util.Map>, Class>> getFlowOverrides() + public final java.util.Map getFlowOverrides() @Nullable public final String getLogLevelOverride() @NotNull @@ -8610,20 +9436,22 @@ public final class net.corda.testing.driver.NodeParameters extends java.lang.Obj @Nullable public final net.corda.core.utilities.NetworkHostAndPort getRpcAddress() @NotNull - public final java.util.List getRpcUsers() + public final java.util.List getRpcUsers() @Nullable public final Boolean getStartInSameProcess() @NotNull + public final java.util.Map getSystemProperties() + @NotNull public final net.corda.testing.driver.VerifierType getVerifierType() public int hashCode() @NotNull public String toString() @NotNull - public final net.corda.testing.driver.NodeParameters withAdditionalCordapps(java.util.Set) + public final net.corda.testing.driver.NodeParameters withAdditionalCordapps(java.util.Set) @NotNull - public final net.corda.testing.driver.NodeParameters withCustomOverrides(java.util.Map) + public final net.corda.testing.driver.NodeParameters withCustomOverrides(java.util.Map) @NotNull - public final net.corda.testing.driver.NodeParameters withFlowOverrides(java.util.Map>, ? extends Class>>) + public final net.corda.testing.driver.NodeParameters withFlowOverrides(java.util.Map) @NotNull public final net.corda.testing.driver.NodeParameters withLogLevelOverride(String) @NotNull @@ -8631,26 +9459,26 @@ public final class net.corda.testing.driver.NodeParameters extends java.lang.Obj @NotNull public final net.corda.testing.driver.NodeParameters withProvidedName(net.corda.core.identity.CordaX500Name) @NotNull - public final net.corda.testing.driver.NodeParameters withRpcUsers(java.util.List) + public final net.corda.testing.driver.NodeParameters withRpcUsers(java.util.List) @NotNull public final net.corda.testing.driver.NodeParameters withStartInSameProcess(Boolean) @NotNull public final net.corda.testing.driver.NodeParameters withVerifierType(net.corda.testing.driver.VerifierType) ## public final class net.corda.testing.driver.NotaryHandle extends java.lang.Object - public (net.corda.core.identity.Party, boolean, net.corda.core.concurrent.CordaFuture>) + public (net.corda.core.identity.Party, boolean, net.corda.core.concurrent.CordaFuture) @NotNull public final net.corda.core.identity.Party component1() public final boolean component2() @NotNull - public final net.corda.core.concurrent.CordaFuture> component3() + public final net.corda.core.concurrent.CordaFuture component3() @NotNull - public final net.corda.testing.driver.NotaryHandle copy(net.corda.core.identity.Party, boolean, net.corda.core.concurrent.CordaFuture>) + public final net.corda.testing.driver.NotaryHandle copy(net.corda.core.identity.Party, boolean, net.corda.core.concurrent.CordaFuture) public boolean equals(Object) @NotNull public final net.corda.core.identity.Party getIdentity() @NotNull - public final net.corda.core.concurrent.CordaFuture> getNodeHandles() + public final net.corda.core.concurrent.CordaFuture getNodeHandles() public final boolean getValidating() public int hashCode() @NotNull @@ -8669,6 +9497,7 @@ public abstract class net.corda.testing.driver.PortAllocation extends java.lang. @NotNull public final net.corda.core.utilities.NetworkHostAndPort nextHostAndPort() public abstract int nextPort() + @NotNull public static final net.corda.testing.driver.PortAllocation$Companion Companion public static final int DEFAULT_START_PORT = 10000 public static final int FIRST_EPHEMERAL_PORT = 30000 @@ -8691,6 +9520,8 @@ public class net.corda.testing.driver.SharedMemoryIncremental extends net.corda. public static net.corda.testing.driver.SharedMemoryIncremental INSTANCE ## public final class net.corda.testing.driver.VerifierType extends java.lang.Enum + @NotNull + public static kotlin.enums.EnumEntries getEntries() public static net.corda.testing.driver.VerifierType valueOf(String) public static net.corda.testing.driver.VerifierType[] values() ## @@ -8713,19 +9544,23 @@ public final class net.corda.testing.driver.WebserverHandle extends java.lang.Ob ## public final class net.corda.testing.flows.FlowTestsUtilsKt extends java.lang.Object @NotNull - public static final kotlin.Pair from(T, net.corda.core.flows.FlowSession) + public static final kotlin.Pair from(T, net.corda.core.flows.FlowSession) @NotNull - public static final R from(java.util.Map>, net.corda.core.flows.FlowSession) + public static final R from(java.util.Map, net.corda.core.flows.FlowSession) @NotNull - public static final kotlin.Pair> from(kotlin.reflect.KClass, net.corda.core.flows.FlowSession) + public static final kotlin.Pair from(kotlin.reflect.KClass, net.corda.core.flows.FlowSession) @Suspendable @NotNull - public static final java.util.List> receiveAll(net.corda.core.flows.FlowLogic, Class, net.corda.core.flows.FlowSession, net.corda.core.flows.FlowSession...) + public static final java.util.List receiveAll(net.corda.core.flows.FlowLogic, Class, net.corda.core.flows.FlowSession, net.corda.core.flows.FlowSession...) @Suspendable @NotNull - public static final java.util.Map> receiveAll(net.corda.core.flows.FlowLogic, kotlin.Pair>, kotlin.Pair>...) + public static final java.util.Map receiveAll(net.corda.core.flows.FlowLogic, kotlin.Pair, kotlin.Pair>...) + @Suspendable + public static final java.util.List receiveAll(net.corda.core.flows.FlowLogic, net.corda.core.flows.FlowSession, net.corda.core.flows.FlowSession...) + public static final net.corda.core.concurrent.CordaFuture registerCordappFlowFactory(net.corda.testing.node.internal.TestStartedNode, kotlin.reflect.KClass, int, kotlin.jvm.functions.Function1) @NotNull - public static final rx.Observable registerCoreFlowFactory(net.corda.testing.node.internal.TestStartedNode, Class>, Class, kotlin.jvm.functions.Function1, boolean) + public static final rx.Observable registerCoreFlowFactory(net.corda.testing.node.internal.TestStartedNode, Class, Class, kotlin.jvm.functions.Function1, boolean) + public static final void waitForAllFlowsToComplete(net.corda.testing.driver.NodeHandle, int, long) ## @DoNotImplement public abstract class net.corda.testing.node.ClusterSpec extends java.lang.Object @@ -8747,20 +9582,22 @@ public static final class net.corda.testing.node.ClusterSpec$Raft extends net.co 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) + @NotNull public static final net.corda.testing.node.DatabaseSnapshot INSTANCE ## @ThreadSafe public final class net.corda.testing.node.InMemoryMessagingNetwork extends net.corda.core.serialization.SingletonSerializeAsToken public (boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, org.apache.activemq.artemis.utils.ReusableLatch, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final synchronized java.util.List getEndpointsExternal() + public final synchronized java.util.List getEndpointsExternal() @NotNull - public final rx.Observable getReceivedMessages() + public final rx.Observable getReceivedMessages() @NotNull - public final rx.Observable getSentMessages() + public final rx.Observable getSentMessages() @Nullable public final net.corda.testing.node.InMemoryMessagingNetwork$MessageTransfer pumpSend(boolean) public final void stop() + @NotNull public static final net.corda.testing.node.InMemoryMessagingNetwork$Companion Companion ## public static final class net.corda.testing.node.InMemoryMessagingNetwork$Companion extends java.lang.Object @@ -8794,6 +9631,7 @@ public static final class net.corda.testing.node.InMemoryMessagingNetwork$Messag public final net.corda.testing.node.InMemoryMessagingNetwork$PeerHandle getSender() @NotNull public String toString() + @NotNull public static final net.corda.testing.node.InMemoryMessagingNetwork$MessageTransfer$Companion Companion ## public static final class net.corda.testing.node.InMemoryMessagingNetwork$MessageTransfer$Companion extends java.lang.Object @@ -8803,6 +9641,7 @@ public static final class net.corda.testing.node.InMemoryMessagingNetwork$MockMe public (net.corda.testing.node.internal.MockNodeMessagingService, kotlin.jvm.internal.DefaultConstructorMarker) @Nullable public final net.corda.testing.node.InMemoryMessagingNetwork$MessageTransfer pumpReceive(boolean) + @NotNull public static final net.corda.testing.node.InMemoryMessagingNetwork$MockMessagingService$Companion Companion ## public static final class net.corda.testing.node.InMemoryMessagingNetwork$MockMessagingService$Companion extends java.lang.Object @@ -8827,7 +9666,7 @@ public static final class net.corda.testing.node.InMemoryMessagingNetwork$PeerHa @DoNotImplement public abstract static class net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) - public abstract A pickNext(net.corda.testing.node.InMemoryMessagingNetwork$DistributedServiceHandle, java.util.List) + public abstract A pickNext(net.corda.testing.node.InMemoryMessagingNetwork$DistributedServiceHandle, java.util.List) ## @DoNotImplement public static final class net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy$Random extends net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy @@ -8836,12 +9675,12 @@ public static final class net.corda.testing.node.InMemoryMessagingNetwork$Servic public (java.util.SplittableRandom, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull public final java.util.SplittableRandom getRandom() - public A pickNext(net.corda.testing.node.InMemoryMessagingNetwork$DistributedServiceHandle, java.util.List) + public A pickNext(net.corda.testing.node.InMemoryMessagingNetwork$DistributedServiceHandle, java.util.List) ## @DoNotImplement public static final class net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy$RoundRobin extends net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy public () - public A pickNext(net.corda.testing.node.InMemoryMessagingNetwork$DistributedServiceHandle, java.util.List) + public A pickNext(net.corda.testing.node.InMemoryMessagingNetwork$DistributedServiceHandle, java.util.List) ## public final class net.corda.testing.node.MockNetFlowTimeOut extends java.lang.Object public (java.time.Duration, int, double) @@ -8862,10 +9701,10 @@ public final class net.corda.testing.node.MockNetNotaryConfig extends java.lang. public final boolean getValidating() ## public class net.corda.testing.node.MockNetwork extends java.lang.Object - public (java.util.List) - public (java.util.List, net.corda.testing.node.MockNetworkParameters) + public (java.util.List) + public (java.util.List, net.corda.testing.node.MockNetworkParameters) public (java.util.List, net.corda.testing.node.MockNetworkParameters, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (java.util.List, net.corda.testing.node.MockNetworkParameters, boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, java.util.List, net.corda.core.node.NetworkParameters) + public (java.util.List, net.corda.testing.node.MockNetworkParameters, boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, java.util.List, net.corda.core.node.NetworkParameters) public (java.util.List, net.corda.testing.node.MockNetworkParameters, boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, java.util.List, net.corda.core.node.NetworkParameters, int, kotlin.jvm.internal.DefaultConstructorMarker) public (net.corda.testing.node.MockNetworkParameters) @NotNull @@ -8897,7 +9736,7 @@ public class net.corda.testing.node.MockNetwork extends java.lang.Object @NotNull public final net.corda.testing.node.UnstartedMockNode createUnstartedNode(net.corda.testing.node.MockNodeParameters) @NotNull - public final java.util.List getCordappPackages() + public final java.util.List getCordappPackages() @NotNull public final net.corda.core.identity.Party getDefaultNotaryIdentity() @NotNull @@ -8909,9 +9748,9 @@ public class net.corda.testing.node.MockNetwork extends java.lang.Object public final boolean getNetworkSendManuallyPumped() public final int getNextNodeId() @NotNull - public final java.util.List getNotaryNodes() + public final java.util.List getNotaryNodes() @NotNull - public final java.util.List getNotarySpecs() + public final java.util.List getNotarySpecs() @NotNull public final net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy getServicePeerAllocationStrategy() public final boolean getThreadPerNode() @@ -8945,32 +9784,32 @@ public final class net.corda.testing.node.MockNetworkNotarySpec extends java.lan ## public final class net.corda.testing.node.MockNetworkParameters extends java.lang.Object public () - public (java.util.Collection) - public (boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, java.util.List, net.corda.core.node.NetworkParameters) - public (boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, java.util.List, net.corda.core.node.NetworkParameters, java.util.Collection) + public (java.util.Collection) + public (boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, java.util.List, net.corda.core.node.NetworkParameters) + public (boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, java.util.List, net.corda.core.node.NetworkParameters, java.util.Collection) public (boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, java.util.List, net.corda.core.node.NetworkParameters, java.util.Collection, int, kotlin.jvm.internal.DefaultConstructorMarker) public final boolean component1() public final boolean component2() @NotNull public final net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy component3() @NotNull - public final java.util.List component4() + public final java.util.List component4() @NotNull public final net.corda.core.node.NetworkParameters component5() @NotNull - public final java.util.Collection component6() + public final java.util.Collection component6() @NotNull - public final net.corda.testing.node.MockNetworkParameters copy(boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, java.util.List, net.corda.core.node.NetworkParameters) + public final net.corda.testing.node.MockNetworkParameters copy(boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, java.util.List, net.corda.core.node.NetworkParameters) @NotNull - public final net.corda.testing.node.MockNetworkParameters copy(boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, java.util.List, net.corda.core.node.NetworkParameters, java.util.Collection) + public final net.corda.testing.node.MockNetworkParameters copy(boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, java.util.List, net.corda.core.node.NetworkParameters, java.util.Collection) public boolean equals(Object) @NotNull - public final java.util.Collection getCordappsForAllNodes() + public final java.util.Collection getCordappsForAllNodes() @NotNull public final net.corda.core.node.NetworkParameters getNetworkParameters() public final boolean getNetworkSendManuallyPumped() @NotNull - public final java.util.List getNotarySpecs() + public final java.util.List getNotarySpecs() @NotNull public final net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy getServicePeerAllocationStrategy() public final boolean getThreadPerNode() @@ -8978,13 +9817,13 @@ public final class net.corda.testing.node.MockNetworkParameters extends java.lan @NotNull public String toString() @NotNull - public final net.corda.testing.node.MockNetworkParameters withCordappsForAllNodes(java.util.Collection) + public final net.corda.testing.node.MockNetworkParameters withCordappsForAllNodes(java.util.Collection) @NotNull public final net.corda.testing.node.MockNetworkParameters withNetworkParameters(net.corda.core.node.NetworkParameters) @NotNull public final net.corda.testing.node.MockNetworkParameters withNetworkSendManuallyPumped(boolean) @NotNull - public final net.corda.testing.node.MockNetworkParameters withNotarySpecs(java.util.List) + public final net.corda.testing.node.MockNetworkParameters withNotarySpecs(java.util.List) @NotNull public final net.corda.testing.node.MockNetworkParameters withServicePeerAllocationStrategy(net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy) @NotNull @@ -8992,10 +9831,10 @@ public final class net.corda.testing.node.MockNetworkParameters extends java.lan ## public final class net.corda.testing.node.MockNodeConfigOverrides extends java.lang.Object public () - public (java.util.Map, net.corda.testing.node.MockNetNotaryConfig, net.corda.testing.node.MockNetFlowTimeOut) + public (java.util.Map, net.corda.testing.node.MockNetNotaryConfig, net.corda.testing.node.MockNetFlowTimeOut) public (java.util.Map, net.corda.testing.node.MockNetNotaryConfig, net.corda.testing.node.MockNetFlowTimeOut, int, kotlin.jvm.internal.DefaultConstructorMarker) @Nullable - public final java.util.Map getExtraDataSourceProperties() + public final java.util.Map getExtraDataSourceProperties() @Nullable public final net.corda.testing.node.MockNetFlowTimeOut getFlowTimeout() @Nullable @@ -9005,7 +9844,7 @@ public final class net.corda.testing.node.MockNodeParameters extends java.lang.O public () public (Integer, net.corda.core.identity.CordaX500Name, java.math.BigInteger, net.corda.testing.node.MockNodeConfigOverrides) public (Integer, net.corda.core.identity.CordaX500Name, java.math.BigInteger, net.corda.testing.node.MockNodeConfigOverrides, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (Integer, net.corda.core.identity.CordaX500Name, java.math.BigInteger, net.corda.testing.node.MockNodeConfigOverrides, java.util.Collection) + public (Integer, net.corda.core.identity.CordaX500Name, java.math.BigInteger, net.corda.testing.node.MockNodeConfigOverrides, java.util.Collection) public (Integer, net.corda.core.identity.CordaX500Name, java.math.BigInteger, net.corda.testing.node.MockNodeConfigOverrides, java.util.Collection, int, kotlin.jvm.internal.DefaultConstructorMarker) @Nullable public final Integer component1() @@ -9016,14 +9855,14 @@ public final class net.corda.testing.node.MockNodeParameters extends java.lang.O @Nullable public final net.corda.testing.node.MockNodeConfigOverrides component4() @NotNull - public final java.util.Collection component5() + public final java.util.Collection component5() @NotNull public final net.corda.testing.node.MockNodeParameters copy(Integer, net.corda.core.identity.CordaX500Name, java.math.BigInteger, net.corda.testing.node.MockNodeConfigOverrides) @NotNull - public final net.corda.testing.node.MockNodeParameters copy(Integer, net.corda.core.identity.CordaX500Name, java.math.BigInteger, net.corda.testing.node.MockNodeConfigOverrides, java.util.Collection) + public final net.corda.testing.node.MockNodeParameters copy(Integer, net.corda.core.identity.CordaX500Name, java.math.BigInteger, net.corda.testing.node.MockNodeConfigOverrides, java.util.Collection) public boolean equals(Object) @NotNull - public final java.util.Collection getAdditionalCordapps() + public final java.util.Collection getAdditionalCordapps() @Nullable public final net.corda.testing.node.MockNodeConfigOverrides getConfigOverrides() @NotNull @@ -9036,7 +9875,7 @@ public final class net.corda.testing.node.MockNodeParameters extends java.lang.O @NotNull public String toString() @NotNull - public final net.corda.testing.node.MockNodeParameters withAdditionalCordapps(java.util.Collection) + public final net.corda.testing.node.MockNodeParameters withAdditionalCordapps(java.util.Collection) @NotNull public final net.corda.testing.node.MockNodeParameters withConfigOverrides(net.corda.testing.node.MockNodeConfigOverrides) @NotNull @@ -9048,22 +9887,22 @@ public final class net.corda.testing.node.MockNodeParameters extends java.lang.O ## public class net.corda.testing.node.MockServices extends java.lang.Object implements net.corda.core.node.ServiceHub public () - public (Iterable) - public (Iterable, net.corda.core.identity.CordaX500Name) - public (Iterable, net.corda.core.identity.CordaX500Name, java.security.KeyPair, java.security.KeyPair...) - public (Iterable, net.corda.core.identity.CordaX500Name, net.corda.core.node.services.IdentityService) + public (Iterable) + public (Iterable, net.corda.core.identity.CordaX500Name) + public (Iterable, net.corda.core.identity.CordaX500Name, java.security.KeyPair, java.security.KeyPair...) + public (Iterable, net.corda.core.identity.CordaX500Name, net.corda.core.node.services.IdentityService) public (Iterable, net.corda.core.identity.CordaX500Name, net.corda.core.node.services.IdentityService, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (Iterable, net.corda.core.identity.CordaX500Name, net.corda.core.node.services.IdentityService, java.security.KeyPair, java.security.KeyPair...) + public (Iterable, net.corda.core.identity.CordaX500Name, net.corda.core.node.services.IdentityService, java.security.KeyPair, java.security.KeyPair...) public (Iterable, net.corda.core.identity.CordaX500Name, net.corda.core.node.services.IdentityService, java.security.KeyPair, java.security.KeyPair[], int, kotlin.jvm.internal.DefaultConstructorMarker) - public (Iterable, net.corda.testing.core.TestIdentity, net.corda.core.node.services.IdentityService, net.corda.core.node.NetworkParameters, java.security.KeyPair...) - public (Iterable, net.corda.testing.core.TestIdentity, net.corda.core.node.services.IdentityService, net.corda.core.node.NetworkParameters, java.security.KeyPair[], net.corda.core.node.services.KeyManagementService) - public (Iterable, net.corda.testing.core.TestIdentity, net.corda.core.node.services.IdentityService, java.security.KeyPair...) + public (Iterable, net.corda.testing.core.TestIdentity, net.corda.core.node.services.IdentityService, net.corda.core.node.NetworkParameters, java.security.KeyPair...) + public (Iterable, net.corda.testing.core.TestIdentity, net.corda.core.node.services.IdentityService, net.corda.core.node.NetworkParameters, java.security.KeyPair[], net.corda.core.node.services.KeyManagementService) + public (Iterable, net.corda.testing.core.TestIdentity, net.corda.core.node.services.IdentityService, java.security.KeyPair...) public (Iterable, net.corda.testing.core.TestIdentity, net.corda.core.node.services.IdentityService, java.security.KeyPair[], int, kotlin.jvm.internal.DefaultConstructorMarker) - public (Iterable, net.corda.testing.core.TestIdentity, java.security.KeyPair...) - public (java.util.List, net.corda.core.identity.CordaX500Name, net.corda.core.node.services.IdentityService, net.corda.core.node.NetworkParameters) - public (java.util.List, net.corda.core.identity.CordaX500Name, net.corda.core.node.services.IdentityService, net.corda.core.node.NetworkParameters, java.security.KeyPair) - public (java.util.List, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, net.corda.testing.core.TestIdentity...) - public (java.util.List, net.corda.testing.core.TestIdentity, net.corda.testing.core.TestIdentity...) + public (Iterable, net.corda.testing.core.TestIdentity, java.security.KeyPair...) + public (java.util.List, net.corda.core.identity.CordaX500Name, net.corda.core.node.services.IdentityService, net.corda.core.node.NetworkParameters) + public (java.util.List, net.corda.core.identity.CordaX500Name, net.corda.core.node.services.IdentityService, net.corda.core.node.NetworkParameters, java.security.KeyPair) + public (java.util.List, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, net.corda.testing.core.TestIdentity...) + public (java.util.List, net.corda.testing.core.TestIdentity, net.corda.testing.core.TestIdentity...) public (net.corda.core.identity.CordaX500Name) public (net.corda.core.identity.CordaX500Name, java.security.KeyPair, java.security.KeyPair...) public (net.corda.core.identity.CordaX500Name, net.corda.core.node.services.IdentityService) @@ -9075,23 +9914,9 @@ public class net.corda.testing.node.MockServices extends java.lang.Object implem public (net.corda.testing.core.TestIdentity, net.corda.testing.core.TestIdentity...) public final void addMockCordapp(String) @NotNull - public net.corda.core.transactions.SignedTransaction addSignature(net.corda.core.transactions.SignedTransaction) + public T cordaService(Class) @NotNull - public net.corda.core.transactions.SignedTransaction addSignature(net.corda.core.transactions.SignedTransaction, java.security.PublicKey) - @NotNull - public T cordaService(Class) - @NotNull - public T cordaTelemetryComponent(Class) - @NotNull - public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction) - @NotNull - public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.FilteredTransaction, java.security.PublicKey) - @NotNull - public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction) - @NotNull - public net.corda.core.crypto.TransactionSignature createSignature(net.corda.core.transactions.SignedTransaction, java.security.PublicKey) - @NotNull - public net.corda.core.cordapp.CordappContext getAppContext() + public T cordaTelemetryComponent(Class) @NotNull public final net.corda.testing.services.MockAttachmentStorage getAttachments() @NotNull @@ -9121,8 +9946,6 @@ public class net.corda.testing.node.MockServices extends java.lang.Object implem @NotNull public net.corda.core.internal.telemetry.TelemetryServiceImpl getTelemetryService() @NotNull - public net.corda.core.node.services.TransactionVerifierService getTransactionVerifierService() - @NotNull public net.corda.core.node.services.TransactionStorage getValidatedTransactions() @NotNull public net.corda.core.node.services.VaultService getVaultService() @@ -9131,39 +9954,30 @@ public class net.corda.testing.node.MockServices extends java.lang.Object implem @NotNull public net.corda.core.contracts.Attachment loadContractAttachment(net.corda.core.contracts.StateRef) @NotNull - public net.corda.core.contracts.TransactionState loadState(net.corda.core.contracts.StateRef) + public net.corda.core.contracts.TransactionState loadState(net.corda.core.contracts.StateRef) @NotNull - public java.util.Set> loadStates(java.util.Set) + public java.util.Set loadStates(java.util.Set) @NotNull public static final java.util.Properties makeTestDataSourceProperties(String) @NotNull - public static final kotlin.Pair makeTestDatabaseAndMockServices(java.util.List, net.corda.core.node.services.IdentityService, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, java.security.KeyPair...) + public static final kotlin.Pair makeTestDatabaseAndMockServices(java.util.List, net.corda.core.node.services.IdentityService, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, java.security.KeyPair...) @NotNull - public static final kotlin.Pair makeTestDatabaseAndMockServices(java.util.List, net.corda.core.node.services.IdentityService, net.corda.testing.core.TestIdentity, java.security.KeyPair...) + public static final kotlin.Pair makeTestDatabaseAndMockServices(java.util.List, net.corda.core.node.services.IdentityService, net.corda.testing.core.TestIdentity, java.security.KeyPair...) @NotNull - public static final kotlin.Pair makeTestDatabaseAndPersistentServices(java.util.List, net.corda.testing.core.TestIdentity, java.util.Set, java.util.Set) + public static final kotlin.Pair makeTestDatabaseAndPersistentServices(java.util.List, net.corda.testing.core.TestIdentity, java.util.Set, java.util.Set) @NotNull - public static final kotlin.Pair makeTestDatabaseAndPersistentServices(java.util.List, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, java.util.Set, java.util.Set) + public static final kotlin.Pair makeTestDatabaseAndPersistentServices(java.util.List, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, java.util.Set, java.util.Set) @NotNull - public static final kotlin.Pair makeTestDatabaseAndPersistentServices(java.util.List, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, java.util.Set, java.util.Set, net.corda.testing.internal.TestingNamedCacheFactory) - public void recordTransactions(Iterable) - public void recordTransactions(net.corda.core.node.StatesToRecord, Iterable) - public void recordTransactions(net.corda.core.transactions.SignedTransaction, net.corda.core.transactions.SignedTransaction...) - public void recordTransactions(boolean, Iterable) - public void recordTransactions(boolean, net.corda.core.transactions.SignedTransaction, net.corda.core.transactions.SignedTransaction...) + public static final kotlin.Pair makeTestDatabaseAndPersistentServices(java.util.List, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, java.util.Set, java.util.Set, net.corda.testing.internal.TestingNamedCacheFactory) + public final void recordTransactions(Iterable, boolean) + public void recordTransactions(net.corda.core.node.StatesToRecord, Iterable) + public final void recordTransactions(net.corda.core.transactions.SignedTransaction, boolean) @NotNull - public Void registerUnloadHandler(kotlin.jvm.functions.Function0) + public Void registerUnloadHandler(kotlin.jvm.functions.Function0) public void setNetworkParametersService(net.corda.core.node.services.NetworkParametersService) + public void withEntityManager(java.util.function.Consumer) + public T withEntityManager(kotlin.jvm.functions.Function1) @NotNull - public net.corda.core.transactions.SignedTransaction signInitialTransaction(net.corda.core.transactions.TransactionBuilder) - @NotNull - public net.corda.core.transactions.SignedTransaction signInitialTransaction(net.corda.core.transactions.TransactionBuilder, Iterable) - @NotNull - public net.corda.core.transactions.SignedTransaction signInitialTransaction(net.corda.core.transactions.TransactionBuilder, java.security.PublicKey) - @NotNull - public net.corda.core.contracts.StateAndRef toStateAndRef(net.corda.core.contracts.StateRef) - public void withEntityManager(java.util.function.Consumer) - public T withEntityManager(kotlin.jvm.functions.Function1) public static final net.corda.testing.node.MockServices$Companion Companion ## public static final class net.corda.testing.node.MockServices$Companion extends java.lang.Object @@ -9171,59 +9985,59 @@ public static final class net.corda.testing.node.MockServices$Companion extends @NotNull public final java.util.Properties makeTestDataSourceProperties(String) @NotNull - public final kotlin.Pair makeTestDatabaseAndMockServices(java.util.List, net.corda.core.node.services.IdentityService, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, java.security.KeyPair...) + public final kotlin.Pair makeTestDatabaseAndMockServices(java.util.List, net.corda.core.node.services.IdentityService, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, java.security.KeyPair...) @NotNull - public final kotlin.Pair makeTestDatabaseAndMockServices(java.util.List, net.corda.core.node.services.IdentityService, net.corda.testing.core.TestIdentity, java.security.KeyPair...) + public final kotlin.Pair makeTestDatabaseAndMockServices(java.util.List, net.corda.core.node.services.IdentityService, net.corda.testing.core.TestIdentity, java.security.KeyPair...) @NotNull - public final kotlin.Pair makeTestDatabaseAndPersistentServices(java.util.List, net.corda.testing.core.TestIdentity, java.util.Set, java.util.Set) + public final kotlin.Pair makeTestDatabaseAndPersistentServices(java.util.List, net.corda.testing.core.TestIdentity, java.util.Set, java.util.Set) @NotNull - public final kotlin.Pair makeTestDatabaseAndPersistentServices(java.util.List, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, java.util.Set, java.util.Set) + public final kotlin.Pair makeTestDatabaseAndPersistentServices(java.util.List, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, java.util.Set, java.util.Set) @NotNull - public final kotlin.Pair makeTestDatabaseAndPersistentServices(java.util.List, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, java.util.Set, java.util.Set, net.corda.testing.internal.TestingNamedCacheFactory) + public final kotlin.Pair makeTestDatabaseAndPersistentServices(java.util.List, net.corda.testing.core.TestIdentity, net.corda.core.node.NetworkParameters, java.util.Set, java.util.Set, net.corda.testing.internal.TestingNamedCacheFactory) ## public final class net.corda.testing.node.MockServicesKt extends java.lang.Object @NotNull - public static final T createMockCordaService(net.corda.testing.node.MockServices, kotlin.jvm.functions.Function1) + public static final T createMockCordaService(net.corda.testing.node.MockServices, kotlin.jvm.functions.Function1) @NotNull public static final net.corda.core.node.services.IdentityService makeTestIdentityService(net.corda.core.identity.PartyAndCertificate...) ## public final class net.corda.testing.node.NodeTestUtils extends java.lang.Object @NotNull - public static final net.corda.testing.dsl.LedgerDSL ledger(net.corda.core.node.ServiceHub, kotlin.jvm.functions.Function1, kotlin.Unit>) + public static final net.corda.testing.dsl.LedgerDSL ledger(net.corda.core.node.ServiceHub, kotlin.jvm.functions.Function1) @NotNull - public static final net.corda.testing.dsl.LedgerDSL ledger(net.corda.core.node.ServiceHub, net.corda.core.identity.Party, kotlin.jvm.functions.Function1, kotlin.Unit>) + public static final net.corda.testing.dsl.LedgerDSL ledger(net.corda.core.node.ServiceHub, net.corda.core.identity.Party, kotlin.jvm.functions.Function1) @NotNull public static final net.corda.core.context.Actor testActor(net.corda.core.identity.CordaX500Name) @NotNull public static final net.corda.core.context.InvocationContext testContext(net.corda.core.identity.CordaX500Name) @NotNull - public static final net.corda.testing.dsl.LedgerDSL transaction(net.corda.core.node.ServiceHub, kotlin.jvm.functions.Function1, ? extends net.corda.testing.dsl.EnforceVerifyOrFail>) + public static final net.corda.testing.dsl.LedgerDSL transaction(net.corda.core.node.ServiceHub, kotlin.jvm.functions.Function1) @NotNull - public static final net.corda.testing.dsl.LedgerDSL transaction(net.corda.core.node.ServiceHub, net.corda.core.identity.Party, kotlin.jvm.functions.Function1, ? extends net.corda.testing.dsl.EnforceVerifyOrFail>) + public static final net.corda.testing.dsl.LedgerDSL transaction(net.corda.core.node.ServiceHub, net.corda.core.identity.Party, kotlin.jvm.functions.Function1) ## public final class net.corda.testing.node.NotarySpec extends java.lang.Object - public (net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec) + public (net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec) public (net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec, String) + public (net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec, String) public (net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec, String, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec, String, boolean) + public (net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec, String, boolean) public (net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec, String, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec, boolean) + public (net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec, boolean) public (net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull public final net.corda.core.identity.CordaX500Name component1() public final boolean component2() @NotNull - public final java.util.List component3() + public final java.util.List component3() @NotNull public final net.corda.testing.driver.VerifierType component4() @Nullable public final net.corda.testing.node.ClusterSpec component5() public final boolean component6() @NotNull - public final net.corda.testing.node.NotarySpec copy(net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec) + public final net.corda.testing.node.NotarySpec copy(net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec) @NotNull - public final net.corda.testing.node.NotarySpec copy(net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec, boolean) + public final net.corda.testing.node.NotarySpec copy(net.corda.core.identity.CordaX500Name, boolean, java.util.List, net.corda.testing.driver.VerifierType, net.corda.testing.node.ClusterSpec, boolean) public boolean equals(Object) @Nullable public final net.corda.testing.node.ClusterSpec getCluster() @@ -9232,7 +10046,7 @@ public final class net.corda.testing.node.NotarySpec extends java.lang.Object @NotNull public final net.corda.core.identity.CordaX500Name getName() @NotNull - public final java.util.List getRpcUsers() + public final java.util.List getRpcUsers() public final boolean getStartInProcess() public final boolean getValidating() @NotNull @@ -9245,7 +10059,7 @@ public final class net.corda.testing.node.NotarySpec extends java.lang.Object public final class net.corda.testing.node.StartedMockNode extends java.lang.Object public (net.corda.testing.node.internal.TestStartedNode, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull - public final java.util.List>> findStateMachines(Class) + public final java.util.List findStateMachines(Class) public final int getId() @NotNull public final net.corda.core.node.NodeInfo getInfo() @@ -9254,13 +10068,14 @@ public final class net.corda.testing.node.StartedMockNode extends java.lang.Obje @Nullable public final net.corda.testing.node.InMemoryMessagingNetwork$MessageTransfer pumpReceive(boolean) @NotNull - public final rx.Observable registerInitiatedFlow(Class) + public final rx.Observable registerInitiatedFlow(Class) @NotNull - public final rx.Observable registerInitiatedFlow(Class>, Class) + public final rx.Observable registerInitiatedFlow(Class, Class) @NotNull - public final net.corda.core.concurrent.CordaFuture startFlow(net.corda.core.flows.FlowLogic) + public final net.corda.core.concurrent.CordaFuture startFlow(net.corda.core.flows.FlowLogic) public final void stop() - public final T transaction(kotlin.jvm.functions.Function0) + public final T transaction(kotlin.jvm.functions.Function0) + @NotNull public static final net.corda.testing.node.StartedMockNode$Companion Companion ## public static final class net.corda.testing.node.StartedMockNode$Companion extends java.lang.Object @@ -9278,9 +10093,10 @@ public abstract class net.corda.testing.node.TestCordapp extends java.lang.Objec @NotNull public static final net.corda.testing.node.TestCordapp findCordapp(String) @NotNull - public abstract java.util.Map getConfig() + public abstract java.util.Map getConfig() + @NotNull + public abstract net.corda.testing.node.TestCordapp withConfig(java.util.Map) @NotNull - public abstract net.corda.testing.node.TestCordapp withConfig(java.util.Map) public static final net.corda.testing.node.TestCordapp$Companion Companion ## public static final class net.corda.testing.node.TestCordapp$Companion extends java.lang.Object @@ -9294,30 +10110,31 @@ public final class net.corda.testing.node.UnstartedMockNode extends java.lang.Ob @NotNull public final net.corda.testing.node.StartedMockNode getStarted() @NotNull - public final T installCordaService(Class) + public final T installCordaService(Class) public final boolean isStarted() @NotNull public final net.corda.testing.node.StartedMockNode start() + @NotNull public static final net.corda.testing.node.UnstartedMockNode$Companion Companion ## public static final class net.corda.testing.node.UnstartedMockNode$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) ## public final class net.corda.testing.node.User extends java.lang.Object - public (String, String, java.util.Set) + public (String, String, java.util.Set) @NotNull public final String component1() @NotNull public final String component2() @NotNull - public final java.util.Set component3() + public final java.util.Set component3() @NotNull - public final net.corda.testing.node.User copy(String, String, java.util.Set) + public final net.corda.testing.node.User copy(String, String, java.util.Set) public boolean equals(Object) @NotNull public final String getPassword() @NotNull - public final java.util.Set getPermissions() + public final java.util.Set getPermissions() @NotNull public final String getUsername() public int hashCode() @@ -9330,29 +10147,29 @@ public class net.corda.client.rpc.ConnectionFailureException extends net.corda.c public (Throwable, int, kotlin.jvm.internal.DefaultConstructorMarker) ## public final class net.corda.client.rpc.CordaRPCClient extends java.lang.Object - public (java.util.List) - public (java.util.List, java.util.Set>) - public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration) - public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration, java.util.Set>) - public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions) - public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) + public (java.util.List) + public (java.util.List, java.util.Set) + public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration) + public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration, java.util.Set) + public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions) + public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, java.util.Set>) + public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, java.util.Set) public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, java.util.Set, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, java.util.Set>) + public (java.util.List, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, java.util.Set) public (net.corda.core.utilities.NetworkHostAndPort) - public (net.corda.core.utilities.NetworkHostAndPort, java.util.Set>) + public (net.corda.core.utilities.NetworkHostAndPort, java.util.Set) public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration) public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, int, kotlin.jvm.internal.DefaultConstructorMarker) public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, ClassLoader) public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, ClassLoader, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, java.util.Set>) + public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, java.util.Set) public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions) public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, java.util.Set>) + public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, java.util.Set) public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, java.util.Set, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, java.util.Set>) + public (net.corda.core.utilities.NetworkHostAndPort, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, java.util.Set) public (net.corda.core.utilities.NetworkHostAndPort, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) public (net.corda.core.utilities.NetworkHostAndPort, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull @@ -9371,7 +10188,8 @@ public final class net.corda.client.rpc.CordaRPCClient extends java.lang.Object public final net.corda.client.rpc.CordaRPCConnection start(String, String, net.corda.core.identity.CordaX500Name) @NotNull public final net.corda.client.rpc.CordaRPCConnection start(String, String, net.corda.core.identity.CordaX500Name, net.corda.client.rpc.GracefulReconnect) - public final A use(String, String, kotlin.jvm.functions.Function1) + public final A use(String, String, kotlin.jvm.functions.Function1) + @NotNull public static final net.corda.client.rpc.CordaRPCClient$Companion Companion ## public static final class net.corda.client.rpc.CordaRPCClient$Companion extends java.lang.Object @@ -9446,6 +10264,7 @@ public class net.corda.client.rpc.CordaRPCClientConfiguration extends java.lang. public int hashCode() @NotNull public String toString() + @NotNull public static final net.corda.client.rpc.CordaRPCClientConfiguration$Companion Companion @NotNull public static final net.corda.client.rpc.CordaRPCClientConfiguration DEFAULT @@ -9455,16 +10274,16 @@ public static final class net.corda.client.rpc.CordaRPCClientConfiguration$Compa ## @DoNotImplement public final class net.corda.client.rpc.CordaRPCConnection extends java.lang.Object implements net.corda.client.rpc.RPCConnection - public (net.corda.client.rpc.RPCConnection) + public (net.corda.client.rpc.RPCConnection) public (net.corda.client.rpc.RPCConnection, java.util.concurrent.ExecutorService, net.corda.client.rpc.internal.ReconnectingCordaRPCOps, kotlin.jvm.internal.DefaultConstructorMarker) - public void close() public void forceClose() @NotNull public net.corda.core.messaging.CordaRPCOps getProxy() public int getServerProtocolVersion() @Nullable - public T getTelemetryHandle(Class) + public T getTelemetryHandle(Class) public void notifyServerAndClose() + @NotNull public static final net.corda.client.rpc.CordaRPCConnection$Companion Companion ## public static final class net.corda.client.rpc.CordaRPCConnection$Companion extends java.lang.Object @@ -9475,13 +10294,13 @@ public final class net.corda.client.rpc.GracefulReconnect extends java.lang.Obje public (Runnable, Runnable) public (Runnable, Runnable, int) public (Runnable, Runnable, int, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (kotlin.jvm.functions.Function0, kotlin.jvm.functions.Function0, int) + public (kotlin.jvm.functions.Function0, kotlin.jvm.functions.Function0, int) public (kotlin.jvm.functions.Function0, kotlin.jvm.functions.Function0, int, int, kotlin.jvm.internal.DefaultConstructorMarker) public final int getMaxAttempts() @NotNull - public final kotlin.jvm.functions.Function0 getOnDisconnect() + public final kotlin.jvm.functions.Function0 getOnDisconnect() @NotNull - public final kotlin.jvm.functions.Function0 getOnReconnect() + public final kotlin.jvm.functions.Function0 getOnReconnect() ## public final class net.corda.client.rpc.MaxRpcRetryException extends net.corda.client.rpc.RPCException public (int, reflect.Method, Throwable) @@ -9493,13 +10312,13 @@ public final class net.corda.client.rpc.PermissionException extends net.corda.co ## @DoNotImplement public interface net.corda.client.rpc.RPCConnection extends java.io.Closeable - public abstract void close() + public void close() public abstract void forceClose() @NotNull public abstract I getProxy() public abstract int getServerProtocolVersion() @Nullable - public abstract T getTelemetryHandle(Class) + public abstract T getTelemetryHandle(Class) public abstract void notifyServerAndClose() ## public class net.corda.client.rpc.RPCException extends net.corda.core.CordaRuntimeException @@ -9514,56 +10333,55 @@ public class net.corda.client.rpc.UnrecoverableRPCException extends net.corda.cl public (String, Throwable, int, kotlin.jvm.internal.DefaultConstructorMarker) ## public final class net.corda.client.rpc.UtilsKt extends java.lang.Object - public static final void notUsed(rx.Observable) + public static final void notUsed(rx.Observable) ## public final class net.corda.client.rpc.ext.MultiRPCClient extends java.lang.Object implements java.lang.AutoCloseable - public (java.util.List, Class, String, String) - public (java.util.List, Class, String, String, java.util.Set>) - public (java.util.List, Class, String, String, java.util.Set>, net.corda.client.rpc.CordaRPCClientConfiguration) - public (java.util.List, Class, String, String, java.util.Set>, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions) - public (java.util.List, Class, String, String, java.util.Set>, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) - public (java.util.List, Class, String, String, java.util.Set>, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace) - public (java.util.List, Class, String, String, java.util.Set>, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace, net.corda.core.context.Actor) - public (java.util.List, Class, String, String, java.util.Set>, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.identity.CordaX500Name) + public (java.util.List, Class, String, String) + public (java.util.List, Class, String, String, java.util.Set) + public (java.util.List, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration) + public (java.util.List, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions) + public (java.util.List, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) + public (java.util.List, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace) + public (java.util.List, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace, net.corda.core.context.Actor) + public (java.util.List, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.identity.CordaX500Name) public (java.util.List, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.identity.CordaX500Name, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (java.util.List, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration) - public (java.util.List, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions) - public (java.util.List, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) + public (java.util.List, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration) + public (java.util.List, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions) + public (java.util.List, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) public (java.util.List, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, ClassLoader, net.corda.client.rpc.CordaRPCClientConfiguration) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, ClassLoader, net.corda.client.rpc.CordaRPCClientConfiguration) public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, ClassLoader, net.corda.client.rpc.CordaRPCClientConfiguration, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set>) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set>, net.corda.client.rpc.CordaRPCClientConfiguration) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set>, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set>, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set>, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set>, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace, net.corda.core.context.Actor) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set>, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.identity.CordaX500Name) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace, net.corda.core.context.Actor) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.identity.CordaX500Name) public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, java.util.Set, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.identity.CordaX500Name, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration) public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, net.corda.client.rpc.CordaRPCClientConfiguration, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, int, kotlin.jvm.internal.DefaultConstructorMarker) - public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) + public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader) public (net.corda.core.utilities.NetworkHostAndPort, Class, String, String, net.corda.core.messaging.ClientRpcSslOptions, ClassLoader, int, kotlin.jvm.internal.DefaultConstructorMarker) - public final boolean addConnectionListener(net.corda.client.rpc.ext.RPCConnectionListener) + public final boolean addConnectionListener(net.corda.client.rpc.ext.RPCConnectionListener) public void close() - public final boolean removeConnectionListener(net.corda.client.rpc.ext.RPCConnectionListener) + public final boolean removeConnectionListener(net.corda.client.rpc.ext.RPCConnectionListener) @NotNull - public final java.util.concurrent.CompletableFuture> start() + public final java.util.concurrent.CompletableFuture start() public final void stop() - public static final net.corda.client.rpc.ext.MultiRPCClient$Companion Companion ## public interface net.corda.client.rpc.ext.RPCConnectionListener - public abstract void onConnect(net.corda.client.rpc.ext.RPCConnectionListener$ConnectionContext) - public abstract void onDisconnect(net.corda.client.rpc.ext.RPCConnectionListener$ConnectionContext) - public abstract void onPermanentFailure(net.corda.client.rpc.ext.RPCConnectionListener$ConnectionContext) + public abstract void onConnect(net.corda.client.rpc.ext.RPCConnectionListener$ConnectionContext) + public abstract void onDisconnect(net.corda.client.rpc.ext.RPCConnectionListener$ConnectionContext) + public abstract void onPermanentFailure(net.corda.client.rpc.ext.RPCConnectionListener$ConnectionContext) ## public static interface net.corda.client.rpc.ext.RPCConnectionListener$ConnectionContext @Nullable - public abstract net.corda.client.rpc.RPCConnection getConnectionOpt() + public abstract net.corda.client.rpc.RPCConnection getConnectionOpt() @Nullable public abstract Throwable getThrowableOpt() @NotNull @@ -9575,9 +10393,11 @@ public final class net.corda.client.rpc.reconnect.CouldNotStartFlowException ext public (Throwable, int, kotlin.jvm.internal.DefaultConstructorMarker) ## public final class net.corda.finance.test.CashSchema extends java.lang.Object + @NotNull public static final net.corda.finance.test.CashSchema INSTANCE ## public final class net.corda.finance.test.SampleCashSchemaV1 extends net.corda.core.schemas.MappedSchema + @NotNull public static final net.corda.finance.test.SampleCashSchemaV1 INSTANCE ## @Entity @@ -9601,28 +10421,30 @@ public static class net.corda.finance.test.SampleCashSchemaV1$PersistentCashStat public void setPennies(long) ## public final class net.corda.finance.test.SampleCashSchemaV2 extends net.corda.core.schemas.MappedSchema + @NotNull public static final net.corda.finance.test.SampleCashSchemaV2 INSTANCE ## @Entity @Table public static class net.corda.finance.test.SampleCashSchemaV2$PersistentCashState extends net.corda.core.schemas.CommonSchemaV1$FungibleState public () - public (String, java.util.Set, net.corda.core.identity.AbstractParty, long, net.corda.core.identity.AbstractParty, net.corda.core.utilities.OpaqueBytes) + public (String, java.util.Set, net.corda.core.identity.AbstractParty, long, net.corda.core.identity.AbstractParty, net.corda.core.utilities.OpaqueBytes) @NotNull public String getCurrency() @Nullable - public java.util.Set getParticipants() + public java.util.Set getParticipants() public void setCurrency(String) - public void setParticipants(java.util.Set) + public void setParticipants(java.util.Set) ## public final class net.corda.finance.test.SampleCashSchemaV3 extends net.corda.core.schemas.MappedSchema + @NotNull public static final net.corda.finance.test.SampleCashSchemaV3 INSTANCE ## @Entity @Table public static class net.corda.finance.test.SampleCashSchemaV3$PersistentCashState extends net.corda.core.schemas.PersistentState public () - public (java.util.Set, net.corda.core.identity.AbstractParty, long, String, net.corda.core.identity.AbstractParty, byte[]) + public (java.util.Set, net.corda.core.identity.AbstractParty, long, String, net.corda.core.identity.AbstractParty, byte[]) public (java.util.Set, net.corda.core.identity.AbstractParty, long, String, net.corda.core.identity.AbstractParty, byte[], int, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull public String getCurrency() @@ -9633,20 +10455,20 @@ public static class net.corda.finance.test.SampleCashSchemaV3$PersistentCashStat @Nullable public net.corda.core.identity.AbstractParty getOwner() @Nullable - public java.util.Set getParticipants() + public java.util.Set getParticipants() public long getPennies() public void setCurrency(String) public void setIssuer(net.corda.core.identity.AbstractParty) public void setIssuerRef(byte[]) public void setOwner(net.corda.core.identity.AbstractParty) - public void setParticipants(java.util.Set) + public void setParticipants(java.util.Set) public void setPennies(long) ## public final class net.corda.testing.dsl.AttachmentResolutionException extends net.corda.core.flows.FlowException public (net.corda.core.crypto.SecureHash) ## public final class net.corda.testing.dsl.DoubleSpentInputs extends net.corda.core.flows.FlowException - public (java.util.List) + public (java.util.List) ## public final class net.corda.testing.dsl.DuplicateOutputLabel extends net.corda.core.flows.FlowException public (String) @@ -9657,16 +10479,17 @@ public abstract class net.corda.testing.dsl.EnforceVerifyOrFail extends java.lan ## @DoNotImplement public static final class net.corda.testing.dsl.EnforceVerifyOrFail$Token extends net.corda.testing.dsl.EnforceVerifyOrFail + @NotNull public static final net.corda.testing.dsl.EnforceVerifyOrFail$Token INSTANCE ## @DoNotImplement public final class net.corda.testing.dsl.LedgerDSL extends java.lang.Object implements net.corda.testing.dsl.LedgerDSLInterpreter public (L, net.corda.core.identity.Party) @NotNull - public net.corda.core.transactions.WireTransaction _transaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) - public void _tweak(kotlin.jvm.functions.Function1, kotlin.Unit>) + public net.corda.core.transactions.WireTransaction _transaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) + public void _tweak(kotlin.jvm.functions.Function1) @NotNull - public net.corda.core.transactions.WireTransaction _unverifiedTransaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) + public net.corda.core.transactions.WireTransaction _unverifiedTransaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) @NotNull public net.corda.core.crypto.SecureHash attachment(java.io.InputStream) @NotNull @@ -9677,88 +10500,85 @@ public final class net.corda.testing.dsl.LedgerDSL extends java.lang.Object impl public net.corda.testing.dsl.EnforceVerifyOrFail failsWith(String) @NotNull public final L getInterpreter() + public final S output(String) + public final net.corda.core.contracts.StateAndRef outputStateAndRef(String) @NotNull - public final S retrieveOutput(Class, String) + public final S retrieveOutput(Class, String) @NotNull - public net.corda.core.contracts.StateAndRef retrieveOutputStateAndRef(Class, String) + public net.corda.core.contracts.StateAndRef retrieveOutputStateAndRef(Class, String) @NotNull - public final net.corda.core.transactions.WireTransaction transaction(String, kotlin.jvm.functions.Function1, ? extends net.corda.testing.dsl.EnforceVerifyOrFail>) + public final net.corda.core.transactions.WireTransaction transaction(String, kotlin.jvm.functions.Function1) @NotNull - public final net.corda.core.transactions.WireTransaction transaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1, ? extends net.corda.testing.dsl.EnforceVerifyOrFail>) + public final net.corda.core.transactions.WireTransaction transaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) @NotNull - public final net.corda.core.transactions.WireTransaction transaction(kotlin.jvm.functions.Function1, ? extends net.corda.testing.dsl.EnforceVerifyOrFail>) - public final void tweak(kotlin.jvm.functions.Function1, kotlin.Unit>) + public final net.corda.core.transactions.WireTransaction transaction(kotlin.jvm.functions.Function1) + public final void tweak(kotlin.jvm.functions.Function1) @NotNull - public final net.corda.core.transactions.WireTransaction unverifiedTransaction(String, kotlin.jvm.functions.Function1, kotlin.Unit>) + public final net.corda.core.transactions.WireTransaction unverifiedTransaction(String, kotlin.jvm.functions.Function1) @NotNull - public final net.corda.core.transactions.WireTransaction unverifiedTransaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1, kotlin.Unit>) + public final net.corda.core.transactions.WireTransaction unverifiedTransaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) @NotNull - public final net.corda.core.transactions.WireTransaction unverifiedTransaction(kotlin.jvm.functions.Function1, kotlin.Unit>) + public final net.corda.core.transactions.WireTransaction unverifiedTransaction(kotlin.jvm.functions.Function1) @NotNull public net.corda.testing.dsl.EnforceVerifyOrFail verifies() ## @DoNotImplement public interface net.corda.testing.dsl.LedgerDSLInterpreter extends net.corda.testing.dsl.OutputStateLookup, net.corda.testing.dsl.Verifies @NotNull - public abstract net.corda.core.transactions.WireTransaction _transaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) - public abstract void _tweak(kotlin.jvm.functions.Function1, kotlin.Unit>) + public abstract net.corda.core.transactions.WireTransaction _transaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) + public abstract void _tweak(kotlin.jvm.functions.Function1) @NotNull - public abstract net.corda.core.transactions.WireTransaction _unverifiedTransaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) + public abstract net.corda.core.transactions.WireTransaction _unverifiedTransaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) @NotNull public abstract net.corda.core.crypto.SecureHash attachment(java.io.InputStream) ## @DoNotImplement public interface net.corda.testing.dsl.OutputStateLookup @NotNull - public abstract net.corda.core.contracts.StateAndRef retrieveOutputStateAndRef(Class, String) + public abstract net.corda.core.contracts.StateAndRef retrieveOutputStateAndRef(Class, String) ## @DoNotImplement public final class net.corda.testing.dsl.TestLedgerDSLInterpreter extends java.lang.Object implements net.corda.testing.dsl.LedgerDSLInterpreter public (net.corda.core.node.ServiceHub) @NotNull - public net.corda.core.transactions.WireTransaction _transaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) - public void _tweak(kotlin.jvm.functions.Function1, kotlin.Unit>) + public net.corda.core.transactions.WireTransaction _transaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) + public void _tweak(kotlin.jvm.functions.Function1) @NotNull - public net.corda.core.transactions.WireTransaction _unverifiedTransaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) + public net.corda.core.transactions.WireTransaction _unverifiedTransaction(String, net.corda.core.transactions.TransactionBuilder, kotlin.jvm.functions.Function1) @NotNull public net.corda.core.crypto.SecureHash attachment(java.io.InputStream) @NotNull public final net.corda.core.node.ServiceHub component1() @NotNull - public final net.corda.testing.dsl.TestLedgerDSLInterpreter copy(net.corda.core.node.ServiceHub, java.util.HashMap>, java.util.HashMap, java.util.HashMap) + public final net.corda.testing.dsl.TestLedgerDSLInterpreter copy(net.corda.core.node.ServiceHub, java.util.HashMap, java.util.HashMap, java.util.HashMap) public boolean equals(Object) @NotNull - public net.corda.testing.dsl.EnforceVerifyOrFail fails() - @NotNull - public net.corda.testing.dsl.EnforceVerifyOrFail fails with(String) - @NotNull - public net.corda.testing.dsl.EnforceVerifyOrFail failsWith(String) - @NotNull public final net.corda.core.node.ServiceHub getServices() @NotNull - public final java.util.List getTransactionsToVerify() + public final java.util.List getTransactionsToVerify() @NotNull - public final java.util.List getTransactionsUnverified() + public final java.util.List getTransactionsUnverified() @NotNull - public final java.util.List getWireTransactions() + public final java.util.List getWireTransactions() public int hashCode() @Nullable public final String outputToLabel(net.corda.core.contracts.ContractState) @NotNull - public net.corda.core.contracts.StateAndRef retrieveOutputStateAndRef(Class, String) + public net.corda.core.contracts.StateAndRef retrieveOutputStateAndRef(Class, String) @NotNull public String toString() @Nullable public final String transactionName(net.corda.core.crypto.SecureHash) @NotNull public net.corda.testing.dsl.EnforceVerifyOrFail verifies() + @NotNull public static final net.corda.testing.dsl.TestLedgerDSLInterpreter$Companion Companion ## public static final class net.corda.testing.dsl.TestLedgerDSLInterpreter$Companion extends java.lang.Object public (kotlin.jvm.internal.DefaultConstructorMarker) ## public static final class net.corda.testing.dsl.TestLedgerDSLInterpreter$TypeMismatch extends java.lang.Exception - public (Class, Class) + public (Class, Class) ## public static final class net.corda.testing.dsl.TestLedgerDSLInterpreter$VerifiesFailed extends java.lang.Exception public (String, Throwable) @@ -9788,26 +10608,20 @@ public static final class net.corda.testing.dsl.TestLedgerDSLInterpreter$WireTra public final class net.corda.testing.dsl.TestTransactionDSLInterpreter extends java.lang.Object implements net.corda.testing.dsl.OutputStateLookup, net.corda.testing.dsl.TransactionDSLInterpreter public (net.corda.testing.dsl.TestLedgerDSLInterpreter, net.corda.core.transactions.TransactionBuilder) public void _attachment(String) - public void _attachment(String, net.corda.core.crypto.SecureHash, java.util.List) - public void _attachment(String, net.corda.core.crypto.SecureHash, java.util.List, java.util.Map) + public void _attachment(String, net.corda.core.crypto.SecureHash, java.util.List) + public void _attachment(String, net.corda.core.crypto.SecureHash, java.util.List, java.util.Map) @NotNull - public net.corda.testing.dsl.EnforceVerifyOrFail _tweak(kotlin.jvm.functions.Function1) + public net.corda.testing.dsl.EnforceVerifyOrFail _tweak(kotlin.jvm.functions.Function1) public void attachment(net.corda.core.crypto.SecureHash) - public void command(java.util.List, net.corda.core.contracts.CommandData) + public void command(java.util.List, net.corda.core.contracts.CommandData) @NotNull public final net.corda.testing.dsl.TestLedgerDSLInterpreter component1() @NotNull public final net.corda.core.transactions.TransactionBuilder component2() @NotNull - public final net.corda.testing.dsl.TestTransactionDSLInterpreter copy(net.corda.testing.dsl.TestLedgerDSLInterpreter, net.corda.core.transactions.TransactionBuilder, java.util.HashMap) + public final net.corda.testing.dsl.TestTransactionDSLInterpreter copy(net.corda.testing.dsl.TestLedgerDSLInterpreter, net.corda.core.transactions.TransactionBuilder, java.util.HashMap) public boolean equals(Object) @NotNull - public net.corda.testing.dsl.EnforceVerifyOrFail fails() - @NotNull - public net.corda.testing.dsl.EnforceVerifyOrFail fails with(String) - @NotNull - public net.corda.testing.dsl.EnforceVerifyOrFail failsWith(String) - @NotNull public net.corda.testing.dsl.TestLedgerDSLInterpreter getLedgerInterpreter() @NotNull public final net.corda.core.node.ServicesForResolution getServices() @@ -9818,7 +10632,7 @@ public final class net.corda.testing.dsl.TestTransactionDSLInterpreter extends j public void output(String, String, net.corda.core.identity.Party, Integer, net.corda.core.contracts.AttachmentConstraint, net.corda.core.contracts.ContractState) public void reference(net.corda.core.contracts.StateRef) @NotNull - public net.corda.core.contracts.StateAndRef retrieveOutputStateAndRef(Class, String) + public net.corda.core.contracts.StateAndRef retrieveOutputStateAndRef(Class, String) public void timeWindow(net.corda.core.contracts.TimeWindow) @NotNull public String toString() @@ -9829,17 +10643,17 @@ public final class net.corda.testing.dsl.TestTransactionDSLInterpreter extends j public final class net.corda.testing.dsl.TransactionDSL extends java.lang.Object implements net.corda.testing.dsl.TransactionDSLInterpreter public (T, net.corda.core.identity.Party) public void _attachment(String) - public void _attachment(String, net.corda.core.crypto.SecureHash, java.util.List) - public void _attachment(String, net.corda.core.crypto.SecureHash, java.util.List, java.util.Map) + public void _attachment(String, net.corda.core.crypto.SecureHash, java.util.List) + public void _attachment(String, net.corda.core.crypto.SecureHash, java.util.List, java.util.Map) @NotNull - public net.corda.testing.dsl.EnforceVerifyOrFail _tweak(kotlin.jvm.functions.Function1) + public net.corda.testing.dsl.EnforceVerifyOrFail _tweak(kotlin.jvm.functions.Function1) public final void attachment(String) public final void attachment(String, net.corda.core.crypto.SecureHash) - public final void attachment(String, net.corda.core.crypto.SecureHash, java.util.List, java.util.Map) + public final void attachment(String, net.corda.core.crypto.SecureHash, java.util.List, java.util.Map) public void attachment(net.corda.core.crypto.SecureHash) public final void attachments(String...) public final void command(java.security.PublicKey, net.corda.core.contracts.CommandData) - public void command(java.util.List, net.corda.core.contracts.CommandData) + public void command(java.util.List, net.corda.core.contracts.CommandData) @NotNull public net.corda.testing.dsl.EnforceVerifyOrFail fails() @NotNull @@ -9847,7 +10661,7 @@ public final class net.corda.testing.dsl.TransactionDSL extends java.lang.Object @NotNull public net.corda.testing.dsl.EnforceVerifyOrFail failsWith(String) @NotNull - public net.corda.testing.dsl.LedgerDSLInterpreter getLedgerInterpreter() + public net.corda.testing.dsl.LedgerDSLInterpreter getLedgerInterpreter() public final void input(String) public final void input(String, String) public final void input(String, net.corda.core.contracts.ContractState) @@ -9863,26 +10677,26 @@ public final class net.corda.testing.dsl.TransactionDSL extends java.lang.Object public final void reference(String, net.corda.core.contracts.ContractState) public void reference(net.corda.core.contracts.StateRef) @NotNull - public net.corda.core.contracts.StateAndRef retrieveOutputStateAndRef(Class, String) + public net.corda.core.contracts.StateAndRef retrieveOutputStateAndRef(Class, String) public final void timeWindow(java.time.Instant) public final void timeWindow(java.time.Instant, java.time.Duration) public void timeWindow(net.corda.core.contracts.TimeWindow) @NotNull - public final net.corda.testing.dsl.EnforceVerifyOrFail tweak(kotlin.jvm.functions.Function1, ? extends net.corda.testing.dsl.EnforceVerifyOrFail>) + public final net.corda.testing.dsl.EnforceVerifyOrFail tweak(kotlin.jvm.functions.Function1) @NotNull public net.corda.testing.dsl.EnforceVerifyOrFail verifies() ## @DoNotImplement public interface net.corda.testing.dsl.TransactionDSLInterpreter extends net.corda.testing.dsl.OutputStateLookup, net.corda.testing.dsl.Verifies public abstract void _attachment(String) - public abstract void _attachment(String, net.corda.core.crypto.SecureHash, java.util.List) - public abstract void _attachment(String, net.corda.core.crypto.SecureHash, java.util.List, java.util.Map) + public abstract void _attachment(String, net.corda.core.crypto.SecureHash, java.util.List) + public abstract void _attachment(String, net.corda.core.crypto.SecureHash, java.util.List, java.util.Map) @NotNull - public abstract net.corda.testing.dsl.EnforceVerifyOrFail _tweak(kotlin.jvm.functions.Function1) + public abstract net.corda.testing.dsl.EnforceVerifyOrFail _tweak(kotlin.jvm.functions.Function1) public abstract void attachment(net.corda.core.crypto.SecureHash) - public abstract void command(java.util.List, net.corda.core.contracts.CommandData) + public abstract void command(java.util.List, net.corda.core.contracts.CommandData) @NotNull - public abstract net.corda.testing.dsl.LedgerDSLInterpreter getLedgerInterpreter() + public abstract net.corda.testing.dsl.LedgerDSLInterpreter getLedgerInterpreter() public abstract void input(net.corda.core.contracts.StateRef) public abstract void output(String, String, net.corda.core.identity.Party, Integer, net.corda.core.contracts.AttachmentConstraint, net.corda.core.contracts.ContractState) public abstract void reference(net.corda.core.contracts.StateRef) @@ -9891,17 +10705,18 @@ public interface net.corda.testing.dsl.TransactionDSLInterpreter extends net.cor @DoNotImplement public interface net.corda.testing.dsl.Verifies @NotNull - public abstract net.corda.testing.dsl.EnforceVerifyOrFail fails() + public net.corda.testing.dsl.EnforceVerifyOrFail fails() @NotNull - public abstract net.corda.testing.dsl.EnforceVerifyOrFail fails with(String) + public net.corda.testing.dsl.EnforceVerifyOrFail fails with(String) @NotNull - public abstract net.corda.testing.dsl.EnforceVerifyOrFail failsWith(String) + public net.corda.testing.dsl.EnforceVerifyOrFail failsWith(String) @NotNull public abstract net.corda.testing.dsl.EnforceVerifyOrFail verifies() ## public final class net.corda.testing.http.HttpApi extends java.lang.Object public (java.net.URL, com.fasterxml.jackson.databind.ObjectMapper) public (java.net.URL, com.fasterxml.jackson.databind.ObjectMapper, int, kotlin.jvm.internal.DefaultConstructorMarker) + public final T getJson(String, java.util.Map) @NotNull public final com.fasterxml.jackson.databind.ObjectMapper getMapper() @NotNull @@ -9909,6 +10724,7 @@ public final class net.corda.testing.http.HttpApi extends java.lang.Object public final void postJson(String, Object) public final void postPlain(String, String) public final void putJson(String, Object) + @NotNull public static final net.corda.testing.http.HttpApi$Companion Companion ## public static final class net.corda.testing.http.HttpApi$Companion extends java.lang.Object @@ -9919,37 +10735,37 @@ public static final class net.corda.testing.http.HttpApi$Companion extends java. public final class net.corda.testing.http.HttpUtils extends java.lang.Object @NotNull public final com.fasterxml.jackson.databind.ObjectMapper getDefaultMapper() + public final T getJson(java.net.URL, java.util.Map, com.fasterxml.jackson.databind.ObjectMapper) public final void postJson(java.net.URL, String) public final void postPlain(java.net.URL, String) public final void putJson(java.net.URL, String) + @NotNull public static final net.corda.testing.http.HttpUtils INSTANCE ## public final class net.corda.testing.services.MockAttachmentStorage extends net.corda.core.serialization.SingletonSerializeAsToken implements net.corda.core.node.services.AttachmentStorage public () @NotNull - public final kotlin.Pair getAttachmentIdAndBytes(java.io.InputStream) + public final kotlin.Pair getAttachmentIdAndBytes(java.io.InputStream) @NotNull - public final java.util.Map> getFiles() + public final java.util.Map getFiles() @NotNull - public java.util.List getLatestContractAttachments(String, int) + public java.util.List getLatestContractAttachments(String, int) public boolean hasAttachment(net.corda.core.crypto.SecureHash) @NotNull public net.corda.core.crypto.SecureHash importAttachment(java.io.InputStream) @NotNull public net.corda.core.crypto.SecureHash importAttachment(java.io.InputStream, String, String) @NotNull - public final net.corda.core.crypto.SecureHash importContractAttachment(java.util.List, String, java.io.InputStream) + public final net.corda.core.crypto.SecureHash importContractAttachment(java.util.List, String, java.io.InputStream) @NotNull - public final net.corda.core.crypto.SecureHash importContractAttachment(java.util.List, String, java.io.InputStream, net.corda.core.crypto.SecureHash) + public final net.corda.core.crypto.SecureHash importContractAttachment(java.util.List, String, java.io.InputStream, net.corda.core.crypto.SecureHash) @NotNull - public final net.corda.core.crypto.SecureHash importContractAttachment(java.util.List, String, java.io.InputStream, net.corda.core.crypto.SecureHash, java.util.List) + public final net.corda.core.crypto.SecureHash importContractAttachment(java.util.List, String, java.io.InputStream, net.corda.core.crypto.SecureHash, java.util.List) public final void importContractAttachment(net.corda.core.crypto.SecureHash, net.corda.core.contracts.ContractAttachment) @NotNull public net.corda.core.crypto.SecureHash importOrGetAttachment(java.io.InputStream) @Nullable public net.corda.core.contracts.Attachment openAttachment(net.corda.core.crypto.SecureHash) @NotNull - public java.util.List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria) - @NotNull - public java.util.List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria, net.corda.core.node.services.vault.AttachmentSort) + public java.util.List queryAttachments(net.corda.core.node.services.vault.AttachmentQueryCriteria, net.corda.core.node.services.vault.AttachmentSort) ## diff --git a/.ci/dev/compatibility/DockerfileJDK11 b/.ci/dev/compatibility/DockerfileJDK11 deleted file mode 100644 index 23aa144955..0000000000 --- a/.ci/dev/compatibility/DockerfileJDK11 +++ /dev/null @@ -1,9 +0,0 @@ -FROM azul/zulu-openjdk:11.0.14 -RUN apt-get update && apt-get install -y curl apt-transport-https \ - ca-certificates \ - curl \ - gnupg2 \ - software-properties-common \ - wget -ARG USER="stresstester" -RUN useradd -m ${USER} diff --git a/.ci/dev/compatibility/JenkinsfileJDK11Azul b/.ci/dev/compatibility/JenkinsfileJDK11Azul deleted file mode 100644 index 23e9e4bf95..0000000000 --- a/.ci/dev/compatibility/JenkinsfileJDK11Azul +++ /dev/null @@ -1,213 +0,0 @@ -#!groovy -/** - * Jenkins pipeline to build Corda OS release with JDK11 - */ - -/** - * Kill already started job. - * Assume new commit takes precendence and results from previous - * unfinished builds are not required. - * This feature doesn't play well with disableConcurrentBuilds() option - */ -@Library('corda-shared-build-pipeline-steps') -import static com.r3.build.BuildControl.killAllExistingBuildsForJob - -killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger()) - -/** - * Sense environment - */ -boolean isReleaseTag = (env.TAG_NAME =~ /^release.*JDK11$/) - -/** - * Common Gradle arguments for all Gradle executions - */ -String COMMON_GRADLE_PARAMS = [ - '--no-daemon', - '--stacktrace', - '--info', - '-Pcompilation.warningsAsErrors=false', - '-Ptests.failFast=true', -].join(' ') - -/** - * The name of subfolders to run tests previously on Another Agent and Same Agent - */ -String sameAgentFolder = 'sameAgent' -String anotherAgentFolder = 'anotherAgent' - -pipeline { - agent { - dockerfile { - label 'standard' - additionalBuildArgs '--build-arg USER="${USER}"' // DON'T change quotation - USER variable is substituted by SHELL!!!! - filename "${sameAgentFolder}/.ci/dev/compatibility/DockerfileJDK11" - } - } - - /* - * List options in alphabetical order - */ - options { - buildDiscarder(logRotator(daysToKeepStr: '14', artifactDaysToKeepStr: '14')) - checkoutToSubdirectory "${sameAgentFolder}" - parallelsAlwaysFailFast() - timeout(time: 6, unit: 'HOURS') - timestamps() - } - - /* - * List environment variables in alphabetical order - */ - environment { - ARTIFACTORY_BUILD_NAME = "Corda :: Publish :: Publish JDK 11 Release to Artifactory :: ${env.BRANCH_NAME}" - ARTIFACTORY_CREDENTIALS = credentials('artifactory-credentials') - CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}" - CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}" - } - - stages { - stage('Compile') { - steps { - dir(sameAgentFolder) { - authenticateGradleWrapper() - sh script: [ - './gradlew', - COMMON_GRADLE_PARAMS, - 'clean', - 'jar' - ].join(' ') - } - } - } - - stage('Copy') { - steps { - sh "rm -rf ${anotherAgentFolder} && mkdir -p ${anotherAgentFolder} && cd ${sameAgentFolder} && cp -aR . ../${anotherAgentFolder}" - } - } - - stage('All Tests') { - parallel { - stage('Another agent') { - post { - always { - dir(anotherAgentFolder) { - archiveArtifacts artifacts: '**/*.log', fingerprint: false - junit testResults: '**/build/test-results/**/*.xml', keepLongStdio: true - } - } - } - stages { - stage('Unit Test') { - steps { - dir(anotherAgentFolder) { - sh script: [ - './gradlew', - COMMON_GRADLE_PARAMS, - 'test' - ].join(' ') - } - } - } - stage('Smoke Test') { - steps { - dir(anotherAgentFolder) { - sh script: [ - './gradlew', - COMMON_GRADLE_PARAMS, - 'smokeTest' - ].join(' ') - } - } - } - stage('Slow Integration Test') { - steps { - dir(anotherAgentFolder) { - sh script: [ - './gradlew', - COMMON_GRADLE_PARAMS, - 'slowIntegrationTest' - ].join(' ') - } - } - } - } - } - stage('Same agent') { - post { - always { - dir(sameAgentFolder) { - archiveArtifacts artifacts: '**/*.log', fingerprint: false - junit testResults: '**/build/test-results/**/*.xml', keepLongStdio: true - } - } - } - stages { - stage('Integration Test') { - steps { - dir(sameAgentFolder) { - sh script: [ - './gradlew', - COMMON_GRADLE_PARAMS, - 'integrationTest' - ].join(' ') - } - } - } - - stage('Deploy Node') { - steps { - dir(sameAgentFolder) { - sh script: [ - './gradlew', - COMMON_GRADLE_PARAMS, - 'deployNode' - ].join(' ') - } - } - } - } - } - } - } - - stage('Publish to Artifactory') { - when { - expression { isReleaseTag } - } - steps { - dir(sameAgentFolder) { - rtServer( - id: 'R3-Artifactory', - url: 'https://software.r3.com/artifactory', - credentialsId: 'artifactory-credentials' - ) - rtGradleDeployer( - id: 'deployer', - serverId: 'R3-Artifactory', - repo: 'corda-releases' - ) - rtGradleRun( - usesPlugin: true, - useWrapper: true, - switches: '-s --info', - tasks: 'artifactoryPublish', - deployerId: 'deployer', - buildName: env.ARTIFACTORY_BUILD_NAME - ) - rtPublishBuildInfo( - serverId: 'R3-Artifactory', - buildName: env.ARTIFACTORY_BUILD_NAME - ) - } - } - } - } - - post { - cleanup { - deleteDir() /* clean up our workspace */ - } - } -} diff --git a/.ci/dev/compatibility/JenkinsfileJDK11Compile b/.ci/dev/compatibility/JenkinsfileJDK11Compile deleted file mode 100644 index 83d4923df3..0000000000 --- a/.ci/dev/compatibility/JenkinsfileJDK11Compile +++ /dev/null @@ -1,58 +0,0 @@ -#!groovy -/** - * Jenkins pipeline to build Corda Opensource Pull Requests with JDK11. - */ - -@Library('corda-shared-build-pipeline-steps') -import static com.r3.build.BuildControl.killAllExistingBuildsForJob - -killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger()) - -pipeline { - agent { - dockerfile { - label 'standard' - additionalBuildArgs '--build-arg USER="${USER}"' // DON'T change quotation - USER variable is substituted by SHELL!!!! - filename '.ci/dev/compatibility/DockerfileJDK11' - } - } - options { - timestamps() - timeout(time: 3, unit: 'HOURS') - buildDiscarder(logRotator(daysToKeepStr: '14', artifactDaysToKeepStr: '14')) - } - - environment { - ARTIFACTORY_CREDENTIALS = credentials('artifactory-credentials') - BUILD_CACHE_CREDENTIALS = credentials('gradle-ent-cache-credentials') - BUILD_CACHE_PASSWORD = "${env.BUILD_CACHE_CREDENTIALS_PSW}" - BUILD_CACHE_USERNAME = "${env.BUILD_CACHE_CREDENTIALS_USR}" - CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}" - CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}" - CORDA_GRADLE_SCAN_KEY = credentials('gradle-build-scans-key') - CORDA_USE_CACHE = "corda-remotes" - } - - stages { - stage('JDK 11 Compile') { - steps { - authenticateGradleWrapper() - sh "./gradlew --no-daemon --parallel --build-cache -Pcompilation.allWarningsAsErrors=true -Ptests.failFast=false " + - "-Ptests.ignoreFailures=true clean compileAll --stacktrace" - } - } - stage('Deploy nodes') { - steps { - sh "./gradlew --no-daemon --build-cache deployNodes" - } - } - } - post { - always { - findBuildScans() - } - cleanup { - deleteDir() /* clean up our workspace */ - } - } -} diff --git a/.ci/dev/forward-merge/Jenkinsfile b/.ci/dev/forward-merge/Jenkinsfile index f66ba5aaed..4c335c50f4 100644 --- a/.ci/dev/forward-merge/Jenkinsfile +++ b/.ci/dev/forward-merge/Jenkinsfile @@ -13,13 +13,13 @@ * the branch name of origin branch, it should match the current branch * and it acts as a fail-safe inside {@code forwardMerger} pipeline */ -String originBranch = 'release/os/4.11' +String originBranch = 'release/os/4.12' /** * the branch name of target branch, it should be the branch with the next version * after the one in current branch. */ -String targetBranch = 'release/os/4.12' +String targetBranch = 'release/os/4.13' /** * Forward merge any changes between #originBranch and #targetBranch diff --git a/.ci/dev/nightly-regression/Jenkinsfile b/.ci/dev/nightly-regression/Jenkinsfile index 1c4f0bd520..9102d5e39d 100644 --- a/.ci/dev/nightly-regression/Jenkinsfile +++ b/.ci/dev/nightly-regression/Jenkinsfile @@ -45,6 +45,8 @@ pipeline { CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}" CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}" CORDA_USE_CACHE = "corda-remotes" + JAVA_HOME = "/usr/lib/jvm/java-17-amazon-corretto" + JAVA_8_HOME = "/usr/lib/jvm/java-1.8.0-amazon-corretto" } stages { diff --git a/.ci/dev/pr-code-checks/Jenkinsfile b/.ci/dev/pr-code-checks/Jenkinsfile index f2996ce6df..c2b238e1b8 100644 --- a/.ci/dev/pr-code-checks/Jenkinsfile +++ b/.ci/dev/pr-code-checks/Jenkinsfile @@ -15,48 +15,32 @@ pipeline { * List environment variables in alphabetical order */ environment { + SNYK_API_TOKEN = credentials('c4-os-snyk-api-token-secret') + C4_OS_SNYK_ORG_ID = credentials('c4-os-snyk-org-id') ARTIFACTORY_CREDENTIALS = credentials('artifactory-credentials') - BUILD_CACHE_CREDENTIALS = credentials('gradle-ent-cache-credentials') - BUILD_CACHE_PASSWORD = "${env.BUILD_CACHE_CREDENTIALS_PSW}" - BUILD_CACHE_USERNAME = "${env.BUILD_CACHE_CREDENTIALS_USR}" CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}" CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}" - CORDA_GRADLE_SCAN_KEY = credentials('gradle-build-scans-key') CORDA_USE_CACHE = "corda-remotes" - C4_OS_SNYK_ORG_ID = credentials('c4-os-snyk-org-id') - SNYK_API_TOKEN = credentials('c4-os-snyk-api-token-secret') + JAVA_HOME = "/usr/lib/jvm/java-17-amazon-corretto" } stages { stage('Detekt check') { steps { authenticateGradleWrapper() - sh "./gradlew --no-daemon --parallel --build-cache clean detekt" + sh "./gradlew --no-daemon clean detekt" } } stage('Compilation warnings check') { steps { - sh "./gradlew --no-daemon --parallel --build-cache -Pcompilation.warningsAsErrors=true compileAll" + sh "./gradlew --no-daemon -Pcompilation.warningsAsErrors=true compileAll" } } stage('Snyk Delta') { - agent { - docker { - image 'build-zulu-openjdk:8' - reuseNode true - registryUrl 'https://engineering-docker.software.r3.com/' - registryCredentialsId 'artifactory-credentials' - args '-v /tmp:/host_tmp' - } - } - environment { - GRADLE_USER_HOME = "/host_tmp/gradle" - } + agent { label 'standard' } steps { - authenticateGradleWrapper() - sh 'mkdir -p ${GRADLE_USER_HOME}' authenticateGradleWrapper() snykDeltaScan(env.SNYK_API_TOKEN, env.C4_OS_SNYK_ORG_ID) } @@ -64,21 +48,19 @@ pipeline { stage('No API change check') { steps { - sh "./gradlew --no-daemon --parallel --build-cache generateApi" + sh "./gradlew --no-daemon generateApi" sh ".ci/check-api-changes.sh" } } stage('Deploy Nodes') { steps { - sh "./gradlew --no-daemon --build-cache jar deployNodes" + sh "./gradlew --no-daemon jar deployNodes" } } } + post { - always { - findBuildScans() - } cleanup { deleteDir() /* clean up our workspace */ } diff --git a/.ci/dev/publish-api-docs/Jenkinsfile b/.ci/dev/publish-api-docs/Jenkinsfile index 2bdda095be..8e75ce3f7c 100644 --- a/.ci/dev/publish-api-docs/Jenkinsfile +++ b/.ci/dev/publish-api-docs/Jenkinsfile @@ -27,6 +27,7 @@ pipeline { ARTIFACTORY_CREDENTIALS = credentials('artifactory-credentials') CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}" CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}" + JAVA_HOME = "/usr/lib/jvm/java-17-amazon-corretto" } stages { diff --git a/.ci/dev/publish-branch/Jenkinsfile.nightly b/.ci/dev/publish-branch/Jenkinsfile.nightly index 6b6c5ac5b0..b560329b81 100644 --- a/.ci/dev/publish-branch/Jenkinsfile.nightly +++ b/.ci/dev/publish-branch/Jenkinsfile.nightly @@ -39,6 +39,7 @@ pipeline { BUILD_CACHE_USERNAME = "${env.BUILD_CACHE_CREDENTIALS_USR}" USE_CACHE = 'corda-remotes' DOCKER_URL = "https://index.docker.io/v1/" + JAVA_HOME = "/usr/lib/jvm/java-17-amazon-corretto" } stages { diff --git a/.ci/dev/publish-branch/Jenkinsfile.preview b/.ci/dev/publish-branch/Jenkinsfile.preview index b795edec93..651add31cc 100644 --- a/.ci/dev/publish-branch/Jenkinsfile.preview +++ b/.ci/dev/publish-branch/Jenkinsfile.preview @@ -24,6 +24,7 @@ pipeline { // in the name ARTIFACTORY_BUILD_NAME = "Corda / Publish / Publish Preview to Artifactory" .replaceAll("/", " :: ") + JAVA_HOME = "/usr/lib/jvm/java-17-amazon-corretto" } stages { diff --git a/.ci/dev/regression/Jenkinsfile b/.ci/dev/regression/Jenkinsfile index d4126f51e5..832a7ce580 100644 --- a/.ci/dev/regression/Jenkinsfile +++ b/.ci/dev/regression/Jenkinsfile @@ -70,6 +70,8 @@ pipeline { SNYK_API_KEY = "c4-os-snyk" //Jenkins credential type: Snyk Api token SNYK_TOKEN = credentials('c4-os-snyk-api-token-secret') //Jenkins credential type: Secret text C4_OS_SNYK_ORG_ID = credentials('corda4-os-snyk-org-id') + JAVA_HOME = "/usr/lib/jvm/java-17-amazon-corretto" + JAVA_8_HOME = "/usr/lib/jvm/java-1.8.0-amazon-corretto" } stages { @@ -327,7 +329,7 @@ pipeline { './gradlew', COMMON_GRADLE_PARAMS, 'docker:pushDockerImage', - '-Pdocker.image.repository=corda/community', + '-Pdocker.image.repository=corda/open-source', '--image OFFICIAL' ].join(' ') } diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 48f0f7fcab..00c08a8d53 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,9 +3,9 @@ # PR Checklist: -- [ ] Have you run the unit, integration and smoke tests as described [here](https://docs.r3.com/en/platform/corda/4.8/open-source/testing.html)? +- [ ] Have you run the unit, integration and smoke tests as described [here](https://docs.r3.com/testing.html)? - [ ] If you added public APIs, did you write the JavaDocs/kdocs? -- [ ] If the changes are of interest to application developers, have you added them to the changelog, and potentially the [release notes](https://docs.corda.net/head/release-notes.html) (`https://docs.r3.com/en/platform/corda/4.8/open-source/release-notes.html`)? -- [ ] If you are contributing for the first time, please read the [contributor agreement](https://docs.r3.com/en/platform/corda/4.8/open-source/contributing.html) now and add a comment to this pull request stating that your PR is in accordance with the [Developer's Certificate of Origin](https://docs.r3.com/en/platform/corda/4.8/open-source/contributing.html#merging-the-changes-back-into-corda). +- [ ] If the changes are of interest to application developers, have you added them to the changelog, and potentially the [release notes](https://docs.r3.com/release-notes.html) (`https://docs.r3.com/release-notes.html`)? +- [ ] If you are contributing for the first time, please read the [contributor agreement](https://docs.r3.com/contributing.html) now and add a comment to this pull request stating that your PR is in accordance with the [Developer's Certificate of Origin](https://docs.r3.com/contributing.html). Thanks for your code, it's appreciated! :) diff --git a/.github/workflows/check-pr-title.yml b/.github/workflows/check-pr-title.yml index 3da232efe8..762d9c5318 100644 --- a/.github/workflows/check-pr-title.yml +++ b/.github/workflows/check-pr-title.yml @@ -9,6 +9,6 @@ jobs: steps: - uses: morrisoncole/pr-lint-action@v1.7.1 with: - title-regex: '^((CORDA|AG|EG|ENT|INFRA|ES)-\d+)(.*)' + title-regex: '^((CORDA|AG|EG|ENT|INFRA|ES|DOC)-\d+)(.*)' on-failed-regex-comment: "PR title failed to match regex -> `%regex%`" repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index da3fe3c032..332847c7a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,4 +2,4 @@ Corda is an open-source project and contributions are welcome! -To find out how to contribute, please see our [contributing docs](https://docs.r3.com/en/platform/corda/4.8/open-source/contributing.html). +To find out how to contribute, please see our [contributing docs](https://docs.r3.com/contributing.html). diff --git a/Jenkinsfile b/Jenkinsfile index f2b5686859..b5013bbb77 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -53,6 +53,8 @@ pipeline { CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}" CORDA_GRADLE_SCAN_KEY = credentials('gradle-build-scans-key') CORDA_USE_CACHE = "corda-remotes" + JAVA_HOME="/usr/lib/jvm/java-17-amazon-corretto" + JAVA_8_HOME = "/usr/lib/jvm/java-1.8.0-amazon-corretto" } stages { @@ -119,6 +121,24 @@ pipeline { ].join(' ') } } + stage('Smoke Test') { + steps { + sh script: [ + './gradlew', + COMMON_GRADLE_PARAMS, + 'smokeTest' + ].join(' ') + } + } + stage('Slow Integration Test') { + steps { + sh script: [ + './gradlew', + COMMON_GRADLE_PARAMS, + 'slowIntegrationTest' + ].join(' ') + } + } } } stage('Same agent') { diff --git a/README.md b/README.md index 5a2056616c..0f6d16929b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Corda + Corda

[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) @@ -25,27 +25,26 @@ However, like all things, Corda must evolve to serve the more stringent needs of ## Getting started -1. Read the [Getting Started](https://docs.corda.net/getting-set-up.html) documentation -2. Run the [Example CorDapp](https://docs.corda.net/tutorial-cordapp.html) -3. Read about Corda's [Key Concepts](https://docs.corda.net/key-concepts.html) -4. Follow the [Hello, World! tutorial](https://docs.corda.net/hello-world-introduction.html) +1. Read the [Getting Started](https://docs.r3.com/getting-set-up.html) documentation +2. Run the [Example CorDapp](https://docs.r3.com/tutorial-cordapp.html) +3. Read about Corda's [Key Concepts](https://docs.r3.com/key-concepts.html) +4. Follow the [Hello, World! tutorial](https://docs.r3.com/hello-world-introduction.html) ## Useful links * [Project Website](https://corda.net) * [Mailing List](https://groups.io/g/corda-dev/) -* [Documentation](https://docs.corda.net) +* [Documentation](https://docs.r3.com) * [Stack Overflow Tag](https://stackoverflow.com/questions/tagged/corda) * [Slack Channel](https://slack.corda.net/) -* [Twitter](https://twitter.com/Cordablockchain) -* [Meetups](https://www.meetup.com/pro/corda/) -* [Training Courses](https://www.corda.net/corda-training/) +* [Twitter](https://twitter.com/inside_r3) +* [Training Courses](https://r3certification.com/) ## Contributing Corda is an open-source project and contributions are welcome! -To find out how to contribute, please see our [contributing docs](https://docs.r3.com/en/platform/corda/4.8/open-source/contributing.html). +To find out how to contribute, please see our [contributing docs](https://docs.r3.com/contributing.html). ## License diff --git a/build.gradle b/build.gradle index e3f7a0f271..2c02bfeedd 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,11 @@ import com.r3.testing.DistributeTestsBy import com.r3.testing.PodLogLevel +import net.corda.plugins.apiscanner.GenerateApi +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import static org.gradle.api.JavaVersion.VERSION_11 -import static org.gradle.api.JavaVersion.VERSION_1_8 +import static org.gradle.api.JavaVersion.VERSION_17 +import static org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 +import static org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 buildscript { // For sharing constants between builds @@ -15,26 +18,18 @@ buildscript { ext.corda_build_edition = System.getenv("CORDA_BUILD_EDITION")?.trim() ?: "Corda Open Source" ext.corda_platform_version = constants.getProperty("platformVersion") + ext.corda_shell_version = constants.getProperty("cordaShellVersion") ext.gradle_plugins_version = constants.getProperty("gradlePluginsVersion") // Dependency versions. Can run 'gradle dependencyUpdates' to find new versions of things. // // TODO: Sort this alphabetically. - ext.kotlin_version = constants.getProperty("kotlinVersion") ext.warnings_as_errors = project.hasProperty("compilation.warningsAsErrors") ? project.property("compilation.warningsAsErrors").toBoolean() : false ext.quasar_group = 'co.paralleluniverse' // Set version of Quasar according to version of Java used: - if (JavaVersion.current().isJava8()) { - ext.quasar_version = constants.getProperty("quasarVersion") - ext.quasar_classifier = constants.getProperty("quasarClassifier") - ext.jdkClassifier = constants.getProperty("jdkClassifier") - } else { - ext.quasar_version = constants.getProperty("quasarVersion11") - ext.quasar_classifier = constants.getProperty("quasarClassifier11") - ext.jdkClassifier = constants.getProperty("jdkClassifier11") - } - ext.cordaScanApiClassifier = jdkClassifier + ext.quasar_version = constants.getProperty("quasarVersion") + ext.quasar_classifier = constants.getProperty("quasarClassifier") ext.quasar_exclusions = [ 'co.paralleluniverse**', 'groovy**', @@ -49,7 +44,7 @@ buildscript { 'org.junit**', 'org.slf4j**', 'worker.org.gradle.**', - 'com.nhaarman.mockito_kotlin**', + 'org.mockito.kotlin**', 'org.assertj**', 'org.hamcrest**', 'org.mockito**', @@ -95,7 +90,6 @@ buildscript { ext.h2_version = constants.getProperty("h2Version") ext.rxjava_version = constants.getProperty("rxjavaVersion") ext.dokka_version = constants.getProperty("dokkaVersion") - ext.eddsa_version = constants.getProperty("eddsaVersion") ext.dependency_checker_version = constants.getProperty("dependencyCheckerVersion") ext.commons_collections_version = constants.getProperty("commonsCollectionsVersion") ext.beanutils_version = constants.getProperty("beanutilsVersion") @@ -116,7 +110,6 @@ buildscript { ext.class_graph_version = constants.getProperty('classgraphVersion') ext.jcabi_manifests_version = constants.getProperty("jcabiManifestsVersion") ext.picocli_version = constants.getProperty("picocliVersion") - ext.commons_lang_version = constants.getProperty("commonsLangVersion") ext.commons_io_version = constants.getProperty("commonsIoVersion") ext.controlsfx_version = constants.getProperty("controlsfxVersion") ext.detekt_version = constants.getProperty('detektVersion') @@ -124,20 +117,10 @@ buildscript { ext.commons_configuration2_version = constants.getProperty("commonsConfiguration2Version") ext.commons_text_version = constants.getProperty("commonsTextVersion") ext.snake_yaml_version = constants.getProperty("snakeYamlVersion") + ext.fontawesomefx_commons_version = constants.getProperty("fontawesomefxCommonsVersion") + ext.fontawesomefx_fontawesome_version = constants.getProperty("fontawesomefxFontawesomeVersion") ext.javaassist_version = constants.getProperty("javaassistVersion") - if (JavaVersion.current().isJava8()) { - ext.fontawesomefx_commons_version = constants.getProperty("fontawesomefxCommonsJava8Version") - ext.fontawesomefx_fontawesome_version = constants.getProperty("fontawesomefxFontawesomeJava8Version") - } else { - ext.fontawesomefx_commons_version = constants.getProperty("fontawesomefxCommonsVersion") - ext.fontawesomefx_fontawesome_version = constants.getProperty("fontawesomefxFontawesomeVersion") - } - - // Update 121 is required for ObjectInputFilter. - // Updates [131, 161] also have zip compression bugs on MacOS (High Sierra). - // when the java version in NodeStartup.hasMinimumJavaVersion() changes, so must this check - ext.java8_minUpdateVersion = constants.getProperty('java8MinUpdateVersion') ext.corda_revision = { try { "git rev-parse HEAD".execute().text.trim() @@ -171,6 +154,7 @@ buildscript { content { includeGroupByRegex 'net\\.corda(\\..*)?' includeGroupByRegex 'com\\.r3(\\..*)?' + includeGroup 'co.paralleluniverse' } } maven { @@ -180,7 +164,6 @@ buildscript { includeGroupByRegex 'com\\.r3(\\..*)?' } } - gradlePluginPortal() mavenCentral() maven { url "${publicArtifactURL}/jcenter-backup" @@ -188,28 +171,21 @@ buildscript { } } dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version" - classpath "net.corda.plugins:publish-utils:$gradle_plugins_version" classpath "net.corda.plugins:quasar-utils:$gradle_plugins_version" classpath "net.corda.plugins:cordformation:$gradle_plugins_version" classpath "net.corda.plugins:cordapp:$gradle_plugins_version" classpath "net.corda.plugins:api-scanner:$gradle_plugins_version" classpath "net.corda.plugins:jar-filter:$gradle_plugins_version" - classpath "net.sf.proguard:proguard-gradle:$proguard_version" + classpath "com.guardsquare:proguard-gradle:$proguard_version" classpath 'com.github.ben-manes:gradle-versions-plugin:0.15.0' - classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version" - classpath "org.jetbrains.dokka:dokka-gradle-plugin:${dokka_version}" - classpath "net.i2p.crypto:eddsa:$eddsa_version" // Needed for ServiceIdentityGenerator in the build environment. - classpath "org.owasp:dependency-check-gradle:${dependency_checker_version}" + classpath "org.jetbrains.dokka:dokka-base:$dokka_version" + classpath "org.owasp:dependency-check-gradle:$dependency_checker_version" classpath "org.jfrog.buildinfo:build-info-extractor-gradle:$artifactory_plugin_version" // Capsule gradle plugin forked and maintained locally to support Gradle 5.x // See https://github.com/corda/gradle-capsule-plugin - classpath "us.kirchmeier:gradle-capsule-plugin:1.0.4_r3" + classpath "us.kirchmeier:gradle-capsule-plugin:1.0.5_r3" classpath group: "com.r3.testing", name: "gradle-distributed-testing-plugin", version: '1.3.0' classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8" - classpath "com.gradle:gradle-enterprise-gradle-plugin:$gradleEnterprisePlugin" - classpath "com.gradle:common-custom-user-data-gradle-plugin:$customUserDataGradlePlugin" } configurations.classpath { @@ -219,34 +195,20 @@ buildscript { } plugins { - // Add the shadow plugin to the plugins classpath for the entire project. - id 'com.github.johnrengelman.shadow' version '2.0.4' apply false + id 'org.jetbrains.kotlin.jvm' apply false + id 'org.jetbrains.kotlin.plugin.allopen' apply false + id 'org.jetbrains.kotlin.plugin.jpa' apply false + id 'com.github.johnrengelman.shadow' version '7.1.2' apply false id "org.ajoberstar.grgit" version "4.0.0" + id 'corda.root-publish' + id "org.jetbrains.dokka" version "1.8.20" } apply plugin: 'project-report' apply plugin: 'com.github.ben-manes.versions' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' apply plugin: 'com.r3.testing.distributed-testing' -apply plugin: "com.gradle.build-scan" -apply plugin: "com.gradle.common-custom-user-data-gradle-plugin" -buildScan { - server = gradleEnterpriseUrl - allowUntrustedServer = false - def apiKey = project.findProperty('CORDA_GRADLE_SCAN_KEY') ?: System.getenv('CORDA_GRADLE_SCAN_KEY') - if (apiKey?.trim()) { - publishAlways() - capture { - taskInputFiles = true - } - uploadInBackground = false - accessKey = apiKey - } -} - -// If the command line project option -PversionFromGit is added to the gradle invocation, we'll resolve +// If the command line project option -PversionFromGit is added to the gradle invocation, we'll resolve // the latest git commit hash and timestamp and create a version postfix from that if (project.hasProperty("versionFromGit")){ ext.versionSuffix = "${grgit.head().dateTime.format("yyyyMMdd_HHmmss")}-${grgit.head().abbreviatedId}" @@ -259,26 +221,17 @@ if (ext.versionSuffix != ""){ ext.corda_release_version = "${ext.baseVersion}".toString() } -// We need the following three lines even though they're inside an allprojects {} block below because otherwise -// IntelliJ gets confused when importing the project and ends up erasing and recreating the .idea directory, along -// with the run configurations. It also doesn't realise that the project is a Java 8 project and misconfigures -// the resulting import. This fixes it. -apply plugin: 'java' - -logger.lifecycle("Java version: {}", JavaVersion.current()) -sourceCompatibility = VERSION_1_8 -targetCompatibility = JavaVersion.current().isJava8() ? VERSION_1_8 : VERSION_11 -logger.lifecycle("Java source compatibility: {}", sourceCompatibility) -logger.lifecycle("Java target compatibility: {}", targetCompatibility) +logger.lifecycle("JDK: {}", System.getProperty("java.home")) logger.lifecycle("Quasar version: {}", quasar_version) logger.lifecycle("Quasar classifier: {}", quasar_classifier.toString()) logger.lifecycle("Building Corda version: {}", corda_release_version) +logger.lifecycle("User home: {}", System.getProperty('user.home')) allprojects { - apply plugin: 'kotlin' + apply plugin: 'java' + apply plugin: 'kotlin-allopen' apply plugin: 'jacoco' apply plugin: 'org.owasp.dependencycheck' - apply plugin: 'kotlin-allopen' apply plugin: 'org.sonarqube' allOpen { @@ -289,19 +242,6 @@ allprojects { ) } - // we do this to allow for Gradle task caching. - // below block tells Gradle to ignore specifically the dymaically generated files in the manifest when checking if a file is up to date - // this has no impact on publishing or production of jar, This only reates to Grades mechamish for verifying the Cache key - normalization { - runtimeClasspath { - ignore("**/*.EC") //signing related - ignore("**/*.SF") //signing related - ignore("**/*.MF") - ignore("**/*.kotlin_module") - ignore("**/Cordapp-Dependencies") - } - } - dependencyCheck { suppressionFile = '.ci/dependency-checker/suppressedLibraries.xml' cveValidForHours = 1 @@ -316,12 +256,17 @@ allprojects { nugetconfEnabled = false } } - sourceCompatibility = VERSION_1_8 - targetCompatibility = JavaVersion.current().isJava8() ? VERSION_1_8 : VERSION_11 + + sourceCompatibility = VERSION_17 + targetCompatibility = VERSION_17 jacoco { - // JDK11 official support (https://github.com/jacoco/jacoco/releases/tag/v0.8.3) - toolVersion = "0.8.3" + toolVersion = "0.8.7" + } + + java { + withSourcesJar() + withJavadocJar() } tasks.withType(JavaCompile).configureEach { @@ -336,13 +281,13 @@ allprojects { options.encoding = 'UTF-8' } - tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { - kotlinOptions { - languageVersion = "1.2" - apiVersion = "1.2" - jvmTarget = VERSION_1_8 + tasks.withType(KotlinCompile).configureEach { + compilerOptions { + languageVersion = KOTLIN_1_9 + apiVersion = KOTLIN_1_9 + jvmTarget = JVM_17 javaParameters = true // Useful for reflection. - freeCompilerArgs = ['-Xjvm-default=compatibility'] + freeCompilerArgs = ['-Xjvm-default=all-compatibility'] allWarningsAsErrors = warnings_as_errors } } @@ -362,15 +307,14 @@ allprojects { attributes('Corda-Docs-Link': corda_docs_link) } } - + tasks.withType(Test).configureEach { + jvmArgs += project(":node:capsule").file("src/main/resources/node-jvm-args.txt").readLines() + jvmArgs += "--add-modules=jdk.incubator.foreign" // For the SharedMemoryIncremental forkEvery = 20 ignoreFailures = project.hasProperty('tests.ignoreFailures') ? project.property('tests.ignoreFailures').toBoolean() : false failFast = project.hasProperty('tests.failFast') ? project.property('tests.failFast').toBoolean() : false - // Prevent the project from creating temporary files outside of the build directory. - systemProperty 'java.io.tmpdir', buildDir.absolutePath - maxHeapSize = "1g" if (project.path.startsWith(':experimental') && System.getProperty("experimental.test.enable") == null) { @@ -380,25 +324,18 @@ allprojects { // Required to use Gradle build cache (until Gradle 5.0 is released with default value of "append" set to false) // See https://github.com/gradle/gradle/issues/5269 and https://github.com/gradle/gradle/pull/6419 extensions.configure(TypeOf.typeOf(JacocoTaskExtension)) { ex -> - ex.append = false +// ex.append = false } - maxParallelForks = (System.env.CORDA_TESTING_FORKS == null) ? 1 : "$System.env.CORDA_TESTING_FORKS".toInteger() - - systemProperty 'java.security.egd', 'file:/dev/./urandom' - } - - tasks.withType(Test).configureEach { if (name.contains("integrationTest")) { maxParallelForks = (System.env.CORDA_INT_TESTING_FORKS == null) ? 1 : "$System.env.CORDA_INT_TESTING_FORKS".toInteger() + } else { + maxParallelForks = (System.env.CORDA_TESTING_FORKS == null) ? 1 : "$System.env.CORDA_TESTING_FORKS".toInteger() } - } - if (jdkClassifier) { - jar { - // JDK11 built and published artifacts to include classifier - archiveClassifier = jdkClassifier - } + // Prevent the project from creating temporary files outside of the build directory. + systemProperty 'java.io.tmpdir', buildDir.absolutePath + systemProperty 'java.security.egd', 'file:/dev/./urandom' } group 'net.corda' @@ -439,6 +376,16 @@ allprojects { includeGroup 'com.github.bft-smart' includeGroup 'com.github.detro' } + metadataSources { + mavenPom() + artifact() + } + } + maven { + url "${publicArtifactURL}/corda-dependencies-dev" + content { + includeGroup 'co.paralleluniverse' + } } maven { url "${publicArtifactURL}/corda-dev" @@ -468,12 +415,12 @@ allprojects { } configurations { - all { + configureEach { resolutionStrategy { - // Force dependencies to use the same version of Kotlin as Corda. - force "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - force "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - force "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + if (pluginManager.hasPlugin("org.jetbrains.kotlin.jvm")) { + // Force dependencies to use the same version of Kotlin as Corda. + force "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + } // Force dependencies to use the same version of Guava as Corda. force "com.google.guava:guava:$guava_version" @@ -508,7 +455,7 @@ allprojects { 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") + substitute module('ch.qos.logback:logback-classic') with module("org.apache.logging.log4j:log4j-slf4j2-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. @@ -519,27 +466,32 @@ allprojects { // Effectively delete this unused and unwanted transitive dependency of Artemis. substitute module('org.jgroups:jgroups') with module("org.apache.activemq:artemis-commons:$artemis_version") - } - } - } - // Select all of the compileClasspath and runtimeClasspath etc configurations, - // but NOT the "classpath" configuration, as that is used by the Gradle plugins. - matching { it.name.endsWith("Classpath") }.configureEach { cfg -> - cfg.resolutionStrategy { - dependencySubstitution { - // Force dependencies to use the same version of Kotlin as Corda. - 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 use of LTS version of BC everywhere + substitute module('org.bouncycastle:bcutil-jdk18on') with module("org.bouncycastle:bcutil-lts8on:$bouncycastle_version") + substitute module('org.bouncycastle:bcprov-jdk18on') with module("org.bouncycastle:bcprov-lts8on:$bouncycastle_version") + substitute module('org.bouncycastle:bcpkix-jdk18on') with module("org.bouncycastle:bcpkix-lts8on:$bouncycastle_version") } // FORCE Gradle to use latest SNAPSHOT dependencies. cacheChangingModulesFor 0, 'seconds' } } + + if (pluginManager.hasPlugin("org.jetbrains.kotlin.jvm")) { + // Select all of the compileClasspath and runtimeClasspath etc configurations, + // but NOT the "classpath" configuration, as that is used by the Gradle plugins. + matching { it.name.endsWith("Classpath") }.configureEach { cfg -> + cfg.resolutionStrategy { + dependencySubstitution { + // Force dependencies to use the same version of Kotlin as Corda. + 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") + } + } + } + } } } @@ -554,37 +506,29 @@ sonarqube { } } -// Check that we are running on a Java 8 JDK. The source/targetCompatibility values above aren't sufficient to -// guarantee this because those are properties checked by the Java plugin, but we're using Kotlin. -// -// We recommend a specific minor version (unfortunately, not checkable directly) because JavaFX adds APIs in -// minor releases, so we can't work with just any Java 8, it has to be a recent one. -if (!JavaVersion.current().java8Compatible) - throw new GradleException("Corda requires Java 8, please upgrade to at least 1.8.0_$java8_minUpdateVersion") - configurations { detekt } // Required for building out the fat JAR. dependencies { - compile project(':node') - compile "com.google.guava:guava:$guava_version" + implementation project(':node') + implementation "com.google.guava:guava:$guava_version" - // Set to corda compile to ensure it exists now deploy nodes no longer relies on build - compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') - compile project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts') + // Set to corda implementation to ensure it exists now deploy nodes no longer relies on build + implementation project(path: ":node:capsule", configuration: 'runtimeArtifacts') + implementation project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts') // For the buildCordappDependenciesJar task - runtime project(':client:jfx') - runtime project(':client:mock') - runtime project(':client:rpc') - runtime project(':core') - runtime project(':confidential-identities') - runtime project(':finance:workflows') - runtime project(':finance:contracts') - runtime project(':testing:testserver') - testCompile project(':test-utils') + runtimeOnly project(':client:jfx') + runtimeOnly project(':client:mock') + runtimeOnly project(':client:rpc') + runtimeOnly project(':core') + runtimeOnly project(':confidential-identities') + runtimeOnly project(':finance:workflows') + runtimeOnly project(':finance:contracts') + runtimeOnly project(':testing:testserver') + testImplementation project(':test-utils') detekt 'io.gitlab.arturbosch.detekt:detekt-cli:1.0.1' } @@ -593,16 +537,16 @@ jar { enabled = false } -task jacocoRootReport(type: org.gradle.testing.jacoco.tasks.JacocoReport) { +tasks.register('jacocoRootReport', JacocoReport) { dependsOn = subprojects.test - additionalSourceDirs = files(subprojects.sourceSets.main.allSource.srcDirs) - sourceDirectories = files(subprojects.sourceSets.main.allSource.srcDirs) - classDirectories = files(subprojects.sourceSets.main.output) - executionData = files(subprojects.jacocoTestReport.executionData) +// additionalSourceDirs = files(subprojects.sourceSets.main.allSource.srcDirs) +// sourceDirectories = files(subprojects.sourceSets.main.allSource.srcDirs) +// classDirectories = files(subprojects.sourceSets.main.output) +// executionData = files(subprojects.jacocoTestReport.executionData) reports { - html.enabled = true - xml.enabled = true - csv.enabled = false + html.required = true + xml.required = true + csv.required = false } onlyIf = { true @@ -622,13 +566,13 @@ tasks.register('detekt', JavaExec) { def plugins = detektPluginsJar.outputs.files.singleFile def params = ['-i', input, '-c', config, '-b', baseline, '--plugins', plugins] inputs.files(detektPluginsJar, config, baseline) - main = "io.gitlab.arturbosch.detekt.cli.Main" + mainClass = "io.gitlab.arturbosch.detekt.cli.Main" classpath = configurations.detekt args(params) } tasks.register('detektBaseline', JavaExec) { - main = "io.gitlab.arturbosch.detekt.cli.Main" + mainClass = "io.gitlab.arturbosch.detekt.cli.Main" classpath = configurations.detekt def input = "$projectDir" def config = "$projectDir/detekt-config.yml, $projectDir/detekt-baseline-config.yml" @@ -638,103 +582,28 @@ tasks.register('detektBaseline', JavaExec) { } tasks.withType(Test).configureEach { - reports.html.destination = file("${reporting.baseDir}/${name}") + reports.html.outputLocation.set(file("${reporting.baseDir}/${name}")) } -task testReport(type: TestReport) { +tasks.register('testReport', TestReport) { destinationDir = file("$buildDir/reports/allTests") // Include the results from the `test` task in all subprojects reportOn subprojects*.test } -bintrayConfig { - user = System.getenv('CORDA_BINTRAY_USER') - key = System.getenv('CORDA_BINTRAY_KEY') - repo = 'corda' - org = 'r3' - licenses = ['Apache-2.0'] - vcsUrl = 'https://github.com/corda/corda' - projectUrl = 'https://github.com/corda/corda' - gpgSign = true - gpgPassphrase = System.getenv('CORDA_BINTRAY_GPG_PASSPHRASE') - publications = [ - 'corda-opentelemetry', - 'corda-opentelemetry-driver', - 'corda-jfx', - 'corda-mock', - 'corda-rpc', - 'corda-core', - 'corda', - 'corda-finance-workflows', - 'corda-finance-contracts', - 'corda-node', - 'corda-node-api', - 'corda-test-common', - 'corda-core-test-utils', - 'corda-test-utils', - 'corda-test-db', - 'corda-jackson', - 'corda-testserver-impl', - 'corda-testserver', - 'corda-node-driver', - 'corda-confidential-identities', - 'corda-shell', - 'corda-tools-shell-cli', - 'corda-serialization', - 'corda-tools-blob-inspector', - 'corda-tools-explorer', - 'corda-tools-network-bootstrapper', - 'corda-tools-cliutils', - 'corda-common-configuration-parsing', - 'corda-common-validation', - 'corda-common-logging', - 'corda-tools-network-builder', - 'corda-tools-checkpoint-agent' - ] - license { - name = 'Apache-2.0' - url = 'https://www.apache.org/licenses/LICENSE-2.0' - distribution = 'repo' - } - developer { - id = 'R3' - name = 'R3' - email = 'dev@corda.net' - } -} - -// Build a ZIP of all JARs required to compile the Cordapp template // Note: corda.jar is used at runtime so no runtime ZIP is necessary. // Resulting ZIP can be found in "build/distributions" -task buildCordappDependenciesZip(type: Zip) { +tasks.register('buildCordappDependenciesZip', Zip) { baseName 'corda-deps' - from configurations.runtime - from configurations.compile - from configurations.testCompile + from configurations.runtimeOnly + from configurations.implementation + from configurations.testImplementation from buildscript.configurations.classpath from 'node/capsule/NOTICE' // CDDL notice duplicatesStrategy = DuplicatesStrategy.EXCLUDE } -artifactory { - publish { - contextUrl = artifactory_contextUrl - repository { - repoKey = 'corda-dev' - username = System.getenv('CORDA_ARTIFACTORY_USERNAME') - password = System.getenv('CORDA_ARTIFACTORY_PASSWORD') - } - - defaults { - // Root project applies the plugin (for this block) but does not need to be published - if (project != rootProject) { - publications(project.extensions.publish.name()) - } - } - } -} - -tasks.register('generateApi', net.corda.plugins.apiscanner.GenerateApi) { +tasks.register('generateApi', GenerateApi) { baseName = "api-corda" } @@ -770,7 +639,7 @@ if (file('corda-docs-only-build').exists() || (System.getenv('CORDA_DOCS_ONLY_BU } wrapper { - gradleVersion = '5.6.4' + gradleVersion = '7.6.4' distributionType = Wrapper.DistributionType.ALL } diff --git a/buildCacheSettings.gradle b/buildCacheSettings.gradle new file mode 100644 index 0000000000..b4d0175f6e --- /dev/null +++ b/buildCacheSettings.gradle @@ -0,0 +1,16 @@ +// Gradle Build Cache configuration recommendation: https://docs.gradle.org/current/userguide/build_cache.html +ext { + isCiServer = System.getenv().containsKey("CORDA_CI") + gradleBuildCacheURL = System.getenv().containsKey("GRADLE_BUILD_CACHE_URL") ? System.getenv().get("GRADLE_BUILD_CACHE_URL") : 'http://localhost:5071/cache/' +} + +buildCache { + local { + enabled = !isCiServer + } + remote(HttpBuildCache) { + enabled = isCiServer + url = gradleBuildCacheURL + push = isCiServer + } +} diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index ee98b87b3d..8ba81c98a4 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,11 +1,56 @@ +plugins { + id 'groovy-gradle-plugin' +} + Properties constants = new Properties() file("$rootDir/../constants.properties").withInputStream { constants.load(it) } +def internalPublishVersion = constants.getProperty('internalPublishVersion') +def artifactoryContextUrl = constants.getProperty('artifactoryContextUrl') + repositories { - mavenCentral() + def cordaUseCache = System.getenv("CORDA_USE_CACHE") + if (cordaUseCache != null) { + maven { + url = "${artifactoryContextUrl}/${cordaUseCache}" + name = "R3 Maven remote repositories" + authentication { + basic(BasicAuthentication) + } + credentials { + username = findProperty('cordaArtifactoryUsername') ?: System.getenv('CORDA_ARTIFACTORY_USERNAME') + password = findProperty('cordaArtifactoryPassword') ?: System.getenv('CORDA_ARTIFACTORY_PASSWORD') + } + metadataSources { + mavenPom() + artifact() + ignoreGradleMetadataRedirection() + } + } + } else { + maven { + url "${artifactoryContextUrl}/engineering-tools-maven" + authentication { + basic(BasicAuthentication) + } + credentials { + username = findProperty('cordaArtifactoryUsername') ?: System.getenv('CORDA_ARTIFACTORY_USERNAME') + password = findProperty('cordaArtifactoryPassword') ?: System.getenv('CORDA_ARTIFACTORY_PASSWORD') + } + content { + includeGroupByRegex 'com\\.r3\\.internal(\\..*)?' + } + } + gradlePluginPortal() + } } dependencies { - compile group: 'com.github.docker-java', name: 'docker-java', version: constants.dockerJavaVersion - compile group: 'com.github.docker-java', name: 'docker-java-transport-httpclient5', version: constants.dockerJavaVersion + implementation "com.github.docker-java:docker-java:$constants.dockerJavaVersion" + implementation "com.github.docker-java:docker-java-transport-httpclient5:$constants.dockerJavaVersion" + implementation "org.jooq:joor:$constants.joorVersion" + + if (System.getenv('CORDA_ARTIFACTORY_USERNAME') != null || project.hasProperty('cordaArtifactoryUsername')) { + implementation "com.r3.internal.gradle.plugins:publish:$internalPublishVersion" + } } diff --git a/buildSrc/src/main/groovy/corda.common-publishing.gradle b/buildSrc/src/main/groovy/corda.common-publishing.gradle new file mode 100644 index 0000000000..20b2d4be8d --- /dev/null +++ b/buildSrc/src/main/groovy/corda.common-publishing.gradle @@ -0,0 +1,92 @@ +import groovy.transform.CompileStatic + +// plugin to cater for R3 vs Non R3 users building code base. R3 employees will leverage internal plugins non +// R3 users will use standard Maven publishing conventions as provided by the Maven-publish gradle plugin +if (System.getenv('CORDA_ARTIFACTORY_USERNAME') != null || project.hasProperty('cordaArtifactoryUsername')) { + logger.info("Internal R3 user - resolving publication build dependencies from internal plugins") + pluginManager.apply('com.r3.internal.gradle.plugins.r3Publish') + afterEvaluate { + publishing { + publications { + configureEach { + def repo = "https://github.com/corda/corda" + pom { + description = project.description + name = project.name + url = repo + scm { + url = repo + } + licenses { + license { + name = 'Apache-2.0' + url = 'https://www.apache.org/licenses/LICENSE-2.0' + distribution = 'repo' + } + } + + developers { + developer { + id = 'R3' + name = 'R3' + email = 'dev@corda.net' + } + } + } + } + } + } + } +} else { + logger.info("External user - using standard maven publishing") + pluginManager.apply('maven-publish') + pluginManager.withPlugin('java') { + afterEvaluate { + publishing { + if (publications.isEmpty()) { + // If we haven't already created a MavenPublication then create one now. + publications { + maven(MavenPublication) { + artifactId = tasks.named('jar', Jar).flatMap { it.archiveBaseName }.get() + groupId group.toString() + from findSoftwareComponent(components).get() + + if (artifacts.matching { it.classifier == 'sources' }.isEmpty()) { + try { + artifact tasks.named('sourcesJar', Jar) + } catch (UnknownTaskException ignored) { + } + } + + try { + artifact tasks.named('javadocJar', Jar) + } catch (UnknownTaskException ignored) { + } + } + } + } + } + } + } + + tasks.withType(GenerateModuleMetadata).configureEach { + enabled = false + } + + tasks.register('install') { + dependsOn 'publishToMavenLocal' + } +} + +@CompileStatic +private static Provider findSoftwareComponent(SoftwareComponentContainer components) { + try { + return components.named('cordapp') + } catch (UnknownDomainObjectException ignored) { + try { + return components.named('kotlin') + } catch (UnknownDomainObjectException ignored2) { + return components.named('java') + } + } +} diff --git a/buildSrc/src/main/groovy/corda.kotlin-1.2.gradle b/buildSrc/src/main/groovy/corda.kotlin-1.2.gradle new file mode 100644 index 0000000000..fa45f93245 --- /dev/null +++ b/buildSrc/src/main/groovy/corda.kotlin-1.2.gradle @@ -0,0 +1,91 @@ +import org.gradle.api.internal.file.DefaultSourceDirectorySet + +import static org.joor.Reflect.onClass + +pluginManager.apply(Kotlin12Plugin.class) + +// We cannot use the 1.2 Kotlin plugin as it only works with a very old version of Gradle, which itself will only work on Java 8. So we need +// our own plugin which calls the 1.2 compiler directly. +class Kotlin12Plugin implements Plugin { + private static final KOTLIN_VERSION = "1.2.71" + + @Override + void apply(Project project) { + project.pluginManager.apply(JavaPlugin.class) + + project.extensions.add("kotlin_1_2_version", KOTLIN_VERSION) + project.dependencies.add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$KOTLIN_VERSION") + + def kotlinCompilerConfiguration = project.configurations.create("kotlinCompiler") + project.dependencies.add("kotlinCompiler", "org.jetbrains.kotlin:kotlin-compiler:$KOTLIN_VERSION") + + project.extensions.getByType(JavaPluginExtension.class).sourceSets.configureEach { sourceSet -> + // Create the "src/*/kotlin" SourceDirectorySet, alongside the "java" one + def kotlinSourceDirectorySet = new DefaultSourceDirectorySet(project.objects.sourceDirectorySet("kotlin", "${sourceSet.displayName} Kotlin source")) + sourceSet.extensions.add(SourceDirectorySet.class, "kotlin", kotlinSourceDirectorySet) + kotlinSourceDirectorySet.filter.include("**/*.java", "**/*.kt") + kotlinSourceDirectorySet.srcDir(project.file("src/${sourceSet.name}/kotlin")) + + def allKotlin = project.objects.sourceDirectorySet("allkotlin", "${sourceSet.displayName} Kotlin source") + allKotlin.filter.include("**/*.kt") + allKotlin.source(kotlinSourceDirectorySet) + + sourceSet.allJava.source(kotlinSourceDirectorySet) + sourceSet.allSource.source(kotlinSourceDirectorySet) + + def kotlinBuildDir = project.layout.buildDirectory.dir("classes/kotlin/${sourceSet.name}") + sourceSet.output.dir(kotlinBuildDir) + + def taskSourceSetName = isMain(sourceSet) ? "" : sourceSet.name.capitalize() + + def compileKotlin = project.tasks.register("compile${taskSourceSetName}Kotlin", KotlinCompile.class) { task -> + // The 1.2 compiler needs to be laoded in a separate class loader, as the build classpath already contains its own version + // of Kotlin. + task.compilerClasspath.from(kotlinCompilerConfiguration) + task.source(allKotlin) + // Paradoxically, the Java sources are also required by the Kotlin compiler. This is actually so that it can correctly + // resolve any references the Kotlin code makes to Java code. + task.source(sourceSet.allJava) + task.classpath = sourceSet.compileClasspath + task.destinationDirectory = kotlinBuildDir + } + + // Compiling the Java code needs the compiled Kotlin code first + project.tasks.named("compile${taskSourceSetName}Java", JavaCompile.class) { task -> + task.classpath += project.files(compileKotlin.map { it.destinationDirectory }) + } + } + } +} + +abstract class KotlinCompile extends AbstractCompile { + @Classpath + abstract ConfigurableFileCollection getCompilerClasspath() + + @TaskAction + void compile() { + def args = [ + "-jvm-target", "1.8", + "-language-version", "1.2", + "-api-version", "1.2", + "-java-parameters", + "-Xjvm-default=compatibility", + "-no-stdlib", + "-Xallow-kotlin-package", // We may have copies of stdlib APIs (see `core-1.2`) + "-cp", classpath.asPath, + "-d", destinationDirectory.get().asFile.absolutePath + ] + args.addAll(source.collect { it.absolutePath }) + + logger.info("args: {}", args) + + def compilerClassLoader = new URLClassLoader(compilerClasspath.collect { it.toURI().toURL() } as URL[]) + def exitCode = onClass("org.jetbrains.kotlin.cli.jvm.K2JVMCompiler", compilerClassLoader) + .create() + .call("exec", System.err, args as String[]) + .get() + if (exitCode.toString() != "OK") { + throw new GradleException("Compilation error. See log for more details") + } + } +} diff --git a/buildSrc/src/main/groovy/corda.root-publish.gradle b/buildSrc/src/main/groovy/corda.root-publish.gradle new file mode 100644 index 0000000000..7eeed46b6c --- /dev/null +++ b/buildSrc/src/main/groovy/corda.root-publish.gradle @@ -0,0 +1,6 @@ +// Apply artifactory r3ArtifactoryPublish plugin +if (System.getenv('CORDA_ARTIFACTORY_USERNAME') != null || project.hasProperty('cordaArtifactoryUsername')) { + project.pluginManager.apply('com.r3.internal.gradle.plugins.r3ArtifactoryPublish') +} + +project.pluginManager.apply('maven-publish') diff --git a/client/jackson/build.gradle b/client/jackson/build.gradle index b86798a8b3..209d0462e9 100644 --- a/client/jackson/build.gradle +++ b/client/jackson/build.gradle @@ -1,25 +1,36 @@ -apply plugin: 'java' -apply plugin: 'kotlin' -apply plugin: 'net.corda.plugins.publish-utils' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.api-scanner' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' + +description 'Corda Jackson module' dependencies { - compile project(':serialization') + api project(':core') + + implementation project(':serialization') - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Jackson and its plugins: parsing to/from JSON and other textual formats. - compile("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version") { + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version") { exclude module: "jackson-databind" } // Yaml is useful for parsing strings to method calls. - compile "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jackson_version" + implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jackson_version" // This adds support for java.time types. - compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version" - compile "com.google.guava:guava:$guava_version" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version" + implementation "com.google.guava:guava:$guava_version" - testCompile project(':test-utils') - testCompile project(path: ':core', configuration: 'testArtifacts') + // Bouncy castle support needed for X509 certificate manipulation + implementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}" + implementation "org.bouncycastle:bcpkix-lts8on:${bouncycastle_version}" + implementation "org.slf4j:slf4j-api:$slf4j_version" + + testImplementation project(':finance:workflows') + testImplementation project(':node-api') + testImplementation project(':test-common') + testImplementation project(':core-test-utils') + testImplementation project(':test-utils') + testImplementation project(":node-driver") + testImplementation project(path: ':core', configuration: 'testArtifacts') testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" @@ -28,7 +39,7 @@ dependencies { testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" } @@ -39,6 +50,11 @@ jar { } } -publish { - name jar.baseName -} \ No newline at end of file +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } +} diff --git a/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt b/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt index 46d7c105f3..e15c760877 100644 --- a/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt +++ b/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt @@ -24,7 +24,7 @@ import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier import com.fasterxml.jackson.databind.deser.std.NumberDeserializers import com.fasterxml.jackson.databind.node.ObjectNode import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule -import com.fasterxml.jackson.module.kotlin.KotlinModule +import com.fasterxml.jackson.module.kotlin.kotlinModule import net.corda.client.jackson.internal.CordaModule import net.corda.client.jackson.internal.ToStringSerialize import net.corda.client.jackson.internal.jsonObject @@ -197,7 +197,7 @@ object JacksonSupport { addSerializer(Date::class.java, DateSerializer) }) registerModule(CordaModule()) - registerModule(KotlinModule().apply { + registerModule(kotlinModule().apply { setDeserializerModifier(KotlinObjectDeserializerModifier) }) diff --git a/client/jackson/src/main/kotlin/net/corda/client/jackson/StringToMethodCallParser.kt b/client/jackson/src/main/kotlin/net/corda/client/jackson/StringToMethodCallParser.kt index 7b9a1dec27..4d95662140 100644 --- a/client/jackson/src/main/kotlin/net/corda/client/jackson/StringToMethodCallParser.kt +++ b/client/jackson/src/main/kotlin/net/corda/client/jackson/StringToMethodCallParser.kt @@ -120,7 +120,7 @@ open class StringToMethodCallParser @JvmOverloads constructor( } /** - * Uses either Kotlin or Java 8 reflection to learn the names of the parameters to a method. + * Uses either Kotlin or Java reflection to learn the names of the parameters to a method. */ open fun paramNamesFromMethod(method: Method): List { val kf: KFunction<*>? = method.kotlinFunction @@ -135,7 +135,7 @@ open class StringToMethodCallParser @JvmOverloads constructor( } /** - * Uses either Kotlin or Java 8 reflection to learn the names of the parameters to a constructor. + * Uses either Kotlin or Java reflection to learn the names of the parameters to a constructor. */ open fun paramNamesFromConstructor(ctor: Constructor<*>): List { val kf: KFunction<*>? = ctor.kotlinFunction diff --git a/client/jackson/src/main/kotlin/net/corda/client/jackson/internal/CordaModule.kt b/client/jackson/src/main/kotlin/net/corda/client/jackson/internal/CordaModule.kt index 24e3efd707..3dddecec1a 100644 --- a/client/jackson/src/main/kotlin/net/corda/client/jackson/internal/CordaModule.kt +++ b/client/jackson/src/main/kotlin/net/corda/client/jackson/internal/CordaModule.kt @@ -95,7 +95,8 @@ import java.math.BigDecimal import java.security.PublicKey import java.security.cert.CertPath import java.time.Instant -import java.util.* +import java.util.Currency +import java.util.UUID class CordaModule : SimpleModule("corda-core") { override fun setupModule(context: SetupContext) { @@ -256,6 +257,7 @@ private data class StxJson( private interface WireTransactionMixin private class WireTransactionSerializer : JsonSerializer() { + @Suppress("INVISIBLE_MEMBER") override fun serialize(value: WireTransaction, gen: JsonGenerator, serializers: SerializerProvider) { gen.writeObject(WireTransactionJson( value.digestService, @@ -265,7 +267,7 @@ private class WireTransactionSerializer : JsonSerializer() { value.outputs, value.commands, value.timeWindow, - value.attachments, + value.legacyAttachments.map { "$it-legacy" } + value.nonLegacyAttachments.map { it.toString() }, value.references, value.privacySalt, value.networkParametersHash @@ -276,15 +278,18 @@ private class WireTransactionSerializer : JsonSerializer() { private class WireTransactionDeserializer : JsonDeserializer() { override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): WireTransaction { val wrapper = parser.readValueAs() + // We're not concerned with backwards compatibility for any JSON string that was created with 4.11 and being materialised in 4.12. + val (legacyAttachments, newerAttachments) = wrapper.attachments.partition { it.endsWith("-legacy") } val componentGroups = createComponentGroups( wrapper.inputs, wrapper.outputs, wrapper.commands, - wrapper.attachments, + newerAttachments.map(SecureHash::parse), wrapper.notary, wrapper.timeWindow, wrapper.references, - wrapper.networkParametersHash + wrapper.networkParametersHash, + legacyAttachments.map { SecureHash.parse(it.removeSuffix("-legacy")) } ) return WireTransaction(componentGroups, wrapper.privacySalt, wrapper.digestService ?: DigestService.sha2_256) } @@ -297,10 +302,11 @@ private class WireTransactionJson(@get:JsonInclude(Include.NON_NULL) val digestS val outputs: List>, val commands: List>, val timeWindow: TimeWindow?, - val attachments: List, + val attachments: List, val references: List, val privacySalt: PrivacySalt, - val networkParametersHash: SecureHash?) + val networkParametersHash: SecureHash? +) private interface TransactionStateMixin { @get:JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) diff --git a/client/jackson/src/test/kotlin/net/corda/client/jackson/JacksonSupportTest.kt b/client/jackson/src/test/kotlin/net/corda/client/jackson/JacksonSupportTest.kt index 26efe9b567..fddafc6547 100644 --- a/client/jackson/src/test/kotlin/net/corda/client/jackson/JacksonSupportTest.kt +++ b/client/jackson/src/test/kotlin/net/corda/client/jackson/JacksonSupportTest.kt @@ -8,27 +8,36 @@ import com.fasterxml.jackson.databind.node.ObjectNode import com.fasterxml.jackson.databind.node.TextNode import com.fasterxml.jackson.dataformat.yaml.YAMLFactory import com.fasterxml.jackson.module.kotlin.convertValue -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever -import com.nhaarman.mockito_kotlin.spy import net.corda.client.jackson.internal.childrenAs import net.corda.client.jackson.internal.valueAs -import net.corda.core.contracts.* +import net.corda.core.contracts.Amount +import net.corda.core.contracts.Command +import net.corda.core.contracts.LinearState +import net.corda.core.contracts.PrivacySalt +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TimeWindow +import net.corda.core.contracts.TransactionState +import net.corda.core.contracts.UniqueIdentifier import net.corda.core.cordapp.CordappProvider -import net.corda.core.crypto.* import net.corda.core.crypto.CompositeKey +import net.corda.core.crypto.Crypto +import net.corda.core.crypto.DigestService +import net.corda.core.crypto.DigitalSignature +import net.corda.core.crypto.PartialMerkleTree import net.corda.core.crypto.PartialMerkleTree.PartialTree -import net.corda.core.identity.* -import net.corda.core.internal.AbstractAttachment +import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.SignatureMetadata +import net.corda.core.crypto.SignatureScheme +import net.corda.core.crypto.TransactionSignature +import net.corda.core.crypto.secureRandomBytes +import net.corda.core.identity.AbstractParty +import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.CordaX500Name +import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.internal.DigitalSignatureWithCert import net.corda.core.node.NodeInfo import net.corda.core.node.ServiceHub -import net.corda.core.node.services.AttachmentStorage -import net.corda.core.node.services.IdentityService -import net.corda.core.node.services.NetworkParametersService -import net.corda.core.node.services.TransactionStorage import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.deserialize @@ -37,14 +46,27 @@ import net.corda.core.transactions.CoreTransaction import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.WireTransaction -import net.corda.core.utilities.* +import net.corda.core.utilities.ByteSequence +import net.corda.core.utilities.NetworkHostAndPort +import net.corda.core.utilities.OpaqueBytes +import net.corda.core.utilities.days +import net.corda.core.utilities.hours +import net.corda.core.utilities.toBase58String +import net.corda.core.utilities.toBase64 +import net.corda.core.utilities.toHexString +import net.corda.coretesting.internal.createNodeInfoAndSigned +import net.corda.coretesting.internal.rigorousMock import net.corda.finance.USD import net.corda.nodeapi.internal.crypto.x509Certificates import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.contracts.DummyContract -import net.corda.testing.core.* -import net.corda.coretesting.internal.createNodeInfoAndSigned -import net.corda.coretesting.internal.rigorousMock +import net.corda.testing.core.ALICE_NAME +import net.corda.testing.core.BOB_NAME +import net.corda.testing.core.DUMMY_NOTARY_NAME +import net.corda.testing.core.DummyCommandData +import net.corda.testing.core.SerializationEnvironmentRule +import net.corda.testing.core.TestIdentity +import net.corda.testing.node.MockServices import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.Before @@ -54,15 +76,22 @@ import org.junit.jupiter.api.TestFactory import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.junit.runners.Parameterized.Parameters +import org.mockito.kotlin.spy +import org.mockito.kotlin.whenever import java.math.BigInteger import java.nio.charset.StandardCharsets.UTF_8 import java.security.PublicKey import java.security.cert.CertPath import java.security.cert.X509Certificate import java.time.Instant -import java.util.* +import java.util.Currency +import java.util.Date +import java.util.UUID import javax.security.auth.x500.X500Principal -import kotlin.collections.ArrayList +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.component3 +import kotlin.collections.component4 @RunWith(Parameterized::class) class JacksonSupportTest(@Suppress("unused") private val name: String, factory: JsonFactory) { @@ -90,23 +119,12 @@ class JacksonSupportTest(@Suppress("unused") private val name: String, factory: @Before fun setup() { - val unsignedAttachment = object : AbstractAttachment({ byteArrayOf() }, "test") { - override val id: SecureHash get() = throw UnsupportedOperationException() - } - - val attachments = rigorousMock().also { - doReturn(unsignedAttachment).whenever(it).openAttachment(any()) - } - services = rigorousMock() + services = MockServices( + listOf("net.corda.testing.contracts"), + MINI_CORP, + testNetworkParameters(minimumPlatformVersion = 4) + ) cordappProvider = rigorousMock() - val networkParameters = testNetworkParameters(minimumPlatformVersion = 4) - val networkParametersService = rigorousMock().also { - doReturn(networkParameters.serialize().hash).whenever(it).currentHash - } - doReturn(networkParametersService).whenever(services).networkParametersService - doReturn(cordappProvider).whenever(services).cordappProvider - doReturn(networkParameters).whenever(services).networkParameters - doReturn(attachments).whenever(services).attachments } @Test(timeout=300_000) @@ -263,17 +281,6 @@ class JacksonSupportTest(@Suppress("unused") private val name: String, factory: @Test(timeout=300_000) fun `SignedTransaction (WireTransaction)`() { val attachmentId = SecureHash.randomSHA256() - doReturn(attachmentId).whenever(cordappProvider).getContractAttachmentID(DummyContract.PROGRAM_ID) - val attachmentStorage = rigorousMock() - doReturn(attachmentStorage).whenever(services).attachments - doReturn(mock()).whenever(services).validatedTransactions - doReturn(mock()).whenever(services).identityService - val attachment = rigorousMock() - doReturn(attachment).whenever(attachmentStorage).openAttachment(attachmentId) - doReturn(attachmentId).whenever(attachment).id - doReturn(emptyList()).whenever(attachment).signerKeys - doReturn(setOf(DummyContract.PROGRAM_ID)).whenever(attachment).allContracts - doReturn("app").whenever(attachment).uploader val wtx = TransactionBuilder( notary = DUMMY_NOTARY, diff --git a/client/jackson/src/test/kotlin/net/corda/client/jackson/StringToMethodCallParserTest.kt b/client/jackson/src/test/kotlin/net/corda/client/jackson/StringToMethodCallParserTest.kt index 2b27c4c2b0..7fcd8259f0 100644 --- a/client/jackson/src/test/kotlin/net/corda/client/jackson/StringToMethodCallParserTest.kt +++ b/client/jackson/src/test/kotlin/net/corda/client/jackson/StringToMethodCallParserTest.kt @@ -26,7 +26,7 @@ class StringToMethodCallParserTest { "simple" to "simple", "string noteTextWord: A test of barewords" to "A test of barewords", "twoStrings a: Some words, b: ' and some words, like, Kirk, would, speak'" to "Some words and some words, like, Kirk, would, speak", - "simpleObject hash: $randomHash" to randomHash.toUpperCase(), + "simpleObject hash: $randomHash" to randomHash.uppercase(Locale.getDefault()), "complexObject pair: { first: 12, second: Word up brother }" to Pair(12, "Word up brother"), "overload a: A" to "A", "overload a: A, b: B" to "AB" @@ -51,7 +51,6 @@ class StringToMethodCallParserTest { val result = parser.parse(Target(), "complexNestedObject pairs: { first: 101, second: [ A, B, C ] }").invoke() assertTrue(result is Pair<*,*>) - result as Pair<*,*> assertEquals(101, result.first) diff --git a/client/jfx/build.gradle b/client/jfx/build.gradle index 06c1bbbd93..7303ee9d19 100644 --- a/client/jfx/build.gradle +++ b/client/jfx/build.gradle @@ -1,28 +1,27 @@ // JDK 11 JavaFX plugins { id 'org.openjfx.javafxplugin' version '0.0.7' apply false + id 'corda.common-publishing' } -if (JavaVersion.current().isJava9Compatible()) { - apply plugin: 'org.openjfx.javafxplugin' - javafx { - version = "11.0.2" - modules = ['javafx.controls', - 'javafx.fxml' - ] - } +apply plugin: 'org.openjfx.javafxplugin' +javafx { + version = "11.0.2" + modules = [ + 'javafx.controls', + 'javafx.fxml' + ] } -apply plugin: 'kotlin' + +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.quasar-utils' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' description 'Corda client JavaFX modules' //noinspection GroovyAssignabilityCheck configurations { - integrationTestCompile.extendsFrom testCompile - integrationTestRuntime.extendsFrom testRuntime + integrationTestImplementation.extendsFrom testImplementation + integrationTestRuntime.extendsFrom testRuntimeOnly } sourceSets { @@ -39,23 +38,26 @@ sourceSets { // build/reports/project/dependencies/index.html for green highlighted parts of the tree. dependencies { - compile project(':core') - compile project(':finance:contracts') - compile project(':finance:workflows') - compile project(':client:rpc') + implementation project(':core') + implementation project(':finance:contracts') + implementation project(':finance:workflows') + implementation project(':client:rpc') - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - compile "com.google.guava:guava:$guava_version" + implementation "com.google.guava:guava:$guava_version" + implementation "io.reactivex:rxjava:$rxjava_version" + + // For caches rather than guava + implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version" // ReactFX: Functional reactive UI programming. - compile 'org.reactfx:reactfx:2.0-M5' - compile 'org.fxmisc.easybind:easybind:1.0.3' + implementation 'org.reactfx:reactfx:2.0-M5' + implementation 'org.fxmisc.easybind:easybind:1.0.3' // Artemis Client: ability to connect to an Artemis broker and control it. // TODO: remove the forced update of commons-collections and beanutils when artemis updates them - compile "org.apache.commons:commons-collections4:${commons_collections_version}" - compile "commons-beanutils:commons-beanutils:${beanutils_version}" - compile("org.apache.activemq:artemis-core-client:${artemis_version}") { + implementation "org.apache.commons:commons-collections4:${commons_collections_version}" + implementation "commons-beanutils:commons-beanutils:${beanutils_version}" + implementation("org.apache.activemq:artemis-core-client:${artemis_version}") { exclude group: 'org.jgroups', module: 'jgroups' } @@ -67,13 +69,14 @@ dependencies { testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile "org.assertj:assertj-core:${assertj_version}" + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + testImplementation "org.assertj:assertj-core:${assertj_version}" - testCompile project(':test-utils') + testImplementation project(':test-utils') // Integration test helpers - integrationTestCompile "junit:junit:$junit_version" - integrationTestCompile project(':node-driver') + integrationTestImplementation "junit:junit:$junit_version" + integrationTestImplementation project(':node-driver') } task integrationTest(type: Test) { @@ -88,6 +91,11 @@ jar { } } -publish { - name jar.baseName +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } } diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/ModelsUtils.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/ModelsUtils.kt index 9655f8b083..d0a15771d9 100644 --- a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/ModelsUtils.kt +++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/ModelsUtils.kt @@ -40,4 +40,4 @@ inline fun observableList(noinline observableListProperty: TrackedDelegate.ObservableListDelegate(M::class, observableListProperty) inline fun observableListReadOnly(noinline observableListProperty: (M) -> ObservableList) = - TrackedDelegate.ObservableListReadOnlyDelegate(M::class, observableListProperty) \ No newline at end of file + TrackedDelegate.ObservableListReadOnlyDelegate(M::class, observableListProperty) diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/utils/AmountBindings.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/utils/AmountBindings.kt index 4d3ef8fa5f..55f39c7ca3 100644 --- a/client/jfx/src/main/kotlin/net/corda/client/jfx/utils/AmountBindings.kt +++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/utils/AmountBindings.kt @@ -14,13 +14,14 @@ import java.util.stream.Collectors * Utility bindings for the [Amount] type, similar in spirit to [Bindings] */ object AmountBindings { + @Suppress("SpreadOperator") fun sum(amounts: ObservableList>, token: T): MonadicBinding> = EasyBind.map( Bindings.createLongBinding({ amounts.stream().collect(Collectors.summingLong { require(it.token == token) it.quantity }) - }, arrayOf(amounts)) + }, *arrayOf(amounts)) ) { sum -> Amount(sum.toLong(), token) } fun exchange( @@ -35,6 +36,7 @@ object AmountBindings { } } + @Suppress("SpreadOperator") fun sumAmountExchange( amounts: ObservableList>, currency: ObservableValue, @@ -45,7 +47,7 @@ object AmountBindings { EasyBind.map( Bindings.createLongBinding({ amounts.stream().collect(Collectors.summingLong { exchange(it) }) - }, arrayOf(amounts)) + }, *arrayOf(amounts)) ) { Amount(it.toLong(), currencyValue) } } } diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/utils/ObservableUtilities.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/utils/ObservableUtilities.kt index f33c1eb126..342a76645a 100644 --- a/client/jfx/src/main/kotlin/net/corda/client/jfx/utils/ObservableUtilities.kt +++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/utils/ObservableUtilities.kt @@ -120,7 +120,7 @@ fun ObservableList.filter(predicate: ObservableValue<(A) -> Boolean>) */ fun ObservableList.filterNotNull(): ObservableList { //TODO This is a tactical work round for an issue with SAM conversion (https://youtrack.jetbrains.com/issue/ALL-1552) so that the M10 explorer works. - return uncheckedCast(uncheckedCast>(this).filtered { t -> t != null }) + return uncheckedCast(uncheckedCast>(this).filtered { t -> t != null }) } /** @@ -128,6 +128,7 @@ fun ObservableList.filterNotNull(): ObservableList { * val concatenatedNames = people.foldObservable("", { names, person -> names + person.name }) * val concatenatedNames2 = people.map(Person::name).fold("", String::plus) */ +@Suppress("SpreadOperator") fun ObservableList.foldObservable(initial: B, folderFunction: (B, A) -> B): ObservableValue { return Bindings.createObjectBinding({ var current = initial @@ -135,7 +136,7 @@ fun ObservableList.foldObservable(initial: B, folderFunction: (B, current = folderFunction(current, it) } current - }, arrayOf(this)) + }, *arrayOf(this)) } /** @@ -285,6 +286,7 @@ fun ObservableList.first(): ObservableValue { return getValueAt(0) } +@Suppress("SpreadOperator") fun ObservableList.last(): ObservableValue { return Bindings.createObjectBinding({ if (size > 0) { @@ -292,7 +294,7 @@ fun ObservableList.last(): ObservableValue { } else { null } - }, arrayOf(this)) + }, *arrayOf(this)) } fun ObservableList.unique(): ObservableList { @@ -303,24 +305,27 @@ fun ObservableList.distinctBy(toKey: (T) -> K): Observable return AggregatedList(this, toKey, { _, entryList -> entryList[0] }) } +@Suppress("SpreadOperator") fun ObservableValue<*>.isNotNull(): BooleanBinding { - return Bindings.createBooleanBinding({ this.value != null }, arrayOf(this)) + return Bindings.createBooleanBinding({ this.value != null }, *arrayOf(this)) } /** * Return first element of the observable list as observable value. * Return provided default value if the list is empty. */ +@Suppress("SpreadOperator") fun ObservableList.firstOrDefault(default: ObservableValue, predicate: (A) -> Boolean): ObservableValue { - return Bindings.createObjectBinding({ this.firstOrNull(predicate) ?: default.value }, arrayOf(this, default)) + return Bindings.createObjectBinding({ this.firstOrNull(predicate) ?: default.value }, *arrayOf(this, default)) } /** * Return first element of the observable list as observable value. * Return ObservableValue(null) if the list is empty. */ +@Suppress("SpreadOperator") fun ObservableList.firstOrNullObservable(predicate: (A) -> Boolean): ObservableValue { - return Bindings.createObjectBinding({ this.firstOrNull(predicate) }, arrayOf(this)) + return Bindings.createObjectBinding({ this.firstOrNull(predicate) }, *arrayOf(this)) } /** diff --git a/client/mock/build.gradle b/client/mock/build.gradle index 712ada2bf1..9963b73d6c 100644 --- a/client/mock/build.gradle +++ b/client/mock/build.gradle @@ -1,7 +1,6 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.quasar-utils' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' description 'Corda client mock modules' @@ -9,9 +8,9 @@ description 'Corda client mock modules' // build/reports/project/dependencies/index.html for green highlighted parts of the tree. dependencies { - compile project(":core") - compile project(':finance:workflows') - compile project(':finance:contracts') + implementation project(":core") + implementation project(':finance:workflows') + implementation project(':finance:contracts') testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" @@ -21,9 +20,9 @@ dependencies { testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" // Unit testing helpers. - testCompile "org.assertj:assertj-core:${assertj_version}" + testImplementation "org.assertj:assertj-core:${assertj_version}" - testCompile project(':test-utils') + testImplementation project(':test-utils') } jar { @@ -39,6 +38,11 @@ jar { } } -publish { - name jar.baseName +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } } diff --git a/client/rpc/build.gradle b/client/rpc/build.gradle index 38bc661404..835ed7f4a8 100644 --- a/client/rpc/build.gradle +++ b/client/rpc/build.gradle @@ -1,28 +1,20 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.quasar-utils' -apply plugin: 'net.corda.plugins.publish-utils' apply plugin: 'net.corda.plugins.api-scanner' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' +apply plugin: 'us.kirchmeier.capsule' description 'Corda client RPC modules' //noinspection GroovyAssignabilityCheck configurations { - integrationTestCompile.extendsFrom testCompile + integrationTestImplementation.extendsFrom testImplementation integrationTestRuntimeOnly.extendsFrom testRuntimeOnly - smokeTestCompile.extendsFrom compile + smokeTestImplementation.extendsFrom compile smokeTestRuntimeOnly.extendsFrom runtimeOnly } -compileKotlin { - kotlinOptions.jvmTarget = "1.8" -} - -compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" -} - sourceSets { integrationTest { kotlin { @@ -55,8 +47,58 @@ sourceSets { } } +dependencies { + implementation project(':core') + implementation project(':node-api') + implementation project(':serialization') + // For caches rather than guava + implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version" + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + implementation "io.reactivex:rxjava:$rxjava_version" + implementation("org.apache.activemq:artemis-core-client:${artemis_version}") { + exclude group: 'org.jgroups', module: 'jgroups' + } + implementation "com.google.guava:guava-testlib:$guava_version" + + testImplementation project(':node') + testImplementation project(':node-driver') + testImplementation project(':client:mock') + testImplementation project(':core-test-utils') + testImplementation "junit:junit:$junit_version" + // Unit testing helpers. + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + testImplementation "org.assertj:assertj-core:${assertj_version}" + testImplementation "io.dropwizard.metrics:metrics-core:$metrics_version" + + testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" + testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" + + integrationTestImplementation project(path: ':node-api', configuration: 'testArtifacts') + integrationTestImplementation project(':common-configuration-parsing') + integrationTestImplementation project(':finance:contracts') + integrationTestImplementation project(':finance:workflows') + integrationTestImplementation project(':test-utils') + integrationTestImplementation "co.paralleluniverse:quasar-core:$quasar_version" + integrationTestImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" + + smokeTestImplementation project(':core') + smokeTestImplementation project(':node-api') + smokeTestImplementation project(':finance:contracts') + smokeTestImplementation project(':finance:workflows') + smokeTestImplementation project(':smoke-test-utils') + smokeTestImplementation project(':testing:cordapps:sleeping') + smokeTestImplementation "junit:junit:$junit_version" + smokeTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + smokeTestImplementation "com.google.guava:guava:$guava_version" + smokeTestImplementation "org.hamcrest:hamcrest-library:2.1" + + smokeTestRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" + smokeTestRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" +} + processSmokeTestResources { - from(project(':node:capsule').tasks['buildCordaJAR']) { + // Bring in the fully built corda.jar for use by NodeFactory in the smoke tests + from(project(":node:capsule").tasks['buildCordaJAR']) { rename 'corda-(.*)', 'corda.jar' } from(project(':finance:workflows').tasks['jar']) { @@ -70,52 +112,12 @@ processSmokeTestResources { } } -// To find potential version conflicts, run "gradle htmlDependencyReport" and then look in -// build/reports/project/dependencies/index.html for green highlighted parts of the tree. - -dependencies { - compile project(':core') - compile project(':node-api') - - // For caches rather than guava - compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version" - - testImplementation "junit:junit:$junit_version" - - testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" - testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - - // Unit testing helpers. - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - testCompile "org.assertj:assertj-core:${assertj_version}" - - testCompile project(':node-driver') - testCompile project(':client:mock') - integrationTestCompile project(path: ':node-api', configuration: 'testArtifacts') - - // Smoke tests do NOT have any Node code on the classpath! - smokeTestCompile project(':smoke-test-utils') - smokeTestCompile project(':finance:contracts') - smokeTestCompile project(':finance:workflows') - smokeTestCompile project(':testing:cordapps:sleeping') - smokeTestCompile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version" - smokeTestCompile "org.apache.logging.log4j:log4j-core:$log4j_version" - smokeTestCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - smokeTestCompile "org.assertj:assertj-core:${assertj_version}" - smokeTestImplementation "junit:junit:$junit_version" - smokeTestRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" - smokeTestRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - - // JDK11: required by Quasar at run-time - smokeTestRuntimeOnly "com.esotericsoftware:kryo:$kryo_version" -} - -task integrationTest(type: Test) { +tasks.register('integrationTest', Test) { testClassesDirs = sourceSets.integrationTest.output.classesDirs classpath = sourceSets.integrationTest.runtimeClasspath } -task smokeTest(type: Test) { +tasks.register('smokeTest', Test) { testClassesDirs = sourceSets.smokeTest.output.classesDirs classpath = sourceSets.smokeTest.runtimeClasspath } @@ -127,6 +129,11 @@ jar { } } -publish { - name jar.baseName +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } } diff --git a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt index 1ebd6f29b5..1e8d08c4ac 100644 --- a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt +++ b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt @@ -54,7 +54,7 @@ import org.junit.Test import rx.subjects.PublishSubject import java.net.URLClassLoader import java.nio.file.Paths -import java.util.* +import java.util.Currency import java.util.concurrent.CountDownLatch import java.util.concurrent.Executors import java.util.concurrent.ScheduledExecutorService diff --git a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCConnectionListenerTest.kt b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCConnectionListenerTest.kt index f08f620032..7cebdc6961 100644 --- a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCConnectionListenerTest.kt +++ b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCConnectionListenerTest.kt @@ -1,12 +1,12 @@ package net.corda.client.rpc -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.atLeastOnce -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.never -import com.nhaarman.mockito_kotlin.times -import com.nhaarman.mockito_kotlin.verify -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.any +import org.mockito.kotlin.atLeastOnce +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import net.corda.client.rpc.internal.RPCClient import net.corda.client.rpc.ext.RPCConnectionListener import net.corda.core.messaging.RPCOps @@ -338,4 +338,4 @@ class RPCConnectionListenerTest(@Suppress("unused") private val iteration: Int) } } } -} \ No newline at end of file +} diff --git a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCMultipleInterfacesTests.kt b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCMultipleInterfacesTests.kt index 9971b2dcf4..c02f20fd35 100644 --- a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCMultipleInterfacesTests.kt +++ b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCMultipleInterfacesTests.kt @@ -1,6 +1,6 @@ package net.corda.client.rpc -import com.nhaarman.mockito_kotlin.mock +import org.mockito.kotlin.mock import net.corda.client.rpc.RPCMultipleInterfacesTests.StringRPCOpsImpl.testPhrase import net.corda.core.crypto.SecureHash import net.corda.core.messaging.CordaRPCOps diff --git a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCStabilityTests.kt b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCStabilityTests.kt index 94effe653a..4ae3373aac 100644 --- a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCStabilityTests.kt +++ b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCStabilityTests.kt @@ -544,7 +544,7 @@ class RPCStabilityTests { } @Test(timeout=300_000) -@Ignore // TODO: This is ignored because Artemis slow consumers are broken. I'm not deleting it in case we can get the feature fixed. + @Ignore // TODO: This is ignored because Artemis slow consumers are broken. I'm not deleting it in case we can get the feature fixed. fun `slow consumers are kicked`() { rpcDriver { val server = startRpcServer(maxBufferedBytesPerClient = 10 * 1024 * 1024, ops = SlowConsumerRPCOpsImpl()).get() @@ -552,7 +552,7 @@ class RPCStabilityTests { // Construct an RPC session manually so that we can hang in the message handler val myQueue = "${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.test.${random63BitValue()}" val session = startArtemisSession(server.broker.hostAndPort!!) - session.createQueue(QueueConfiguration(myQueue) + session.createQueue(QueueConfiguration.of(myQueue) .setRoutingType(ActiveMQDefaultConfiguration.getDefaultRoutingType()) .setAddress(myQueue) .setTemporary(true) @@ -569,7 +569,7 @@ class RPCStabilityTests { val message = session.createMessage(false) val request = RPCApi.ClientToServer.RpcRequest( - clientAddress = SimpleString(myQueue), + clientAddress = SimpleString.of(myQueue), methodName = SlowConsumerRPCOps::streamAtInterval.name, serialisedArguments = listOf(100.millis, 1234).serialize(context = SerializationDefaults.RPC_SERVER_CONTEXT), replyId = Trace.InvocationId.newInstance(), @@ -593,7 +593,7 @@ class RPCStabilityTests { // Construct an RPC client session manually val myQueue = "${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.test.${random63BitValue()}" val session = startArtemisSession(server.broker.hostAndPort!!) - session.createQueue(QueueConfiguration(myQueue) + session.createQueue(QueueConfiguration.of(myQueue) .setRoutingType(ActiveMQDefaultConfiguration.getDefaultRoutingType()) .setAddress(myQueue) .setTemporary(true) @@ -612,7 +612,7 @@ class RPCStabilityTests { val message = session.createMessage(false) val request = RPCApi.ClientToServer.RpcRequest( - clientAddress = SimpleString(myQueue), + clientAddress = SimpleString.of(myQueue), methodName = DummyOps::protocolVersion.name, serialisedArguments = emptyList().serialize(context = SerializationDefaults.RPC_SERVER_CONTEXT), replyId = Trace.InvocationId.newInstance(), @@ -669,4 +669,4 @@ fun RPCDriverDSL.pollUntilClientNumber(server: RpcServerHandle, expected: Int) { val clientAddresses = server.broker.serverControl.addressNames.filter { it.startsWith(RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX) } clientAddresses.size == expected }.get() -} \ No newline at end of file +} diff --git a/client/rpc/src/integration-test/kotlin/net/corda/client/rpcreconnect/CordaRPCClientReconnectionTest.kt b/client/rpc/src/integration-test/kotlin/net/corda/client/rpcreconnect/CordaRPCClientReconnectionTest.kt index 3ae1838664..171fdb8603 100644 --- a/client/rpc/src/integration-test/kotlin/net/corda/client/rpcreconnect/CordaRPCClientReconnectionTest.kt +++ b/client/rpc/src/integration-test/kotlin/net/corda/client/rpcreconnect/CordaRPCClientReconnectionTest.kt @@ -110,11 +110,11 @@ class CordaRPCClientReconnectionTest { assertThatThrownBy { val node = startNode () - val client = CordaRPCClient(node.rpcAddress, config.copy(minimumServerProtocolVersion = 100, maxReconnectAttempts = 1)) + val client = CordaRPCClient(node.rpcAddress, config.copy(minimumServerProtocolVersion = 999, maxReconnectAttempts = 1)) client.start(rpcUser.username, rpcUser.password, gracefulReconnect = gracefulReconnect) } .isInstanceOf(UnrecoverableRPCException::class.java) - .hasMessageStartingWith("Requested minimum protocol version (100) is higher than the server's supported protocol version ") + .hasMessageStartingWith("Requested minimum protocol version (999) is higher than the server's supported protocol version ") } } @@ -638,4 +638,4 @@ class CordaRPCClientReconnectionTest { throw IllegalStateException("bye") } } -} \ No newline at end of file +} diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ClientCacheFactory.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ClientCacheFactory.kt index bad74ecd2b..a2da56cd64 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ClientCacheFactory.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ClientCacheFactory.kt @@ -7,12 +7,12 @@ import com.github.benmanes.caffeine.cache.LoadingCache import net.corda.core.internal.NamedCacheFactory class ClientCacheFactory : NamedCacheFactory { - override fun buildNamed(caffeine: Caffeine, name: String): Cache { + override fun buildNamed(caffeine: Caffeine, name: String): Cache { checkCacheName(name) return caffeine.build() } - override fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache { + override fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache { checkCacheName(name) return caffeine.build(loader) } diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt index a79cf6bfbe..141ad76b79 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt @@ -150,7 +150,6 @@ internal class RPCClientProxyHandler( } } - @Suppress("TooGenericExceptionCaught") private fun closeObservable(observable: UnicastSubject>) { // Notify listeners of the observables that the connection is being terminated. try { @@ -300,7 +299,7 @@ internal class RPCClientProxyHandler( class FailoverHandler(private val detected: () -> Unit = {}, private val completed: () -> Unit = {}, private val failed: () -> Unit = {}): FailoverEventListener { - override fun failoverEvent(eventType: FailoverEventType?) { + override fun failoverEvent(eventType: FailoverEventType) { when (eventType) { FailoverEventType.FAILURE_DETECTED -> { detected() } FailoverEventType.FAILOVER_COMPLETED -> { completed() } @@ -346,7 +345,7 @@ internal class RPCClientProxyHandler( impersonatedActor, rpcClientTelemetry.telemetryService.getCurrentTelemetryData() ) - val replyFuture = SettableFuture.create() + val replyFuture = SettableFuture.create() require(rpcReplyMap.put(replyId, replyFuture) == null) { "Generated several RPC requests with same ID $replyId" } @@ -589,7 +588,6 @@ internal class RPCClientProxyHandler( } if (observableIds != null) { log.debug { "Reaping ${observableIds.size} observables" } - @Suppress("TooGenericExceptionCaught") try { sendMessage(RPCApi.ClientToServer.ObservablesClosed(observableIds)) } catch(ex: Exception) { @@ -654,9 +652,9 @@ internal class RPCClientProxyHandler( producerSession = sessionFactory!!.createSession(rpcUsername, rpcPassword, false, true, true, false, DEFAULT_ACK_BATCH_SIZE) rpcProducer = producerSession!!.createProducer(RPCApi.RPC_SERVER_QUEUE_NAME) consumerSession = sessionFactory!!.createSession(rpcUsername, rpcPassword, false, true, true, false, 16384) - clientAddress = SimpleString("${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.$rpcUsername.${random63BitValue()}") + clientAddress = SimpleString.of("${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.$rpcUsername.${random63BitValue()}") log.debug { "Client address: $clientAddress" } - consumerSession!!.createQueue(QueueConfiguration(clientAddress).setAddress(clientAddress).setRoutingType(RoutingType.ANYCAST) + consumerSession!!.createQueue(QueueConfiguration.of(clientAddress).setAddress(clientAddress).setRoutingType(RoutingType.ANYCAST) .setTemporary(true).setDurable(false)) rpcConsumer = consumerSession!!.createConsumer(clientAddress) rpcConsumer!!.setMessageHandler(this::artemisMessageHandler) diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientTelemetry.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientTelemetry.kt index c2c9457919..cc7693d0f5 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientTelemetry.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientTelemetry.kt @@ -1,14 +1,15 @@ 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 +import net.corda.nodeapi.internal.telemetry.OpenTelemetryComponent -class RPCClientTelemetry(val serviceName: String, val openTelemetryEnabled: Boolean, - val simpleLogTelemetryEnabled: Boolean, val spanStartEndEventsEnabled: Boolean, +class RPCClientTelemetry(serviceName: String, + val openTelemetryEnabled: Boolean, + val simpleLogTelemetryEnabled: Boolean, + val spanStartEndEventsEnabled: Boolean, val copyBaggageToTags: Boolean) { - companion object { private val log = contextLogger() } @@ -39,4 +40,4 @@ class RPCClientTelemetry(val serviceName: String, val openTelemetryEnabled: Bool fun getTelemetryHandle(telemetryClass: Class): T? { return telemetryService.getTelemetryHandle(telemetryClass) } -} \ No newline at end of file +} diff --git a/client/rpc/src/smoke-test/java/net/corda/java/rpc/StandaloneCordaRPCJavaClientTest.java b/client/rpc/src/smoke-test/java/net/corda/java/rpc/StandaloneCordaRPCJavaClientTest.java index 2c17ac72e3..bb06d45679 100644 --- a/client/rpc/src/smoke-test/java/net/corda/java/rpc/StandaloneCordaRPCJavaClientTest.java +++ b/client/rpc/src/smoke-test/java/net/corda/java/rpc/StandaloneCordaRPCJavaClientTest.java @@ -1,6 +1,5 @@ package net.corda.java.rpc; -import net.corda.client.rpc.CordaRPCConnection; import net.corda.core.contracts.Amount; import net.corda.core.identity.CordaX500Name; import net.corda.core.identity.Party; @@ -10,88 +9,48 @@ import net.corda.core.utilities.OpaqueBytes; import net.corda.finance.flows.AbstractCashFlow; import net.corda.finance.flows.CashIssueFlow; import net.corda.nodeapi.internal.config.User; -import net.corda.smoketesting.NodeConfig; +import net.corda.smoketesting.NodeParams; import net.corda.smoketesting.NodeProcess; import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; +import java.util.Currency; +import java.util.HashSet; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Stream; import static java.util.Collections.singletonList; import static kotlin.test.AssertionsKt.assertEquals; -import static kotlin.test.AssertionsKt.fail; import static net.corda.finance.workflows.GetBalances.getCashBalance; +import static net.corda.kotlin.rpc.StandaloneCordaRPClientTest.gatherCordapps; public class StandaloneCordaRPCJavaClientTest { + private final User superUser = new User("superUser", "test", new HashSet<>(singletonList("ALL"))); - public static void copyCordapps(NodeProcess.Factory factory, NodeConfig notaryConfig) { - Path cordappsDir = (factory.baseDirectory(notaryConfig).resolve(NodeProcess.CORDAPPS_DIR_NAME)); - try { - Files.createDirectories(cordappsDir); - } catch (IOException ex) { - fail("Failed to create directories"); - } - try (Stream paths = Files.walk(Paths.get("build", "resources", "smokeTest"))) { - paths.filter(path -> path.toFile().getName().startsWith("cordapp")).forEach(file -> { - try { - Files.copy(file, cordappsDir.resolve(file.getFileName())); - } catch (IOException ex) { - fail("Failed to copy cordapp jar"); - } - }); - } catch (IOException e) { - fail("Failed to walk files"); - } - } + private final AtomicInteger port = new AtomicInteger(15000); + private final NodeProcess.Factory factory = new NodeProcess.Factory(); - private List perms = singletonList("ALL"); - private Set permSet = new HashSet<>(perms); - private User superUser = new User("superUser", "test", permSet); - - private AtomicInteger port = new AtomicInteger(15000); - - private NodeProcess notary; private CordaRPCOps rpcProxy; - private CordaRPCConnection connection; private Party notaryNodeIdentity; - private NodeConfig notaryConfig = new NodeConfig( - new CordaX500Name("Notary Service", "Zurich", "CH"), - port.getAndIncrement(), - port.getAndIncrement(), - port.getAndIncrement(), - true, - singletonList(superUser), - true - ); - @Before public void setUp() { - NodeProcess.Factory factory = new NodeProcess.Factory(); - copyCordapps(factory, notaryConfig); - notary = factory.create(notaryConfig); - connection = notary.connect(superUser); - rpcProxy = connection.getProxy(); + NodeProcess notary = factory.createNotaries(new NodeParams( + new CordaX500Name("Notary Service", "Zurich", "CH"), + port.getAndIncrement(), + port.getAndIncrement(), + port.getAndIncrement(), + singletonList(superUser), + gatherCordapps() + )).get(0); + rpcProxy = notary.connect(superUser).getProxy(); notaryNodeIdentity = rpcProxy.nodeInfo().getLegalIdentities().get(0); } @After public void done() { - try { - connection.close(); - } finally { - if (notary != null) { - notary.close(); - } - } + factory.close(); } @Test diff --git a/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt b/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt index 54504da08b..9c08d7a48d 100644 --- a/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt +++ b/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt @@ -27,6 +27,7 @@ import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.minutes import net.corda.core.utilities.seconds import net.corda.finance.DOLLARS +import net.corda.finance.GBP import net.corda.finance.POUNDS import net.corda.finance.SWISS_FRANCS import net.corda.finance.USD @@ -35,89 +36,103 @@ import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashPaymentFlow import net.corda.finance.workflows.getCashBalance import net.corda.finance.workflows.getCashBalances -import net.corda.java.rpc.StandaloneCordaRPCJavaClientTest import net.corda.nodeapi.internal.config.User import net.corda.sleeping.SleepingFlow -import net.corda.smoketesting.NodeConfig +import net.corda.smoketesting.NodeParams import net.corda.smoketesting.NodeProcess -import org.apache.commons.io.output.NullOutputStream.NULL_OUTPUT_STREAM import org.hamcrest.text.MatchesPattern import org.junit.After +import org.junit.AfterClass import org.junit.Before +import org.junit.BeforeClass import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException import java.io.FilterInputStream import java.io.InputStream -import java.util.Currency +import java.io.OutputStream.nullOutputStream +import java.nio.file.Path import java.util.concurrent.CountDownLatch import java.util.concurrent.atomic.AtomicInteger import java.util.regex.Pattern +import kotlin.io.path.Path +import kotlin.io.path.listDirectoryEntries import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertNotEquals import kotlin.test.assertTrue class StandaloneCordaRPClientTest { - private companion object { + companion object { private val log = contextLogger() val superUser = User("superUser", "test", permissions = setOf("ALL")) val nonUser = User("nonUser", "test", permissions = emptySet()) val rpcUser = User("rpcUser", "test", permissions = setOf("InvokeRpc.startFlow", "InvokeRpc.killFlow")) val flowUser = User("flowUser", "test", permissions = setOf("StartFlow.net.corda.finance.flows.CashIssueFlow")) val port = AtomicInteger(15200) - const val attachmentSize = 2116 + const val ATTACHMENT_SIZE = 2116 val timeout = 60.seconds + + private val factory = NodeProcess.Factory() + + private lateinit var notary: NodeProcess + + private val notaryConfig = NodeParams( + legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"), + p2pPort = port.andIncrement, + rpcPort = port.andIncrement, + rpcAdminPort = port.andIncrement, + users = listOf(superUser, nonUser, rpcUser, flowUser), + cordappJars = gatherCordapps() + ) + + @BeforeClass + @JvmStatic + fun startNotary() { + notary = factory.createNotaries(notaryConfig)[0] + } + + @AfterClass + @JvmStatic + fun close() { + factory.close() + } + + @JvmStatic + fun gatherCordapps(): List { + return Path("build", "resources", "smokeTest").listDirectoryEntries("cordapp*.jar") + } } - private lateinit var factory: NodeProcess.Factory - private lateinit var notary: NodeProcess - private lateinit var rpcProxy: CordaRPCOps private lateinit var connection: CordaRPCConnection - private lateinit var notaryNode: NodeInfo + private lateinit var rpcProxy: CordaRPCOps private lateinit var notaryNodeIdentity: Party - private val notaryConfig = NodeConfig( - legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"), - p2pPort = port.andIncrement, - rpcPort = port.andIncrement, - rpcAdminPort = port.andIncrement, - isNotary = true, - users = listOf(superUser, nonUser, rpcUser, flowUser) - ) - @get:Rule val exception: ExpectedException = ExpectedException.none() @Before fun setUp() { - factory = NodeProcess.Factory() - StandaloneCordaRPCJavaClientTest.copyCordapps(factory, notaryConfig) - notary = factory.create(notaryConfig) connection = notary.connect(superUser) rpcProxy = connection.proxy - notaryNode = fetchNotaryIdentity() notaryNodeIdentity = rpcProxy.nodeInfo().legalIdentitiesAndCerts.first().party } @After - fun done() { - connection.use { - notary.close() - } + fun closeConnection() { + connection.close() } - @Test(timeout=300_000) fun `test attachments`() { - val attachment = InputStreamAndHash.createInMemoryTestZip(attachmentSize, 1) + val attachment = InputStreamAndHash.createInMemoryTestZip(ATTACHMENT_SIZE, 1) assertFalse(rpcProxy.attachmentExists(attachment.sha256)) val id = attachment.inputStream.use { rpcProxy.uploadAttachment(it) } assertEquals(attachment.sha256, id, "Attachment has incorrect SHA256 hash") - val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use { it -> - it.copyTo(NULL_OUTPUT_STREAM) + val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use { + it.copyTo(nullOutputStream()) SecureHash.createSHA256(it.hash().asBytes()) } assertEquals(attachment.sha256, hash) @@ -126,13 +141,13 @@ class StandaloneCordaRPClientTest { @Ignore("CORDA-1520 - After switching from Kryo to AMQP this test won't work") @Test(timeout=300_000) fun `test wrapped attachments`() { - val attachment = InputStreamAndHash.createInMemoryTestZip(attachmentSize, 1) + val attachment = InputStreamAndHash.createInMemoryTestZip(ATTACHMENT_SIZE, 1) assertFalse(rpcProxy.attachmentExists(attachment.sha256)) val id = WrapperStream(attachment.inputStream).use { rpcProxy.uploadAttachment(it) } assertEquals(attachment.sha256, id, "Attachment has incorrect SHA256 hash") - val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use { it -> - it.copyTo(NULL_OUTPUT_STREAM) + val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use { + it.copyTo(nullOutputStream()) SecureHash.createSHA256(it.hash().asBytes()) } assertEquals(attachment.sha256, hash) @@ -168,8 +183,7 @@ class StandaloneCordaRPClientTest { @Test(timeout=300_000) fun `test state machines`() { - val (stateMachines, updates) = rpcProxy.stateMachinesFeed() - assertEquals(0, stateMachines.size) + val (_, updates) = rpcProxy.stateMachinesFeed() val updateLatch = CountDownLatch(1) val updateCount = AtomicInteger(0) @@ -190,8 +204,9 @@ class StandaloneCordaRPClientTest { @Test(timeout=300_000) fun `test vault track by`() { - val (vault, vaultUpdates) = rpcProxy.vaultTrackBy(paging = PageSpecification(DEFAULT_PAGE_NUM)) - assertEquals(0, vault.totalStatesAvailable) + val initialGbpBalance = rpcProxy.getCashBalance(GBP) + + val (_, vaultUpdates) = rpcProxy.vaultTrackBy(paging = PageSpecification(DEFAULT_PAGE_NUM)) val updateLatch = CountDownLatch(1) vaultUpdates.subscribe { update -> @@ -207,34 +222,35 @@ class StandaloneCordaRPClientTest { // Check that this cash exists in the vault val cashBalance = rpcProxy.getCashBalances() log.info("Cash Balances: $cashBalance") - assertEquals(1, cashBalance.size) - assertEquals(629.POUNDS, cashBalance[Currency.getInstance("GBP")]) + assertEquals(629.POUNDS, cashBalance[GBP]!! - initialGbpBalance) } @Test(timeout=300_000) fun `test vault query by`() { - // Now issue some cash - rpcProxy.startFlow(::CashIssueFlow, 629.POUNDS, OpaqueBytes.of(0), notaryNodeIdentity) - .returnValue.getOrThrow(timeout) - val criteria = QueryCriteria.VaultQueryCriteria(status = Vault.StateStatus.ALL) val paging = PageSpecification(DEFAULT_PAGE_NUM, 10) val sorting = Sort(setOf(Sort.SortColumn(SortAttribute.Standard(Sort.VaultStateAttribute.RECORDED_TIME), Sort.Direction.DESC))) + val initialStateCount = rpcProxy.vaultQueryBy(criteria, paging, sorting).totalStatesAvailable + val initialGbpBalance = rpcProxy.getCashBalance(GBP) + + // Now issue some cash + rpcProxy.startFlow(::CashIssueFlow, 629.POUNDS, OpaqueBytes.of(0), notaryNodeIdentity) + .returnValue.getOrThrow(timeout) + val queryResults = rpcProxy.vaultQueryBy(criteria, paging, sorting) - assertEquals(1, queryResults.totalStatesAvailable) + assertEquals(1, queryResults.totalStatesAvailable - initialStateCount) assertEquals(queryResults.states.first().state.data.amount.quantity, 629.POUNDS.quantity) rpcProxy.startFlow(::CashPaymentFlow, 100.POUNDS, notaryNodeIdentity, true, notaryNodeIdentity).returnValue.getOrThrow() val moreResults = rpcProxy.vaultQueryBy(criteria, paging, sorting) - assertEquals(3, moreResults.totalStatesAvailable) // 629 - 100 + 100 + assertEquals(3, moreResults.totalStatesAvailable - initialStateCount) // 629 - 100 + 100 // Check that this cash exists in the vault val cashBalances = rpcProxy.getCashBalances() log.info("Cash Balances: $cashBalances") - assertEquals(1, cashBalances.size) - assertEquals(629.POUNDS, cashBalances[Currency.getInstance("GBP")]) + assertEquals(629.POUNDS, cashBalances[GBP]!! - initialGbpBalance) } @Test(timeout=300_000) diff --git a/client/rpc/src/test/kotlin/net/corda/client/rpc/Measure.kt b/client/rpc/src/test/kotlin/net/corda/client/rpc/Measure.kt index 1e288f2741..c970becbce 100644 --- a/client/rpc/src/test/kotlin/net/corda/client/rpc/Measure.kt +++ b/client/rpc/src/test/kotlin/net/corda/client/rpc/Measure.kt @@ -2,6 +2,7 @@ package net.corda.client.rpc import net.corda.core.internal.uncheckedCast import kotlin.reflect.KCallable +import kotlin.reflect.jvm.ExperimentalReflectionOnLambdas import kotlin.reflect.jvm.reflect /** @@ -10,15 +11,19 @@ import kotlin.reflect.jvm.reflect * different combinations of parameters. */ +@OptIn(ExperimentalReflectionOnLambdas::class) fun measure(a: Iterable, f: (A) -> R) = measure(listOf(a), f.reflect()!!) { f(uncheckedCast(it[0])) } +@OptIn(ExperimentalReflectionOnLambdas::class) fun measure(a: Iterable, b: Iterable, f: (A, B) -> R) = measure(listOf(a, b), f.reflect()!!) { f(uncheckedCast(it[0]), uncheckedCast(it[1])) } +@OptIn(ExperimentalReflectionOnLambdas::class) fun measure(a: Iterable, b: Iterable, c: Iterable, f: (A, B, C) -> R) = measure(listOf(a, b, c), f.reflect()!!) { f(uncheckedCast(it[0]), uncheckedCast(it[1]), uncheckedCast(it[2])) } +@OptIn(ExperimentalReflectionOnLambdas::class) fun measure(a: Iterable, b: Iterable, c: Iterable, d: Iterable, f: (A, B, C, D) -> R) = measure(listOf(a, b, c, d), f.reflect()!!) { f(uncheckedCast(it[0]), uncheckedCast(it[1]), uncheckedCast(it[2]), uncheckedCast(it[3])) } diff --git a/client/rpc/src/test/kotlin/net/corda/client/rpc/RPCFailureTests.kt b/client/rpc/src/test/kotlin/net/corda/client/rpc/RPCFailureTests.kt index 2bb907b44d..156922d2d1 100644 --- a/client/rpc/src/test/kotlin/net/corda/client/rpc/RPCFailureTests.kt +++ b/client/rpc/src/test/kotlin/net/corda/client/rpc/RPCFailureTests.kt @@ -49,14 +49,14 @@ class RPCFailureTests { @Test(timeout=300_000) fun `kotlin NPE`() = rpc { assertThatThrownBy { it.kotlinNPE() }.isInstanceOf(CordaRuntimeException::class.java) - .hasMessageContaining("kotlin.KotlinNullPointerException") + .hasMessageContaining("java.lang.NullPointerException") } @Test(timeout=300_000) fun `kotlin NPE async`() = rpc { val future = it.kotlinNPEAsync() assertThatThrownBy { future.getOrThrow() }.isInstanceOf(CordaRuntimeException::class.java) - .hasMessageContaining("kotlin.KotlinNullPointerException") + .hasMessageContaining("java.lang.NullPointerException") } @Test(timeout=300_000) diff --git a/common/configuration-parsing/build.gradle b/common/configuration-parsing/build.gradle index 1fb78d4406..7092bd2e81 100644 --- a/common/configuration-parsing/build.gradle +++ b/common/configuration-parsing/build.gradle @@ -1,15 +1,14 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'corda.common-publishing' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +description 'Corda common-configuration-parsing module' dependencies { - compile group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8", version: kotlin_version - compile group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: kotlin_version + implementation group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: kotlin_version - compile group: "com.typesafe", name: "config", version: typesafe_config_version + implementation group: "com.typesafe", name: "config", version: typesafe_config_version - compile project(":common-validation") + implementation project(":common-validation") testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" @@ -18,14 +17,20 @@ dependencies { testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile group: "org.jetbrains.kotlin", name: "kotlin-test", version: kotlin_version - testCompile group: "org.assertj", name: "assertj-core", version: assertj_version + testImplementation group: "org.jetbrains.kotlin", name: "kotlin-test", version: kotlin_version + testImplementation group: "org.assertj", name: "assertj-core", version: assertj_version } jar { baseName 'corda-common-configuration-parsing' } -publish { - name jar.baseName -} \ No newline at end of file +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } +} + diff --git a/common/configuration-parsing/src/main/kotlin/net/corda/common/configuration/parsing/internal/Configuration.kt b/common/configuration-parsing/src/main/kotlin/net/corda/common/configuration/parsing/internal/Configuration.kt index ba623b2b56..e585e86d62 100644 --- a/common/configuration-parsing/src/main/kotlin/net/corda/common/configuration/parsing/internal/Configuration.kt +++ b/common/configuration-parsing/src/main/kotlin/net/corda/common/configuration/parsing/internal/Configuration.kt @@ -5,6 +5,7 @@ import net.corda.common.configuration.parsing.internal.versioned.VersionExtracto import net.corda.common.validation.internal.Validated import net.corda.common.validation.internal.Validated.Companion.invalid import java.time.Duration +import java.util.Locale import kotlin.reflect.KClass /** @@ -468,7 +469,7 @@ object Configuration { fun of(message: String, keyName: String? = null, typeName: String = UNKNOWN, containingPath: List = emptyList()): WrongType = contextualize(keyName ?: UNKNOWN, containingPath).let { (key, path) -> WrongType(key, typeName, message, path) } - fun forKey(keyName: String, expectedTypeName: String, actualTypeName: String): WrongType = of("$keyName has type ${actualTypeName.toUpperCase()} rather than ${expectedTypeName.toUpperCase()}") + fun forKey(keyName: String, expectedTypeName: String, actualTypeName: String): WrongType = of("$keyName has type ${actualTypeName.uppercase(Locale.getDefault())} rather than ${expectedTypeName.uppercase(Locale.getDefault())}") } override fun withContainingPath(vararg containingPath: String) = WrongType(keyName, typeName, message, containingPath.toList()) diff --git a/common/configuration-parsing/src/test/kotlin/net/corda/common/configuration/parsing/internal/SpecificationTest.kt b/common/configuration-parsing/src/test/kotlin/net/corda/common/configuration/parsing/internal/SpecificationTest.kt index 96a9f181ef..9b0535df90 100644 --- a/common/configuration-parsing/src/test/kotlin/net/corda/common/configuration/parsing/internal/SpecificationTest.kt +++ b/common/configuration-parsing/src/test/kotlin/net/corda/common/configuration/parsing/internal/SpecificationTest.kt @@ -61,7 +61,7 @@ class SpecificationTest { override fun parseValid(configuration: Config, options: Configuration.Options): Valid { val config = configuration.withOptions(options) - return valid(AtomicLong(config[maxElement]!!)) + return valid(AtomicLong(config[maxElement])) } } @@ -103,7 +103,7 @@ class SpecificationTest { if (elements.any { element -> element <= 1 }) { return invalid(Configuration.Validation.Error.BadValue.of("elements cannot be less than or equal to 1")) } - return valid(elements.max()!!) + return valid(elements.max()) } val spec = object : Configuration.Specification("AtomicLong") { diff --git a/common/logging/build.gradle b/common/logging/build.gradle index 98afc0d6cd..5c1c6760c7 100644 --- a/common/logging/build.gradle +++ b/common/logging/build.gradle @@ -1,28 +1,28 @@ import org.apache.tools.ant.filters.ReplaceTokens -apply plugin: 'kotlin' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'corda.common-publishing' + +description 'Corda common-logging module' dependencies { - compile group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8", version: kotlin_version - compile group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: kotlin_version + implementation group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: kotlin_version - compile group: "com.typesafe", name: "config", version: typesafe_config_version + implementation group: "com.typesafe", name: "config", version: typesafe_config_version // Log4J: logging framework - compile "org.apache.logging.log4j:log4j-core:$log4j_version" + implementation "org.apache.logging.log4j:log4j-core:$log4j_version" - compile "com.jcabi:jcabi-manifests:$jcabi_manifests_version" + implementation "com.jcabi:jcabi-manifests:$jcabi_manifests_version" // Need to depend on one other Corda project in order to get hold of a valid manifest for the tests - testCompile project(":common-validation") + testImplementation project(":common-validation") // test dependencies testImplementation "junit:junit:$junit_version" - testCompile group: "org.jetbrains.kotlin", name: "kotlin-test", version: kotlin_version - testCompile "org.mockito:mockito-core:$mockito_version" - testCompile "com.natpryce:hamkrest:$hamkrest_version" + testImplementation group: "org.jetbrains.kotlin", name: "kotlin-test", version: kotlin_version + testImplementation "org.mockito:mockito-core:$mockito_version" + testImplementation "com.natpryce:hamkrest:$hamkrest_version" } @@ -33,11 +33,19 @@ task generateSource(type: Copy) { into 'src/main' } compileKotlin.dependsOn generateSource +processResources.dependsOn generateSource +sourcesJar.dependsOn generateSource jar { baseName 'corda-common-logging' } -publish { - name jar.baseName -} \ No newline at end of file +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } +} + diff --git a/common/logging/src/main/kotlin/net/corda/common/logging/Constants.kt b/common/logging/src/main/kotlin/net/corda/common/logging/Constants.kt index cc86ed31ab..d8b45b85e6 100644 --- a/common/logging/src/main/kotlin/net/corda/common/logging/Constants.kt +++ b/common/logging/src/main/kotlin/net/corda/common/logging/Constants.kt @@ -9,4 +9,4 @@ package net.corda.common.logging * (originally added to source control for ease of use) */ -internal const val CURRENT_MAJOR_RELEASE = "4.11-SNAPSHOT" \ No newline at end of file +internal const val CURRENT_MAJOR_RELEASE = "4.12-SNAPSHOT" \ No newline at end of file diff --git a/common/logging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorReportingUtils.kt b/common/logging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorReportingUtils.kt index 827a78c450..b30bec40bd 100644 --- a/common/logging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorReportingUtils.kt +++ b/common/logging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorReportingUtils.kt @@ -1,6 +1,7 @@ package net.corda.common.logging.errorReporting import org.slf4j.Logger +import java.util.Locale /** * Report errors that have occurred. @@ -12,7 +13,7 @@ import org.slf4j.Logger fun Logger.report(error: ErrorCode<*>) = ErrorReporting().getReporter().report(error, this) internal fun ErrorCode<*>.formatCode() : String { - val namespaceString = this.code.namespace.toLowerCase().replace("_", "-") - val codeString = this.code.toString().toLowerCase().replace("_", "-") + val namespaceString = this.code.namespace.lowercase(Locale.getDefault()).replace("_", "-") + val codeString = this.code.toString().lowercase(Locale.getDefault()).replace("_", "-") return "$namespaceString-$codeString" } \ No newline at end of file diff --git a/common/validation/build.gradle b/common/validation/build.gradle index 5f54996c3f..5b14f50640 100644 --- a/common/validation/build.gradle +++ b/common/validation/build.gradle @@ -1,17 +1,21 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'corda.common-publishing' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +description 'Corda common-validation module' dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" } jar { baseName 'corda-common-validation' } -publish { - name jar.baseName -} \ No newline at end of file +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } +} diff --git a/confidential-identities/build.gradle b/confidential-identities/build.gradle index 549ff0e4db..616fffc0c5 100644 --- a/confidential-identities/build.gradle +++ b/confidential-identities/build.gradle @@ -1,18 +1,24 @@ // This contains the SwapIdentitiesFlow which can be used for exchanging confidential identities as part of a flow. // TODO: Merge this into core: the original plan was to develop it independently but in practice it's too widely used to break compatibility now, as finance uses it. -apply plugin: 'kotlin' -apply plugin: 'net.corda.plugins.publish-utils' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordapp' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' description 'Corda Experimental Confidential Identities' -dependencies { - cordaCompile project(':core') +cordapp { + targetPlatformVersion corda_platform_version.toInteger() +} - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" +dependencies { + cordaProvided project(':core') + + api "org.slf4j:slf4j-api:$slf4j_version" + + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" + testImplementation "co.paralleluniverse:quasar-core:$quasar_version" testImplementation "junit:junit:$junit_version" testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" @@ -20,19 +26,28 @@ dependencies { testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" // Guava: Google test library (collections test suite) - testCompile "com.google.guava:guava-testlib:$guava_version" + testImplementation "com.google.guava:guava-testlib:$guava_version" // Bring in the MockNode infrastructure for writing protocol unit tests. - testCompile project(":node-driver") + testImplementation project(":node") + testImplementation project(":node-api") + testImplementation project(":node-driver") + testImplementation project(":core-test-utils") + testImplementation project(':finance:contracts') + testImplementation project(':finance:workflows') // AssertJ: for fluent assertions for testing - testCompile "org.assertj:assertj-core:$assertj_version" + testImplementation "org.assertj:assertj-core:$assertj_version" + testImplementation "com.natpryce:hamkrest:$hamkrest_version" + testImplementation "io.reactivex:rxjava:$rxjava_version" } -jar { - baseName 'corda-confidential-identities' -} - -publish { - name jar.baseName +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-confidential-identities' + from components.cordapp + artifact javadocJar + } + } } diff --git a/confidential-identities/src/test/kotlin/net/corda/confidential/IdentitySyncFlowTests.kt b/confidential-identities/src/test/kotlin/net/corda/confidential/IdentitySyncFlowTests.kt index 2262afe3c5..f2c4d1f94c 100644 --- a/confidential-identities/src/test/kotlin/net/corda/confidential/IdentitySyncFlowTests.kt +++ b/confidential-identities/src/test/kotlin/net/corda/confidential/IdentitySyncFlowTests.kt @@ -129,4 +129,4 @@ class IdentitySyncFlowTests { otherSideSession.send(true) } } -} \ No newline at end of file +} diff --git a/config/dev/log4j2.xml b/config/dev/log4j2.xml index f6e9ce38d9..f2033897f3 100644 --- a/config/dev/log4j2.xml +++ b/config/dev/log4j2.xml @@ -2,64 +2,26 @@ - ${sys:log-path:-logs} - node-${hostName} - diagnostic-${hostName} - ${log-path}/archive - ${sys:defaultLogLevel:-info} - ${sys:consoleLogLevel:-error} + ${sys:log-path:-logs} + node-${hostName} + diagnostic-${hostName} + ${log_path}/archive + ${sys:defaultLogLevel:-info} + ${sys:consoleLogLevel:-error} - - - + + + + - - - - - - - - - - - - - - - - - - - - - + + + + @@ -69,24 +31,10 @@ + fileName="${log_path}/${log_name}.log" + filePattern="${archive}/${log_name}.%date{yyyy-MM-dd}-%i.log.gz"> - - - - - - + @@ -95,7 +43,7 @@ - + @@ -109,24 +57,10 @@ + fileName="${log_path}/${diagnostic_log_name}.log" + filePattern="${archive}/${diagnostic_log_name}.%date{yyyy-MM-dd}-%i.log.gz"> - - - - - - + @@ -135,7 +69,7 @@ - + @@ -147,7 +81,7 @@ @@ -171,7 +105,7 @@ - + @@ -187,8 +121,8 @@ - - + + diff --git a/constants.properties b/constants.properties index 309968d183..cea5182e89 100644 --- a/constants.properties +++ b/constants.properties @@ -3,35 +3,32 @@ # their own projects. So don't get fancy with syntax! # Fancy syntax - multi pass ${whatever} replacement -cordaVersion=4.11 +cordaVersion=4.12 versionSuffix=SNAPSHOT -gradlePluginsVersion=5.0.12 -kotlinVersion=1.2.71 -java8MinUpdateVersion=171 +cordaShellVersion=4.12-SNAPSHOT +gradlePluginsVersion=5.1.1 +artifactoryContextUrl=https://software.r3.com/artifactory +internalPublishVersion=1.+ # ***************************************************************# # When incrementing platformVersion make sure to update # # net.corda.core.internal.CordaUtilsKt.PLATFORM_VERSION as well. # # ***************************************************************# -platformVersion=13 +platformVersion=140 openTelemetryVersion=1.20.1 openTelemetrySemConvVersion=1.20.1-alpha -guavaVersion=28.0-jre -# Quasar version to use with Java 8: -quasarVersion=0.7.16_r3 -# Quasar version to use with Java 11: -quasarVersion11=0.8.1_r3 -jdkClassifier11=jdk11 +guavaVersion=33.1.0-jre +quasarVersion=0.9.0_r3 dockerJavaVersion=3.2.5 -proguardVersion=6.1.1 -// bouncy castle version must not be changed on a patch release. Needs a full release test cycle to flush out any issues. -bouncycastleVersion=1.78.1 +proguardVersion=7.3.1 +# Switch to release version when out +bouncycastleVersion=2.73.6 classgraphVersion=4.8.135 disruptorVersion=3.4.2 typesafeConfigVersion=1.3.4 jsr305Version=3.0.2 artifactoryPluginVersion=4.16.1 -snakeYamlVersion=1.33 -caffeineVersion=2.9.3 +snakeYamlVersion=2.2 +caffeineVersion=3.1.8 metricsVersion=4.1.0 metricsNewRelicVersion=1.1.1 openSourceBranch=https://github.com/corda/corda/blob/release/os/4.4 @@ -46,22 +43,22 @@ commonsTextVersion=1.10.0 # 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 +capsuleVersion=1.0.4_r3 +asmVersion=9.5 +artemisVersion=2.36.0 # TODO Upgrade Jackson only when corda is using kotlin 1.3.10 jacksonVersion=2.17.2 -jacksonKotlinVersion=2.9.7 -jettyVersion=9.4.53.v20231009 -jerseyVersion=2.25 +jacksonKotlinVersion=2.17.0 +jettyVersion=12.0.7 +jerseyVersion=3.1.6 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 +slf4JVersion=2.0.12 +log4JVersion=2.23.1 +okhttpVersion=4.12.0 +nettyVersion=4.1.109.Final +fileuploadVersion=2.0.0-M1 +kryoVersion=5.5.0 kryoSerializerVersion=0.43 # Legacy JUnit 4 version junitVersion=4.12 @@ -71,8 +68,8 @@ junitVersion=4.12 junitVintageVersion=5.5.0-RC1 junitJupiterVersion=5.5.0-RC1 junitPlatformVersion=1.5.0-RC1 -mockitoVersion=2.28.2 -mockitoKotlinVersion=1.6.0 +mockitoVersion=5.5.0 +mockitoKotlinVersion=5.2.1 hamkrestVersion=1.7.0.0 joptSimpleVersion=5.0.2 jansiVersion=1.18 @@ -80,13 +77,12 @@ hibernateVersion=5.6.14.Final # h2Version - Update docs if renamed or removed. h2Version=2.2.224 rxjavaVersion=1.3.8 -dokkaVersion=0.10.1 -eddsaVersion=0.3.0 +dokkaVersion=1.8.20 dependencyCheckerVersion=5.2.0 commonsCollectionsVersion=4.3 beanutilsVersion=1.9.4 shiroVersion=1.10.0 -hikariVersion=3.3.1 +hikariVersion=5.1.0 liquibaseVersion=4.20.0 dockerComposeRuleVersion=1.5.0 seleniumVersion=3.141.59 @@ -97,13 +93,9 @@ protonjVersion=0.33.0 snappyVersion=0.5 jcabiManifestsVersion=1.1 picocliVersion=3.9.6 -commonsLangVersion=3.9 -commonsIoVersion=2.6 +commonsIoVersion=2.7 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 -javaassistVersion=3.27.0-GA +javaassistVersion=3.29.2-GA +joorVersion=0.9.15 diff --git a/core-1.2/README.md b/core-1.2/README.md new file mode 100644 index 0000000000..9543551417 --- /dev/null +++ b/core-1.2/README.md @@ -0,0 +1,4 @@ +This is a Kotlin 1.2 version of the `core` module, which is consumed by the `verifier` module, for verifying contracts written in Kotlin +1.2. This is just a "shell" module which uses the existing the code in `core` and compiles it with the 1.2 compiler. + +To allow `core` to benefit from new APIs introduced since 1.2, those APIs much be copied into this module with the same `kotlin` package. diff --git a/core-1.2/build.gradle b/core-1.2/build.gradle new file mode 100644 index 0000000000..26368194bb --- /dev/null +++ b/core-1.2/build.gradle @@ -0,0 +1,34 @@ +apply plugin: "corda.kotlin-1.2" +apply plugin: "corda.common-publishing" + +description 'Corda core built with Kotlin 1.2' + +sourceSets { + main { + java.srcDir("../core/src/main/java") + kotlin.srcDir("../core/src/main/kotlin") + } +} + +dependencies { + // Use the same dependencies as core (minus Kotlin) + implementation(project(path: ":core", configuration: "resolvableImplementation")) { + exclude(group: "org.jetbrains.kotlin") + } + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_1_2_version" + implementation "co.paralleluniverse:quasar-core:$quasar_version" +} + +jar { + archiveBaseName = 'corda-core-1.2' +} + +// TODO Don't publish publicly as it's only needed by the `verifier` module which consumes this into a fat jar. +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-core-1.2' + from components.java + } + } +} diff --git a/core-1.2/src/main/kotlin/kotlin/CharCode1.2.kt b/core-1.2/src/main/kotlin/kotlin/CharCode1.2.kt new file mode 100644 index 0000000000..af607eb7ed --- /dev/null +++ b/core-1.2/src/main/kotlin/kotlin/CharCode1.2.kt @@ -0,0 +1,5 @@ +// Implement the new post-1.2 APIs which are used by core and serialization +@file:Suppress("unused") +package kotlin + +inline val Char.code: Int get() = this.toInt() diff --git a/core-1.2/src/main/kotlin/kotlin/collections/KotlinCollections1.2.kt b/core-1.2/src/main/kotlin/kotlin/collections/KotlinCollections1.2.kt new file mode 100644 index 0000000000..9e9650968f --- /dev/null +++ b/core-1.2/src/main/kotlin/kotlin/collections/KotlinCollections1.2.kt @@ -0,0 +1,37 @@ +// Implement the new post-1.2 APIs which are used by core and serialization +@file:Suppress("unused", "MagicNumber", "INVISIBLE_MEMBER") + +package kotlin.collections + +inline fun Iterable.associateWith(valueSelector: (K) -> V): Map { + val result = LinkedHashMap(mapCapacity(if (this is Collection<*>) size else 10).coerceAtLeast(16)) + return associateWithTo(result, valueSelector) +} + +inline fun > Iterable.associateWithTo(destination: M, valueSelector: (K) -> V): M { + for (element in this) { + destination.put(element, valueSelector(element)) + } + return destination +} + +inline fun Iterable.sumOf(selector: (T) -> Int): Int { + var sum = 0 + for (element in this) { + sum += selector(element) + } + return sum +} + +inline fun > Iterable.maxOf(selector: (T) -> R): R { + val iterator = iterator() + if (!iterator.hasNext()) throw NoSuchElementException() + var maxValue = selector(iterator.next()) + while (iterator.hasNext()) { + val v = selector(iterator.next()) + if (maxValue < v) { + maxValue = v + } + } + return maxValue +} diff --git a/core-1.2/src/main/kotlin/kotlin/io/path/KotlinIoPath1.2.kt b/core-1.2/src/main/kotlin/kotlin/io/path/KotlinIoPath1.2.kt new file mode 100644 index 0000000000..3a11116527 --- /dev/null +++ b/core-1.2/src/main/kotlin/kotlin/io/path/KotlinIoPath1.2.kt @@ -0,0 +1,37 @@ +// Implement the new post-1.2 APIs which are used by core and serialization +@file:Suppress("unused", "SpreadOperator", "NOTHING_TO_INLINE") + +package kotlin.io.path + +import java.io.InputStream +import java.io.OutputStream +import java.nio.file.Files +import java.nio.file.LinkOption +import java.nio.file.OpenOption +import java.nio.file.Path +import java.nio.file.attribute.FileAttribute + +inline operator fun Path.div(other: String): Path = this.resolve(other) + +fun Path.listDirectoryEntries(glob: String = "*"): List = Files.newDirectoryStream(this, glob).use { it.toList() } + +inline fun Path.createDirectories(vararg attributes: FileAttribute<*>): Path = Files.createDirectories(this, *attributes) + +inline fun Path.deleteIfExists(): Boolean = Files.deleteIfExists(this) + +inline fun Path.exists(vararg options: LinkOption): Boolean = Files.exists(this, *options) + +inline fun Path.inputStream(vararg options: OpenOption): InputStream = Files.newInputStream(this, *options) + +inline fun Path.outputStream(vararg options: OpenOption): OutputStream = Files.newOutputStream(this, *options) + +inline fun Path.isDirectory(vararg options: LinkOption): Boolean = Files.isDirectory(this, *options) + +inline fun Path.isSymbolicLink(): Boolean = Files.isSymbolicLink(this) + +inline fun Path.readSymbolicLink(): Path = Files.readSymbolicLink(this) + +val Path.name: String + get() = fileName?.toString().orEmpty() + +inline fun Path.readBytes(): ByteArray = Files.readAllBytes(this) diff --git a/core-1.2/src/main/kotlin/kotlin/text/CharJVM1.2.kt b/core-1.2/src/main/kotlin/kotlin/text/CharJVM1.2.kt new file mode 100644 index 0000000000..af44e3d053 --- /dev/null +++ b/core-1.2/src/main/kotlin/kotlin/text/CharJVM1.2.kt @@ -0,0 +1,24 @@ +// Implement the new post-1.2 APIs which are used by core and serialization +@file:Suppress("NOTHING_TO_INLINE", "unused") + +package kotlin.text + +import java.util.Locale + +inline fun Char.isLowerCase(): Boolean = Character.isLowerCase(this) +public fun Char.lowercase(locale: Locale): String = toString().lowercase(locale) +inline fun Char.lowercaseChar(): Char = Character.toLowerCase(this) +inline fun Char.uppercase(): String = toString().uppercase() +fun Char.uppercase(locale: Locale): String = toString().uppercase(locale) +inline fun Char.titlecaseChar(): Char = Character.toTitleCase(this) +fun Char.titlecase(locale: Locale): String { + val localizedUppercase = uppercase(locale) + if (localizedUppercase.length > 1) { + return if (this == '\u0149') localizedUppercase else localizedUppercase[0] + localizedUppercase.substring(1).lowercase() + } + if (localizedUppercase != uppercase()) { + return localizedUppercase + } + return titlecaseChar().toString() +} + diff --git a/core-1.2/src/main/kotlin/kotlin/text/StringBuilder1.2.kt b/core-1.2/src/main/kotlin/kotlin/text/StringBuilder1.2.kt new file mode 100644 index 0000000000..a3afc05d46 --- /dev/null +++ b/core-1.2/src/main/kotlin/kotlin/text/StringBuilder1.2.kt @@ -0,0 +1,12 @@ +// Implement the new post-1.2 APIs which are used by core and serialization +@file:Suppress("NOTHING_TO_INLINE", "unused") +package kotlin.text + +// StringBuilder +fun StringBuilder.append(vararg value: String?): StringBuilder { + for (item in value) + append(item) + return this +} +inline fun StringBuilder.appendLine(): StringBuilder = append('\n') +inline fun StringBuilder.appendLine(value: String?): StringBuilder = append(value).appendLine() diff --git a/core-1.2/src/main/kotlin/kotlin/text/Strings1.2.kt b/core-1.2/src/main/kotlin/kotlin/text/Strings1.2.kt new file mode 100644 index 0000000000..2900656a43 --- /dev/null +++ b/core-1.2/src/main/kotlin/kotlin/text/Strings1.2.kt @@ -0,0 +1,8 @@ +// Implement the new post-1.2 APIs which are used by core and serialization +@file:Suppress("unused") + +package kotlin.text + +inline fun String.replaceFirstChar(transform: (Char) -> CharSequence): String { + return if (isNotEmpty()) transform(this[0]).toString() + substring(1) else this +} diff --git a/core-1.2/src/main/kotlin/kotlin/text/StringsJVM1.2.kt b/core-1.2/src/main/kotlin/kotlin/text/StringsJVM1.2.kt new file mode 100644 index 0000000000..09f2695fed --- /dev/null +++ b/core-1.2/src/main/kotlin/kotlin/text/StringsJVM1.2.kt @@ -0,0 +1,12 @@ +// Implement the new post-1.2 APIs which are used by core and serialization +@file:Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "NOTHING_TO_INLINE", "unused") + +package kotlin.text + +import java.util.Locale + +// String extensions +inline fun String.lowercase(): String = (this as java.lang.String).toLowerCase(Locale.ROOT) +inline fun String.lowercase(locale: Locale): String = (this as java.lang.String).toLowerCase(locale) +inline fun String.uppercase(): String = (this as java.lang.String).toUpperCase(Locale.ROOT) +inline fun String.uppercase(locale: Locale): String = (this as java.lang.String).toUpperCase(locale) diff --git a/core-tests/build.gradle b/core-tests/build.gradle index ea5f7d4ecf..08823f41ee 100644 --- a/core-tests/build.gradle +++ b/core-tests/build.gradle @@ -1,18 +1,21 @@ -apply plugin: 'kotlin' -apply plugin: 'kotlin-jpa' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'org.jetbrains.kotlin.plugin.jpa' apply plugin: 'net.corda.plugins.quasar-utils' +apply plugin: 'idea' description 'Corda core tests' configurations { - integrationTestCompile.extendsFrom testCompile + integrationTestImplementation.extendsFrom testImplementation integrationTestRuntimeOnly.extendsFrom testRuntimeOnly - smokeTestCompile.extendsFrom compile + smokeTestImplementation.extendsFrom implementation smokeTestRuntimeOnly.extendsFrom runtimeOnly -} -evaluationDependsOn(':node:capsule') + testArtifacts.extendsFrom testRuntimeOnlyClasspath + + corda4_11 +} sourceSets { integrationTest { @@ -41,63 +44,98 @@ sourceSets { processSmokeTestResources { // Bring in the fully built corda.jar for use by NodeFactory in the smoke tests - from(project(':node:capsule').tasks['buildCordaJAR']) { + from(tasks.getByPath(":node:capsule:buildCordaJAR")) { rename 'corda-(.*)', 'corda.jar' } + from(tasks.getByPath(":finance:workflows:jar")) { + rename 'corda-finance-workflows-.*.jar', 'corda-finance-workflows.jar' + } + from(tasks.getByPath(":finance:contracts:jar")) { + rename 'corda-finance-contracts-.*.jar', 'corda-finance-contracts.jar' + } + from(tasks.getByPath(":testing:cordapps:4.11-workflows:jar")) + from(configurations.corda4_11) +} + +processIntegrationTestResources { + from(tasks.getByPath(":finance:contracts:jar")) { + rename 'corda-finance-contracts-.*.jar', 'corda-finance-contracts.jar' + } + from(configurations.corda4_11) +} + +processTestResources { + from(configurations.corda4_11) } dependencies { - + testImplementation project(":core") + testImplementation project(":serialization") + testImplementation project(":finance:contracts") + testImplementation project(":finance:workflows") + testImplementation project(":node") + testImplementation project(":node-api") + testImplementation project(":client:rpc") + testImplementation project(":common-configuration-parsing") + testImplementation project(":core-test-utils") + testImplementation project(":test-utils") + testImplementation project(":node-driver") + // used by FinalityFlowTests + testImplementation project(':testing:cordapps:cashobservers') + testImplementation(project(path: ':core', configuration: 'testArtifacts')) { + transitive = false + } testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" + testImplementation "org.apache.commons:commons-fileupload2-jakarta:$fileupload_version" + // Guava: Google test library (collections test suite) + testImplementation "com.google.guava:guava-testlib:$guava_version" + testImplementation "com.google.jimfs:jimfs:1.1" + testImplementation "com.typesafe:config:$typesafe_config_version" + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + // Hamkrest, for fluent, composable matchers + testImplementation "com.natpryce:hamkrest:$hamkrest_version" + testImplementation 'org.hamcrest:hamcrest-library:2.1' + testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" + testImplementation "org.mockito:mockito-core:$mockito_version" + // AssertJ: for fluent assertions for testing + testImplementation "org.assertj:assertj-core:${assertj_version}" + // Guava: Google utilities library. + testImplementation "com.google.guava:guava:$guava_version" + testImplementation "com.esotericsoftware:kryo:$kryo_version" + testImplementation "co.paralleluniverse:quasar-core:$quasar_version" + testImplementation "org.hibernate:hibernate-core:$hibernate_version" + testImplementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}" + testImplementation "io.netty:netty-common:$netty_version" + testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile "commons-fileupload:commons-fileupload:$fileupload_version" - testCompile project(":core") - testCompile project(path: ':core', configuration: 'testArtifacts') - - // Guava: Google test library (collections test suite) - testCompile "com.google.guava:guava-testlib:$guava_version" - - // Bring in the MockNode infrastructure for writing protocol unit tests. - testCompile project(":node-driver") - - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - - // Hamkrest, for fluent, composable matchers - testCompile "com.natpryce:hamkrest:$hamkrest_version" - - // SLF4J: commons-logging bindings for a SLF4J back end - compile "org.slf4j:jcl-over-slf4j:$slf4j_version" - compile "org.slf4j:slf4j-api:$slf4j_version" - - // AssertJ: for fluent assertions for testing - testCompile "org.assertj:assertj-core:${assertj_version}" - - // Guava: Google utilities library. - testCompile "com.google.guava:guava:$guava_version" - // Smoke tests do NOT have any Node code on the classpath! + smokeTestImplementation project(":core") + smokeTestImplementation project(":node-api") + smokeTestImplementation project(":client:rpc") + smokeTestImplementation project(':smoke-test-utils') + smokeTestImplementation project(':core-test-utils') + smokeTestImplementation project(":finance:workflows") + smokeTestImplementation project(":testing:cordapps:4.11-workflows") + smokeTestImplementation project(":finance:contracts") + smokeTestImplementation "org.assertj:assertj-core:${assertj_version}" + smokeTestImplementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}" + smokeTestImplementation "co.paralleluniverse:quasar-core:$quasar_version" smokeTestImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" smokeTestImplementation "junit:junit:$junit_version" smokeTestRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" smokeTestRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" smokeTestRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" + smokeTestRuntimeOnly "org.slf4j:slf4j-simple:$slf4j_version" - smokeTestCompile project(':smoke-test-utils') - smokeTestCompile "org.assertj:assertj-core:${assertj_version}" - - // used by FinalityFlowTests - testCompile project(':testing:cordapps:cashobservers') -} - -configurations { - testArtifacts.extendsFrom testRuntimeClasspath + corda4_11 "net.corda:corda-finance-contracts:4.11" + corda4_11 "net.corda:corda-finance-workflows:4.11" + corda4_11 "net.corda:corda:4.11" } tasks.withType(Test).configureEach { @@ -105,27 +143,36 @@ tasks.withType(Test).configureEach { forkEvery = 10 } -task testJar(type: Jar) { +tasks.register('testJar', Jar) { classifier "tests" from sourceSets.test.output } -task integrationTest(type: Test) { +tasks.register('integrationTest', Test) { testClassesDirs = sourceSets.integrationTest.output.classesDirs classpath = sourceSets.integrationTest.runtimeClasspath } -task smokeTestJar(type: Jar) { +tasks.register('smokeTestJar', Jar) { classifier 'smokeTests' - from sourceSets.smokeTest.output + from(sourceSets.smokeTest.output) { + exclude("*.jar") + } } -task smokeTest(type: Test) { +tasks.register('smokeTest', Test) { dependsOn smokeTestJar testClassesDirs = sourceSets.smokeTest.output.classesDirs classpath = sourceSets.smokeTest.runtimeClasspath } +idea { + module { + downloadJavadoc = true + downloadSources = true + } +} + // quasar exclusions upon agent code instrumentation at run-time quasar { excludePackages.addAll( @@ -140,7 +187,6 @@ quasar { "io.github.classgraph**", "io.netty*", "liquibase**", - "net.i2p.crypto.**", "nonapi.io.github.classgraph.**", "org.apiguardian.**", "org.bouncycastle**", diff --git a/core-tests/src/integration-test/kotlin/net/corda/coretests/transactions/TransactionBuilderDriverTest.kt b/core-tests/src/integration-test/kotlin/net/corda/coretests/transactions/TransactionBuilderDriverTest.kt new file mode 100644 index 0000000000..4eecc1ee45 --- /dev/null +++ b/core-tests/src/integration-test/kotlin/net/corda/coretests/transactions/TransactionBuilderDriverTest.kt @@ -0,0 +1,198 @@ +package net.corda.coretests.transactions + +import co.paralleluniverse.fibers.Suspendable +import net.corda.core.contracts.TransactionState +import net.corda.core.flows.FlowLogic +import net.corda.core.flows.StartableByRPC +import net.corda.core.internal.hash +import net.corda.core.internal.mapToSet +import net.corda.core.internal.toPath +import net.corda.core.messaging.startFlow +import net.corda.core.transactions.SignedTransaction +import net.corda.core.transactions.TransactionBuilder +import net.corda.core.utilities.OpaqueBytes +import net.corda.core.utilities.getOrThrow +import net.corda.coretesting.internal.delete +import net.corda.coretesting.internal.modifyJarManifest +import net.corda.coretesting.internal.useZipFile +import net.corda.finance.DOLLARS +import net.corda.finance.contracts.CommercialPaper +import net.corda.finance.contracts.asset.Cash +import net.corda.finance.flows.CashIssueAndPaymentFlow +import net.corda.finance.issuedBy +import net.corda.testing.common.internal.testNetworkParameters +import net.corda.testing.core.ALICE_NAME +import net.corda.testing.core.internal.JarSignatureTestUtils.unsignJar +import net.corda.testing.driver.NodeHandle +import net.corda.testing.driver.NodeParameters +import net.corda.testing.node.TestCordapp +import net.corda.testing.node.internal.DriverDSLImpl +import net.corda.testing.node.internal.FINANCE_WORKFLOWS_CORDAPP +import net.corda.testing.node.internal.TestCordappInternal +import net.corda.testing.node.internal.UriTestCordapp +import net.corda.testing.node.internal.enclosedCordapp +import net.corda.testing.node.internal.internalDriver +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy +import org.junit.Test +import java.nio.file.Files +import java.nio.file.Path +import java.time.Duration +import java.time.Instant +import kotlin.io.path.absolutePathString +import kotlin.io.path.copyTo +import kotlin.io.path.createDirectories +import kotlin.io.path.inputStream +import kotlin.io.path.isRegularFile +import kotlin.io.path.moveTo + +class TransactionBuilderDriverTest { + companion object { + val currentFinanceContractsJar = this::class.java.getResource("/corda-finance-contracts.jar")!!.toPath() + val legacyFinanceContractsJar = this::class.java.getResource("/corda-finance-contracts-4.11.jar")!!.toPath() + } + + @Test(timeout=300_000) + fun `adds CorDapp dependencies`() { + internalDriver(cordappsForAllNodes = listOf(FINANCE_WORKFLOWS_CORDAPP), startNodesInProcess = false) { + val (cordapp, dependency) = splitFinanceContractCordapp(currentFinanceContractsJar) + + cordapp.jarFile.inputStream().use(defaultNotaryNode.getOrThrow().rpc::uploadAttachment) + dependency.jarFile.inputStream().use(defaultNotaryNode.getOrThrow().rpc::uploadAttachment) + + // Start the node with the CorDapp but without the dependency + val node = startNode(NodeParameters(ALICE_NAME, additionalCordapps = listOf(cordapp))).getOrThrow() + + // First make sure the missing dependency causes an issue + assertThatThrownBy { + createTransaction(node) + }.hasMessageContaining("Transaction being built has a missing attachment for class net/corda/finance/contracts/asset/") + + // Upload the missing dependency + dependency.jarFile.inputStream().use(node.rpc::uploadAttachment) + + val stx = createTransaction(node) + assertThat(stx.tx.attachments).contains(cordapp.jarFile.hash, dependency.jarFile.hash) + } + } + + @Test(timeout=300_000) + fun `adds legacy contracts CorDapp dependencies`() { + internalDriver( + cordappsForAllNodes = listOf(FINANCE_WORKFLOWS_CORDAPP), + startNodesInProcess = false, + networkParameters = testNetworkParameters(minimumPlatformVersion = 4) + ) { + val (legacyContracts, legacyDependency) = splitFinanceContractCordapp(legacyFinanceContractsJar) + val currentContracts = TestCordapp.of(currentFinanceContractsJar.toUri()).asSigned() as TestCordappInternal + + currentContracts.jarFile.inputStream().use(defaultNotaryNode.getOrThrow().rpc::uploadAttachment) + + // Start the node with the legacy CorDapp but without the dependency + val node = startNode(NodeParameters( + ALICE_NAME, + additionalCordapps = listOf(currentContracts), + legacyContracts = listOf(legacyContracts) + )).getOrThrow() + + // First make sure the missing dependency causes an issue + assertThatThrownBy { + createTransaction(node) + }.hasMessageContaining("Transaction being built has a missing legacy attachment for class net/corda/finance/contracts/asset/") + + // Upload the missing dependency + legacyDependency.jarFile.inputStream().use(node.rpc::uploadAttachment) + + val stx = createTransaction(node) + assertThat(stx.tx.legacyAttachments).contains(legacyContracts.jarFile.hash, legacyDependency.jarFile.hash) + } + } + + @Test(timeout=300_000) + fun `prevents transaction which is multi-contract but not backwards compatible because one of the contracts has missing legacy attachment`() { + internalDriver( + cordappsForAllNodes = listOf(FINANCE_WORKFLOWS_CORDAPP, enclosedCordapp()), + startNodesInProcess = false, + networkParameters = testNetworkParameters(minimumPlatformVersion = 4), + isDebug = true + ) { + val (currentCashContract, currentCpContract) = splitJar(currentFinanceContractsJar) { "CommercialPaper" in it.absolutePathString() } + val (legacyCashContract, _) = splitJar(legacyFinanceContractsJar) { "CommercialPaper" in it.absolutePathString() } + + currentCashContract.jarFile.inputStream().use(defaultNotaryNode.getOrThrow().rpc::uploadAttachment) + currentCpContract.jarFile.inputStream().use(defaultNotaryNode.getOrThrow().rpc::uploadAttachment) + + // The node has the legacy CommericalPaper contract missing + val node = startNode(NodeParameters( + ALICE_NAME, + additionalCordapps = listOf(currentCashContract, currentCpContract), + legacyContracts = listOf(legacyCashContract) + )).getOrThrow() + + assertThatThrownBy { node.rpc.startFlow(::TwoContractTransactionFlow).returnValue.getOrThrow() } + .hasMessageContaining("Transaction being built has a missing legacy attachment") + .hasMessageContaining("CommercialPaper") + } + } + + /** + * Split the given finance contracts jar into two such that the second jar becomes a dependency to the first. + */ + private fun DriverDSLImpl.splitFinanceContractCordapp(contractsJar: Path): Pair { + return splitJar(contractsJar) { it.absolutePathString() == "/net/corda/finance/contracts/asset/CashUtilities.class" } + } + + private fun DriverDSLImpl.splitJar(path: Path, move: (Path) -> Boolean): Pair { + val jar1 = Files.createTempFile(driverDirectory, "jar1-", ".jar") + val jar2 = Files.createTempFile(driverDirectory, "jar2-", ".jar") + + path.copyTo(jar1, overwrite = true) + jar1.useZipFile { zipFs1 -> + jar2.useZipFile { zipFs2 -> + Files.walk(zipFs1.getPath("/")).filter { it.isRegularFile() && move(it) }.forEach { file -> + val target = zipFs2.getPath(file.absolutePathString()) + target.parent?.createDirectories() + file.moveTo(target) + } + } + } + jar1.modifyJarManifest { manifest -> + manifest.mainAttributes.delete("Sealed") + } + jar1.unsignJar() + + return Pair( + TestCordapp.of(jar1.toUri()).asSigned() as UriTestCordapp, + TestCordapp.of(jar2.toUri()).asSigned() as UriTestCordapp + ) + } + + private fun DriverDSLImpl.createTransaction(node: NodeHandle): SignedTransaction { + return node.rpc.startFlow( + ::CashIssueAndPaymentFlow, + 1.DOLLARS, + OpaqueBytes.of(0x00), + defaultNotaryIdentity, + false, + defaultNotaryIdentity + ).returnValue.getOrThrow().stx + } + + + @StartableByRPC + class TwoContractTransactionFlow : FlowLogic() { + @Suspendable + override fun call() { + val notary = serviceHub.networkMapCache.notaryIdentities[0] + val builder = TransactionBuilder(notary) + val issuer = ourIdentity.ref(OpaqueBytes.of(0x00)) + val amount = 1.DOLLARS.issuedBy(issuer) + val signers = Cash().generateIssue(builder, amount, ourIdentity, notary) + builder.addOutputState(TransactionState(CommercialPaper.State(issuer, ourIdentity, amount, Instant.MAX), notary = notary)) + builder.addCommand(CommercialPaper.Commands.Issue(), signers.first()) + builder.setTimeWindow(Instant.now(), Duration.ofMinutes(1)) + require(builder.outputStates().mapToSet { it.contract }.size > 1) + serviceHub.signInitialTransaction(builder, signers) + } + } +} diff --git a/core-tests/src/smoke-test/kotlin/net/corda/coretests/NodeVersioningTest.kt b/core-tests/src/smoke-test/kotlin/net/corda/coretests/NodeVersioningTest.kt index 12a303de02..e290b19644 100644 --- a/core-tests/src/smoke-test/kotlin/net/corda/coretests/NodeVersioningTest.kt +++ b/core-tests/src/smoke-test/kotlin/net/corda/coretests/NodeVersioningTest.kt @@ -4,20 +4,20 @@ import co.paralleluniverse.fibers.Suspendable import net.corda.core.flows.FlowLogic import net.corda.core.flows.StartableByRPC import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.* +import net.corda.core.internal.PLATFORM_VERSION import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow import net.corda.nodeapi.internal.config.User -import net.corda.smoketesting.NodeConfig +import net.corda.smoketesting.NodeParams import net.corda.smoketesting.NodeProcess import org.assertj.core.api.Assertions.assertThat import org.junit.After import org.junit.Before import org.junit.Test -import java.nio.file.Paths import java.util.concurrent.atomic.AtomicInteger import java.util.jar.JarFile -import kotlin.streams.toList +import kotlin.io.path.Path +import kotlin.io.path.listDirectoryEntries class NodeVersioningTest { private companion object { @@ -27,58 +27,39 @@ class NodeVersioningTest { private val factory = NodeProcess.Factory() - private val notaryConfig = NodeConfig( - legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"), - p2pPort = port.andIncrement, - rpcPort = port.andIncrement, - rpcAdminPort = port.andIncrement, - isNotary = true, - users = listOf(superUser) - ) - - private val aliceConfig = NodeConfig( - legalName = CordaX500Name(organisation = "Alice Corp", locality = "Madrid", country = "ES"), - p2pPort = port.andIncrement, - rpcPort = port.andIncrement, - rpcAdminPort = port.andIncrement, - isNotary = false, - users = listOf(superUser) - ) - private lateinit var notary: NodeProcess @Before - fun setUp() { - notary = factory.create(notaryConfig) + fun startNotary() { + notary = factory.createNotaries(NodeParams( + legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"), + p2pPort = port.andIncrement, + rpcPort = port.andIncrement, + rpcAdminPort = port.andIncrement, + users = listOf(superUser), + // Find the jar file for the smoke tests of this module + cordappJars = Path("build", "libs").listDirectoryEntries("*-smokeTests*") + ))[0] } @After fun done() { - notary.close() + factory.close() } @Test(timeout=300_000) fun `platform version in manifest file`() { - val manifest = JarFile(factory.cordaJar.toFile()).manifest + val manifest = JarFile(NodeProcess.Factory.getCordaJar().toFile()).manifest assertThat(manifest.mainAttributes.getValue("Corda-Platform-Version").toInt()).isEqualTo(PLATFORM_VERSION) } @Test(timeout=300_000) fun `platform version from RPC`() { - val cordappsDir = (factory.baseDirectory(aliceConfig) / NodeProcess.CORDAPPS_DIR_NAME).createDirectories() - // Find the jar file for the smoke tests of this module - val selfCordapp = Paths.get("build", "libs").list { - it.filter { "-smokeTests" in it.toString() }.toList().single() - } - selfCordapp.copyToDirectory(cordappsDir) - - factory.create(aliceConfig).use { alice -> - alice.connect(superUser).use { - val rpc = it.proxy - assertThat(rpc.protocolVersion).isEqualTo(PLATFORM_VERSION) - assertThat(rpc.nodeInfo().platformVersion).isEqualTo(PLATFORM_VERSION) - assertThat(rpc.startFlow(NodeVersioningTest::GetPlatformVersionFlow).returnValue.getOrThrow()).isEqualTo(PLATFORM_VERSION) - } + notary.connect(superUser).use { + val rpc = it.proxy + assertThat(rpc.protocolVersion).isEqualTo(PLATFORM_VERSION) + assertThat(rpc.nodeInfo().platformVersion).isEqualTo(PLATFORM_VERSION) + assertThat(rpc.startFlow(NodeVersioningTest::GetPlatformVersionFlow).returnValue.getOrThrow()).isEqualTo(PLATFORM_VERSION) } } diff --git a/core-tests/src/smoke-test/kotlin/net/corda/coretests/cordapp/CordappSmokeTest.kt b/core-tests/src/smoke-test/kotlin/net/corda/coretests/cordapp/CordappSmokeTest.kt index 6374390c23..d4b2fbda44 100644 --- a/core-tests/src/smoke-test/kotlin/net/corda/coretests/cordapp/CordappSmokeTest.kt +++ b/core-tests/src/smoke-test/kotlin/net/corda/coretests/cordapp/CordappSmokeTest.kt @@ -3,11 +3,15 @@ package net.corda.coretests.cordapp import co.paralleluniverse.fibers.Suspendable import net.corda.core.crypto.Crypto.generateKeyPair import net.corda.core.crypto.sign -import net.corda.core.flows.* +import net.corda.core.flows.FlowInfo +import net.corda.core.flows.FlowLogic +import net.corda.core.flows.FlowSession +import net.corda.core.flows.InitiatedBy +import net.corda.core.flows.InitiatingFlow +import net.corda.core.flows.StartableByRPC import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate -import net.corda.core.internal.* import net.corda.core.messaging.startFlow import net.corda.core.node.NodeInfo import net.corda.core.serialization.serialize @@ -21,20 +25,23 @@ import net.corda.nodeapi.internal.config.User import net.corda.nodeapi.internal.createDevNodeCa import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.X509Utilities -import net.corda.smoketesting.NodeConfig +import net.corda.smoketesting.NodeParams import net.corda.smoketesting.NodeProcess -import net.corda.smoketesting.NodeProcess.Companion.CORDAPPS_DIR_NAME import org.assertj.core.api.Assertions.assertThat import org.junit.After import org.junit.Before import org.junit.Test import java.nio.file.Path -import java.nio.file.Paths import java.security.KeyPair import java.security.PrivateKey import java.security.PublicKey import java.util.concurrent.atomic.AtomicInteger -import kotlin.streams.toList +import kotlin.io.path.Path +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.name +import kotlin.io.path.writeBytes class CordappSmokeTest { private companion object { @@ -44,45 +51,35 @@ class CordappSmokeTest { private val factory = NodeProcess.Factory() - private val notaryConfig = NodeConfig( - legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"), - p2pPort = port.andIncrement, - rpcPort = port.andIncrement, - rpcAdminPort = port.andIncrement, - isNotary = true, - users = listOf(superUser) - ) - - private val aliceConfig = NodeConfig( + private val aliceConfig = NodeParams( legalName = CordaX500Name(organisation = "Alice Corp", locality = "Madrid", country = "ES"), p2pPort = port.andIncrement, rpcPort = port.andIncrement, rpcAdminPort = port.andIncrement, - isNotary = false, - users = listOf(superUser) + users = listOf(superUser), + // Find the jar file for the smoke tests of this module + cordappJars = Path("build", "libs").listDirectoryEntries("*-smokeTests*") ) - private lateinit var notary: NodeProcess - @Before - fun setUp() { - notary = factory.create(notaryConfig) + fun startNotary() { + factory.createNotaries(NodeParams( + legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"), + p2pPort = port.andIncrement, + rpcPort = port.andIncrement, + rpcAdminPort = port.andIncrement, + users = listOf(superUser) + )) } @After fun done() { - notary.close() + factory.close() } @Test(timeout=300_000) fun `FlowContent appName returns the filename of the CorDapp jar`() { val baseDir = factory.baseDirectory(aliceConfig) - val cordappsDir = (baseDir / CORDAPPS_DIR_NAME).createDirectories() - // Find the jar file for the smoke tests of this module - val selfCordapp = Paths.get("build", "libs").list { - it.filter { "-smokeTests" in it.toString() }.toList().single() - } - selfCordapp.copyToDirectory(cordappsDir) // The `nodeReadyFuture` in the persistent network map cache will not complete unless there is at least one other // node in the network. We work around this limitation by putting another node info file in the additional-node-info @@ -91,24 +88,17 @@ class CordappSmokeTest { val additionalNodeInfoDir = (baseDir / "additional-node-infos").createDirectories() createDummyNodeInfo(additionalNodeInfoDir) - factory.create(aliceConfig).use { alice -> - alice.connect(superUser).use { connectionToAlice -> - val aliceIdentity = connectionToAlice.proxy.nodeInfo().legalIdentitiesAndCerts.first().party - val future = connectionToAlice.proxy.startFlow(CordappSmokeTest::GatherContextsFlow, aliceIdentity).returnValue - val (sessionInitContext, sessionConfirmContext) = future.getOrThrow() - val selfCordappName = selfCordapp.fileName.toString().removeSuffix(".jar") - assertThat(sessionInitContext.appName).isEqualTo(selfCordappName) - assertThat(sessionConfirmContext.appName).isEqualTo(selfCordappName) - } + val alice = factory.createNode(aliceConfig) + alice.connect(superUser).use { connectionToAlice -> + val aliceIdentity = connectionToAlice.proxy.nodeInfo().legalIdentitiesAndCerts.first().party + val future = connectionToAlice.proxy.startFlow(CordappSmokeTest::GatherContextsFlow, aliceIdentity).returnValue + val (sessionInitContext, sessionConfirmContext) = future.getOrThrow() + val selfCordappName = aliceConfig.cordappJars[0].name.removeSuffix(".jar") + assertThat(sessionInitContext.appName).isEqualTo(selfCordappName) + assertThat(sessionConfirmContext.appName).isEqualTo(selfCordappName) } } - @Test(timeout=300_000) - fun `empty cordapps directory`() { - (factory.baseDirectory(aliceConfig) / CORDAPPS_DIR_NAME).createDirectories() - factory.create(aliceConfig).close() - } - @InitiatingFlow @StartableByRPC class GatherContextsFlow(private val otherParty: Party) : FlowLogic>() { @@ -139,7 +129,7 @@ class CordappSmokeTest { val dummyKeyPair = generateKeyPair() val nodeInfo = createNodeInfoWithSingleIdentity(CordaX500Name(organisation = "Bob Corp", locality = "Madrid", country = "ES"), dummyKeyPair, dummyKeyPair.public) val signedNodeInfo = signWith(nodeInfo, listOf(dummyKeyPair.private)) - (additionalNodeInfoDir / "nodeInfo-41408E093F95EAD51F6892C34DEB65AE1A3569A4B0E5744769A1B485AF8E04B5").write(signedNodeInfo.serialize().bytes) + (additionalNodeInfoDir / "nodeInfo-41408E093F95EAD51F6892C34DEB65AE1A3569A4B0E5744769A1B485AF8E04B5").writeBytes(signedNodeInfo.serialize().bytes) } private fun createNodeInfoWithSingleIdentity(name: CordaX500Name, nodeKeyPair: KeyPair, identityCertPublicKey: PublicKey): NodeInfo { diff --git a/core-tests/src/smoke-test/kotlin/net/corda/coretests/verification/ExternalVerificationTests.kt b/core-tests/src/smoke-test/kotlin/net/corda/coretests/verification/ExternalVerificationTests.kt new file mode 100644 index 0000000000..fd742d58f2 --- /dev/null +++ b/core-tests/src/smoke-test/kotlin/net/corda/coretests/verification/ExternalVerificationTests.kt @@ -0,0 +1,304 @@ +package net.corda.coretests.verification + +import net.corda.client.rpc.CordaRPCClientConfiguration +import net.corda.client.rpc.notUsed +import net.corda.core.contracts.Amount +import net.corda.core.crypto.SecureHash +import net.corda.core.flows.UnexpectedFlowEndException +import net.corda.core.identity.CordaX500Name +import net.corda.core.identity.Party +import net.corda.core.internal.PlatformVersionSwitches.MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS +import net.corda.core.internal.toPath +import net.corda.core.messaging.CordaRPCOps +import net.corda.core.messaging.startFlow +import net.corda.core.node.NodeInfo +import net.corda.core.transactions.SignedTransaction +import net.corda.core.utilities.OpaqueBytes +import net.corda.core.utilities.getOrThrow +import net.corda.coretests.verification.VerificationType.BOTH +import net.corda.coretests.verification.VerificationType.EXTERNAL +import net.corda.finance.DOLLARS +import net.corda.finance.USD +import net.corda.finance.contracts.asset.Cash +import net.corda.finance.flows.AbstractCashFlow +import net.corda.finance.flows.CashIssueFlow +import net.corda.finance.flows.CashPaymentFlow +import net.corda.finance.workflows.getCashBalance +import net.corda.nodeapi.internal.config.User +import net.corda.smoketesting.NodeParams +import net.corda.smoketesting.NodeProcess +import net.corda.testing.common.internal.testNetworkParameters +import net.corda.testing.cordapps.workflows411.IssueAndChangeNotaryFlow +import net.corda.testing.core.DUMMY_NOTARY_NAME +import net.corda.testing.core.internal.JarSignatureTestUtils.unsignJar +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.junit.AfterClass +import org.junit.BeforeClass +import org.junit.Test +import rx.Observable +import java.net.InetAddress +import java.nio.file.Path +import java.util.Currency +import java.util.concurrent.CompletableFuture +import java.util.concurrent.atomic.AtomicInteger +import kotlin.io.path.Path +import kotlin.io.path.copyTo +import kotlin.io.path.div +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.readText +import kotlin.io.path.useLines + +class ExternalVerificationSignedCordappsTest { + private companion object { + private val factory = NodeProcess.Factory(testNetworkParameters(minimumPlatformVersion = MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS)) + + private lateinit var notaries: List + private lateinit var oldNode: NodeProcess + private lateinit var currentNode: NodeProcess + + @BeforeClass + @JvmStatic + fun startNodes() { + val (legacyContractsCordapp, legacyWorkflowsCordapp) = listOf("contracts", "workflows").map { smokeTestResource("corda-finance-$it-4.11.jar") } + // The current version finance CorDapp jars + val currentCordapps = listOf("contracts", "workflows").map { smokeTestResource("corda-finance-$it.jar") } + + notaries = factory.createNotaries( + nodeParams(DUMMY_NOTARY_NAME, cordappJars = currentCordapps, legacyContractJars = listOf(legacyContractsCordapp)), + nodeParams(CordaX500Name("Notary Service 2", "Zurich", "CH"), currentCordapps) + ) + oldNode = factory.createNode(nodeParams( + CordaX500Name("Old", "Delhi", "IN"), + listOf(legacyContractsCordapp, legacyWorkflowsCordapp, smokeTestResource("4.11-workflows-cordapp.jar")), + clientRpcConfig = CordaRPCClientConfiguration(minimumServerProtocolVersion = 13), + version = "4.11" + )) + currentNode = factory.createNode(nodeParams( + CordaX500Name("New", "York", "US"), + currentCordapps, + listOf(legacyContractsCordapp) + )) + } + + @AfterClass + @JvmStatic + fun close() { + factory.close() + // Make sure all UNIX domain files are deleted + (notaries + currentNode).forEach { node -> + node.logFile("node")!!.useLines { lines -> + for (line in lines) { + if ("ExternalVerifierHandleImpl" in line && "Binding to UNIX domain file " in line) { + assertThat(Path(line.substringAfterLast("Binding to UNIX domain file "))).doesNotExist() + } + } + } + } + } + } + + @Test(timeout=300_000) + fun `transaction containing 4_11 contract attachment only sent to current node`() { + val (issuanceTx, paymentTx) = cashIssuanceAndPayment(issuer = oldNode, recipient = currentNode) + notaries[0].assertTransactionsWereVerified(EXTERNAL, paymentTx.id) + currentNode.assertTransactionsWereVerified(EXTERNAL, issuanceTx.id, paymentTx.id) + } + + @Test(timeout=300_000) + fun `transaction containing 4_11 and 4_12 contract attachments sent to old node`() { + val (issuanceTx, paymentTx) = cashIssuanceAndPayment(issuer = currentNode, recipient = oldNode) + notaries[0].assertTransactionsWereVerified(BOTH, paymentTx.id) + currentNode.assertTransactionsWereVerified(BOTH, issuanceTx.id, paymentTx.id) + } + + @Test(timeout=300_000) + fun `notary change transaction`() { + val oldRpc = oldNode.connect(superUser).proxy + val oldNodeInfo = oldRpc.nodeInfo() + val notaryIdentities = oldRpc.notaryIdentities() + for (notary in notaries) { + notary.connect(superUser).use { it.proxy.waitForVisibility(oldNodeInfo) } + } + oldRpc.startFlow(::IssueAndChangeNotaryFlow, notaryIdentities[0], notaryIdentities[1]).returnValue.getOrThrow() + } + + private fun cashIssuanceAndPayment(issuer: NodeProcess, recipient: NodeProcess): Pair { + val issuerRpc = issuer.connect(superUser).proxy + val recipientRpc = recipient.connect(superUser).proxy + val recipientNodeInfo = recipientRpc.nodeInfo() + val notaryIdentity = issuerRpc.notaryIdentities()[0] + + val beforeAmount = recipientRpc.getCashBalance(USD) + + val (issuanceTx) = issuerRpc.startFlow( + ::CashIssueFlow, + 10.DOLLARS, + OpaqueBytes.of(0x01), + notaryIdentity + ).returnValue.getOrThrow() + + issuerRpc.waitForVisibility(recipientNodeInfo) + recipientRpc.waitForVisibility(issuerRpc.nodeInfo()) + + val (_, update) = recipientRpc.vaultTrack(Cash.State::class.java) + val cashArrived = update.waitForFirst { true } + + val (paymentTx) = issuerRpc.startFlow( + ::CashPaymentFlow, + 10.DOLLARS, + recipientNodeInfo.legalIdentities[0], + false, + ).returnValue.getOrThrow() + + cashArrived.getOrThrow() + assertThat(recipientRpc.getCashBalance(USD) - beforeAmount).isEqualTo(10.DOLLARS) + + return Pair(issuanceTx, paymentTx) + } +} + +class ExternalVerificationUnsignedCordappsTest { + private companion object { + private val factory = NodeProcess.Factory(testNetworkParameters(minimumPlatformVersion = MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS)) + + private lateinit var notary: NodeProcess + private lateinit var oldNode: NodeProcess + private lateinit var newNode: NodeProcess + + @BeforeClass + @JvmStatic + fun startNodes() { + // The 4.11 finance CorDapp jars + val legacyCordapps = listOf(unsignedResourceJar("corda-finance-contracts-4.11.jar"), smokeTestResource("corda-finance-workflows-4.11.jar")) + // The current version finance CorDapp jars + val currentCordapps = listOf(unsignedResourceJar("corda-finance-contracts.jar"), smokeTestResource("corda-finance-workflows.jar")) + + notary = factory.createNotaries(nodeParams(DUMMY_NOTARY_NAME, currentCordapps))[0] + oldNode = factory.createNode(nodeParams( + CordaX500Name("Old", "Delhi", "IN"), + legacyCordapps, + clientRpcConfig = CordaRPCClientConfiguration(minimumServerProtocolVersion = 13), + version = "4.11" + )) + newNode = factory.createNode(nodeParams(CordaX500Name("New", "York", "US"), currentCordapps)) + } + + @AfterClass + @JvmStatic + fun close() { + factory.close() + } + + private fun unsignedResourceJar(name: String): Path { + val signedJar = smokeTestResource(name) + val copy = signedJar.copyTo(Path("${signedJar.toString().substringBeforeLast(".")}-UNSIGNED.jar"), overwrite = true) + copy.unsignJar() + return copy + } + } + + @Test(timeout = 300_000) + fun `transactions can fail verification in external verifier`() { + val issuerRpc = oldNode.connect(superUser).proxy + val recipientRpc = newNode.connect(superUser).proxy + val recipientNodeInfo = recipientRpc.nodeInfo() + val notaryIdentity = issuerRpc.notaryIdentities()[0] + + val (issuanceTx) = issuerRpc.startFlow( + ::CashIssueFlow, + 10.DOLLARS, + OpaqueBytes.of(0x01), + notaryIdentity + ).returnValue.getOrThrow() + + issuerRpc.waitForVisibility(recipientNodeInfo) + recipientRpc.waitForVisibility(issuerRpc.nodeInfo()) + + assertThatExceptionOfType(UnexpectedFlowEndException::class.java).isThrownBy { + issuerRpc.startFlow, Party, Boolean, CashPaymentFlow>( + ::CashPaymentFlow, + 10.DOLLARS, + recipientNodeInfo.legalIdentities[0], + false, + ).returnValue.getOrThrow() + } + + assertThat(newNode.externalVerifierLogs()).contains("WireTransaction(id=${issuanceTx.id}) failed to verify") + } +} + +private val superUser = User("superUser", "test", permissions = setOf("ALL")) +private val portCounter = AtomicInteger(15100) + +private fun smokeTestResource(name: String): Path = ExternalVerificationSignedCordappsTest::class.java.getResource("/$name")!!.toPath() + +private fun nodeParams( + legalName: CordaX500Name, + cordappJars: List = emptyList(), + legacyContractJars: List = emptyList(), + clientRpcConfig: CordaRPCClientConfiguration = CordaRPCClientConfiguration.DEFAULT, + version: String? = null +): NodeParams { + return NodeParams( + legalName = legalName, + p2pPort = portCounter.andIncrement, + rpcPort = portCounter.andIncrement, + rpcAdminPort = portCounter.andIncrement, + users = listOf(superUser), + cordappJars = cordappJars, + legacyContractJars = legacyContractJars, + clientRpcConfig = clientRpcConfig, + version = version + ) +} + +private fun CordaRPCOps.waitForVisibility(other: NodeInfo) { + val (snapshot, updates) = networkMapFeed() + if (other in snapshot) { + updates.notUsed() + } else { + updates.waitForFirst { it.node == other }.getOrThrow() + } +} + +private fun Observable.waitForFirst(predicate: (T) -> Boolean): CompletableFuture { + val found = CompletableFuture() + val subscription = subscribe { + if (predicate(it)) { + found.complete(Unit) + } + } + return found.whenComplete { _, _ -> subscription.unsubscribe() } +} + +private fun NodeProcess.assertTransactionsWereVerified(verificationType: VerificationType, vararg txIds: SecureHash) { + val nodeLogs = logContents("node")!! + val externalVerifierLogs = externalVerifierLogs() + for (txId in txIds) { + assertThat(nodeLogs).contains("WireTransaction(id=$txId) will be verified ${verificationType.logStatement}") + if (verificationType != VerificationType.IN_PROCESS) { + assertThat(externalVerifierLogs).describedAs("External verifier was not started").isNotNull() + assertThat(externalVerifierLogs).contains("WireTransaction(id=$txId) verified") + } + } +} + +private fun NodeProcess.externalVerifierLogs(): String? = logContents("verifier") + +private fun NodeProcess.logFile(name: String): Path? { + return (nodeDir / "logs").listDirectoryEntries("$name-${InetAddress.getLocalHost().hostName}.log").singleOrNull() +} + +private fun NodeProcess.logContents(name: String): String? = logFile(name)?.readText() + +private enum class VerificationType { + IN_PROCESS, EXTERNAL, BOTH; + + val logStatement: String + get() = when (this) { + IN_PROCESS -> "in-process" + EXTERNAL -> "by the external verifer" + BOTH -> "both in-process and by the external verifer" + } +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/contracts/AmountTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/contracts/AmountTests.kt index e382969aa0..07dcbcdb70 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/contracts/AmountTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/contracts/AmountTests.kt @@ -56,8 +56,8 @@ class AmountTests { val splits = baseAmount.splitEvenly(partitionCount) assertEquals(partitionCount, splits.size) assertEquals(baseAmount, splits.sumOrZero(baseAmount.token)) - val min = splits.min()!! - val max = splits.max()!! + val min = splits.min() + val max = splits.max() assertTrue(max.quantity - min.quantity <= 1L, "Amount quantities should differ by at most one token") } } diff --git a/core-tests/src/test/kotlin/net/corda/coretests/contracts/ConstraintsPropagationTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/contracts/ConstraintsPropagationTests.kt index 67d0a8e7cb..c955e830d2 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/contracts/ConstraintsPropagationTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/contracts/ConstraintsPropagationTests.kt @@ -1,9 +1,17 @@ package net.corda.coretests.contracts -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever -import net.corda.core.contracts.* +import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint +import net.corda.core.contracts.AutomaticPlaceholderConstraint +import net.corda.core.contracts.BelongsToContract +import net.corda.core.contracts.CommandData +import net.corda.core.contracts.Contract +import net.corda.core.contracts.ContractAttachment +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.HashAttachmentConstraint +import net.corda.core.contracts.NoConstraintPropagation +import net.corda.core.contracts.SignatureAttachmentConstraint +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.WhitelistedByZoneAttachmentConstraint import net.corda.core.crypto.Crypto import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash.Companion.allOnesHash @@ -14,17 +22,16 @@ import net.corda.core.crypto.sign import net.corda.core.identity.AbstractParty import net.corda.core.identity.CordaX500Name import net.corda.core.internal.canBeTransitionedFrom -import net.corda.core.internal.inputStream +import net.corda.core.internal.read import net.corda.core.internal.requireSupportedHashType -import net.corda.core.internal.toPath import net.corda.core.node.NotaryInfo import net.corda.core.node.services.IdentityService import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction import net.corda.finance.POUNDS -import net.corda.finance.`issued by` import net.corda.finance.contracts.asset.Cash +import net.corda.finance.`issued by` import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.DUMMY_NOTARY_NAME @@ -36,7 +43,15 @@ import net.corda.testing.core.internal.SelfCleaningDir import net.corda.testing.internal.MockCordappProvider import net.corda.testing.node.MockServices import net.corda.testing.node.ledger -import org.junit.* +import org.junit.AfterClass +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import java.security.PublicKey import java.util.jar.Attributes import kotlin.test.assertFailsWith @@ -91,8 +106,8 @@ class ConstraintsPropagationTests { }, networkParameters = testNetworkParameters(minimumPlatformVersion = 4) .copy(whitelistedContractImplementations = mapOf( - Cash.PROGRAM_ID to listOf(SecureHash.zeroHash, SecureHash.allOnesHash), - noPropagationContractClassName to listOf(SecureHash.zeroHash)), + Cash.PROGRAM_ID to listOf(zeroHash, allOnesHash), + noPropagationContractClassName to listOf(zeroHash)), notaries = listOf(NotaryInfo(DUMMY_NOTARY, true))) ) { override fun loadContractAttachment(stateRef: StateRef) = servicesForResolution.loadContractAttachment(stateRef) @@ -103,13 +118,13 @@ class ConstraintsPropagationTests { fun `Happy path with the HashConstraint`() { ledgerServices.ledger(DUMMY_NOTARY) { ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash) + attachment(Cash.PROGRAM_ID, allOnesHash) output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, HashAttachmentConstraint(allOnesHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() }) transaction { - attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash) + attachment(Cash.PROGRAM_ID, allOnesHash) input("c1") output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, HashAttachmentConstraint(allOnesHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) @@ -125,13 +140,13 @@ class ConstraintsPropagationTests { val cordappAttachmentIds = cordapps.map { cordapp -> val unsignedAttId = - cordapp.jarPath.toPath().inputStream().use { unsignedJarStream -> + cordapp.jarPath.openStream().use { unsignedJarStream -> ledgerServices.attachments.importContractAttachment(cordapp.contractClassNames, "rpc", unsignedJarStream, null) } val jarAndSigner = ContractJarTestUtils.signContractJar(cordapp.jarPath, copyFirst = true, keyStoreDir = keyStoreDir.path) val signedJar = jarAndSigner.first val signedAttId = - signedJar.inputStream().use { signedJarStream -> + signedJar.read { signedJarStream -> ledgerServices.attachments.importContractAttachment(cordapp.contractClassNames, "rpc", signedJarStream, null, listOf(jarAndSigner.second)) } Pair(unsignedAttId, signedAttId) @@ -163,14 +178,14 @@ class ConstraintsPropagationTests { fun `Fail early in the TransactionBuilder when attempting to change the hash of the HashConstraint on the spending transaction`() { ledgerServices.ledger(DUMMY_NOTARY) { transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash) + attachment(Cash.PROGRAM_ID, zeroHash) output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, HashAttachmentConstraint(zeroHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() } assertFailsWith { transaction { - attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash) + attachment(Cash.PROGRAM_ID, allOnesHash) input("c1") output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, HashAttachmentConstraint(allOnesHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) @@ -184,27 +199,27 @@ class ConstraintsPropagationTests { fun `Transaction validation fails, when constraints do not propagate correctly`() { ledgerServices.ledger(DUMMY_NOTARY) { ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash) + attachment(Cash.PROGRAM_ID, zeroHash) output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, HashAttachmentConstraint(zeroHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() }) ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash) + attachment(Cash.PROGRAM_ID, zeroHash) input("c1") output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) failsWith("are not propagated correctly") }) ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash) + attachment(Cash.PROGRAM_ID, zeroHash) input("c1") output(Cash.PROGRAM_ID, "c3", DUMMY_NOTARY, null, SignatureAttachmentConstraint(ALICE_PUBKEY), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) fails() }) transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash) + attachment(Cash.PROGRAM_ID, zeroHash) input("c1") output(Cash.PROGRAM_ID, "c4", DUMMY_NOTARY, null, AlwaysAcceptAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) @@ -217,13 +232,13 @@ class ConstraintsPropagationTests { fun `When the constraint of the output state is a valid transition from the input state, transaction validation works`() { ledgerServices.ledger(DUMMY_NOTARY) { ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash) + attachment(Cash.PROGRAM_ID, zeroHash) output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() }) transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash) + attachment(Cash.PROGRAM_ID, zeroHash) input("c1") output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, HashAttachmentConstraint(zeroHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) @@ -237,7 +252,7 @@ class ConstraintsPropagationTests { ledgerServices.ledger(DUMMY_NOTARY) { ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash) + attachment(Cash.PROGRAM_ID, zeroHash) output(Cash.PROGRAM_ID, "w1", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() @@ -245,7 +260,7 @@ class ConstraintsPropagationTests { // the attachment is signed transaction { - attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey)) + attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey)) input("w1") output(Cash.PROGRAM_ID, "w2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) @@ -258,14 +273,14 @@ class ConstraintsPropagationTests { fun `Switching from the WhitelistConstraint to the Signature Constraint fails if the signature constraint does not inherit all jar signatures`() { ledgerServices.ledger(DUMMY_NOTARY) { ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash) + attachment(Cash.PROGRAM_ID, zeroHash) output(Cash.PROGRAM_ID, "w1", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() }) // the attachment is not signed transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash) + attachment(Cash.PROGRAM_ID, zeroHash) input("w1") output(Cash.PROGRAM_ID, "w2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(ALICE_PUBKEY), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) @@ -279,13 +294,13 @@ class ConstraintsPropagationTests { fun `On contract annotated with NoConstraintPropagation there is no platform check for propagation, but the transaction builder can't use the AutomaticPlaceholderConstraint`() { ledgerServices.ledger(DUMMY_NOTARY) { ledgerServices.recordTransaction(transaction { - attachment(noPropagationContractClassName, SecureHash.zeroHash) + attachment(noPropagationContractClassName, zeroHash) output(noPropagationContractClassName, "c1", DUMMY_NOTARY, null, HashAttachmentConstraint(zeroHash), NoPropagationContractState()) command(ALICE_PUBKEY, NoPropagationContract.Create()) verifies() }) ledgerServices.recordTransaction(transaction { - attachment(noPropagationContractClassName, SecureHash.zeroHash) + attachment(noPropagationContractClassName, zeroHash) input("c1") output(noPropagationContractClassName, "c2", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, NoPropagationContractState()) command(ALICE_PUBKEY, NoPropagationContract.Create()) @@ -293,7 +308,7 @@ class ConstraintsPropagationTests { }) assertFailsWith { transaction { - attachment(noPropagationContractClassName, SecureHash.zeroHash) + attachment(noPropagationContractClassName, zeroHash) input("c1") output(noPropagationContractClassName, "c3", DUMMY_NOTARY, null, AutomaticPlaceholderConstraint, NoPropagationContractState()) command(ALICE_PUBKEY, NoPropagationContract.Create()) @@ -387,13 +402,13 @@ class ConstraintsPropagationTests { fun `Input state contract version may be incompatible with lower version`() { ledgerServices.ledger(DUMMY_NOTARY) { ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2")) + attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2")) output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() }) transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "1")) + attachment(Cash.PROGRAM_ID, zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "1")) input("c1") output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) @@ -406,13 +421,13 @@ class ConstraintsPropagationTests { fun `Input state contract version is compatible with the same version`() { ledgerServices.ledger(DUMMY_NOTARY) { ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "3")) + attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "3")) output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() }) transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "3")) + attachment(Cash.PROGRAM_ID, zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "3")) input("c1") output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) @@ -425,13 +440,13 @@ class ConstraintsPropagationTests { fun `Input state contract version is compatible with higher version`() { ledgerServices.ledger(DUMMY_NOTARY) { ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "1")) + attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "1")) output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() }) transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2")) + attachment(Cash.PROGRAM_ID, zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2")) input("c1") output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) @@ -444,13 +459,13 @@ class ConstraintsPropagationTests { fun `Input states contract version may be lower that current contract version`() { ledgerServices.ledger(DUMMY_NOTARY) { ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "1")) + attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "1")) output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() }) ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2")) + attachment(Cash.PROGRAM_ID, zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2")) output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() @@ -469,13 +484,13 @@ class ConstraintsPropagationTests { fun `Input state with contract version can be downgraded to no version`() { ledgerServices.ledger(DUMMY_NOTARY) { ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2")) + attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2")) output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() }) transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash, listOf(hashToSignatureConstraintsKey), emptyMap()) + attachment(Cash.PROGRAM_ID, zeroHash, listOf(hashToSignatureConstraintsKey), emptyMap()) input("c1") output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) @@ -488,13 +503,13 @@ class ConstraintsPropagationTests { fun `Input state without contract version is compatible with any version`() { ledgerServices.ledger(DUMMY_NOTARY) { ledgerServices.recordTransaction(transaction { - attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey), emptyMap()) + attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey), emptyMap()) output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Issue()) verifies() }) transaction { - attachment(Cash.PROGRAM_ID, SecureHash.zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2")) + attachment(Cash.PROGRAM_ID, zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2")) input("c1") output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY)) command(ALICE_PUBKEY, Cash.Commands.Move()) diff --git a/core-tests/src/test/kotlin/net/corda/coretests/contracts/ContractHierarchyTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/contracts/ContractHierarchyTest.kt index 0fbc6e8ae9..89ce133d27 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/contracts/ContractHierarchyTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/contracts/ContractHierarchyTest.kt @@ -107,4 +107,4 @@ class ContractHierarchyTest { subFlow(FinalityFlow(tx, otherSideSession)) } } -} \ No newline at end of file +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/contracts/ContractsDSLTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/contracts/ContractsDSLTests.kt index 4768cf9681..87c0998b97 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/contracts/ContractsDSLTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/contracts/ContractsDSLTests.kt @@ -1,11 +1,16 @@ package net.corda.coretests.contracts -import net.corda.core.contracts.* +import net.corda.core.contracts.CommandData +import net.corda.core.contracts.CommandWithParties +import net.corda.core.contracts.TypeOnlyCommandData +import net.corda.core.contracts.requireSingleCommand +import net.corda.core.contracts.select import net.corda.core.identity.AbstractParty import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.testing.core.TestIdentity -import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException +import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @@ -35,8 +40,8 @@ class RequireSingleCommandTests(private val testFunction: (Collection> = listOf( - arrayOf({ commands: Collection> -> commands.requireSingleCommand() }, "Inline version"), - arrayOf({ commands: Collection> -> commands.requireSingleCommand(TestCommands::class.java) }, "Interop version") + arrayOf({ commands: Collection> -> commands.requireSingleCommand() }, "Inline version"), + arrayOf({ commands: Collection> -> commands.requireSingleCommand(TestCommands::class.java) }, "Interop version") ) } @@ -47,16 +52,18 @@ class RequireSingleCommandTests(private val testFunction: (Collection> = listOf( - arrayOf({ commands: Collection>, signer: PublicKey?, party: AbstractParty? -> commands.select(signer, party) }, "Inline version"), - arrayOf({ commands: Collection>, signer: PublicKey?, party: AbstractParty? -> commands.select(TestCommands::class.java, signer, party) }, "Interop version") + arrayOf({ commands: Collection>, signer: PublicKey?, party: AbstractParty? -> commands.select(signer, party) }, "Inline version"), + arrayOf({ commands: Collection>, signer: PublicKey?, party: AbstractParty? -> commands.select(TestCommands::class.java, signer, party) }, "Interop version") ) } @@ -118,8 +125,8 @@ class SelectWithMultipleInputsTests(private val testFunction: (Collection> = listOf( - arrayOf({ commands: Collection>, signers: Collection?, party: Collection? -> commands.select(signers, party) }, "Inline version"), - arrayOf({ commands: Collection>, signers: Collection?, party: Collection? -> commands.select(TestCommands::class.java, signers, party) }, "Interop version") + arrayOf({ commands: Collection>, signers: Collection?, party: Collection? -> commands.select(signers, party) }, "Inline version"), + arrayOf({ commands: Collection>, signers: Collection?, party: Collection? -> commands.select(TestCommands::class.java, signers, party) }, "Interop version") ) } diff --git a/core-tests/src/test/kotlin/net/corda/coretests/contracts/PackageOwnershipVerificationTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/contracts/PackageOwnershipVerificationTests.kt index 76de8b33de..35ced6b2ad 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/contracts/PackageOwnershipVerificationTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/contracts/PackageOwnershipVerificationTests.kt @@ -1,8 +1,8 @@ package net.corda.coretests.contracts -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import net.corda.core.contracts.* import net.corda.core.crypto.Crypto import net.corda.core.crypto.SecureHash @@ -110,4 +110,4 @@ class DummyContract : Contract { } } -class DummyIssue : TypeOnlyCommandData() \ No newline at end of file +class DummyIssue : TypeOnlyCommandData() diff --git a/core-tests/src/test/kotlin/net/corda/coretests/crypto/CompositeKeyTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/crypto/CompositeKeyTests.kt index 613afca0b5..24ed2ba451 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/crypto/CompositeKeyTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/crypto/CompositeKeyTests.kt @@ -3,7 +3,6 @@ package net.corda.coretests.crypto import net.corda.core.crypto.* import net.corda.core.crypto.CompositeKey.NodeAndWeight import net.corda.core.internal.declaredField -import net.corda.core.internal.div import net.corda.core.serialization.serialize import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.toBase58String @@ -19,6 +18,7 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import java.security.PublicKey import javax.security.auth.x500.X500Principal +import kotlin.io.path.div import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertFalse @@ -295,21 +295,19 @@ class CompositeKeyTests { val keyPairK1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256) val keyPairR1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256) val keyPairEd = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512) - val keyPairSP = Crypto.generateKeyPair(Crypto.SPHINCS256_SHA256) val RSASignature = keyPairRSA.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairRSA.public).schemeNumberID))) val K1Signature = keyPairK1.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairK1.public).schemeNumberID))) val R1Signature = keyPairR1.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairR1.public).schemeNumberID))) val EdSignature = keyPairEd.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairEd.public).schemeNumberID))) - val SPSignature = keyPairSP.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairSP.public).schemeNumberID))) - val compositeKey = CompositeKey.Builder().addKeys(keyPairRSA.public, keyPairK1.public, keyPairR1.public, keyPairEd.public, keyPairSP.public).build() as CompositeKey + val compositeKey = CompositeKey.Builder().addKeys(keyPairRSA.public, keyPairK1.public, keyPairR1.public, keyPairEd.public).build() as CompositeKey - val signatures = listOf(RSASignature, K1Signature, R1Signature, EdSignature, SPSignature) + val signatures = listOf(RSASignature, K1Signature, R1Signature, EdSignature) assertTrue { compositeKey.isFulfilledBy(signatures.byKeys()) } // One signature is missing. - val signaturesWithoutRSA = listOf(K1Signature, R1Signature, EdSignature, SPSignature) + val signaturesWithoutRSA = listOf(K1Signature, R1Signature, EdSignature) assertFalse { compositeKey.isFulfilledBy(signaturesWithoutRSA.byKeys()) } } @@ -320,20 +318,18 @@ class CompositeKeyTests { val keyPairK1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256) val keyPairR1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256) val keyPairEd = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512) - val keyPairSP = Crypto.generateKeyPair(Crypto.SPHINCS256_SHA256) val RSASignature = keyPairRSA.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairRSA.public).schemeNumberID))) val K1Signature = keyPairK1.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairK1.public).schemeNumberID))) val R1Signature = keyPairR1.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairR1.public).schemeNumberID))) val EdSignature = keyPairEd.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairEd.public).schemeNumberID))) - val SPSignature = keyPairSP.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairSP.public).schemeNumberID))) - val compositeKey = CompositeKey.Builder().addKeys(keyPairRSA.public, keyPairK1.public, keyPairR1.public, keyPairEd.public, keyPairSP.public).build() as CompositeKey + val compositeKey = CompositeKey.Builder().addKeys(keyPairRSA.public, keyPairK1.public, keyPairR1.public, keyPairEd.public).build() as CompositeKey - val signatures = listOf(RSASignature, K1Signature, R1Signature, EdSignature, SPSignature) + val signatures = listOf(RSASignature, K1Signature, R1Signature, EdSignature) assertTrue { compositeKey.isFulfilledBy(signatures.byKeys()) } // One signature is missing. - val signaturesWithoutRSA = listOf(K1Signature, R1Signature, EdSignature, SPSignature) + val signaturesWithoutRSA = listOf(K1Signature, R1Signature, EdSignature) assertFalse { compositeKey.isFulfilledBy(signaturesWithoutRSA.byKeys()) } // Create self sign CA. @@ -374,13 +370,12 @@ class CompositeKeyTests { val (_, pub3) = Crypto.generateKeyPair(Crypto.RSA_SHA256) val (_, pub4) = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512) val (_, pub5) = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256) - val (_, pub6) = Crypto.generateKeyPair(Crypto.SPHINCS256_SHA256) - val (_, pub7) = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256) + val (_, pub6) = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256) // Using default weight = 1, thus all weights are equal. - val composite1 = CompositeKey.Builder().addKeys(pub1, pub2, pub3, pub4, pub5, pub6, pub7).build() as CompositeKey + val composite1 = CompositeKey.Builder().addKeys(pub1, pub2, pub3, pub4, pub5, pub6).build() as CompositeKey // Store in reverse order. - val composite2 = CompositeKey.Builder().addKeys(pub7, pub6, pub5, pub4, pub3, pub2, pub1).build() as CompositeKey + val composite2 = CompositeKey.Builder().addKeys(pub6, pub5, pub4, pub3, pub2, pub1).build() as CompositeKey // There are 7! = 5040 permutations, but as sorting is deterministic the following should never fail. assertEquals(composite1.children, composite2.children) } diff --git a/core-tests/src/test/kotlin/net/corda/coretests/crypto/PartialMerkleTreeTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/crypto/PartialMerkleTreeTest.kt index bb6c457ec2..212f7df992 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/crypto/PartialMerkleTreeTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/crypto/PartialMerkleTreeTest.kt @@ -1,11 +1,19 @@ package net.corda.coretests.crypto -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever -import net.corda.core.contracts.* -import net.corda.core.crypto.* +import net.corda.core.contracts.Command +import net.corda.core.contracts.PrivacySalt +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TimeWindow +import net.corda.core.contracts.TransactionState +import net.corda.core.crypto.DigestService +import net.corda.core.crypto.MerkleTree +import net.corda.core.crypto.MerkleTreeException +import net.corda.core.crypto.PartialMerkleTree +import net.corda.core.crypto.SecureHash import net.corda.core.crypto.internal.DigestAlgorithmFactory +import net.corda.core.crypto.keys +import net.corda.core.crypto.randomHash +import net.corda.core.crypto.sha256 import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.BLAKE2s256DigestAlgorithm @@ -16,9 +24,10 @@ import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize import net.corda.core.transactions.ReferenceStateRef import net.corda.core.transactions.WireTransaction +import net.corda.coretesting.internal.TEST_TX_TIME import net.corda.finance.DOLLARS -import net.corda.finance.`issued by` import net.corda.finance.contracts.asset.Cash +import net.corda.finance.`issued by` import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.SerializationEnvironmentRule @@ -26,20 +35,29 @@ import net.corda.testing.core.TestIdentity import net.corda.testing.dsl.LedgerDSL import net.corda.testing.dsl.TestLedgerDSLInterpreter import net.corda.testing.dsl.TestTransactionDSLInterpreter -import net.corda.coretesting.internal.TEST_TX_TIME import net.corda.testing.internal.createWireTransaction import net.corda.testing.node.MockServices import net.corda.testing.node.ledger +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import java.security.PublicKey import java.util.function.Predicate import java.util.stream.IntStream import kotlin.streams.toList -import kotlin.test.* +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertNotEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.assertTrue @RunWith(Parameterized::class) class PartialMerkleTreeTest(private var digestService: DigestService) { @@ -204,7 +222,7 @@ class PartialMerkleTreeTest(private var digestService: DigestService) { @Test(timeout=300_000) fun `nothing filtered`() { - val ftxNothing = testTx.buildFilteredTransaction(Predicate { false }) + val ftxNothing = testTx.buildFilteredTransaction { false } assertTrue(ftxNothing.componentGroups.isEmpty()) assertTrue(ftxNothing.attachments.isEmpty()) assertTrue(ftxNothing.commands.isEmpty()) @@ -291,10 +309,12 @@ class PartialMerkleTreeTest(private var digestService: DigestService) { assertFalse(pmt.verify(wrongRoot, inclHashes)) } - @Test(expected = Exception::class, timeout=300_000) + @Test(timeout=300_000) fun `hash map serialization not allowed`() { val hm1 = hashMapOf("a" to 1, "b" to 2, "c" to 3, "e" to 4) - hm1.serialize() + assertThatIllegalArgumentException().isThrownBy { + hm1.serialize() + } } private fun makeSimpleCashWtx( @@ -322,11 +342,11 @@ class PartialMerkleTreeTest(private var digestService: DigestService) { val merkleTree = MerkleTree.getMerkleTree(sampleLeaves, digestService) // Provided hashes are not in the tree. - assertFailsWith { PartialMerkleTree.build(merkleTree, listOf(digestService.hash("20"))) } + assertFailsWith { PartialMerkleTree.build(merkleTree, listOf(digestService.hash("20"))) } // One of the provided hashes is not in the tree. - assertFailsWith { PartialMerkleTree.build(merkleTree, listOf(digestService.hash("20"), digestService.hash("1"), digestService.hash("5"))) } + assertFailsWith { PartialMerkleTree.build(merkleTree, listOf(digestService.hash("20"), digestService.hash("1"), digestService.hash("5"))) } - val pmt = PartialMerkleTree.build(merkleTree, listOf(digestService.hash("1"), digestService.hash("5"), digestService.hash("0"), digestService.hash("19"))) + val pmt = PartialMerkleTree.build(merkleTree, listOf(digestService.hash("1"), digestService.hash("5"), digestService.hash("0"), digestService.hash("19"))) // First leaf. assertEquals(0, pmt.leafIndex(digestService.hash("0"))) // Second leaf. @@ -340,17 +360,17 @@ class PartialMerkleTreeTest(private var digestService: DigestService) { // The provided hash is not in the tree (using a leaf that didn't exist in the original Merkle tree). assertFailsWith { pmt.leafIndex(digestService.hash("30")) } - val pmtFirstElementOnly = PartialMerkleTree.build(merkleTree, listOf(digestService.hash("0"))) + val pmtFirstElementOnly = PartialMerkleTree.build(merkleTree, listOf(digestService.hash("0"))) assertEquals(0, pmtFirstElementOnly.leafIndex(digestService.hash("0"))) // The provided hash is not in the tree. assertFailsWith { pmtFirstElementOnly.leafIndex(digestService.hash("10")) } - val pmtLastElementOnly = PartialMerkleTree.build(merkleTree, listOf(digestService.hash("19"))) + val pmtLastElementOnly = PartialMerkleTree.build(merkleTree, listOf(digestService.hash("19"))) assertEquals(19, pmtLastElementOnly.leafIndex(digestService.hash("19"))) // The provided hash is not in the tree. assertFailsWith { pmtLastElementOnly.leafIndex(digestService.hash("10")) } - val pmtOneElement = PartialMerkleTree.build(merkleTree, listOf(digestService.hash("5"))) + val pmtOneElement = PartialMerkleTree.build(merkleTree, listOf(digestService.hash("5"))) assertEquals(5, pmtOneElement.leafIndex(digestService.hash("5"))) // The provided hash is not in the tree. assertFailsWith { pmtOneElement.leafIndex(digestService.hash("10")) } diff --git a/core-tests/src/test/kotlin/net/corda/coretests/crypto/PartialMerkleTreeWithNamedHashMultiAlgTreeTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/crypto/PartialMerkleTreeWithNamedHashMultiAlgTreeTest.kt index c131f2b0b1..0dac2b8eea 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/crypto/PartialMerkleTreeWithNamedHashMultiAlgTreeTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/crypto/PartialMerkleTreeWithNamedHashMultiAlgTreeTest.kt @@ -1,17 +1,14 @@ package net.corda.coretests.crypto -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.contracts.Command import net.corda.core.contracts.PrivacySalt import net.corda.core.contracts.StateRef import net.corda.core.contracts.TimeWindow import net.corda.core.contracts.TransactionState +import net.corda.core.crypto.DigestService import net.corda.core.crypto.MerkleTree import net.corda.core.crypto.MerkleTreeException import net.corda.core.crypto.PartialMerkleTree -import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash.Companion.SHA2_384 import net.corda.core.crypto.SecureHash.Companion.hashAs @@ -26,9 +23,10 @@ import net.corda.core.serialization.serialize import net.corda.core.transactions.ReferenceStateRef import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.OpaqueBytes +import net.corda.coretesting.internal.TEST_TX_TIME import net.corda.finance.DOLLARS -import net.corda.finance.`issued by` import net.corda.finance.contracts.asset.Cash +import net.corda.finance.`issued by` import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.SerializationEnvironmentRule @@ -36,10 +34,10 @@ import net.corda.testing.core.TestIdentity import net.corda.testing.dsl.LedgerDSL import net.corda.testing.dsl.TestLedgerDSLInterpreter import net.corda.testing.dsl.TestTransactionDSLInterpreter -import net.corda.coretesting.internal.TEST_TX_TIME import net.corda.testing.internal.createWireTransaction import net.corda.testing.node.MockServices import net.corda.testing.node.ledger +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException import org.junit.Assert.assertFalse import org.junit.Assert.assertNotEquals import org.junit.Assert.assertNotNull @@ -49,6 +47,9 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.jupiter.api.Assertions.assertEquals +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import java.security.PublicKey import java.util.function.Predicate import java.util.stream.IntStream @@ -209,7 +210,7 @@ class PartialMerkleTreeWithNamedHashMultiAlgTreeTest { @Test(timeout=300_000) fun `nothing filtered`() { - val ftxNothing = testTx.buildFilteredTransaction(Predicate { false }) + val ftxNothing = testTx.buildFilteredTransaction { false } assertTrue(ftxNothing.componentGroups.isEmpty()) assertTrue(ftxNothing.attachments.isEmpty()) assertTrue(ftxNothing.commands.isEmpty()) @@ -296,10 +297,12 @@ class PartialMerkleTreeWithNamedHashMultiAlgTreeTest { assertFalse(pmt.verify(wrongRoot, inclHashes)) } - @Test(expected = Exception::class, timeout=300_000) + @Test(timeout=300_000) fun `hash map serialization not allowed`() { val hm1 = hashMapOf("a" to 1, "b" to 2, "c" to 3, "e" to 4) - hm1.serialize() + assertThatIllegalArgumentException().isThrownBy { + hm1.serialize() + } } private fun makeSimpleCashWtx( @@ -381,4 +384,4 @@ class PartialMerkleTreeWithNamedHashMultiAlgTreeTest { assertEquals(1, ftx.references.size) ftx.verify() } -} \ No newline at end of file +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/crypto/PartialMerkleTreeWithNamedHashTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/crypto/PartialMerkleTreeWithNamedHashTest.kt index 77bb40f6b9..434f3db57e 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/crypto/PartialMerkleTreeWithNamedHashTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/crypto/PartialMerkleTreeWithNamedHashTest.kt @@ -1,17 +1,14 @@ package net.corda.coretests.crypto -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.contracts.Command import net.corda.core.contracts.PrivacySalt import net.corda.core.contracts.StateRef import net.corda.core.contracts.TimeWindow import net.corda.core.contracts.TransactionState +import net.corda.core.crypto.DigestService import net.corda.core.crypto.MerkleTree import net.corda.core.crypto.MerkleTreeException import net.corda.core.crypto.PartialMerkleTree -import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash.Companion.SHA2_384 import net.corda.core.crypto.SecureHash.Companion.hashAs @@ -26,9 +23,10 @@ import net.corda.core.serialization.serialize import net.corda.core.transactions.ReferenceStateRef import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.OpaqueBytes +import net.corda.coretesting.internal.TEST_TX_TIME import net.corda.finance.DOLLARS -import net.corda.finance.`issued by` import net.corda.finance.contracts.asset.Cash +import net.corda.finance.`issued by` import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.SerializationEnvironmentRule @@ -36,10 +34,10 @@ import net.corda.testing.core.TestIdentity import net.corda.testing.dsl.LedgerDSL import net.corda.testing.dsl.TestLedgerDSLInterpreter import net.corda.testing.dsl.TestTransactionDSLInterpreter -import net.corda.coretesting.internal.TEST_TX_TIME import net.corda.testing.internal.createWireTransaction import net.corda.testing.node.MockServices import net.corda.testing.node.ledger +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException import org.junit.Assert.assertFalse import org.junit.Assert.assertNotEquals import org.junit.Assert.assertNotNull @@ -49,6 +47,9 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.jupiter.api.Assertions.assertEquals +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import java.security.PublicKey import java.util.function.Predicate import java.util.stream.IntStream @@ -209,7 +210,7 @@ class PartialMerkleTreeWithNamedHashTest { @Test(timeout=300_000) fun `nothing filtered`() { - val ftxNothing = testTx.buildFilteredTransaction(Predicate { false }) + val ftxNothing = testTx.buildFilteredTransaction { false } assertTrue(ftxNothing.componentGroups.isEmpty()) assertTrue(ftxNothing.attachments.isEmpty()) assertTrue(ftxNothing.commands.isEmpty()) @@ -296,10 +297,12 @@ class PartialMerkleTreeWithNamedHashTest { assertFalse(pmt.verify(wrongRoot, inclHashes)) } - @Test(expected = Exception::class, timeout=300_000) + @Test(timeout=300_000) fun `hash map serialization not allowed`() { val hm1 = hashMapOf("a" to 1, "b" to 2, "c" to 3, "e" to 4) - hm1.serialize() + assertThatIllegalArgumentException().isThrownBy { + hm1.serialize() + } } private fun makeSimpleCashWtx( @@ -381,4 +384,4 @@ class PartialMerkleTreeWithNamedHashTest { assertEquals(1, ftx.references.size) ftx.verify() } -} \ No newline at end of file +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/crypto/SignedDataTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/crypto/SignedDataTest.kt index 1e0a0181ef..7e6ea4d74d 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/crypto/SignedDataTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/crypto/SignedDataTest.kt @@ -6,6 +6,7 @@ import net.corda.core.crypto.sign import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.serialize import net.corda.testing.core.SerializationEnvironmentRule +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Before import org.junit.Rule import org.junit.Test @@ -35,12 +36,14 @@ class SignedDataTest { assertEquals(data, unwrappedData) } - @Test(expected = SignatureException::class, timeout=300_000) + @Test(timeout=300_000) fun `make sure incorrectly signed data raises an exception`() { val keyPairA = generateKeyPair() val keyPairB = generateKeyPair() val sig = keyPairA.private.sign(serialized.bytes, keyPairB.public) val wrappedData = SignedData(serialized, sig) - wrappedData.verified() + assertThatExceptionOfType(SignatureException::class.java).isThrownBy { + wrappedData.verified() + } } } diff --git a/core-tests/src/test/kotlin/net/corda/coretests/crypto/TransactionSignatureTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/crypto/TransactionSignatureTest.kt index 734c0c0d10..22a007208e 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/crypto/TransactionSignatureTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/crypto/TransactionSignatureTest.kt @@ -1,7 +1,17 @@ package net.corda.coretests.crypto -import net.corda.core.crypto.* +import net.corda.core.crypto.Crypto +import net.corda.core.crypto.MerkleTree +import net.corda.core.crypto.MerkleTreeException +import net.corda.core.crypto.PartialMerkleTree +import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.SignableData +import net.corda.core.crypto.SignatureMetadata +import net.corda.core.crypto.TransactionSignature +import net.corda.core.crypto.sha256 +import net.corda.core.crypto.sign import net.corda.testing.core.SerializationEnvironmentRule +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Rule import org.junit.Test import java.math.BigInteger @@ -39,12 +49,14 @@ class TransactionSignatureTest { } /** Verification should fail; corrupted metadata - clearData (Merkle root) has changed. */ - @Test(expected = SignatureException::class,timeout=300_000) + @Test(timeout=300_000) fun `Signature metadata full failure clearData has changed`() { val keyPair = Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256") val signableData = SignableData(testBytes.sha256(), SignatureMetadata(1, Crypto.findSignatureScheme(keyPair.public).schemeNumberID)) val transactionSignature = keyPair.sign(signableData) - Crypto.doVerify((testBytes + testBytes).sha256(), transactionSignature) + assertThatExceptionOfType(SignatureException::class.java).isThrownBy { + Crypto.doVerify((testBytes + testBytes).sha256(), transactionSignature) + } } @Test(timeout=300_000) diff --git a/core-tests/src/test/kotlin/net/corda/coretests/flows/AbstractFlowExternalOperationTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/flows/AbstractFlowExternalOperationTest.kt index 559369c442..f313bab60f 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/flows/AbstractFlowExternalOperationTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/flows/AbstractFlowExternalOperationTest.kt @@ -1,6 +1,7 @@ package net.corda.coretests.flows import co.paralleluniverse.fibers.Suspendable +import co.paralleluniverse.strands.Strand import net.corda.core.CordaException import net.corda.core.flows.FlowExternalAsyncOperation import net.corda.core.flows.FlowExternalOperation @@ -133,7 +134,7 @@ abstract class AbstractFlowExternalOperationTest { fun createFuture(): CompletableFuture { return CompletableFuture.supplyAsync(Supplier { log.info("Starting sleep inside of future") - Thread.sleep(1000) + Strand.sleep(1000) log.info("Finished sleep inside of future") "Here is your return value" }, executorService) @@ -255,4 +256,4 @@ abstract class AbstractFlowExternalOperationTest { return function(serviceHub, deduplicationId) } } -} \ No newline at end of file +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/flows/CollectSignaturesFlowTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/flows/CollectSignaturesFlowTests.kt index f0287086c6..5556e5aa40 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/flows/CollectSignaturesFlowTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/flows/CollectSignaturesFlowTests.kt @@ -23,22 +23,22 @@ import net.corda.core.identity.groupAbstractPartyByWellKnownParty import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.getOrThrow +import net.corda.coretesting.internal.matchers.flow.willReturn +import net.corda.coretesting.internal.matchers.flow.willThrow import net.corda.testing.contracts.DummyContract import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.BOB_NAME import net.corda.testing.core.CHARLIE_NAME import net.corda.testing.core.TestIdentity import net.corda.testing.core.singleIdentity -import net.corda.coretesting.internal.matchers.flow.willReturn -import net.corda.coretesting.internal.matchers.flow.willThrow import net.corda.testing.node.MockServices import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.TestStartedNode import net.corda.testing.node.internal.enclosedCordapp -import org.hamcrest.CoreMatchers.`is` +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException import org.junit.AfterClass -import org.junit.Assert import org.junit.Test import java.security.PublicKey @@ -92,7 +92,7 @@ class CollectSignaturesFlowTests : WithContracts { mockNet.runNetwork() val stx = future.get() val missingSigners = stx.getMissingSigners() - Assert.assertThat(missingSigners, `is`(emptySet())) + assertThat(missingSigners).isEmpty() } @Test(timeout=300_000) @@ -122,10 +122,10 @@ class CollectSignaturesFlowTests : WithContracts { mockNet.runNetwork() val stx = future.get() val missingSigners = stx.getMissingSigners() - Assert.assertThat(missingSigners, `is`(emptySet())) + assertThat(missingSigners).isEmpty() } - @Test(expected = IllegalArgumentException::class, timeout=300_000) + @Test(timeout=300_000) fun `throws exception when extra sessions are initiated`() { bobNode.registerInitiatedFlow(ExtraSessionsFlowResponder::class.java) charlieNode.registerInitiatedFlow(ExtraSessionsFlowResponder::class.java) @@ -137,7 +137,9 @@ class CollectSignaturesFlowTests : WithContracts { listOf(bobNode.info.singleIdentity(), alice))) .resultFuture mockNet.runNetwork() - future.getOrThrow() + assertThatIllegalArgumentException().isThrownBy { + future.getOrThrow() + } } @Test(timeout=300_000) @@ -152,7 +154,7 @@ class CollectSignaturesFlowTests : WithContracts { listOf(bobNode.info.singleIdentity(), alice))).resultFuture mockNet.runNetwork() val signedTx = future.getOrThrow() - Assert.assertThat(signedTx.getMissingSigners(), `is`(emptySet())) + assertThat(signedTx.getMissingSigners()).isEmpty() } @Test(timeout=300_000) @@ -216,7 +218,7 @@ class CollectSignaturesFlowTests : WithContracts { } } - @InitiatedBy(TestFlow.Initiator::class) + @InitiatedBy(Initiator::class) class Responder(private val otherSideSession: FlowSession) : FlowLogic() { @Suspendable override fun call() { @@ -251,7 +253,7 @@ class AnonymousSessionTestFlow(private val cis: List) : Flo } } val state = DummyContract.MultiOwnerState(owners = cis.map { AnonymousParty(it.owningKey) }) - val create = net.corda.testing.contracts.DummyContract.Commands.Create() + val create = DummyContract.Commands.Create() val txBuilder = TransactionBuilder(notary = serviceHub.networkMapCache.notaryIdentities.first()) .addOutputState(state) .addCommand(create, cis.map { it.owningKey }) @@ -289,7 +291,7 @@ class MixAndMatchAnonymousSessionTestFlow(private val cis: List, private val involve: L val sessions = openFor.map { initiateFlow(it) } val state = DummyContract.MultiOwnerState(owners = involve.map { AnonymousParty(it.owningKey) }) - val create = net.corda.testing.contracts.DummyContract.Commands.Create() + val create = DummyContract.Commands.Create() val txBuilder = TransactionBuilder(notary = serviceHub.networkMapCache.notaryIdentities.first()) .addOutputState(state) .addCommand(create, involve.map { it.owningKey }) diff --git a/core-tests/src/test/kotlin/net/corda/coretests/flows/ContractUpgradeFlowRPCTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/flows/ContractUpgradeFlowRPCTest.kt index 01e9e81df7..70e0996a9d 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/flows/ContractUpgradeFlowRPCTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/flows/ContractUpgradeFlowRPCTest.kt @@ -9,6 +9,7 @@ import net.corda.core.CordaRuntimeException import net.corda.core.contracts.ContractState import net.corda.core.contracts.StateAndRef import net.corda.core.flows.ContractUpgradeFlow +import net.corda.core.internal.getRequiredTransaction import net.corda.core.messaging.CordaRPCOps import net.corda.core.transactions.ContractUpgradeLedgerTransaction import net.corda.core.transactions.SignedTransaction @@ -120,8 +121,7 @@ class ContractUpgradeFlowRPCTest : WithContracts, WithFinality { isUpgrade()) private fun TestStartedNode.getContractUpgradeTransaction(state: StateAndRef) = - services.validatedTransactions.getTransaction(state.ref.txhash)!! - .resolveContractUpgradeTransaction(services) + services.getRequiredTransaction(state.ref.txhash).resolveContractUpgradeTransaction(services) private inline fun isUpgrade() = isUpgradeFrom() and isUpgradeTo() diff --git a/core-tests/src/test/kotlin/net/corda/coretests/flows/ContractUpgradeFlowTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/flows/ContractUpgradeFlowTest.kt index e6994316a8..e7947144d6 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/flows/ContractUpgradeFlowTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/flows/ContractUpgradeFlowTest.kt @@ -1,31 +1,54 @@ package net.corda.coretests.flows -import com.natpryce.hamkrest.* +import com.natpryce.hamkrest.Matcher +import com.natpryce.hamkrest.and +import com.natpryce.hamkrest.anything import com.natpryce.hamkrest.assertion.assertThat -import net.corda.core.contracts.* +import com.natpryce.hamkrest.equalTo +import com.natpryce.hamkrest.has +import com.natpryce.hamkrest.isA +import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint +import net.corda.core.contracts.Amount +import net.corda.core.contracts.AttachmentConstraint +import net.corda.core.contracts.BelongsToContract +import net.corda.core.contracts.CommandAndState +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.FungibleAsset +import net.corda.core.contracts.Issued +import net.corda.core.contracts.StateAndRef +import net.corda.core.contracts.TypeOnlyCommandData +import net.corda.core.contracts.UpgradedContractWithLegacyConstraint import net.corda.core.flows.UnexpectedFlowEndException import net.corda.core.identity.AbstractParty import net.corda.core.internal.Emoji +import net.corda.core.internal.getRequiredTransaction +import net.corda.core.internal.mapToSet import net.corda.core.transactions.ContractUpgradeLedgerTransaction import net.corda.core.transactions.LedgerTransaction import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow +import net.corda.coretesting.internal.matchers.flow.willReturn +import net.corda.coretesting.internal.matchers.flow.willThrow import net.corda.finance.USD -import net.corda.finance.`issued by` import net.corda.finance.contracts.asset.Cash import net.corda.finance.flows.CashIssueFlow +import net.corda.finance.`issued by` import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContractV2 import net.corda.testing.contracts.DummyContractV3 import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.BOB_NAME import net.corda.testing.core.singleIdentity -import net.corda.coretesting.internal.matchers.flow.willReturn -import net.corda.coretesting.internal.matchers.flow.willThrow -import net.corda.testing.node.internal.* +import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP +import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP +import net.corda.testing.node.internal.FINANCE_WORKFLOWS_CORDAPP +import net.corda.testing.node.internal.InternalMockNetwork +import net.corda.testing.node.internal.TestStartedNode +import net.corda.testing.node.internal.enclosedCordapp +import net.corda.testing.node.internal.startFlow import org.junit.AfterClass import org.junit.Test -import java.util.* +import java.util.Currency class ContractUpgradeFlowTest : WithContracts, WithFinality { @@ -159,7 +182,7 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality { @BelongsToContract(CashV2::class) data class State(override val amount: Amount>, val owners: List) : FungibleAsset { override val owner: AbstractParty = owners.first() - override val exitKeys = (owners + amount.token.issuer.party).map { it.owningKey }.toSet() + override val exitKeys = (owners + amount.token.issuer.party).mapToSet { it.owningKey } override val participants = owners override fun withNewOwnerAndAmount(newAmount: Amount>, newOwner: AbstractParty) = copy(amount = amount.copy(newAmount.quantity), owners = listOf(newOwner)) @@ -180,8 +203,7 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality { isUpgrade()) private fun TestStartedNode.getContractUpgradeTransaction(state: StateAndRef) = - services.validatedTransactions.getTransaction(state.ref.txhash)!! - .resolveContractUpgradeTransaction(services) + services.getRequiredTransaction(state.ref.txhash).resolveContractUpgradeTransaction(services) private inline fun isUpgrade() = isUpgradeFrom() and isUpgradeTo() diff --git a/core-tests/src/test/kotlin/net/corda/coretests/flows/FastThreadLocalTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/flows/FastThreadLocalTest.kt index f029492750..7ae6e5d0e0 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/flows/FastThreadLocalTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/flows/FastThreadLocalTest.kt @@ -13,7 +13,7 @@ import net.corda.core.internal.rootCause import net.corda.core.utilities.getOrThrow import org.assertj.core.api.Assertions.catchThrowable import org.hamcrest.Matchers.lessThanOrEqualTo -import org.junit.Assert.assertThat +import org.hamcrest.MatcherAssert.assertThat import org.junit.Test import java.util.* import java.util.concurrent.ExecutorService @@ -85,7 +85,7 @@ class FastThreadLocalTest { } private class UnserializableObj { - @Suppress("unused") + @Suppress("unused", "IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION") private val fail: Nothing by lazy { throw UnsupportedOperationException("Nice try.") } } diff --git a/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalAsyncOperationTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalAsyncOperationTest.kt index 13767431a0..e847fd5788 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalAsyncOperationTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalAsyncOperationTest.kt @@ -15,6 +15,7 @@ import net.corda.testing.core.singleIdentity import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.driver import org.junit.Test +import java.io.Serializable import java.sql.SQLTransientConnectionException import java.util.concurrent.CompletableFuture import kotlin.test.assertFailsWith @@ -22,6 +23,8 @@ import kotlin.test.assertTrue class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() { + private fun interface SerializableLambda2 : (S, T) -> R, Serializable + @Test(timeout = 300_000) fun `external async operation`() { driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) { @@ -196,15 +199,15 @@ class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() { @StartableByRPC class FlowWithExternalAsyncOperationPropagatesException(party: Party, private val exceptionType: Class) : FlowWithExternalProcess(party) { - @Suspendable override fun testCode(): Any { val e = createException() - return await(ExternalAsyncOperation(serviceHub) { _, _ -> + + return await(ExternalAsyncOperation(serviceHub, (SerializableLambda2 { _, _ -> CompletableFuture().apply { completeExceptionally(e) } - }) + }))) } private fun createException() = when (exceptionType) { @@ -252,7 +255,6 @@ class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() { @StartableByRPC class FlowWithExternalAsyncOperationThatDirectlyAccessesServiceHubFailsRetry(party: Party) : FlowWithExternalProcess(party) { - @Suppress("TooGenericExceptionCaught") @Suspendable override fun testCode(): Any { return await(ExternalAsyncOperation(serviceHub) { _, _ -> @@ -287,4 +289,4 @@ class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() { serviceHub.cordaService(FutureService::class.java).startMultipleFuturesAndJoin() }.also { log.info("Result - $it") }) } -} \ No newline at end of file +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalOperationTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalOperationTest.kt index f7dea8bcda..24666b7609 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalOperationTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalOperationTest.kt @@ -21,12 +21,15 @@ import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.driver import net.corda.testing.node.internal.cordappsForPackages import org.junit.Test +import java.io.Serializable import java.sql.SQLTransientConnectionException import kotlin.test.assertFailsWith import kotlin.test.assertTrue class FlowExternalOperationTest : AbstractFlowExternalOperationTest() { + private fun interface SerializableLambda2 : (S, T) -> R, Serializable + @Test(timeout = 300_000) fun `external operation`() { driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) { @@ -254,7 +257,7 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() { @Suspendable override fun testCode() { val e = createException() - await(ExternalOperation(serviceHub) { _, _ -> throw e }) + await(ExternalOperation(serviceHub, (SerializableLambda2 { _, _ -> throw e }))) } private fun createException() = when (exceptionType) { @@ -270,7 +273,7 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() { @Suspendable override fun testCode(): Any = try { - await(ExternalOperation(serviceHub) { _, _ -> + await(ExternalOperation(serviceHub) { _, _ -> throw IllegalStateException("threw exception in background process") }) } catch (e: IllegalStateException) { @@ -284,7 +287,7 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() { @Suspendable override fun testCode(): Any = - await(ExternalOperation(serviceHub) { serviceHub, _ -> + await(ExternalOperation(serviceHub) { serviceHub, _ -> serviceHub.cordaService(FutureService::class.java).throwHospitalHandledException() }) } @@ -292,11 +295,10 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() { @StartableByRPC class FlowWithExternalOperationThatDirectlyAccessesServiceHubFailsRetry(party: Party) : FlowWithExternalProcess(party) { - @Suppress("TooGenericExceptionCaught") @Suspendable override fun testCode(): Any { try { - await(ExternalOperation(serviceHub) { _, _ -> + await(ExternalOperation(serviceHub) { _, _ -> serviceHub.cordaService(FutureService::class.java).throwHospitalHandledException() }) } catch (e: NullPointerException) { @@ -430,4 +432,4 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() { }) } } -} \ No newline at end of file +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowSleepTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowSleepTest.kt index 214d31dbd0..5fe6193f9e 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowSleepTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowSleepTest.kt @@ -79,7 +79,7 @@ class FlowSleepTest { @Suspendable override fun call(): Pair { val start = Instant.now() - sleep(5.seconds) + sleep(6.seconds) return start to Instant.now() } } @@ -90,9 +90,9 @@ class FlowSleepTest { @Suspendable override fun call(): Triple { val start = Instant.now() - sleep(5.seconds) + sleep(6.seconds) val middle = Instant.now() - sleep(10.seconds) + sleep(11.seconds) return Triple(start, middle, Instant.now()) } } @@ -143,4 +143,4 @@ class FlowSleepTest { session.send("I got you bro") } } -} \ No newline at end of file +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/flows/ReceiveAllFlowTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/flows/ReceiveAllFlowTests.kt index 8dff9e634b..7006a5e8a5 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/flows/ReceiveAllFlowTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/flows/ReceiveAllFlowTests.kt @@ -58,7 +58,7 @@ class ReceiveMultipleFlowTests : WithMockNet { assertEquals(message, receivedMessage) session.send(answer) } - } as FlowLogic + } } assertThat( @@ -139,4 +139,4 @@ private inline fun TestStartedNode.registerAnswer(kClass: KClass { return startFlow(WithFinality::FinalityInvoker, stx, recipients.toSet(), emptySet()).andRunNetwork() diff --git a/core-tests/src/test/kotlin/net/corda/coretests/internal/NetworkParametersResolutionTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/internal/NetworkParametersResolutionTest.kt index 544a597adb..f511c48734 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/internal/NetworkParametersResolutionTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/internal/NetworkParametersResolutionTest.kt @@ -226,4 +226,4 @@ class NetworkParametersResolutionTest { }.withMessageContaining("The network parameters epoch (${defaultParams.epoch}) of this transaction " + "is older than the epoch (${params2.epoch}) of input state: ${stx2.inputs.first()}") } -} \ No newline at end of file +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/internal/ResolveTransactionsFlowTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/internal/ResolveTransactionsFlowTest.kt index c6b9858914..c5652001d5 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/internal/ResolveTransactionsFlowTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/internal/ResolveTransactionsFlowTest.kt @@ -258,7 +258,7 @@ class ResolveTransactionsFlowTest { // Used for checking larger chains resolve correctly. Note that this takes a long time to run, and so is not suitable for a CI gate. @Test(timeout=300_000) -@Ignore + @Ignore fun `Can resolve large chain of transactions`() { val txToResolve = makeLargeTransactionChain(2500) val p = TestFlow(txToResolve, megaCorp) diff --git a/core-tests/src/test/kotlin/net/corda/coretests/internal/verification/AttachmentFixupsTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/internal/verification/AttachmentFixupsTest.kt new file mode 100644 index 0000000000..4102ba9bc3 --- /dev/null +++ b/core-tests/src/test/kotlin/net/corda/coretests/internal/verification/AttachmentFixupsTest.kt @@ -0,0 +1,135 @@ +package net.corda.coretests.internal.verification + +import net.corda.core.internal.verification.AttachmentFixups +import net.corda.core.node.services.AttachmentId +import net.corda.node.internal.cordapp.JarScanningCordappLoader +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import java.nio.file.Files +import java.nio.file.Path +import java.util.jar.JarOutputStream +import java.util.zip.Deflater +import java.util.zip.ZipEntry +import kotlin.io.path.outputStream +import kotlin.test.assertFailsWith + +class AttachmentFixupsTest { + companion object { + @JvmField + val ID1 = AttachmentId.randomSHA256() + @JvmField + val ID2 = AttachmentId.randomSHA256() + @JvmField + val ID3 = AttachmentId.randomSHA256() + @JvmField + val ID4 = AttachmentId.randomSHA256() + } + + @Test(timeout=300_000) + fun `test fixup rule that adds attachment`() { + val fixupJar = Files.createTempFile("fixup", ".jar") + .writeFixupRules("$ID1 => $ID2, $ID3") + val fixedIDs = with(newFixupService(fixupJar)) { + fixupAttachmentIds(listOf(ID1)) + } + assertThat(fixedIDs).containsExactly(ID2, ID3) + } + + @Test(timeout=300_000) + fun `test fixup rule that deletes attachment`() { + val fixupJar = Files.createTempFile("fixup", ".jar") + .writeFixupRules("$ID1 =>") + val fixedIDs = with(newFixupService(fixupJar)) { + fixupAttachmentIds(listOf(ID1)) + } + assertThat(fixedIDs).isEmpty() + } + + @Test(timeout=300_000) + fun `test fixup rule with blank LHS`() { + val fixupJar = Files.createTempFile("fixup", ".jar") + .writeFixupRules(" => $ID2") + val ex = assertFailsWith { + newFixupService(fixupJar) + } + assertThat(ex).hasMessageContaining( + "Forbidden empty list of source attachment IDs in '$fixupJar'" + ) + } + + @Test(timeout=300_000) + fun `test fixup rule without arrows`() { + val rule = " $ID1 " + val fixupJar = Files.createTempFile("fixup", ".jar") + .writeFixupRules(rule) + val ex = assertFailsWith { + newFixupService(fixupJar) + } + assertThat(ex).hasMessageContaining( + "Invalid fix-up line '${rule.trim()}' in '$fixupJar'" + ) + } + + @Test(timeout=300_000) + fun `test fixup rule with too many arrows`() { + val rule = " $ID1 => $ID2 => $ID3 " + val fixupJar = Files.createTempFile("fixup", ".jar") + .writeFixupRules(rule) + val ex = assertFailsWith { + newFixupService(fixupJar) + } + assertThat(ex).hasMessageContaining( + "Invalid fix-up line '${rule.trim()}' in '$fixupJar'" + ) + } + + @Test(timeout=300_000) + fun `test fixup file containing multiple rules and comments`() { + val fixupJar = Files.createTempFile("fixup", ".jar").writeFixupRules( + "# Whole line comment", + "\t$ID1,$ID2 => $ID2,, $ID3 # EOl comment", + " # Empty line with comment", + "", + "$ID3 => $ID4" + ) + val fixedIDs = with(newFixupService(fixupJar)) { + fixupAttachmentIds(listOf(ID2, ID1)) + } + assertThat(fixedIDs).containsExactlyInAnyOrder(ID2, ID4) + } + + private fun Path.writeFixupRules(vararg lines: String): Path { + JarOutputStream(outputStream()).use { jar -> + jar.setMethod(ZipEntry.DEFLATED) + jar.setLevel(Deflater.NO_COMPRESSION) + jar.putNextEntry(directoryEntry("META-INF")) + jar.putNextEntry(fileEntry("META-INF/Corda-Fixups")) + for (line in lines) { + jar.write(line.toByteArray()) + jar.write('\r'.code) + jar.write('\n'.code) + } + } + return this + } + + private fun directoryEntry(internalName: String): ZipEntry { + return ZipEntry("$internalName/").apply { + method = ZipEntry.STORED + compressedSize = 0 + size = 0 + crc = 0 + } + } + + private fun fileEntry(internalName: String): ZipEntry { + return ZipEntry(internalName).apply { + method = ZipEntry.DEFLATED + } + } + + private fun newFixupService(vararg paths: Path): AttachmentFixups { + val loader = JarScanningCordappLoader(paths.toSet()) + return AttachmentFixups().apply { load(loader.appClassLoader) } + } +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/node/NetworkParametersTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/node/NetworkParametersTest.kt index aabda7d94d..c5287eb042 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/node/NetworkParametersTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/node/NetworkParametersTest.kt @@ -1,7 +1,7 @@ package net.corda.coretests.node -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import net.corda.core.crypto.generateKeyPair import net.corda.core.internal.getPackageOwnerOf import net.corda.core.node.NetworkParameters diff --git a/core-tests/src/test/kotlin/net/corda/coretests/node/VaultUpdateTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/node/VaultUpdateTests.kt index 3bf7e3835f..5d6410d8bb 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/node/VaultUpdateTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/node/VaultUpdateTests.kt @@ -15,7 +15,7 @@ class VaultUpdateTests { private companion object { const val DUMMY_PROGRAM_ID = "net.corda.coretests.node.VaultUpdateTests\$DummyContract" val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party - val emptyUpdate = Vault.Update(emptySet(), emptySet(), type = Vault.UpdateType.GENERAL, references = emptySet()) + val emptyUpdate = Vault.Update(emptySet>(), emptySet(), type = Vault.UpdateType.GENERAL, references = emptySet()) } object DummyContract : Contract { diff --git a/core-tests/src/test/kotlin/net/corda/coretests/serialization/AttachmentSerializationTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/serialization/AttachmentSerializationTest.kt index 1fed709a98..b1735fdf8e 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/serialization/AttachmentSerializationTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/serialization/AttachmentSerializationTest.kt @@ -116,6 +116,7 @@ class AttachmentSerializationTest { private class CustomAttachment(override val id: SecureHash, internal val customContent: String) : Attachment { override fun open() = throw UnsupportedOperationException("Not implemented.") override val signerKeys get() = throw UnsupportedOperationException() + @Suppress("OVERRIDE_DEPRECATION") override val signers: List get() = throw UnsupportedOperationException() override val size get() = throw UnsupportedOperationException() } diff --git a/core-tests/src/test/kotlin/net/corda/coretests/serialization/TransactionSerializationTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/serialization/TransactionSerializationTests.kt index 2a37727aa4..61228efec1 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/serialization/TransactionSerializationTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/serialization/TransactionSerializationTests.kt @@ -1,6 +1,6 @@ package net.corda.coretests.serialization -import com.nhaarman.mockito_kotlin.mock +import org.mockito.kotlin.mock import net.corda.core.contracts.* import net.corda.core.crypto.Crypto import net.corda.core.crypto.SignatureMetadata diff --git a/core-tests/src/test/kotlin/net/corda/coretests/transactions/AttachmentsClassLoaderSerializationTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/transactions/AttachmentsClassLoaderSerializationTests.kt index 63f5461e46..ce8b6571b9 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/transactions/AttachmentsClassLoaderSerializationTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/transactions/AttachmentsClassLoaderSerializationTests.kt @@ -11,13 +11,13 @@ import net.corda.core.utilities.ByteSequence import net.corda.core.utilities.OpaqueBytes import net.corda.isolated.contracts.DummyContractBackdoor import net.corda.node.services.attachments.NodeAttachmentTrustCalculator +import net.corda.node.services.persistence.toInternal import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.TestIdentity import net.corda.testing.internal.TestingNamedCacheFactory import net.corda.testing.internal.fakeAttachment -import net.corda.testing.internal.services.InternalMockAttachmentStorage import net.corda.testing.services.MockAttachmentStorage import org.apache.commons.io.IOUtils import org.junit.Assert.assertEquals @@ -30,7 +30,7 @@ import kotlin.test.assertFailsWith class AttachmentsClassLoaderSerializationTests { companion object { - val ISOLATED_CONTRACTS_JAR_PATH: URL = AttachmentsClassLoaderSerializationTests::class.java.getResource("/isolated.jar") + val ISOLATED_CONTRACTS_JAR_PATH: URL = AttachmentsClassLoaderSerializationTests::class.java.getResource("/isolated.jar")!! private const val ISOLATED_CONTRACT_CLASS_NAME = "net.corda.isolated.contracts.AnotherDummyContract" } @@ -38,20 +38,19 @@ class AttachmentsClassLoaderSerializationTests { @JvmField val testSerialization = SerializationEnvironmentRule() - private val storage = InternalMockAttachmentStorage(MockAttachmentStorage()) + private val storage = MockAttachmentStorage().toInternal() private val attachmentTrustCalculator = NodeAttachmentTrustCalculator(storage, TestingNamedCacheFactory()) @Test(timeout=300_000) fun `Can serialize and deserialize with an attachment classloader`() { - - val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party - val MEGA_CORP = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")).party + val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20).party + val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")).party val isolatedId = storage.importAttachment(ISOLATED_CONTRACTS_JAR_PATH.openStream(), "app", "isolated.jar") val att1 = storage.importAttachment(fakeAttachment("file1.txt", "some data").inputStream(), "app", "file1.jar") val att2 = storage.importAttachment(fakeAttachment("file2.txt", "some other data").inputStream(), "app", "file2.jar") - val serialisedState = AttachmentsClassLoaderBuilder.withAttachmentsClassloaderContext( + val serialisedState = AttachmentsClassLoaderBuilder.withAttachmentsClassLoaderContext( arrayOf(isolatedId, att1, att2).map { storage.openAttachment(it)!! }, testNetworkParameters(), SecureHash.zeroHash, @@ -64,7 +63,7 @@ class AttachmentsClassLoaderSerializationTests { val txt = IOUtils.toString(classLoader.getResourceAsStream("file1.txt"), Charsets.UTF_8.name()) assertEquals("some data", txt) - val state = (contract as DummyContractBackdoor).generateInitial(MEGA_CORP.ref(1), 1, DUMMY_NOTARY).outputStates().first() + val state = (contract as DummyContractBackdoor).generateInitial(megaCorp.ref(1), 1, dummyNotary).outputStates().first() val serialisedState = state.serialize() val state1 = serialisedState.deserialize() diff --git a/core-tests/src/test/kotlin/net/corda/coretests/transactions/AttachmentsClassLoaderTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/transactions/AttachmentsClassLoaderTests.kt index e0f3778418..8c60b950be 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/transactions/AttachmentsClassLoaderTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/transactions/AttachmentsClassLoaderTests.kt @@ -19,13 +19,13 @@ import net.corda.core.internal.AttachmentTrustCalculator import net.corda.core.internal.createLedgerTransaction import net.corda.core.internal.declaredField import net.corda.core.internal.hash -import net.corda.core.internal.inputStream import net.corda.core.node.NetworkParameters import net.corda.core.node.services.AttachmentId import net.corda.core.serialization.internal.AttachmentsClassLoader import net.corda.core.serialization.internal.AttachmentsClassLoaderCacheImpl import net.corda.core.transactions.LedgerTransaction import net.corda.node.services.attachments.NodeAttachmentTrustCalculator +import net.corda.node.services.persistence.toInternal import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.contracts.DummyContract import net.corda.testing.core.ALICE_NAME @@ -37,14 +37,12 @@ import net.corda.testing.core.internal.ContractJarTestUtils import net.corda.testing.core.internal.ContractJarTestUtils.signContractJar import net.corda.testing.internal.TestingNamedCacheFactory import net.corda.testing.internal.fakeAttachment -import net.corda.testing.internal.services.InternalMockAttachmentStorage import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP import net.corda.testing.services.MockAttachmentStorage import org.apache.commons.io.IOUtils import org.assertj.core.api.Assertions.assertThat import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertEquals -import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule @@ -55,14 +53,16 @@ import java.io.InputStream import java.net.URL import java.nio.file.Path import java.security.PublicKey +import kotlin.io.path.inputStream +import kotlin.io.path.readBytes import kotlin.test.assertFailsWith import kotlin.test.fail class AttachmentsClassLoaderTests { companion object { // TODO Update this test to use the new isolated.jar - val ISOLATED_CONTRACTS_JAR_PATH: URL = AttachmentsClassLoaderTests::class.java.getResource("old-isolated.jar") - val ISOLATED_CONTRACTS_JAR_PATH_V4: URL = AttachmentsClassLoaderTests::class.java.getResource("isolated-4.0.jar") + val ISOLATED_CONTRACTS_JAR_PATH: URL = AttachmentsClassLoaderTests::class.java.getResource("old-isolated.jar")!! + val ISOLATED_CONTRACTS_JAR_PATH_V4: URL = AttachmentsClassLoaderTests::class.java.getResource("isolated-4.0.jar")!! private const val ISOLATED_CONTRACT_CLASS_NAME = "net.corda.finance.contracts.isolated.AnotherDummyContract" private fun readAttachment(attachment: Attachment, filepath: String): ByteArray { @@ -87,7 +87,6 @@ class AttachmentsClassLoaderTests { val testSerialization = SerializationEnvironmentRule() private lateinit var storage: MockAttachmentStorage - private lateinit var internalStorage: InternalMockAttachmentStorage private lateinit var attachmentTrustCalculator: AttachmentTrustCalculator private val networkParameters = testNetworkParameters() private val cacheFactory = TestingNamedCacheFactory(1) @@ -114,8 +113,7 @@ class AttachmentsClassLoaderTests { @Before fun setup() { storage = MockAttachmentStorage() - internalStorage = InternalMockAttachmentStorage(storage) - attachmentTrustCalculator = NodeAttachmentTrustCalculator(internalStorage, cacheFactory) + attachmentTrustCalculator = NodeAttachmentTrustCalculator(storage.toInternal(), cacheFactory) } @Test(timeout=300_000) @@ -128,8 +126,6 @@ class AttachmentsClassLoaderTests { @Test(timeout=300_000) fun `test contracts have no permissions for protection domain`() { val isolatedId = importAttachment(ISOLATED_CONTRACTS_JAR_PATH.openStream(), "app", "isolated.jar") - assertNull(System.getSecurityManager()) - createClassloader(isolatedId).use { classLoader -> val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, classLoader) val protectionDomain = contractClass.protectionDomain ?: fail("Protection Domain missing") @@ -451,7 +447,7 @@ class AttachmentsClassLoaderTests { val keyPairB = Crypto.generateKeyPair() attachmentTrustCalculator = NodeAttachmentTrustCalculator( - InternalMockAttachmentStorage(storage), + storage.toInternal(), cacheFactory, blacklistedAttachmentSigningKeys = listOf(keyPairA.public.hash) ) @@ -488,7 +484,7 @@ class AttachmentsClassLoaderTests { val keyPairA = Crypto.generateKeyPair() attachmentTrustCalculator = NodeAttachmentTrustCalculator( - InternalMockAttachmentStorage(storage), + storage.toInternal(), cacheFactory, blacklistedAttachmentSigningKeys = listOf(keyPairA.public.hash) ) @@ -614,7 +610,7 @@ class AttachmentsClassLoaderTests { private fun createAttachments(contractJarPath: Path) : List { - val attachment = object : AbstractAttachment({contractJarPath.inputStream().readBytes()}, uploader = "app") { + val attachment = object : AbstractAttachment(contractJarPath::readBytes, uploader = "app") { @Suppress("OverridingDeprecatedMember") @Deprecated("Use signerKeys. There is no requirement that attachment signers are Corda parties.") override val signers: List = emptyList() diff --git a/core-tests/src/test/kotlin/net/corda/coretests/transactions/CompatibleTransactionTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/transactions/CompatibleTransactionTests.kt index 10ea1e949c..7fc2ad4f1c 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/transactions/CompatibleTransactionTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/transactions/CompatibleTransactionTests.kt @@ -1,23 +1,56 @@ package net.corda.coretests.transactions -import net.corda.core.contracts.* -import net.corda.core.contracts.ComponentGroupEnum.* -import net.corda.core.crypto.* +import net.corda.core.contracts.Command +import net.corda.core.contracts.ComponentGroupEnum +import net.corda.core.contracts.ComponentGroupEnum.ATTACHMENTS_V2_GROUP +import net.corda.core.contracts.ComponentGroupEnum.COMMANDS_GROUP +import net.corda.core.contracts.ComponentGroupEnum.INPUTS_GROUP +import net.corda.core.contracts.ComponentGroupEnum.NOTARY_GROUP +import net.corda.core.contracts.ComponentGroupEnum.OUTPUTS_GROUP +import net.corda.core.contracts.ComponentGroupEnum.PARAMETERS_GROUP +import net.corda.core.contracts.ComponentGroupEnum.SIGNERS_GROUP +import net.corda.core.contracts.ComponentGroupEnum.TIMEWINDOW_GROUP +import net.corda.core.contracts.PrivacySalt +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TimeWindow +import net.corda.core.contracts.TransactionState +import net.corda.core.crypto.DigestService +import net.corda.core.crypto.MerkleTree +import net.corda.core.crypto.PartialMerkleTree +import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.generateKeyPair +import net.corda.core.crypto.secureRandomBytes import net.corda.core.internal.accessAvailableComponentHashes import net.corda.core.internal.accessGroupHashes import net.corda.core.internal.accessGroupMerkleRoots import net.corda.core.internal.createComponentGroups +import net.corda.core.internal.getRequiredGroup import net.corda.core.serialization.serialize -import net.corda.core.transactions.* +import net.corda.core.transactions.ComponentGroup +import net.corda.core.transactions.ComponentVisibilityException +import net.corda.core.transactions.FilteredComponentGroup +import net.corda.core.transactions.FilteredTransaction +import net.corda.core.transactions.FilteredTransactionVerificationException +import net.corda.core.transactions.NetworkParametersHash +import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.OpaqueBytes import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyState -import net.corda.testing.core.* +import net.corda.testing.core.BOB_NAME +import net.corda.testing.core.DUMMY_NOTARY_NAME +import net.corda.testing.core.SerializationEnvironmentRule +import net.corda.testing.core.TestIdentity +import net.corda.testing.core.dummyCommand import org.junit.Rule import org.junit.Test import java.time.Instant import java.util.function.Predicate -import kotlin.test.* +import kotlin.test.assertEquals +import kotlin.test.assertFails +import kotlin.test.assertFailsWith +import kotlin.test.assertNotEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull class CompatibleTransactionTests { private companion object { @@ -47,7 +80,7 @@ class CompatibleTransactionTests { private val inputGroup by lazy { ComponentGroup(INPUTS_GROUP.ordinal, inputs.map { it.serialize() }) } private val outputGroup by lazy { ComponentGroup(OUTPUTS_GROUP.ordinal, outputs.map { it.serialize() }) } private val commandGroup by lazy { ComponentGroup(COMMANDS_GROUP.ordinal, commands.map { it.value.serialize() }) } - private val attachmentGroup by lazy { ComponentGroup(ATTACHMENTS_GROUP.ordinal, attachments.map { it.serialize() }) } // The list is empty. + private val attachmentGroup by lazy { ComponentGroup(ATTACHMENTS_V2_GROUP.ordinal, attachments.map { it.serialize() }) } // The list is empty. private val notaryGroup by lazy { ComponentGroup(NOTARY_GROUP.ordinal, listOf(notary.serialize())) } private val timeWindowGroup by lazy { ComponentGroup(TIMEWINDOW_GROUP.ordinal, listOf(timeWindow.serialize())) } private val signersGroup by lazy { ComponentGroup(SIGNERS_GROUP.ordinal, commands.map { it.signers.serialize() }) } @@ -96,7 +129,7 @@ class CompatibleTransactionTests { // Ordering inside a component group matters. val inputsShuffled = listOf(stateRef2, stateRef1, stateRef3) - val inputShuffledGroup = ComponentGroup(INPUTS_GROUP.ordinal, inputsShuffled.map { it -> it.serialize() }) + val inputShuffledGroup = ComponentGroup(INPUTS_GROUP.ordinal, inputsShuffled.map { it.serialize() }) val componentGroupsB = listOf( inputShuffledGroup, outputGroup, @@ -114,8 +147,8 @@ class CompatibleTransactionTests { // But outputs group Merkle leaf (and the rest) remained the same. assertEquals(wireTransactionA.accessGroupMerkleRoots()[OUTPUTS_GROUP.ordinal], wireTransaction1ShuffledInputs.accessGroupMerkleRoots()[OUTPUTS_GROUP.ordinal]) assertEquals(wireTransactionA.accessGroupMerkleRoots()[NOTARY_GROUP.ordinal], wireTransaction1ShuffledInputs.accessGroupMerkleRoots()[NOTARY_GROUP.ordinal]) - assertNull(wireTransactionA.accessGroupMerkleRoots()[ATTACHMENTS_GROUP.ordinal]) - assertNull(wireTransaction1ShuffledInputs.accessGroupMerkleRoots()[ATTACHMENTS_GROUP.ordinal]) + assertNull(wireTransactionA.accessGroupMerkleRoots()[ATTACHMENTS_V2_GROUP.ordinal]) + assertNull(wireTransaction1ShuffledInputs.accessGroupMerkleRoots()[ATTACHMENTS_V2_GROUP.ordinal]) // Group leaves (components) ordering does not affect the id. In this case, we added outputs group before inputs. val shuffledComponentGroupsA = listOf( @@ -140,7 +173,7 @@ class CompatibleTransactionTests { inputGroup, outputGroup, commandGroup, - ComponentGroup(ATTACHMENTS_GROUP.ordinal, inputGroup.components), + ComponentGroup(ATTACHMENTS_V2_GROUP.ordinal, inputGroup.components), notaryGroup, timeWindowGroup, signersGroup @@ -201,23 +234,16 @@ class CompatibleTransactionTests { @Test(timeout=300_000) fun `FilteredTransaction constructors and compatibility`() { // Filter out all of the components. - val ftxNothing = wireTransactionA.buildFilteredTransaction(Predicate { false }) // Nothing filtered. + val ftxNothing = wireTransactionA.buildFilteredTransaction { false } // Nothing filtered. // Although nothing filtered, we still receive the group hashes for the top level Merkle tree. // Note that attachments are not sent, but group hashes include the allOnesHash flag for the attachment group hash; that's why we expect +1 group hashes. assertEquals(wireTransactionA.componentGroups.size + 1, ftxNothing.groupHashes.size) ftxNothing.verify() // Include all of the components. - val ftxAll = wireTransactionA.buildFilteredTransaction(Predicate { true }) // All filtered. + val ftxAll = wireTransactionA.buildFilteredTransaction { true } // All filtered. ftxAll.verify() - ftxAll.checkAllComponentsVisible(INPUTS_GROUP) - ftxAll.checkAllComponentsVisible(OUTPUTS_GROUP) - ftxAll.checkAllComponentsVisible(COMMANDS_GROUP) - ftxAll.checkAllComponentsVisible(ATTACHMENTS_GROUP) - ftxAll.checkAllComponentsVisible(NOTARY_GROUP) - ftxAll.checkAllComponentsVisible(TIMEWINDOW_GROUP) - ftxAll.checkAllComponentsVisible(SIGNERS_GROUP) - ftxAll.checkAllComponentsVisible(PARAMETERS_GROUP) + ComponentGroupEnum.entries.forEach(ftxAll::checkAllComponentsVisible) // Filter inputs only. fun filtering(elem: Any): Boolean { @@ -232,9 +258,9 @@ class CompatibleTransactionTests { ftxInputs.checkAllComponentsVisible(INPUTS_GROUP) assertEquals(1, ftxInputs.filteredComponentGroups.size) // We only add component groups that are not empty, thus in this case: the inputs only. - assertEquals(3, ftxInputs.filteredComponentGroups.firstOrNull { it.groupIndex == INPUTS_GROUP.ordinal }!!.components.size) // All 3 inputs are present. - assertEquals(3, ftxInputs.filteredComponentGroups.firstOrNull { it.groupIndex == INPUTS_GROUP.ordinal }!!.nonces.size) // And their corresponding nonces. - assertNotNull(ftxInputs.filteredComponentGroups.firstOrNull { it.groupIndex == INPUTS_GROUP.ordinal }!!.partialMerkleTree) // And the Merkle tree. + assertEquals(3, ftxInputs.filteredComponentGroups.getRequiredGroup(INPUTS_GROUP).components.size) // All 3 inputs are present. + assertEquals(3, ftxInputs.filteredComponentGroups.getRequiredGroup(INPUTS_GROUP).nonces.size) // And their corresponding nonces. + assertNotNull(ftxInputs.filteredComponentGroups.getRequiredGroup(INPUTS_GROUP).partialMerkleTree) // And the Merkle tree. // Filter one input only. fun filteringOneInput(elem: Any) = elem == inputs[0] @@ -244,9 +270,9 @@ class CompatibleTransactionTests { assertFailsWith { ftxOneInput.checkAllComponentsVisible(INPUTS_GROUP) } assertEquals(1, ftxOneInput.filteredComponentGroups.size) // We only add component groups that are not empty, thus in this case: the inputs only. - assertEquals(1, ftxOneInput.filteredComponentGroups.firstOrNull { it.groupIndex == INPUTS_GROUP.ordinal }!!.components.size) // 1 input is present. - assertEquals(1, ftxOneInput.filteredComponentGroups.firstOrNull { it.groupIndex == INPUTS_GROUP.ordinal }!!.nonces.size) // And its corresponding nonce. - assertNotNull(ftxOneInput.filteredComponentGroups.firstOrNull { it.groupIndex == INPUTS_GROUP.ordinal }!!.partialMerkleTree) // And the Merkle tree. + assertEquals(1, ftxOneInput.filteredComponentGroups.getRequiredGroup(INPUTS_GROUP).components.size) // 1 input is present. + assertEquals(1, ftxOneInput.filteredComponentGroups.getRequiredGroup(INPUTS_GROUP).nonces.size) // And its corresponding nonce. + assertNotNull(ftxOneInput.filteredComponentGroups.getRequiredGroup(INPUTS_GROUP).partialMerkleTree) // And the Merkle tree. // The old client (receiving more component types than expected) is still compatible. val componentGroupsCompatibleA = listOf( @@ -265,14 +291,14 @@ class CompatibleTransactionTests { assertEquals(wireTransactionCompatibleA.id, ftxCompatible.id) assertEquals(1, ftxCompatible.filteredComponentGroups.size) - assertEquals(3, ftxCompatible.filteredComponentGroups.firstOrNull { it.groupIndex == INPUTS_GROUP.ordinal }!!.components.size) - assertEquals(3, ftxCompatible.filteredComponentGroups.firstOrNull { it.groupIndex == INPUTS_GROUP.ordinal }!!.nonces.size) - assertNotNull(ftxCompatible.filteredComponentGroups.firstOrNull { it.groupIndex == INPUTS_GROUP.ordinal }!!.partialMerkleTree) + assertEquals(3, ftxCompatible.filteredComponentGroups.getRequiredGroup(INPUTS_GROUP).components.size) + assertEquals(3, ftxCompatible.filteredComponentGroups.getRequiredGroup(INPUTS_GROUP).nonces.size) + assertNotNull(ftxCompatible.filteredComponentGroups.getRequiredGroup(INPUTS_GROUP).partialMerkleTree) assertNull(wireTransactionCompatibleA.networkParametersHash) assertNull(ftxCompatible.networkParametersHash) // Now, let's allow everything, including the new component type that we cannot process. - val ftxCompatibleAll = wireTransactionCompatibleA.buildFilteredTransaction(Predicate { true }) // All filtered, including the unknown component. + val ftxCompatibleAll = wireTransactionCompatibleA.buildFilteredTransaction { true } // All filtered, including the unknown component. ftxCompatibleAll.verify() assertEquals(wireTransactionCompatibleA.id, ftxCompatibleAll.id) @@ -292,7 +318,7 @@ class CompatibleTransactionTests { ftxCompatibleNoInputs.verify() assertFailsWith { ftxCompatibleNoInputs.checkAllComponentsVisible(INPUTS_GROUP) } assertEquals(wireTransactionCompatibleA.componentGroups.size - 1, ftxCompatibleNoInputs.filteredComponentGroups.size) - assertEquals(wireTransactionCompatibleA.componentGroups.map { it.groupIndex }.max()!!, ftxCompatibleNoInputs.groupHashes.size - 1) + assertEquals(wireTransactionCompatibleA.componentGroups.maxOfOrNull { it.groupIndex }, ftxCompatibleNoInputs.groupHashes.size - 1) } @Test(timeout=300_000) @@ -451,7 +477,7 @@ class CompatibleTransactionTests { val key2CommandsFtx = wtx.buildFilteredTransaction(Predicate(::filterKEY2Commands)) // val commandDataComponents = key1CommandsFtx.filteredComponentGroups[0].components - val commandDataHashes = wtx.accessAvailableComponentHashes()[ComponentGroupEnum.COMMANDS_GROUP.ordinal]!! + val commandDataHashes = wtx.accessAvailableComponentHashes()[COMMANDS_GROUP.ordinal]!! val noLastCommandDataPMT = PartialMerkleTree.build( MerkleTree.getMerkleTree(commandDataHashes, wtx.digestService), commandDataHashes.subList(0, 1) @@ -466,7 +492,7 @@ class CompatibleTransactionTests { ) val signerComponents = key1CommandsFtx.filteredComponentGroups[1].components - val signerHashes = wtx.accessAvailableComponentHashes()[ComponentGroupEnum.SIGNERS_GROUP.ordinal]!! + val signerHashes = wtx.accessAvailableComponentHashes()[SIGNERS_GROUP.ordinal]!! val noLastSignerPMT = PartialMerkleTree.build( MerkleTree.getMerkleTree(signerHashes, wtx.digestService), signerHashes.subList(0, 2) @@ -527,7 +553,7 @@ class CompatibleTransactionTests { // Modify last signer (we have a pointer from commandData). // Update partial Merkle tree for signers. val alterSignerComponents = signerComponents.subList(0, 2) + signerComponents[1] // Third one is removed and the 2nd command is added twice. - val alterSignersHashes = wtx.accessAvailableComponentHashes()[ComponentGroupEnum.SIGNERS_GROUP.ordinal]!!.subList(0, 2) + wtx.digestService.componentHash(key1CommandsFtx.filteredComponentGroups[1].nonces[2], alterSignerComponents[2]) + val alterSignersHashes = wtx.accessAvailableComponentHashes()[SIGNERS_GROUP.ordinal]!!.subList(0, 2) + wtx.digestService.componentHash(key1CommandsFtx.filteredComponentGroups[1].nonces[2], alterSignerComponents[2]) val alterMTree = MerkleTree.getMerkleTree(alterSignersHashes, wtx.digestService) val alterSignerPMTK = PartialMerkleTree.build( alterMTree, @@ -561,7 +587,7 @@ class CompatibleTransactionTests { fun `parameters hash visibility`() { fun paramsFilter(elem: Any): Boolean = elem is NetworkParametersHash && elem.hash == paramsHash fun attachmentFilter(elem: Any): Boolean = elem is SecureHash && elem == paramsHash - val attachments = ComponentGroup(ATTACHMENTS_GROUP.ordinal, listOf(paramsHash.serialize())) // Same hash as network parameters + val attachments = ComponentGroup(ATTACHMENTS_V2_GROUP.ordinal, listOf(paramsHash.serialize())) // Same hash as network parameters val componentGroups = listOf( inputGroup, outputGroup, @@ -577,12 +603,12 @@ class CompatibleTransactionTests { ftx1.verify() assertEquals(wtx.id, ftx1.id) ftx1.checkAllComponentsVisible(PARAMETERS_GROUP) - assertFailsWith { ftx1.checkAllComponentsVisible(ATTACHMENTS_GROUP) } + assertFailsWith { ftx1.checkAllComponentsVisible(ATTACHMENTS_V2_GROUP) } // Filter only attachment. val ftx2 = wtx.buildFilteredTransaction(Predicate(::attachmentFilter)) ftx2.verify() assertEquals(wtx.id, ftx2.id) - ftx2.checkAllComponentsVisible(ATTACHMENTS_GROUP) + ftx2.checkAllComponentsVisible(ATTACHMENTS_V2_GROUP) assertFailsWith { ftx2.checkAllComponentsVisible(PARAMETERS_GROUP) } } } diff --git a/core-tests/src/test/kotlin/net/corda/coretests/transactions/LedgerTransactionQueryTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/transactions/LedgerTransactionQueryTests.kt index f222925b30..a3615af380 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/transactions/LedgerTransactionQueryTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/transactions/LedgerTransactionQueryTests.kt @@ -1,8 +1,8 @@ package net.corda.coretests.transactions -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import net.corda.core.contracts.* import net.corda.core.crypto.generateKeyPair import net.corda.core.identity.AbstractParty @@ -315,4 +315,4 @@ class LedgerTransactionQueryTests { val intCmd2 = ltx.findCommand { it.id == 3 } assertEquals(ltx.getCommand(7), intCmd2) } -} \ No newline at end of file +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/transactions/ReferenceInputStateTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/transactions/ReferenceInputStateTests.kt index b602595618..b9ff8cbddc 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/transactions/ReferenceInputStateTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/transactions/ReferenceInputStateTests.kt @@ -1,8 +1,8 @@ package net.corda.coretests.transactions -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import net.corda.core.contracts.* import net.corda.core.contracts.Requirements.using import net.corda.core.crypto.SecureHash @@ -206,4 +206,4 @@ class ReferenceStateTests { .addInputState(stateAndRef).addReferenceState(stateAndRef.referenced()) }.withMessage("A StateRef cannot be both an input and a reference input in the same transaction.") } -} \ No newline at end of file +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionBuilderMockNetworkTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionBuilderMockNetworkTest.kt new file mode 100644 index 0000000000..b54fbc334d --- /dev/null +++ b/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionBuilderMockNetworkTest.kt @@ -0,0 +1,119 @@ +package net.corda.coretests.transactions + +import net.corda.core.contracts.SignatureAttachmentConstraint +import net.corda.core.contracts.TransactionState +import net.corda.core.internal.PlatformVersionSwitches.MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS +import net.corda.core.internal.RPC_UPLOADER +import net.corda.core.internal.copyToDirectory +import net.corda.core.internal.hash +import net.corda.core.internal.toPath +import net.corda.core.transactions.TransactionBuilder +import net.corda.finance.DOLLARS +import net.corda.finance.contracts.asset.Cash +import net.corda.finance.issuedBy +import net.corda.testing.common.internal.testNetworkParameters +import net.corda.testing.contracts.DummyContract +import net.corda.testing.contracts.DummyState +import net.corda.testing.core.DummyCommandData +import net.corda.testing.core.internal.JarSignatureTestUtils.unsignJar +import net.corda.testing.core.singleIdentity +import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP +import net.corda.testing.node.internal.InternalMockNetwork +import net.corda.testing.node.internal.MockNodeArgs +import net.corda.testing.node.internal.cordappWithPackages +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException +import org.junit.After +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import java.nio.file.Path +import kotlin.io.path.copyTo +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.inputStream + +@Suppress("INVISIBLE_MEMBER") +class TransactionBuilderMockNetworkTest { + companion object { + val legacyFinanceContractsJar = this::class.java.getResource("/corda-finance-contracts-4.11.jar")!!.toPath() + } + + @Rule + @JvmField + val tempFolder = TemporaryFolder() + + private val mockNetwork = InternalMockNetwork( + cordappsForAllNodes = setOf( + FINANCE_CONTRACTS_CORDAPP, + cordappWithPackages("net.corda.testing.contracts").signed() + ), + initialNetworkParameters = testNetworkParameters(minimumPlatformVersion = MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS) + ) + + @After + fun close() { + mockNetwork.close() + } + + @Test(timeout=300_000) + fun `automatic signature constraint`() { + val services = mockNetwork.notaryNodes[0].services + + val attachment = services.attachments.openAttachment(services.attachments.getLatestContractAttachments(DummyContract.PROGRAM_ID)[0]) + val attachmentSigner = attachment!!.signerKeys.single() + + val expectedConstraint = SignatureAttachmentConstraint(attachmentSigner) + assertThat(expectedConstraint.isSatisfiedBy(attachment)).isTrue() + + val outputState = TransactionState(data = DummyState(), contract = DummyContract.PROGRAM_ID, notary = mockNetwork.defaultNotaryIdentity) + val builder = TransactionBuilder() + .addOutputState(outputState) + .addCommand(DummyCommandData, mockNetwork.defaultNotaryIdentity.owningKey) + val wtx = builder.toWireTransaction(services) + + assertThat(wtx.outputs).containsOnly(outputState.copy(constraint = expectedConstraint)) + } + + @Test(timeout=300_000) + fun `contract overlap in explicit attachments`() { + val duplicateJar = tempFolder.newFile("duplicate.jar").toPath() + FINANCE_CONTRACTS_CORDAPP.jarFile.copyTo(duplicateJar, overwrite = true) + duplicateJar.unsignJar() // Change its hash + + val node = mockNetwork.createNode() + val duplicateId = duplicateJar.inputStream().use { + node.services.attachments.privilegedImportAttachment(it, RPC_UPLOADER, null) + } + assertThat(FINANCE_CONTRACTS_CORDAPP.jarFile.hash).isNotEqualTo(duplicateId) + + val builder = TransactionBuilder() + builder.addAttachment(FINANCE_CONTRACTS_CORDAPP.jarFile.hash) + builder.addAttachment(duplicateId) + val identity = node.info.singleIdentity() + Cash().generateIssue(builder, 10.DOLLARS.issuedBy(identity.ref(0x00)), identity, mockNetwork.defaultNotaryIdentity) + assertThatIllegalArgumentException() + .isThrownBy { builder.toWireTransaction(node.services) } + .withMessageContaining("Multiple attachments specified for the same contract") + } + + @Test(timeout=300_000) + fun `populates legacy attachment group if legacy contract CorDapp is present`() { + val node = mockNetwork.createNode { args -> + args.copyToLegacyContracts(legacyFinanceContractsJar) + InternalMockNetwork.MockNode(args) + } + val builder = TransactionBuilder() + val identity = node.info.singleIdentity() + Cash().generateIssue(builder, 10.DOLLARS.issuedBy(identity.ref(0x00)), identity, mockNetwork.defaultNotaryIdentity) + val stx = node.services.signInitialTransaction(builder) + assertThat(stx.tx.nonLegacyAttachments).contains(FINANCE_CONTRACTS_CORDAPP.jarFile.hash) + assertThat(stx.tx.legacyAttachments).contains(legacyFinanceContractsJar.hash) + stx.verify(node.services) + } + + private fun MockNodeArgs.copyToLegacyContracts(vararg jars: Path) { + val legacyContractsDir = (config.baseDirectory / "legacy-contracts").createDirectories() + jars.forEach { it.copyToDirectory(legacyContractsDir) } + } +} diff --git a/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionBuilderTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionBuilderTest.kt index 0f3c35300b..9155b42611 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionBuilderTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionBuilderTest.kt @@ -1,54 +1,40 @@ package net.corda.coretests.transactions -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.contracts.Command -import net.corda.core.contracts.ContractAttachment import net.corda.core.contracts.HashAttachmentConstraint import net.corda.core.contracts.PrivacySalt -import net.corda.core.contracts.SignatureAttachmentConstraint import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.StateRef import net.corda.core.contracts.TimeWindow import net.corda.core.contracts.TransactionState -import net.corda.core.contracts.TransactionVerificationException -import net.corda.core.cordapp.CordappProvider -import net.corda.core.crypto.CompositeKey +import net.corda.core.contracts.TransactionVerificationException.UnsupportedHashTypeException import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash -import net.corda.core.identity.Party -import net.corda.core.internal.AbstractAttachment import net.corda.core.internal.HashAgility import net.corda.core.internal.PLATFORM_VERSION +import net.corda.core.internal.RPC_UPLOADER import net.corda.core.internal.digestService -import net.corda.core.node.ServicesForResolution import net.corda.core.node.ZoneVersionTooLowException -import net.corda.core.node.services.AttachmentStorage -import net.corda.core.node.services.IdentityService -import net.corda.core.node.services.NetworkParametersService -import net.corda.core.serialization.serialize import net.corda.core.transactions.TransactionBuilder -import net.corda.coretesting.internal.rigorousMock import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyState import net.corda.testing.core.ALICE_NAME -import net.corda.testing.core.BOB_NAME import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.DummyCommandData import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.TestIdentity +import net.corda.testing.node.MockServices +import net.corda.testing.node.internal.cordappWithPackages import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException import org.assertj.core.api.Assertions.assertThatThrownBy -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Before import org.junit.Ignore import org.junit.Rule import org.junit.Test -import java.security.PublicKey import java.time.Instant +import kotlin.io.path.inputStream import kotlin.test.assertFailsWith class TransactionBuilderTest { @@ -57,35 +43,15 @@ class TransactionBuilderTest { val testSerialization = SerializationEnvironmentRule() private val notary = TestIdentity(DUMMY_NOTARY_NAME).party - private val services = rigorousMock() - private val contractAttachmentId = SecureHash.randomSHA256() - private val attachments = rigorousMock() - private val networkParametersService = mock() - - @Before - fun setup() { - val cordappProvider = rigorousMock() - val networkParameters = testNetworkParameters(minimumPlatformVersion = PLATFORM_VERSION) - doReturn(networkParametersService).whenever(services).networkParametersService - doReturn(networkParameters.serialize().hash).whenever(networkParametersService).currentHash - doReturn(cordappProvider).whenever(services).cordappProvider - doReturn(contractAttachmentId).whenever(cordappProvider).getContractAttachmentID(DummyContract.PROGRAM_ID) - doReturn(networkParameters).whenever(services).networkParameters - doReturn(mock()).whenever(services).identityService - - val attachmentStorage = rigorousMock() - doReturn(attachmentStorage).whenever(services).attachments - val attachment = rigorousMock() - doReturn(attachment).whenever(attachmentStorage).openAttachment(contractAttachmentId) - doReturn(contractAttachmentId).whenever(attachment).id - doReturn(setOf(DummyContract.PROGRAM_ID)).whenever(attachment).allContracts - doReturn("app").whenever(attachment).uploader - doReturn(emptyList()).whenever(attachment).signerKeys - doReturn(listOf(contractAttachmentId)).whenever(attachmentStorage) - .getLatestContractAttachments("net.corda.testing.contracts.DummyContract") - } + private val services = MockServices( + listOf("net.corda.testing.contracts"), + TestIdentity(ALICE_NAME), + testNetworkParameters(minimumPlatformVersion = PLATFORM_VERSION) + ) + private val contractAttachmentId = services.attachments.getLatestContractAttachments(DummyContract.PROGRAM_ID)[0] @Test(timeout=300_000) + @Suppress("INVISIBLE_MEMBER") fun `bare minimum issuance tx`() { val outputState = TransactionState( data = DummyState(), @@ -99,13 +65,14 @@ class TransactionBuilderTest { val wtx = builder.toWireTransaction(services) assertThat(wtx.outputs).containsOnly(outputState) assertThat(wtx.commands).containsOnly(Command(DummyCommandData, notary.owningKey)) - assertThat(wtx.networkParametersHash).isEqualTo(networkParametersService.currentHash) + assertThat(wtx.networkParametersHash).isEqualTo(services.networkParametersService.currentHash) + // From 4.12 attachments are added to the new component group by default + assertThat(wtx.nonLegacyAttachments).isNotEmpty + assertThat(wtx.legacyAttachments).isEmpty() } @Test(timeout=300_000) fun `automatic hash constraint`() { - doReturn(unsignedAttachment).whenever(attachments).openAttachment(contractAttachmentId) - val outputState = TransactionState(data = DummyState(), contract = DummyContract.PROGRAM_ID, notary = notary) val builder = TransactionBuilder() .addOutputState(outputState) @@ -116,8 +83,6 @@ class TransactionBuilderTest { @Test(timeout=300_000) fun `reference states`() { - doReturn(unsignedAttachment).whenever(attachments).openAttachment(contractAttachmentId) - val referenceState = TransactionState(DummyState(), DummyContract.PROGRAM_ID, notary) val referenceStateRef = StateRef(SecureHash.randomSHA256(), 1) val builder = TransactionBuilder(notary) @@ -125,54 +90,20 @@ class TransactionBuilderTest { .addOutputState(TransactionState(DummyState(), DummyContract.PROGRAM_ID, notary)) .addCommand(DummyCommandData, notary.owningKey) - doReturn(testNetworkParameters(minimumPlatformVersion = 3)).whenever(services).networkParameters - assertThatThrownBy { builder.toWireTransaction(services) } - .isInstanceOf(ZoneVersionTooLowException::class.java) - .hasMessageContaining("Reference states") + with(testNetworkParameters(minimumPlatformVersion = 3)) { + val services = MockServices(listOf("net.corda.testing.contracts"), TestIdentity(ALICE_NAME), this) + assertThatThrownBy { builder.toWireTransaction(services) } + .isInstanceOf(ZoneVersionTooLowException::class.java) + .hasMessageContaining("Reference states") + } - doReturn(testNetworkParameters(minimumPlatformVersion = 4)).whenever(services).networkParameters - doReturn(referenceState).whenever(services).loadState(referenceStateRef) - val wtx = builder.toWireTransaction(services) - assertThat(wtx.references).containsOnly(referenceStateRef) + with(testNetworkParameters(minimumPlatformVersion = 4)) { + val services = MockServices(listOf("net.corda.testing.contracts"), TestIdentity(ALICE_NAME), this) + val wtx = builder.toWireTransaction(services) + assertThat(wtx.references).containsOnly(referenceStateRef) + } } - @Test(timeout=300_000) - fun `automatic signature constraint`() { - val aliceParty = TestIdentity(ALICE_NAME).party - val bobParty = TestIdentity(BOB_NAME).party - val compositeKey = CompositeKey.Builder().addKeys(aliceParty.owningKey, bobParty.owningKey).build() - val expectedConstraint = SignatureAttachmentConstraint(compositeKey) - val signedAttachment = signedAttachment(aliceParty, bobParty) - - assertTrue(expectedConstraint.isSatisfiedBy(signedAttachment)) - assertFalse(expectedConstraint.isSatisfiedBy(unsignedAttachment)) - - doReturn(attachments).whenever(services).attachments - doReturn(signedAttachment).whenever(attachments).openAttachment(contractAttachmentId) - doReturn(listOf(contractAttachmentId)).whenever(attachments) - .getLatestContractAttachments("net.corda.testing.contracts.DummyContract") - - val outputState = TransactionState(data = DummyState(), contract = DummyContract.PROGRAM_ID, notary = notary) - val builder = TransactionBuilder() - .addOutputState(outputState) - .addCommand(DummyCommandData, notary.owningKey) - val wtx = builder.toWireTransaction(services) - - assertThat(wtx.outputs).containsOnly(outputState.copy(constraint = expectedConstraint)) - } - - private val unsignedAttachment = ContractAttachment(object : AbstractAttachment({ byteArrayOf() }, "test") { - override val id: SecureHash get() = throw UnsupportedOperationException() - - override val signerKeys: List get() = emptyList() - }, DummyContract.PROGRAM_ID) - - private fun signedAttachment(vararg parties: Party) = ContractAttachment.create(object : AbstractAttachment({ byteArrayOf() }, "test") { - override val id: SecureHash get() = contractAttachmentId - - override val signerKeys: List get() = parties.map { it.owningKey } - }, DummyContract.PROGRAM_ID, signerKeys = parties.map { it.owningKey }) - @Test(timeout=300_000) fun `list accessors are mutable copies`() { val inputState1 = TransactionState(DummyState(), DummyContract.PROGRAM_ID, notary) @@ -270,7 +201,7 @@ class TransactionBuilderTest { } @Ignore - @Test(timeout=300_000, expected = TransactionVerificationException.UnsupportedHashTypeException::class) + @Test(timeout=300_000) fun `throws with non-default hash algorithm`() { HashAgility.init() try { @@ -286,13 +217,15 @@ class TransactionBuilderTest { .addOutputState(outputState) .addCommand(DummyCommandData, notary.owningKey) - builder.toWireTransaction(services) + assertThatExceptionOfType(UnsupportedHashTypeException::class.java).isThrownBy { + builder.toWireTransaction(services) + } } finally { HashAgility.init() } } - @Test(timeout=300_000, expected = Test.None::class) + @Test(timeout=300_000) fun `allows non-default hash algorithm`() { HashAgility.init(txHashAlgoName = DigestService.sha2_384.hashAlgorithm) assertThat(services.digestService).isEqualTo(DigestService.sha2_384) @@ -332,4 +265,25 @@ class TransactionBuilderTest { builder.toWireTransaction(services, schemeId) } } + + @Test(timeout=300_000) + fun `contract overlap in explicit attachments`() { + val overlappingAttachmentId = cordappWithPackages("net.corda.testing").jarFile.inputStream().use { + services.attachments.importAttachment(it, RPC_UPLOADER, null) + } + + val outputState = TransactionState( + data = DummyState(), + contract = DummyContract.PROGRAM_ID, + notary = notary + ) + val builder = TransactionBuilder() + .addAttachment(contractAttachmentId) + .addAttachment(overlappingAttachmentId) + .addOutputState(outputState) + .addCommand(DummyCommandData, notary.owningKey) + assertThatIllegalArgumentException() + .isThrownBy { builder.toWireTransaction(services) } + .withMessageContaining("Multiple attachments specified for the same contract net.corda.testing.contracts.DummyContract") + } } diff --git a/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionEncumbranceTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionEncumbranceTests.kt index cde9dc4da7..4ba46d594b 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionEncumbranceTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionEncumbranceTests.kt @@ -1,8 +1,8 @@ package net.corda.coretests.transactions -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import net.corda.core.contracts.* import net.corda.core.identity.AbstractParty import net.corda.core.identity.CordaX500Name diff --git a/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionTests.kt index 62254d6b4e..b987af0440 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionTests.kt @@ -1,7 +1,7 @@ package net.corda.coretests.transactions -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import net.corda.core.contracts.* import net.corda.core.crypto.* import net.corda.core.crypto.CompositeKey @@ -205,7 +205,7 @@ class TransactionTests(private val digestService : DigestService) { val attachments = listOf(ContractAttachment(object : AbstractAttachment({ (AttachmentsClassLoaderTests::class.java.getResource(ISOLATED_JAR) ?: fail("Missing $ISOLATED_JAR")).openStream().readBytes() }, TESTDSL_UPLOADER) { - @Suppress("OverridingDeprecatedMember") + @Suppress("OVERRIDE_DEPRECATION") override val signers: List = emptyList() override val signerKeys: List = emptyList() override val size: Int = 1234 diff --git a/core-tests/src/test/kotlin/net/corda/coretests/utilities/KotlinUtilsTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/utilities/KotlinUtilsTest.kt index e989b3a107..105752de31 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/utilities/KotlinUtilsTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/utilities/KotlinUtilsTest.kt @@ -13,7 +13,8 @@ import net.corda.testing.core.SerializationEnvironmentRule import org.assertj.core.api.Assertions.assertThat import org.junit.Rule import org.junit.Test -import org.junit.rules.ExpectedException +import org.junit.jupiter.api.assertThrows +import kotlin.test.assertTrue object EmptyWhitelist : ClassWhitelist { override fun hasListed(type: Class<*>): Boolean = false @@ -23,9 +24,6 @@ class KotlinUtilsTest { @Rule @JvmField val testSerialization = SerializationEnvironmentRule() - @JvmField - @Rule - val expectedEx: ExpectedException = ExpectedException.none() private val KRYO_CHECKPOINT_NOWHITELIST_CONTEXT = CheckpointSerializationContextImpl( javaClass.classLoader, @@ -54,10 +52,11 @@ class KotlinUtilsTest { @Test(timeout=300_000) fun `deserialise transient property with non-capturing lambda`() { - expectedEx.expect(KryoException::class.java) - expectedEx.expectMessage("is not annotated or on the whitelist, so cannot be used in serialization") - val original = NonCapturingTransientProperty() - original.checkpointSerialize(context = KRYO_CHECKPOINT_CONTEXT).checkpointDeserialize(context = KRYO_CHECKPOINT_NOWHITELIST_CONTEXT) + val anException = assertThrows { + val original = NonCapturingTransientProperty() + original.checkpointSerialize(context = KRYO_CHECKPOINT_CONTEXT).checkpointDeserialize(context = KRYO_CHECKPOINT_NOWHITELIST_CONTEXT) + } + anException.message?.let { assertTrue(it.contains("is not annotated or on the whitelist, so cannot be used in serialization")) } } @Test(timeout=300_000) @@ -73,12 +72,11 @@ class KotlinUtilsTest { @Test(timeout=300_000) fun `deserialise transient property with capturing lambda`() { - expectedEx.expect(KryoException::class.java) - expectedEx.expectMessage("is not annotated or on the whitelist, so cannot be used in serialization") - - val original = CapturingTransientProperty("Hello") - - original.checkpointSerialize(context = KRYO_CHECKPOINT_CONTEXT).checkpointDeserialize(context = KRYO_CHECKPOINT_NOWHITELIST_CONTEXT) + val anException = assertThrows { + val original = CapturingTransientProperty("Hello") + original.checkpointSerialize(context = KRYO_CHECKPOINT_CONTEXT).checkpointDeserialize(context = KRYO_CHECKPOINT_NOWHITELIST_CONTEXT) + } + anException.message?.let { assertTrue(it.contains("is not annotated or on the whitelist, so cannot be used in serialization")) } } private class NullTransientProperty { @@ -98,4 +96,4 @@ class KotlinUtilsTest { private class CapturingTransientProperty(val prefix: String, val seed: Long = random63BitValue()) { val transientVal by transient { prefix + seed + random63BitValue() } } -} \ No newline at end of file +} diff --git a/core/build.gradle b/core/build.gradle index 36ca45311b..6674d832ea 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,109 +1,78 @@ -import static org.gradle.api.JavaVersion.VERSION_1_8 - -apply plugin: 'kotlin' -apply plugin: 'kotlin-jpa' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'org.jetbrains.kotlin.plugin.jpa' apply plugin: 'net.corda.plugins.quasar-utils' -apply plugin: 'net.corda.plugins.publish-utils' apply plugin: 'net.corda.plugins.api-scanner' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' description 'Corda core' -targetCompatibility = VERSION_1_8 - sourceSets { obfuscator } configurations { - integrationTestCompile.extendsFrom testCompile + resolvableImplementation.extendsFrom implementation + + integrationTestImplementation.extendsFrom testImplementation integrationTestRuntimeOnly.extendsFrom testRuntimeOnly smokeTestCompile.extendsFrom compile smokeTestRuntimeOnly.extendsFrom runtimeOnly + + testArtifacts.extendsFrom(testRuntimeClasspath) } dependencies { - - 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 "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" - testImplementation "junit:junit:$junit_version" - testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" - testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - - testCompile "commons-fileupload:commons-fileupload:$fileupload_version" - - // Guava: Google test library (collections test suite) - testCompile "com.google.guava:guava-testlib:$guava_version" - - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - - // Hamkrest, for fluent, composable matchers - testCompile "com.natpryce:hamkrest:$hamkrest_version" - - // Thread safety annotations - compile "com.google.code.findbugs:jsr305:$jsr305_version" - - // SLF4J: commons-logging bindings for a SLF4J back end - compile "org.slf4j:jcl-over-slf4j:$slf4j_version" - compile "org.slf4j:slf4j-api:$slf4j_version" - - // AssertJ: for fluent assertions for testing - testCompile "org.assertj:assertj-core:${assertj_version}" - - // Guava: Google utilities library. - compile "com.google.guava:guava:$guava_version" - - // For caches rather than guava - compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version" - + // These are exposed in our public APIs and are thus "api" dependencies + api "org.slf4j:slf4j-api:$slf4j_version" // RxJava: observable streams of events. - compile "io.reactivex:rxjava:$rxjava_version" - - compile "org.apache.commons:commons-lang3:$commons_lang_version" - - // Java ed25519 implementation. See https://github.com/str4d/ed25519-java/ - compile "net.i2p.crypto:eddsa:$eddsa_version" + api "io.reactivex:rxjava:$rxjava_version" + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + // SLF4J: commons-logging bindings for a SLF4J back end + implementation "org.slf4j:jcl-over-slf4j:$slf4j_version" + // Guava: Google utilities library. + implementation "com.google.guava:guava:$guava_version" + // For caches rather than guava + implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version" + implementation "org.apache.commons:commons-lang3:$commons_lang3_version" // Bouncy castle support needed for X509 certificate manipulation - compile "org.bouncycastle:bcprov-jdk18on:${bouncycastle_version}" - compile "org.bouncycastle:bcpkix-jdk18on:${bouncycastle_version}" - - // JPA 2.2 annotations. - compile "javax.persistence:javax.persistence-api:2.2" - + implementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}" // required to use @Type annotation - compile "org.hibernate:hibernate-core:$hibernate_version" - + implementation "org.hibernate:hibernate-core:$hibernate_version" // FastThreadLocal - compile "io.netty:netty-common:$netty_version" + implementation "io.netty:netty-common:$netty_version" + implementation "io.github.classgraph:classgraph:$class_graph_version" - compile group: "io.github.classgraph", name: "classgraph", version: class_graph_version + testImplementation sourceSets.obfuscator.output + testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version" + testImplementation "junit:junit:$junit_version" + testImplementation "org.apache.commons:commons-fileupload2-jakarta:$fileupload_version" + // Guava: Google test library (collections test suite) + testImplementation "com.google.guava:guava-testlib:$guava_version" + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + // Hamkrest, for fluent, composable matchers + testImplementation "com.natpryce:hamkrest:$hamkrest_version" + // AssertJ: for fluent assertions for testing + testImplementation "org.assertj:assertj-core:$assertj_version" + testImplementation "org.bouncycastle:bcpkix-lts8on:$bouncycastle_version" + testImplementation "org.ow2.asm:asm:$asm_version" - testCompile "org.ow2.asm:asm:$asm_version" - - // JDK11: required by Quasar at run-time testRuntimeOnly "com.esotericsoftware:kryo:$kryo_version" + testRuntimeOnly "org.slf4j:slf4j-simple:$slf4j_version" - testCompile "com.nhaarman:mockito-kotlin:$mockito_kotlin_version" - testCompile "org.mockito:mockito-core:$mockito_version" - testCompile "org.assertj:assertj-core:$assertj_version" - testCompile "com.natpryce:hamkrest:$hamkrest_version" - testCompile 'org.hamcrest:hamcrest-library:2.1' - + testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" + testImplementation "org.mockito:mockito-core:$mockito_version" + testImplementation "org.assertj:assertj-core:$assertj_version" + testImplementation "com.natpryce:hamkrest:$hamkrest_version" + testImplementation 'org.hamcrest:hamcrest-library:2.1' } // TODO Consider moving it to quasar-utils in the future (introduced with PR-1388) -task copyQuasarJar(type: Copy) { +tasks.register('copyQuasarJar', Copy) { from configurations.quasar into "$project.rootProject.projectDir/lib" - rename { filename -> "quasar.jar"} + rename { filename -> "quasar.jar" } } jar { @@ -112,11 +81,6 @@ jar { archiveClassifier = '' } -configurations { - testArtifacts.extendsFrom testRuntimeClasspath -} - - processTestResources { inputs.files(jar) into("zip") { @@ -130,7 +94,8 @@ test { maxParallelForks = (System.env.CORDA_CORE_TESTING_FORKS == null) ? 1 : "$System.env.CORDA_CORE_TESTING_FORKS".toInteger() } -task testJar(type: Jar) { +tasks.register('testJar', Jar) { + dependsOn testClasses classifier "tests" from sourceSets.test.output } @@ -149,7 +114,6 @@ quasar { "io.github.classgraph**", "io.netty*", "liquibase**", - "net.i2p.crypto.**", "nonapi.io.github.classgraph.**", "org.apiguardian.**", "org.bouncycastle**", @@ -165,11 +129,6 @@ quasar { "io.opentelemetry.**") } -artifacts { - testArtifacts testJar - publish testJar -} - scanApi { excludeClasses = [ // Kotlin should probably have declared this class as "synthetic". @@ -177,13 +136,23 @@ scanApi { ] } -publish { - name jar.baseName -} - tasks.register("writeTestResources", JavaExec) { classpath sourceSets.obfuscator.output classpath sourceSets.obfuscator.runtimeClasspath main 'net.corda.core.internal.utilities.TestResourceWriter' args new File(sourceSets.test.resources.srcDirs.first(), "zip").toString() } + +artifacts { + testArtifacts testJar +} + +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-core' + artifact testJar + from components.java + } + } +} diff --git a/core/src/main/kotlin/net/corda/core/concurrent/ConcurrencyUtils.kt b/core/src/main/kotlin/net/corda/core/concurrent/ConcurrencyUtils.kt index 30d8156db6..cd5c338d9f 100644 --- a/core/src/main/kotlin/net/corda/core/concurrent/ConcurrencyUtils.kt +++ b/core/src/main/kotlin/net/corda/core/concurrent/ConcurrencyUtils.kt @@ -1,7 +1,7 @@ @file:JvmName("ConcurrencyUtils") package net.corda.core.concurrent -import net.corda.core.internal.VisibleForTesting +import net.corda.core.CordaInternal import net.corda.core.internal.concurrent.openFuture import net.corda.core.utilities.getOrThrow import org.slf4j.Logger @@ -27,9 +27,8 @@ fun Future.match(success: (V) -> W, failure: (Throwable) -> W): W { fun firstOf(vararg futures: CordaFuture, handler: (CordaFuture) -> W) = firstOf(futures, defaultLog, handler) private val defaultLog = LoggerFactory.getLogger("net.corda.core.concurrent") -@VisibleForTesting -internal const val shortCircuitedTaskFailedMessage = "Short-circuited task failed:" +@CordaInternal internal fun firstOf(futures: Array>, log: Logger, handler: (CordaFuture) -> W): CordaFuture { val resultFuture = openFuture() val winnerChosen = AtomicBoolean() @@ -40,7 +39,7 @@ internal fun firstOf(futures: Array>, log: Logger, it.isCancelled -> { // Do nothing. } - else -> it.match({}, { log.error(shortCircuitedTaskFailedMessage, it) }) + else -> it.match({}, { log.error("Short-circuited task failed:", it) }) } } } diff --git a/core/src/main/kotlin/net/corda/core/contracts/Attachment.kt b/core/src/main/kotlin/net/corda/core/contracts/Attachment.kt index 4cb6c42ba6..4716211407 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/Attachment.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/Attachment.kt @@ -35,7 +35,6 @@ import java.util.jar.JarInputStream interface Attachment : NamedByHash { fun open(): InputStream - @JvmDefault fun openAsJAR(): JarInputStream { val stream = open() return try { @@ -49,7 +48,6 @@ interface Attachment : NamedByHash { * Finds the named file case insensitively and copies it to the output stream. * @throws [FileNotFoundException] if the given path doesn't exist in the attachment. */ - @JvmDefault fun extractFile(path: String, outputTo: OutputStream) = openAsJAR().use { it.extractFile(path, outputTo) } /** diff --git a/core/src/main/kotlin/net/corda/core/contracts/AttachmentConstraint.kt b/core/src/main/kotlin/net/corda/core/contracts/AttachmentConstraint.kt index e7efccdde9..1e3593d28d 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/AttachmentConstraint.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/AttachmentConstraint.kt @@ -11,12 +11,12 @@ import net.corda.core.internal.utilities.Internable import net.corda.core.internal.utilities.PrivateInterner import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.TransactionBuilder +import net.corda.core.utilities.contextLogger +import net.corda.core.utilities.debug import net.corda.core.utilities.loggerFor import java.lang.annotation.Inherited import java.security.PublicKey -private val log = loggerFor() - /** * This annotation should only be added to [Contract] classes. * If the annotation is present, then we assume that [Contract.verify] will ensure that the output states have an acceptable constraint. @@ -48,8 +48,11 @@ object AlwaysAcceptAttachmentConstraint : AttachmentConstraint { */ data class HashAttachmentConstraint(val attachmentId: SecureHash) : AttachmentConstraint { companion object { + private val log = contextLogger() + val disableHashConstraints = System.getProperty("net.corda.node.disableHashConstraints")?.toBoolean() ?: false } + override fun isSatisfiedBy(attachment: Attachment): Boolean { return if (attachment is AttachmentWithContext) { log.debug("Checking attachment uploader ${attachment.contractAttachment.uploader} is trusted") @@ -67,10 +70,12 @@ data class HashAttachmentConstraint(val attachmentId: SecureHash) : AttachmentCo * It allows for centralized control over the cordapps that can be used. */ object WhitelistedByZoneAttachmentConstraint : AttachmentConstraint { + private val log = loggerFor() + override fun isSatisfiedBy(attachment: Attachment): Boolean { return if (attachment is AttachmentWithContext) { val whitelist = attachment.whitelistedContractImplementations - log.debug("Checking ${attachment.contract} is in CZ whitelist $whitelist") + log.debug { "Checking ${attachment.contract} is in CZ whitelist $whitelist" } attachment.id in (whitelist[attachment.contract] ?: emptyList()) } else { log.warn("CZ whitelisted constraint check failed: ${attachment.id} not in CZ whitelist") @@ -111,14 +116,16 @@ object AutomaticPlaceholderConstraint : AttachmentConstraint { */ data class SignatureAttachmentConstraint(val key: PublicKey) : AttachmentConstraint { override fun isSatisfiedBy(attachment: Attachment): Boolean { - log.debug("Checking signature constraints: verifying $key in contract attachment signer keys: ${attachment.signerKeys}") - return if (!key.isFulfilledBy(attachment.signerKeys.map { it })) { + log.debug { "Checking signature constraints: verifying $key in contract attachment signer keys: ${attachment.signerKeys}" } + return if (!key.isFulfilledBy(attachment.signerKeys)) { log.warn("Untrusted signing key: expected $key. but contract attachment contains ${attachment.signerKeys}") false } else true } companion object : Internable { + private val log = contextLogger() + @CordaInternal override val interner = PrivateInterner() diff --git a/core/src/main/kotlin/net/corda/core/contracts/ComponentGroupEnum.kt b/core/src/main/kotlin/net/corda/core/contracts/ComponentGroupEnum.kt index 6492d8154f..93bdeff2dc 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/ComponentGroupEnum.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/ComponentGroupEnum.kt @@ -8,10 +8,11 @@ enum class ComponentGroupEnum { INPUTS_GROUP, // ordinal = 0. OUTPUTS_GROUP, // ordinal = 1. COMMANDS_GROUP, // ordinal = 2. - ATTACHMENTS_GROUP, // ordinal = 3. + ATTACHMENTS_GROUP, // ordinal = 3. This is for legacy attachments. It's not been renamed for backwards compatibility. NOTARY_GROUP, // ordinal = 4. TIMEWINDOW_GROUP, // ordinal = 5. SIGNERS_GROUP, // ordinal = 6. REFERENCES_GROUP, // ordinal = 7. - PARAMETERS_GROUP // ordinal = 8. + PARAMETERS_GROUP, // ordinal = 8. + ATTACHMENTS_V2_GROUP // ordinal = 9. From 4.12+ this group is used for attachments. } diff --git a/core/src/main/kotlin/net/corda/core/contracts/ContractAttachment.kt b/core/src/main/kotlin/net/corda/core/contracts/ContractAttachment.kt index 0b56707ee1..24852fad3c 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/ContractAttachment.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/ContractAttachment.kt @@ -27,6 +27,7 @@ class ContractAttachment private constructor( companion object { @CordaInternal + @JvmSynthetic fun create(attachment: Attachment, contract: ContractClassName, additionalContracts: Set = emptySet(), diff --git a/core/src/main/kotlin/net/corda/core/crypto/CompositeKey.kt b/core/src/main/kotlin/net/corda/core/crypto/CompositeKey.kt index e968257931..dfa5da1998 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/CompositeKey.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/CompositeKey.kt @@ -14,7 +14,7 @@ import org.bouncycastle.asn1.DERSequence import org.bouncycastle.asn1.x509.AlgorithmIdentifier import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo import java.security.PublicKey -import java.util.* +import java.util.IdentityHashMap /** * A tree data structure that enables the representation of composite public keys, which are used to represent @@ -50,8 +50,7 @@ class CompositeKey private constructor(val threshold: Int, children: List - require(childAsn1 is ASN1Sequence) { "Child key is not in ASN1 format" } - val childSeq = childAsn1 as ASN1Sequence + val childSeq = requireNotNull(childAsn1 as? ASN1Sequence) { "Child key is not in ASN1 format" } val key = Crypto.decodePublicKey((childSeq.getObjectAt(0) as DERBitString).bytes) val weight = ASN1Integer.getInstance(childSeq.getObjectAt(1)) builder.addKey(key, weight.positiveValue.toInt()) @@ -278,7 +277,7 @@ class CompositeKey private constructor(val threshold: Int, children: List 0) { "Threshold must not be specified or its value must be greater than zero" } val n = children.size return when { - n > 1 -> CompositeKey(threshold ?: children.map { (_, weight) -> weight }.sum(), children) + n > 1 -> CompositeKey(threshold ?: children.sumOf { (_, weight) -> weight }, children) n == 1 -> { require(threshold == null || threshold == children.first().weight) { "Trying to build invalid CompositeKey, threshold value different than weight of single child node." } diff --git a/core/src/main/kotlin/net/corda/core/crypto/CordaSecurityProvider.kt b/core/src/main/kotlin/net/corda/core/crypto/CordaSecurityProvider.kt index 4530312eec..70bf257a3f 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/CordaSecurityProvider.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/CordaSecurityProvider.kt @@ -5,11 +5,10 @@ import net.corda.core.crypto.CordaObjectIdentifier.COMPOSITE_SIGNATURE import net.corda.core.crypto.internal.PlatformSecureRandomService import org.bouncycastle.asn1.ASN1ObjectIdentifier import java.security.Provider -import java.util.* +import java.util.Optional import java.util.concurrent.ConcurrentHashMap -@Suppress("DEPRECATION") // JDK11: should replace with Provider(String name, double version, String info) (since 9) -class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME security provider wrapper") { +class CordaSecurityProvider : Provider(PROVIDER_NAME, "0.2", "$PROVIDER_NAME security provider") { companion object { const val PROVIDER_NAME = "Corda" } @@ -17,16 +16,8 @@ class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME secur private val services = ConcurrentHashMap, Optional>() init { - put("KeyFactory.${CompositeKey.KEY_ALGORITHM}", CompositeKeyFactory::class.java.name) - put("Alg.Alias.KeyFactory.$COMPOSITE_KEY", CompositeKey.KEY_ALGORITHM) - put("Alg.Alias.KeyFactory.OID.$COMPOSITE_KEY", CompositeKey.KEY_ALGORITHM) - put("Signature.${CompositeSignature.SIGNATURE_ALGORITHM}", CompositeSignature::class.java.name) - put("Alg.Alias.Signature.$COMPOSITE_SIGNATURE", CompositeSignature.SIGNATURE_ALGORITHM) - put("Alg.Alias.Signature.OID.$COMPOSITE_SIGNATURE", CompositeSignature.SIGNATURE_ALGORITHM) - putPlatformSecureRandomService() - } - - private fun putPlatformSecureRandomService() { + putService(Service(this, "KeyFactory", CompositeKey.KEY_ALGORITHM, CompositeKeyFactory::class.java.name, listOf("$COMPOSITE_KEY", "OID.$COMPOSITE_KEY"), null)) + putService(Service(this, "Signature", CompositeSignature.SIGNATURE_ALGORITHM, CompositeSignature::class.java.name, listOf("$COMPOSITE_SIGNATURE", "OID.$COMPOSITE_SIGNATURE"), null)) putService(PlatformSecureRandomService(this)) } diff --git a/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt b/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt index 8018c68892..88eaf43198 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt @@ -1,31 +1,22 @@ package net.corda.core.crypto import net.corda.core.CordaOID +import net.corda.core.crypto.Crypto.EDDSA_ED25519_SHA512 import net.corda.core.crypto.internal.AliasPrivateKey +import net.corda.core.crypto.internal.Curve25519.isOnCurve25519 import net.corda.core.crypto.internal.Instances.withSignature import net.corda.core.crypto.internal.PublicKeyCache -import net.corda.core.crypto.internal.bouncyCastlePQCProvider import net.corda.core.crypto.internal.cordaBouncyCastleProvider 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.internal.utilities.PrivateInterner import net.corda.core.serialization.serialize import net.corda.core.utilities.ByteSequence -import net.i2p.crypto.eddsa.EdDSAEngine -import net.i2p.crypto.eddsa.EdDSAPrivateKey -import net.i2p.crypto.eddsa.EdDSAPublicKey -import net.i2p.crypto.eddsa.math.GroupElement -import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec -import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable -import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec -import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec -import org.bouncycastle.asn1.ASN1Integer import org.bouncycastle.asn1.ASN1ObjectIdentifier import org.bouncycastle.asn1.DERNull import org.bouncycastle.asn1.DERUTF8String import org.bouncycastle.asn1.DLSequence -import org.bouncycastle.asn1.bc.BCObjectIdentifiers +import org.bouncycastle.asn1.edec.EdECObjectIdentifiers import org.bouncycastle.asn1.nist.NISTObjectIdentifiers import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers import org.bouncycastle.asn1.pkcs.PrivateKeyInfo @@ -34,12 +25,16 @@ import org.bouncycastle.asn1.x509.AlgorithmIdentifier import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo import org.bouncycastle.asn1.x9.X9ObjectIdentifiers import org.bouncycastle.crypto.CryptoServicesRegistrar +import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters +import org.bouncycastle.crypto.util.PrivateKeyInfoFactory +import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPrivateKey import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPublicKey import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateKey import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey +import org.bouncycastle.jcajce.spec.EdDSAParameterSpec import org.bouncycastle.jce.ECNamedCurveTable import org.bouncycastle.jce.provider.BouncyCastleProvider import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec @@ -49,19 +44,19 @@ import org.bouncycastle.jce.spec.ECPublicKeySpec import org.bouncycastle.math.ec.ECConstants import org.bouncycastle.math.ec.FixedPointCombMultiplier import org.bouncycastle.math.ec.WNafUtil -import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey -import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey -import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec +import org.bouncycastle.math.ec.rfc8032.Ed25519 import java.math.BigInteger import java.security.InvalidKeyException import java.security.Key -import java.security.KeyFactory import java.security.KeyPair import java.security.KeyPairGenerator import java.security.PrivateKey import java.security.Provider import java.security.PublicKey +import java.security.Signature import java.security.SignatureException +import java.security.interfaces.EdECPrivateKey +import java.security.interfaces.EdECPublicKey import java.security.spec.InvalidKeySpecException import java.security.spec.PKCS8EncodedKeySpec import java.security.spec.X509EncodedKeySpec @@ -77,8 +72,7 @@ import javax.crypto.spec.SecretKeySpec *
  • RSA_SHA256 (RSA PKCS#1 using SHA256 as hash algorithm). *
  • ECDSA_SECP256K1_SHA256 (ECDSA using the secp256k1 Koblitz curve and SHA256 as hash algorithm). *
  • ECDSA_SECP256R1_SHA256 (ECDSA using the secp256r1 (NIST P-256) curve and SHA256 as hash algorithm). - *
  • EDDSA_ED25519_SHA512 (EdDSA using the ed255519 twisted Edwards curve and SHA512 as hash algorithm). - *
  • SPHINCS256_SHA512 (SPHINCS-256 hash-based signature scheme using SHA512 as hash algorithm). + *
  • salt values should not be chosen by an attacker. *

    * - * Regarding the last requirement, according to Krawczyk's HKDF scheme: While there is no need to keep the salt secret, - * it is assumed that salt values are independent of the input keying material. - * @see Cryptographic Extraction and Key Derivation - The HKDF Scheme. + * Regarding the last requirement, according to Krawczyk's HKDF scheme: _While there is no need to keep the salt secret, + * it is assumed that salt values are independent of the input keying material_ + * (see [Cryptographic Extraction and Key Derivation - The HKDF Scheme](http://eprint.iacr.org/2010/264.pdf)). * * There are also protocols that require an authenticated nonce (e.g. when a DH derived key is used as a seed) and thus * we need to make sure that nonces come from legitimate parties rather than selected by an attacker. @@ -845,13 +809,7 @@ object Crypto { private fun deriveKeyPairEdDSA(privateKey: PrivateKey, seed: ByteArray): KeyPair { // Compute HMAC(privateKey, seed). val macBytes = deriveHMAC(privateKey, seed) - - // Calculate key pair. - val params = EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec - 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 publicKeyD = EdDSAPublicKeySpec(privateKeyD.a, params) - return KeyPair(internPublicKey(EdDSAPublicKey(publicKeyD)), EdDSAPrivateKey(privateKeyD)) + return deriveEdDSAKeyPair(macBytes) } /** @@ -882,15 +840,20 @@ object Crypto { fun deriveKeyPairFromEntropy(entropy: BigInteger): KeyPair = deriveKeyPairFromEntropy(DEFAULT_SIGNATURE_SCHEME, entropy) // Custom key pair generator from entropy. - // The BigIntenger.toByteArray() uses the two's-complement representation. + // The BigInteger.toByteArray() uses the two's-complement representation. // The entropy is transformed to a byte array in big-endian byte-order and // only the first ed25519.field.getb() / 8 bytes are used. private fun deriveEdDSAKeyPairFromEntropy(entropy: BigInteger): KeyPair { - val params = EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec - 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 pub = EdDSAPublicKeySpec(priv.a, params) - return KeyPair(internPublicKey(EdDSAPublicKey(pub)), EdDSAPrivateKey(priv)) + return deriveEdDSAKeyPair(entropy.toByteArray().copyOf(Ed25519.PUBLIC_KEY_SIZE)) + } + + private fun deriveEdDSAKeyPair(bytes: ByteArray): KeyPair { + val privateKeyParams = Ed25519PrivateKeyParameters(bytes, 0) // This will copy the first 256 bits + val encodedPrivateKey = PrivateKeyInfoFactory.createPrivateKeyInfo(privateKeyParams).encoded + val privateKey = EDDSA_ED25519_SHA512.keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedPrivateKey)) + val encodedPublicKey = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(privateKeyParams.generatePublicKey()).encoded + val publicKey = EDDSA_ED25519_SHA512.keyFactory.generatePublic(X509EncodedKeySpec(encodedPublicKey)) + return KeyPair(internPublicKey(publicKey), privateKey) } // Custom key pair generator from an entropy required for various tests. It is similar to deriveKeyPairECDSA, @@ -925,7 +888,7 @@ object Crypto { val mac = Mac.getInstance("HmacSHA512", cordaBouncyCastleProvider) val keyData = when (privateKey) { is BCECPrivateKey -> privateKey.d.toByteArray() - is EdDSAPrivateKey -> privateKey.geta() + is EdECPrivateKey -> privateKey.bytes.get() else -> throw InvalidKeyException("Key type ${privateKey.algorithm} is not supported for deterministic key derivation") } val key = SecretKeySpec(keyData, "HmacSHA512") @@ -936,12 +899,12 @@ object Crypto { /** * Check if a point's coordinates are on the expected curve to avoid certain types of ECC attacks. * Point-at-infinity is not permitted as well. - * @see Small subgroup and invalid-curve attacks for a more descriptive explanation on such attacks. + * See [Small subgroup and invalid-curve attacks](https://safecurves.cr.yp.to/twist.html) for a more descriptive explanation on such attacks. * We use this function on [validatePublicKey], which is currently used for signature verification only. * Thus, as these attacks are mostly not relevant to signature verification, we should note that * we are doing it out of an abundance of caution and specifically to proactively protect developers * against using these points as part of a DH key agreement or for use cases as yet unimagined. - * This method currently applies to BouncyCastle's ECDSA (both R1 and K1 curves) and I2P's EdDSA (ed25519 curve). + * This method currently applies to BouncyCastle's ECDSA (both R1 and K1 curves) and JCA EdDSA (ed25519 curve). * @param publicKey a [PublicKey], usually used to validate a signer's public key in on the Curve. * @param signatureScheme a [SignatureScheme] object, retrieved from supported signature schemes, see [Crypto]. * @return true if the point lies on the curve or false if it doesn't. @@ -954,17 +917,13 @@ object Crypto { } return when (publicKey) { is BCECPublicKey -> publicKey.parameters == signatureScheme.algSpec && !publicKey.q.isInfinity && publicKey.q.isValid - is EdDSAPublicKey -> publicKey.params == signatureScheme.algSpec && !isEdDSAPointAtInfinity(publicKey) && publicKey.a.isOnCurve - else -> throw IllegalArgumentException("Unsupported key type: ${publicKey::class}") + // It's not clear if the isOnCurve25519 check is necessary since we use BC for Ed25519, and it seems the BCEdDSAPublicKey c'tor + // does a validation check. + is EdECPublicKey -> signatureScheme == EDDSA_ED25519_SHA512 && publicKey.params.name.equals("Ed25519", ignoreCase = true) && publicKey.point.isOnCurve25519 + else -> throw IllegalArgumentException("Unsupported key type: ${publicKey.javaClass.name}") } } - // Return true if EdDSA publicKey is point at infinity. - // For EdDSA a custom function is required as it is not supported by the I2P implementation. - private fun isEdDSAPointAtInfinity(publicKey: EdDSAPublicKey): Boolean { - return publicKey.a.toP3() == (EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec).curve.getZero(GroupElement.Representation.P3) - } - /** Check if the requested [SignatureScheme] is supported by the system. */ @JvmStatic fun isSupportedSignatureScheme(signatureScheme: SignatureScheme): Boolean { @@ -981,31 +940,15 @@ object Crypto { // Check if a public key satisfies algorithm specs (for ECC: key should lie on the curve and not being point-at-infinity). private fun validatePublicKey(signatureScheme: SignatureScheme, key: PublicKey): Boolean { return when (key) { - is BCECPublicKey, is EdDSAPublicKey -> publicKeyOnCurve(signatureScheme, key) + is BCECPublicKey, is EdECPublicKey -> publicKeyOnCurve(signatureScheme, key) is BCRSAPublicKey -> key.modulus.bitLength() >= 2048 // Although the recommended RSA key size is 3072, we accept any key >= 2048bits. - is BCSphincs256PublicKey -> true - else -> throw IllegalArgumentException("Unsupported key type: ${key::class}") + else -> throw IllegalArgumentException("Unsupported key type: ${key.javaClass.name}") } } private val interner = PrivateInterner() private fun internPublicKey(key: PublicKey): PublicKey = PublicKeyCache.cachePublicKey(interner.intern(key)) - - private fun convertIfBCEdDSAPublicKey(key: PublicKey): PublicKey { - return internPublicKey(when (key) { - is BCEdDSAPublicKey -> EdDSAPublicKey(X509EncodedKeySpec(key.encoded)) - else -> key - }) - } - - private fun convertIfBCEdDSAPrivateKey(key: PrivateKey): PrivateKey { - return when (key) { - is BCEdDSAPrivateKey -> EdDSAPrivateKey(PKCS8EncodedKeySpec(key.encoded)) - else -> key - } - } - /** * Convert a public key to a supported implementation. * @param key a public key. @@ -1027,13 +970,11 @@ object Crypto { */ @JvmStatic fun toSupportedPublicKey(key: PublicKey): PublicKey { - return when (key) { - is BCECPublicKey -> internPublicKey(key) - is BCRSAPublicKey -> internPublicKey(key) - is BCSphincs256PublicKey -> internPublicKey(key) - is EdDSAPublicKey -> internPublicKey(key) - is CompositeKey -> internPublicKey(key) - is BCEdDSAPublicKey -> convertIfBCEdDSAPublicKey(key) + return when { + key is BCEdDSAPublicKey && key is EdECPublicKey -> internPublicKey(key) // The BC implementation is not public + key is BCECPublicKey -> internPublicKey(key) + key is BCRSAPublicKey -> internPublicKey(key) + key is CompositeKey -> internPublicKey(key) else -> decodePublicKey(key.encoded) } } @@ -1048,12 +989,10 @@ object Crypto { */ @JvmStatic fun toSupportedPrivateKey(key: PrivateKey): PrivateKey { - return when (key) { - is BCECPrivateKey -> key - is BCRSAPrivateKey -> key - is BCSphincs256PrivateKey -> key - is EdDSAPrivateKey -> key - is BCEdDSAPrivateKey -> convertIfBCEdDSAPrivateKey(key) + return when { + key is BCEdDSAPrivateKey && key is EdECPrivateKey -> key // The BC implementation is not public + key is BCECPrivateKey -> key + key is BCRSAPrivateKey -> key else -> decodePrivateKey(key.encoded) } } @@ -1095,8 +1034,4 @@ object Crypto { private fun setBouncyCastleRNG() { CryptoServicesRegistrar.setSecureRandom(newSecureRandom()) } - - private fun keyFactory(signatureScheme: SignatureScheme) = signatureScheme.getKeyFactory { - KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName]) - } } diff --git a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt index 3fc649f989..797123bf4d 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt @@ -3,7 +3,8 @@ package net.corda.core.crypto import net.corda.core.contracts.PrivacySalt -import net.corda.core.crypto.internal.platformSecureRandomFactory +import net.corda.core.crypto.internal.PlatformSecureRandomService +import net.corda.core.crypto.internal.cordaSecurityProvider import net.corda.core.serialization.SerializationDefaults import net.corda.core.serialization.serialize import net.corda.core.utilities.OpaqueBytes @@ -19,6 +20,7 @@ import java.security.PublicKey import java.security.SecureRandom import java.security.SecureRandomSpi import java.security.SignatureException +import kotlin.math.abs /** * Utility to simplify the act of signing a byte array. @@ -231,7 +233,12 @@ object DummySecureRandom : SecureRandom(DummySecureRandomSpi(), null) * which should never happen and suggests an unusual JVM or non-standard Java library. */ @Throws(NoSuchAlgorithmException::class) -fun newSecureRandom(): SecureRandom = platformSecureRandomFactory() +fun newSecureRandom(): SecureRandom = sharedSecureRandom + +// This is safe to share because of the underlying implementation of SecureRandomSpi +private val sharedSecureRandom: SecureRandom by lazy(LazyThreadSafetyMode.PUBLICATION) { + SecureRandom.getInstance(PlatformSecureRandomService.ALGORITHM, cordaSecurityProvider) +} /** * Returns a random positive non-zero long generated using a secure RNG. This function sacrifies a bit of entropy in order @@ -239,7 +246,7 @@ fun newSecureRandom(): SecureRandom = platformSecureRandomFactory() */ fun random63BitValue(): Long { while (true) { - val candidate = Math.abs(newSecureRandom().nextLong()) + val candidate = abs(newSecureRandom().nextLong()) // No need to check for -0L if (candidate != 0L && candidate != Long.MIN_VALUE) { return candidate diff --git a/core/src/main/kotlin/net/corda/core/crypto/SecureHash.kt b/core/src/main/kotlin/net/corda/core/crypto/SecureHash.kt index a930aa254d..1d02a19120 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/SecureHash.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/SecureHash.kt @@ -11,6 +11,7 @@ import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.parseAsHex import net.corda.core.utilities.toHexString import java.security.MessageDigest +import java.util.Locale import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentMap import java.util.function.Supplier @@ -182,7 +183,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) { */ @JvmStatic fun parse(str: String?): SHA256 { - return str?.toUpperCase()?.parseAsHex()?.let { + return str?.uppercase(Locale.getDefault())?.parseAsHex()?.let { when (it.size) { 32 -> interner.intern(SHA256(it)) else -> throw IllegalArgumentException("Provided string is ${it.size} bytes not 32 bytes in hex: $str") diff --git a/core/src/main/kotlin/net/corda/core/crypto/SignatureScheme.kt b/core/src/main/kotlin/net/corda/core/crypto/SignatureScheme.kt index 27b3fc4750..b4d6eeb2f0 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/SignatureScheme.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/SignatureScheme.kt @@ -1,5 +1,6 @@ package net.corda.core.crypto +import net.corda.core.crypto.internal.providerMap import org.bouncycastle.asn1.x509.AlgorithmIdentifier import java.security.KeyFactory import java.security.Signature @@ -9,12 +10,12 @@ import java.security.spec.AlgorithmParameterSpec * This class is used to define a digital signature scheme. * @param schemeNumberID unique number ID for better efficiency on-wire serialisation. * @param schemeCodeName unique code name for this signature scheme (e.g. RSA_SHA256, ECDSA_SECP256K1_SHA256, ECDSA_SECP256R1_SHA256, - * EDDSA_ED25519_SHA512, SPHINCS-256_SHA512). + * EDDSA_ED25519_SHA512). * @param signatureOID ASN.1 algorithm identifier of the signature algorithm (e.g 1.3.101.112 for EdDSA) * @param alternativeOIDs ASN.1 algorithm identifiers for keys of the signature, where we want to map multiple keys to * the same signature scheme. * @param providerName the provider's name (e.g. "BC"). - * @param algorithmName which signature algorithm is used (e.g. RSA, ECDSA. EdDSA, SPHINCS-256). + * @param algorithmName which signature algorithm is used (e.g. RSA, ECDSA. EdDSA). * @param signatureName a signature-scheme name as required to create [Signature] objects (e.g. "SHA256withECDSA") * @param algSpec parameter specs for the underlying algorithm. Note that RSA is defined by the key size rather than algSpec. * eg. ECGenParameterSpec("secp256k1"). @@ -36,11 +37,6 @@ data class SignatureScheme( @Volatile private var memoizedKeyFactory: KeyFactory? = null - internal fun getKeyFactory(factoryFactory: () -> KeyFactory): KeyFactory { - return memoizedKeyFactory ?: run { - val newFactory = factoryFactory() - memoizedKeyFactory = newFactory - newFactory - } - } + internal val keyFactory: KeyFactory + get() = memoizedKeyFactory ?: KeyFactory.getInstance(algorithmName, providerMap[providerName]).also { memoizedKeyFactory = it } } diff --git a/core/src/main/kotlin/net/corda/core/crypto/internal/Curve25519.kt b/core/src/main/kotlin/net/corda/core/crypto/internal/Curve25519.kt new file mode 100644 index 0000000000..7b5a7dd9f8 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/crypto/internal/Curve25519.kt @@ -0,0 +1,46 @@ + +package net.corda.core.crypto.internal + +import java.math.BigInteger +import java.math.BigInteger.TWO +import java.security.spec.EdECPoint + +/** + * Parameters for Curve25519, as defined in https://www.rfc-editor.org/rfc/rfc7748#section-4.1. + */ +@Suppress("MagicNumber") +object Curve25519 { + val p = TWO.pow(255) - 19.toBigInteger() // 2^255 - 19 + val d = ModP(BigInteger("37095705934669439343138083508754565189542113879843219016388785533085940283555")) + + val EdECPoint.isOnCurve25519: Boolean + // https://www.rfc-editor.org/rfc/rfc8032.html#section-5.1.3 + get() { + if (y >= p) return false + val ySquared = ModP(y).pow(TWO) + val u = ySquared - 1 // y^2 - 1 (mod p) + val v = d * ySquared + 1 // dy^2 + 1 (mod p) + val x = (u / v).pow((p + 3.toBigInteger()).shiftRight(3)) // (u/v)^((p+3)/8) (mod p) + val vxSquared = v * x.pow(TWO) + return vxSquared == u || vxSquared == -u + } + + fun BigInteger.modP(): ModP = ModP(mod(p)) + + private fun BigInteger.additiveInverse(): BigInteger = p - this + + data class ModP(val value: BigInteger) : Comparable { + fun pow(exponent: BigInteger): ModP = ModP(value.modPow(exponent, p)) + + operator fun unaryMinus(): ModP = ModP(value.additiveInverse()) + operator fun plus(other: ModP): ModP = (this.value + other.value).modP() + operator fun plus(other: Int): ModP = (this.value + other.toBigInteger()).modP() + operator fun minus(other: ModP): ModP = (this.value + other.value.additiveInverse()).modP() + operator fun minus(other: Int): ModP = (this.value + other.toBigInteger().additiveInverse()).modP() + operator fun times(other: ModP): ModP = (this.value * other.value).modP() + operator fun div(other: ModP): ModP = (this.value * other.value.modInverse(p)).modP() + + override fun compareTo(other: ModP): Int = this.value.compareTo(other.value) + override fun toString(): String = "$value (mod Curve25519 p)" + } +} diff --git a/core/src/main/kotlin/net/corda/core/crypto/internal/DigestAlgorithmFactory.kt b/core/src/main/kotlin/net/corda/core/crypto/internal/DigestAlgorithmFactory.kt index 892506aa76..98510ebe2f 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/internal/DigestAlgorithmFactory.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/internal/DigestAlgorithmFactory.kt @@ -1,10 +1,11 @@ package net.corda.core.crypto.internal import net.corda.core.crypto.DigestAlgorithm -import java.lang.reflect.Constructor +import net.corda.core.internal.loadClassOfType import java.security.MessageDigest import java.security.NoSuchAlgorithmException -import java.util.* +import java.util.Collections +import java.util.Locale import java.util.concurrent.ConcurrentHashMap sealed class DigestAlgorithmFactory { @@ -28,9 +29,8 @@ sealed class DigestAlgorithmFactory { } private class CustomAlgorithmFactory(className: String) : DigestAlgorithmFactory() { - val constructor: Constructor = Class.forName(className, false, javaClass.classLoader) - .asSubclass(DigestAlgorithm::class.java) - .getConstructor() + private val constructor = loadClassOfType(className, false, javaClass.classLoader).getConstructor() + override val algorithm: String = constructor.newInstance().algorithm override fun create(): DigestAlgorithm { @@ -45,7 +45,7 @@ sealed class DigestAlgorithmFactory { private val factories = ConcurrentHashMap() private fun check(algorithm: String) { - require(algorithm.toUpperCase() == algorithm) { "Hash algorithm name $this must be in the upper case" } + require(algorithm.uppercase(Locale.getDefault()) == algorithm) { "Hash algorithm name $this must be in the upper case" } require(algorithm !in BANNED) { "$algorithm is forbidden!" } } diff --git a/core/src/main/kotlin/net/corda/core/crypto/internal/Instances.kt b/core/src/main/kotlin/net/corda/core/crypto/internal/Instances.kt index fc7336f855..64b5feef78 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/internal/Instances.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/internal/Instances.kt @@ -26,9 +26,8 @@ object Instances { private val signatureFactory: SignatureFactory = CachingSignatureFactory() // The provider itself is a very bad key class as hashCode() is expensive and contended. So use name and version instead. - private data class SignatureKey(val algorithm: String, val providerName: String?, val providerVersion: Double?) { - constructor(algorithm: String, provider: Provider?) : this(algorithm, provider?.name, - @Suppress("DEPRECATION") provider?.version) // JDK11: should replace with getVersionStr() (since 9) + private data class SignatureKey(val algorithm: String, val providerName: String?, val providerVersion: String?) { + constructor(algorithm: String, provider: Provider?) : this(algorithm, provider?.name, provider?.versionStr) } private class CachingSignatureFactory : SignatureFactory { diff --git a/core/src/main/kotlin/net/corda/core/crypto/internal/PlatformSecureRandom.kt b/core/src/main/kotlin/net/corda/core/crypto/internal/PlatformSecureRandom.kt index 3a0062b251..951e4a1cfd 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/internal/PlatformSecureRandom.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/internal/PlatformSecureRandom.kt @@ -2,8 +2,6 @@ package net.corda.core.crypto.internal import io.netty.util.concurrent.FastThreadLocal -import net.corda.core.crypto.DummySecureRandom -import net.corda.core.utilities.SgxSupport import net.corda.core.utilities.loggerFor import org.apache.commons.lang3.SystemUtils import java.io.DataInputStream @@ -14,38 +12,25 @@ import java.io.InputStream import java.security.Provider import java.security.SecureRandom import java.security.SecureRandomSpi - -/** - * This has been migrated into a separate class so that it - * is easier to delete from the core-deterministic module. - */ -internal val platformSecureRandom: () -> SecureRandom = when { - SgxSupport.isInsideEnclave -> { - { DummySecureRandom } - } - else -> { - { sharedSecureRandom } - } -} +import kotlin.system.exitProcess class PlatformSecureRandomService(provider: Provider) - : Provider.Service(provider, "SecureRandom", algorithm, PlatformSecureRandomSpi::javaClass.name, null, null) { + : Provider.Service(provider, "SecureRandom", ALGORITHM, PlatformSecureRandomSpi::class.java.name, null, mapOf("ThreadSafe" to "true")) { companion object { - const val algorithm = "CordaPRNG" + const val ALGORITHM = "CordaPRNG" + private val logger = loggerFor() } private val instance: SecureRandomSpi = if (SystemUtils.IS_OS_LINUX) tryAndUseLinuxSecureRandomSpi() else PlatformSecureRandomSpi() - @Suppress("TooGenericExceptionCaught", "TooGenericExceptionThrown") private fun tryAndUseLinuxSecureRandomSpi(): SecureRandomSpi = try { LinuxSecureRandomSpi() } catch (e: Exception) { logger.error("Unable to initialise LinuxSecureRandomSpi. The exception logged with this message might assist with diagnosis." + " The process will now exit.", e) - System.exit(1) - throw RuntimeException("Never reached, but calms the compiler.") + exitProcess(1) } override fun newInstance(constructorParameter: Any?) = instance @@ -63,7 +48,7 @@ private class PlatformSecureRandomSpi : SecureRandomSpi() { override fun engineGenerateSeed(numBytes: Int): ByteArray = secureRandom.generateSeed(numBytes) } -@Suppress("TooGenericExceptionCaught", "TooGenericExceptionThrown") +@Suppress("TooGenericExceptionThrown") private class LinuxSecureRandomSpi : SecureRandomSpi() { private fun openURandom(): InputStream { try { @@ -88,8 +73,3 @@ private class LinuxSecureRandomSpi : SecureRandomSpi() { override fun engineGenerateSeed(numBytes: Int): ByteArray = ByteArray(numBytes).apply { engineNextBytes(this) } } - -// This is safe to share because of the underlying implementation of SecureRandomSpi -private val sharedSecureRandom: SecureRandom by lazy(LazyThreadSafetyMode.PUBLICATION) { - SecureRandom.getInstance(PlatformSecureRandomService.algorithm) -} diff --git a/core/src/main/kotlin/net/corda/core/crypto/internal/ProviderMap.kt b/core/src/main/kotlin/net/corda/core/crypto/internal/ProviderMap.kt index 0ac52cdedb..e68a6bfc8b 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/internal/ProviderMap.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/internal/ProviderMap.kt @@ -1,24 +1,16 @@ package net.corda.core.crypto.internal import net.corda.core.crypto.CordaSecurityProvider -import net.corda.core.crypto.Crypto.EDDSA_ED25519_SHA512 -import net.corda.core.crypto.Crypto.decodePrivateKey -import net.corda.core.crypto.Crypto.decodePublicKey -import net.corda.core.internal.X509EdDSAEngine -import net.i2p.crypto.eddsa.EdDSAEngine -import net.i2p.crypto.eddsa.EdDSASecurityProvider -import org.bouncycastle.asn1.ASN1ObjectIdentifier -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo -import org.bouncycastle.jcajce.provider.asymmetric.ec.AlgorithmParametersSpi -import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter import org.bouncycastle.jce.provider.BouncyCastleProvider -import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider import java.security.Provider -import java.security.SecureRandom import java.security.Security import java.util.Collections.unmodifiableMap +val sunEcProvider = checkNotNull(Security.getProvider("SunEC")).also { + // Insert Secp256k1SupportProvider just in-front of SunEC for adding back support for secp256k1 + Security.insertProviderAt(Secp256k1SupportProvider(), Security.getProviders().indexOf(it)) +} + val cordaSecurityProvider = CordaSecurityProvider().also { // Among the others, we should register [CordaSecurityProvider] as the first provider, to ensure that when invoking [SecureRandom()] // the [platformSecureRandom] is returned (which is registered in CordaSecurityProvider). @@ -28,37 +20,16 @@ val cordaSecurityProvider = CordaSecurityProvider().also { // a SecureRandom implementation. Security.insertProviderAt(it, 1) // The position is 1-based. } -// OID taken from https://tools.ietf.org/html/draft-ietf-curdle-pkix-00 -val `id-Curve25519ph` = ASN1ObjectIdentifier("1.3.101.112") -val cordaBouncyCastleProvider = BouncyCastleProvider().apply { - putAll(EdDSASecurityProvider()) - // Override the normal EdDSA engine with one which can handle X509 keys. - put("Signature.${EdDSAEngine.SIGNATURE_ALGORITHM}", X509EdDSAEngine::class.java.name) - put("Signature.Ed25519", X509EdDSAEngine::class.java.name) - addKeyInfoConverter(`id-Curve25519ph`, object : AsymmetricKeyInfoConverter { - override fun generatePublic(keyInfo: SubjectPublicKeyInfo) = decodePublicKey(EDDSA_ED25519_SHA512, keyInfo.encoded) - override fun generatePrivate(keyInfo: PrivateKeyInfo) = decodePrivateKey(EDDSA_ED25519_SHA512, keyInfo.encoded) - }) - // Required due to [X509CRL].verify() reported issues in network-services after BC 1.60 update. - put("AlgorithmParameters.SHA256WITHECDSA", AlgorithmParametersSpi::class.java.name) -}.also { - // This registration is needed for reading back EdDSA key from java keystore. - // TODO: Find a way to make JKS work with bouncy castle provider or implement our own provide so we don't have to register bouncy castle provider. + +val cordaBouncyCastleProvider = BouncyCastleProvider().also { Security.addProvider(it) } -val bouncyCastlePQCProvider = BouncyCastlePQCProvider().apply { - require(name == "BCPQC") { "Invalid PQCProvider name" } -}.also { - Security.addProvider(it) -} // This map is required to defend against users that forcibly call Security.addProvider / Security.removeProvider // that could cause unexpected and suspicious behaviour. // i.e. if someone removes a Provider and then he/she adds a new one with the same name. // The val is immutable to avoid any harmful state changes. internal val providerMap: Map = unmodifiableMap( - listOf(cordaBouncyCastleProvider, cordaSecurityProvider, bouncyCastlePQCProvider) + listOf(cordaBouncyCastleProvider, cordaSecurityProvider) .associateByTo(LinkedHashMap(), Provider::getName) ) - -fun platformSecureRandomFactory(): SecureRandom = platformSecureRandom() // To minimise diff of CryptoUtils against open-source. diff --git a/core/src/main/kotlin/net/corda/core/crypto/internal/Secp256k1SupportProvider.kt b/core/src/main/kotlin/net/corda/core/crypto/internal/Secp256k1SupportProvider.kt new file mode 100644 index 0000000000..fc0d4f09b0 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/crypto/internal/Secp256k1SupportProvider.kt @@ -0,0 +1,177 @@ +@file:Suppress("MagicNumber") + +package net.corda.core.crypto.internal + +import net.corda.core.crypto.Crypto +import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util +import org.bouncycastle.jce.ECNamedCurveTable +import org.bouncycastle.jce.provider.BouncyCastleProvider +import org.bouncycastle.jce.spec.ECNamedCurveSpec +import java.security.AlgorithmParameters +import java.security.KeyPair +import java.security.KeyPairGeneratorSpi +import java.security.PrivateKey +import java.security.Provider +import java.security.PublicKey +import java.security.SecureRandom +import java.security.Signature +import java.security.SignatureSpi +import java.security.interfaces.ECPrivateKey +import java.security.interfaces.ECPublicKey +import java.security.spec.AlgorithmParameterSpec +import java.security.spec.ECParameterSpec +import java.security.spec.NamedParameterSpec + +/** + * Augment the SunEC provider with secp256k1 curve support by delegating to [BouncyCastleProvider] when secp256k1 keys or params are + * requested. Otherwise delegates to SunEC. + * + * Note, this class only exists to cater for the scenerio where [Signature.getInstance] is called directly without a provider (which happens + * to be the JCE recommendation) and thus the `SunEC` provider is selected. Bouncy Castle is already automatically used via [Crypto]. + */ +class Secp256k1SupportProvider : Provider("Secp256k1Support", "1.0", "Augmenting SunEC with support for the secp256k1 curve via BC") { + init { + put("Signature.SHA256withECDSA", Secp256k1SupportSignatureSpi::class.java.name) + put("KeyPairGenerator.EC", Secp256k1SupportKeyPairGeneratorSpi::class.java.name) + put("AlgorithmParameters.EC", "sun.security.util.ECParameters") + put("KeyFactory.EC", "sun.security.ec.ECKeyFactory") + } + + class Secp256k1SupportSignatureSpi : SignatureSpi() { + private lateinit var sunEc: Signature + private lateinit var bc: Signature + private lateinit var selected: Signature + + override fun engineInitVerify(publicKey: PublicKey?) { + selectProvider((publicKey as? ECPublicKey)?.params) + selected.initVerify(publicKey) + } + + override fun engineInitSign(privateKey: PrivateKey?) { + selectProvider((privateKey as? ECPrivateKey)?.params) + selected.initSign(privateKey) + } + + override fun engineSetParameter(params: AlgorithmParameterSpec?) { + selectProvider(params) + // The BC implementation throws UnsupportedOperationException, so we just avoid calling it. + if (selected !== bc) { + selected.setParameter(params) + } + } + + private fun selectProvider(params: AlgorithmParameterSpec?) { + if (params.isSecp256k1) { + if (!::bc.isInitialized) { + bc = Signature.getInstance("SHA256withECDSA", cordaBouncyCastleProvider) + } + selected = bc + } else { + selectSunEc() + } + } + + private fun selectSunEc() { + if (!::sunEc.isInitialized) { + sunEc = Signature.getInstance("SHA256withECDSA", sunEcProvider) + } + selected = sunEc + } + + override fun engineUpdate(b: Byte) { + defaultToSunEc() + selected.update(b) + } + + override fun engineUpdate(b: ByteArray?, off: Int, len: Int) { + defaultToSunEc() + selected.update(b, off, len) + } + + override fun engineSign(): ByteArray { + defaultToSunEc() + return selected.sign() + } + + override fun engineVerify(sigBytes: ByteArray?): Boolean { + defaultToSunEc() + return selected.verify(sigBytes) + } + + override fun engineGetParameters(): AlgorithmParameters { + defaultToSunEc() + return selected.parameters + } + + @Deprecated("Deprecated in Java") + @Suppress("DEPRECATION") + override fun engineSetParameter(param: String?, value: Any?) { + defaultToSunEc() + selected.setParameter(param, value) + } + + @Deprecated("Deprecated in Java") + @Suppress("DEPRECATION") + override fun engineGetParameter(param: String?): Any { + defaultToSunEc() + return selected.getParameter(param) + } + + private fun defaultToSunEc() { + // Even though it's probably a bug to start using the Signature object without first calling one of the intialize methods, + // default it to SunEC provider anyway and let it deal with the issue. + if (!::selected.isInitialized) { + selectSunEc() + } + } + } + + class Secp256k1SupportKeyPairGeneratorSpi : KeyPairGeneratorSpi() { + // The methods in KeyPairGeneratorSpi are public, which allows us to directly call them. This is not the case with SignatureSpi (above). + private lateinit var sunEc: KeyPairGeneratorSpi + private lateinit var bc: KeyPairGeneratorSpi + private lateinit var selected: KeyPairGeneratorSpi + + override fun initialize(keysize: Int, random: SecureRandom?) { + selectSunEc() + selected.initialize(keysize, random) + } + + override fun initialize(params: AlgorithmParameterSpec?, random: SecureRandom?) { + if (params.isSecp256k1) { + if (!::bc.isInitialized) { + bc = org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi.EC() + } + selected = bc + } else { + selectSunEc() + } + selected.initialize(params, random) + } + + private fun selectSunEc() { + if (!::sunEc.isInitialized) { + sunEc = sunEcProvider.getService("KeyPairGenerator", "EC").newInstance(null) as KeyPairGeneratorSpi + } + selected = sunEc + } + + override fun generateKeyPair(): KeyPair { + if (!::selected.isInitialized) { + // In-case initialize wasn't first called, default to SunEC + selectSunEc() + } + return selected.generateKeyPair() + } + } +} + +private val bcSecp256k1Spec = ECNamedCurveTable.getParameterSpec("secp256k1") + +val AlgorithmParameterSpec?.isSecp256k1: Boolean + get() = when (this) { + is NamedParameterSpec -> name.equals("secp256k1", ignoreCase = true) + is ECNamedCurveSpec -> name.equals("secp256k1", ignoreCase = true) + is ECParameterSpec -> EC5Util.convertSpec(this) == bcSecp256k1Spec + else -> false + } diff --git a/core/src/main/kotlin/net/corda/core/flows/CollectSignaturesFlow.kt b/core/src/main/kotlin/net/corda/core/flows/CollectSignaturesFlow.kt index f3ad937530..609c710f35 100644 --- a/core/src/main/kotlin/net/corda/core/flows/CollectSignaturesFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/CollectSignaturesFlow.kt @@ -8,6 +8,7 @@ import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.identity.groupPublicKeysByWellKnownParty +import net.corda.core.internal.mapToSet import net.corda.core.node.ServiceHub import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction @@ -67,12 +68,12 @@ import java.security.PublicKey class CollectSignaturesFlow @JvmOverloads constructor(val partiallySignedTx: SignedTransaction, val sessionsToCollectFrom: Collection, val myOptionalKeys: Iterable?, - override val progressTracker: ProgressTracker = CollectSignaturesFlow.tracker()) : FlowLogic() { + override val progressTracker: ProgressTracker = tracker()) : FlowLogic() { @JvmOverloads constructor( partiallySignedTx: SignedTransaction, sessionsToCollectFrom: Collection, - progressTracker: ProgressTracker = CollectSignaturesFlow.tracker() + progressTracker: ProgressTracker = tracker() ) : this(partiallySignedTx, sessionsToCollectFrom, null, progressTracker) companion object { @@ -90,7 +91,7 @@ class CollectSignaturesFlow @JvmOverloads constructor(val partiallySignedTx: Sig // Check the signatures which have already been provided and that the transaction is valid. // Usually just the Initiator and possibly an oracle would have signed at this point. val myKeys: Iterable = myOptionalKeys ?: listOf(ourIdentity.owningKey) - val signed = partiallySignedTx.sigs.map { it.by } + val signed = partiallySignedTx.sigs.mapToSet { it.by } val notSigned = partiallySignedTx.tx.requiredSigningKeys - signed // One of the signatures collected so far MUST be from the initiator of this flow. @@ -99,8 +100,7 @@ class CollectSignaturesFlow @JvmOverloads constructor(val partiallySignedTx: Sig } // The signatures must be valid and the transaction must be valid. - partiallySignedTx.verifySignaturesExcept(notSigned) - partiallySignedTx.tx.toLedgerTransaction(serviceHub).verify() + partiallySignedTx.verify(serviceHub, checkSufficientSignatures = false) // Determine who still needs to sign. progressTracker.currentStep = COLLECTING @@ -235,7 +235,7 @@ class CollectSignatureFlow(val partiallySignedTx: SignedTransaction, val session * - Call the flow via [FlowLogic.subFlow] * - The flow returns the transaction signed with the additional signature. * - * Example - checking and signing a transaction involving a [net.corda.core.contracts.DummyContract], see + * Example - checking and signing a transaction involving a `DummyContract`, see * CollectSignaturesFlowTests.kt for further examples: * * class Responder(val otherPartySession: FlowSession): FlowLogic() { @@ -259,7 +259,7 @@ class CollectSignatureFlow(val partiallySignedTx: SignedTransaction, val session * @param otherSideSession The session which is providing you a transaction to sign. */ abstract class SignTransactionFlow @JvmOverloads constructor(val otherSideSession: FlowSession, - override val progressTracker: ProgressTracker = SignTransactionFlow.tracker()) : FlowLogic() { + override val progressTracker: ProgressTracker = tracker()) : FlowLogic() { companion object { object RECEIVING : ProgressTracker.Step("Receiving transaction proposal for signing.") @@ -285,14 +285,12 @@ abstract class SignTransactionFlow @JvmOverloads constructor(val otherSideSessio progressTracker.currentStep = VERIFYING // Check that the Responder actually needs to sign. checkMySignaturesRequired(stx, signingKeys) - // Check the signatures which have already been provided. Usually the Initiators and possibly an Oracle's. - checkSignatures(stx) - stx.tx.toLedgerTransaction(serviceHub).verify() + stx.verify(serviceHub, checkSufficientSignatures = false) // Perform some custom verification over the transaction. try { checkTransaction(stx) } catch (e: Exception) { - if (e is IllegalStateException || e is IllegalArgumentException || e is AssertionError) + if (e is IllegalStateException || e is IllegalArgumentException) throw FlowException(e) else throw e @@ -308,14 +306,6 @@ abstract class SignTransactionFlow @JvmOverloads constructor(val otherSideSessio return stx + mySignatures } - @Suspendable - private fun checkSignatures(stx: SignedTransaction) { - val signed = stx.sigs.map { it.by } - val allSigners = stx.tx.requiredSigningKeys - val notSigned = allSigners - signed - stx.verifySignaturesExcept(notSigned) - } - /** * The [checkTransaction] method allows the caller of this flow to provide some additional checks over the proposed * transaction received from the counterparty. For example: diff --git a/core/src/main/kotlin/net/corda/core/flows/FinalityFlow.kt b/core/src/main/kotlin/net/corda/core/flows/FinalityFlow.kt index a2f3e23609..2b0afbb95a 100644 --- a/core/src/main/kotlin/net/corda/core/flows/FinalityFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/FinalityFlow.kt @@ -11,12 +11,14 @@ import net.corda.core.internal.PlatformVersionSwitches import net.corda.core.internal.ServiceHubCoreInternal import net.corda.core.internal.pushToLoggingContext import net.corda.core.internal.telemetry.telemetryServiceInternal +import net.corda.core.internal.verification.toVerifyingServiceHub import net.corda.core.internal.warnOnce import net.corda.core.node.StatesToRecord import net.corda.core.node.StatesToRecord.ONLY_RELEVANT import net.corda.core.serialization.DeprecatedConstructorForDeserialization import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.SignedTransaction +import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.Try import net.corda.core.utilities.debug @@ -170,6 +172,7 @@ class FinalityFlow private constructor(val transaction: SignedTransaction, @Suppress("ComplexMethod", "NestedBlockDepth") @Throws(NotaryException::class) override fun call(): SignedTransaction { + require(transaction.coreTransaction is WireTransaction) // Sanity check if (!newApi) { logger.warnOnce("The current usage of FinalityFlow is unsafe. Please consider upgrading your CorDapp to use " + "FinalityFlow with FlowSessions. (${serviceHub.getAppContext().cordapp.info})") @@ -447,9 +450,12 @@ class FinalityFlow private constructor(val transaction: SignedTransaction, // The notary signature(s) are allowed to be missing but no others. if (notary != null) transaction.verifySignaturesExcept(notary.owningKey) else transaction.verifyRequiredSignatures() // TODO= [CORDA-3267] Remove duplicate signature verification - val ltx = transaction.toLedgerTransaction(serviceHub, false) - ltx.verify() - return ltx + val ltx = transaction.verifyInternal(serviceHub.toVerifyingServiceHub(), checkSufficientSignatures = false) + // verifyInternal returns null if the transaction was verified externally, which *could* happen on a very odd scenerio of a 4.11 + // node creating the transaction but a 4.12 kicking off finality. In that case, we still want a LedgerTransaction object for + // recording to the vault, etc. Note that calling verify() on this will fail as it doesn't have the necessary non-legacy attachments + // for verification by the node. + return ltx ?: transaction.toLedgerTransaction(serviceHub, checkSufficientSignatures = false) } } diff --git a/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt b/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt index 7520eae9ce..61f4266ed1 100644 --- a/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt +++ b/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt @@ -573,7 +573,7 @@ abstract class FlowLogic { } private fun associateSessionsToReceiveType(receiveType: Class, sessions: List): Map> { - return sessions.associateByTo(LinkedHashMap(), { it }, { receiveType }) + return sessions.associateWithTo(LinkedHashMap()) { receiveType } } private fun castMapValuesToKnownType(map: Map>): List> { diff --git a/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt b/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt index 173107dd5f..91bc460bce 100644 --- a/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt @@ -11,6 +11,8 @@ import net.corda.core.internal.NetworkParametersStorage import net.corda.core.internal.PlatformVersionSwitches import net.corda.core.internal.RetrieveAnyTransactionPayload import net.corda.core.internal.ServiceHubCoreInternal +import net.corda.core.internal.getRequiredTransaction +import net.corda.core.internal.mapToSet import net.corda.core.internal.readFully import net.corda.core.node.ServicesForResolution import net.corda.core.node.StatesToRecord @@ -169,13 +171,10 @@ open class DataVendingFlow(val otherSessions: Set, val payload: Any is SignedTransaction -> TransactionAuthorisationFilter().addAuthorised(getInputTransactions(payload)) is RetrieveAnyTransactionPayload -> TransactionAuthorisationFilter(acceptAll = true) is List<*> -> TransactionAuthorisationFilter().addAuthorised(payload.flatMap { someObject -> - if (someObject is StateAndRef<*>) { - getInputTransactions(serviceHub.validatedTransactions.getTransaction(someObject.ref.txhash)!!) + someObject.ref.txhash - } - else if (someObject is NamedByHash) { - setOf(someObject.id) - } else { - throw Exception("Unknown payload type: ${someObject!!::class.java} ?") + when (someObject) { + is StateAndRef<*> -> getInputTransactions(serviceHub.getRequiredTransaction(someObject.ref.txhash)) + someObject.ref.txhash + is NamedByHash -> setOf(someObject.id) + else -> throw Exception("Unknown payload type: ${someObject!!::class.java} ?") } }.toSet()) else -> throw Exception("Unknown payload type: ${payload::class.java} ?") @@ -308,7 +307,7 @@ open class DataVendingFlow(val otherSessions: Set, val payload: Any @Suspendable private fun getInputTransactions(tx: SignedTransaction): Set { - return tx.inputs.map { it.txhash }.toSet() + tx.references.map { it.txhash }.toSet() + return tx.inputs.mapToSet { it.txhash } + tx.references.mapToSet { it.txhash } } private class TransactionAuthorisationFilter(private val authorisedTransactions: MutableSet = mutableSetOf(), val acceptAll: Boolean = false) { diff --git a/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt b/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt index 4fdea7cda2..955b84ca3c 100644 --- a/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt +++ b/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt @@ -1,7 +1,6 @@ package net.corda.core.identity import net.corda.core.internal.CertRole -import net.corda.core.internal.uncheckedCast import net.corda.core.internal.validate import net.corda.core.serialization.CordaSerializable import java.security.PublicKey @@ -27,7 +26,7 @@ class PartyAndCertificate(val certPath: CertPath) { require(certs.size >= 2) { "Certificate path must at least include subject and issuing certificates" } certificate = certs[0] as X509Certificate val role = CertRole.extract(certificate) - require(role?.isIdentity ?: false) { "Party certificate ${certificate.subjectDN} does not have a well known or confidential identity role. Found: $role" } + require(role?.isIdentity ?: false) { "Party certificate ${certificate.getSubjectX500Principal()} does not have a well known or confidential identity role. Found: $role" } } @Transient @@ -47,12 +46,13 @@ class PartyAndCertificate(val certPath: CertPath) { fun verify(trustAnchor: TrustAnchor): PKIXCertPathValidatorResult = verify(setOf(trustAnchor)) /** Verify the certificate path is valid against one of the specified trust anchors. */ + @Suppress("UNCHECKED_CAST") fun verify(trustAnchors: Set): PKIXCertPathValidatorResult { val result = certPath.validate(trustAnchors) // Apply Corda-specific validity rules to the chain. This only applies to chains with any roles present, so // an all-null chain is in theory valid. var parentRole: CertRole? = CertRole.extract(result.trustAnchor.trustedCert) - val certChain: List = uncheckedCast(certPath.certificates) + val certChain = certPath.certificates as List for (certIdx in (0 until certChain.size).reversed()) { val certificate = certChain[certIdx] val role = CertRole.extract(certificate) @@ -61,7 +61,7 @@ class PartyAndCertificate(val certPath: CertPath) { throw CertPathValidatorException("Child certificate whose issuer includes a Corda role, must also specify Corda role") } if (!role.isValidParent(parentRole)) { - val certificateString = certificate.subjectDN.toString() + val certificateString = certificate.getSubjectX500Principal().toString() throw CertPathValidatorException("The issuing certificate for $certificateString has role $parentRole, expected one of ${role.validParents}") } } diff --git a/core/src/main/kotlin/net/corda/core/internal/AbstractAttachment.kt b/core/src/main/kotlin/net/corda/core/internal/AbstractAttachment.kt index d5d25bc6cc..a07d9b1f7a 100644 --- a/core/src/main/kotlin/net/corda/core/internal/AbstractAttachment.kt +++ b/core/src/main/kotlin/net/corda/core/internal/AbstractAttachment.kt @@ -11,6 +11,7 @@ import java.io.IOException import java.io.InputStream import java.io.OutputStream import java.security.PublicKey +import java.util.Locale import java.util.jar.JarInputStream const val DEPLOYED_CORDAPP_UPLOADER = "app" @@ -60,18 +61,19 @@ abstract class AbstractAttachment(dataLoader: () -> ByteArray, val uploader: Str openAsJAR().use(JarSignatureCollector::collectSigners) } + @Suppress("OVERRIDE_DEPRECATION") override val signers: List by lazy { openAsJAR().use(JarSignatureCollector::collectSigningParties) } override fun equals(other: Any?) = other === this || other is Attachment && other.id == this.id override fun hashCode() = id.hashCode() - override fun toString() = "${javaClass.simpleName}(id=$id)" + override fun toString() = toSimpleString() } @Throws(IOException::class) fun JarInputStream.extractFile(path: String, outputTo: OutputStream) { - fun String.norm() = toLowerCase().split('\\', '/') // XXX: Should this really be locale-sensitive? + fun String.norm() = lowercase(Locale.getDefault()).split('\\', '/') // XXX: Should this really be locale-sensitive? val p = path.norm() while (true) { val e = nextJarEntry ?: break diff --git a/core/src/main/kotlin/net/corda/core/internal/ClassLoadingUtils.kt b/core/src/main/kotlin/net/corda/core/internal/ClassLoadingUtils.kt index e7834fd567..2891a7a7fb 100644 --- a/core/src/main/kotlin/net/corda/core/internal/ClassLoadingUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/ClassLoadingUtils.kt @@ -21,8 +21,7 @@ import net.corda.core.serialization.internal.AttachmentURLStreamHandlerFactory.a fun createInstancesOfClassesImplementing(classloader: ClassLoader, clazz: Class, classVersionRange: IntRange? = null): Set { return getNamesOfClassesImplementing(classloader, clazz, classVersionRange) - .map { Class.forName(it, false, classloader).asSubclass(clazz) } - .mapTo(LinkedHashSet()) { it.kotlin.objectOrNewInstance() } + .mapToSet { loadClassOfType(clazz, it, false, classloader).kotlin.objectOrNewInstance() } } /** @@ -34,24 +33,40 @@ fun createInstancesOfClassesImplementing(classloader: ClassLoader, claz * @return names of the identified classes. * @throws UnsupportedClassVersionError if the class version is not within range. */ -fun getNamesOfClassesImplementing(classloader: ClassLoader, clazz: Class, - classVersionRange: IntRange? = null): Set { - return ClassGraph().overrideClassLoaders(classloader) - .enableURLScheme(attachmentScheme) - .ignoreParentClassLoaders() - .enableClassInfo() - .pooledScan() - .use { result -> - classVersionRange?.let { - result.allClasses.firstOrNull { c -> c.classfileMajorVersion !in classVersionRange }?.also { - throw UnsupportedClassVersionError("Class ${it.name} found in ${it.classpathElementURL} " + - "has an unsupported class version of ${it.classfileMajorVersion}") +fun getNamesOfClassesImplementing(classloader: ClassLoader, clazz: Class, classVersionRange: IntRange? = null): Set { + val classGraph = ClassGraph() + if (classloader !== ClassLoader.getSystemClassLoader()) { + classGraph.overrideClassLoaders(classloader) + } + return classGraph + .enableURLScheme(attachmentScheme) + .ignoreParentClassLoaders() + .enableClassInfo() + .pooledScan() + .use { result -> + classVersionRange?.let { + result.allClasses.firstOrNull { c -> c.classfileMajorVersion !in classVersionRange }?.also { + throw UnsupportedClassVersionError("Class ${it.name} found in ${it.classpathElementURL} " + + "has an unsupported class version of ${it.classfileMajorVersion}") + } } + result.getClassesImplementing(clazz.name) + .filterNot(ClassInfo::isAbstract) + .mapToSet(ClassInfo::getName) } - result.getClassesImplementing(clazz.name) - .filterNot(ClassInfo::isAbstract) - .mapTo(LinkedHashSet(), ClassInfo::getName) - } +} + +/** + * @throws ClassNotFoundException + * @throws ClassCastException + * @see Class.forName + */ +inline fun loadClassOfType(className: String, initialize: Boolean = true, classLoader: ClassLoader? = null): Class { + return loadClassOfType(T::class.java, className, initialize, classLoader) +} + +fun loadClassOfType(type: Class, className: String, initialize: Boolean = true, classLoader: ClassLoader? = null): Class { + return Class.forName(className, initialize, classLoader).asSubclass(type) } fun executeWithThreadContextClassLoader(classloader: ClassLoader, fn: () -> T): T { @@ -62,5 +77,4 @@ fun executeWithThreadContextClassLoader(classloader: ClassLoader, fn: } finally { Thread.currentThread().contextClassLoader = threadClassLoader } - } diff --git a/core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt b/core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt index 8461583901..e5cef3fca2 100644 --- a/core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt @@ -1,35 +1,27 @@ -@file:Suppress("TooManyFunctions") +@file:Suppress("MatchingDeclarationName") package net.corda.core.internal -import net.corda.core.contracts.Attachment import net.corda.core.contracts.ContractClassName -import net.corda.core.cordapp.CordappProvider +import net.corda.core.contracts.NamedByHash +import net.corda.core.contracts.TransactionResolutionException +import net.corda.core.crypto.SecureHash import net.corda.core.flows.DataVendingFlow import net.corda.core.flows.FlowLogic import net.corda.core.node.NetworkParameters +import net.corda.core.node.ServiceHub import net.corda.core.node.ServicesForResolution import net.corda.core.node.ZoneVersionTooLowException -import net.corda.core.node.services.AttachmentId -import net.corda.core.node.services.AttachmentStorage -import net.corda.core.node.services.vault.AttachmentQueryCriteria -import net.corda.core.node.services.vault.AttachmentSort -import net.corda.core.node.services.vault.Builder -import net.corda.core.node.services.vault.Sort +import net.corda.core.node.services.TransactionStorage import net.corda.core.serialization.CordaSerializable -import net.corda.core.serialization.SerializationContext -import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.SignedTransaction -import net.corda.core.transactions.TransactionBuilder -import net.corda.core.transactions.WireTransaction import org.slf4j.MDC import java.security.PublicKey -import java.util.jar.JarInputStream // *Internal* Corda-specific utilities. // When incrementing platformVersion make sure to update PLATFORM_VERSION in constants.properties as well. -const val PLATFORM_VERSION = 13 +const val PLATFORM_VERSION = 140 fun ServicesForResolution.ensureMinimumPlatformVersion(requiredMinPlatformVersion: Int, feature: String) { checkMinimumPlatformVersion(networkParameters.minimumPlatformVersion, requiredMinPlatformVersion, feature) @@ -45,34 +37,6 @@ fun checkMinimumPlatformVersion(minimumPlatformVersion: Int, requiredMinPlatform } } -// JDK11: revisit (JDK 9+ uses different numbering scheme: see https://docs.oracle.com/javase/9/docs/api/java/lang/Runtime.Version.html) -@Throws(NumberFormatException::class) -fun getJavaUpdateVersion(javaVersion: String): Long = javaVersion.substringAfter("_").substringBefore("-").toLong() - -enum class JavaVersion(val versionString: String) { - Java_1_8("1.8"), - Java_11("11"); - - companion object { - fun isVersionAtLeast(version: JavaVersion): Boolean { - return currentVersion.toFloat() >= version.versionString.toFloat() - } - - private val currentVersion: String = System.getProperty("java.specification.version") ?: - throw IllegalStateException("Unable to retrieve system property java.specification.version") - } -} - -/** Provide access to internal method for AttachmentClassLoaderTests. */ -fun TransactionBuilder.toWireTransaction(services: ServicesForResolution, serializationContext: SerializationContext): WireTransaction { - return toWireTransactionWithContext(services, serializationContext) -} - -/** Provide access to internal method for AttachmentClassLoaderTests. */ -fun TransactionBuilder.toLedgerTransaction(services: ServicesForResolution, serializationContext: SerializationContext): LedgerTransaction { - return toLedgerTransactionWithContext(services, serializationContext) -} - /** Checks if this flow is an idempotent flow. */ fun Class>.isIdempotentFlow(): Boolean { return IdempotentFlow::class.java.isAssignableFrom(this) @@ -125,40 +89,10 @@ fun noPackageOverlap(packages: Collection): Boolean { return packages.all { outer -> packages.none { inner -> inner != outer && inner.startsWith("$outer.") } } } -/** - * @return The set of [AttachmentId]s after the node's fix-up rules have been applied to [attachmentIds]. - */ -fun CordappProvider.internalFixupAttachmentIds(attachmentIds: Collection): Set { - return (this as CordappFixupInternal).fixupAttachmentIds(attachmentIds) +fun TransactionStorage.getRequiredTransaction(txhash: SecureHash): SignedTransaction { + return getTransaction(txhash) ?: throw TransactionResolutionException(txhash) } -/** - * Scans trusted (installed locally) attachments to find all that contain the [className]. - * This is required as a workaround until explicit cordapp dependencies are implemented. - * DO NOT USE IN CLIENT code. - * - * @return the attachments with the highest version. - * - * TODO: Should throw when the class is found in multiple contract attachments (not different versions). - */ -fun AttachmentStorage.internalFindTrustedAttachmentForClass(className: String): Attachment? { - val allTrusted = queryAttachments( - AttachmentQueryCriteria.AttachmentsQueryCriteria().withUploader(Builder.`in`(TRUSTED_UPLOADERS)), - AttachmentSort(listOf(AttachmentSort.AttachmentSortColumn(AttachmentSort.AttachmentSortAttribute.VERSION, Sort.Direction.DESC)))) +fun ServiceHub.getRequiredTransaction(txhash: SecureHash): SignedTransaction = validatedTransactions.getRequiredTransaction(txhash) - // TODO - add caching if performance is affected. - for (attId in allTrusted) { - val attch = openAttachment(attId)!! - if (attch.openAsJAR().use { hasFile(it, "$className.class") }) return attch - } - return null -} - -private fun hasFile(jarStream: JarInputStream, className: String): Boolean { - while (true) { - val e = jarStream.nextJarEntry ?: return false - if (e.name == className) { - return true - } - } -} +fun NamedByHash.toSimpleString(): String = "${javaClass.simpleName}(id=$id)" diff --git a/core/src/main/kotlin/net/corda/core/internal/CordappFixupInternal.kt b/core/src/main/kotlin/net/corda/core/internal/CordappFixupInternal.kt deleted file mode 100644 index e1ac4e22c6..0000000000 --- a/core/src/main/kotlin/net/corda/core/internal/CordappFixupInternal.kt +++ /dev/null @@ -1,7 +0,0 @@ -package net.corda.core.internal - -import net.corda.core.node.services.AttachmentId - -interface CordappFixupInternal { - fun fixupAttachmentIds(attachmentIds: Collection): Set -} diff --git a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt index e3df734e91..6b65af672f 100644 --- a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt @@ -1,4 +1,6 @@ @file:JvmName("InternalUtils") +@file:Suppress("MagicNumber") + package net.corda.core.internal import net.corda.core.crypto.Crypto @@ -15,6 +17,7 @@ import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.UntrustworthyData import net.corda.core.utilities.seconds import org.slf4j.Logger +import org.slf4j.event.Level import rx.Observable import rx.Observer import rx.observers.Subscribers @@ -23,16 +26,13 @@ import rx.subjects.UnicastSubject import java.io.ByteArrayOutputStream import java.io.IOException import java.io.InputStream -import java.io.OutputStream import java.lang.reflect.Field import java.lang.reflect.Member import java.lang.reflect.Modifier -import java.math.BigDecimal import java.net.HttpURLConnection import java.net.HttpURLConnection.HTTP_MOVED_PERM import java.net.HttpURLConnection.HTTP_OK import java.net.Proxy -import java.net.URI import java.net.URL import java.nio.ByteBuffer import java.nio.file.CopyOption @@ -53,6 +53,7 @@ import java.security.cert.X509Certificate import java.time.Duration import java.time.temporal.Temporal import java.util.Collections +import java.util.Locale import java.util.PrimitiveIterator import java.util.Spliterator import java.util.Spliterator.DISTINCT @@ -65,6 +66,8 @@ import java.util.Spliterator.SUBSIZED import java.util.Spliterators import java.util.concurrent.ExecutorService import java.util.concurrent.TimeUnit +import java.util.jar.JarEntry +import java.util.jar.JarInputStream import java.util.stream.Collectors import java.util.stream.Collectors.toCollection import java.util.stream.IntStream @@ -77,7 +80,14 @@ import kotlin.math.roundToLong import kotlin.reflect.KClass import kotlin.reflect.full.createInstance -val Throwable.rootCause: Throwable get() = cause?.rootCause ?: this +val Throwable.rootCause: Throwable + get() { + var root = this + while (true) { + root = root.cause ?: return root + } + } + val Throwable.rootMessage: String? get() { var message = this.message var throwable = cause @@ -95,8 +105,8 @@ infix fun Temporal.until(endExclusive: Temporal): Duration = Duration.between(th operator fun Duration.div(divider: Long): Duration = dividedBy(divider) operator fun Duration.times(multiplicand: Long): Duration = multipliedBy(multiplicand) operator fun Duration.times(multiplicand: Double): Duration = Duration.ofNanos((toNanos() * multiplicand).roundToLong()) -fun min(d1: Duration, d2: Duration): Duration = if (d1 <= d2) d1 else d2 +fun min(d1: Duration, d2: Duration): Duration = if (d1 <= d2) d1 else d2 /** * Returns the single element matching the given [predicate], or `null` if the collection is empty, or throws exception @@ -126,29 +136,57 @@ fun List.noneOrSingle(): T? { } } -/** Returns a random element in the list, or `null` if empty */ -fun List.randomOrNull(): T? { - return when (size) { - 0 -> null - 1 -> this[0] - else -> this[(Math.random() * size).toInt()] - } -} - /** Returns the index of the given item or throws [IllegalArgumentException] if not found. */ fun List.indexOfOrThrow(item: T): Int { val i = indexOf(item) - require(i != -1){"No such element"} + require(i != -1) { "No such element" } return i } +/** + * Similar to [Iterable.map] except it maps to a [Set] which preserves the iteration order. + */ +@Suppress("INVISIBLE_MEMBER", "RemoveExplicitTypeArguments") // Because the external verifier uses Kotlin 1.2 +inline fun Collection.mapToSet(transform: (T) -> R): Set { + return when (size) { + 0 -> emptySet() + 1 -> setOf(transform(first())) + else -> mapTo(LinkedHashSet(mapCapacity(size)), transform) + } +} + +/** + * Similar to [Iterable.flatMap] except it maps to a [Set] which preserves the iteration order. + */ +inline fun Collection.flatMapToSet(transform: (T) -> Iterable): Set { + return if (isEmpty()) emptySet() else flatMapTo(LinkedHashSet(), transform) +} + +/** + * Map the elements of the [Iterable] to multiple keys. By default duplicate mappings are not allowed. The returned [Map] preserves the + * iteration order of the values. + */ +inline fun Iterable.groupByMultipleKeys( + keysSelector: (V) -> Iterable, + onDuplicate: (K, V, V) -> Unit = { key, value1, value2 -> throw IllegalArgumentException("Duplicate mapping for $key ($value1, $value2)") } +): Map { + val map = LinkedHashMap() + for (value in this) { + for (key in keysSelector(value)) { + val duplicate = map.put(key, value) ?: continue + onDuplicate(key, value, duplicate) + } + } + return map +} + fun InputStream.copyTo(target: Path, vararg options: CopyOption): Long = Files.copy(this, target, *options) /** Same as [InputStream.readBytes] but also closes the stream. */ fun InputStream.readFully(): ByteArray = use { it.readBytes() } /** Calculate the hash of the remaining bytes in this input stream. The stream is closed at the end. */ -fun InputStream.hash(): SecureHash { +fun InputStream.hash(): SecureHash.SHA256 { return use { val md = MessageDigest.getInstance("SHA-256") val buffer = ByteArray(DEFAULT_BUFFER_SIZE) @@ -165,16 +203,9 @@ fun InputStream.hash(): SecureHash { inline fun InputStream.readObject(): T = readFully().deserialize() -object NullOutputStream : OutputStream() { - override fun write(b: Int) = Unit - override fun write(b: ByteArray) = Unit - override fun write(b: ByteArray, off: Int, len: Int) = Unit -} +fun JarInputStream.entries(): Sequence = generateSequence(nextJarEntry) { nextJarEntry } -fun String.abbreviate(maxWidth: Int): String = if (length <= maxWidth) this else take(maxWidth - 1) + "…" - -/** Return the sum of an Iterable of [BigDecimal]s. */ -fun Iterable.sum(): BigDecimal = fold(BigDecimal.ZERO) { a, b -> a + b } +fun String.abbreviate(maxWidth: Int): String = if (length <= maxWidth) this else "${take(maxWidth - 1)}…" /** * Returns an Observable that buffers events until subscribed. @@ -208,8 +239,6 @@ inline fun elapsedTime(block: () -> Unit): Duration { fun Logger.logElapsedTime(label: String, body: () -> T): T = logElapsedTime(label, this, body) -// TODO: Add inline back when a new Kotlin version is released and check if the java.lang.VerifyError -// returns in the IRSSimulationTest. If not, commit the inline back. fun logElapsedTime(label: String, logger: Logger? = null, body: () -> T): T { // Use nanoTime as it's monotonic. val now = System.nanoTime() @@ -286,7 +315,7 @@ private fun IntProgression.toSpliterator(): Spliterator.OfInt { fun IntProgression.stream(parallel: Boolean = false): IntStream = StreamSupport.intStream(toSpliterator(), parallel) // When toArray has filled in the array, the component type is no longer T? but T (that may itself be nullable): -inline fun Stream.toTypedArray(): Array = uncheckedCast(toArray { size -> arrayOfNulls(size) }) +inline fun Stream.toTypedArray(): Array? = uncheckedCast(toArray { size -> arrayOfNulls(size) }) inline fun Stream.mapNotNull(crossinline transform: (T) -> R?): Stream { return flatMap { @@ -298,6 +327,8 @@ inline fun Stream.mapNotNull(crossinline transform: (T) -> R?): /** Similar to [Collectors.toSet] except the Set is guaranteed to be ordered. */ fun Stream.toSet(): Set = collect(toCollection { LinkedHashSet() }) +val Class<*>.isJdkClass: Boolean get() = module.name?.startsWith("java.") == true + fun Class.castIfPossible(obj: Any): T? = if (isInstance(obj)) cast(obj) else null /** Returns a [DeclaredField] wrapper around the declared (possibly non-public) static field of the receiver [Class]. */ @@ -335,7 +366,8 @@ val Class.kotlinObjectInstance: T? get() { field?.let { if (it.type == this && it.isPublic && it.isStatic && it.isFinal) { it.isAccessible = true - uncheckedCast(it.get(null)) + @Suppress("UNCHECKED_CAST") + it.get(null) as T } else { null } @@ -365,17 +397,10 @@ class DeclaredField(clazz: Class<*>, name: String, private val receiver: Any? val name: String = javaField.name private fun Field.accessible(action: Field.() -> RESULT): RESULT { - @Suppress("DEPRECATION") // JDK11: isAccessible() should be replaced with canAccess() (since 9) - val accessible = isAccessible isAccessible = true - try { - return action(this) - } finally { - isAccessible = accessible - } + return action(this) } - @Throws(NoSuchFieldException::class) private fun findField(fieldName: String, clazz: Class<*>?): Field { if (clazz == null) { throw NoSuchFieldException(fieldName) @@ -431,9 +456,7 @@ inline val Member.isStatic: Boolean get() = Modifier.isStatic(modifiers) inline val Member.isFinal: Boolean get() = Modifier.isFinal(modifiers) -fun URI.toPath(): Path = Paths.get(this) - -fun URL.toPath(): Path = toURI().toPath() +fun URL.toPath(): Path = Paths.get(toURI()) val DEFAULT_HTTP_CONNECT_TIMEOUT = 30.seconds.toMillis() val DEFAULT_HTTP_READ_TIMEOUT = 30.seconds.toMillis() @@ -529,11 +552,6 @@ fun ByteBuffer.copyBytes(): ByteArray = ByteArray(remaining()).also { get(it) } val PublicKey.hash: SecureHash get() = Crypto.encodePublicKey(this).sha256() -/** - * Extension method for providing a sumBy method that processes and returns a Long - */ -fun Iterable.sumByLong(selector: (T) -> Long): Long = this.map { selector(it) }.sum() - fun SerializedBytes.checkPayloadIs(type: Class): UntrustworthyData { val payloadData: T = try { val serializer = SerializationDefaults.SERIALIZATION_FACTORY @@ -560,6 +578,10 @@ fun MutableMap.toSynchronised(): MutableMap = Collections.syn /** @see Collections.synchronizedSet */ fun MutableSet.toSynchronised(): MutableSet = Collections.synchronizedSet(this) +fun Collection<*>.equivalent(other: Collection<*>): Boolean { + return this.size == other.size && this.containsAll(other) && other.containsAll(this) +} + /** * List implementation that applies the expensive [transform] function only when the element is accessed and caches calculated values. * Size is very cheap as it doesn't call [transform]. @@ -613,5 +635,20 @@ fun Logger.warnOnce(warning: String) { } } -const val JDK1_2_CLASS_FILE_FORMAT_MAJOR_VERSION = 46 -const val JDK8_CLASS_FILE_FORMAT_MAJOR_VERSION = 52 +val Logger.level: Level + get() = when { + isTraceEnabled -> Level.TRACE + isDebugEnabled -> Level.DEBUG + isInfoEnabled -> Level.INFO + isWarnEnabled -> Level.WARN + isErrorEnabled -> Level.ERROR + else -> throw IllegalStateException("Unknown logging level") + } + +const val JAVA_1_2_CLASS_FILE_MAJOR_VERSION = 46 +const val JAVA_8_CLASS_FILE_MAJOR_VERSION = 52 +const val JAVA_17_CLASS_FILE_MAJOR_VERSION = 61 + +fun String.capitalize(): String = replaceFirstChar { it.titlecase(Locale.getDefault()) } + +fun String.decapitalize(): String = replaceFirstChar { it.lowercase(Locale.getDefault()) } diff --git a/core/src/main/kotlin/net/corda/core/internal/JarSignatureCollector.kt b/core/src/main/kotlin/net/corda/core/internal/JarSignatureCollector.kt index 6132dec45d..7ff377250d 100644 --- a/core/src/main/kotlin/net/corda/core/internal/JarSignatureCollector.kt +++ b/core/src/main/kotlin/net/corda/core/internal/JarSignatureCollector.kt @@ -57,8 +57,8 @@ object JarSignatureCollector { return firstSignerSet } - private val JarInputStream.fileSignerSets: List>> get() = - entries.thatAreSignable.shreddedFrom(this).toFileSignerSet().toList() + private val JarInputStream.fileSignerSets: List>> + get() = entries().thatAreSignable.shreddedFrom(this).toFileSignerSet().toList() private val Sequence.thatAreSignable: Sequence get() = filterNot { isNotSignable(it) } @@ -85,8 +85,6 @@ object JarSignatureCollector { private fun Set.toCertificates(): List = map { it.signerCertPath.certificates[0] as X509Certificate }.sortedBy { it.toString() } // Sorted for determinism. - - private val JarInputStream.entries get(): Sequence = generateSequence(nextJarEntry) { nextJarEntry } } class InvalidJarSignersException(msg: String) : Exception(msg) \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/internal/NamedCache.kt b/core/src/main/kotlin/net/corda/core/internal/NamedCache.kt index 82c1c35b66..1f47b5ccd3 100644 --- a/core/src/main/kotlin/net/corda/core/internal/NamedCache.kt +++ b/core/src/main/kotlin/net/corda/core/internal/NamedCache.kt @@ -9,18 +9,24 @@ import com.github.benmanes.caffeine.cache.LoadingCache * Allow extra functionality to be injected to our caches. */ interface NamedCacheFactory { + companion object { + private val allowedChars = Regex("""^[0-9A-Za-z_.]*$""") + } + /** * Restrict the allowed characters of a cache name - this ensures that each cache has a name, and that * the name can be used to create a file name or a metric name. */ fun checkCacheName(name: String) { - require(!name.isBlank()){"Name must not be empty or only whitespace"} - require(allowedChars.matches(name)){"Invalid characters in cache name"} + require(name.isNotBlank()) { "Name must not be empty or only whitespace" } + require(allowedChars.matches(name)) { "Invalid characters in cache name" } } - fun buildNamed(caffeine: Caffeine, name: String): Cache + fun buildNamed(name: String): Cache = buildNamed(Caffeine.newBuilder(), name) - fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache + fun buildNamed(caffeine: Caffeine, name: String): Cache + + fun buildNamed(name: String, loader: CacheLoader): LoadingCache = buildNamed(Caffeine.newBuilder(), name, loader) + + fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache } - -private val allowedChars = Regex("^[0-9A-Za-z_.]*\$") diff --git a/core/src/main/kotlin/net/corda/core/internal/NetworkParametersServiceInternal.kt b/core/src/main/kotlin/net/corda/core/internal/NetworkParametersStorage.kt similarity index 100% rename from core/src/main/kotlin/net/corda/core/internal/NetworkParametersServiceInternal.kt rename to core/src/main/kotlin/net/corda/core/internal/NetworkParametersStorage.kt diff --git a/core/src/main/kotlin/net/corda/core/internal/PathUtils.kt b/core/src/main/kotlin/net/corda/core/internal/PathUtils.kt index ffe686894c..4abfe8ee60 100644 --- a/core/src/main/kotlin/net/corda/core/internal/PathUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/PathUtils.kt @@ -2,41 +2,28 @@ package net.corda.core.internal import net.corda.core.crypto.SecureHash import net.corda.core.serialization.deserialize -import java.io.* -import java.nio.charset.Charset -import java.nio.charset.StandardCharsets.UTF_8 -import java.nio.file.* +import java.io.IOException +import java.io.InputStream +import java.io.OutputStream +import java.nio.file.CopyOption +import java.nio.file.FileVisitResult +import java.nio.file.Files +import java.nio.file.LinkOption +import java.nio.file.OpenOption +import java.nio.file.Path +import java.nio.file.SimpleFileVisitor import java.nio.file.attribute.BasicFileAttributes -import java.nio.file.attribute.FileAttribute -import java.nio.file.attribute.FileTime -import java.util.stream.Stream -import kotlin.streams.toList - -/** - * Allows you to write code like: Paths.get("someDir") / "subdir" / "filename" but using the Paths API to avoid platform - * separator problems. - * @see Path.resolve - */ -operator fun Path.div(other: String): Path = resolve(other) - -/** - * Allows you to write code like: "someDir" / "subdir" / "filename" but using the Paths API to avoid platform - * separator problems. - * @see Path.resolve - */ -operator fun String.div(other: String): Path = Paths.get(this) / other - -/** @see Files.createFile */ -fun Path.createFile(vararg attrs: FileAttribute<*>): Path = Files.createFile(this, *attrs) - -/** @see Files.createDirectory */ -fun Path.createDirectory(vararg attrs: FileAttribute<*>): Path = Files.createDirectory(this, *attrs) - -/** @see Files.createDirectories */ -fun Path.createDirectories(vararg attrs: FileAttribute<*>): Path = Files.createDirectories(this, *attrs) - -/** @see Files.exists */ -fun Path.exists(vararg options: LinkOption): Boolean = Files.exists(this, *options) +import kotlin.io.path.createDirectories +import kotlin.io.path.deleteIfExists +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.inputStream +import kotlin.io.path.isDirectory +import kotlin.io.path.isSymbolicLink +import kotlin.io.path.name +import kotlin.io.path.outputStream +import kotlin.io.path.readBytes +import kotlin.io.path.readSymbolicLink /** Copy the file into the target directory using [Files.copy]. */ fun Path.copyToDirectory(targetDir: Path, vararg options: CopyOption): Path { @@ -50,107 +37,32 @@ fun Path.copyToDirectory(targetDir: Path, vararg options: CopyOption): Path { * Path.toString() is assumed safe because fileName should * not include any path separator characters. */ - val targetFile = targetDir.resolve(fileName.toString()) + val targetFile = targetDir / name Files.copy(this, targetFile, *options) return targetFile } -/** @see Files.copy */ -fun Path.copyTo(target: Path, vararg options: CopyOption): Path = Files.copy(this, target, *options) - -/** @see Files.move */ -fun Path.moveTo(target: Path, vararg options: CopyOption): Path = Files.move(this, target, *options) - -/** @see Files.move */ -fun Path.renameTo(fileName: String, vararg options: CopyOption): Path = moveTo(parent / fileName, *options) - /** See overload of [Files.copy] which takes in an [InputStream]. */ fun Path.copyTo(out: OutputStream): Long = Files.copy(this, out) -/** @see Files.isRegularFile */ -fun Path.isRegularFile(vararg options: LinkOption): Boolean = Files.isRegularFile(this, *options) - -/** @see Files.isReadable */ -inline val Path.isReadable: Boolean get() = Files.isReadable(this) - -/** @see Files.size */ -inline val Path.size: Long get() = Files.size(this) - /** @see Files.readAttributes */ fun Path.attributes(vararg options: LinkOption): BasicFileAttributes = Files.readAttributes(this, BasicFileAttributes::class.java, *options) -/** @see Files.getLastModifiedTime */ -fun Path.lastModifiedTime(vararg options: LinkOption): FileTime = Files.getLastModifiedTime(this, *options) - -/** @see Files.isDirectory */ -fun Path.isDirectory(vararg options: LinkOption): Boolean = Files.isDirectory(this, *options) - -/** @see Files.isSameFile */ -fun Path.isSameAs(other: Path): Boolean = Files.isSameFile(this, other) - -/** - * Same as [Files.list] except it also closes the [Stream]. - * @return the output of [block] - */ -inline fun Path.list(block: (Stream) -> R): R = Files.list(this).use(block) - -/** Same as [list] but materialises all the entiries into a list. */ -fun Path.list(): List = list { it.toList() } - -/** @see Files.walk */ -inline fun Path.walk(maxDepth: Int = Int.MAX_VALUE, vararg options: FileVisitOption, block: (Stream) -> R): R { - return Files.walk(this, maxDepth, *options).use(block) -} - -/** @see Files.delete */ -fun Path.delete(): Unit = Files.delete(this) - -/** @see Files.deleteIfExists */ -fun Path.deleteIfExists(): Boolean = Files.deleteIfExists(this) - /** Deletes this path (if it exists) and if it's a directory, all its child paths recursively. */ fun Path.deleteRecursively() { if (!exists()) return Files.walkFileTree(this, object : SimpleFileVisitor() { override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult { - file.delete() + file.deleteIfExists() return FileVisitResult.CONTINUE } override fun postVisitDirectory(dir: Path, exception: IOException?): FileVisitResult { - dir.delete() + dir.deleteIfExists() return FileVisitResult.CONTINUE } }) } -/** @see Files.newOutputStream */ -fun Path.outputStream(vararg options: OpenOption): OutputStream = Files.newOutputStream(this, *options) - -/** @see Files.newInputStream */ -fun Path.inputStream(vararg options: OpenOption): InputStream = Files.newInputStream(this, *options) - -/** @see Files.newBufferedReader */ -fun Path.reader(charset: Charset = UTF_8): BufferedReader = Files.newBufferedReader(this, charset) - -/** @see Files.newBufferedWriter */ -fun Path.writer(charset: Charset = UTF_8, vararg options: OpenOption): BufferedWriter { - return Files.newBufferedWriter(this, charset, *options) -} - -/** @see Files.readAllBytes */ -fun Path.readAll(): ByteArray = Files.readAllBytes(this) - -/** Read in this entire file as a string using the given encoding. */ -fun Path.readText(charset: Charset = UTF_8): String = reader(charset).use(Reader::readText) - -/** @see Files.write */ -fun Path.write(bytes: ByteArray, vararg options: OpenOption): Path = Files.write(this, bytes, *options) - -/** Write the given string to this file. */ -fun Path.writeText(text: String, charset: Charset = UTF_8, vararg options: OpenOption) { - writer(charset, *options).use { it.write(text) } -} - /** * Same as [inputStream] except it also closes the [InputStream]. * @return the output of [block] @@ -169,35 +81,14 @@ inline fun Path.write(createDirs: Boolean = false, vararg options: OpenOption = outputStream(*options).use(block) } -/** - * Same as [Files.lines] except it also closes the [Stream] - * @return the output of [block] - */ -inline fun Path.readLines(charset: Charset = UTF_8, block: (Stream) -> R): R { - return Files.lines(this, charset).use(block) -} - -/** @see Files.readAllLines */ -fun Path.readAllLines(charset: Charset = UTF_8): List = Files.readAllLines(this, charset) - -fun Path.writeLines(lines: Iterable, charset: Charset = UTF_8, vararg options: OpenOption): Path { - return Files.write(this, lines, charset, *options) -} - /** * Read in this file as an AMQP serialised blob of type [T]. * @see [deserialize] */ -inline fun Path.readObject(): T = readAll().deserialize() +inline fun Path.readObject(): T = readBytes().deserialize() /** Calculate the hash of the contents of this file. */ -inline val Path.hash: SecureHash get() = read { it.hash() } +inline val Path.hash: SecureHash.SHA256 get() = read { it.hash() } /* Check if the Path is symbolic link */ -fun Path.safeSymbolicRead(): Path { - if (Files.isSymbolicLink(this)) { - return (Files.readSymbolicLink(this)) - } else { - return (this) - } -} +fun Path.safeSymbolicRead(): Path = if (isSymbolicLink()) readSymbolicLink() else this diff --git a/core/src/main/kotlin/net/corda/core/internal/ResolveTransactionsFlow.kt b/core/src/main/kotlin/net/corda/core/internal/ResolveTransactionsFlow.kt index 3896d5648c..456f6b6c6c 100644 --- a/core/src/main/kotlin/net/corda/core/internal/ResolveTransactionsFlow.kt +++ b/core/src/main/kotlin/net/corda/core/internal/ResolveTransactionsFlow.kt @@ -94,7 +94,7 @@ class ResolveTransactionsFlow private constructor( fun fetchMissingAttachments(transaction: SignedTransaction): Boolean { val tx = transaction.coreTransaction val attachmentIds = when (tx) { - is WireTransaction -> tx.attachments.toSet() + is WireTransaction -> tx.allAttachments is ContractUpgradeWireTransaction -> setOf(tx.legacyContractAttachmentId, tx.upgradedContractAttachmentId) else -> return false } diff --git a/core/src/main/kotlin/net/corda/core/internal/ServiceHubCoreInternal.kt b/core/src/main/kotlin/net/corda/core/internal/ServiceHubCoreInternal.kt index bd7c1142ac..84ba452deb 100644 --- a/core/src/main/kotlin/net/corda/core/internal/ServiceHubCoreInternal.kt +++ b/core/src/main/kotlin/net/corda/core/internal/ServiceHubCoreInternal.kt @@ -6,19 +6,15 @@ import net.corda.core.crypto.TransactionSignature import net.corda.core.flows.TransactionMetadata import net.corda.core.identity.CordaX500Name import net.corda.core.internal.notary.NotaryService -import net.corda.core.node.ServiceHub +import net.corda.core.internal.verification.VerifyingServiceHub import net.corda.core.node.StatesToRecord -import net.corda.core.serialization.internal.AttachmentsClassLoaderCache import net.corda.core.transactions.SignedTransaction import java.util.concurrent.ExecutorService // TODO: This should really be called ServiceHubInternal but that name is already taken by net.corda.node.services.api.ServiceHubInternal. -interface ServiceHubCoreInternal : ServiceHub { - +interface ServiceHubCoreInternal : VerifyingServiceHub { val externalOperationExecutor: ExecutorService - val attachmentTrustCalculator: AttachmentTrustCalculator - /** * Optional `NotaryService` which will be `null` for all non-Notary nodes. */ @@ -26,8 +22,6 @@ interface ServiceHubCoreInternal : ServiceHub { fun createTransactionsResolver(flow: ResolveTransactionsFlow): TransactionsResolver - val attachmentsClassLoaderCache: AttachmentsClassLoaderCache - /** * Stores [SignedTransaction] and participant signatures without the notary signature in the local transaction storage, * inclusive of flow recovery metadata. diff --git a/core/src/main/kotlin/net/corda/core/internal/StatePointerSearch.kt b/core/src/main/kotlin/net/corda/core/internal/StatePointerSearch.kt index e552172844..b17f50e0c8 100644 --- a/core/src/main/kotlin/net/corda/core/internal/StatePointerSearch.kt +++ b/core/src/main/kotlin/net/corda/core/internal/StatePointerSearch.kt @@ -13,7 +13,7 @@ import java.util.* class StatePointerSearch(val state: ContractState) { private companion object { // Classes in these packages should not be part of a search. - private val blackListedPackages = setOf("java.", "javax.", "org.bouncycastle.", "net.i2p.crypto.") + private val blackListedPackages = setOf("java.", "javax.", "org.bouncycastle.") } // Type required for traversal. diff --git a/core/src/main/kotlin/net/corda/core/internal/TransactionUtils.kt b/core/src/main/kotlin/net/corda/core/internal/TransactionUtils.kt index 41e94a236a..d6ed4e254a 100644 --- a/core/src/main/kotlin/net/corda/core/internal/TransactionUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/TransactionUtils.kt @@ -1,6 +1,27 @@ package net.corda.core.internal -import net.corda.core.contracts.* +import net.corda.core.contracts.Command +import net.corda.core.contracts.CommandData +import net.corda.core.contracts.ComponentGroupEnum +import net.corda.core.contracts.ComponentGroupEnum.ATTACHMENTS_GROUP +import net.corda.core.contracts.ComponentGroupEnum.ATTACHMENTS_V2_GROUP +import net.corda.core.contracts.ComponentGroupEnum.COMMANDS_GROUP +import net.corda.core.contracts.ComponentGroupEnum.INPUTS_GROUP +import net.corda.core.contracts.ComponentGroupEnum.NOTARY_GROUP +import net.corda.core.contracts.ComponentGroupEnum.OUTPUTS_GROUP +import net.corda.core.contracts.ComponentGroupEnum.PARAMETERS_GROUP +import net.corda.core.contracts.ComponentGroupEnum.REFERENCES_GROUP +import net.corda.core.contracts.ComponentGroupEnum.SIGNERS_GROUP +import net.corda.core.contracts.ComponentGroupEnum.TIMEWINDOW_GROUP +import net.corda.core.contracts.ContractClassName +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.NamedByHash +import net.corda.core.contracts.PrivacySalt +import net.corda.core.contracts.StateAndRef +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TimeWindow +import net.corda.core.contracts.TransactionState +import net.corda.core.contracts.TransactionVerificationException import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash import net.corda.core.crypto.algorithm @@ -8,8 +29,20 @@ import net.corda.core.crypto.internal.DigestAlgorithmFactory import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party import net.corda.core.node.ServicesForResolution -import net.corda.core.serialization.* -import net.corda.core.transactions.* +import net.corda.core.serialization.MissingAttachmentsException +import net.corda.core.serialization.MissingAttachmentsRuntimeException +import net.corda.core.serialization.SerializationContext +import net.corda.core.serialization.SerializationFactory +import net.corda.core.serialization.SerializedBytes +import net.corda.core.serialization.deserialize +import net.corda.core.serialization.serialize +import net.corda.core.transactions.BaseTransaction +import net.corda.core.transactions.ComponentGroup +import net.corda.core.transactions.ContractUpgradeWireTransaction +import net.corda.core.transactions.FilteredComponentGroup +import net.corda.core.transactions.FullTransaction +import net.corda.core.transactions.NotaryChangeWireTransaction +import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.OpaqueBytes import java.io.ByteArrayOutputStream import java.security.PublicKey @@ -68,8 +101,7 @@ fun deserialiseComponentGroup(componentGroups: List, forceDeserialize: Boolean = false, factory: SerializationFactory = SerializationFactory.defaultFactory, context: SerializationContext = factory.defaultContext): List { - val group = componentGroups.firstOrNull { it.groupIndex == groupEnum.ordinal } - + val group = componentGroups.getGroup(groupEnum) if (group == null || group.components.isEmpty()) { return emptyList() } @@ -85,7 +117,7 @@ fun deserialiseComponentGroup(componentGroups: List, factory.deserialize(component, clazz.java, context) } catch (e: MissingAttachmentsException) { /** - * [ServiceHub.signInitialTransaction] forgets to declare that + * `ServiceHub.signInitialTransaction` forgets to declare that * it may throw any checked exceptions. Wrap this one inside * an unchecked version to avoid breaking Java CorDapps. */ @@ -96,7 +128,13 @@ fun deserialiseComponentGroup(componentGroups: List, } } -/** +fun List.getGroup(type: ComponentGroupEnum): T? = firstOrNull { it.groupIndex == type.ordinal } + +fun List.getRequiredGroup(type: ComponentGroupEnum): T { + return requireNotNull(getGroup(type)) { "Missing component group $type" } +} + +/**x * Exception raised if an error was encountered while attempting to deserialise a component group in a transaction. */ class TransactionDeserialisationException(groupEnum: ComponentGroupEnum, index: Int, cause: Exception): @@ -119,17 +157,19 @@ fun deserialiseCommands( // TODO: we could avoid deserialising unrelated signers. // However, current approach ensures the transaction is not malformed // and it will throw if any of the signers objects is not List of public keys). - val signersList: List> = uncheckedCast(deserialiseComponentGroup(componentGroups, List::class, ComponentGroupEnum.SIGNERS_GROUP, forceDeserialize, factory, context)) - val commandDataList: List = deserialiseComponentGroup(componentGroups, CommandData::class, ComponentGroupEnum.COMMANDS_GROUP, forceDeserialize, factory, context) - val group = componentGroups.firstOrNull { it.groupIndex == ComponentGroupEnum.COMMANDS_GROUP.ordinal } + val signersList: List> = uncheckedCast(deserialiseComponentGroup(componentGroups, List::class, SIGNERS_GROUP, forceDeserialize, factory, context)) + val commandDataList: List = deserialiseComponentGroup(componentGroups, CommandData::class, COMMANDS_GROUP, forceDeserialize, factory, context) + val group = componentGroups.getGroup(COMMANDS_GROUP) return if (group is FilteredComponentGroup) { check(commandDataList.size <= signersList.size) { "Invalid Transaction. Less Signers (${signersList.size}) than CommandData (${commandDataList.size}) objects" } val componentHashes = group.components.mapIndexed { index, component -> digestService.componentHash(group.nonces[index], component) } val leafIndices = componentHashes.map { group.partialMerkleTree.leafIndex(it) } - if (leafIndices.isNotEmpty()) + if (leafIndices.isNotEmpty()) { + @Suppress("UNNECESSARY_NOT_NULL_ASSERTION") // Because the external verifier uses Kotlin 1.2 check(leafIndices.max()!! < signersList.size) { "Invalid Transaction. A command with no corresponding signer detected" } + } commandDataList.lazyMapped { commandData, index -> Command(commandData, signersList[leafIndices[index]]) } } else { // It is a WireTransaction @@ -141,10 +181,7 @@ fun deserialiseCommands( } } -/** - * Creating list of [ComponentGroup] used in one of the constructors of [WireTransaction] required - * for backwards compatibility purposes. - */ +@Suppress("LongParameterList") fun createComponentGroups(inputs: List, outputs: List>, commands: List>, @@ -152,31 +189,44 @@ fun createComponentGroups(inputs: List, notary: Party?, timeWindow: TimeWindow?, references: List, - networkParametersHash: SecureHash?): List { + networkParametersHash: SecureHash?, + // The old attachments group is now only used to create transaction compatible with 4.11 (or earlier) nodes + legacyAttachments: List = emptyList()): List { val serializationFactory = SerializationFactory.defaultFactory val serializationContext = serializationFactory.defaultContext val serialize = { value: Any, _: Int -> value.serialize(serializationFactory, serializationContext) } val componentGroupMap: MutableList = mutableListOf() - if (inputs.isNotEmpty()) componentGroupMap.add(ComponentGroup(ComponentGroupEnum.INPUTS_GROUP.ordinal, inputs.lazyMapped(serialize))) - if (references.isNotEmpty()) componentGroupMap.add(ComponentGroup(ComponentGroupEnum.REFERENCES_GROUP.ordinal, references.lazyMapped(serialize))) - if (outputs.isNotEmpty()) componentGroupMap.add(ComponentGroup(ComponentGroupEnum.OUTPUTS_GROUP.ordinal, outputs.lazyMapped(serialize))) + componentGroupMap.addListGroup(INPUTS_GROUP, inputs, serialize) + componentGroupMap.addListGroup(REFERENCES_GROUP, references, serialize) + componentGroupMap.addListGroup(OUTPUTS_GROUP, outputs, serialize) // Adding commandData only to the commands group. Signers are added in their own group. - if (commands.isNotEmpty()) componentGroupMap.add(ComponentGroup(ComponentGroupEnum.COMMANDS_GROUP.ordinal, commands.map { it.value }.lazyMapped(serialize))) - if (attachments.isNotEmpty()) componentGroupMap.add(ComponentGroup(ComponentGroupEnum.ATTACHMENTS_GROUP.ordinal, attachments.lazyMapped(serialize))) - if (notary != null) componentGroupMap.add(ComponentGroup(ComponentGroupEnum.NOTARY_GROUP.ordinal, listOf(notary).lazyMapped(serialize))) - if (timeWindow != null) componentGroupMap.add(ComponentGroup(ComponentGroupEnum.TIMEWINDOW_GROUP.ordinal, listOf(timeWindow).lazyMapped(serialize))) + componentGroupMap.addListGroup(COMMANDS_GROUP, commands.map { it.value }, serialize) + // Attachments which can only be processed by 4.12 and later. + componentGroupMap.addListGroup(ATTACHMENTS_V2_GROUP, attachments, serialize) + // The original attachments group now only contains attachments which can be processed by 4.11 and earlier (and the external verifier). + componentGroupMap.addListGroup(ATTACHMENTS_GROUP, legacyAttachments, serialize) + if (notary != null) componentGroupMap.add(ComponentGroup(NOTARY_GROUP.ordinal, listOf(notary).lazyMapped(serialize))) + if (timeWindow != null) componentGroupMap.add(ComponentGroup(TIMEWINDOW_GROUP.ordinal, listOf(timeWindow).lazyMapped(serialize))) // Adding signers to their own group. This is required for command visibility purposes: a party receiving // a FilteredTransaction can now verify it sees all the commands it should sign. - if (commands.isNotEmpty()) componentGroupMap.add(ComponentGroup(ComponentGroupEnum.SIGNERS_GROUP.ordinal, commands.map { it.signers }.lazyMapped(serialize))) - if (networkParametersHash != null) componentGroupMap.add(ComponentGroup(ComponentGroupEnum.PARAMETERS_GROUP.ordinal, listOf(networkParametersHash.serialize()))) + componentGroupMap.addListGroup(SIGNERS_GROUP, commands.map { it.signers }, serialize) + if (networkParametersHash != null) componentGroupMap.add(ComponentGroup(PARAMETERS_GROUP.ordinal, listOf(networkParametersHash.serialize()))) return componentGroupMap } +private fun MutableList.addListGroup(type: ComponentGroupEnum, list: List, serialize: (Any, Int) -> SerializedBytes) { + if (list.isNotEmpty()) { + add(ComponentGroup(type.ordinal, list.lazyMapped(serialize))) + } +} + +typealias SerializedTransactionState = SerializedBytes> + /** * A SerializedStateAndRef is a pair (BinaryStateRepresentation, StateRef). * The [serializedState] is the actual component from the original wire transaction. */ -data class SerializedStateAndRef(val serializedState: SerializedBytes>, val ref: StateRef) { +data class SerializedStateAndRef(val serializedState: SerializedTransactionState, val ref: StateRef) { fun toStateAndRef(factory: SerializationFactory, context: SerializationContext) = StateAndRef(serializedState.deserialize(factory, context), ref) fun toStateAndRef(): StateAndRef { val factory = SerializationFactory.defaultFactory @@ -266,5 +316,13 @@ internal fun checkNotaryWhitelisted(ftx: FullTransaction) { } } - - +fun getRequiredSigningKeysInternal(inputs: Sequence>, notary: Party?): Set { + val keys = LinkedHashSet() + for (input in inputs) { + input.state.data.participants.mapTo(keys) { it.owningKey } + } + if (notary != null) { + keys += notary.owningKey + } + return keys +} diff --git a/core/src/main/kotlin/net/corda/core/internal/X509EdDSAEngine.kt b/core/src/main/kotlin/net/corda/core/internal/X509EdDSAEngine.kt deleted file mode 100644 index 94c4897da8..0000000000 --- a/core/src/main/kotlin/net/corda/core/internal/X509EdDSAEngine.kt +++ /dev/null @@ -1,59 +0,0 @@ -package net.corda.core.internal - -import net.corda.core.crypto.Crypto -import net.i2p.crypto.eddsa.EdDSAEngine -import net.i2p.crypto.eddsa.EdDSAPublicKey -import java.security.AlgorithmParameters -import java.security.InvalidKeyException -import java.security.MessageDigest -import java.security.PrivateKey -import java.security.PublicKey -import java.security.SecureRandom -import java.security.Signature -import java.security.spec.AlgorithmParameterSpec -import java.security.spec.X509EncodedKeySpec - -/** - * Wrapper around [EdDSAEngine] which can intelligently rewrite X509Keys to a [EdDSAPublicKey]. This is a temporary - * solution until this is integrated upstream and/or a custom certificate factory implemented to force the correct - * key type. Only intercepts public keys passed into [engineInitVerify], as there is no equivalent issue with private - * keys. - */ -class X509EdDSAEngine : Signature { - private val engine: EdDSAEngine - - constructor() : super(EdDSAEngine.SIGNATURE_ALGORITHM) { - engine = EdDSAEngine() - } - - constructor(digest: MessageDigest) : super(EdDSAEngine.SIGNATURE_ALGORITHM) { - engine = EdDSAEngine(digest) - } - - override fun engineInitSign(privateKey: PrivateKey) = engine.initSign(privateKey) - - override fun engineInitSign(privateKey: PrivateKey, random: SecureRandom) = engine.initSign(privateKey, random) - - override fun engineInitVerify(publicKey: PublicKey) { - val parsedKey = try { - publicKey as? EdDSAPublicKey ?: EdDSAPublicKey(X509EncodedKeySpec(Crypto.encodePublicKey(publicKey))) - } catch (e: Exception) { - throw (InvalidKeyException(e.message)) - } - engine.initVerify(parsedKey) - } - - override fun engineSign(): ByteArray = engine.sign() - override fun engineVerify(sigBytes: ByteArray): Boolean = engine.verify(sigBytes) - - override fun engineUpdate(b: Byte) = engine.update(b) - override fun engineUpdate(b: ByteArray, off: Int, len: Int) = engine.update(b, off, len) - - override fun engineGetParameters(): AlgorithmParameters = engine.parameters - override fun engineSetParameter(params: AlgorithmParameterSpec) = engine.setParameter(params) - @Suppress("DEPRECATION", "OverridingDeprecatedMember") - override fun engineGetParameter(param: String): Any = engine.getParameter(param) - - @Suppress("DEPRECATION", "OverridingDeprecatedMember") - override fun engineSetParameter(param: String, value: Any?) = engine.setParameter(param, value) -} diff --git a/core/src/main/kotlin/net/corda/core/internal/concurrent/CordaFutureImpl.kt b/core/src/main/kotlin/net/corda/core/internal/concurrent/CordaFutureImpl.kt index 0f62fd752f..92744ad2e6 100644 --- a/core/src/main/kotlin/net/corda/core/internal/concurrent/CordaFutureImpl.kt +++ b/core/src/main/kotlin/net/corda/core/internal/concurrent/CordaFutureImpl.kt @@ -84,7 +84,6 @@ fun CordaFuture.mapError(transform: (Throwable) -> Throwa * But if this future or the transform fails, the returned future's outcome is the same throwable. * In the case where this future fails, the transform is not invoked. */ -@Suppress("TooGenericExceptionCaught") fun CordaFuture.flatMap(transform: (V) -> CordaFuture): CordaFuture = CordaFutureImpl().also { result -> thenMatch(success@ { result.captureLater(try { @@ -146,7 +145,6 @@ interface ValueOrException { fun captureLater(f: CordaFuture) = f.then { capture { f.getOrThrow() } } /** Run the given block (in the foreground) and set this future to its outcome. */ - @Suppress("TooGenericExceptionCaught") fun capture(block: () -> V): Boolean { return set(try { block() @@ -164,18 +162,17 @@ interface OpenFuture : ValueOrException, CordaFuture /** Unless you really want this particular implementation, use [openFuture] to make one. */ @VisibleForTesting -internal class CordaFutureImpl(private val impl: CompletableFuture = CompletableFuture()) : Future by impl, OpenFuture { +class CordaFutureImpl(private val impl: CompletableFuture = CompletableFuture()) : Future by impl, OpenFuture { companion object { private val defaultLog = contextLogger() - internal const val listenerFailedMessage = "Future listener failed:" + const val listenerFailedMessage = "Future listener failed:" } override fun set(value: V) = impl.complete(value) override fun setException(t: Throwable) = impl.completeExceptionally(t) override fun then(callback: (CordaFuture) -> W) = thenImpl(defaultLog, callback) /** For testing only. */ - @Suppress("TooGenericExceptionCaught") - internal fun thenImpl(log: Logger, callback: (CordaFuture) -> W) { + fun thenImpl(log: Logger, callback: (CordaFuture) -> W) { impl.whenComplete { _, _ -> try { callback(this) @@ -198,4 +195,4 @@ internal class CordaFutureImpl(private val impl: CompletableFuture = Compl } } -internal fun Future.get(timeout: Duration? = null): V = if (timeout == null) get() else get(timeout.toNanos(), TimeUnit.NANOSECONDS) +fun Future.get(timeout: Duration? = null): V = if (timeout == null) get() else get(timeout.toNanos(), TimeUnit.NANOSECONDS) diff --git a/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappImpl.kt b/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappImpl.kt index 32951790c1..9e745aec44 100644 --- a/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappImpl.kt +++ b/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappImpl.kt @@ -5,8 +5,8 @@ import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.internal.PLATFORM_VERSION import net.corda.core.internal.VisibleForTesting +import net.corda.core.internal.hash import net.corda.core.internal.notary.NotaryService -import net.corda.core.internal.toPath import net.corda.core.internal.telemetry.TelemetryComponent import net.corda.core.schemas.MappedSchema import net.corda.core.serialization.CheckpointCustomSerializer @@ -14,9 +14,12 @@ import net.corda.core.serialization.SerializationCustomSerializer import net.corda.core.serialization.SerializationWhitelist import net.corda.core.serialization.SerializeAsToken import java.net.URL +import java.nio.file.Path import java.nio.file.Paths +import kotlin.io.path.name data class CordappImpl( + val jarFile: Path, override val contractClassNames: List, override val initiatedFlows: List>>, override val rpcFlows: List>>, @@ -29,18 +32,22 @@ data class CordappImpl( override val checkpointCustomSerializers: List>, override val customSchemas: Set, override val allFlows: List>>, - override val jarPath: URL, override val info: Cordapp.Info, - override val jarHash: SecureHash.SHA256, override val minimumPlatformVersion: Int, override val targetPlatformVersion: Int, + override val jarHash: SecureHash.SHA256 = jarFile.hash, + val languageVersion: LanguageVersion = LanguageVersion.Data, val notaryService: Class? = null, /** Indicates whether the CorDapp is loaded from external sources, or generated on node startup (virtual). */ val isLoaded: Boolean = true, private val explicitCordappClasses: List = emptyList(), val isVirtual: Boolean = false ) : Cordapp { - override val name: String = jarName(jarPath) + override val jarPath: URL + get() = jarFile.toUri().toURL() + + override val name: String + get() = jarName(jarFile) // TODO: Also add [SchedulableFlow] as a Cordapp class override val cordappClasses: List = run { @@ -48,8 +55,12 @@ data class CordappImpl( classList.mapNotNull { it?.name } + contractClassNames + explicitCordappClasses } + override fun equals(other: Any?): Boolean = other is CordappImpl && this.jarHash == other.jarHash + + override fun hashCode(): Int = 31 * jarHash.hashCode() + companion object { - fun jarName(url: URL): String = (url.toPath().fileName ?: "").toString().removeSuffix(".jar") + fun jarName(url: Path): String = url.name.removeSuffix(".jar") /** CorDapp manifest entries */ const val CORDAPP_CONTRACT_NAME = "Cordapp-Contract-Name" @@ -73,6 +84,7 @@ data class CordappImpl( @VisibleForTesting val TEST_INSTANCE = CordappImpl( + jarFile = Paths.get(""), contractClassNames = emptyList(), initiatedFlows = emptyList(), rpcFlows = emptyList(), @@ -84,7 +96,6 @@ data class CordappImpl( serializationCustomSerializers = emptyList(), checkpointCustomSerializers = emptyList(), customSchemas = emptySet(), - jarPath = Paths.get("").toUri().toURL(), info = UNKNOWN_INFO, allFlows = emptyList(), jarHash = SecureHash.allOnesHash, diff --git a/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappProviderInternal.kt b/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappProviderInternal.kt new file mode 100644 index 0000000000..fd83ba26f1 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappProviderInternal.kt @@ -0,0 +1,23 @@ +package net.corda.core.internal.cordapp + +import net.corda.core.contracts.ContractAttachment +import net.corda.core.contracts.ContractClassName +import net.corda.core.cordapp.Cordapp +import net.corda.core.cordapp.CordappProvider +import net.corda.core.flows.FlowLogic +import net.corda.core.internal.verification.AttachmentFixups + +interface CordappProviderInternal : CordappProvider { + val appClassLoader: ClassLoader + val attachmentFixups: AttachmentFixups + val cordapps: List + fun getCordappForFlow(flowLogic: FlowLogic<*>): Cordapp? + + /** + * Similar to [getContractAttachmentID] except it returns the [ContractAttachment] object and also returns an optional second attachment + * representing the legacy version (4.11 or earlier) of the contract, if one exists. + */ + fun getContractAttachments(contractClassName: ContractClassName): ContractAttachmentWithLegacy? +} + +data class ContractAttachmentWithLegacy(val currentAttachment: ContractAttachment, val legacyAttachment: ContractAttachment? = null) diff --git a/core/src/main/kotlin/net/corda/core/internal/cordapp/KotlinMetadataVersion.kt b/core/src/main/kotlin/net/corda/core/internal/cordapp/KotlinMetadataVersion.kt new file mode 100644 index 0000000000..3fc946dd03 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/internal/cordapp/KotlinMetadataVersion.kt @@ -0,0 +1,32 @@ +package net.corda.core.internal.cordapp + +data class KotlinMetadataVersion(val major: Int, val minor: Int, val patch: Int = 0) : Comparable { + companion object { + fun from(versionArray: IntArray): KotlinMetadataVersion { + val (major, minor, patch) = versionArray + return KotlinMetadataVersion(major, minor, patch) + } + } + + init { + require(major >= 0) { "Major version should be not less than 0" } + require(minor >= 0) { "Minor version should be not less than 0" } + require(patch >= 0) { "Patch version should be not less than 0" } + } + + /** + * Returns the equivalent [KotlinVersion] without the patch. + */ + val languageMinorVersion: KotlinVersion + // See `kotlinx.metadata.jvm.JvmMetadataVersion` + get() = if (major == 1 && minor == 1) KotlinVersion(1, 2) else KotlinVersion(major, minor) + + override fun compareTo(other: KotlinMetadataVersion): Int { + val majors = this.major.compareTo(other.major) + if (majors != 0) return majors + val minors = this.minor.compareTo(other.minor) + return if (minors != 0) minors else this.patch.compareTo(other.patch) + } + + override fun toString(): String = "$major.$minor.$patch" +} diff --git a/core/src/main/kotlin/net/corda/core/internal/cordapp/LanguageVersion.kt b/core/src/main/kotlin/net/corda/core/internal/cordapp/LanguageVersion.kt new file mode 100644 index 0000000000..d85a714844 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/internal/cordapp/LanguageVersion.kt @@ -0,0 +1,56 @@ +package net.corda.core.internal.cordapp + +import net.corda.core.internal.JAVA_17_CLASS_FILE_MAJOR_VERSION +import net.corda.core.internal.JAVA_1_2_CLASS_FILE_MAJOR_VERSION +import net.corda.core.internal.JAVA_8_CLASS_FILE_MAJOR_VERSION + +sealed class LanguageVersion { + /** + * Returns true if this version is compatible with Corda 4.11 or earlier. + */ + abstract val isLegacyCompatible: Boolean + + /** + * Returns true if this version is compatible with Corda 4.12 or later. + */ + abstract val isNonLegacyCompatible: Boolean + + @Suppress("ConvertObjectToDataObject") // External verifier uses Kotlin 1.2 + object Data : LanguageVersion() { + override val isLegacyCompatible: Boolean + get() = true + + override val isNonLegacyCompatible: Boolean + get() = true + + override fun toString(): String = "Data" + } + + data class Bytecode(val classFileMajorVersion: Int, val kotlinMetadataVersion: KotlinMetadataVersion?): LanguageVersion() { + companion object { + private val KOTLIN_1_2_VERSION = KotlinVersion(1, 2) + private val KOTLIN_1_9_VERSION = KotlinVersion(1, 9) + } + + init { + require(classFileMajorVersion in JAVA_1_2_CLASS_FILE_MAJOR_VERSION..JAVA_17_CLASS_FILE_MAJOR_VERSION) { + "Unsupported class file major version $classFileMajorVersion" + } + val kotlinVersion = kotlinMetadataVersion?.languageMinorVersion + require(kotlinVersion == null || kotlinVersion == KOTLIN_1_2_VERSION || kotlinVersion == KOTLIN_1_9_VERSION) { + "Unsupported Kotlin metadata version $kotlinMetadataVersion" + } + } + + override val isLegacyCompatible: Boolean + get() = when { + classFileMajorVersion > JAVA_8_CLASS_FILE_MAJOR_VERSION -> false + kotlinMetadataVersion == null -> true // Java 8 CorDapp is fine + else -> kotlinMetadataVersion.languageMinorVersion == KOTLIN_1_2_VERSION + } + + override val isNonLegacyCompatible: Boolean + // Java-only CorDapp will always be compatible on 4.12 + get() = if (kotlinMetadataVersion == null) true else kotlinMetadataVersion.languageMinorVersion == KOTLIN_1_9_VERSION + } +} diff --git a/core/src/main/kotlin/net/corda/core/internal/telemetry/TelemetryServiceImpl.kt b/core/src/main/kotlin/net/corda/core/internal/telemetry/TelemetryServiceImpl.kt index 54bc1249f7..9c307cee00 100644 --- a/core/src/main/kotlin/net/corda/core/internal/telemetry/TelemetryServiceImpl.kt +++ b/core/src/main/kotlin/net/corda/core/internal/telemetry/TelemetryServiceImpl.kt @@ -178,7 +178,6 @@ class TelemetryServiceImpl : SingletonSerializeAsToken(), TelemetryService { } } - @Suppress("TooGenericExceptionCaught") inline fun span(name: String, attributes: Map = emptyMap(), flowLogic: FlowLogic<*>? = null, block: () -> R): R { val telemetryId = startSpan(name, attributes, flowLogic) try { @@ -195,7 +194,7 @@ class TelemetryServiceImpl : SingletonSerializeAsToken(), TelemetryService { } @CordaInternal - @Suppress("LongParameterList", "TooGenericExceptionCaught") + @Suppress("LongParameterList") inline fun spanForFlow(name: String, attributes: Map, flowLogic: FlowLogic<*>? = null, remoteSerializedTelemetry: SerializedTelemetry? = null, block: () -> R): R { val telemetryId = startSpanForFlow(name, attributes, flowLogic, remoteSerializedTelemetry) try { diff --git a/core/src/main/kotlin/net/corda/core/internal/utilities/PrivateInterner.kt b/core/src/main/kotlin/net/corda/core/internal/utilities/PrivateInterner.kt index 8fbe92f4f9..5407ca4560 100644 --- a/core/src/main/kotlin/net/corda/core/internal/utilities/PrivateInterner.kt +++ b/core/src/main/kotlin/net/corda/core/internal/utilities/PrivateInterner.kt @@ -38,20 +38,20 @@ class PrivateInterner(val verifier: IternabilityVerifier = AlwaysInternabl } fun isSerializableCore(clazz: Class<*>): Boolean { - if (!(clazz.packageNameOrNull?.startsWith("net.corda.core") ?: false)) return false + if (clazz.packageNameOrNull?.startsWith("net.corda.core") != true) return false return hasCordaSerializable(clazz) } fun findInterner(clazz: Class<*>?): PrivateInterner? { // Kotlin reflection has a habit of throwing exceptions, so protect just in case. - try { - return clazz?.kotlin?.companionObjectInstance?.let { + return try { + clazz?.kotlin?.companionObjectInstance?.let { (it as? Internable<*>)?.let { uncheckedCast(it.interner) } } } catch (_: Throwable) { - return null + null } } return if (clazz != null) { @@ -64,6 +64,6 @@ class PrivateInterner(val verifier: IternabilityVerifier = AlwaysInternabl private val interner = Interners.newBuilder().weak().concurrencyLevel(CONCURRENCY_LEVEL).build() - fun intern(sample: S): S = if (DISABLE) sample else uncheckedCast(verifier.choose(sample, interner.intern(sample))) + fun intern(sample: S): S = if (DISABLE) sample else uncheckedCast(verifier.choose(sample, interner.intern(sample!!))) } diff --git a/core/src/main/kotlin/net/corda/core/internal/verification/AttachmentFixups.kt b/core/src/main/kotlin/net/corda/core/internal/verification/AttachmentFixups.kt new file mode 100644 index 0000000000..ab01403edb --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/internal/verification/AttachmentFixups.kt @@ -0,0 +1,79 @@ +package net.corda.core.internal.verification + +import net.corda.core.crypto.SecureHash +import net.corda.core.internal.mapNotNull +import net.corda.core.node.services.AttachmentFixup +import net.corda.core.node.services.AttachmentId +import net.corda.core.node.services.AttachmentStorage +import net.corda.core.transactions.TransactionBuilder +import net.corda.core.utilities.loggerFor +import java.net.JarURLConnection +import java.net.URL + +class AttachmentFixups { + private val fixupRules = ArrayList() + + /** + * Loads the "fixup" rules from all META-INF/Corda-Fixups files. + * These files have the following format: + * ,...=>,,... + * where each is the SHA256 of a CorDapp JAR that [TransactionBuilder] will expect to find inside [AttachmentStorage]. + * + * These rules are for repairing broken CorDapps. A correctly written CorDapp should not require them. + */ + fun load(appClassLoader: ClassLoader) { + for (url in appClassLoader.resources("META-INF/Corda-Fixups")) { + val connection = toValidFixupResource(url) ?: continue + connection.inputStream.bufferedReader().lines().use { lines -> + lines.mapNotNull(::cleanLine).forEach { line -> + val tokens = line.split("=>") + require(tokens.size == 2) { + "Invalid fix-up line '$line' in '${connection.jarFile.name}'" + } + val sourceIds = parseIds(tokens[0]) + require(sourceIds.isNotEmpty()) { + "Forbidden empty list of source attachment IDs in '${connection.jarFile.name}'" + } + val targetIds = parseIds(tokens[1]) + fixupRules += AttachmentFixup(sourceIds, targetIds) + } + } + } + } + + private fun toValidFixupResource(url: URL): JarURLConnection? { + val connection = url.openConnection() as? JarURLConnection ?: return null + val isValid = connection.jarFile.stream().allMatch { it.name.startsWith("META-INF/") } + if (!isValid) { + loggerFor().warn("FixUp '{}' contains files outside META-INF/ - IGNORING!", connection.jarFile.name) + return null + } + return connection + } + + private fun cleanLine(line: String): String? = line.substringBefore('#').trim().takeIf(String::isNotEmpty) + + private fun parseIds(ids: String): Set { + return ids.splitToSequence(",") + .map(String::trim) + .filter { it.isNotEmpty() } + .mapTo(LinkedHashSet(), SecureHash.Companion::create) + } + + /** + * Apply this node's attachment fix-up rules to the given attachment IDs. + * + * @param attachmentIds A collection of [AttachmentId]s, e.g. as provided by a transaction. + * @return The [attachmentIds] with the fix-up rules applied. + */ + fun fixupAttachmentIds(attachmentIds: Collection): Set { + val replacementIds = LinkedHashSet(attachmentIds) + for ((sourceIds, targetIds) in fixupRules) { + if (replacementIds.containsAll(sourceIds)) { + replacementIds.removeAll(sourceIds) + replacementIds.addAll(targetIds) + } + } + return replacementIds + } +} diff --git a/core/src/main/kotlin/net/corda/core/internal/verification/ExternalVerifierHandle.kt b/core/src/main/kotlin/net/corda/core/internal/verification/ExternalVerifierHandle.kt new file mode 100644 index 0000000000..5563193024 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/internal/verification/ExternalVerifierHandle.kt @@ -0,0 +1,7 @@ +package net.corda.core.internal.verification + +import net.corda.core.transactions.CoreTransaction + +interface ExternalVerifierHandle : AutoCloseable { + fun verifyTransaction(ctx: CoreTransaction) +} diff --git a/core/src/main/kotlin/net/corda/core/internal/verification/NodeVerificationSupport.kt b/core/src/main/kotlin/net/corda/core/internal/verification/NodeVerificationSupport.kt new file mode 100644 index 0000000000..6a8a5ffbc5 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/internal/verification/NodeVerificationSupport.kt @@ -0,0 +1,151 @@ +package net.corda.core.internal.verification + +import net.corda.core.contracts.Attachment +import net.corda.core.contracts.ComponentGroupEnum.OUTPUTS_GROUP +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TransactionResolutionException +import net.corda.core.crypto.SecureHash +import net.corda.core.identity.Party +import net.corda.core.internal.AttachmentTrustCalculator +import net.corda.core.internal.SerializedTransactionState +import net.corda.core.internal.TRUSTED_UPLOADERS +import net.corda.core.internal.cordapp.CordappProviderInternal +import net.corda.core.internal.entries +import net.corda.core.internal.getRequiredGroup +import net.corda.core.internal.getRequiredTransaction +import net.corda.core.node.NetworkParameters +import net.corda.core.node.services.AttachmentStorage +import net.corda.core.node.services.IdentityService +import net.corda.core.node.services.NetworkParametersService +import net.corda.core.node.services.TransactionStorage +import net.corda.core.node.services.vault.AttachmentQueryCriteria.AttachmentsQueryCriteria +import net.corda.core.node.services.vault.AttachmentSort +import net.corda.core.node.services.vault.AttachmentSort.AttachmentSortAttribute +import net.corda.core.node.services.vault.AttachmentSort.AttachmentSortColumn +import net.corda.core.node.services.vault.Builder +import net.corda.core.node.services.vault.Sort +import net.corda.core.serialization.deserialize +import net.corda.core.serialization.internal.AttachmentsClassLoaderBuilder +import net.corda.core.serialization.serialize +import net.corda.core.transactions.ContractUpgradeLedgerTransaction +import net.corda.core.transactions.ContractUpgradeWireTransaction +import net.corda.core.transactions.MissingContractAttachments +import net.corda.core.transactions.NotaryChangeLedgerTransaction +import net.corda.core.transactions.NotaryChangeWireTransaction +import net.corda.core.transactions.WireTransaction +import java.security.PublicKey + +/** + * Implements [VerificationSupport] in terms of node-based services. + */ +interface NodeVerificationSupport : VerificationSupport { + val networkParameters: NetworkParameters + + val validatedTransactions: TransactionStorage + + val identityService: IdentityService + + val attachments: AttachmentStorage + + val networkParametersService: NetworkParametersService + + val cordappProvider: CordappProviderInternal + + val attachmentTrustCalculator: AttachmentTrustCalculator + + val externalVerifierHandle: ExternalVerifierHandle + + override val appClassLoader: ClassLoader + get() = cordappProvider.appClassLoader + + // TODO Bulk party lookup? + override fun getParties(keys: Collection): List = keys.map(identityService::partyFromKey) + + override fun getAttachment(id: SecureHash): Attachment? = attachments.openAttachment(id) + + override fun getNetworkParameters(id: SecureHash?): NetworkParameters? { + return if (id != null) networkParametersService.lookup(id) else networkParameters + } + + /** + * This is the main logic that knows how to retrieve the binary representation of [StateRef]s. + * + * For [ContractUpgradeWireTransaction] or [NotaryChangeWireTransaction] it knows how to recreate the output state in the + * correct classloader independent of the node's classpath. + */ + override fun getSerializedState(stateRef: StateRef): SerializedTransactionState { + val coreTransaction = validatedTransactions.getRequiredTransaction(stateRef.txhash).coreTransaction + return when (coreTransaction) { + is WireTransaction -> getRegularOutput(coreTransaction, stateRef.index) + is ContractUpgradeWireTransaction -> getContractUpdateOutput(coreTransaction, stateRef.index) + is NotaryChangeWireTransaction -> getNotaryChangeOutput(coreTransaction, stateRef.index) + else -> throw UnsupportedOperationException("Attempting to resolve input ${stateRef.index} of a ${coreTransaction.javaClass} " + + "transaction. This is not supported.") + } + } + + private fun getRegularOutput(coreTransaction: WireTransaction, outputIndex: Int): SerializedTransactionState { + @Suppress("UNCHECKED_CAST") + return coreTransaction.componentGroups.getRequiredGroup(OUTPUTS_GROUP).components[outputIndex] as SerializedTransactionState + } + + /** + * Creates a binary serialized component for a virtual output state serialised and executed with the attachments from the transaction. + */ + @Suppress("ThrowsCount") + private fun getContractUpdateOutput(wtx: ContractUpgradeWireTransaction, outputIndex: Int): SerializedTransactionState { + val binaryInput = getSerializedState(wtx.inputs[outputIndex]) + val legacyContractAttachment = getAttachment(wtx.legacyContractAttachmentId) ?: throw MissingContractAttachments(emptyList()) + val upgradedContractAttachment = getAttachment(wtx.upgradedContractAttachmentId) ?: throw MissingContractAttachments(emptyList()) + val networkParameters = getNetworkParameters(wtx.networkParametersHash) ?: throw TransactionResolutionException(wtx.id) + + return AttachmentsClassLoaderBuilder.withAttachmentsClassLoaderContext( + listOf(legacyContractAttachment, upgradedContractAttachment), + networkParameters, + wtx.id, + ::isAttachmentTrusted, + attachmentsClassLoaderCache = attachmentsClassLoaderCache + ) { serializationContext -> + val upgradedContract = ContractUpgradeLedgerTransaction.loadUpgradedContract(wtx.upgradedContractClassName, wtx.id, serializationContext.deserializationClassLoader) + val outputState = ContractUpgradeWireTransaction.calculateUpgradedState(binaryInput.deserialize(), upgradedContract, upgradedContractAttachment) + outputState.serialize() + } + } + + /** + * This should return a serialized virtual output state, that will be used to verify spending transactions. + * The binary output should not depend on the classpath of the node that is verifying the transaction. + * + * Ideally the serialization engine would support partial deserialization so that only the Notary ( and the encumbrance can be replaced + * from the binary input state) + */ + // TODO - currently this uses the main classloader. + private fun getNotaryChangeOutput(wtx: NotaryChangeWireTransaction, outputIndex: Int): SerializedTransactionState { + val input = getStateAndRef(wtx.inputs[outputIndex]) + val output = NotaryChangeLedgerTransaction.computeOutput(input, wtx.newNotary) { wtx.inputs } + return output.serialize() + } + + /** + * Scans trusted (installed locally) attachments to find all that contain the [className]. + * + * @return attachments containing the given class in descending version order. This means any legacy attachments will occur after the + * current version one. + */ + override fun getTrustedClassAttachments(className: String): List { + val allTrusted = attachments.queryAttachments( + AttachmentsQueryCriteria().withUploader(Builder.`in`(TRUSTED_UPLOADERS)), + AttachmentSort(listOf(AttachmentSortColumn(AttachmentSortAttribute.VERSION, Sort.Direction.DESC))) + ) + val fileName = "$className.class" + return allTrusted.mapNotNull { id -> attachments.openAttachment(id)!!.takeIf { it.hasFile(fileName) } } + } + + private fun Attachment.hasFile(className: String): Boolean = openAsJAR().use { it.entries().any { entry -> entry.name == className } } + + override fun isAttachmentTrusted(attachment: Attachment): Boolean = attachmentTrustCalculator.calculate(attachment) + + override fun fixupAttachmentIds(attachmentIds: Collection): Set { + return cordappProvider.attachmentFixups.fixupAttachmentIds(attachmentIds) + } +} diff --git a/core/src/main/kotlin/net/corda/core/internal/verification/VerificationResult.kt b/core/src/main/kotlin/net/corda/core/internal/verification/VerificationResult.kt new file mode 100644 index 0000000000..a316e12375 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/internal/verification/VerificationResult.kt @@ -0,0 +1,64 @@ +package net.corda.core.internal.verification + +import net.corda.core.transactions.LedgerTransaction +import net.corda.core.utilities.Try +import net.corda.core.utilities.Try.Failure +import net.corda.core.utilities.Try.Success + +sealed class VerificationResult { + /** + * The in-process result for the current version of the transcaction. + */ + abstract val inProcessResult: Try? + + /** + * The external verifier result for the legacy version of the transaction. + */ + abstract val externalResult: Try? + + abstract fun enforceSuccess(): LedgerTransaction? + + + data class InProcess(override val inProcessResult: Try) : VerificationResult() { + override val externalResult: Try? + get() = null + + override fun enforceSuccess(): LedgerTransaction? = inProcessResult.getOrThrow() + } + + data class External(override val externalResult: Try) : VerificationResult() { + override val inProcessResult: Try? + get() = null + + override fun enforceSuccess(): LedgerTransaction? { + externalResult.getOrThrow() + // We could create a LedgerTransaction here, and except for calling `verify()`, it would be valid to use. However, it's best + // we let the caller deal with that, since we can't prevent them from calling it. + return null + } + } + + data class InProcessAndExternal( + override val inProcessResult: Try, + override val externalResult: Try + ) : VerificationResult() { + override fun enforceSuccess(): LedgerTransaction { + return when (externalResult) { + is Success -> when (inProcessResult) { + is Success -> inProcessResult.value + is Failure -> throw IllegalStateException( + "Current version of transaction failed to verify, but legacy version did verify (in external verifier)", + inProcessResult.exception + ) + } + is Failure -> throw when (inProcessResult) { + is Success -> IllegalStateException( + "Current version of transaction verified, but legacy version failed to verify (in external verifier)", + externalResult.exception + ) + is Failure -> inProcessResult.exception.apply { addSuppressed(externalResult.exception) } + } + } + } + } +} diff --git a/core/src/main/kotlin/net/corda/core/internal/verification/VerificationSupport.kt b/core/src/main/kotlin/net/corda/core/internal/verification/VerificationSupport.kt new file mode 100644 index 0000000000..401b8135f4 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/internal/verification/VerificationSupport.kt @@ -0,0 +1,50 @@ +package net.corda.core.internal.verification + +import net.corda.core.contracts.Attachment +import net.corda.core.contracts.StateAndRef +import net.corda.core.contracts.StateRef +import net.corda.core.crypto.SecureHash +import net.corda.core.identity.Party +import net.corda.core.internal.SerializedTransactionState +import net.corda.core.node.NetworkParameters +import net.corda.core.serialization.SerializationContext +import net.corda.core.serialization.deserialize +import net.corda.core.serialization.internal.AttachmentsClassLoaderCache +import net.corda.core.transactions.LedgerTransaction +import net.corda.core.transactions.defaultVerifier +import java.security.PublicKey + +/** + * Represents the operations required to resolve and verify a transaction. + */ +interface VerificationSupport { + val isInProcess: Boolean get() = true + + val appClassLoader: ClassLoader + + val attachmentsClassLoaderCache: AttachmentsClassLoaderCache? get() = null + + // TODO Use SequencedCollection if upgraded to Java 21 + fun getParties(keys: Collection): List + + fun getAttachment(id: SecureHash): Attachment? + + // TODO Use SequencedCollection if upgraded to Java 21 + fun getAttachments(ids: Collection): List = ids.map(::getAttachment) + + fun isAttachmentTrusted(attachment: Attachment): Boolean + + fun getTrustedClassAttachments(className: String): List + + fun getNetworkParameters(id: SecureHash?): NetworkParameters? + + fun getSerializedState(stateRef: StateRef): SerializedTransactionState + + fun getStateAndRef(stateRef: StateRef): StateAndRef<*> = StateAndRef(getSerializedState(stateRef).deserialize(), stateRef) + + fun fixupAttachmentIds(attachmentIds: Collection): Set + + fun createVerifier(ltx: LedgerTransaction, serializationContext: SerializationContext): Verifier { + return defaultVerifier(ltx, serializationContext) + } +} diff --git a/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt b/core/src/main/kotlin/net/corda/core/internal/verification/Verifier.kt similarity index 94% rename from core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt rename to core/src/main/kotlin/net/corda/core/internal/verification/Verifier.kt index 840163238f..ab448bd0b0 100644 --- a/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt +++ b/core/src/main/kotlin/net/corda/core/internal/verification/Verifier.kt @@ -1,7 +1,5 @@ -package net.corda.core.internal +package net.corda.core.internal.verification -import net.corda.core.concurrent.CordaFuture -import net.corda.core.contracts.Attachment import net.corda.core.contracts.Contract import net.corda.core.contracts.ContractAttachment import net.corda.core.contracts.ContractClassName @@ -30,21 +28,26 @@ import net.corda.core.contracts.TransactionVerificationException.TransactionNota import net.corda.core.contracts.TransactionVerificationException.TransactionRequiredContractUnspecifiedException import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SecureHash +import net.corda.core.internal.AttachmentWithContext +import net.corda.core.internal.MAX_NUMBER_OF_KEYS_IN_SIGNATURE_CONSTRAINT +import net.corda.core.internal.PlatformVersionSwitches +import net.corda.core.internal.canBeTransitionedFrom +import net.corda.core.internal.checkConstraintValidity +import net.corda.core.internal.checkMinimumPlatformVersion +import net.corda.core.internal.checkNotaryWhitelisted +import net.corda.core.internal.checkSupportedHashType +import net.corda.core.internal.contractHasAutomaticConstraintPropagation +import net.corda.core.internal.loadClassOfType +import net.corda.core.internal.mapToSet +import net.corda.core.internal.requiredContractClassName import net.corda.core.internal.rules.StateContractValidationEnforcementRule +import net.corda.core.internal.warnContractWithoutConstraintPropagation +import net.corda.core.internal.warnOnce import net.corda.core.transactions.LedgerTransaction import net.corda.core.utilities.loggerFor import java.util.function.Function import java.util.function.Supplier -interface TransactionVerifierServiceInternal { - fun reverifyWithFixups(transaction: LedgerTransaction, missingClass: String?): CordaFuture<*> -} - -/** - * Defined here for visibility reasons. - */ -fun LedgerTransaction.prepareVerify(attachments: List) = internalPrepareVerify(attachments) - interface Verifier { /** @@ -142,10 +145,12 @@ private class Validator(private val ltx: LedgerTransaction, private val transact */ @Suppress("ThrowsCount") private fun getUniqueContractAttachmentsByContract(): Map { - val contractClasses = allStates.mapTo(LinkedHashSet(), TransactionState<*>::contract) + val contractClasses = allStates.mapToSet { it.contract } // Check that there are no duplicate attachments added. - if (ltx.attachments.size != ltx.attachments.toSet().size) throw DuplicateAttachmentsRejection(ltx.id, ltx.attachments.groupBy { it }.filterValues { it.size > 1 }.keys.first()) + if (ltx.attachments.size != ltx.attachments.toSet().size) { + throw DuplicateAttachmentsRejection(ltx.id, ltx.attachments.groupBy { it }.filterValues { it.size > 1 }.keys.first()) + } // For each attachment this finds all the relevant state contracts that it provides. // And then maps them to the attachment. @@ -393,7 +398,7 @@ private class Validator(private val ltx: LedgerTransaction, private val transact @Suppress("NestedBlockDepth", "MagicNumber") private fun verifyConstraints(contractAttachmentsByContract: Map) { // For each contract/constraint pair check that the relevant attachment is valid. - allStates.mapTo(LinkedHashSet()) { it.contract to it.constraint }.forEach { (contract, constraint) -> + allStates.mapToSet { it.contract to it.constraint }.forEach { (contract, constraint) -> if (constraint is SignatureAttachmentConstraint) { /** * Support for signature constraints has been added on @@ -435,12 +440,11 @@ private class Validator(private val ltx: LedgerTransaction, private val transact * Verify the given [LedgerTransaction]. This includes validating * its contents, as well as executing all of its smart contracts. */ -@Suppress("TooGenericExceptionCaught") class TransactionVerifier(private val transactionClassLoader: ClassLoader) : Function, Unit> { // Loads the contract class from the transactionClassLoader. private fun createContractClass(id: SecureHash, contractClassName: ContractClassName): Class { return try { - Class.forName(contractClassName, false, transactionClassLoader).asSubclass(Contract::class.java) + loadClassOfType(contractClassName, false, transactionClassLoader) } catch (e: Exception) { throw ContractCreationError(id, contractClassName, e) } @@ -448,7 +452,7 @@ class TransactionVerifier(private val transactionClassLoader: ClassLoader) : Fun private fun generateContracts(ltx: LedgerTransaction): List { return (ltx.inputs.map(StateAndRef::state) + ltx.outputs) - .mapTo(LinkedHashSet(), TransactionState<*>::contract) + .mapToSet { it.contract } .map { contractClassName -> createContractClass(ltx.id, contractClassName) }.map { contractClass -> @@ -465,6 +469,7 @@ class TransactionVerifier(private val transactionClassLoader: ClassLoader) : Fun } override fun apply(transactionFactory: Supplier) { + @Suppress("VARIABLE_WITH_REDUNDANT_INITIALIZER") // Because the external verifier uses Kotlin 1.2 var firstLtx: LedgerTransaction? = null transactionFactory.get().let { ltx -> diff --git a/core/src/main/kotlin/net/corda/core/internal/verification/VerifyingServiceHub.kt b/core/src/main/kotlin/net/corda/core/internal/verification/VerifyingServiceHub.kt new file mode 100644 index 0000000000..78c5e790cf --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/internal/verification/VerifyingServiceHub.kt @@ -0,0 +1,77 @@ +package net.corda.core.internal.verification + +import net.corda.core.contracts.Attachment +import net.corda.core.contracts.AttachmentResolutionException +import net.corda.core.contracts.ContractAttachment +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.StateAndRef +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TransactionState +import net.corda.core.crypto.SecureHash +import net.corda.core.internal.getRequiredTransaction +import net.corda.core.node.ServiceHub +import net.corda.core.node.ServicesForResolution +import net.corda.core.serialization.deserialize +import net.corda.core.transactions.ContractUpgradeWireTransaction +import net.corda.core.transactions.NotaryChangeWireTransaction +import net.corda.core.transactions.WireTransaction + +@Suppress("TooManyFunctions", "ThrowsCount") +interface VerifyingServiceHub : ServiceHub, NodeVerificationSupport { + override fun loadContractAttachment(stateRef: StateRef): Attachment { + // We may need to recursively chase transactions if there are notary changes. + return loadContractAttachment(stateRef, null) + } + + private fun loadContractAttachment(stateRef: StateRef, forContractClassName: String?): Attachment { + val stx = getRequiredTransaction(stateRef.txhash) + val ctx = stx.coreTransaction + return when (ctx) { + is WireTransaction -> { + val contractClassName = forContractClassName ?: ctx.outRef(stateRef.index).state.contract + ctx.attachments + .asSequence() + .mapNotNull { id -> loadAttachmentContainingContract(id, contractClassName) } + .firstOrNull() ?: throw AttachmentResolutionException(stateRef.txhash) + } + is ContractUpgradeWireTransaction -> { + attachments.openAttachment(ctx.upgradedContractAttachmentId) ?: throw AttachmentResolutionException(stateRef.txhash) + } + is NotaryChangeWireTransaction -> { + val transactionState = getSerializedState(stateRef).deserialize() + val input = ctx.inputs.firstOrNull() ?: throw AttachmentResolutionException(stateRef.txhash) + loadContractAttachment(input, transactionState.contract) + } + else -> throw UnsupportedOperationException("Attempting to resolve attachment for index ${stateRef.index} of a " + + "${ctx.javaClass} transaction. This is not supported.") + } + } + + private fun loadAttachmentContainingContract(id: SecureHash, contractClassName: String): Attachment? { + return attachments.openAttachment(id)?.takeIf { it is ContractAttachment && contractClassName in it.allContracts } + } + + override fun loadState(stateRef: StateRef): TransactionState<*> = getSerializedState(stateRef).deserialize() + + override fun loadStates(stateRefs: Set): Set> = loadStatesInternal(stateRefs, LinkedHashSet()) + + fun >> loadStatesInternal(input: Iterable, output: C): C { + return input.mapTo(output, ::toStateAndRef) + } +} + +fun ServicesForResolution.toVerifyingServiceHub(): VerifyingServiceHub { + if (this is VerifyingServiceHub) { + return this + } + // All ServicesForResolution instances should also implement VerifyingServiceHub, which is something we can enforce with the + // @DoNotImplement annotation. The only exception however is MockServices, which does not since it's public API and VerifyingServiceHub + // is internal. Instead, MockServices has a private VerifyingServiceHub "view" which we get at via reflection. + var clazz: Class<*> = javaClass + while (true) { + if (clazz.name == "net.corda.testing.node.MockServices") { + return clazz.getDeclaredMethod("getVerifyingView").apply { isAccessible = true }.invoke(this) as VerifyingServiceHub + } + clazz = clazz.superclass ?: throw ClassCastException("${javaClass.name} is not a VerifyingServiceHub") + } +} diff --git a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt index 264d49d7ad..2bf4bcdfcd 100644 --- a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt +++ b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt @@ -11,6 +11,7 @@ import net.corda.core.crypto.TransactionSignature import net.corda.core.flows.ContractUpgradeFlow import net.corda.core.internal.PlatformVersionSwitches.TWO_PHASE_FINALITY import net.corda.core.internal.telemetry.TelemetryComponent +import net.corda.core.internal.uncheckedCast import net.corda.core.node.services.* import net.corda.core.node.services.diagnostics.DiagnosticsService import net.corda.core.serialization.CordaSerializable @@ -81,7 +82,6 @@ interface ServicesForResolution { /** * Provides a callback for the Node to customise the [LedgerTransaction]. */ - @JvmDefault fun specialise(ltx: LedgerTransaction): LedgerTransaction = ltx } @@ -171,12 +171,6 @@ interface ServiceHub : ServicesForResolution { */ val telemetryService: TelemetryService - /** - * INTERNAL. DO NOT USE. - * @suppress - */ - val transactionVerifierService: TransactionVerifierService - /** * A [Clock] representing the node's current time. This should be used in preference to directly accessing the * clock so the current time can be controlled during unit testing. @@ -284,8 +278,7 @@ interface ServiceHub : ServicesForResolution { */ @Throws(TransactionResolutionException::class) fun toStateAndRef(stateRef: StateRef): StateAndRef { - val stx = validatedTransactions.getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash) - return stx.resolveBaseTransaction(this).outRef(stateRef.index) + return StateAndRef(uncheckedCast(loadState(stateRef)), stateRef) } private val legalIdentityKey: PublicKey get() = this.myInfo.legalIdentitiesAndCerts.first().owningKey @@ -425,8 +418,8 @@ interface ServiceHub : ServicesForResolution { * When used within a flow, this session automatically forms part of the enclosing flow transaction boundary, * and thus queryable data will include everything committed as of the last checkpoint. * - * We want to make sure users have a restricted access to administrative functions, this function will return a [RestrictedConnection] instance. - * The following methods are blocked: + * We want to make sure users have a restricted access to administrative functions, this function will return a [Connection] instance + * with the following methods blocked: * - abort(executor: Executor?) * - clearWarnings() * - close() diff --git a/core/src/main/kotlin/net/corda/core/node/services/AttachmentStorage.kt b/core/src/main/kotlin/net/corda/core/node/services/AttachmentStorage.kt index e39de6f7b7..20b29e3b1e 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/AttachmentStorage.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/AttachmentStorage.kt @@ -1,4 +1,3 @@ - package net.corda.core.node.services import net.corda.core.DoNotImplement diff --git a/core/src/main/kotlin/net/corda/core/node/services/TransactionVerifierService.kt b/core/src/main/kotlin/net/corda/core/node/services/TransactionVerifierService.kt deleted file mode 100644 index d72eec72f2..0000000000 --- a/core/src/main/kotlin/net/corda/core/node/services/TransactionVerifierService.kt +++ /dev/null @@ -1,18 +0,0 @@ -package net.corda.core.node.services - -import net.corda.core.DoNotImplement -import net.corda.core.concurrent.CordaFuture -import net.corda.core.transactions.LedgerTransaction - -/** - * Provides verification service. The implementation may be a simple in-memory verify() call or perhaps an IPC/RPC. - * @suppress - */ -@DoNotImplement -interface TransactionVerifierService { - /** - * @param transaction The transaction to be verified. - * @return A future that completes successfully if the transaction verified, or sets an exception the verifier threw. - */ - fun verify(transaction: LedgerTransaction): CordaFuture<*> -} \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/node/services/VaultService.kt b/core/src/main/kotlin/net/corda/core/node/services/VaultService.kt index e11e59cc9c..95bdc189ce 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/VaultService.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/VaultService.kt @@ -123,24 +123,24 @@ class Vault(val states: Iterable>) { override fun toString(): String { val sb = StringBuilder() - sb.appendln("${consumed.size} consumed, ${produced.size} produced") - sb.appendln("") - sb.appendln("Consumed:") + sb.appendLine("${consumed.size} consumed, ${produced.size} produced") + sb.appendLine("") + sb.appendLine("Consumed:") consumed.forEach { - sb.appendln("${it.ref}: ${it.state}") + sb.appendLine("${it.ref}: ${it.state}") } - sb.appendln("") - sb.appendln("Produced:") + sb.appendLine("") + sb.appendLine("Produced:") produced.forEach { - sb.appendln("${it.ref}: ${it.state}") + sb.appendLine("${it.ref}: ${it.state}") } - sb.appendln("References:") + sb.appendLine("References:") references.forEach { - sb.appendln("${it.ref}: ${it.state}") + sb.appendLine("${it.ref}: ${it.state}") } - sb.appendln("Consuming TxIds:") + sb.appendLine("Consuming TxIds:") consumingTxIds.forEach { - sb.appendln("${it.key}: ${it.value}") + sb.appendLine("${it.key}: ${it.value}") } return sb.toString() } @@ -308,9 +308,9 @@ class Vault(val states: Iterable>) { companion object { @Deprecated("No longer used. The vault does not emit empty updates") - val NoUpdate = Update(emptySet(), emptySet(), type = UpdateType.GENERAL, references = emptySet()) + val NoUpdate = Update(emptySet(), emptySet(), type = UpdateType.GENERAL, references = emptySet()) @Deprecated("No longer used. The vault does not emit empty updates") - val NoNotaryUpdate = Update(emptySet(), emptySet(), type = UpdateType.NOTARY_CHANGE, references = emptySet()) + val NoNotaryUpdate = Update(emptySet(), emptySet(), type = UpdateType.NOTARY_CHANGE, references = emptySet()) } } @@ -589,4 +589,4 @@ class VaultQueryException(description: String, cause: Exception? = null) : FlowE class StatesNotAvailableException(override val message: String?, override val cause: Throwable? = null) : FlowException(message, cause) { override fun toString() = "Soft locking error: $message" -} \ No newline at end of file +} diff --git a/core/src/main/kotlin/net/corda/core/observable/internal/ResilientSubscriber.kt b/core/src/main/kotlin/net/corda/core/observable/internal/ResilientSubscriber.kt index 074a17a719..05a9b24811 100644 --- a/core/src/main/kotlin/net/corda/core/observable/internal/ResilientSubscriber.kt +++ b/core/src/main/kotlin/net/corda/core/observable/internal/ResilientSubscriber.kt @@ -33,7 +33,6 @@ class ResilientSubscriber(actual: Subscriber) : SafeSubscriber(actua * It only delegates to [SafeSubscriber.onError] if it wraps an [ActionSubscriber] which is * a leaf in an Subscribers' tree structure. */ - @Suppress("TooGenericExceptionCaught") override fun onNext(t: T) { try { actual.onNext(t) @@ -62,7 +61,6 @@ class ResilientSubscriber(actual: Subscriber) : SafeSubscriber(actua /** * Duplicate of [SafeSubscriber._onError]. However, it will not call [Subscriber.unsubscribe]. */ - @Suppress("TooGenericExceptionCaught") override fun _onError(e: Throwable) { @Suppress("DEPRECATION") RxJavaPlugins.getInstance().errorHandler.handleError(e) diff --git a/core/src/main/kotlin/net/corda/core/schemas/CommonSchema.kt b/core/src/main/kotlin/net/corda/core/schemas/CommonSchema.kt index 3a41f0ead8..72cb0ec0b5 100644 --- a/core/src/main/kotlin/net/corda/core/schemas/CommonSchema.kt +++ b/core/src/main/kotlin/net/corda/core/schemas/CommonSchema.kt @@ -26,7 +26,7 @@ object CommonSchemaV1 : MappedSchema(schemaFamily = CommonSchema.javaClass, vers /** X500Name of participant parties **/ @Transient - open var participants: MutableSet? = null, + var participants: MutableSet? = null, /** * Represents a [LinearState] [UniqueIdentifier] @@ -51,7 +51,7 @@ object CommonSchemaV1 : MappedSchema(schemaFamily = CommonSchema.javaClass, vers /** X500Name of participant parties **/ @Transient - open var participants: MutableSet? = null, + var participants: MutableSet? = null, /** [OwnableState] attributes */ diff --git a/core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt b/core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt index 5295b4a46a..79b86d2b96 100644 --- a/core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt +++ b/core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt @@ -75,9 +75,10 @@ open class MappedSchema(schemaFamily: Class<*>, * A super class for all mapped states exported to a schema that ensures the [StateRef] appears on the database row. The * [StateRef] will be set to the correct value by the framework (there's no need to set during mapping generation by the state itself). */ +@Suppress("RedundantModalityModifier") // Because the external verifier uses Kotlin 1.2 @MappedSuperclass @CordaSerializable -class PersistentState(@EmbeddedId override var stateRef: PersistentStateRef? = null) : DirectStatePersistable +open class PersistentState(@EmbeddedId override var stateRef: PersistentStateRef? = null) : DirectStatePersistable /** * Embedded [StateRef] representation used in state mapping. diff --git a/core/src/main/kotlin/net/corda/core/serialization/internal/AttachmentsClassLoader.kt b/core/src/main/kotlin/net/corda/core/serialization/internal/AttachmentsClassLoader.kt index 0d84556633..d10b6b962d 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/internal/AttachmentsClassLoader.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/internal/AttachmentsClassLoader.kt @@ -8,8 +8,8 @@ import net.corda.core.contracts.TransactionVerificationException import net.corda.core.contracts.TransactionVerificationException.OverlappingAttachmentsException import net.corda.core.contracts.TransactionVerificationException.PackageOwnershipException import net.corda.core.crypto.SecureHash -import net.corda.core.internal.JDK1_2_CLASS_FILE_FORMAT_MAJOR_VERSION -import net.corda.core.internal.JDK8_CLASS_FILE_FORMAT_MAJOR_VERSION +import net.corda.core.internal.JAVA_17_CLASS_FILE_MAJOR_VERSION +import net.corda.core.internal.JAVA_1_2_CLASS_FILE_MAJOR_VERSION import net.corda.core.internal.JarSignatureCollector import net.corda.core.internal.NamedCacheFactory import net.corda.core.internal.PlatformVersionSwitches @@ -17,6 +17,7 @@ import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.cordapp.targetPlatformVersion import net.corda.core.internal.createInstancesOfClassesImplementing import net.corda.core.internal.createSimpleCache +import net.corda.core.internal.entries import net.corda.core.internal.toSynchronised import net.corda.core.node.NetworkParameters import net.corda.core.serialization.AMQP_ENVELOPE_CACHE_INITIAL_CAPACITY @@ -48,7 +49,6 @@ import java.util.ServiceLoader import java.util.WeakHashMap import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicLong -import java.util.function.Function import kotlin.collections.component1 import kotlin.collections.component2 import kotlin.collections.set @@ -93,41 +93,26 @@ class AttachmentsClassLoader(attachments: List, * or use a decorator and reflection to bypass the single-call-per-JVM restriction otherwise. */ private fun setOrDecorateURLStreamHandlerFactory() { - // Retrieve the `URL.factory` field - val factoryField = URL::class.java.getDeclaredField("factory") - // Make it accessible - factoryField.isAccessible = true - - // Check for preset factory, set directly if missing - val existingFactory: URLStreamHandlerFactory? = factoryField.get(null) as URLStreamHandlerFactory? - if (existingFactory == null) { + try { URL.setURLStreamHandlerFactory(AttachmentURLStreamHandlerFactory) - } - // Otherwise, decorate the existing and replace via reflection - // as calling `URL.setURLStreamHandlerFactory` again will throw an error - else { + } catch (e: Error) { log.warn("The URLStreamHandlerFactory was already set in the JVM. Please be aware that this is not recommended.") + val factoryField = URL::class.java.getDeclaredField("factory").apply { isAccessible = true } // Retrieve the field "streamHandlerLock" of the class URL that // is the lock used to synchronize access to the protocol handlers - val lockField = URL::class.java.getDeclaredField("streamHandlerLock") + val lockField = URL::class.java.getDeclaredField("streamHandlerLock").apply { isAccessible = true } // It is a private field so we need to make it accessible - // Note: this will only work as-is in JDK8. - lockField.isAccessible = true + val existingFactory = factoryField.get(null) as URLStreamHandlerFactory? // Use the same lock to reset the factory synchronized(lockField.get(null)) { // Reset the value to prevent Error due to a factory already defined factoryField.set(null, null) // Set our custom factory and wrap the current one into it - URL.setURLStreamHandlerFactory( - // Set the factory to a decorator - object : URLStreamHandlerFactory { - // route between our own and the pre-existing factory - override fun createURLStreamHandler(protocol: String): URLStreamHandler? { - return AttachmentURLStreamHandlerFactory.createURLStreamHandler(protocol) - ?: existingFactory.createURLStreamHandler(protocol) - } - } - ) + URL.setURLStreamHandlerFactory { protocol -> + // route between our own and the pre-existing factory + AttachmentURLStreamHandlerFactory.createURLStreamHandler(protocol) + ?: existingFactory?.createURLStreamHandler(protocol) + } } } } @@ -158,9 +143,7 @@ class AttachmentsClassLoader(attachments: List, checkAttachments(attachments) } - private class AttachmentHashContext( - val txId: SecureHash, - val buffer: ByteArray = ByteArray(DEFAULT_BUFFER_SIZE)) + private class AttachmentHashContext(val buffer: ByteArray = ByteArray(DEFAULT_BUFFER_SIZE)) private fun hash(inputStream : InputStream, ctx : AttachmentHashContext) : SecureHash.SHA256 { val md = MessageDigest.getInstance(SecureHash.SHA2_256) @@ -177,19 +160,13 @@ class AttachmentsClassLoader(attachments: List, } private fun containsClasses(attachment: Attachment): Boolean { - attachment.openAsJAR().use { jar -> - while (true) { - val entry = jar.nextJarEntry ?: return false - if (entry.name.endsWith(".class", ignoreCase = true)) return true - } - } - return false + return attachment.openAsJAR().use { it.entries().any { entry -> entry.name.endsWith(".class", ignoreCase = true) } } } // This function attempts to strike a balance between security and usability when it comes to the no-overlap rule. // TODO - investigate potential exploits. private fun shouldCheckForNoOverlap(path: String, targetPlatformVersion: Int): Boolean { - require(path.toLowerCase() == path) + require(path.lowercase() == path) require(!path.contains('\\')) return when { @@ -206,7 +183,10 @@ class AttachmentsClassLoader(attachments: List, @Suppress("ThrowsCount", "ComplexMethod", "NestedBlockDepth") private fun checkAttachments(attachments: List) { - require(attachments.isNotEmpty()) { "attachments list is empty" } + require(attachments.isNotEmpty()) { + "Transaction attachments list is empty. This can happen if verifying a legacy transaction (4.11 or older) with " + + "LedgerTransaction.verify(). Try using SignedTransaction.verify() instead." + } // Here is where we enforce the no-overlap and package ownership rules. // @@ -234,7 +214,7 @@ class AttachmentsClassLoader(attachments: List, // claim their parts of the Java package namespace via registration with the zone operator. val classLoaderEntries = mutableMapOf() - val ctx = AttachmentHashContext(sampleTxId) + val ctx = AttachmentHashContext() for (attachment in attachments) { // We may have been given an attachment loaded from the database in which case, important info like // signers is already calculated. @@ -270,7 +250,7 @@ class AttachmentsClassLoader(attachments: List, // filesystem tries to be case insensitive. This may break developers who attempt to use ProGuard. // // Also convert to Unix path separators as all resource/class lookups will expect this. - val path = entry.name.toLowerCase(Locale.US).replace('\\', '/') + val path = entry.name.lowercase(Locale.US).replace('\\', '/') // Namespace ownership. We only check class files: resources are loaded relative to a JAR anyway. if (path.endsWith(".class")) { @@ -285,7 +265,7 @@ class AttachmentsClassLoader(attachments: List, for ((namespace, pubkey) in params.packageOwnership) { // Note that due to the toLowerCase() call above, we'll be comparing against a lowercased // version of the ownership claim. - val ns = namespace.toLowerCase(Locale.US) + val ns = namespace.lowercase(Locale.US) // We need an additional . to avoid matching com.foo.Widget against com.foobar.Zap if (pkgName == ns || pkgName.startsWith("$ns.")) { if (pubkey !in signers) @@ -348,7 +328,7 @@ object AttachmentsClassLoaderBuilder { * @param txId The transaction ID that triggered this request; it's unused except for error messages and exceptions that can occur during setup. */ @Suppress("LongParameterList") - fun withAttachmentsClassloaderContext(attachments: List, + fun withAttachmentsClassLoaderContext(attachments: List, params: NetworkParameters, txId: SecureHash, isAttachmentTrusted: (Attachment) -> Boolean, @@ -358,12 +338,12 @@ object AttachmentsClassLoaderBuilder { val attachmentIds = attachments.mapTo(LinkedHashSet(), Attachment::id) val cache = attachmentsClassLoaderCache ?: fallBackCache - val cachedSerializationContext = cache.computeIfAbsent(AttachmentsClassLoaderKey(attachmentIds, params), Function { key -> + val cachedSerializationContext = cache.computeIfAbsent(AttachmentsClassLoaderKey(attachmentIds, params)) { key -> // Create classloader and load serializers, whitelisted classes val transactionClassLoader = AttachmentsClassLoader(attachments, key.params, txId, isAttachmentTrusted, parent) val serializers = try { createInstancesOfClassesImplementing(transactionClassLoader, SerializationCustomSerializer::class.java, - JDK1_2_CLASS_FILE_FORMAT_MAJOR_VERSION..JDK8_CLASS_FILE_FORMAT_MAJOR_VERSION) + JAVA_1_2_CLASS_FILE_MAJOR_VERSION..JAVA_17_CLASS_FILE_MAJOR_VERSION) } catch (ex: UnsupportedClassVersionError) { throw TransactionVerificationException.UnsupportedClassVersionError(txId, ex.message!!, ex) } @@ -380,9 +360,9 @@ object AttachmentsClassLoaderBuilder { .withWhitelist(whitelistedClasses) .withCustomSerializers(serializers) .withoutCarpenter() - }) + } - val serializationContext = cachedSerializationContext.withProperties(mapOf( + val serializationContext = cachedSerializationContext.withProperties(mapOf( // Duplicate the SerializationContext from the cache and give // it these extra properties, just for this transaction. // However, keep a strong reference to the cached SerializationContext so we can @@ -419,7 +399,7 @@ object AttachmentURLStreamHandlerFactory : URLStreamHandlerFactory { @Synchronized fun toUrl(attachment: Attachment): URL { - val uniqueURL = URL(attachmentScheme, "", -1, attachment.id.toString()+ "?" + uniqueness.getAndIncrement(), AttachmentURLStreamHandler) + val uniqueURL = URL(attachmentScheme, "", -1, "${attachment.id}?${uniqueness.getAndIncrement()}", AttachmentURLStreamHandler) loadedAttachments[uniqueURL] = attachment return uniqueURL } @@ -436,12 +416,12 @@ object AttachmentURLStreamHandlerFactory : URLStreamHandlerFactory { override fun equals(attachmentUrl: URL, otherURL: URL?): Boolean { if (attachmentUrl.protocol != otherURL?.protocol) return false - if (attachmentUrl.protocol != attachmentScheme) throw IllegalArgumentException("Cannot handle protocol: ${attachmentUrl.protocol}") + require(attachmentUrl.protocol == attachmentScheme) { "Cannot handle protocol: ${attachmentUrl.protocol}" } return attachmentUrl.file == otherURL?.file } override fun hashCode(url: URL): Int { - if (url.protocol != attachmentScheme) throw IllegalArgumentException("Cannot handle protocol: ${url.protocol}") + require(url.protocol == attachmentScheme) { "Cannot handle protocol: ${url.protocol}" } return url.file.hashCode() } } @@ -473,7 +453,10 @@ private class AttachmentsHolderImpl : AttachmentsHolder { } interface AttachmentsClassLoaderCache { - fun computeIfAbsent(key: AttachmentsClassLoaderKey, mappingFunction: Function): SerializationContext + fun computeIfAbsent( + key: AttachmentsClassLoaderKey, + mappingFunction: (AttachmentsClassLoaderKey) -> SerializationContext + ): SerializationContext } class AttachmentsClassLoaderCacheImpl(cacheFactory: NamedCacheFactory) : SingletonSerializeAsToken(), AttachmentsClassLoaderCache { @@ -489,7 +472,6 @@ class AttachmentsClassLoaderCacheImpl(cacheFactory: NamedCacheFactory) : Singlet private val toBeClosed = ConcurrentHashMap.newKeySet() private val expiryQueue = ReferenceQueue() - @Suppress("TooGenericExceptionCaught") private fun purgeExpiryQueue() { // Close the AttachmentsClassLoader for every SerializationContext // that has already been garbage-collected. @@ -522,18 +504,23 @@ class AttachmentsClassLoaderCacheImpl(cacheFactory: NamedCacheFactory) : Singlet }, "AttachmentsClassLoader_cache" ) - override fun computeIfAbsent(key: AttachmentsClassLoaderKey, mappingFunction: Function): SerializationContext { + override fun computeIfAbsent( + key: AttachmentsClassLoaderKey, + mappingFunction: (AttachmentsClassLoaderKey) -> SerializationContext + ): SerializationContext { purgeExpiryQueue() return cache.get(key, mappingFunction) ?: throw NullPointerException("null returned from cache mapping function") } } class AttachmentsClassLoaderSimpleCacheImpl(cacheSize: Int) : AttachmentsClassLoaderCache { - private val cache: MutableMap = createSimpleCache(cacheSize).toSynchronised() - override fun computeIfAbsent(key: AttachmentsClassLoaderKey, mappingFunction: Function): SerializationContext { + override fun computeIfAbsent( + key: AttachmentsClassLoaderKey, + mappingFunction: (AttachmentsClassLoaderKey) -> SerializationContext + ): SerializationContext { return cache.computeIfAbsent(key, mappingFunction) } } diff --git a/core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt index 23b986b721..9c17aa7696 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt @@ -1,16 +1,22 @@ package net.corda.core.transactions import net.corda.core.DoNotImplement -import net.corda.core.contracts.* +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.NamedByHash +import net.corda.core.contracts.StateAndRef +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TransactionState import net.corda.core.identity.Party import net.corda.core.internal.castIfPossible import net.corda.core.internal.indexOfOrThrow +import net.corda.core.internal.toSimpleString import net.corda.core.internal.uncheckedCast import java.util.function.Predicate /** * An abstract class defining fields shared by all transaction types in the system. */ +@Suppress("RedundantSamConstructor") // Because the external verifier uses Kotlin 1.2 @DoNotImplement abstract class BaseTransaction : NamedByHash { /** A list of reusable reference data states which can be referred to by other contracts in this transaction. */ @@ -163,5 +169,5 @@ abstract class BaseTransaction : NamedByHash { return findOutRef(T::class.java, Predicate { predicate(it) }) } - override fun toString(): String = "${javaClass.simpleName}(id=$id)" + override fun toString(): String = toSimpleString() } \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/transactions/ContractUpgradeTransactions.kt b/core/src/main/kotlin/net/corda/core/transactions/ContractUpgradeTransactions.kt index 145da6a07c..e2809a51fe 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/ContractUpgradeTransactions.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/ContractUpgradeTransactions.kt @@ -1,29 +1,48 @@ package net.corda.core.transactions import net.corda.core.CordaInternal -import net.corda.core.contracts.* +import net.corda.core.contracts.Attachment +import net.corda.core.contracts.AttachmentResolutionException +import net.corda.core.contracts.ContractAttachment +import net.corda.core.contracts.ContractClassName +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.HashAttachmentConstraint +import net.corda.core.contracts.PrivacySalt +import net.corda.core.contracts.StateAndRef +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TransactionResolutionException +import net.corda.core.contracts.TransactionState +import net.corda.core.contracts.TransactionVerificationException +import net.corda.core.contracts.UpgradedContract +import net.corda.core.contracts.UpgradedContractWithLegacyConstraint +import net.corda.core.contracts.WhitelistedByZoneAttachmentConstraint import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash import net.corda.core.crypto.TransactionSignature import net.corda.core.identity.Party import net.corda.core.internal.AttachmentWithContext -import net.corda.core.internal.ServiceHubCoreInternal import net.corda.core.internal.combinedHash +import net.corda.core.internal.getRequiredSigningKeysInternal +import net.corda.core.internal.loadClassOfType +import net.corda.core.internal.verification.NodeVerificationSupport +import net.corda.core.internal.verification.VerificationResult +import net.corda.core.internal.verification.VerificationSupport +import net.corda.core.internal.verification.toVerifyingServiceHub import net.corda.core.node.NetworkParameters import net.corda.core.node.ServicesForResolution import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.DeprecatedConstructorForDeserialization -import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.deserialize -import net.corda.core.serialization.internal.AttachmentsClassLoaderBuilder -import net.corda.core.serialization.serialize import net.corda.core.transactions.ContractUpgradeFilteredTransaction.FilteredComponent -import net.corda.core.transactions.ContractUpgradeLedgerTransaction.Companion.loadUpgradedContract -import net.corda.core.transactions.ContractUpgradeLedgerTransaction.Companion.retrieveAppClassLoader import net.corda.core.transactions.ContractUpgradeWireTransaction.Companion.calculateUpgradedState -import net.corda.core.transactions.ContractUpgradeWireTransaction.Component.* -import net.corda.core.transactions.WireTransaction.Companion.resolveStateRefBinaryComponent +import net.corda.core.transactions.ContractUpgradeWireTransaction.Component.INPUTS +import net.corda.core.transactions.ContractUpgradeWireTransaction.Component.LEGACY_ATTACHMENT +import net.corda.core.transactions.ContractUpgradeWireTransaction.Component.NOTARY +import net.corda.core.transactions.ContractUpgradeWireTransaction.Component.PARAMETERS_HASH +import net.corda.core.transactions.ContractUpgradeWireTransaction.Component.UPGRADED_ATTACHMENT +import net.corda.core.transactions.ContractUpgradeWireTransaction.Component.UPGRADED_CONTRACT import net.corda.core.utilities.OpaqueBytes +import net.corda.core.utilities.Try import net.corda.core.utilities.toBase58String import java.security.PublicKey @@ -52,7 +71,10 @@ data class ContractUpgradeWireTransaction( * Runs the explicit upgrade logic. */ @CordaInternal - internal fun calculateUpgradedState(state: TransactionState, upgradedContract: UpgradedContract, upgradedContractAttachment: Attachment): TransactionState { + @JvmSynthetic + internal fun calculateUpgradedState(state: TransactionState, + upgradedContract: UpgradedContract, + upgradedContractAttachment: Attachment): TransactionState { // TODO: if there are encumbrance states in the inputs, just copy them across without modifying val upgradedState: S = upgradedContract.upgrade(state.data) val inputConstraint = state.constraint @@ -121,60 +143,12 @@ data class ContractUpgradeWireTransaction( /** Resolves input states and contract attachments, and builds a ContractUpgradeLedgerTransaction. */ fun resolve(services: ServicesForResolution, sigs: List): ContractUpgradeLedgerTransaction { - val resolvedInputs = services.loadStates(inputs.toSet()).toList() - val legacyContractAttachment = services.attachments.openAttachment(legacyContractAttachmentId) - ?: throw AttachmentResolutionException(legacyContractAttachmentId) - val upgradedContractAttachment = services.attachments.openAttachment(upgradedContractAttachmentId) - ?: throw AttachmentResolutionException(upgradedContractAttachmentId) - val hashToResolve = networkParametersHash ?: services.networkParametersService.defaultHash - val resolvedNetworkParameters = services.networkParametersService.lookup(hashToResolve) ?: throw TransactionResolutionException(id) - return ContractUpgradeLedgerTransaction.create( - resolvedInputs, - notary, - legacyContractAttachment, - upgradedContractAttachment, - id, - privacySalt, - sigs, - resolvedNetworkParameters, - loadUpgradedContract(upgradedContractClassName, retrieveAppClassLoader(services)) - ) - } - - private fun upgradedContract(className: ContractClassName, classLoader: ClassLoader): UpgradedContract = try { - @Suppress("UNCHECKED_CAST") - Class.forName(className, false, classLoader).asSubclass(UpgradedContract::class.java).getDeclaredConstructor().newInstance() as UpgradedContract - } catch (e: Exception) { - throw TransactionVerificationException.ContractCreationError(id, className, e) - } - - /** - * Creates a binary serialized component for a virtual output state serialised and executed with the attachments from the transaction. - */ - @CordaInternal - internal fun resolveOutputComponent(services: ServicesForResolution, stateRef: StateRef, params: NetworkParameters): SerializedBytes> { - val binaryInput: SerializedBytes> = resolveStateRefBinaryComponent(inputs[stateRef.index], services)!! - val legacyAttachment = services.attachments.openAttachment(legacyContractAttachmentId) - ?: throw MissingContractAttachments(emptyList()) - val upgradedAttachment = services.attachments.openAttachment(upgradedContractAttachmentId) - ?: throw MissingContractAttachments(emptyList()) - - return AttachmentsClassLoaderBuilder.withAttachmentsClassloaderContext( - listOf(legacyAttachment, upgradedAttachment), - params, - id, - { (services as ServiceHubCoreInternal).attachmentTrustCalculator.calculate(it) }, - attachmentsClassLoaderCache = (services as ServiceHubCoreInternal).attachmentsClassLoaderCache) { serializationContext -> - val resolvedInput = binaryInput.deserialize() - val upgradedContract = upgradedContract(upgradedContractClassName, serializationContext.deserializationClassLoader) - val outputState = calculateUpgradedState(resolvedInput, upgradedContract, upgradedAttachment) - outputState.serialize() - } + return ContractUpgradeLedgerTransaction.resolve(services.toVerifyingServiceHub(), this, sigs) } /** Constructs a filtered transaction: the inputs, the notary party and network parameters hash are always visible, while the rest are hidden. */ fun buildFilteredTransaction(): ContractUpgradeFilteredTransaction { - val totalComponents = (0 until serializedComponents.size).toSet() + val totalComponents = serializedComponents.indices.toSet() val visibleComponents = mapOf( INPUTS.ordinal to FilteredComponent(serializedComponents[INPUTS.ordinal], nonces[INPUTS.ordinal]), NOTARY.ordinal to FilteredComponent(serializedComponents[NOTARY.ordinal], nonces[NOTARY.ordinal]), @@ -188,6 +162,20 @@ data class ContractUpgradeWireTransaction( return ContractUpgradeFilteredTransaction(visibleComponents, hiddenComponents, digestService) } + @CordaInternal + @JvmSynthetic + internal fun tryVerify(verificationSupport: NodeVerificationSupport): VerificationResult.External { + // Contract upgrades only work on 4.11 and earlier + return VerificationResult.External(Try.on { verificationSupport.externalVerifierHandle.verifyTransaction(this) }) + } + + @CordaInternal + @JvmSynthetic + internal fun verifyInProcess(verificationSupport: VerificationSupport) { + // No contract code is run when verifying contract upgrade transactions, it is sufficient to check invariants during initialisation. + ContractUpgradeLedgerTransaction.resolve(verificationSupport, this, emptyList()) + } + enum class Component { INPUTS, NOTARY, LEGACY_ATTACHMENT, UPGRADED_CONTRACT, UPGRADED_ATTACHMENT, PARAMETERS_HASH } @@ -287,39 +275,46 @@ private constructor( get() = upgradedContract::class.java.name companion object { - @CordaInternal - internal fun create( - inputs: List>, - notary: Party, - legacyContractAttachment: Attachment, - upgradedContractAttachment: Attachment, - id: SecureHash, - privacySalt: PrivacySalt, - sigs: List, - networkParameters: NetworkParameters, - upgradedContract: UpgradedContract - ): ContractUpgradeLedgerTransaction { - return ContractUpgradeLedgerTransaction(inputs, notary, legacyContractAttachment, upgradedContractAttachment, id, privacySalt, sigs, networkParameters, upgradedContract) + @JvmSynthetic + @Suppress("ThrowsCount") + fun resolve(verificationSupport: VerificationSupport, + wtx: ContractUpgradeWireTransaction, + sigs: List): ContractUpgradeLedgerTransaction { + val inputs = wtx.inputs.map(verificationSupport::getStateAndRef) + val (legacyContractAttachment, upgradedContractAttachment) = verificationSupport.getAttachments(listOf( + wtx.legacyContractAttachmentId, + wtx.upgradedContractAttachmentId + )) + val networkParameters = verificationSupport.getNetworkParameters(wtx.networkParametersHash) + ?: throw TransactionResolutionException(wtx.id) + val upgradedContract = loadUpgradedContract(wtx.upgradedContractClassName, wtx.id, verificationSupport.appClassLoader) + return ContractUpgradeLedgerTransaction( + inputs, + wtx.notary, + legacyContractAttachment ?: throw AttachmentResolutionException(wtx.legacyContractAttachmentId), + upgradedContractAttachment ?: throw AttachmentResolutionException(wtx.upgradedContractAttachmentId), + wtx.id, + wtx.privacySalt, + sigs, + networkParameters, + upgradedContract + ) } - // TODO - this has to use a classloader created from the upgraded attachment. + // TODO There is an inconsistency with the class loader used with this method. Transaction resolution uses the app class loader, + // whilst TransactionStorageVerification.getContractUpdateOutput uses an attachments class loder comprised of the the legacy and + // upgraded attachments @CordaInternal - internal fun loadUpgradedContract(upgradedContractClassName: ContractClassName, classLoader: ClassLoader): UpgradedContract { - @Suppress("UNCHECKED_CAST") - return Class.forName(upgradedContractClassName, false, classLoader) - .asSubclass(Contract::class.java) - .getConstructor() - .newInstance() as UpgradedContract - } - - // This is a "hack" to retrieve the CordappsClassloader from the services without having access to all classes. - @CordaInternal - internal fun retrieveAppClassLoader(services: ServicesForResolution): ClassLoader { - val cordappLoader = services.cordappProvider::class.java.getMethod("getCordappLoader").invoke(services.cordappProvider) - - @Suppress("UNCHECKED_CAST") - return cordappLoader::class.java.getMethod("getAppClassLoader").invoke(cordappLoader) as ClassLoader + @JvmSynthetic + internal fun loadUpgradedContract(className: ContractClassName, id: SecureHash, classLoader: ClassLoader): UpgradedContract { + return try { + loadClassOfType>(className, false, classLoader) + .getDeclaredConstructor() + .newInstance() + } catch (e: Exception) { + throw TransactionVerificationException.ContractCreationError(id, className, e) + } } } @@ -366,7 +361,7 @@ private constructor( /** The required signers are the set of all input states' participants. */ override val requiredSigningKeys: Set - get() = inputs.flatMap { it.state.data.participants }.map { it.owningKey }.toSet() + notary.owningKey + get() = getRequiredSigningKeysInternal(inputs.asSequence(), notary) override fun getKeyDescriptions(keys: Set): List { return keys.map { it.toBase58String() } @@ -401,7 +396,7 @@ private constructor( privacySalt: PrivacySalt, sigs: List, networkParameters: NetworkParameters - ) : this(inputs, notary, legacyContractAttachment, upgradedContractAttachment, id, privacySalt, sigs, networkParameters, loadUpgradedContract(upgradedContractClassName, ContractUpgradeLedgerTransaction::class.java.classLoader)) + ) : this(inputs, notary, legacyContractAttachment, upgradedContractAttachment, id, privacySalt, sigs, networkParameters, loadUpgradedContract(upgradedContractClassName, id, ContractUpgradeLedgerTransaction::class.java.classLoader)) @Deprecated("ContractUpgradeLedgerTransaction should not be created directly, use ContractUpgradeWireTransaction.resolve instead.") fun copy( diff --git a/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt index 846799d0b3..3a866562e4 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt @@ -16,21 +16,21 @@ import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party -import net.corda.core.internal.AbstractVerifier import net.corda.core.internal.SerializedStateAndRef -import net.corda.core.internal.Verifier import net.corda.core.internal.castIfPossible import net.corda.core.internal.deserialiseCommands import net.corda.core.internal.deserialiseComponentGroup import net.corda.core.internal.eagerDeserialise import net.corda.core.internal.isUploaderTrusted import net.corda.core.internal.uncheckedCast +import net.corda.core.internal.verification.AbstractVerifier +import net.corda.core.internal.verification.Verifier import net.corda.core.node.NetworkParameters import net.corda.core.serialization.DeprecatedConstructorForDeserialization import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationFactory -import net.corda.core.serialization.internal.AttachmentsClassLoaderCache import net.corda.core.serialization.internal.AttachmentsClassLoaderBuilder +import net.corda.core.serialization.internal.AttachmentsClassLoaderCache import net.corda.core.utilities.contextLogger import java.util.Collections.unmodifiableList import java.util.function.Predicate @@ -58,7 +58,7 @@ import java.util.function.Supplier * * [LedgerTransaction]s should never be instantiated directly from client code, but rather via WireTransaction.toLedgerTransaction */ -@Suppress("LongParameterList") +@Suppress("LongParameterList", "RedundantSamConstructor") // Because the external verifier uses Kotlin 1.2 class LedgerTransaction private constructor( // DOCSTART 1 @@ -153,34 +153,35 @@ private constructor( serializedInputs: List? = null, serializedReferences: List? = null, isAttachmentTrusted: (Attachment) -> Boolean, + verifierFactory: (LedgerTransaction, SerializationContext) -> Verifier, attachmentsClassLoaderCache: AttachmentsClassLoaderCache?, digestService: DigestService ): LedgerTransaction { return LedgerTransaction( - inputs = inputs, - outputs = outputs, - commands = commands, - attachments = attachments, - id = id, - notary = notary, - timeWindow = timeWindow, - privacySalt = privacySalt, - networkParameters = networkParameters, - references = references, - componentGroups = protectOrNull(componentGroups), - serializedInputs = protectOrNull(serializedInputs), - serializedReferences = protectOrNull(serializedReferences), - isAttachmentTrusted = isAttachmentTrusted, - verifierFactory = ::BasicVerifier, - attachmentsClassLoaderCache = attachmentsClassLoaderCache, - digestService = digestService + inputs = inputs, + outputs = outputs, + commands = commands, + attachments = attachments, + id = id, + notary = notary, + timeWindow = timeWindow, + privacySalt = privacySalt, + networkParameters = networkParameters, + references = references, + componentGroups = protectOrNull(componentGroups), + serializedInputs = protectOrNull(serializedInputs), + serializedReferences = protectOrNull(serializedReferences), + isAttachmentTrusted = isAttachmentTrusted, + verifierFactory = verifierFactory, + attachmentsClassLoaderCache = attachmentsClassLoaderCache, + digestService = digestService ) } /** * This factory function will create an instance of [LedgerTransaction] * that will be used for contract verification. - * @see BasicVerifier + * @see DefaultVerifier */ @CordaInternal fun createForContractVerify( @@ -239,30 +240,34 @@ private constructor( * The reason for this is that classes (contract states) deserialized in this classloader would actually be a different type from what * the calling code would expect. * + * If receiving [SignedTransaction]s over the wire from other nodes, then it is recommended the verification be done via + * [SignedTransaction.verify] directly rather than via [SignedTransaction.toLedgerTransaction]. If transaction is from a legacy node + * (4.11 or older) then the later solution will not work. + * * @throws TransactionVerificationException if anything goes wrong. */ @Throws(TransactionVerificationException::class) fun verify() { - internalPrepareVerify(attachments).verify() + verifyInternal() } /** * This method has to be called in a context where it has access to the database. */ @CordaInternal - internal fun internalPrepareVerify(txAttachments: List): Verifier { + @JvmSynthetic + internal fun verifyInternal(txAttachments: List = this.attachments) { // Switch thread local deserialization context to using a cached attachments classloader. This classloader enforces various rules // like no-overlap, package namespace ownership and (in future) deterministic Java. - return AttachmentsClassLoaderBuilder.withAttachmentsClassloaderContext( + val verifier = AttachmentsClassLoaderBuilder.withAttachmentsClassLoaderContext( txAttachments, getParamsWithGoo(), id, - isAttachmentTrusted = isAttachmentTrusted, - attachmentsClassLoaderCache = attachmentsClassLoaderCache) { serializationContext -> - + isAttachmentTrusted, + attachmentsClassLoaderCache = attachmentsClassLoaderCache + ) { serializationContext -> // Legacy check - warns if the LedgerTransaction was created incorrectly. checkLtxForVerification() - // Create a copy of the outer LedgerTransaction which deserializes all fields using // the serialization context (or its deserializationClassloader). // Only the copy will be used for verification, and the outer shell will be discarded. @@ -270,6 +275,7 @@ private constructor( // NOTE: The Verifier creates the copies of the LedgerTransaction object now. verifierFactory(this, serializationContext) } + verifier.verify() } /** @@ -706,7 +712,7 @@ private constructor( serializedInputs = null, serializedReferences = null, isAttachmentTrusted = Attachment::isUploaderTrusted, - verifierFactory = ::BasicVerifier, + verifierFactory = ::DefaultVerifier, attachmentsClassLoaderCache = null ) @@ -736,7 +742,7 @@ private constructor( serializedInputs = null, serializedReferences = null, isAttachmentTrusted = Attachment::isUploaderTrusted, - verifierFactory = ::BasicVerifier, + verifierFactory = ::DefaultVerifier, attachmentsClassLoaderCache = null ) @@ -804,14 +810,19 @@ private constructor( } } +@CordaInternal +@JvmSynthetic +fun defaultVerifier(ltx: LedgerTransaction, serializationContext: SerializationContext): Verifier { + return DefaultVerifier(ltx, serializationContext) +} + /** * This is the default [Verifier] that configures Corda * to execute [Contract.verify(LedgerTransaction)]. * * THIS CLASS IS NOT PUBLIC API, AND IS DELIBERATELY PRIVATE! */ -@CordaInternal -private class BasicVerifier( +private class DefaultVerifier( ltx: LedgerTransaction, private val serializationContext: SerializationContext ) : AbstractVerifier(ltx, serializationContext.deserializationClassLoader) { @@ -874,7 +885,6 @@ private class BasicVerifier( * THIS CLASS IS NOT PUBLIC API, AND IS DELIBERATELY PRIVATE! */ @Suppress("unused_parameter") -@CordaInternal private class NoOpVerifier(ltx: LedgerTransaction, serializationContext: SerializationContext) : Verifier { // Invoking LedgerTransaction.verify() from Contract.verify(LedgerTransaction) // will execute this function. But why would anyone do that?! diff --git a/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt index 897598335b..ab786503ee 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt @@ -1,12 +1,15 @@ package net.corda.core.transactions import net.corda.core.CordaException +import net.corda.core.CordaInternal import net.corda.core.contracts.* import net.corda.core.contracts.ComponentGroupEnum.* import net.corda.core.crypto.* import net.corda.core.identity.Party import net.corda.core.internal.deserialiseCommands import net.corda.core.internal.deserialiseComponentGroup +import net.corda.core.internal.getGroup +import net.corda.core.internal.getRequiredGroup import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.DeprecatedConstructorForDeserialization import net.corda.core.serialization.SerializedBytes @@ -29,8 +32,34 @@ abstract class TraversableTransaction(open val componentGroups: List) : this(componentGroups, DigestService.sha2_256) + /** + * Returns the attachments compatible with 4.11 and earlier. This may be empty, which means this transaction cannot be verified by a + * 4.11 node. On 4.12 and later these attachments are ignored. + */ + val legacyAttachments: List = deserialiseComponentGroup(componentGroups, SecureHash::class, ATTACHMENTS_GROUP) + + /** + * Returns the attachments compatible with 4.12 and later. This will be empty for transactions created on 4.11 or earlier. + * + * [legacyAttachments] and [nonLegacyAttachments] are independent of each other and may contain the same attachments. This is to provide backwards + * compatibility and enable both 4.11 and 4.12 nodes to verify the same transaction. + */ + @CordaInternal + @JvmSynthetic + internal val nonLegacyAttachments: List = deserialiseComponentGroup(componentGroups, SecureHash::class, ATTACHMENTS_V2_GROUP) + /** Hashes of the ZIP/JAR files that are needed to interpret the contents of this wire transaction. */ - val attachments: List = deserialiseComponentGroup(componentGroups, SecureHash::class, ATTACHMENTS_GROUP) + val attachments: List + get() = when { + legacyAttachments.isEmpty() -> nonLegacyAttachments // 4.12+ only transaction + nonLegacyAttachments.isEmpty() -> legacyAttachments // 4.11 or earlier transaction + else -> nonLegacyAttachments // This is a backwards compatible transaction, but from an API PoV we're not concerned with the legacy attachments + } + + @CordaInternal + internal val allAttachments: Set + @JvmSynthetic + get() = legacyAttachments.toMutableSet().apply { addAll(nonLegacyAttachments) } /** Pointers to the input states on the ledger, identified by (tx identity hash, output index). */ override val inputs: List = deserialiseComponentGroup(componentGroups, StateRef::class, INPUTS_GROUP) @@ -67,18 +96,20 @@ abstract class TraversableTransaction(open val componentGroups: List> get() { - val result = mutableListOf(inputs, outputs, commands, attachments, references) + val result = mutableListOf(inputs, outputs, commands, legacyAttachments, references) notary?.let { result += listOf(it) } timeWindow?.let { result += listOf(it) } networkParametersHash?.let { result += listOf(it) } + result += nonLegacyAttachments return result } } @@ -153,12 +184,10 @@ class FilteredTransaction internal constructor( // This is required for visibility purposes, see FilteredTransaction.checkAllCommandsVisible() for more details. if (componentGroupIndex == COMMANDS_GROUP.ordinal && !signersIncluded) { signersIncluded = true - val signersGroupIndex = SIGNERS_GROUP.ordinal // There exist commands, thus the signers group is not empty. - val signersGroupComponents = wtx.componentGroups.first { it.groupIndex == signersGroupIndex } - filteredSerialisedComponents[signersGroupIndex] = signersGroupComponents.components.toMutableList() - filteredComponentNonces[signersGroupIndex] = wtx.availableComponentNonces[signersGroupIndex]!!.toMutableList() - filteredComponentHashes[signersGroupIndex] = wtx.availableComponentHashes[signersGroupIndex]!!.toMutableList() + filteredSerialisedComponents[SIGNERS_GROUP.ordinal] = wtx.componentGroups.getRequiredGroup(SIGNERS_GROUP).components.toMutableList() + filteredComponentNonces[SIGNERS_GROUP.ordinal] = wtx.availableComponentNonces[SIGNERS_GROUP.ordinal]!!.toMutableList() + filteredComponentHashes[SIGNERS_GROUP.ordinal] = wtx.availableComponentHashes[SIGNERS_GROUP.ordinal]!!.toMutableList() } } @@ -166,7 +195,8 @@ class FilteredTransaction internal constructor( wtx.inputs.forEachIndexed { internalIndex, it -> filter(it, INPUTS_GROUP.ordinal, internalIndex) } wtx.outputs.forEachIndexed { internalIndex, it -> filter(it, OUTPUTS_GROUP.ordinal, internalIndex) } wtx.commands.forEachIndexed { internalIndex, it -> filter(it, COMMANDS_GROUP.ordinal, internalIndex) } - wtx.attachments.forEachIndexed { internalIndex, it -> filter(it, ATTACHMENTS_GROUP.ordinal, internalIndex) } + wtx.legacyAttachments.forEachIndexed { internalIndex, it -> filter(it, ATTACHMENTS_GROUP.ordinal, internalIndex) } + wtx.nonLegacyAttachments.forEachIndexed { internalIndex, it -> filter(it, ATTACHMENTS_V2_GROUP.ordinal, internalIndex) } if (wtx.notary != null) filter(wtx.notary, NOTARY_GROUP.ordinal, 0) if (wtx.timeWindow != null) filter(wtx.timeWindow, TIMEWINDOW_GROUP.ordinal, 0) // Note that because [inputs] and [references] share the same type [StateRef], we use a wrapper for references [ReferenceStateRef], @@ -269,7 +299,7 @@ class FilteredTransaction internal constructor( */ @Throws(ComponentVisibilityException::class) fun checkAllComponentsVisible(componentGroupEnum: ComponentGroupEnum) { - val group = filteredComponentGroups.firstOrNull { it.groupIndex == componentGroupEnum.ordinal } + val group = filteredComponentGroups.getGroup(componentGroupEnum) if (group == null) { // If we don't receive elements of a particular component, check if its ordinal is bigger that the // groupHashes.size or if the group hash is allOnesHash, @@ -300,7 +330,7 @@ class FilteredTransaction internal constructor( */ @Throws(ComponentVisibilityException::class) fun checkCommandVisibility(publicKey: PublicKey) { - val commandSigners = componentGroups.firstOrNull { it.groupIndex == SIGNERS_GROUP.ordinal } + val commandSigners = componentGroups.getGroup(SIGNERS_GROUP) val expectedNumOfCommands = expectedNumOfCommands(publicKey, commandSigners) val receivedForThisKeyNumOfCommands = commands.filter { publicKey in it.signers }.size visibilityCheck(expectedNumOfCommands == receivedForThisKeyNumOfCommands) { diff --git a/core/src/main/kotlin/net/corda/core/transactions/MissingContractAttachments.kt b/core/src/main/kotlin/net/corda/core/transactions/MissingContractAttachments.kt index e2debdcd1a..9e314521b1 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/MissingContractAttachments.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/MissingContractAttachments.kt @@ -4,6 +4,7 @@ import net.corda.core.contracts.ContractState import net.corda.core.contracts.TransactionState import net.corda.core.flows.FlowException import net.corda.core.internal.Version +import net.corda.core.internal.mapToSet import net.corda.core.serialization.CordaSerializable /** @@ -14,6 +15,8 @@ import net.corda.core.serialization.CordaSerializable @CordaSerializable class MissingContractAttachments @JvmOverloads -constructor(val states: List>, contractsClassName: String? = null, minimumRequiredContractClassVersion: Version? = null) : FlowException( - "Cannot find contract attachments for " + - "${contractsClassName ?: states.map { it.contract }.distinct()}${minimumRequiredContractClassVersion?.let { ", minimum required contract class version $minimumRequiredContractClassVersion"}}.") +constructor(val states: List>, + contractsClassName: String? = null, + minimumRequiredContractClassVersion: Version? = null +) : FlowException("Cannot find contract attachments for " + + "${contractsClassName ?: states.mapToSet { it.contract }}${minimumRequiredContractClassVersion?.let { ", minimum required contract class version $minimumRequiredContractClassVersion"} ?: ""}.") diff --git a/core/src/main/kotlin/net/corda/core/transactions/NotaryChangeTransactions.kt b/core/src/main/kotlin/net/corda/core/transactions/NotaryChangeTransactions.kt index ab42260f37..7e18999049 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/NotaryChangeTransactions.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/NotaryChangeTransactions.kt @@ -1,21 +1,35 @@ package net.corda.core.transactions import net.corda.core.CordaInternal -import net.corda.core.contracts.* +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.StateAndRef +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TransactionResolutionException +import net.corda.core.contracts.TransactionState +import net.corda.core.contracts.TransactionVerificationException import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash import net.corda.core.crypto.TransactionSignature import net.corda.core.identity.Party +import net.corda.core.internal.getRequiredSigningKeysInternal +import net.corda.core.internal.indexOfOrThrow +import net.corda.core.internal.verification.NodeVerificationSupport +import net.corda.core.internal.verification.VerificationResult +import net.corda.core.internal.verification.VerificationSupport +import net.corda.core.internal.verification.toVerifyingServiceHub import net.corda.core.node.NetworkParameters import net.corda.core.node.ServiceHub import net.corda.core.node.ServicesForResolution import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.DeprecatedConstructorForDeserialization -import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize -import net.corda.core.transactions.NotaryChangeWireTransaction.Component.* +import net.corda.core.transactions.NotaryChangeWireTransaction.Component.INPUTS +import net.corda.core.transactions.NotaryChangeWireTransaction.Component.NEW_NOTARY +import net.corda.core.transactions.NotaryChangeWireTransaction.Component.NOTARY +import net.corda.core.transactions.NotaryChangeWireTransaction.Component.PARAMETERS_HASH import net.corda.core.utilities.OpaqueBytes +import net.corda.core.utilities.Try import net.corda.core.utilities.toBase58String import java.security.PublicKey @@ -88,32 +102,22 @@ data class NotaryChangeWireTransaction( /** Resolves input states and network parameters and builds a [NotaryChangeLedgerTransaction]. */ fun resolve(services: ServicesForResolution, sigs: List): NotaryChangeLedgerTransaction { - val resolvedInputs = services.loadStates(inputs.toSet()).toList() - val hashToResolve = networkParametersHash ?: services.networkParametersService.defaultHash - val resolvedNetworkParameters = services.networkParametersService.lookup(hashToResolve) - ?: throw TransactionResolutionException(id) - return NotaryChangeLedgerTransaction.create(resolvedInputs, notary, newNotary, id, sigs, resolvedNetworkParameters) + return NotaryChangeLedgerTransaction.resolve(services.toVerifyingServiceHub(), this, sigs) } /** Resolves input states and builds a [NotaryChangeLedgerTransaction]. */ - fun resolve(services: ServiceHub, sigs: List) = resolve(services as ServicesForResolution, sigs) + fun resolve(services: ServiceHub, sigs: List): NotaryChangeLedgerTransaction { + return resolve(services as ServicesForResolution, sigs) + } - /** - * This should return a serialized virtual output state, that will be used to verify spending transactions. - * The binary output should not depend on the classpath of the node that is verifying the transaction. - * - * Ideally the serialization engine would support partial deserialization so that only the Notary ( and the encumbrance can be replaced from the binary input state) - * - * - * TODO - currently this uses the main classloader. - */ @CordaInternal - internal fun resolveOutputComponent( - services: ServicesForResolution, - stateRef: StateRef, - @Suppress("UNUSED_PARAMETER") params: NetworkParameters - ): SerializedBytes> { - return services.loadState(stateRef).serialize() + @JvmSynthetic + internal fun tryVerify(verificationSupport: NodeVerificationSupport): VerificationResult.InProcess { + return VerificationResult.InProcess(Try.on { + // No contract code is run when verifying notary change transactions, it is sufficient to check invariants during initialisation. + NotaryChangeLedgerTransaction.resolve(verificationSupport, this, emptyList()) + null + }) } enum class Component { @@ -140,13 +144,25 @@ private constructor( ) : FullTransaction(), TransactionWithSignatures { companion object { @CordaInternal - internal fun create(inputs: List>, - notary: Party, - newNotary: Party, - id: SecureHash, - sigs: List, - networkParameters: NetworkParameters): NotaryChangeLedgerTransaction { - return NotaryChangeLedgerTransaction(inputs, notary, newNotary, id, sigs, networkParameters) + @JvmSynthetic + fun resolve(verificationSupport: VerificationSupport, + wireTx: NotaryChangeWireTransaction, + sigs: List): NotaryChangeLedgerTransaction { + val inputs = wireTx.inputs.map(verificationSupport::getStateAndRef) + val networkParameters = verificationSupport.getNetworkParameters(wireTx.networkParametersHash) + ?: throw TransactionResolutionException(wireTx.id) + return NotaryChangeLedgerTransaction(inputs, wireTx.notary, wireTx.newNotary, wireTx.id, sigs, networkParameters) + } + + @CordaInternal + @JvmSynthetic + internal inline fun computeOutput(input: StateAndRef<*>, newNotary: Party, inputs: () -> List): TransactionState<*> { + val (state, ref) = input + val newEncumbrance = state.encumbrance?.let { + val encumbranceStateRef = ref.copy(index = state.encumbrance) + inputs().indexOfOrThrow(encumbranceStateRef) + } + return state.copy(notary = newNotary, encumbrance = newEncumbrance) } } @@ -174,22 +190,10 @@ private constructor( /** We compute the outputs on demand by applying the notary field modification to the inputs. */ override val outputs: List> - get() = computeOutputs() - - private fun computeOutputs(): List> { - val inputPositionIndex: Map = inputs.mapIndexed { index, stateAndRef -> stateAndRef.ref to index }.toMap() - return inputs.map { (state, ref) -> - if (state.encumbrance != null) { - val encumbranceStateRef = StateRef(ref.txhash, state.encumbrance) - val encumbrancePosition = inputPositionIndex[encumbranceStateRef] - ?: throw IllegalStateException("Unable to generate output states – transaction not constructed correctly.") - state.copy(notary = newNotary, encumbrance = encumbrancePosition) - } else state.copy(notary = newNotary) - } - } + get() = inputs.map { computeOutput(it, newNotary) { inputs.map(StateAndRef::ref) } } override val requiredSigningKeys: Set - get() = inputs.flatMap { it.state.data.participants }.map { it.owningKey }.toSet() + notary.owningKey + get() = getRequiredSigningKeysInternal(inputs.asSequence(), notary) override fun getKeyDescriptions(keys: Set): List { return keys.map { it.toBase58String() } diff --git a/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt index 94e2079967..b15875d4e2 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt @@ -1,31 +1,41 @@ package net.corda.core.transactions import net.corda.core.CordaException +import net.corda.core.CordaInternal import net.corda.core.CordaThrowable -import net.corda.core.contracts.* -import net.corda.core.crypto.* +import net.corda.core.contracts.AttachmentResolutionException +import net.corda.core.contracts.NamedByHash +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TransactionResolutionException +import net.corda.core.contracts.TransactionVerificationException +import net.corda.core.contracts.TransactionVerificationException.TransactionNetworkParameterOrderingException +import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.SignableData +import net.corda.core.crypto.SignatureMetadata +import net.corda.core.crypto.TransactionSignature +import net.corda.core.crypto.sign +import net.corda.core.crypto.toStringShort import net.corda.core.identity.Party -import net.corda.core.internal.TransactionDeserialisationException -import net.corda.core.internal.TransactionVerifierServiceInternal import net.corda.core.internal.VisibleForTesting +import net.corda.core.internal.getRequiredSigningKeysInternal +import net.corda.core.internal.toSimpleString +import net.corda.core.internal.verification.NodeVerificationSupport +import net.corda.core.internal.verification.toVerifyingServiceHub import net.corda.core.node.ServiceHub import net.corda.core.node.ServicesForResolution import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.deserialize -import net.corda.core.serialization.internal.MissingSerializerException import net.corda.core.serialization.serialize -import net.corda.core.utilities.contextLogger -import net.corda.core.utilities.getOrThrow -import java.io.NotSerializableException +import net.corda.core.utilities.toBase58String import java.security.KeyPair import java.security.PublicKey import java.security.SignatureException -import java.util.* import java.util.function.Predicate /** - * SignedTransaction wraps a serialized WireTransaction. It contains one or more signatures, each one for + * SignedTransaction wraps a serialized [CoreTransaction], though it will almost exclusively be a [WireTransaction]. + * It contains one or more signatures, each one for * a public key (including composite keys) that is mentioned inside a transaction command. SignedTransaction is the top level transaction type * and the type most frequently passed around the network and stored. The identity of a transaction is the hash of Merkle root * of a WireTransaction, therefore if you are storing data keyed by WT hash be aware that multiple different STs may @@ -142,6 +152,9 @@ data class SignedTransaction(val txBits: SerializedBytes, @JvmOverloads @Throws(SignatureException::class, AttachmentResolutionException::class, TransactionResolutionException::class) fun toLedgerTransaction(services: ServiceHub, checkSufficientSignatures: Boolean = true): LedgerTransaction { + val verifyingServiceHub = services.toVerifyingServiceHub() + // We need parameters check here, because finality flow calls stx.toLedgerTransaction() and then verify. + resolveAndCheckNetworkParameters(verifyingServiceHub) // TODO: We could probably optimise the below by // a) not throwing if threshold is eventually satisfied, but some of the rest of the signatures are failing. // b) omit verifying signatures when threshold requirement is met. @@ -149,14 +162,8 @@ data class SignedTransaction(val txBits: SerializedBytes, // For the above to work, [checkSignaturesAreValid] should take the [requiredSigningKeys] as input // and probably combine logic from signature validation and key-fulfilment // in [TransactionWithSignatures.verifySignaturesExcept]. - if (checkSufficientSignatures) { - verifyRequiredSignatures() // It internally invokes checkSignaturesAreValid(). - } else { - checkSignaturesAreValid() - } - // We need parameters check here, because finality flow calls stx.toLedgerTransaction() and then verify. - resolveAndCheckNetworkParameters(services) - return tx.toLedgerTransaction(services) + verifySignatures(verifyingServiceHub, checkSufficientSignatures) + return tx.toLedgerTransactionInternal(verifyingServiceHub) } /** @@ -172,109 +179,61 @@ data class SignedTransaction(val txBits: SerializedBytes, @JvmOverloads @Throws(SignatureException::class, AttachmentResolutionException::class, TransactionResolutionException::class, TransactionVerificationException::class) fun verify(services: ServiceHub, checkSufficientSignatures: Boolean = true) { - resolveAndCheckNetworkParameters(services) - when (coreTransaction) { - is NotaryChangeWireTransaction -> verifyNotaryChangeTransaction(services, checkSufficientSignatures) - is ContractUpgradeWireTransaction -> verifyContractUpgradeTransaction(services, checkSufficientSignatures) - else -> verifyRegularTransaction(services, checkSufficientSignatures) + verifyInternal(services.toVerifyingServiceHub(), checkSufficientSignatures) + } + + /** + * Internal version of the public [verify] which takes in a [NodeVerificationSupport] instead of the heavier [ServiceHub]. + * + * Depending on the contract attachments, this method will either verify this transaction in-process or send it to the external verifier + * for out-of-process verification. + * + * @return The [FullTransaction] that was successfully verified in-process. Returns null if the verification was successfully done externally. + */ + @CordaInternal + @JvmSynthetic + internal fun verifyInternal(verificationSupport: NodeVerificationSupport, checkSufficientSignatures: Boolean = true): LedgerTransaction? { + resolveAndCheckNetworkParameters(verificationSupport) + verifySignatures(verificationSupport, checkSufficientSignatures) + val ctx = coreTransaction + val verificationResult = when (ctx) { + // TODO: Verify contract constraints here as well as in LedgerTransaction to ensure that anything being deserialised + // from the attachment is trusted. This will require some partial serialisation work to not load the ContractState + // objects from the TransactionState. + is WireTransaction -> ctx.tryVerify(verificationSupport) + is ContractUpgradeWireTransaction -> ctx.tryVerify(verificationSupport) + is NotaryChangeWireTransaction -> ctx.tryVerify(verificationSupport) + else -> throw IllegalStateException("${ctx.toSimpleString()} cannot be verified") } + return verificationResult.enforceSuccess() } @Suppress("ThrowsCount") - private fun resolveAndCheckNetworkParameters(services: ServiceHub) { + private fun resolveAndCheckNetworkParameters(services: NodeVerificationSupport) { val hashOrDefault = networkParametersHash ?: services.networkParametersService.defaultHash - val txNetworkParameters = services.networkParametersService.lookup(hashOrDefault) - ?: throw TransactionResolutionException(id) + val txNetworkParameters = services.networkParametersService.lookup(hashOrDefault) ?: throw TransactionResolutionException(id) val groupedInputsAndRefs = (inputs + references).groupBy { it.txhash } - groupedInputsAndRefs.map { entry -> - val tx = services.validatedTransactions.getTransaction(entry.key)?.coreTransaction - ?: throw TransactionResolutionException(id) + for ((txId, stateRefs) in groupedInputsAndRefs) { + val tx = services.validatedTransactions.getTransaction(txId)?.coreTransaction ?: throw TransactionResolutionException(id) val paramHash = tx.networkParametersHash ?: services.networkParametersService.defaultHash val params = services.networkParametersService.lookup(paramHash) ?: throw TransactionResolutionException(id) - if (txNetworkParameters.epoch < params.epoch) - throw TransactionVerificationException.TransactionNetworkParameterOrderingException(id, entry.value.first(), txNetworkParameters, params) - } - } - - /** No contract code is run when verifying notary change transactions, it is sufficient to check invariants during initialisation. */ - private fun verifyNotaryChangeTransaction(services: ServiceHub, checkSufficientSignatures: Boolean) { - val ntx = resolveNotaryChangeTransaction(services) - if (checkSufficientSignatures) ntx.verifyRequiredSignatures() - else checkSignaturesAreValid() - } - - /** No contract code is run when verifying contract upgrade transactions, it is sufficient to check invariants during initialisation. */ - private fun verifyContractUpgradeTransaction(services: ServicesForResolution, checkSufficientSignatures: Boolean) { - val ctx = resolveContractUpgradeTransaction(services) - if (checkSufficientSignatures) ctx.verifyRequiredSignatures() - else checkSignaturesAreValid() - } - - // TODO: Verify contract constraints here as well as in LedgerTransaction to ensure that anything being deserialised - // from the attachment is trusted. This will require some partial serialisation work to not load the ContractState - // objects from the TransactionState. - private fun verifyRegularTransaction(services: ServiceHub, checkSufficientSignatures: Boolean) { - val ltx = toLedgerTransaction(services, checkSufficientSignatures) - try { - // TODO: allow non-blocking verification. - services.transactionVerifierService.verify(ltx).getOrThrow() - } catch (e: NoClassDefFoundError) { - checkReverifyAllowed(e) - val missingClass = e.message ?: throw e - log.warn("Transaction {} has missing class: {}", ltx.id, missingClass) - reverifyWithFixups(ltx, services, missingClass) - } catch (e: NotSerializableException) { - checkReverifyAllowed(e) - retryVerification(e, e, ltx, services) - } catch (e: TransactionDeserialisationException) { - checkReverifyAllowed(e) - retryVerification(e.cause, e, ltx, services) - } - } - - private fun checkReverifyAllowed(ex: Throwable) { - // If that transaction was created with and after Corda 4 then just fail. - // The lenient dependency verification is only supported for Corda 3 transactions. - // To detect if the transaction was created before Corda 4 we check if the transaction has the NetworkParameters component group. - if (networkParametersHash != null) { - log.warn("TRANSACTION VERIFY FAILED - No attempt to auto-repair as TX is Corda 4+") - throw ex - } - } - - @Suppress("ThrowsCount") - private fun retryVerification(cause: Throwable?, ex: Throwable, ltx: LedgerTransaction, services: ServiceHub) { - when (cause) { - is MissingSerializerException -> { - log.warn("Missing serializers: typeDescriptor={}, typeNames={}", cause.typeDescriptor ?: "", cause.typeNames) - reverifyWithFixups(ltx, services, null) + if (txNetworkParameters.epoch < params.epoch) { + throw TransactionNetworkParameterOrderingException(id, stateRefs.first(), txNetworkParameters, params) } - is NotSerializableException -> { - val underlying = cause.cause - if (underlying is ClassNotFoundException) { - val missingClass = underlying.message?.replace('.', '/') ?: throw ex - log.warn("Transaction {} has missing class: {}", ltx.id, missingClass) - reverifyWithFixups(ltx, services, missingClass) - } else { - throw ex - } - } - else -> throw ex } } - // Transactions created before Corda 4 can be missing dependencies on other CorDapps. - // This code has detected a missing custom serializer - probably located inside a workflow CorDapp. - // We need to extract this CorDapp from AttachmentStorage and try verifying this transaction again. - private fun reverifyWithFixups(ltx: LedgerTransaction, services: ServiceHub, missingClass: String?) { - log.warn("""Detected that transaction $id does not contain all cordapp dependencies. - |This may be the result of a bug in a previous version of Corda. - |Attempting to re-verify having applied this node's fix-up rules. - |Please check with the originator that this is a valid transaction.""".trimMargin()) - - (services.transactionVerifierService as TransactionVerifierServiceInternal) - .reverifyWithFixups(ltx, missingClass) - .getOrThrow() + private fun verifySignatures(verificationSupport: NodeVerificationSupport, checkSufficientSignatures: Boolean) { + if (checkSufficientSignatures) { + val ctx = coreTransaction + val tws: TransactionWithSignatures = when (ctx) { + is WireTransaction -> this // SignedTransaction implements TransactionWithSignatures in terms of WireTransaction + else -> CoreTransactionWithSignatures(ctx, sigs, verificationSupport) + } + tws.verifyRequiredSignatures() // Internally checkSignaturesAreValid is invoked + } else { + checkSignaturesAreValid() + } } /** @@ -306,7 +265,7 @@ data class SignedTransaction(val txBits: SerializedBytes, } /** - * If [transaction] is a [NotaryChangeWireTransaction], loads the input states and resolves it to a + * If [coreTransaction] is a [NotaryChangeWireTransaction], loads the input states and resolves it to a * [NotaryChangeLedgerTransaction] so the signatures can be verified. */ fun resolveNotaryChangeTransaction(services: ServicesForResolution): NotaryChangeLedgerTransaction { @@ -316,10 +275,12 @@ data class SignedTransaction(val txBits: SerializedBytes, } /** - * If [transaction] is a [NotaryChangeWireTransaction], loads the input states and resolves it to a + * If [coreTransaction] is a [NotaryChangeWireTransaction], loads the input states and resolves it to a * [NotaryChangeLedgerTransaction] so the signatures can be verified. */ - fun resolveNotaryChangeTransaction(services: ServiceHub) = resolveNotaryChangeTransaction(services as ServicesForResolution) + fun resolveNotaryChangeTransaction(services: ServiceHub): NotaryChangeLedgerTransaction { + return resolveNotaryChangeTransaction(services as ServicesForResolution) + } /** * If [coreTransaction] is a [ContractUpgradeWireTransaction], loads the input states and resolves it to a @@ -331,7 +292,7 @@ data class SignedTransaction(val txBits: SerializedBytes, return ctx.resolve(services, sigs) } - override fun toString(): String = "${javaClass.simpleName}(id=$id)" + override fun toString(): String = toSimpleString() private companion object { private fun missingSignatureMsg(missing: Set, descriptions: List, id: SecureHash): String { @@ -339,13 +300,28 @@ data class SignedTransaction(val txBits: SerializedBytes, "keys: ${missing.joinToString { it.toStringShort() }}, " + "by signers: ${descriptions.joinToString()} " } - - private val log = contextLogger() } class SignaturesMissingException(val missing: Set, val descriptions: List, override val id: SecureHash) : NamedByHash, SignatureException(missingSignatureMsg(missing, descriptions, id)), CordaThrowable by CordaException(missingSignatureMsg(missing, descriptions, id)) + /** + * A [TransactionWithSignatures] wrapper for [CoreTransaction]s which need to resolve their input states in order to get at the signers + * list. + */ + private data class CoreTransactionWithSignatures( + private val ctx: CoreTransaction, + override val sigs: List, + private val verificationSupport: NodeVerificationSupport + ) : TransactionWithSignatures, NamedByHash by ctx { + override val requiredSigningKeys: Set + get() = getRequiredSigningKeysInternal(ctx.inputs.asSequence().map(verificationSupport::getStateAndRef), ctx.notary) + + override fun getKeyDescriptions(keys: Set): List = keys.map { it.toBase58String() } + + override fun toString(): String = toSimpleString() + } + //region Deprecated /** Returns the contained [NotaryChangeWireTransaction], or throws if this is a normal transaction. */ @Deprecated("No replacement, this should not be used outside of Corda core") diff --git a/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt b/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt index 4cede898a0..237c8c39d2 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt @@ -2,13 +2,16 @@ package net.corda.core.transactions import co.paralleluniverse.strands.Strand -import net.corda.core.CordaInternal import net.corda.core.contracts.* import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SignableData import net.corda.core.crypto.SignatureMetadata import net.corda.core.identity.Party import net.corda.core.internal.* +import net.corda.core.internal.PlatformVersionSwitches.MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS +import net.corda.core.internal.cordapp.ContractAttachmentWithLegacy +import net.corda.core.internal.verification.VerifyingServiceHub +import net.corda.core.internal.verification.toVerifyingServiceHub import net.corda.core.node.NetworkParameters import net.corda.core.node.ServiceHub import net.corda.core.node.ServicesForResolution @@ -22,15 +25,14 @@ import net.corda.core.serialization.SerializationFactory import net.corda.core.serialization.SerializationMagic import net.corda.core.serialization.SerializationSchemeContext import net.corda.core.serialization.internal.CustomSerializationSchemeUtils.Companion.getCustomSerializationMagicFromSchemeId +import net.corda.core.utilities.Try.Failure import net.corda.core.utilities.contextLogger +import net.corda.core.utilities.debug import java.security.PublicKey import java.time.Duration import java.time.Instant import java.util.* import java.util.regex.Pattern -import kotlin.collections.ArrayList -import kotlin.collections.component1 -import kotlin.collections.component2 import kotlin.reflect.KClass /** @@ -73,13 +75,13 @@ open class TransactionBuilder( private fun defaultLockId() = (Strand.currentStrand() as? FlowStateMachine<*>)?.id?.uuid ?: UUID.randomUUID() private val log = contextLogger() private val MISSING_CLASS_DISABLED = java.lang.Boolean.getBoolean("net.corda.transactionbuilder.missingclass.disabled") - + private val automaticConstraints = setOf( + AutomaticPlaceholderConstraint, + @Suppress("DEPRECATION") AutomaticHashConstraint + ) private const val ID_PATTERN = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*" private val FQCP: Pattern = Pattern.compile("$ID_PATTERN(/$ID_PATTERN)+") private fun isValidJavaClass(identifier: String) = FQCP.matcher(identifier).matches() - private fun Collection<*>.deepEquals(other: Collection<*>): Boolean { - return (size == other.size) && containsAll(other) && other.containsAll(this) - } private fun Collection.toPrettyString(): String = sorted().joinToString( separator = System.lineSeparator(), prefix = System.lineSeparator() @@ -88,7 +90,8 @@ open class TransactionBuilder( private val inputsWithTransactionState = arrayListOf>() private val referencesWithTransactionState = arrayListOf>() - private val excludedAttachments = arrayListOf() + private var excludedAttachments: Set = emptySet() + private var extraLegacyAttachments: MutableSet? = null /** * Creates a copy of the builder. @@ -139,8 +142,7 @@ open class TransactionBuilder( * @throws [ZoneVersionTooLowException] if there are reference states and the zone minimum platform version is less than 4. */ @Throws(MissingContractAttachments::class) - fun toWireTransaction(services: ServicesForResolution): WireTransaction = toWireTransactionWithContext(services, null) - .apply { checkSupportedHashType() } + fun toWireTransaction(services: ServicesForResolution): WireTransaction = toWireTransaction(services.toVerifyingServiceHub()) /** * Generates a [WireTransaction] from this builder, resolves any [AutomaticPlaceholderConstraint], and selects the attachments to use for this transaction. @@ -154,7 +156,7 @@ open class TransactionBuilder( */ @Throws(MissingContractAttachments::class) fun toWireTransaction(services: ServicesForResolution, schemeId: Int): WireTransaction { - return toWireTransaction(services, schemeId, emptyMap()).apply { checkSupportedHashType() } + return toWireTransaction(services, schemeId, emptyMap()) } /** @@ -174,28 +176,21 @@ open class TransactionBuilder( fun toWireTransaction(services: ServicesForResolution, schemeId: Int, properties: Map): WireTransaction { val magic: SerializationMagic = getCustomSerializationMagicFromSchemeId(schemeId) val serializationContext = SerializationDefaults.P2P_CONTEXT.withPreferredSerializationVersion(magic).withProperties(properties) - return toWireTransactionWithContext(services, serializationContext).apply { checkSupportedHashType() } + return toWireTransaction(services.toVerifyingServiceHub(), serializationContext) } - @CordaInternal - internal fun toWireTransactionWithContext( - services: ServicesForResolution, - serializationContext: SerializationContext? - ) : WireTransaction = toWireTransactionWithContext(services, serializationContext, 0) - - private tailrec fun toWireTransactionWithContext( - services: ServicesForResolution, - serializationContext: SerializationContext?, - tryCount: Int + private tailrec fun toWireTransaction( + serviceHub: VerifyingServiceHub, + serializationContext: SerializationContext? = null, + tryCount: Int = 0 ): WireTransaction { val referenceStates = referenceStates() if (referenceStates.isNotEmpty()) { - services.ensureMinimumPlatformVersion(4, "Reference states") + serviceHub.ensureMinimumPlatformVersion(4, "Reference states") } - resolveNotary(services) + resolveNotary(serviceHub) - val (allContractAttachments: Collection, resolvedOutputs: List>) - = selectContractAttachmentsAndOutputStateConstraints(services, serializationContext) + val (allContractAttachments, resolvedOutputs) = selectContractAttachmentsAndOutputStateConstraints(serviceHub) // Final sanity check that all states have the correct constraints. for (state in (inputsWithTransactionState.map { it.state } + resolvedOutputs)) { @@ -203,19 +198,30 @@ open class TransactionBuilder( } val wireTx = SerializationFactory.defaultFactory.withCurrentContext(serializationContext) { + // Sort the attachments to ensure transaction builds are stable. + val nonLegacyAttachments = allContractAttachments.mapTo(TreeSet()) { it.currentAttachment.id }.apply { + addAll(attachments) + removeAll(excludedAttachments) + }.toList() + val legacyAttachments = allContractAttachments.mapNotNullTo(TreeSet()) { it.legacyAttachment?.id }.apply { + if (extraLegacyAttachments != null) { + addAll(extraLegacyAttachments!!) + } + }.toList() WireTransaction( createComponentGroups( inputStates(), resolvedOutputs, commands(), - // Sort the attachments to ensure transaction builds are stable. - ((allContractAttachments + attachments).toSortedSet() - excludedAttachments).toList(), + nonLegacyAttachments, notary, window, referenceStates, - services.networkParametersService.currentHash), + serviceHub.networkParametersService.currentHash, + legacyAttachments + ), privacySalt, - services.digestService + serviceHub.digestService ) } @@ -223,76 +229,96 @@ open class TransactionBuilder( // This is a workaround as the current version of Corda does not support cordapp dependencies. // It works by running transaction validation and then scan the attachment storage for missing classes. // TODO - remove once proper support for cordapp dependencies is added. - val addedDependency = addMissingDependency(services, wireTx, tryCount) + val addedDependency = addMissingDependency(serviceHub, wireTx, tryCount) - return if (addedDependency) - toWireTransactionWithContext(services, serializationContext, tryCount + 1) - else - wireTx - } - - // Returns the first exception in the hierarchy that matches one of the [types]. - private tailrec fun Throwable.rootClassNotFoundCause(vararg types: KClass<*>): Throwable = when { - this::class in types -> this - this.cause == null -> this - else -> this.cause!!.rootClassNotFoundCause(*types) + return if (addedDependency) { + toWireTransaction(serviceHub, serializationContext, tryCount + 1) + } else { + wireTx.apply { checkSupportedHashType() } + } } /** * @return true if a new dependency was successfully added. */ - private fun addMissingDependency(services: ServicesForResolution, wireTx: WireTransaction, tryCount: Int): Boolean { - return try { - wireTx.toLedgerTransaction(services).verify() - // The transaction verified successfully without adding any extra dependency. - false - } catch (e: Throwable) { - val rootError = e.rootClassNotFoundCause(ClassNotFoundException::class, NoClassDefFoundError::class) + private fun addMissingDependency(serviceHub: VerifyingServiceHub, wireTx: WireTransaction, tryCount: Int): Boolean { + log.debug { "Checking if there are any missing attachment dependencies for transaction ${wireTx.id}..." } + val verificationResult = wireTx.tryVerify(serviceHub) + // Check both legacy and non-legacy components are working, and try to add any missing dependencies if either are not. + (verificationResult.inProcessResult as? Failure)?.let { (inProcessException) -> + return addMissingDependency(inProcessException, wireTx, false, serviceHub, tryCount) + } + log.debug("Non-legacy portion of transaction does not have any missing attachments, checking legacy portion...") + (verificationResult.externalResult as? Failure)?.let { (externalException) -> + return addMissingDependency(externalException, wireTx, true, serviceHub, tryCount) + } + log.debug("Legacy portion of transaction also does not have any missing attachments") + // The transaction verified successfully without needing any extra dependency. + return false + } - when { - // Handle various exceptions that can be thrown during verification and drill down the wrappings. - // Note: this is a best effort to preserve backwards compatibility. - rootError is ClassNotFoundException -> { - ((tryCount == 0) && fixupAttachments(wireTx.attachments, services, e)) - || addMissingAttachment((rootError.message ?: throw e).replace('.', '/'), services, e) - } - rootError is NoClassDefFoundError -> { - ((tryCount == 0) && fixupAttachments(wireTx.attachments, services, e)) - || addMissingAttachment(rootError.message ?: throw e, services, e) - } - - // Ignore these exceptions as they will break unit tests. - // The point here is only to detect missing dependencies. The other exceptions are irrelevant. - e is TransactionVerificationException -> false - e is TransactionResolutionException -> false - e is IllegalStateException -> false - e is IllegalArgumentException -> false - - // Fail early if none of the expected scenarios were hit. - else -> { - log.error("""The transaction currently built will not validate because of an unknown error most likely caused by a - missing dependency in the transaction attachments. - Please contact the developer of the CorDapp for further instructions. - """.trimIndent(), e) - throw e - } + private fun addMissingDependency(e: Throwable, wireTx: WireTransaction, isLegacy: Boolean, serviceHub: VerifyingServiceHub, tryCount: Int): Boolean { + val missingClass = extractMissingClass(e) + if (log.isDebugEnabled) { + log.debug("${if (isLegacy) "Legacy" else "Non-legacy"} portion of transaction has missing dependency (missingClass=$missingClass) $wireTx", e) + } + return when { + missingClass != null -> { + val attachments = if (isLegacy) wireTx.legacyAttachments else wireTx.nonLegacyAttachments + (tryCount == 0 && fixupAttachments(attachments, serviceHub, e)) || addMissingAttachment(missingClass, isLegacy, serviceHub, e) + } + // Ignore these exceptions as they will break unit tests. + // The point here is only to detect missing dependencies. The other exceptions are irrelevant. + e is TransactionVerificationException -> false + e is TransactionResolutionException -> false + e is IllegalStateException -> false + e is IllegalArgumentException -> false + // Fail early if none of the expected scenarios were hit. + else -> { + log.error("""The transaction currently built will not validate because of an unknown error most likely caused by a + missing dependency in the transaction attachments. + Please contact the developer of the CorDapp for further instructions. + """.trimIndent(), e) + throw e } } } + private fun extractMissingClass(throwable: Throwable): String? { + var current = throwable + while (true) { + if (current is ClassNotFoundException) { + return current.message?.replace('.', '/') + } + if (current is NoClassDefFoundError) { + return current.message + } + val message = current.message + if (message != null) { + message.extractClassAfter(NoClassDefFoundError::class)?.let { return it } + message.extractClassAfter(ClassNotFoundException::class)?.let { return it.replace('.', '/') } + } + current = current.cause ?: return null + } + } + + private fun String.extractClassAfter(exceptionClass: KClass): String? { + return substringAfterLast("${exceptionClass.java.name}: ", "").takeIf { it.isNotEmpty() } + } + private fun fixupAttachments( - txAttachments: List, - services: ServicesForResolution, - originalException: Throwable + txAttachments: List, + serviceHub: VerifyingServiceHub, + originalException: Throwable ): Boolean { - val replacementAttachments = services.cordappProvider.internalFixupAttachmentIds(txAttachments) - if (replacementAttachments.deepEquals(txAttachments)) { + val replacementAttachments = serviceHub.fixupAttachmentIds(txAttachments) + if (replacementAttachments.equivalent(txAttachments)) { return false } val extraAttachments = replacementAttachments - txAttachments extraAttachments.forEach { id -> - val attachment = services.attachments.openAttachment(id) + val attachment = serviceHub.attachments.openAttachment(id) if (attachment == null || !attachment.isUploaderTrusted()) { log.warn("""The node's fix-up rules suggest including attachment {}, which cannot be found either. |Please contact the developer of the CorDapp for further instructions. @@ -302,10 +328,7 @@ open class TransactionBuilder( } attachments.addAll(extraAttachments) - with(excludedAttachments) { - clear() - addAll(txAttachments - replacementAttachments) - } + excludedAttachments = (txAttachments - replacementAttachments).toSet() log.warn("Attempting to rebuild transaction with these extra attachments:{}{}and these attachments removed:{}", extraAttachments.toPrettyString(), @@ -315,7 +338,7 @@ open class TransactionBuilder( return true } - private fun addMissingAttachment(missingClass: String, services: ServicesForResolution, originalException: Throwable): Boolean { + private fun addMissingAttachment(missingClass: String, isLegacy: Boolean, serviceHub: VerifyingServiceHub, originalException: Throwable): Boolean { if (!isValidJavaClass(missingClass)) { log.warn("Could not autodetect a valid attachment for the transaction being built.") throw originalException @@ -324,14 +347,19 @@ open class TransactionBuilder( throw originalException } - val attachment = services.attachments.internalFindTrustedAttachmentForClass(missingClass) + val attachments = serviceHub.getTrustedClassAttachments(missingClass) + val attachment = if (isLegacy) { + // Any attachment which contains the class but isn't a non-legacy CorDapp is *probably* the legacy attachment we're looking for + val nonLegacyCordapps = serviceHub.cordappProvider.cordapps.mapToSet { it.jarHash } + attachments.firstOrNull { it.id !in nonLegacyCordapps } + } else { + attachments.firstOrNull() + } if (attachment == null) { - log.error("""The transaction currently built is missing an attachment for class: $missingClass. - Attempted to find a suitable attachment but could not find any in the storage. - Please contact the developer of the CorDapp for further instructions. - """.trimIndent()) - throw originalException + throw IllegalStateException("Transaction being built has a missing ${if (isLegacy) "legacy " else ""}attachment for class " + + "$missingClass. Could not find a suitable attachment from storage. Please contact the developer of the CorDapp for " + + "further instructions.", originalException) } log.warnOnce("""The transaction currently built is missing an attachment for class: $missingClass. @@ -339,7 +367,12 @@ open class TransactionBuilder( Please contact the developer of the CorDapp and install the latest version, as this approach might be insecure. """.trimIndent()) - addAttachment(attachment.id) + if (isLegacy) { + (extraLegacyAttachments ?: LinkedHashSet().also { extraLegacyAttachments = it }) += attachment.id + } else { + addAttachment(attachment.id) + } + return true } @@ -353,26 +386,15 @@ open class TransactionBuilder( * TODO also on the versions of the attachments of the transactions generating the input states. ( after we add versioning) */ private fun selectContractAttachmentsAndOutputStateConstraints( - services: ServicesForResolution, - @Suppress("UNUSED_PARAMETER") serializationContext: SerializationContext? - ): Pair, List>> { - + serviceHub: VerifyingServiceHub + ): Pair, List>> { // Determine the explicitly set contract attachments. - val explicitAttachmentContracts: List> = this.attachments - .map(services.attachments::openAttachment) - .mapNotNull { it as? ContractAttachment } - .flatMap { attch -> - attch.allContracts.map { it to attch.id } + val explicitContractToAttachments = attachments + .mapNotNull { serviceHub.attachments.openAttachment(it) as? ContractAttachment } + .groupByMultipleKeys(ContractAttachment::allContracts) { contract, attachment1, attachment2 -> + throw IllegalArgumentException("Multiple attachments specified for the same contract $contract ($attachment1, $attachment2).") } - // And fail early if there's more than 1 for a contract. - require(explicitAttachmentContracts.isEmpty() - || explicitAttachmentContracts.groupBy { (ctr, _) -> ctr }.all { (_, groups) -> groups.size == 1 }) { - "Multiple attachments set for the same contract." - } - - val explicitAttachmentContractsMap: Map = explicitAttachmentContracts.toMap() - val inputContractGroups: Map>> = inputsWithTransactionState.map { it.state } .groupBy { it.contract } val outputContractGroups: Map>> = outputs.groupBy { it.contract } @@ -383,38 +405,33 @@ open class TransactionBuilder( // Filter out all contracts that might have been already used by 'normal' input or output states. val referenceStateGroups: Map>> = referencesWithTransactionState.groupBy { it.contract } - val refStateContractAttachments: List = referenceStateGroups + val refStateContractAttachments = referenceStateGroups .filterNot { it.key in allContracts } - .map { refStateEntry -> - getInstalledContractAttachmentId( - refStateEntry.key, - refStateEntry.value, - services - ) - } + .map { refStateEntry -> serviceHub.getInstalledContractAttachments(refStateEntry.key, refStateEntry::value) } // For each contract, resolve the AutomaticPlaceholderConstraint, and select the attachment. - val contractAttachmentsAndResolvedOutputStates: List>?>> = allContracts.toSet() - .map { ctr -> - handleContract(ctr, inputContractGroups[ctr], outputContractGroups[ctr], explicitAttachmentContractsMap[ctr], services) - } + val contractAttachmentsAndResolvedOutputStates = allContracts.map { contract -> + selectAttachmentAndResolveOutputStates( + contract, + inputContractGroups[contract], + outputContractGroups[contract], + explicitContractToAttachments[contract], + serviceHub + ) + } - val resolvedStates: List> = contractAttachmentsAndResolvedOutputStates.mapNotNull { it.second } - .flatten() + val resolvedStates = contractAttachmentsAndResolvedOutputStates.flatMap { it.second } // The output states need to preserve the order in which they were added. - val resolvedOutputStatesInTheOriginalOrder: List> = outputStates().map { os -> resolvedStates.find { rs -> rs.data == os.data && rs.encumbrance == os.encumbrance }!! } + val resolvedOutputStatesInTheOriginalOrder: List> = outputStates().map { os -> + resolvedStates.first { rs -> rs.data == os.data && rs.encumbrance == os.encumbrance } + } - val attachments: Collection = contractAttachmentsAndResolvedOutputStates.map { it.first } + refStateContractAttachments + val attachments = contractAttachmentsAndResolvedOutputStates.map { it.first } + refStateContractAttachments return Pair(attachments, resolvedOutputStatesInTheOriginalOrder) } - private val automaticConstraints = setOf( - AutomaticPlaceholderConstraint, - @Suppress("DEPRECATION") AutomaticHashConstraint - ) - /** * Selects an attachment and resolves the constraints for the output states with [AutomaticPlaceholderConstraint]. * @@ -430,20 +447,18 @@ open class TransactionBuilder( * * * For input states with [WhitelistedByZoneAttachmentConstraint] or a [AlwaysAcceptAttachmentConstraint] implementations, then the currently installed cordapp version is used. */ - private fun handleContract( + private fun selectAttachmentAndResolveOutputStates( contractClassName: ContractClassName, inputStates: List>?, outputStates: List>?, - explicitContractAttachment: AttachmentId?, - services: ServicesForResolution - ): Pair>?> { + explicitContractAttachment: ContractAttachment?, + serviceHub: VerifyingServiceHub + ): Pair>> { val inputsAndOutputs = (inputStates ?: emptyList()) + (outputStates ?: emptyList()) - fun selectAttachment() = getInstalledContractAttachmentId( - contractClassName, - inputsAndOutputs.filterNot { it.constraint in automaticConstraints }, - services - ) + fun selectAttachmentForContract() = serviceHub.getInstalledContractAttachments(contractClassName) { + inputsAndOutputs.filterNot { it.constraint in automaticConstraints } + } /* This block handles the very specific code path where a [HashAttachmentConstraint] can @@ -453,79 +468,77 @@ open class TransactionBuilder( This can only happen in a private network where all nodes have started with a system parameter that disables the hash constraint check. */ - if (canMigrateFromHashToSignatureConstraint(inputStates, outputStates, services)) { - val attachmentId = selectAttachment() - val attachment = services.attachments.openAttachment(attachmentId) - require(attachment != null) { "Contract attachment $attachmentId for $contractClassName is missing." } - if ((attachment as ContractAttachment).isSigned && (explicitContractAttachment == null || explicitContractAttachment == attachment.id)) { - val signatureConstraint = - makeSignatureAttachmentConstraint(attachment.signerKeys) + if (canMigrateFromHashToSignatureConstraint(inputStates, outputStates, serviceHub)) { + val attachmentWithLegacy = selectAttachmentForContract() + val (attachment) = attachmentWithLegacy + if (attachment.isSigned && (explicitContractAttachment == null || explicitContractAttachment.id == attachment.id)) { + val signatureConstraint = makeSignatureAttachmentConstraint(attachment.signerKeys) require(signatureConstraint.isSatisfiedBy(attachment)) { "Selected output constraint: $signatureConstraint not satisfying ${attachment.id}" } val resolvedOutputStates = outputStates?.map { - if (it.constraint in automaticConstraints) { - it.copy(constraint = signatureConstraint) - } else { - it - } - } - return attachment.id to resolvedOutputStates + if (it.constraint in automaticConstraints) it.copy(constraint = signatureConstraint) else it + } ?: emptyList() + return attachmentWithLegacy to resolvedOutputStates } } // Determine if there are any HashConstraints that pin the version of a contract. If there are, check if we trust them. - val hashAttachments = inputsAndOutputs + val hashAttachments: Set = inputsAndOutputs .filter { it.constraint is HashAttachmentConstraint } - .map { state -> - val attachment = services.attachments.openAttachment((state.constraint as HashAttachmentConstraint).attachmentId) - if (attachment == null || attachment !is ContractAttachment || !isUploaderTrusted(attachment.uploader)) { + .mapToSet, ContractAttachment> { state -> + val attachment = serviceHub.attachments.openAttachment((state.constraint as HashAttachmentConstraint).attachmentId) + if (attachment !is ContractAttachment || !isUploaderTrusted(attachment.uploader)) { // This should never happen because these are input states that should have been validated already. throw MissingContractAttachments(listOf(state)) } attachment - }.toSet() + } // Check that states with the HashConstraint don't conflict between themselves or with an explicitly set attachment. require(hashAttachments.size <= 1) { - "Transaction was built with $contractClassName states with multiple HashConstraints. This is illegal, because it makes it impossible to validate with a single version of the contract code." + "Transaction was built with $contractClassName states with multiple HashConstraints. This is illegal, because it makes it " + + "impossible to validate with a single version of the contract code." } + val hashAttachment = hashAttachments.singleOrNull() - if (explicitContractAttachment != null && hashAttachments.singleOrNull() != null) { - require(explicitContractAttachment == (hashAttachments.single() as ContractAttachment).attachment.id) { - "An attachment has been explicitly set for contract $contractClassName in the transaction builder which conflicts with the HashConstraint of a state." + val selectedAttachment = if (explicitContractAttachment != null) { + if (hashAttachment != null) { + require(explicitContractAttachment.id == hashAttachment.id) { + "An attachment has been explicitly set for contract $contractClassName in the transaction builder which conflicts " + + "with the HashConstraint of a state." + } } + // This *has* to be used by this transaction as it is explicit + ContractAttachmentWithLegacy(explicitContractAttachment, null) // By definition there can be no legacy version + } else { + hashAttachment?.let { ContractAttachmentWithLegacy(it, null) } ?: selectAttachmentForContract() } - // This will contain the hash of the JAR that *has* to be used by this Transaction, because it is explicit. Or null if none. - val forcedAttachmentId = explicitContractAttachment ?: hashAttachments.singleOrNull()?.id - - // This will contain the hash of the JAR that will be used by this Transaction. - val selectedAttachmentId = forcedAttachmentId ?: selectAttachment() - - val attachmentToUse = services.attachments.openAttachment(selectedAttachmentId)?.let { it as ContractAttachment } - ?: throw IllegalArgumentException("Contract attachment $selectedAttachmentId for $contractClassName is missing.") - // For Exit transactions (no output states) there is no need to resolve the output constraints. if (outputStates == null) { - return Pair(selectedAttachmentId, null) + return Pair(selectedAttachment, emptyList()) } // If there are no automatic constraints, there is nothing to resolve. if (outputStates.none { it.constraint in automaticConstraints }) { - return Pair(selectedAttachmentId, outputStates) + return Pair(selectedAttachment, outputStates) } // The final step is to resolve AutomaticPlaceholderConstraint. val automaticConstraintPropagation = contractClassName.contractHasAutomaticConstraintPropagation(inputsAndOutputs.first().data::class.java.classLoader) // When automaticConstraintPropagation is disabled for a contract, output states must an explicit Constraint. - require(automaticConstraintPropagation) { "Contract $contractClassName was marked with @NoConstraintPropagation, which means the constraint of the output states has to be set explicitly." } + require(automaticConstraintPropagation) { + "Contract $contractClassName was marked with @NoConstraintPropagation, which means the constraint of the output states has to be set explicitly." + } // This is the logic to determine the constraint which will replace the AutomaticPlaceholderConstraint. - val defaultOutputConstraint = selectAttachmentConstraint(contractClassName, inputStates, attachmentToUse, services) + val defaultOutputConstraint = selectAttachmentConstraint(contractClassName, inputStates, selectedAttachment.currentAttachment, serviceHub) // Sanity check that the selected attachment actually passes. - val constraintAttachment = AttachmentWithContext(attachmentToUse, contractClassName, services.networkParameters.whitelistedContractImplementations) - require(defaultOutputConstraint.isSatisfiedBy(constraintAttachment)) { "Selected output constraint: $defaultOutputConstraint not satisfying $selectedAttachmentId" } + val constraintAttachment = AttachmentWithContext(selectedAttachment.currentAttachment, contractClassName, serviceHub.networkParameters.whitelistedContractImplementations) + require(defaultOutputConstraint.isSatisfiedBy(constraintAttachment)) { + "Selected output constraint: $defaultOutputConstraint not satisfying $selectedAttachment" + } val resolvedOutputStates = outputStates.map { val outputConstraint = it.constraint @@ -534,14 +547,16 @@ open class TransactionBuilder( } else { // If the constraint on the output state is already set, and is not a valid transition or can't be transitioned, then fail early. inputStates?.forEach { input -> - require(outputConstraint.canBeTransitionedFrom(input.constraint, attachmentToUse)) { "Output state constraint $outputConstraint cannot be transitioned from ${input.constraint}" } + require(outputConstraint.canBeTransitionedFrom(input.constraint, selectedAttachment.currentAttachment)) { + "Output state constraint $outputConstraint cannot be transitioned from ${input.constraint}" + } } require(outputConstraint.isSatisfiedBy(constraintAttachment)) { "Output state constraint check fails. $outputConstraint" } it } } - return Pair(selectedAttachmentId, resolvedOutputStates) + return Pair(selectedAttachment, resolvedOutputStates) } /** @@ -572,21 +587,25 @@ open class TransactionBuilder( contractClassName: ContractClassName, inputStates: List>?, attachmentToUse: ContractAttachment, - services: ServicesForResolution): AttachmentConstraint = when { - inputStates != null -> attachmentConstraintsTransition(inputStates.groupBy { it.constraint }.keys, attachmentToUse, services) - attachmentToUse.signerKeys.isNotEmpty() && services.networkParameters.minimumPlatformVersion < PlatformVersionSwitches.MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS -> { - log.warnOnce("Signature constraints not available on network requiring a minimum platform version of ${PlatformVersionSwitches.MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS}. Current is: ${services.networkParameters.minimumPlatformVersion}.") - if (useWhitelistedByZoneAttachmentConstraint(contractClassName, services.networkParameters)) { - log.warnOnce("Reverting back to using whitelisted zone constraints for contract $contractClassName") - WhitelistedByZoneAttachmentConstraint - } else { - log.warnOnce("Reverting back to using hash constraints for contract $contractClassName") - HashAttachmentConstraint(attachmentToUse.id) + services: ServicesForResolution + ): AttachmentConstraint { + return when { + inputStates != null -> attachmentConstraintsTransition(inputStates.groupBy { it.constraint }.keys, attachmentToUse, services) + attachmentToUse.signerKeys.isNotEmpty() && services.networkParameters.minimumPlatformVersion < MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS -> { + log.warnOnce("Signature constraints not available on network requiring a minimum platform version of " + + "$MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS. Current is: ${services.networkParameters.minimumPlatformVersion}.") + if (useWhitelistedByZoneAttachmentConstraint(contractClassName, services.networkParameters)) { + log.warnOnce("Reverting back to using whitelisted zone constraints for contract $contractClassName") + WhitelistedByZoneAttachmentConstraint + } else { + log.warnOnce("Reverting back to using hash constraints for contract $contractClassName") + HashAttachmentConstraint(attachmentToUse.id) + } } + attachmentToUse.signerKeys.isNotEmpty() -> makeSignatureAttachmentConstraint(attachmentToUse.signerKeys) + useWhitelistedByZoneAttachmentConstraint(contractClassName, services.networkParameters) -> WhitelistedByZoneAttachmentConstraint + else -> HashAttachmentConstraint(attachmentToUse.id) } - attachmentToUse.signerKeys.isNotEmpty() -> makeSignatureAttachmentConstraint(attachmentToUse.signerKeys) - useWhitelistedByZoneAttachmentConstraint(contractClassName, services.networkParameters) -> WhitelistedByZoneAttachmentConstraint - else -> HashAttachmentConstraint(attachmentToUse.id) } /** @@ -625,7 +644,7 @@ open class TransactionBuilder( // This ensures a smooth migration from a Whitelist Constraint to a Signature Constraint constraints.any { it is WhitelistedByZoneAttachmentConstraint } && attachmentToUse.isSigned && - services.networkParameters.minimumPlatformVersion >= PlatformVersionSwitches.MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS -> + services.networkParameters.minimumPlatformVersion >= MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS -> transitionToSignatureConstraint(constraints, attachmentToUse) // This condition is hit when the current node has not installed the latest signed version but has already received states that have been migrated @@ -651,27 +670,31 @@ open class TransactionBuilder( SignatureAttachmentConstraint.create(CompositeKey.Builder().addKeys(attachmentSigners) .build()) - private fun getInstalledContractAttachmentId( + private inline fun VerifyingServiceHub.getInstalledContractAttachments( contractClassName: String, - states: List>, - services: ServicesForResolution - ): AttachmentId { - return services.cordappProvider.getContractAttachmentID(contractClassName) - ?: throw MissingContractAttachments(states, contractClassName) + statesForException: () -> List> + ): ContractAttachmentWithLegacy { + // TODO Stop using legacy attachments when the 4.12 min platform version is reached https://r3-cev.atlassian.net/browse/ENT-11479 + val attachmentWithLegacy = cordappProvider.getContractAttachments(contractClassName) + ?: throw MissingContractAttachments(statesForException(), contractClassName) + if (attachmentWithLegacy.legacyAttachment == null) { + log.warnOnce("Contract $contractClassName does not have a legacy (4.11 or earlier) version installed. This means the " + + "transaction will not be compatible with older nodes.") + } + return attachmentWithLegacy } - private fun useWhitelistedByZoneAttachmentConstraint(contractClassName: ContractClassName, networkParameters: NetworkParameters) = contractClassName in networkParameters.whitelistedContractImplementations.keys + private fun useWhitelistedByZoneAttachmentConstraint(contractClassName: ContractClassName, networkParameters: NetworkParameters): Boolean { + return contractClassName in networkParameters.whitelistedContractImplementations.keys + } @Throws(AttachmentResolutionException::class, TransactionResolutionException::class) fun toLedgerTransaction(services: ServiceHub) = toWireTransaction(services).toLedgerTransaction(services) - internal fun toLedgerTransactionWithContext(services: ServicesForResolution, serializationContext: SerializationContext): LedgerTransaction { - return toWireTransactionWithContext(services, serializationContext).toLedgerTransaction(services) - } - @Throws(AttachmentResolutionException::class, TransactionResolutionException::class, TransactionVerificationException::class) fun verify(services: ServiceHub) { - toLedgerTransaction(services).verify() + // Make sure the external verifier is involved if the transaction has a legacy component. + toWireTransaction(services).tryVerify(services.toVerifyingServiceHub()).enforceSuccess() } private fun checkNotary(stateAndRef: StateAndRef<*>) { @@ -692,7 +715,7 @@ open class TransactionBuilder( } // Transaction can combine different identities of the same notary after key rotation. - private fun checkReferencesUseSameNotary() = referencesWithTransactionState.map { it.notary.name }.toSet().size == 1 + private fun checkReferencesUseSameNotary() = referencesWithTransactionState.mapToSet { it.notary.name }.size == 1 // Automatically correct notary after its key rotation private fun resolveNotary(services: ServicesForResolution) { @@ -719,8 +742,6 @@ open class TransactionBuilder( * If this method is called outside the context of a flow, a [ServiceHub] instance must be passed to this method * for it to be able to resolve [StatePointer]s. Usually for a unit test, this will be an instance of mock services. * - * @param serviceHub a [ServiceHub] instance needed for performing vault queries. - * * @throws IllegalStateException if no [ServiceHub] is provided and no flow context is available. */ private fun resolveStatePointers(transactionState: TransactionState<*>) { diff --git a/core/src/main/kotlin/net/corda/core/transactions/TransactionWithSignatures.kt b/core/src/main/kotlin/net/corda/core/transactions/TransactionWithSignatures.kt index 72c027b9ff..13f019188d 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/TransactionWithSignatures.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/TransactionWithSignatures.kt @@ -4,6 +4,7 @@ import net.corda.core.DoNotImplement import net.corda.core.contracts.NamedByHash import net.corda.core.crypto.TransactionSignature import net.corda.core.crypto.isFulfilledBy +import net.corda.core.internal.mapToSet import net.corda.core.transactions.SignedTransaction.SignaturesMissingException import net.corda.core.utilities.toNonEmptySet import java.security.InvalidKeyException @@ -31,7 +32,6 @@ interface TransactionWithSignatures : NamedByHash { * @throws SignatureException if any signatures are invalid or unrecognised. * @throws SignaturesMissingException if any signatures should have been present but were not. */ - @JvmDefault @Throws(SignatureException::class) fun verifyRequiredSignatures() = verifySignaturesExcept(emptySet()) @@ -47,7 +47,6 @@ interface TransactionWithSignatures : NamedByHash { * @throws SignatureException if any signatures are invalid or unrecognised. * @throws SignaturesMissingException if any signatures should have been present but were not. */ - @JvmDefault @Throws(SignatureException::class) fun verifySignaturesExcept(vararg allowedToBeMissing: PublicKey) { verifySignaturesExcept(Arrays.asList(*allowedToBeMissing)) @@ -65,7 +64,6 @@ interface TransactionWithSignatures : NamedByHash { * @throws SignatureException if any signatures are invalid or unrecognised. * @throws SignaturesMissingException if any signatures should have been present but were not. */ - @JvmDefault @Throws(SignatureException::class) fun verifySignaturesExcept(allowedToBeMissing: Collection) { val needed = getMissingSigners() - allowedToBeMissing @@ -83,7 +81,6 @@ interface TransactionWithSignatures : NamedByHash { * @throws InvalidKeyException if the key on a signature is invalid. * @throws SignatureException if a signature fails to verify. */ - @JvmDefault @Throws(InvalidKeyException::class, SignatureException::class) fun checkSignaturesAreValid() { for (sig in sigs) { @@ -102,11 +99,10 @@ interface TransactionWithSignatures : NamedByHash { /** * Return the [PublicKey]s for which we still need signatures. */ - @JvmDefault fun getMissingSigners(): Set { - val sigKeys = sigs.map { it.by }.toSet() + val sigKeys = sigs.mapToSet { it.by } // TODO Problem is that we can get single PublicKey wrapped as CompositeKey in allowedToBeMissing/mustSign // equals on CompositeKey won't catch this case (do we want to single PublicKey be equal to the same key wrapped in CompositeKey with threshold 1?) - return requiredSigningKeys.filter { !it.isFulfilledBy(sigKeys) }.toSet() + return requiredSigningKeys.asSequence().filter { !it.isFulfilledBy(sigKeys) }.toSet() } -} \ No newline at end of file +} diff --git a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt index a0fa249240..79765cb6c6 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt @@ -1,23 +1,62 @@ package net.corda.core.transactions import net.corda.core.CordaInternal -import net.corda.core.contracts.* +import net.corda.core.contracts.Attachment +import net.corda.core.contracts.AttachmentResolutionException +import net.corda.core.contracts.Command +import net.corda.core.contracts.CommandWithParties +import net.corda.core.contracts.ComponentGroupEnum import net.corda.core.contracts.ComponentGroupEnum.COMMANDS_GROUP import net.corda.core.contracts.ComponentGroupEnum.OUTPUTS_GROUP -import net.corda.core.crypto.* +import net.corda.core.contracts.ComponentGroupEnum.SIGNERS_GROUP +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.PrivacySalt +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TimeWindow +import net.corda.core.contracts.TransactionResolutionException +import net.corda.core.contracts.TransactionState +import net.corda.core.contracts.TransactionVerificationException +import net.corda.core.crypto.DigestService +import net.corda.core.crypto.MerkleTree +import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.TransactionSignature +import net.corda.core.crypto.keys import net.corda.core.identity.Party -import net.corda.core.internal.* +import net.corda.core.internal.Emoji +import net.corda.core.internal.SerializedStateAndRef +import net.corda.core.internal.SerializedTransactionState +import net.corda.core.internal.TransactionDeserialisationException +import net.corda.core.internal.createComponentGroups +import net.corda.core.internal.deserialiseComponentGroup +import net.corda.core.internal.equivalent +import net.corda.core.internal.flatMapToSet +import net.corda.core.internal.getGroup +import net.corda.core.internal.isUploaderTrusted +import net.corda.core.internal.lazyMapped +import net.corda.core.internal.mapToSet +import net.corda.core.internal.toSimpleString +import net.corda.core.internal.uncheckedCast +import net.corda.core.internal.verification.NodeVerificationSupport +import net.corda.core.internal.verification.VerificationResult +import net.corda.core.internal.verification.VerificationResult.External +import net.corda.core.internal.verification.VerificationResult.InProcess +import net.corda.core.internal.verification.VerificationResult.InProcessAndExternal +import net.corda.core.internal.verification.VerificationSupport +import net.corda.core.internal.verification.toVerifyingServiceHub import net.corda.core.node.NetworkParameters -import net.corda.core.node.ServiceHub import net.corda.core.node.ServicesForResolution import net.corda.core.node.services.AttachmentId import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.DeprecatedConstructorForDeserialization +import net.corda.core.serialization.MissingAttachmentsException import net.corda.core.serialization.SerializationFactory -import net.corda.core.serialization.SerializedBytes -import net.corda.core.serialization.internal.AttachmentsClassLoaderCache +import net.corda.core.serialization.internal.MissingSerializerException import net.corda.core.serialization.serialize import net.corda.core.utilities.OpaqueBytes +import net.corda.core.utilities.Try +import net.corda.core.utilities.contextLogger +import net.corda.core.utilities.debug +import java.io.NotSerializableException import java.security.PublicKey import java.security.SignatureException import java.util.function.Predicate @@ -47,6 +86,7 @@ import java.util.function.Predicate *

    */ @CordaSerializable +@Suppress("ThrowsCount", "TooManyFunctions", "MagicNumber") class WireTransaction(componentGroups: List, val privacySalt: PrivacySalt, digestService: DigestService) : TraversableTransaction(componentGroups, digestService) { constructor(componentGroups: List) : this(componentGroups, PrivacySalt()) @@ -71,7 +111,7 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr init { check(componentGroups.all { it.components.isNotEmpty() }) { "Empty component groups are not allowed" } - check(componentGroups.map { it.groupIndex }.toSet().size == componentGroups.size) { "Duplicated component groups detected" } + check(componentGroups.mapToSet { it.groupIndex }.size == componentGroups.size) { "Duplicated component groups detected" } checkBaseInvariants() check(inputs.isNotEmpty() || outputs.isNotEmpty()) { "A transaction must contain at least one input or output state" } check(commands.isNotEmpty()) { "A transaction must contain at least one command" } @@ -84,13 +124,20 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr /** Public keys that need to be fulfilled by signatures in order for the transaction to be valid. */ val requiredSigningKeys: Set get() { - val commandKeys = commands.flatMap { it.signers }.toSet() - // TODO: prevent notary field from being set if there are no inputs and no time-window. - return if (notary != null && (inputs.isNotEmpty() || references.isNotEmpty() || timeWindow != null)) { - commandKeys + notary.owningKey + val keys = LinkedHashSet() + val signersGroup: List> = uncheckedCast(deserialiseComponentGroup(componentGroups, List::class, SIGNERS_GROUP)) + if (signersGroup.isNotEmpty()) { + signersGroup.forEach { keys.addAll(it) } } else { - commandKeys + // On the very odd chance we're dealing with a pre-3.x transaction, use the commands to get the signers. However, this has + // risk of not being deserialisable if the correct CorDapp is not installed. This is why this is only used as a last resort. + commands.flatMapTo(keys) { it.signers } } + // TODO: prevent notary field from being set if there are no inputs and no time-window. + if (notary != null && (inputs.isNotEmpty() || references.isNotEmpty() || timeWindow != null)) { + keys += notary.owningKey + } + return keys } /** @@ -102,28 +149,7 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr */ @Throws(AttachmentResolutionException::class, TransactionResolutionException::class) fun toLedgerTransaction(services: ServicesForResolution): LedgerTransaction { - return services.specialise( - toLedgerTransactionInternal( - resolveIdentity = { services.identityService.partyFromKey(it) }, - resolveAttachment = { services.attachments.openAttachment(it) }, - resolveStateRefAsSerialized = { resolveStateRefBinaryComponent(it, services) }, - resolveParameters = { - val hashToResolve = it ?: services.networkParametersService.defaultHash - services.networkParametersService.lookup(hashToResolve) - }, - // `as?` is used due to [MockServices] not implementing [ServiceHubCoreInternal] - isAttachmentTrusted = { (services as? ServiceHubCoreInternal)?.attachmentTrustCalculator?.calculate(it) ?: true }, - attachmentsClassLoaderCache = (services as? ServiceHubCoreInternal)?.attachmentsClassLoaderCache - ) - ) - } - - // Helper for deprecated toLedgerTransaction - @Suppress("UNUSED") // not sure if this field can be removed safely?? - private val missingAttachment: Attachment by lazy { - object : AbstractAttachment({ byteArrayOf() }, DEPLOYED_CORDAPP_UPLOADER ) { - override val id: SecureHash get() = throw UnsupportedOperationException() - } + return toLedgerTransactionInternal(services.toVerifyingServiceHub()) } /** @@ -143,29 +169,37 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr @Suppress("UNUSED_PARAMETER") resolveContractAttachment: (TransactionState) -> AttachmentId? ): LedgerTransaction { // This reverts to serializing the resolved transaction state. - return toLedgerTransactionInternal( - resolveIdentity, - resolveAttachment, - { stateRef -> resolveStateRef(stateRef)?.serialize() }, - { null }, - Attachment::isUploaderTrusted, - null - ) + return toLedgerTransactionInternal(object : VerificationSupport { + override fun getParties(keys: Collection): List = keys.map(resolveIdentity) + override fun getAttachment(id: SecureHash): Attachment? = resolveAttachment(id) + override fun getNetworkParameters(id: SecureHash?): NetworkParameters? = null + override fun isAttachmentTrusted(attachment: Attachment): Boolean = attachment.isUploaderTrusted() + override fun getSerializedState(stateRef: StateRef): SerializedTransactionState { + return resolveStateRef(stateRef)?.serialize() ?: throw TransactionResolutionException(stateRef.txhash) + } + // These are not used + override val appClassLoader: ClassLoader get() = throw AbstractMethodError() + override fun getTrustedClassAttachments(className: String) = throw AbstractMethodError() + override fun fixupAttachmentIds(attachmentIds: Collection) = throw AbstractMethodError() + }) } - @Suppress("LongParameterList", "ThrowsCount") - private fun toLedgerTransactionInternal( - resolveIdentity: (PublicKey) -> Party?, - resolveAttachment: (SecureHash) -> Attachment?, - resolveStateRefAsSerialized: (StateRef) -> SerializedBytes>?, - resolveParameters: (SecureHash?) -> NetworkParameters?, - isAttachmentTrusted: (Attachment) -> Boolean, - attachmentsClassLoaderCache: AttachmentsClassLoaderCache? - ): LedgerTransaction { + @CordaInternal + @JvmSynthetic + internal fun toLedgerTransactionInternal(verificationSupport: VerificationSupport): LedgerTransaction { // Look up public keys to authenticated identities. - val authenticatedCommands = commands.lazyMapped { cmd, _ -> - val parties = cmd.signers.mapNotNull(resolveIdentity) - CommandWithParties(cmd.signers, parties, cmd.value) + val authenticatedCommands = if (verificationSupport.isInProcess) { + commands.lazyMapped { cmd, _ -> + val parties = verificationSupport.getParties(cmd.signers).filterNotNull() + CommandWithParties(cmd.signers, parties, cmd.value) + } + } else { + val allSigners = commands.flatMapToSet { it.signers } + val allParties = verificationSupport.getParties(allSigners) + commands.map { cmd -> + val parties = cmd.signers.mapNotNull { allParties[allSigners.indexOf(it)] } + CommandWithParties(cmd.signers, parties, cmd.value) + } } // Ensure that the lazy mappings will use the correct SerializationContext. @@ -175,19 +209,30 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr ssar.toStateAndRef(serializationFactory, serializationContext) } - val serializedResolvedInputs = inputs.map { ref -> - SerializedStateAndRef(resolveStateRefAsSerialized(ref) ?: throw TransactionResolutionException(ref.txhash), ref) + val serializedResolvedInputs = inputs.map { + SerializedStateAndRef(verificationSupport.getSerializedState(it), it) } val resolvedInputs = serializedResolvedInputs.lazyMapped(toStateAndRef) - val serializedResolvedReferences = references.map { ref -> - SerializedStateAndRef(resolveStateRefAsSerialized(ref) ?: throw TransactionResolutionException(ref.txhash), ref) + val serializedResolvedReferences = references.map { + SerializedStateAndRef(verificationSupport.getSerializedState(it), it) } val resolvedReferences = serializedResolvedReferences.lazyMapped(toStateAndRef) - val resolvedAttachments = attachments.lazyMapped { att, _ -> resolveAttachment(att) ?: throw AttachmentResolutionException(att) } + val resolvedAttachments = if (verificationSupport.isInProcess) { + // The 4.12+ node only looks at the new attachments group + nonLegacyAttachments.lazyMapped { id, _ -> + verificationSupport.getAttachment(id) ?: throw AttachmentResolutionException(id) + } + } else { + // The 4.11 external verifier only looks at the legacy attachments group since it will only contain attachments compatible with 4.11 + verificationSupport.getAttachments(legacyAttachments).mapIndexed { index, attachment -> + attachment ?: throw AttachmentResolutionException(legacyAttachments[index]) + } + } - val resolvedNetworkParameters = resolveParameters(networkParametersHash) ?: throw TransactionResolutionException.UnknownParametersException(id, networkParametersHash!!) + val resolvedNetworkParameters = verificationSupport.getNetworkParameters(networkParametersHash) + ?: throw TransactionResolutionException.UnknownParametersException(id, networkParametersHash!!) val ltx = LedgerTransaction.create( resolvedInputs, @@ -203,8 +248,9 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr componentGroups, serializedResolvedInputs, serializedResolvedReferences, - isAttachmentTrusted, - attachmentsClassLoaderCache, + verificationSupport::isAttachmentTrusted, + verificationSupport::createVerifier, + verificationSupport.attachmentsClassLoaderCache, digestService ) @@ -230,15 +276,15 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr // This calculates a value that is slightly lower than the actual re-serialized version. But it is stable and does not depend on the classloader. fun componentGroupSize(componentGroup: ComponentGroupEnum): Int { - return this.componentGroups.firstOrNull { it.groupIndex == componentGroup.ordinal }?.let { cg -> cg.components.sumBy { it.size } + 4 } ?: 0 + return componentGroups.getGroup(componentGroup)?.let { cg -> cg.components.sumOf { it.size } + 4 } ?: 0 } // Check attachments size first as they are most likely to go over the limit. With ContractAttachment instances // it's likely that the same underlying Attachment CorDapp will occur more than once so we dedup on the attachment id. ltx.attachments.distinctBy { it.id }.forEach { minus(it.size) } - minus(resolvedSerializedInputs.sumBy { it.serializedState.size }) - minus(resolvedSerializedReferences.sumBy { it.serializedState.size }) + minus(resolvedSerializedInputs.sumOf { it.serializedState.size }) + minus(resolvedSerializedReferences.sumOf { it.serializedState.size }) // For Commands and outputs we can use the component groups as they are already serialized. minus(componentGroupSize(COMMANDS_GROUP)) @@ -273,7 +319,7 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr // Even if empty and not used, we should at least send oneHashes for each known // or received but unknown (thus, bigger than known ordinal) component groups. val allOnesHash = digestService.allOnesHash - for (i in 0..componentGroups.map { it.groupIndex }.max()!!) { + for (i in 0..componentGroups.maxOf { it.groupIndex }) { val root = groupsMerkleRoots[i] ?: allOnesHash listOfLeaves.add(root) } @@ -302,10 +348,10 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr * nothing about the rest. */ internal val availableComponentNonces: Map> by lazy { - if(digestService.hashAlgorithm == SecureHash.SHA2_256) { + if (digestService.hashAlgorithm == SecureHash.SHA2_256) { componentGroups.associate { it.groupIndex to it.components.mapIndexed { internalIndex, internalIt -> digestService.componentHash(internalIt, privacySalt, it.groupIndex, internalIndex) } } } else { - componentGroups.associate { it.groupIndex to it.components.mapIndexed { internalIndex, _ -> digestService.computeNonce(privacySalt, it.groupIndex, internalIndex) } } + componentGroups.associate { it.groupIndex to List(it.components.size) { internalIndex -> digestService.computeNonce(privacySalt, it.groupIndex, internalIndex) } } } } @@ -325,91 +371,221 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr * @throws IllegalArgumentException if the signature key doesn't appear in any command. */ fun checkSignature(sig: TransactionSignature) { - require(commands.any { it.signers.any { sig.by in it.keys } }) { "Signature key doesn't match any command" } + require(commands.any { it.signers.any { signer -> sig.by in signer.keys } }) { "Signature key doesn't match any command" } sig.verify(id) } - companion object { - @CordaInternal - @Deprecated("Do not use, this is internal API") - fun createComponentGroups(inputs: List, - outputs: List>, - commands: List>, - attachments: List, - notary: Party?, - timeWindow: TimeWindow?): List { - return createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow, emptyList(), null) - } - - /** - * This is the main logic that knows how to retrieve the binary representation of [StateRef]s. - * - * For [ContractUpgradeWireTransaction] or [NotaryChangeWireTransaction] it knows how to recreate the output state in the - * correct classloader independent of the node's classpath. - */ - @CordaInternal - fun resolveStateRefBinaryComponent(stateRef: StateRef, services: ServicesForResolution): SerializedBytes>? { - return if (services is ServiceHub) { - val coreTransaction = services.validatedTransactions.getTransaction(stateRef.txhash)?.coreTransaction - ?: throw TransactionResolutionException(stateRef.txhash) - // Get the network parameters from the tx or whatever the default params are. - val paramsHash = coreTransaction.networkParametersHash ?: services.networkParametersService.defaultHash - val params = services.networkParametersService.lookup(paramsHash) - ?: throw IllegalStateException("Should have been able to fetch parameters by this point: $paramsHash") - @Suppress("UNCHECKED_CAST") - when (coreTransaction) { - is WireTransaction -> coreTransaction.componentGroups - .firstOrNull { it.groupIndex == OUTPUTS_GROUP.ordinal } - ?.components - ?.get(stateRef.index) as SerializedBytes>? - is ContractUpgradeWireTransaction -> coreTransaction.resolveOutputComponent(services, stateRef, params) - is NotaryChangeWireTransaction -> coreTransaction.resolveOutputComponent(services, stateRef, params) - else -> throw UnsupportedOperationException("Attempting to resolve input ${stateRef.index} of a ${coreTransaction.javaClass} transaction. This is not supported.") - } - } else { - // For backwards compatibility revert to using the node classloader. - services.loadState(stateRef).serialize() + /** + * Perform verification of this [WireTransaction] and return the result as a [VerificationResult]. Depending on what types of attachments + * this transaction has, verification may have been done in-process by the node, or via the external verifier, or both. + * + * It's important that [VerificationResult.enforceSuccess] be called to make sure the verification was successful or its value analysed. + */ + @CordaInternal + @JvmSynthetic + internal fun tryVerify(verificationSupport: NodeVerificationSupport): VerificationResult { + return when { + legacyAttachments.isEmpty() -> { + log.debug { "${toSimpleString()} will be verified in-process" } + InProcess(Try.on { verifyInProcess(verificationSupport) }) + } + nonLegacyAttachments.isEmpty() -> { + log.debug { "${toSimpleString()} will be verified by the external verifer" } + External(Try.on { verificationSupport.externalVerifierHandle.verifyTransaction(this) }) + } + else -> { + log.debug { "${toSimpleString()} will be verified both in-process and by the external verifer" } + val inProcessResult = Try.on { verifyInProcess(verificationSupport) } + val externalResult = Try.on { verificationSupport.externalVerifierHandle.verifyTransaction(this) } + InProcessAndExternal(inProcessResult, externalResult) } } } + @CordaInternal + @JvmSynthetic + internal fun verifyInProcess(verificationSupport: VerificationSupport): LedgerTransaction { + val ltx = toLedgerTransactionInternal(verificationSupport) + try { + ltx.verify() + } catch (e: NoClassDefFoundError) { + checkReverifyAllowed(e) + val missingClass = e.message ?: throw e + log.warn("Transaction {} has missing class: {}", ltx.id, missingClass) + reverifyWithFixups(ltx, verificationSupport, missingClass) + } catch (e: NotSerializableException) { + checkReverifyAllowed(e) + retryVerification(e, e, ltx, verificationSupport) + } catch (e: TransactionDeserialisationException) { + checkReverifyAllowed(e) + retryVerification(e.cause, e, ltx, verificationSupport) + } + return ltx + } + + private fun checkReverifyAllowed(ex: Throwable) { + // If that transaction was created with and after Corda 4 then just fail. + // The lenient dependency verification is only supported for Corda 3 transactions. + // To detect if the transaction was created before Corda 4 we check if the transaction has the NetworkParameters component group. + if (networkParametersHash != null) { + log.warn("TRANSACTION VERIFY FAILED - No attempt to auto-repair as TX is Corda 4+") + throw ex + } + } + + private fun retryVerification(cause: Throwable?, ex: Throwable, ltx: LedgerTransaction, verificationSupport: VerificationSupport) { + when (cause) { + is MissingSerializerException -> { + log.warn("Missing serializers: typeDescriptor={}, typeNames={}", cause.typeDescriptor ?: "", cause.typeNames) + reverifyWithFixups(ltx, verificationSupport, null) + } + is NotSerializableException -> { + val underlying = cause.cause + if (underlying is ClassNotFoundException) { + val missingClass = underlying.message?.replace('.', '/') ?: throw ex + log.warn("Transaction {} has missing class: {}", ltx.id, missingClass) + reverifyWithFixups(ltx, verificationSupport, missingClass) + } else { + throw ex + } + } + else -> throw ex + } + } + + // Transactions created before Corda 4 can be missing dependencies on other CorDapps. + // This code has detected a missing custom serializer - probably located inside a workflow CorDapp. + // We need to extract this CorDapp from AttachmentStorage and try verifying this transaction again. + private fun reverifyWithFixups(ltx: LedgerTransaction, verificationSupport: VerificationSupport, missingClass: String?) { + log.warn("""Detected that transaction $id does not contain all cordapp dependencies. + |This may be the result of a bug in a previous version of Corda. + |Attempting to re-verify having applied this node's fix-up rules. + |Please check with the originator that this is a valid transaction.""".trimMargin()) + + val replacementAttachments = computeReplacementAttachments(ltx, verificationSupport, missingClass) + log.warn("Reverifying transaction {} with attachments:{}", ltx.id, replacementAttachments) + ltx.verifyInternal(replacementAttachments.toList()) + } + + private fun computeReplacementAttachments(ltx: LedgerTransaction, + verificationSupport: VerificationSupport, + missingClass: String?): Collection { + val replacements = fixupAttachments(verificationSupport, ltx.attachments) + if (!replacements.equivalent(ltx.attachments)) { + return replacements + } + + // We cannot continue unless we have some idea which class is missing from the attachments. + if (missingClass == null) { + throw TransactionVerificationException.BrokenTransactionException( + txId = ltx.id, + message = "No fix-up rules provided for broken attachments: $replacements" + ) + } + + /* + * The Node's fix-up rules have not been able to adjust the transaction's attachments, + * so resort to the original mechanism of trying to find an attachment that contains + * the missing class. + */ + val extraAttachment = requireNotNull(verificationSupport.getTrustedClassAttachments(missingClass).firstOrNull()) { + """Transaction $ltx is incorrectly formed. Most likely it was created during version 3 of Corda + |when the verification logic was more lenient. Attempted to find local dependency for class: $missingClass, + |but could not find one. + |If you wish to verify this transaction, please contact the originator of the transaction and install the + |provided missing JAR. + |You can install it using the RPC command: `uploadAttachment` without restarting the node. + |""".trimMargin() + } + + return replacements.toMutableSet().apply { + /* + * Check our transaction doesn't already contain this extra attachment. + * It seems unlikely that we would, but better safe than sorry! + */ + if (!add(extraAttachment)) { + throw TransactionVerificationException.BrokenTransactionException( + txId = ltx.id, + message = "Unlinkable class $missingClass inside broken attachments: $replacements" + ) + } + + log.warn("""Detected that transaction $ltx does not contain all cordapp dependencies. + |This may be the result of a bug in a previous version of Corda. + |Attempting to verify using the additional trusted dependency: $extraAttachment for class $missingClass. + |Please check with the originator that this is a valid transaction. + |YOU ARE ONLY SEEING THIS MESSAGE BECAUSE THE CORDAPPS THAT CREATED THIS TRANSACTION ARE BROKEN! + |WE HAVE TRIED TO REPAIR THE TRANSACTION AS BEST WE CAN, BUT CANNOT GUARANTEE WE HAVE SUCCEEDED! + |PLEASE FIX THE CORDAPPS AND MIGRATE THESE BROKEN TRANSACTIONS AS SOON AS POSSIBLE! + |THIS MESSAGE IS **SUPPOSED** TO BE SCARY!! + |""".trimMargin() + ) + } + } + + /** + * Apply this node's attachment fix-up rules to the given attachments. + * + * @param attachments A collection of [Attachment] objects, e.g. as provided by a transaction. + * @return The [attachments] with the node's fix-up rules applied. + */ + private fun fixupAttachments(verificationSupport: VerificationSupport, attachments: Collection): Collection { + val attachmentsById = attachments.associateByTo(LinkedHashMap(), Attachment::id) + val replacementIds = verificationSupport.fixupAttachmentIds(attachmentsById.keys) + attachmentsById.keys.retainAll(replacementIds) + val extraIds = replacementIds - attachmentsById.keys + val extraAttachments = verificationSupport.getAttachments(extraIds) + for ((index, extraId) in extraIds.withIndex()) { + val extraAttachment = extraAttachments[index] + if (extraAttachment == null || !extraAttachment.isUploaderTrusted()) { + throw MissingAttachmentsException(listOf(extraId)) + } + attachmentsById[extraId] = extraAttachment + } + return attachmentsById.values + } + override fun toString(): String { - val buf = StringBuilder() - buf.appendln("Transaction:") + val buf = StringBuilder(1024) + buf.appendLine("Transaction $id:") for (reference in references) { val emoji = Emoji.rightArrow - buf.appendln("${emoji}REFS: $reference") + buf.appendLine("${emoji}REFS: $reference") } for (input in inputs) { val emoji = Emoji.rightArrow - buf.appendln("${emoji}INPUT: $input") + buf.appendLine("${emoji}INPUT: $input") } for ((data) in outputs) { val emoji = Emoji.leftArrow - buf.appendln("${emoji}OUTPUT: $data") + buf.appendLine("${emoji}OUTPUT: $data") } for (command in commands) { val emoji = Emoji.diamond - buf.appendln("${emoji}COMMAND: $command") + buf.appendLine("${emoji}COMMAND: $command") } - for (attachment in attachments) { + for (attachment in nonLegacyAttachments) { val emoji = Emoji.paperclip - buf.appendln("${emoji}ATTACHMENT: $attachment") + buf.appendLine("${emoji}ATTACHMENT: $attachment") + } + for (attachment in legacyAttachments) { + val emoji = Emoji.paperclip + buf.appendLine("${emoji}ATTACHMENT: $attachment (legacy)") } if (networkParametersHash != null) { - buf.appendln("PARAMETERS HASH: $networkParametersHash") + val emoji = Emoji.newspaper + buf.appendLine("${emoji}NETWORK PARAMS: $networkParametersHash") } return buf.toString() } - override fun equals(other: Any?): Boolean { - if (other is WireTransaction) { - return (this.id == other.id) - } - return false - } + override fun equals(other: Any?): Boolean = other is WireTransaction && this.id == other.id override fun hashCode(): Int = id.hashCode() + + private companion object { + private val log = contextLogger() + } } /** diff --git a/core/src/main/kotlin/net/corda/core/utilities/ProgressTracker.kt b/core/src/main/kotlin/net/corda/core/utilities/ProgressTracker.kt index 5532ba1f61..0cd5f284a0 100644 --- a/core/src/main/kotlin/net/corda/core/utilities/ProgressTracker.kt +++ b/core/src/main/kotlin/net/corda/core/utilities/ProgressTracker.kt @@ -5,8 +5,9 @@ import net.corda.core.internal.warnOnce import net.corda.core.serialization.CordaSerializable import rx.Observable import rx.Subscription +import rx.functions.Action1 import rx.subjects.ReplaySubject -import java.util.* +import java.io.Serializable /** * A progress tracker helps surface information about the progress of an operation to a user interface or API of some @@ -32,11 +33,13 @@ import java.util.* */ @CordaSerializable class ProgressTracker(vararg inputSteps: Step) { - private companion object { private val log = contextLogger() } + @FunctionalInterface + private interface SerializableAction1 : Action1, Serializable + @CordaSerializable sealed class Change(val progressTracker: ProgressTracker) { data class Position(val tracker: ProgressTracker, val newStep: Step) : Change(tracker) { @@ -57,7 +60,11 @@ class ProgressTracker(vararg inputSteps: Step) { */ @CordaSerializable open class Step(open val label: String) { - private fun definitionLocation(): String = Exception().stackTrace.first { it.className != ProgressTracker.Step::class.java.name }.let { "${it.className}:${it.lineNumber}" } + private fun definitionLocation(): String { + return Exception().stackTrace + .first { it.className != Step::class.java.name } + .let { "${it.className}:${it.lineNumber}" } + } // Required when Steps with the same name are defined in multiple places. private val discriminator: String = definitionLocation() @@ -145,10 +152,17 @@ class ProgressTracker(vararg inputSteps: Step) { stepIndex = index _changes.onNext(Change.Position(this, steps[index])) recalculateStepsTreeIndex() - curChangeSubscription = currentStep.changes.subscribe({ - _changes.onNext(it) - if (it is Change.Structural || it is Change.Rendering) rebuildStepsTree() else recalculateStepsTreeIndex() - }, { _changes.onError(it) }) + curChangeSubscription = currentStep.changes.subscribe( + object : SerializableAction1 { + override fun call(c: Change) { + _changes.onNext(c) + if (c is Change.Structural || c is Change.Rendering) rebuildStepsTree() else recalculateStepsTreeIndex() + } + }, + object : SerializableAction1 { + override fun call(t: Throwable) = _changes.onError(t) + } + ) if (currentStep == DONE) { _changes.onCompleted() @@ -178,9 +192,7 @@ class ProgressTracker(vararg inputSteps: Step) { * The zero-based index of the current step in the [steps] array (i.e. with UNSTARTED and DONE) */ var stepIndex: Int = 0 - private set(value) { - field = value - } + private set /** * The zero-bases index of the current step in a [allStepsLabels] list @@ -202,18 +214,25 @@ class ProgressTracker(vararg inputSteps: Step) { fun getChildProgressTracker(step: Step): ProgressTracker? = childProgressTrackers[step]?.tracker - fun setChildProgressTracker(step: ProgressTracker.Step, childProgressTracker: ProgressTracker) { - val subscription = childProgressTracker.changes.subscribe({ - _changes.onNext(it) - if (it is Change.Structural || it is Change.Rendering) rebuildStepsTree() else recalculateStepsTreeIndex() - }, { _changes.onError(it) }) + fun setChildProgressTracker(step: Step, childProgressTracker: ProgressTracker) { + val subscription = childProgressTracker.changes.subscribe( + object : SerializableAction1 { + override fun call(c: Change) { + _changes.onNext(c) + if (c is Change.Structural || c is Change.Rendering) rebuildStepsTree() else recalculateStepsTreeIndex() + } + }, + object : SerializableAction1 { + override fun call(t: Throwable) = _changes.onError(t) + } + ) childProgressTrackers[step] = Child(childProgressTracker, subscription) childProgressTracker.parent = this _changes.onNext(Change.Structural(this, step)) rebuildStepsTree() } - private fun removeChildProgressTracker(step: ProgressTracker.Step) { + private fun removeChildProgressTracker(step: Step) { childProgressTrackers.remove(step)?.let { it.tracker.parent = null it.subscription?.unsubscribe() @@ -332,5 +351,6 @@ class ProgressTracker(vararg inputSteps: Step) { */ val hasEnded: Boolean get() = _changes.hasCompleted() || _changes.hasThrowable() } + // TODO: Expose the concept of errors. // TODO: It'd be helpful if this class was at least partly thread safe. diff --git a/core/src/main/kotlin/net/corda/core/utilities/SgxSupport.kt b/core/src/main/kotlin/net/corda/core/utilities/SgxSupport.kt deleted file mode 100644 index b4691cb1e0..0000000000 --- a/core/src/main/kotlin/net/corda/core/utilities/SgxSupport.kt +++ /dev/null @@ -1,8 +0,0 @@ -package net.corda.core.utilities - -object SgxSupport { - @JvmStatic - val isInsideEnclave: Boolean by lazy { - (System.getProperty("os.name") == "Linux") && (System.getProperty("java.vm.name") == "Avian (Corda)") - } -} diff --git a/core/src/main/kotlin/net/corda/core/utilities/Try.kt b/core/src/main/kotlin/net/corda/core/utilities/Try.kt index f492f9af8f..314ac5a38d 100644 --- a/core/src/main/kotlin/net/corda/core/utilities/Try.kt +++ b/core/src/main/kotlin/net/corda/core/utilities/Try.kt @@ -60,12 +60,13 @@ sealed class Try { * Maps the given function to the values from this [Success] and [other], or returns `this` if this is a [Failure] * or [other] if [other] is a [Failure]. */ + @Suppress("UNCHECKED_CAST") inline fun combine(other: Try, function: (A, B) -> C): Try = when (this) { is Success -> when (other) { is Success -> Success(function(value, other.value)) - is Failure -> uncheckedCast(other) + is Failure -> other as Try } - is Failure -> uncheckedCast(this) + is Failure -> this as Try } /** Applies the given action to the value if [Success], or does nothing if [Failure]. Returns `this` for chaining. */ diff --git a/core/src/obfuscator/kotlin/net/corda/core/internal/utilities/TestResourceWriter.kt b/core/src/obfuscator/kotlin/net/corda/core/internal/utilities/TestResourceWriter.kt index a0ba712730..683217f6ba 100644 --- a/core/src/obfuscator/kotlin/net/corda/core/internal/utilities/TestResourceWriter.kt +++ b/core/src/obfuscator/kotlin/net/corda/core/internal/utilities/TestResourceWriter.kt @@ -6,6 +6,7 @@ import java.nio.file.Files import java.nio.file.Paths import java.util.zip.ZipEntry import java.util.zip.ZipOutputStream +import kotlin.io.path.Path object TestResourceWriter { @@ -18,13 +19,13 @@ object TestResourceWriter { @JvmStatic @Suppress("NestedBlockDepth", "MagicNumber") fun main(vararg args : String) { - for(arg in args) { + for (arg in args) { /** * Download zip bombs */ for(url in externalZipBombUrls) { url.openStream().use { inputStream -> - val destination = Paths.get(arg).resolve(Paths.get(url.path + ".xor").fileName) + val destination = Path(arg).resolve(Paths.get("${url.path}.xor").fileName) Files.newOutputStream(destination).buffered().let(::XorOutputStream).use { outputStream -> inputStream.copyTo(outputStream) } diff --git a/core/src/test/java/net/corda/core/internal/X509EdDSAEngineTest.java b/core/src/test/java/net/corda/core/internal/X509EdDSAEngineTest.java deleted file mode 100644 index d5d458c97f..0000000000 --- a/core/src/test/java/net/corda/core/internal/X509EdDSAEngineTest.java +++ /dev/null @@ -1,133 +0,0 @@ -package net.corda.core.internal; - -import net.corda.core.crypto.Crypto; -import net.i2p.crypto.eddsa.EdDSAEngine; -import net.i2p.crypto.eddsa.EdDSAPublicKey; -import org.junit.Test; -import sun.security.util.BitArray; -import sun.security.util.ObjectIdentifier; -import sun.security.x509.AlgorithmId; -import sun.security.x509.X509Key; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.KeyPair; -import java.security.SignatureException; -import java.util.Random; - -import static org.junit.Assert.assertTrue; - -/** - * JDK11 upgrade: rewritten in Java to gain access to private internal JDK classes via module directives (not available to Kotlin compiler): - * import sun.security.util.BitArray; - * import sun.security.util.ObjectIdentifier; - * import sun.security.x509.AlgorithmId; - * import sun.security.x509.X509Key; - */ -public class X509EdDSAEngineTest { - - private static long SEED = 20170920L; - private static int TEST_DATA_SIZE = 2000; - - // offset into an EdDSA header indicating where the key header and actual key start - // in the underlying byte array - private static int keyHeaderStart = 9; - private static int keyStart = 12; - - private X509Key toX509Key(EdDSAPublicKey publicKey) throws IOException, InvalidKeyException { - byte[] internals = publicKey.getEncoded(); - - // key size in the header includes the count unused bits at the end of the key - // [keyHeaderStart + 2] but NOT the key header ID [keyHeaderStart] so the - // actual length of the key blob is size - 1 - int keySize = (internals[keyHeaderStart + 1]) - 1; - - byte[] key = new byte[keySize]; - System.arraycopy(internals, keyStart, key, 0, keySize); - - // 1.3.101.102 is the EdDSA OID - return new TestX509Key(new AlgorithmId(new ObjectIdentifier("1.3.101.112")), new BitArray(keySize * 8, key)); - } - - class TestX509Key extends X509Key { - TestX509Key(AlgorithmId algorithmId, BitArray key) throws InvalidKeyException { - this.algid = algorithmId; - this.setKey(key); - this.encode(); - } - } - - /** - * Put the X509EdDSA engine through basic tests to verify that the functions are hooked up correctly. - */ - @Test - public void SignAndVerify() throws InvalidKeyException, SignatureException { - X509EdDSAEngine engine = new X509EdDSAEngine(); - KeyPair keyPair = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger.valueOf(SEED)); - EdDSAPublicKey publicKey = (EdDSAPublicKey) keyPair.getPublic(); - byte[] randomBytes = new byte[TEST_DATA_SIZE]; - new Random(SEED).nextBytes(randomBytes); - engine.initSign(keyPair.getPrivate()); - engine.update(randomBytes[0]); - engine.update(randomBytes, 1, randomBytes.length - 1); - - // Now verify the signature - byte[] signature = engine.sign(); - - engine.initVerify(publicKey); - engine.update(randomBytes); - assertTrue(engine.verify(signature)); - } - - /** - * Verify that signing with an X509Key wrapped EdDSA key works. - */ - @Test - public void SignAndVerifyWithX509Key() throws InvalidKeyException, SignatureException, IOException { - X509EdDSAEngine engine = new X509EdDSAEngine(); - KeyPair keyPair = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger.valueOf(SEED + 1)); - X509Key publicKey = toX509Key((EdDSAPublicKey) keyPair.getPublic()); - byte[] randomBytes = new byte[TEST_DATA_SIZE]; - new Random(SEED + 1).nextBytes(randomBytes); - engine.initSign(keyPair.getPrivate()); - engine.update(randomBytes[0]); - engine.update(randomBytes, 1, randomBytes.length - 1); - - // Now verify the signature - byte[] signature = engine.sign(); - - engine.initVerify(publicKey); - engine.update(randomBytes); - assertTrue(engine.verify(signature)); - } - - /** - * Verify that signing with an X509Key wrapped EdDSA key succeeds when using the underlying EdDSAEngine. - */ - @Test - public void SignAndVerifyWithX509KeyAndOldEngineFails() throws InvalidKeyException, SignatureException, IOException { - X509EdDSAEngine engine = new X509EdDSAEngine(); - KeyPair keyPair = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger.valueOf(SEED + 1)); - X509Key publicKey = toX509Key((EdDSAPublicKey) keyPair.getPublic()); - byte[] randomBytes = new byte[TEST_DATA_SIZE]; - new Random(SEED + 1).nextBytes(randomBytes); - engine.initSign(keyPair.getPrivate()); - engine.update(randomBytes[0]); - engine.update(randomBytes, 1, randomBytes.length - 1); - - // Now verify the signature - byte[] signature = engine.sign(); - engine.initVerify(publicKey); - engine.update(randomBytes); - engine.verify(signature); - } - - /** Verify will fail if the input public key cannot be converted to EdDSA public key. */ - @Test(expected = InvalidKeyException.class) - public void verifyWithNonSupportedKeyTypeFails() throws InvalidKeyException { - EdDSAEngine engine = new EdDSAEngine(); - KeyPair keyPair = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, BigInteger.valueOf(SEED)); - engine.initVerify(keyPair.getPublic()); - } -} diff --git a/core/src/test/kotlin/net/corda/core/concurrent/ConcurrencyUtilsTest.kt b/core/src/test/kotlin/net/corda/core/concurrent/ConcurrencyUtilsTest.kt index 491e530e39..59c790f8a8 100644 --- a/core/src/test/kotlin/net/corda/core/concurrent/ConcurrencyUtilsTest.kt +++ b/core/src/test/kotlin/net/corda/core/concurrent/ConcurrencyUtilsTest.kt @@ -1,6 +1,6 @@ package net.corda.core.concurrent -import com.nhaarman.mockito_kotlin.* +import org.mockito.kotlin.* import net.corda.core.internal.concurrent.openFuture import net.corda.core.utilities.getOrThrow import org.assertj.core.api.Assertions.assertThatThrownBy @@ -34,7 +34,7 @@ class ConcurrencyUtilsTest { val throwable = EOFException("log me") f2.setException(throwable) assertEquals(1, invocations) // Least astonishing to skip handler side-effects. - verify(log).error(eq(shortCircuitedTaskFailedMessage), same(throwable)) + verify(log).error(eq("Short-circuited task failed:"), same(throwable)) verifyNoMoreInteractions(log) } @@ -68,7 +68,7 @@ class ConcurrencyUtilsTest { f1.set(100) assertEquals(100, g.getOrThrow()) assertEquals(1, invocations) // Handler didn't run as g was already done. - verify(log).error(eq(shortCircuitedTaskFailedMessage), same(nonCancel)) + verify(log).error(eq("Short-circuited task failed:"), same(nonCancel)) verifyNoMoreInteractions(log) assertThatThrownBy { f2.getOrThrow() }.isSameAs(nonCancel) } @@ -98,7 +98,7 @@ class ConcurrencyUtilsTest { }, failures::add) }.isSameAs(x) assertEquals(listOf(100), successes) - assertEquals(emptyList(), failures) + assertEquals(emptyList(), failures) } @Test(timeout=300_000) @@ -109,12 +109,12 @@ class ConcurrencyUtilsTest { val failures = mutableListOf() val x = Throwable() assertThatThrownBy { - f.match(successes::add, { + f.match(successes::add) { failures.add(it) throw x - }) + } }.isSameAs(x) - assertEquals(emptyList(), successes) + assertEquals(emptyList(), successes) assertEquals(listOf(e), failures) } } diff --git a/core/src/test/kotlin/net/corda/core/contracts/StructuresTests.kt b/core/src/test/kotlin/net/corda/core/contracts/StructuresTests.kt index 74b42fad56..c6b4f20317 100644 --- a/core/src/test/kotlin/net/corda/core/contracts/StructuresTests.kt +++ b/core/src/test/kotlin/net/corda/core/contracts/StructuresTests.kt @@ -1,23 +1,25 @@ package net.corda.core.contracts -import com.nhaarman.mockito_kotlin.doAnswer -import com.nhaarman.mockito_kotlin.spy -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.identity.Party import org.junit.Test +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.spy +import org.mockito.kotlin.whenever import java.io.ByteArrayOutputStream import java.io.IOException -import java.util.* +import java.util.UUID import java.util.jar.JarFile.MANIFEST_NAME import java.util.zip.ZipEntry import java.util.zip.ZipOutputStream import kotlin.test.assertEquals import kotlin.test.assertNotEquals +import kotlin.test.assertTrue import kotlin.test.fail class AttachmentTest { @Test(timeout=300_000) + @Suppress("ThrowsCount") fun `openAsJAR does not leak file handle if attachment has corrupted manifest`() { var closeCalls = 0 val inputStream = spy(ByteArrayOutputStream().apply { @@ -32,6 +34,7 @@ class AttachmentTest { override val id get() = throw UnsupportedOperationException() override fun open() = inputStream override val signerKeys get() = throw UnsupportedOperationException() + @Suppress("OVERRIDE_DEPRECATION") override val signers: List get() = throw UnsupportedOperationException() override val size: Int = 512 } @@ -39,7 +42,7 @@ class AttachmentTest { attachment.openAsJAR() fail("Expected line too long.") } catch (e: IOException) { - assertEquals("line too long", e.message) + assertTrue { e.message!!.contains("line too long") } } assertEquals(1, closeCalls) } @@ -74,4 +77,4 @@ class UniqueIdentifierTests { assertEquals(ids[1], ids[2]) assertEquals(ids[1].hashCode(), ids[2].hashCode()) } -} \ No newline at end of file +} diff --git a/core/src/test/kotlin/net/corda/core/crypto/CryptoUtilsTest.kt b/core/src/test/kotlin/net/corda/core/crypto/CryptoUtilsTest.kt index dc36d3d729..06b2e711a3 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/CryptoUtilsTest.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/CryptoUtilsTest.kt @@ -5,36 +5,31 @@ import net.corda.core.crypto.Crypto.ECDSA_SECP256K1_SHA256 import net.corda.core.crypto.Crypto.ECDSA_SECP256R1_SHA256 import net.corda.core.crypto.Crypto.EDDSA_ED25519_SHA512 import net.corda.core.crypto.Crypto.RSA_SHA256 -import net.corda.core.crypto.Crypto.SPHINCS256_SHA256 import net.corda.core.crypto.internal.PlatformSecureRandomService import net.corda.core.utilities.OpaqueBytes -import net.i2p.crypto.eddsa.EdDSAKey -import net.i2p.crypto.eddsa.EdDSAPrivateKey -import net.i2p.crypto.eddsa.EdDSAPublicKey -import net.i2p.crypto.eddsa.math.GroupElement -import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec -import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable -import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec import org.apache.commons.lang3.ArrayUtils.EMPTY_BYTE_ARRAY -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException +import org.assertj.core.api.Assertions.assertThatThrownBy import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey import org.bouncycastle.jce.ECNamedCurveTable import org.bouncycastle.jce.interfaces.ECKey import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec -import org.bouncycastle.operator.ContentSigner -import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey -import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey import org.junit.Assert.assertNotEquals -import org.junit.Assume import org.junit.Test import java.math.BigInteger import java.security.KeyPairGenerator import java.security.SecureRandom import java.security.Security -import java.util.* -import kotlin.test.* +import java.security.interfaces.EdECPrivateKey +import java.security.interfaces.EdECPublicKey +import java.security.spec.NamedParameterSpec +import java.util.Random +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertTrue +import kotlin.test.fail /** * Run tests for cryptographic algorithms. @@ -54,21 +49,18 @@ class CryptoUtilsTest { val ecdsaKKeyPair = Crypto.generateKeyPair(ECDSA_SECP256K1_SHA256) val ecdsaRKeyPair = Crypto.generateKeyPair(ECDSA_SECP256R1_SHA256) val eddsaKeyPair = Crypto.generateKeyPair(EDDSA_ED25519_SHA512) - val sphincsKeyPair = Crypto.generateKeyPair(SPHINCS256_SHA256) // not null private keys assertNotNull(rsaKeyPair.private) assertNotNull(ecdsaKKeyPair.private) assertNotNull(ecdsaRKeyPair.private) assertNotNull(eddsaKeyPair.private) - assertNotNull(sphincsKeyPair.private) // not null public keys assertNotNull(rsaKeyPair.public) assertNotNull(ecdsaKKeyPair.public) assertNotNull(ecdsaRKeyPair.public) assertNotNull(eddsaKeyPair.public) - assertNotNull(sphincsKeyPair.public) // fail on unsupported algorithm try { @@ -128,11 +120,8 @@ class CryptoUtilsTest { // test on malformed signatures (even if they change for 1 bit) signedData[0] = signedData[0].inc() - try { + assertThatThrownBy { Crypto.doVerify(pubKey, signedData, testBytes) - fail() - } catch (e: Exception) { - // expected } } @@ -301,66 +290,11 @@ class CryptoUtilsTest { } } - @Test(timeout=300_000) - fun `SPHINCS-256 full process keygen-sign-verify`() { - val keyPair = Crypto.generateKeyPair(SPHINCS256_SHA256) - val (privKey, pubKey) = keyPair - // test for some data - val signedData = Crypto.doSign(privKey, testBytes) - val verification = Crypto.doVerify(pubKey, signedData, testBytes) - assertTrue(verification) - - // test for empty data signing - try { - Crypto.doSign(privKey, EMPTY_BYTE_ARRAY) - fail() - } catch (e: Exception) { - // expected - } - - // test for empty source data when verifying - try { - Crypto.doVerify(pubKey, testBytes, EMPTY_BYTE_ARRAY) - fail() - } catch (e: Exception) { - // expected - } - - // test for empty signed data when verifying - try { - Crypto.doVerify(pubKey, EMPTY_BYTE_ARRAY, testBytes) - fail() - } catch (e: Exception) { - // expected - } - - // test for zero bytes data - val signedDataZeros = Crypto.doSign(privKey, test100ZeroBytes) - val verificationZeros = Crypto.doVerify(pubKey, signedDataZeros, test100ZeroBytes) - assertTrue(verificationZeros) - - // test for 1MB of data (I successfully tested it locally for 1GB as well) - val MBbyte = ByteArray(1000000) // 1.000.000 - Random().nextBytes(MBbyte) - val signedDataBig = Crypto.doSign(privKey, MBbyte) - val verificationBig = Crypto.doVerify(pubKey, signedDataBig, MBbyte) - assertTrue(verificationBig) - - // test on malformed signatures (even if they change for 1 bit) - signedData[0] = signedData[0].inc() - try { - Crypto.doVerify(pubKey, signedData, testBytes) - fail() - } catch (e: Exception) { - // expected - } - } - // test list of supported algorithms @Test(timeout=300_000) fun `Check supported algorithms`() { val algList: List = Crypto.supportedSignatureSchemes().map { it.schemeCodeName } - val expectedAlgSet = setOf("RSA_SHA256", "ECDSA_SECP256K1_SHA256", "ECDSA_SECP256R1_SHA256", "EDDSA_ED25519_SHA512", "SPHINCS-256_SHA512", "COMPOSITE") + val expectedAlgSet = setOf("RSA_SHA256", "ECDSA_SECP256K1_SHA256", "ECDSA_SECP256R1_SHA256", "EDDSA_ED25519_SHA512", "COMPOSITE") assertTrue { Sets.symmetricDifference(expectedAlgSet, algList.toSet()).isEmpty(); } } @@ -425,36 +359,6 @@ class CryptoUtilsTest { assertEquals(pubKey2, pubKey) } - @Test(timeout=300_000) - fun `SPHINCS-256 encode decode keys - required for serialization`() { - // Generate key pair. - val keyPair = Crypto.generateKeyPair(SPHINCS256_SHA256) - val privKey: BCSphincs256PrivateKey = keyPair.private as BCSphincs256PrivateKey - val pubKey: BCSphincs256PublicKey = keyPair.public as BCSphincs256PublicKey - - //1st method for encoding/decoding - val privKey2 = Crypto.decodePrivateKey(privKey.encoded) - assertEquals(privKey2, privKey) - - // Encode and decode public key. - val pubKey2 = Crypto.decodePublicKey(pubKey.encoded) - assertEquals(pubKey2, pubKey) - - //2nd method for encoding/decoding - - // Encode and decode private key. - val privKeyInfo: PrivateKeyInfo = PrivateKeyInfo.getInstance(privKey.encoded) - val decodedPrivKey = BCSphincs256PrivateKey(privKeyInfo) - // Check that decoded private key is equal to the initial one. - assertEquals(decodedPrivKey, privKey) - - // Encode and decode public key. - val pubKeyInfo: SubjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(pubKey.encoded) - val decodedPubKey = BCSphincs256PublicKey(pubKeyInfo) - // Check that decoded private key is equal to the initial one. - assertEquals(decodedPubKey, pubKey) - } - @Test(timeout=300_000) fun `RSA scheme finder by key type`() { val keyPairRSA = Crypto.generateKeyPair(RSA_SHA256) @@ -493,18 +397,10 @@ class CryptoUtilsTest { val keyPairEd = Crypto.generateKeyPair(EDDSA_ED25519_SHA512) val (privEd, pubEd) = keyPairEd - assertEquals(privEd.algorithm, "EdDSA") - assertEquals((privEd as EdDSAKey).params, EdDSANamedCurveTable.getByName("ED25519")) - assertEquals(pubEd.algorithm, "EdDSA") - assertEquals((pubEd as EdDSAKey).params, EdDSANamedCurveTable.getByName("ED25519")) - } - - @Test(timeout=300_000) - fun `SPHINCS-256 scheme finder by key type`() { - val keyPairSP = Crypto.generateKeyPair(SPHINCS256_SHA256) - val (privSP, pubSP) = keyPairSP - assertEquals(privSP.algorithm, "SPHINCS-256") - assertEquals(pubSP.algorithm, "SPHINCS-256") + assertEquals(privEd.algorithm, "Ed25519") + assertEquals((privEd as EdECPrivateKey).params.name, NamedParameterSpec.ED25519.name) + assertEquals(pubEd.algorithm, "Ed25519") + assertEquals((pubEd as EdECPublicKey).params.name, NamedParameterSpec.ED25519.name) } @Test(timeout=300_000) @@ -515,11 +411,11 @@ class CryptoUtilsTest { val encodedPubEd = pubEd.encoded val decodedPrivEd = Crypto.decodePrivateKey(encodedPrivEd) - assertEquals(decodedPrivEd.algorithm, "EdDSA") + assertEquals(decodedPrivEd.algorithm, "Ed25519") assertEquals(decodedPrivEd, privEd) val decodedPubEd = Crypto.decodePublicKey(encodedPubEd) - assertEquals(decodedPubEd.algorithm, "EdDSA") + assertEquals(decodedPubEd.algorithm, "Ed25519") assertEquals(decodedPubEd, pubEd) } @@ -571,22 +467,6 @@ class CryptoUtilsTest { assertEquals(decodedPubRSA, pubRSA) } - @Test(timeout=300_000) - fun `Automatic SPHINCS-256 key-type detection and decoding`() { - val keyPairSP = Crypto.generateKeyPair(SPHINCS256_SHA256) - val (privSP, pubSP) = keyPairSP - val encodedPrivSP = privSP.encoded - val encodedPubSP = pubSP.encoded - - val decodedPrivSP = Crypto.decodePrivateKey(encodedPrivSP) - assertEquals(decodedPrivSP.algorithm, "SPHINCS-256") - assertEquals(decodedPrivSP, privSP) - - val decodedPubSP = Crypto.decodePublicKey(encodedPubSP) - assertEquals(decodedPubSP.algorithm, "SPHINCS-256") - assertEquals(decodedPubSP, pubSP) - } - @Test(timeout=300_000) fun `Failure test between K1 and R1 keys`() { val keyPairK1 = Crypto.generateKeyPair(ECDSA_SECP256K1_SHA256) @@ -629,7 +509,7 @@ class CryptoUtilsTest { val encodedPrivK1 = privK1.encoded // fail on malformed key. - for (i in 0 until encodedPrivK1.size) { + for (i in encodedPrivK1.indices) { val b = encodedPrivK1[i] encodedPrivK1[i] = b.inc() try { @@ -655,24 +535,25 @@ class CryptoUtilsTest { @Test(timeout=300_000) fun `Check EdDSA public key on curve`() { - val keyPairEdDSA = Crypto.generateKeyPair(EDDSA_ED25519_SHA512) - val pubEdDSA = keyPairEdDSA.public - assertTrue(Crypto.publicKeyOnCurve(EDDSA_ED25519_SHA512, pubEdDSA)) - // Use R1 curve for check. - assertFalse(Crypto.publicKeyOnCurve(ECDSA_SECP256R1_SHA256, pubEdDSA)) - // Check for point at infinity. - val pubKeySpec = EdDSAPublicKeySpec((EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec).curve.getZero(GroupElement.Representation.P3), EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec) - assertFalse(Crypto.publicKeyOnCurve(EDDSA_ED25519_SHA512, EdDSAPublicKey(pubKeySpec))) + repeat(100) { + val keyPairEdDSA = Crypto.generateKeyPair(EDDSA_ED25519_SHA512) + val pubEdDSA = keyPairEdDSA.public + assertTrue(Crypto.publicKeyOnCurve(EDDSA_ED25519_SHA512, pubEdDSA)) + // Use R1 curve for check. + assertFalse(Crypto.publicKeyOnCurve(ECDSA_SECP256R1_SHA256, pubEdDSA)) + } } - @Test(expected = IllegalArgumentException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `Unsupported EC public key type on curve`() { val keyGen = KeyPairGenerator.getInstance("EC") // sun.security.ec.ECPublicKeyImpl keyGen.initialize(256, newSecureRandom()) val pairSun = keyGen.generateKeyPair() val pubSun = pairSun.public // Should fail as pubSun is not a BCECPublicKey. - Crypto.publicKeyOnCurve(ECDSA_SECP256R1_SHA256, pubSun) + assertThatIllegalArgumentException().isThrownBy { + Crypto.publicKeyOnCurve(ECDSA_SECP256R1_SHA256, pubSun) + } } @Test(timeout=300_000) @@ -765,10 +646,8 @@ class CryptoUtilsTest { // Check scheme. assertEquals(priv.algorithm, dpriv.algorithm) assertEquals(pub.algorithm, dpub.algorithm) - assertTrue(dpriv is EdDSAPrivateKey) - assertTrue(dpub is EdDSAPublicKey) - assertEquals((dpriv as EdDSAKey).params, EdDSANamedCurveTable.getByName("ED25519")) - assertEquals((dpub as EdDSAKey).params, EdDSANamedCurveTable.getByName("ED25519")) + assertEquals((dpriv as EdECPrivateKey).params.name, NamedParameterSpec.ED25519.name) + assertEquals((dpub as EdECPublicKey).params.name, NamedParameterSpec.ED25519.name) assertEquals(Crypto.findSignatureScheme(dpriv), EDDSA_ED25519_SHA512) assertEquals(Crypto.findSignatureScheme(dpub), EDDSA_ED25519_SHA512) @@ -908,8 +787,8 @@ class CryptoUtilsTest { } @Test(timeout=300_000) - fun `Ensure deterministic signatures of EdDSA, SPHINCS-256 and RSA PKCS1`() { - listOf(EDDSA_ED25519_SHA512, SPHINCS256_SHA256, RSA_SHA256) + fun `Ensure deterministic signatures of EdDSA and RSA PKCS1`() { + listOf(EDDSA_ED25519_SHA512, RSA_SHA256) .forEach { testDeterministicSignatures(it) } } @@ -928,32 +807,25 @@ class CryptoUtilsTest { assertNotEquals(OpaqueBytes(signedData1stTime), OpaqueBytes(signedZeroArray1stTime)) } - fun ContentSigner.write(message: ByteArray) { - this.outputStream.write(message) - this.outputStream.close() - } - @Test(timeout=300_000) fun `test default SecureRandom uses platformSecureRandom`() { - Assume.assumeFalse(IS_OPENJ9) // See CORDA-4055 // Note than in Corda, [CordaSecurityProvider] is registered as the first provider. // Remove [CordaSecurityProvider] in case it is already registered. Security.removeProvider(CordaSecurityProvider.PROVIDER_NAME) // Try after removing CordaSecurityProvider. val secureRandomNotRegisteredCordaProvider = SecureRandom() - assertNotEquals(PlatformSecureRandomService.algorithm, secureRandomNotRegisteredCordaProvider.algorithm) + assertNotEquals(PlatformSecureRandomService.ALGORITHM, secureRandomNotRegisteredCordaProvider.algorithm) // Now register CordaSecurityProvider as last Provider. Security.addProvider(CordaSecurityProvider()) val secureRandomRegisteredLastCordaProvider = SecureRandom() - assertNotEquals(PlatformSecureRandomService.algorithm, secureRandomRegisteredLastCordaProvider.algorithm) + assertNotEquals(PlatformSecureRandomService.ALGORITHM, secureRandomRegisteredLastCordaProvider.algorithm) // Remove Corda Provider again and add it as the first Provider entry. Security.removeProvider(CordaSecurityProvider.PROVIDER_NAME) Security.insertProviderAt(CordaSecurityProvider(), 1) // This is base-1. val secureRandomRegisteredFirstCordaProvider = SecureRandom() - assertEquals(PlatformSecureRandomService.algorithm, secureRandomRegisteredFirstCordaProvider.algorithm) + assertEquals(PlatformSecureRandomService.ALGORITHM, secureRandomRegisteredFirstCordaProvider.algorithm) } - private val IS_OPENJ9 = System.getProperty("java.vm.name").toLowerCase().contains("openj9") } diff --git a/core/src/test/kotlin/net/corda/core/crypto/EdDSATests.kt b/core/src/test/kotlin/net/corda/core/crypto/EdDSATests.kt index cadb29c18a..1acac1c4e4 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/EdDSATests.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/EdDSATests.kt @@ -1,16 +1,17 @@ package net.corda.core.crypto +import net.corda.core.crypto.Crypto.EDDSA_ED25519_SHA512 +import net.corda.core.crypto.internal.Instances.withSignature import net.corda.core.utilities.hexToByteArray import net.corda.core.utilities.toHex -import net.i2p.crypto.eddsa.EdDSAPrivateKey -import net.i2p.crypto.eddsa.EdDSASecurityProvider -import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec -import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec +import org.assertj.core.api.Assertions.assertThat +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo import org.junit.Test +import java.security.KeyFactory import java.security.PrivateKey -import java.security.Signature -import kotlin.test.assertEquals -import kotlin.test.assertNotEquals +import java.security.spec.EdECPrivateKeySpec +import java.security.spec.NamedParameterSpec +import java.security.spec.X509EncodedKeySpec /** * Testing PureEdDSA Ed25519 using test vectors from https://tools.ietf.org/html/rfc8032#section-7.1 @@ -18,8 +19,6 @@ import kotlin.test.assertNotEquals class EdDSATests { @Test(timeout=300_000) fun `PureEdDSA Ed25519 test vectors`() { - val edParams = Crypto.EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec - // MESSAGE (length 0 bytes). val testVector1 = SignatureTestVector( "9d61b19deffd5a60ba844af492ec2cc4" + @@ -152,9 +151,21 @@ class EdDSATests { ) val testVectors = listOf(testVector1, testVector2, testVector3, testVector1024, testVectorSHAabc) - testVectors.forEach { - val privateKey = EdDSAPrivateKey(EdDSAPrivateKeySpec(it.privateKeyHex.hexToByteArray(), edParams)) - assertEquals(it.signatureOutputHex, doSign(privateKey, it.messageToSignHex.hexToByteArray()).toHex().toLowerCase()) + testVectors.forEach { testVector -> + val messageBytes = testVector.messageToSignHex.hexToByteArray() + val signatureBytes = testVector.signatureOutputHex.hexToByteArray() + // Check the private key produces the expected signature + val privateKey = KeyFactory.getInstance("Ed25519", "SunEC").generatePrivate(EdECPrivateKeySpec(NamedParameterSpec.ED25519, testVector.privateKeyHex.hexToByteArray())) + assertThat(doSign(privateKey, messageBytes)).isEqualTo(signatureBytes) + // Check the public key verifies the signature + val result = withSignature(EDDSA_ED25519_SHA512) { signature -> + val publicKeyInfo = SubjectPublicKeyInfo(EDDSA_ED25519_SHA512.signatureOID, testVector.publicKeyHex.hexToByteArray()) + val publicKey = EDDSA_ED25519_SHA512.keyFactory.generatePublic(X509EncodedKeySpec(publicKeyInfo.encoded)) + signature.initVerify(publicKey) + signature.update(messageBytes) + signature.verify(signatureBytes) + } + assertThat(result).isTrue() } // Test vector for the variant Ed25519ctx, expected to fail. @@ -170,8 +181,8 @@ class EdDSATests { "5a5ca2df6668346291c2043d4eb3e90d" ) - val privateKey = EdDSAPrivateKey(EdDSAPrivateKeySpec(testVectorEd25519ctx.privateKeyHex.hexToByteArray(), edParams)) - assertNotEquals(testVectorEd25519ctx.signatureOutputHex, doSign(privateKey, testVectorEd25519ctx.messageToSignHex.hexToByteArray()).toHex().toLowerCase()) + val privateKey = KeyFactory.getInstance("Ed25519", "SunEC").generatePrivate(EdECPrivateKeySpec(NamedParameterSpec.ED25519, testVectorEd25519ctx.privateKeyHex.hexToByteArray())) + assertThat(doSign(privateKey, testVectorEd25519ctx.messageToSignHex.hexToByteArray()).toHex().lowercase()).isNotEqualTo(testVectorEd25519ctx.signatureOutputHex) } /** A test vector object for digital signature schemes. */ @@ -182,9 +193,10 @@ class EdDSATests { // Required to implement a custom doSign function, because Corda's Crypto.doSign does not allow empty messages (testVector1). private fun doSign(privateKey: PrivateKey, clearData: ByteArray): ByteArray { - val signature = Signature.getInstance(Crypto.EDDSA_ED25519_SHA512.signatureName, EdDSASecurityProvider()) - signature.initSign(privateKey) - signature.update(clearData) - return signature.sign() + return withSignature(EDDSA_ED25519_SHA512) { signature -> + signature.initSign(privateKey) + signature.update(clearData) + signature.sign() + } } } diff --git a/core/src/test/kotlin/net/corda/core/crypto/SecureHashTest.kt b/core/src/test/kotlin/net/corda/core/crypto/SecureHashTest.kt index ae29915d0d..44d7a0292a 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/SecureHashTest.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/SecureHashTest.kt @@ -1,9 +1,7 @@ package net.corda.core.crypto import net.corda.core.crypto.SecureHash.Companion.SHA2_256 -import net.corda.core.internal.JavaVersion import org.assertj.core.api.Assertions.assertThat -import org.junit.Assume import org.junit.Test import org.junit.jupiter.api.assertThrows import java.lang.IllegalArgumentException @@ -29,7 +27,6 @@ class SecureHashTest { @Test(timeout = 300_000) fun `test new sha3-256 secure hash`() { - Assume.assumeTrue(JavaVersion.isVersionAtLeast(JavaVersion.Java_11)) val hash = SecureHash.hashAs("SHA3-256", byteArrayOf(0x64, -0x13, 0x42, 0x3a)) assertEquals(SecureHash.create("SHA3-256:A243D53F7273F4C92ED901A14F11B372FDF6FF69583149AFD4AFA24BF17A8880"), hash) assertEquals("SHA3-256:A243D53F7273F4C92ED901A14F11B372FDF6FF69583149AFD4AFA24BF17A8880", hash.toString()) diff --git a/core/src/test/kotlin/net/corda/core/internal/ClassLoadingUtilsTest.kt b/core/src/test/kotlin/net/corda/core/internal/ClassLoadingUtilsTest.kt index 68bd3ba625..244b449538 100644 --- a/core/src/test/kotlin/net/corda/core/internal/ClassLoadingUtilsTest.kt +++ b/core/src/test/kotlin/net/corda/core/internal/ClassLoadingUtilsTest.kt @@ -1,6 +1,6 @@ package net.corda.core.internal -import com.nhaarman.mockito_kotlin.mock +import org.mockito.kotlin.mock import net.corda.core.contracts.ContractAttachment import net.corda.core.contracts.ContractClassName import net.corda.core.crypto.SecureHash @@ -9,6 +9,7 @@ import net.corda.core.node.services.AttachmentId import net.corda.core.serialization.internal.AttachmentURLStreamHandlerFactory import net.corda.core.serialization.internal.AttachmentsClassLoader import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.Assert.assertEquals import org.junit.Assert.assertNull @@ -76,9 +77,11 @@ class ClassLoadingUtilsTest { .doesNotContain(AbstractClass::class.java.name) } - @Test(expected = IllegalArgumentException::class,timeout=300_000) + @Test(timeout=300_000) fun throwsExceptionWhenClassDoesNotContainProperConstructors() { - createInstancesOfClassesImplementing(BaseInterface::class.java.classLoader, BaseInterface2::class.java) + assertThatIllegalArgumentException().isThrownBy { + createInstancesOfClassesImplementing(BaseInterface::class.java.classLoader, BaseInterface2::class.java) + } } @Test(timeout=300_000) diff --git a/core/src/test/kotlin/net/corda/core/internal/internalAccessTestHelpers.kt b/core/src/test/kotlin/net/corda/core/internal/InternalAccessTestHelpers.kt similarity index 68% rename from core/src/test/kotlin/net/corda/core/internal/internalAccessTestHelpers.kt rename to core/src/test/kotlin/net/corda/core/internal/InternalAccessTestHelpers.kt index 16a6e6bef8..5f9e48bb2e 100644 --- a/core/src/test/kotlin/net/corda/core/internal/internalAccessTestHelpers.kt +++ b/core/src/test/kotlin/net/corda/core/internal/InternalAccessTestHelpers.kt @@ -1,9 +1,19 @@ package net.corda.core.internal -import net.corda.core.contracts.* +import net.corda.core.contracts.Attachment +import net.corda.core.contracts.CommandData +import net.corda.core.contracts.CommandWithParties +import net.corda.core.contracts.Contract +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.PrivacySalt +import net.corda.core.contracts.StateAndRef +import net.corda.core.contracts.TimeWindow +import net.corda.core.contracts.TransactionState +import net.corda.core.contracts.TransactionVerificationException import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash import net.corda.core.identity.Party +import net.corda.core.internal.verification.AbstractVerifier import net.corda.core.node.NetworkParameters import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.internal.AttachmentsClassLoaderCache @@ -40,15 +50,35 @@ fun createLedgerTransaction( isAttachmentTrusted: (Attachment) -> Boolean, attachmentsClassLoaderCache: AttachmentsClassLoaderCache, digestService: DigestService = DigestService.default -): LedgerTransaction = LedgerTransaction.create( - inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, networkParameters, references, componentGroups, serializedInputs, serializedReferences, isAttachmentTrusted, attachmentsClassLoaderCache, digestService -).specialise(::PassthroughVerifier) +): LedgerTransaction { + return LedgerTransaction.create( + inputs, + outputs, + commands, + attachments, + id, + notary, + timeWindow, + privacySalt, + networkParameters, + references, + componentGroups, + serializedInputs, + serializedReferences, + isAttachmentTrusted, + ::PassthroughVerifier, + attachmentsClassLoaderCache, + digestService + ) +} fun createContractCreationError(txId: SecureHash, contractClass: String, cause: Throwable) = TransactionVerificationException.ContractCreationError(txId, contractClass, cause) fun createContractRejection(txId: SecureHash, contract: Contract, cause: Throwable) = TransactionVerificationException.ContractRejection(txId, contract, cause) /** * Verify the [LedgerTransaction] we already have. + * + * Note, this is not secure! */ private class PassthroughVerifier(ltx: LedgerTransaction, context: SerializationContext) : AbstractVerifier(ltx, context.deserializationClassLoader) { override val transaction: Supplier diff --git a/core/src/test/kotlin/net/corda/core/internal/InternalUtilsTest.kt b/core/src/test/kotlin/net/corda/core/internal/InternalUtilsTest.kt index ac2333cabd..eccbaa5498 100644 --- a/core/src/test/kotlin/net/corda/core/internal/InternalUtilsTest.kt +++ b/core/src/test/kotlin/net/corda/core/internal/InternalUtilsTest.kt @@ -1,8 +1,8 @@ package net.corda.core.internal -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.times -import com.nhaarman.mockito_kotlin.verify +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import net.corda.core.contracts.TimeWindow import net.corda.core.crypto.SecureHash import org.assertj.core.api.Assertions.assertThat @@ -89,10 +89,10 @@ open class InternalUtilsTest { @Test(timeout=300_000) fun `Stream toTypedArray works`() { - val a: Array = Stream.of("one", "two").toTypedArray() + val a: Array = uncheckedCast(Stream.of("one", "two").toTypedArray()) assertEquals(Array::class.java, a.javaClass) assertArrayEquals(arrayOf("one", "two"), a) - val b: Array = Stream.of("one", "two", null).toTypedArray() + val b: Array = uncheckedCast(Stream.of("one", "two", null).toTypedArray()) assertEquals(Array::class.java, b.javaClass) assertArrayEquals(arrayOf("one", "two", null), b) } @@ -100,10 +100,11 @@ open class InternalUtilsTest { @Test(timeout=300_000) fun kotlinObjectInstance() { assertThat(PublicObject::class.java.kotlinObjectInstance).isSameAs(PublicObject) - assertThat(PrivateObject::class.java.kotlinObjectInstance).isSameAs(PrivateObject) assertThat(ProtectedObject::class.java.kotlinObjectInstance).isSameAs(ProtectedObject) + assertThat(PrivateObject::class.java.kotlinObjectInstance).isSameAs(PrivateObject) assertThat(TimeWindow::class.java.kotlinObjectInstance).isNull() assertThat(PrivateClass::class.java.kotlinObjectInstance).isNull() + } @Test(timeout=300_000) diff --git a/core/src/test/kotlin/net/corda/core/internal/NamedCacheTest.kt b/core/src/test/kotlin/net/corda/core/internal/NamedCacheTest.kt index 0074b209a0..1be74edce3 100644 --- a/core/src/test/kotlin/net/corda/core/internal/NamedCacheTest.kt +++ b/core/src/test/kotlin/net/corda/core/internal/NamedCacheTest.kt @@ -8,11 +8,11 @@ import org.junit.Test import kotlin.test.assertEquals class NamedCacheTest : NamedCacheFactory { - override fun buildNamed(caffeine: Caffeine, name: String): Cache { + override fun buildNamed(caffeine: Caffeine, name: String): Cache { throw IllegalStateException("Should not be called") } - override fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache { + override fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache { throw IllegalStateException("Should not be called") } diff --git a/core/src/test/kotlin/net/corda/core/internal/PathUtilsTest.kt b/core/src/test/kotlin/net/corda/core/internal/PathUtilsTest.kt index 75398c991c..53996dea7c 100644 --- a/core/src/test/kotlin/net/corda/core/internal/PathUtilsTest.kt +++ b/core/src/test/kotlin/net/corda/core/internal/PathUtilsTest.kt @@ -7,6 +7,9 @@ import org.junit.rules.TemporaryFolder import java.net.URI import java.nio.file.FileSystems import java.nio.file.Path +import kotlin.io.path.createDirectories +import kotlin.io.path.createFile +import kotlin.io.path.div class PathUtilsTest { @Rule diff --git a/core/src/test/kotlin/net/corda/core/internal/ToggleFieldTest.kt b/core/src/test/kotlin/net/corda/core/internal/ToggleFieldTest.kt index 446b41a3e5..d93fb0d772 100644 --- a/core/src/test/kotlin/net/corda/core/internal/ToggleFieldTest.kt +++ b/core/src/test/kotlin/net/corda/core/internal/ToggleFieldTest.kt @@ -1,9 +1,9 @@ package net.corda.core.internal -import com.nhaarman.mockito_kotlin.argThat -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify -import com.nhaarman.mockito_kotlin.verifyNoMoreInteractions +import org.mockito.kotlin.argThat +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyNoMoreInteractions import net.corda.core.internal.concurrent.fork import net.corda.core.utilities.getOrThrow import org.assertj.core.api.Assertions.assertThatThrownBy diff --git a/core/src/test/kotlin/net/corda/core/internal/concurrent/CordaFutureImplTest.kt b/core/src/test/kotlin/net/corda/core/internal/concurrent/CordaFutureImplTest.kt index 365b06993c..3fc3621b85 100644 --- a/core/src/test/kotlin/net/corda/core/internal/concurrent/CordaFutureImplTest.kt +++ b/core/src/test/kotlin/net/corda/core/internal/concurrent/CordaFutureImplTest.kt @@ -1,6 +1,6 @@ package net.corda.core.internal.concurrent -import com.nhaarman.mockito_kotlin.* +import org.mockito.kotlin.* import net.corda.core.concurrent.CordaFuture import net.corda.core.internal.join import net.corda.core.utilities.getOrThrow @@ -21,7 +21,7 @@ class CordaFutureTest { assertEquals(100, e.fork { 100 }.getOrThrow()) val x = Exception() val f = e.fork { throw x } - Assertions.assertThatThrownBy { f.getOrThrow() }.isSameAs(x) + Assertions.assertThatThrownBy { f.getOrThrow() }.isSameAs(x) } finally { e.shutdown() } @@ -54,7 +54,7 @@ class CordaFutureTest { val x = Exception() val g = f.map { throw x } f.set(100) - Assertions.assertThatThrownBy { g.getOrThrow() }.isSameAs(x) + Assertions.assertThatThrownBy { g.getOrThrow() }.isSameAs(x) } run { val block = mock<(Any?) -> Any?>() diff --git a/core/src/test/kotlin/net/corda/core/utilities/ByteArraysTest.kt b/core/src/test/kotlin/net/corda/core/utilities/ByteArraysTest.kt index 11454f0723..1ff21dda36 100644 --- a/core/src/test/kotlin/net/corda/core/utilities/ByteArraysTest.kt +++ b/core/src/test/kotlin/net/corda/core/utilities/ByteArraysTest.kt @@ -2,7 +2,6 @@ package net.corda.core.utilities import net.corda.core.contracts.StateRef import net.corda.core.crypto.SecureHash -import net.corda.core.internal.declaredField import org.assertj.core.api.Assertions.catchThrowable import org.junit.Assert.assertSame import org.junit.Assert.assertTrue @@ -14,22 +13,17 @@ import kotlin.test.assertEquals class ByteArraysTest { @Test(timeout=300_000) fun `slice works`() { - byteArrayOf(9, 9, 0, 1, 2, 3, 4, 9, 9).let { - sliceWorksImpl(it, OpaqueBytesSubSequence(it, 2, 5)) - } - byteArrayOf(0, 1, 2, 3, 4).let { - sliceWorksImpl(it, OpaqueBytes(it)) - } + sliceWorksImpl(OpaqueBytesSubSequence(byteArrayOf(9, 9, 0, 1, 2, 3, 4, 9, 9), 2, 5)) + sliceWorksImpl(OpaqueBytes(byteArrayOf(0, 1, 2, 3, 4))) } - private fun sliceWorksImpl(array: ByteArray, seq: ByteSequence) { + private fun sliceWorksImpl(seq: ByteSequence) { // Python-style negative indices can be implemented later if needed: assertSame(IllegalArgumentException::class.java, catchThrowable { seq.slice(-1) }.javaClass) assertSame(IllegalArgumentException::class.java, catchThrowable { seq.slice(end = -1) }.javaClass) fun check(expected: ByteArray, actual: ByteBuffer) { assertEquals(ByteBuffer.wrap(expected), actual) assertSame(ReadOnlyBufferException::class.java, catchThrowable { actual.array() }.javaClass) - assertSame(array, actual.declaredField(ByteBuffer::class, "hb").value) } check(byteArrayOf(0, 1, 2, 3, 4), seq.slice()) check(byteArrayOf(0, 1, 2, 3, 4), seq.slice(0, 5)) @@ -48,14 +42,14 @@ class ByteArraysTest { @Test(timeout=300_000) fun `test hex parsing strictly uppercase`() { - val HEX_REGEX = "^[0-9A-F]+\$".toRegex() + val hexRegex = "^[0-9A-F]+\$".toRegex() val privacySalt = net.corda.core.contracts.PrivacySalt() val privacySaltAsHexString = privacySalt.bytes.toHexString() - assertTrue(privacySaltAsHexString.matches(HEX_REGEX)) + assertTrue(privacySaltAsHexString.matches(hexRegex)) val stateRef = StateRef(SecureHash.randomSHA256(), 0) val txhashAsHexString = stateRef.txhash.bytes.toHexString() - assertTrue(txhashAsHexString.matches(HEX_REGEX)) + assertTrue(txhashAsHexString.matches(hexRegex)) } } diff --git a/core/src/test/kotlin/net/corda/core/utilities/EncodingUtilsTest.kt b/core/src/test/kotlin/net/corda/core/utilities/EncodingUtilsTest.kt index 9ba508771b..a1072ea34b 100644 --- a/core/src/test/kotlin/net/corda/core/utilities/EncodingUtilsTest.kt +++ b/core/src/test/kotlin/net/corda/core/utilities/EncodingUtilsTest.kt @@ -3,6 +3,7 @@ package net.corda.core.utilities import net.corda.core.crypto.AddressFormatException import org.apache.commons.lang3.ArrayUtils.EMPTY_BYTE_ARRAY import org.junit.Test +import java.util.Locale import kotlin.test.assertEquals import kotlin.test.fail @@ -54,7 +55,7 @@ class EncodingUtilsTest { @Test(timeout=300_000) fun `decoding lowercase and mixed HEX`() { - val testHexStringLowercase = testHexString.toLowerCase() + val testHexStringLowercase = testHexString.lowercase(Locale.getDefault()) assertEquals(testHexString.hexToRealString(), testHexStringLowercase.hexToRealString()) val testHexStringMixed = testHexString.replace('C', 'c') diff --git a/core/src/test/kotlin/net/corda/core/utilities/LazyMappedListTest.kt b/core/src/test/kotlin/net/corda/core/utilities/LazyMappedListTest.kt index 82920cef91..a152bfcf32 100644 --- a/core/src/test/kotlin/net/corda/core/utilities/LazyMappedListTest.kt +++ b/core/src/test/kotlin/net/corda/core/utilities/LazyMappedListTest.kt @@ -5,16 +5,12 @@ import net.corda.core.internal.lazyMapped import net.corda.core.internal.TransactionDeserialisationException import net.corda.core.internal.eagerDeserialise import net.corda.core.serialization.MissingAttachmentsException -import org.junit.Rule import org.junit.Test -import org.junit.rules.ExpectedException +import org.junit.jupiter.api.assertThrows import kotlin.test.assertEquals class LazyMappedListTest { - @get:Rule - val exception: ExpectedException = ExpectedException.none() - @Test(timeout=300_000) fun `LazyMappedList works`() { val originalList = (1 until 10).toList() @@ -44,14 +40,13 @@ class LazyMappedListTest { @Test(timeout=300_000) fun testMissingAttachments() { - exception.expect(MissingAttachmentsException::class.java) - exception.expectMessage("Uncatchable!") - - val lazyList = (0 until 5).toList().lazyMapped { _, _ -> - throw MissingAttachmentsException(emptyList(), "Uncatchable!") + val anException = assertThrows { + val lazyList = (0 until 5).toList().lazyMapped { _, _ -> + throw MissingAttachmentsException(emptyList(), "Uncatchable!") + } + lazyList.eagerDeserialise { _, _ -> -999 } } - - lazyList.eagerDeserialise { _, _ -> -999 } + assertEquals("Uncatchable!", anException.message) } @Test(timeout=300_000) diff --git a/detekt-baseline.xml b/detekt-baseline.xml index a3bfde2f82..d3fdd92468 100644 --- a/detekt-baseline.xml +++ b/detekt-baseline.xml @@ -1393,179 +1393,6 @@ ThrowsCount:TransactionVerifierServiceInternal.kt$Verifier$ private fun getUniqueContractAttachmentsByContract(): Map<ContractClassName, ContractAttachment> ThrowsCount:TransactionVerifierServiceInternal.kt$Verifier$// Using basic graph theory, a full cycle of encumbered (co-dependent) states should exist to achieve bi-directional // encumbrances. This property is important to ensure that no states involved in an encumbrance-relationship // can be spent on their own. Briefly, if any of the states is having more than one encumbrance references by // other states, a full cycle detection will fail. As a result, all of the encumbered states must be present // as "from" and "to" only once (or zero times if no encumbrance takes place). For instance, // a -> b // c -> b and a -> b // b -> a b -> c // do not satisfy the bi-directionality (full cycle) property. // // In the first example "b" appears twice in encumbrance ("to") list and "c" exists in the encumbered ("from") list only. // Due the above, one could consume "a" and "b" in the same transaction and then, because "b" is already consumed, "c" cannot be spent. // // Similarly, the second example does not form a full cycle because "a" and "c" exist in one of the lists only. // As a result, one can consume "b" and "c" in the same transactions, which will make "a" impossible to be spent. // // On other hand the following are valid constructions: // a -> b a -> c // b -> c and c -> b // c -> a b -> a // and form a full cycle, meaning that the bi-directionality property is satisfied. private fun checkBidirectionalOutputEncumbrances(statesAndEncumbrance: List<Pair<Int, Int>>) ThrowsCount:WireTransaction.kt$WireTransaction.Companion$ @CordaInternal fun resolveStateRefBinaryComponent(stateRef: StateRef, services: ServicesForResolution): SerializedBytes<TransactionState<ContractState>>? - TooGenericExceptionCaught:AMQPChannelHandler.kt$AMQPChannelHandler$ex: Exception - TooGenericExceptionCaught:AMQPExceptions.kt$th: Throwable - TooGenericExceptionCaught:AMQPTestUtils.kt$e: Exception - TooGenericExceptionCaught:AbstractNode.kt$AbstractNode$e: Exception - TooGenericExceptionCaught:AbstractNode.kt$AbstractNode.<no name provided>$e: Exception - TooGenericExceptionCaught:AbstractNode.kt$ex: Exception - TooGenericExceptionCaught:AbstractNodeTests.kt$ColdJVM.Companion$t: Throwable - TooGenericExceptionCaught:Amount.kt$Amount.Companion$e: Exception - TooGenericExceptionCaught:ArtemisRpcBroker.kt$ArtemisRpcBroker$th: Throwable - TooGenericExceptionCaught:AttachmentDemo.kt$e: Exception - TooGenericExceptionCaught:AttachmentLoadingTests.kt$AttachmentLoadingTests.ConsumeAndBroadcastResponderFlow$e: Exception - TooGenericExceptionCaught:AttachmentVersionNumberMigration.kt$AttachmentVersionNumberMigration$e: Exception - TooGenericExceptionCaught:AzureSmbVolume.kt$AzureSmbVolume$e: Exception - TooGenericExceptionCaught:BCCryptoService.kt$BCCryptoService$e: Exception - TooGenericExceptionCaught:BankOfCordaWebApi.kt$BankOfCordaWebApi$e: Exception - TooGenericExceptionCaught:BlobInspector.kt$BlobInspector$e: Exception - TooGenericExceptionCaught:BootstrapperView.kt$BootstrapperView$e: Exception - TooGenericExceptionCaught:BrokerJaasLoginModule.kt$BrokerJaasLoginModule$e: Exception - TooGenericExceptionCaught:CertRole.kt$CertRole.Companion$ex: ArrayIndexOutOfBoundsException - TooGenericExceptionCaught:CheckpointAgent.kt$CheckpointAgent.Companion$e: Exception - TooGenericExceptionCaught:CheckpointAgent.kt$CheckpointHook$throwable: Throwable - TooGenericExceptionCaught:CheckpointDumperImpl.kt$CheckpointDumperImpl$e: Exception - TooGenericExceptionCaught:CheckpointVerifier.kt$CheckpointVerifier$e: Exception - TooGenericExceptionCaught:CollectSignaturesFlow.kt$SignTransactionFlow$e: Exception - TooGenericExceptionCaught:ConcurrencyUtils.kt$t: Throwable - TooGenericExceptionCaught:ConfigUtilities.kt$e:Exception - TooGenericExceptionCaught:ConnectionStateMachine.kt$ConnectionStateMachine$ex: Exception - TooGenericExceptionCaught:ContractAttachmentSerializer.kt$ContractAttachmentSerializer$e: Exception - TooGenericExceptionCaught:ContractUpgradeTransactions.kt$ContractUpgradeWireTransaction$e: Exception - TooGenericExceptionCaught:CordaAuthenticationPlugin.kt$CordaAuthenticationPlugin$e: Exception - TooGenericExceptionCaught:CordaClassResolver.kt$LoggingWhitelist.Companion$ioEx: Exception - TooGenericExceptionCaught:CordaPersistence.kt$CordaPersistence$e: Exception - TooGenericExceptionCaught:CordaRPCClientTest.kt$CordaRPCClientTest$e: Exception - TooGenericExceptionCaught:CordaRPCOpsImpl.kt$CordaRPCOpsImpl$e: Exception - TooGenericExceptionCaught:CordaServiceLifecycleFatalTests.kt$CordaServiceLifecycleFatalTests$ex: Exception - TooGenericExceptionCaught:CryptoUtilsTest.kt$CryptoUtilsTest$e: Exception - TooGenericExceptionCaught:DBNetworkParametersStorage.kt$DBNetworkParametersStorage$e: Exception - TooGenericExceptionCaught:DataUploadServlet.kt$DataUploadServlet$e: RuntimeException - TooGenericExceptionCaught:DbMapDeadlockTest.kt$DbMapDeadlockTest$e: Exception - TooGenericExceptionCaught:DemoBenchView.kt$DemoBenchView$e: Exception - TooGenericExceptionCaught:DeserializationInput.kt$DeserializationInput$e: Exception - TooGenericExceptionCaught:DeserializeSimpleTypesTests.kt$DeserializeSimpleTypesTests$e: Exception - TooGenericExceptionCaught:DistributionMux.kt$DistributionMux$ex: Exception - TooGenericExceptionCaught:DockerInstantiator.kt$DockerInstantiator$e: Exception - TooGenericExceptionCaught:DriverDSLImpl.kt$DriverDSLImpl$e: Exception - TooGenericExceptionCaught:DriverDSLImpl.kt$DriverDSLImpl.Companion$th: Throwable - TooGenericExceptionCaught:DriverDSLImpl.kt$exception: Throwable - TooGenericExceptionCaught:DriverTests.kt$DriverTests$e: Exception - TooGenericExceptionCaught:ErrorHandling.kt$ErrorHandling.CheckpointAfterErrorFlow$t: Throwable - TooGenericExceptionCaught:EventProcessor.kt$EventProcessor$ex: Exception - TooGenericExceptionCaught:Eventually.kt$e: Exception - TooGenericExceptionCaught:Expect.kt$exception: Exception - TooGenericExceptionCaught:Explorer.kt$Explorer$e: Exception - TooGenericExceptionCaught:FinanceJSONSupport.kt$CalendarDeserializer$e: Exception - TooGenericExceptionCaught:FlowHandle.kt$FlowProgressHandleImpl$e: Exception - TooGenericExceptionCaught:FlowMessaging.kt$FlowMessagingImpl$exception: Exception - TooGenericExceptionCaught:FlowStackSnapshotTest.kt$FlowStackSnapshotTest$exception: Exception - TooGenericExceptionCaught:FlowStateMachineImpl.kt$FlowStateMachineImpl$exception: Exception - TooGenericExceptionCaught:FlowStateMachineImpl.kt$FlowStateMachineImpl$t: Throwable - TooGenericExceptionCaught:FutureMatchers.kt$<no name provided>$e: Exception - TooGenericExceptionCaught:HibernateConfiguration.kt$HibernateConfiguration$e: Exception - TooGenericExceptionCaught:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$e: Exception - TooGenericExceptionCaught:IRSDemo.kt$e: Exception - TooGenericExceptionCaught:IRSDemoTest.kt$IRSDemoTest.InterestRateSwapStateDeserializer$e: Exception - TooGenericExceptionCaught:InitialRegistrationCli.kt$InitialRegistration$e: Exception - TooGenericExceptionCaught:InitialRegistrationCli.kt$InitialRegistration.Companion$e: Exception - TooGenericExceptionCaught:Injectors.kt$e: Exception - TooGenericExceptionCaught:InstallShellExtensionsParser.kt$ShellExtensionsGenerator$exception: Exception - TooGenericExceptionCaught:InteractiveShell.kt$InteractiveShell$e: Exception - TooGenericExceptionCaught:InteractiveShell.kt$InteractiveShell$e: IndexOutOfBoundsException - TooGenericExceptionCaught:InterestSwapRestAPI.kt$InterestRateSwapAPI$ex: Exception - TooGenericExceptionCaught:InternalMockNetwork.kt$InternalMockNetwork$t: Throwable - TooGenericExceptionCaught:InternalTestUtils.kt$<no name provided>$e: Exception - TooGenericExceptionCaught:InternalUtils.kt$ex: Exception - TooGenericExceptionCaught:InternalUtils.kt$th: Throwable - TooGenericExceptionCaught:IssueCash.kt$IssueCash$e: Exception - TooGenericExceptionCaught:JacksonSupport.kt$JacksonSupport.PartyDeserializer$e: Exception - TooGenericExceptionCaught:JacksonSupport.kt$JacksonSupport.PublicKeyDeserializer$e: Exception - TooGenericExceptionCaught:JacksonSupport.kt$JacksonSupport.SecureHashDeserializer$e: Exception - TooGenericExceptionCaught:JarScanningCordappLoader.kt$JarScanningCordappLoader$e: Exception - TooGenericExceptionCaught:Kryo.kt$ImmutableClassSerializer$e: Exception - TooGenericExceptionCaught:LedgerDSLInterpreter.kt$Verifies$exception: Exception - TooGenericExceptionCaught:LoadTest.kt$LoadTest$throwable: Throwable - TooGenericExceptionCaught:LoginView.kt$LoginView$e: Exception - TooGenericExceptionCaught:Main.kt$Main$e: Exception - TooGenericExceptionCaught:MerkleTransaction.kt$FilteredTransaction$e: Exception - TooGenericExceptionCaught:MigrationServicesForResolution.kt$MigrationServicesForResolution$e: Exception - TooGenericExceptionCaught:MockAttachmentStorage.kt$MockAttachmentStorage$e: Exception - TooGenericExceptionCaught:MockCryptoService.kt$MockCryptoService$e: Exception - TooGenericExceptionCaught:MockNodeMessagingService.kt$MockNodeMessagingService$e: Exception - TooGenericExceptionCaught:MultiRPCClient.kt$MultiRPCClient$ex: Throwable - TooGenericExceptionCaught:MyCustomNotaryService.kt$MyValidatingNotaryFlow$e: Exception - TooGenericExceptionCaught:NamedCacheTest.kt$NamedCacheTest$e: Exception - TooGenericExceptionCaught:NettyTestHandler.kt$NettyTestHandler$e: Throwable - TooGenericExceptionCaught:NetworkBootstrapper.kt$NetworkBootstrapper$e: Exception - TooGenericExceptionCaught:NetworkMapServer.kt$NetworkMapServer.InMemoryNetworkMapService$e: Exception - TooGenericExceptionCaught:NetworkMapUpdater.kt$NetworkMapUpdater$e: Exception - TooGenericExceptionCaught:NetworkMapUpdater.kt$NetworkMapUpdater.<no name provided>$e: Exception - TooGenericExceptionCaught:NetworkParameterOverridesSpec.kt$NetworkParameterOverridesSpec.PackageOwnershipSpec$e: Exception - TooGenericExceptionCaught:NetworkParametersReader.kt$NetworkParametersReader$e: Exception - TooGenericExceptionCaught:NetworkRegistrationHelper.kt$NetworkRegistrationHelper$e: Exception - TooGenericExceptionCaught:NodeController.kt$NodeController$e: Exception - TooGenericExceptionCaught:NodeInfoWatcher.kt$NodeInfoWatcher$e: Exception - TooGenericExceptionCaught:NodeInterestRates.kt$NodeInterestRates$e: Exception - TooGenericExceptionCaught:NodeMonitorModel.kt$NodeMonitorModel$e: Exception - TooGenericExceptionCaught:NodeProcess.kt$NodeProcess.Factory$e: Exception - TooGenericExceptionCaught:NodeRPC.kt$NodeRPC$e: Exception - TooGenericExceptionCaught:NodeRPC.kt$NodeRPC.<no name provided>$e: Exception - TooGenericExceptionCaught:NodeSchedulerService.kt$NodeSchedulerService$e: Exception - TooGenericExceptionCaught:NodeStartup.kt$NodeStartup$e: Exception - TooGenericExceptionCaught:NodeTerminalView.kt$NodeTerminalView$e: Exception - TooGenericExceptionCaught:NodeVaultService.kt$NodeVaultService$e: Exception - TooGenericExceptionCaught:NodeVaultServiceTest.kt$NodeVaultServiceTest$e: Exception - TooGenericExceptionCaught:NonValidatingNotaryFlow.kt$NonValidatingNotaryFlow$e: Exception - TooGenericExceptionCaught:NotaryServiceFlow.kt$NotaryServiceFlow$e: Exception - TooGenericExceptionCaught:NotaryUtils.kt$e: Exception - TooGenericExceptionCaught:ObjectDiffer.kt$ObjectDiffer$throwable: Exception - TooGenericExceptionCaught:P2PMessagingClient.kt$P2PMessagingClient$e: Exception - TooGenericExceptionCaught:PersistentUniquenessProvider.kt$PersistentUniquenessProvider$e: Exception - TooGenericExceptionCaught:ProfileController.kt$ProfileController$e: Exception - TooGenericExceptionCaught:PropertyValidationTest.kt$PropertyValidationTest$e: Exception - TooGenericExceptionCaught:QuasarInstrumentationHook.kt$QuasarInstrumentationHook$throwable: Throwable - TooGenericExceptionCaught:R3Pty.kt$R3Pty$e: Exception - TooGenericExceptionCaught:RPCApi.kt$RPCApi.ServerToClient.Companion$e: Exception - TooGenericExceptionCaught:RPCClient.kt$RPCClient$throwable: Throwable - TooGenericExceptionCaught:RPCClientProxyHandler.kt$RPCClientProxyHandler$e: Exception - TooGenericExceptionCaught:RPCClientProxyHandler.kt$RPCClientProxyHandler$e: RuntimeException - TooGenericExceptionCaught:RPCPermissionResolver.kt$RPCPermissionResolver.InterfaceMethodMapCacheLoader$ex: Exception - TooGenericExceptionCaught:RPCServer.kt$RPCServer$e: Exception - TooGenericExceptionCaught:RPCServer.kt$RPCServer$exception: Throwable - TooGenericExceptionCaught:RPCServer.kt$RPCServer$throwable: Throwable - TooGenericExceptionCaught:RPCStabilityTests.kt$RPCStabilityTests$e2: Exception - TooGenericExceptionCaught:RPCStabilityTests.kt$RPCStabilityTests$e: Exception - TooGenericExceptionCaught:RandomFailingProxy.kt$RandomFailingProxy$e: Exception - TooGenericExceptionCaught:ReceiveTransactionFlow.kt$ReceiveTransactionFlow$e: Exception - TooGenericExceptionCaught:ReconnectingCordaRPCOps.kt$ReconnectingCordaRPCOps.ReconnectingRPCConnection$ex: Exception - TooGenericExceptionCaught:ReconnectingObservable.kt$ReconnectingObservable.ReconnectingSubscriber$e: Exception - TooGenericExceptionCaught:RpcServerObservableSerializerTests.kt$RpcServerObservableSerializerTests$e: Exception - TooGenericExceptionCaught:SSLHelper.kt$ex: Exception - TooGenericExceptionCaught:SerializationOutputTests.kt$SerializationOutputTests$t: Throwable - TooGenericExceptionCaught:ShutdownManager.kt$ShutdownManager$t: Throwable - TooGenericExceptionCaught:SimpleAMQPClient.kt$SimpleAMQPClient$e: Exception - TooGenericExceptionCaught:SimpleMQClient.kt$SimpleMQClient$e: Exception - TooGenericExceptionCaught:SingleThreadedStateMachineManager.kt$SingleThreadedStateMachineManager$e: Exception - TooGenericExceptionCaught:SingleThreadedStateMachineManager.kt$SingleThreadedStateMachineManager$ex: Exception - TooGenericExceptionCaught:SingleThreadedStateMachineManager.kt$SingleThreadedStateMachineManager$exception: Exception - TooGenericExceptionCaught:SingleThreadedStateMachineManager.kt$SingleThreadedStateMachineManager$t: Throwable - TooGenericExceptionCaught:StandaloneShell.kt$StandaloneShell$e: Exception - TooGenericExceptionCaught:StandardConfigValueParsers.kt$e: Exception - TooGenericExceptionCaught:StringToMethodCallParser.kt$StringToMethodCallParser$e: Exception - TooGenericExceptionCaught:TLSAuthenticationTests.kt$TLSAuthenticationTests$ex: Exception - TooGenericExceptionCaught:ThrowableSerializer.kt$ThrowableSerializer$e: Exception - TooGenericExceptionCaught:TlsDiffAlgorithmsTest.kt$TlsDiffAlgorithmsTest$ex: Exception - TooGenericExceptionCaught:TlsDiffProtocolsTest.kt$TlsDiffProtocolsTest$ex: Exception - TooGenericExceptionCaught:TraderDemo.kt$TraderDemo$e: Exception - TooGenericExceptionCaught:TransactionBuilder.kt$TransactionBuilder$e: Throwable - TooGenericExceptionCaught:TransactionSignatureTest.kt$TransactionSignatureTest$e: Throwable - TooGenericExceptionCaught:TransactionUtils.kt$e: Exception - TooGenericExceptionCaught:TransformTypes.kt$TransformTypes.Companion$e: IndexOutOfBoundsException - TooGenericExceptionCaught:TransitionExecutorImpl.kt$TransitionExecutorImpl$exception: Exception - TooGenericExceptionCaught:Try.kt$Try.Companion$t: Throwable - TooGenericExceptionCaught:UserValidationPlugin.kt$UserValidationPlugin$e: Throwable - TooGenericExceptionCaught:Utils.kt$e: Exception - TooGenericExceptionCaught:V1NodeConfigurationSpec.kt$V1NodeConfigurationSpec$e: Exception - TooGenericExceptionCaught:ValidatingNotaryFlow.kt$ValidatingNotaryFlow$e: Exception - TooGenericExceptionCaught:VaultStateMigration.kt$VaultStateIterator$e: Exception - TooGenericExceptionCaught:VaultStateMigration.kt$VaultStateMigration$e: Exception - TooGenericExceptionCaught:WebServer.kt$WebServer$e: Exception - TooGenericExceptionCaught:WebServer.kt$e: Exception - TooGenericExceptionCaught:WebServer.kt$ex: Exception - TooGenericExceptionCaught:WithMockNet.kt$WithMockNet.<no name provided>$e: Exception - TooGenericExceptionCaught:X509EdDSAEngine.kt$X509EdDSAEngine$e: Exception - TooGenericExceptionCaught:X509UtilitiesTest.kt$X509UtilitiesTest$ex: Exception TooGenericExceptionThrown:AMQPExceptionsTests.kt$AMQPExceptionsTests$throw Exception("FAILED") TooGenericExceptionThrown:AzureBackend.kt$AzureBackend.Companion$throw RuntimeException(e) TooGenericExceptionThrown:ClassLoadingUtilsTest.kt$ClassLoadingUtilsTest$throw RuntimeException() @@ -1599,7 +1426,6 @@ TooManyFunctions:ActionExecutorImpl.kt$ActionExecutorImpl : ActionExecutor TooManyFunctions:AppendOnlyPersistentMap.kt$AppendOnlyPersistentMapBase<K, V, E, out EK> TooManyFunctions:ArtemisTcpTransport.kt$ArtemisTcpTransport$Companion - TooManyFunctions:BCCryptoService.kt$BCCryptoService : CryptoService TooManyFunctions:BFTSmart.kt$BFTSmart$Replica : DefaultRecoverable TooManyFunctions:BaseTransaction.kt$BaseTransaction : NamedByHash TooManyFunctions:ClassCarpenter.kt$ClassCarpenterImpl : ClassCarpenter @@ -1675,6 +1501,7 @@ TopLevelPropertyNaming:SerializationEnvironment.kt$val _inheritableContextSerializationEnv = InheritableThreadLocalToggleField<SerializationEnvironment>("inheritableContextSerializationEnv") { stack -> stack.fold(false) { isAGlobalThreadBeingCreated, e -> isAGlobalThreadBeingCreated || (e.className == "io.netty.util.concurrent.GlobalEventExecutor" && e.methodName == "startThread") || (e.className == "java.util.concurrent.ForkJoinPool\$DefaultForkJoinWorkerThreadFactory" && e.methodName == "newThread") } } TopLevelPropertyNaming:SerializationEnvironment.kt$val _rpcClientSerializationEnv = SimpleToggleField<SerializationEnvironment>("rpcClientSerializationEnv") TopLevelPropertyNaming:SerializationFormat.kt$const val encodingNotPermittedFormat = "Encoding not permitted: %s" + TopLevelPropertyNaming:ConcurrencyUtils.kt$@VisibleForTesting const val shortCircuitedTaskFailedMessage = "Short-circuited task failed:" UnusedImports:Amount.kt$import net.corda.core.crypto.CompositeKey UnusedImports:Amount.kt$import net.corda.core.identity.Party UnusedImports:DummyLinearStateSchemaV1.kt$import net.corda.core.contracts.ContractState @@ -1815,7 +1642,7 @@ WildcardImport:AMQPTestUtils.kt$import net.corda.serialization.internal.amqp.* WildcardImport:AMQPTypeIdentifierParser.kt$import org.apache.qpid.proton.amqp.* WildcardImport:AMQPTypeIdentifiers.kt$import org.apache.qpid.proton.amqp.* - WildcardImport:ANSIProgressRendererTest.kt$import com.nhaarman.mockito_kotlin.* + WildcardImport:ANSIProgressRendererTest.kt$import org.mockito.kotlin.* WildcardImport:AbstractCashFlow.kt$import net.corda.core.flows.* WildcardImport:AbstractCashSelection.kt$import net.corda.core.utilities.* WildcardImport:AdvancedExceptionDialog.kt$import javafx.scene.control.* @@ -1841,9 +1668,6 @@ WildcardImport:AttachmentsClassLoader.kt$import net.corda.core.serialization.* WildcardImport:AttachmentsClassLoaderStaticContractTests.kt$import net.corda.core.contracts.* WildcardImport:AutoOfferFlow.kt$import net.corda.core.flows.* - WildcardImport:BCCryptoService.kt$import java.security.* - WildcardImport:BCCryptoService.kt$import net.corda.nodeapi.internal.cryptoservice.* - WildcardImport:BCCryptoServiceTests.kt$import java.security.* WildcardImport:BFTNotaryServiceTests.kt$import net.corda.core.crypto.* WildcardImport:BFTNotaryServiceTests.kt$import net.corda.testing.node.internal.* WildcardImport:BFTSmart.kt$import net.corda.core.crypto.* @@ -1903,7 +1727,7 @@ WildcardImport:CompositeKeyFactory.kt$import java.security.* WildcardImport:CompositeKeyTests.kt$import net.corda.core.crypto.* WildcardImport:CompositeSignature.kt$import java.security.* - WildcardImport:ConcurrencyUtilsTest.kt$import com.nhaarman.mockito_kotlin.* + WildcardImport:ConcurrencyUtilsTest.kt$import org.mockito.kotlin.* WildcardImport:ConfigParsingTest.kt$import org.assertj.core.api.Assertions.* WildcardImport:ConfigUtilities.kt$import com.typesafe.config.* WildcardImport:Configuration.kt$import com.typesafe.config.* @@ -1934,7 +1758,7 @@ WildcardImport:CordaCliWrapper.kt$import picocli.CommandLine.* WildcardImport:CordaExceptionTest.kt$import net.corda.core.contracts.TransactionVerificationException.* WildcardImport:CordaExceptionTest.kt$import org.junit.Assert.* - WildcardImport:CordaFutureImplTest.kt$import com.nhaarman.mockito_kotlin.* + WildcardImport:CordaFutureImplTest.kt$import org.mockito.kotlin.* WildcardImport:CordaInternal.kt$import kotlin.annotation.AnnotationTarget.* WildcardImport:CordaModule.kt$import com.fasterxml.jackson.annotation.* WildcardImport:CordaModule.kt$import com.fasterxml.jackson.databind.* @@ -2019,7 +1843,7 @@ WildcardImport:GuiUtilities.kt$import tornadofx.* WildcardImport:HTTPNetworkRegistrationService.kt$import java.net.HttpURLConnection.* WildcardImport:HardRestartTest.kt$import net.corda.core.flows.* - WildcardImport:HibernateConfigurationTest.kt$import com.nhaarman.mockito_kotlin.* + WildcardImport:HibernateConfigurationTest.kt$import org.mockito.kotlin.* WildcardImport:HibernateConfigurationTest.kt$import net.corda.testing.core.* WildcardImport:HibernateConfigurationTest.kt$import org.junit.* WildcardImport:HibernateQueryCriteriaParser.kt$import javax.persistence.criteria.* @@ -2162,7 +1986,7 @@ WildcardImport:NodeInterestRatesTest.kt$import org.junit.Assert.* WildcardImport:NodeRegistrationTest.kt$import javax.ws.rs.* WildcardImport:NodeSchedulerService.kt$import net.corda.core.internal.* - WildcardImport:NodeSchedulerServiceTest.kt$import com.nhaarman.mockito_kotlin.* + WildcardImport:NodeSchedulerServiceTest.kt$import org.mockito.kotlin.* WildcardImport:NodeSchedulerServiceTest.kt$import net.corda.core.contracts.* WildcardImport:NodeSchedulerServiceTest.kt$import org.junit.* WildcardImport:NodeSchemaService.kt$import net.corda.core.schemas.* @@ -2413,7 +2237,7 @@ WildcardImport:VaultService.kt$import net.corda.core.contracts.* WildcardImport:VaultService.kt$import net.corda.core.node.services.Vault.RelevancyStatus.* WildcardImport:VaultService.kt$import net.corda.core.node.services.vault.* - WildcardImport:VaultSoftLockManagerTest.kt$import com.nhaarman.mockito_kotlin.* + WildcardImport:VaultSoftLockManagerTest.kt$import org.mockito.kotlin.* WildcardImport:VaultSoftLockManagerTest.kt$import net.corda.core.contracts.* WildcardImport:VaultStateMigration.kt$import net.corda.core.contracts.* WildcardImport:VaultStateMigration.kt$import net.corda.core.serialization.internal.* diff --git a/detekt-config.yml b/detekt-config.yml index 9aa08b9df7..2a0d80c65d 100644 --- a/detekt-config.yml +++ b/detekt-config.yml @@ -77,17 +77,6 @@ empty-blocks: exceptions: active: true excludes: "**/buildSrc/**" - TooGenericExceptionCaught: - active: true - exceptionNames: - - ArrayIndexOutOfBoundsException - - Error - - Exception - - IllegalMonitorStateException - - NullPointerException - - IndexOutOfBoundsException - - RuntimeException - - Throwable TooGenericExceptionThrown: active: true exceptionNames: diff --git a/detekt-plugins/build.gradle b/detekt-plugins/build.gradle index 4657d00954..87ee3a3184 100644 --- a/detekt-plugins/build.gradle +++ b/detekt-plugins/build.gradle @@ -3,7 +3,6 @@ plugins { } dependencies { - implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' implementation "io.gitlab.arturbosch.detekt:detekt-api:$detekt_version" testImplementation "junit:junit:$junit_version" testImplementation "io.gitlab.arturbosch.detekt:detekt-test:$detekt_version" diff --git a/docker/build.gradle b/docker/build.gradle index 09fb2ba8e6..e5fe02bbaf 100644 --- a/docker/build.gradle +++ b/docker/build.gradle @@ -13,7 +13,7 @@ import java.time.format.DateTimeFormatter import java.util.stream.Collectors import java.util.stream.Stream -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'application' // We need to set mainClassName before applying the shadow plugin. @@ -21,7 +21,12 @@ mainClassName = 'net.corda.core.ConfigExporterMain' apply plugin: 'com.github.johnrengelman.shadow' dependencies{ - compile project(':node') + implementation project(':node') + implementation project(':node-api') + implementation project(':common-configuration-parsing') + implementation project(':common-validation') + + implementation "com.typesafe:config:$typesafe_config_version" } shadowJar { @@ -33,25 +38,24 @@ shadowJar { } enum ImageVariant { - UBUNTU_ZULU("Dockerfile", "1.8", "zulu-openjdk8"), - UBUNTU_ZULU_11("Dockerfile11", "11", "zulu-openjdk11"), - AL_CORRETTO("DockerfileAL", "1.8", "amazonlinux2"), + UBUNTU_ZULU("Dockerfile", "17", "zulu-openjdk"), + AL_CORRETTO("DockerfileAL", "17", "amazonlinux2"), OFFICIAL(UBUNTU_ZULU) String dockerFile String javaVersion - String baseImgaeFullName + String baseImageFullName ImageVariant(ImageVariant other) { this.dockerFile = other.dockerFile this.javaVersion = other.javaVersion - this.baseImgaeFullName = other.baseImgaeFullName + this.baseImageFullName = other.baseImageFullName } - ImageVariant(String dockerFile, String javaVersion, String baseImgaeFullName) { + ImageVariant(String dockerFile, String javaVersion, String baseImageFullName) { this.dockerFile = dockerFile this.javaVersion = javaVersion - this.baseImgaeFullName = baseImgaeFullName + this.baseImageFullName = baseImageFullName } static final String getRepository(Project project) { @@ -59,7 +63,7 @@ enum ImageVariant { } Set buildTags(Project project) { - return ["${project.version.toString().toLowerCase()}-${baseImgaeFullName}"].stream().map { + return ["${project.version.toString().toLowerCase()}-${baseImageFullName}"].stream().map { toAppend -> "${getRepository(project)}:${toAppend}".toString() }.map(Identifier.&fromCompoundString).collect(Collectors.toSet()) } @@ -75,12 +79,12 @@ class BuildDockerFolderTask extends DefaultTask { } @OptionValues("image") - Collection allVariants() { + Collection getAllVariants() { return EnumSet.allOf(ImageVariant.class) } @Input - Iterable variantsToBuild() { + Iterable getVariantsToBuild() { return ImageVariant.toBeBuilt } @@ -94,16 +98,12 @@ class BuildDockerFolderTask extends DefaultTask { return project.fileTree("${project.projectDir}/src/bash") } - @Lazy - private File cordaJar = project.findProject(":node:capsule").tasks.buildCordaJAR.outputs.files.singleFile + private File cordaJar = project.findProject(":node:capsule").tasks.buildCordaJAR.outputs.files.filter { + it.name.contains("corda") + }.singleFile - @Lazy private File configExporter = project.tasks.shadowJar.outputs.files.singleFile - @Lazy - private File dbMigrator = project.findProject(":tools:dbmigration").tasks.shadowJar.outputs.files.singleFile - - @InputFiles private FileCollection getRequiredArtifacts() { FileCollection res = project.tasks.shadowJar.outputs.files def capsuleProject = project.findProject(":node:capsule") @@ -150,10 +150,11 @@ class BuildDockerImageTask extends DefaultTask { } @OptionValues("image") - Collection allVariants() { + Collection getAllVariants() { return EnumSet.allOf(ImageVariant.class) } + @OutputDirectory final File dockerBuildDir = project.file("${project.buildDir}/docker/build") @OutputDirectory @@ -211,7 +212,7 @@ class PushDockerImage extends DefaultTask { } @OptionValues("image") - Collection allVariants() { + Collection getAllVariants() { return EnumSet.allOf(ImageVariant.class) } @@ -247,11 +248,14 @@ class PushDockerImage extends DefaultTask { } } -def buildDockerFolderTask = tasks.register("buildDockerFolder", BuildDockerFolderTask) +def buildDockerFolderTask = tasks.register("buildDockerFolder", BuildDockerFolderTask) { + dependsOn = [ tasks.named('shadowJar') ] +} + def buildDockerImageTask = tasks.register("buildDockerImage", BuildDockerImageTask) { from(buildDockerFolderTask.get()) } tasks.register("pushDockerImage", PushDockerImage) { from(buildDockerImageTask.get()) -} \ No newline at end of file +} diff --git a/docker/src/bash/example-mini-network.sh b/docker/src/bash/example-mini-network.sh index f8e628a7e1..e59e9eb698 100755 --- a/docker/src/bash/example-mini-network.sh +++ b/docker/src/bash/example-mini-network.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash NODE_LIST=("dockerNode1" "dockerNode2" "dockerNode3") NETWORK_NAME=mininet -CORDAPP_VERSION="4.11-SNAPSHOT" -DOCKER_IMAGE_VERSION="corda-zulu-4.11-snapshot" +CORDAPP_VERSION="4.12-SNAPSHOT" +DOCKER_IMAGE_VERSION="corda-zulu-4.12-snapshot" mkdir cordapps rm -f cordapps/* diff --git a/docker/src/bash/generate-config.sh b/docker/src/bash/generate-config.sh index 3d313afb32..f8ea1f3519 100755 --- a/docker/src/bash/generate-config.sh +++ b/docker/src/bash/generate-config.sh @@ -37,7 +37,7 @@ function generateGenericCZConfig() { : ${MY_EMAIL_ADDRESS:? '$MY_EMAIL_ADDRESS, the email to use when joining must be set as an environment variable'} : ${NETWORK_TRUST_PASSWORD=:? '$NETWORK_TRUST_PASSWORD, the password to the network store to use when joining must be set as environment variable'} : ${RPC_USER=:? '$RPC_USER, the name of the primary rpc user must be set as environment variable'} - : ${SSHPORT=:? 'SSHPORT, the port number for the SSHD must be set as enviroment variable'} + : ${SSHPORT=:? 'SSHPORT, the port number for the SSHD must be set as environment variable'} if [[ ! -f ${CERTIFICATES_FOLDER}/${TRUST_STORE_NAME} ]]; then @@ -121,7 +121,7 @@ while :; do done : ${TRUST_STORE_NAME="network-root-truststore.jks"} -: ${JVM_ARGS='-Xmx4g -Xms2g -XX:+UseG1GC'} +: ${JVM_ARGS='-Xmx4g -Xms2g'} if [[ ${GENERATE_TEST_NET} == 1 ]]; then : ${MY_PUBLIC_ADDRESS:? 'MY_PUBLIC_ADDRESS must be set as environment variable'} diff --git a/docker/src/docker/Dockerfile b/docker/src/docker/Dockerfile index a6014f8973..ecd3bb48d5 100644 --- a/docker/src/docker/Dockerfile +++ b/docker/src/docker/Dockerfile @@ -1,11 +1,11 @@ -FROM azul/zulu-openjdk:8u392 +FROM azul/zulu-openjdk:17.0.8.1 ## Remove Azul Zulu repo, as it is gone by now RUN rm -rf /etc/apt/sources.list.d/zulu.list ## Add packages, clean cache, create dirs, create corda user and change ownership RUN apt-get update && \ - apt-mark hold zulu8-jdk && \ + apt-mark hold zulu17-jdk && \ apt-get -y upgrade && \ apt-get -y install bash curl unzip && \ rm -rf /var/lib/apt/lists/* && \ @@ -33,7 +33,7 @@ ENV CORDAPPS_FOLDER="/opt/corda/cordapps" \ MY_RPC_PORT=10201 \ MY_RPC_ADMIN_PORT=10202 \ PATH=$PATH:/opt/corda/bin \ - JVM_ARGS="-XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap " \ + JVM_ARGS="-XX:+UnlockExperimentalVMOptions " \ CORDA_ARGS="" ##CORDAPPS FOLDER diff --git a/docker/src/docker/Dockerfile-debug b/docker/src/docker/Dockerfile-debug index b7dd204884..8b36530f5e 100644 --- a/docker/src/docker/Dockerfile-debug +++ b/docker/src/docker/Dockerfile-debug @@ -1,8 +1,8 @@ -FROM azul/zulu-openjdk:8u392 +FROM azul/zulu-openjdk:17.0.8.1 ## Add packages, clean cache, create dirs, create corda user and change ownership RUN apt-get update && \ - apt-mark hold zulu8-jdk && \ + apt-mark hold zulu17-jdk && \ apt-get -y upgrade && \ apt-get -y install bash curl unzip netstat lsof telnet netcat && \ rm -rf /var/lib/apt/lists/* && \ @@ -28,7 +28,7 @@ ENV CORDAPPS_FOLDER="/opt/corda/cordapps" \ MY_RPC_PORT=10201 \ MY_RPC_ADMIN_PORT=10202 \ PATH=$PATH:/opt/corda/bin \ - JVM_ARGS="-XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap " \ + JVM_ARGS="-XX:+UnlockExperimentalVMOptions " \ CORDA_ARGS="" ##CORDAPPS FOLDER diff --git a/docker/src/docker/Dockerfile.zulu-sa-jdk-11-patch b/docker/src/docker/Dockerfile.zulu-sa-jdk-11-patch deleted file mode 100644 index 1b52b6de42..0000000000 --- a/docker/src/docker/Dockerfile.zulu-sa-jdk-11-patch +++ /dev/null @@ -1,28 +0,0 @@ -# Build and publish an Azul Zulu patched JDK 11 to the R3 Azure docker registry as follows: - -# colljos@ci-agent-101l:~$ cd /home/colljos/azul/case17645 -# $docker build . -f Dockerfile.zulu-sa-jdk-11-patch --no-cache -t azul/zulu-sa-jdk:11.0.3_7_LTS -# $docker tag azul/zulu-sa-jdk:11.0.3_7_LTS corda.azurecr.io/jdk/azul/zulu-sa-jdk:11.0.3_7_LTS -# $docker login -u corda corda.azurecr.io -# docker push corda.azurecr.io/jdk/azul/zulu-sa-jdk:11.0.3_7_LTS - -# Remember to set the DOCKER env variables accordingly to access the R3 Azure docker registry: -# export DOCKER_URL=https://corda.azurecr.io -# export DOCKER_USERNAME= -# export DOCKER_PASSWORD= - -RUN addgroup corda && adduser --ingroup corda --disabled-password -gecos "" --shell /bin/bash corda - -COPY zulu11.31.16-sa-jdk11.0.3-linux_x64.tar /opt - -RUN tar xvf /opt/zulu11.31.16-sa-jdk11.0.3-linux_x64.tar -C /opt && ln -s /opt/zulu11.31.16-sa-jdk11.0.3-linux_x64 /opt/jdk - -RUN rm /opt/zulu11.31.16-sa-jdk11.0.3-linux_x64.tar && \ - chown -R corda /opt/zulu11.31.16-sa-jdk11.0.3-linux_x64 && \ - chgrp -R corda /opt/zulu11.31.16-sa-jdk11.0.3-linux_x64 - -# Set environment -ENV JAVA_HOME /opt/jdk -ENV PATH ${PATH}:${JAVA_HOME}/bin - -CMD ["java", "-version"] \ No newline at end of file diff --git a/docker/src/docker/Dockerfile11 b/docker/src/docker/Dockerfile11 deleted file mode 100644 index 20b48ddcdc..0000000000 --- a/docker/src/docker/Dockerfile11 +++ /dev/null @@ -1,82 +0,0 @@ -# Using Azul Zulu patched JDK 11 (local built and published docker image) - -# colljos@ci-agent-101l:~$ jdk11azul -# openjdk version "11.0.3" 2019-04-16 LTS -# OpenJDK Runtime Environment Zulu11.31+16-SA (build 11.0.3+7-LTS) -# OpenJDK 64-Bit Server VM Zulu11.31+16-SA (build 11.0.3+7-LTS, mixed mode) - -# Remember to set the DOCKER env variables accordingly to access the R3 Azure docker registry: -# export DOCKER_URL=https://corda.azurecr.io -# export DOCKER_USERNAME= -# export DOCKER_PASSWORD= - -FROM corda.azurecr.io/jdk/azul/zulu-sa-jdk:11.0.3_7_LTS - -## Add packages, clean cache, create dirs, create corda user and change ownership -RUN apt-get update && \ - apt-get -y upgrade && \ - apt-get -y install bash curl unzip && \ - rm -rf /var/lib/apt/lists/* && \ - mkdir -p /opt/corda/cordapps && \ - mkdir -p /opt/corda/persistence && \ - mkdir -p /opt/corda/artemis && \ - mkdir -p /opt/corda/certificates && \ - mkdir -p /opt/corda/drivers && \ - mkdir -p /opt/corda/logs && \ - mkdir -p /opt/corda/bin && \ - mkdir -p /opt/corda/additional-node-infos && \ - mkdir -p /etc/corda && \ - chown -R corda /opt/corda && \ - chgrp -R corda /opt/corda && \ - chown -R corda /etc/corda && \ - chgrp -R corda /etc/corda && \ - chown -R corda /opt/corda && \ - chgrp -R corda /opt/corda && \ - chown -R corda /etc/corda && \ - chgrp -R corda /etc/corda - -ENV CORDAPPS_FOLDER="/opt/corda/cordapps" \ - PERSISTENCE_FOLDER="/opt/corda/persistence" \ - ARTEMIS_FOLDER="/opt/corda/artemis" \ - CERTIFICATES_FOLDER="/opt/corda/certificates" \ - DRIVERS_FOLDER="/opt/corda/drivers" \ - CONFIG_FOLDER="/etc/corda" \ - MY_P2P_PORT=10200 \ - MY_RPC_PORT=10201 \ - MY_RPC_ADMIN_PORT=10202 \ - PATH=$PATH:/opt/corda/bin \ - JVM_ARGS="-XX:+UseG1GC -XX:+UnlockExperimentalVMOptions " \ - CORDA_ARGS="" - -##CORDAPPS FOLDER -VOLUME ["/opt/corda/cordapps"] -##PERSISTENCE FOLDER -VOLUME ["/opt/corda/persistence"] -##ARTEMIS FOLDER -VOLUME ["/opt/corda/artemis"] -##CERTS FOLDER -VOLUME ["/opt/corda/certificates"] -##OPTIONAL JDBC DRIVERS FOLDER -VOLUME ["/opt/corda/drivers"] -##LOG FOLDER -VOLUME ["/opt/corda/logs"] -##ADDITIONAL NODE INFOS FOLDER -VOLUME ["/opt/corda/additional-node-infos"] -##CONFIG LOCATION -VOLUME ["/etc/corda"] - -##CORDA JAR -COPY --chown=corda:corda corda.jar /opt/corda/bin/corda.jar -##CONFIG MANIPULATOR JAR -COPY --chown=corda:corda config-exporter.jar /opt/corda/config-exporter.jar -##CONFIG GENERATOR SHELL SCRIPT -COPY --chown=corda:corda generate-config.sh /opt/corda/bin/config-generator -##CORDA RUN SCRIPT -COPY --chown=corda:corda run-corda.sh /opt/corda/bin/run-corda -##BASE CONFIG FOR GENERATOR -COPY --chown=corda:corda starting-node.conf /opt/corda/starting-node.conf - -USER "corda" -EXPOSE ${MY_P2P_PORT} ${MY_RPC_PORT} ${MY_RPC_ADMIN_PORT} -WORKDIR /opt/corda -CMD ["run-corda"] \ No newline at end of file diff --git a/docker/src/docker/DockerfileAL b/docker/src/docker/DockerfileAL index 11f3db261b..73a21334d7 100644 --- a/docker/src/docker/DockerfileAL +++ b/docker/src/docker/DockerfileAL @@ -1,4 +1,4 @@ -FROM amazoncorretto:8u422-al2 +FROM amazoncorretto:17.0.9 ## Add packages, clean cache, create dirs, create corda user and change ownership RUN yum -y install bash && \ @@ -31,7 +31,7 @@ ENV CORDAPPS_FOLDER="/opt/corda/cordapps" \ MY_RPC_PORT=10201 \ MY_RPC_ADMIN_PORT=10202 \ PATH=$PATH:/opt/corda/bin \ - JVM_ARGS="-XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap " \ + JVM_ARGS="-XX:+UnlockExperimentalVMOptions " \ CORDA_ARGS="" ##CORDAPPS FOLDER @@ -65,4 +65,4 @@ COPY --chown=corda:corda starting-node.conf /opt/corda/starting-node.conf USER "corda" EXPOSE ${MY_P2P_PORT} ${MY_RPC_PORT} ${MY_RPC_ADMIN_PORT} WORKDIR /opt/corda -CMD ["run-corda"] \ No newline at end of file +CMD ["run-corda"] diff --git a/docker/src/docker/DockerfileAL-debug b/docker/src/docker/DockerfileAL-debug index 3cc6a9f0e7..a19e679828 100644 --- a/docker/src/docker/DockerfileAL-debug +++ b/docker/src/docker/DockerfileAL-debug @@ -2,7 +2,7 @@ FROM amazonlinux:2 ## Add packages, clean cache, create dirs, create corda user and change ownership RUN amazon-linux-extras enable corretto8 && \ - yum -y install java-1.8.0-amazon-corretto-devel && \ + yum -y install java-17.0.9-amazon-corretto-devel && \ yum -y install bash && \ yum -y install curl && \ yum -y install unzip && \ @@ -31,7 +31,7 @@ ENV CORDAPPS_FOLDER="/opt/corda/cordapps" \ MY_RPC_PORT=10201 \ MY_RPC_ADMIN_PORT=10202 \ PATH=$PATH:/opt/corda/bin \ - JVM_ARGS="-XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap " \ + JVM_ARGS="-XX:+UnlockExperimentalVMOptions " \ CORDA_ARGS="" ##CORDAPPS FOLDER diff --git a/docker/test-docker.sh b/docker/test-docker.sh index e5b35a294c..4f3724c4c2 100755 --- a/docker/test-docker.sh +++ b/docker/test-docker.sh @@ -41,8 +41,8 @@ docker run -d --name corda-test-${SALT} --network=host --hostname=127.0.0.1 \ -e CORDA_ARGS="--log-to-console --no-local-shell" \ $IMAGE config-generator --generic -# Succesfully registered (with http://localhost:8080) -docker logs -f corda-test-${SALT} | grep -q "Succesfully registered" +# Successfully registered (with http://localhost:8080) +docker logs -f corda-test-${SALT} | grep -q "Successfully registered" if [ ! "$(docker ps -q -f name=corda-test-${SALT})" ]; then echo "TEST-IMAGE-${IMAGE}: FAIL corda-test has exited." docker logs corda-test-${SALT} @@ -50,7 +50,7 @@ if [ ! "$(docker ps -q -f name=corda-test-${SALT})" ]; then docker rm -f corda-test-${SALT} exit 1 else - echo "TEST-IMAGE-${IMAGE}: SUCCESS : Succesfully registered with http://localhost:8080" + echo "TEST-IMAGE-${IMAGE}: SUCCESS : Successfully registered with http://localhost:8080" fi # Node started up and registered diff --git a/docs/build.gradle b/docs/build.gradle index 94fd4e6043..6304abc268 100644 --- a/docs/build.gradle +++ b/docs/build.gradle @@ -1,12 +1,11 @@ import org.apache.tools.ant.taskdefs.condition.Os apply plugin: 'org.jetbrains.dokka' -apply plugin: 'net.corda.plugins.publish-utils' apply plugin: 'maven-publish' apply plugin: 'com.jfrog.artifactory' dependencies { - compile rootProject + implementation rootProject } def internalPackagePrefixes(sourceDirs) { @@ -23,68 +22,66 @@ def internalPackagePrefixes(sourceDirs) { } ext { - // TODO: Add '../client/jfx/src/main/kotlin' and '../client/mock/src/main/kotlin' if we decide to make them into public API - dokkaSourceDirs = files('../core/src/main/kotlin', '../client/rpc/src/main/kotlin', '../finance/workflows/src/main/kotlin', '../finance/contracts/src/main/kotlin', '../client/jackson/src/main/kotlin', - '../testing/test-utils/src/main/kotlin', '../testing/node-driver/src/main/kotlin') - internalPackagePrefixes = internalPackagePrefixes(dokkaSourceDirs) archivedApiDocsBaseFilename = 'api-docs' } -dokka { - outputDirectory = file("${rootProject.rootDir}/docs/build/html/api/kotlin") +jar { + enabled = false } -task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) { - outputFormat = "javadoc" +dokkaHtml { + outputDirectory = file("${rootProject.rootDir}/docs/build/html/api/html") +} + +dokkaJavadoc { outputDirectory = file("${rootProject.rootDir}/docs/build/html/api/javadoc") } -[dokka, dokkaJavadoc].collect { - it.configuration { - moduleName = 'corda' - dokkaSourceDirs.collect { sourceDir -> - sourceRoot { - path = sourceDir.path +[dokkaHtml, dokkaJavadoc].forEach { + it.dokkaSourceSets { + customSourceSet { + sourceRoot(file('../core/src/main/kotlin')) + sourceRoot(file('../client/rpc/src/main/kotlin')) + sourceRoot(file('../finance/workflows/src/main/kotlin')) + sourceRoot(file('../finance/contracts/src/main/kotlin')) + sourceRoot(file('../client/jackson/src/main/kotlin')) + sourceRoot(file('../testing/test-utils/src/main/kotlin')) + sourceRoot(file('../testing/node-driver/src/main/kotlin')) + sourceRoot(file('../core/src/main/kotlin')) + sourceRoot(file('../client/rpc/src/main/kotlin')) + sourceRoot(file('../client/rpc/src/main/kotlin')) + + externalDocumentationLink { + url.set(new URL("https://fasterxml.github.io/jackson-core/javadoc/2.9/")) } - } - includes = ['packages.md'] - jdkVersion = 8 - externalDocumentationLink { - url = new URL("https://fasterxml.github.io/jackson-core/javadoc/2.9/") - } - externalDocumentationLink { - url = new URL("https://docs.oracle.com/javafx/2/api/") - } - externalDocumentationLink { - url = new URL("https://www.bouncycastle.org/docs/docs1.5on/") - } - internalPackagePrefixes.collect { packagePrefix -> - perPackageOption { - prefix = packagePrefix - suppress = true + externalDocumentationLink { + url.set(new URL("https://docs.oracle.com/javafx/2/api/")) + } + externalDocumentationLink { + url.set(new URL("https://www.bouncycastle.org/docs/docs1.5on/")) } } } } -task apidocs(dependsOn: ['dokka', 'dokkaJavadoc']) { +task apidocs(dependsOn: ['dokkaHtml', 'dokkaJavadoc']) { group "Documentation" description "Build API documentation" } -task makeHTMLDocs(type: Exec){ +task makeHTMLDocs(type: Exec) { if (Os.isFamily(Os.FAMILY_WINDOWS)) { commandLine "docker", "run", "--rm", "-v", "${project.projectDir}:/opt/docs_builder", "-v", "${project.projectDir}/..:/opt", "corda/docs-builder:latest", "bash", "-c", "make-docsite-html.sh" } else { - commandLine "bash", "-c", "docker run --rm --user \$(id -u):\$(id -g) -v ${project.projectDir}:/opt/docs_builder -v ${project.projectDir}/..:/opt corda/docs-builder:latest bash -c make-docsite-html.sh" + commandLine "bash", "-c", "docker run --rm --user \$(id -u):\$(id -g) -v ${project.projectDir}:/opt/docs_builder -v ${project.projectDir}/..:/opt corda/docs-builder:latest bash -c make-docsite-html.sh" } } -task makePDFDocs(type: Exec){ +task makePDFDocs(type: Exec) { if (Os.isFamily(Os.FAMILY_WINDOWS)) { commandLine "docker", "run", "--rm", "-v", "${project.projectDir}:/opt/docs_builder", "-v", "${project.projectDir}/..:/opt", "corda/docs-builder:latest", "bash", "-c", "make-docsite-pdf.sh" } else { - commandLine "bash", "-c", "docker run --rm --user \$(id -u):\$(id -g) -v ${project.projectDir}:/opt/docs_builder -v ${project.projectDir}/..:/opt corda/docs-builder:latest bash -c make-docsite-pdf.sh" + commandLine "bash", "-c", "docker run --rm --user \$(id -u):\$(id -g) -v ${project.projectDir}:/opt/docs_builder -v ${project.projectDir}/..:/opt corda/docs-builder:latest bash -c make-docsite-pdf.sh" } } diff --git a/experimental/avalanche/Readme.md b/experimental/avalanche/Readme.md index e41775f225..4f7ed92ac1 100644 --- a/experimental/avalanche/Readme.md +++ b/experimental/avalanche/Readme.md @@ -18,7 +18,7 @@ for f in node-0-*.dot; do dot -Tpng -O $f; done ``` The above command generates a number of PNG files `node-0-*.png`, showing the evolution of the DAG. The nodes are labeled with the ID of the spent state, -the chit and confidence values. The prefered transaction of a conflict set is +the chit and confidence values. The preferred transaction of a conflict set is labelled with a star. Accepted transactions are blue. ![DAG](./images/node-0-003.dot.png) diff --git a/experimental/avalanche/build.gradle b/experimental/avalanche/build.gradle index 540bc2947b..db0b9d8647 100644 --- a/experimental/avalanche/build.gradle +++ b/experimental/avalanche/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'application' // We need to set mainClassName before applying the shadow plugin. mainClassName = "net.corda.avalanche.MainKt" @@ -6,8 +6,7 @@ mainClassName = "net.corda.avalanche.MainKt" apply plugin: 'com.github.johnrengelman.shadow' dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - compile "info.picocli:picocli:$picocli_version" + implementation "info.picocli:picocli:$picocli_version" testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" diff --git a/experimental/blobwriter/build.gradle b/experimental/blobwriter/build.gradle index f061b2d5b0..a94c466085 100644 --- a/experimental/blobwriter/build.gradle +++ b/experimental/blobwriter/build.gradle @@ -4,16 +4,19 @@ apply plugin : 'application' mainClassName = "net.corda.blobwriter.BlobWriter.kt" dependencies { - compile project(':tools:cliutils') - compile project(":common-logging") - compile project(':serialization') + implementation project(':core') + implementation project(':tools:cliutils') + implementation project(":common-logging") + implementation project(':serialization') - compile "org.slf4j:jul-to-slf4j:$slf4j_version" - compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version" + implementation "org.slf4j:jul-to-slf4j:$slf4j_version" + implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version" } +configurations.implementation.canBeResolved = true + jar { - from (configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) { + from (configurations.implementation.collect { it.isDirectory() ? it : zipTree(it) }) { exclude "META-INF/*.SF" exclude "META-INF/*.DSA" exclude "META-INF/*.RSA" @@ -24,4 +27,5 @@ jar { 'Main-Class': 'net.corda.blobwriter.BlobWriterKt' ) } + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } diff --git a/experimental/blobwriter/src/main/kotlin/net/corda/blobwriter/BlobWriter.kt b/experimental/blobwriter/src/main/kotlin/net/corda/blobwriter/BlobWriter.kt index 3594ad43a7..335f2b4838 100644 --- a/experimental/blobwriter/src/main/kotlin/net/corda/blobwriter/BlobWriter.kt +++ b/experimental/blobwriter/src/main/kotlin/net/corda/blobwriter/BlobWriter.kt @@ -74,11 +74,12 @@ data class _L_i__ (val listy: List<_i_>) data class _ALd_ (val a: Array>) +@Suppress("UNUSED_PARAMETER", "PLATFORM_CLASS_MAPPED_TO_KOTLIN") fun main (args: Array) { initialiseSerialization() val path = "../cpp-serializer/bin/test-files"; File("$path/_i_").writeBytes (_i_ (69).serialize().bytes) - File("$path/_Oi_").writeBytes (_Oi_ (Integer (1)).serialize().bytes) + File("$path/_Oi_").writeBytes (_Oi_ (Integer.valueOf (1) as Integer).serialize().bytes) File("$path/_l_").writeBytes (_l_ (100000000000L).serialize().bytes) File("$path/_Li_").writeBytes (_Li_(listOf (1, 2, 3, 4, 5, 6)).serialize().bytes) File("$path/_Ai_").writeBytes (_Ai_(arrayOf (1, 2, 3, 4, 5, 6)).serialize().bytes) diff --git a/experimental/build.gradle b/experimental/build.gradle index e8b82c4b85..f5fdc33bd5 100644 --- a/experimental/build.gradle +++ b/experimental/build.gradle @@ -1,7 +1,7 @@ group 'com.r3cev.prototyping' version '1.0-SNAPSHOT' -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' compileKotlin { kotlinOptions.suppressWarnings = true @@ -11,20 +11,24 @@ compileTestKotlin { } dependencies { - compile project(':core') - compile project(':finance:contracts') - compile project(':finance:workflows') + implementation project(':core') + implementation project(':finance:contracts') + implementation project(':finance:workflows') // ObjectWeb Asm: a library for synthesising and working with JVM bytecode. - compile "org.ow2.asm:asm:$asm_version" + implementation "org.ow2.asm:asm:$asm_version" - compile "com.google.guava:guava:$guava_version" + implementation "com.google.guava:guava:$guava_version" + + testImplementation project(':core-test-utils') + testImplementation project(':test-utils') testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" + testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile project(':node-driver') + testImplementation project(':node-driver') } diff --git a/experimental/corda-utils/build.gradle b/experimental/corda-utils/build.gradle index 89092ca3be..589c56c199 100644 --- a/experimental/corda-utils/build.gradle +++ b/experimental/corda-utils/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' sourceSets { @@ -12,16 +12,17 @@ sourceSets { } configurations { - integrationTestCompile.extendsFrom testCompile - integrationTestRuntime.extendsFrom testRuntime + integrationTestImplementation.extendsFrom testImplementation + integrationTestRuntime.extendsFrom testRuntimeOnly } dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - compile project(':core') - compile project(':node-api') - testCompile project(':test-utils') - testCompile project(':node-driver') + implementation project(':core') + implementation project(':node-api') + + testImplementation project(':core-test-utils') + testImplementation project(':test-utils') + testImplementation project(':node-driver') testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" diff --git a/experimental/netparams/build.gradle b/experimental/netparams/build.gradle index 1664444b50..f16ea07cb6 100644 --- a/experimental/netparams/build.gradle +++ b/experimental/netparams/build.gradle @@ -1,29 +1,35 @@ -apply plugin: 'java' -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' description 'NetworkParameters signing tool' dependencies { - compile project(':tools:cliutils') - compile "org.slf4j:jul-to-slf4j:$slf4j_version" - compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version" - compile "com.jcabi:jcabi-manifests:$jcabi_manifests_version" - compile project(':core') - compile project(':node-api') + implementation project(':core') + implementation project(':node-api') + implementation project(':serialization') + implementation project(':tools:cliutils') + + implementation "org.slf4j:jul-to-slf4j:$slf4j_version" + implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version" + implementation "com.jcabi:jcabi-manifests:$jcabi_manifests_version" + implementation "com.typesafe:config:$typesafe_config_version" + implementation "info.picocli:picocli:$picocli_version" } +configurations.implementation.canBeResolved = true + jar { - from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) { + from(configurations.implementation.collect { it.isDirectory() ? it : zipTree(it) }) { exclude "META-INF/*.SF" exclude "META-INF/*.DSA" exclude "META-INF/*.RSA" } - baseName = "netparams" + archiveBaseName = "netparams" manifest { attributes( 'Main-Class': 'net.corda.netparams.NetParamsKt' ) } + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } processResources { diff --git a/experimental/nodeinfo/build.gradle b/experimental/nodeinfo/build.gradle index fe4628c119..75e5439775 100644 --- a/experimental/nodeinfo/build.gradle +++ b/experimental/nodeinfo/build.gradle @@ -1,29 +1,34 @@ -apply plugin: 'java' -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' description 'NodeInfo signing tool' dependencies { - compile project(':tools:cliutils') - compile "org.slf4j:jul-to-slf4j:$slf4j_version" - compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version" - compile "com.jcabi:jcabi-manifests:$jcabi_manifests_version" - compile project(':core') - compile project(':node-api') + implementation project(':core') + implementation project(':node-api') + implementation project(':serialization') + implementation project(':tools:cliutils') + + implementation "org.slf4j:jul-to-slf4j:$slf4j_version" + implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version" + implementation "com.jcabi:jcabi-manifests:$jcabi_manifests_version" + implementation "info.picocli:picocli:$picocli_version" } +configurations.implementation.canBeResolved = true + jar { - from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) { + from(configurations.implementation.collect { it.isDirectory() ? it : zipTree(it) }) { exclude "META-INF/*.SF" exclude "META-INF/*.DSA" exclude "META-INF/*.RSA" } - baseName = "nodeinfo" + archiveBaseName = "nodeinfo" manifest { attributes( 'Main-Class': 'net.corda.nodeinfo.NodeInfoKt' ) } + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } processResources { diff --git a/experimental/nodeinfo/src/main/kotlin/net.corda.nodeinfo/NodeInfo.kt b/experimental/nodeinfo/src/main/kotlin/net.corda.nodeinfo/NodeInfo.kt index 20039ba17d..7a10e88cfa 100644 --- a/experimental/nodeinfo/src/main/kotlin/net.corda.nodeinfo/NodeInfo.kt +++ b/experimental/nodeinfo/src/main/kotlin/net.corda.nodeinfo/NodeInfo.kt @@ -4,8 +4,6 @@ import net.corda.cliutils.CordaCliWrapper import net.corda.cliutils.start import net.corda.core.crypto.sign import net.corda.core.identity.PartyAndCertificate -import net.corda.core.internal.div -import net.corda.core.internal.readAll import net.corda.core.node.NodeInfo import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializedBytes @@ -26,6 +24,8 @@ import picocli.CommandLine.Option import java.io.File import java.nio.file.Path import java.security.cert.CertificateFactory +import kotlin.io.path.div +import kotlin.io.path.readBytes /** * NodeInfo signing tool for Corda @@ -66,7 +66,7 @@ class NodeInfoSigner : CordaCliWrapper("nodeinfo-signer", "Display and generate private var displayPath: Path? = null @Option(names = ["--address"], paramLabel = "host:port", description = ["Public address of node"], converter = [NetworkHostAndPortConverter::class]) - private var addressList: MutableList = mutableListOf() + private var addressList: MutableList = mutableListOf() @Option(names = ["--platform-version"], paramLabel = "int", description = ["Platform version that this node supports"]) private var platformVersion: Int = 4 @@ -93,10 +93,7 @@ class NodeInfoSigner : CordaCliWrapper("nodeinfo-signer", "Display and generate print(prompt) System.out.flush() val console = System.console() - if(console != null) - return console.readPassword().toString() - else - return readLine()!! + return console?.readPassword()?.toString() ?: readln() } private object AMQPInspectorSerializationScheme : AbstractAMQPSerializationScheme(emptyList()) { @@ -147,7 +144,7 @@ class NodeInfoSigner : CordaCliWrapper("nodeinfo-signer", "Display and generate println("address: " + nodeInfo.addresses[0]) println("platformVersion: " + nodeInfo.platformVersion) println("serial " + nodeInfo.serial) - return 0; + return 0 } else { require(addressList.size > 0){ "At least one --address must be specified" } @@ -165,7 +162,7 @@ class NodeInfoSigner : CordaCliWrapper("nodeinfo-signer", "Display and generate val nodeInfoSigned = generateNodeInfo() val fileNameHash = nodeInfoSigned.nodeInfo.legalIdentities[0].name.serialize().hash - val outputFile = outputDirectory!!.toString() / "nodeinfo-${fileNameHash.toString()}" + val outputFile = outputDirectory!! / "nodeinfo-$fileNameHash" println(outputFile) @@ -174,8 +171,8 @@ class NodeInfoSigner : CordaCliWrapper("nodeinfo-signer", "Display and generate } fun nodeInfoFromFile(nodeInfoPath: File) : NodeInfo { - var serializedNodeInfo = SerializedBytes(nodeInfoPath.toPath().readAll()) - var signedNodeInfo = serializedNodeInfo.deserialize() + val serializedNodeInfo = SerializedBytes(nodeInfoPath.toPath().readBytes()) + val signedNodeInfo = serializedNodeInfo.deserialize() return signedNodeInfo.verified() } diff --git a/experimental/quasar-hook/build.gradle b/experimental/quasar-hook/build.gradle index df09b426d7..682b063b91 100644 --- a/experimental/quasar-hook/build.gradle +++ b/experimental/quasar-hook/build.gradle @@ -1,14 +1,14 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' description 'A javaagent to allow hooking into the instrumentation by Quasar' dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - compile "org.javassist:javassist:$javaassist_version" + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + implementation "org.javassist:javassist:$javaassist_version" } +configurations.implementation.canBeResolved = true jar { archiveName = "${project.name}.jar" manifest { @@ -21,5 +21,6 @@ jar { 'Implementation-Version': rootProject.version ) } - from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + from { configurations.implementation.collect { it.isDirectory() ? it : zipTree(it) } } + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } diff --git a/experimental/src/main/kotlin/net/corda/finance/contracts/universal/PrettyPrint.kt b/experimental/src/main/kotlin/net/corda/finance/contracts/universal/PrettyPrint.kt index 9c043ffd48..3ed9dd1862 100644 --- a/experimental/src/main/kotlin/net/corda/finance/contracts/universal/PrettyPrint.kt +++ b/experimental/src/main/kotlin/net/corda/finance/contracts/universal/PrettyPrint.kt @@ -6,6 +6,7 @@ import net.corda.core.internal.uncheckedCast import java.math.BigDecimal import java.security.PublicKey import java.time.Instant +import java.util.Locale private class PrettyPrint(arr : Arrangement) { val parties = involvedParties(arr) @@ -24,7 +25,7 @@ private class PrettyPrint(arr : Arrangement) { private fun println(message: Any?) { if (atStart) repeat(indentLevel) { sb.append(' ') } - sb.appendln(message) + sb.appendLine(message) atStart = true } @@ -46,10 +47,10 @@ private class PrettyPrint(arr : Arrangement) { val usedPartyNames = mutableSetOf() fun createPartyName(party : Party): String { - val parts = party.name.organisation.toLowerCase().split(' ') + val parts = party.name.organisation.lowercase(Locale.getDefault()).split(' ') var camelName = parts.drop(1).fold(parts.first()) { - s, i -> s + i.first().toUpperCase() + i.drop(1) + s, i -> s + i.first().uppercaseChar() + i.drop(1) } if (usedPartyNames.contains(camelName)) { diff --git a/experimental/src/main/kotlin/net/corda/finance/contracts/universal/UniversalContract.kt b/experimental/src/main/kotlin/net/corda/finance/contracts/universal/UniversalContract.kt index b5b1a97c6d..0c235766e8 100644 --- a/experimental/src/main/kotlin/net/corda/finance/contracts/universal/UniversalContract.kt +++ b/experimental/src/main/kotlin/net/corda/finance/contracts/universal/UniversalContract.kt @@ -1,6 +1,12 @@ package net.corda.finance.contracts.universal -import net.corda.core.contracts.* +import net.corda.core.contracts.CommandData +import net.corda.core.contracts.Contract +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.PartyAndReference +import net.corda.core.contracts.TypeOnlyCommandData +import net.corda.core.contracts.requireSingleCommand +import net.corda.core.contracts.requireThat import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party import net.corda.core.internal.uncheckedCast @@ -182,7 +188,7 @@ class UniversalContract : Contract { "transaction has a single command".using(tx.commands.size == 1) } - val cmd = tx.commands.requireSingleCommand() + val cmd = tx.commands.requireSingleCommand() val value = cmd.value @@ -275,6 +281,7 @@ class UniversalContract : Contract { } } + @Suppress("UNCHECKED_CAST") fun replaceFixing(tx: LedgerTransaction, perceivable: Perceivable, fixings: Map, unusedFixings: MutableSet): Perceivable = when (perceivable) { @@ -282,14 +289,14 @@ class UniversalContract : Contract { is UnaryPlus -> UnaryPlus(replaceFixing(tx, perceivable.arg, fixings, unusedFixings)) is PerceivableOperation -> PerceivableOperation(replaceFixing(tx, perceivable.left, fixings, unusedFixings), perceivable.op, replaceFixing(tx, perceivable.right, fixings, unusedFixings)) - is Interest -> uncheckedCast(Interest(replaceFixing(tx, perceivable.amount, fixings, unusedFixings), + is Interest -> Interest(replaceFixing(tx, perceivable.amount, fixings, unusedFixings), perceivable.dayCountConvention, replaceFixing(tx, perceivable.interest, fixings, unusedFixings), - perceivable.start, perceivable.end)) + perceivable.start, perceivable.end) as Perceivable is Fixing -> { val dt = evalInstant(perceivable.date) if (dt != null && fixings.containsKey(FixOf(perceivable.source, dt.toLocalDate(), perceivable.tenor))) { unusedFixings.remove(FixOf(perceivable.source, dt.toLocalDate(), perceivable.tenor)) - uncheckedCast(Const(fixings[FixOf(perceivable.source, dt.toLocalDate(), perceivable.tenor)]!!)) + Const(fixings[FixOf(perceivable.source, dt.toLocalDate(), perceivable.tenor)]!!) as Perceivable } else perceivable } else -> throw NotImplementedError("replaceFixing - " + perceivable.javaClass.name) diff --git a/experimental/src/test/kotlin/net/corda/finance/contracts/universal/Cap.kt b/experimental/src/test/kotlin/net/corda/finance/contracts/universal/Cap.kt index 8a07bb3810..75df980c09 100644 --- a/experimental/src/test/kotlin/net/corda/finance/contracts/universal/Cap.kt +++ b/experimental/src/test/kotlin/net/corda/finance/contracts/universal/Cap.kt @@ -1,8 +1,8 @@ package net.corda.finance.contracts.universal -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import net.corda.core.identity.CordaX500Name import net.corda.core.node.services.IdentityService import net.corda.finance.contracts.BusinessCalendar diff --git a/experimental/src/test/kotlin/net/corda/finance/contracts/universal/ContractDefinition.kt b/experimental/src/test/kotlin/net/corda/finance/contracts/universal/ContractDefinition.kt index 4db963a9f6..019485ca6c 100644 --- a/experimental/src/test/kotlin/net/corda/finance/contracts/universal/ContractDefinition.kt +++ b/experimental/src/test/kotlin/net/corda/finance/contracts/universal/ContractDefinition.kt @@ -4,7 +4,7 @@ import net.corda.core.crypto.generateKeyPair import net.corda.core.identity.CordaX500Name import net.corda.testing.core.TestIdentity import org.junit.Test -import java.util.* +import java.util.Currency import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -118,8 +118,6 @@ class ContractDefinition { assertTrue(arr is Actions) - if (arr is Actions) { - assertEquals(1, arr.actions.size) - } + assertEquals(1, arr.actions.size) } } diff --git a/finance/contracts/build.gradle b/finance/contracts/build.gradle index 6459515034..46845fd014 100644 --- a/finance/contracts/build.gradle +++ b/finance/contracts/build.gradle @@ -1,21 +1,27 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' // Java Persistence API support: create no-arg constructor // see: http://stackoverflow.com/questions/32038177/kotlin-with-jpa-default-constructor-hell -apply plugin: 'kotlin-jpa' -apply plugin: 'net.corda.plugins.publish-utils' +apply plugin: 'org.jetbrains.kotlin.plugin.jpa' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordapp' -apply plugin: 'com.jfrog.artifactory' -apply from: "${rootProject.projectDir}/java8.gradle" +apply plugin: 'corda.common-publishing' description 'Corda finance module - contracts' dependencies { - cordaCompile project(':core') + cordaProvided project(':core') - testCompile project(':test-utils') - testCompile project(path: ':core', configuration: 'testArtifacts') - testCompile project(':node-driver') + implementation "javax.persistence:javax.persistence-api:2.2" + implementation "org.hibernate:hibernate-core:$hibernate_version" + implementation "org.slf4j:slf4j-api:$slf4j_version" + + testImplementation project(path: ':core', configuration: 'testArtifacts') + testImplementation project(':node') + testImplementation project(':node-api') + testImplementation project(':finance:workflows') + testImplementation project(':core-test-utils') + testImplementation project(':test-utils') + testImplementation project(':node-driver') testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" @@ -24,11 +30,11 @@ dependencies { testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" // AssertJ: for fluent assertions for testing - testCompile "org.assertj:assertj-core:$assertj_version" + testImplementation "org.assertj:assertj-core:$assertj_version" } configurations { - testArtifacts.extendsFrom testRuntimeClasspath + testArtifacts.extendsFrom testRuntimeOnlyClasspath } jar { @@ -45,7 +51,7 @@ cordapp { minimumPlatformVersion 1 contract { name "Corda Finance Demo" - versionId 1 + versionId 2 vendor "R3" licence "Open Source (Apache 2)" } @@ -53,6 +59,12 @@ cordapp { // ./gradlew -Dsigning.enabled="true" -Dsigning.keystore="/path/to/keystore.jks" -Dsigning.alias="alias" -Dsigning.storepass="password" -Dsigning.keypass="password" } -publish { - name jar.baseName +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-finance-contracts' + from components.cordapp + artifact javadocJar + } + } } diff --git a/finance/contracts/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt b/finance/contracts/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt index 67b075dee0..ee1e0584e6 100644 --- a/finance/contracts/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt +++ b/finance/contracts/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt @@ -4,6 +4,7 @@ import net.corda.core.contracts.* import net.corda.core.identity.AnonymousParty import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party +import net.corda.core.internal.getRequiredTransaction import net.corda.core.node.NotaryInfo import net.corda.core.node.services.Vault import net.corda.core.transactions.SignedTransaction @@ -284,8 +285,8 @@ class CommercialPaperTestsGeneric { } // Propagate the cash transactions to each side. - aliceServices.recordTransactions(bigCorpCash.states.map { megaCorpServices.validatedTransactions.getTransaction(it.ref.txhash)!! }) - megaCorpServices.recordTransactions(aliceCash.states.map { aliceServices.validatedTransactions.getTransaction(it.ref.txhash)!! }) + aliceServices.recordTransactions(bigCorpCash.states.map { megaCorpServices.getRequiredTransaction(it.ref.txhash) }) + megaCorpServices.recordTransactions(aliceCash.states.map { aliceServices.getRequiredTransaction(it.ref.txhash) }) // MegaCorp™ issues $10,000 of commercial paper, to mature in 30 days, owned initially by itself. val faceValue = 10000.DOLLARS `issued by` dummyCashIssuer.ref(1) diff --git a/finance/contracts/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt b/finance/contracts/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt index bb9356a8c4..9ac767da8d 100644 --- a/finance/contracts/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt +++ b/finance/contracts/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt @@ -31,6 +31,9 @@ import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServ import net.corda.testing.node.ledger import net.corda.testing.node.makeTestIdentityService import net.corda.testing.node.transaction +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException +import org.assertj.core.api.Assertions.assertThatIllegalStateException import org.junit.After import org.junit.Before import org.junit.Rule @@ -300,7 +303,7 @@ class CashTests { * Test that the issuance builder rejects building into a transaction with existing * cash inputs. */ - @Test(expected = IllegalStateException::class, timeout=300_000) + @Test(timeout=300_000) fun `reject issuance with inputs`() { // Issue some cash var ptx = TransactionBuilder(dummyNotary.party) @@ -311,7 +314,9 @@ class CashTests { // Include the previously issued cash in a new issuance command ptx = TransactionBuilder(dummyNotary.party) ptx.addInputState(tx.tx.outRef(0)) - Cash().generateIssue(ptx, 100.DOLLARS `issued by` miniCorp.ref(12, 34), owner = miniCorp.party, notary = dummyNotary.party) + assertThatIllegalStateException().isThrownBy { + Cash().generateIssue(ptx, 100.DOLLARS `issued by` miniCorp.ref(12, 34), owner = miniCorp.party, notary = dummyNotary.party) + } } @Test(timeout=300_000) @@ -762,13 +767,15 @@ class CashTests { assertEquals(6000.DOLLARS `issued by` defaultIssuer, states.sumCashBy(megaCorp.party)) } - @Test(expected = UnsupportedOperationException::class, timeout=300_000) + @Test(timeout=300_000) fun `summing by owner throws`() { val states = listOf( Cash.State(2000.DOLLARS `issued by` defaultIssuer, megaCorp.party), Cash.State(4000.DOLLARS `issued by` defaultIssuer, megaCorp.party) ) - states.sumCashBy(miniCorp.party) + assertThatExceptionOfType(UnsupportedOperationException::class.java).isThrownBy { + states.sumCashBy(miniCorp.party) + } } @Test(timeout=300_000) @@ -778,10 +785,12 @@ class CashTests { assertNull(states.sumCashOrNull()) } - @Test(expected = UnsupportedOperationException::class, timeout=300_000) + @Test(timeout=300_000) fun `summing no currencies throws`() { val states = emptyList() - states.sumCash() + assertThatExceptionOfType(UnsupportedOperationException::class.java).isThrownBy { + states.sumCash() + } } @Test(timeout=300_000) @@ -797,14 +806,16 @@ class CashTests { assertEquals(expected, actual) } - @Test(expected = IllegalArgumentException::class, timeout=300_000) + @Test(timeout=300_000) fun `summing multiple currencies`() { val states = listOf( Cash.State(1000.DOLLARS `issued by` defaultIssuer, megaCorp.party), Cash.State(4000.POUNDS `issued by` defaultIssuer, megaCorp.party) ) // Test that summing everything fails because we're mixing units - states.sumCash() + assertThatIllegalArgumentException().isThrownBy { + states.sumCash() + } } // Double spend. diff --git a/finance/contracts/src/test/kotlin/net/corda/finance/contracts/asset/ObligationTests.kt b/finance/contracts/src/test/kotlin/net/corda/finance/contracts/asset/ObligationTests.kt index 6b0d18f71e..2987384530 100644 --- a/finance/contracts/src/test/kotlin/net/corda/finance/contracts/asset/ObligationTests.kt +++ b/finance/contracts/src/test/kotlin/net/corda/finance/contracts/asset/ObligationTests.kt @@ -1,9 +1,14 @@ package net.corda.finance.contracts.asset -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever -import net.corda.core.contracts.* +import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint +import net.corda.core.contracts.Amount +import net.corda.core.contracts.BelongsToContract +import net.corda.core.contracts.ContractClassName +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.Issued +import net.corda.core.contracts.StateAndRef +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TransactionState import net.corda.core.crypto.NullKeys.NULL_PARTY import net.corda.core.crypto.SecureHash import net.corda.core.crypto.sha256 @@ -16,25 +21,44 @@ import net.corda.core.utilities.NonEmptySet import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.days import net.corda.core.utilities.hours -import net.corda.finance.* +import net.corda.coretesting.internal.TEST_TX_TIME +import net.corda.finance.DOLLARS +import net.corda.finance.GBP +import net.corda.finance.POUNDS +import net.corda.finance.USD import net.corda.finance.contracts.Commodity import net.corda.finance.contracts.NetType import net.corda.finance.contracts.asset.Obligation.Lifecycle +import net.corda.finance.`issued by` import net.corda.finance.workflows.asset.ObligationUtils import net.corda.testing.contracts.DummyContract -import net.corda.testing.core.* -import net.corda.testing.dsl.* -import net.corda.coretesting.internal.TEST_TX_TIME +import net.corda.testing.core.ALICE_NAME +import net.corda.testing.core.BOB_NAME +import net.corda.testing.core.CHARLIE_NAME +import net.corda.testing.core.DUMMY_NOTARY_NAME +import net.corda.testing.core.DummyCommandData +import net.corda.testing.core.SerializationEnvironmentRule +import net.corda.testing.core.TestIdentity +import net.corda.testing.dsl.EnforceVerifyOrFail +import net.corda.testing.dsl.LedgerDSL +import net.corda.testing.dsl.TestLedgerDSLInterpreter +import net.corda.testing.dsl.TestTransactionDSLInterpreter +import net.corda.testing.dsl.TransactionDSL +import net.corda.testing.dsl.TransactionDSLInterpreter import net.corda.testing.internal.fakeAttachment import net.corda.testing.internal.vault.CommodityState import net.corda.testing.node.MockServices import net.corda.testing.node.ledger import net.corda.testing.node.transaction +import org.assertj.core.api.Assertions.assertThatIllegalStateException import org.junit.Rule import org.junit.Test +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import java.time.Instant import java.time.temporal.ChronoUnit -import java.util.* +import java.util.Currency import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertNotEquals @@ -253,7 +277,7 @@ class ObligationTests { * Test that the issuance builder rejects building into a transaction with existing * cash inputs. */ - @Test(expected = IllegalStateException::class, timeout=300_000) + @Test(timeout=300_000) fun `reject issuance with inputs`() { // Issue some obligation val tx = TransactionBuilder(DUMMY_NOTARY).apply { @@ -265,8 +289,10 @@ class ObligationTests { // Include the previously issued obligation in a new issuance command val ptx = TransactionBuilder(DUMMY_NOTARY) ptx.addInputState(tx.outRef>(0)) - ObligationUtils.generateIssue(ptx, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, - beneficiary = MINI_CORP, notary = DUMMY_NOTARY) + assertThatIllegalStateException().isThrownBy { + ObligationUtils.generateIssue(ptx, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, + beneficiary = MINI_CORP, notary = DUMMY_NOTARY) + } } /** Test generating a transaction to net two obligations of the same size, and therefore there are no outputs. */ @@ -576,7 +602,7 @@ class ObligationTests { val defaultFcoj = Issued(defaultIssuer, Commodity.getInstance("FCOJ")!!) val oneUnitFcoj = Amount(1, defaultFcoj) val obligationDef = Obligation.Terms(NonEmptySet.of(commodityContractBytes.sha256() as SecureHash), NonEmptySet.of(defaultFcoj), TEST_TX_TIME) - val oneUnitFcojObligation = Obligation.State(Obligation.Lifecycle.NORMAL, ALICE, + val oneUnitFcojObligation = Obligation.State(Lifecycle.NORMAL, ALICE, obligationDef, oneUnitFcoj.quantity, NULL_PARTY) // Try settling a simple commodity obligation ledgerServices.ledger(DUMMY_NOTARY) { @@ -853,9 +879,11 @@ class ObligationTests { fiveKDollarsFromMegaToMega.copy(template = megaCorpDollarSettlement.copy(acceptableIssuedProducts = miniCorpIssuer)).bilateralNetState) } - @Test(expected = IllegalStateException::class, timeout=300_000) + @Test(timeout=300_000) fun `states cannot be netted if not in the normal state`() { - inState.copy(lifecycle = Lifecycle.DEFAULTED).bilateralNetState + assertThatIllegalStateException().isThrownBy { + inState.copy(lifecycle = Lifecycle.DEFAULTED).bilateralNetState + } } /** @@ -968,5 +996,5 @@ class ObligationTests { private val Issued.OBLIGATION_DEF: Obligation.Terms get() = Obligation.Terms(NonEmptySet.of(cashContractBytes.sha256() as SecureHash), NonEmptySet.of(this), TEST_TX_TIME) private val Amount>.OBLIGATION: Obligation.State - get() = Obligation.State(Obligation.Lifecycle.NORMAL, DUMMY_OBLIGATION_ISSUER, token.OBLIGATION_DEF, quantity, NULL_PARTY) -} \ No newline at end of file + get() = Obligation.State(Lifecycle.NORMAL, DUMMY_OBLIGATION_ISSUER, token.OBLIGATION_DEF, quantity, NULL_PARTY) +} diff --git a/finance/workflows/build.gradle b/finance/workflows/build.gradle index 20e8a388b9..d52deea15a 100644 --- a/finance/workflows/build.gradle +++ b/finance/workflows/build.gradle @@ -1,11 +1,10 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' // Java Persistence API support: create no-arg constructor // see: http://stackoverflow.com/questions/32038177/kotlin-with-jpa-default-constructor-hell -apply plugin: 'kotlin-jpa' -apply plugin: 'net.corda.plugins.publish-utils' +apply plugin: 'org.jetbrains.kotlin.plugin.jpa' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordapp' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' description 'Corda finance module - flows' @@ -23,8 +22,8 @@ sourceSets { } configurations { - testArtifacts.extendsFrom testRuntimeClasspath - integrationTestCompile.extendsFrom testCompile + testArtifacts.extendsFrom testRuntimeOnlyClasspath + integrationTestImplementation.extendsFrom testImplementation integrationTestRuntimeOnly.extendsFrom testRuntimeOnly } @@ -32,24 +31,29 @@ dependencies { // Note: 3rd party CorDapps should remember to include the relevant Finance CorDapp dependencies using `cordapp` // cordapp project(':finance:workflows') // cordapp project(':finance:contracts') - cordaCompile project(':core') - cordaCompile project(':confidential-identities') + cordaProvided project(':core') + cordaProvided project(':confidential-identities') cordapp project(':finance:contracts') - testCompile project(':test-utils') - testCompile project(path: ':core', configuration: 'testArtifacts') - testCompile project(':node-driver') + testImplementation project(':node') + testImplementation project(':node-api') + testImplementation project(':node-driver') + testImplementation project(':serialization') + testImplementation project(path: ':core', configuration: 'testArtifacts') + testImplementation project(':core-test-utils') + testImplementation project(':test-utils') testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" + testImplementation "org.apache.qpid:proton-j:$protonj_version" testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" // AssertJ: for fluent assertions for testing - testCompile "org.assertj:assertj-core:$assertj_version" + testImplementation "org.assertj:assertj-core:$assertj_version" } task testJar(type: Jar) { @@ -62,12 +66,13 @@ task integrationTest(type: Test, dependsOn: []) { classpath = sourceSets.integrationTest.runtimeClasspath } -artifacts { - testArtifacts testJar +jar { + archiveBaseName = 'corda-finance-workflows' + archiveClassifier = '' } -jar { - baseName 'corda-finance-workflows' +artifacts { + testArtifacts testJar } cordapp { @@ -83,6 +88,12 @@ cordapp { // ./gradlew -Dsigning.enabled="true" -Dsigning.keystore="/path/to/keystore.jks" -Dsigning.alias="alias" -Dsigning.storepass="password" -Dsigning.keypass="password" } -publish { - name jar.baseName +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-finance-workflows' + from components.cordapp + artifact javadocJar + } + } } diff --git a/finance/workflows/src/main/kotlin/net/corda/finance/workflows/asset/selection/AbstractCashSelection.kt b/finance/workflows/src/main/kotlin/net/corda/finance/workflows/asset/selection/AbstractCashSelection.kt index 403c80e287..7e46dde20d 100644 --- a/finance/workflows/src/main/kotlin/net/corda/finance/workflows/asset/selection/AbstractCashSelection.kt +++ b/finance/workflows/src/main/kotlin/net/corda/finance/workflows/asset/selection/AbstractCashSelection.kt @@ -8,15 +8,20 @@ import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party -import net.corda.core.internal.uncheckedCast import net.corda.core.node.ServiceHub import net.corda.core.node.services.StatesNotAvailableException -import net.corda.core.utilities.* +import net.corda.core.utilities.OpaqueBytes +import net.corda.core.utilities.contextLogger +import net.corda.core.utilities.millis +import net.corda.core.utilities.toNonEmptySet +import net.corda.core.utilities.trace import net.corda.finance.contracts.asset.Cash import java.sql.Connection import java.sql.DatabaseMetaData import java.sql.ResultSet -import java.util.* +import java.util.Currency +import java.util.ServiceLoader +import java.util.UUID import java.util.concurrent.atomic.AtomicReference /** @@ -31,8 +36,8 @@ abstract class AbstractCashSelection(private val maxRetries : Int = 8, private v companion object { val instance = AtomicReference() - fun getInstance(metadata: () -> java.sql.DatabaseMetaData): AbstractCashSelection { - return instance.get() ?: { + fun getInstance(metadata: () -> DatabaseMetaData): AbstractCashSelection { + return instance.get() ?: run { val metadataLocal = metadata() val cashSelectionAlgos = ServiceLoader.load(AbstractCashSelection::class.java, this::class.java.classLoader).toList() val cashSelectionAlgo = cashSelectionAlgos.firstOrNull { it.isCompatible(metadataLocal) } @@ -42,7 +47,7 @@ abstract class AbstractCashSelection(private val maxRetries : Int = 8, private v } ?: throw ClassNotFoundException("\nUnable to load compatible cash selection algorithm implementation for JDBC driver name '${metadataLocal.driverName}'." + "\nPlease specify an implementation in META-INF/services/${AbstractCashSelection::class.qualifiedName}." + "\nAvailable implementations: $cashSelectionAlgos") - }.invoke() + } } private val log = contextLogger() @@ -139,19 +144,20 @@ abstract class AbstractCashSelection(private val maxRetries : Int = 8, private v if (stateRefs.isNotEmpty()) { // TODO: future implementation to retrieve contract states from a Vault BLOB store - stateAndRefs.addAll(uncheckedCast(services.loadStates(stateRefs))) + @Suppress("UNCHECKED_CAST") + stateAndRefs.addAll(services.loadStates(stateRefs) as Collection>) } val success = stateAndRefs.isNotEmpty() && totalPennies >= amount.quantity if (success) { // we should have a minimum number of states to satisfy our selection `amount` criteria - log.trace("Coin selection for $amount retrieved ${stateAndRefs.count()} states totalling $totalPennies pennies: $stateAndRefs") + log.trace { "Coin selection for $amount retrieved ${stateAndRefs.count()} states totalling $totalPennies pennies: $stateAndRefs" } // With the current single threaded state machine available states are guaranteed to lock. // TODO However, we will have to revisit these methods in the future multi-threaded. services.vaultService.softLockReserve(lockId, (stateAndRefs.map { it.ref }).toNonEmptySet()) } else { - log.trace("Coin selection requested $amount but retrieved $totalPennies pennies with state refs: ${stateAndRefs.map { it.ref }}") + log.trace { "Coin selection requested $amount but retrieved $totalPennies pennies with state refs: ${stateAndRefs.map { it.ref }}" } } success } diff --git a/gradle.properties b/gradle.properties index a54780ad19..2a11c69c5c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,10 @@ kotlin.incremental=true -org.gradle.jvmargs=-XX:+UseG1GC -Xmx4g -Dfile.encoding=UTF-8 -org.gradle.caching=true +org.gradle.jvmargs=-Xmx6g -Dfile.encoding=UTF-8' +org.gradle.caching=false owasp.failOnError=false owasp.failBuildOnCVSS=11.0 compilation.allWarningsAsErrors=false test.parallel=false - -# Gradle Enterprise -gradleEnterpriseUrl = https://gradle.dev.r3.com -gradleEnterprisePlugin = 3.8.1 -customUserDataGradlePlugin = 1.6.3 +kotlin_version=1.9.20 +commons_lang3_version=3.12.0 +json_api_version=1.1.4 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016..afba109285 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0ebb3108e2..5c00f617e8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-all.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 83f2acfdc3..65dcd68d65 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,78 +17,113 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -105,84 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done fi +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 24467a141f..6689b85bee 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,10 +25,14 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,38 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/isolated/build.gradle b/isolated/build.gradle index dbb1095c99..d21f442372 100644 --- a/isolated/build.gradle +++ b/isolated/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.cordapp' description 'Isolated CorDapp for testing' diff --git a/java8.gradle b/java8.gradle deleted file mode 100644 index 50a462aa41..0000000000 --- a/java8.gradle +++ /dev/null @@ -1,22 +0,0 @@ -import static org.gradle.api.JavaVersion.VERSION_1_8 - -/* - * Gradle script plugin: Configure a module such that Java and Kotlin - * are always compiled for Java 8. - */ -apply plugin: 'kotlin' - -tasks.withType(AbstractCompile).configureEach { - // This is a bit ugly, but Gradle isn't recognising the KotlinCompile task - // as it does the built-in JavaCompile task. - if (it.class.name.startsWith('org.jetbrains.kotlin.gradle.tasks.KotlinCompile')) { - kotlinOptions { - jvmTarget = VERSION_1_8 - } - } -} - -tasks.withType(JavaCompile).configureEach { - sourceCompatibility = VERSION_1_8 - targetCompatibility = VERSION_1_8 -} diff --git a/node-api-tests/build.gradle b/node-api-tests/build.gradle index 8d4edc4aff..36f19894ac 100644 --- a/node-api-tests/build.gradle +++ b/node-api-tests/build.gradle @@ -1,20 +1,38 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.quasar-utils' description 'NodeAPI tests that require node etc' dependencies { - testCompile project(":node-api") - testCompile project(path: ':node-api', configuration:'testArtifacts') + testImplementation project(":core") + testImplementation project(":node") + testImplementation project(":node-api") + testImplementation project(":serialization") + testImplementation project(":core-test-utils") + testImplementation project(path: ':node-api', configuration:'testArtifacts') + + testImplementation "javax.persistence:javax.persistence-api:2.2" testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" + testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" + testImplementation "com.typesafe:config:$typesafe_config_version" + testImplementation "io.dropwizard.metrics:metrics-core:$metrics_version" + testImplementation "co.paralleluniverse:quasar-core:$quasar_version" + testImplementation "com.google.guava:guava:$guava_version" + + testImplementation "io.netty:netty-transport-native-unix-common:$netty_version" + testImplementation "io.netty:netty-handler-proxy:$netty_version" + + // Bouncy castle support needed for X509 certificate manipulation + testImplementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}" + testImplementation "org.bouncycastle:bcpkix-lts8on:${bouncycastle_version}" testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" // Unit testing helpers. - testCompile "org.assertj:assertj-core:$assertj_version" - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - testCompile project(':node-driver') - testCompile project(':test-utils') + testImplementation "org.assertj:assertj-core:$assertj_version" + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + testImplementation project(':node-driver') + testImplementation project(':test-utils') } diff --git a/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/AttachmentsClassLoaderStaticContractTests.kt b/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/AttachmentsClassLoaderStaticContractTests.kt index e6aa5e3963..d08375d8aa 100644 --- a/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/AttachmentsClassLoaderStaticContractTests.kt +++ b/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/AttachmentsClassLoaderStaticContractTests.kt @@ -1,34 +1,24 @@ package net.corda.nodeapitests.internal -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever -import net.corda.core.contracts.* -import net.corda.core.crypto.SecureHash +import net.corda.core.contracts.Command +import net.corda.core.contracts.CommandData +import net.corda.core.contracts.Contract +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.PartyAndReference +import net.corda.core.contracts.StateAndContract +import net.corda.core.contracts.TypeOnlyCommandData import net.corda.core.identity.AbstractParty import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party -import net.corda.core.node.ServicesForResolution -import net.corda.core.node.services.AttachmentStorage -import net.corda.core.node.services.IdentityService -import net.corda.core.node.services.NetworkParametersService import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.TransactionBuilder -import net.corda.nodeapi.internal.cordapp.CordappLoader -import net.corda.node.internal.cordapp.CordappProviderImpl -import net.corda.node.internal.cordapp.JarScanningCordappLoader import net.corda.nodeapitests.internal.AttachmentsClassLoaderStaticContractTests.AttachmentDummyContract.Companion.ATTACHMENT_PROGRAM_ID -import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.TestIdentity -import net.corda.testing.internal.MockCordappConfigProvider -import net.corda.coretesting.internal.rigorousMock -import net.corda.testing.node.internal.cordappWithPackages -import net.corda.testing.services.MockAttachmentStorage +import net.corda.testing.node.MockServices import org.assertj.core.api.Assertions.assertThat import org.junit.Assert.assertEquals import org.junit.Rule @@ -69,31 +59,7 @@ class AttachmentsClassLoaderStaticContractTests { } } - private val networkParameters = testNetworkParameters() - - private val networkParametersService get() = mock().also { - doReturn(networkParameters.serialize().hash).whenever(it).currentHash - } - - private val serviceHub get() = rigorousMock().also { - val cordappProviderImpl = CordappProviderImpl(cordappLoaderForPackages(listOf("net.corda.nodeapitests.internal")), MockCordappConfigProvider(), MockAttachmentStorage()) - cordappProviderImpl.start() - doReturn(cordappProviderImpl).whenever(it).cordappProvider - doReturn(networkParametersService).whenever(it).networkParametersService - doReturn(networkParameters).whenever(it).networkParameters - val attachmentStorage = rigorousMock() - doReturn(attachmentStorage).whenever(it).attachments - val attachment = rigorousMock() - doReturn(attachment).whenever(attachmentStorage).openAttachment(any()) - doReturn(it.cordappProvider.getContractAttachmentID(AttachmentDummyContract.ATTACHMENT_PROGRAM_ID)).whenever(attachment).id - doReturn(setOf(AttachmentDummyContract.ATTACHMENT_PROGRAM_ID)).whenever(attachment).allContracts - doReturn("app").whenever(attachment).uploader - doReturn(emptyList()).whenever(attachment).signerKeys - val contractAttachmentId = SecureHash.randomSHA256() - doReturn(listOf(contractAttachmentId)).whenever(attachmentStorage) - .getLatestContractAttachments(AttachmentDummyContract.ATTACHMENT_PROGRAM_ID) - doReturn(mock()).whenever(it).identityService - } + private val serviceHub = MockServices() @Test(timeout=300_000) fun `test serialization of WireTransaction with statically loaded contract`() { @@ -112,8 +78,4 @@ class AttachmentsClassLoaderStaticContractTests { val contractClass = Class.forName(ATTACHMENT_PROGRAM_ID) assertThat(contractClass.getDeclaredConstructor().newInstance()).isInstanceOf(Contract::class.java) } - - private fun cordappLoaderForPackages(packages: Collection): CordappLoader { - return JarScanningCordappLoader.fromJarUrls(listOf(cordappWithPackages(*packages.toTypedArray()).jarFile.toUri().toURL())) - } } diff --git a/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/crypto/X509UtilitiesTest.kt b/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/crypto/X509UtilitiesTest.kt index 9affc6a0b1..b96b910468 100644 --- a/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/crypto/X509UtilitiesTest.kt +++ b/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/crypto/X509UtilitiesTest.kt @@ -1,6 +1,5 @@ package net.corda.nodeapitests.internal.crypto - import io.netty.handler.ssl.ClientAuth import io.netty.handler.ssl.SslContextBuilder import io.netty.handler.ssl.SslProvider @@ -10,12 +9,10 @@ import net.corda.core.crypto.Crypto.ECDSA_SECP256K1_SHA256 import net.corda.core.crypto.Crypto.ECDSA_SECP256R1_SHA256 import net.corda.core.crypto.Crypto.EDDSA_ED25519_SHA512 import net.corda.core.crypto.Crypto.RSA_SHA256 -import net.corda.core.crypto.Crypto.SPHINCS256_SHA256 import net.corda.core.crypto.Crypto.generateKeyPair import net.corda.core.crypto.SignatureScheme import net.corda.core.crypto.newSecureRandom import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.div import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize @@ -52,9 +49,7 @@ import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.BOB_NAME import net.corda.testing.core.TestIdentity import net.corda.testing.driver.internal.incrementalPortAllocation -import net.corda.testing.internal.IS_OPENJ9 import net.corda.testing.internal.createDevIntermediateCaCertPath -import net.i2p.crypto.eddsa.EdDSAPrivateKey import org.assertj.core.api.Assertions.assertThat import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier import org.bouncycastle.asn1.x509.BasicConstraints @@ -62,9 +57,6 @@ import org.bouncycastle.asn1.x509.CRLDistPoint import org.bouncycastle.asn1.x509.Extension import org.bouncycastle.asn1.x509.KeyUsage import org.bouncycastle.asn1.x509.SubjectKeyIdentifier -import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPrivateKey -import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey -import org.junit.Assume import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder @@ -79,13 +71,15 @@ import java.security.KeyPair import java.security.PrivateKey import java.security.cert.CertPath import java.security.cert.X509Certificate -import java.util.* +import java.security.interfaces.EdECPrivateKey +import java.util.Date import javax.net.ssl.SSLContext import javax.net.ssl.SSLParameters import javax.net.ssl.SSLServerSocket import javax.net.ssl.SSLSocket import javax.security.auth.x500.X500Principal import kotlin.concurrent.thread +import kotlin.io.path.div import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertFalse @@ -112,21 +106,17 @@ class X509UtilitiesTest { Pair(DEFAULT_TLS_SIGNATURE_SCHEME, DEFAULT_TLS_SIGNATURE_SCHEME), Pair(DEFAULT_IDENTITY_SIGNATURE_SCHEME, DEFAULT_IDENTITY_SIGNATURE_SCHEME), Pair(DEFAULT_TLS_SIGNATURE_SCHEME, DEFAULT_IDENTITY_SIGNATURE_SCHEME), - Pair(ECDSA_SECP256R1_SHA256, SPHINCS256_SHA256), Pair(ECDSA_SECP256K1_SHA256, RSA_SHA256), Pair(EDDSA_ED25519_SHA512, ECDSA_SECP256K1_SHA256), Pair(RSA_SHA256, EDDSA_ED25519_SHA512), Pair(EDDSA_ED25519_SHA512, ECDSA_SECP256R1_SHA256), - Pair(SPHINCS256_SHA256, ECDSA_SECP256R1_SHA256) ) val schemeToKeyTypes = listOf( // By default, JKS returns SUN EC key. - Triple(ECDSA_SECP256R1_SHA256,java.security.interfaces.ECPrivateKey::class.java, org.bouncycastle.jce.interfaces.ECPrivateKey::class.java), - Triple(ECDSA_SECP256K1_SHA256,java.security.interfaces.ECPrivateKey::class.java, org.bouncycastle.jce.interfaces.ECPrivateKey::class.java), - Triple(EDDSA_ED25519_SHA512, EdDSAPrivateKey::class.java, EdDSAPrivateKey::class.java), - // By default, JKS returns SUN RSA key. - Triple(SPHINCS256_SHA256, BCSphincs256PrivateKey::class.java, BCSphincs256PrivateKey::class.java) + Triple(ECDSA_SECP256R1_SHA256, java.security.interfaces.ECPrivateKey::class.java, org.bouncycastle.jce.interfaces.ECPrivateKey::class.java), + Triple(ECDSA_SECP256K1_SHA256, java.security.interfaces.ECPrivateKey::class.java, org.bouncycastle.jce.interfaces.ECPrivateKey::class.java), + Triple(EDDSA_ED25519_SHA512, EdECPrivateKey::class.java, EdECPrivateKey::class.java), ) } @@ -136,8 +126,7 @@ class X509UtilitiesTest { @Test(timeout=300_000) fun `create valid self-signed CA certificate`() { - Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY - && ( it != SPHINCS256_SHA256)}.forEach { validSelfSignedCertificate(it) } + Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY }.forEach { validSelfSignedCertificate(it) } } private fun validSelfSignedCertificate(signatureScheme: SignatureScheme) { @@ -158,7 +147,7 @@ class X509UtilitiesTest { @Test(timeout=300_000) fun `load and save a PEM file certificate`() { - Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY }.forEach { loadSavePEMCert(it) } + Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY }.forEach(::loadSavePEMCert) } private fun loadSavePEMCert(signatureScheme: SignatureScheme) { @@ -172,8 +161,7 @@ class X509UtilitiesTest { @Test(timeout=300_000) fun `create valid server certificate chain`() { - certChainSchemeCombinations.filter{ it.first != SPHINCS256_SHA256 } - .forEach { createValidServerCertChain(it.first, it.second) } + certChainSchemeCombinations.forEach { createValidServerCertChain(it.first, it.second) } } private fun createValidServerCertChain(signatureSchemeRoot: SignatureScheme, signatureSchemeChild: SignatureScheme) { @@ -231,7 +219,7 @@ class X509UtilitiesTest { val certCrlDistPoint = CRLDistPoint.getInstance(getExtension(Extension.cRLDistributionPoints).parsedValue) assertTrue(certCrlDistPoint.distributionPoints.first().distributionPoint.toString().contains(crlDistPoint)) val certCaAuthorityKeyIdentifier = AuthorityKeyIdentifier.getInstance(getExtension(Extension.authorityKeyIdentifier).parsedValue) - assertTrue(Arrays.equals(caSubjectKeyIdentifier.keyIdentifier, certCaAuthorityKeyIdentifier.keyIdentifier)) + assertThat(caSubjectKeyIdentifier.keyIdentifier).isEqualTo(certCaAuthorityKeyIdentifier.keyIdentifier) } } @@ -247,7 +235,7 @@ class X509UtilitiesTest { val testName = X500Principal("CN=Test,O=R3 Ltd,L=London,C=GB") val selfSignCert = X509Utilities.createSelfSignedCACertificate(testName, keyPair) - assertTrue(Arrays.equals(selfSignCert.publicKey.encoded, keyPair.public.encoded)) + assertThat(selfSignCert.publicKey.encoded).isEqualTo(keyPair.public.encoded) // Save the private key with self sign cert in the keystore. val keyStore = loadOrCreateKeyStore(tmpKeyStore, "keystorepass") @@ -296,8 +284,8 @@ class X509UtilitiesTest { // Now sign something with private key and verify against certificate public key val testData = "123456".toByteArray() - val signature = Crypto.doSign(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME, serverKeyPair.private, testData) - assertTrue { Crypto.isValid(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME, serverCert.publicKey, signature, testData) } + val signature = Crypto.doSign(DEFAULT_TLS_SIGNATURE_SCHEME, serverKeyPair.private, testData) + assertTrue { Crypto.isValid(DEFAULT_TLS_SIGNATURE_SCHEME, serverCert.publicKey, signature, testData) } } @Test(timeout=300_000) @@ -389,7 +377,6 @@ class X509UtilitiesTest { @Test(timeout=300_000) fun `create server cert and use in OpenSSL channel`() { - Assume.assumeTrue(!IS_OPENJ9) val sslConfig = CertificateStoreStubs.P2P.withCertificatesDirectory(tempFolder.root.toPath(), keyStorePassword = "serverstorepass") val (rootCa, intermediateCa) = createDevIntermediateCaCertPath() @@ -452,13 +439,11 @@ class X509UtilitiesTest { schemeToKeyTypes.forEach { getCorrectKeyFromKeystore(it.first, it.second, it.third) } } - private fun getCorrectKeyFromKeystore(signatureScheme: SignatureScheme, uncastedClass: Class, castedClass: Class) { + private fun getCorrectKeyFromKeystore(signatureScheme: SignatureScheme, rawClass: Class, supportedClass: Class) { val keyPair = generateKeyPair(signatureScheme) - val (keyFromKeystore, keyFromKeystoreCasted) = storeAndGetKeysFromKeystore(keyPair) - if (uncastedClass == EdDSAPrivateKey::class.java && keyFromKeystore !is BCEdDSAPrivateKey) { - assertThat(keyFromKeystore).isInstanceOf(uncastedClass) - } - assertThat(keyFromKeystoreCasted).isInstanceOf(castedClass) + val (rawKey, supportedKey) = storeAndGetKeysFromKeystore(keyPair) + assertThat(rawKey).isInstanceOf(rawClass) + assertThat(supportedKey).isInstanceOf(supportedClass) } private fun storeAndGetKeysFromKeystore(keyPair: KeyPair): Pair { @@ -467,9 +452,9 @@ class X509UtilitiesTest { val keyStore = loadOrCreateKeyStore(tempFile("testKeystore.jks"), "keystorepassword") keyStore.setKeyEntry("Key", keyPair.private, "keypassword".toCharArray(), arrayOf(selfSignCert)) - val keyFromKeystore = keyStore.getKey("Key", "keypassword".toCharArray()) - val keyFromKeystoreCasted = keyStore.getSupportedKey("Key", "keypassword") - return Pair(keyFromKeystore, keyFromKeystoreCasted) + val rawKey = keyStore.getKey("Key", "keypassword".toCharArray()) + val supportedKey = keyStore.getSupportedKey("Key", "keypassword") + return Pair(rawKey, supportedKey) } @Test(timeout=300_000) diff --git a/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/network/NetworkBootstrapperTest.kt b/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/network/NetworkBootstrapperTest.kt index 1bb90dd223..0607d971f5 100644 --- a/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/network/NetworkBootstrapperTest.kt +++ b/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/network/NetworkBootstrapperTest.kt @@ -4,68 +4,74 @@ import com.typesafe.config.ConfigFactory import net.corda.core.crypto.secureRandomBytes import net.corda.core.crypto.sha256 import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.* +import net.corda.core.internal.NODE_INFO_DIRECTORY +import net.corda.core.internal.PLATFORM_VERSION +import net.corda.core.internal.copyTo +import net.corda.core.internal.readObject import net.corda.core.node.NetworkParameters import net.corda.core.node.NodeInfo import net.corda.core.serialization.serialize +import net.corda.core.utilities.days +import net.corda.coretesting.internal.createNodeInfoAndSigned import net.corda.node.services.config.NotaryConfig import net.corda.nodeapi.internal.DEV_ROOT_CA -import net.corda.core.internal.NODE_INFO_DIRECTORY -import net.corda.core.utilities.days import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.config.parseAs import net.corda.nodeapi.internal.config.toConfig +import net.corda.nodeapi.internal.network.CopyCordapps +import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME +import net.corda.nodeapi.internal.network.NetworkBootstrapper import net.corda.nodeapi.internal.network.NetworkBootstrapper.Companion.DEFAULT_MAX_MESSAGE_SIZE import net.corda.nodeapi.internal.network.NetworkBootstrapper.Companion.DEFAULT_MAX_TRANSACTION_SIZE +import net.corda.nodeapi.internal.network.NetworkParametersOverrides import net.corda.nodeapi.internal.network.NodeInfoFilesCopier.Companion.NODE_INFO_FILE_NAME_PREFIX +import net.corda.nodeapi.internal.network.PackageOwner +import net.corda.nodeapi.internal.network.SignedNetworkParameters +import net.corda.nodeapi.internal.network.TestContractsJar +import net.corda.nodeapi.internal.network.verifiedNetworkParametersCert import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.BOB_NAME import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.TestIdentity -import net.corda.coretesting.internal.createNodeInfoAndSigned -import net.corda.nodeapi.internal.network.CopyCordapps -import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME -import net.corda.nodeapi.internal.network.NetworkBootstrapper -import net.corda.nodeapi.internal.network.NetworkParametersOverrides -import net.corda.nodeapi.internal.network.PackageOwner -import net.corda.nodeapi.internal.network.SignedNetworkParameters -import net.corda.nodeapi.internal.network.TestContractsJar -import net.corda.nodeapi.internal.network.verifiedNetworkParametersCert import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.After import org.junit.AfterClass import org.junit.Rule import org.junit.Test -import org.junit.rules.ExpectedException +import org.junit.jupiter.api.assertThrows import org.junit.rules.TemporaryFolder import java.nio.file.Files import java.nio.file.Path import java.security.PublicKey import java.time.Duration -import kotlin.streams.toList +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.name +import kotlin.io.path.readBytes +import kotlin.io.path.useDirectoryEntries +import kotlin.io.path.writeBytes +import kotlin.io.path.writeText +import kotlin.test.assertEquals class NetworkBootstrapperTest { @Rule @JvmField val tempFolder = TemporaryFolder() - @Rule - @JvmField - val expectedEx: ExpectedException = ExpectedException.none() - @Rule @JvmField val testSerialization = SerializationEnvironmentRule() companion object { private val fakeEmbeddedCorda = fakeFileBytes() - private val fakeEmbeddedCordaJar = Files.createTempFile("corda", ".jar").write(fakeEmbeddedCorda) + private val fakeEmbeddedCordaJar = Files.createTempFile("corda", ".jar").apply { writeBytes(fakeEmbeddedCorda) } private fun fakeFileBytes(writeToFile: Path? = null): ByteArray { val bytes = secureRandomBytes(128) - writeToFile?.write(bytes) + writeToFile?.writeBytes(bytes) return bytes } @@ -263,8 +269,8 @@ class NetworkBootstrapperTest { assertThat(networkParameters.eventHorizon).isEqualTo(eventHorizon) } - private val ALICE = TestIdentity(ALICE_NAME, 70) - private val BOB = TestIdentity(BOB_NAME, 80) + private val alice = TestIdentity(ALICE_NAME, 70) + private val bob = TestIdentity(BOB_NAME, 80) private val alicePackageName = "com.example.alice" private val bobPackageName = "com.example.bob" @@ -272,39 +278,40 @@ class NetworkBootstrapperTest { @Test(timeout=300_000) fun `register new package namespace in existing network`() { createNodeConfFile("alice", aliceConfig) - bootstrap(packageOwnership = mapOf(Pair(alicePackageName, ALICE.publicKey))) - assertContainsPackageOwner("alice", mapOf(Pair(alicePackageName, ALICE.publicKey))) + bootstrap(packageOwnership = mapOf(Pair(alicePackageName, alice.publicKey))) + assertContainsPackageOwner("alice", mapOf(Pair(alicePackageName, alice.publicKey))) } @Test(timeout=300_000) fun `register additional package namespace in existing network`() { createNodeConfFile("alice", aliceConfig) - bootstrap(packageOwnership = mapOf(Pair(alicePackageName, ALICE.publicKey))) - assertContainsPackageOwner("alice", mapOf(Pair(alicePackageName, ALICE.publicKey))) + bootstrap(packageOwnership = mapOf(Pair(alicePackageName, alice.publicKey))) + assertContainsPackageOwner("alice", mapOf(Pair(alicePackageName, alice.publicKey))) // register additional package name createNodeConfFile("bob", bobConfig) - bootstrap(packageOwnership = mapOf(Pair(alicePackageName, ALICE.publicKey), Pair(bobPackageName, BOB.publicKey))) - assertContainsPackageOwner("bob", mapOf(Pair(alicePackageName, ALICE.publicKey), Pair(bobPackageName, BOB.publicKey))) + bootstrap(packageOwnership = mapOf(Pair(alicePackageName, alice.publicKey), Pair(bobPackageName, bob.publicKey))) + assertContainsPackageOwner("bob", mapOf(Pair(alicePackageName, alice.publicKey), Pair(bobPackageName, bob.publicKey))) } @Test(timeout=300_000) fun `attempt to register overlapping namespaces in existing network`() { createNodeConfFile("alice", aliceConfig) val greedyNamespace = "com.example" - bootstrap(packageOwnership = mapOf(Pair(greedyNamespace, ALICE.publicKey))) - assertContainsPackageOwner("alice", mapOf(Pair(greedyNamespace, ALICE.publicKey))) + bootstrap(packageOwnership = mapOf(Pair(greedyNamespace, alice.publicKey))) + assertContainsPackageOwner("alice", mapOf(Pair(greedyNamespace, alice.publicKey))) // register overlapping package name createNodeConfFile("bob", bobConfig) - expectedEx.expect(IllegalArgumentException::class.java) - expectedEx.expectMessage("Multiple packages added to the packageOwnership overlap.") - bootstrap(packageOwnership = mapOf(Pair(greedyNamespace, ALICE.publicKey), Pair(bobPackageName, BOB.publicKey))) + val anException = assertThrows { + bootstrap(packageOwnership = mapOf(Pair(greedyNamespace, alice.publicKey), Pair(bobPackageName, bob.publicKey))) + } + assertEquals("Multiple packages added to the packageOwnership overlap.", anException.message) } @Test(timeout=300_000) fun `unregister single package namespace in network of one`() { createNodeConfFile("alice", aliceConfig) - bootstrap(packageOwnership = mapOf(Pair(alicePackageName, ALICE.publicKey))) - assertContainsPackageOwner("alice", mapOf(Pair(alicePackageName, ALICE.publicKey))) + bootstrap(packageOwnership = mapOf(Pair(alicePackageName, alice.publicKey))) + assertContainsPackageOwner("alice", mapOf(Pair(alicePackageName, alice.publicKey))) // unregister package name bootstrap(packageOwnership = emptyMap()) assertContainsPackageOwner("alice", emptyMap()) @@ -313,16 +320,16 @@ class NetworkBootstrapperTest { @Test(timeout=300_000) fun `unregister single package namespace in network of many`() { createNodeConfFile("alice", aliceConfig) - bootstrap(packageOwnership = mapOf(Pair(alicePackageName, ALICE.publicKey), Pair(bobPackageName, BOB.publicKey))) + bootstrap(packageOwnership = mapOf(Pair(alicePackageName, alice.publicKey), Pair(bobPackageName, bob.publicKey))) // unregister package name - bootstrap(packageOwnership = mapOf(Pair(alicePackageName, ALICE.publicKey))) - assertContainsPackageOwner("alice", mapOf(Pair(alicePackageName, ALICE.publicKey))) + bootstrap(packageOwnership = mapOf(Pair(alicePackageName, alice.publicKey))) + assertContainsPackageOwner("alice", mapOf(Pair(alicePackageName, alice.publicKey))) } @Test(timeout=300_000) fun `unregister all package namespaces in existing network`() { createNodeConfFile("alice", aliceConfig) - bootstrap(packageOwnership = mapOf(Pair(alicePackageName, ALICE.publicKey), Pair(bobPackageName, BOB.publicKey))) + bootstrap(packageOwnership = mapOf(Pair(alicePackageName, alice.publicKey), Pair(bobPackageName, bob.publicKey))) // unregister all package names bootstrap(packageOwnership = emptyMap()) assertContainsPackageOwner("alice", emptyMap()) @@ -336,7 +343,7 @@ class NetworkBootstrapperTest { maxMessageSize: Int? = DEFAULT_MAX_MESSAGE_SIZE, maxTransactionSize: Int? = DEFAULT_MAX_TRANSACTION_SIZE, eventHorizon: Duration? = 30.days) { - providedCordaJar = (rootDir / "corda.jar").let { if (it.exists()) it.readAll() else null } + providedCordaJar = (rootDir / "corda.jar").let { if (it.exists()) it.readBytes() else null } bootstrapper.bootstrap(rootDir, copyCordapps, NetworkParametersOverrides( minimumPlatformVersion = minimumPlatformVerison, maxMessageSize = maxMessageSize, @@ -376,9 +383,7 @@ class NetworkBootstrapperTest { } private val Path.nodeInfoFile: Path - get() { - return list { it.filter { it.fileName.toString().startsWith(NODE_INFO_FILE_NAME_PREFIX) }.toList() }.single() - } + get() = useDirectoryEntries { it.single { it.name.startsWith(NODE_INFO_FILE_NAME_PREFIX) } } private val Path.nodeInfo: NodeInfo get() = nodeInfoFile.readObject().verified() @@ -389,7 +394,7 @@ class NetworkBootstrapperTest { private fun assertBootstrappedNetwork(cordaJar: ByteArray, vararg nodes: Pair): NetworkParameters { val networkParameters = (rootDir / nodes[0].first).networkParameters - val allNodeInfoFiles = nodes.map { (rootDir / it.first).nodeInfoFile }.associateBy({ it }, Path::readAll) + val allNodeInfoFiles = nodes.map { (rootDir / it.first).nodeInfoFile }.associateWith(Path::readBytes) for ((nodeDirName, config) in nodes) { val nodeDir = rootDir / nodeDirName @@ -398,7 +403,7 @@ class NetworkBootstrapperTest { assertThat(nodeDir.networkParameters).isEqualTo(networkParameters) // Make sure all the nodes have all of each others' node-info files allNodeInfoFiles.forEach { nodeInfoFile, bytes -> - assertThat(nodeDir / NODE_INFO_DIRECTORY / nodeInfoFile.fileName.toString()).hasBinaryContent(bytes) + assertThat(nodeDir / NODE_INFO_DIRECTORY / nodeInfoFile.name).hasBinaryContent(bytes) } } diff --git a/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/serialization/kryo/KryoAttachmentTest.kt b/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/serialization/kryo/KryoAttachmentTest.kt index fdc17def6b..83a0aaa9b6 100644 --- a/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/serialization/kryo/KryoAttachmentTest.kt +++ b/node-api-tests/src/test/kotlin/net/corda/nodeapitests/internal/serialization/kryo/KryoAttachmentTest.kt @@ -1,7 +1,7 @@ package net.corda.nodeapitests.internal.serialization.kryo -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import net.corda.core.crypto.SecureHash import net.corda.core.serialization.EncodingWhitelist import net.corda.core.serialization.internal.CheckpointSerializationContext @@ -49,7 +49,7 @@ class KryoAttachmentTest(private val compression: CordaSerializationEncoding?) { @Test(timeout=300_000) fun `HashCheckingStream (de)serialize`() { - val rubbish = ByteArray(12345) { (it * it * 0.12345).toByte() } + val rubbish = ByteArray(12345) { (it * it * 0.12345).toInt().toByte() } val readRubbishStream: InputStream = NodeAttachmentService.HashCheckingStream( SecureHash.sha256(rubbish), rubbish.size, @@ -60,4 +60,4 @@ class KryoAttachmentTest(private val compression: CordaSerializationEncoding?) { } Assert.assertEquals(-1, readRubbishStream.read()) } -} \ No newline at end of file +} diff --git a/node-api/build.gradle b/node-api/build.gradle index c4cdfdd906..9a88cbac1b 100644 --- a/node-api/build.gradle +++ b/node-api/build.gradle @@ -1,55 +1,71 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.quasar-utils' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' description 'Corda node API' dependencies { - compile project(":core") - compile project(":serialization") // TODO Remove this once the NetworkBootstrapper class is moved into the tools:bootstrapper module - compile project(':common-configuration-parsing') // TODO Remove this dependency once NetworkBootsrapper is moved into tools:bootstrapper - compile project(':common-logging') + api project(":core") + implementation project(":serialization") // TODO Remove this once the NetworkBootstrapper class is moved into the tools:bootstrapper module + implementation project(':common-configuration-parsing') // TODO Remove this dependency once NetworkBootsrapper is moved into tools:bootstrapper + implementation project(':common-logging') + implementation project(":common-validation") - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + implementation "io.opentelemetry:opentelemetry-api:$open_telemetry_version" + compileOnly project(':opentelemetry') + + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" // TODO: remove the forced update of commons-collections and beanutils when artemis updates them - compile "org.apache.commons:commons-collections4:${commons_collections_version}" - compile "commons-beanutils:commons-beanutils:${beanutils_version}" - compile("org.apache.activemq:artemis-core-client:${artemis_version}") { + implementation "org.apache.commons:commons-collections4:${commons_collections_version}" + implementation "commons-beanutils:commons-beanutils:${beanutils_version}" + implementation("org.apache.activemq:artemis-core-client:${artemis_version}") { exclude group: 'org.jgroups', module: 'jgroups' } - compile "org.apache.activemq:artemis-commons:${artemis_version}" + implementation "org.apache.activemq:artemis-commons:${artemis_version}" + implementation "javax.json:javax.json-api:$json_api_version" + implementation "com.google.code.findbugs:jsr305:$jsr305_version" - compile "io.netty:netty-handler-proxy:$netty_version" + implementation "io.netty:netty-handler-proxy:$netty_version" // TypeSafe Config: for simple and human friendly config files. - compile "com.typesafe:config:$typesafe_config_version" + implementation "com.typesafe:config:$typesafe_config_version" - compile "org.apache.qpid:proton-j:$protonj_version" + implementation "org.apache.qpid:proton-j:$protonj_version" // SQL connection pooling library - compile "com.zaxxer:HikariCP:$hikari_version" - + implementation "com.zaxxer:HikariCP:$hikari_version" + // ClassGraph: classpath scanning - compile "io.github.classgraph:classgraph:$class_graph_version" + implementation "io.github.classgraph:classgraph:$class_graph_version" // Kryo: object graph serialization. - compile "com.esotericsoftware:kryo:$kryo_version" - compile "de.javakaffee:kryo-serializers:$kryo_serializer_version" + implementation "com.esotericsoftware:kryo:$kryo_version" + implementation "de.javakaffee:kryo-serializers:$kryo_serializer_version" // For caches rather than guava - compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version" + implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version" // For db migration - compile "org.liquibase:liquibase-core:$liquibase_version" - compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" - runtime 'com.mattbertolini:liquibase-slf4j:2.0.0' + implementation "org.liquibase:liquibase-core:$liquibase_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" - // JDK11: required by Quasar at run-time - runtime "com.esotericsoftware:kryo:$kryo_version" + // Bouncy castle support needed for X509 certificate manipulation + implementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}" + implementation "org.bouncycastle:bcpkix-lts8on:${bouncycastle_version}" + implementation "io.reactivex:rxjava:$rxjava_version" + implementation "javax.persistence:javax.persistence-api:2.2" + implementation "org.hibernate:hibernate-core:$hibernate_version" + implementation "co.paralleluniverse:quasar-osgi-annotations:$quasar_version" + implementation "com.google.guava:guava:$guava_version" + + runtimeOnly 'com.mattbertolini:liquibase-slf4j:2.0.0' + + runtimeOnly "com.esotericsoftware:kryo:$kryo_version" + + testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" + testImplementation "co.paralleluniverse:quasar-core:$quasar_version" testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" @@ -57,14 +73,15 @@ dependencies { testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile project(':node-driver') + testImplementation project(':node-driver') // Unit testing helpers. - testCompile "org.assertj:assertj-core:$assertj_version" - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - testCompile project(':core-test-utils') + testImplementation "org.assertj:assertj-core:$assertj_version" + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + testImplementation project(':core-test-utils') + testImplementation project(':test-utils') - compile ("org.apache.activemq:artemis-amqp-protocol:${artemis_version}") { + implementation ("org.apache.activemq:artemis-amqp-protocol:${artemis_version}") { // Gains our proton-j version from core module. exclude group: 'org.apache.qpid', module: 'proton-j' exclude group: 'org.jgroups', module: 'jgroups' @@ -72,23 +89,27 @@ dependencies { } configurations { - testArtifacts.extendsFrom testRuntimeClasspath + testArtifacts.extendsFrom testRuntimeOnlyClasspath } -task testJar(type: Jar) { +tasks.register('testJar', Jar) { classifier "tests" from sourceSets.test.output } artifacts { testArtifacts testJar - publish testJar } jar { baseName 'corda-node-api' } -publish { - name jar.baseName +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/ArtemisMessagingComponent.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/ArtemisMessagingComponent.kt index 7e61e90630..25172487ac 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/ArtemisMessagingComponent.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/ArtemisMessagingComponent.kt @@ -42,18 +42,18 @@ class ArtemisMessagingComponent { // We should probably try to unify our notion of "topic" (really, just a string that identifies an endpoint // that will handle messages, like a URL) with the terminology used by underlying MQ libraries, to avoid // confusion. - val topicProperty = SimpleString("platform-topic") - val cordaVendorProperty = SimpleString("corda-vendor") - val releaseVersionProperty = SimpleString("release-version") - val platformVersionProperty = SimpleString("platform-version") - val senderUUID = SimpleString("sender-uuid") - val senderSeqNo = SimpleString("send-seq-no") + val topicProperty = SimpleString.of("platform-topic") + val cordaVendorProperty = SimpleString.of("corda-vendor") + val releaseVersionProperty = SimpleString.of("release-version") + val platformVersionProperty = SimpleString.of("platform-version") + val senderUUID = SimpleString.of("sender-uuid") + val senderSeqNo = SimpleString.of("send-seq-no") /** * In the operation mode where we have an out of process bridge we cannot correctly populate the Artemis validated user header * as the TLS does not terminate directly onto Artemis. We therefore use this internal only header to forward * the equivalent information from the Float. */ - val bridgedCertificateSubject = SimpleString("sender-subject-name") + val bridgedCertificateSubject = SimpleString.of("sender-subject-name") object Type { const val KEY = "corda_p2p_message_type" diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/ContractsScanning.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/ContractsScanning.kt index 63543aaa66..7f5f7c4021 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/ContractsScanning.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/ContractsScanning.kt @@ -6,17 +6,22 @@ import net.corda.core.contracts.ContractClassName import net.corda.core.contracts.UpgradedContract import net.corda.core.contracts.UpgradedContractWithLegacyConstraint import net.corda.core.crypto.SecureHash -import net.corda.core.internal.* +import net.corda.core.internal.copyTo +import net.corda.core.internal.hash +import net.corda.core.internal.logElapsedTime +import net.corda.core.internal.pooledScan +import net.corda.core.internal.read import org.slf4j.LoggerFactory import java.io.InputStream import java.nio.file.Files import java.nio.file.Path import java.nio.file.StandardCopyOption import java.util.Collections.singleton +import kotlin.io.path.deleteIfExists // When scanning of the CorDapp Jar is performed without "corda-core.jar" being in the classpath, there is no way to appreciate // relationships between those interfaces, therefore they have to be listed explicitly. -val coreContractClasses = setOf(Contract::class, UpgradedContractWithLegacyConstraint::class, UpgradedContract::class) +val coreContractClasses = setOf(Contract::class.java, UpgradedContractWithLegacyConstraint::class.java, UpgradedContract::class.java) interface ContractsJar { val hash: SecureHash @@ -31,7 +36,8 @@ class ContractsJarFile(private val file: Path) : ContractsJar { return scanResult.use { result -> coreContractClasses - .flatMap { result.getClassesImplementing(it.qualifiedName)} + .asSequence() + .flatMap(result::getClassesImplementing) .filterNot { it.isAbstract } .filterNot { it.isInterface } .map { it.name } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/DevIdentityGenerator.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/DevIdentityGenerator.kt index 43a5aaa903..c0cf57f737 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/DevIdentityGenerator.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/DevIdentityGenerator.kt @@ -4,8 +4,6 @@ import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.generateKeyPair import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party -import net.corda.core.internal.createDirectories -import net.corda.core.internal.div import net.corda.core.utilities.trace import net.corda.nodeapi.internal.config.FileBasedCertificateStoreSupplier import net.corda.nodeapi.internal.config.SslConfiguration @@ -21,6 +19,8 @@ import java.security.KeyPair import java.security.PublicKey import java.security.cert.X509Certificate import javax.security.auth.x500.X500Principal +import kotlin.io.path.createDirectories +import kotlin.io.path.div /** * Contains utility methods for generating identities for a node. diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/AMQPBridgeManager.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/AMQPBridgeManager.kt index 2a4456ca36..9422fcba7f 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/AMQPBridgeManager.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/AMQPBridgeManager.kt @@ -1,6 +1,6 @@ -@file:Suppress("TooGenericExceptionCaught") // needs to catch and handle/rethrow *all* exceptions in many places package net.corda.nodeapi.internal.bridging +import co.paralleluniverse.fibers.instrument.DontInstrument import com.google.common.util.concurrent.ThreadFactoryBuilder import io.netty.channel.EventLoop import io.netty.channel.EventLoopGroup @@ -155,7 +155,7 @@ open class AMQPBridgeManager(keyStore: CertificateStore, = Executors.newSingleThreadScheduledExecutor(ThreadFactoryBuilder().setNameFormat("bridge-connection-reset-%d").build()) private fun artemis(inProgress: ArtemisState, block: (precedingState: ArtemisState) -> ArtemisState) { - val runnable = { + val runnable = @DontInstrument { synchronized(artemis!!) { try { val precedingState = artemisState @@ -276,7 +276,7 @@ open class AMQPBridgeManager(keyStore: CertificateStore, closeConsumer() consumer = null val closingSession = session - eventLoop.execute { + eventLoop.execute @DontInstrument { synchronized(artemis!!) { if (session == closingSession) { artemis(ArtemisState.STOPPING) { @@ -541,4 +541,4 @@ open class AMQPBridgeManager(keyStore: CertificateStore, sslDelegatedTaskExecutor = null } } -} \ No newline at end of file +} diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/BridgeControlListener.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/BridgeControlListener.kt index 357088bc0a..9c60a9885f 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/BridgeControlListener.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/BridgeControlListener.kt @@ -1,4 +1,3 @@ -@file:Suppress("TooGenericExceptionCaught") // needs to catch and handle/rethrow *all* exceptions package net.corda.nodeapi.internal.bridging import net.corda.core.identity.CordaX500Name @@ -27,6 +26,7 @@ import rx.Observable import rx.subjects.PublishSubject import java.time.Duration import java.util.* +import kotlin.system.exitProcess class BridgeControlListener(private val keyStore: CertificateStore, trustStore: CertificateStore, @@ -88,7 +88,7 @@ class BridgeControlListener(private val keyStore: CertificateStore, registerBridgeControlListener(artemisSession) registerBridgeDuplicateChecker(artemisSession) // Attempt to read available inboxes directly from Artemis before requesting updates from connected nodes - validInboundQueues.addAll(artemisSession.addressQuery(SimpleString("$P2P_PREFIX#")).queueNames.map { it.toString() }) + validInboundQueues.addAll(artemisSession.addressQuery(SimpleString.of("$P2P_PREFIX#")).queueNames.map { it.toString() }) log.info("Found inboxes: $validInboundQueues") if (active) { _activeChange.onNext(true) @@ -107,7 +107,7 @@ class BridgeControlListener(private val keyStore: CertificateStore, private fun registerBridgeControlListener(artemisSession: ClientSession) { try { artemisSession.createQueue( - QueueConfiguration(bridgeControlQueue).setAddress(BRIDGE_CONTROL).setRoutingType(RoutingType.MULTICAST) + QueueConfiguration.of(bridgeControlQueue).setAddress(BRIDGE_CONTROL).setRoutingType(RoutingType.MULTICAST) .setTemporary(true).setDurable(false)) } catch (ex: ActiveMQQueueExistsException) { // Ignore if there is a queue still not cleaned up @@ -129,7 +129,7 @@ class BridgeControlListener(private val keyStore: CertificateStore, private fun registerBridgeDuplicateChecker(artemisSession: ClientSession) { try { artemisSession.createQueue( - QueueConfiguration(bridgeNotifyQueue).setAddress(BRIDGE_NOTIFY).setRoutingType(RoutingType.MULTICAST) + QueueConfiguration.of(bridgeNotifyQueue).setAddress(BRIDGE_NOTIFY).setRoutingType(RoutingType.MULTICAST) .setTemporary(true).setDurable(false)) } catch (ex: ActiveMQQueueExistsException) { // Ignore if there is a queue still not cleaned up @@ -142,7 +142,7 @@ class BridgeControlListener(private val keyStore: CertificateStore, val notifyMessage = data.deserialize(context = SerializationDefaults.P2P_CONTEXT) if (notifyMessage.bridgeIdentity != bridgeId) { log.error("Fatal Error! Two bridges have been configured simultaneously! Check the enterpriseConfiguration.externalBridge status") - System.exit(1) + exitProcess(1) } } catch (ex: Exception) { log.error("Unable to process bridge notification message", ex) @@ -189,11 +189,11 @@ class BridgeControlListener(private val keyStore: CertificateStore, } private fun validateInboxQueueName(queueName: String): Boolean { - return queueName.startsWith(P2P_PREFIX) && artemis!!.started!!.session.queueQuery(SimpleString(queueName)).isExists + return queueName.startsWith(P2P_PREFIX) && artemis!!.started!!.session.queueQuery(SimpleString.of(queueName)).isExists } private fun validateBridgingQueueName(queueName: String): Boolean { - return queueName.startsWith(PEERS_PREFIX) && artemis!!.started!!.session.queueQuery(SimpleString(queueName)).isExists + return queueName.startsWith(PEERS_PREFIX) && artemis!!.started!!.session.queueQuery(SimpleString.of(queueName)).isExists } private fun processControlMessage(msg: ClientMessage) { @@ -204,7 +204,7 @@ class BridgeControlListener(private val keyStore: CertificateStore, is BridgeControl.NodeToBridgeSnapshot -> { if (!isConfigured(controlMessage.nodeIdentity)) { log.error("Fatal error! Bridge not configured with keystore for node with legal name ${controlMessage.nodeIdentity}.") - System.exit(1) + exitProcess(1) } if (!controlMessage.inboxQueues.all { validateInboxQueueName(it) }) { log.error("Invalid queue names in control message $controlMessage") diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/LoopbackBridgeManager.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/LoopbackBridgeManager.kt index 2dd9f8bff0..ce68cfbd96 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/LoopbackBridgeManager.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/LoopbackBridgeManager.kt @@ -136,7 +136,7 @@ class LoopbackBridgeManager(keyStore: CertificateStore, private fun clientArtemisMessageHandler(artemisMessage: ClientMessage) { logDebugWithMDC { "Loopback Send to ${legalNames.first()} uuid: ${artemisMessage.getObjectProperty(MESSAGE_ID_KEY)}" } val peerInbox = translateLocalQueueToInboxAddress(queueName) - producer?.send(SimpleString(peerInbox), artemisMessage) { artemisMessage.individualAcknowledge() } + producer?.send(SimpleString.of(peerInbox), artemisMessage) { artemisMessage.individualAcknowledge() } bridgeMetricsService?.let { metricsService -> val properties = ArtemisMessagingComponent.Companion.P2PMessagingHeaders.whitelistedHeaders.mapNotNull { key -> if (artemisMessage.containsProperty(key)) { diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/CertificateStore.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/CertificateStore.kt index b5285c93cd..b50e9d8fa3 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/CertificateStore.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/CertificateStore.kt @@ -1,12 +1,9 @@ package net.corda.nodeapi.internal.config import net.corda.core.crypto.internal.AliasPrivateKey -import net.corda.core.internal.outputStream import net.corda.nodeapi.internal.crypto.X509KeyStore import net.corda.nodeapi.internal.crypto.addOrReplaceCertificate import java.io.InputStream -import java.io.OutputStream -import java.nio.file.OpenOption import java.nio.file.Path import java.security.PrivateKey import java.security.cert.X509Certificate @@ -21,17 +18,18 @@ interface CertificateStore : Iterable> { fun fromInputStream(stream: InputStream, password: String, entryPassword: String): CertificateStore = DelegatingCertificateStore(X509KeyStore.fromInputStream(stream, password), password, entryPassword) - fun fromResource(storeResourceName: String, password: String, entryPassword: String, classLoader: ClassLoader = Thread.currentThread().contextClassLoader): CertificateStore = fromInputStream(classLoader.getResourceAsStream(storeResourceName), password, entryPassword) + fun fromResource(storeResourceName: String, + password: String, + entryPassword: String, + classLoader: ClassLoader = Thread.currentThread().contextClassLoader): CertificateStore { + return fromInputStream(classLoader.getResourceAsStream(storeResourceName)!!, password, entryPassword) + } } val value: X509KeyStore val password: String val entryPassword: String - fun writeTo(stream: OutputStream) = value.internal.store(stream, password.toCharArray()) - - fun writeTo(path: Path, vararg options: OpenOption) = path.outputStream(*options) - fun update(action: X509KeyStore.() -> Unit) { val result = action.invoke(value) value.save() @@ -80,7 +78,7 @@ interface CertificateStore : Iterable> { } fun setCertPathOnly(alias: String, certificates: List) { - // In case CryptoService and CertificateStore share the same KeyStore (i.e., when BCCryptoService is used), + // In case CryptoService and CertificateStore share the same KeyStore (i.e., when DefaultCryptoService is used), // extract the existing key from the Keystore and store it again along with the new certificate chain. // This is because KeyStores do not support updateKeyEntry and thus we cannot update the certificate chain // without overriding the key entry. diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/ConfigUtilities.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/ConfigUtilities.kt index 56f12e0dde..b23286c3f1 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/ConfigUtilities.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/ConfigUtilities.kt @@ -3,7 +3,13 @@ package net.corda.nodeapi.internal.config -import com.typesafe.config.* +import com.typesafe.config.Config +import com.typesafe.config.ConfigException +import com.typesafe.config.ConfigFactory +import com.typesafe.config.ConfigUtil +import com.typesafe.config.ConfigValue +import com.typesafe.config.ConfigValueFactory +import com.typesafe.config.ConfigValueType import net.corda.core.identity.CordaX500Name import net.corda.core.internal.isStatic import net.corda.core.internal.noneOrSingle @@ -11,9 +17,7 @@ import net.corda.core.internal.uncheckedCast import net.corda.core.utilities.NetworkHostAndPort import org.slf4j.Logger import org.slf4j.LoggerFactory -import java.lang.reflect.Field import java.lang.reflect.InvocationTargetException -import java.lang.reflect.ParameterizedType import java.net.Proxy import java.net.URL import java.nio.file.Path @@ -22,7 +26,9 @@ import java.time.Duration import java.time.Instant import java.time.LocalDate import java.time.temporal.Temporal -import java.util.* +import java.time.temporal.TemporalAmount +import java.util.Properties +import java.util.UUID import javax.security.auth.x500.X500Principal import kotlin.reflect.KClass import kotlin.reflect.KProperty @@ -99,7 +105,7 @@ fun Config.parseAs( .toSortedSet() onUnknownKeys.invoke(unknownConfigurationKeys, logger) - val args = parameters.filterNot { it.isOptional && !hasPath(it.name!!) }.associateBy({ it }) { param -> + val args = parameters.filterNot { it.isOptional && !hasPath(it.name!!) }.associateWith { param -> // Get the matching property for this parameter val property = clazz.memberProperties.first { it.name == param.name } val path = defaultToOldPath(property) @@ -181,7 +187,7 @@ private fun Config.getSingleValue( X500Principal::class -> X500Principal(getString(path)) CordaX500Name::class -> { when (getValue(path).valueType()) { - ConfigValueType.OBJECT -> getConfig(path).parseAs(onUnknownKeys) + ConfigValueType.OBJECT -> getConfig(path).parseAs(onUnknownKeys) as CordaX500Name else -> CordaX500Name.parse(getString(path)) } } @@ -291,104 +297,45 @@ private fun > enumBridge(clazz: Class, name: String): T { */ fun Any.toConfig(): Config = ConfigValueFactory.fromMap(toConfigMap()).toConfig() -fun Any?.toConfigValue(): ConfigValue = if (this is ConfigValue) { - this -} else if (this != null) { - ConfigValueFactory.fromAnyRef(convertValue(this)) -} else { - ConfigValueFactory.fromAnyRef(null) -} +fun Any?.toConfigValue(): ConfigValue = ConfigValueFactory.fromAnyRef(sanitiseForFromAnyRef(this)) -@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") // Reflect over the fields of the receiver and generate a value Map that can use to create Config object. -private fun Any.toConfigMap(): Map { - val values = HashMap() +private fun Any.toConfigMap(): Map { + val values = LinkedHashMap() for (field in javaClass.declaredFields) { if (field.isStatic || field.isSynthetic) continue field.isAccessible = true val value = field.get(this) ?: continue - val configValue = if (value is String || value is Boolean || value is Number) { - // These types are supported by Config as use as is - value - } else if (value is Temporal || value is NetworkHostAndPort || value is CordaX500Name || - value is Path || value is URL || value is UUID || value is X500Principal) { - // These types make sense to be represented as Strings and the exact inverse parsing function for use in parseAs - value.toString() - } else if (value is Enum<*>) { - // Expicitly use the Enum's name in case the toString is overridden, which would make parsing problematic. - value.name - } else if (value is Properties) { - // For Properties we treat keys with . as nested configs - ConfigFactory.parseMap(uncheckedCast(value)).root() - } else if (value is Iterable<*>) { - value.toConfigIterable(field) - } else { - // Else this is a custom object recursed over - value.toConfigMap() - } - values[field.name] = configValue + values[field.name] = sanitiseForFromAnyRef(value) } return values } -private fun convertValue(value: Any): Any { - - return if (value is String || value is Boolean || value is Number) { +/** + * @see ConfigValueFactory.fromAnyRef + */ +private fun sanitiseForFromAnyRef(value: Any?): Any? { + return when (value) { // These types are supported by Config as use as is - value - } else if (value is Temporal || value is NetworkHostAndPort || value is CordaX500Name || - value is Path || value is URL || value is UUID || value is X500Principal) { - // These types make sense to be represented as Strings and the exact inverse parsing function for use in parseAs - value.toString() - } else if (value is Enum<*>) { - // Expicitly use the Enum's name in case the toString is overridden, which would make parsing problematic. - value.name - } else if (value is Properties) { + is String, is Boolean, is Number, is ConfigValue, is Duration, null -> value + is Enum<*> -> value.name + // These types make sense to be represented as Strings + is Temporal, is TemporalAmount, is NetworkHostAndPort, is CordaX500Name, is Path, is URL, is UUID, is X500Principal -> value.toString() // For Properties we treat keys with . as nested configs - ConfigFactory.parseMap(uncheckedCast(value)).root() - } else if (value is Iterable<*>) { - value.toConfigIterable() - } else { + is Properties -> ConfigFactory.parseMap(uncheckedCast(value)).root() + is Map<*, *> -> ConfigFactory.parseMap(value.map { it.key.toString() to sanitiseForFromAnyRef(it.value) }.toMap()).root() + is Iterable<*> -> value.map(::sanitiseForFromAnyRef) // Else this is a custom object recursed over - value.toConfigMap() + else -> value.toConfigMap() } } -// For Iterables figure out the type parameter and apply the same logic as above on the individual elements. -private fun Iterable<*>.toConfigIterable(field: Field): Iterable { - val elementType = (field.genericType as ParameterizedType).actualTypeArguments[0] as Class<*> - return when (elementType) { - // For the types already supported by Config we can use the Iterable as is - String::class.java -> this - Integer::class.java -> this - java.lang.Long::class.java -> this - java.lang.Double::class.java -> this - java.lang.Boolean::class.java -> this - LocalDate::class.java -> map(Any?::toString) - Instant::class.java -> map(Any?::toString) - NetworkHostAndPort::class.java -> map(Any?::toString) - Path::class.java -> map(Any?::toString) - URL::class.java -> map(Any?::toString) - X500Principal::class.java -> map(Any?::toString) - UUID::class.java -> map(Any?::toString) - CordaX500Name::class.java -> map(Any?::toString) - Properties::class.java -> map { ConfigFactory.parseMap(uncheckedCast(it)).root() } - else -> if (elementType.isEnum) { - map { (it as Enum<*>).name } - } else { - map { it?.toConfigMap() } - } - } -} - -private fun Iterable<*>.toConfigIterable(): Iterable = map { element -> element?.let(::convertValue) } - // The typesafe .getBoolean function is case sensitive, this is a case insensitive version fun Config.getBooleanCaseInsensitive(path: String): Boolean { try { return getBoolean(path) - } catch(e:Exception) { - val stringVal = getString(path).toLowerCase() + } catch (e: Exception) { + val stringVal = getString(path).lowercase() if (stringVal == "true" || stringVal == "false") { return stringVal.toBoolean() } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/User.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/User.kt index b5c8f09b2f..f6aa1012ad 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/User.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/User.kt @@ -6,6 +6,4 @@ data class User( val password: String, val permissions: Set) { override fun toString(): String = "${javaClass.simpleName}($username, permissions=$permissions)" - @Deprecated("Use toConfig().root().unwrapped() instead", ReplaceWith("toConfig().root().unwrapped()")) - fun toMap(): Map = toConfig().root().unwrapped() } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/cordapp/CordappLoader.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/cordapp/CordappLoader.kt index c58f212393..dcfc3a6a14 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/cordapp/CordappLoader.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/cordapp/CordappLoader.kt @@ -1,33 +1,32 @@ package net.corda.nodeapi.internal.cordapp import net.corda.core.cordapp.Cordapp -import net.corda.core.flows.FlowLogic import net.corda.core.internal.cordapp.CordappImpl +import net.corda.core.internal.flatMapToSet import net.corda.core.schemas.MappedSchema /** * Handles loading [Cordapp]s. */ interface CordappLoader : AutoCloseable { - /** * Returns all [Cordapp]s found. */ val cordapps: List + /** + * Returns all legacy (4.11 or older) contract CorDapps. These are used to form backward compatible transactions. + */ + val legacyContractCordapps: List + /** * Returns a [ClassLoader] containing all types from all [Cordapp]s. */ val appClassLoader: ClassLoader +} - /** - * Returns a map between flow class and owning [Cordapp]. - * The mappings are unique, and the node will not start otherwise. - */ - val flowCordappMap: Map>, Cordapp> - - /** - * Returns all [MappedSchema] found inside the [Cordapp]s. - */ - val cordappSchemas: Set -} \ No newline at end of file +/** + * Returns all [MappedSchema] found inside the [Cordapp]s. + */ +val CordappLoader.cordappSchemas: Set + get() = cordapps.flatMapToSet { it.customSchemas } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/ContentSignerBuilder.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/ContentSignerBuilder.kt index bbee9e5d2a..a84fb0ad08 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/ContentSignerBuilder.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/ContentSignerBuilder.kt @@ -1,6 +1,5 @@ package net.corda.nodeapi.internal.crypto -import net.corda.core.crypto.Crypto.SPHINCS256_SHA256 import net.corda.core.crypto.SignatureScheme import net.corda.core.crypto.internal.Instances import org.bouncycastle.asn1.x509.AlgorithmIdentifier @@ -27,9 +26,7 @@ object ContentSignerBuilder { val sig = try { signatureInstance.apply { - // TODO special handling for Sphincs due to a known BouncyCastle's Sphincs bug we reported. - // It is fixed in BC 161b12, so consider updating the below if-statement after updating BouncyCastle. - if (random != null && signatureScheme != SPHINCS256_SHA256) { + if (random != null) { initSign(privateKey, random) } else { initSign(privateKey) @@ -48,7 +45,7 @@ object ContentSignerBuilder { private class SignatureOutputStream(private val sig: Signature, private val optimised: Boolean) : OutputStream() { private var alreadySigned = false - internal val signature: ByteArray by lazy { + val signature: ByteArray by lazy { try { alreadySigned = true sig.sign() diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/KeyStoreUtilities.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/KeyStoreUtilities.kt index 78919407fb..eae170e39f 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/KeyStoreUtilities.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/KeyStoreUtilities.kt @@ -3,13 +3,22 @@ package net.corda.nodeapi.internal.crypto import net.corda.core.crypto.Crypto -import net.corda.core.internal.* +import net.corda.core.internal.read +import net.corda.core.internal.safeSymbolicRead +import net.corda.core.internal.write import java.io.IOException import java.io.InputStream import java.nio.file.Path -import java.security.* +import java.security.Key +import java.security.KeyPair +import java.security.KeyStore +import java.security.KeyStoreException +import java.security.PrivateKey +import java.security.Provider import java.security.cert.Certificate import java.security.cert.X509Certificate +import kotlin.io.path.createDirectories +import kotlin.io.path.exists const val KEYSTORE_TYPE = "JKS" @@ -144,8 +153,8 @@ fun KeyStore.getX509Certificate(alias: String): X509Certificate { * @param keyPassword Password to unlock the private key entries. * @return the requested private key in supported type. * @throws KeyStoreException if the keystore has not been initialized. - * @throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found (not supported from the Keystore provider). - * @throws UnrecoverableKeyException if the key cannot be recovered (e.g., the given password is wrong). + * @throws java.security.NoSuchAlgorithmException if the algorithm for recovering the key cannot be found (not supported from the Keystore provider). + * @throws java.security.UnrecoverableKeyException if the key cannot be recovered (e.g., the given password is wrong). * @throws IllegalArgumentException on not supported scheme or if the given key specification * is inappropriate for a supported key factory to produce a private key. */ diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt index d617b7fb0f..c9e17b9773 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt @@ -1,4 +1,4 @@ -@file:Suppress("MagicNumber", "TooGenericExceptionCaught") +@file:Suppress("MagicNumber") package net.corda.nodeapi.internal.crypto @@ -7,11 +7,9 @@ import net.corda.core.crypto.Crypto import net.corda.core.crypto.newSecureRandom import net.corda.core.internal.CertRole import net.corda.core.internal.SignedDataWithCert -import net.corda.core.internal.reader import net.corda.core.internal.signWithCert import net.corda.core.internal.uncheckedCast import net.corda.core.internal.validate -import net.corda.core.internal.writer import net.corda.core.utilities.days import net.corda.core.utilities.millis import net.corda.core.utilities.toHex @@ -63,14 +61,15 @@ import java.security.cert.X509Certificate import java.time.Duration import java.time.Instant import java.time.temporal.ChronoUnit -import java.util.ArrayList import java.util.Date import javax.security.auth.x500.X500Principal import kotlin.experimental.and import kotlin.experimental.or +import kotlin.io.path.reader +import kotlin.io.path.writer object X509Utilities { - // Note that this default value only applies to BCCryptoService. Other implementations of CryptoService may have to use different + // Note that this default value only applies to DefaultCryptoService. Other implementations of CryptoService may have to use different // schemes (for instance `UtimacoCryptoService.DEFAULT_IDENTITY_SIGNATURE_SCHEME`). val DEFAULT_IDENTITY_SIGNATURE_SCHEME = Crypto.EDDSA_ED25519_SHA512 val DEFAULT_TLS_SIGNATURE_SCHEME = Crypto.ECDSA_SECP256R1_SHA256 @@ -304,10 +303,10 @@ object X509Utilities { crlDistPoint: String? = null, crlIssuer: X500Name? = null): X509Certificate { val builder = createPartialCertificate(certificateType, issuer, issuerPublicKey, subject, subjectPublicKey, validityWindow, nameConstraints, crlDistPoint, crlIssuer) - return builder.build(issuerSigner).run { - require(isValidOn(Date())){"Certificate is not valid at instant now"} - toJca() - } + val certificate = builder.build(issuerSigner).toJca() + certificate.checkValidity(Date()) + certificate.verify(issuerPublicKey) + return certificate } /** @@ -341,18 +340,22 @@ object X509Utilities { validityWindow, nameConstraints, crlDistPoint, - crlIssuer) - return builder.build(signer).run { - require(isValidOn(Date())){"Certificate is not valid at instant now"} - require(isSignatureValid(JcaContentVerifierProviderBuilder().build(issuerKeyPair.public))){"Invalid signature"} - toJca() - } + crlIssuer + ) + val certificate = builder.build(signer).toJca() + certificate.checkValidity(Date()) + certificate.verify(issuerKeyPair.public) + return certificate } /** * Create certificate signing request using provided information. */ - fun createCertificateSigningRequest(subject: X500Principal, email: String, publicKey: PublicKey, contentSigner: ContentSigner, certRole: CertRole = CertRole.NODE_CA): PKCS10CertificationRequest { + fun createCertificateSigningRequest(subject: X500Principal, + email: String, + publicKey: PublicKey, + contentSigner: ContentSigner, + certRole: CertRole = CertRole.NODE_CA): PKCS10CertificationRequest { return JcaPKCS10CertificationRequestBuilder(subject, publicKey) .addAttribute(BCStyle.E, DERUTF8String(email)) .addAttribute(ASN1ObjectIdentifier(CordaOID.X509_EXTENSION_CORDA_ROLE), certRole) @@ -411,7 +414,7 @@ object X509Utilities { } // Assuming cert type to role is 1:1 -val CertRole.certificateType: CertificateType get() = CertificateType.values().first { it.role == this } +val CertRole.certificateType: CertificateType get() = CertificateType.entries.first { it.role == this } /** * Convert a [X509Certificate] into BouncyCastle's [X509CertificateHolder]. diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/cryptoservice/bouncycastle/BCCryptoService.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/cryptoservice/DefaultCryptoService.kt similarity index 87% rename from node-api/src/main/kotlin/net/corda/nodeapi/internal/cryptoservice/bouncycastle/BCCryptoService.kt rename to node-api/src/main/kotlin/net/corda/nodeapi/internal/cryptoservice/DefaultCryptoService.kt index d57f750b96..f48cbe0fb1 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/cryptoservice/bouncycastle/BCCryptoService.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/cryptoservice/DefaultCryptoService.kt @@ -1,9 +1,8 @@ -package net.corda.nodeapi.internal.cryptoservice.bouncycastle +package net.corda.nodeapi.internal.cryptoservice import net.corda.core.crypto.Crypto import net.corda.core.crypto.SignatureScheme -import net.corda.core.crypto.internal.Instances.getSignatureInstance -import net.corda.core.crypto.internal.cordaBouncyCastleProvider +import net.corda.core.crypto.internal.Instances.withSignature import net.corda.core.crypto.newSecureRandom import net.corda.core.crypto.sha256 import net.corda.core.utilities.detailedLogger @@ -14,27 +13,30 @@ import net.corda.nodeapi.internal.crypto.ContentSignerBuilder import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore import net.corda.nodeapi.internal.crypto.save -import net.corda.nodeapi.internal.cryptoservice.* -import net.corda.nodeapi.internal.cryptoservice.CryptoService -import net.corda.nodeapi.internal.cryptoservice.CryptoServiceException import org.bouncycastle.operator.ContentSigner import java.nio.file.Path -import java.security.* +import java.security.KeyPair +import java.security.KeyPairGenerator +import java.security.KeyStore +import java.security.PrivateKey +import java.security.Provider +import java.security.PublicKey +import java.security.Signature import java.security.spec.ECGenParameterSpec import javax.crypto.Cipher import javax.crypto.KeyGenerator import javax.security.auth.x500.X500Principal /** - * Basic implementation of a [CryptoService] that uses BouncyCastle for cryptographic operations + * Basic implementation of a [CryptoService] which uses Corda's [Provider]s for cryptographic operations * and a Java KeyStore in the form of [CertificateStore] to store private keys. - * This service reuses the [NodeConfiguration.signingCertificateStore] to store keys. * * The [wrappingKeyStorePath] must be provided in order to execute any wrapping operations (e.g. [createWrappingKey], [generateWrappedKeyPair]) */ -class BCCryptoService(private val legalName: X500Principal, - private val certificateStoreSupplier: CertificateStoreSupplier, - private val wrappingKeyStorePath: Path? = null) : CryptoService { +@Suppress("TooManyFunctions") +class DefaultCryptoService(private val legalName: X500Principal, + private val certificateStoreSupplier: CertificateStoreSupplier, + private val wrappingKeyStorePath: Path? = null) : CryptoService { private companion object { val detailedLogger = detailedLogger() @@ -97,7 +99,7 @@ class BCCryptoService(private val legalName: X500Principal, private fun signWithAlgorithm(alias: String, data: ByteArray, signAlgorithm: String): ByteArray { val privateKey = certificateStore.query { getPrivateKey(alias, certificateStore.entryPassword) } - val signature = Signature.getInstance(signAlgorithm, cordaBouncyCastleProvider) + val signature = Signature.getInstance(signAlgorithm) detailedLogger.trace { "CryptoService(action=signing_start;alias=$alias;algorithm=$signAlgorithm)" } signature.initSign(privateKey, newSecureRandom()) signature.update(data) @@ -126,7 +128,7 @@ class BCCryptoService(private val legalName: X500Principal, /** * If a node is running in [NodeConfiguration.devMode] and for backwards compatibility purposes, the same [KeyStore] - * is reused outside [BCCryptoService] to update certificate paths. [resyncKeystore] will sync [BCCryptoService]'s + * is reused outside [DefaultCryptoService] to update certificate paths. [resyncKeystore] will sync [DefaultCryptoService]'s * loaded [certificateStore] in memory with the contents of the corresponding [KeyStore] file. */ fun resyncKeystore() { @@ -178,7 +180,7 @@ class BCCryptoService(private val legalName: X500Principal, } val wrappingKey = wrappingKeyStore.getKey(masterKeyAlias, certificateStore.entryPassword.toCharArray()) - val cipher = Cipher.getInstance("AESWRAPPAD", cordaBouncyCastleProvider) + val cipher = Cipher.getInstance("AESWRAPPAD") cipher.init(Cipher.WRAP_MODE, wrappingKey) val keyPairGenerator = keyPairGeneratorFromScheme(childKeyScheme) @@ -199,22 +201,23 @@ class BCCryptoService(private val legalName: X500Principal, 1 -> "AESWRAPPAD" else -> "AES" } - val cipher = Cipher.getInstance(algorithm, cordaBouncyCastleProvider) + val cipher = Cipher.getInstance(algorithm) cipher.init(Cipher.UNWRAP_MODE, wrappingKey) val privateKey = cipher.unwrap(wrappedPrivateKey.keyMaterial, keyAlgorithmFromScheme(wrappedPrivateKey.signatureScheme), Cipher.PRIVATE_KEY) as PrivateKey - val signature = getSignatureInstance(wrappedPrivateKey.signatureScheme.signatureName, cordaBouncyCastleProvider) - signature.initSign(privateKey, newSecureRandom()) - signature.update(payloadToSign) - return signature.sign() + return withSignature(wrappedPrivateKey.signatureScheme) { signature -> + signature.initSign(privateKey, newSecureRandom()) + signature.update(payloadToSign) + signature.sign() + } } - override fun getWrappingMode(): WrappingMode? = WrappingMode.DEGRADED_WRAPPED + override fun getWrappingMode(): WrappingMode = WrappingMode.DEGRADED_WRAPPED private fun keyPairGeneratorFromScheme(scheme: SignatureScheme): KeyPairGenerator { val algorithm = keyAlgorithmFromScheme(scheme) - val keyPairGenerator = KeyPairGenerator.getInstance(algorithm, cordaBouncyCastleProvider) + val keyPairGenerator = KeyPairGenerator.getInstance(algorithm) when (scheme) { Crypto.ECDSA_SECP256R1_SHA256 -> keyPairGenerator.initialize(ECGenParameterSpec("secp256r1")) Crypto.ECDSA_SECP256K1_SHA256 -> keyPairGenerator.initialize(ECGenParameterSpec("secp256k1")) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt index 70a4ea0f68..ccfa533b6a 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt @@ -6,9 +6,20 @@ import com.typesafe.config.ConfigFactory import net.corda.common.configuration.parsing.internal.Configuration import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party -import net.corda.core.internal.* +import net.corda.core.internal.JarSignatureCollector +import net.corda.core.internal.NODE_INFO_DIRECTORY +import net.corda.core.internal.PLATFORM_VERSION +import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.concurrent.fork import net.corda.core.internal.concurrent.transpose +import net.corda.core.internal.copyTo +import net.corda.core.internal.copyToDirectory +import net.corda.core.internal.div +import net.corda.core.internal.location +import net.corda.core.internal.read +import net.corda.core.internal.readObject +import net.corda.core.internal.times +import net.corda.core.internal.toPath import net.corda.core.node.NetworkParameters import net.corda.core.node.NodeInfo import net.corda.core.node.NotaryInfo @@ -21,7 +32,11 @@ import net.corda.core.serialization.internal._contextSerializationEnv import net.corda.core.utilities.days import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.seconds -import net.corda.nodeapi.internal.* +import net.corda.nodeapi.internal.ContractsJar +import net.corda.nodeapi.internal.ContractsJarFile +import net.corda.nodeapi.internal.DEV_ROOT_CA +import net.corda.nodeapi.internal.DevIdentityGenerator +import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.config.getBooleanCaseInsensitive import net.corda.nodeapi.internal.network.NodeInfoFilesCopier.Companion.NODE_INFO_FILE_NAME_PREFIX import net.corda.serialization.internal.AMQP_P2P_CONTEXT @@ -29,7 +44,6 @@ import net.corda.serialization.internal.CordaSerializationMagic import net.corda.serialization.internal.SerializationFactoryImpl import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme import net.corda.serialization.internal.amqp.amqpMagic -import java.io.File import java.net.URL import java.nio.file.FileAlreadyExistsException import java.nio.file.Path @@ -38,7 +52,7 @@ import java.nio.file.StandardCopyOption.REPLACE_EXISTING import java.security.PublicKey import java.time.Duration import java.time.Instant -import java.util.* +import java.util.Timer import java.util.concurrent.Executors import java.util.concurrent.TimeUnit import java.util.jar.JarInputStream @@ -46,7 +60,16 @@ import kotlin.collections.component1 import kotlin.collections.component2 import kotlin.collections.set import kotlin.concurrent.schedule -import kotlin.streams.toList +import kotlin.io.path.copyTo +import kotlin.io.path.createDirectories +import kotlin.io.path.deleteExisting +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.isSameFileAs +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.name +import kotlin.io.path.readBytes +import kotlin.io.path.useDirectoryEntries /** * Class to bootstrap a local network of Corda nodes on the same filesystem. @@ -89,7 +112,7 @@ constructor(private val initSerEnv: Boolean, private val jarsThatArentCordapps = setOf("corda.jar", "runnodes.jar") private fun extractEmbeddedCordaJar(): URL { - return Thread.currentThread().contextClassLoader.getResource("corda.jar") + return Thread.currentThread().contextClassLoader.getResource("corda.jar")!! } private fun generateNodeInfos(nodeDirs: List): List { @@ -112,9 +135,7 @@ constructor(private val initSerEnv: Boolean, private fun generateNodeInfo(nodeDir: Path): Path { runNodeJob(nodeInfoGenCmd, nodeDir, "node-info-gen.log") - return nodeDir.list { paths -> - paths.filter { it.fileName.toString().startsWith(NODE_INFO_FILE_NAME_PREFIX) }.findFirst().get() - } + return nodeDir.useDirectoryEntries { paths -> paths.single { it.name.startsWith(NODE_INFO_FILE_NAME_PREFIX) } } } private fun createDbSchemas(nodeDir: Path) { @@ -123,11 +144,11 @@ constructor(private val initSerEnv: Boolean, private fun runNodeJob(command: List, nodeDir: Path, logfileName: String) { val logsDir = (nodeDir / LOGS_DIR_NAME).createDirectories() - val nodeRedirectFile = (logsDir / logfileName).toFile() + val nodeRedirectFile = logsDir / logfileName val process = ProcessBuilder(command) .directory(nodeDir.toFile()) .redirectErrorStream(true) - .redirectOutput(nodeRedirectFile) + .redirectOutput(nodeRedirectFile.toFile()) .apply { environment()["CAPSULE_CACHE_DIR"] = "../.cache" } .start() try { @@ -143,7 +164,7 @@ constructor(private val initSerEnv: Boolean, } } - private fun printNodeOutputToConsoleAndThrow(stdoutFile: File) { + private fun printNodeOutputToConsoleAndThrow(stdoutFile: Path) { val nodeDir = stdoutFile.parent val nodeIdentifier = try { ConfigFactory.parseFile((nodeDir / "node.conf").toFile()).getString("myLegalName") @@ -151,7 +172,7 @@ constructor(private val initSerEnv: Boolean, nodeDir } System.err.println("#### Error while generating node info file $nodeIdentifier ####") - stdoutFile.inputStream().copyTo(System.err) + stdoutFile.copyTo(System.err) throw IllegalStateException("Error while generating node info file. Please check the logs in $nodeDir.") } @@ -239,9 +260,8 @@ constructor(private val initSerEnv: Boolean, require(networkParameterOverrides.minimumPlatformVersion == null || networkParameterOverrides.minimumPlatformVersion <= PLATFORM_VERSION) { "Minimum platform version cannot be greater than $PLATFORM_VERSION" } // Don't accidentally include the bootstrapper jar as a CorDapp! val bootstrapperJar = javaClass.location.toPath() - val cordappJars = directory.list { paths -> - paths.filter { it.toString().endsWith(".jar") && !it.isSameAs(bootstrapperJar) && !jarsThatArentCordapps.contains(it.fileName.toString().toLowerCase()) } - .toList() + val cordappJars = directory.useDirectoryEntries("*.jar") { jars -> + jars.filter { !it.isSameFileAs(bootstrapperJar) && it.name.lowercase() !in jarsThatArentCordapps }.toList() } bootstrap(directory, cordappJars, copyCordapps, fromCordform = false, networkParametersOverrides = networkParameterOverrides) } @@ -263,7 +283,7 @@ constructor(private val initSerEnv: Boolean, println("Nodes found in the following sub-directories: ${nodeDirs.map { it.fileName }}") } - val configs = nodeDirs.associateBy({ it }, { ConfigFactory.parseFile((it / "node.conf").toFile()) }) + val configs = nodeDirs.associateWith { ConfigFactory.parseFile((it / "node.conf").toFile()) } checkForDuplicateLegalNames(configs.values) copyCordapps.copy(cordappJars, nodeDirs, networkAlreadyExists, fromCordform) @@ -301,9 +321,7 @@ constructor(private val initSerEnv: Boolean, } } - private fun Path.listEndingWith(suffix: String): List { - return list { file -> file.filter { it.toString().endsWith(suffix) }.toList() } - } + private fun Path.listEndingWith(suffix: String): List = listDirectoryEntries("*$suffix") private fun createNodeDirectoriesIfNeeded(directory: Path, fromCordform: Boolean): Boolean { var networkAlreadyExists = false @@ -320,7 +338,7 @@ constructor(private val initSerEnv: Boolean, val webServerConfFiles = directory.listEndingWith("_web-server.conf") for (confFile in confFiles) { - val nodeName = confFile.fileName.toString().removeSuffix("_node.conf") + val nodeName = confFile.name.removeSuffix("_node.conf") println("Generating node directory for $nodeName") if ((directory / nodeName).exists()) { //directory already exists, so assume this network has been bootstrapped before @@ -333,25 +351,28 @@ constructor(private val initSerEnv: Boolean, cordaJar.copyToDirectory(nodeDir, REPLACE_EXISTING) } - val nodeDirs = directory.list { subDir -> subDir.filter { (it / "node.conf").exists() && !(it / "corda.jar").exists() }.toList() } - for (nodeDir in nodeDirs) { - println("Copying corda.jar into node directory ${nodeDir.fileName}") - cordaJar.copyToDirectory(nodeDir) + directory.useDirectoryEntries { subDir -> + subDir + .filter { (it / "node.conf").exists() && !(it / "corda.jar").exists() } + .forEach { nodeDir -> + println("Copying corda.jar into node directory ${nodeDir.fileName}") + cordaJar.copyToDirectory(nodeDir) + } } if (fromCordform) { - confFiles.forEach(Path::delete) - webServerConfFiles.forEach(Path::delete) + confFiles.forEach(Path::deleteExisting) + webServerConfFiles.forEach(Path::deleteExisting) } if (fromCordform || usingEmbedded) { - cordaJar.delete() + cordaJar.deleteExisting() } return networkAlreadyExists } private fun gatherNodeDirectories(directory: Path): List { - val nodeDirs = directory.list { subDir -> subDir.filter { (it / "corda.jar").exists() }.toList() } + val nodeDirs = directory.useDirectoryEntries { subDir -> subDir.filter { (it / "corda.jar").exists() }.toList() } for (nodeDir in nodeDirs) { require((nodeDir / "node.conf").exists()) { "Missing node.conf in node directory ${nodeDir.fileName}" } } @@ -395,7 +416,7 @@ constructor(private val initSerEnv: Boolean, val netParamsFilesGrouped = nodeDirs.mapNotNull { val netParamsFile = it / NETWORK_PARAMS_FILE_NAME if (netParamsFile.exists()) netParamsFile else null - }.groupBy { SerializedBytes(it.readAll()) } + }.groupBy { SerializedBytes(it.readBytes()) } when (netParamsFilesGrouped.size) { 0 -> return null @@ -493,9 +514,7 @@ constructor(private val initSerEnv: Boolean, } private fun isSigned(file: Path): Boolean = file.read { - JarInputStream(it).use { - JarSignatureCollector.collectSigningParties(it).isNotEmpty() - } + JarInputStream(it).use(JarSignatureCollector::collectSigningParties).isNotEmpty() } } @@ -505,8 +524,7 @@ fun NetworkParameters.overrideWith(override: NetworkParametersOverrides): Networ maxMessageSize = override.maxMessageSize ?: this.maxMessageSize, maxTransactionSize = override.maxTransactionSize ?: this.maxTransactionSize, eventHorizon = override.eventHorizon ?: this.eventHorizon, - packageOwnership = override.packageOwnership?.map { it.javaPackageName to it.publicKey }?.toMap() - ?: this.packageOwnership + packageOwnership = override.packageOwnership?.associate { it.javaPackageName to it.publicKey } ?: this.packageOwnership ) } @@ -573,4 +591,4 @@ enum class CopyCordapps { } this.copyTo(cordappJars, nodeDirs, networkAlreadyExists, fromCordform) } -} \ No newline at end of file +} diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkParametersCopier.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkParametersCopier.kt index ed8241153f..25c408c802 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkParametersCopier.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkParametersCopier.kt @@ -3,7 +3,6 @@ package net.corda.nodeapi.internal.network import net.corda.core.internal.SignedDataWithCert import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.copyTo -import net.corda.core.internal.div import net.corda.core.node.NetworkParameters import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.serialize @@ -12,6 +11,7 @@ import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair import java.nio.file.FileAlreadyExistsException import java.nio.file.Path import java.nio.file.StandardCopyOption +import kotlin.io.path.div class NetworkParametersCopier( networkParameters: NetworkParameters, diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NodeInfoFilesCopier.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NodeInfoFilesCopier.kt index e8d2763662..d845d78b5a 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NodeInfoFilesCopier.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NodeInfoFilesCopier.kt @@ -1,6 +1,7 @@ package net.corda.nodeapi.internal.network -import net.corda.core.internal.* +import net.corda.core.internal.NODE_INFO_DIRECTORY +import net.corda.core.internal.ThreadBox import net.corda.core.utilities.contextLogger import net.corda.core.utilities.debug import rx.Observable @@ -14,6 +15,14 @@ import java.nio.file.StandardCopyOption.COPY_ATTRIBUTES import java.nio.file.StandardCopyOption.REPLACE_EXISTING import java.nio.file.attribute.FileTime import java.util.concurrent.TimeUnit +import kotlin.io.path.copyTo +import kotlin.io.path.createDirectories +import kotlin.io.path.deleteIfExists +import kotlin.io.path.getLastModifiedTime +import kotlin.io.path.isRegularFile +import kotlin.io.path.moveTo +import kotlin.io.path.name +import kotlin.io.path.useDirectoryEntries /** * Utility class which copies nodeInfo files across a set of running nodes. @@ -96,10 +105,10 @@ class NodeInfoFilesCopier(private val scheduler: Scheduler = Schedulers.io()) : private fun poll() { nodeDataMapBox.locked { for (nodeData in values) { - nodeData.nodeDir.list { paths -> + nodeData.nodeDir.useDirectoryEntries { paths -> paths .filter { it.isRegularFile() } - .filter { it.fileName.toString().startsWith(NODE_INFO_FILE_NAME_PREFIX) } + .filter { it.name.startsWith(NODE_INFO_FILE_NAME_PREFIX) } .forEach { processPath(nodeData, it) } } } @@ -110,7 +119,7 @@ class NodeInfoFilesCopier(private val scheduler: Scheduler = Schedulers.io()) : // be copied. private fun processPath(nodeData: NodeData, path: Path) { nodeDataMapBox.alreadyLocked { - val newTimestamp = path.lastModifiedTime() + val newTimestamp = path.getLastModifiedTime() val previousTimestamp = nodeData.previouslySeenFiles.put(path, newTimestamp) ?: FileTime.fromMillis(-1) if (newTimestamp > previousTimestamp) { for (destination in this.values.filter { it.nodeDir != nodeData.nodeDir }.map { it.additionalNodeInfoDirectory }) { @@ -134,15 +143,15 @@ class NodeInfoFilesCopier(private val scheduler: Scheduler = Schedulers.io()) : source.copyTo(tempDestination, COPY_ATTRIBUTES, REPLACE_EXISTING) } catch (exception: IOException) { log.warn("Couldn't copy $source to $tempDestination.", exception) - tempDestination.delete() + tempDestination.deleteIfExists() throw exception } try { // Then rename it to the desired name. This way the file 'appears' on the filesystem as an atomic operation. - tempDestination.moveTo(destination, REPLACE_EXISTING) + tempDestination.moveTo(destination, overwrite = true) } catch (exception: IOException) { log.warn("Couldn't move $tempDestination to $destination.", exception) - tempDestination.delete() + tempDestination.deleteIfExists() throw exception } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/WhitelistGenerator.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/WhitelistGenerator.kt index ef76b11d52..d6817c8153 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/WhitelistGenerator.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/WhitelistGenerator.kt @@ -1,12 +1,15 @@ package net.corda.nodeapi.internal.network import net.corda.core.contracts.ContractClassName -import net.corda.core.internal.* +import net.corda.core.internal.toMultiMap import net.corda.core.node.NetworkParameters import net.corda.core.node.services.AttachmentId import net.corda.nodeapi.internal.ContractsJar import org.slf4j.LoggerFactory import java.nio.file.Path +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.readLines private const val EXCLUDE_WHITELIST_FILE_NAME = "exclude_whitelist.txt" private const val INCLUDE_WHITELIST_FILE_NAME = "include_whitelist.txt" @@ -37,7 +40,7 @@ fun generateWhitelist(networkParameters: NetworkParameters?, .flatMap { jar -> (jar.scan()).filter { includeContracts.contains(it) }.map { it to jar.hash } } .toMultiMap() - return (newWhiteList.keys + existingWhitelist.keys + newSignedJarsWhiteList.keys).associateBy({ it }) { + return (newWhiteList.keys + existingWhitelist.keys + newSignedJarsWhiteList.keys).associateWith { val existingHashes = existingWhitelist[it] ?: emptyList() val newHashes = newWhiteList[it] ?: emptyList() val newHashesFormSignedJar = newSignedJarsWhiteList[it] ?: emptyList() @@ -49,4 +52,4 @@ fun readExcludeWhitelist(directory: Path): List = readAllLines(directory fun readIncludeWhitelist(directory: Path): List = readAllLines(directory / INCLUDE_WHITELIST_FILE_NAME) -private fun readAllLines(path: Path) : List = if (path.exists()) path.readAllLines().map(String::trim) else emptyList() +private fun readAllLines(path: Path): List = if (path.exists()) path.readLines().map(String::trim) else emptyList() diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/AttachmentVersionNumberMigration.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/AttachmentVersionNumberMigration.kt index 0fb5496865..86e216e958 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/AttachmentVersionNumberMigration.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/AttachmentVersionNumberMigration.kt @@ -5,7 +5,6 @@ import liquibase.database.Database import liquibase.database.jvm.JdbcConnection import liquibase.exception.ValidationErrors import liquibase.resource.ResourceAccessor -import net.corda.core.internal.div import net.corda.core.internal.readObject import net.corda.core.node.NetworkParameters import net.corda.core.serialization.deserialize @@ -15,6 +14,7 @@ import net.corda.nodeapi.internal.network.SignedNetworkParameters import net.corda.nodeapi.internal.persistence.SchemaMigration.Companion.NODE_BASE_DIR_KEY import java.nio.file.Path import java.nio.file.Paths +import kotlin.io.path.div class AttachmentVersionNumberMigration : CustomTaskChange { companion object { @@ -27,8 +27,8 @@ class AttachmentVersionNumberMigration : CustomTaskChange { try { logger.info("Start executing...") - var networkParameters: NetworkParameters? - val baseDir = System.getProperty(SchemaMigration.NODE_BASE_DIR_KEY) + val networkParameters: NetworkParameters? + val baseDir = System.getProperty(NODE_BASE_DIR_KEY) val availableAttachments = getAttachmentsWithDefaultVersion(connection) if (baseDir != null) { val path = Paths.get(baseDir) / NETWORK_PARAMS_FILE_NAME @@ -56,7 +56,7 @@ class AttachmentVersionNumberMigration : CustomTaskChange { availableAttachments.forEach { attachmentId -> val versions = networkParameters.whitelistedContractImplementations.values.map { it.indexOfFirst { aid -> aid.toString() == attachmentId } }.filter { it >= 0 } - val maxPosition = versions.max() ?: 0 + val maxPosition = versions.maxOrNull() ?: 0 if (maxPosition > 0) { val version = maxPosition + 1 val updateVersionMsg = "Updating version of attachment $attachmentId to '$version'." @@ -115,4 +115,4 @@ class AttachmentVersionNumberMigration : CustomTaskChange { it.executeUpdate() } } -} \ No newline at end of file +} diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt index ee210ca365..598b666c58 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt @@ -1,6 +1,5 @@ package net.corda.nodeapi.internal.persistence -import com.github.benmanes.caffeine.cache.Caffeine import net.corda.core.internal.NamedCacheFactory import net.corda.core.internal.castIfPossible import net.corda.core.schemas.MappedSchema @@ -54,7 +53,7 @@ class HibernateConfiguration( val sessionFactoryFactory = findSessionFactoryFactory(jdbcUrl, customClassLoader) - private val sessionFactories = cacheFactory.buildNamed, SessionFactory>(Caffeine.newBuilder(), "HibernateConfiguration_sessionFactories") + private val sessionFactories = cacheFactory.buildNamed, SessionFactory>("HibernateConfiguration_sessionFactories") val sessionFactoryForRegisteredSchemas = schemas.let { logger.info("Init HibernateConfiguration for schemas: $it") diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/AMQPChannelHandler.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/AMQPChannelHandler.kt index 41e38251d3..25b7f33a74 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/AMQPChannelHandler.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/AMQPChannelHandler.kt @@ -67,8 +67,8 @@ internal class AMQPChannelHandler(private val serverMode: Boolean, try { MDC.put("serverMode", serverMode.toString()) MDC.put("remoteAddress", if (::remoteAddress.isInitialized) remoteAddress.toString() else null) - MDC.put("localCert", localCert?.subjectDN?.toString()) - MDC.put("remoteCert", remoteCert?.subjectDN?.toString()) + MDC.put("localCert", localCert?.getSubjectX500Principal()?.toString()) + MDC.put("remoteCert", remoteCert?.getSubjectX500Principal()?.toString()) MDC.put("allowedRemoteLegalNames", allowedRemoteLegalNames?.joinToString(separator = ";") { it.toString() }) block() } finally { diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/AMQPConfiguration.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/AMQPConfiguration.kt index c992dd55e4..a7449d4b0b 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/AMQPConfiguration.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/AMQPConfiguration.kt @@ -10,7 +10,6 @@ interface AMQPConfiguration { * SASL User name presented during protocol handshake. No SASL login if NULL. * For legacy interoperability with Artemis authorisation we typically require this to be "PEER_USER" */ - @JvmDefault val userName: String? get() = ArtemisMessagingComponent.PEER_USER @@ -18,7 +17,6 @@ interface AMQPConfiguration { * SASL plain text password presented during protocol handshake. No SASL login if NULL. * For legacy interoperability with Artemis authorisation we typically require this to be "PEER_USER" */ - @JvmDefault val password: String? get() = ArtemisMessagingComponent.PEER_USER @@ -35,14 +33,12 @@ interface AMQPConfiguration { /** * Control how CRL check will be performed. */ - @JvmDefault val revocationConfig: RevocationConfig get() = RevocationConfigImpl(RevocationConfig.Mode.SOFT_FAIL) /** * Enables full debug tracing of all netty and AMQP level packets. This logs aat very high volume and is only for developers. */ - @JvmDefault val trace: Boolean get() = false @@ -52,22 +48,18 @@ interface AMQPConfiguration { */ val maxMessageSize: Int - @JvmDefault val proxyConfig: ProxyConfig? get() = null - @JvmDefault val sourceX500Name: String? get() = null /** * Whether to use the tcnative open/boring SSL provider or the default Java SSL provider */ - @JvmDefault val useOpenSsl: Boolean get() = false - @JvmDefault val sslHandshakeTimeout: Duration get() = DEFAULT_SSL_HANDSHAKE_TIMEOUT // Aligned with sun.security.provider.certpath.URICertStore.DEFAULT_CRL_CONNECT_TIMEOUT @@ -80,11 +72,9 @@ interface AMQPConfiguration { /** * An optional set of IPv4/IPv6 remote address strings which will be compared to the remote address of inbound connections and these will only log at TRACE level */ - @JvmDefault val silencedIPs: Set get() = emptySet() - @JvmDefault val enableSNI: Boolean get() = true } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/CertHoldingKeyManagerFactoryWrapper.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/CertHoldingKeyManagerFactoryWrapper.kt index 752b249a71..ea6d708b5d 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/CertHoldingKeyManagerFactoryWrapper.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/CertHoldingKeyManagerFactoryWrapper.kt @@ -9,25 +9,18 @@ import javax.net.ssl.ManagerFactoryParameters import javax.net.ssl.X509ExtendedKeyManager import javax.net.ssl.X509KeyManager -class CertHoldingKeyManagerFactorySpiWrapper(private val factorySpi: KeyManagerFactorySpi, private val amqpConfig: AMQPConfiguration) : KeyManagerFactorySpi() { +private class CertHoldingKeyManagerFactorySpiWrapper(private val keyManagerFactory: KeyManagerFactory, + private val amqpConfig: AMQPConfiguration) : KeyManagerFactorySpi() { override fun engineInit(keyStore: KeyStore?, password: CharArray?) { - val engineInitMethod = KeyManagerFactorySpi::class.java.getDeclaredMethod("engineInit", KeyStore::class.java, CharArray::class.java) - engineInitMethod.isAccessible = true - engineInitMethod.invoke(factorySpi, keyStore, password) + keyManagerFactory.init(keyStore, password) } override fun engineInit(spec: ManagerFactoryParameters?) { - val engineInitMethod = KeyManagerFactorySpi::class.java.getDeclaredMethod("engineInit", ManagerFactoryParameters::class.java) - engineInitMethod.isAccessible = true - engineInitMethod.invoke(factorySpi, spec) + keyManagerFactory.init(spec) } private fun getKeyManagersImpl(): Array { - val engineGetKeyManagersMethod = KeyManagerFactorySpi::class.java.getDeclaredMethod("engineGetKeyManagers") - engineGetKeyManagersMethod.isAccessible = true - @Suppress("UNCHECKED_CAST") - val keyManagers = engineGetKeyManagersMethod.invoke(factorySpi) as Array - return if (factorySpi is CertHoldingKeyManagerFactorySpiWrapper) keyManagers else keyManagers.map { + return keyManagerFactory.keyManagers.map { val aliasProvidingKeyManager = getDefaultKeyManager(it) // Use the SNIKeyManager if keystore has several entries and only for clients and non-openSSL servers. // Condition of using SNIKeyManager: if its client, or JDKSsl server. @@ -62,15 +55,11 @@ class CertHoldingKeyManagerFactorySpiWrapper(private val factorySpi: KeyManagerF * the wrapper is not thread safe as in it will return the last used alias/cert chain and has itself no notion * of belonging to a certain channel. */ -class CertHoldingKeyManagerFactoryWrapper(factory: KeyManagerFactory, amqpConfig: AMQPConfiguration) : KeyManagerFactory(getFactorySpi(factory, amqpConfig), factory.provider, factory.algorithm) { - companion object { - private fun getFactorySpi(factory: KeyManagerFactory, amqpConfig: AMQPConfiguration): KeyManagerFactorySpi { - val spiField = KeyManagerFactory::class.java.getDeclaredField("factorySpi") - spiField.isAccessible = true - return CertHoldingKeyManagerFactorySpiWrapper(spiField.get(factory) as KeyManagerFactorySpi, amqpConfig) - } - } - +class CertHoldingKeyManagerFactoryWrapper(factory: KeyManagerFactory, amqpConfig: AMQPConfiguration) : KeyManagerFactory( + CertHoldingKeyManagerFactorySpiWrapper(factory, amqpConfig), + factory.provider, + factory.algorithm +) { fun getCurrentCertChain(): Array? { val keyManager = keyManagers.firstOrNull() val alias = if (keyManager is AliasProvidingKeyMangerWrapper) keyManager.lastAlias else null @@ -78,4 +67,4 @@ class CertHoldingKeyManagerFactoryWrapper(factory: KeyManagerFactory, amqpConfig keyManager.getCertificateChain(alias) } else null } -} \ No newline at end of file +} diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/ConnectionChange.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/ConnectionChange.kt index e900f93306..4ddc353f03 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/ConnectionChange.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/ConnectionChange.kt @@ -5,6 +5,6 @@ import java.security.cert.X509Certificate data class ConnectionChange(val remoteAddress: InetSocketAddress, val remoteCert: X509Certificate?, val connected: Boolean, val connectionResult: ConnectionResult) { override fun toString(): String { - return "ConnectionChange remoteAddress: $remoteAddress connected state: $connected cert subject: ${remoteCert?.subjectDN} result: ${connectionResult}" + return "ConnectionChange remoteAddress: $remoteAddress connected state: $connected cert subject: ${remoteCert?.getSubjectX500Principal()} result: ${connectionResult}" } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/RevocationConfig.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/RevocationConfig.kt index 4e1b4b1930..14bb78d283 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/RevocationConfig.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/RevocationConfig.kt @@ -3,6 +3,7 @@ package net.corda.nodeapi.internal.protonwrapper.netty import com.typesafe.config.Config import net.corda.nodeapi.internal.config.ConfigParser import net.corda.nodeapi.internal.config.CustomConfigParser +import java.util.Locale /** * Data structure for controlling the way how Certificate Revocation Lists are handled. @@ -58,7 +59,7 @@ class RevocationConfigParser : ConfigParser { require(allKeys.size == 1 && allKeys.contains(oneAndTheOnly)) {"For RevocationConfig, it is expected to have '$oneAndTheOnly' property only. " + "Actual set of properties: $allKeys. Please check 'revocationConfig' section."} val mode = config.getString(oneAndTheOnly) - return when (mode.toUpperCase()) { + return when (mode.uppercase(Locale.getDefault())) { "SOFT_FAIL" -> RevocationConfigImpl(RevocationConfig.Mode.SOFT_FAIL) "HARD_FAIL" -> RevocationConfigImpl(RevocationConfig.Mode.HARD_FAIL) "EXTERNAL_SOURCE" -> RevocationConfigImpl(RevocationConfig.Mode.EXTERNAL_SOURCE, null) // null for now till `enrichExternalCrlSource` is called diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/SSLHelper.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/SSLHelper.kt index 6d8bc6b344..4f7dcb8da3 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/SSLHelper.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/SSLHelper.kt @@ -40,6 +40,7 @@ import java.security.cert.CertificateException import java.security.cert.PKIXBuilderParameters import java.security.cert.X509CertSelector import java.security.cert.X509Certificate +import java.util.Locale import java.util.concurrent.Executor import java.util.concurrent.ThreadPoolExecutor import javax.net.ssl.CertPathTrustManagerParameters @@ -349,5 +350,5 @@ internal fun x500toHostName(x500Name: CordaX500Name): String { val secureHash = SecureHash.sha256(x500Name.toString()) // RFC 1035 specifies a limit 255 bytes for hostnames with each label being 63 bytes or less. Due to this, the string // representation of the SHA256 hash is truncated to 32 characters. - return String.format(HOSTNAME_FORMAT, secureHash.toString().take(32).toLowerCase()) + return String.format(HOSTNAME_FORMAT, secureHash.toString().take(32).lowercase(Locale.getDefault())) } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/TrustManagerFactoryWrapper.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/TrustManagerFactoryWrapper.kt index 7565b1cdc2..934279f75c 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/TrustManagerFactoryWrapper.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/TrustManagerFactoryWrapper.kt @@ -7,34 +7,24 @@ import javax.net.ssl.TrustManagerFactory import javax.net.ssl.TrustManagerFactorySpi import javax.net.ssl.X509ExtendedTrustManager -class LoggingTrustManagerFactorySpiWrapper(private val factorySpi: TrustManagerFactorySpi) : TrustManagerFactorySpi() { +class LoggingTrustManagerFactorySpiWrapper(private val trustManagerFactory: TrustManagerFactory) : TrustManagerFactorySpi() { override fun engineGetTrustManagers(): Array { - val engineGetTrustManagersMethod = TrustManagerFactorySpi::class.java.getDeclaredMethod("engineGetTrustManagers") - engineGetTrustManagersMethod.isAccessible = true - @Suppress("UNCHECKED_CAST") - val trustManagers = engineGetTrustManagersMethod.invoke(factorySpi) as Array - return if (factorySpi is LoggingTrustManagerFactorySpiWrapper) trustManagers else trustManagers.filterIsInstance(X509ExtendedTrustManager::class.java).map { LoggingTrustManagerWrapper(it) }.toTypedArray() + return trustManagerFactory.trustManagers + .mapNotNull { (it as? X509ExtendedTrustManager)?.let(::LoggingTrustManagerWrapper) } + .toTypedArray() } override fun engineInit(ks: KeyStore?) { - val engineInitMethod = TrustManagerFactorySpi::class.java.getDeclaredMethod("engineInit", KeyStore::class.java) - engineInitMethod.isAccessible = true - engineInitMethod.invoke(factorySpi, ks) + trustManagerFactory.init(ks) } override fun engineInit(spec: ManagerFactoryParameters?) { - val engineInitMethod = TrustManagerFactorySpi::class.java.getDeclaredMethod("engineInit", ManagerFactoryParameters::class.java) - engineInitMethod.isAccessible = true - engineInitMethod.invoke(factorySpi, spec) + trustManagerFactory.init(spec) } } -class LoggingTrustManagerFactoryWrapper(factory: TrustManagerFactory) : TrustManagerFactory(getFactorySpi(factory), factory.provider, factory.algorithm) { - companion object { - private fun getFactorySpi(factory: TrustManagerFactory): TrustManagerFactorySpi { - val spiField = TrustManagerFactory::class.java.getDeclaredField("factorySpi") - spiField.isAccessible = true - return LoggingTrustManagerFactorySpiWrapper(spiField.get(factory) as TrustManagerFactorySpi) - } - } -} \ No newline at end of file +class LoggingTrustManagerFactoryWrapper(factory: TrustManagerFactory) : TrustManagerFactory( + LoggingTrustManagerFactorySpiWrapper(factory), + factory.provider, + factory.algorithm +) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/revocation/CertDistPointCrlSource.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/revocation/CertDistPointCrlSource.kt index ee589e73a9..94200603a0 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/revocation/CertDistPointCrlSource.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/revocation/CertDistPointCrlSource.kt @@ -5,7 +5,6 @@ import com.github.benmanes.caffeine.cache.LoadingCache import net.corda.core.internal.readFully import net.corda.core.utilities.contextLogger import net.corda.core.utilities.debug -import net.corda.core.utilities.contextLogger import net.corda.core.utilities.minutes import net.corda.core.utilities.seconds import net.corda.nodeapi.internal.crypto.X509CertificateFactory @@ -21,7 +20,6 @@ import javax.security.auth.x500.X500Principal /** * [CrlSource] which downloads CRLs from the distribution points in the X509 certificate and caches them. */ -@Suppress("TooGenericExceptionCaught") class CertDistPointCrlSource(cacheSize: Long = DEFAULT_CACHE_SIZE, cacheExpiry: Duration = DEFAULT_CACHE_EXPIRY, private val connectTimeout: Duration = DEFAULT_CONNECT_TIMEOUT, diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/revocation/CordaRevocationChecker.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/revocation/CordaRevocationChecker.kt index 1e0a3ecf53..6d6be84fd8 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/revocation/CordaRevocationChecker.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/revocation/CordaRevocationChecker.kt @@ -33,7 +33,6 @@ class CordaRevocationChecker(private val crlSource: CrlSource, checkApprovedCRLs(cert, getCRLs(cert)) } - @Suppress("TooGenericExceptionCaught") private fun getCRLs(cert: X509Certificate): Set { val crls = try { crlSource.fetch(cert) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/rpc/client/RpcClientCordaFutureSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/rpc/client/RpcClientCordaFutureSerializer.kt index f7c23472f4..e7d091fbdb 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/rpc/client/RpcClientCordaFutureSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/rpc/client/RpcClientCordaFutureSerializer.kt @@ -2,6 +2,7 @@ package net.corda.nodeapi.internal.rpc.client import net.corda.core.concurrent.CordaFuture import net.corda.core.toFuture +import net.corda.serialization.internal.NotSerializableException import net.corda.serialization.internal.amqp.CustomSerializer import net.corda.serialization.internal.amqp.SerializerFactory import rx.Observable @@ -20,9 +21,7 @@ class RpcClientCordaFutureSerializer (factory: SerializerFactory) try { return proxy.observable.toFuture() } catch (e: NotSerializableException) { - throw NotSerializableException("Failed to deserialize Future from proxy Observable - ${e.message}\n").apply { - initCause(e.cause) - } + throw NotSerializableException("Failed to deserialize Future from proxy Observable - ${e.message}\n", e.cause) } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CordaClassResolver.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CordaClassResolver.kt index 59d514e98e..b96c3ccec3 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CordaClassResolver.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CordaClassResolver.kt @@ -13,7 +13,6 @@ import com.esotericsoftware.kryo.util.DefaultClassResolver import com.esotericsoftware.kryo.util.Util import net.corda.core.internal.kotlinObjectInstance import net.corda.core.internal.utilities.PrivateInterner -import net.corda.core.internal.writer import net.corda.core.serialization.ClassWhitelist import net.corda.core.serialization.internal.AttachmentsClassLoader import net.corda.core.serialization.internal.CheckpointSerializationContext @@ -28,8 +27,8 @@ import java.nio.file.Paths import java.nio.file.StandardOpenOption.APPEND import java.nio.file.StandardOpenOption.CREATE import java.nio.file.StandardOpenOption.WRITE -import java.util.ArrayList import java.util.Collections +import kotlin.io.path.writer /** * Corda specific class resolver which enables extra customisation for the purposes of serialization using Kryo @@ -93,7 +92,10 @@ class CordaClassResolver(serializationContext: CheckpointSerializationContext) : val serializer = when { objectInstance != null -> KotlinObjectSerializer(objectInstance) kotlin.jvm.internal.Lambda::class.java.isAssignableFrom(targetType) -> // Kotlin lambdas extend this class and any captured variables are stored in synthetic fields - FieldSerializer(kryo, targetType).apply { setIgnoreSyntheticFields(false) } + FieldSerializer(kryo, targetType).apply { + fieldSerializerConfig.ignoreSyntheticFields = false + updateFields() + } Throwable::class.java.isAssignableFrom(targetType) -> ThrowableSerializer(kryo, targetType) else -> maybeWrapForInterning(kryo.getDefaultSerializer(targetType), targetType) } @@ -114,12 +116,12 @@ class CordaClassResolver(serializationContext: CheckpointSerializationContext) : // Trivial Serializer which simply returns the given instance, which we already know is a Kotlin object private class KotlinObjectSerializer(private val objectInstance: Any) : Serializer() { - override fun read(kryo: Kryo, input: Input, type: Class): Any = objectInstance + override fun read(kryo: Kryo, input: Input, type: Class): Any = objectInstance override fun write(kryo: Kryo, output: Output, obj: Any) = Unit } private class InterningSerializer(private val delegate: Serializer, private val interner: PrivateInterner) : Serializer() { - override fun read(kryo: Kryo, input: Input, type: Class): Any = interner.intern(delegate.read(kryo, input, type)) + override fun read(kryo: Kryo, input: Input, type: Class): Any = interner.intern(delegate.read(kryo, input, type)) override fun write(kryo: Kryo, output: Output, obj: Any) = delegate.write(kryo, output, obj) } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CordaClosureSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CordaClosureSerializer.kt index 13ecd2682c..aed7096a37 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CordaClosureSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CordaClosureSerializer.kt @@ -19,11 +19,3 @@ object CordaClosureSerializer : ClosureSerializer() { return target is Serializable } } - -object CordaClosureBlacklistSerializer : ClosureSerializer() { - const val ERROR_MESSAGE = "Java 8 Lambda expressions are not supported for serialization." - - override fun write(kryo: Kryo, output: Output, target: Any) { - throw IllegalArgumentException(ERROR_MESSAGE) - } -} \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CustomIteratorSerializers.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CustomIteratorSerializers.kt index b02779fae8..193707dc0c 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CustomIteratorSerializers.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CustomIteratorSerializers.kt @@ -34,7 +34,7 @@ internal object LinkedHashMapIteratorSerializer : Serializer>() { kryo.writeClassAndObject(output, current) } - override fun read(kryo: Kryo, input: Input, type: Class>): Iterator<*> { + override fun read(kryo: Kryo, input: Input, type: Class>): Iterator<*> { val outerMap = kryo.readClassAndObject(input) as Map<*, *> return when (type) { KEY_ITERATOR_CLASS -> { @@ -103,7 +103,7 @@ object LinkedHashMapEntrySerializer : Serializer>() { kryo.writeClassAndObject(output, e.value) } - override fun read(kryo: Kryo, input: Input, type: Class>): Map.Entry<*, *> { + override fun read(kryo: Kryo, input: Input, type: Class>): Map.Entry<*, *> { val key = kryo.readClassAndObject(input) val value = kryo.readClassAndObject(input) return constr.newInstance(0, key, value, null) as Map.Entry<*, *> @@ -126,7 +126,7 @@ object LinkedListItrSerializer : Serializer>() { output.writeInt(obj.nextIndex()) } - override fun read(kryo: Kryo, input: Input, type: Class>): ListIterator { + override fun read(kryo: Kryo, input: Input, type: Class>): ListIterator { val list = kryo.readClassAndObject(input) as LinkedList<*> val index = input.readInt() return list.listIterator(index) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CustomSerializerCheckpointAdaptor.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CustomSerializerCheckpointAdaptor.kt index 4f3475696b..73f69ae210 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CustomSerializerCheckpointAdaptor.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/CustomSerializerCheckpointAdaptor.kt @@ -64,7 +64,7 @@ internal class CustomSerializerCheckpointAdaptor(private val userSer /** * Deserialize an object from the Kryo stream. */ - override fun read(kryo: Kryo, input: Input, type: Class): OBJ { + override fun read(kryo: Kryo, input: Input, type: Class): OBJ { @Suppress("UNCHECKED_CAST") fun readFromKryo() = kryo.readClassAndObject(input) as T diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/DefaultKryoCustomizer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/DefaultKryoCustomizer.kt index b2cb7cab94..76597a3f32 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/DefaultKryoCustomizer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/DefaultKryoCustomizer.kt @@ -2,11 +2,13 @@ package net.corda.nodeapi.internal.serialization.kryo import com.esotericsoftware.kryo.Kryo import com.esotericsoftware.kryo.Serializer +import com.esotericsoftware.kryo.SerializerFactory import com.esotericsoftware.kryo.io.Input import com.esotericsoftware.kryo.io.Output import com.esotericsoftware.kryo.serializers.ClosureSerializer import com.esotericsoftware.kryo.serializers.CompatibleFieldSerializer import com.esotericsoftware.kryo.serializers.FieldSerializer +import com.esotericsoftware.kryo.util.DefaultInstantiatorStrategy import de.javakaffee.kryoserializers.ArraysAsListSerializer import de.javakaffee.kryoserializers.BitSetSerializer import de.javakaffee.kryoserializers.UnmodifiableCollectionsSerializer @@ -18,7 +20,6 @@ import de.javakaffee.kryoserializers.guava.ImmutableSortedSetSerializer import net.corda.core.contracts.ContractAttachment import net.corda.core.contracts.ContractClassName import net.corda.core.contracts.PrivacySalt -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SecureHash import net.corda.core.identity.PartyAndCertificate import net.corda.core.internal.AbstractAttachment @@ -38,14 +39,6 @@ import net.corda.core.utilities.toNonEmptySet import net.corda.serialization.internal.DefaultWhitelist import net.corda.serialization.internal.GeneratedAttachment import net.corda.serialization.internal.MutableClassWhitelist -import net.i2p.crypto.eddsa.EdDSAPrivateKey -import net.i2p.crypto.eddsa.EdDSAPublicKey -import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey -import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey -import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey -import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey -import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey -import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey import org.objenesis.instantiator.ObjectInstantiator import org.objenesis.strategy.InstantiatorStrategy import org.objenesis.strategy.StdInstantiatorStrategy @@ -60,23 +53,40 @@ import java.security.PublicKey import java.security.cert.CertPath import java.security.cert.X509Certificate import java.util.* -import kotlin.collections.ArrayList object DefaultKryoCustomizer { private val serializationWhitelists: List by lazy { ServiceLoader.load(SerializationWhitelist::class.java, this.javaClass.classLoader).toList() + DefaultWhitelist } - fun customize(kryo: Kryo, publicKeySerializer: Serializer = PublicKeySerializer): Kryo { + fun customize(kryo: Kryo): Kryo { return kryo.apply { - // Store a little schema of field names in the stream the first time a class is used which increases tolerance - // for change to a class. - setDefaultSerializer(CompatibleFieldSerializer::class.java) + isRegistrationRequired = false + references = true + // Needed because of https://github.com/EsotericSoftware/kryo/issues/864 + setOptimizedGenerics(false) + + val defaultFactoryConfig = FieldSerializer.FieldSerializerConfig() // Take the safest route here and allow subclasses to have fields named the same as super classes. - fieldSerializerConfig.cachedFieldNameStrategy = FieldSerializer.CachedFieldNameStrategy.EXTENDED + defaultFactoryConfig.extendedFieldNames = true + defaultFactoryConfig.serializeTransient = false + // For checkpoints we still want all the synthetic fields. This allows inner classes to reference + // their parents after deserialization. + defaultFactoryConfig.ignoreSyntheticFields = false + kryo.setDefaultSerializer(SerializerFactory.FieldSerializerFactory(defaultFactoryConfig)) instantiatorStrategy = CustomInstantiatorStrategy() + addDefaultSerializer(Iterator::class.java, object : SerializerFactory.BaseSerializerFactory() { + override fun newSerializer(kryo: Kryo, type: Class<*>): IteratorSerializer { + val config = CompatibleFieldSerializer.CompatibleFieldSerializerConfig().apply { + ignoreSyntheticFields = false + extendedFieldNames = true + } + return IteratorSerializer(type, CompatibleFieldSerializer(kryo, type, config)) + } + }) + // Required for HashCheckingStream (de)serialization. // Note that return type should be specifically set to InputStream, otherwise it may not work, // i.e. val aStream : InputStream = HashCheckingStream(...). @@ -90,6 +100,8 @@ object DefaultKryoCustomizer { // Please add any new registrations to the end. addDefaultSerializer(LinkedHashMapIteratorSerializer.getIterator()::class.java.superclass, LinkedHashMapIteratorSerializer) + addDefaultSerializer(PublicKey::class.java, PublicKeySerializer) + addDefaultSerializer(PrivateKey::class.java, PrivateKeySerializer) register(LinkedHashMapEntrySerializer.getEntry()::class.java, LinkedHashMapEntrySerializer) register(LinkedListItrSerializer.getListItr()::class.java, LinkedListItrSerializer) register(Arrays.asList("").javaClass, ArraysAsListSerializer()) @@ -106,12 +118,6 @@ object DefaultKryoCustomizer { // InputStream subclasses whitelisting, required for attachments. register(BufferedInputStream::class.java, InputStreamSerializer) register(Class.forName("sun.net.www.protocol.jar.JarURLConnection\$JarURLInputStream"), InputStreamSerializer) - noReferencesWithin() - register(PublicKey::class.java, publicKeySerializer) - register(PrivateKey::class.java, PrivateKeySerializer) - register(EdDSAPublicKey::class.java, publicKeySerializer) - register(EdDSAPrivateKey::class.java, PrivateKeySerializer) - register(CompositeKey::class.java, publicKeySerializer) // Using a custom serializer for compactness // Exceptions. We don't bother sending the stack traces as the client will fill in its own anyway. register(Array::class, read = { _, _ -> emptyArray() }, write = { _, _, _ -> }) // This ensures a NonEmptySetSerializer is constructed with an initial value. @@ -120,12 +126,6 @@ object DefaultKryoCustomizer { register(Class::class.java, ClassSerializer) register(FileInputStream::class.java, InputStreamSerializer) register(CertPath::class.java, CertPathSerializer) - register(BCECPrivateKey::class.java, PrivateKeySerializer) - register(BCECPublicKey::class.java, publicKeySerializer) - register(BCRSAPrivateCrtKey::class.java, PrivateKeySerializer) - register(BCRSAPublicKey::class.java, publicKeySerializer) - register(BCSphincs256PrivateKey::class.java, PrivateKeySerializer) - register(BCSphincs256PublicKey::class.java, publicKeySerializer) register(NotaryChangeWireTransaction::class.java, NotaryChangeWireTransactionSerializer) register(PartyAndCertificate::class.java, PartyAndCertificateSerializer) @@ -136,14 +136,10 @@ object DefaultKryoCustomizer { register(ContractAttachment::class.java, ContractAttachmentSerializer) register(java.lang.invoke.SerializedLambda::class.java) - register(ClosureSerializer.Closure::class.java, CordaClosureBlacklistSerializer) + register(ClosureSerializer.Closure::class.java, CordaClosureSerializer) register(ContractUpgradeWireTransaction::class.java, ContractUpgradeWireTransactionSerializer) register(ContractUpgradeFilteredTransaction::class.java, ContractUpgradeFilteredTransactionSerializer) - addDefaultSerializer(Iterator::class.java) {kryo, type -> - IteratorSerializer(type, CompatibleFieldSerializer>(kryo, type).apply { setIgnoreSyntheticFields(false) }) - } - for (whitelistProvider in serializationWhitelists) { val types = whitelistProvider.whitelist require(types.toSet().size == types.size) { @@ -162,7 +158,7 @@ object DefaultKryoCustomizer { private val fallbackStrategy = StdInstantiatorStrategy() // Use this to allow construction of objects using a JVM backdoor that skips invoking the constructors, if there // is no no-arg constructor available. - private val defaultStrategy = Kryo.DefaultInstantiatorStrategy(fallbackStrategy) + private val defaultStrategy = DefaultInstantiatorStrategy(fallbackStrategy) override fun newInstantiatorOf(type: Class): ObjectInstantiator { // However this doesn't work for non-public classes in the java. namespace @@ -176,7 +172,7 @@ object DefaultKryoCustomizer { kryo.writeClassAndObject(output, obj.certPath) } - override fun read(kryo: Kryo, input: Input, type: Class): PartyAndCertificate { + override fun read(kryo: Kryo, input: Input, type: Class): PartyAndCertificate { return PartyAndCertificate(kryo.readClassAndObject(input) as CertPath) } } @@ -188,7 +184,7 @@ object DefaultKryoCustomizer { obj.forEach { kryo.writeClassAndObject(output, it) } } - override fun read(kryo: Kryo, input: Input, type: Class>): NonEmptySet { + override fun read(kryo: Kryo, input: Input, type: Class>): NonEmptySet { val size = input.readInt(true) require(size >= 1) { "Invalid size read off the wire: $size" } val list = ArrayList(size) @@ -208,7 +204,7 @@ object DefaultKryoCustomizer { output.writeBytesWithLength(obj.bytes) } - override fun read(kryo: Kryo, input: Input, type: Class): PrivacySalt { + override fun read(kryo: Kryo, input: Input, type: Class): PrivacySalt { return PrivacySalt(input.readBytesWithLength()) } } @@ -230,7 +226,7 @@ object DefaultKryoCustomizer { } @Suppress("UNCHECKED_CAST") - override fun read(kryo: Kryo, input: Input, type: Class): ContractAttachment { + override fun read(kryo: Kryo, input: Input, type: Class): ContractAttachment { if (kryo.serializationContext() != null) { val attachmentHash = SecureHash.createSHA256(input.readBytes(32)) val contract = input.readString() @@ -261,4 +257,4 @@ object DefaultKryoCustomizer { } } } -} \ No newline at end of file +} diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/IteratorSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/IteratorSerializer.kt index 601f384593..d618251e37 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/IteratorSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/IteratorSerializer.kt @@ -20,7 +20,7 @@ class IteratorSerializer(type: Class<*>, private val serializer: Serializer>): Iterator<*> { + override fun read(kryo: Kryo, input: Input, type: Class>): Iterator<*> { val iterator = serializer.read(kryo, input, type) return fixIterator(iterator) } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/Kryo.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/Kryo.kt index d747c23b97..0ad5a7d037 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/Kryo.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/Kryo.kt @@ -5,7 +5,7 @@ import com.esotericsoftware.kryo.Kryo import com.esotericsoftware.kryo.KryoException import com.esotericsoftware.kryo.Registration import com.esotericsoftware.kryo.Serializer -import com.esotericsoftware.kryo.factories.ReflectionSerializerFactory +import com.esotericsoftware.kryo.SerializerFactory import com.esotericsoftware.kryo.io.Input import com.esotericsoftware.kryo.io.Output import com.esotericsoftware.kryo.serializers.CompatibleFieldSerializer @@ -28,7 +28,6 @@ import net.corda.core.transactions.NotaryChangeWireTransaction import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.OpaqueBytes -import net.corda.core.utilities.SgxSupport import net.corda.serialization.internal.serializationContextKey import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -39,7 +38,6 @@ import java.security.PublicKey import java.security.cert.CertPath import java.security.cert.CertificateFactory import java.security.cert.X509Certificate -import java.util.Collections import javax.annotation.concurrent.ThreadSafe import kotlin.reflect.KClass import kotlin.reflect.KMutableProperty @@ -68,7 +66,7 @@ object SerializedBytesSerializer : Serializer>() { obj.writeTo(output) } - override fun read(kryo: Kryo, input: Input, type: Class>): SerializedBytes { + override fun read(kryo: Kryo, input: Input, type: Class>): SerializedBytes { return SerializedBytes(input.readBytes(input.readVarInt(true))) } } @@ -84,11 +82,8 @@ class ImmutableClassSerializer(val klass: KClass) : Serializer() init { // Verify that this class is immutable (all properties are final). - // We disable this check inside SGX as the reflection blows up. - if (!SgxSupport.isInsideEnclave) { - props.forEach { - require(it !is KMutableProperty<*>) { "$it mutable property of class: ${klass} is unsupported" } - } + props.forEach { + require(it !is KMutableProperty<*>) { "$it mutable property of class: $klass is unsupported" } } } @@ -123,7 +118,8 @@ class ImmutableClassSerializer(val klass: KClass) : Serializer() } } - override fun read(kryo: Kryo, input: Input, type: Class): T { + @Suppress("ComplexMethod") + override fun read(kryo: Kryo, input: Input, type: Class): T { require(type.kotlin == klass) val numFields = input.readVarInt(true) val fieldTypeHash = input.readInt() @@ -177,7 +173,7 @@ object InputStreamSerializer : Serializer() { } } - override fun read(kryo: Kryo, input: Input, type: Class): InputStream { + override fun read(kryo: Kryo, input: Input, type: Class): InputStream { val chunks = ArrayList() while (true) { val chunk = input.readBytesWithLength() @@ -187,7 +183,7 @@ object InputStreamSerializer : Serializer() { chunks.add(chunk) } } - val flattened = ByteArray(chunks.sumBy { it.size }) + val flattened = ByteArray(chunks.sumOf { it.size }) var offset = 0 for (chunk in chunks) { System.arraycopy(chunk, 0, flattened, offset, chunk.size) @@ -227,7 +223,7 @@ object WireTransactionSerializer : Serializer() { kryo.writeClassAndObject(output, obj.digestService) } - override fun read(kryo: Kryo, input: Input, type: Class): WireTransaction { + override fun read(kryo: Kryo, input: Input, type: Class): WireTransaction { val componentGroups: List = uncheckedCast(kryo.readClassAndObject(input)) val privacySalt = kryo.readClassAndObject(input) as PrivacySalt val digestService = kryo.readClassAndObject(input) as? DigestService @@ -242,7 +238,7 @@ object NotaryChangeWireTransactionSerializer : Serializer): NotaryChangeWireTransaction { + override fun read(kryo: Kryo, input: Input, type: Class): NotaryChangeWireTransaction { val components: List = uncheckedCast(kryo.readClassAndObject(input)) val digestService = kryo.readClassAndObject(input) as? DigestService return NotaryChangeWireTransaction(components, digestService ?: DigestService.sha2_256) @@ -257,7 +253,7 @@ object ContractUpgradeWireTransactionSerializer : Serializer): ContractUpgradeWireTransaction { + override fun read(kryo: Kryo, input: Input, type: Class): ContractUpgradeWireTransaction { val components: List = uncheckedCast(kryo.readClassAndObject(input)) val privacySalt = kryo.readClassAndObject(input) as PrivacySalt val digestService = kryo.readClassAndObject(input) as? DigestService @@ -272,7 +268,7 @@ object ContractUpgradeFilteredTransactionSerializer : Serializer): ContractUpgradeFilteredTransaction { + override fun read(kryo: Kryo, input: Input, type: Class): ContractUpgradeFilteredTransaction { val visibleComponents: Map = uncheckedCast(kryo.readClassAndObject(input)) val hiddenComponents: Map = uncheckedCast(kryo.readClassAndObject(input)) return ContractUpgradeFilteredTransaction(visibleComponents, hiddenComponents) @@ -286,7 +282,7 @@ object SignedTransactionSerializer : Serializer() { kryo.writeClassAndObject(output, obj.sigs) } - override fun read(kryo: Kryo, input: Input, type: Class): SignedTransaction { + override fun read(kryo: Kryo, input: Input, type: Class): SignedTransaction { return SignedTransaction( uncheckedCast>(kryo.readClassAndObject(input)), uncheckedCast>(kryo.readClassAndObject(input)) @@ -300,7 +296,7 @@ object PrivateKeySerializer : Serializer() { output.writeBytesWithLength(obj.encoded) } - override fun read(kryo: Kryo, input: Input, type: Class): PrivateKey { + override fun read(kryo: Kryo, input: Input, type: Class): PrivateKey { val A = input.readBytesWithLength() return Crypto.decodePrivateKey(A) } @@ -314,7 +310,7 @@ object PublicKeySerializer : Serializer() { output.writeBytesWithLength(Crypto.encodePublicKey(obj)) } - override fun read(kryo: Kryo, input: Input, type: Class): PublicKey { + override fun read(kryo: Kryo, input: Input, type: Class): PublicKey { val A = input.readBytesWithLength() return Crypto.decodePublicKey(A) } @@ -382,7 +378,7 @@ inline fun Kryo.register( return register( type.java, object : Serializer() { - override fun read(kryo: Kryo, input: Input, clazz: Class): T = read(kryo, input) + override fun read(kryo: Kryo, input: Input, clazz: Class): T = read(kryo, input) override fun write(kryo: Kryo, output: Output, obj: T) = write(kryo, output, obj) } ) @@ -399,7 +395,7 @@ inline fun Kryo.noReferencesWithin() { class NoReferencesSerializer(private val baseSerializer: Serializer) : Serializer() { - override fun read(kryo: Kryo, input: Input, type: Class): T { + override fun read(kryo: Kryo, input: Input, type: Class): T { return kryo.withoutReferences { baseSerializer.read(kryo, input, type) } } @@ -424,13 +420,13 @@ object LoggerSerializer : Serializer() { output.writeString(obj.name) } - override fun read(kryo: Kryo, input: Input, type: Class): Logger { + override fun read(kryo: Kryo, input: Input, type: Class): Logger { return LoggerFactory.getLogger(input.readString()) } } object ClassSerializer : Serializer>() { - override fun read(kryo: Kryo, input: Input, type: Class>): Class<*> { + override fun read(kryo: Kryo, input: Input, type: Class>): Class<*> { val className = input.readString() return if (className == "void") Void.TYPE else Class.forName(className, true, kryo.classLoader) } @@ -442,7 +438,7 @@ object ClassSerializer : Serializer>() { @ThreadSafe object CertPathSerializer : Serializer() { - override fun read(kryo: Kryo, input: Input, type: Class): CertPath { + override fun read(kryo: Kryo, input: Input, type: Class): CertPath { val factory = CertificateFactory.getInstance(input.readString()) return factory.generateCertPath(input.readBytesWithLength().inputStream()) } @@ -455,7 +451,7 @@ object CertPathSerializer : Serializer() { @ThreadSafe object X509CertificateSerializer : Serializer() { - override fun read(kryo: Kryo, input: Input, type: Class): X509Certificate { + override fun read(kryo: Kryo, input: Input, type: Class): X509Certificate { return CertificateFactory.getInstance("X.509").generateCertificate(input.readBytesWithLength().inputStream()) as X509Certificate } @@ -464,7 +460,7 @@ object X509CertificateSerializer : Serializer() { } } -fun Kryo.serializationContext(): SerializeAsTokenContext? = context.get(serializationContextKey) as? SerializeAsTokenContext +fun Kryo.serializationContext(): SerializeAsTokenContext? = context.get(serializationContextKey) as? SerializeAsTokenContext /** * For serializing instances if [Throwable] honoring the fact that [java.lang.Throwable.suppressedExceptions] @@ -477,18 +473,12 @@ fun Kryo.serializationContext(): SerializeAsTokenContext? = context.get(serializ class ThrowableSerializer(kryo: Kryo, type: Class) : Serializer(false, true) { private companion object { - private val IS_OPENJ9 = System.getProperty("java.vm.name").toLowerCase().contains("openj9") private val suppressedField = Throwable::class.java.getDeclaredField("suppressedExceptions") private val sentinelValue = let { - if (!IS_OPENJ9) { - val sentinelField = Throwable::class.java.getDeclaredField("SUPPRESSED_SENTINEL") - sentinelField.isAccessible = true - sentinelField.get(null) - } - else { - Collections.EMPTY_LIST - } + val sentinelField = Throwable::class.java.getDeclaredField("SUPPRESSED_SENTINEL") + sentinelField.isAccessible = true + sentinelField.get(null) } init { @@ -496,13 +486,14 @@ class ThrowableSerializer(kryo: Kryo, type: Class) : Serializer } } - private val delegate: Serializer = uncheckedCast(ReflectionSerializerFactory.makeSerializer(kryo, FieldSerializer::class.java, type)) + @Suppress("UNCHECKED_CAST") + private val delegate: Serializer = SerializerFactory.ReflectionSerializerFactory.newSerializer(kryo, FieldSerializer::class.java, type) as Serializer override fun write(kryo: Kryo, output: Output, throwable: Throwable) { delegate.write(kryo, output, throwable) } - override fun read(kryo: Kryo, input: Input, type: Class): Throwable { + override fun read(kryo: Kryo, input: Input, type: Class): Throwable { val throwableRead = delegate.read(kryo, input, type) if (throwableRead.suppressed.isEmpty()) { throwableRead.setSuppressedToSentinel() @@ -519,5 +510,5 @@ class ThrowableSerializer(kryo: Kryo, type: Class) : Serializer object LazyMappedListSerializer : Serializer>() { // Using a MutableList so that Kryo will always write an instance of java.util.ArrayList. override fun write(kryo: Kryo, output: Output, obj: List<*>) = kryo.writeClassAndObject(output, obj.toMutableList()) - override fun read(kryo: Kryo, input: Input, type: Class>) = kryo.readClassAndObject(input) as? List<*> + override fun read(kryo: Kryo, input: Input, type: Class>) = kryo.readClassAndObject(input) as? List<*> } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoCheckpointSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoCheckpointSerializer.kt index 178682e088..dd67326e53 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoCheckpointSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoCheckpointSerializer.kt @@ -7,7 +7,6 @@ import com.esotericsoftware.kryo.KryoException import com.esotericsoftware.kryo.Serializer import com.esotericsoftware.kryo.io.Input import com.esotericsoftware.kryo.io.Output -import com.esotericsoftware.kryo.pool.KryoPool import com.esotericsoftware.kryo.serializers.ClosureSerializer import net.corda.core.internal.uncheckedCast import net.corda.core.serialization.CheckpointCustomSerializer @@ -38,17 +37,16 @@ private object AutoCloseableSerialisationDetector : Serializer() throw UnsupportedOperationException(message) } - override fun read(kryo: Kryo, input: Input, type: Class) = throw IllegalStateException("Should not reach here!") + override fun read(kryo: Kryo, input: Input, type: Class) = throw IllegalStateException("Should not reach here!") } object KryoCheckpointSerializer : CheckpointSerializer { private val kryoPoolsForContexts = ConcurrentHashMap>>, KryoPool>() - private fun getPool(context: CheckpointSerializationContext): KryoPool { return kryoPoolsForContexts.computeIfAbsent(Triple(context.whitelist, context.deserializationClassLoader, context.checkpointCustomSerializers)) { - KryoPool.Builder { - val serializer = Fiber.getFiberSerializer(false) as KryoSerializer - val classResolver = CordaClassResolver(context).apply { setKryo(serializer.kryo) } + KryoPool { + val classResolver = CordaClassResolver(context) + val serializer = Fiber.getFiberSerializer(classResolver,false) as KryoSerializer // TODO The ClassResolver can only be set in the Kryo constructor and Quasar doesn't provide us with a way of doing that val field = Kryo::class.java.getDeclaredField("classResolver").apply { isAccessible = true } serializer.kryo.apply { @@ -64,9 +62,9 @@ object KryoCheckpointSerializer : CheckpointSerializer { warnAboutDuplicateSerializers(customSerializers) val classToSerializer = mapInputClassToCustomSerializer(context.deserializationClassLoader, customSerializers) addDefaultCustomSerializers(this, classToSerializer) + referenceResolver } - }.build() - + } } } @@ -113,13 +111,13 @@ object KryoCheckpointSerializer : CheckpointSerializer { .forEach { (clazz, customSerializer) -> kryo.addDefaultSerializer(clazz, customSerializer) } private fun CheckpointSerializationContext.kryo(task: Kryo.() -> T): T { - return getPool(this).run { kryo -> - kryo.context.ensureCapacity(properties.size) - properties.forEach { kryo.context.put(it.key, it.value) } + return getPool(this).run { + this.context.ensureCapacity(properties.size) + properties.forEach { this.context.put(it.key, it.value) } try { - kryo.task() + this.task() } finally { - kryo.context.clear() + this.context.clear() } } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoPool.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoPool.kt new file mode 100644 index 0000000000..0353c7861c --- /dev/null +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoPool.kt @@ -0,0 +1,23 @@ +package net.corda.nodeapi.internal.serialization.kryo + +import com.esotericsoftware.kryo.Kryo +import com.esotericsoftware.kryo.util.Pool + +fun interface KryoFactory { + fun create(): Kryo +} + +class KryoPool(val factory: KryoFactory) : Pool(true, true) { + override fun create(): Kryo { + return factory.create() + } + + fun run(task: Kryo.()->T): T { + val kryo: Kryo = obtain() + return try { + kryo.task() + } finally { + free(kryo) + } + } +} diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/SerializeAsTokenSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/SerializeAsTokenSerializer.kt index 142e9fe35e..44e6debc4f 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/SerializeAsTokenSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/SerializeAsTokenSerializer.kt @@ -18,7 +18,7 @@ class SerializeAsTokenSerializer : Serializer() { ?: throw KryoException("Attempt to write a ${SerializeAsToken::class.simpleName} instance of ${obj.javaClass.name} without initialising a context"))) } - override fun read(kryo: Kryo, input: Input, type: Class): T { + override fun read(kryo: Kryo, input: Input, type: Class): T { val token = (kryo.readClassAndObject(input) as? SerializationToken) ?: throw KryoException("Non-token read for tokenized type: ${type.name}") val fromToken = token.fromToken(kryo.serializationContext() @@ -26,4 +26,4 @@ class SerializeAsTokenSerializer : Serializer() { return type.castIfPossible(fromToken) ?: throw KryoException("Token read ($token) did not return expected tokenized type: ${type.name}") } -} \ No newline at end of file +} diff --git a/core/src/main/kotlin/net/corda/core/internal/telemetry/OpenTelemetryComponent.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/telemetry/OpenTelemetryComponent.kt similarity index 93% rename from core/src/main/kotlin/net/corda/core/internal/telemetry/OpenTelemetryComponent.kt rename to node-api/src/main/kotlin/net/corda/nodeapi/internal/telemetry/OpenTelemetryComponent.kt index 33446f2901..ee20c3a977 100644 --- a/core/src/main/kotlin/net/corda/core/internal/telemetry/OpenTelemetryComponent.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/telemetry/OpenTelemetryComponent.kt @@ -1,5 +1,6 @@ -package net.corda.core.internal.telemetry +package net.corda.nodeapi.internal.telemetry +import co.paralleluniverse.fibers.instrument.DontInstrument import io.opentelemetry.api.GlobalOpenTelemetry import io.opentelemetry.api.OpenTelemetry import io.opentelemetry.api.baggage.Baggage @@ -11,14 +12,23 @@ 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 net.corda.core.flows.FlowLogic +import net.corda.core.internal.telemetry.EndSpanEvent +import net.corda.core.internal.telemetry.EndSpanForFlowEvent +import net.corda.core.internal.telemetry.RecordExceptionEvent +import net.corda.core.internal.telemetry.SetStatusEvent +import net.corda.core.internal.telemetry.ShutdownTelemetryEvent +import net.corda.core.internal.telemetry.StartSpanEvent +import net.corda.core.internal.telemetry.StartSpanForFlowEvent +import net.corda.core.internal.telemetry.TelemetryComponent +import net.corda.core.internal.telemetry.TelemetryDataItem +import net.corda.core.internal.telemetry.TelemetryEvent +import net.corda.core.internal.telemetry.TelemetryStatusCode +import net.corda.core.serialization.CordaSerializable +import net.corda.opentelemetrydriver.OpenTelemetryDriver +import java.util.UUID +import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentLinkedDeque @CordaSerializable @@ -34,7 +44,7 @@ data class SpanInfo(val name: String, val span: Span, val spanScope: Scope, class TracerSetup(serviceName: String) { private var openTelemetryDriver: Any? = null - val openTelemetry: OpenTelemetry by lazy { + val openTelemetry: OpenTelemetry by lazy @DontInstrument { try { openTelemetryDriver = OpenTelemetryDriver(serviceName) (openTelemetryDriver as OpenTelemetryDriver).openTelemetry @@ -53,12 +63,11 @@ class TracerSetup(serviceName: String) { } @Suppress("TooManyFunctions") -class OpenTelemetryComponent(val serviceName: String, val spanStartEndEventsEnabled: Boolean, val copyBaggageToTags: Boolean) : TelemetryComponent { +class OpenTelemetryComponent(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" } @@ -89,15 +98,15 @@ class OpenTelemetryComponent(val serviceName: String, val spanStartEndEventsEnab } private fun extractContext(carrier: ContextCarrier): Context { - val getter = object : TextMapGetter { + val getter = object : TextMapGetter { 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 { - return carrier?.context?.keys ?: mutableListOf() + override fun keys(carrier: ContextCarrier): MutableIterable { + return carrier.context.keys } } return carrier.let { @@ -371,4 +380,4 @@ class OpenTelemetryComponent(val serviceName: String, val spanStartEndEventsEnab val spanInfo = spans[telemetryId] spanInfo?.span?.recordException(throwable) } -} \ No newline at end of file +} diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/SignedNodeInfoTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/SignedNodeInfoTest.kt index eb7f2c20b6..39fa3073ae 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/SignedNodeInfoTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/SignedNodeInfoTest.kt @@ -6,13 +6,13 @@ import net.corda.core.identity.CordaX500Name import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.utilities.NetworkHostAndPort +import net.corda.coretesting.internal.TestNodeInfoBuilder +import net.corda.coretesting.internal.signWith import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.BOB_NAME import net.corda.testing.core.SerializationEnvironmentRule -import net.corda.coretesting.internal.TestNodeInfoBuilder -import net.corda.coretesting.internal.signWith import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.Rule diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/config/ConfigParsingTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/config/ConfigParsingTest.kt index d26ceec789..27f92456b1 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/config/ConfigParsingTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/config/ConfigParsingTest.kt @@ -6,16 +6,19 @@ import com.typesafe.config.ConfigFactory.empty import com.typesafe.config.ConfigRenderOptions.defaults import com.typesafe.config.ConfigValueFactory import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort -import org.assertj.core.api.Assertions.* +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.Test import java.net.URL import java.nio.file.Path import java.time.Instant import java.time.LocalDate -import java.util.* +import java.util.Properties +import java.util.UUID import javax.security.auth.x500.X500Principal +import kotlin.io.path.div import kotlin.reflect.full.primaryConstructor class ConfigParsingTest { @@ -85,7 +88,7 @@ class ConfigParsingTest { @Test(timeout=300_000) fun Path() { - val path = "tmp" / "test" + val path = Path.of("tmp", "test") testPropertyType(path, path / "file", valuesToString = true) } @@ -105,7 +108,7 @@ class ConfigParsingTest { } @Test(timeout=300_000) - fun CordaX500Name() { + fun `test CordaX500Name`() { val name1 = CordaX500Name(organisation = "Mock Party", locality = "London", country = "GB") testPropertyType( name1, @@ -370,4 +373,4 @@ class ConfigParsingTest { } enum class TestEnum { Value1, Value2 } -} \ No newline at end of file +} diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/ContentSignerBuilderTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/ContentSignerBuilderTest.kt index 6920c78093..7b3a329a9b 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/ContentSignerBuilderTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/ContentSignerBuilderTest.kt @@ -28,6 +28,6 @@ class ContentSignerBuilderTest { .isThrownBy { ContentSignerBuilder.build(signatureScheme, issuerKeyPair.private, provider) } - .withMessage("Incorrect key type EC for signature scheme NONEwithEdDSA") + .withMessage("Incorrect key type EC for signature scheme Ed25519") } -} \ No newline at end of file +} diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/cryptoservice/bouncycastle/BCCryptoServiceTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/cryptoservice/DefaultCryptoServiceTests.kt similarity index 83% rename from node-api/src/test/kotlin/net/corda/nodeapi/internal/cryptoservice/bouncycastle/BCCryptoServiceTests.kt rename to node-api/src/test/kotlin/net/corda/nodeapi/internal/cryptoservice/DefaultCryptoServiceTests.kt index 364ef13ce4..560f33a69a 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/cryptoservice/bouncycastle/BCCryptoServiceTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/cryptoservice/DefaultCryptoServiceTests.kt @@ -1,20 +1,15 @@ -package net.corda.nodeapi.internal.cryptoservice.bouncycastle +package net.corda.nodeapi.internal.cryptoservice import net.corda.core.crypto.Crypto import net.corda.core.crypto.SignatureScheme import net.corda.core.crypto.internal.cordaBouncyCastleProvider -import net.corda.core.internal.div import net.corda.core.utilities.days +import net.corda.coretesting.internal.stubs.CertificateStoreStubs import net.corda.nodeapi.internal.config.CertificateStoreSupplier import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.X509Utilities -import net.corda.nodeapi.internal.cryptoservice.CryptoService -import net.corda.nodeapi.internal.cryptoservice.CryptoServiceException -import net.corda.nodeapi.internal.cryptoservice.WrappedPrivateKey -import net.corda.nodeapi.internal.cryptoservice.WrappingMode -import net.corda.testing.core.ALICE_NAME -import net.corda.coretesting.internal.stubs.CertificateStoreStubs import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore +import net.corda.testing.core.ALICE_NAME import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy import org.bouncycastle.jce.provider.BouncyCastleProvider @@ -24,17 +19,22 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import java.io.FileOutputStream import java.nio.file.Path -import java.security.* +import java.security.KeyPair +import java.security.KeyPairGenerator +import java.security.KeyStore +import java.security.PublicKey +import java.security.Signature import java.security.spec.ECGenParameterSpec import java.time.Duration -import java.util.* +import java.util.UUID import javax.crypto.Cipher import javax.security.auth.x500.X500Principal +import kotlin.io.path.div import kotlin.test.assertFailsWith import kotlin.test.assertFalse import kotlin.test.assertTrue -class BCCryptoServiceTests { +class DefaultCryptoServiceTests { companion object { val clearData = "data".toByteArray() } @@ -48,8 +48,8 @@ class BCCryptoServiceTests { @JvmField val temporaryKeystoreFolder = TemporaryFolder() - lateinit var certificatesDirectory: Path - lateinit var wrappingKeyStorePath: Path + private lateinit var certificatesDirectory: Path + private lateinit var wrappingKeyStorePath: Path @Before fun setUp() { @@ -60,14 +60,13 @@ class BCCryptoServiceTests { } @Test(timeout=300_000) - fun `BCCryptoService generate key pair and sign both data and cert`() { - val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) + fun `cryptoService generate key pair and sign both data and cert`() { + val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) // Testing every supported scheme. - Crypto.supportedSignatureSchemes().filter { it != Crypto.COMPOSITE_KEY - && it.signatureName != "SHA512WITHSPHINCS256"}.forEach { generateKeyAndSignForScheme(cryptoService, it) } + Crypto.supportedSignatureSchemes().filter { it != Crypto.COMPOSITE_KEY }.forEach { generateKeyAndSignForScheme(cryptoService, it) } } - private fun generateKeyAndSignForScheme(cryptoService: BCCryptoService, signatureScheme: SignatureScheme) { + private fun generateKeyAndSignForScheme(cryptoService: DefaultCryptoService, signatureScheme: SignatureScheme) { val alias = "signature${signatureScheme.schemeNumberID}" val pubKey = cryptoService.generateKeyPair(alias, signatureScheme) assertTrue { cryptoService.containsKey(alias) } @@ -93,11 +92,10 @@ class BCCryptoServiceTests { } @Test(timeout=300_000) - fun `BCCryptoService generate key pair and sign with existing schemes`() { - val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) + fun `cryptoService generate key pair and sign with existing schemes`() { + val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) // Testing every supported scheme. - Crypto.supportedSignatureSchemes().filter { it != Crypto.COMPOSITE_KEY - && it.signatureName != "SHA512WITHSPHINCS256"}.forEach { + Crypto.supportedSignatureSchemes().filter { it != Crypto.COMPOSITE_KEY }.forEach { val alias = "signature${it.schemeNumberID}" val pubKey = cryptoService.generateKeyPair(alias, it) assertTrue { cryptoService.containsKey(alias) } @@ -107,8 +105,7 @@ class BCCryptoServiceTests { } @Test(timeout=300_000) - fun `BCCryptoService generate key pair and sign with passed signing algorithm`() { - + fun `cryptoService generate key pair and sign with passed signing algorithm`() { assertTrue{signAndVerify(signAlgo = "NONEwithRSA", alias = "myKeyAlias", keyTypeAlgo = "RSA")} assertTrue{signAndVerify(signAlgo = "MD2withRSA", alias = "myKeyAlias", keyTypeAlgo = "RSA")} assertTrue{signAndVerify(signAlgo = "MD5withRSA", alias = "myKeyAlias", keyTypeAlgo = "RSA")} @@ -128,7 +125,7 @@ class BCCryptoServiceTests { private fun signAndVerify(signAlgo: String, alias: String, keyTypeAlgo: String): Boolean { val keyPairGenerator = KeyPairGenerator.getInstance(keyTypeAlgo) val keyPair = keyPairGenerator.genKeyPair() - val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, createKeystore(alias, keyPair), wrappingKeyStorePath) + val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, createKeystore(alias, keyPair), wrappingKeyStorePath) assertTrue { cryptoService.containsKey(alias) } val signatureData = cryptoService.sign(alias, clearData, signAlgo) return verify(signAlgo, cryptoService.getPublicKey(alias), signatureData, clearData) @@ -171,7 +168,7 @@ class BCCryptoServiceTests { @Test(timeout=300_000) fun `When key does not exist getPublicKey, sign and getSigner should throw`() { val nonExistingAlias = "nonExistingAlias" - val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) + val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) assertFalse { cryptoService.containsKey(nonExistingAlias) } assertFailsWith { cryptoService.getPublicKey(nonExistingAlias) } assertFailsWith { cryptoService.sign(nonExistingAlias, clearData) } @@ -180,7 +177,7 @@ class BCCryptoServiceTests { @Test(timeout=300_000) fun `cryptoService supports degraded mode of wrapping`() { - val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) + val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) val supportedMode = cryptoService.getWrappingMode() assertThat(supportedMode).isEqualTo(WrappingMode.DEGRADED_WRAPPED) @@ -188,7 +185,7 @@ class BCCryptoServiceTests { @Test(timeout=300_000) fun `cryptoService does not fail when requested to create same wrapping key twice with failIfExists is false`() { - val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) + val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) val keyAlias = UUID.randomUUID().toString() cryptoService.createWrappingKey(keyAlias) @@ -197,7 +194,7 @@ class BCCryptoServiceTests { @Test(timeout=300_000) fun `cryptoService does fail when requested to create same wrapping key twice with failIfExists is true`() { - val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) + val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) val keyAlias = UUID.randomUUID().toString() cryptoService.createWrappingKey(keyAlias) @@ -209,7 +206,7 @@ class BCCryptoServiceTests { @Test(timeout=300_000) fun `cryptoService fails when asked to generate wrapped key pair or sign, but the master key specified does not exist`() { - val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) + val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) val wrappingKeyAlias = UUID.randomUUID().toString() @@ -226,7 +223,7 @@ class BCCryptoServiceTests { @Test(timeout=300_000) fun `cryptoService can generate wrapped key pair and sign with the private key successfully, using default algorithm`() { - val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) + val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) val wrappingKeyAlias = UUID.randomUUID().toString() cryptoService.createWrappingKey(wrappingKeyAlias) @@ -235,7 +232,7 @@ class BCCryptoServiceTests { @Test(timeout=300_000) fun `cryptoService can generate wrapped key pair and sign with the private key successfully`() { - val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) + val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) val wrappingKeyAlias = UUID.randomUUID().toString() cryptoService.createWrappingKey(wrappingKeyAlias) @@ -260,7 +257,7 @@ class BCCryptoServiceTests { @Test(timeout=300_000) fun `cryptoService can sign with previously encoded version of wrapped key`() { - val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) + val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath) val wrappingKeyAlias = UUID.randomUUID().toString() cryptoService.createWrappingKey(wrappingKeyAlias) diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/lifecycle/NodeLifecycleEventsDistributorMultiThreadedTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/lifecycle/NodeLifecycleEventsDistributorMultiThreadedTest.kt index e7ae3f00e6..a4d90c47ab 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/lifecycle/NodeLifecycleEventsDistributorMultiThreadedTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/lifecycle/NodeLifecycleEventsDistributorMultiThreadedTest.kt @@ -1,6 +1,6 @@ package net.corda.nodeapi.internal.lifecycle -import com.nhaarman.mockito_kotlin.mock +import org.mockito.kotlin.mock import net.corda.core.internal.stream import net.corda.core.utilities.Try import net.corda.core.utilities.contextLogger @@ -59,4 +59,4 @@ internal class NodeLifecycleEventsDistributorMultiThreadedTest { reportSuccess(nodeLifecycleEvent) } } -} \ No newline at end of file +} diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/network/NodeInfoFilesCopierTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/network/NodeInfoFilesCopierTest.kt index ee4458067a..6b07ca574a 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/network/NodeInfoFilesCopierTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/network/NodeInfoFilesCopierTest.kt @@ -1,8 +1,5 @@ package net.corda.nodeapi.internal.network -import net.corda.core.internal.div -import net.corda.core.internal.list -import net.corda.core.internal.write import net.corda.core.internal.NODE_INFO_DIRECTORY import net.corda.testing.common.internal.eventually import org.assertj.core.api.Assertions.assertThat @@ -14,6 +11,10 @@ import rx.schedulers.TestScheduler import java.nio.file.Path import java.time.Duration import java.util.concurrent.TimeUnit +import kotlin.io.path.div +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.name +import kotlin.io.path.writeBytes class NodeInfoFilesCopierTest { companion object { @@ -34,7 +35,7 @@ class NodeInfoFilesCopierTest { private val rootPath get() = folder.root.toPath() private val scheduler = TestScheduler() - private fun nodeDir(nodeBaseDir: String) = rootPath.resolve(nodeBaseDir).resolve(ORGANIZATION.toLowerCase()) + private fun nodeDir(nodeBaseDir: String): Path = rootPath / nodeBaseDir / ORGANIZATION.lowercase() private val node1RootPath by lazy { nodeDir(NODE_1_PATH) } private val node2RootPath by lazy { nodeDir(NODE_2_PATH) } @@ -56,8 +57,8 @@ class NodeInfoFilesCopierTest { advanceTime() // Create 2 files, a nodeInfo and another file in node1 folder. - (node1RootPath / GOOD_NODE_INFO_NAME).write(content) - (node1RootPath / BAD_NODE_INFO_NAME).write(content) + (node1RootPath / GOOD_NODE_INFO_NAME).writeBytes(content) + (node1RootPath / BAD_NODE_INFO_NAME).writeBytes(content) // Configure the second node. nodeInfoFilesCopier.addConfig(node2RootPath) @@ -77,8 +78,8 @@ class NodeInfoFilesCopierTest { advanceTime() // Create 2 files, one of which to be copied, in a node root path. - (node2RootPath / GOOD_NODE_INFO_NAME).write(content) - (node2RootPath / BAD_NODE_INFO_NAME).write(content) + (node2RootPath / GOOD_NODE_INFO_NAME).writeBytes(content) + (node2RootPath / BAD_NODE_INFO_NAME).writeBytes(content) advanceTime() eventually(Duration.ofMinutes(1)) { @@ -95,14 +96,14 @@ class NodeInfoFilesCopierTest { advanceTime() // Create a file, in node 2 root path. - (node2RootPath / GOOD_NODE_INFO_NAME).write(content) + (node2RootPath / GOOD_NODE_INFO_NAME).writeBytes(content) advanceTime() // Remove node 2 nodeInfoFilesCopier.removeConfig(node2RootPath) // Create another file in node 2 directory. - (node2RootPath / GOOD_NODE_INFO_NAME).write(content) + (node2RootPath / GOOD_NODE_INFO_NAME).writeBytes(content) advanceTime() eventually(Duration.ofMinutes(1)) { @@ -121,11 +122,11 @@ class NodeInfoFilesCopierTest { nodeInfoFilesCopier.reset() advanceTime() - (node2RootPath / GOOD_NODE_INFO_NAME_2).write(content) + (node2RootPath / GOOD_NODE_INFO_NAME_2).writeBytes(content) // Give some time to the filesystem to report the change. eventually { - assertThat(node1AdditionalNodeInfoPath.list()).isEmpty() + assertThat(node1AdditionalNodeInfoPath.listDirectoryEntries()).isEmpty() } } @@ -134,8 +135,8 @@ class NodeInfoFilesCopierTest { } private fun checkDirectoryContainsSingleFile(path: Path, filename: String) { - val files = path.list() + val files = path.listDirectoryEntries() assertThat(files).hasSize(1) - assertThat(files[0].fileName.toString()).isEqualTo(filename) + assertThat(files[0].name).isEqualTo(filename) } } \ No newline at end of file diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfigurationFactoryLoadingTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfigurationFactoryLoadingTest.kt index ff6a1b4245..27f976e0ae 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfigurationFactoryLoadingTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfigurationFactoryLoadingTest.kt @@ -1,6 +1,6 @@ package net.corda.nodeapi.internal.persistence -import com.nhaarman.mockito_kotlin.mock +import org.mockito.kotlin.mock import net.corda.core.internal.NamedCacheFactory import org.junit.Assert import org.junit.Test @@ -23,4 +23,4 @@ class HibernateConfigurationFactoryLoadingTest { Assert.assertEquals("Failed to find a SessionFactoryFactory to handle $jdbcUrl - factories present for ${presentFactories}", e.message) } } -} \ No newline at end of file +} diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/persistence/RestrictedConnectionTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/persistence/RestrictedConnectionTest.kt index 39f2d7af73..ade3879f1f 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/persistence/RestrictedConnectionTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/persistence/RestrictedConnectionTest.kt @@ -1,16 +1,24 @@ package net.corda.nodeapi.internal.persistence -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.cordapp.Cordapp import net.corda.core.cordapp.CordappContext import net.corda.core.internal.PLATFORM_VERSION import net.corda.core.node.ServiceHub +import org.assertj.core.api.Assertions.assertThat +import org.junit.Rule import org.junit.Test +import org.junit.rules.TestRule +import org.junit.runners.model.Statement +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import java.sql.Connection import java.sql.Savepoint class RestrictedConnectionTest { + companion object { + private const val TEST_STRING: String = "test" + private const val TEST_INT: Int = 1 + } private val connection: Connection = mock() private val savePoint: Savepoint = mock() @@ -21,212 +29,227 @@ class RestrictedConnectionTest { } private val restrictedConnection: RestrictedConnection = RestrictedConnection(connection, serviceHub) - companion object { - private const val TEST_STRING: String = "test" - private const val TEST_INT: Int = 1 + @Rule + @JvmField + val assertUnsupportedExceptionBasedOnTestName = TestRule { base, description -> + object : Statement() { + override fun evaluate() { + val exception = try { + base.evaluate() + null + } catch (e: UnsupportedOperationException) { + e + } + if (description.methodName.endsWith(" throws unsupported exception")) { + assertThat(exception).isNotNull() + } else { + assertThat(exception).isNull() + } + } + } } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `abort with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.abort { println("I'm just an executor for this test...") } } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `clearWarnings with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.clearWarnings() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `close with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.close() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `commit with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.commit() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setSavepoint with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.setSavepoint() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setSavepoint with name with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.setSavepoint(TEST_STRING) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `releaseSavepoint with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.releaseSavepoint(savePoint) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `rollback with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.rollback() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `rollbackWithSavepoint with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.rollback(savePoint) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setCatalog with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.catalog = TEST_STRING } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setTransactionIsolation with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.transactionIsolation = TEST_INT } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setTypeMap with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) val map: MutableMap> = mutableMapOf() restrictedConnection.typeMap = map } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setHoldability with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.holdability = TEST_INT } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setSchema with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.schema = TEST_STRING } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setNetworkTimeout with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.setNetworkTimeout({ println("I'm just an executor for this test...") }, TEST_INT) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setAutoCommit with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.autoCommit = true } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setReadOnly with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedConnection.isReadOnly = true } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `abort with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.abort { println("I'm just an executor for this test...") } } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `clearWarnings with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.clearWarnings() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `close with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.close() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `commit with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.commit() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setSavepoint with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.setSavepoint() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setSavepoint with name with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.setSavepoint(TEST_STRING) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `releaseSavepoint with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.releaseSavepoint(savePoint) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `rollback with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.rollback() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `rollbackWithSavepoint with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.rollback(savePoint) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setCatalog with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.catalog = TEST_STRING } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setTransactionIsolation with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.transactionIsolation = TEST_INT } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setTypeMap with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) val map: MutableMap> = mutableMapOf() restrictedConnection.typeMap = map } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setHoldability with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.holdability = TEST_INT } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) - fun `setSchema with target platform version of current 7 unsupported exception`() { + @Test(timeout = 300_000) + fun `setSchema with target platform version of current 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.schema = TEST_STRING } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setNetworkTimeout with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.setNetworkTimeout({ println("I'm just an executor for this test...") }, TEST_INT) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setAutoCommit with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.autoCommit = true } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setReadOnly with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedConnection.isReadOnly = true @@ -334,4 +357,4 @@ class RestrictedConnectionTest { whenever(cordapp.targetPlatformVersion).thenReturn(6) restrictedConnection.isReadOnly = true } -} \ No newline at end of file +} diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/persistence/RestrictedEntityManagerTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/persistence/RestrictedEntityManagerTest.kt index 92994a7fab..c9b4f4dea0 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/persistence/RestrictedEntityManagerTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/persistence/RestrictedEntityManagerTest.kt @@ -1,13 +1,17 @@ package net.corda.nodeapi.internal.persistence -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.cordapp.Cordapp import net.corda.core.cordapp.CordappContext import net.corda.core.internal.PLATFORM_VERSION import net.corda.core.node.ServiceHub +import org.assertj.core.api.Assertions.assertThat +import org.junit.Rule import org.junit.Test +import org.junit.rules.TestRule +import org.junit.runners.model.Statement +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import javax.persistence.EntityManager import javax.persistence.EntityTransaction import javax.persistence.LockModeType @@ -23,19 +27,39 @@ class RestrictedEntityManagerTest { } private val restrictedEntityManager = RestrictedEntityManager(entitymanager, serviceHub) - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Rule + @JvmField + val assertUnsupportedExceptionBasedOnTestName = TestRule { base, description -> + object : Statement() { + override fun evaluate() { + val exception = try { + base.evaluate() + null + } catch (e: UnsupportedOperationException) { + e + } + if (description.methodName.endsWith(" throws unsupported exception")) { + assertThat(exception).isNotNull() + } else { + assertThat(exception).isNull() + } + } + } + } + + @Test(timeout = 300_000) fun `close with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedEntityManager.close() } @Test(timeout = 300_000) - fun `clear with target platform version of current corda version throws unsupported exception`() { + fun `clear with target platform version of current corda version`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedEntityManager.clear() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `getMetaModel with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedEntityManager.metamodel @@ -48,32 +72,32 @@ class RestrictedEntityManagerTest { assertTrue(restrictedEntityManager.transaction is RestrictedEntityTransaction) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `joinTransaction with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedEntityManager.joinTransaction() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `lock with two parameters with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedEntityManager.lock(Object(), LockModeType.OPTIMISTIC) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `lock with three parameters with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) val map: MutableMap = mutableMapOf() restrictedEntityManager.lock(Object(), LockModeType.OPTIMISTIC, map) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setProperty with target platform version of current corda version throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION) restrictedEntityManager.setProperty("number", 12) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `close with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedEntityManager.close() @@ -85,39 +109,39 @@ class RestrictedEntityManagerTest { restrictedEntityManager.clear() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `getMetaModel with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedEntityManager.metamodel } @Test(timeout = 300_000) - fun `getTransaction with target platform version of 7 throws unsupported exception`() { + fun `getTransaction with target platform version of 7`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) whenever(entitymanager.transaction).doReturn(transaction) assertTrue(restrictedEntityManager.transaction is RestrictedEntityTransaction) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `joinTransaction with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedEntityManager.joinTransaction() } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `lock with two parameters with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedEntityManager.lock(Object(), LockModeType.OPTIMISTIC) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `lock with three parameters with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) val map: MutableMap = mutableMapOf() restrictedEntityManager.lock(Object(), LockModeType.OPTIMISTIC, map) } - @Test(expected = UnsupportedOperationException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `setProperty with target platform version of 7 throws unsupported exception`() { whenever(cordapp.targetPlatformVersion).thenReturn(7) restrictedEntityManager.setProperty("number", 12) @@ -172,4 +196,4 @@ class RestrictedEntityManagerTest { whenever(cordapp.targetPlatformVersion).thenReturn(6) restrictedEntityManager.setProperty("number", 12) } -} \ No newline at end of file +} diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/protonwrapper/engine/EventProcessorTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/protonwrapper/engine/EventProcessorTest.kt index 9a8aee79c2..e156cb421b 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/protonwrapper/engine/EventProcessorTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/protonwrapper/engine/EventProcessorTest.kt @@ -1,9 +1,9 @@ package net.corda.nodeapi.internal.protonwrapper.engine -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import io.netty.channel.Channel import io.netty.channel.ChannelFuture import io.netty.channel.DefaultEventLoop @@ -68,4 +68,4 @@ class EventProcessorTest { doReturn(null).whenever(it).localAddress() doReturn(null).whenever(it).remoteAddress() } -} \ No newline at end of file +} diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/SSLHelperTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/SSLHelperTest.kt index 12eb6d3e35..6b5a9d5013 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/SSLHelperTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/SSLHelperTest.kt @@ -35,7 +35,7 @@ class SSLHelperTest { trustManagerFactory, ImmediateExecutor.INSTANCE ) - val legalNameHash = SecureHash.sha256(legalName.toString()).toString().take(32).toLowerCase() + val legalNameHash = SecureHash.sha256(legalName.toString()).toString().take(32).lowercase() // These hardcoded values must not be changed, something is broken if you have to change these hardcoded values. assertEquals("O=Test, L=London, C=GB", legalName.toString()) diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/CustomSerializationSchemeAdapterTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/CustomSerializationSchemeAdapterTests.kt index 2d4f751ddf..9671c2dfa6 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/CustomSerializationSchemeAdapterTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/CustomSerializationSchemeAdapterTests.kt @@ -4,6 +4,7 @@ import net.corda.core.serialization.SerializationSchemeContext import net.corda.core.serialization.CustomSerializationScheme import net.corda.core.utilities.ByteSequence import net.corda.nodeapi.internal.serialization.testutils.serializationContext +import net.corda.serialization.internal.verifier.CustomSerializationSchemeAdapter import org.junit.Test import org.junit.jupiter.api.Assertions.assertTrue import java.io.NotSerializableException diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/RoundTripObservableSerializerTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/RoundTripObservableSerializerTests.kt index f60f5488f5..e7a89bf0a3 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/RoundTripObservableSerializerTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/RoundTripObservableSerializerTests.kt @@ -4,7 +4,7 @@ import co.paralleluniverse.common.util.SameThreadExecutor import com.github.benmanes.caffeine.cache.Cache import com.github.benmanes.caffeine.cache.Caffeine import com.github.benmanes.caffeine.cache.RemovalListener -import com.nhaarman.mockito_kotlin.mock +import org.mockito.kotlin.mock import net.corda.nodeapi.internal.rpc.client.RpcClientObservableDeSerializer import net.corda.core.context.Trace import net.corda.core.internal.ThreadBox @@ -70,7 +70,7 @@ class RoundTripObservableSerializerTests { subscriptionMap(id), clientAddressToObservables = ConcurrentHashMap(), deduplicationIdentity = "thisIsATest", - clientAddress = SimpleString("clientAddress")) + clientAddress = SimpleString.of("clientAddress")) val serverSerializer = serializationScheme.rpcServerSerializerFactory(serverObservableContext) diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/RpcServerObservableSerializerTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/RpcServerObservableSerializerTests.kt index d0f8f6b3f6..2f0025f569 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/RpcServerObservableSerializerTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/RpcServerObservableSerializerTests.kt @@ -2,7 +2,7 @@ package net.corda.nodeapi.internal.serialization import com.github.benmanes.caffeine.cache.Cache import com.github.benmanes.caffeine.cache.Caffeine -import com.nhaarman.mockito_kotlin.mock +import org.mockito.kotlin.mock import net.corda.core.context.Trace import net.corda.nodeapi.internal.serialization.testutils.TestObservableContext import net.corda.nodeapi.internal.serialization.testutils.serializationContext @@ -49,7 +49,7 @@ class RpcServerObservableSerializerTests { subscriptionMap(), clientAddressToObservables = ConcurrentHashMap(), deduplicationIdentity = "thisIsATest", - clientAddress = SimpleString("clientAddress")) + clientAddress = SimpleString.of("clientAddress")) val newContext = RpcServerObservableSerializer.createContext(serializationContext, observable) @@ -65,7 +65,7 @@ class RpcServerObservableSerializerTests { subscriptionMap(), clientAddressToObservables = ConcurrentHashMap(), deduplicationIdentity = "thisIsATest", - clientAddress = SimpleString(testClientAddress)) + clientAddress = SimpleString.of(testClientAddress)) val sf = SerializerFactoryBuilder.build(AllWhitelist, javaClass.classLoader).apply { register(RpcServerObservableSerializer()) @@ -80,4 +80,4 @@ class RpcServerObservableSerializerTests { throw Error("Serialization of observable should not throw - ${e.message}") } } -} \ No newline at end of file +} diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/ArrayListItrConcurrentModificationException.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/ArrayListItrConcurrentModificationException.kt index 588ad953d9..0543e7b4eb 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/ArrayListItrConcurrentModificationException.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/ArrayListItrConcurrentModificationException.kt @@ -1,7 +1,7 @@ package net.corda.nodeapi.internal.serialization.kryo -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import net.corda.core.serialization.EncodingWhitelist import net.corda.core.serialization.internal.CheckpointSerializationContext import net.corda.core.serialization.internal.checkpointDeserialize diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoStreamsTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoStreamsTest.kt index b54bd8c458..56a403e3e9 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoStreamsTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoStreamsTest.kt @@ -1,13 +1,13 @@ package net.corda.nodeapi.internal.serialization.kryo -import net.corda.core.internal.declaredField import net.corda.serialization.internal.ByteBufferOutputStream import org.assertj.core.api.Assertions.catchThrowable import org.junit.Assert.assertArrayEquals import org.junit.Test -import java.io.* +import java.io.InputStream +import java.io.OutputStream import java.nio.BufferOverflowException -import java.util.* +import java.util.Random import java.util.zip.DeflaterOutputStream import java.util.zip.InflaterInputStream import kotlin.test.assertEquals @@ -67,15 +67,12 @@ class KryoStreamsTest { fun `ByteBufferOutputStream works`() { val stream = ByteBufferOutputStream(3) stream.write("abc".toByteArray()) - val getBuf = stream.declaredField(ByteArrayOutputStream::class, "buf")::value - assertEquals(3, getBuf().size) repeat(2) { assertSame(BufferOverflowException::class.java, catchThrowable { stream.alsoAsByteBuffer(9) { it.put("0123456789".toByteArray()) } }.javaClass) - assertEquals(3 + 9, getBuf().size) } // This time make too much space: stream.alsoAsByteBuffer(11) { diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoTests.kt index 2f070a4d24..f81252c499 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoTests.kt @@ -6,8 +6,6 @@ import com.esotericsoftware.kryo.KryoSerializable import com.esotericsoftware.kryo.io.Input import com.esotericsoftware.kryo.io.Output import com.google.common.primitives.Ints -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.contracts.PrivacySalt import net.corda.core.contracts.SignatureAttachmentConstraint import net.corda.core.crypto.Crypto @@ -37,7 +35,6 @@ import net.corda.serialization.internal.encodingNotPermittedFormat import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.TestIdentity import net.corda.testing.core.internal.CheckpointSerializationEnvironmentRule -import org.apache.commons.lang3.SystemUtils import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.catchThrowable @@ -49,6 +46,8 @@ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.junit.runners.Parameterized.Parameters +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import org.slf4j.LoggerFactory import java.io.InputStream import java.time.Instant @@ -66,7 +65,7 @@ class KryoTests(private val compression: CordaSerializationEncoding?) { private val ALICE_PUBKEY = TestIdentity(ALICE_NAME, 70).publicKey @Parameters(name = "{0}") @JvmStatic - fun compression() = arrayOf(null) + CordaSerializationEncoding.values() + fun compression(): List = CordaSerializationEncoding.entries + null } @get:Rule @@ -138,7 +137,12 @@ class KryoTests(private val compression: CordaSerializationEncoding?) { @Test(timeout=300_000) fun `deserialised key pair functions the same as serialised one`() { - val keyPair = generateKeyPair() + // The default signature scheme, EDDSA_ED25519_SHA512, generates public keys which have a writeReplace method (EdDSAPublicKeyImpl). + // This is picked up by Quasar's custom ReplaceableObjectKryo, which will *always* use the writeReplace for serialisation, ignoring + // any Kryo serialisers that might have been configured. This thus means the deserialisation path does not go via + // Cryto.decodePublicKey, which interns the materialised PublicKey. To avoid all of this, and test the last assertion, we use + // ECDSA keys, whose implementation doesn't have a writeReplace method. + val keyPair = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256) val bitsToSign: ByteArray = Ints.toByteArray(0x01234567) val wrongBits: ByteArray = Ints.toByteArray(0x76543210) val signature = keyPair.sign(bitsToSign) @@ -182,7 +186,7 @@ class KryoTests(private val compression: CordaSerializationEncoding?) { @Test(timeout=300_000) fun `InputStream serialisation`() { - val rubbish = ByteArray(12345) { (it * it * 0.12345).toByte() } + val rubbish = ByteArray(12345) { (it * it * 0.12345).toInt().toByte() } val readRubbishStream: InputStream = rubbish.inputStream().checkpointSerialize(context).checkpointDeserialize(context) for (i in 0..12344) { assertEquals(rubbish[i], readRubbishStream.read().toByte()) @@ -393,11 +397,7 @@ class KryoTests(private val compression: CordaSerializationEncoding?) { val obj = Holder(ByteArray(20000)) val uncompressedSize = obj.checkpointSerialize(context.withEncoding(null)).size val compressedSize = obj.checkpointSerialize(context.withEncoding(CordaSerializationEncoding.SNAPPY)).size - // If these need fixing, sounds like Kryo wire format changed and checkpoints might not survive an upgrade. - if (SystemUtils.IS_JAVA_11) - assertEquals(20184, uncompressedSize) - else - assertEquals(20234, uncompressedSize) - assertEquals(1123, compressedSize) + assertEquals(20127, uncompressedSize) + assertEquals(1095, compressedSize) } } diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/networkParamsWrite b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/networkParamsWrite deleted file mode 100644 index dcdbaa7b5f..0000000000 Binary files a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/networkParamsWrite and /dev/null differ diff --git a/node/build.gradle b/node/build.gradle index 81418360f7..881235caa9 100644 --- a/node/build.gradle +++ b/node/build.gradle @@ -2,14 +2,12 @@ plugins { id 'com.google.cloud.tools.jib' version '0.9.4' } -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' // Java Persistence API support: create no-arg constructor // see: http://stackoverflow.com/questions/32038177/kotlin-with-jpa-default-constructor-hell -apply plugin: 'kotlin-jpa' -apply plugin: 'java' +apply plugin: 'org.jetbrains.kotlin.plugin.jpa' apply plugin: 'net.corda.plugins.quasar-utils' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' description 'Corda node modules' @@ -22,11 +20,13 @@ ext { //noinspection GroovyAssignabilityCheck configurations { - integrationTestCompile.extendsFrom testCompile + integrationTestImplementation.extendsFrom testImplementation integrationTestRuntimeOnly.extendsFrom testRuntimeOnly - slowIntegrationTestCompile.extendsFrom testCompile + slowIntegrationTestImplementation.extendsFrom testImplementation slowIntegrationTestRuntimeOnly.extendsFrom testRuntimeOnly + + corda4_11 } sourceSets { @@ -74,165 +74,166 @@ jib.container { processResources { from file("$rootDir/config/dev/log4j2.xml") from file("$rootDir/config/dev/jolokia-access.xml") + from(tasks.getByPath(":verifier:shadowJar")) { + into("net/corda/node/verification") + rename { "external-verifier.jar" } + } } processTestResources { from file("$rootDir/config/test/jolokia-access.xml") + from(tasks.getByPath(":finance:contracts:jar")) { + rename 'corda-finance-contracts-.*.jar', 'corda-finance-contracts.jar' + } + from(tasks.getByPath(":finance:workflows:jar")) { + rename 'corda-finance-workflows-.*.jar', 'corda-finance-workflows.jar' + } + from(tasks.getByPath(":testing:cordapps:cashobservers:jar")) { + rename 'testing-cashobservers-cordapp-.*.jar', 'testing-cashobservers-cordapp.jar' + } + from(configurations.corda4_11) } // To find potential version conflicts, run "gradle htmlDependencyReport" and then look in // build/reports/project/dependencies/index.html for green highlighted parts of the tree. dependencies { - compile project(':node-api') - compile project(':client:rpc') - compile project(':client:jackson') - compile project(':tools:cliutils') - compile project(':common-validation') - compile project(':common-configuration-parsing') - compile project(':common-logging') - - implementation "io.opentelemetry:opentelemetry-api:${open_telemetry_version}" + implementation project(':core') + implementation project(':node-api') + implementation project(':client:rpc') + implementation project(':client:jackson') + implementation project(':tools:cliutils') + implementation project(':common-validation') + implementation project(':common-configuration-parsing') + implementation project(':common-logging') + implementation project(':serialization') // Backwards compatibility goo: Apps expect confidential-identities to be loaded by default. // We could eventually gate this on a target-version check. - compile project(':confidential-identities') - + implementation project(':confidential-identities') + implementation "io.opentelemetry:opentelemetry-api:${open_telemetry_version}" // Log4J: logging framework (with SLF4J bindings) - compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" - compile "org.apache.logging.log4j:log4j-web:${log4j_version}" - compile "org.slf4j:jul-to-slf4j:$slf4j_version" - - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - runtimeOnly "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" - compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - - compile "org.fusesource.jansi:jansi:$jansi_version" - compile "com.google.guava:guava:$guava_version" - + implementation "org.apache.logging.log4j:log4j-slf4j2-impl:${log4j_version}" + implementation "org.apache.logging.log4j:log4j-web:${log4j_version}" + implementation "org.slf4j:jul-to-slf4j:$slf4j_version" + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + implementation "org.fusesource.jansi:jansi:$jansi_version" + implementation "com.google.guava:guava:$guava_version" + implementation "commons-io:commons-io:$commons_io_version" // For caches rather than guava - compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version" - + implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version" // For async logging - compile "com.lmax:disruptor:$disruptor_version" - + implementation "com.lmax:disruptor:$disruptor_version" // Artemis: for reliable p2p message queues. // TODO: remove the forced update of commons-collections and beanutils when artemis updates them - compile "org.apache.commons:commons-collections4:${commons_collections_version}" - compile "commons-beanutils:commons-beanutils:${beanutils_version}" - compile("org.apache.activemq:artemis-server:${artemis_version}") { + implementation "org.apache.commons:commons-collections4:${commons_collections_version}" + implementation "commons-beanutils:commons-beanutils:${beanutils_version}" + implementation("org.apache.activemq:artemis-server:${artemis_version}") { exclude group: 'org.apache.commons', module: 'commons-dbcp2' exclude group: 'org.jgroups', module: 'jgroups' } - compile("org.apache.activemq:artemis-core-client:${artemis_version}") { + implementation("org.apache.activemq:artemis-core-client:${artemis_version}") { exclude group: 'org.jgroups', module: 'jgroups' } - runtime("org.apache.activemq:artemis-amqp-protocol:${artemis_version}") { + // Bouncy castle support needed for X509 certificate manipulation + implementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}" + implementation "org.bouncycastle:bcpkix-lts8on:${bouncycastle_version}" + implementation "com.esotericsoftware:kryo:$kryo_version" + implementation "com.fasterxml.jackson.core:jackson-annotations:${jackson_version}" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + // Manifests: for reading stuff from the manifest file + implementation "com.jcabi:jcabi-manifests:$jcabi_manifests_version" + // Coda Hale's Metrics: for monitoring of key statistics + implementation "io.dropwizard.metrics:metrics-jmx:$metrics_version" + implementation "io.github.classgraph:classgraph:$class_graph_version" + implementation "org.liquibase:liquibase-core:$liquibase_version" + // TypeSafe Config: for simple and human friendly config files. + implementation "com.typesafe:config:$typesafe_config_version" + implementation "io.reactivex:rxjava:$rxjava_version" + implementation("org.apache.activemq:artemis-amqp-protocol:${artemis_version}") { // Gains our proton-j version from core module. exclude group: 'org.apache.qpid', module: 'proton-j' exclude group: 'org.jgroups', module: 'jgroups' } + // For H2 database support in persistence + implementation "com.h2database:h2:$h2_version" + // SQL connection pooling library + implementation "com.zaxxer:HikariCP:${hikari_version}" + // Hibernate: an object relational mapper for writing state objects to the database automatically. + implementation "org.hibernate:hibernate-core:$hibernate_version" + implementation "org.hibernate:hibernate-java8:$hibernate_version" + // OkHTTP: Simple HTTP library. + implementation "com.squareup.okhttp3:okhttp:$okhttp_version" + // Apache Shiro: authentication, authorization and session management. + implementation "org.apache.shiro:shiro-core:${shiro_version}" + //Picocli for command line interface + implementation "info.picocli:picocli:$picocli_version" + // BFT-Smart dependencies + implementation 'com.github.bft-smart:library:master-v1.1-beta-g6215ec8-87' + // Java Atomix: RAFT library + implementation 'io.atomix.copycat:copycat-client:1.2.3' + implementation 'io.atomix.copycat:copycat-server:1.2.3' + implementation 'io.atomix.catalyst:catalyst-netty:1.1.2' + // Jolokia JVM monitoring agent, required to push logs through slf4j + implementation "org.jolokia:jolokia-jvm:${jolokia_version}:agent" + // Optional New Relic JVM reporter, used to push metrics to the configured account associated with a newrelic.yml configuration. See https://mvnrepository.com/artifact/com.palominolabs.metrics/metrics-new-relic + implementation "com.palominolabs.metrics:metrics-new-relic:${metrics_new_relic_version}" + // Adding native SSL library to allow using native SSL with Artemis and AMQP + implementation "io.netty:netty-tcnative-boringssl-static:$tcnative_version" + implementation 'org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.8.0' - // Manifests: for reading stuff from the manifest file - compile "com.jcabi:jcabi-manifests:$jcabi_manifests_version" - - // Coda Hale's Metrics: for monitoring of key statistics - compile "io.dropwizard.metrics:metrics-jmx:$metrics_version" - - // TypeSafe Config: for simple and human friendly config files. - compile "com.typesafe:config:$typesafe_config_version" - + testImplementation(project(':test-cli')) + testImplementation(project(':test-utils')) + // Unit testing helpers. + testImplementation project(':node-driver') + testImplementation project(':core-test-utils') + testImplementation project(':test-utils') + testImplementation project(':client:jfx') + testImplementation project(':finance:contracts') + testImplementation project(':finance:workflows') + // sample test schemas + testImplementation project(path: ':finance:contracts', configuration: 'testArtifacts') + testImplementation project(':testing:cordapps:dbfailure:dbfworkflows') + testImplementation "org.assertj:assertj-core:${assertj_version}" + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" + // Jetty dependencies for NetworkMapClient test. + // Web stuff: for HTTP[S] servlets + testImplementation "org.hamcrest:hamcrest-library:2.1" + testImplementation "org.eclipse.jetty.ee10:jetty-ee10-servlet:${jetty_version}" + testImplementation "org.eclipse.jetty.ee10:jetty-ee10-webapp:${jetty_version}" + testImplementation "javax.servlet:javax.servlet-api:${servlet_version}" + testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" + testImplementation "com.google.jimfs:jimfs:1.1" + testImplementation "co.paralleluniverse:quasar-core:$quasar_version" + testImplementation "com.natpryce:hamkrest:$hamkrest_version" + // Jersey for JAX-RS implementation for use in Jetty + testImplementation "org.glassfish.jersey.core:jersey-server:${jersey_version}" + testImplementation "org.glassfish.jersey.containers:jersey-container-servlet-core:${jersey_version}" + testImplementation "org.glassfish.jersey.containers:jersey-container-jetty-http:${jersey_version}" + testImplementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version" testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - // Unit testing helpers. - testCompile "org.assertj:assertj-core:${assertj_version}" - testCompile project(':node-driver') - testCompile project(':test-utils') - testCompile project(':client:jfx') - testCompile project(':finance:contracts') - testCompile project(':finance:workflows') - - // sample test schemas - testCompile project(path: ':finance:contracts', configuration: 'testArtifacts') - - // For H2 database support in persistence - compile "com.h2database:h2:$h2_version" - - // SQL connection pooling library - compile "com.zaxxer:HikariCP:${hikari_version}" - - // Hibernate: an object relational mapper for writing state objects to the database automatically. - compile "org.hibernate:hibernate-core:$hibernate_version" - compile "org.hibernate:hibernate-java8:$hibernate_version" - - // OkHTTP: Simple HTTP library. - compile "com.squareup.okhttp3:okhttp:$okhttp_version" - - // Apache Shiro: authentication, authorization and session management. - compile "org.apache.shiro:shiro-core:${shiro_version}" - - //Picocli for command line interface - compile "info.picocli:picocli:$picocli_version" - + integrationTestImplementation project(":testing:cordapps:dbfailure:dbfcontracts") + integrationTestImplementation project(":testing:cordapps:missingmigration") // Integration test helpers - integrationTestCompile "junit:junit:$junit_version" - integrationTestCompile "org.assertj:assertj-core:${assertj_version}" - integrationTestCompile "org.apache.qpid:qpid-jms-client:${protonj_version}" - - // BFT-Smart dependencies - compile 'com.github.bft-smart:library:master-v1.1-beta-g6215ec8-87' - - // Java Atomix: RAFT library - compile 'io.atomix.copycat:copycat-client:1.2.3' - compile 'io.atomix.copycat:copycat-server:1.2.3' - compile 'io.atomix.catalyst:catalyst-netty:1.1.2' - - // Jetty dependencies for NetworkMapClient test. - // Web stuff: for HTTP[S] servlets - testCompile "org.eclipse.jetty:jetty-servlet:${jetty_version}" - testCompile "org.eclipse.jetty:jetty-webapp:${jetty_version}" - testCompile "javax.servlet:javax.servlet-api:${servlet_version}" - - // Jersey for JAX-RS implementation for use in Jetty - testCompile "org.glassfish.jersey.core:jersey-server:${jersey_version}" - testCompile "org.glassfish.jersey.containers:jersey-container-servlet-core:${jersey_version}" - testCompile "org.glassfish.jersey.containers:jersey-container-jetty-http:${jersey_version}" - - // Jolokia JVM monitoring agent, required to push logs through slf4j - compile "org.jolokia:jolokia-jvm:${jolokia_version}:agent" - // Optional New Relic JVM reporter, used to push metrics to the configured account associated with a newrelic.yml configuration. See https://mvnrepository.com/artifact/com.palominolabs.metrics/metrics-new-relic - compile "com.palominolabs.metrics:metrics-new-relic:${metrics_new_relic_version}" - - // Adding native SSL library to allow using native SSL with Artemis and AMQP - compile "io.netty:netty-tcnative-boringssl-static:$tcnative_version" - - // Byteman for runtime (termination) rules injection on the running node - // Submission tool allowing to install rules on running nodes - slowIntegrationTestCompile "org.jboss.byteman:byteman-submit:4.0.11" - // The actual Byteman agent which should only be in the classpath of the out of process nodes - slowIntegrationTestCompile "org.jboss.byteman:byteman:4.0.11" - - testCompile(project(':test-cli')) - testCompile(project(':test-utils')) - - slowIntegrationTestCompile sourceSets.main.output - slowIntegrationTestCompile sourceSets.test.output - slowIntegrationTestCompile configurations.compile - slowIntegrationTestCompile configurations.testCompile - slowIntegrationTestRuntime configurations.runtime - slowIntegrationTestRuntime configurations.testRuntime - - integrationTestCompile(project(":testing:cordapps:missingmigration")) - - testCompile project(':testing:cordapps:dbfailure:dbfworkflows') + integrationTestImplementation "de.javakaffee:kryo-serializers:$kryo_serializer_version" + integrationTestImplementation "junit:junit:$junit_version" + integrationTestImplementation "org.assertj:assertj-core:${assertj_version}" + integrationTestImplementation "org.apache.qpid:qpid-jms-client:${protonj_version}" // used by FinalityFlowErrorHandlingTest - slowIntegrationTestCompile project(':testing:cordapps:cashobservers') + slowIntegrationTestImplementation project(':testing:cordapps:cashobservers') + // Byteman for runtime (termination) rules injection on the running node + // Submission tool allowing to install rules on running nodes + slowIntegrationTestImplementation "org.jboss.byteman:byteman-submit:4.0.22" + // The actual Byteman agent which should only be in the classpath of the out of process nodes + slowIntegrationTestImplementation "org.jboss.byteman:byteman:4.0.22" + + corda4_11 "net.corda:corda-finance-contracts:4.11" } tasks.withType(JavaCompile).configureEach { @@ -241,15 +242,15 @@ tasks.withType(JavaCompile).configureEach { } tasks.withType(Test).configureEach { - if (JavaVersion.current() == JavaVersion.VERSION_11) { - jvmArgs '-Djdk.attach.allowAttachSelf=true' - } + jvmArgs '-Djdk.attach.allowAttachSelf=true' } tasks.register('integrationTest', Test) { testClassesDirs = sourceSets.integrationTest.output.classesDirs classpath = sourceSets.integrationTest.runtimeClasspath maxParallelForks = (System.env.CORDA_NODE_INT_TESTING_FORKS == null) ? 1 : "$System.env.CORDA_NODE_INT_TESTING_FORKS".toInteger() + // CertificateRevocationListNodeTests + systemProperty 'net.corda.dpcrl.connect.timeout', '4000' } tasks.register('slowIntegrationTest', Test) { @@ -275,7 +276,6 @@ quasar { "io.github.classgraph**", "io.netty*", "liquibase**", - "net.i2p.crypto.**", "nonapi.io.github.classgraph.**", "org.apiguardian.**", "org.bouncycastle**", @@ -295,11 +295,16 @@ jar { baseName 'corda-node' } -publish { - name jar.baseName -} - tasks.named('test', Test) { maxHeapSize = "3g" maxParallelForks = (System.env.CORDA_NODE_TESTING_FORKS == null) ? 1 : "$System.env.CORDA_NODE_TESTING_FORKS".toInteger() } + +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } +} diff --git a/node/capsule/build.gradle b/node/capsule/build.gradle index 8026e23ab9..b18c9a2523 100644 --- a/node/capsule/build.gradle +++ b/node/capsule/build.gradle @@ -2,9 +2,8 @@ * This build.gradle exists to publish our capsule (executable fat jar) to maven. It cannot be placed in the * node project because the bintray plugin cannot publish two modules from one project. */ -apply plugin: 'net.corda.plugins.publish-utils' apply plugin: 'us.kirchmeier.capsule' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' description 'Corda standalone node' @@ -16,6 +15,8 @@ configurations { } dependencies { + testRuntimeOnly project(":node") + // TypeSafe Config: for simple and human friendly config files. capsuleRuntime "com.typesafe:config:$typesafe_config_version" compileOnly "com.typesafe:config:$typesafe_config_version" @@ -24,7 +25,7 @@ dependencies { // Capsule is a library for building independently executable fat JARs. // We only need this dependency to compile our Caplet against. compileOnly "co.paralleluniverse:capsule:$capsule_version" - testCompile "co.paralleluniverse:capsule:$capsule_version" + testImplementation "co.paralleluniverse:capsule:$capsule_version" testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" @@ -38,66 +39,71 @@ capsule { def nodeProject = project(':node') -task buildCordaJAR(type: FatCapsule, dependsOn: [ - nodeProject.tasks.named('jar'), - ]) { +configurations.runtimeOnly.canBeResolved = true +tasks.register('buildCordaJAR', FatCapsule) { + dependsOn(nodeProject.tasks.named('jar')) applicationClass 'net.corda.node.Corda' archiveBaseName = 'corda' + archiveClassifier = '' archiveVersion = corda_release_version - archiveClassifier = jdkClassifier archiveName = archiveFileName.get() applicationSource = files( - nodeProject.configurations.runtimeClasspath, - nodeProject.tasks.jar, - nodeProject.buildDir.toString() + '/resources/main/corda-reference.conf', - "$rootDir/config/dev/log4j2.xml", - 'NOTICE' // Copy CDDL notice + nodeProject.configurations.runtimeClasspath, + nodeProject.tasks.jar, + nodeProject.buildDir.toString() + '/resources/main/corda-reference.conf', + "$rootDir/config/dev/log4j2.xml", + 'NOTICE' // Copy CDDL notice ) from configurations.capsuleRuntime.files.collect { zipTree(it) } with jar manifest { - if (JavaVersion.current() == JavaVersion.VERSION_11) { - attributes('Add-Opens': 'java.management/com.sun.jmx.mbeanserver java.base/java.lang') - } + attributes('Add-Opens': 'java.management/com.sun.jmx.mbeanserver') } capsuleManifest { applicationVersion = corda_release_version applicationId = "net.corda.node.Corda" // 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.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 quasarExcludeExpression = "x(antlr**;bftsmart**;co.paralleluniverse**;com.codahale**;com.esotericsoftware**;com.fasterxml**;com.google**;com.ibm**;com.intellij**;com.jcabi**;org.mockito**;com.opengamma**;com.typesafe**;com.zaxxer**;de.javakaffee**;groovy**;groovyjarjarantlr**;groovyjarjarasm**;io.atomix**;io.github**;io.netty**;jdk**;kotlin**;net.bytebuddy**;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.core.serialization.internal.**)" - javaAgents = quasar_classifier ? ["quasar-core-${quasar_version}-${quasar_classifier}.jar=${quasarExcludeExpression}${quasarClassLoaderExclusion}"] : ["quasar-core-${quasar_version}.jar=${quasarExcludeExpression}${quasarClassLoaderExclusion}"] + def quasarOptions = "m" + javaAgents = quasar_classifier ? ["quasar-core-${quasar_version}-${quasar_classifier}.jar=${quasarOptions}${quasarExcludeExpression}${quasarClassLoaderExclusion}"] : ["quasar-core-${quasar_version}.jar=${quasarExcludeExpression}${quasarClassLoaderExclusion}"] systemProperties['visualvm.display.name'] = 'Corda' - if (JavaVersion.current() == JavaVersion.VERSION_1_8) { - minJavaVersion = '1.8.0' - minUpdateVersion['1.8'] = java8_minUpdateVersion - } caplets = ['CordaCaplet'] // JVM configuration: // - Constrain to small heap sizes to ease development on low end devices. - // - Switch to the G1 GC which is going to be the default in Java 9 and gives low pause times/string dedup. // NOTE: these can be overridden in node.conf. // // If you change these flags, please also update Driver.kt - jvmArgs = ['-Xmx512m', '-XX:+UseG1GC'] - if (JavaVersion.current() == JavaVersion.VERSION_11) { - jvmArgs += ['-Djdk.attach.allowAttachSelf=true'] + jvmArgs = ['-Xmx512m'] + jvmArgs += ['-Djdk.attach.allowAttachSelf=true'] + } +} + +tasks.whenTaskAdded { task -> + if (task.name.contains("generateMetadataFileForCordaJARPublication")) { + task.enabled = false + } +} + +javadoc.dependsOn ':testing:testserver:testcapsule:buildWebserverJar' +javadoc.dependsOn buildCordaJAR +compileTestJava.dependsOn ':testing:testserver:testcapsule:buildWebserverJar' +compileTestJava.dependsOn buildCordaJAR + +artifacts { + runtimeArtifacts buildCordaJAR +} + +publishing { + publications { + cordaJAR(MavenPublication) { + artifactId 'corda' + artifact(buildCordaJAR) + artifact(javadocJar) + artifact(sourcesJar) } } } - -artifacts { - archives buildCordaJAR - runtimeArtifacts buildCordaJAR - publish buildCordaJAR { - classifier '' - } -} - -publish { - disableDefaultJar = true - name 'corda' -} diff --git a/node/capsule/src/main/java/CordaCaplet.java b/node/capsule/src/main/java/CordaCaplet.java index 25e1b26d58..240d9c6c37 100644 --- a/node/capsule/src/main/java/CordaCaplet.java +++ b/node/capsule/src/main/java/CordaCaplet.java @@ -2,29 +2,40 @@ // must also be in the default package. When using Kotlin there are a whole host of exceptions // trying to construct this from Capsule, so it is written in Java. -import com.typesafe.config.*; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigException; +import com.typesafe.config.ConfigFactory; +import com.typesafe.config.ConfigParseOptions; +import com.typesafe.config.ConfigValue; import sun.misc.Signal; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; -import java.net.URL; -import java.nio.file.DirectoryStream; +import java.io.InputStream; +import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.*; -import java.util.jar.JarInputStream; -import java.util.jar.Manifest; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Stream; import static com.typesafe.config.ConfigUtil.splitPath; -import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static java.util.Objects.requireNonNull; +import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; public class CordaCaplet extends Capsule { private Config nodeConfig = null; private String baseDir = null; + private final List cmdLineAddOpens = new ArrayList<>(); + protected CordaCaplet(Capsule pred) { super(pred); } @@ -47,7 +58,7 @@ public class CordaCaplet extends Capsule { File getConfigFile(List args, String baseDir) { String config = getOptionMultiple(args, Arrays.asList("--config-file", "-f")); - return (config == null || config.equals("")) ? new File(baseDir, "node.conf") : new File(config); + return (config == null || config.isEmpty()) ? new File(baseDir, "node.conf") : new File(config); } String getBaseDirectory(List args) { @@ -77,7 +88,7 @@ public class CordaCaplet extends Capsule { } if (arg.toLowerCase().startsWith(lowerCaseOption)) { - if (arg.length() > option.length() && arg.substring(option.length(), option.length() + 1).equals("=")) { + if (arg.length() > option.length() && arg.charAt(option.length()) == '=') { return arg.substring(option.length() + 1); } else { return null; @@ -92,6 +103,7 @@ public class CordaCaplet extends Capsule { protected ProcessBuilder prelaunch(List jvmArgs, List args) { checkJavaVersion(); nodeConfig = parseConfigFile(args); + cmdLineAddOpens.addAll(jvmArgs.stream().filter(arg -> arg.startsWith("--add-opens")).collect(toList())); return super.prelaunch(jvmArgs, args); } @@ -109,23 +121,20 @@ public class CordaCaplet extends Capsule { // For multiple instances Capsule jvm args handling works on basis that one overrides the other. @Override protected int launch(ProcessBuilder pb) throws IOException, InterruptedException { - if (isAtLeastJavaVersion11()) { - List args = pb.command(); - List myArgs = Arrays.asList( - "--add-opens=java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED", - "--add-opens=java.base/java.lang=ALL-UNNAMED", - "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED", - "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED", - "--add-opens=java.base/java.util=ALL-UNNAMED", - "--add-opens=java.base/java.time=ALL-UNNAMED", - "--add-opens=java.base/java.io=ALL-UNNAMED", - "--add-opens=java.base/java.nio=ALL-UNNAMED"); - args.addAll(1, myArgs); - pb.command(args); - } + List args = pb.command(); + List nodeJvmArgs = getNodeJvmArgs(); + nodeJvmArgs.addAll(cmdLineAddOpens); + args.addAll(1, nodeJvmArgs); + pb.command(args); return super.launch(pb); } + private List getNodeJvmArgs() throws IOException { + try (InputStream resource = requireNonNull(getClass().getResourceAsStream("/node-jvm-args.txt"))) { + return new BufferedReader(new InputStreamReader(resource)).lines().collect(toList()); + } + } + /** * Overriding the Caplet classpath generation via the intended interface in Capsule. */ @@ -145,12 +154,12 @@ public class CordaCaplet extends Capsule { } // Add additional directories of JARs to the classpath (at the end), e.g., for JDBC drivers. - augmentClasspath((List) cp, new File(baseDir, "drivers")); + augmentClasspath((List) cp, Path.of(baseDir, "drivers")); try { List jarDirs = nodeConfig.getStringList("jarDirs"); log(LOG_VERBOSE, "Configured JAR directories = " + jarDirs); for (String jarDir : jarDirs) { - augmentClasspath((List) cp, new File(jarDir)); + augmentClasspath((List) cp, Path.of(jarDir)); } } catch (ConfigException.Missing e) { // Ignore since it's ok to be Missing. Other errors would be unexpected. @@ -164,6 +173,7 @@ public class CordaCaplet extends Capsule { boolean defaultOutOfMemoryErrorHandling = true; try { List configJvmArgs = nodeConfig.getStringList("custom.jvmArgs"); + cmdLineAddOpens.addAll(configJvmArgs.stream().filter(arg -> arg.startsWith("--add-opens")).collect(toList())); jvmArgs.clear(); jvmArgs.addAll(configJvmArgs); log(LOG_VERBOSE, "Configured JVM args = " + jvmArgs); @@ -180,9 +190,6 @@ public class CordaCaplet extends Capsule { jvmArgs.add("-XX:+HeapDumpOnOutOfMemoryError"); jvmArgs.add("-XX:+CrashOnOutOfMemoryError"); } - if (isAtLeastJavaVersion11()) { - jvmArgs.add("-Dnashorn.args=--no-deprecation-warning"); - } return (T) jvmArgs; } else if (ATTR_SYSTEM_PROPERTIES == attr) { // Add system properties, if specified, from the config. @@ -190,7 +197,7 @@ public class CordaCaplet extends Capsule { try { Map overrideSystemProps = nodeConfig.getConfig("systemProperties").entrySet().stream() .map(Property::create) - .collect(toMap(Property::getKey, Property::getValue)); + .collect(toMap(Property::key, Property::value)); log(LOG_VERBOSE, "Configured system properties = " + overrideSystemProps); for (Map.Entry entry : overrideSystemProps.entrySet()) { systemProps.put(entry.getKey(), entry.getValue().toString()); @@ -204,37 +211,26 @@ public class CordaCaplet extends Capsule { } else return super.attribute(attr); } - private void augmentClasspath(List classpath, File dir) { - try { - if (dir.exists()) { - // The following might return null if the directory is not there (we check this already) or if an I/O error occurs. - for (File file : dir.listFiles()) { - addToClasspath(classpath, file); - } - } else { - log(LOG_VERBOSE, "Directory to add in Classpath was not found " + dir.getAbsolutePath()); + private void augmentClasspath(List classpath, Path dir) { + if (Files.exists(dir)) { + try (var files = Files.list(dir)) { + files.forEach((file) -> addToClasspath(classpath, file)); + } catch (IOException e) { + log(LOG_QUIET, e); } - } catch (SecurityException | NullPointerException e) { - log(LOG_QUIET, e); + } else { + log(LOG_VERBOSE, "Directory to add in Classpath was not found " + dir.toAbsolutePath()); } } private static void checkJavaVersion() { String version = System.getProperty("java.version"); - if (version == null || Stream.of("1.8", "11").noneMatch(version::startsWith)) { - System.err.printf("Error: Unsupported Java version %s; currently only version 1.8 or 11 is supported.\n", version); + if (version == null || Stream.of("17").noneMatch(version::startsWith)) { + System.err.printf("Error: Unsupported Java version %s; currently only version 17 is supported.\n", version); System.exit(1); } } - private static boolean isAtLeastJavaVersion11() { - String version = System.getProperty("java.specification.version"); - if (version != null) { - return Float.parseFloat(version) >= 11f; - } - return false; - } - private Boolean checkIfCordappDirExists(File dir) { try { if (!dir.mkdir() && !dir.exists()) { // It is unlikely to enter this if-branch, but just in case. @@ -253,18 +249,18 @@ public class CordaCaplet extends Capsule { log(LOG_VERBOSE, "Cordapps dir could not be created"); } - private void addToClasspath(List classpath, File file) { + private void addToClasspath(List classpath, Path file) { try { - if (file.canRead()) { - if (file.isFile() && isJAR(file)) { - classpath.add(file.toPath().toAbsolutePath()); - } else if (file.isDirectory()) { // Search in nested folders as well. TODO: check for circular symlinks. + if (Files.isReadable(file)) { + if (Files.isRegularFile(file) && isJAR(file)) { + classpath.add(file.toAbsolutePath()); + } else if (Files.isDirectory(file)) { // Search in nested folders as well. TODO: check for circular symlinks. augmentClasspath(classpath, file); } } else { - log(LOG_VERBOSE, "File or directory to add in Classpath could not be read " + file.getAbsolutePath()); + log(LOG_VERBOSE, "File or directory to add in Classpath could not be read " + file.toAbsolutePath()); } - } catch (SecurityException | NullPointerException e) { + } catch (SecurityException e) { log(LOG_QUIET, e); } } @@ -277,30 +273,14 @@ public class CordaCaplet extends Capsule { }); } - private Boolean isJAR(File file) { - return file.getName().toLowerCase().endsWith(".jar"); + private Boolean isJAR(Path file) { + return file.toString().toLowerCase().endsWith(".jar"); } /** * Helper class so that we can parse the "systemProperties" element of node.conf. */ - private static class Property { - private final String key; - private final Object value; - - Property(String key, Object value) { - this.key = key; - this.value = value; - } - - String getKey() { - return key; - } - - Object getValue() { - return value; - } - + private record Property(String key, Object value) { static Property create(Map.Entry entry) { // String.join is preferred here over Typesafe's joinPath method, as the joinPath method would put quotes around the system // property key which is undesirable here. diff --git a/node/capsule/src/main/resources/node-jvm-args.txt b/node/capsule/src/main/resources/node-jvm-args.txt new file mode 100644 index 0000000000..965a2ea188 --- /dev/null +++ b/node/capsule/src/main/resources/node-jvm-args.txt @@ -0,0 +1,28 @@ +--add-opens=java.base/java.io=ALL-UNNAMED +--add-opens=java.base/java.lang=ALL-UNNAMED +--add-opens=java.base/java.lang.invoke=ALL-UNNAMED +--add-opens=java.base/java.lang.ref=ALL-UNNAMED +--add-opens=java.base/java.lang.reflect=ALL-UNNAMED +--add-opens=java.base/java.math=ALL-UNNAMED +--add-opens=java.base/java.nio=ALL-UNNAMED +--add-opens=java.base/java.nio.charset=ALL-UNNAMED +--add-opens=java.base/java.security=ALL-UNNAMED +--add-opens=java.base/java.security.cert=ALL-UNNAMED +--add-opens=java.base/java.security.spec=ALL-UNNAMED +--add-opens=java.base/java.time=ALL-UNNAMED +--add-opens=java.base/java.util=ALL-UNNAMED +--add-opens=java.base/java.util.concurrent=ALL-UNNAMED +--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED +--add-opens=java.base/java.util.regex=ALL-UNNAMED +--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED +--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED +--add-opens=java.base/sun.security.pkcs=ALL-UNNAMED +--add-opens=java.base/sun.security.util=ALL-UNNAMED +--add-opens=java.base/sun.security.x509=ALL-UNNAMED +--add-opens=java.management/java.lang.management=ALL-UNNAMED +--add-opens=java.management/sun.management=ALL-UNNAMED +--add-opens=java.logging/java.util.logging=ALL-UNNAMED +--add-opens=java.sql/java.sql=ALL-UNNAMED +--add-opens=jdk.crypto.ec/sun.security.ec=ALL-UNNAMED +--add-opens=jdk.crypto.ec/sun.security.ec.ed=ALL-UNNAMED +--add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED diff --git a/node/src/integration-test-slow/kotlin/net/corda/client/rpc/FlowsExecutionModeRpcTest.kt b/node/src/integration-test-slow/kotlin/net/corda/client/rpc/FlowsExecutionModeRpcTest.kt index e75e444607..3c931e15f8 100644 --- a/node/src/integration-test-slow/kotlin/net/corda/client/rpc/FlowsExecutionModeRpcTest.kt +++ b/node/src/integration-test-slow/kotlin/net/corda/client/rpc/FlowsExecutionModeRpcTest.kt @@ -9,6 +9,7 @@ import net.corda.testing.node.User import org.assertj.core.api.Assertions import org.junit.Assume import org.junit.Test +import java.util.Locale class FlowsExecutionModeRpcTest { @@ -16,7 +17,7 @@ class FlowsExecutionModeRpcTest { fun `persistent state survives node restart`() { // Temporary disable this test when executed on Windows. It is known to be sporadically failing. // More investigation is needed to establish why. - Assume.assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) + Assume.assumeFalse(System.getProperty("os.name").lowercase(Locale.getDefault()).startsWith("win")) val user = User("mark", "dadada", setOf(Permissions.invokeRpc("setFlowsDrainingModeEnabled"), Permissions.invokeRpc("isFlowsDrainingModeEnabled"))) driver(DriverParameters( diff --git a/node/src/integration-test-slow/kotlin/net/corda/node/flows/FinalityFlowErrorHandlingTest.kt b/node/src/integration-test-slow/kotlin/net/corda/node/flows/FinalityFlowErrorHandlingTest.kt index dc0133f575..de87ba1e3e 100644 --- a/node/src/integration-test-slow/kotlin/net/corda/node/flows/FinalityFlowErrorHandlingTest.kt +++ b/node/src/integration-test-slow/kotlin/net/corda/node/flows/FinalityFlowErrorHandlingTest.kt @@ -104,4 +104,4 @@ class GetFlowTransaction(private val txId: SecureHash) : FlowLogic(), Permissions.invokeRpc("vaultQuery"))) val message = Message("Hello world!") @@ -95,7 +96,7 @@ class NodeStatePersistenceTests { result } assertNotNull(stateAndRef) - val retrievedMessage = stateAndRef!!.state.data.message + val retrievedMessage = stateAndRef.state.data.message assertEquals(message, retrievedMessage) } } diff --git a/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineErrorHandlingTest.kt b/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineErrorHandlingTest.kt index 8885b936ee..4cef381ae6 100644 --- a/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineErrorHandlingTest.kt +++ b/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineErrorHandlingTest.kt @@ -9,8 +9,6 @@ import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party -import net.corda.core.internal.list -import net.corda.core.internal.readAllLines import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow import net.corda.core.node.AppServiceHub @@ -37,6 +35,8 @@ import org.jboss.byteman.agent.submit.Submit import org.junit.Before import java.time.Duration import java.util.concurrent.TimeUnit +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.readLines import kotlin.test.assertEquals abstract class StateMachineErrorHandlingTest { @@ -116,9 +116,9 @@ abstract class StateMachineErrorHandlingTest { } private fun NodeHandle.getBytemanOutput(): List { - return baseDirectory.list() + return baseDirectory.listDirectoryEntries() .filter { "net.corda.node.Corda" in it.toString() && "stdout.log" in it.toString() } - .flatMap { it.readAllLines() } + .flatMap { it.readLines() } } internal fun OutOfProcessImpl.stop(timeout: Duration): Boolean { diff --git a/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineFinalityErrorHandlingTest.kt b/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineFinalityErrorHandlingTest.kt index 86b1781442..accb6edcd8 100644 --- a/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineFinalityErrorHandlingTest.kt +++ b/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineFinalityErrorHandlingTest.kt @@ -8,7 +8,7 @@ import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.seconds import net.corda.finance.DOLLARS import net.corda.finance.flows.CashIssueAndPaymentFlow -import net.corda.node.services.api.ServiceHubInternal +import net.corda.node.services.persistence.DBTransactionStorage import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.CHARLIE_NAME import net.corda.testing.core.DUMMY_NOTARY_NAME @@ -56,7 +56,7 @@ class StateMachineFinalityErrorHandlingTest : StateMachineErrorHandlingTest() { ENDRULE RULE Throw exception when recording transaction - INTERFACE ${ServiceHubInternal::class.java.name} + CLASS ${DBTransactionStorage::class.java.name} METHOD finalizeTransactionWithExtraSignatures AT ENTRY IF flagged("finality_flag") && flagged("resolve_tx_flag") @@ -117,7 +117,7 @@ class StateMachineFinalityErrorHandlingTest : StateMachineErrorHandlingTest() { ENDRULE RULE Throw exception when recording transaction - INTERFACE ${ServiceHubInternal::class.java.name} + CLASS ${DBTransactionStorage::class.java.name} METHOD finalizeTransactionWithExtraSignatures AT ENTRY IF flagged("finality_flag") && flagged("resolve_tx_flag") @@ -277,4 +277,4 @@ class StateMachineFinalityErrorHandlingTest : StateMachineErrorHandlingTest() { assertEquals(1, charlie.rpc.stateMachinesSnapshot().size) } } -} \ No newline at end of file +} diff --git a/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineFlowInitErrorHandlingTest.kt b/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineFlowInitErrorHandlingTest.kt index 24f06c9600..7466c5dd07 100644 --- a/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineFlowInitErrorHandlingTest.kt +++ b/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineFlowInitErrorHandlingTest.kt @@ -1210,4 +1210,4 @@ class StateMachineFlowInitErrorHandlingTest : StateMachineErrorHandlingTest() { alice.rpc.assertNumberOfCheckpoints() } } -} \ No newline at end of file +} diff --git a/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineGeneralErrorHandlingTest.kt b/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineGeneralErrorHandlingTest.kt index 282c3d9bb4..6541d61881 100644 --- a/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineGeneralErrorHandlingTest.kt +++ b/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineGeneralErrorHandlingTest.kt @@ -703,7 +703,6 @@ class StateMachineGeneralErrorHandlingTest : StateMachineErrorHandlingTest() { * * On shutdown this flow will still terminate correctly and not prevent the node from shutting down. */ - @Suppress("TooGenericExceptionCaught") @Test(timeout = 300_000) fun `a dead flow can be shutdown`() { startDriver { @@ -761,4 +760,4 @@ class StateMachineGeneralErrorHandlingTest : StateMachineErrorHandlingTest() { return "cant get here" } } -} \ No newline at end of file +} diff --git a/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineKillFlowErrorHandlingTest.kt b/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineKillFlowErrorHandlingTest.kt index 2a4814fe00..083bb235ff 100644 --- a/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineKillFlowErrorHandlingTest.kt +++ b/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineKillFlowErrorHandlingTest.kt @@ -340,4 +340,4 @@ class StateMachineKillFlowErrorHandlingTest : StateMachineErrorHandlingTest() { Thread.sleep(20000) } } -} \ No newline at end of file +} diff --git a/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineSubFlowErrorHandlingTest.kt b/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineSubFlowErrorHandlingTest.kt index 020206962d..442dc11499 100644 --- a/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineSubFlowErrorHandlingTest.kt +++ b/node/src/integration-test-slow/kotlin/net/corda/node/services/statemachine/StateMachineSubFlowErrorHandlingTest.kt @@ -400,4 +400,4 @@ class StateMachineSubFlowErrorHandlingTest : StateMachineErrorHandlingTest() { return "Finished executing the inline subflow - ${this.runId}" } } -} \ No newline at end of file +} diff --git a/node/src/integration-test-slow/kotlin/net/corda/node/utilities/registration/NodeRegistrationTest.kt b/node/src/integration-test-slow/kotlin/net/corda/node/utilities/registration/NodeRegistrationTest.kt index fe5bfbf63f..86f91e0918 100644 --- a/node/src/integration-test-slow/kotlin/net/corda/node/utilities/registration/NodeRegistrationTest.kt +++ b/node/src/integration-test-slow/kotlin/net/corda/node/utilities/registration/NodeRegistrationTest.kt @@ -1,5 +1,13 @@ package net.corda.node.utilities.registration +import jakarta.ws.rs.Consumes +import jakarta.ws.rs.GET +import jakarta.ws.rs.POST +import jakarta.ws.rs.Path +import jakarta.ws.rs.PathParam +import jakarta.ws.rs.Produces +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response import net.corda.core.identity.CordaX500Name import net.corda.core.internal.logElapsedTime import net.corda.core.internal.readFully @@ -40,9 +48,6 @@ import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentSkipListSet import java.util.zip.ZipEntry import java.util.zip.ZipOutputStream -import javax.ws.rs.* -import javax.ws.rs.core.MediaType -import javax.ws.rs.core.Response class NodeRegistrationTest { companion object { @@ -65,7 +70,7 @@ class NodeRegistrationTest { pollInterval = 1.seconds, hostAndPort = portAllocation.nextHostAndPort(), myHostNameValue = "localhost", - additionalServices = *arrayOf(registrationHandler)) + additionalServices = arrayOf(registrationHandler)) serverHostAndPort = server.start() } diff --git a/node/src/integration-test/kotlin/net/corda/contracts/SignatureConstraintMigrationFromHashConstraintsTests.kt b/node/src/integration-test/kotlin/net/corda/contracts/SignatureConstraintMigrationFromHashConstraintsTests.kt index a69723cdc3..070adc9a44 100644 --- a/node/src/integration-test/kotlin/net/corda/contracts/SignatureConstraintMigrationFromHashConstraintsTests.kt +++ b/node/src/integration-test/kotlin/net/corda/contracts/SignatureConstraintMigrationFromHashConstraintsTests.kt @@ -5,7 +5,6 @@ import net.corda.core.contracts.HashAttachmentConstraint import net.corda.core.contracts.SignatureAttachmentConstraint import net.corda.core.contracts.StateAndRef import net.corda.core.internal.deleteRecursively -import net.corda.core.internal.div import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow import net.corda.testing.common.internal.testNetworkParameters @@ -15,6 +14,7 @@ import net.corda.testing.node.internal.internalDriver import org.junit.Assume.assumeFalse import org.junit.Ignore import org.junit.Test +import kotlin.io.path.div import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue @@ -23,14 +23,14 @@ open class SignatureConstraintMigrationFromHashConstraintsTests : SignatureConst @Test(timeout=300_000) fun `can evolve from lower contract class version to higher one`() { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) // See NodeStatePersistenceTests.kt. + assumeFalse(System.getProperty("os.name").lowercase().startsWith("win")) // See NodeStatePersistenceTests.kt. val stateAndRef: StateAndRef? = internalDriver( inMemoryDB = false, networkParameters = testNetworkParameters(notaries = emptyList(), minimumPlatformVersion = 4), systemProperties = mapOf("net.corda.recordtransaction.signature.verification.disabled" to true.toString()) ) { - val nodeName = { + val nodeName = run { val nodeHandle = startNode(NodeParameters(rpcUsers = listOf(user), additionalCordapps = listOf(oldCordapp))).getOrThrow() val nodeName = nodeHandle.nodeInfo.singleIdentity().name CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { @@ -38,39 +38,36 @@ open class SignatureConstraintMigrationFromHashConstraintsTests : SignatureConst } nodeHandle.stop() nodeName - }() - val result = { - (baseDirectory(nodeName) / "cordapps").deleteRecursively() - val nodeHandle = startNode( - NodeParameters( - providedName = nodeName, - rpcUsers = listOf(user), - additionalCordapps = listOf(newCordapp) - ) - ).getOrThrow() - var result: StateAndRef? = CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { - val page = it.proxy.vaultQuery(MessageState::class.java) - page.states.singleOrNull() - } - CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { - it.proxy.startFlow(::ConsumeMessage, result!!, defaultNotaryIdentity, false, false).returnValue.getOrThrow() - } - result = CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { - val page = it.proxy.vaultQuery(MessageState::class.java) - page.states.singleOrNull() - } - nodeHandle.stop() - result - }() + } + (baseDirectory(nodeName) / "cordapps").deleteRecursively() + val nodeHandle = startNode( + NodeParameters( + providedName = nodeName, + rpcUsers = listOf(user), + additionalCordapps = listOf(newCordapp) + ) + ).getOrThrow() + var result: StateAndRef? = CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { + val page = it.proxy.vaultQuery(MessageState::class.java) + page.states.singleOrNull() + } + CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { + it.proxy.startFlow(::ConsumeMessage, result!!, defaultNotaryIdentity, false, false).returnValue.getOrThrow() + } + result = CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { + val page = it.proxy.vaultQuery(MessageState::class.java) + page.states.singleOrNull() + } + nodeHandle.stop() result } assertNotNull(stateAndRef) - assertEquals(transformedMessage, stateAndRef!!.state.data.message) + assertEquals(transformedMessage, stateAndRef.state.data.message) } @Test(timeout=300_000) fun `auto migration from HashConstraint to SignatureConstraint`() { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) // See NodeStatePersistenceTests.kt. + assumeFalse(System.getProperty("os.name").lowercase().startsWith("win")) // See NodeStatePersistenceTests.kt. val (issuanceTransaction, consumingTransaction) = upgradeCorDappBetweenTransactions( cordapp = oldUnsignedCordapp, newCordapp = newCordapp, @@ -86,7 +83,7 @@ open class SignatureConstraintMigrationFromHashConstraintsTests : SignatureConst @Test(timeout=300_000) fun `HashConstraint cannot be migrated if 'disableHashConstraints' system property is not set to true`() { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) // See NodeStatePersistenceTests.kt. + assumeFalse(System.getProperty("os.name").lowercase().startsWith("win")) // See NodeStatePersistenceTests.kt. val (issuanceTransaction, consumingTransaction) = upgradeCorDappBetweenTransactions( cordapp = oldUnsignedCordapp, newCordapp = newCordapp, @@ -102,7 +99,7 @@ open class SignatureConstraintMigrationFromHashConstraintsTests : SignatureConst @Test(timeout=300_000) fun `HashConstraint cannot be migrated to SignatureConstraint if new jar is not signed`() { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) // See NodeStatePersistenceTests.kt. + assumeFalse(System.getProperty("os.name").lowercase().startsWith("win")) // See NodeStatePersistenceTests.kt. val (issuanceTransaction, consumingTransaction) = upgradeCorDappBetweenTransactions( cordapp = oldUnsignedCordapp, newCordapp = newUnsignedCordapp, @@ -118,7 +115,7 @@ open class SignatureConstraintMigrationFromHashConstraintsTests : SignatureConst @Test(timeout=300_000) fun `HashConstraint cannot be migrated to SignatureConstraint if platform version is not 4 or greater`() { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) // See NodeStatePersistenceTests.kt. + assumeFalse(System.getProperty("os.name").lowercase().startsWith("win")) // See NodeStatePersistenceTests.kt. val (issuanceTransaction, consumingTransaction) = upgradeCorDappBetweenTransactions( cordapp = oldUnsignedCordapp, newCordapp = newCordapp, @@ -136,7 +133,7 @@ open class SignatureConstraintMigrationFromHashConstraintsTests : SignatureConst @Ignore("ENT-5676: Disabling to isolate Gradle process death cause") @Test(timeout=300_000) fun `HashConstraint cannot be migrated to SignatureConstraint if a HashConstraint is specified for one state and another uses an AutomaticPlaceholderConstraint`() { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) // See NodeStatePersistenceTests.kt. + assumeFalse(System.getProperty("os.name").lowercase().startsWith("win")) // See NodeStatePersistenceTests.kt. val (issuanceTransaction, consumingTransaction) = upgradeCorDappBetweenTransactions( cordapp = oldUnsignedCordapp, newCordapp = newCordapp, diff --git a/node/src/integration-test/kotlin/net/corda/contracts/SignatureConstraintMigrationFromWhitelistConstraintTests.kt b/node/src/integration-test/kotlin/net/corda/contracts/SignatureConstraintMigrationFromWhitelistConstraintTests.kt index 8c194ac2a9..14c3451a3c 100644 --- a/node/src/integration-test/kotlin/net/corda/contracts/SignatureConstraintMigrationFromWhitelistConstraintTests.kt +++ b/node/src/integration-test/kotlin/net/corda/contracts/SignatureConstraintMigrationFromWhitelistConstraintTests.kt @@ -6,7 +6,6 @@ import net.corda.core.contracts.SignatureAttachmentConstraint import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.WhitelistedByZoneAttachmentConstraint import net.corda.core.internal.deleteRecursively -import net.corda.core.internal.div import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow import net.corda.testing.common.internal.testNetworkParameters @@ -14,8 +13,9 @@ import net.corda.testing.core.singleIdentity import net.corda.testing.driver.NodeParameters import net.corda.testing.node.internal.internalDriver import org.assertj.core.api.Assertions -import org.junit.Assume +import org.junit.Assume.assumeFalse import org.junit.Test +import kotlin.io.path.div import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue @@ -25,14 +25,14 @@ open class SignatureConstraintMigrationFromWhitelistConstraintTests : Signature @Test(timeout=300_000) fun `can evolve from lower contract class version to higher one`() { - Assume.assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) // See NodeStatePersistenceTests.kt. + assumeFalse(System.getProperty("os.name").lowercase().startsWith("win")) // See NodeStatePersistenceTests.kt. val stateAndRef: StateAndRef? = internalDriver( inMemoryDB = false, networkParameters = testNetworkParameters(notaries = emptyList(), minimumPlatformVersion = 4), systemProperties = mapOf("net.corda.recordtransaction.signature.verification.disabled" to true.toString()) ) { - val nodeName = { + val nodeName = run { val nodeHandle = startNode(NodeParameters(rpcUsers = listOf(user), additionalCordapps = listOf(oldCordapp))).getOrThrow() val nodeName = nodeHandle.nodeInfo.singleIdentity().name CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { @@ -40,39 +40,36 @@ open class SignatureConstraintMigrationFromWhitelistConstraintTests : Signature } nodeHandle.stop() nodeName - }() - val result = { - (baseDirectory(nodeName) / "cordapps").deleteRecursively() - val nodeHandle = startNode( - NodeParameters( - providedName = nodeName, - rpcUsers = listOf(user), - additionalCordapps = listOf(newCordapp) - ) - ).getOrThrow() - var result: StateAndRef? = CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { - val page = it.proxy.vaultQuery(MessageState::class.java) - page.states.singleOrNull() - } - CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { - it.proxy.startFlow(::ConsumeMessage, result!!, defaultNotaryIdentity, false, false).returnValue.getOrThrow() - } - result = CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { - val page = it.proxy.vaultQuery(MessageState::class.java) - page.states.singleOrNull() - } - nodeHandle.stop() - result - }() + } + (baseDirectory(nodeName) / "cordapps").deleteRecursively() + val nodeHandle = startNode( + NodeParameters( + providedName = nodeName, + rpcUsers = listOf(user), + additionalCordapps = listOf(newCordapp) + ) + ).getOrThrow() + var result: StateAndRef? = CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { + val page = it.proxy.vaultQuery(MessageState::class.java) + page.states.singleOrNull() + } + CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { + it.proxy.startFlow(::ConsumeMessage, result!!, defaultNotaryIdentity, false, false).returnValue.getOrThrow() + } + result = CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use { + val page = it.proxy.vaultQuery(MessageState::class.java) + page.states.singleOrNull() + } + nodeHandle.stop() result } assertNotNull(stateAndRef) - assertEquals(transformedMessage, stateAndRef!!.state.data.message) + assertEquals(transformedMessage, stateAndRef.state.data.message) } @Test(timeout=300_000) fun `auto migration from WhitelistConstraint to SignatureConstraint`() { - Assume.assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) // See NodeStatePersistenceTests.kt. + assumeFalse(System.getProperty("os.name").lowercase().startsWith("win")) // See NodeStatePersistenceTests.kt. val (issuanceTransaction, consumingTransaction) = upgradeCorDappBetweenTransactions( cordapp = oldUnsignedCordapp, newCordapp = newCordapp, @@ -93,7 +90,7 @@ open class SignatureConstraintMigrationFromWhitelistConstraintTests : Signature @Test(timeout=300_000) fun `WhitelistConstraint cannot be migrated to SignatureConstraint if platform version is not 4 or greater`() { - Assume.assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) // See NodeStatePersistenceTests.kt. + assumeFalse(System.getProperty("os.name").lowercase().startsWith("win")) // See NodeStatePersistenceTests.kt. val (issuanceTransaction, consumingTransaction) = upgradeCorDappBetweenTransactions( cordapp = oldUnsignedCordapp, newCordapp = newCordapp, @@ -115,7 +112,7 @@ open class SignatureConstraintMigrationFromWhitelistConstraintTests : Signature @Test(timeout=300_000) fun `WhitelistConstraint cannot be migrated to SignatureConstraint if signed JAR is not whitelisted`() { - Assume.assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) // See NodeStatePersistenceTests.kt. + assumeFalse(System.getProperty("os.name").lowercase().startsWith("win")) // See NodeStatePersistenceTests.kt. Assertions.assertThatExceptionOfType(CordaRuntimeException::class.java).isThrownBy { upgradeCorDappBetweenTransactions( cordapp = oldUnsignedCordapp, @@ -130,7 +127,7 @@ open class SignatureConstraintMigrationFromWhitelistConstraintTests : Signature @Test(timeout=300_000) fun `auto migration from WhitelistConstraint to SignatureConstraint will only transition states that do not have a constraint specified`() { - Assume.assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) // See NodeStatePersistenceTests.kt. + assumeFalse(System.getProperty("os.name").lowercase().startsWith("win")) // See NodeStatePersistenceTests.kt. val (issuanceTransaction, consumingTransaction) = upgradeCorDappBetweenTransactions( cordapp = oldUnsignedCordapp, newCordapp = newCordapp, diff --git a/node/src/integration-test/kotlin/net/corda/contracts/SignatureConstraintVersioningTests.kt b/node/src/integration-test/kotlin/net/corda/contracts/SignatureConstraintVersioningTests.kt index bd243e7127..10a1d3c553 100644 --- a/node/src/integration-test/kotlin/net/corda/contracts/SignatureConstraintVersioningTests.kt +++ b/node/src/integration-test/kotlin/net/corda/contracts/SignatureConstraintVersioningTests.kt @@ -9,7 +9,6 @@ import net.corda.core.flows.StartableByRPC import net.corda.core.identity.AbstractParty import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party -import net.corda.core.internal.delete import net.corda.core.internal.packageName import net.corda.core.internal.readFully import net.corda.core.messaging.startFlow @@ -32,6 +31,7 @@ import net.corda.testing.node.internal.internalDriver import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths +import kotlin.io.path.deleteExisting open class SignatureConstraintVersioningTests { @@ -111,7 +111,7 @@ open class SignatureConstraintVersioningTests { private fun deleteCorDapp(baseDirectory: Path, cordapp: CustomCordapp) { val cordappPath = baseDirectory.resolve(Paths.get("cordapps")).resolve(cordapp.jarFile.fileName) - cordappPath.delete() + cordappPath.deleteExisting() } private fun DriverDSL.createConsumingTransaction( diff --git a/node/src/integration-test/kotlin/net/corda/contracts/mutator/MutatorContract.kt b/node/src/integration-test/kotlin/net/corda/contracts/mutator/MutatorContract.kt index 239525c576..d6a44ff4e6 100644 --- a/node/src/integration-test/kotlin/net/corda/contracts/mutator/MutatorContract.kt +++ b/node/src/integration-test/kotlin/net/corda/contracts/mutator/MutatorContract.kt @@ -8,7 +8,7 @@ import net.corda.core.contracts.TransactionState import net.corda.core.contracts.requireSingleCommand import net.corda.core.contracts.requireThat import net.corda.core.identity.AbstractParty -import net.corda.core.internal.Verifier +import net.corda.core.internal.verification.Verifier import net.corda.core.serialization.SerializationContext import net.corda.core.transactions.LedgerTransaction diff --git a/node/src/integration-test/kotlin/net/corda/node/AddressBindingFailureTests.kt b/node/src/integration-test/kotlin/net/corda/node/AddressBindingFailureTests.kt index 3e549d6581..27bedc57d4 100644 --- a/node/src/integration-test/kotlin/net/corda/node/AddressBindingFailureTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/AddressBindingFailureTests.kt @@ -21,7 +21,7 @@ class AddressBindingFailureTests { } @Test(timeout=300_000) - fun `p2p address`() = assertBindExceptionForOverrides { address -> mapOf("p2pAddress" to address.toString()) } + fun `p2p address`() = assertBindExceptionForOverrides("localhost") { address -> mapOf("p2pAddress" to address.toString()) } @Test(timeout=300_000) fun `rpc address`() = assertBindExceptionForOverrides { address -> mapOf("rpcSettings" to mapOf("address" to address.toString())) } @@ -52,11 +52,12 @@ class AddressBindingFailureTests { } } - private fun assertBindExceptionForOverrides(overrides: (NetworkHostAndPort) -> Map) { + private fun assertBindExceptionForOverrides(bindAddress: String? = null, overrides: (NetworkHostAndPort) -> Map) { ServerSocket(0).use { socket -> - val address = InetSocketAddress("localhost", socket.localPort).toNetworkHostAndPort() + val address = bindAddress?.let { InetSocketAddress(it, socket.localPort).toNetworkHostAndPort() } ?: + InetSocketAddress(socket.inetAddress, socket.localPort).toNetworkHostAndPort() driver(DriverParameters(startNodesInProcess = true, notarySpecs = emptyList(), inMemoryDB = false, @@ -71,4 +72,4 @@ class AddressBindingFailureTests { } private fun InetSocketAddress.toNetworkHostAndPort() = NetworkHostAndPort(hostName, port) -} \ No newline at end of file +} diff --git a/node/src/integration-test/kotlin/net/corda/node/AuthDBTests.kt b/node/src/integration-test/kotlin/net/corda/node/AuthDBTests.kt index 5687bfa9d3..00e77537a9 100644 --- a/node/src/integration-test/kotlin/net/corda/node/AuthDBTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/AuthDBTests.kt @@ -7,6 +7,7 @@ import net.corda.client.rpc.RPCException import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC +import net.corda.core.internal.mapToSet import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow import net.corda.finance.flows.CashIssueFlow @@ -28,7 +29,7 @@ import org.junit.runner.RunWith import org.junit.runners.Parameterized import java.sql.Connection import java.sql.Statement -import java.util.* +import java.util.Properties import kotlin.test.assertFailsWith /* @@ -286,7 +287,7 @@ private class UsersDB(name: String, users: List = emptyList(), rol } init { - require(users.map { it.username }.toSet().size == users.size) { + require(users.mapToSet { it.username }.size == users.size) { "Duplicate username in input" } connection = DataSourceFactory.createDataSource(Properties().apply { diff --git a/node/src/integration-test/kotlin/net/corda/node/BootTests.kt b/node/src/integration-test/kotlin/net/corda/node/BootTests.kt index d2e741824d..2fc575b4fb 100644 --- a/node/src/integration-test/kotlin/net/corda/node/BootTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/BootTests.kt @@ -5,9 +5,9 @@ import net.corda.client.rpc.CordaRPCClient import net.corda.core.CordaRuntimeException import net.corda.core.flows.FlowLogic import net.corda.core.flows.StartableByRPC -import net.corda.core.internal.* import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow +import net.corda.coretesting.internal.stubs.CertificateStoreStubs import net.corda.node.internal.NodeStartup import net.corda.node.services.Permissions.Companion.startFlow import net.corda.nodeapi.internal.crypto.X509Utilities.NODE_IDENTITY_KEY_ALIAS @@ -18,18 +18,24 @@ import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.NodeParameters import net.corda.testing.driver.driver -import net.corda.coretesting.internal.stubs.CertificateStoreStubs import net.corda.testing.node.User import net.corda.testing.node.internal.enclosedCordapp import net.corda.testing.node.internal.startNode +import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.Test import java.io.ByteArrayOutputStream import java.io.ObjectInputStream import java.io.ObjectOutputStream import java.io.Serializable +import kotlin.io.path.deleteExisting +import kotlin.io.path.div +import kotlin.io.path.isRegularFile +import kotlin.io.path.name +import kotlin.io.path.readLines +import kotlin.io.path.useDirectoryEntries +import kotlin.io.path.useLines import kotlin.test.assertEquals -import kotlin.test.assertTrue class BootTests { @Test(timeout=300_000) @@ -58,13 +64,13 @@ class BootTests { driver(DriverParameters(notarySpecs = emptyList(), cordappsForAllNodes = emptyList())) { val alice = startNode(providedName = ALICE_NAME).get() val logFolder = alice.baseDirectory / NodeStartup.LOGS_DIRECTORY_NAME - val logFile = logFolder.list { it.filter { a -> a.isRegularFile() && a.fileName.toString().startsWith("node") }.findFirst().get() } + val logFile = logFolder.useDirectoryEntries { it.single { a -> a.isRegularFile() && a.name.startsWith("node") } } // Start second Alice, should fail assertThatThrownBy { startNode(providedName = ALICE_NAME).getOrThrow() } // We count the number of nodes that wrote into the logfile by counting "Logs can be found in" - val numberOfNodesThatLogged = logFile.readLines { it.filter { NodeStartup.LOGS_CAN_BE_FOUND_IN_STRING in it }.count() } + val numberOfNodesThatLogged = logFile.useLines { lines -> lines.count { NodeStartup.LOGS_CAN_BE_FOUND_IN_STRING in it } } assertEquals(1, numberOfNodesThatLogged) } } @@ -79,7 +85,7 @@ class BootTests { )) { val alice = startNode(providedName = ALICE_NAME).getOrThrow() val aliceCertDir = alice.baseDirectory / "certificates" - (aliceCertDir / "nodekeystore.jks").delete() + (aliceCertDir / "nodekeystore.jks").deleteExisting() val cert = CertificateStoreStubs.Signing.withCertificatesDirectory(aliceCertDir).get(true) // Creating a new certificate store does not populate that store with the node certificate path. If the node certificate path is // missing, the node will fail to start but not because the legal identity is missing. To test that a missing legal identity @@ -91,9 +97,9 @@ class BootTests { startNode(providedName = ALICE_NAME).getOrThrow() } val logFolder = alice.baseDirectory / NodeStartup.LOGS_DIRECTORY_NAME - val logFile = logFolder.list { it.filter { a -> a.isRegularFile() && a.fileName.toString().startsWith("node") }.findFirst().get() } - val lines = logFile.readLines { lines -> lines.filter { NODE_IDENTITY_KEY_ALIAS in it }.toArray() } - assertTrue(lines.count() > 0) + val logFile = logFolder.useDirectoryEntries { it.single { a -> a.isRegularFile() && a.name.startsWith("node") } } + val lines = logFile.readLines().filter { NODE_IDENTITY_KEY_ALIAS in it } + assertThat(lines).hasSizeGreaterThan(0) } } diff --git a/node/src/integration-test/kotlin/net/corda/node/ContractWithMissingCustomSerializerTest.kt b/node/src/integration-test/kotlin/net/corda/node/ContractWithMissingCustomSerializerTest.kt index 78ee896844..95333a9e92 100644 --- a/node/src/integration-test/kotlin/net/corda/node/ContractWithMissingCustomSerializerTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/ContractWithMissingCustomSerializerTest.kt @@ -7,7 +7,7 @@ import net.corda.core.CordaRuntimeException import net.corda.core.contracts.TransactionVerificationException.BrokenTransactionException import net.corda.core.contracts.TransactionVerificationException.ContractRejection import net.corda.core.internal.hash -import net.corda.core.internal.inputStream +import net.corda.core.internal.read import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow import net.corda.flows.serialization.missing.MissingSerializerBuilderFlow @@ -77,7 +77,7 @@ class ContractWithMissingCustomSerializerTest(private val runInProcess: Boolean) .start(user.username, user.password) .use { client -> with(client.proxy) { - uploadAttachment(flowCorDapp.jarFile.inputStream()) + flowCorDapp.jarFile.read { uploadAttachment(it) } startFlow(::MissingSerializerFlow, BOBBINS).returnValue.getOrThrow() } } diff --git a/node/src/integration-test/kotlin/net/corda/node/CordappConstraintsTests.kt b/node/src/integration-test/kotlin/net/corda/node/CordappConstraintsTests.kt index 6532f158e0..ca73549ecd 100644 --- a/node/src/integration-test/kotlin/net/corda/node/CordappConstraintsTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/CordappConstraintsTests.kt @@ -5,7 +5,6 @@ import net.corda.core.contracts.SignatureAttachmentConstraint import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.withoutIssuer import net.corda.core.internal.deleteRecursively -import net.corda.core.internal.div import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow import net.corda.core.messaging.vaultQueryBy @@ -33,6 +32,7 @@ import net.corda.testing.node.internal.cordappWithPackages import org.assertj.core.api.Assertions.assertThat import org.junit.Ignore import org.junit.Test +import kotlin.io.path.div class CordappConstraintsTests { @@ -285,7 +285,7 @@ class CordappConstraintsTests { packageOwnership = mapOf("net.corda.finance.contracts.asset" to packageOwnerKey) ) listOf(alice, bob, notary).forEach { node -> - println("Shutting down the node for ${node} ... ") + println("Shutting down the node for $node ... ") (node as OutOfProcess).process.destroyForcibly() node.stop() NetworkParametersCopier(newParams, overwriteFile = true).install(node.baseDirectory) diff --git a/node/src/integration-test/kotlin/net/corda/node/CustomSerializationSchemeDriverTest.kt b/node/src/integration-test/kotlin/net/corda/node/CustomSerializationSchemeDriverTest.kt index 26a2039406..c56fe5d7bd 100644 --- a/node/src/integration-test/kotlin/net/corda/node/CustomSerializationSchemeDriverTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/CustomSerializationSchemeDriverTest.kt @@ -4,6 +4,7 @@ import co.paralleluniverse.fibers.Suspendable import com.esotericsoftware.kryo.Kryo import com.esotericsoftware.kryo.io.Input import com.esotericsoftware.kryo.io.Output +import com.esotericsoftware.kryo.util.DefaultInstantiatorStrategy import de.javakaffee.kryoserializers.ArraysAsListSerializer import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint import net.corda.core.contracts.BelongsToContract @@ -40,6 +41,7 @@ import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.ByteSequence import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.unwrap +import net.corda.nodeapi.internal.serialization.kryo.PublicKeySerializer import net.corda.serialization.internal.CordaSerializationMagic import net.corda.serialization.internal.SerializationFactoryImpl import net.corda.testing.core.ALICE_NAME @@ -50,6 +52,7 @@ import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.NodeParameters import net.corda.testing.driver.driver import net.corda.testing.node.internal.enclosedCordapp +import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPublicKey import org.junit.Test import org.objenesis.instantiator.ObjectInstantiator import org.objenesis.strategy.InstantiatorStrategy @@ -57,7 +60,7 @@ import org.objenesis.strategy.StdInstantiatorStrategy import java.io.ByteArrayOutputStream import java.lang.reflect.Modifier import java.security.PublicKey -import java.util.* +import java.util.Arrays import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -93,7 +96,10 @@ class CustomSerializationSchemeDriverTest { @Test(timeout = 300_000) fun `flow can write a wire transaction serialized with custom kryo serializer to the ledger`() { - driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = listOf(enclosedCordapp()))) { + driver(DriverParameters( + cordappsForAllNodes = listOf(enclosedCordapp()), + systemProperties = mapOf("experimental.corda.customSerializationScheme" to KryoScheme::class.java.name) + )) { val (alice, bob) = listOf( startNode(NodeParameters(providedName = ALICE_NAME)), startNode(NodeParameters(providedName = BOB_NAME)) @@ -134,7 +140,7 @@ class CustomSerializationSchemeDriverTest { @StartableByRPC @InitiatingFlow - class WriteTxToLedgerFlow(val counterparty: Party, val notary: Party) : FlowLogic() { + class WriteTxToLedgerFlow(private val counterparty: Party, val notary: Party) : FlowLogic() { @Suspendable override fun call(): SecureHash { val wireTx = createWireTx(serviceHub, notary, counterparty.owningKey, KryoScheme.SCHEME_ID) @@ -145,7 +151,7 @@ class CustomSerializationSchemeDriverTest { return fullySignedTx.id } - fun signWireTx(wireTx: WireTransaction) : SignedTransaction { + private fun signWireTx(wireTx: WireTransaction) : SignedTransaction { val signatureMetadata = SignatureMetadata( serviceHub.myInfo.platformVersion, Crypto.findSignatureScheme(serviceHub.myInfo.legalIdentitiesAndCerts.first().owningKey).schemeNumberID @@ -156,18 +162,18 @@ class CustomSerializationSchemeDriverTest { } } + @Suppress("unused") @InitiatedBy(WriteTxToLedgerFlow::class) class SignWireTxFlow(private val session: FlowSession): FlowLogic() { @Suspendable override fun call(): SignedTransaction { - val signTransactionFlow = object : SignTransactionFlow(session) { - override fun checkTransaction(stx: SignedTransaction) { - return - } - } - val txId = subFlow(signTransactionFlow).id + val txId = subFlow(NoCheckSignTransactionFlow(session)).id return subFlow(ReceiveFinalityFlow(session, expectedTxId = txId)) } + + class NoCheckSignTransactionFlow(session: FlowSession) : SignTransactionFlow(session) { + override fun checkTransaction(stx: SignedTransaction) = Unit + } } @StartableByRPC @@ -225,7 +231,7 @@ class CustomSerializationSchemeDriverTest { @StartableByRPC @InitiatingFlow - class SendFlow(val counterparty: Party) : FlowLogic() { + class SendFlow(private val counterparty: Party) : FlowLogic() { @Suspendable override fun call(): Boolean { val wtx = createWireTx(serviceHub, counterparty, counterparty.owningKey, KryoScheme.SCHEME_ID) @@ -236,13 +242,14 @@ class CustomSerializationSchemeDriverTest { } @StartableByRPC - class CreateWireTxFlow(val counterparty: Party) : FlowLogic() { + class CreateWireTxFlow(private val counterparty: Party) : FlowLogic() { @Suspendable override fun call(): WireTransaction { return createWireTx(serviceHub, counterparty, counterparty.owningKey, KryoScheme.SCHEME_ID) } } + @Suppress("unused") @InitiatedBy(SendFlow::class) class ReceiveFlow(private val session: FlowSession): FlowLogic() { @Suspendable @@ -296,9 +303,13 @@ class CustomSerializationSchemeDriverTest { } private fun customiseKryo(kryo: Kryo, classLoader: ClassLoader) { + kryo.references = true + kryo.isRegistrationRequired = false kryo.instantiatorStrategy = CustomInstantiatorStrategy() kryo.classLoader = classLoader + @Suppress("ReplaceJavaStaticMethodWithKotlinAnalog") kryo.register(Arrays.asList("").javaClass, ArraysAsListSerializer()) + kryo.addDefaultSerializer(BCEdDSAPublicKey::class.java, PublicKeySerializer) } //Stolen from DefaultKryoCustomizer.kt @@ -307,7 +318,7 @@ class CustomSerializationSchemeDriverTest { // Use this to allow construction of objects using a JVM backdoor that skips invoking the constructors, if there // is no no-arg constructor available. - private val defaultStrategy = Kryo.DefaultInstantiatorStrategy(fallbackStrategy) + private val defaultStrategy = DefaultInstantiatorStrategy(fallbackStrategy) override fun newInstantiatorOf(type: Class): ObjectInstantiator { // However this doesn't work for non-public classes in the java. namespace diff --git a/node/src/integration-test/kotlin/net/corda/node/NodePerformanceTests.kt b/node/src/integration-test/kotlin/net/corda/node/NodePerformanceTests.kt index 45e20f37ab..3b6c4df876 100644 --- a/node/src/integration-test/kotlin/net/corda/node/NodePerformanceTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/NodePerformanceTests.kt @@ -31,7 +31,6 @@ import org.junit.Ignore import org.junit.Test import java.util.* import java.util.concurrent.TimeUnit -import kotlin.streams.toList @Ignore("Run these locally") class NodePerformanceTests { @@ -114,4 +113,4 @@ class NodePerformanceTests { } } } -} \ No newline at end of file +} diff --git a/node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt b/node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt index 646772745f..b58bfbee00 100644 --- a/node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt @@ -5,7 +5,6 @@ import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.driver import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP import net.corda.testing.node.internal.FINANCE_WORKFLOWS_CORDAPP -import org.apache.commons.lang3.SystemUtils import org.junit.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -16,9 +15,8 @@ class NodeRPCTests { private val CORDA_VENDOR_CE = "Corda Community Edition" private val CORDAPPS = listOf(FINANCE_CONTRACTS_CORDAPP, FINANCE_WORKFLOWS_CORDAPP) private val CORDAPP_TYPES = setOf("Contract CorDapp", "Workflow CorDapp") - private val CLASSIFIER = if (SystemUtils.IS_JAVA_11) "-jdk11" else "" private val CORDAPP_CONTRACTS_NAME_REGEX = "corda-finance-contracts-$CORDA_VERSION_REGEX".toRegex() - private val CORDAPP_WORKFLOWS_NAME_REGEX = "corda-finance-workflows-$CORDA_VERSION_REGEX$CLASSIFIER".toRegex() + private val CORDAPP_WORKFLOWS_NAME_REGEX = "corda-finance-workflows-$CORDA_VERSION_REGEX".toRegex() private val CORDAPP_SHORT_NAME = "Corda Finance Demo" private val CORDAPP_VENDOR = "R3" private val CORDAPP_LICENCE = "Open Source (Apache 2)" @@ -46,4 +44,4 @@ class NodeRPCTests { assertTrue(cordappInfo.jarHash.toString().matches(HEXADECIMAL_REGEX)) } } -} \ No newline at end of file +} diff --git a/node/src/integration-test/kotlin/net/corda/node/VaultUpdateDeserializationTest.kt b/node/src/integration-test/kotlin/net/corda/node/VaultUpdateDeserializationTest.kt index 48aadf45d4..e77da5a9c1 100644 --- a/node/src/integration-test/kotlin/net/corda/node/VaultUpdateDeserializationTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/VaultUpdateDeserializationTest.kt @@ -6,7 +6,6 @@ import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.assertTrue import net.corda.core.internal.InputStreamAndHash import net.corda.core.internal.deleteRecursively -import net.corda.core.internal.div import net.corda.core.messaging.startFlow import net.corda.core.messaging.vaultQueryBy import net.corda.core.utilities.getOrThrow @@ -28,6 +27,7 @@ import net.corda.testing.node.TestCordapp import net.corda.testing.node.internal.cordappWithPackages import org.junit.Test import java.util.concurrent.TimeoutException +import kotlin.io.path.div import net.corda.contracts.incompatible.version1.AttachmentContract as AttachmentContractV1 import net.corda.flows.incompatible.version1.AttachmentFlow as AttachmentFlowV1 diff --git a/node/src/integration-test/kotlin/net/corda/node/amqp/AMQPBridgeTest.kt b/node/src/integration-test/kotlin/net/corda/node/amqp/AMQPBridgeTest.kt index c099cf3e7c..3e1fb603e0 100644 --- a/node/src/integration-test/kotlin/net/corda/node/amqp/AMQPBridgeTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/amqp/AMQPBridgeTest.kt @@ -1,9 +1,8 @@ package net.corda.node.amqp -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import net.corda.core.crypto.toStringShort -import net.corda.core.internal.div import net.corda.core.toFuture import net.corda.core.utilities.loggerFor import net.corda.node.services.config.NodeConfiguration @@ -32,6 +31,7 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder import java.util.* +import kotlin.io.path.div import kotlin.test.assertEquals class AMQPBridgeTest { @@ -41,7 +41,7 @@ class AMQPBridgeTest { private val log = loggerFor() - private val BOB = TestIdentity(BOB_NAME) + private val bob = TestIdentity(BOB_NAME) private val portAllocation = incrementalPortAllocation() private val artemisAddress = portAllocation.nextHostAndPort() @@ -52,7 +52,7 @@ class AMQPBridgeTest { @Test(timeout=300_000) fun `test acked and nacked messages`() { // Create local queue - val sourceQueueName = "internal.peers." + BOB.publicKey.toStringShort() + val sourceQueueName = "internal.peers." + bob.publicKey.toStringShort() val (artemisServer, artemisClient, bridgeManager) = createArtemis(sourceQueueName) // Pre-populate local queue with 3 messages @@ -62,7 +62,7 @@ class AMQPBridgeTest { putIntProperty(P2PMessagingHeaders.senderUUID, i) writeBodyBufferBytes("Test$i".toByteArray()) // Use the magic deduplication property built into Artemis as our message identity too - putStringProperty(HDR_DUPLICATE_DETECTION_ID, SimpleString(UUID.randomUUID().toString())) + putStringProperty(HDR_DUPLICATE_DETECTION_ID, SimpleString.of(UUID.randomUUID().toString())) } artemis.producer.send(sourceQueueName, artemisMessage) } @@ -139,7 +139,7 @@ class AMQPBridgeTest { putIntProperty(P2PMessagingHeaders.senderUUID, 3) writeBodyBufferBytes("Test3".toByteArray()) // Use the magic deduplication property built into Artemis as our message identity too - putStringProperty(HDR_DUPLICATE_DETECTION_ID, SimpleString(UUID.randomUUID().toString())) + putStringProperty(HDR_DUPLICATE_DETECTION_ID, SimpleString.of(UUID.randomUUID().toString())) } artemis.producer.send(sourceQueueName, artemisMessage) @@ -174,7 +174,7 @@ class AMQPBridgeTest { fun `bridge with strict CRL checking does not connect to server with invalid certificates`() { // Note that the opposite of this test (that a connection is established if strict checking is disabled) is carried out by the // ack/nack test above. "Strict CRL checking" means that soft fail mode is disabled. - val sourceQueueName = "internal.peers." + BOB.publicKey.toStringShort() + val sourceQueueName = "internal.peers." + bob.publicKey.toStringShort() val (artemisServer, artemisClient, bridge) = createArtemis(sourceQueueName, crlCheckSoftFail = false) createAMQPServer().use { @@ -224,8 +224,8 @@ class AMQPBridgeTest { if (sourceQueueName != null) { // Local queue for outgoing messages artemis.session.createQueue( - QueueConfiguration(sourceQueueName).setRoutingType(RoutingType.ANYCAST).setAddress(sourceQueueName).setDurable(true)) - bridgeManager.deployBridge(ALICE_NAME.toString(), sourceQueueName, listOf(amqpAddress), setOf(BOB.name)) + QueueConfiguration.of(sourceQueueName).setRoutingType(RoutingType.ANYCAST).setAddress(sourceQueueName).setDurable(true)) + bridgeManager.deployBridge(ALICE_NAME.toString(), sourceQueueName, listOf(amqpAddress), setOf(bob.name)) } return Triple(artemisServer, artemisClient, bridgeManager) } @@ -256,4 +256,4 @@ class AMQPBridgeTest { amqpConfig ) } -} \ No newline at end of file +} diff --git a/node/src/integration-test/kotlin/net/corda/node/amqp/AMQPClientSslErrorsTest.kt b/node/src/integration-test/kotlin/net/corda/node/amqp/AMQPClientSslErrorsTest.kt index 62f3168e0b..428b0fb324 100644 --- a/node/src/integration-test/kotlin/net/corda/node/amqp/AMQPClientSslErrorsTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/amqp/AMQPClientSslErrorsTest.kt @@ -1,10 +1,8 @@ package net.corda.node.amqp -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever -import net.corda.core.internal.JavaVersion -import net.corda.core.internal.div +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import net.corda.core.toFuture import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.contextLogger @@ -24,8 +22,8 @@ import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.BOB_NAME import net.corda.testing.driver.internal.incrementalPortAllocation import net.corda.testing.internal.fixedCrlSource -import org.junit.Assume.assumeFalse import org.junit.Before +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder @@ -34,6 +32,7 @@ import org.junit.runners.Parameterized import java.time.Duration import javax.net.ssl.KeyManagerFactory import javax.net.ssl.TrustManagerFactory +import kotlin.io.path.div import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -43,6 +42,7 @@ import kotlin.test.assertTrue * * In order to have control over handshake internals a simple TLS server is created which may have a configurable handshake delay. */ +@Ignore // These tests were disabled for JDK11+ very shortly after being introduced (https://github.com/corda/corda/pull/6560) @RunWith(Parameterized::class) class AMQPClientSslErrorsTest(@Suppress("unused") private val iteration: Int) { @@ -144,10 +144,7 @@ class AMQPClientSslErrorsTest(@Suppress("unused") private val iteration: Int) { } @Test(timeout = 300_000) - fun trivialClientServerExchange() { - // SSL works quite differently in JDK 11 and re-work is needed - assumeFalse(JavaVersion.isVersionAtLeast(JavaVersion.Java_11)) - + fun `trivial client server exchange`() { val serverPort = portAllocation.nextPort() val serverThread = ServerThread(serverKeyManagerFactory, serverTrustManagerFactory, serverPort).also { it.start() } @@ -182,10 +179,7 @@ class AMQPClientSslErrorsTest(@Suppress("unused") private val iteration: Int) { } @Test(timeout = 300_000) - fun amqpClientServerConnect() { - // SSL works quite differently in JDK 11 and re-work is needed - assumeFalse(JavaVersion.isVersionAtLeast(JavaVersion.Java_11)) - + fun `amqp client server connect`() { val serverPort = portAllocation.nextPort() val serverThread = ServerThread(serverKeyManagerFactory, serverTrustManagerFactory, serverPort) .also { it.start() } @@ -205,10 +199,7 @@ class AMQPClientSslErrorsTest(@Suppress("unused") private val iteration: Int) { } @Test(timeout = 300_000) - fun amqpClientServerHandshakeTimeout() { - // SSL works quite differently in JDK 11 and re-work is needed - assumeFalse(JavaVersion.isVersionAtLeast(JavaVersion.Java_11)) - + fun `amqp client server handshake timeout`() { val serverPort = portAllocation.nextPort() val serverThread = ServerThread(serverKeyManagerFactory, serverTrustManagerFactory, serverPort, 5.seconds) .also { it.start() } @@ -226,4 +217,4 @@ class AMQPClientSslErrorsTest(@Suppress("unused") private val iteration: Int) { } assertFalse(serverThread.isActive) } -} \ No newline at end of file +} diff --git a/node/src/integration-test/kotlin/net/corda/node/amqp/CertificateRevocationListNodeTests.kt b/node/src/integration-test/kotlin/net/corda/node/amqp/CertificateRevocationListNodeTests.kt index d7649fcfef..6536742a25 100644 --- a/node/src/integration-test/kotlin/net/corda/node/amqp/CertificateRevocationListNodeTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/amqp/CertificateRevocationListNodeTests.kt @@ -2,8 +2,6 @@ package net.corda.node.amqp -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.crypto.Crypto import net.corda.core.identity.CordaX500Name import net.corda.core.internal.div @@ -46,6 +44,8 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import java.io.Closeable import java.security.cert.X509Certificate import java.time.Duration @@ -54,6 +54,7 @@ import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger import java.util.stream.IntStream +import kotlin.io.path.div abstract class AbstractServerRevocationTest { @Rule @@ -498,7 +499,7 @@ class ArtemisServerRevocationTest : AbstractServerRevocationTest() { val queueName = "${P2P_PREFIX}Test" artemisNode.client.started!!.session.createQueue( - QueueConfiguration(queueName).setRoutingType(RoutingType.ANYCAST).setAddress(queueName).setDurable(true) + QueueConfiguration.of(queueName).setRoutingType(RoutingType.ANYCAST).setAddress(queueName).setDurable(true) ) val clientConnectionChangeStatus = client.waitForInitialConnectionAndCaptureChanges(expectedConnectedStatus) diff --git a/node/src/integration-test/kotlin/net/corda/node/amqp/ProtonWrapperTests.kt b/node/src/integration-test/kotlin/net/corda/node/amqp/ProtonWrapperTests.kt index 97f77fc5e2..4ff3a1b26d 100644 --- a/node/src/integration-test/kotlin/net/corda/node/amqp/ProtonWrapperTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/amqp/ProtonWrapperTests.kt @@ -1,13 +1,12 @@ package net.corda.node.amqp -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import io.netty.channel.EventLoopGroup import io.netty.channel.nio.NioEventLoopGroup import io.netty.util.concurrent.DefaultThreadFactory import net.corda.core.crypto.newSecureRandom import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.div import net.corda.core.toFuture import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.contextLogger @@ -56,6 +55,7 @@ import javax.net.ssl.SSLServerSocket import javax.net.ssl.SSLSocket import javax.net.ssl.TrustManagerFactory import kotlin.concurrent.thread +import kotlin.io.path.div import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -213,7 +213,6 @@ class ProtonWrapperTests { 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`() { /* @@ -375,7 +374,7 @@ class ProtonWrapperTests { assertEquals(CHARLIE_NAME, CordaX500Name.build(clientConnected.get().remoteCert!!.subjectX500Principal)) val artemis = artemisClient.started!! val sendAddress = P2P_PREFIX + "Test" - artemis.session.createQueue(QueueConfiguration("queue") + artemis.session.createQueue(QueueConfiguration.of("queue") .setRoutingType(RoutingType.ANYCAST).setAddress(sendAddress).setDurable(true)) val consumer = artemis.session.createConsumer("queue") val testData = "Test".toByteArray() @@ -405,7 +404,7 @@ class ProtonWrapperTests { assertEquals(CHARLIE_NAME, CordaX500Name.build(clientConnected.get().remoteCert!!.subjectX500Principal)) val artemis = artemisClient.started!! val sendAddress = P2P_PREFIX + "Test" - artemis.session.createQueue(QueueConfiguration("queue") + artemis.session.createQueue(QueueConfiguration.of("queue") .setRoutingType(RoutingType.ANYCAST).setAddress(sendAddress).setDurable(true)) val consumer = artemis.session.createConsumer("queue") diff --git a/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/CustomCheckpointSerializerTest.kt b/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/CustomCheckpointSerializerTest.kt index 0efb030fff..23f83459f6 100644 --- a/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/CustomCheckpointSerializerTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/CustomCheckpointSerializerTest.kt @@ -1,7 +1,7 @@ package net.corda.node.customcheckpointserializer -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import net.corda.core.crypto.generateKeyPair import net.corda.core.serialization.EncodingWhitelist import net.corda.core.serialization.internal.CheckpointSerializationContext diff --git a/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/DuplicateSerializerLogWithSameSerializerTest.kt b/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/DuplSerializerLogWithSameSerializerTest.kt similarity index 97% rename from node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/DuplicateSerializerLogWithSameSerializerTest.kt rename to node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/DuplSerializerLogWithSameSerializerTest.kt index 3608bc7a6b..5c3fcef2fb 100644 --- a/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/DuplicateSerializerLogWithSameSerializerTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/DuplSerializerLogWithSameSerializerTest.kt @@ -15,7 +15,7 @@ import org.assertj.core.api.Assertions import org.junit.Test import java.time.Duration -class DuplicateSerializerLogWithSameSerializerTest { +class DuplSerializerLogWithSameSerializerTest { @Test(timeout=300_000) fun `check duplicate serialisers are logged not logged for the same class`() { diff --git a/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/ReferenceLoopTest.kt b/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/ReferenceLoopTest.kt index 92a8d396c4..b956977860 100644 --- a/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/ReferenceLoopTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/ReferenceLoopTest.kt @@ -1,7 +1,7 @@ package net.corda.node.customcheckpointserializer -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import net.corda.core.serialization.CheckpointCustomSerializer import net.corda.core.serialization.EncodingWhitelist import net.corda.core.serialization.internal.CheckpointSerializationContext diff --git a/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/TestCorDapp.kt b/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/TestCorDapp.kt index 1d3e929dde..ee94fc62d0 100644 --- a/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/TestCorDapp.kt +++ b/node/src/integration-test/kotlin/net/corda/node/customcheckpointserializer/TestCorDapp.kt @@ -7,7 +7,6 @@ import net.corda.core.flows.StartableByRPC import net.corda.core.serialization.CheckpointCustomSerializer import net.corda.testing.node.internal.CustomCordapp import net.corda.testing.node.internal.enclosedCordapp -import net.i2p.crypto.eddsa.EdDSAPublicKey import org.assertj.core.api.Assertions import java.security.PublicKey import java.time.Duration @@ -198,17 +197,4 @@ class TestCorDapp { throw FlowException("Broken on purpose") } } - - @Suppress("unused") - class BrokenEdDSAPublicKeySerializer : - CheckpointCustomSerializer { - override fun toProxy(obj: EdDSAPublicKey): String { - throw FlowException("Broken on purpose") - } - - override fun fromProxy(proxy: String): EdDSAPublicKey { - throw FlowException("Broken on purpose") - } - } - } diff --git a/node/src/integration-test/kotlin/net/corda/node/flows/FlowEntityManagerTest.kt b/node/src/integration-test/kotlin/net/corda/node/flows/FlowEntityManagerTest.kt index b54d9d0d75..7d8c56633d 100644 --- a/node/src/integration-test/kotlin/net/corda/node/flows/FlowEntityManagerTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/flows/FlowEntityManagerTest.kt @@ -31,9 +31,7 @@ import net.corda.testing.core.DummyCommandData import net.corda.testing.core.singleIdentity import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.driver -import org.apache.commons.lang3.SystemUtils import org.hibernate.exception.ConstraintViolationException -import org.junit.Assume import org.junit.Before import org.junit.Test import java.lang.RuntimeException @@ -44,7 +42,7 @@ import java.util.concurrent.Semaphore import javax.persistence.PersistenceException import kotlin.test.assertEquals -@Suppress("TooGenericExceptionCaught", "TooGenericExceptionThrown") +@Suppress("TooGenericExceptionThrown") class FlowEntityManagerTest : AbstractFlowEntityManagerTest() { @Before @@ -318,8 +316,6 @@ class FlowEntityManagerTest : AbstractFlowEntityManagerTest() { @Test(timeout = 300_000) fun `constraint violation that is caught inside an entity manager should allow a flow to continue processing as normal`() { - // This test is generating JDK11 contract code on JDK11 - Assume.assumeTrue(!SystemUtils.IS_JAVA_11) var counter = 0 StaffedFlowHospital.onFlowDischarged.add { _, _ -> ++counter } driver(DriverParameters(startNodesInProcess = true)) { @@ -900,4 +896,4 @@ class FlowEntityManagerTest : AbstractFlowEntityManagerTest() { }.get() } } -} \ No newline at end of file +} diff --git a/node/src/integration-test/kotlin/net/corda/node/flows/FlowOverrideTests.kt b/node/src/integration-test/kotlin/net/corda/node/flows/FlowOverrideTests.kt index 5fb4afd3a4..21d948d632 100644 --- a/node/src/integration-test/kotlin/net/corda/node/flows/FlowOverrideTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/flows/FlowOverrideTests.kt @@ -15,7 +15,7 @@ import net.corda.testing.driver.NodeParameters import net.corda.testing.driver.driver import net.corda.testing.node.internal.cordappForClasses import org.hamcrest.CoreMatchers.`is` -import org.junit.Assert.assertThat +import org.hamcrest.MatcherAssert.assertThat import org.junit.Test class FlowOverrideTests { diff --git a/node/src/integration-test/kotlin/net/corda/node/flows/FlowReloadAfterCheckpointTest.kt b/node/src/integration-test/kotlin/net/corda/node/flows/FlowReloadAfterCheckpointTest.kt index 7f83f94cb6..9f4095615a 100644 --- a/node/src/integration-test/kotlin/net/corda/node/flows/FlowReloadAfterCheckpointTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/flows/FlowReloadAfterCheckpointTest.kt @@ -13,6 +13,7 @@ import net.corda.core.internal.FlowIORequest import net.corda.core.internal.IdempotentFlow import net.corda.core.internal.TimedFlow import net.corda.core.internal.concurrent.transpose +import net.corda.core.internal.mapToSet import net.corda.core.messaging.StateMachineTransactionMapping import net.corda.core.messaging.startFlow import net.corda.core.utilities.OpaqueBytes @@ -69,8 +70,8 @@ class FlowReloadAfterCheckpointTest { val handle = alice.rpc.startFlow(::ReloadFromCheckpointFlow, bob.nodeInfo.singleIdentity(), false, false, false) val flowStartedByAlice = handle.id handle.returnValue.getOrThrow() - assertEquals(5, reloads.filter { it == flowStartedByAlice }.count()) - assertEquals(6, reloads.filter { it == ReloadFromCheckpointResponder.flowId }.count()) + assertEquals(5, reloads.count { it == flowStartedByAlice }) + assertEquals(6, reloads.count { it == ReloadFromCheckpointResponder.flowId }) } } @@ -127,8 +128,8 @@ class FlowReloadAfterCheckpointTest { observations.await(DEFAULT_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS) reloads.await(DEFAULT_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS) assertEquals(flowStartedByAlice, observations.singleOrNull()) - assertEquals(4, reloads.filter { it == flowStartedByAlice }.count()) - assertEquals(4, reloads.filter { it == ReloadFromCheckpointResponder.flowId }.count()) + assertEquals(4, reloads.count { it == flowStartedByAlice }) + assertEquals(4, reloads.count { it == ReloadFromCheckpointResponder.flowId }) } } @@ -154,8 +155,8 @@ class FlowReloadAfterCheckpointTest { val flowStartedByAlice = handle.id handle.returnValue.getOrThrow() reloads.await(DEFAULT_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS) - assertEquals(5, reloads.filter { it == flowStartedByAlice }.count()) - assertEquals(6, reloads.filter { it == ReloadFromCheckpointResponder.flowId }.count()) + assertEquals(5, reloads.count { it == flowStartedByAlice }) + assertEquals(6, reloads.count { it == ReloadFromCheckpointResponder.flowId }) } } @@ -332,8 +333,7 @@ class FlowReloadAfterCheckpointTest { val flowStartedByAlice = handle.id handle.returnValue.getOrThrow(30.seconds) val flowStartedByBob = bob.rpc.stateMachineRecordedTransactionMappingSnapshot() - .map(StateMachineTransactionMapping::stateMachineRunId) - .toSet() + .mapToSet(StateMachineTransactionMapping::stateMachineRunId) .single() reloads.await(DEFAULT_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS) assertEquals(8, reloads.filter { it == flowStartedByAlice }.size) @@ -522,6 +522,6 @@ class FlowReloadAfterCheckpointTest { } internal class BrokenMap(delegate: MutableMap = mutableMapOf()) : MutableMap by delegate { - override fun put(key: K, value: V): V? = throw IllegalStateException("Broken on purpose") + override fun put(key: K, value: V): V = throw IllegalStateException("Broken on purpose") } diff --git a/node/src/integration-test/kotlin/net/corda/node/flows/FlowWithClientIdTest.kt b/node/src/integration-test/kotlin/net/corda/node/flows/FlowWithClientIdTest.kt index 89a4f99f95..9c94e0cb41 100644 --- a/node/src/integration-test/kotlin/net/corda/node/flows/FlowWithClientIdTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/flows/FlowWithClientIdTest.kt @@ -719,4 +719,4 @@ class FlowWithClientIdTest { internal class UnserializableException( val unserializableObject: BrokenMap = BrokenMap() ) : CordaRuntimeException("123") -} \ No newline at end of file +} diff --git a/node/src/integration-test/kotlin/net/corda/node/modes/draining/P2PFlowsDrainingModeTest.kt b/node/src/integration-test/kotlin/net/corda/node/modes/draining/P2PFlowsDrainingModeTest.kt index a72ff9d4bf..aefa655033 100644 --- a/node/src/integration-test/kotlin/net/corda/node/modes/draining/P2PFlowsDrainingModeTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/modes/draining/P2PFlowsDrainingModeTest.kt @@ -186,4 +186,4 @@ class InitiatedFlow(private val initiatingSession: FlowSession) : FlowLogic().unwrap { it } initiatingSession.send("$message answer") } -} \ No newline at end of file +} diff --git a/node/src/integration-test/kotlin/net/corda/node/multiRpc/MultiRpcClientTest.kt b/node/src/integration-test/kotlin/net/corda/node/multiRpc/MultiRpcClientTest.kt index 48fd72f7c0..712385fea9 100644 --- a/node/src/integration-test/kotlin/net/corda/node/multiRpc/MultiRpcClientTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/multiRpc/MultiRpcClientTest.kt @@ -1,9 +1,9 @@ package net.corda.node.multiRpc -import com.nhaarman.mockito_kotlin.argThat -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.times -import com.nhaarman.mockito_kotlin.verify +import org.mockito.kotlin.argThat +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import net.corda.client.rpc.ConnectionFailureException import net.corda.client.rpc.ext.MultiRPCClient import net.corda.client.rpc.ext.RPCConnectionListener @@ -128,4 +128,4 @@ class MultiRpcClientTest { verify(observer, times(1)).onError(argThat { this as? ConnectionFailureException != null }) } } -} \ No newline at end of file +} diff --git a/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt index e62b1f4883..5a87c87c41 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt @@ -1,49 +1,42 @@ package net.corda.node.services import co.paralleluniverse.fibers.Suspendable -import net.corda.core.contracts.* -import net.corda.core.flows.* -import net.corda.core.identity.AbstractParty -import net.corda.core.identity.CordaX500Name +import net.corda.core.contracts.Amount +import net.corda.core.contracts.TransactionVerificationException +import net.corda.core.flows.FinalityFlow +import net.corda.core.flows.FlowException +import net.corda.core.flows.FlowLogic +import net.corda.core.flows.FlowSession +import net.corda.core.flows.InitiatedBy +import net.corda.core.flows.InitiatingFlow +import net.corda.core.flows.ReceiveFinalityFlow +import net.corda.core.flows.StartableByRPC import net.corda.core.identity.Party -import net.corda.core.internal.* import net.corda.core.internal.concurrent.transpose import net.corda.core.messaging.startFlow -import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.TransactionBuilder +import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.unwrap -import net.corda.testing.common.internal.checkNotOnClasspath +import net.corda.finance.DOLLARS +import net.corda.finance.flows.CashIssueFlow +import net.corda.finance.workflows.asset.CashUtils import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.BOB_NAME import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.singleIdentity -import net.corda.testing.driver.DriverDSL import net.corda.testing.driver.DriverParameters +import net.corda.testing.driver.NodeParameters import net.corda.testing.driver.driver import net.corda.testing.node.NotarySpec +import net.corda.testing.node.internal.FINANCE_CORDAPPS +import net.corda.testing.node.internal.FINANCE_WORKFLOWS_CORDAPP import net.corda.testing.node.internal.enclosedCordapp import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.Test -import java.net.URL -import java.net.URLClassLoader +import java.util.Currency class AttachmentLoadingTests { - private companion object { - val isolatedJar: URL = AttachmentLoadingTests::class.java.getResource("/isolated.jar") - val isolatedClassLoader = URLClassLoader(arrayOf(isolatedJar)) - val issuanceFlowClass: Class> = uncheckedCast(loadFromIsolated("net.corda.isolated.workflows.IsolatedIssuanceFlow")) - - init { - checkNotOnClasspath("net.corda.isolated.contracts.AnotherDummyContract") { - "isolated module cannot be on the classpath as otherwise it will be pulled into the nodes the driver creates and " + - "contaminate the tests. This is a known issue with the driver and we must work around it until it's fixed." - } - } - - fun loadFromIsolated(className: String): Class<*> = Class.forName(className, false, isolatedClassLoader) - } - @Test(timeout=300_000) fun `contracts downloaded from the network are not executed`() { driver(DriverParameters( @@ -51,61 +44,36 @@ class AttachmentLoadingTests { notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = false)), cordappsForAllNodes = listOf(enclosedCordapp()) )) { - installIsolatedCordapp(ALICE_NAME) - val (alice, bob) = listOf( - startNode(providedName = ALICE_NAME), - startNode(providedName = BOB_NAME) + startNode(NodeParameters(ALICE_NAME, additionalCordapps = FINANCE_CORDAPPS)), + startNode(NodeParameters(BOB_NAME, additionalCordapps = listOf(FINANCE_WORKFLOWS_CORDAPP))) ).transpose().getOrThrow() - val stateRef = alice.rpc.startFlowDynamic(issuanceFlowClass, 1234).returnValue.getOrThrow() + alice.rpc.startFlow(::CashIssueFlow, 10.DOLLARS, OpaqueBytes.of(0x00), defaultNotaryIdentity).returnValue.getOrThrow() - assertThatThrownBy { alice.rpc.startFlow(::ConsumeAndBroadcastFlow, stateRef, bob.nodeInfo.singleIdentity()).returnValue.getOrThrow() } + assertThatThrownBy { alice.rpc.startFlow(::ConsumeAndBroadcastFlow, 10.DOLLARS, bob.nodeInfo.singleIdentity()).returnValue.getOrThrow() } // ConsumeAndBroadcastResponderFlow re-throws any non-FlowExceptions with just their class name in the message so that // we can verify here Bob threw the correct exception .hasMessage(TransactionVerificationException.UntrustedAttachmentsException::class.java.name) } } - @Test(timeout=300_000) - fun `contract is executed if installed locally`() { - driver(DriverParameters( - startNodesInProcess = false, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = false)), - cordappsForAllNodes = listOf(enclosedCordapp()) - )) { - installIsolatedCordapp(ALICE_NAME) - installIsolatedCordapp(BOB_NAME) - - val (alice, bob) = listOf( - startNode(providedName = ALICE_NAME), - startNode(providedName = BOB_NAME) - ).transpose().getOrThrow() - - val stateRef = alice.rpc.startFlowDynamic(issuanceFlowClass, 1234).returnValue.getOrThrow() - alice.rpc.startFlow(::ConsumeAndBroadcastFlow, stateRef, bob.nodeInfo.singleIdentity()).returnValue.getOrThrow() - } - } - - private fun DriverDSL.installIsolatedCordapp(name: CordaX500Name) { - val cordappsDir = (baseDirectory(name) / "cordapps").createDirectories() - isolatedJar.toPath().copyToDirectory(cordappsDir) - } - @InitiatingFlow @StartableByRPC - class ConsumeAndBroadcastFlow(private val stateRef: StateRef, private val otherSide: Party) : FlowLogic() { + class ConsumeAndBroadcastFlow(private val amount: Amount, private val otherSide: Party) : FlowLogic() { @Suspendable override fun call() { val notary = serviceHub.networkMapCache.notaryIdentities[0] - val stateAndRef = serviceHub.toStateAndRef(stateRef) - val stx = serviceHub.signInitialTransaction( - TransactionBuilder(notary) - .addInputState(stateAndRef) - .addOutputState(ConsumeContract.State()) - .addCommand(Command(ConsumeContract.Cmd, ourIdentity.owningKey)) + val builder = TransactionBuilder(notary) + val (_, keysForSigning) = CashUtils.generateSpend( + serviceHub, + builder, + amount, + ourIdentityAndCert, + otherSide, + anonymous = false ) - stx.verify(serviceHub, checkSufficientSignatures = false) + val stx = serviceHub.signInitialTransaction(builder, keysForSigning) val session = initiateFlow(otherSide) subFlow(FinalityFlow(stx, session)) // It's important we wait on this dummy receive, as otherwise it's possible we miss any errors the other side throws @@ -127,16 +95,4 @@ class AttachmentLoadingTests { otherSide.send("OK") } } - - class ConsumeContract : Contract { - override fun verify(tx: LedgerTransaction) { - // Accept everything - } - - class State : ContractState { - override val participants: List get() = emptyList() - } - - object Cmd : TypeOnlyCommandData() - } } diff --git a/node/src/integration-test/kotlin/net/corda/node/services/CordaServiceIssueOnceAtStartupTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/CordaServiceIssueOnceAtStartupTests.kt index 2e27e36f05..3f19955c9a 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/CordaServiceIssueOnceAtStartupTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/CordaServiceIssueOnceAtStartupTests.kt @@ -29,6 +29,7 @@ import org.junit.Test import java.io.File import kotlin.test.assertEquals import kotlin.test.assertTrue +import kotlin.io.path.createTempFile /** * The idea of this test is upon start-up of the node check if cash been already issued and if not issue under certain reference. @@ -40,7 +41,7 @@ class CordaServiceIssueOnceAtStartupTests { private val armedPropName = this::class.java.enclosingClass.name + "-armed" private val logger = contextLogger() private val tempFilePropertyName = this::class.java.enclosingClass.name + "-tmpFile" - private val tmpFile = createTempFile(prefix = tempFilePropertyName) + private val tmpFile = createTempFile(prefix = tempFilePropertyName).toFile() private const val vaultQueryExecutedMarker = "VaultQueryExecuted" private const val sentFlowMarker = "SentFlow" } diff --git a/node/src/integration-test/kotlin/net/corda/node/services/CordaServiceLifecycleFatalTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/CordaServiceLifecycleFatalTests.kt index 35c1352c7a..0cbca6894a 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/CordaServiceLifecycleFatalTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/CordaServiceLifecycleFatalTests.kt @@ -18,7 +18,7 @@ import org.junit.Test import java.io.File import kotlin.test.assertEquals import kotlin.test.assertFailsWith - +import kotlin.io.path.createTempFile class CordaServiceLifecycleFatalTests { companion object { @@ -34,7 +34,7 @@ class CordaServiceLifecycleFatalTests { // Temporaty file used as a latch between two processes private val tempFilePropertyName = this::class.java.enclosingClass.name + "-tmpFile" - private val tmpFile = createTempFile(prefix = tempFilePropertyName) + private val tmpFile = createTempFile(prefix = tempFilePropertyName).toFile() private const val readyToThrowMarker = "ReadyToThrow" private const val goodToThrowMarker = "GoodToThrow" diff --git a/node/src/integration-test/kotlin/net/corda/node/services/identity/CertificateRotationTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/identity/CertificateRotationTest.kt index 34ad626ef5..0c1ee5a8cd 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/identity/CertificateRotationTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/identity/CertificateRotationTest.kt @@ -1,7 +1,6 @@ package net.corda.node.services.identity import net.corda.core.internal.PLATFORM_VERSION -import net.corda.core.internal.div import net.corda.core.utilities.OpaqueBytes import net.corda.coretesting.internal.stubs.CertificateStoreStubs import net.corda.finance.DOLLARS @@ -28,6 +27,7 @@ import org.junit.After import org.junit.Test import java.nio.file.Path import java.security.PublicKey +import kotlin.io.path.div import kotlin.test.assertEquals import kotlin.test.assertNotEquals import kotlin.test.assertNull diff --git a/node/src/integration-test/kotlin/net/corda/node/services/identity/NotaryCertificateRotationTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/identity/NotaryCertificateRotationTest.kt index 6c067e27ec..b77ea1fe1d 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/identity/NotaryCertificateRotationTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/identity/NotaryCertificateRotationTest.kt @@ -1,8 +1,8 @@ package net.corda.node.services.identity +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import co.paralleluniverse.fibers.Suspendable -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowSession @@ -50,7 +50,7 @@ import org.junit.After import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized -import java.util.* +import kotlin.io.path.createDirectories import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertNull @@ -262,4 +262,4 @@ class NotaryCertificateRotationTest(private val validating: Boolean) { subFlow(ReceiveTransactionFlow(otherSide, statesToRecord = StatesToRecord.ALL_VISIBLE)) } } -} \ No newline at end of file +} diff --git a/node/src/integration-test/kotlin/net/corda/node/services/identity/TrustRootTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/identity/TrustRootTest.kt index 779863ce50..176013d691 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/identity/TrustRootTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/identity/TrustRootTest.kt @@ -1,10 +1,9 @@ package net.corda.node.services.identity -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party -import net.corda.core.internal.div import net.corda.core.utilities.OpaqueBytes import net.corda.coretesting.internal.stubs.CertificateStoreStubs import net.corda.finance.DOLLARS @@ -36,6 +35,7 @@ import net.corda.testing.node.internal.startFlow import org.junit.After import org.junit.Test import javax.security.auth.x500.X500Principal +import kotlin.io.path.div import kotlin.test.assertEquals class TrustRootTest { @@ -212,4 +212,4 @@ class TrustRootTest { nodeIds.forEach { install(mockNet.baseDirectory(it)) } } } -} \ No newline at end of file +} diff --git a/node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt index cf9d022bff..5a8c5736f0 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt @@ -1,10 +1,9 @@ package net.corda.node.services.messaging import com.codahale.metrics.MetricRegistry -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import net.corda.core.crypto.generateKeyPair -import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.seconds import net.corda.coretesting.internal.rigorousMock @@ -40,6 +39,7 @@ import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.TimeUnit.MILLISECONDS import kotlin.concurrent.thread +import kotlin.io.path.div import kotlin.test.assertEquals import kotlin.test.assertNull import kotlin.test.assertTrue @@ -233,7 +233,7 @@ class ArtemisMessagingTest { MetricRegistry(), TestingNamedCacheFactory(), isDrainingModeOn = { false }, - drainingModeWasChangedEvents = PublishSubject.create>(), + drainingModeWasChangedEvents = PublishSubject.create(), terminateOnConnectionError = false, timeoutConfig = P2PMessagingClient.TimeoutConfig(10.seconds, 10.seconds, 10.seconds)).apply { config.configureWithDevSSLCertificate() diff --git a/node/src/integration-test/kotlin/net/corda/node/services/messaging/FlowManagerRPCOpsTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/messaging/FlowManagerRPCOpsTest.kt index 320db43d3c..0218aa1db3 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/messaging/FlowManagerRPCOpsTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/messaging/FlowManagerRPCOpsTest.kt @@ -2,10 +2,6 @@ package net.corda.node.services.messaging import net.corda.client.rpc.ext.MultiRPCClient -import net.corda.core.internal.createDirectories -import net.corda.core.internal.div -import net.corda.core.internal.isRegularFile -import net.corda.core.internal.list import net.corda.core.messaging.flows.FlowManagerRPCOps import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.seconds @@ -16,6 +12,10 @@ import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.driver import net.corda.testing.node.User import org.junit.Test +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.isRegularFile +import kotlin.io.path.listDirectoryEntries import kotlin.test.assertNotNull import net.corda.core.internal.messaging.FlowManagerRPCOps as InternalFlowManagerRPCOps @@ -39,7 +39,7 @@ class FlowManagerRPCOpsTest { it.stop() } - assertNotNull(logDirPath.list().singleOrNull { it.isRegularFile() }) + assertNotNull(logDirPath.listDirectoryEntries().singleOrNull { it.isRegularFile() }) } } @@ -61,7 +61,7 @@ class FlowManagerRPCOpsTest { it.stop() } - assertNotNull(logDirPath.list().singleOrNull { it.isRegularFile() }) + assertNotNull(logDirPath.listDirectoryEntries().singleOrNull { it.isRegularFile() }) } } } \ No newline at end of file diff --git a/node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapTest.kt index a3738df972..78f36b7442 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapTest.kt @@ -2,7 +2,9 @@ package net.corda.node.services.network import net.corda.core.crypto.random63BitValue import net.corda.core.identity.Party -import net.corda.core.internal.* +import net.corda.core.internal.NODE_INFO_DIRECTORY +import net.corda.core.internal.bufferUntilSubscribed +import net.corda.core.internal.readObject import net.corda.core.messaging.ParametersUpdateInfo import net.corda.core.node.NetworkParameters import net.corda.core.node.NodeInfo @@ -17,23 +19,34 @@ import net.corda.nodeapi.internal.network.SignedNetworkParameters import net.corda.testing.common.internal.addNotary import net.corda.testing.common.internal.eventually import net.corda.testing.common.internal.testNetworkParameters -import net.corda.testing.core.* +import net.corda.testing.core.ALICE_NAME +import net.corda.testing.core.BOB_NAME +import net.corda.testing.core.SerializationEnvironmentRule +import net.corda.testing.core.TestIdentity +import net.corda.testing.core.expect +import net.corda.testing.core.expectEvents +import net.corda.testing.core.sequence import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.internal.NodeHandleInternal import net.corda.testing.driver.internal.incrementalPortAllocation -import net.corda.testing.node.internal.* +import net.corda.testing.node.internal.CompatibilityZoneParams +import net.corda.testing.node.internal.DriverDSLImpl +import net.corda.testing.node.internal.SplitCompatibilityZoneParams +import net.corda.testing.node.internal.internalDriver import net.corda.testing.node.internal.network.NetworkMapServer +import net.corda.testing.node.internal.startNode import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy -import org.hamcrest.CoreMatchers.`is` import org.junit.After import org.junit.Assert.assertEquals -import org.junit.Assert.assertThat import org.junit.Before import org.junit.Rule import org.junit.Test import java.net.URL import java.time.Instant +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.listDirectoryEntries class NetworkMapTest { @Rule @@ -280,9 +293,10 @@ class NetworkMapTest { // Make sure the nodes aren't getting the node infos from their additional-node-infos directories val nodeInfosDir = baseDirectory / NODE_INFO_DIRECTORY if (nodeInfosDir.exists()) { - assertThat(nodeInfosDir.list().size, `is`(1)) - assertThat(nodeInfosDir.list().single().readObject() - .verified().legalIdentities.first(), `is`(this.nodeInfo.legalIdentities.first())) + val nodeInfos = nodeInfosDir.listDirectoryEntries() + assertThat(nodeInfos).hasSize(1) + assertThat(nodeInfos.single().readObject().verified().legalIdentities.first()) + .isEqualTo(nodeInfo.legalIdentities.first()) } assertThat(rpc.networkMapSnapshot()).containsOnly(*nodes) } diff --git a/node/src/integration-test/kotlin/net/corda/node/services/rpc/ArtemisRpcTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/rpc/ArtemisRpcTests.kt index 4128a5eab8..d88f53a3f0 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/rpc/ArtemisRpcTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/rpc/ArtemisRpcTests.kt @@ -4,7 +4,6 @@ import net.corda.client.rpc.RPCException import net.corda.client.rpc.internal.RPCClient import net.corda.core.context.AuthServiceId import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.div import net.corda.core.messaging.ClientRpcSslOptions import net.corda.core.messaging.RPCOps import net.corda.core.utilities.NetworkHostAndPort @@ -34,6 +33,7 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import java.nio.file.Path import javax.security.auth.x500.X500Principal +import kotlin.io.path.div class ArtemisRpcTests { private val ports: PortAllocation = incrementalPortAllocation() diff --git a/node/src/integration-test/kotlin/net/corda/node/services/rpc/DumpCheckpointsTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/rpc/DumpCheckpointsTest.kt index a4582f6740..13282918e4 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/rpc/DumpCheckpointsTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/rpc/DumpCheckpointsTest.kt @@ -6,11 +6,6 @@ import com.natpryce.hamkrest.containsSubstring import net.corda.client.rpc.CordaRPCClient import net.corda.core.flows.FlowLogic import net.corda.core.flows.StartableByRPC -import net.corda.core.internal.createDirectories -import net.corda.core.internal.div -import net.corda.core.internal.inputStream -import net.corda.core.internal.isRegularFile -import net.corda.core.internal.list import net.corda.core.internal.readFully import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow @@ -30,6 +25,11 @@ import org.junit.Test import java.nio.file.Path import java.util.concurrent.CountDownLatch import java.util.zip.ZipInputStream +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.inputStream +import kotlin.io.path.isRegularFile +import kotlin.io.path.listDirectoryEntries import kotlin.test.assertEquals class DumpCheckpointsTest { @@ -88,10 +88,10 @@ class DumpCheckpointsTest { private fun checkDumpFile(dir: Path, containsClass: Class>, flowStatus: Checkpoint.FlowStatus) { // The directory supposed to contain a single ZIP file - val file = dir.list().single { it.isRegularFile() } + val file = dir.listDirectoryEntries().single { it.isRegularFile() } ZipInputStream(file.inputStream()).use { zip -> - val entry = zip.nextEntry + val entry = zip.nextEntry!! assertThat(entry.name, containsSubstring("json")) val content = String(zip.readFully()) assertThat(content, containsSubstring(containsClass.name)) diff --git a/node/src/integration-test/kotlin/net/corda/node/services/rpc/RpcSslTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/rpc/RpcSslTest.kt index ceb715533b..335cac82f8 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/rpc/RpcSslTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/rpc/RpcSslTest.kt @@ -2,7 +2,6 @@ package net.corda.node.services.rpc import net.corda.client.rpc.CordaRPCClient import net.corda.client.rpc.RPCException -import net.corda.core.internal.div import net.corda.core.messaging.ClientRpcSslOptions import net.corda.core.utilities.getOrThrow import net.corda.node.services.Permissions.Companion.all @@ -23,6 +22,7 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder import javax.security.auth.x500.X500Principal +import kotlin.io.path.div class RpcSslTest { diff --git a/node/src/integration-test/kotlin/net/corda/node/services/statemachine/FlowHospitalTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/statemachine/FlowHospitalTest.kt index f14f60cc5b..91bda3c280 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/statemachine/FlowHospitalTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/statemachine/FlowHospitalTest.kt @@ -139,7 +139,7 @@ class FlowHospitalTest { @Test(timeout = 300_000) fun `HospitalizeFlowException thrown`() { - var observationCounter: Int = 0 + var observationCounter = 0 StaffedFlowHospital.onFlowKeptForOvernightObservation.add { _, _ -> ++observationCounter } @@ -161,7 +161,7 @@ class FlowHospitalTest { @Test(timeout = 300_000) fun `Custom exception wrapping HospitalizeFlowException thrown`() { - var observationCounter: Int = 0 + var observationCounter = 0 StaffedFlowHospital.onFlowKeptForOvernightObservation.add { _, _ -> ++observationCounter } @@ -183,7 +183,7 @@ class FlowHospitalTest { @Test(timeout = 300_000) fun `Custom exception extending HospitalizeFlowException thrown`() { - var observationCounter: Int = 0 + var observationCounter = 0 StaffedFlowHospital.onFlowKeptForOvernightObservation.add { _, _ -> ++observationCounter } @@ -470,7 +470,7 @@ class FlowHospitalTest { @Suspendable override fun call() { - val throwable = hospitalizeFlowExceptionClass.newInstance() + val throwable = hospitalizeFlowExceptionClass.getDeclaredConstructor().newInstance() (throwable as? Throwable)?.let { throw it } @@ -561,7 +561,6 @@ class FlowHospitalTest { var exceptionSeenInUserFlow = false } - @Suppress("TooGenericExceptionCaught") @Suspendable override fun call() { val consumeError = session.receive().unwrap { it } diff --git a/node/src/integration-test/kotlin/net/corda/node/services/statemachine/HardRestartTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/statemachine/HardRestartTest.kt index 5b1f99b130..fe1782c033 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/statemachine/HardRestartTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/statemachine/HardRestartTest.kt @@ -6,7 +6,6 @@ import net.corda.core.flows.* import net.corda.core.identity.Party import net.corda.core.internal.concurrent.fork import net.corda.core.internal.concurrent.transpose -import net.corda.core.internal.div import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow @@ -27,6 +26,7 @@ import java.util.* import java.util.concurrent.CountDownLatch import java.util.concurrent.Executors import kotlin.concurrent.thread +import kotlin.io.path.div import kotlin.test.assertEquals class HardRestartTest { @@ -184,17 +184,17 @@ class HardRestartTest { @StartableByRPC @InitiatingFlow @InitiatedBy(RecursiveB::class) - class RecursiveA(val mode: RecursiveMode) : FlowLogic() { + class RecursiveA(private val mode: RecursiveMode) : FlowLogic() { constructor(otherSession: FlowSession) : this(RecursiveMode.Recursive(otherSession)) constructor(otherParty: Party, initialDepth: Int) : this(RecursiveMode.Top(otherParty, initialDepth)) @Suspendable override fun call(): String { return when (mode) { - is HardRestartTest.RecursiveMode.Top -> { + is RecursiveMode.Top -> { val session = initiateFlow(mode.otherParty) session.sendAndReceive(mode.initialDepth).unwrap { it } } - is HardRestartTest.RecursiveMode.Recursive -> { + is RecursiveMode.Recursive -> { val depth = mode.otherSession.receive().unwrap { it } val string = if (depth > 0) { val newSession = initiateFlow(mode.otherSession.counterparty) diff --git a/node/src/integration-test/kotlin/net/corda/node/verification/ExternalVerifierTest.kt b/node/src/integration-test/kotlin/net/corda/node/verification/ExternalVerifierTest.kt new file mode 100644 index 0000000000..2d58b3a20c --- /dev/null +++ b/node/src/integration-test/kotlin/net/corda/node/verification/ExternalVerifierTest.kt @@ -0,0 +1,29 @@ +package net.corda.node.verification + +import io.github.classgraph.ClassGraph +import net.corda.core.internal.pooledScan +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test + +class ExternalVerifierTest { + @Test(timeout=300_000) + fun `external verifier does not have newer Kotlin`() { + val kotlinClasses = ClassGraph() + .overrideClasspath(javaClass.getResource("external-verifier.jar")!!) + .enableAnnotationInfo() + .pooledScan() + .use { result -> + result.getClassesWithAnnotation(Metadata::class.java).associateBy({ it.name }, { + val annotationInfo = it.getAnnotationInfo(Metadata::class.java) + val metadataVersion = annotationInfo.parameterValues.get("mv").value as IntArray + "${metadataVersion[0]}.${metadataVersion[1]}" + }) + } + + // First make sure we're capturing the right data + assertThat(kotlinClasses).containsKeys("net.corda.verifier.ExternalVerifier") + // Kotlin metadata version 1.1 maps to language versions 1.0 to 1.3 + val newerKotlinClasses = kotlinClasses.filterValues { metadataVersion -> metadataVersion != "1.1" } + assertThat(newerKotlinClasses).isEmpty() + } +} diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt index 6b3ee8a9d2..7107349eda 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt @@ -3,22 +3,19 @@ package net.corda.services.messaging import net.corda.core.crypto.Crypto import net.corda.core.crypto.toStringShort import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.createDirectories -import net.corda.core.internal.div -import net.corda.core.internal.exists import net.corda.core.internal.toX500Name import net.corda.coretesting.internal.configureTestSSL +import net.corda.coretesting.internal.stubs.CertificateStoreStubs import net.corda.nodeapi.RPCApi +import net.corda.nodeapi.internal.ArtemisMessagingComponent import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_P2P_USER import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.PEER_USER import net.corda.nodeapi.internal.DEV_INTERMEDIATE_CA import net.corda.nodeapi.internal.DEV_ROOT_CA import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.X509Utilities -import net.corda.nodeapi.internal.loadDevCaTrustStore -import net.corda.coretesting.internal.stubs.CertificateStoreStubs -import net.corda.nodeapi.internal.ArtemisMessagingComponent import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA +import net.corda.nodeapi.internal.loadDevCaTrustStore import net.corda.nodeapi.internal.registerDevP2pCertificates import net.corda.services.messaging.SimpleAMQPClient.Companion.sendAndVerify import net.corda.testing.core.BOB_NAME @@ -37,6 +34,9 @@ import org.junit.Test import java.nio.file.Files import javax.jms.JMSSecurityException import javax.security.auth.x500.X500Principal +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.exists import kotlin.test.assertEquals /** @@ -52,7 +52,7 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() { } @Test(timeout=300_000) - fun `send message to RPC requests address`() { + fun `send message to RPC requests address`() { assertProducerQueueCreationAttackFails(RPCApi.RPC_SERVER_QUEUE_NAME) } @@ -178,7 +178,7 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() { } override fun `send message to notifications address`() { - assertProducerQueueCreationAttackFails(ArtemisMessagingComponent.NOTIFICATIONS_ADDRESS) + assertProducerQueueCreationAttackFails(ArtemisMessagingComponent.NOTIFICATIONS_ADDRESS) } @Test(timeout=300_000) diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt index 3b012b7672..5290d4fd08 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt @@ -117,7 +117,7 @@ abstract class MQSecurityTest : NodeBasedTest() { fun loginToRPCAndGetClientQueue(): String { loginToRPC(alice.node.configuration.rpcOptions.address, rpcUser) - val clientQueueQuery = SimpleString("${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.${rpcUser.username}.*") + val clientQueueQuery = SimpleString.of("${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.${rpcUser.username}.*") val client = clientTo(alice.node.configuration.rpcOptions.address) client.start(rpcUser.username, rpcUser.password, false) return client.session.addressQuery(clientQueueQuery).queueNames.single().toString() @@ -131,7 +131,7 @@ abstract class MQSecurityTest : NodeBasedTest() { fun assertTempQueueCreationAttackFails(queue: String) { assertAttackFails(queue, "CREATE_NON_DURABLE_QUEUE") { - attacker.session.createQueue(QueueConfiguration(queue) + attacker.session.createQueue(QueueConfiguration.of(queue) .setRoutingType(RoutingType.MULTICAST) .setAddress(queue) .setTemporary(true) @@ -153,7 +153,7 @@ abstract class MQSecurityTest : NodeBasedTest() { val permission = if (durable) "CREATE_DURABLE_QUEUE" else "CREATE_NON_DURABLE_QUEUE" assertAttackFails(queue, permission) { attacker.session.createQueue( - QueueConfiguration(queue).setAddress(queue).setRoutingType(RoutingType.MULTICAST).setDurable(durable)) + QueueConfiguration.of(queue).setAddress(queue).setRoutingType(RoutingType.MULTICAST).setDurable(durable)) } // Double-check assertThatExceptionOfType(ActiveMQNonExistentQueueException::class.java).isThrownBy { diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMQSecurityTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMQSecurityTest.kt index 1773b03380..d89bd3297d 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMQSecurityTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMQSecurityTest.kt @@ -37,7 +37,7 @@ abstract class P2PMQSecurityTest : MQSecurityTest() { val queue = session.createQueue(address) assertThatExceptionOfType(JMSException::class.java).isThrownBy { session.createProducer(queue) - }.withMessageContaining(address).withMessageContaining("CREATE_DURABLE_QUEUE") + }.withMessageContaining(address).withMessageContaining("CREATE_ADDRESS") } @Test(timeout=300_000) @@ -79,4 +79,4 @@ abstract class P2PMQSecurityTest : MQSecurityTest() { val user1Queue = loginToRPCAndGetClientQueue() assertConsumeAttackFailsNonexistent(user1Queue) } -} \ No newline at end of file +} diff --git a/node/src/integration-test/resources/isolated.jar b/node/src/integration-test/resources/isolated.jar deleted file mode 100644 index 3df99a710f..0000000000 Binary files a/node/src/integration-test/resources/isolated.jar and /dev/null differ diff --git a/node/src/main/kotlin/net/corda/node/NodeCmdLineOptions.kt b/node/src/main/kotlin/net/corda/node/NodeCmdLineOptions.kt index e544d5669a..d64015ee05 100644 --- a/node/src/main/kotlin/net/corda/node/NodeCmdLineOptions.kt +++ b/node/src/main/kotlin/net/corda/node/NodeCmdLineOptions.kt @@ -8,7 +8,6 @@ import net.corda.common.configuration.parsing.internal.Configuration import net.corda.common.validation.internal.Validated import net.corda.common.validation.internal.Validated.Companion.invalid import net.corda.common.validation.internal.Validated.Companion.valid -import net.corda.core.internal.div import net.corda.core.utilities.loggerFor import net.corda.node.services.config.ConfigHelper import net.corda.node.services.config.NodeConfiguration @@ -18,6 +17,7 @@ import net.corda.nodeapi.internal.config.UnknownConfigKeysPolicy import picocli.CommandLine.Option import java.nio.file.Path import java.nio.file.Paths +import kotlin.io.path.div open class SharedNodeCmdLineOptions { private companion object { @@ -34,7 +34,7 @@ open class SharedNodeCmdLineOptions { description = ["The path to the config file. By default this is node.conf in the base directory."] ) private var _configFile: Path? = null - val configFile: Path get() = if (_configFile != null) baseDirectory.resolve(_configFile) else (baseDirectory / "node.conf") + val configFile: Path get() = _configFile?.let(baseDirectory::resolve) ?: (baseDirectory / "node.conf") @Option( names = ["--on-unknown-config-keys"], diff --git a/node/src/main/kotlin/net/corda/node/SerialFilter.kt b/node/src/main/kotlin/net/corda/node/SerialFilter.kt index 9998eacd7b..0cb47d52e8 100644 --- a/node/src/main/kotlin/net/corda/node/SerialFilter.kt +++ b/node/src/main/kotlin/net/corda/node/SerialFilter.kt @@ -1,53 +1,12 @@ package net.corda.node -import net.corda.core.internal.DeclaredField -import net.corda.core.internal.staticField -import net.corda.node.internal.Node -import java.lang.reflect.Method -import java.lang.reflect.Proxy +import java.io.ObjectInputFilter +import java.io.ObjectInputFilter.Status internal object SerialFilter { - private val filterInterface: Class<*> - private val serialClassGetter: Method - private val undecided: Any - private val rejected: Any - private val serialFilterLock: Any - private val serialFilterField: DeclaredField - - init { - // ObjectInputFilter and friends are in java.io in Java 9 but sun.misc in backports: - fun getFilterInterface(packageName: String): Class<*>? { - return try { - Class.forName("$packageName.ObjectInputFilter") - } catch (e: ClassNotFoundException) { - null - } - } - // JDK 8u121 is the earliest JDK8 JVM that supports this functionality. - filterInterface = getFilterInterface("java.io") - ?: getFilterInterface("sun.misc") - ?: Node.failStartUp("Corda forbids Java deserialisation. Please upgrade to at least JDK 8u121.") - serialClassGetter = Class.forName("${filterInterface.name}\$FilterInfo").getMethod("serialClass") - val statusEnum = Class.forName("${filterInterface.name}\$Status") - undecided = statusEnum.getField("UNDECIDED").get(null) - rejected = statusEnum.getField("REJECTED").get(null) - val configClass = Class.forName("${filterInterface.name}\$Config") - serialFilterLock = configClass.staticField("serialFilterLock").value - serialFilterField = configClass.staticField("serialFilter") - } - internal fun install(acceptClass: (Class<*>) -> Boolean) { - val filter = Proxy.newProxyInstance(javaClass.classLoader, arrayOf(filterInterface)) { _, _, args -> - val serialClass = serialClassGetter.invoke(args[0]) as Class<*>? - if (applyPredicate(acceptClass, serialClass)) { - undecided - } else { - rejected - } - } - // Can't simply use the setter as in non-trampoline mode Capsule has inited the filter in premain: - synchronized(serialFilterLock) { - serialFilterField.value = filter + ObjectInputFilter.Config.setSerialFilter { filterInfo -> + if (applyPredicate(acceptClass, filterInfo.serialClass())) Status.UNDECIDED else Status.REJECTED } } diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 72c31fc33c..629f21a8aa 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -38,11 +38,10 @@ import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.concurrent.flatMap import net.corda.core.internal.concurrent.map import net.corda.core.internal.concurrent.openFuture -import net.corda.core.internal.div +import net.corda.core.internal.cordapp.CordappProviderInternal import net.corda.core.internal.messaging.AttachmentTrustInfoRPCOps import net.corda.core.internal.notary.NotaryService import net.corda.core.internal.rootMessage -import net.corda.core.internal.telemetry.OpenTelemetryComponent import net.corda.core.internal.telemetry.SimpleLogTelemetryComponent import net.corda.core.internal.telemetry.TelemetryComponent import net.corda.core.internal.telemetry.TelemetryServiceImpl @@ -55,13 +54,11 @@ import net.corda.core.node.AppServiceHub import net.corda.core.node.NetworkParameters import net.corda.core.node.NodeInfo import net.corda.core.node.ServiceHub -import net.corda.core.node.ServicesForResolution import net.corda.core.node.services.ContractUpgradeService import net.corda.core.node.services.CordaService import net.corda.core.node.services.IdentityService import net.corda.core.node.services.KeyManagementService import net.corda.core.node.services.TelemetryService -import net.corda.core.node.services.TransactionVerifierService import net.corda.core.node.services.diagnostics.DiagnosticsService import net.corda.core.schemas.MappedSchema import net.corda.core.serialization.SerializationWhitelist @@ -70,7 +67,6 @@ import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.internal.AttachmentsClassLoaderCache import net.corda.core.serialization.internal.AttachmentsClassLoaderCacheImpl import net.corda.core.toFuture -import net.corda.core.transactions.LedgerTransaction import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.days import net.corda.core.utilities.millis @@ -82,8 +78,8 @@ import net.corda.node.internal.checkpoints.FlowManagerRPCOpsImpl import net.corda.node.internal.classloading.requireAnnotation import net.corda.node.internal.cordapp.CordappConfigFileProvider import net.corda.node.internal.cordapp.CordappProviderImpl -import net.corda.node.internal.cordapp.CordappProviderInternal import net.corda.node.internal.cordapp.JarScanningCordappLoader +import net.corda.node.internal.cordapp.JarScanningCordappLoader.Companion.LEGACY_CONTRACTS_DIR_NAME import net.corda.node.internal.cordapp.VirtualCordapp import net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy import net.corda.node.internal.rpc.proxies.ThreadContextAdjustingRpcOpsProxy @@ -122,10 +118,10 @@ import net.corda.node.services.network.PersistentNetworkMapCache import net.corda.node.services.network.PersistentPartyInfoCache import net.corda.node.services.persistence.AbstractPartyDescriptor import net.corda.node.services.persistence.AbstractPartyToX500NameAsStringConverter +import net.corda.node.services.persistence.AesDbEncryptionService import net.corda.node.services.persistence.AttachmentStorageInternal import net.corda.node.services.persistence.DBCheckpointPerformanceRecorder import net.corda.node.services.persistence.DBCheckpointStorage -import net.corda.node.services.persistence.AesDbEncryptionService import net.corda.node.services.persistence.DBTransactionMappingStorage import net.corda.node.services.persistence.DBTransactionStorageLedgerRecovery import net.corda.node.services.persistence.NodeAttachmentService @@ -141,22 +137,24 @@ import net.corda.node.services.statemachine.FlowOperator import net.corda.node.services.statemachine.FlowStateMachineImpl import net.corda.node.services.statemachine.SingleThreadedStateMachineManager import net.corda.node.services.statemachine.StateMachineManager -import net.corda.node.services.transactions.InMemoryTransactionVerifierService import net.corda.node.services.upgrade.ContractUpgradeServiceImpl import net.corda.node.services.vault.NodeVaultService import net.corda.node.utilities.AffinityExecutor import net.corda.node.utilities.BindableNamedCacheFactory import net.corda.node.utilities.NamedThreadFactory import net.corda.node.utilities.NotaryLoader +import net.corda.node.verification.ExternalVerifierHandleImpl import net.corda.nodeapi.internal.NodeInfoAndSigned import net.corda.nodeapi.internal.NodeStatus import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.cordapp.CordappLoader +import net.corda.nodeapi.internal.cordapp.cordappSchemas import net.corda.nodeapi.internal.cryptoservice.CryptoService -import net.corda.nodeapi.internal.cryptoservice.bouncycastle.BCCryptoService +import net.corda.nodeapi.internal.cryptoservice.DefaultCryptoService import net.corda.nodeapi.internal.lifecycle.NodeLifecycleEvent import net.corda.nodeapi.internal.lifecycle.NodeLifecycleEventsDistributor import net.corda.nodeapi.internal.lifecycle.NodeServicesContext +import net.corda.nodeapi.internal.namedThreadPoolExecutor import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.CordaTransactionSupportImpl import net.corda.nodeapi.internal.persistence.CouldNotCreateDataSourceException @@ -169,7 +167,7 @@ import net.corda.nodeapi.internal.persistence.RestrictedEntityManager import net.corda.nodeapi.internal.persistence.SchemaMigration import net.corda.nodeapi.internal.persistence.contextDatabase import net.corda.nodeapi.internal.persistence.withoutDatabaseAccess -import net.corda.nodeapi.internal.namedThreadPoolExecutor +import net.corda.nodeapi.internal.telemetry.OpenTelemetryComponent import org.apache.activemq.artemis.utils.ReusableLatch import org.jolokia.jvmagent.JolokiaServer import org.jolokia.jvmagent.JolokiaServerConfig @@ -181,7 +179,6 @@ import java.sql.Savepoint import java.time.Clock import java.time.Duration import java.time.format.DateTimeParseException -import java.util.ArrayList import java.util.Properties import java.util.concurrent.ExecutorService import java.util.concurrent.Executors @@ -190,6 +187,8 @@ import java.util.concurrent.TimeUnit.SECONDS import java.util.function.Consumer import javax.persistence.EntityManager import javax.sql.DataSource +import kotlin.io.path.div +import kotlin.io.path.exists /** * A base node implementation that can be customised either for production (with real implementations that do real @@ -299,22 +298,11 @@ abstract class AbstractNode(val configuration: NodeConfiguration, val pkToIdCache = PublicKeyToOwningIdentityCacheImpl(database, cacheFactory) @Suppress("LeakingThis") val keyManagementService = makeKeyManagementService(identityService).tokenize() - val servicesForResolution = ServicesForResolutionImpl(identityService, attachments, cordappProvider, networkParametersStorage, transactionStorage).also { - attachments.servicesForResolution = it - } - @Suppress("LeakingThis") - val vaultService = makeVaultService(keyManagementService, servicesForResolution, database, cordappLoader).tokenize() val nodeProperties = NodePropertiesPersistentStore(StubbedNodeUniqueIdProvider::value, database, cacheFactory) val flowLogicRefFactory = makeFlowLogicRefFactoryImpl() // TODO Cancelling parameters updates - if we do that, how we ensure that no one uses cancelled parameters in the transactions? val networkMapUpdater = makeNetworkMapUpdater() - @Suppress("LeakingThis") - val transactionVerifierService = InMemoryTransactionVerifierService( - numberOfWorkers = transactionVerifierWorkerCount, - cordappProvider = cordappProvider, - attachments = attachments - ).tokenize() private val attachmentsClassLoaderCache: AttachmentsClassLoaderCache = AttachmentsClassLoaderCacheImpl(cacheFactory).tokenize() val contractUpgradeService = ContractUpgradeServiceImpl(cacheFactory).tokenize() val auditService = DummyAuditService().tokenize() @@ -326,7 +314,9 @@ abstract class AbstractNode(val configuration: NodeConfiguration, log.warn("MessagingService subscription error", it) }) } - val services = ServiceHubInternalImpl().tokenize() + val services = ServiceHubImpl().tokenize() + @Suppress("LeakingThis") + val vaultService = makeVaultService(keyManagementService, database, cordappLoader).tokenize() val checkpointStorage = DBCheckpointStorage(DBCheckpointPerformanceRecorder(services.monitoringService.metrics), platformClock) @Suppress("LeakingThis") val smm = makeStateMachineManager() @@ -338,7 +328,6 @@ abstract class AbstractNode(val configuration: NodeConfiguration, private val cordappTelemetryComponents = MutableClassToInstanceMap.create() private val shutdownExecutor = Executors.newSingleThreadExecutor(DefaultThreadFactory("Shutdown")) - protected abstract val transactionVerifierWorkerCount: Int /** * Should be [rx.schedulers.Schedulers.io] for production, * or [rx.internal.schedulers.CachedThreadScheduler] (with shutdown registered with [runOnStop]) for shared-JVM testing. @@ -351,7 +340,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, * Completes once the node has successfully registered with the network map service * or has loaded network map data from local database. */ - val nodeReadyFuture: CordaFuture get() = networkMapCache.nodeReady.map { Unit } + val nodeReadyFuture: CordaFuture<*> get() = networkMapCache.nodeReady open val serializationWhitelists: List by lazy { cordappLoader.cordapps.flatMap { it.serializationWhitelists } @@ -469,8 +458,8 @@ abstract class AbstractNode(val configuration: NodeConfiguration, Node.printBasicNodeInfo("Running database schema migration scripts ...") val props = configuration.dataSourceProperties if (props.isEmpty) throw DatabaseConfigurationException("There must be a database configured.") - var pendingAppChanges: Int = 0 - var pendingCoreChanges: Int = 0 + var pendingAppChanges = 0 + var pendingCoreChanges = 0 database.startHikariPool(props, metricRegistry) { dataSource, haveCheckpoints -> val schemaMigration = SchemaMigration(dataSource, cordappLoader, configuration.networkParametersPath, configuration.myLegalName) if(updateCoreSchemas) { @@ -496,6 +485,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, "Node's platform version is lower than network's required minimumPlatformVersion" } networkMapCache.start(netParams.notaries) + services.networkParameters = netParams database.transaction { networkParametersStorage.setCurrentParameters(signedNetParams, trustRoots) @@ -505,13 +495,13 @@ abstract class AbstractNode(val configuration: NodeConfiguration, val updatedSchemas = listOfNotNull( ("core").takeIf { updateCoreSchemas }, ("app").takeIf { updateAppSchemas } - ).joinToString(separator = " and "); + ).joinToString(separator = " and ") val pendingChanges = listOfNotNull( ("no outstanding").takeIf { pendingAppChanges == 0 && pendingCoreChanges == 0 }, ("$pendingCoreChanges outstanding core").takeIf { !updateCoreSchemas && pendingCoreChanges > 0 }, ("$pendingAppChanges outstanding app").takeIf { !updateAppSchemas && pendingAppChanges > 0 } - ).joinToString(prefix = "There are ", postfix = " database changes."); + ).joinToString(prefix = "There are ", postfix = " database changes.") Node.printBasicNodeInfo("Database migration scripts for $updatedSchemas schemas complete. $pendingChanges") } @@ -832,7 +822,6 @@ abstract class AbstractNode(val configuration: NodeConfiguration, networkMapCache, NodeInfoWatcher( configuration.baseDirectory, - @Suppress("LeakingThis") rxIoScheduler, Duration.ofMillis(configuration.additionalNodeInfoPollingFrequencyMsec) ), @@ -846,7 +835,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, platformClock, database, flowStarter, - servicesForResolution, + services, flowLogicRefFactory, nodeProperties, configuration.drainingModePollPeriod, @@ -866,6 +855,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, } return JarScanningCordappLoader.fromDirectories( configuration.cordappDirectories, + (configuration.baseDirectory / LEGACY_CONTRACTS_DIR_NAME).takeIf { it.exists() }, versionInfo, extraCordapps = generatedCordapps, signerKeyFingerprintBlacklist = blacklistedKeys @@ -1071,7 +1061,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, } protected open fun makeCryptoService(): CryptoService { - return BCCryptoService(configuration.myLegalName.x500Principal, configuration.signingCertificateStore) + return DefaultCryptoService(configuration.myLegalName.x500Principal, configuration.signingCertificateStore) } @VisibleForTesting @@ -1160,15 +1150,11 @@ abstract class AbstractNode(val configuration: NodeConfiguration, networkParameters: NetworkParameters) protected open fun makeVaultService(keyManagementService: KeyManagementService, - services: NodeServicesForResolution, database: CordaPersistence, cordappLoader: CordappLoader): VaultServiceInternal { return NodeVaultService(platformClock, keyManagementService, services, database, schemaService, cordappLoader.appClassLoader) } - // JDK 11: switch to directly instantiating jolokia server (rather than indirectly via dynamically self attaching Java Agents, - // which is no longer supported from JDK 9 onwards (https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8180425). - // No longer need to use https://github.com/electronicarts/ea-agent-loader either (which is also deprecated) private fun initialiseJolokia() { configuration.jmxMonitoringHttpPort?.let { port -> val config = JolokiaServerConfig(mapOf("port" to port.toString())) @@ -1178,9 +1164,10 @@ abstract class AbstractNode(val configuration: NodeConfiguration, } } - inner class ServiceHubInternalImpl : SingletonSerializeAsToken(), ServiceHubInternal, ServicesForResolution by servicesForResolution, NetworkParameterUpdateListener { + inner class ServiceHubImpl : SingletonSerializeAsToken(), ServiceHubInternal, NetworkParameterUpdateListener { override val rpcFlows = ArrayList>>() override val stateMachineRecordedTransactionMapping = DBTransactionMappingStorage(database) + override val externalVerifierHandle = ExternalVerifierHandleImpl(this, configuration.baseDirectory).also { runOnStop += it::close } override val identityService: IdentityService get() = this@AbstractNode.identityService override val keyManagementService: KeyManagementService get() = this@AbstractNode.keyManagementService override val schemaService: SchemaService get() = this@AbstractNode.schemaService @@ -1191,7 +1178,6 @@ abstract class AbstractNode(val configuration: NodeConfiguration, override val nodeProperties: NodePropertiesStore get() = this@AbstractNode.nodeProperties override val database: CordaPersistence get() = this@AbstractNode.database override val monitoringService: MonitoringService get() = this@AbstractNode.monitoringService - override val transactionVerifierService: TransactionVerifierService get() = this@AbstractNode.transactionVerifierService override val contractUpgradeService: ContractUpgradeService get() = this@AbstractNode.contractUpgradeService override val auditService: AuditService get() = this@AbstractNode.auditService override val attachments: AttachmentStorageInternal get() = this@AbstractNode.attachments @@ -1213,12 +1199,15 @@ abstract class AbstractNode(val configuration: NodeConfiguration, override val attachmentsClassLoaderCache: AttachmentsClassLoaderCache get() = this@AbstractNode.attachmentsClassLoaderCache @Volatile - private lateinit var _networkParameters: NetworkParameters - override val networkParameters: NetworkParameters get() = _networkParameters + override lateinit var networkParameters: NetworkParameters + + init { + this@AbstractNode.attachments.nodeVerificationSupport = this + } fun start(myInfo: NodeInfo, networkParameters: NetworkParameters) { this._myInfo = myInfo - this._networkParameters = networkParameters + this.networkParameters = networkParameters } override fun cordaService(type: Class): T { @@ -1241,7 +1230,6 @@ abstract class AbstractNode(val configuration: NodeConfiguration, */ override fun jdbcSession(): Connection = RestrictedConnection(database.createSession(), services) - @Suppress("TooGenericExceptionCaught") override fun withEntityManager(block: EntityManager.() -> T): T { return database.transaction(useErrorHandler = false) { session.flush() @@ -1300,12 +1288,8 @@ abstract class AbstractNode(val configuration: NodeConfiguration, this@AbstractNode.runOnStop += runOnStop } - override fun specialise(ltx: LedgerTransaction): LedgerTransaction { - return servicesForResolution.specialise(ltx) - } - override fun onNewNetworkParameters(networkParameters: NetworkParameters) { - this._networkParameters = networkParameters + this.networkParameters = networkParameters } } } diff --git a/node/src/main/kotlin/net/corda/node/internal/AppServiceHubImpl.kt b/node/src/main/kotlin/net/corda/node/internal/AppServiceHubImpl.kt index 5acf706f91..041a1ec756 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AppServiceHubImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AppServiceHubImpl.kt @@ -4,13 +4,13 @@ import net.corda.core.context.InvocationContext import net.corda.core.flows.FlowLogic import net.corda.core.flows.StartableByService import net.corda.core.internal.FlowStateMachineHandle +import net.corda.core.internal.ServiceHubCoreInternal import net.corda.core.internal.concurrent.doneFuture import net.corda.core.messaging.FlowHandle import net.corda.core.messaging.FlowHandleImpl import net.corda.core.messaging.FlowProgressHandle import net.corda.core.messaging.FlowProgressHandleImpl import net.corda.core.node.AppServiceHub -import net.corda.core.node.ServiceHub import net.corda.core.node.services.ServiceLifecycleEvent import net.corda.core.node.services.ServiceLifecycleObserver import net.corda.core.node.services.vault.CordaTransactionSupport @@ -24,15 +24,16 @@ import net.corda.nodeapi.internal.lifecycle.NodeLifecycleEventsDistributor import net.corda.nodeapi.internal.lifecycle.NodeLifecycleObserver import net.corda.nodeapi.internal.lifecycle.NodeLifecycleObserver.Companion.reportSuccess import rx.Observable -import java.util.* +import java.util.Objects /** * This customizes the ServiceHub for each [net.corda.core.node.services.CordaService] that is initiating flows. */ -internal class AppServiceHubImpl(private val serviceHub: ServiceHub, private val flowStarter: FlowStarter, +internal class AppServiceHubImpl(private val serviceHub: ServiceHubCoreInternal, + private val flowStarter: FlowStarter, override val database: CordaTransactionSupport, private val nodeLifecycleEventsDistributor: NodeLifecycleEventsDistributor) - : AppServiceHub, ServiceHub by serviceHub { + : AppServiceHub, ServiceHubCoreInternal by serviceHub { companion object { diff --git a/node/src/main/kotlin/net/corda/node/internal/CheckpointVerifier.kt b/node/src/main/kotlin/net/corda/node/internal/CheckpointVerifier.kt index 052de0ab3c..c793a8904b 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CheckpointVerifier.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CheckpointVerifier.kt @@ -1,5 +1,6 @@ package net.corda.node.internal +import com.esotericsoftware.kryo.KryoException import net.corda.core.cordapp.Cordapp import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic @@ -42,13 +43,14 @@ object CheckpointVerifier { it.forEach { (_, serializedCheckpoint) -> val checkpoint = try { serializedCheckpoint.deserialize(checkpointSerializationContext) - } catch (e: ClassNotFoundException) { - val message = e.message - if (message != null) { - throw CheckpointIncompatibleException.CordappNotInstalledException(message) - } else { - throw CheckpointIncompatibleException.CannotBeDeserialisedException(e) + } catch (e: KryoException) { + if (e.cause is ClassNotFoundException) { + val message = (e.cause as ClassNotFoundException).message + if (message != null) { + throw CheckpointIncompatibleException.CordappNotInstalledException(message) + } } + throw CheckpointIncompatibleException.CannotBeDeserialisedException(e) } catch (e: Exception) { throw CheckpointIncompatibleException.CannotBeDeserialisedException(e) } diff --git a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt index 3612abbf2d..290e2e1b41 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt @@ -138,18 +138,18 @@ internal class CordaRPCOpsImpl( return services.vaultService._trackBy(criteria, paging, sorting, contractStateType) } - @Suppress("OverridingDeprecatedMember", "DEPRECATION") + @Suppress("OVERRIDE_DEPRECATION", "OverridingDeprecatedMember", "DEPRECATION") override fun internalVerifiedTransactionsSnapshot(): List { val (snapshot, updates) = internalVerifiedTransactionsFeed() updates.notUsed() return snapshot } - @Suppress("OverridingDeprecatedMember") + @Suppress("OVERRIDE_DEPRECATION") override fun internalFindVerifiedTransaction(txnId: SecureHash): SignedTransaction? = services.validatedTransactions.getTransaction(txnId) - @Suppress("OverridingDeprecatedMember") + @Suppress("OVERRIDE_DEPRECATION") override fun internalVerifiedTransactionsFeed(): DataFeed, SignedTransaction> { return services.validatedTransactions.track() } diff --git a/node/src/main/kotlin/net/corda/node/internal/DataSourceFactory.kt b/node/src/main/kotlin/net/corda/node/internal/DataSourceFactory.kt index 1f5bf5d966..e55be29918 100644 --- a/node/src/main/kotlin/net/corda/node/internal/DataSourceFactory.kt +++ b/node/src/main/kotlin/net/corda/node/internal/DataSourceFactory.kt @@ -4,11 +4,8 @@ import com.codahale.metrics.MetricRegistry import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import com.zaxxer.hikari.util.PropertyElf -import net.corda.core.internal.declaredField -import org.h2.engine.Database import org.h2.engine.Engine import org.slf4j.LoggerFactory -import java.lang.reflect.Modifier import java.util.* import javax.sql.DataSource @@ -27,10 +24,6 @@ object DataSourceFactory { init { LoggerFactory.getLogger(javaClass).debug("Applying H2 fix.") // See CORDA-924. - Engine::class.java.getDeclaredField("DATABASES").apply { - isAccessible = true - declaredField("modifiers").apply { value = value and Modifier.FINAL.inv() } - }.set(null, SynchronizedGetPutRemove()) } fun createDataSource(hikariProperties: Properties, pool: Boolean = true, metricRegistry: MetricRegistry? = null): DataSource { diff --git a/node/src/main/kotlin/net/corda/node/internal/KeyStoreHandler.kt b/node/src/main/kotlin/net/corda/node/internal/KeyStoreHandler.kt index 6c4225cdc0..f5ff1aa2c3 100644 --- a/node/src/main/kotlin/net/corda/node/internal/KeyStoreHandler.kt +++ b/node/src/main/kotlin/net/corda/node/internal/KeyStoreHandler.kt @@ -16,7 +16,7 @@ import net.corda.nodeapi.internal.crypto.X509Utilities.DISTRIBUTED_NOTARY_KEY_AL import net.corda.nodeapi.internal.crypto.X509Utilities.NODE_IDENTITY_KEY_ALIAS import net.corda.nodeapi.internal.crypto.checkValidity import net.corda.nodeapi.internal.cryptoservice.CryptoService -import net.corda.nodeapi.internal.cryptoservice.bouncycastle.BCCryptoService +import net.corda.nodeapi.internal.cryptoservice.DefaultCryptoService import java.io.IOException import java.math.BigInteger import java.nio.file.NoSuchFileException @@ -54,8 +54,8 @@ class KeyStoreHandler(private val configuration: NodeConfiguration, private val if (configuration.devMode) { configuration.configureWithDevSSLCertificate(cryptoService, devModeKeyEntropy) // configureWithDevSSLCertificate is a devMode process that writes directly to keystore files, so - // we should re-synchronise BCCryptoService with the updated keystore file. - if (cryptoService is BCCryptoService) { + // we should re-synchronise DefaultCryptoService with the updated keystore file. + if (cryptoService is DefaultCryptoService) { cryptoService.resyncKeystore() } } diff --git a/node/src/main/kotlin/net/corda/node/internal/NetworkParametersReader.kt b/node/src/main/kotlin/net/corda/node/internal/NetworkParametersReader.kt index 9bacaeda56..505d599959 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NetworkParametersReader.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NetworkParametersReader.kt @@ -2,9 +2,6 @@ package net.corda.node.internal import net.corda.core.crypto.SecureHash import net.corda.core.internal.copyTo -import net.corda.core.internal.div -import net.corda.core.internal.exists -import net.corda.core.internal.moveTo import net.corda.core.internal.readObject import net.corda.core.node.NetworkParameters import net.corda.core.serialization.serialize @@ -15,8 +12,10 @@ import net.corda.nodeapi.internal.network.NETWORK_PARAMS_UPDATE_FILE_NAME import net.corda.nodeapi.internal.network.SignedNetworkParameters import net.corda.nodeapi.internal.network.verifiedNetworkParametersCert import java.nio.file.Path -import java.nio.file.StandardCopyOption import java.security.cert.X509Certificate +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.moveTo class NetworkParametersReader(private val trustRoots: Set, private val networkMapClient: NetworkMapClient?, @@ -80,7 +79,7 @@ class NetworkParametersReader(private val trustRoots: Set, if (signedUpdatedParameters.raw.hash != advertisedParametersHash) { throw Error.OldParamsAndUpdate() } - parametersUpdateFile.moveTo(networkParamsFile, StandardCopyOption.REPLACE_EXISTING) + parametersUpdateFile.moveTo(networkParamsFile, overwrite = true) logger.info("Scheduled update to network parameters has occurred - node now updated to these new parameters.") return signedUpdatedParameters } diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index 963095597d..502be42bf9 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -7,8 +7,8 @@ import com.github.benmanes.caffeine.cache.Caffeine import com.palominolabs.metrics.newrelic.AllEnabledMetricAttributeFilter import com.palominolabs.metrics.newrelic.NewRelicReporter import io.netty.util.NettyRuntime -import net.corda.nodeapi.internal.rpc.client.AMQPClientSerializationScheme import net.corda.cliutils.ShellConstants +import net.corda.common.logging.errorReporting.NodeDatabaseErrors import net.corda.core.concurrent.CordaFuture import net.corda.core.flows.FlowLogic import net.corda.core.identity.CordaX500Name @@ -16,9 +16,7 @@ import net.corda.core.identity.PartyAndCertificate import net.corda.core.internal.Emoji import net.corda.core.internal.concurrent.openFuture import net.corda.core.internal.concurrent.thenMatch -import net.corda.core.internal.div import net.corda.core.internal.errors.AddressBindingException -import net.corda.core.internal.getJavaUpdateVersion import net.corda.core.internal.notary.NotaryService import net.corda.core.messaging.RPCOps import net.corda.core.node.NetworkParameters @@ -36,9 +34,6 @@ import net.corda.node.internal.artemis.BrokerAddresses import net.corda.node.internal.security.RPCSecurityManager import net.corda.node.internal.security.RPCSecurityManagerImpl import net.corda.node.internal.security.RPCSecurityManagerWithAdditionalUser -import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme -import net.corda.nodeapi.internal.serialization.kryo.KRYO_CHECKPOINT_CONTEXT -import net.corda.nodeapi.internal.serialization.kryo.KryoCheckpointSerializer import net.corda.node.services.Permissions import net.corda.node.services.api.FlowStarter import net.corda.node.services.api.ServiceHubInternal @@ -65,8 +60,6 @@ import net.corda.node.utilities.DefaultNamedCacheFactory import net.corda.node.utilities.DemoClock import net.corda.node.utilities.errorAndTerminate import net.corda.nodeapi.internal.ArtemisMessagingClient -import net.corda.common.logging.errorReporting.NodeDatabaseErrors -import net.corda.node.internal.classloading.scanForCustomSerializationScheme import net.corda.nodeapi.internal.ShutdownHook import net.corda.nodeapi.internal.addShutdownHook import net.corda.nodeapi.internal.bridging.BridgeControlListener @@ -74,6 +67,10 @@ import net.corda.nodeapi.internal.config.User import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.persistence.CouldNotCreateDataSourceException import net.corda.nodeapi.internal.protonwrapper.netty.toRevocationConfig +import net.corda.nodeapi.internal.rpc.client.AMQPClientSerializationScheme +import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme +import net.corda.nodeapi.internal.serialization.kryo.KRYO_CHECKPOINT_CONTEXT +import net.corda.nodeapi.internal.serialization.kryo.KryoCheckpointSerializer import net.corda.serialization.internal.AMQP_P2P_CONTEXT import net.corda.serialization.internal.AMQP_RPC_CLIENT_CONTEXT import net.corda.serialization.internal.AMQP_RPC_SERVER_CONTEXT @@ -81,6 +78,8 @@ import net.corda.serialization.internal.AMQP_STORAGE_CONTEXT import net.corda.serialization.internal.SerializationFactoryImpl import net.corda.serialization.internal.amqp.SerializationFactoryCacheKey import net.corda.serialization.internal.amqp.SerializerFactory +import net.corda.serialization.internal.verifier.loadCustomSerializationScheme +import org.apache.commons.lang3.JavaVersion import org.apache.commons.lang3.SystemUtils import org.h2.jdbc.JdbcSQLNonTransientConnectionException import org.slf4j.Logger @@ -91,12 +90,12 @@ import java.lang.Long.max import java.lang.Long.min import java.net.BindException import java.net.InetAddress -import java.nio.file.Path import java.nio.file.Paths import java.time.Clock import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger import javax.management.ObjectName +import kotlin.io.path.div import kotlin.system.exitProcess class NodeWithInfo(val node: Node, val info: NodeInfo) { @@ -170,7 +169,7 @@ open class Node(configuration: NodeConfiguration, fun isInvalidJavaVersion(): Boolean { if (!hasMinimumJavaVersion()) { - println("You are using a version of Java that is not supported (${SystemUtils.JAVA_VERSION}). Please upgrade to the latest version of Java 8.") + println("You are using a version of Java that is not supported (${SystemUtils.JAVA_VERSION}). Please upgrade to the latest version of Java 17.") println("Corda will now exit...") return true } @@ -178,22 +177,11 @@ open class Node(configuration: NodeConfiguration, } private fun hasMinimumJavaVersion(): Boolean { - // JDK 11: review naming convention and checking of 'minUpdateVersion' and 'distributionType` (OpenJDK, Oracle, Zulu, AdoptOpenJDK, Cornetto) - return try { - if (SystemUtils.IS_JAVA_11) - return true - else { - val update = getJavaUpdateVersion(SystemUtils.JAVA_VERSION) // To filter out cases like 1.8.0_202-ea - (SystemUtils.IS_JAVA_1_8 && update >= 171) - } - } catch (e: NumberFormatException) { // custom JDKs may not have the update version (e.g. 1.8.0-adoptopenjdk) - false - } + return SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_17) } } override val log: Logger get() = staticLog - override val transactionVerifierWorkerCount: Int get() = 4 private var internalRpcMessagingClient: InternalRPCMessagingClient? = null private var rpcBroker: ArtemisBroker? = null @@ -296,7 +284,7 @@ open class Node(configuration: NodeConfiguration, printBasicNodeInfo("Advertised P2P messaging addresses", nodeInfo.addresses.joinToString()) val rpcServerConfiguration = RPCServerConfiguration.DEFAULT - rpcServerAddresses?.let { + rpcServerAddresses.let { internalRpcMessagingClient = InternalRPCMessagingClient(configuration.p2pSslOptions, it.admin, MAX_RPC_MESSAGE_SIZE, CordaX500Name.build(configuration.p2pSslOptions.keyStore.get()[X509Utilities.CORDA_CLIENT_TLS].subjectX500Principal), rpcServerConfiguration) printBasicNodeInfo("RPC connection address", it.primary.toString()) printBasicNodeInfo("RPC admin connection address", it.admin.toString()) @@ -352,22 +340,18 @@ open class Node(configuration: NodeConfiguration, ) } - private fun startLocalRpcBroker(securityManager: RPCSecurityManager): BrokerAddresses? { - return with(configuration) { - rpcOptions.address.let { - val rpcBrokerDirectory: Path = baseDirectory / "brokers" / "rpc" - with(rpcOptions) { - rpcBroker = if (useSsl) { - ArtemisRpcBroker.withSsl(configuration.p2pSslOptions, this.address, adminAddress, sslConfig!!, securityManager, MAX_RPC_MESSAGE_SIZE, - journalBufferTimeout, jmxMonitoringHttpPort != null, rpcBrokerDirectory, shouldStartLocalShell()) - } else { - ArtemisRpcBroker.withoutSsl(configuration.p2pSslOptions, this.address, adminAddress, securityManager, MAX_RPC_MESSAGE_SIZE, - journalBufferTimeout, jmxMonitoringHttpPort != null, rpcBrokerDirectory, shouldStartLocalShell()) - } - } - rpcBroker!!.addresses + private fun startLocalRpcBroker(securityManager: RPCSecurityManager): BrokerAddresses { + val rpcBrokerDirectory = configuration.baseDirectory / "brokers" / "rpc" + with(configuration.rpcOptions) { + rpcBroker = if (useSsl) { + ArtemisRpcBroker.withSsl(configuration.p2pSslOptions, this.address, adminAddress, sslConfig!!, securityManager, MAX_RPC_MESSAGE_SIZE, + journalBufferTimeout, configuration.jmxMonitoringHttpPort != null, rpcBrokerDirectory, configuration.shouldStartLocalShell()) + } else { + ArtemisRpcBroker.withoutSsl(configuration.p2pSslOptions, this.address, adminAddress, securityManager, MAX_RPC_MESSAGE_SIZE, + journalBufferTimeout, configuration.jmxMonitoringHttpPort != null, rpcBrokerDirectory, configuration.shouldStartLocalShell()) } } + return rpcBroker!!.addresses } override fun myAddresses(): List = listOf(getAdvertisedAddress()) + configuration.additionalP2PAddresses @@ -391,7 +375,7 @@ open class Node(configuration: NodeConfiguration, * machine's public IP address to be used instead by looking through the network interfaces. */ private fun tryDetectIfNotPublicHost(host: String): String? { - return if (host.toLowerCase() == "localhost") { + return if (host.lowercase() == "localhost") { log.warn("p2pAddress specified as localhost. Trying to autodetect a suitable public address to advertise in network map." + "To disable autodetect set detectPublicIp = false in the node.conf, or consider using messagingServerAddress and messagingServerExternal") val foundPublicIP = AddressUtils.tryDetectPublicIP() @@ -530,6 +514,7 @@ open class Node(configuration: NodeConfiguration, when (configuration.jmxReporterType) { JmxReporterType.JOLOKIA -> registerJolokiaReporter(metrics) JmxReporterType.NEW_RELIC -> registerNewRelicReporter(metrics) + null -> log.info("JMX Reeporter not registered") } } @@ -570,7 +555,7 @@ open class Node(configuration: NodeConfiguration, if (!initialiseSerialization) return val classloader = cordappLoader.appClassLoader val customScheme = System.getProperty("experimental.corda.customSerializationScheme")?.let { - scanForCustomSerializationScheme(it, classloader) + loadCustomSerializationScheme(it, classloader) } nodeSerializationEnv = SerializationEnvironment.with( SerializationFactoryImpl().apply { diff --git a/node/src/main/kotlin/net/corda/node/internal/NodeServicesForResolution.kt b/node/src/main/kotlin/net/corda/node/internal/NodeServicesForResolution.kt deleted file mode 100644 index 5baa528297..0000000000 --- a/node/src/main/kotlin/net/corda/node/internal/NodeServicesForResolution.kt +++ /dev/null @@ -1,15 +0,0 @@ -package net.corda.node.internal - -import net.corda.core.contracts.ContractState -import net.corda.core.contracts.StateAndRef -import net.corda.core.contracts.StateRef -import net.corda.core.contracts.TransactionResolutionException -import net.corda.core.node.ServicesForResolution -import java.util.LinkedHashSet - -interface NodeServicesForResolution : ServicesForResolution { - @Throws(TransactionResolutionException::class) - override fun loadStates(stateRefs: Set): Set> = loadStates(stateRefs, LinkedHashSet()) - - fun >> loadStates(input: Iterable, output: C): C -} diff --git a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt index 1772210e56..0f25e9c31c 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt @@ -17,13 +17,8 @@ import net.corda.core.internal.HashAgility import net.corda.core.internal.PLATFORM_VERSION import net.corda.core.internal.concurrent.thenMatch import net.corda.core.internal.cordapp.CordappImpl -import net.corda.core.internal.createDirectories -import net.corda.core.internal.div import net.corda.core.internal.errors.AddressBindingException -import net.corda.core.internal.exists -import net.corda.core.internal.isDirectory import net.corda.core.internal.location -import net.corda.core.internal.randomOrNull import net.corda.core.internal.safeSymbolicRead import net.corda.core.utilities.Try import net.corda.core.utilities.contextLogger @@ -51,8 +46,9 @@ import net.corda.node.services.config.shouldStartLocalShell import net.corda.node.utilities.registration.NodeRegistrationException import net.corda.nodeapi.internal.JVMAgentUtilities import net.corda.nodeapi.internal.addShutdownHook -import net.corda.nodeapi.internal.persistence.CouldNotCreateDataSourceException import net.corda.nodeapi.internal.persistence.DatabaseIncompatibleException +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.core.LoggerContext import org.fusesource.jansi.Ansi import org.slf4j.bridge.SLF4JBridgeHandler import picocli.CommandLine.Mixin @@ -65,6 +61,10 @@ import java.nio.file.Path import java.time.DayOfWeek import java.time.ZonedDateTime import java.util.function.Consumer +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.isDirectory /** An interface that can be implemented to tell the node what to do once it's intitiated. */ interface RunAfterNodeInitialisation { @@ -217,7 +217,7 @@ open class NodeStartup : NodeStartupLogging { if (requireCertificates && !canReadCertificatesDirectory(configuration.certificatesDirectory, configuration.devMode)) return ExitCodes.FAILURE // Step 7. Configuring special serialisation requirements, i.e., bft-smart relies on Java serialization. - if (attempt { banJavaSerialisation(configuration) }.doOnFailure(Consumer { error -> error.logAsUnexpected("Exception while configuring serialisation") }) !is Try.Success) return ExitCodes.FAILURE + if (attempt { banJavaSerialisation(configuration) }.doOnFailure { error -> error.logAsUnexpected("Exception while configuring serialisation") } !is Try.Success) return ExitCodes.FAILURE // Step 8. Any actions required before starting up the Corda network layer. if (attempt { preNetworkRegistration(configuration) }.doOnFailure(Consumer(::handleRegistrationError)) !is Try.Success) return ExitCodes.FAILURE @@ -278,11 +278,9 @@ open class NodeStartup : NodeStartupLogging { logger.info("Platform Version: ${versionInfo.platformVersion}") logger.info("Revision: ${versionInfo.revision}") val info = ManagementFactory.getRuntimeMXBean() - logger.info("PID: ${info.name.split("@").firstOrNull()}") // TODO Java 9 has better support for this + logger.info("PID: ${ProcessHandle.current().pid()}") logger.info("Main class: ${NodeConfiguration::class.java.location.toURI().path}") logger.info("CommandLine Args: ${info.inputArguments.joinToString(" ")}") - // JDK 11 (bootclasspath no longer supported from JDK 9) - if (info.isBootClassPathSupported) logger.info("bootclasspath: ${info.bootClassPath}") logger.info("classpath: ${info.classPath}") logger.info("VM ${info.vmName} ${info.vmVendor} ${info.vmVersion}") logger.info("Machine: ${lookupMachineNameAndMaybeWarn()}") @@ -472,7 +470,6 @@ interface NodeStartupLogging { companion object { val logger by lazy { contextLogger() } val startupErrors = setOf(MultipleCordappsForFlowException::class, CheckpointIncompatibleException::class, AddressBindingException::class, NetworkParametersReader::class, DatabaseIncompatibleException::class) - @Suppress("TooGenericExceptionCaught") val PRINT_ERRORS_TO_STD_ERR = try { System.getProperty("net.corda.node.printErrorsToStdErr") == "true" } catch (e: NullPointerException) { @@ -515,7 +512,6 @@ interface NodeStartupLogging { when { error is ErrorCode<*> -> logger.report(error) error.isExpectedWhenStartingNode() -> error.logAsExpected() - error is CouldNotCreateDataSourceException -> error.logAsUnexpected() error is Errors.NativeIoException && error.message?.contains("Address already in use") == true -> error.logAsExpected("One of the ports required by the Corda node is already in use.") error is Errors.NativeIoException && error.message?.contains("Can't assign requested address") == true -> error.logAsExpected("Exception during node startup. Check that addresses in node config resolve correctly.") error is UnresolvedAddressException -> error.logAsExpected("Exception during node startup. Check that addresses in node config resolve correctly.") @@ -535,20 +531,21 @@ fun CliWrapperBase.initLogging(baseDirectory: Path): Boolean { System.setProperty("consoleLogLevel", specifiedLogLevel) Node.renderBasicInfoToConsole = false } + (LogManager.getContext(false) as LoggerContext).reconfigure() //Test for access to the logging path and shutdown if we are unable to reach it. val logPath = baseDirectory / NodeCliCommand.LOGS_DIRECTORY_NAME try { logPath.safeSymbolicRead().createDirectories() } catch (e: IOException) { - printError("Unable to create logging directory ${logPath.toString()}. Node will now shutdown.") + printError("Unable to create logging directory $logPath. Node will now shutdown.") return false } catch (e: SecurityException) { - printError("Current user is unable to access logging directory ${logPath.toString()}. Node will now shutdown.") + printError("Current user is unable to access logging directory $logPath. Node will now shutdown.") return false } if (!logPath.isDirectory()) { - printError("Unable to access logging directory ${logPath.toString()}. Node will now shutdown.") + printError("Unable to access logging directory $logPath. Node will now shutdown.") return false } diff --git a/node/src/main/kotlin/net/corda/node/internal/ServicesForResolutionImpl.kt b/node/src/main/kotlin/net/corda/node/internal/ServicesForResolutionImpl.kt deleted file mode 100644 index ffb21894c1..0000000000 --- a/node/src/main/kotlin/net/corda/node/internal/ServicesForResolutionImpl.kt +++ /dev/null @@ -1,85 +0,0 @@ -package net.corda.node.internal - -import net.corda.core.contracts.Attachment -import net.corda.core.contracts.AttachmentResolutionException -import net.corda.core.contracts.ContractAttachment -import net.corda.core.contracts.ContractState -import net.corda.core.contracts.StateAndRef -import net.corda.core.contracts.StateRef -import net.corda.core.contracts.TransactionResolutionException -import net.corda.core.contracts.TransactionState -import net.corda.core.cordapp.CordappProvider -import net.corda.core.crypto.SecureHash -import net.corda.core.internal.SerializedStateAndRef -import net.corda.core.internal.uncheckedCast -import net.corda.core.node.NetworkParameters -import net.corda.core.node.services.AttachmentStorage -import net.corda.core.node.services.IdentityService -import net.corda.core.node.services.NetworkParametersService -import net.corda.core.node.services.TransactionStorage -import net.corda.core.transactions.BaseTransaction -import net.corda.core.transactions.ContractUpgradeWireTransaction -import net.corda.core.transactions.NotaryChangeWireTransaction -import net.corda.core.transactions.SignedTransaction -import net.corda.core.transactions.WireTransaction -import net.corda.core.transactions.WireTransaction.Companion.resolveStateRefBinaryComponent - -data class ServicesForResolutionImpl( - override val identityService: IdentityService, - override val attachments: AttachmentStorage, - override val cordappProvider: CordappProvider, - override val networkParametersService: NetworkParametersService, - private val validatedTransactions: TransactionStorage -) : NodeServicesForResolution { - override val networkParameters: NetworkParameters get() = networkParametersService.lookup(networkParametersService.currentHash) ?: - throw IllegalArgumentException("No current parameters in network parameters storage") - - @Throws(TransactionResolutionException::class) - override fun loadState(stateRef: StateRef): TransactionState<*> { - return toBaseTransaction(stateRef.txhash).outputs[stateRef.index] - } - - override fun >> loadStates(input: Iterable, output: C): C { - val baseTxs = HashMap() - return input.mapTo(output) { stateRef -> - val baseTx = baseTxs.computeIfAbsent(stateRef.txhash, ::toBaseTransaction) - StateAndRef(uncheckedCast(baseTx.outputs[stateRef.index]), stateRef) - } - } - - @Throws(TransactionResolutionException::class, AttachmentResolutionException::class) - override fun loadContractAttachment(stateRef: StateRef): Attachment { - // We may need to recursively chase transactions if there are notary changes. - fun inner(stateRef: StateRef, forContractClassName: String?): Attachment { - val ctx = getSignedTransaction(stateRef.txhash).coreTransaction - when (ctx) { - is WireTransaction -> { - val transactionState = ctx.outRef(stateRef.index).state - for (attachmentId in ctx.attachments) { - val attachment = attachments.openAttachment(attachmentId) - if (attachment is ContractAttachment && (forContractClassName ?: transactionState.contract) in attachment.allContracts) { - return attachment - } - } - throw AttachmentResolutionException(stateRef.txhash) - } - is ContractUpgradeWireTransaction -> { - return attachments.openAttachment(ctx.upgradedContractAttachmentId) ?: throw AttachmentResolutionException(stateRef.txhash) - } - is NotaryChangeWireTransaction -> { - val transactionState = SerializedStateAndRef(resolveStateRefBinaryComponent(stateRef, this)!!, stateRef).toStateAndRef().state - // TODO: check only one (or until one is resolved successfully), max recursive invocations check? - return ctx.inputs.map { inner(it, transactionState.contract) }.firstOrNull() ?: throw AttachmentResolutionException(stateRef.txhash) - } - else -> throw UnsupportedOperationException("Attempting to resolve attachment for index ${stateRef.index} of a ${ctx.javaClass} transaction. This is not supported.") - } - } - return inner(stateRef, null) - } - - private fun toBaseTransaction(txhash: SecureHash): BaseTransaction = getSignedTransaction(txhash).resolveBaseTransaction(this) - - private fun getSignedTransaction(txhash: SecureHash): SignedTransaction { - return validatedTransactions.getTransaction(txhash) ?: throw TransactionResolutionException(txhash) - } -} diff --git a/node/src/main/kotlin/net/corda/node/internal/artemis/BrokerJaasLoginModule.kt b/node/src/main/kotlin/net/corda/node/internal/artemis/BrokerJaasLoginModule.kt index 4038a0f2ef..f0b289d068 100644 --- a/node/src/main/kotlin/net/corda/node/internal/artemis/BrokerJaasLoginModule.kt +++ b/node/src/main/kotlin/net/corda/node/internal/artemis/BrokerJaasLoginModule.kt @@ -127,7 +127,7 @@ class BrokerJaasLoginModule : BaseBrokerJaasLoginModule() { ArtemisMessagingComponent.NODE_P2P_USER -> { requireTls(certificates) CertificateChainCheckPolicy.LeafMustMatch.createCheck(nodeJaasConfig.keyStore, nodeJaasConfig.trustStore).checkCertificateChain(certificates) - Pair(certificates.first().subjectDN.name, listOf(RolePrincipal(NODE_P2P_ROLE))) + Pair(certificates.first().getSubjectX500Principal().name, listOf(RolePrincipal(NODE_P2P_ROLE))) } ArtemisMessagingComponent.NODE_RPC_USER -> { requireTls(certificates) @@ -141,7 +141,7 @@ class BrokerJaasLoginModule : BaseBrokerJaasLoginModule() { CertificateChainCheckPolicy.RootMustMatch .createCheck(p2pJaasConfig.keyStore, p2pJaasConfig.trustStore) .checkCertificateChain(certificates) - Pair(certificates.first().subjectDN.name, listOf(RolePrincipal(PEER_ROLE))) + Pair(certificates.first().getSubjectX500Principal().name, listOf(RolePrincipal(PEER_ROLE))) } else -> { requireNotNull(rpcJaasConfig) { "Attempted to connect as an rpc user to the P2P broker." } diff --git a/node/src/main/kotlin/net/corda/node/internal/artemis/CertificateChainCheckPolicy.kt b/node/src/main/kotlin/net/corda/node/internal/artemis/CertificateChainCheckPolicy.kt index 6a4a77f071..baa10af3ea 100644 --- a/node/src/main/kotlin/net/corda/node/internal/artemis/CertificateChainCheckPolicy.kt +++ b/node/src/main/kotlin/net/corda/node/internal/artemis/CertificateChainCheckPolicy.kt @@ -79,7 +79,7 @@ sealed class CertificateChainCheckPolicy { class UsernameMustMatchCommonNameCheck : Check { lateinit var username: String override fun checkCertificateChain(theirChain: Array) { - if (!theirChain.any { certificate -> CordaX500Name.parse(certificate.subjectDN.name).commonName == username }) { + if (!theirChain.any { certificate -> CordaX500Name.parse(certificate.getSubjectX500Principal().name).commonName == username }) { throw CertificateException("Client certificate does not match login username.") } } diff --git a/node/src/main/kotlin/net/corda/node/internal/artemis/UserValidationPlugin.kt b/node/src/main/kotlin/net/corda/node/internal/artemis/UserValidationPlugin.kt index 963f5169a6..3355a32097 100644 --- a/node/src/main/kotlin/net/corda/node/internal/artemis/UserValidationPlugin.kt +++ b/node/src/main/kotlin/net/corda/node/internal/artemis/UserValidationPlugin.kt @@ -1,5 +1,6 @@ package net.corda.node.internal.artemis +import net.corda.core.internal.isEquivalentTo import net.corda.core.utilities.contextLogger import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.PEER_USER import org.apache.activemq.artemis.api.core.ActiveMQSecurityException @@ -8,6 +9,7 @@ import org.apache.activemq.artemis.core.server.ServerSession import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerPlugin import org.apache.activemq.artemis.core.transaction.Transaction import org.apache.activemq.artemis.protocol.amqp.broker.AMQPMessage +import javax.security.auth.x500.X500Principal /** * Plugin to verify the user in the AMQP message header against the user in the authenticated session. @@ -32,7 +34,7 @@ class UserValidationPlugin : ActiveMQServerPlugin { throw ActiveMQSecurityException("Invalid message type: expected [${AMQPMessage::class.java.name}], got [${message.javaClass.name}]") } val user = message.getStringProperty(Message.HDR_VALIDATED_USER) - if (user != null && user != session.validatedUser) { + if (user != null && !X500Principal(user).isEquivalentTo(X500Principal(session.validatedUser))) { throw ActiveMQSecurityException("_AMQ_VALIDATED_USER mismatch: expected [${session.validatedUser}], got [${user}]") } } diff --git a/node/src/main/kotlin/net/corda/node/internal/classloading/Utils.kt b/node/src/main/kotlin/net/corda/node/internal/classloading/Utils.kt index bb49eeb179..958e879981 100644 --- a/node/src/main/kotlin/net/corda/node/internal/classloading/Utils.kt +++ b/node/src/main/kotlin/net/corda/node/internal/classloading/Utils.kt @@ -2,31 +2,6 @@ package net.corda.node.internal.classloading -import net.corda.core.serialization.CustomSerializationScheme -import net.corda.node.internal.ConfigurationException -import net.corda.nodeapi.internal.serialization.CustomSerializationSchemeAdapter -import net.corda.serialization.internal.SerializationScheme -import java.lang.reflect.Constructor - inline fun Class<*>.requireAnnotation(): A { return requireNotNull(getDeclaredAnnotation(A::class.java)) { "$name needs to be annotated with ${A::class.java.name}" } } - -fun scanForCustomSerializationScheme(className: String, classLoader: ClassLoader) : SerializationScheme { - val schemaClass = try { - Class.forName(className, false, classLoader) - } catch (exception: ClassNotFoundException) { - throw ConfigurationException("$className was declared as a custom serialization scheme but could not be found.") - } - val constructor = validateScheme(schemaClass, className) - return CustomSerializationSchemeAdapter(constructor.newInstance() as CustomSerializationScheme) -} - -private fun validateScheme(clazz: Class<*>, className: String): Constructor<*> { - if (!clazz.interfaces.contains(CustomSerializationScheme::class.java)) { - throw ConfigurationException("$className was declared as a custom serialization scheme but does not implement" + - " ${CustomSerializationScheme::class.java.canonicalName}") - } - return clazz.constructors.singleOrNull { it.parameters.isEmpty() } ?: throw ConfigurationException("$className was declared as a " + - "custom serialization scheme but does not have a no argument constructor.") -} \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappConfigFileProvider.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappConfigFileProvider.kt index 5a6e8377b6..e34ca20ba4 100644 --- a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappConfigFileProvider.kt +++ b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappConfigFileProvider.kt @@ -2,12 +2,12 @@ package net.corda.node.internal.cordapp import com.typesafe.config.Config import com.typesafe.config.ConfigFactory -import net.corda.core.internal.createDirectories -import net.corda.core.internal.div -import net.corda.core.internal.exists import net.corda.core.internal.noneOrSingle import net.corda.core.utilities.contextLogger import java.nio.file.Path +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.exists class CordappConfigFileProvider(cordappDirectories: List) : CordappConfigProvider { companion object { diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderImpl.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderImpl.kt index 79a657b0ad..60e6483074 100644 --- a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderImpl.kt @@ -1,42 +1,36 @@ package net.corda.node.internal.cordapp -import com.google.common.collect.HashBiMap -import net.corda.core.contracts.Attachment +import net.corda.core.contracts.ContractAttachment import net.corda.core.contracts.ContractClassName import net.corda.core.cordapp.Cordapp import net.corda.core.cordapp.CordappContext -import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER +import net.corda.core.internal.cordapp.ContractAttachmentWithLegacy import net.corda.core.internal.cordapp.CordappImpl -import net.corda.core.internal.isUploaderTrusted -import net.corda.core.node.services.AttachmentFixup +import net.corda.core.internal.cordapp.CordappProviderInternal +import net.corda.core.internal.groupByMultipleKeys +import net.corda.core.internal.verification.AttachmentFixups import net.corda.core.node.services.AttachmentId -import net.corda.core.node.services.AttachmentStorage -import net.corda.core.serialization.MissingAttachmentsException import net.corda.core.serialization.SingletonSerializeAsToken -import net.corda.core.utilities.contextLogger import net.corda.node.services.persistence.AttachmentStorageInternal import net.corda.nodeapi.internal.cordapp.CordappLoader -import java.net.JarURLConnection -import java.net.URL import java.util.concurrent.ConcurrentHashMap -import java.util.jar.JarFile +import kotlin.io.path.absolutePathString +import kotlin.io.path.inputStream /** * Cordapp provider and store. For querying CorDapps for their attachment and vice versa. */ -open class CordappProviderImpl(val cordappLoader: CordappLoader, +open class CordappProviderImpl(private val cordappLoader: CordappLoader, private val cordappConfigProvider: CordappConfigProvider, - private val attachmentStorage: AttachmentStorage) : SingletonSerializeAsToken(), CordappProviderInternal { - companion object { - const val COMMENT_MARKER = '#' - private val log = contextLogger() - } - + private val attachmentStorage: AttachmentStorageInternal) : SingletonSerializeAsToken(), CordappProviderInternal { private val contextCache = ConcurrentHashMap() - private val cordappAttachments = HashBiMap.create() - private val attachmentFixups = arrayListOf() + private lateinit var flowToCordapp: Map>, CordappImpl> + + override val attachmentFixups = AttachmentFixups() + + override val appClassLoader: ClassLoader get() = cordappLoader.appClassLoader /** * Current known CorDapps loaded on this node @@ -44,15 +38,11 @@ open class CordappProviderImpl(val cordappLoader: CordappLoader, override val cordapps: List get() = cordappLoader.cordapps fun start() { - cordappAttachments.putAll(loadContractsIntoAttachmentStore()) - verifyInstalledCordapps() + loadContractsIntoAttachmentStore(cordappLoader.cordapps) + loadContractsIntoAttachmentStore(cordappLoader.legacyContractCordapps) + flowToCordapp = makeFlowToCordapp() // Load the fix-ups after uploading any new contracts into attachment storage. - attachmentFixups.addAll(loadAttachmentFixups()) - } - - private fun verifyInstalledCordapps() { - // This will invoke the lazy flowCordappMap property, thus triggering the MultipleCordappsForFlow check. - cordappLoader.flowCordappMap + attachmentFixups.load(cordappLoader.appClassLoader) } override fun getAppContext(): CordappContext { @@ -68,127 +58,47 @@ open class CordappProviderImpl(val cordappLoader: CordappLoader, } override fun getContractAttachmentID(contractClassName: ContractClassName): AttachmentId? { - return getCordappForClass(contractClassName)?.let(this::getCordappAttachmentId) + return cordappLoader.cordapps.findCordapp(contractClassName) } - /** - * Gets the attachment ID of this CorDapp. Only CorDapps with contracts have an attachment ID - * - * @param cordapp The cordapp to get the attachment ID - * @return An attachment ID if it exists, otherwise nothing - */ - fun getCordappAttachmentId(cordapp: Cordapp): SecureHash? = cordappAttachments.inverse()[cordapp.jarPath] + override fun getContractAttachments(contractClassName: ContractClassName): ContractAttachmentWithLegacy? { + val currentAttachmentId = getContractAttachmentID(contractClassName) ?: return null + val legacyAttachmentId = cordappLoader.legacyContractCordapps.findCordapp(contractClassName) + return ContractAttachmentWithLegacy(getContractAttachment(currentAttachmentId), legacyAttachmentId?.let(::getContractAttachment)) + } - private fun loadContractsIntoAttachmentStore(): Map = - cordapps.filter { it.contractClassNames.isNotEmpty() }.map { cordapp -> - cordapp.jarPath.openStream().use { stream -> - try { - // This code can be reached by [MockNetwork] tests which uses [MockAttachmentStorage] - // [MockAttachmentStorage] cannot implement [AttachmentStorageInternal] because - // doing so results in internal functions being exposed in the public API. - if (attachmentStorage is AttachmentStorageInternal) { - attachmentStorage.privilegedImportAttachment( - stream, - DEPLOYED_CORDAPP_UPLOADER, - cordapp.info.shortName - ) - } else { - attachmentStorage.importAttachment( - stream, - DEPLOYED_CORDAPP_UPLOADER, - cordapp.info.shortName - ) - } - } catch (faee: java.nio.file.FileAlreadyExistsException) { - AttachmentId.create(faee.message!!) - } - } to cordapp.jarPath - }.toMap() + private fun List.findCordapp(contractClassName: ContractClassName): AttachmentId? { + // loadContractsIntoAttachmentStore makes sure the jarHash is the attachment ID + return find { contractClassName in it.contractClassNames }?.jarHash + } - /** - * Loads the "fixup" rules from all META-INF/Corda-Fixups files. - * These files have the following format: - * ,...=>,,... - * where each is the SHA256 of a CorDapp JAR that - * [net.corda.core.transactions.TransactionBuilder] will expect to find - * inside [AttachmentStorage]. - * - * These rules are for repairing broken CorDapps. A correctly written - * CorDapp should not require them. - */ - private fun loadAttachmentFixups(): List { - return cordappLoader.appClassLoader.getResources("META-INF/Corda-Fixups").asSequence() - .mapNotNull { fixup -> - fixup.openConnection() as? JarURLConnection - }.filter { fixupConnection -> - isValidFixup(fixupConnection.jarFile) - }.flatMapTo(ArrayList()) { fixupConnection -> - fixupConnection.inputStream.bufferedReader().useLines { lines -> - lines.map { it.substringBefore(COMMENT_MARKER) }.map(String::trim).filterNot(String::isEmpty).map { line -> - val tokens = line.split("=>") - require(tokens.size == 2) { - "Invalid fix-up line '$line' in '${fixupConnection.jarFile.name}'" - } - val source = parseIds(tokens[0]) - require(source.isNotEmpty()) { - "Forbidden empty list of source attachment IDs in '${fixupConnection.jarFile.name}'" - } - val target = parseIds(tokens[1]) - Pair(source, target) - }.toList().asSequence() - } + private fun loadContractsIntoAttachmentStore(cordapps: List) { + for (cordapp in cordapps) { + if (cordapp.contractClassNames.isEmpty()) continue + val attachmentId = cordapp.jarFile.inputStream().use { stream -> + attachmentStorage.privilegedImportOrGetAttachment(stream, DEPLOYED_CORDAPP_UPLOADER, cordapp.info.shortName) } - } - - private fun isValidFixup(jarFile: JarFile): Boolean { - return jarFile.entries().asSequence().all { it.name.startsWith("META-INF/") }.also { isValid -> - if (!isValid) { - log.warn("FixUp '{}' contains files outside META-INF/ - IGNORING!", jarFile.name) + // TODO We could remove this check if we had an import method for CorDapps, since it wouldn't need to hash the InputStream. + // As it stands, we just have to double-check the hashes match, which should be the case (see NodeAttachmentService). + check(attachmentId == cordapp.jarHash) { + "Something has gone wrong. SHA-256 hash of ${cordapp.jarFile} (${cordapp.jarHash}) does not match attachment ID ($attachmentId)" } } } - private fun parseIds(ids: String): Set { - return ids.split(",").map(String::trim) - .filterNot(String::isEmpty) - .mapTo(LinkedHashSet(), SecureHash.Companion::create) + private fun getContractAttachment(id: AttachmentId): ContractAttachment { + return checkNotNull(attachmentStorage.openAttachment(id) as? ContractAttachment) { "Contract attachment $id has gone missing!" } } - /** - * Apply this node's attachment fix-up rules to the given attachment IDs. - * - * @param attachmentIds A collection of [AttachmentId]s, e.g. as provided by a transaction. - * @return The [attachmentIds] with the fix-up rules applied. - */ - override fun fixupAttachmentIds(attachmentIds: Collection): Set { - val replacementIds = LinkedHashSet(attachmentIds) - attachmentFixups.forEach { (source, target) -> - if (replacementIds.containsAll(source)) { - replacementIds.removeAll(source) - replacementIds.addAll(target) - } + private fun makeFlowToCordapp(): Map>, CordappImpl> { + return cordappLoader.cordapps.groupByMultipleKeys(CordappImpl::allFlows) { flowClass, _, _ -> + val overlappingCordapps = cordappLoader.cordapps.filter { flowClass in it.allFlows } + throw MultipleCordappsForFlowException("There are multiple CorDapp JARs on the classpath for flow ${flowClass.name}: " + + "[ ${overlappingCordapps.joinToString { it.jarPath.toString() }} ].", + flowClass.name, + overlappingCordapps.joinToString { it.jarFile.absolutePathString() } + ) } - return replacementIds - } - - /** - * Apply this node's attachment fix-up rules to the given attachments. - * - * @param attachments A collection of [Attachment] objects, e.g. as provided by a transaction. - * @return The [attachments] with the node's fix-up rules applied. - */ - override fun fixupAttachments(attachments: Collection): Collection { - val attachmentsById = attachments.associateByTo(LinkedHashMap(), Attachment::id) - val replacementIds = fixupAttachmentIds(attachmentsById.keys) - attachmentsById.keys.retainAll(replacementIds) - (replacementIds - attachmentsById.keys).forEach { extraId -> - val extraAttachment = attachmentStorage.openAttachment(extraId) - if (extraAttachment == null || !extraAttachment.isUploaderTrusted()) { - throw MissingAttachmentsException(listOf(extraId)) - } - attachmentsById[extraId] = extraAttachment - } - return attachmentsById.values } /** @@ -201,7 +111,7 @@ open class CordappProviderImpl(val cordappLoader: CordappLoader, return contextCache.computeIfAbsent(cordapp) { CordappContext.create( cordapp, - getCordappAttachmentId(cordapp), + cordapp.jarHash.takeIf(attachmentStorage::hasAttachment), // Not all CorDapps are attachments cordappLoader.appClassLoader, TypesafeCordappConfig(cordappConfigProvider.getConfigByName(cordapp.name)) ) @@ -214,7 +124,7 @@ open class CordappProviderImpl(val cordappLoader: CordappLoader, * @param className The class name * @return cordapp A cordapp or null if no cordapp has the given class loaded */ - fun getCordappForClass(className: String): Cordapp? = cordapps.find { it.cordappClasses.contains(className) } + fun getCordappForClass(className: String): CordappImpl? = cordapps.find { it.cordappClasses.contains(className) } - override fun getCordappForFlow(flowLogic: FlowLogic<*>) = cordappLoader.flowCordappMap[flowLogic.javaClass] + override fun getCordappForFlow(flowLogic: FlowLogic<*>): Cordapp? = flowToCordapp[flowLogic.javaClass] } diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderInternal.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderInternal.kt deleted file mode 100644 index ed8f410bfa..0000000000 --- a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderInternal.kt +++ /dev/null @@ -1,14 +0,0 @@ -package net.corda.node.internal.cordapp - -import net.corda.core.contracts.Attachment -import net.corda.core.cordapp.Cordapp -import net.corda.core.cordapp.CordappProvider -import net.corda.core.flows.FlowLogic -import net.corda.core.internal.CordappFixupInternal -import net.corda.core.internal.cordapp.CordappImpl - -interface CordappProviderInternal : CordappProvider, CordappFixupInternal { - val cordapps: List - fun getCordappForFlow(flowLogic: FlowLogic<*>): Cordapp? - fun fixupAttachments(attachments: Collection): Collection -} diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt index ce64bd28f5..6bcdf1d577 100644 --- a/node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt +++ b/node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt @@ -2,6 +2,7 @@ package net.corda.node.internal.cordapp import io.github.classgraph.ClassGraph import io.github.classgraph.ClassInfo +import io.github.classgraph.ClassInfoList import io.github.classgraph.ScanResult import net.corda.common.logging.errorReporting.CordappErrors import net.corda.common.logging.errorReporting.ErrorCode @@ -9,194 +10,253 @@ import net.corda.core.CordaRuntimeException import net.corda.core.cordapp.Cordapp import net.corda.core.crypto.SecureHash import net.corda.core.crypto.sha256 -import net.corda.core.flows.* -import net.corda.core.internal.* +import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy +import net.corda.core.flows.SchedulableFlow +import net.corda.core.flows.StartableByRPC +import net.corda.core.flows.StartableByService +import net.corda.core.internal.JarSignatureCollector +import net.corda.core.internal.PlatformVersionSwitches import net.corda.core.internal.cordapp.CordappImpl import net.corda.core.internal.cordapp.CordappImpl.Companion.UNKNOWN_INFO +import net.corda.core.internal.cordapp.KotlinMetadataVersion +import net.corda.core.internal.cordapp.LanguageVersion import net.corda.core.internal.cordapp.get +import net.corda.core.internal.flatMapToSet +import net.corda.core.internal.groupByMultipleKeys +import net.corda.core.internal.hash +import net.corda.core.internal.isAbstractClass +import net.corda.core.internal.loadClassOfType +import net.corda.core.internal.location +import net.corda.core.internal.mapToSet import net.corda.core.internal.notary.NotaryService import net.corda.core.internal.notary.SinglePartyNotaryService -import net.corda.core.node.services.CordaService +import net.corda.core.internal.objectOrNewInstance +import net.corda.core.internal.pooledScan import net.corda.core.internal.telemetry.TelemetryComponent +import net.corda.core.internal.toPath +import net.corda.core.internal.toTypedArray +import net.corda.core.internal.warnContractWithoutConstraintPropagation +import net.corda.core.node.services.CordaService import net.corda.core.schemas.MappedSchema import net.corda.core.serialization.CheckpointCustomSerializer import net.corda.core.serialization.SerializationCustomSerializer import net.corda.core.serialization.SerializationWhitelist import net.corda.core.serialization.SerializeAsToken import net.corda.core.utilities.contextLogger +import net.corda.core.utilities.debug +import net.corda.core.utilities.trace import net.corda.node.VersionInfo import net.corda.nodeapi.internal.cordapp.CordappLoader import net.corda.nodeapi.internal.coreContractClasses import net.corda.serialization.internal.DefaultWhitelist import java.lang.reflect.Modifier -import java.math.BigInteger -import java.net.URL import java.net.URLClassLoader import java.nio.file.Path -import java.util.* -import java.util.concurrent.ConcurrentHashMap +import java.util.ServiceLoader +import java.util.TreeSet import java.util.jar.JarInputStream import java.util.jar.Manifest -import java.util.zip.ZipInputStream -import kotlin.collections.LinkedHashSet +import kotlin.io.path.absolutePathString +import kotlin.io.path.exists +import kotlin.io.path.inputStream +import kotlin.io.path.isSameFileAs +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.useDirectoryEntries import kotlin.reflect.KClass -import kotlin.streams.toList +import kotlin.reflect.KProperty1 /** * Handles CorDapp loading and classpath scanning of CorDapp JARs * - * @property cordappJarPaths The classpath of cordapp JARs + * @property cordappJars The classpath of cordapp JARs + * @property legacyContractJars Legacy contract CorDapps (4.11 or earlier) needed for backwards compatibility with 4.11 nodes. */ -class JarScanningCordappLoader private constructor(private val cordappJarPaths: List, - private val versionInfo: VersionInfo = VersionInfo.UNKNOWN, - extraCordapps: List, - private val signerKeyFingerprintBlacklist: List = emptyList()) : CordappLoaderTemplate() { - init { - if (cordappJarPaths.isEmpty()) { - logger.info("No CorDapp paths provided") - } else { - logger.info("Loading CorDapps from ${cordappJarPaths.joinToString()}") - } - } - private val cordappClasses: ConcurrentHashMap> = ConcurrentHashMap() - override val cordapps: List by lazy { loadCordapps() + extraCordapps } - - override val appClassLoader: URLClassLoader = URLClassLoader(cordappJarPaths.stream().map { it.url }.toTypedArray(), javaClass.classLoader) - - override fun close() = appClassLoader.close() - +@Suppress("TooManyFunctions") +class JarScanningCordappLoader(private val cordappJars: Set, + private val legacyContractJars: Set = emptySet(), + private val versionInfo: VersionInfo = VersionInfo.UNKNOWN, + private val extraCordapps: List = emptyList(), + private val signerKeyFingerprintBlacklist: List = emptyList()) : CordappLoader { companion object { private val logger = contextLogger() + const val LEGACY_CONTRACTS_DIR_NAME = "legacy-contracts" + /** * Creates a CordappLoader from multiple directories. * * @param cordappDirs Directories used to scan for CorDapp JARs. + * @param legacyContractsDir Directory containing legacy contract CorDapps (4.11 or earlier). */ fun fromDirectories(cordappDirs: Collection, + legacyContractsDir: Path? = null, versionInfo: VersionInfo = VersionInfo.UNKNOWN, extraCordapps: List = emptyList(), signerKeyFingerprintBlacklist: List = emptyList()): JarScanningCordappLoader { - logger.info("Looking for CorDapps in ${cordappDirs.distinct().joinToString(", ", "[", "]")}") - val paths = cordappDirs.distinct().flatMap(this::jarUrlsInDirectory).map { it.restricted() } - return JarScanningCordappLoader(paths, versionInfo, extraCordapps, signerKeyFingerprintBlacklist) - } - - /** - * Creates a CordappLoader loader out of a list of JAR URLs. - * - * @param scanJars Uses the JAR URLs provided for classpath scanning and Cordapp detection. - */ - fun fromJarUrls(scanJars: List, versionInfo: VersionInfo = VersionInfo.UNKNOWN, extraCordapps: List = emptyList(), - cordappsSignerKeyFingerprintBlacklist: List = emptyList()): JarScanningCordappLoader { - val paths = scanJars.map { it.restricted() } - return JarScanningCordappLoader(paths, versionInfo, extraCordapps, cordappsSignerKeyFingerprintBlacklist) - } - - private fun URL.restricted(rootPackageName: String? = null) = RestrictedURL(this, rootPackageName) - - private fun jarUrlsInDirectory(directory: Path): List { - return if (!directory.exists()) { - emptyList() - } else { - directory.list { paths -> - // `toFile()` can't be used here... - paths.filter { it.toString().endsWith(".jar") }.map { it.toUri().toURL() }.toList() - } - } + logger.info("Looking for CorDapps in ${cordappDirs.toSet().joinToString(", ", "[", "]")}") + val cordappJars = cordappDirs + .asSequence() + .flatMap { if (it.exists()) it.listDirectoryEntries("*.jar") else emptyList() } + .toSet() + val legacyContractJars = legacyContractsDir?.useDirectoryEntries("*.jar") { it.toSet() } ?: emptySet() + return JarScanningCordappLoader(cordappJars, legacyContractJars, versionInfo, extraCordapps, signerKeyFingerprintBlacklist) } } - private fun loadCordapps(): List { - val invalidCordapps = mutableMapOf() - - val cordapps = cordappJarPaths - .map { url -> scanCordapp(url).use { it.toCordapp(url) } } - .filter { - if (it.minimumPlatformVersion > versionInfo.platformVersion) { - logger.warn("Not loading CorDapp ${it.info.shortName} (${it.info.vendor}) as it requires minimum " + - "platform version ${it.minimumPlatformVersion} (This node is running version ${versionInfo.platformVersion}).") - invalidCordapps.put("CorDapp requires minimumPlatformVersion: ${it.minimumPlatformVersion}, but was: ${versionInfo.platformVersion}", it.jarPath) - false - } else { - true - } - } - .filter { - if (signerKeyFingerprintBlacklist.isEmpty()) { - true //Nothing blacklisted, no need to check - } else { - val certificates = it.jarPath.openStream().let(::JarInputStream).use(JarSignatureCollector::collectCertificates) - val blockedCertificates = certificates.filter { it.publicKey.hash.sha256() in signerKeyFingerprintBlacklist } - if (certificates.isEmpty() || (certificates - blockedCertificates).isNotEmpty()) - true // Cordapp is not signed or it is signed by at least one non-blacklisted certificate - else { - logger.warn("Not loading CorDapp ${it.info.shortName} (${it.info.vendor}) as it is signed by blacklisted key(s) only (probably development key): " + - "${blockedCertificates.map { it.publicKey }}.") - invalidCordapps.put("Corresponding contracts are signed by blacklisted key(s) only (probably development key),", it.jarPath) - false - } - } - } - - if (invalidCordapps.isNotEmpty()) { - throw InvalidCordappException("Invalid Cordapps found, that couldn't be loaded: " + - "${invalidCordapps.map { "Problem: ${it.key} in Cordapp ${it.value}" }}, ") - } - - cordapps.forEach(::register) - return cordapps + init { + logger.debug { "cordappJars: $cordappJars" } + logger.debug { "legacyContractJars: $legacyContractJars" } } - private fun register(cordapp: Cordapp) { - val contractClasses = cordapp.contractClassNames.toSet() - val existingClasses = cordappClasses.keys - val classesToRegister = cordapp.cordappClasses.toSet() - val notAlreadyRegisteredClasses = classesToRegister - existingClasses - val alreadyRegistered= HashMap(cordappClasses).apply { keys.retainAll(classesToRegister) } + override val appClassLoader = URLClassLoader(cordappJars.stream().map { it.toUri().toURL() }.toTypedArray(), javaClass.classLoader) - notAlreadyRegisteredClasses.forEach { cordappClasses[it] = setOf(cordapp) } + private val internal by lazy(::InternalHolder) - for ((registeredClassName, registeredCordapps) in alreadyRegistered) { - val duplicateCordapps = registeredCordapps.filter { it.jarHash == cordapp.jarHash }.toSet() + override val cordapps: List + get() = internal.nonLegacyCordapps - if (duplicateCordapps.isNotEmpty()) { - throw DuplicateCordappsInstalledException(cordapp, duplicateCordapps) + override val legacyContractCordapps: List + get() = internal.legacyContractCordapps + + override fun close() = appClassLoader.close() + + private inner class InternalHolder { + val nonLegacyCordapps = cordappJars.mapTo(ArrayList(), ::scanCordapp) + val legacyContractCordapps = legacyContractJars.map(::scanCordapp) + + init { + commonChecks(nonLegacyCordapps, LanguageVersion::isNonLegacyCompatible) + nonLegacyCordapps += extraCordapps + if (legacyContractCordapps.isNotEmpty()) { + commonChecks(legacyContractCordapps, LanguageVersion::isLegacyCompatible) + checkLegacyContracts() } - if (registeredClassName in contractClasses) { - throw IllegalStateException("More than one CorDapp installed on the node for contract $registeredClassName. " + + } + + private fun commonChecks(cordapps: List, compatibilityProperty: KProperty1) { + for (cordapp in cordapps) { + check(compatibilityProperty(cordapp.languageVersion)) { + val isLegacyCompatibleCheck = compatibilityProperty == LanguageVersion::isLegacyCompatible + val msg = when { + isLegacyCompatibleCheck -> "not legacy; please remove or place it in the node's CorDapps directory." + cordapp.contractClassNames.isEmpty() -> "legacy (should be 4.12 or later)" + else -> "legacy contracts; please place it in the node's '$LEGACY_CONTRACTS_DIR_NAME' directory." + } + "CorDapp ${cordapp.jarFile} is $msg" + } + } + checkInvalidCordapps(cordapps) + checkDuplicateCordapps(cordapps) + // The same contract may occur in both 4.11 and 4.12 CorDapps for ledger compatibility, so we only check for overlap within each + // compatibility group + checkContractOverlap(cordapps) + } + + private fun checkInvalidCordapps(cordapps: List) { + val invalidCordapps = LinkedHashMap() + + for (cordapp in cordapps) { + if (cordapp.minimumPlatformVersion > versionInfo.platformVersion) { + logger.error("Not loading CorDapp ${cordapp.info.shortName} (${cordapp.info.vendor}) as it requires minimum " + + "platform version ${cordapp.minimumPlatformVersion} (This node is running version ${versionInfo.platformVersion}).") + invalidCordapps["CorDapp requires minimumPlatformVersion ${cordapp.minimumPlatformVersion}, but this node is running version ${versionInfo.platformVersion}"] = cordapp + } + if (signerKeyFingerprintBlacklist.isNotEmpty()) { + val certificates = cordapp.jarPath.openStream().let(::JarInputStream).use(JarSignatureCollector::collectCertificates) + val blockedCertificates = certificates.filterTo(HashSet()) { it.publicKey.hash.sha256() in signerKeyFingerprintBlacklist } + if (certificates.isNotEmpty() && (certificates - blockedCertificates).isEmpty()) { + logger.error("Not loading CorDapp ${cordapp.info.shortName} (${cordapp.info.vendor}) as it is signed by blacklisted " + + "key(s) only (probably development key): ${blockedCertificates.map { it.publicKey }}.") + invalidCordapps["Corresponding contracts are signed by blacklisted key(s) only (probably development key),"] = cordapp + } + } + } + + if (invalidCordapps.isNotEmpty()) { + throw InvalidCordappException("Invalid Cordapps found, that couldn't be loaded: " + + "${invalidCordapps.map { "Problem: ${it.key} in Cordapp ${it.value.jarFile}" }}, ") + } + } + + private fun checkDuplicateCordapps(cordapps: List) { + for (group in cordapps.groupBy { it.jarHash }.values) { + if (group.size > 1) { + throw DuplicateCordappsInstalledException(group[0], group.drop(1)) + } + } + } + + private fun checkContractOverlap(cordapps: List) { + cordapps.groupByMultipleKeys(CordappImpl::contractClassNames) { contract, cordapp1, cordapp2 -> + throw IllegalStateException("Contract $contract occuring in multiple CorDapps (${cordapp1.name}, ${cordapp2.name}). " + "Please remove the previous version when upgrading to a new version.") } - cordappClasses[registeredClassName] = registeredCordapps + cordapp } + + private fun checkLegacyContracts() { + for (legacyCordapp in legacyContractCordapps) { + if (legacyCordapp.contractClassNames.isEmpty()) continue + logger.debug { "Contracts CorDapp ${legacyCordapp.name} is legacy (4.11 or older), searching for corresponding 4.12+ contracts" } + for (legacyContract in legacyCordapp.contractClassNames) { + val newerCordapp = nonLegacyCordapps.find { legacyContract in it.contractClassNames } + checkNotNull(newerCordapp) { + "Contract $legacyContract in legacy CorDapp (4.11 or older) '${legacyCordapp.jarFile}' does not have a " + + "corresponding newer version (4.12 or later). Please add this corresponding CorDapp or remove the legacy one." + } + check(newerCordapp.contractVersionId > legacyCordapp.contractVersionId) { + "Newer contract CorDapp '${newerCordapp.jarFile}' does not have a higher versionId " + + "(${newerCordapp.contractVersionId}) than corresponding legacy contract CorDapp " + + "'${legacyCordapp.jarFile}' (${legacyCordapp.contractVersionId})" + } + checkSignersMatch(legacyCordapp, newerCordapp) + } + } + } + + private fun checkSignersMatch(legacyCordapp: CordappImpl, nonLegacyCordapp: CordappImpl) { + val legacySigners = legacyCordapp.jarPath.openStream().let(::JarInputStream).use(JarSignatureCollector::collectSigners) + val nonLegacySigners = nonLegacyCordapp.jarPath.openStream().let(::JarInputStream).use(JarSignatureCollector::collectSigners) + check(legacySigners == nonLegacySigners) { + "Newer contract CorDapp '${nonLegacyCordapp.jarFile}' signers do not match legacy contract CorDapp " + + "'${legacyCordapp.jarFile}' signers." + } + } + + private val CordappImpl.contractVersionId: Int + get() = when (val info = info) { + is Cordapp.Info.Contract -> info.versionId + is Cordapp.Info.ContractAndWorkflow -> info.contract.versionId + else -> 1 + } } - private fun RestrictedScanResult.toCordapp(url: RestrictedURL): CordappImpl { - val manifest: Manifest? = url.url.openStream().use { JarInputStream(it).manifest } - val info = parseCordappInfo(manifest, CordappImpl.jarName(url.url)) + private fun ScanResult.toCordapp(path: Path): CordappImpl { + val manifest: Manifest? = JarInputStream(path.inputStream()).use { it.manifest } + val info = parseCordappInfo(manifest, CordappImpl.jarName(path)) val minPlatformVersion = manifest?.get(CordappImpl.MIN_PLATFORM_VERSION)?.toIntOrNull() ?: 1 val targetPlatformVersion = manifest?.get(CordappImpl.TARGET_PLATFORM_VERSION)?.toIntOrNull() ?: minPlatformVersion - validateContractStateClassVersion(this) - validateWhitelistClassVersion(this) + val languageVersion = determineLanguageVersion(path) + logger.debug { "$path: $languageVersion" } return CordappImpl( - findContractClassNamesWithVersionCheck(this), + path, + findContractClassNames(this), findInitiatedFlows(this), findRPCFlows(this), findServiceFlows(this), findSchedulableFlows(this), findServices(this), findTelemetryComponents(this), - findWhitelists(url), + findWhitelists(path), findSerializers(this), findCheckpointSerializers(this), findCustomSchemas(this), findAllFlows(this), - url.url, info, - getJarHash(url.url), minPlatformVersion, targetPlatformVersion, - findNotaryService(this), + languageVersion = languageVersion, + notaryService = findNotaryService(this), explicitCordappClasses = findAllCordappClasses(this) ) } @@ -265,29 +325,27 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths: return version } - private fun findNotaryService(scanResult: RestrictedScanResult): Class? { + private fun findNotaryService(scanResult: ScanResult): Class? { // Note: we search for implementations of both NotaryService and SinglePartyNotaryService as // the scanner won't find subclasses deeper down the hierarchy if any intermediate class is not // present in the CorDapp. - val result = scanResult.getClassesWithSuperclass(NotaryService::class) + - scanResult.getClassesWithSuperclass(SinglePartyNotaryService::class) + val result = scanResult.getClassesExtending(NotaryService::class) + + scanResult.getClassesExtending(SinglePartyNotaryService::class) if (result.isNotEmpty()) { logger.info("Found notary service CorDapp implementations: " + result.joinToString(", ")) } return result.firstOrNull() } - private fun getJarHash(url: URL): SecureHash.SHA256 = url.openStream().readFully().sha256() - - private fun findServices(scanResult: RestrictedScanResult): List> { + private fun findServices(scanResult: ScanResult): List> { return scanResult.getClassesWithAnnotation(SerializeAsToken::class, CordaService::class) } - private fun findTelemetryComponents(scanResult: RestrictedScanResult): List> { + private fun findTelemetryComponents(scanResult: ScanResult): List> { return scanResult.getClassesImplementing(TelemetryComponent::class) } - private fun findInitiatedFlows(scanResult: RestrictedScanResult): List>> { + private fun findInitiatedFlows(scanResult: ScanResult): List>> { return scanResult.getClassesWithAnnotation(FlowLogic::class, InitiatedBy::class) } @@ -295,76 +353,68 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths: return Modifier.isPublic(modifiers) && !isLocalClass && !isAnonymousClass && (!isMemberClass || Modifier.isStatic(modifiers)) } - private fun findRPCFlows(scanResult: RestrictedScanResult): List>> { + private fun findRPCFlows(scanResult: ScanResult): List>> { return scanResult.getClassesWithAnnotation(FlowLogic::class, StartableByRPC::class).filter { it.isUserInvokable() } } - private fun findServiceFlows(scanResult: RestrictedScanResult): List>> { + private fun findServiceFlows(scanResult: ScanResult): List>> { return scanResult.getClassesWithAnnotation(FlowLogic::class, StartableByService::class) } - private fun findSchedulableFlows(scanResult: RestrictedScanResult): List>> { + private fun findSchedulableFlows(scanResult: ScanResult): List>> { return scanResult.getClassesWithAnnotation(FlowLogic::class, SchedulableFlow::class) } - private fun findAllFlows(scanResult: RestrictedScanResult): List>> { - return scanResult.getConcreteClassesOfType(FlowLogic::class) + private fun findAllFlows(scanResult: ScanResult): List>> { + return scanResult.getClassesExtending(FlowLogic::class) } - private fun findAllCordappClasses(scanResult: RestrictedScanResult): List { - return scanResult.getAllStandardClasses() + scanResult.getAllInterfaces() + private fun findAllCordappClasses(scanResult: ScanResult): List { + val cordappClasses = ArrayList() + scanResult.allStandardClasses.mapTo(cordappClasses) { it.name } + scanResult.allInterfaces.mapTo(cordappClasses) { it.name } + return cordappClasses } - private fun findContractClassNamesWithVersionCheck(scanResult: RestrictedScanResult): List { - val contractClasses = coreContractClasses.flatMapTo(LinkedHashSet()) { scanResult.getNamesOfClassesImplementingWithClassVersionCheck(it) }.toList() + private fun findContractClassNames(scanResult: ScanResult): List { + val contractClasses = coreContractClasses.flatMapToSet(scanResult::getClassesImplementing) for (contractClass in contractClasses) { - contractClass.warnContractWithoutConstraintPropagation(appClassLoader) + contractClass.name.warnContractWithoutConstraintPropagation(appClassLoader) } - return contractClasses + return contractClasses.map { it.name } } - private fun validateContractStateClassVersion(scanResult: RestrictedScanResult) { - coreContractClasses.forEach { scanResult.versionCheckClassesImplementing(it) } - } - - private fun validateWhitelistClassVersion(scanResult: RestrictedScanResult) { - scanResult.versionCheckClassesImplementing(SerializationWhitelist::class) - } - - private fun findWhitelists(cordappJarPath: RestrictedURL): List { + private fun findWhitelists(cordappJar: Path): List { val whitelists = ServiceLoader.load(SerializationWhitelist::class.java, appClassLoader).toList() return whitelists.filter { - it.javaClass.location == cordappJarPath.url && it.javaClass.name.startsWith(cordappJarPath.qualifiedNamePrefix) + it.javaClass.location.toPath().isSameFileAs(cordappJar) } + DefaultWhitelist // Always add the DefaultWhitelist to the whitelist for an app. } - private fun findSerializers(scanResult: RestrictedScanResult): List> { - return scanResult.getClassesImplementingWithClassVersionCheck(SerializationCustomSerializer::class) + private fun findSerializers(scanResult: ScanResult): List> { + return scanResult.getClassesImplementing(SerializationCustomSerializer::class).map { it.kotlin.objectOrNewInstance() } } - private fun findCheckpointSerializers(scanResult: RestrictedScanResult): List> { - return scanResult.getClassesImplementingWithClassVersionCheck(CheckpointCustomSerializer::class) + private fun findCheckpointSerializers(scanResult: ScanResult): List> { + return scanResult.getClassesImplementing(CheckpointCustomSerializer::class).map { it.kotlin.objectOrNewInstance() } } - private fun findCustomSchemas(scanResult: RestrictedScanResult): Set { - return scanResult.getClassesWithSuperclass(MappedSchema::class).instances().toSet() + private fun findCustomSchemas(scanResult: ScanResult): Set { + return scanResult.getClassesExtending(MappedSchema::class).mapToSet { it.kotlin.objectOrNewInstance() } } - private fun scanCordapp(cordappJarPath: RestrictedURL): RestrictedScanResult { - val cordappElement = cordappJarPath.url.toString() - logger.info("Scanning CorDapp in $cordappElement") - val scanResult = ClassGraph() - .filterClasspathElementsByURL { elt -> elt == cordappJarPath.url } - .overrideClassLoaders(appClassLoader) - .ignoreParentClassLoaders() - .enableAllInfo() - .pooledScan() - return RestrictedScanResult(scanResult, cordappJarPath.qualifiedNamePrefix, cordappJarPath) + private fun scanCordapp(cordappJar: Path): CordappImpl { + logger.info("Scanning CorDapp ${cordappJar.absolutePathString()}") + return ClassGraph() + .overrideClasspath(cordappJar.absolutePathString()) + .enableAllInfo() + .pooledScan() + .use { it.toCordapp(cordappJar) } } private fun loadClass(className: String, type: KClass): Class? { return try { - Class.forName(className, false, appClassLoader).asSubclass(type.java) + loadClassOfType(type.java, className, false, appClassLoader) } catch (e: ClassCastException) { logger.warn("As $className must be a sub-type of ${type.java.name}") null @@ -374,101 +424,50 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths: } } - // TODO Remove this class as rootPackageName is never non-null. - /** @property rootPackageName only this package and subpackages may be extracted from [url], or null to allow all packages. */ - private data class RestrictedURL(val url: URL, val rootPackageName: String?) { - val qualifiedNamePrefix: String get() = rootPackageName?.let { "$it." } ?: "" + private fun ScanResult.getClassesExtending(type: KClass): List> { + return getSubclasses(type.java).getAllConcreteClasses(type) } - private fun List>.instances(): List { - return map { it.kotlin.objectOrNewInstance() } + private fun ScanResult.getClassesImplementing(type: KClass): List> { + return getClassesImplementing(type.java).getAllConcreteClasses(type) } - private inner class RestrictedScanResult(private val scanResult: ScanResult, private val qualifiedNamePrefix: String, - private val cordappJarPath: RestrictedURL) : AutoCloseable { + private fun ScanResult.getClassesWithAnnotation(type: KClass, annotation: KClass): List> { + return getClassesWithAnnotation(annotation.java).getAllConcreteClasses(type) + } - fun getNamesOfClassesImplementingWithClassVersionCheck(type: KClass<*>): List { - return scanResult.getClassesImplementing(type.java.name).filter { it.name.startsWith(qualifiedNamePrefix) }.map { - validateClassFileVersion(it) - it.name - } + private fun ClassInfoList.getAllConcreteClasses(type: KClass): List> { + return mapNotNull { loadClass(it.name, type)?.takeUnless(Class<*>::isAbstractClass) } + } + + private fun ScanResult.determineLanguageVersion(cordappJar: Path): LanguageVersion { + val allClasses = allClassesAsMap.values + if (allClasses.isEmpty()) { + return LanguageVersion.Data } - - fun versionCheckClassesImplementing(type: KClass<*>) { - return scanResult.getClassesImplementing(type.java.name).filter { it.name.startsWith(qualifiedNamePrefix) }.forEach { - validateClassFileVersion(it) - } + val classFileMajorVersion = allClasses.maxOf { it.classfileMajorVersion } + val kotlinMetadataVersion = allClasses + .mapNotNullTo(TreeSet()) { it.kotlinMetadataVersion() } + .let { kotlinMetadataVersions -> + // If there's more than one minor version of Kotlin + if (kotlinMetadataVersions.size > 1 && kotlinMetadataVersions.mapToSet { it.copy(patch = 0) }.size > 1) { + logger.warn("CorDapp $cordappJar comprised of multiple Kotlin versions (kotlinMetadataVersions=$kotlinMetadataVersions). " + + "This may cause compatibility issues.") + } + kotlinMetadataVersions.takeIf { it.isNotEmpty() }?.last() + } + try { + return LanguageVersion.Bytecode(classFileMajorVersion, kotlinMetadataVersion) + } catch (e: IllegalArgumentException) { + throw IllegalStateException("Unable to load CorDapp $cordappJar: ${e.message}") } + } - fun getClassesWithSuperclass(type: KClass): List> { - return scanResult - .getSubclasses(type.java.name) - .names - .filter { it.startsWith(qualifiedNamePrefix) } - .mapNotNull { loadClass(it, type) } - .filterNot { it.isAbstractClass } - } - - fun getClassesImplementingWithClassVersionCheck(type: KClass): List { - return scanResult - .getClassesImplementing(type.java.name) - .filter { it.name.startsWith(qualifiedNamePrefix) } - .mapNotNull { - validateClassFileVersion(it) - loadClass(it.name, type) } - .filterNot { it.isAbstractClass } - .map { it.kotlin.objectOrNewInstance() } - } - - fun getClassesImplementing(type: KClass): List> { - return scanResult - .getClassesImplementing(type.java.name) - .filter { it.name.startsWith(qualifiedNamePrefix) } - .mapNotNull { - loadClass(it.name, type) } - .filterNot { it.isAbstractClass } - } - - fun getClassesWithAnnotation(type: KClass, annotation: KClass): List> { - return scanResult - .getClassesWithAnnotation(annotation.java.name) - .names - .filter { it.startsWith(qualifiedNamePrefix) } - .mapNotNull { loadClass(it, type) } - .filterNot { Modifier.isAbstract(it.modifiers) } - } - - fun getConcreteClassesOfType(type: KClass): List> { - return scanResult - .getSubclasses(type.java.name) - .names - .filter { it.startsWith(qualifiedNamePrefix) } - .mapNotNull { loadClass(it, type) } - .filterNot { it.isAbstractClass } - } - - fun getAllStandardClasses(): List { - return scanResult - .allStandardClasses - .names - .filter { it.startsWith(qualifiedNamePrefix) } - } - - fun getAllInterfaces(): List { - return scanResult - .allInterfaces - .names - .filter { it.startsWith(qualifiedNamePrefix) } - } - - private fun validateClassFileVersion(classInfo: ClassInfo) { - if (classInfo.classfileMajorVersion < JDK1_2_CLASS_FILE_FORMAT_MAJOR_VERSION || - classInfo.classfileMajorVersion > JDK8_CLASS_FILE_FORMAT_MAJOR_VERSION) - throw IllegalStateException("Class ${classInfo.name} from jar file ${cordappJarPath.url} has an invalid version of " + - "${classInfo.classfileMajorVersion}") - } - - override fun close() = scanResult.close() + private fun ClassInfo.kotlinMetadataVersion(): KotlinMetadataVersion? { + val kotlinMetadata = getAnnotationInfo(Metadata::class.java) ?: return null + val kotlinMetadataVersion = KotlinMetadataVersion.from(kotlinMetadata.parameterValues.get("mv").value as IntArray) + logger.trace { "$name: $kotlinMetadataVersion" } + return kotlinMetadataVersion } } @@ -496,7 +495,7 @@ class CordappInvalidVersionException( /** * Thrown if duplicate CorDapps are installed on the node */ -class DuplicateCordappsInstalledException(app: Cordapp, duplicates: Set) +class DuplicateCordappsInstalledException(app: Cordapp, duplicates: Collection) : CordaRuntimeException("IllegalStateExcepion", "The CorDapp (name: ${app.info.shortName}, file: ${app.name}) " + "is installed multiple times on the node. The following files correspond to the exact same content: " + "${duplicates.map { it.name }}", null), ErrorCode { @@ -508,42 +507,3 @@ class DuplicateCordappsInstalledException(app: Cordapp, duplicates: Set * Thrown if an exception occurs during loading cordapps. */ class InvalidCordappException(message: String) : CordaRuntimeException(message) - -abstract class CordappLoaderTemplate : CordappLoader { - - companion object { - - private val logger = contextLogger() - } - - override val flowCordappMap: Map>, Cordapp> by lazy { - cordapps.flatMap { corDapp -> corDapp.allFlows.map { flow -> flow to corDapp } } - .groupBy { it.first } - .mapValues { entry -> - if (entry.value.size > 1) { - logger.error("There are multiple CorDapp JARs on the classpath for flow " + - "${entry.value.first().first.name}: [ ${entry.value.joinToString { it.second.jarPath.toString() }} ].") - entry.value.forEach { (_, cordapp) -> - ZipInputStream(cordapp.jarPath.openStream()).use { zip -> - val ident = BigInteger(64, Random()).toString(36) - logger.error("Contents of: ${cordapp.jarPath} will be prefaced with: $ident") - var e = zip.nextEntry - while (e != null) { - logger.error("$ident\t ${e.name}") - e = zip.nextEntry - } - } - } - throw MultipleCordappsForFlowException("There are multiple CorDapp JARs on the classpath for flow " + - "${entry.value.first().first.name}: [ ${entry.value.joinToString { it.second.jarPath.toString() }} ].", - entry.value.first().first.name, - entry.value.joinToString { it.second.jarPath.toString() }) - } - entry.value.single().second - } - } - - override val cordappSchemas: Set by lazy { - cordapps.flatMap { it.customSchemas }.toSet() - } -} diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/VirtualCordapps.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/VirtualCordapps.kt index 08b7adb372..d14d09c605 100644 --- a/node/src/main/kotlin/net/corda/node/internal/cordapp/VirtualCordapps.kt +++ b/node/src/main/kotlin/net/corda/node/internal/cordapp/VirtualCordapps.kt @@ -5,6 +5,7 @@ import net.corda.core.crypto.SecureHash import net.corda.core.flows.ContractUpgradeFlow import net.corda.core.internal.cordapp.CordappImpl import net.corda.core.internal.location +import net.corda.core.internal.toPath import net.corda.node.VersionInfo import net.corda.notary.experimental.bftsmart.BFTSmartNotarySchemaV1 import net.corda.notary.experimental.bftsmart.BFTSmartNotaryService @@ -24,6 +25,7 @@ internal object VirtualCordapp { /** A Cordapp representing the core package which is not scanned automatically. */ fun generateCore(versionInfo: VersionInfo): CordappImpl { return CordappImpl( + jarFile = ContractUpgradeFlow.javaClass.location.toPath(), // Core JAR location contractClassNames = listOf(), initiatedFlows = listOf(), rpcFlows = coreRpcFlows, @@ -37,7 +39,6 @@ internal object VirtualCordapp { customSchemas = setOf(), info = Cordapp.Info.Default("corda-core", versionInfo.vendor, versionInfo.releaseVersion, "Open Source (Apache 2)"), allFlows = listOf(), - jarPath = ContractUpgradeFlow.javaClass.location, // Core JAR location jarHash = SecureHash.allOnesHash, minimumPlatformVersion = versionInfo.platformVersion, targetPlatformVersion = versionInfo.platformVersion, @@ -49,6 +50,7 @@ internal object VirtualCordapp { /** A Cordapp for the built-in notary service implementation. */ fun generateJPANotary(versionInfo: VersionInfo): CordappImpl { return CordappImpl( + jarFile = JPANotaryService::class.java.location.toPath(), contractClassNames = listOf(), initiatedFlows = listOf(), rpcFlows = listOf(), @@ -62,7 +64,6 @@ internal object VirtualCordapp { customSchemas = setOf(JPANotarySchemaV1), info = Cordapp.Info.Default("corda-notary", versionInfo.vendor, versionInfo.releaseVersion, "Open Source (Apache 2)"), allFlows = listOf(), - jarPath = JPANotaryService::class.java.location, jarHash = SecureHash.allOnesHash, minimumPlatformVersion = versionInfo.platformVersion, targetPlatformVersion = versionInfo.platformVersion, @@ -75,6 +76,7 @@ internal object VirtualCordapp { /** A Cordapp for the built-in Raft notary service implementation. */ fun generateRaftNotary(versionInfo: VersionInfo): CordappImpl { return CordappImpl( + jarFile = RaftNotaryService::class.java.location.toPath(), contractClassNames = listOf(), initiatedFlows = listOf(), rpcFlows = listOf(), @@ -88,7 +90,6 @@ internal object VirtualCordapp { customSchemas = setOf(RaftNotarySchemaV1), info = Cordapp.Info.Default("corda-notary-raft", versionInfo.vendor, versionInfo.releaseVersion, "Open Source (Apache 2)"), allFlows = listOf(), - jarPath = RaftNotaryService::class.java.location, jarHash = SecureHash.allOnesHash, minimumPlatformVersion = versionInfo.platformVersion, targetPlatformVersion = versionInfo.platformVersion, @@ -100,6 +101,7 @@ internal object VirtualCordapp { /** A Cordapp for the built-in BFT-Smart notary service implementation. */ fun generateBFTSmartNotary(versionInfo: VersionInfo): CordappImpl { return CordappImpl( + jarFile = BFTSmartNotaryService::class.java.location.toPath(), contractClassNames = listOf(), initiatedFlows = listOf(), rpcFlows = listOf(), @@ -113,7 +115,6 @@ internal object VirtualCordapp { customSchemas = setOf(BFTSmartNotarySchemaV1), info = Cordapp.Info.Default("corda-notary-bft-smart", versionInfo.vendor, versionInfo.releaseVersion, "Open Source (Apache 2)"), allFlows = listOf(), - jarPath = BFTSmartNotaryService::class.java.location, jarHash = SecureHash.allOnesHash, minimumPlatformVersion = versionInfo.platformVersion, targetPlatformVersion = versionInfo.platformVersion, diff --git a/node/src/main/kotlin/net/corda/node/internal/security/RPCPermissionResolver.kt b/node/src/main/kotlin/net/corda/node/internal/security/RPCPermissionResolver.kt index e166fca2af..6087cf0594 100644 --- a/node/src/main/kotlin/net/corda/node/internal/security/RPCPermissionResolver.kt +++ b/node/src/main/kotlin/net/corda/node/internal/security/RPCPermissionResolver.kt @@ -12,6 +12,7 @@ import org.apache.shiro.authz.Permission import org.apache.shiro.authz.permission.PermissionResolver import org.slf4j.LoggerFactory import java.lang.reflect.Method +import java.util.Locale import kotlin.reflect.KClass import kotlin.reflect.KFunction import kotlin.reflect.KProperty @@ -54,7 +55,7 @@ internal object RPCPermissionResolver : PermissionResolver { private val FLOW_RPC_PERMITTED_START_FLOW_WITH_CLIENT_ID_CALLS = setOf("startFlowWithClientId", "startFlowDynamicWithClientId") override fun resolvePermission(representation: String): Permission { - when (representation.substringBefore(SEPARATOR).toLowerCase()) { + when (representation.substringBefore(SEPARATOR).lowercase(Locale.getDefault())) { ACTION_INVOKE_RPC -> { val rpcCall = representation.substringAfter(SEPARATOR, "") require(representation.count { it == SEPARATOR } == 1 && rpcCall.isNotEmpty()) { "Malformed permission string" } @@ -90,7 +91,7 @@ internal object RPCPermissionResolver : PermissionResolver { * 3. Methods of specific group: InvokeRpc:com.fully.qualified.package.CustomClientRpcOps#READONLY */ private fun attemptNewStyleParsing(permAsString: String): Permission { - return when(permAsString.substringBefore(NEW_STYLE_SEP).toLowerCase()) { + return when(permAsString.substringBefore(NEW_STYLE_SEP).lowercase(Locale.getDefault())) { ACTION_INVOKE_RPC -> { val interfaceAndMethods = permAsString.substringAfter(NEW_STYLE_SEP, "") val interfaceParts = interfaceAndMethods.split(INTERFACE_SEPARATOR) @@ -98,7 +99,7 @@ internal object RPCPermissionResolver : PermissionResolver { val methodsMap = requireNotNull(cache.get(interfaceParts[0])) { "Method map for ${interfaceParts[0]} must not be null in the cache. There must have been error processing interface. " + "Please look at the error log lines above." } - val lookupKey = interfaceAndMethods.toLowerCase() + val lookupKey = interfaceAndMethods.lowercase(Locale.getDefault()) val methods = requireNotNull(methodsMap[lookupKey]) { "Cannot find record for " + "'$lookupKey' for interface '${interfaceParts[0]}' in $methodsMap. " + "Please check permissions configuration string '$permAsString' matching class representation." } @@ -171,9 +172,9 @@ internal object RPCPermissionResolver : PermissionResolver { return emptyList() } - val allKey = methodFullName(interfaceClass.java, ACTION_ALL).toLowerCase() + val allKey = methodFullName(interfaceClass.java, ACTION_ALL).lowercase(Locale.getDefault()) val methodFullName = methodFullName(method) return listOf(allKey to methodFullName) + // ALL group - listOf(methodFullName.toLowerCase() to methodFullName) // Full method names individually + listOf(methodFullName.lowercase(Locale.getDefault()) to methodFullName) // Full method names individually } } \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/internal/security/RPCSecurityManagerImpl.kt b/node/src/main/kotlin/net/corda/node/internal/security/RPCSecurityManagerImpl.kt index 605bf0bd71..8b7951710c 100644 --- a/node/src/main/kotlin/net/corda/node/internal/security/RPCSecurityManagerImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/security/RPCSecurityManagerImpl.kt @@ -1,8 +1,6 @@ package net.corda.node.internal.security - import com.github.benmanes.caffeine.cache.Cache -import com.github.benmanes.caffeine.cache.Caffeine import com.google.common.primitives.Ints import net.corda.core.internal.NamedCacheFactory import net.corda.core.internal.uncheckedCast @@ -12,7 +10,11 @@ import net.corda.node.services.config.AuthDataSourceType import net.corda.node.services.config.PasswordEncryption import net.corda.node.services.config.SecurityConfiguration import net.corda.nodeapi.internal.config.User -import org.apache.shiro.authc.* +import org.apache.shiro.authc.AuthenticationException +import org.apache.shiro.authc.AuthenticationInfo +import org.apache.shiro.authc.AuthenticationToken +import org.apache.shiro.authc.SimpleAuthenticationInfo +import org.apache.shiro.authc.UsernamePasswordToken import org.apache.shiro.authc.credential.PasswordMatcher import org.apache.shiro.authc.credential.SimpleCredentialsMatcher import org.apache.shiro.authz.AuthorizationInfo @@ -36,13 +38,8 @@ private typealias AuthServiceConfig = SecurityConfiguration.AuthService class RPCSecurityManagerImpl(config: AuthServiceConfig, cacheFactory: NamedCacheFactory) : RPCSecurityManager { override val id = config.id - private val manager: DefaultSecurityManager + private val manager: DefaultSecurityManager = buildImpl(config, cacheFactory) - init { - manager = buildImpl(config, cacheFactory) - } - - @Throws(FailedLoginException::class) override fun authenticate(principal: String, password: Password): AuthorizingSubject { password.use { val authToken = UsernamePasswordToken(principal, it.value) @@ -85,11 +82,12 @@ class RPCSecurityManagerImpl(config: AuthServiceConfig, cacheFactory: NamedCache } return DefaultSecurityManager(realm).also { // Setup optional cache layer if configured - it.cacheManager = config.options?.cache?.let { + it.cacheManager = config.options?.cache?.let { options -> CaffeineCacheManager( - timeToLiveSeconds = it.expireAfterSecs, - maxSize = it.maxEntries, - cacheFactory = cacheFactory) + timeToLiveSeconds = options.expireAfterSecs, + maxSize = options.maxEntries, + cacheFactory = cacheFactory + ) } } } @@ -195,8 +193,7 @@ private typealias ShiroCache = org.apache.shiro.cache.Cache /* * Adapts a [com.github.benmanes.caffeine.cache.Cache] to a [org.apache.shiro.cache.Cache] implementation. */ -private fun Cache.toShiroCache() = object : ShiroCache { - +private fun Cache.toShiroCache() = object : ShiroCache { private val impl = this@toShiroCache override operator fun get(key: K) = impl.getIfPresent(key) @@ -233,18 +230,18 @@ private class CaffeineCacheManager(val maxSize: Long, private val instances = ConcurrentHashMap>() - override fun getCache(name: String): ShiroCache { + override fun getCache(name: String): ShiroCache { val result = instances[name] ?: buildCache(name) instances.putIfAbsent(name, result) return uncheckedCast(result) } - private fun buildCache(name: String): ShiroCache { + private fun buildCache(name: String): ShiroCache { logger.info("Constructing cache '$name' with maximumSize=$maxSize, TTL=${timeToLiveSeconds}s") - return cacheFactory.buildNamed(Caffeine.newBuilder(), "RPCSecurityManagerShiroCache_$name").toShiroCache() + return cacheFactory.buildNamed("RPCSecurityManagerShiroCache_$name").toShiroCache() } companion object { private val logger = loggerFor() } -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/internal/subcommands/GenerateRpcSslCertsCli.kt b/node/src/main/kotlin/net/corda/node/internal/subcommands/GenerateRpcSslCertsCli.kt index 1c3fdee97a..e9c2ac07e1 100644 --- a/node/src/main/kotlin/net/corda/node/internal/subcommands/GenerateRpcSslCertsCli.kt +++ b/node/src/main/kotlin/net/corda/node/internal/subcommands/GenerateRpcSslCertsCli.kt @@ -1,7 +1,5 @@ package net.corda.node.internal.subcommands -import net.corda.core.internal.div -import net.corda.core.internal.exists import net.corda.node.internal.Node import net.corda.node.internal.NodeCliCommand import net.corda.node.internal.NodeStartup @@ -11,6 +9,8 @@ import net.corda.node.utilities.createKeyPairAndSelfSignedTLSCertificate import net.corda.node.utilities.saveToKeyStore import net.corda.node.utilities.saveToTrustStore import java.io.Console +import kotlin.io.path.div +import kotlin.io.path.exists import kotlin.system.exitProcess class GenerateRpcSslCertsCli(startup: NodeStartup): NodeCliCommand("generate-rpc-ssl-settings", "Generate the SSL key and trust stores for a secure RPC connection.", startup) { diff --git a/node/src/main/kotlin/net/corda/node/internal/subcommands/InitialRegistrationCli.kt b/node/src/main/kotlin/net/corda/node/internal/subcommands/InitialRegistrationCli.kt index c7e8cc12c5..c248dd7286 100644 --- a/node/src/main/kotlin/net/corda/node/internal/subcommands/InitialRegistrationCli.kt +++ b/node/src/main/kotlin/net/corda/node/internal/subcommands/InitialRegistrationCli.kt @@ -1,13 +1,14 @@ package net.corda.node.internal.subcommands import net.corda.cliutils.CliWrapperBase -import net.corda.core.internal.createFile -import net.corda.core.internal.div -import net.corda.core.internal.exists import net.corda.node.InitialRegistrationCmdLineOptions import net.corda.node.NodeRegistrationOption -import net.corda.node.internal.* +import net.corda.node.internal.Node +import net.corda.node.internal.NodeStartup +import net.corda.node.internal.NodeStartupLogging import net.corda.node.internal.NodeStartupLogging.Companion.logger +import net.corda.node.internal.RunAfterNodeInitialisation +import net.corda.node.internal.initLogging import net.corda.node.services.config.NodeConfiguration import net.corda.node.utilities.registration.HTTPNetworkRegistrationService import net.corda.node.utilities.registration.NodeRegistrationConfiguration @@ -17,6 +18,9 @@ import picocli.CommandLine.Option import java.io.File import java.nio.file.Path import java.util.function.Consumer +import kotlin.io.path.createFile +import kotlin.io.path.div +import kotlin.io.path.exists class InitialRegistrationCli(val startup: NodeStartup): CliWrapperBase("initial-registration", "Start initial node registration with Corda network to obtain certificate from the permissioning server.") { @Option(names = ["-t", "--network-root-truststore"], description = ["Network root trust store obtained from network operator."]) @@ -29,7 +33,8 @@ class InitialRegistrationCli(val startup: NodeStartup): CliWrapperBase("initial- var skipSchemaCreation: Boolean = false override fun runProgram() : Int { - val networkRootTrustStorePath: Path = networkRootTrustStorePathParameter ?: cmdLineOptions.baseDirectory / "certificates" / "network-root-truststore.jks" + val networkRootTrustStorePath: Path = networkRootTrustStorePathParameter + ?: (cmdLineOptions.baseDirectory / "certificates" / "network-root-truststore.jks") return startup.initialiseAndRun(cmdLineOptions, InitialRegistration(cmdLineOptions.baseDirectory, networkRootTrustStorePath, networkRootTrustStorePassword, skipSchemaCreation, startup)) } diff --git a/node/src/main/kotlin/net/corda/node/migration/CordaMigration.kt b/node/src/main/kotlin/net/corda/node/migration/CordaMigration.kt index 4c28ab7304..717b94a5d1 100644 --- a/node/src/main/kotlin/net/corda/node/migration/CordaMigration.kt +++ b/node/src/main/kotlin/net/corda/node/migration/CordaMigration.kt @@ -7,17 +7,13 @@ import liquibase.database.jvm.JdbcConnection import liquibase.exception.ValidationErrors import liquibase.resource.ResourceAccessor import net.corda.core.schemas.MappedSchema -import net.corda.node.SimpleClock import net.corda.node.services.identity.PersistentIdentityService import net.corda.node.services.persistence.AbstractPartyToX500NameAsStringConverter -import net.corda.node.services.persistence.DBTransactionStorage -import net.corda.node.services.persistence.NodeAttachmentService import net.corda.node.services.persistence.PublicKeyToTextConverter import net.corda.nodeapi.internal.persistence.CordaPersistence import java.io.PrintWriter import java.sql.Connection import java.sql.SQLFeatureNotSupportedException -import java.time.Clock import java.util.logging.Logger import javax.sql.DataSource @@ -39,11 +35,6 @@ abstract class CordaMigration : CustomTaskChange { private lateinit var _cordaDB: CordaPersistence - val servicesForResolution: MigrationServicesForResolution - get() = _servicesForResolution - - private lateinit var _servicesForResolution: MigrationServicesForResolution - /** * Initialise a subset of node services so that data from these can be used to perform migrations. * @@ -60,12 +51,6 @@ abstract class CordaMigration : CustomTaskChange { _cordaDB = createDatabase(url, cacheFactory, identityService, schema) cordaDB.start(dataSource) identityService.database = cordaDB - - cordaDB.transaction { - val dbTransactions = DBTransactionStorage(cordaDB, cacheFactory, SimpleClock(Clock.systemUTC())) - val attachmentsService = NodeAttachmentService(metricRegistry, cacheFactory, cordaDB) - _servicesForResolution = MigrationServicesForResolution(identityService, attachmentsService, dbTransactions, cordaDB, cacheFactory) - } } private fun createDatabase(jdbcUrl: String, diff --git a/node/src/main/kotlin/net/corda/node/migration/MigrationNamedCacheFactory.kt b/node/src/main/kotlin/net/corda/node/migration/MigrationNamedCacheFactory.kt index 9b32d0a17b..012f145a91 100644 --- a/node/src/main/kotlin/net/corda/node/migration/MigrationNamedCacheFactory.kt +++ b/node/src/main/kotlin/net/corda/node/migration/MigrationNamedCacheFactory.kt @@ -44,11 +44,11 @@ class MigrationNamedCacheFactory(private val metricRegistry: MetricRegistry?, } } - override fun buildNamed(caffeine: Caffeine, name: String): Cache { + override fun buildNamed(caffeine: Caffeine, name: String): Cache { return configuredForNamed(caffeine, name).build() } - override fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache { + override fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache { return configuredForNamed(caffeine, name).build(loader) } diff --git a/node/src/main/kotlin/net/corda/node/migration/MigrationServicesForResolution.kt b/node/src/main/kotlin/net/corda/node/migration/MigrationServicesForResolution.kt deleted file mode 100644 index 0186b9659c..0000000000 --- a/node/src/main/kotlin/net/corda/node/migration/MigrationServicesForResolution.kt +++ /dev/null @@ -1,175 +0,0 @@ -package net.corda.node.migration - -import net.corda.core.contracts.* -import net.corda.core.cordapp.CordappContext -import net.corda.core.cordapp.CordappProvider -import net.corda.core.crypto.SecureHash -import net.corda.core.internal.deserialiseComponentGroup -import net.corda.core.internal.div -import net.corda.core.internal.readObject -import net.corda.core.node.NetworkParameters -import net.corda.core.node.ServicesForResolution -import net.corda.core.node.services.AttachmentId -import net.corda.core.node.services.IdentityService -import net.corda.core.node.services.NetworkParametersService -import net.corda.core.node.services.TransactionStorage -import net.corda.core.serialization.deserialize -import net.corda.core.serialization.internal.AttachmentsClassLoaderBuilder -import net.corda.core.serialization.internal.AttachmentsClassLoaderCache -import net.corda.core.serialization.internal.AttachmentsClassLoaderCacheImpl -import net.corda.core.transactions.ContractUpgradeLedgerTransaction -import net.corda.core.transactions.NotaryChangeLedgerTransaction -import net.corda.core.transactions.WireTransaction -import net.corda.core.utilities.contextLogger -import net.corda.node.internal.DBNetworkParametersStorage -import net.corda.node.services.attachments.NodeAttachmentTrustCalculator -import net.corda.node.services.persistence.AttachmentStorageInternal -import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME -import net.corda.nodeapi.internal.network.SignedNetworkParameters -import net.corda.nodeapi.internal.persistence.CordaPersistence -import net.corda.nodeapi.internal.persistence.SchemaMigration -import java.nio.file.Paths -import java.time.Clock -import java.time.Duration -import java.util.Comparator.comparingInt - -class MigrationServicesForResolution( - override val identityService: IdentityService, - override val attachments: AttachmentStorageInternal, - private val transactions: TransactionStorage, - private val cordaDB: CordaPersistence, - cacheFactory: MigrationNamedCacheFactory -): ServicesForResolution { - - companion object { - val logger = contextLogger() - } - override val cordappProvider: CordappProvider - get() = object : CordappProvider { - - val cordappLoader = SchemaMigration.loader.get() - - override fun getAppContext(): CordappContext { - TODO("not implemented") - } - - override fun getContractAttachmentID(contractClassName: ContractClassName): AttachmentId? { - TODO("not implemented") - } - } - private val cordappLoader = SchemaMigration.loader.get() - - private val attachmentTrustCalculator = NodeAttachmentTrustCalculator( - attachments, - cacheFactory - ) - - private val attachmentsClassLoaderCache: AttachmentsClassLoaderCache = AttachmentsClassLoaderCacheImpl(cacheFactory) - - private fun defaultNetworkParameters(): NetworkParameters { - logger.warn("Using a dummy set of network parameters for migration.") - val clock = Clock.systemUTC() - return NetworkParameters( - 1, - listOf(), - 1, - 1, - clock.instant(), - 1, - mapOf(), - Duration.ZERO, - mapOf() - ) - } - - private fun getNetworkParametersFromFile(): SignedNetworkParameters? { - return try { - val dir = System.getProperty(SchemaMigration.NODE_BASE_DIR_KEY) - val path = Paths.get(dir) / NETWORK_PARAMS_FILE_NAME - path.readObject() - } catch (e: Exception) { - logger.info("Couldn't find network parameters file: ${e.message}. This is expected if the node is starting for the first time.") - null - } - } - - override val networkParametersService: NetworkParametersService = object : NetworkParametersService { - - private val storage = DBNetworkParametersStorage.createParametersMap(cacheFactory) - - private val filedParams = getNetworkParametersFromFile() - - override val defaultHash: SecureHash = filedParams?.raw?.hash ?: SecureHash.getZeroHash() - override val currentHash: SecureHash = cordaDB.transaction { - storage.allPersisted.use { - it.max(comparingInt { it.second.verified().epoch }).map { it.first }.orElse(defaultHash) - } - } - - override fun lookup(hash: SecureHash): NetworkParameters? { - // Note that the parameters in any file shouldn't be put into the database - this will be done by the node on startup. - return if (hash == filedParams?.raw?.hash) { - filedParams.raw.deserialize() - } else { - cordaDB.transaction { storage[hash]?.verified() } - } - } - } - - override val networkParameters: NetworkParameters = networkParametersService.lookup(networkParametersService.currentHash) - ?: getNetworkParametersFromFile()?.raw?.deserialize() - ?: defaultNetworkParameters() - - private fun extractStateFromTx(tx: WireTransaction, stateIndices: Collection): List> { - return try { - val txAttachments = tx.attachments.mapNotNull { attachments.openAttachment(it)} - val states = AttachmentsClassLoaderBuilder.withAttachmentsClassloaderContext( - txAttachments, - networkParameters, - tx.id, - attachmentTrustCalculator::calculate, - cordappLoader.appClassLoader, - attachmentsClassLoaderCache) { - deserialiseComponentGroup(tx.componentGroups, TransactionState::class, ComponentGroupEnum.OUTPUTS_GROUP, forceDeserialize = true) - } - states.filterIndexed {index, _ -> stateIndices.contains(index)}.toList() - } catch (e: Exception) { - // If there is no attachment that allows the state class to be deserialised correctly, then carpent a state class anyway. It - // might still be possible to access the participants depending on how the state class was serialised. - logger.debug("Could not use attachments to deserialise transaction output states for transaction ${tx.id}") - tx.outputs.filterIndexed { index, _ -> stateIndices.contains(index)} - } - } - - override fun loadState(stateRef: StateRef): TransactionState<*> { - val stx = transactions.getTransaction(stateRef.txhash) - ?: throw MigrationException("Could not get transaction with hash ${stateRef.txhash} out of vault") - val baseTx = stx.resolveBaseTransaction(this) - return when (baseTx) { - is NotaryChangeLedgerTransaction -> baseTx.outputs[stateRef.index] - is ContractUpgradeLedgerTransaction -> baseTx.outputs[stateRef.index] - is WireTransaction -> extractStateFromTx(baseTx, listOf(stateRef.index)).first() - else -> throw MigrationException("Unknown transaction type ${baseTx::class.qualifiedName} found when loading a state") - } - } - - override fun loadStates(stateRefs: Set): Set> { - return stateRefs.groupBy { it.txhash }.flatMap { - val stx = transactions.getTransaction(it.key) - ?: throw MigrationException("Could not get transaction with hash ${it.key} out of vault") - val baseTx = stx.resolveBaseTransaction(this) - val stateList = when (baseTx) { - is NotaryChangeLedgerTransaction -> it.value.map { stateRef -> StateAndRef(baseTx.outputs[stateRef.index], stateRef) } - is ContractUpgradeLedgerTransaction -> it.value.map { stateRef -> StateAndRef(baseTx.outputs[stateRef.index], stateRef) } - is WireTransaction -> extractStateFromTx(baseTx, it.value.map { stateRef -> stateRef.index }) - .mapIndexed {index, state -> StateAndRef(state, StateRef(baseTx.id, index)) } - else -> throw MigrationException("Unknown transaction type ${baseTx::class.qualifiedName} found when loading a state") - } - stateList - }.toSet() - } - - override fun loadContractAttachment(stateRef: StateRef): Attachment { - throw NotImplementedError() - } -} \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/migration/VaultStateMigration.kt b/node/src/main/kotlin/net/corda/node/migration/VaultStateMigration.kt index 28d8dc3a89..f47b80c374 100644 --- a/node/src/main/kotlin/net/corda/node/migration/VaultStateMigration.kt +++ b/node/src/main/kotlin/net/corda/node/migration/VaultStateMigration.kt @@ -1,13 +1,9 @@ package net.corda.node.migration import liquibase.database.Database -import net.corda.core.contracts.* -import net.corda.core.identity.CordaX500Name import net.corda.core.node.services.Vault import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.PersistentStateRef -import net.corda.core.serialization.SerializationContext -import net.corda.core.serialization.internal.* import net.corda.core.utilities.contextLogger import net.corda.node.internal.DBNetworkParametersStorage import net.corda.node.internal.schemas.NodeInfoSchemaV1 @@ -16,103 +12,21 @@ import net.corda.node.services.keys.BasicHSMKeyManagementService import net.corda.node.services.network.PersistentNetworkMapCache import net.corda.node.services.persistence.DBTransactionStorage import net.corda.node.services.persistence.NodeAttachmentService -import net.corda.node.services.vault.NodeVaultService import net.corda.node.services.vault.VaultSchemaV1 -import net.corda.node.services.vault.toStateRef import net.corda.nodeapi.internal.persistence.CordaPersistence -import net.corda.nodeapi.internal.persistence.DatabaseTransaction -import net.corda.nodeapi.internal.persistence.SchemaMigration import net.corda.nodeapi.internal.persistence.currentDBSession -import net.corda.serialization.internal.AMQP_P2P_CONTEXT -import net.corda.serialization.internal.AMQP_STORAGE_CONTEXT -import net.corda.serialization.internal.CordaSerializationMagic -import net.corda.serialization.internal.SerializationFactoryImpl -import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme -import net.corda.serialization.internal.amqp.amqpMagic -import org.hibernate.Session import org.hibernate.query.Query -import java.util.concurrent.ForkJoinPool -import java.util.concurrent.ForkJoinTask -import java.util.concurrent.RecursiveAction import javax.persistence.criteria.Root import javax.persistence.criteria.Selection class VaultStateMigration : CordaMigration() { - companion object { - private val logger = contextLogger() - } - - private fun addStateParties(session: Session, stateAndRef: StateAndRef) { - val state = stateAndRef.state.data - val persistentStateRef = PersistentStateRef(stateAndRef.ref) - try { - state.participants.groupBy { it.owningKey }.forEach { participants -> - val persistentParty = VaultSchemaV1.PersistentParty(persistentStateRef, participants.value.first()) - session.persist(persistentParty) - } - } catch (e: AbstractMethodError) { - // This should only happen if there was no attachment that could be used to deserialise the output states, and the state was - // serialised such that the participants list cannot be accessed (participants is calculated and not marked as a - // SerializableCalculatedProperty. - throw VaultStateMigrationException("Cannot add state parties for state ${stateAndRef.ref} as state class is not on the " + - "classpath and participants cannot be synthesised") - } - } - - private fun getStateAndRef(persistentState: VaultSchemaV1.VaultStates): StateAndRef { - val persistentStateRef = persistentState.stateRef ?: - throw VaultStateMigrationException("Persistent state ref missing from state") - val stateRef = persistentStateRef.toStateRef() - val state = try { - servicesForResolution.loadState(stateRef) - } catch (e: Exception) { - throw VaultStateMigrationException("Could not load state for stateRef $stateRef : ${e.message}", e) - } - return StateAndRef(state, stateRef) - } - - override fun execute(database: Database?) { - logger.info("Migrating vault state data to V4 tables") - if (database == null) { - logger.error("Cannot migrate vault states: Liquibase failed to provide a suitable database connection") - throw VaultStateMigrationException("Cannot migrate vault states as liquibase failed to provide a suitable database connection") - } + override fun execute(database: Database) { initialiseNodeServices(database, setOf(VaultMigrationSchemaV1, VaultSchemaV1, NodeInfoSchemaV1)) - var statesSkipped = 0 val persistentStates = VaultStateIterator(cordaDB) if (persistentStates.numStates > 0) { - logger.warn("Found ${persistentStates.numStates} states to update from a previous version. This may take a while for large " - + "volumes of data.") + throw VaultStateMigrationException("Found ${persistentStates.numStates} states that need to be updated to V4. Please upgrade " + + "to an older version of Corda first to perform this migration.") } - val ourName = CordaX500Name.parse(System.getProperty(SchemaMigration.NODE_X500_NAME)) - VaultStateIterator.withSerializationEnv { - persistentStates.forEach { - val session = currentDBSession() - try { - val stateAndRef = getStateAndRef(it) - - addStateParties(session, stateAndRef) - - // Can get away without checking for AbstractMethodErrors here as these will have already occurred when trying to add - // state parties. - val myKeys = stateAndRef.state.data.participants.map { participant -> participant.owningKey} - .filter { key -> identityService.certificateFromKey(key)?.name == ourName }.toSet() - if (!NodeVaultService.isRelevant(stateAndRef.state.data, myKeys)) { - it.relevancyStatus = Vault.RelevancyStatus.NOT_RELEVANT - } - } catch (e: VaultStateMigrationException) { - logger.warn("An error occurred while migrating a vault state: ${e.message}. Skipping. This will cause the " + - "migration to fail.", e) - statesSkipped++ - } - } - } - if (statesSkipped > 0) { - logger.error("$statesSkipped states could not be migrated as there was no class available for them.") - throw VaultStateMigrationException("Failed to migrate $statesSkipped states in the vault. Check the logs for details of the " + - "error for each state.") - } - logger.info("Finished performing vault state data migration for ${persistentStates.numStates - statesSkipped} states") } } @@ -147,49 +61,9 @@ object VaultMigrationSchemaV1 : MappedSchema(schemaFamily = VaultMigrationSchema * Currently, this class filters out those persistent states that have entries in the state party table. This behaviour is required for the * vault state migration, as entries in this table should not be duplicated. Unconsumed states are also filtered out for performance. */ -class VaultStateIterator(private val database: CordaPersistence) : Iterator { +class VaultStateIterator(private val database: CordaPersistence) { companion object { val logger = contextLogger() - - private object AMQPInspectorSerializationScheme : AbstractAMQPSerializationScheme(emptyList()) { - override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean { - return magic == amqpMagic - } - - override fun rpcClientSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException() - override fun rpcServerSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException() - } - - private fun initialiseSerialization() { - // Deserialise with the lenient carpenter as we only care for the AMQP field getters - _inheritableContextSerializationEnv.set(SerializationEnvironment.with( - SerializationFactoryImpl().apply { - registerScheme(AMQPInspectorSerializationScheme) - }, - p2pContext = AMQP_P2P_CONTEXT.withLenientCarpenter(), - storageContext = AMQP_STORAGE_CONTEXT.withLenientCarpenter() - )) - } - - private fun disableSerialization() { - _inheritableContextSerializationEnv.set(null) - } - - fun withSerializationEnv(block: () -> Unit) { - val newEnv = if (_allEnabledSerializationEnvs.isEmpty()) { - initialiseSerialization() - true - } else { - false - } - effectiveSerializationEnv.serializationFactory.withCurrentContext(effectiveSerializationEnv.storageContext.withLenientCarpenter()) { - block() - } - - if (newEnv) { - disableSerialization() - } - } } private val criteriaBuilder = database.entityManagerFactory.criteriaBuilder val numStates = getTotalStates() @@ -224,111 +98,6 @@ class VaultStateIterator(private val database: CordaPersistence) : Iterator { - endTransaction() - transaction = database.newTransaction() - val query = createVaultStatesQuery(VaultSchemaV1.VaultStates::class.java) { it } - // The above query excludes states that have entries in the state party table. As the iteration proceeds, each state has entries - // added to this table. The result is that when the next page is retrieved, any results that were in the previous page are not in - // the query at all! As such, the next set of states that need processing start at the first result. - query.firstResult = 0 - query.maxResults = pageSize - pageNumber++ - val result = query.resultList - logger.debug("Loaded page $pageNumber of ${(numStates - 1 / pageNumber.toLong()) + 1}. Current page has ${result.size} vault states") - return result - } - - private var currentIndex = 0 - - override fun hasNext(): Boolean { - val nextElementPresent = currentIndex + ((pageNumber - 1) * pageSize) < numStates - if (!nextElementPresent) { - endTransaction() - } - return nextElementPresent - } - - override fun next(): VaultSchemaV1.VaultStates { - if (currentIndex == pageSize) { - currentPage = getNextPage() - currentIndex = 0 - } - val stateToReturn = currentPage[currentIndex] - currentIndex++ - return stateToReturn - } - - // The rest of this class is an attempt at multithreading that was ultimately scuppered by liquibase not providing a connection pool. - // This may be useful as a starting point for improving performance of the migration, so is left here. To start using it, remove the - // serialization environment changes in the execute function in the migration, and change forEach -> parallelForEach. - private val pool = ForkJoinPool.commonPool() - - private class VaultPageTask(val database: CordaPersistence, - val page: List, - val block: (VaultSchemaV1.VaultStates) -> Unit): RecursiveAction() { - - private val pageSize = page.size - private val tolerance = 10 - - override fun compute() { - withSerializationEnv { - if (pageSize > tolerance) { - ForkJoinTask.invokeAll(createSubtasks()) - } else { - applyBlock() - } - } - } - - private fun createSubtasks(): List { - return listOf(VaultPageTask(database, page.subList(0, pageSize / 2), block), VaultPageTask(database, page.subList(pageSize / 2, pageSize), block)) - } - - private fun applyBlock() { - effectiveSerializationEnv.serializationFactory.withCurrentContext(effectiveSerializationEnv.storageContext.withLenientCarpenter()) { - database.transaction { - page.forEach { block(it) } - } - } - } - } - - private fun hasNextPage(): Boolean { - val nextPagePresent = pageNumber * pageSize < numStates - if (!nextPagePresent) { - endTransaction() - } - return nextPagePresent - } - - /** - * Iterate through all states in the vault, parallelizing the work on each page of vault states. - */ - fun parallelForEach(block: (VaultSchemaV1.VaultStates) -> Unit) { - pool.invoke(VaultPageTask(database, currentPage, block)) - while (hasNextPage()) { - currentPage = getNextPage() - pool.invoke(VaultPageTask(database, currentPage, block)) - } - } } class VaultStateMigrationException(msg: String, cause: Exception? = null) : Exception(msg, cause) \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt b/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt index b283c137c4..93df592800 100644 --- a/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt +++ b/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt @@ -17,6 +17,7 @@ import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.concurrent.OpenFuture import net.corda.core.internal.dependencies import net.corda.core.internal.requireSupportedHashType +import net.corda.core.internal.verification.Verifier import net.corda.core.internal.warnOnce import net.corda.core.messaging.DataFeed import net.corda.core.messaging.StateMachineTransactionMapping @@ -25,11 +26,13 @@ import net.corda.core.node.StatesToRecord import net.corda.core.node.services.NetworkMapCache import net.corda.core.node.services.NetworkMapCacheBase import net.corda.core.node.services.TransactionStorage +import net.corda.core.serialization.SerializationContext +import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction +import net.corda.core.transactions.defaultVerifier import net.corda.core.utilities.contextLogger import net.corda.node.internal.InitiatedFlowFactory -import net.corda.node.internal.cordapp.CordappProviderInternal import net.corda.node.services.DbTransactionsResolver import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.messaging.MessagingService @@ -37,13 +40,11 @@ import net.corda.node.services.network.NetworkMapUpdater import net.corda.node.services.persistence.AttachmentStorageInternal import net.corda.node.services.statemachine.ExternalEvent import net.corda.node.services.statemachine.FlowStateMachineImpl +import net.corda.node.verification.NoDbAccessVerifier import net.corda.nodeapi.internal.persistence.CordaPersistence +import java.security.PublicKey import java.security.SignatureException -import java.util.ArrayList import java.util.Collections -import java.util.HashMap -import java.util.HashSet -import java.util.LinkedHashSet interface NetworkMapCacheInternal : NetworkMapCache, NetworkMapCacheBase { override val nodeReady: OpenFuture @@ -186,11 +187,14 @@ interface ServiceHubInternal : ServiceHubCoreInternal { val configuration: NodeConfiguration val nodeProperties: NodePropertiesStore val networkMapUpdater: NetworkMapUpdater - override val cordappProvider: CordappProviderInternal fun getFlowFactory(initiatingFlowClass: Class>): InitiatedFlowFactory<*>? val cacheFactory: NamedCacheFactory + override fun createVerifier(ltx: LedgerTransaction, serializationContext: SerializationContext): Verifier { + return NoDbAccessVerifier(defaultVerifier(ltx, serializationContext)) + } + override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable) = recordTransactions(statesToRecord, txs, SIGNATURE_VERIFICATION_DISABLED) diff --git a/node/src/main/kotlin/net/corda/node/services/attachments/NodeAttachmentTrustCalculator.kt b/node/src/main/kotlin/net/corda/node/services/attachments/NodeAttachmentTrustCalculator.kt index 2305203338..285f7fca5a 100644 --- a/node/src/main/kotlin/net/corda/node/services/attachments/NodeAttachmentTrustCalculator.kt +++ b/node/src/main/kotlin/net/corda/node/services/attachments/NodeAttachmentTrustCalculator.kt @@ -1,10 +1,16 @@ package net.corda.node.services.attachments -import com.github.benmanes.caffeine.cache.Caffeine import net.corda.core.contracts.Attachment import net.corda.core.contracts.ContractAttachment import net.corda.core.crypto.SecureHash -import net.corda.core.internal.* +import net.corda.core.internal.AbstractAttachment +import net.corda.core.internal.AttachmentTrustCalculator +import net.corda.core.internal.AttachmentTrustInfo +import net.corda.core.internal.NamedCacheFactory +import net.corda.core.internal.TRUSTED_UPLOADERS +import net.corda.core.internal.VisibleForTesting +import net.corda.core.internal.hash +import net.corda.core.internal.isUploaderTrusted import net.corda.core.node.services.AttachmentId import net.corda.core.node.services.vault.AttachmentQueryCriteria import net.corda.core.node.services.vault.Builder @@ -35,10 +41,7 @@ class NodeAttachmentTrustCalculator( ) : this(attachmentStorage, null, cacheFactory, blacklistedAttachmentSigningKeys) // A cache for caching whether a signing key is trusted - private val trustedKeysCache = cacheFactory.buildNamed( - Caffeine.newBuilder(), - "NodeAttachmentTrustCalculator_trustedKeysCache" - ) + private val trustedKeysCache = cacheFactory.buildNamed("NodeAttachmentTrustCalculator_trustedKeysCache") override fun calculate(attachment: Attachment): Boolean { @@ -92,9 +95,7 @@ class NodeAttachmentTrustCalculator( val trustRoot = if (attachment.isSignedByBlacklistedKey()) { null } else { - attachment.signerKeys - .mapNotNull { publicKeyToTrustRootMap[it] } - .firstOrNull() + attachment.signerKeys.firstNotNullOfOrNull { publicKeyToTrustRootMap[it] } } attachmentTrustInfos += AttachmentTrustInfo( attachmentId = attachment.id, diff --git a/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt b/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt index 524c565579..bd5c9c9999 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt @@ -8,9 +8,6 @@ import net.corda.common.configuration.parsing.internal.Configuration import net.corda.core.crypto.Crypto import net.corda.core.identity.CordaX500Name import net.corda.core.internal.VisibleForTesting -import net.corda.core.internal.createDirectories -import net.corda.core.internal.div -import net.corda.core.internal.exists import net.corda.node.internal.Node import net.corda.node.services.config.schema.v1.V1NodeConfigurationSpec import net.corda.nodeapi.internal.DEV_CA_KEY_STORE_PASS @@ -20,7 +17,7 @@ import net.corda.nodeapi.internal.config.toProperties import net.corda.nodeapi.internal.crypto.X509KeyStore import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.cryptoservice.CryptoService -import net.corda.nodeapi.internal.cryptoservice.bouncycastle.BCCryptoService +import net.corda.nodeapi.internal.cryptoservice.DefaultCryptoService import net.corda.nodeapi.internal.installDevNodeCaCertPath import net.corda.nodeapi.internal.loadDevCaTrustStore import net.corda.nodeapi.internal.registerDevP2pCertificates @@ -28,6 +25,9 @@ import net.corda.nodeapi.internal.storeLegalIdentity import org.slf4j.LoggerFactory import java.math.BigInteger import java.nio.file.Path +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.exists import kotlin.math.min fun configOf(vararg pairs: Pair): Config = ConfigFactory.parseMap(mapOf(*pairs)) @@ -42,7 +42,7 @@ object ConfigHelper { private val log = LoggerFactory.getLogger(javaClass) - val DEFAULT_CONFIG_FILENAME = "node.conf" + const val DEFAULT_CONFIG_FILENAME = "node.conf" @Suppress("LongParameterList") fun loadConfig(baseDirectory: Path, @@ -74,7 +74,7 @@ object ConfigHelper { val appConfig = ConfigFactory.parseFile(configFile.toFile(), parseOptions.setAllowMissing(allowMissingConfig)) // Detect the underlying OS. If mac or windows non-server then we assume we're running in devMode. Unless specified otherwise. - val smartDevMode = CordaSystemUtils.isOsMac() || (CordaSystemUtils.isOsWindows() && !CordaSystemUtils.getOsName().toLowerCase().contains("server")) + val smartDevMode = CordaSystemUtils.isOsMac() || (CordaSystemUtils.isOsWindows() && "server" !in CordaSystemUtils.getOsName().lowercase()) val devModeConfig = ConfigFactory.parseMap(mapOf("devMode" to smartDevMode)) // Detect the number of cores @@ -121,7 +121,7 @@ object ConfigHelper { // Reject environment variable that are in all caps // since these cannot be properties. - if (original == original.toUpperCase()){ + if (original == original.uppercase()){ return@mapKeys original } @@ -195,7 +195,7 @@ fun MutualSslConfiguration.configureDevKeyAndTrustStores(myLegalName: CordaX500N FileBasedCertificateStoreSupplier(keyStore.path, keyStore.storePassword, keyStore.entryPassword).get(true) .also { it.registerDevP2pCertificates(myLegalName) } when (cryptoService) { - is BCCryptoService, null -> { + is DefaultCryptoService, null -> { val signingKeyStore = FileBasedCertificateStoreSupplier(signingCertificateStore.path, signingCertificateStore.storePassword, signingCertificateStore.entryPassword).get(true) .also { it.installDevNodeCaCertPath(myLegalName) diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt index a5cf742a9e..02d3695995 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt @@ -77,7 +77,7 @@ interface NodeConfiguration : ConfigurationWithOptionsContainer { val baseDirectory: Path val certificatesDirectory: Path // signingCertificateStore is used to store certificate chains. - // However, BCCryptoService is reusing this to store keys as well. + // However, DefaultCryptoService is reusing this to store keys as well. val signingCertificateStore: FileBasedCertificateStoreSupplier val p2pSslOptions: MutualSslConfiguration diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt index facf8ad3f6..39abe4b4c7 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt @@ -3,7 +3,6 @@ package net.corda.node.services.config import com.typesafe.config.ConfigException import net.corda.common.configuration.parsing.internal.ConfigurationWithOptions import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.loggerFor import net.corda.core.utilities.seconds @@ -22,6 +21,7 @@ import java.time.Duration import java.util.Properties import java.util.UUID import javax.security.auth.x500.X500Principal +import kotlin.io.path.div data class NodeConfigurationImpl( /** This is not retrieved from the config file but rather from a command line argument. */ @@ -34,6 +34,7 @@ data class NodeConfigurationImpl( override val crlCheckSoftFail: Boolean, override val crlCheckArtemisServer: Boolean = Defaults.crlCheckArtemisServer, override val dataSourceProperties: Properties, + @Deprecated("Use of single compatibility zone URL is deprecated", replaceWith = ReplaceWith("networkServices.networkMapURL")) override val compatibilityZoneURL: URL? = Defaults.compatibilityZoneURL, override var networkServices: NetworkServicesConfig? = Defaults.networkServices, override val tlsCertCrlDistPoint: URL? = Defaults.tlsCertCrlDistPoint, @@ -229,11 +230,11 @@ data class NodeConfigurationImpl( private fun validateTlsCertCrlConfig(): List { val errors = mutableListOf() if (tlsCertCrlIssuer != null) { - if (tlsCertCrlDistPoint == null) { + if (tlsCertCrlDistPoint === null) { errors += "'tlsCertCrlDistPoint' is mandatory when 'tlsCertCrlIssuer' is specified" } } - if (!crlCheckSoftFail && tlsCertCrlDistPoint == null) { + if (!crlCheckSoftFail && tlsCertCrlDistPoint === null) { errors += "'tlsCertCrlDistPoint' is mandatory when 'crlCheckSoftFail' is false" } return errors diff --git a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt index 023a1e66df..2c06a0e844 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt @@ -8,7 +8,6 @@ import net.corda.common.validation.internal.Validated.Companion.invalid import net.corda.common.validation.internal.Validated.Companion.valid import net.corda.node.services.config.* import net.corda.node.services.config.NodeConfigurationImpl.Defaults -import net.corda.node.services.config.NodeConfigurationImpl.Defaults.reloadCheckpointAfterSuspend import net.corda.node.services.config.schema.parsers.* internal object V1NodeConfigurationSpec : Configuration.Specification("NodeConfiguration") { @@ -152,4 +151,4 @@ internal object V1NodeConfigurationSpec : Configuration.Specification) { notaryIdentityCache = HashSet(notaries.map { it.identity }) } -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt index c0a6ed0388..0521c97ebf 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt @@ -1,7 +1,6 @@ package net.corda.node.services.messaging import net.corda.core.internal.ThreadBox -import net.corda.core.internal.div import net.corda.core.internal.errors.AddressBindingException import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.utilities.NetworkHostAndPort @@ -46,6 +45,7 @@ import java.lang.Long.max import javax.annotation.concurrent.ThreadSafe import javax.security.auth.login.AppConfigurationEntry import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag.REQUIRED +import kotlin.io.path.div // TODO: Verify that nobody can connect to us and fiddle with our config over the socket due to the secman. // TODO: Implement a discovery engine that can trigger builds of new connections when another node registers? (later) @@ -113,7 +113,6 @@ class ArtemisMessagingServer(private val config: NodeConfiguration, registerPostQueueDeletionCallback { address, qName -> log.debug { "Queue deleted: $qName for $address" } } } - @Suppress("TooGenericExceptionCaught") try { activeMQServer.startSynchronously() } catch (e: Throwable) { @@ -170,7 +169,7 @@ class ArtemisMessagingServer(private val config: NodeConfiguration, journalBufferTimeout_NIO = journalBufferTimeout ?: ActiveMQDefaultConfiguration.getDefaultJournalBufferTimeoutNio() journalBufferTimeout_AIO = journalBufferTimeout ?: ActiveMQDefaultConfiguration.getDefaultJournalBufferTimeoutAio() journalFileSize = maxMessageSize + JOURNAL_HEADER_SIZE// The size of each journal file in bytes. Artemis default is 10MiB. - managementNotificationAddress = SimpleString(NOTIFICATIONS_ADDRESS) + managementNotificationAddress = SimpleString.of(NOTIFICATIONS_ADDRESS) // JMX enablement if (config.jmxMonitoringHttpPort != null) { @@ -190,7 +189,7 @@ class ArtemisMessagingServer(private val config: NodeConfiguration, * 4. Verifiers. These are given read access to the verification request queue and write access to the response queue. */ private fun ConfigurationImpl.configureAddressSecurity(): Configuration { - val nodeInternalRole = Role(NODE_P2P_ROLE, true, true, true, true, true, true, true, true, true, true) + val nodeInternalRole = Role(NODE_P2P_ROLE, true, true, true, true, true, true, true, true, true, true, false, false) securityRoles["$INTERNAL_PREFIX#"] = setOf(nodeInternalRole) // Do not add any other roles here as it's only for the node securityRoles["$P2P_PREFIX#"] = setOf(nodeInternalRole, restrictedRole(PEER_ROLE, send = true)) securityInvalidationInterval = SECURITY_INVALIDATION_INTERVAL @@ -201,7 +200,7 @@ class ArtemisMessagingServer(private val config: NodeConfiguration, deleteDurableQueue: Boolean = false, createNonDurableQueue: Boolean = false, deleteNonDurableQueue: Boolean = false, manage: Boolean = false, browse: Boolean = false): Role { return Role(name, send, consume, createDurableQueue, deleteDurableQueue, createNonDurableQueue, - deleteNonDurableQueue, manage, browse, createDurableQueue || createNonDurableQueue, deleteDurableQueue || deleteNonDurableQueue) + deleteNonDurableQueue, manage, browse, createDurableQueue || createNonDurableQueue, deleteDurableQueue || deleteNonDurableQueue, false, false) } private fun createArtemisSecurityManager(): ActiveMQJAASSecurityManager { diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/MessagingExecutor.kt b/node/src/main/kotlin/net/corda/node/services/messaging/MessagingExecutor.kt index 0734c958e1..148d692aba 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/MessagingExecutor.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/MessagingExecutor.kt @@ -33,8 +33,8 @@ class MessagingExecutor( val resolver: AddressToArtemisQueueResolver, val ourSenderUUID: String ) { - private val cordaVendor = SimpleString(versionInfo.vendor) - private val releaseVersion = SimpleString(versionInfo.releaseVersion) + private val cordaVendor = SimpleString.of(versionInfo.vendor) + private val releaseVersion = SimpleString.of(versionInfo.releaseVersion) private val ourSenderSeqNo = AtomicLong() private companion object { @@ -50,7 +50,7 @@ class MessagingExecutor( "Send to: $mqAddress topic: ${message.topic} " + "sessionID: ${message.topic} id: ${message.uniqueMessageId}" } - producer.send(SimpleString(mqAddress), artemisMessage) + producer.send(SimpleString.of(mqAddress), artemisMessage) } @Synchronized @@ -72,13 +72,13 @@ class MessagingExecutor( putStringProperty(P2PMessagingHeaders.cordaVendorProperty, cordaVendor) putStringProperty(P2PMessagingHeaders.releaseVersionProperty, releaseVersion) putIntProperty(P2PMessagingHeaders.platformVersionProperty, versionInfo.platformVersion) - putStringProperty(P2PMessagingHeaders.topicProperty, SimpleString(message.topic)) + putStringProperty(P2PMessagingHeaders.topicProperty, SimpleString.of(message.topic)) writeBodyBufferBytes(message.data.bytes) // Use the magic deduplication property built into Artemis as our message identity too - putStringProperty(org.apache.activemq.artemis.api.core.Message.HDR_DUPLICATE_DETECTION_ID, SimpleString(message.uniqueMessageId.toString)) + putStringProperty(org.apache.activemq.artemis.api.core.Message.HDR_DUPLICATE_DETECTION_ID, SimpleString.of(message.uniqueMessageId.toString)) // If we are the sender (ie. we are not going through recovery of some sort), use sequence number short cut. if (ourSenderUUID == message.senderUUID) { - putStringProperty(P2PMessagingHeaders.senderUUID, SimpleString(ourSenderUUID)) + putStringProperty(P2PMessagingHeaders.senderUUID, SimpleString.of(ourSenderUUID)) putLongProperty(P2PMessagingHeaders.senderSeqNo, ourSenderSeqNo.getAndIncrement()) } // For demo purposes - if set then add a delay to messages in order to demonstrate that the flows are doing as intended diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/NodeNettyAcceptorFactory.kt b/node/src/main/kotlin/net/corda/node/services/messaging/NodeNettyAcceptorFactory.kt index 69809cafc6..98e8a1603d 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/NodeNettyAcceptorFactory.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/NodeNettyAcceptorFactory.kt @@ -15,8 +15,8 @@ import net.corda.nodeapi.internal.protonwrapper.netty.sslDelegatedTaskExecutor import net.corda.nodeapi.internal.setThreadPoolName import org.apache.activemq.artemis.api.core.BaseInterceptor import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptor -import org.apache.activemq.artemis.core.server.balancing.RedirectHandler import org.apache.activemq.artemis.core.server.cluster.ClusterConnection +import org.apache.activemq.artemis.core.server.routing.RoutingHandler import org.apache.activemq.artemis.spi.core.protocol.ProtocolManager import org.apache.activemq.artemis.spi.core.remoting.Acceptor import org.apache.activemq.artemis.spi.core.remoting.AcceptorFactory @@ -44,7 +44,7 @@ class NodeNettyAcceptorFactory : AcceptorFactory { listener: ServerConnectionLifeCycleListener?, threadPool: Executor, scheduledThreadPool: ScheduledExecutorService, - protocolMap: MutableMap, RedirectHandler<*>>>?): Acceptor { + protocolMap: MutableMap, RoutingHandler<*>>>?): Acceptor { val threadPoolName = ConfigurationHelper.getStringProperty(ArtemisTcpTransport.THREAD_POOL_NAME_NAME, "Acceptor", configuration) threadPool.setThreadPoolName("$threadPoolName-artemis") scheduledThreadPool.setThreadPoolName("$threadPoolName-artemis-scheduler") @@ -70,7 +70,7 @@ class NodeNettyAcceptorFactory : AcceptorFactory { listener: ServerConnectionLifeCycleListener?, scheduledThreadPool: ScheduledExecutorService?, failureExecutor: Executor, - protocolMap: MutableMap, RedirectHandler<*>>>?, + protocolMap: MutableMap, RoutingHandler<*>>>?, private val threadPoolName: String) : NettyAcceptor(name, clusterConnection, configuration, handler, listener, scheduledThreadPool, failureExecutor, protocolMap) { diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/NodeSSLContextFactory.kt b/node/src/main/kotlin/net/corda/node/services/messaging/NodeSSLContextFactory.kt index c61e550c56..e2c49e8b83 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/NodeSSLContextFactory.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/NodeSSLContextFactory.kt @@ -7,16 +7,14 @@ import net.corda.nodeapi.internal.ArtemisTcpTransport.Companion.TRUST_MANAGER_FA import net.corda.nodeapi.internal.protonwrapper.netty.createAndInitSslContext import org.apache.activemq.artemis.core.remoting.impl.ssl.DefaultOpenSSLContextFactory import org.apache.activemq.artemis.core.remoting.impl.ssl.DefaultSSLContextFactory +import org.apache.activemq.artemis.core.remoting.impl.ssl.SSLSupport import org.apache.activemq.artemis.spi.core.remoting.ssl.SSLContextConfig import org.apache.activemq.artemis.utils.ClassloadingUtil -import org.apache.commons.io.IOUtils import java.io.File import java.io.InputStream import java.net.MalformedURLException import java.net.URL -import java.security.AccessController import java.security.KeyStore -import java.security.PrivilegedAction import javax.net.ssl.KeyManagerFactory import javax.net.ssl.SSLContext import javax.net.ssl.TrustManagerFactory @@ -80,7 +78,7 @@ private fun loadKeystore( val keyStore = keystoreProvider?.let { KeyStore.getInstance(keystoreType, it) } ?: KeyStore.getInstance(keystoreType) var inputStream : InputStream? = null try { - if (keystorePath != null && keystorePath.isNotEmpty()) { + if (!keystorePath.isNullOrEmpty()) { val keystoreURL = validateStoreURL(keystorePath) inputStream = keystoreURL.openStream() } @@ -104,25 +102,20 @@ private fun validateStoreURL(storePath: String): URL { if (file.exists() && file.isFile) { file.toURI().toURL() } else { - findResource(storePath) + ClassloadingUtil.findResource(storePath) } } } - -/** - * This is a copy of [SSLSupport.findResource] so we can have a full copy of - * [SSLSupport.validateStoreURL] and. - */ -private fun findResource(resourceName: String): URL { - return AccessController.doPrivileged(PrivilegedAction { - ClassloadingUtil.findResource(resourceName) - }) -} - - /** * This is an inline function for [InputStream] so it can be closed and * ignore an exception. */ -private fun InputStream?.closeQuietly() = IOUtils.closeQuietly(this) \ No newline at end of file +private fun InputStream?.closeQuietly() { + try { + this?.close() + } + catch ( ex : Exception ) { + // quietly absorb problems + } +} diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt index ea132130f1..33a5a8786d 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt @@ -279,8 +279,8 @@ class P2PMessagingClient(val config: NodeConfiguration, private fun InnerState.registerBridgeControl(session: ClientSession, inboxes: List) { val bridgeNotifyQueue = "$BRIDGE_NOTIFY.${myIdentity.toStringShort()}" - if (!session.queueQuery(SimpleString(bridgeNotifyQueue)).isExists) { - session.createQueue(QueueConfiguration(bridgeNotifyQueue).setAddress(BRIDGE_NOTIFY).setRoutingType(RoutingType.MULTICAST) + if (!session.queueQuery(SimpleString.of(bridgeNotifyQueue)).isExists) { + session.createQueue(QueueConfiguration.of(bridgeNotifyQueue).setAddress(BRIDGE_NOTIFY).setRoutingType(RoutingType.MULTICAST) .setTemporary(true).setDurable(false)) } val bridgeConsumer = session.createConsumer(bridgeNotifyQueue) @@ -316,7 +316,7 @@ class P2PMessagingClient(val config: NodeConfiguration, node.legalIdentitiesAndCerts.map { partyAndCertificate -> val messagingAddress = NodeAddress(partyAndCertificate.party.owningKey) BridgeEntry(messagingAddress.queueName, node.addresses, node.legalIdentities.map { it.name }, serviceAddress = false) - }.filter { producerSession!!.queueQuery(SimpleString(it.queueName)).isExists }.asSequence() + }.filter { producerSession!!.queueQuery(SimpleString.of(it.queueName)).isExists }.asSequence() } } @@ -360,7 +360,7 @@ class P2PMessagingClient(val config: NodeConfiguration, } } - val queues = session.addressQuery(SimpleString("$PEERS_PREFIX#")).queueNames + val queues = session.addressQuery(SimpleString.of("$PEERS_PREFIX#")).queueNames knownQueues.clear() for (queue in queues) { val queueQuery = session.queueQuery(queue) @@ -604,10 +604,10 @@ class P2PMessagingClient(val config: NodeConfiguration, sendBridgeCreateMessage() delayStartQueues -= queueName } else { - val queueQuery = session.queueQuery(SimpleString(queueName)) + val queueQuery = session.queueQuery(SimpleString.of(queueName)) if (!queueQuery.isExists) { log.info("Create fresh queue $queueName bound on same address") - session.createQueue(QueueConfiguration(queueName).setRoutingType(RoutingType.ANYCAST).setAddress(queueName) + session.createQueue(QueueConfiguration.of(queueName).setRoutingType(RoutingType.ANYCAST).setAddress(queueName) .setDurable(true).setAutoCreated(false) .setMaxConsumers(ActiveMQDefaultConfiguration.getDefaultMaxQueueConsumers()) .setPurgeOnNoConsumers(ActiveMQDefaultConfiguration.getDefaultPurgeOnNoConsumers()) @@ -660,7 +660,7 @@ private class P2PMessagingConsumer( private val metricsRegistry : MetricRegistry) : LifecycleSupport { private companion object { - private const val initialSessionMessages = "${P2PMessagingHeaders.Type.KEY}<>'${P2PMessagingHeaders.Type.SESSION_INIT_VALUE}'" + private const val initialSessionMessages = "${P2PMessagingHeaders.Type.KEY} is null or ${P2PMessagingHeaders.Type.KEY}<>'${P2PMessagingHeaders.Type.SESSION_INIT_VALUE}'" private val logger by lazy { loggerFor() } } diff --git a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapClient.kt b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapClient.kt index 90c962b484..79db7a7fe9 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapClient.kt @@ -62,7 +62,7 @@ class NetworkMapClient(compatibilityZoneURL: URL, private val versionInfo: Versi val connection = url.openHttpConnection() val signedNetworkMap = connection.responseAs() val networkMap = signedNetworkMap.verifiedNetworkMapCert(trustRoots) - val timeout = connection.cacheControl.maxAgeSeconds().seconds + val timeout = connection.cacheControl.maxAgeSeconds.seconds val version = connection.cordaServerVersion logger.trace { "Fetched network map update from $url successfully: $networkMap" } return NetworkMapResponse(networkMap, timeout, version) diff --git a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt index 584b050425..a65a7ff2f6 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt @@ -9,15 +9,12 @@ import net.corda.core.crypto.sha256 import net.corda.core.internal.NetworkParametersStorage import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.copyTo -import net.corda.core.internal.div -import net.corda.core.internal.exists import net.corda.core.internal.readObject import net.corda.core.internal.sign import net.corda.core.messaging.DataFeed import net.corda.core.messaging.ParametersUpdateInfo import net.corda.core.node.AutoAcceptable import net.corda.core.node.NetworkParameters -import net.corda.core.node.NodeInfo import net.corda.core.node.services.KeyManagementService import net.corda.core.serialization.serialize import net.corda.core.utilities.contextLogger @@ -44,15 +41,15 @@ import java.nio.file.Path import java.nio.file.StandardCopyOption import java.security.cert.X509Certificate import java.time.Duration -import java.util.* +import java.util.UUID import java.util.concurrent.CompletableFuture import java.util.concurrent.Executors import java.util.concurrent.ScheduledThreadPoolExecutor import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicReference -import java.util.function.Consumer -import java.util.function.Supplier +import kotlin.io.path.div +import kotlin.io.path.exists import kotlin.reflect.KProperty1 import kotlin.reflect.full.declaredMemberProperties import kotlin.reflect.full.findAnnotation @@ -247,7 +244,7 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal, networkMapClient!!.getNodeInfos() } catch (e: Exception) { logger.warn("Error encountered when downloading node infos", e) - emptyList() + emptyList() } (allHashesFromNetworkMap - nodeInfos.map { it.serialize().sha256() }).forEach { logger.warn("Error encountered when downloading node info '$it', skipping...") @@ -273,7 +270,7 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal, val networkMapDownloadFutures = hashesToFetch.chunked(max(hashesToFetch.size / threadsToUseForNetworkMapDownload, 1)) .map { nodeInfosToGet -> //for a set of chunked hashes, get the nodeInfo for each hash - CompletableFuture.supplyAsync(Supplier> { + CompletableFuture.supplyAsync({ nodeInfosToGet.mapNotNull { nodeInfo -> try { networkMapClient.getNodeInfo(nodeInfo) @@ -283,7 +280,7 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal, null } } - }, executorToUseForDownloadingNodeInfos).thenAcceptAsync(Consumer { retrievedNodeInfos -> + }, executorToUseForDownloadingNodeInfos).thenAcceptAsync({ retrievedNodeInfos -> // Add new node info to the network map cache, these could be new node info or modification of node info for existing nodes. networkMapCache.addOrUpdateNodes(retrievedNodeInfos) }, executorToUseForInsertionIntoDB) @@ -309,7 +306,7 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal, } catch (e: Exception) { // Failure to retrieve one network map using UUID shouldn't stop the whole update. logger.warn("Error encountered when downloading network map with uuid '$it', skipping...", e) - emptyList() + emptyList() } } } else { diff --git a/node/src/main/kotlin/net/corda/node/services/network/NodeInfoWatcher.kt b/node/src/main/kotlin/net/corda/node/services/network/NodeInfoWatcher.kt index d0fcfa450f..26854cacb9 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NodeInfoWatcher.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NodeInfoWatcher.kt @@ -1,7 +1,9 @@ package net.corda.node.services.network import net.corda.core.crypto.SecureHash -import net.corda.core.internal.* +import net.corda.core.internal.NODE_INFO_DIRECTORY +import net.corda.core.internal.copyTo +import net.corda.core.internal.readObject import net.corda.core.node.NodeInfo import net.corda.core.serialization.serialize import net.corda.core.utilities.contextLogger @@ -16,7 +18,11 @@ import java.nio.file.StandardCopyOption.REPLACE_EXISTING import java.nio.file.attribute.FileTime import java.time.Duration import java.util.concurrent.TimeUnit -import kotlin.streams.toList +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.getLastModifiedTime +import kotlin.io.path.isRegularFile +import kotlin.io.path.useDirectoryEntries sealed class NodeInfoUpdate { data class Add(val nodeInfo: NodeInfo) : NodeInfoUpdate() @@ -82,7 +88,7 @@ class NodeInfoWatcher(private val nodePath: Path, private fun pollDirectory(): List { logger.debug { "pollDirectory $nodeInfosDir" } val processedPaths = HashSet() - val result = nodeInfosDir.list { paths -> + val result = nodeInfosDir.useDirectoryEntries { paths -> paths .filter { logger.debug { "Examining $it" } @@ -91,7 +97,7 @@ class NodeInfoWatcher(private val nodePath: Path, .filter { !it.toString().endsWith(".tmp") } .filter { it.isRegularFile() } .filter { file -> - val lastModifiedTime = file.lastModifiedTime() + val lastModifiedTime = file.getLastModifiedTime() val previousLastModifiedTime = nodeInfoFilesMap[file]?.lastModified val newOrChangedFile = previousLastModifiedTime == null || lastModifiedTime > previousLastModifiedTime processedPaths.add(file) @@ -101,7 +107,7 @@ class NodeInfoWatcher(private val nodePath: Path, logger.debug { "Reading SignedNodeInfo from $file" } try { val nodeInfoSigned = NodeInfoAndSigned(file.readObject()) - nodeInfoFilesMap[file] = NodeInfoFromFile(nodeInfoSigned.signed.raw.hash, file.lastModifiedTime()) + nodeInfoFilesMap[file] = NodeInfoFromFile(nodeInfoSigned.signed.raw.hash, file.getLastModifiedTime()) nodeInfoSigned } catch (e: Exception) { logger.warn("Unable to read SignedNodeInfo from $file", e) diff --git a/node/src/main/kotlin/net/corda/node/services/network/PersistentPartyInfoCache.kt b/node/src/main/kotlin/net/corda/node/services/network/PersistentPartyInfoCache.kt index 6cee01c45a..9958d8ee27 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/PersistentPartyInfoCache.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/PersistentPartyInfoCache.kt @@ -15,17 +15,17 @@ class PersistentPartyInfoCache(private val networkMapCache: PersistentNetworkMap private val database: CordaPersistence) { // probably better off using a BiMap here: https://www.baeldung.com/guava-bimap - private val cordaX500NameToPartyIdCache = NonInvalidatingCache( - cacheFactory = cacheFactory, - name = "RecoveryPartyInfoCache_byCordaX500Name") { key -> - database.transaction { queryByCordaX500Name(session, key) } - } + private val cordaX500NameToPartyIdCache = NonInvalidatingCache( + cacheFactory = cacheFactory, + name = "RecoveryPartyInfoCache_byCordaX500Name" + ) { key -> database.transaction { queryByCordaX500Name(session, key) } } - private val partyIdToCordaX500NameCache = NonInvalidatingCache( - cacheFactory = cacheFactory, - name = "RecoveryPartyInfoCache_byPartyId") { key -> - database.transaction { queryByPartyId(session, key) } - } + private val partyIdToCordaX500NameCache = NonInvalidatingCache( + cacheFactory = cacheFactory, + name = "RecoveryPartyInfoCache_byPartyId" + ) { key -> + database.transaction { queryByPartyId(session, key) } + } private lateinit var trackNetworkMapUpdates: Observable diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/AbstractPartyDescriptor.kt b/node/src/main/kotlin/net/corda/node/services/persistence/AbstractPartyDescriptor.kt index b121ac9887..d4b1b66763 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/AbstractPartyDescriptor.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/AbstractPartyDescriptor.kt @@ -52,17 +52,18 @@ class AbstractPartyDescriptor(private val wellKnownPartyFromX500Name: (CordaX500 } } + @Suppress("UNCHECKED_CAST") override fun unwrap(value: AbstractParty?, type: Class, options: WrapperOptions): X? { return if (value != null) { if (AbstractParty::class.java.isAssignableFrom(type)) { return uncheckedCast(value) } if (String::class.java.isAssignableFrom(type)) { - return uncheckedCast(toString(value)) + return toString(value) as X? } throw unknownUnwrap(type) } else { null } } -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/AttachmentStorageInternal.kt b/node/src/main/kotlin/net/corda/node/services/persistence/AttachmentStorageInternal.kt index 11cb8b992b..cd90f301a0 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/AttachmentStorageInternal.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/AttachmentStorageInternal.kt @@ -6,20 +6,29 @@ import net.corda.core.node.services.AttachmentStorage import net.corda.core.node.services.vault.AttachmentQueryCriteria import net.corda.nodeapi.exceptions.DuplicateAttachmentException import java.io.InputStream +import java.nio.file.FileAlreadyExistsException import java.util.stream.Stream interface AttachmentStorageInternal : AttachmentStorage { - /** * This is the same as [importAttachment] expect there are no checks done on the uploader field. This API is internal * and is only for the node. */ - fun privilegedImportAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId + fun privilegedImportAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId { + // Default implementation is not privileged + return importAttachment(jar, uploader, filename) + } /** * Similar to above but returns existing [AttachmentId] instead of throwing [DuplicateAttachmentException] */ - fun privilegedImportOrGetAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId + fun privilegedImportOrGetAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId { + return try { + privilegedImportAttachment(jar, uploader, filename) + } catch (faee: FileAlreadyExistsException) { + AttachmentId.create(faee.message!!) + } + } /** * Get all attachments as a [Stream], filtered by the input [AttachmentQueryCriteria], @@ -27,5 +36,16 @@ interface AttachmentStorageInternal : AttachmentStorage { * * The [Stream] must be closed once used. */ - fun getAllAttachmentsByCriteria(criteria: AttachmentQueryCriteria = AttachmentQueryCriteria.AttachmentsQueryCriteria()): Stream> -} \ No newline at end of file + fun getAllAttachmentsByCriteria( + criteria: AttachmentQueryCriteria = AttachmentQueryCriteria.AttachmentsQueryCriteria() + ): Stream> { + return queryAttachments(criteria).stream().map { null to openAttachment(it)!! } + } +} + +fun AttachmentStorage.toInternal(): AttachmentStorageInternal { + return when (this) { + is AttachmentStorageInternal -> this + else -> object : AttachmentStorageInternal, AttachmentStorage by this {} + } +} diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt b/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt index 42078c9764..e36388f0e3 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt @@ -50,7 +50,6 @@ import javax.persistence.Entity import javax.persistence.Id import javax.persistence.Lob import javax.persistence.Table -import kotlin.streams.toList @Suppress("TooManyFunctions") open class DBTransactionStorage(private val database: CordaPersistence, cacheFactory: NamedCacheFactory, @@ -183,7 +182,7 @@ open class DBTransactionStorage(private val database: CordaPersistence, cacheFac private fun weighTx(actTx: TxCacheValue?): Int { if (actTx == null) return 0 - return TXCACHEVALUE_OVERHEAD_BYTES + actTx.sigs.sumBy { it.size + TRANSACTION_SIGNATURE_OVERHEAD_BYTES } + actTx.txBits.size + return TXCACHEVALUE_OVERHEAD_BYTES + actTx.sigs.sumOf { it.size + TRANSACTION_SIGNATURE_OVERHEAD_BYTES } + actTx.txBits.size } private val log = contextLogger() diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/HashedDistributionList.kt b/node/src/main/kotlin/net/corda/node/services/persistence/HashedDistributionList.kt index 5fee0f24b2..756f33a296 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/HashedDistributionList.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/HashedDistributionList.kt @@ -10,7 +10,6 @@ import java.io.DataOutputStream import java.nio.ByteBuffer import java.time.Instant -@Suppress("TooGenericExceptionCaught") @CordaSerializable data class HashedDistributionList( val senderStatesToRecord: StatesToRecord, @@ -60,7 +59,7 @@ data class HashedDistributionList( fun unauthenticatedDeserialise(encryptedBytes: ByteArray, encryptionService: EncryptionService): PublicHeader { val additionalData = encryptionService.extractUnauthenticatedAdditionalData(encryptedBytes) requireNotNull(additionalData) { "Missing additional data field" } - return deserialise(additionalData!!) + return deserialise(additionalData) } fun deserialise(bytes: ByteArray): PublicHeader { @@ -91,7 +90,7 @@ data class HashedDistributionList( fun decrypt(encryptedBytes: ByteArray, encryptionService: EncryptionService): HashedDistributionList { val (plaintext, authenticatedAdditionalData) = encryptionService.decrypt(encryptedBytes) requireNotNull(authenticatedAdditionalData) { "Missing authenticated header" } - val publicHeader = PublicHeader.deserialise(authenticatedAdditionalData!!) + val publicHeader = PublicHeader.deserialise(authenticatedAdditionalData) val input = DataInputStream(plaintext.inputStream()) try { val senderStatesToRecord = statesToRecordValues[input.readByte().toInt()] diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt index 830eecc632..e89578af87 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt @@ -28,7 +28,7 @@ import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VER import net.corda.core.internal.isUploaderTrusted import net.corda.core.internal.readFully import net.corda.core.internal.utilities.ZipBombDetector -import net.corda.core.node.ServicesForResolution +import net.corda.core.internal.verification.NodeVerificationSupport import net.corda.core.node.services.AttachmentId import net.corda.core.node.services.vault.AttachmentQueryCriteria import net.corda.core.node.services.vault.AttachmentSort @@ -53,6 +53,7 @@ import java.io.ByteArrayInputStream import java.io.FilterInputStream import java.io.IOException import java.io.InputStream +import java.nio.file.FileAlreadyExistsException import java.nio.file.Paths import java.security.PublicKey import java.time.Instant @@ -85,7 +86,7 @@ class NodeAttachmentService @JvmOverloads constructor( ) : AttachmentStorageInternal, SingletonSerializeAsToken() { // This is to break the circular dependency. - lateinit var servicesForResolution: ServicesForResolution + lateinit var nodeVerificationSupport: NodeVerificationSupport companion object { private val log = contextLogger() @@ -109,7 +110,7 @@ class NodeAttachmentService @JvmOverloads constructor( // Can be null for not-signed JARs. val allManifestEntries = jar.manifest?.entries?.keys?.toMutableList() val extraFilesNotFoundInEntries = mutableListOf() - val manifestHasEntries= allManifestEntries != null && allManifestEntries.isNotEmpty() + val manifestHasEntries = !allManifestEntries.isNullOrEmpty() while (true) { val cursor = jar.nextJarEntry ?: break @@ -225,7 +226,7 @@ class NodeAttachmentService @JvmOverloads constructor( // This is invoked by [InputStreamSerializer], which does NOT close the stream afterwards. @Throws(IOException::class) - override fun read(b: ByteArray?, off: Int, len: Int): Int { + override fun read(b: ByteArray, off: Int, len: Int): Int { return super.read(b, off, len).apply { if (this == -1) { validate() @@ -256,11 +257,11 @@ class NodeAttachmentService @JvmOverloads constructor( } private class AttachmentImpl( - override val id: SecureHash, - dataLoader: () -> ByteArray, - private val checkOnLoad: Boolean, - uploader: String?, - override val signerKeys: List + override val id: SecureHash, + dataLoader: () -> ByteArray, + private val checkOnLoad: Boolean, + uploader: String?, + override val signerKeys: List, ) : AbstractAttachment(dataLoader, uploader), SerializeAsToken { override fun open(): InputStream { @@ -270,22 +271,21 @@ class NodeAttachmentService @JvmOverloads constructor( } private class Token( - private val id: SecureHash, - private val checkOnLoad: Boolean, - private val uploader: String?, - private val signerKeys: List + private val id: SecureHash, + private val checkOnLoad: Boolean, + private val uploader: String?, + private val signerKeys: List, ) : SerializationToken { override fun fromToken(context: SerializeAsTokenContext) = AttachmentImpl( - id, - context.attachmentDataLoader(id), - checkOnLoad, - uploader, - signerKeys + id, + context.attachmentDataLoader(id), + checkOnLoad, + uploader, + signerKeys, ) } - override fun toToken(context: SerializeAsTokenContext) = - Token(id, checkOnLoad, uploader, signerKeys) + override fun toToken(context: SerializeAsTokenContext) = Token(id, checkOnLoad, uploader, signerKeys) } private val attachmentContentCache = NonInvalidatingWeightBasedCache( @@ -305,14 +305,14 @@ class NodeAttachmentService @JvmOverloads constructor( private fun createAttachmentFromDatabase(attachment: DBAttachment): Attachment { val attachmentImpl = AttachmentImpl( - id = SecureHash.create(attachment.attId), - dataLoader = { attachment.content }, - checkOnLoad = checkAttachmentsOnLoad, - uploader = attachment.uploader, - signerKeys = attachment.signers?.toList() ?: emptyList() + id = SecureHash.create(attachment.attId), + dataLoader = { attachment.content }, + checkOnLoad = checkAttachmentsOnLoad, + uploader = attachment.uploader, + signerKeys = attachment.signers?.toList() ?: emptyList() ) val contracts = attachment.contractClassNames - return if (contracts != null && contracts.isNotEmpty()) { + return if (!contracts.isNullOrEmpty()) { ContractAttachment.create( attachment = attachmentImpl, contract = contracts.first(), @@ -336,7 +336,7 @@ class NodeAttachmentService @JvmOverloads constructor( return null } - @Suppress("OverridingDeprecatedMember") + @Suppress("OVERRIDE_DEPRECATION") override fun importAttachment(jar: InputStream): AttachmentId { return import(jar, UNKNOWN_UPLOADER, null) } @@ -357,23 +357,15 @@ class NodeAttachmentService @JvmOverloads constructor( return import(jar, uploader, filename) } - override fun privilegedImportOrGetAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId { - return try { - import(jar, uploader, filename) - } catch (faee: java.nio.file.FileAlreadyExistsException) { - AttachmentId.create(faee.message!!) - } - } - override fun hasAttachment(attachmentId: AttachmentId): Boolean = database.transaction { currentDBSession().find(DBAttachment::class.java, attachmentId.toString()) != null } private fun increaseDefaultVersionIfWhitelistedAttachment(contractClassNames: List, contractVersionFromFile: Int, attachmentId: AttachmentId) = if (contractVersionFromFile == DEFAULT_CORDAPP_VERSION) { - val versions = contractClassNames.mapNotNull { servicesForResolution.networkParameters.whitelistedContractImplementations[it]?.indexOf(attachmentId) } + val versions = contractClassNames.mapNotNull { nodeVerificationSupport.networkParameters.whitelistedContractImplementations[it]?.indexOf(attachmentId) } .filter { it >= 0 }.map { it + 1 } // +1 as versions starts from 1 not 0 - val max = versions.max() + val max = versions.maxOrNull() if (max != null && max > contractVersionFromFile) { val msg = "Updating version of attachment $attachmentId from '$contractVersionFromFile' to '$max'" if (versions.toSet().size > 1) @@ -397,7 +389,7 @@ class NodeAttachmentService @JvmOverloads constructor( // set the hash field of the new attachment record. val bytes = inputStream.readFully() - require(!ZipBombDetector.scanZip(ByteArrayInputStream(bytes), servicesForResolution.networkParameters.maxTransactionSize.toLong())) { + require(!ZipBombDetector.scanZip(ByteArrayInputStream(bytes), nodeVerificationSupport.networkParameters.maxTransactionSize.toLong())) { "The attachment is too large and exceeds both max transaction size and the maximum allowed compression ratio" } val id = bytes.sha256() @@ -447,18 +439,14 @@ class NodeAttachmentService @JvmOverloads constructor( private fun getVersion(attachmentBytes: ByteArray) = JarInputStream(attachmentBytes.inputStream()).use { - try { - it.manifest?.mainAttributes?.getValue(CORDAPP_CONTRACT_VERSION)?.toInt() ?: DEFAULT_CORDAPP_VERSION - } catch (e: NumberFormatException) { - DEFAULT_CORDAPP_VERSION - } + it.manifest?.mainAttributes?.getValue(CORDAPP_CONTRACT_VERSION)?.toIntOrNull() ?: DEFAULT_CORDAPP_VERSION } - @Suppress("OverridingDeprecatedMember") + @Suppress("OVERRIDE_DEPRECATION") override fun importOrGetAttachment(jar: InputStream): AttachmentId { return try { import(jar, UNKNOWN_UPLOADER, null) - } catch (faee: java.nio.file.FileAlreadyExistsException) { + } catch (faee: FileAlreadyExistsException) { AttachmentId.create(faee.message!!) } } @@ -595,4 +583,4 @@ class NodeAttachmentService @JvmOverloads constructor( null ).resultStream.map { it.filename to createAttachmentFromDatabase(it) } } -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/PublicKeyToOwningIdentityCacheImpl.kt b/node/src/main/kotlin/net/corda/node/services/persistence/PublicKeyToOwningIdentityCacheImpl.kt index fd3d01431d..c40b9cad89 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/PublicKeyToOwningIdentityCacheImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/PublicKeyToOwningIdentityCacheImpl.kt @@ -1,6 +1,5 @@ package net.corda.node.services.persistence -import com.github.benmanes.caffeine.cache.Caffeine import net.corda.core.crypto.toStringShort import net.corda.core.internal.NamedCacheFactory import net.corda.core.utilities.contextLogger @@ -19,10 +18,7 @@ class PublicKeyToOwningIdentityCacheImpl(private val database: CordaPersistence, val log = contextLogger() } - private val cache = cacheFactory.buildNamed( - Caffeine.newBuilder(), - "PublicKeyToOwningIdentityCache_cache" - ) + private val cache = cacheFactory.buildNamed("PublicKeyToOwningIdentityCache_cache") /** * Return the owning identity associated with a given key. diff --git a/node/src/main/kotlin/net/corda/node/services/rpc/ArtemisRpcBroker.kt b/node/src/main/kotlin/net/corda/node/services/rpc/ArtemisRpcBroker.kt index 6ae79d378e..cf9162e48e 100644 --- a/node/src/main/kotlin/net/corda/node/services/rpc/ArtemisRpcBroker.kt +++ b/node/src/main/kotlin/net/corda/node/services/rpc/ArtemisRpcBroker.kt @@ -52,7 +52,6 @@ class ArtemisRpcBroker internal constructor( } } - @Suppress("TooGenericExceptionCaught") override fun start() { logger.debug { "Artemis RPC broker is starting for: $addresses" } try { @@ -90,7 +89,7 @@ class ArtemisRpcBroker internal constructor( val serverSecurityManager = createArtemisSecurityManager(serverConfiguration.loginListener) return ActiveMQServerImpl(serverConfiguration, serverSecurityManager).apply { - registerPostQueueDeletionCallback { address, qName -> logger.debug("Queue deleted: $qName for $address") } + registerPostQueueDeletionCallback { address, qName -> logger.debug { "Queue deleted: $qName for $address" } } } } diff --git a/node/src/main/kotlin/net/corda/node/services/rpc/CheckpointDumperImpl.kt b/node/src/main/kotlin/net/corda/node/services/rpc/CheckpointDumperImpl.kt index a9aceab60b..eba41dd71f 100644 --- a/node/src/main/kotlin/net/corda/node/services/rpc/CheckpointDumperImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/rpc/CheckpointDumperImpl.kt @@ -37,11 +37,7 @@ import net.corda.core.internal.FlowAsyncOperation import net.corda.core.internal.FlowIORequest import net.corda.core.internal.WaitForStateConsumption import net.corda.core.internal.declaredField -import net.corda.core.internal.div -import net.corda.core.internal.exists import net.corda.core.internal.objectOrNewInstance -import net.corda.core.internal.outputStream -import net.corda.core.internal.uncheckedCast import net.corda.core.node.AppServiceHub.Companion.SERVICE_PRIORITY_NORMAL import net.corda.core.node.ServiceHub import net.corda.core.serialization.SerializeAsToken @@ -80,12 +76,16 @@ import java.time.Duration import java.time.Instant import java.time.ZoneOffset.UTC import java.time.format.DateTimeFormatter -import java.util.* +import java.util.UUID import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger import java.util.zip.CRC32 import java.util.zip.ZipEntry import java.util.zip.ZipOutputStream +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.name +import kotlin.io.path.outputStream import kotlin.reflect.KProperty1 import kotlin.reflect.full.companionObject import kotlin.reflect.full.memberProperties @@ -107,7 +107,6 @@ class CheckpointDumperImpl(private val checkpointStorage: CheckpointStorage, pri context: CheckpointSerializationContext, runId: StateMachineRunId, flowState: FlowState.Started) { - @Suppress("TooGenericExceptionCaught") try { flowState.frozenFiber.checkpointDeserialize(context) } catch (e: Exception) { @@ -271,9 +270,9 @@ class CheckpointDumperImpl(private val checkpointStorage: CheckpointStorage, pri if(flowState is FlowState.Started) writeFiber2Zip(zip, checkpointSerializationContext, runId, flowState) } - val jarFilter = { directoryEntry : Path -> directoryEntry.fileName.toString().endsWith(".jar") } + val jarFilter = { directoryEntry : Path -> directoryEntry.name.endsWith(".jar") } //Dump cordApps jar in the "cordapp" folder - for(cordappDirectory in cordappDirectories) { + for (cordappDirectory in cordappDirectories) { val corDappJars = Files.list(cordappDirectory).filter(jarFilter).asSequence() corDappJars.forEach { corDappJar -> //Jar files are already compressed, so they are stored in the zip as they are @@ -285,7 +284,7 @@ class CheckpointDumperImpl(private val checkpointStorage: CheckpointStorage, pri // the driver jars in the driver folder of the node to the driver folder of the dump file val pairs = listOf( "lib" to FileSystems.newFileSystem( - Paths.get(System.getProperty("capsule.jar")), null).getPath("/"), + Paths.get(System.getProperty("capsule.jar"))).getPath("/"), "drivers" to baseDirectory.resolve("drivers") ) for((dest, source) in pairs) { @@ -319,7 +318,7 @@ class CheckpointDumperImpl(private val checkpointStorage: CheckpointStorage, pri } /** - * Note that this method dynamically uses [net.corda.tools.CheckpointAgent.running], make sure to keep it up to date with + * Note that this method dynamically uses `net.corda.tools.CheckpointAgent.running`, make sure to keep it up to date with * the checkpoint agent source code */ private fun checkpointAgentRunning() = try { @@ -594,6 +593,7 @@ class CheckpointDumperImpl(private val checkpointStorage: CheckpointStorage, pri gen.writeEndArray() } - override fun handledType(): Class> = uncheckedCast(Map::class.java) + @Suppress("UNCHECKED_CAST") + override fun handledType(): Class> = Map::class.java as Class> } -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/services/rpc/RPCServer.kt b/node/src/main/kotlin/net/corda/node/services/rpc/RPCServer.kt index 9d50bc72d3..20d16d996a 100644 --- a/node/src/main/kotlin/net/corda/node/services/rpc/RPCServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/rpc/RPCServer.kt @@ -321,14 +321,14 @@ class RPCServer( require(notificationType == CoreNotificationType.BINDING_REMOVED.name){"Message contained notification type of $notificationType instead of expected ${CoreNotificationType.BINDING_REMOVED.name}"} val clientAddress = artemisMessage.getStringProperty(ManagementHelper.HDR_ROUTING_NAME) log.info("Detected RPC client disconnect on address $clientAddress, scheduling for reaping") - invalidateClient(SimpleString(clientAddress)) + invalidateClient(SimpleString.of(clientAddress)) } private fun bindingAdditionArtemisMessageHandler(artemisMessage: ClientMessage) { lifeCycle.requireState(State.STARTED) val notificationType = artemisMessage.getStringProperty(ManagementHelper.HDR_NOTIFICATION_TYPE) require(notificationType == CoreNotificationType.BINDING_ADDED.name){"Message contained notification type of $notificationType instead of expected ${CoreNotificationType.BINDING_ADDED.name}"} - val clientAddress = SimpleString(artemisMessage.getStringProperty(ManagementHelper.HDR_ROUTING_NAME)) + val clientAddress = SimpleString.of(artemisMessage.getStringProperty(ManagementHelper.HDR_ROUTING_NAME)) log.debug("RPC client queue created on address $clientAddress") val buffer = stopBuffering(clientAddress) diff --git a/node/src/main/kotlin/net/corda/node/services/rpc/RpcBrokerConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/rpc/RpcBrokerConfiguration.kt index 13af138c8e..66446e76d1 100644 --- a/node/src/main/kotlin/net/corda/node/services/rpc/RpcBrokerConfiguration.kt +++ b/node/src/main/kotlin/net/corda/node/services/rpc/RpcBrokerConfiguration.kt @@ -1,6 +1,5 @@ package net.corda.node.services.rpc -import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort import net.corda.node.internal.artemis.BrokerJaasLoginModule import net.corda.node.internal.artemis.SecureArtemisConfiguration @@ -18,6 +17,7 @@ import org.apache.activemq.artemis.core.security.Role import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy import org.apache.activemq.artemis.core.settings.impl.AddressSettings import java.nio.file.Path +import kotlin.io.path.div internal class RpcBrokerConfiguration(baseDirectory: Path, maxMessageSize: Int, journalBufferTimeout: Int?, jmxEnabled: Boolean, address: NetworkHostAndPort, adminAddress: NetworkHostAndPort?, sslOptions: BrokerRpcSslOptions?, @@ -39,8 +39,8 @@ internal class RpcBrokerConfiguration(baseDirectory: Path, maxMessageSize: Int, queueConfigs = queueConfigurations() - managementNotificationAddress = SimpleString(ArtemisMessagingComponent.NOTIFICATIONS_ADDRESS) - addressesSettings = mapOf( + managementNotificationAddress = SimpleString.of(ArtemisMessagingComponent.NOTIFICATIONS_ADDRESS) + addressSettings = mapOf( "${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.#" to AddressSettings().apply { maxSizeBytes = 5L * maxMessageSize addressFullMessagePolicy = AddressFullMessagePolicy.PAGE @@ -51,7 +51,7 @@ internal class RpcBrokerConfiguration(baseDirectory: Path, maxMessageSize: Int, globalMaxSize = Runtime.getRuntime().maxMemory() / 8 initialiseSettings(maxMessageSize, journalBufferTimeout) - val nodeInternalRole = Role(BrokerJaasLoginModule.NODE_RPC_ROLE, true, true, true, true, true, true, true, true, true, true) + val nodeInternalRole = Role(BrokerJaasLoginModule.NODE_RPC_ROLE, true, true, true, true, true, true, true, true, true, true, false, false) val addRPCRoleToUsers = if (shouldStartLocalShell) listOf(INTERNAL_SHELL_USER) else emptyList() val rolesAdderOnLogin = RolesAdderOnLogin(addRPCRoleToUsers) { username -> @@ -127,12 +127,12 @@ internal class RpcBrokerConfiguration(baseDirectory: Path, maxMessageSize: Int, } private fun queueConfiguration(name: String, address: String = name, filter: String? = null, durable: Boolean): QueueConfiguration { - return QueueConfiguration(name).setAddress(address).setFilterString(filter).setDurable(durable) + return QueueConfiguration.of(name).setAddress(address).setFilterString(filter).setDurable(durable) } private fun restrictedRole(name: String, send: Boolean = false, consume: Boolean = false, createDurableQueue: Boolean = false, deleteDurableQueue: Boolean = false, createNonDurableQueue: Boolean = false, deleteNonDurableQueue: Boolean = false, manage: Boolean = false, browse: Boolean = false): Role { - return Role(name, send, consume, createDurableQueue, deleteDurableQueue, createNonDurableQueue, deleteNonDurableQueue, manage, browse, createDurableQueue || createNonDurableQueue, deleteDurableQueue || deleteNonDurableQueue) + return Role(name, send, consume, createDurableQueue, deleteDurableQueue, createNonDurableQueue, deleteNonDurableQueue, manage, browse, createDurableQueue || createNonDurableQueue, deleteDurableQueue || deleteNonDurableQueue, false, false) } } \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/ActionExecutorImpl.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/ActionExecutorImpl.kt index 87b4a508c5..9b3391cc43 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/ActionExecutorImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/ActionExecutorImpl.kt @@ -112,7 +112,6 @@ internal class ActionExecutorImpl( } } - @Suppress("TooGenericExceptionCaught") // this is fully intentional here, see comment in the catch clause @Suspendable private fun executeAcknowledgeMessages(action: Action.AcknowledgeMessages) { action.deduplicationHandlers.forEach { @@ -231,7 +230,6 @@ internal class ActionExecutorImpl( action.currentState.run { numberOfCommits = checkpoint.checkpointState.numberOfCommits } } - @Suppress("TooGenericExceptionCaught") @Suspendable private fun executeAsyncOperation(fiber: FlowFiber, action: Action.ExecuteAsyncOperation) { try { diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowCreator.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowCreator.kt index 504faa9995..a9461d643d 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowCreator.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowCreator.kt @@ -174,7 +174,6 @@ class FlowCreator( return Flow(flowStateMachineImpl, resultFuture) } - @Suppress("TooGenericExceptionCaught") private fun Checkpoint.getFiberFromCheckpoint(runId: StateMachineRunId, firstRestore: Boolean): FlowStateMachineImpl<*>? { try { return when(flowState) { @@ -214,7 +213,7 @@ class FlowCreator( } private fun verifyFlowLogicIsSuspendable(logic: FlowLogic) { - // Quasar requires (in Java 8) that at least the call method be annotated suspendable. Unfortunately, it's + // Quasar requires that at least the call method be annotated suspendable. Unfortunately, it's // easy to forget to add this when creating a new flow, so we check here to give the user a better error. // // The Kotlin compiler can sometimes generate a synthetic bridge method from a single call declaration, which diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowDefaultUncaughtExceptionHandler.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowDefaultUncaughtExceptionHandler.kt index a77967258d..607d99ad76 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowDefaultUncaughtExceptionHandler.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowDefaultUncaughtExceptionHandler.kt @@ -63,7 +63,6 @@ internal class FlowDefaultUncaughtExceptionHandler( scheduledExecutor.schedule({ setFlowToHospitalizedRescheduleOnFailure(id) }, 0, TimeUnit.SECONDS) } - @Suppress("TooGenericExceptionCaught") private fun setFlowToHospitalizedRescheduleOnFailure(id: StateMachineRunId) { try { innerState.withLock { diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowLogicRefFactoryImpl.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowLogicRefFactoryImpl.kt index dfd2b1a8db..178182a9d9 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowLogicRefFactoryImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowLogicRefFactoryImpl.kt @@ -3,10 +3,12 @@ package net.corda.node.services.statemachine import com.google.common.primitives.Primitives import net.corda.core.flows.* import net.corda.core.internal.VisibleForTesting +import net.corda.core.internal.loadClassOfType import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.utilities.contextLogger import org.slf4j.Logger +import java.lang.ClassCastException import java.lang.reflect.ParameterizedType import java.lang.reflect.Type import java.lang.reflect.TypeVariable @@ -57,13 +59,13 @@ open class FlowLogicRefFactoryImpl(private val classloader: ClassLoader) : Singl } private fun validatedFlowClassFromName(flowClassName: String): Class> { - val forName = try { - Class.forName(flowClassName, true, classloader) + return try { + loadClassOfType>(flowClassName, true, classloader) } catch (e: ClassNotFoundException) { throw IllegalFlowLogicException(flowClassName, "Flow not found: $flowClassName") - } - return forName.asSubclass(FlowLogic::class.java) ?: + } catch (e: ClassCastException) { throw IllegalFlowLogicException(flowClassName, "The class $flowClassName is not a subclass of FlowLogic.") + } } override fun createForRPC(flowClass: Class>, vararg args: Any?): FlowLogicRef { diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt index 56a983cf3d..ad7603463b 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt @@ -1,7 +1,6 @@ package net.corda.node.services.statemachine import co.paralleluniverse.fibers.Fiber -import co.paralleluniverse.fibers.Fiber.parkAndSerialize import co.paralleluniverse.fibers.FiberScheduler import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.strands.Strand @@ -32,13 +31,12 @@ import net.corda.core.internal.IdempotentFlow import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.concurrent.OpenFuture import net.corda.core.internal.isIdempotentFlow -import net.corda.core.internal.isRegularFile import net.corda.core.internal.location -import net.corda.core.internal.toPath -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.internal.toPath +import net.corda.core.internal.uncheckedCast import net.corda.core.serialization.SerializationDefaults import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.internal.CheckpointSerializationContext @@ -48,7 +46,6 @@ import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.Try import net.corda.core.utilities.debug import net.corda.core.utilities.trace -import net.corda.node.internal.cordapp.CordappProviderImpl import net.corda.node.services.api.FlowAppAuditEvent import net.corda.node.services.api.FlowPermissionAuditEvent import net.corda.node.services.api.ServiceHubInternal @@ -66,6 +63,7 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import org.slf4j.MDC import java.util.concurrent.TimeUnit +import kotlin.io.path.isRegularFile class FlowPermissionException(message: String) : FlowException(message) @@ -322,7 +320,7 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, 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 + Thread.currentThread().contextClassLoader = serviceHub.cordappProvider.appClassLoader val threadLocal = transientValues.database.hikariPoolThreadLocal if (threadLocal != null) { val valueFromThread = swappedOutThreadLocalValue(threadLocal) @@ -351,7 +349,7 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, // 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 + Thread.currentThread().contextClassLoader = serviceHub.cordappProvider.appClassLoader // context.serializedTelemetry is from an rpc client, serializedTelemetry is from a peer, otherwise nothing val serializedTelemetrySrc = context.serializedTelemetry ?: serializedTelemetry diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/SingleThreadedStateMachineManager.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/SingleThreadedStateMachineManager.kt index 7d22beb30b..9f6e0eca97 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/SingleThreadedStateMachineManager.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/SingleThreadedStateMachineManager.kt @@ -61,7 +61,6 @@ import javax.annotation.concurrent.ThreadSafe import kotlin.collections.component1 import kotlin.collections.component2 import kotlin.collections.set -import kotlin.streams.toList /** * The StateMachineManagerImpl will always invoke the flow fibers on the given [AffinityExecutor], regardless of which @@ -183,7 +182,7 @@ internal class SingleThreadedStateMachineManager( ) val (flows, pausedFlows) = restoreFlowsFromCheckpoints() - metrics.register("Flows.InFlight", Gauge { innerState.flows.size }) + metrics.register("Flows.InFlight", Gauge { innerState.flows.size }) setFlowDefaultUncaughtExceptionHandler() @@ -634,7 +633,7 @@ internal class SingleThreadedStateMachineManager( } } - @Suppress("TooGenericExceptionCaught", "ComplexMethod", "MaxLineLength") // this is fully intentional here, see comment in the catch clause + @Suppress("ComplexMethod", "MaxLineLength") // this is fully intentional here, see comment in the catch clause override fun retryFlowFromSafePoint(currentState: StateMachineState) { currentState.cancelFutureIfRunning() // Get set of external events @@ -974,7 +973,7 @@ internal class SingleThreadedStateMachineManager( } totalStartedFlows.inc() addAndStartFlow(flowId, flow) - return startedFuture.map { flow.fiber as FlowStateMachine } + return startedFuture.map { flow.fiber } } override fun scheduleFlowTimeout(flowId: StateMachineRunId) { @@ -1062,6 +1061,7 @@ internal class SingleThreadedStateMachineManager( Fiber.unparkDeserialized(flow.fiber, scheduler) } is FlowState.Finished -> throw IllegalStateException("Cannot start (or resume) a finished flow.") + is FlowState.Paused -> { /* Do Nothing. */ } } } @@ -1228,7 +1228,7 @@ internal class SingleThreadedStateMachineManager( override val logic: Nothing? = null override val id: StateMachineRunId = id override val resultFuture: CordaFuture = resultFuture - override val clientId: String? = clientId + override val clientId: String = clientId } ) @@ -1239,7 +1239,8 @@ internal class SingleThreadedStateMachineManager( null } else { val existingFuture = activeOrRemovedClientIdFutureForReattach(it, clientId) - uncheckedCast(existingFuture?.let {existingFuture.get() }) + @Suppress("UNCHECKED_CAST") + existingFuture?.let {existingFuture.get() } as FlowStateMachineHandle } } } diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/StaffedFlowHospital.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/StaffedFlowHospital.kt index e853cd66a5..ebeacb33c7 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/StaffedFlowHospital.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/StaffedFlowHospital.kt @@ -31,6 +31,7 @@ import java.sql.SQLTransientConnectionException import java.time.Clock import java.time.Duration import java.time.Instant +import java.util.Locale import java.util.Timer import java.util.concurrent.ConcurrentHashMap import javax.persistence.PersistenceException @@ -305,11 +306,11 @@ class StaffedFlowHospital(private val flowMessaging: FlowMessaging, log.info("Error ${index + 1} of ${errors.size}:", error) val diagnoses: Map> = staff.groupBy { it.consult(flowFiber, currentState, error, medicalHistory) } // We're only interested in the highest priority diagnosis for the error - val (diagnosis, by) = diagnoses.entries.minBy { it.key }!! + val (diagnosis, by) = diagnoses.entries.minBy { it.key } ConsultationReport(error, diagnosis, by) } // And we're only interested in the error with the highest priority diagnosis - .minBy { it.diagnosis }!! + .minBy { it.diagnosis } } private data class ConsultationReport(val error: Throwable, val diagnosis: Diagnosis, val by: List) @@ -726,7 +727,7 @@ private fun Throwable?.mentionsThrowable(exceptionType: Class return false } val containsMessage = if (errorMessage != null) { - message?.toLowerCase()?.contains(errorMessage) ?: false + message?.lowercase(Locale.getDefault())?.contains(errorMessage) ?: false } else { true } diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/transitions/StartedFlowTransition.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/transitions/StartedFlowTransition.kt index b0c2020802..fd3491376e 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/transitions/StartedFlowTransition.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/transitions/StartedFlowTransition.kt @@ -131,7 +131,6 @@ class StartedFlowTransition( } } - @Suppress("TooGenericExceptionCaught") private fun sendAndReceiveTransition(flowIORequest: FlowIORequest.SendAndReceive): TransitionResult { val sessionIdToMessage = LinkedHashMap>() val sessionIdToSession = LinkedHashMap() @@ -195,7 +194,6 @@ class StartedFlowTransition( } } - @Suppress("TooGenericExceptionCaught") private fun receiveTransition(flowIORequest: FlowIORequest.Receive): TransitionResult { return builder { val sessionIdToSession = LinkedHashMap() @@ -279,9 +277,7 @@ class StartedFlowTransition( var index = 0 for (sourceSessionId in sessionIdToSession.keys) { val sessionState = checkpoint.checkpointState.sessions[sourceSessionId] - if (sessionState == null) { - return freshErrorTransition(CannotFindSessionException(sourceSessionId)) - } + ?: return freshErrorTransition(CannotFindSessionException(sourceSessionId)) if (sessionState !is SessionState.Uninitiated) { continue } diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/transitions/TopLevelTransition.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/transitions/TopLevelTransition.kt index 19de1970b7..513e09d3a0 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/transitions/TopLevelTransition.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/transitions/TopLevelTransition.kt @@ -42,7 +42,7 @@ class TopLevelTransition( val log = contextLogger() } - @Suppress("ComplexMethod", "TooGenericExceptionCaught") + @Suppress("ComplexMethod") override fun transition(): TransitionResult { return try { if (startingState.isKilled) { diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/InMemoryTransactionVerifierService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/InMemoryTransactionVerifierService.kt deleted file mode 100644 index e70712e9e0..0000000000 --- a/node/src/main/kotlin/net/corda/node/services/transactions/InMemoryTransactionVerifierService.kt +++ /dev/null @@ -1,120 +0,0 @@ -package net.corda.node.services.transactions - -import net.corda.core.concurrent.CordaFuture -import net.corda.core.contracts.Attachment -import net.corda.core.contracts.TransactionVerificationException.BrokenTransactionException -import net.corda.core.internal.TransactionVerifierServiceInternal -import net.corda.core.internal.concurrent.openFuture -import net.corda.core.internal.internalFindTrustedAttachmentForClass -import net.corda.core.internal.prepareVerify -import net.corda.core.node.services.AttachmentStorage -import net.corda.core.node.services.TransactionVerifierService -import net.corda.core.serialization.SingletonSerializeAsToken -import net.corda.core.transactions.LedgerTransaction -import net.corda.core.utilities.contextLogger -import net.corda.node.internal.cordapp.CordappProviderInternal -import net.corda.nodeapi.internal.persistence.withoutDatabaseAccess - -class InMemoryTransactionVerifierService( - @Suppress("UNUSED_PARAMETER") numberOfWorkers: Int, - private val cordappProvider: CordappProviderInternal, - private val attachments: AttachmentStorage -) : SingletonSerializeAsToken(), TransactionVerifierService, TransactionVerifierServiceInternal, AutoCloseable { - companion object { - private val SEPARATOR = System.lineSeparator() + "-> " - private val log = contextLogger() - - fun Collection<*>.deepEquals(other: Collection<*>): Boolean { - return size == other.size && containsAll(other) && other.containsAll(this) - } - - fun Collection.toPrettyString(): String { - return joinToString(separator = SEPARATOR, prefix = SEPARATOR, postfix = System.lineSeparator()) { attachment -> - attachment.id.toString() - } - } - } - - override fun verify(transaction: LedgerTransaction): CordaFuture<*> { - return openFuture().apply { - capture { - val verifier = transaction.prepareVerify(transaction.attachments) - withoutDatabaseAccess { - verifier.verify() - } - } - } - } - - private fun computeReplacementAttachmentsFor(ltx: LedgerTransaction, missingClass: String?): Collection { - val replacements = cordappProvider.fixupAttachments(ltx.attachments) - return if (replacements.deepEquals(ltx.attachments)) { - /* - * We cannot continue unless we have some idea which - * class is missing from the attachments. - */ - if (missingClass == null) { - throw BrokenTransactionException( - txId = ltx.id, - message = "No fix-up rules provided for broken attachments:${replacements.toPrettyString()}" - ) - } - - /* - * The Node's fix-up rules have not been able to adjust the transaction's attachments, - * so resort to the original mechanism of trying to find an attachment that contains - * the missing class. (Do you feel lucky, Punk?) - */ - val extraAttachment = requireNotNull(attachments.internalFindTrustedAttachmentForClass(missingClass)) { - """Transaction $ltx is incorrectly formed. Most likely it was created during version 3 of Corda - |when the verification logic was more lenient. Attempted to find local dependency for class: $missingClass, - |but could not find one. - |If you wish to verify this transaction, please contact the originator of the transaction and install the - |provided missing JAR. - |You can install it using the RPC command: `uploadAttachment` without restarting the node. - |""".trimMargin() - } - - replacements.toMutableSet().apply { - /* - * Check our transaction doesn't already contain this extra attachment. - * It seems unlikely that we would, but better safe than sorry! - */ - if (!add(extraAttachment)) { - throw BrokenTransactionException( - txId = ltx.id, - message = "Unlinkable class $missingClass inside broken attachments:${replacements.toPrettyString()}" - ) - } - - log.warn("""Detected that transaction $ltx does not contain all cordapp dependencies. - |This may be the result of a bug in a previous version of Corda. - |Attempting to verify using the additional trusted dependency: $extraAttachment for class $missingClass. - |Please check with the originator that this is a valid transaction. - |YOU ARE ONLY SEEING THIS MESSAGE BECAUSE THE CORDAPPS THAT CREATED THIS TRANSACTION ARE BROKEN! - |WE HAVE TRIED TO REPAIR THE TRANSACTION AS BEST WE CAN, BUT CANNOT GUARANTEE WE HAVE SUCCEEDED! - |PLEASE FIX THE CORDAPPS AND MIGRATE THESE BROKEN TRANSACTIONS AS SOON AS POSSIBLE! - |THIS MESSAGE IS **SUPPOSED** TO BE SCARY!! - |""".trimMargin() - ) - } - } else { - replacements - } - } - - override fun reverifyWithFixups(transaction: LedgerTransaction, missingClass: String?): CordaFuture<*> { - return openFuture().apply { - capture { - val replacementAttachments = computeReplacementAttachmentsFor(transaction, missingClass) - log.warn("Reverifying transaction {} with attachments:{}", transaction.id, replacementAttachments.toPrettyString()) - val verifier = transaction.prepareVerify(replacementAttachments.toList()) - withoutDatabaseAccess { - verifier.verify() - } - } - } - } - - override fun close() {} -} diff --git a/node/src/main/kotlin/net/corda/node/services/vault/HibernateQueryCriteriaParser.kt b/node/src/main/kotlin/net/corda/node/services/vault/HibernateQueryCriteriaParser.kt index b5f9b327c2..a29c36e9d8 100644 --- a/node/src/main/kotlin/net/corda/node/services/vault/HibernateQueryCriteriaParser.kt +++ b/node/src/main/kotlin/net/corda/node/services/vault/HibernateQueryCriteriaParser.kt @@ -82,9 +82,9 @@ abstract class AbstractQueryCriteriaParser, in P: column as Path when (columnPredicate.operator) { EQUAL -> criteriaBuilder.equal(column, literal) - EQUAL_IGNORE_CASE -> criteriaBuilder.equal(criteriaBuilder.upper(column), literal.toUpperCase()) + EQUAL_IGNORE_CASE -> criteriaBuilder.equal(criteriaBuilder.upper(column), literal.uppercase(Locale.getDefault())) NOT_EQUAL -> criteriaBuilder.notEqual(column, literal) - NOT_EQUAL_IGNORE_CASE -> criteriaBuilder.notEqual(criteriaBuilder.upper(column), literal.toUpperCase()) + NOT_EQUAL_IGNORE_CASE -> criteriaBuilder.notEqual(criteriaBuilder.upper(column), literal.uppercase(Locale.getDefault())) } } else { when (columnPredicate.operator) { @@ -111,9 +111,9 @@ abstract class AbstractQueryCriteriaParser, in P: column as Path return when (columnPredicate.operator) { LIKE -> criteriaBuilder.like(column, columnPredicate.rightLiteral) - LIKE_IGNORE_CASE -> criteriaBuilder.like(criteriaBuilder.upper(column), columnPredicate.rightLiteral.toUpperCase()) + LIKE_IGNORE_CASE -> criteriaBuilder.like(criteriaBuilder.upper(column), columnPredicate.rightLiteral.uppercase(Locale.getDefault())) NOT_LIKE -> criteriaBuilder.notLike(column, columnPredicate.rightLiteral) - NOT_LIKE_IGNORE_CASE -> criteriaBuilder.notLike(criteriaBuilder.upper(column), columnPredicate.rightLiteral.toUpperCase()) + NOT_LIKE_IGNORE_CASE -> criteriaBuilder.notLike(criteriaBuilder.upper(column), columnPredicate.rightLiteral.uppercase(Locale.getDefault())) } } @@ -126,9 +126,9 @@ abstract class AbstractQueryCriteriaParser, in P: literal as Collection when (columnPredicate.operator) { IN -> column.`in`(literal) - IN_IGNORE_CASE -> criteriaBuilder.upper(column).`in`(literal.map { it.toUpperCase() }) + IN_IGNORE_CASE -> criteriaBuilder.upper(column).`in`(literal.map { it.uppercase(Locale.getDefault()) }) NOT_IN -> criteriaBuilder.not(column.`in`(literal)) - NOT_IN_IGNORE_CASE -> criteriaBuilder.not(criteriaBuilder.upper(column).`in`(literal.map { it.toUpperCase() })) + NOT_IN_IGNORE_CASE -> criteriaBuilder.not(criteriaBuilder.upper(column).`in`(literal.map { it.uppercase(Locale.getDefault()) })) } } else { when (columnPredicate.operator) { diff --git a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt index e0fdce29c0..7ac437fe10 100644 --- a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt +++ b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt @@ -19,8 +19,10 @@ import net.corda.core.internal.ThreadBox import net.corda.core.internal.TransactionDeserialisationException import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.bufferUntilSubscribed +import net.corda.core.internal.mapToSet import net.corda.core.internal.tee import net.corda.core.internal.uncheckedCast +import net.corda.core.internal.verification.VerifyingServiceHub import net.corda.core.internal.warnOnce import net.corda.core.messaging.DataFeed import net.corda.core.node.StatesToRecord @@ -50,7 +52,6 @@ import net.corda.core.utilities.contextLogger import net.corda.core.utilities.debug import net.corda.core.utilities.toNonEmptySet import net.corda.core.utilities.trace -import net.corda.node.internal.NodeServicesForResolution import net.corda.node.services.api.SchemaService import net.corda.node.services.api.VaultServiceInternal import net.corda.node.services.schema.PersistentStateService @@ -69,7 +70,6 @@ import java.security.PublicKey import java.sql.SQLException import java.time.Clock import java.time.Instant -import java.util.Arrays import java.util.UUID import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.CopyOnWriteArraySet @@ -97,7 +97,7 @@ import kotlin.collections.component2 class NodeVaultService( private val clock: Clock, private val keyManagementService: KeyManagementService, - private val servicesForResolution: NodeServicesForResolution, + private val serviceHub: VerifyingServiceHub, private val database: CordaPersistence, schemaService: SchemaService, private val appClassloader: ClassLoader @@ -230,7 +230,7 @@ class NodeVaultService( // Persist the consumed inputs. consumedStateRefs.forEach { stateRef -> - val state = session.get(VaultSchemaV1.VaultStates::class.java, PersistentStateRef(stateRef)) + val state = session.get(VaultSchemaV1.VaultStates::class.java, PersistentStateRef(stateRef)) state?.run { // Only update the state if it has not previously been consumed (this could have happened if the transaction is being // re-recorded. @@ -313,7 +313,7 @@ class NodeVaultService( fun withValidDeserialization(list: List, txId: SecureHash): Map { var error: TransactionDeserialisationException? = null - val map = (0 until list.size).mapNotNull { idx -> + val map = list.indices.mapNotNull { idx -> try { idx to list[idx] } catch (e: TransactionDeserialisationException) { @@ -357,7 +357,7 @@ class NodeVaultService( val outputRefs = tx.outRefsOfType().map { it.ref } val seenRefs = loadStates(outputRefs).map { it.ref } val unseenRefs = outputRefs - seenRefs - val unseenOutputIdxs = unseenRefs.map { it.index }.toSet() + val unseenOutputIdxs = unseenRefs.mapToSet { it.index } outputs.filter { it.key in unseenOutputIdxs } } else { outputs @@ -386,7 +386,7 @@ class NodeVaultService( StatesToRecord.ALL_VISIBLE, StatesToRecord.ONLY_RELEVANT -> { val notSeenReferences = tx.references - loadStates(tx.references).map { it.ref } // TODO: This is expensive - is there another way? - tx.toLedgerTransaction(servicesForResolution).deserializableRefStates() + tx.toLedgerTransaction(serviceHub).deserializableRefStates() .filter { (_, stateAndRef) -> stateAndRef.ref in notSeenReferences } .values } @@ -401,8 +401,8 @@ class NodeVaultService( // We also can't do filtering beforehand, since for notary change transactions output encumbrance pointers // get recalculated based on input positions. val ltx: FullTransaction = when (tx) { - is NotaryChangeWireTransaction -> tx.resolve(servicesForResolution, emptyList()) - is ContractUpgradeWireTransaction -> tx.resolve(servicesForResolution, emptyList()) + is NotaryChangeWireTransaction -> tx.resolve(serviceHub, emptyList()) + is ContractUpgradeWireTransaction -> tx.resolve(serviceHub, emptyList()) else -> throw IllegalArgumentException("Unsupported transaction type: ${tx.javaClass.name}") } val myKeys by lazy { keyManagementService.filterMyKeys(ltx.outputs.flatMap { it.data.participants.map { it.owningKey } }) } @@ -545,8 +545,8 @@ class NodeVaultService( val stateStatusPredication = criteriaBuilder.equal(get(VaultSchemaV1.VaultStates::stateStatus.name), Vault.StateStatus.UNCONSUMED) val lockIdPredicate = criteriaBuilder.or(get(VaultSchemaV1.VaultStates::lockId.name).isNull, criteriaBuilder.equal(get(VaultSchemaV1.VaultStates::lockId.name), lockId.toString())) - update.set(get(VaultSchemaV1.VaultStates::lockId.name), lockId.toString()) - update.set(get(VaultSchemaV1.VaultStates::lockUpdateTime.name), softLockTimestamp) + update.set(get(VaultSchemaV1.VaultStates::lockId.name), lockId.toString()) + update.set(get(VaultSchemaV1.VaultStates::lockUpdateTime.name), softLockTimestamp) update.where(stateStatusPredication, lockIdPredicate, *commonPredicates) } if (updatedRows > 0 && updatedRows == stateRefs.size) { @@ -599,8 +599,8 @@ class NodeVaultService( criteriaBuilder.executeUpdate(session, stateRefs) { update, persistentStateRefs -> val stateStatusPredication = criteriaBuilder.equal(get(VaultSchemaV1.VaultStates::stateStatus.name), Vault.StateStatus.UNCONSUMED) val lockIdPredicate = criteriaBuilder.equal(get(VaultSchemaV1.VaultStates::lockId.name), lockId.toString()) - update.set(get(VaultSchemaV1.VaultStates::lockId.name), criteriaBuilder.nullLiteral(String::class.java)) - update.set(get(VaultSchemaV1.VaultStates::lockUpdateTime.name), softLockTimestamp) + update.set(get(VaultSchemaV1.VaultStates::lockId.name), criteriaBuilder.nullLiteral(String::class.java)) + update.set(get(VaultSchemaV1.VaultStates::lockUpdateTime.name), softLockTimestamp) configure(update, arrayOf(stateStatusPredication, lockIdPredicate), persistentStateRefs) } @@ -751,16 +751,13 @@ class NodeVaultService( if (result0 is VaultSchemaV1.VaultStates) { statesMetadata.add(result0.toStateMetadata()) } else { - log.debug { "OtherResults: ${Arrays.toString(result.toArray())}" } + log.debug { "OtherResults: ${result.toArray().contentToString()}" } otherResults.addAll(result.toArray().asList()) } } } - val states: List> = servicesForResolution.loadStates( - statesMetadata.mapTo(LinkedHashSet()) { it.ref }, - ArrayList() - ) + val states: List> = serviceHub.loadStatesInternal(statesMetadata.mapToSet { it.ref }, ArrayList()) val totalStatesAvailable = when { paging.isDefault -> -1L @@ -842,14 +839,14 @@ class NodeVaultService( @Throws(VaultQueryException::class) override fun _trackBy(criteria: QueryCriteria, paging: PageSpecification, sorting: Sort, contractStateType: Class): DataFeed, Vault.Update> { return mutex.locked { - val updates: Observable> = uncheckedCast(_updatesPublisher.bufferUntilSubscribed()) + @Suppress("UNCHECKED_CAST") + val updates: Observable> = _updatesPublisher.bufferUntilSubscribed() as Observable> if (contextTransactionOrNull != null) { log.warn("trackBy is called with an already existing, open DB transaction. As a result, there might be states missing from both the snapshot and observable, included in the returned data feed, because of race conditions.") } val snapshotResults = _queryBy(criteria, paging, sorting, contractStateType) - val snapshotStatesRefs = snapshotResults.statesMetadata.map { it.ref }.toSet() - val snapshotConsumedStatesRefs = snapshotResults.statesMetadata.filter { it.consumedTime != null } - .map { it.ref }.toSet() + val snapshotStatesRefs = snapshotResults.statesMetadata.mapToSet { it.ref } + val snapshotConsumedStatesRefs = snapshotResults.statesMetadata.filter { it.consumedTime != null }.mapToSet { it.ref } val filteredUpdates = updates.filter { it.containsType(contractStateType, snapshotResults.stateTypes) } .map { filterContractStates(it, contractStateType) } .filter { !hasBeenSeen(it, snapshotStatesRefs, snapshotConsumedStatesRefs) } @@ -884,8 +881,8 @@ class NodeVaultService( * the snapshot or in the observable). */ private fun hasBeenSeen(update: Vault.Update, snapshotStatesRefs: Set, snapshotConsumedStatesRefs: Set): Boolean { - val updateProducedStatesRefs = update.produced.map { it.ref }.toSet() - val updateConsumedStatesRefs = update.consumed.map { it.ref }.toSet() + val updateProducedStatesRefs = update.produced.mapToSet { it.ref } + val updateConsumedStatesRefs = update.consumed.mapToSet { it.ref } return snapshotStatesRefs.containsAll(updateProducedStatesRefs) && snapshotConsumedStatesRefs.containsAll(updateConsumedStatesRefs) } @@ -969,4 +966,4 @@ private fun CriteriaBuilder.executeUpdate( } /** The Observable returned allows subscribing with custom SafeSubscribers to source [Observable]. */ -internal fun Observable.resilientOnError(): Observable = Observable.unsafeCreate(OnResilientSubscribe(this, false)) \ No newline at end of file +internal fun Observable.resilientOnError(): Observable = Observable.unsafeCreate(OnResilientSubscribe(this, false)) diff --git a/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt b/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt index 98de78ac0c..25938e6fb1 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt @@ -1,8 +1,6 @@ package net.corda.node.utilities import com.github.benmanes.caffeine.cache.LoadingCache -import com.github.benmanes.caffeine.cache.Weigher -import net.corda.core.crypto.SecureHash import net.corda.core.internal.NamedCacheFactory import net.corda.core.utilities.contextLogger import net.corda.nodeapi.internal.persistence.DatabaseTransaction @@ -10,7 +8,6 @@ import net.corda.nodeapi.internal.persistence.contextTransaction import net.corda.nodeapi.internal.persistence.currentDBSession import org.hibernate.Session import org.hibernate.internal.SessionImpl -import java.util.* import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicReference @@ -22,7 +19,8 @@ import java.util.stream.Stream * * This class relies heavily on the fact that compute operations in the cache are atomic for a particular key. */ -abstract class AppendOnlyPersistentMapBase( +@Suppress("TooManyFunctions") +abstract class AppendOnlyPersistentMapBase( val toPersistentEntityKey: (K) -> EK, val fromPersistentEntity: (E) -> Pair, val toPersistentEntity: (key: K, value: V) -> E, @@ -249,7 +247,7 @@ abstract class AppendOnlyPersistentMapBase( cache.invalidateAll() } - fun clear(id: SecureHash) = cache.invalidate(id) + fun clear(id: K) = cache.invalidate(id) // Helpers to know if transaction(s) are currently writing the given key. private fun weAreWriting(key: K): Boolean = pendingKeys[key]?.transactions?.contains(contextTransaction) ?: false @@ -326,9 +324,9 @@ abstract class AppendOnlyPersistentMapBase( } // No one is writing, but we haven't looked in the database yet. This can only be when there are no writers. - class Unknown(private val map: AppendOnlyPersistentMapBase, - private val key: K, - private val _valueLoader: () -> T?) : Transactional() { + class Unknown(private val map: AppendOnlyPersistentMapBase, + private val key: K, + private val _valueLoader: () -> T?) : Transactional() { override val value: T get() = valueWithoutIsolationDelegate.value ?: throw NoSuchElementException("Not present") override val isPresent: Boolean @@ -351,11 +349,11 @@ abstract class AppendOnlyPersistentMapBase( // Written in a transaction (uncommitted) somewhere, but there's a small window when this might be seen after commit, // hence the committed flag. - class InFlight(private val map: AppendOnlyPersistentMapBase, - private val key: K, - val weight: Int, - private val _readerValueLoader: () -> T?, - private val _writerValueLoader: () -> T = { throw IllegalAccessException("No value loader provided") }) : Transactional() { + class InFlight(private val map: AppendOnlyPersistentMapBase, + private val key: K, + val weight: Int, + private val _readerValueLoader: () -> T?, + private val _writerValueLoader: () -> T = { throw IllegalAccessException("No value loader provided") }) : Transactional() { // A flag to indicate this has now been committed, but hasn't yet been replaced with Committed. This also // de-duplicates writes of the Committed value to the cache. @@ -363,10 +361,10 @@ abstract class AppendOnlyPersistentMapBase( // What to do if a non-writer needs to see the value and it hasn't yet been committed to the database. // Can be updated into a no-op once evaluated. - private val readerValueLoader = AtomicReference<() -> T?>(_readerValueLoader) + private val readerValueLoader = AtomicReference(_readerValueLoader) // What to do if a writer needs to see the value and it hasn't yet been committed to the database. // Can be updated into a no-op once evaluated. - private val writerValueLoader = AtomicReference<() -> T>(_writerValueLoader) + private val writerValueLoader = AtomicReference(_writerValueLoader) fun alsoWrite(_value: T) { // Make the lazy loader the writers see actually just return the value that has been set. @@ -382,11 +380,11 @@ abstract class AppendOnlyPersistentMapBase( // and then stop saying the transaction is writing the key. tx.onCommit { strongMap.cache.asMap().computeIfPresent(strongKey) { _, transactional: Transactional -> - if (transactional is Transactional.InFlight<*, T>) { + if (transactional is InFlight<*, T>) { transactional.committed.set(true) val value = transactional.peekableValue if (value != null) { - Transactional.Committed(value) + Committed(value) } else { transactional } @@ -447,7 +445,7 @@ abstract class AppendOnlyPersistentMapBase( } // Open for tests to override -open class AppendOnlyPersistentMap( +open class AppendOnlyPersistentMap( cacheFactory: NamedCacheFactory, name: String, toPersistentEntityKey: (K) -> EK, @@ -466,7 +464,7 @@ open class AppendOnlyPersistentMap( } // Same as above, but with weighted values (e.g. memory footprint sensitive). -class WeightBasedAppendOnlyPersistentMap( +class WeightBasedAppendOnlyPersistentMap( cacheFactory: NamedCacheFactory, name: String, toPersistentEntityKey: (K) -> EK, @@ -485,7 +483,7 @@ class WeightBasedAppendOnlyPersistentMap( override val cache = NonInvalidatingWeightBasedCache( cacheFactory = cacheFactory, name = name, - weigher = Weigher { key, value: Transactional -> + weigher = { key, value: Transactional -> value.shallowSize + if (value is Transactional.InFlight<*, *>) { value.weight * 2 } else { diff --git a/node/src/main/kotlin/net/corda/node/utilities/InfrequentlyMutatedCache.kt b/node/src/main/kotlin/net/corda/node/utilities/InfrequentlyMutatedCache.kt index 4121a92cb9..4902ada180 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/InfrequentlyMutatedCache.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/InfrequentlyMutatedCache.kt @@ -1,6 +1,5 @@ package net.corda.node.utilities -import com.github.benmanes.caffeine.cache.Caffeine import net.corda.core.internal.NamedCacheFactory import net.corda.core.internal.VisibleForTesting import net.corda.nodeapi.internal.persistence.contextTransactionOrNull @@ -101,7 +100,7 @@ class InfrequentlyMutatedCache(name: String, cacheFactory: Nam } } - private val backingCache = cacheFactory.buildNamed>(Caffeine.newBuilder(), name) + private val backingCache = cacheFactory.buildNamed>(name) // This protects against the cache purging something that is marked as invalid and thus we "forget" it shouldn't be cached. private val currentlyInvalid = ConcurrentHashMap>() diff --git a/node/src/main/kotlin/net/corda/node/utilities/NodeNamedCache.kt b/node/src/main/kotlin/net/corda/node/utilities/NodeNamedCache.kt index fa06c1b25b..ade0ab12ae 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/NodeNamedCache.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/NodeNamedCache.kt @@ -79,12 +79,12 @@ open class DefaultNamedCacheFactory protected constructor(private val metricRegi checkNotNull(nodeConfiguration) } - override fun buildNamed(caffeine: Caffeine, name: String): Cache { + override fun buildNamed(caffeine: Caffeine, name: String): Cache { checkState(name) return configuredForNamed(caffeine, name).build() } - override fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache { + override fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache { checkState(name) return configuredForNamed(caffeine, name).build(loader) } diff --git a/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingCache.kt b/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingCache.kt index 25688233c2..b8b02af6f0 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingCache.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingCache.kt @@ -6,22 +6,17 @@ import com.github.benmanes.caffeine.cache.LoadingCache import com.github.benmanes.caffeine.cache.Weigher import net.corda.core.internal.NamedCacheFactory -class NonInvalidatingCache private constructor( - val cache: LoadingCache -) : LoadingCache by cache { - - constructor(cacheFactory: NamedCacheFactory, name: String, loadFunction: (K) -> V) : - this(buildCache(cacheFactory, name, loadFunction)) +class NonInvalidatingCache private constructor(val cache: LoadingCache) : LoadingCache by cache { + constructor(cacheFactory: NamedCacheFactory, name: String, loadFunction: (K) -> V?) : this(buildCache(cacheFactory, name, loadFunction)) private companion object { - private fun buildCache(cacheFactory: NamedCacheFactory, name: String, loadFunction: (K) -> V): LoadingCache { - val builder = Caffeine.newBuilder() - return cacheFactory.buildNamed(builder, name, NonInvalidatingCacheLoader(loadFunction)) + private fun buildCache(cacheFactory: NamedCacheFactory, name: String, loadFunction: (K) -> V?): LoadingCache { + return cacheFactory.buildNamed(name, NonInvalidatingCacheLoader(loadFunction)) } } // TODO look into overriding loadAll() if we ever use it - class NonInvalidatingCacheLoader(val loadFunction: (K) -> V) : CacheLoader { + class NonInvalidatingCacheLoader(val loadFunction: (K) -> V?) : CacheLoader { override fun reload(key: K, oldValue: V): V { throw IllegalStateException("Non invalidating cache refreshed") } @@ -30,16 +25,17 @@ class NonInvalidatingCache private constructor( } } -class NonInvalidatingWeightBasedCache private constructor( - val cache: LoadingCache -) : LoadingCache by cache { - constructor (cacheFactory: NamedCacheFactory, name: String, weigher: Weigher, loadFunction: (K) -> V) : +class NonInvalidatingWeightBasedCache private constructor(val cache: LoadingCache) : LoadingCache by cache { + constructor(cacheFactory: NamedCacheFactory, name: String, weigher: Weigher, loadFunction: (K) -> V?) : this(buildCache(cacheFactory, name, weigher, loadFunction)) private companion object { - private fun buildCache(cacheFactory: NamedCacheFactory, name: String, weigher: Weigher, loadFunction: (K) -> V): LoadingCache { + private fun buildCache(cacheFactory: NamedCacheFactory, + name: String, + weigher: Weigher, + loadFunction: (K) -> V?): LoadingCache { val builder = Caffeine.newBuilder().weigher(weigher) return cacheFactory.buildNamed(builder, name, NonInvalidatingCache.NonInvalidatingCacheLoader(loadFunction)) } } -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingUnboundCache.kt b/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingUnboundCache.kt index 634189a7b7..6c97ca4df4 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingUnboundCache.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingUnboundCache.kt @@ -7,17 +7,20 @@ import com.github.benmanes.caffeine.cache.LoadingCache import com.github.benmanes.caffeine.cache.RemovalListener import net.corda.core.internal.NamedCacheFactory -class NonInvalidatingUnboundCache private constructor( - val cache: LoadingCache -) : LoadingCache by cache { - - constructor(name: String, cacheFactory: NamedCacheFactory, loadFunction: (K) -> V, removalListener: RemovalListener = RemovalListener { _, _, _ -> }, +class NonInvalidatingUnboundCache private constructor(val cache: LoadingCache) : LoadingCache by cache { + constructor(name: String, + cacheFactory: NamedCacheFactory, + loadFunction: (K) -> V?, + removalListener: RemovalListener = RemovalListener { _, _, _ -> }, keysToPreload: () -> Iterable = { emptyList() }) : this(buildCache(name, cacheFactory, loadFunction, removalListener, keysToPreload)) private companion object { - private fun buildCache(name: String, cacheFactory: NamedCacheFactory, loadFunction: (K) -> V, removalListener: RemovalListener, - keysToPreload: () -> Iterable): LoadingCache { + private fun buildCache(name: String, + cacheFactory: NamedCacheFactory, + loadFunction: (K) -> V?, + removalListener: RemovalListener, + keysToPreload: () -> Iterable): LoadingCache { val builder = Caffeine.newBuilder().removalListener(removalListener).executor(SameThreadExecutor.getExecutor()) return cacheFactory.buildNamed(builder, name, NonInvalidatingCacheLoader(loadFunction)).apply { getAll(keysToPreload()) @@ -26,11 +29,11 @@ class NonInvalidatingUnboundCache private constructor( } // TODO look into overriding loadAll() if we ever use it - private class NonInvalidatingCacheLoader(val loadFunction: (K) -> V) : CacheLoader { + private class NonInvalidatingCacheLoader(val loadFunction: (K) -> V?) : CacheLoader { override fun reload(key: K, oldValue: V): V { throw IllegalStateException("Non invalidating cache refreshed") } override fun load(key: K) = loadFunction(key) } -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/utilities/ObjectDiffer.kt b/node/src/main/kotlin/net/corda/node/utilities/ObjectDiffer.kt index d0cd3fa79f..933365c8d6 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/ObjectDiffer.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/ObjectDiffer.kt @@ -135,7 +135,7 @@ object ObjectDiffer { continue } if (method.name.startsWith("get") && method.name.length > 3 && method.parameterCount == 0) { - val fieldName = method.name[3].toLowerCase() + method.name.substring(4) + val fieldName = method.name[3].lowercaseChar() + method.name.substring(4) foci.add(FieldFocus(fieldName, method.returnType, method)) } else if (method.name.startsWith("is") && method.parameterCount == 0) { foci.add(FieldFocus(method.name, method.returnType, method)) diff --git a/node/src/main/kotlin/net/corda/node/utilities/PersistentMap.kt b/node/src/main/kotlin/net/corda/node/utilities/PersistentMap.kt index a006ee9883..3fcc754ff5 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/PersistentMap.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/PersistentMap.kt @@ -10,7 +10,7 @@ import java.util.* /** * Implements an unbound caching layer on top of a table accessed via Hibernate mapping. */ -class PersistentMap( +class PersistentMap( name: String, val toPersistentEntityKey: (K) -> EK, val fromPersistentEntity: (E) -> Pair, @@ -126,7 +126,7 @@ class PersistentMap( return result } - private class NotReallyMutableEntry(key: K, value: V) : AbstractMap.SimpleImmutableEntry(key, value), MutableMap.MutableEntry { + private class NotReallyMutableEntry(key: K, value: V) : SimpleImmutableEntry(key, value), MutableMap.MutableEntry { override fun setValue(newValue: V): V { throw UnsupportedOperationException("Not really mutable. Implement if really required.") } diff --git a/node/src/main/kotlin/net/corda/node/utilities/registration/HTTPNetworkRegistrationService.kt b/node/src/main/kotlin/net/corda/node/utilities/registration/HTTPNetworkRegistrationService.kt index 653f6fdaf9..68cfc3cee9 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/registration/HTTPNetworkRegistrationService.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/registration/HTTPNetworkRegistrationService.kt @@ -9,7 +9,7 @@ import net.corda.node.VersionInfo import net.corda.node.services.config.NetworkServicesConfig import net.corda.nodeapi.internal.crypto.X509CertificateFactory import okhttp3.CacheControl -import okhttp3.Headers +import okhttp3.Headers.Companion.toHeaders import org.bouncycastle.pkcs.PKCS10CertificationRequest import java.io.IOException import java.net.HttpURLConnection @@ -36,7 +36,7 @@ class HTTPNetworkRegistrationService( // Poll server to download the signed certificate once request has been approved. val conn = URL("$registrationURL/$requestId").openHttpConnection() conn.requestMethod = "GET" - val maxAge = conn.cacheControl.maxAgeSeconds() + val maxAge = conn.cacheControl.maxAgeSeconds // Default poll interval to 10 seconds if not specified by the server, for backward compatibility. val pollInterval = if (maxAge == -1) 10.seconds else maxAge.seconds @@ -67,10 +67,10 @@ class HTTPNetworkRegistrationService( val HttpURLConnection.cacheControl: CacheControl get() { - return CacheControl.parse(Headers.of(headerFields.filterKeys { it != null }.mapValues { it.value[0] })) + return CacheControl.parse(headerFields.filterKeys { it != null }.mapValues { it.value[0] }.toHeaders()) } val HttpURLConnection.cordaServerVersion: String get() { return headerFields["X-Corda-Server-Version"]?.singleOrNull() ?: "1" - } \ No newline at end of file + } diff --git a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt index 272a2f04d2..a82bdd5308 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt @@ -3,7 +3,10 @@ package net.corda.node.utilities.registration import net.corda.core.crypto.Crypto import net.corda.core.crypto.internal.AliasPrivateKey import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.* +import net.corda.core.internal.CertRole +import net.corda.core.internal.isEquivalentTo +import net.corda.core.internal.safeSymbolicRead +import net.corda.core.internal.toX500Name import net.corda.core.utilities.contextLogger import net.corda.node.NodeRegistrationOption import net.corda.node.services.config.NodeConfiguration @@ -19,14 +22,13 @@ import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA import net.corda.nodeapi.internal.crypto.X509Utilities.DEFAULT_VALIDITY_WINDOW import net.corda.nodeapi.internal.crypto.x509 import net.corda.nodeapi.internal.cryptoservice.CryptoService -import net.corda.nodeapi.internal.cryptoservice.bouncycastle.BCCryptoService +import net.corda.nodeapi.internal.cryptoservice.DefaultCryptoService import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.openssl.jcajce.JcaPEMWriter import org.bouncycastle.operator.ContentSigner import org.bouncycastle.util.io.pem.PemObject import java.io.IOException import java.io.StringWriter -import java.lang.IllegalStateException import java.net.ConnectException import java.net.URL import java.nio.file.Path @@ -35,6 +37,12 @@ import java.security.cert.X509Certificate import java.time.Duration import javax.naming.ServiceUnavailableException import javax.security.auth.x500.X500Principal +import kotlin.io.path.createDirectories +import kotlin.io.path.deleteIfExists +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.useLines +import kotlin.io.path.writeLines /** * Helper for managing the node registration process, which checks for any existing certificates and requests them if @@ -90,7 +98,7 @@ open class NetworkRegistrationHelper( certificatesDirectory.safeSymbolicRead().createDirectories() // We need this in case cryptoService and certificateStore share the same KeyStore (for backwards compatibility purposes). // If we didn't, then an update to cryptoService wouldn't be reflected to certificateStore that is already loaded in memory. - val certStore: CertificateStore = if (cryptoService is BCCryptoService) cryptoService.certificateStore else certificateStore + val certStore: CertificateStore = if (cryptoService is DefaultCryptoService) cryptoService.certificateStore else certificateStore // SELF_SIGNED_PRIVATE_KEY is used as progress indicator. if (certStore.contains(nodeCaKeyAlias) && !certStore.contains(SELF_SIGNED_PRIVATE_KEY)) { @@ -113,8 +121,11 @@ open class NetworkRegistrationHelper( requestIdStore.deleteIfExists() } - private fun generateKeyPairAndCertificate(keyAlias: String, legalName: CordaX500Name, certificateRole: CertRole, certStore: CertificateStore): Pair> { - val entityPublicKey = loadOrGenerateKeyPair(keyAlias) + private fun generateKeyPairAndCertificate(keyAlias: String, + legalName: CordaX500Name, + certificateRole: CertRole, + certStore: CertificateStore): Pair> { + val entityPublicKey = loadOrGenerateKeyPair(keyAlias, certificateRole) val requestId = submitOrResumeCertificateSigningRequest(entityPublicKey, legalName, certificateRole, cryptoService.getSigner(keyAlias)) @@ -161,7 +172,7 @@ open class NetworkRegistrationHelper( certificatesDirectory.safeSymbolicRead().createDirectories() // We need this in case cryptoService and certificateStore share the same KeyStore (for backwards compatibility purposes). // If we didn't, then an update to cryptoService wouldn't be reflected to certificateStore that is already loaded in memory. - val certStore: CertificateStore = if (cryptoService is BCCryptoService) cryptoService.certificateStore else certificateStore + val certStore: CertificateStore = if (cryptoService is DefaultCryptoService) cryptoService.certificateStore else certificateStore if (!certStore.contains(nodeCaKeyAlias)) { logProgress("Node CA key doesn't exist, program will now terminate...") @@ -201,11 +212,16 @@ open class NetworkRegistrationHelper( logProgress("Node identity private key and certificate chain stored in $nodeIdentityAlias.") } - private fun loadOrGenerateKeyPair(keyAlias: String): PublicKey { + private fun loadOrGenerateKeyPair(keyAlias: String, certificateRole: CertRole): PublicKey { return if (cryptoService.containsKey(keyAlias)) { cryptoService.getPublicKey(keyAlias)!! } else { - cryptoService.generateKeyPair(keyAlias, cryptoService.defaultTLSSignatureScheme()) + val signatureScheme = if (certificateRole == CertRole.SERVICE_IDENTITY) { + cryptoService.defaultIdentitySignatureScheme() + } else { + cryptoService.defaultTLSSignatureScheme() + } + cryptoService.generateKeyPair(keyAlias, signatureScheme) } } @@ -330,7 +346,7 @@ open class NetworkRegistrationHelper( logProgress("Successfully submitted request to Corda certificate signing server, request ID: $requestId.") requestId } else { - val requestId = requestIdStore.readLines { it.findFirst().get() } + val requestId = requestIdStore.useLines { it.first() } logProgress("Resuming from previous certificate signing request, request ID: $requestId.") requestId } @@ -366,7 +382,7 @@ class NodeRegistrationConfiguration( tlsCertCrlDistPoint = config.tlsCertCrlDistPoint, certificatesDirectory = config.certificatesDirectory, emailAddress = config.emailAddress, - cryptoService = BCCryptoService(config.myLegalName.x500Principal, config.signingCertificateStore), + cryptoService = DefaultCryptoService(config.myLegalName.x500Principal, config.signingCertificateStore), certificateStore = config.signingCertificateStore.get(true), notaryServiceConfig = config.notary?.let { // Validation of the presence of the notary service legal name is only done here and not in the top level configuration @@ -380,7 +396,7 @@ class NodeRegistrationConfiguration( require(it.serviceLegalName != config.myLegalName) { "The notary service legal name must be different from the node legal name" } - NotaryServiceConfig(X509Utilities.DISTRIBUTED_NOTARY_KEY_ALIAS, it.serviceLegalName!!) + NotaryServiceConfig(X509Utilities.DISTRIBUTED_NOTARY_KEY_ALIAS, it.serviceLegalName) } ) } @@ -511,7 +527,7 @@ private class FixedPeriodLimitedRetrialStrategy(times: Int, private val period: private var counter = times - override fun invoke(@Suppress("UNUSED_PARAMETER") previousPeriod: Duration?): Duration? { + override fun invoke(previousPeriod: Duration?): Duration? { synchronized(this) { return if (counter-- > 0) period else null } diff --git a/node/src/main/kotlin/net/corda/node/verification/ExternalVerifierHandleImpl.kt b/node/src/main/kotlin/net/corda/node/verification/ExternalVerifierHandleImpl.kt new file mode 100644 index 0000000000..fd9c1cd91a --- /dev/null +++ b/node/src/main/kotlin/net/corda/node/verification/ExternalVerifierHandleImpl.kt @@ -0,0 +1,253 @@ +package net.corda.node.verification + +import net.corda.core.contracts.Attachment +import net.corda.core.crypto.random63BitValue +import net.corda.core.internal.AbstractAttachment +import net.corda.core.internal.copyTo +import net.corda.core.internal.level +import net.corda.core.internal.mapToSet +import net.corda.core.internal.readFully +import net.corda.core.internal.toSimpleString +import net.corda.core.internal.verification.ExternalVerifierHandle +import net.corda.core.internal.verification.NodeVerificationSupport +import net.corda.core.serialization.serialize +import net.corda.core.transactions.CoreTransaction +import net.corda.core.utilities.Try +import net.corda.core.utilities.contextLogger +import net.corda.core.utilities.debug +import net.corda.serialization.internal.GeneratedAttachment +import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme.Companion.customSerializers +import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme.Companion.serializationWhitelists +import net.corda.serialization.internal.verifier.AttachmentWithTrust +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.AttachmentResult +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.AttachmentsResult +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.Initialisation +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.NetworkParametersResult +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.PartiesResult +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.TrustedClassAttachmentsResult +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.VerificationRequest +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerificationResult +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerifierRequest +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerifierRequest.GetAttachment +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerifierRequest.GetAttachments +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerifierRequest.GetNetworkParameters +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerifierRequest.GetParties +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerifierRequest.GetTrustedClassAttachments +import net.corda.serialization.internal.verifier.readCordaSerializable +import net.corda.serialization.internal.verifier.writeCordaSerializable +import java.io.IOException +import java.lang.Character.MAX_RADIX +import java.lang.ProcessBuilder.Redirect +import java.lang.management.ManagementFactory +import java.net.StandardProtocolFamily +import java.net.UnixDomainSocketAddress +import java.nio.channels.ServerSocketChannel +import java.nio.channels.SocketChannel +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.StandardCopyOption.REPLACE_EXISTING +import java.nio.file.attribute.PosixFileAttributeView +import java.nio.file.attribute.PosixFilePermissions.fromString +import kotlin.io.path.Path +import kotlin.io.path.absolutePathString +import kotlin.io.path.createDirectories +import kotlin.io.path.deleteIfExists +import kotlin.io.path.div +import kotlin.io.path.fileAttributesViewOrNull +import kotlin.io.path.isExecutable +import kotlin.io.path.isWritable + +/** + * Handle to the node's external verifier. The verifier process is started lazily on the first verification request. + */ +class ExternalVerifierHandleImpl( + private val verificationSupport: NodeVerificationSupport, + private val baseDirectory: Path +) : ExternalVerifierHandle { + companion object { + private val log = contextLogger() + + private const val MAX_ATTEMPTS = 5 + + private val verifierJar: Path = Files.createTempFile("corda-external-verifier", ".jar") + init { + // Extract the embedded verifier jar + Companion::class.java.getResourceAsStream("external-verifier.jar")!!.use { + it.copyTo(verifierJar, REPLACE_EXISTING) + } + log.debug { "Extracted external verifier jar to ${verifierJar.absolutePathString()}" } + verifierJar.toFile().deleteOnExit() + } + } + + private lateinit var socketFile: Path + private lateinit var serverChannel: ServerSocketChannel + @Volatile + private var connection: Connection? = null + + override fun verifyTransaction(ctx: CoreTransaction) { + log.info("Verify ${ctx.toSimpleString()} externally") + // By definition input states are unique, and so it makes sense to eagerly send them across with the transaction. + // Reference states are not, but for now we'll send them anyway and assume they aren't used often. If this assumption is not + // correct, and there's a benefit, then we can send them lazily. + val ctxInputsAndReferences = (ctx.inputs + ctx.references).associateWith(verificationSupport::getSerializedState) + val request = VerificationRequest(ctx, ctxInputsAndReferences) + + // To keep things simple the verifier only supports one verification request at a time. + synchronized(this) { + startServer() + var attempt = 1 + while (true) { + val result = try { + tryVerification(request) + } catch (e: Exception) { + processError(attempt, e) + attempt += 1 + continue + } + when (result) { + is Try.Success -> return + is Try.Failure -> throw result.exception + } + } + } + } + + private fun startServer() { + if (::socketFile.isInitialized) return + // Try to create the UNIX domain file in /tmp to keep the full path under the 100 char limit. If we don't have access to it then + // fallback to the temp dir specified by the JVM and hope it's short enough. + val tempDir = Path("/tmp").takeIf { it.isWritable() && it.isExecutable() } ?: Path(System.getProperty("java.io.tmpdir")) + socketFile = tempDir / "corda-external-verifier-${random63BitValue().toString(MAX_RADIX)}.socket" + serverChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX) + log.debug { "Binding to UNIX domain file $socketFile" } + serverChannel.bind(UnixDomainSocketAddress.of(socketFile), 1) + // Lock down access to the file + socketFile.fileAttributesViewOrNull()?.setPermissions(fromString("rwx------")) + // Just in case... + Runtime.getRuntime().addShutdownHook(Thread(::close)) + } + + private fun processError(attempt: Int, e: Exception) { + if (attempt == MAX_ATTEMPTS) { + throw IOException("Unable to verify with external verifier", e) + } else { + log.warn("Unable to verify with external verifier, trying again...", e) + } + try { + connection?.close() + } catch (e: Exception) { + log.debug("Problem closing external verifier connection", e) + } + connection = null + } + + private fun tryVerification(request: VerificationRequest): Try { + val connection = getConnection() + connection.channel.writeCordaSerializable(request) + // Send the verification request and then wait for any requests from verifier for more information. The last message will either + // be a verification success or failure message. + while (true) { + val message = connection.channel.readCordaSerializable(ExternalVerifierOutbound::class) + log.debug { "Received from external verifier: $message" } + when (message) { + // Process the information the verifier needs and then loop back and wait for more messages + is VerifierRequest -> processVerifierRequest(message, connection) + is VerificationResult -> return message.result + } + } + } + + private fun getConnection(): Connection { + return connection ?: Connection().also { connection = it } + } + + private fun processVerifierRequest(request: VerifierRequest, connection: Connection) { + val result = when (request) { + is GetParties -> PartiesResult(verificationSupport.getParties(request.keys)) + is GetAttachment -> AttachmentResult(verificationSupport.getAttachment(request.id)?.withTrust()) + is GetAttachments -> AttachmentsResult(verificationSupport.getAttachments(request.ids).map { it?.withTrust() }) + is GetNetworkParameters -> NetworkParametersResult(verificationSupport.getNetworkParameters(request.id)) + is GetTrustedClassAttachments -> TrustedClassAttachmentsResult(verificationSupport.getTrustedClassAttachments(request.className).map { it.id }) + } + log.debug { "Sending response to external verifier: $result" } + connection.channel.writeCordaSerializable(result) + } + + private fun Attachment.withTrust(): AttachmentWithTrust { + val isTrusted = verificationSupport.isAttachmentTrusted(this) + val attachmentForSer = when (this) { + // The Attachment retrieved from the database is not serialisable, so we have to convert it into one + is AbstractAttachment -> GeneratedAttachment(open().readFully(), uploader) + // For everything else we keep as is, in particular preserving ContractAttachment + else -> this + } + return AttachmentWithTrust(attachmentForSer, isTrusted) + } + + override fun close() { + connection?.close() + connection = null + if (::serverChannel.isInitialized) { + serverChannel.close() + } + if (::socketFile.isInitialized) { + socketFile.deleteIfExists() + } + } + + private inner class Connection : AutoCloseable { + private val verifierProcess: Process + val channel: SocketChannel + + init { + val inheritedJvmArgs = ManagementFactory.getRuntimeMXBean().inputArguments.filter { "--add-opens" in it } + val command = ArrayList() + command += "${Path(System.getProperty("java.home"), "bin", "java")}" + command += inheritedJvmArgs + command += listOf( + "-jar", + "$verifierJar", + socketFile.absolutePathString(), + log.level.name.lowercase() + ) + log.debug { "External verifier command: $command" } + val logsDirectory = (baseDirectory / "logs").createDirectories() + verifierProcess = ProcessBuilder(command) + .redirectOutput(Redirect.appendTo((logsDirectory / "verifier-stdout.log").toFile())) + .redirectError(Redirect.appendTo((logsDirectory / "verifier-stderr.log").toFile())) + .directory(baseDirectory.toFile()) + .start() + log.info("External verifier process started; PID ${verifierProcess.pid()}") + + verifierProcess.onExit().whenComplete { _, _ -> + if (connection != null) { + log.warn("The external verifier has unexpectedly terminated with error code ${verifierProcess.exitValue()}. " + + "Please check verifier logs for more details.") + } + // Allow a new process to be started on the next verification request + connection = null + } + + channel = serverChannel.accept() + + val cordapps = verificationSupport.cordappProvider.cordapps + val initialisation = Initialisation( + customSerializerClassNames = cordapps.customSerializers.mapToSet { it.javaClass.name }, + serializationWhitelistClassNames = cordapps.serializationWhitelists.mapToSet { it.javaClass.name }, + System.getProperty("experimental.corda.customSerializationScheme"), // See Node#initialiseSerialization + serializedCurrentNetworkParameters = verificationSupport.networkParameters.serialize() + ) + channel.writeCordaSerializable(initialisation) + } + + override fun close() { + try { + channel.close() + } finally { + verifierProcess.destroyForcibly() + } + } + } +} diff --git a/node/src/main/kotlin/net/corda/node/verification/NoDbAccessVerifier.kt b/node/src/main/kotlin/net/corda/node/verification/NoDbAccessVerifier.kt new file mode 100644 index 0000000000..992031cb80 --- /dev/null +++ b/node/src/main/kotlin/net/corda/node/verification/NoDbAccessVerifier.kt @@ -0,0 +1,12 @@ +package net.corda.node.verification + +import net.corda.core.internal.verification.Verifier +import net.corda.nodeapi.internal.persistence.withoutDatabaseAccess + +class NoDbAccessVerifier(private val delegate: Verifier) : Verifier { + override fun verify() { + withoutDatabaseAccess { + delegate.verify() + } + } +} diff --git a/node/src/main/kotlin/net/corda/notary/experimental/bftsmart/BFTSmart.kt b/node/src/main/kotlin/net/corda/notary/experimental/bftsmart/BFTSmart.kt index df8cf87857..705d6dc23c 100644 --- a/node/src/main/kotlin/net/corda/notary/experimental/bftsmart/BFTSmart.kt +++ b/node/src/main/kotlin/net/corda/notary/experimental/bftsmart/BFTSmart.kt @@ -26,6 +26,7 @@ import net.corda.core.internal.notary.NotaryInternalException import net.corda.core.internal.notary.isConsumedByTheSameTx import net.corda.core.internal.notary.validateTimeWindow import net.corda.core.internal.toTypedArray +import net.corda.core.internal.uncheckedCast import net.corda.core.schemas.PersistentStateRef import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.SingletonSerializeAsToken @@ -215,7 +216,7 @@ object BFTSmart { } override fun appExecuteBatch(command: Array, mcs: Array): Array { - return Arrays.stream(command).map(this::executeCommand).toTypedArray() + return uncheckedCast(Arrays.stream(command).map(this::executeCommand).toTypedArray()) } /** diff --git a/node/src/main/kotlin/net/corda/notary/experimental/bftsmart/BFTSmartConfigInternal.kt b/node/src/main/kotlin/net/corda/notary/experimental/bftsmart/BFTSmartConfigInternal.kt index a33fe68bd3..21f7747902 100644 --- a/node/src/main/kotlin/net/corda/notary/experimental/bftsmart/BFTSmartConfigInternal.kt +++ b/node/src/main/kotlin/net/corda/notary/experimental/bftsmart/BFTSmartConfigInternal.kt @@ -1,7 +1,5 @@ package net.corda.notary.experimental.bftsmart -import net.corda.core.internal.div -import net.corda.core.internal.writer import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.contextLogger import net.corda.core.utilities.debug @@ -12,6 +10,8 @@ import java.net.Socket import java.net.SocketException import java.nio.file.Files import java.util.concurrent.TimeUnit.MILLISECONDS +import kotlin.io.path.div +import kotlin.io.path.writer data class BFTSmartConfig( /** The zero-based index of the current replica. All replicas must specify a unique replica id. */ @@ -59,7 +59,13 @@ class BFTSmartConfigInternal(private val replicaAddresses: List, references: List): Map { - val persistentStateRefs = (states + references).map { encodeStateRef(it) }.toSet() + val persistentStateRefs = (states + references).mapToSet(::encodeStateRef) val committedStates = mutableListOf() for (idsBatch in persistentStateRefs.chunked(config.maxInputStates)) { @@ -229,8 +231,7 @@ class JPAUniquenessProvider( var exceptionCaught: SQLException? = null while (retryCount <= config.maxDBTransactionRetryCount) { try { - val res = block() - return res + return block() } catch (e: SQLException) { retryCount++ Thread.sleep(backOff) @@ -242,7 +243,7 @@ class JPAUniquenessProvider( } private fun findAllConflicts(session: Session, requests: List): MutableMap { - log.info("Processing notarization requests with ${requests.sumBy { it.states.size }} input states and ${requests.sumBy { it.references.size }} references") + log.info("Processing notarization requests with ${requests.sumOf { it.states.size }} input states and ${requests.sumOf { it.references.size }} references") val allStates = requests.flatMap { it.states } val allReferences = requests.flatMap { it.references } @@ -338,7 +339,6 @@ class JPAUniquenessProvider( return session.find(CommittedTransaction::class.java, txId.toString()) != null } - @Suppress("TooGenericExceptionCaught") private fun processRequests(requests: List) { try { // Note that there is an additional retry mechanism within the transaction itself. diff --git a/node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java b/node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java index 0a4330967a..c26c0c0b86 100644 --- a/node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java +++ b/node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java @@ -10,8 +10,8 @@ import net.corda.core.crypto.SecureHash; import net.corda.core.identity.AbstractParty; import net.corda.core.identity.CordaX500Name; import net.corda.core.identity.Party; +import net.corda.core.internal.verification.NodeVerificationSupport; import net.corda.core.messaging.DataFeed; -import net.corda.core.node.ServicesForResolution; import net.corda.core.node.services.AttachmentStorage; import net.corda.core.node.services.IdentityService; import net.corda.core.node.services.Vault; @@ -97,9 +97,9 @@ public class VaultQueryJavaTests { vaultFiller = new VaultFiller(services, DUMMY_NOTARY); vaultService = services.getVaultService(); storage = new NodeAttachmentService(new MetricRegistry(), new TestingNamedCacheFactory(100), database); - ServicesForResolution serviceForResolution = mock(ServicesForResolution.class); - ((NodeAttachmentService) storage).servicesForResolution = serviceForResolution; - doReturn(testNetworkParameters()).when(serviceForResolution).getNetworkParameters(); + NodeVerificationSupport nodeVerificationSupport = mock(NodeVerificationSupport.class); + ((NodeAttachmentService) storage).nodeVerificationSupport = nodeVerificationSupport; + doReturn(testNetworkParameters()).when(nodeVerificationSupport).getNetworkParameters(); } @After diff --git a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt index 68c2df4307..d6e42be13a 100644 --- a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt +++ b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt @@ -15,7 +15,6 @@ import net.corda.core.flows.StartableByRPC import net.corda.core.flows.StateMachineRunId import net.corda.core.identity.Party import net.corda.core.internal.RPC_UPLOADER -import net.corda.core.internal.uncheckedCast import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.StateMachineUpdate import net.corda.core.messaging.startFlow @@ -408,7 +407,8 @@ class CordaRPCOpsImplTest { @Test(timeout=300_000) fun `non-ContractState class for the contractStateType param in vault queries`() { CURRENT_RPC_CONTEXT.set(RpcAuthContext(InvocationContext.rpc(testActor()), buildSubject("TEST_USER", emptySet()))) - val nonContractStateClass: Class = uncheckedCast(Cash::class.java) + @Suppress("UNCHECKED_CAST") + val nonContractStateClass = Cash::class.java as Class withPermissions(invokeRpc("vaultTrack"), invokeRpc("vaultQuery")) { assertThatThrownBy { rpc.vaultQuery(nonContractStateClass) }.hasMessageContaining(Cash::class.java.name) assertThatThrownBy { rpc.vaultTrack(nonContractStateClass) }.hasMessageContaining(Cash::class.java.name) diff --git a/node/src/test/kotlin/net/corda/node/internal/AbstractNodeTests.kt b/node/src/test/kotlin/net/corda/node/internal/AbstractNodeTests.kt index 0fb0382234..eac71e88b1 100644 --- a/node/src/test/kotlin/net/corda/node/internal/AbstractNodeTests.kt +++ b/node/src/test/kotlin/net/corda/node/internal/AbstractNodeTests.kt @@ -1,6 +1,6 @@ package net.corda.node.internal -import com.nhaarman.mockito_kotlin.mock +import org.mockito.kotlin.mock import net.corda.core.internal.concurrent.fork import net.corda.core.internal.concurrent.transpose import net.corda.core.utilities.contextLogger diff --git a/node/src/test/kotlin/net/corda/node/internal/CustomSerializationSchemeScanningTest.kt b/node/src/test/kotlin/net/corda/node/internal/CustomSerializationSchemeScanningTest.kt index 1837a8fb49..e920a197f0 100644 --- a/node/src/test/kotlin/net/corda/node/internal/CustomSerializationSchemeScanningTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/CustomSerializationSchemeScanningTest.kt @@ -1,10 +1,11 @@ package net.corda.node.internal +import net.corda.core.CordaException import net.corda.core.serialization.CustomSerializationScheme import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationSchemeContext import net.corda.core.utilities.ByteSequence -import net.corda.node.internal.classloading.scanForCustomSerializationScheme +import net.corda.serialization.internal.verifier.loadCustomSerializationScheme import org.junit.Test import org.mockito.Mockito import kotlin.test.assertFailsWith @@ -33,7 +34,7 @@ class CustomSerializationSchemeScanningTest { @Test(timeout = 300_000) fun `Can scan for custom serialization scheme and build a serialization scheme`() { - val scheme = scanForCustomSerializationScheme(DummySerializationScheme::class.java.name, this::class.java.classLoader) + val scheme = loadCustomSerializationScheme(DummySerializationScheme::class.java.name, this::class.java.classLoader) val mockContext = Mockito.mock(SerializationContext::class.java) assertFailsWith("Tried to serialize with DummySerializationScheme") { scheme.serialize(Any::class.java, mockContext) @@ -43,27 +44,27 @@ class CustomSerializationSchemeScanningTest { @Test(timeout = 300_000) fun `verification fails with a helpful error if the class is not found in the classloader`() { val missingClassName = "org.testing.DoesNotExist" - assertFailsWith("$missingClassName was declared as a custom serialization scheme but could not " + + assertFailsWith("$missingClassName was declared as a custom serialization scheme but could not " + "be found.") { - scanForCustomSerializationScheme(missingClassName, this::class.java.classLoader) + loadCustomSerializationScheme(missingClassName, this::class.java.classLoader) } } @Test(timeout = 300_000) fun `verification fails with a helpful error if the class is not a custom serialization scheme`() { val schemeName = NonSerializationScheme::class.java.name - assertFailsWith("$schemeName was declared as a custom serialization scheme but does not " + + assertFailsWith("$schemeName was declared as a custom serialization scheme but does not " + "implement CustomSerializationScheme.") { - scanForCustomSerializationScheme(schemeName, this::class.java.classLoader) + loadCustomSerializationScheme(schemeName, this::class.java.classLoader) } } @Test(timeout = 300_000) fun `verification fails with a helpful error if the class does not have a no arg constructor`() { val schemeName = DummySerializationSchemeWithoutNoArgConstructor::class.java.name - assertFailsWith("$schemeName was declared as a custom serialization scheme but does not " + + assertFailsWith("$schemeName was declared as a custom serialization scheme but does not " + "have a no argument constructor.") { - scanForCustomSerializationScheme(schemeName, this::class.java.classLoader) + loadCustomSerializationScheme(schemeName, this::class.java.classLoader) } } } diff --git a/node/src/test/kotlin/net/corda/node/internal/KeyStoreHandlerTest.kt b/node/src/test/kotlin/net/corda/node/internal/KeyStoreHandlerTest.kt index 9ad6096470..e6b39038a6 100644 --- a/node/src/test/kotlin/net/corda/node/internal/KeyStoreHandlerTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/KeyStoreHandlerTest.kt @@ -1,11 +1,10 @@ package net.corda.node.internal -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Crypto import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.div import net.corda.coretesting.internal.rigorousMock import net.corda.coretesting.internal.stubs.CertificateStoreStubs import net.corda.node.services.config.NodeConfiguration @@ -24,7 +23,7 @@ import net.corda.nodeapi.internal.crypto.X509Utilities.DISTRIBUTED_NOTARY_COMPOS import net.corda.nodeapi.internal.crypto.X509Utilities.DISTRIBUTED_NOTARY_KEY_ALIAS import net.corda.nodeapi.internal.crypto.X509Utilities.NODE_IDENTITY_KEY_ALIAS import net.corda.nodeapi.internal.cryptoservice.CryptoService -import net.corda.nodeapi.internal.cryptoservice.bouncycastle.BCCryptoService +import net.corda.nodeapi.internal.cryptoservice.DefaultCryptoService import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.BOB_NAME import org.assertj.core.api.Assertions.assertThat @@ -35,6 +34,7 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import java.security.KeyPair import java.security.PublicKey +import kotlin.io.path.div class KeyStoreHandlerTest { @Rule @@ -47,7 +47,7 @@ class KeyStoreHandlerTest { private val keyStore get() = config.signingCertificateStore.get() - private lateinit var cryptoService: BCCryptoService + private lateinit var cryptoService: DefaultCryptoService private lateinit var keyStoreHandler: KeyStoreHandler @@ -64,7 +64,7 @@ class KeyStoreHandlerTest { doReturn(ALICE_NAME).whenever(it).myLegalName doReturn(null).whenever(it).notary } - cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore) + cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore) keyStoreHandler = KeyStoreHandler(config, cryptoService) } @@ -190,7 +190,7 @@ class KeyStoreHandlerTest { val devCertificateDir = tempFolder.root.toPath() / "certificates-dev" val signingCertificateStore = CertificateStoreStubs.Signing.withCertificatesDirectory(devCertificateDir) val p2pSslOptions = CertificateStoreStubs.P2P.withCertificatesDirectory(devCertificateDir) - val devCryptoService = BCCryptoService(config.myLegalName.x500Principal, signingCertificateStore) + val devCryptoService = DefaultCryptoService(config.myLegalName.x500Principal, signingCertificateStore) doReturn(true).whenever(config).devMode doReturn(signingCertificateStore).whenever(config).signingCertificateStore @@ -398,4 +398,4 @@ class KeyStoreHandlerTest { keyStoreHandler.init() }.hasMessageContaining("The configured legalName").hasMessageContaining("doesn't match what's in the key store") } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/internal/NodeFlowManagerTest.kt b/node/src/test/kotlin/net/corda/node/internal/NodeFlowManagerTest.kt index 4a417f368a..2c79968935 100644 --- a/node/src/test/kotlin/net/corda/node/internal/NodeFlowManagerTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/NodeFlowManagerTest.kt @@ -6,14 +6,10 @@ import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.node.services.config.FlowOverride import net.corda.node.services.config.FlowOverrideConfig -import org.hamcrest.CoreMatchers.`is` -import org.hamcrest.CoreMatchers.instanceOf -import org.junit.Assert +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatIllegalStateException import org.junit.Test import org.mockito.Mockito -import java.lang.IllegalStateException - -private val marker = "This is a special marker" class NodeFlowManagerTest { @@ -57,12 +53,14 @@ class NodeFlowManagerTest { } - @Test(expected = IllegalStateException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `should fail to validate if more than one registration with equal weight`() { val nodeFlowManager = NodeFlowManager() nodeFlowManager.registerInitiatedFlow(Init::class.java, Resp::class.java) nodeFlowManager.registerInitiatedFlow(Init::class.java, Resp2::class.java) - nodeFlowManager.validateRegistrations() + assertThatIllegalStateException().isThrownBy { + nodeFlowManager.validateRegistrations() + } } @Test(timeout = 300_000) @@ -73,7 +71,7 @@ class NodeFlowManagerTest { nodeFlowManager.validateRegistrations() val factory = nodeFlowManager.getFlowFactoryForInitiatingFlow(Init::class.java)!! val flow = factory.createFlow(Mockito.mock(FlowSession::class.java)) - Assert.assertThat(flow, `is`(instanceOf(RespSub::class.java))) + assertThat(flow).isInstanceOf(RespSub::class.java) } @Test(timeout = 300_000) @@ -84,14 +82,14 @@ class NodeFlowManagerTest { nodeFlowManager.validateRegistrations() var factory = nodeFlowManager.getFlowFactoryForInitiatingFlow(Init::class.java)!! var flow = factory.createFlow(Mockito.mock(FlowSession::class.java)) - Assert.assertThat(flow, `is`(instanceOf(RespSub::class.java))) + assertThat(flow).isInstanceOf(RespSub::class.java) // update nodeFlowManager.registerInitiatedFlow(Init::class.java, RespSubSub::class.java) nodeFlowManager.validateRegistrations() factory = nodeFlowManager.getFlowFactoryForInitiatingFlow(Init::class.java)!! flow = factory.createFlow(Mockito.mock(FlowSession::class.java)) - Assert.assertThat(flow, `is`(instanceOf(RespSubSub::class.java))) + assertThat(flow).isInstanceOf(RespSubSub::class.java) } @Test(timeout=300_000) @@ -105,6 +103,6 @@ class NodeFlowManagerTest { val factory = nodeFlowManager.getFlowFactoryForInitiatingFlow(Init::class.java)!! val flow = factory.createFlow(Mockito.mock(FlowSession::class.java)) - Assert.assertThat(flow, `is`(instanceOf(Resp::class.java))) + assertThat(flow).isInstanceOf(Resp::class.java) } } \ No newline at end of file diff --git a/node/src/test/kotlin/net/corda/node/internal/NodeH2SecurityTests.kt b/node/src/test/kotlin/net/corda/node/internal/NodeH2SecurityTests.kt index 6bd7e357e9..1c46fa8c54 100644 --- a/node/src/test/kotlin/net/corda/node/internal/NodeH2SecurityTests.kt +++ b/node/src/test/kotlin/net/corda/node/internal/NodeH2SecurityTests.kt @@ -1,9 +1,5 @@ package net.corda.node.internal -import com.nhaarman.mockito_kotlin.atLeast -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.identity.CordaX500Name import net.corda.core.serialization.SerializeAsToken import net.corda.core.utilities.NetworkHostAndPort @@ -20,12 +16,17 @@ import net.corda.nodeapi.internal.persistence.DatabaseConfig import org.assertj.core.api.Assertions.assertThat import org.h2.tools.Server import org.junit.Test +import org.mockito.kotlin.atLeast +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.net.InetAddress import java.sql.Connection import java.sql.DatabaseMetaData -import java.util.* +import java.util.Properties import java.util.concurrent.ExecutorService import javax.sql.DataSource +import kotlin.io.path.Path import kotlin.test.assertFailsWith class NodeH2SecurityTests { @@ -133,13 +134,13 @@ class NodeH2SecurityTests { init { whenever(config.database).thenReturn(database) whenever(config.dataSourceProperties).thenReturn(hikaryProperties) - whenever(config.baseDirectory).thenReturn(mock()) + whenever(config.baseDirectory).thenReturn(Path(".")) 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) { fun startDb() = startDatabase() override fun makeMessagingService(): MessagingService { @@ -173,4 +174,4 @@ class NodeH2SecurityTests { return server } } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/internal/NodeStartupCliTest.kt b/node/src/test/kotlin/net/corda/node/internal/NodeStartupCliTest.kt index 5433f96758..644f654477 100644 --- a/node/src/test/kotlin/net/corda/node/internal/NodeStartupCliTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/NodeStartupCliTest.kt @@ -1,8 +1,6 @@ package net.corda.node.internal import net.corda.cliutils.CommonCliConstants -import net.corda.core.internal.div -import net.corda.core.internal.exists import net.corda.nodeapi.internal.config.UnknownConfigKeysPolicy import org.assertj.core.api.Assertions import org.junit.BeforeClass @@ -14,6 +12,8 @@ import picocli.CommandLine import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths +import kotlin.io.path.div +import kotlin.io.path.exists import kotlin.test.assertFalse import kotlin.test.assertTrue diff --git a/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt b/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt index 50fe6525c4..d102e7ddf0 100644 --- a/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt @@ -1,19 +1,20 @@ package net.corda.node.internal -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.delete -import net.corda.core.internal.getJavaUpdateVersion -import net.corda.core.internal.list import net.corda.core.internal.readObject import net.corda.core.node.NodeInfo import net.corda.core.serialization.serialize import net.corda.core.utilities.NetworkHostAndPort +import net.corda.coretesting.internal.createNodeInfoAndSigned +import net.corda.coretesting.internal.rigorousMock import net.corda.node.VersionInfo import net.corda.node.internal.schemas.NodeInfoSchemaV1 -import net.corda.node.services.config.* +import net.corda.node.services.config.FlowOverrideConfig +import net.corda.node.services.config.FlowTimeoutConfiguration +import net.corda.node.services.config.NodeConfigurationImpl +import net.corda.node.services.config.NodeRpcSettings +import net.corda.node.services.config.TelemetryConfiguration +import net.corda.node.services.config.VerifierType import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.network.NodeInfoFilesCopier.Companion.NODE_INFO_FILE_NAME_PREFIX import net.corda.nodeapi.internal.persistence.CordaPersistence @@ -21,21 +22,21 @@ import net.corda.nodeapi.internal.persistence.DatabaseConfig import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.internal.configureDatabase -import net.corda.coretesting.internal.createNodeInfoAndSigned -import net.corda.coretesting.internal.rigorousMock import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties -import org.apache.commons.lang3.SystemUtils import org.assertj.core.api.Assertions.assertThat -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import java.nio.file.Path import java.time.Duration +import kotlin.io.path.deleteExisting +import kotlin.io.path.name +import kotlin.io.path.useDirectoryEntries import kotlin.test.assertEquals -import kotlin.test.assertFailsWith import kotlin.test.assertNull -import kotlin.test.assertTrue class NodeTest { @Rule @@ -46,8 +47,8 @@ class NodeTest { val testSerialization = SerializationEnvironmentRule() private fun nodeInfoFile(): Path? { - return temporaryFolder.root.toPath().list { paths -> - paths.filter { it.fileName.toString().startsWith(NODE_INFO_FILE_NAME_PREFIX) }.findAny().orElse(null) + return temporaryFolder.root.toPath().useDirectoryEntries { paths -> + paths.find { it.name.startsWith(NODE_INFO_FILE_NAME_PREFIX) } } } @@ -58,7 +59,7 @@ class NodeTest { try { return path.readObject().verified() } finally { - path.delete() + path.deleteExisting() } } @@ -90,7 +91,7 @@ class NodeTest { val persistentNodeInfo = NodeInfoSchemaV1.PersistentNodeInfo( id = 0, hash = nodeInfo.serialize().hash.toString(), - addresses = nodeInfo.addresses.map { NodeInfoSchemaV1.DBHostAndPort.fromHostAndPort(it) }, + addresses = nodeInfo.addresses.map(NodeInfoSchemaV1.DBHostAndPort::fromHostAndPort), legalIdentitiesAndCerts = nodeInfo.legalIdentitiesAndCerts.mapIndexed { idx, elem -> NodeInfoSchemaV1.DBPartyAndCertificate(elem, isMain = idx == 0) }, @@ -137,11 +138,11 @@ class NodeTest { serial = nodeInfo1.serial ) - configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use { - it.transaction { + configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use { persistence -> + persistence.transaction { session.save(persistentNodeInfo1) } - it.transaction { + persistence.transaction { session.save(persistentNodeInfo2) } @@ -156,22 +157,6 @@ class NodeTest { } } - // JDK 11 check - @Test(timeout=300_000) - fun `test getJavaRuntimeVersion`() { - assertTrue(SystemUtils.IS_JAVA_1_8 || SystemUtils.IS_JAVA_11) - } - - // JDK11: revisit (JDK 9+ uses different numbering scheme: see https://docs.oracle.com/javase/9/docs/api/java/lang/Runtime.Version.html) - @Ignore - @Test(timeout=300_000) - fun `test getJavaUpdateVersion`() { - assertThat(getJavaUpdateVersion("1.8.0_202-ea")).isEqualTo(202) - assertThat(getJavaUpdateVersion("1.8.0_202")).isEqualTo(202) - assertFailsWith { getJavaUpdateVersion("1.8.0_202wrong-format") } - assertFailsWith { getJavaUpdateVersion("1.8.0-adoptopenjdk") } - } - private fun getAllInfos(database: CordaPersistence): List { return database.transaction { val criteria = session.criteriaBuilder.createQuery(NodeInfoSchemaV1.PersistentNodeInfo::class.java) diff --git a/node/src/test/kotlin/net/corda/node/internal/artemis/UserValidationPluginTest.kt b/node/src/test/kotlin/net/corda/node/internal/artemis/UserValidationPluginTest.kt index b6b9288884..e9a73b28e6 100644 --- a/node/src/test/kotlin/net/corda/node/internal/artemis/UserValidationPluginTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/artemis/UserValidationPluginTest.kt @@ -1,9 +1,9 @@ package net.corda.node.internal.artemis -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.doThrow -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.doThrow +import org.mockito.kotlin.whenever import net.corda.coretesting.internal.rigorousMock import net.corda.nodeapi.internal.ArtemisMessagingComponent import net.corda.testing.core.ALICE_NAME @@ -93,4 +93,4 @@ class UserValidationPluginTest { plugin.beforeSend(session, rigorousMock(), messageWithException, direct = false, noAutoCreateQueue = false) }.withMessageContaining("My security exception") } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappConfigFileProviderTests.kt b/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappConfigFileProviderTests.kt index 5dad12f765..5e03040c92 100644 --- a/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappConfigFileProviderTests.kt +++ b/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappConfigFileProviderTests.kt @@ -4,11 +4,12 @@ import com.typesafe.config.Config import com.typesafe.config.ConfigException import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigRenderOptions -import net.corda.core.internal.div -import net.corda.core.internal.writeText import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Test import java.nio.file.Paths +import kotlin.io.path.div +import kotlin.io.path.writeText class CordappConfigFileProviderTests { private companion object { @@ -45,10 +46,12 @@ class CordappConfigFileProviderTests { assertThat(provider.getConfigByName(cordappName)).isEqualTo(alternateValidConfig) } - @Test(expected = ConfigException.Parse::class, timeout=300_000) + @Test(timeout=300_000) fun `an invalid config throws an exception`() { cordappConfFile.writeText(invalidConfig) - provider.getConfigByName(cordappName) + assertThatExceptionOfType(ConfigException::class.java).isThrownBy { + provider.getConfigByName(cordappName) + } } /** diff --git a/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappProviderImplTests.kt b/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappProviderImplTests.kt index 1a62060097..88942ca7cc 100644 --- a/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappProviderImplTests.kt +++ b/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappProviderImplTests.kt @@ -2,37 +2,43 @@ package net.corda.node.internal.cordapp import com.typesafe.config.Config import com.typesafe.config.ConfigFactory +import net.corda.core.internal.hash +import net.corda.core.internal.toPath import net.corda.core.node.services.AttachmentId -import net.corda.core.node.services.AttachmentStorage -import net.corda.node.VersionInfo -import net.corda.testing.core.internal.ContractJarTestUtils -import net.corda.testing.core.internal.SelfCleaningDir +import net.corda.core.utilities.OpaqueBytes +import net.corda.finance.DOLLARS +import net.corda.finance.contracts.asset.Cash +import net.corda.finance.flows.CashIssueFlow +import net.corda.node.services.persistence.AttachmentStorageInternal +import net.corda.node.services.persistence.toInternal +import net.corda.testing.core.ALICE_NAME +import net.corda.testing.core.TestIdentity +import net.corda.testing.core.internal.JarSignatureTestUtils.unsignJar import net.corda.testing.internal.MockCordappConfigProvider import net.corda.testing.services.MockAttachmentStorage import org.assertj.core.api.Assertions.assertThat -import org.junit.Assert.* +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull import org.junit.Before +import org.junit.Rule import org.junit.Test +import org.junit.rules.TemporaryFolder import java.io.File import java.io.FileOutputStream -import java.lang.IllegalStateException -import java.net.URL -import java.nio.file.Files -import java.util.Arrays.asList +import java.nio.file.Path import java.util.jar.JarOutputStream import java.util.zip.Deflater.NO_COMPRESSION import java.util.zip.ZipEntry import java.util.zip.ZipEntry.DEFLATED import java.util.zip.ZipEntry.STORED +import kotlin.io.path.copyTo import kotlin.test.assertFailsWith class CordappProviderImplTests { private companion object { - val isolatedJAR: URL = this::class.java.getResource("/isolated.jar") - // TODO: Cordapp name should differ from the JAR name - const val isolatedCordappName = "isolated" - val emptyJAR: URL = this::class.java.getResource("empty.jar") - val validConfig: Config = ConfigFactory.parseString("key=value") + val currentFinanceContractsJar = this::class.java.getResource("/corda-finance-contracts.jar")!!.toPath() + val currentFinanceWorkflowsJar = this::class.java.getResource("/corda-finance-workflows.jar")!!.toPath() + val legacyFinanceContractsJar = this::class.java.getResource("/corda-finance-contracts-4.11.jar")!!.toPath() @JvmField val ID1 = AttachmentId.randomSHA256() @@ -59,35 +65,29 @@ class CordappProviderImplTests { } } - private lateinit var attachmentStore: AttachmentStorage + @Rule + @JvmField + val tempFolder = TemporaryFolder() + + private lateinit var attachmentStore: AttachmentStorageInternal @Before fun setup() { - attachmentStore = MockAttachmentStorage() - } - - @Test(timeout=300_000) - fun `isolated jar is loaded into the attachment store`() { - val provider = newCordappProvider(isolatedJAR) - val maybeAttachmentId = provider.getCordappAttachmentId(provider.cordapps.first()) - - assertNotNull(maybeAttachmentId) - assertNotNull(attachmentStore.openAttachment(maybeAttachmentId!!)) + attachmentStore = MockAttachmentStorage().toInternal() } @Test(timeout=300_000) fun `empty jar is not loaded into the attachment store`() { - val provider = newCordappProvider(emptyJAR) - assertNull(provider.getCordappAttachmentId(provider.cordapps.first())) + val provider = newCordappProvider(setOf(Companion::class.java.getResource("empty.jar")!!.toPath())) + assertThat(attachmentStore.openAttachment(provider.cordapps.single().jarHash)).isNull() } @Test(timeout=300_000) fun `test that we find a cordapp class that is loaded into the store`() { - val provider = newCordappProvider(isolatedJAR) - val className = "net.corda.isolated.contracts.AnotherDummyContract" + val provider = newCordappProvider(setOf(currentFinanceContractsJar)) val expected = provider.cordapps.first() - val actual = provider.getCordappForClass(className) + val actual = provider.getCordappForClass(Cash::class.java.name) assertNotNull(actual) assertEquals(expected, actual) @@ -95,34 +95,60 @@ class CordappProviderImplTests { @Test(timeout=300_000) fun `test that we find an attachment for a cordapp contract class`() { - val provider = newCordappProvider(isolatedJAR) - val className = "net.corda.isolated.contracts.AnotherDummyContract" + val provider = newCordappProvider(setOf(currentFinanceContractsJar)) val expected = provider.getAppContext(provider.cordapps.first()).attachmentId - val actual = provider.getContractAttachmentID(className) + val actual = provider.getContractAttachmentID(Cash::class.java.name) assertNotNull(actual) assertEquals(actual!!, expected) } @Test(timeout=300_000) - fun `test cordapp configuration`() { + fun `test cordapp configuration`() { val configProvider = MockCordappConfigProvider() - configProvider.cordappConfigs[isolatedCordappName] = validConfig - val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR), VersionInfo.UNKNOWN) - val provider = CordappProviderImpl(loader, configProvider, attachmentStore).apply { start() } + configProvider.cordappConfigs["corda-finance-contracts"] = ConfigFactory.parseString("key=value") + val provider = newCordappProvider(setOf(currentFinanceContractsJar), cordappConfigProvider = configProvider) val expected = provider.getAppContext(provider.cordapps.first()).config assertThat(expected.getString("key")).isEqualTo("value") } + @Test(timeout=300_000) + fun getCordappForFlow() { + val provider = newCordappProvider(setOf(currentFinanceWorkflowsJar)) + val cashIssueFlow = CashIssueFlow(10.DOLLARS, OpaqueBytes.of(0x00), TestIdentity(ALICE_NAME).party) + assertThat(provider.getCordappForFlow(cashIssueFlow)?.jarPath?.toPath()).isEqualTo(currentFinanceWorkflowsJar) + } + + @Test(timeout=300_000) + fun `does not load the same flow across different CorDapps`() { + val unsignedJar = tempFolder.newFile("duplicate.jar").toPath() + currentFinanceWorkflowsJar.copyTo(unsignedJar, overwrite = true) + // We just need to change the file's hash and thus avoid the duplicate CorDapp check + unsignedJar.unsignJar() + assertThat(unsignedJar.hash).isNotEqualTo(currentFinanceWorkflowsJar.hash) + assertFailsWith { + newCordappProvider(setOf(currentFinanceWorkflowsJar, unsignedJar)) + } + } + + @Test(timeout=300_000) + fun `retrieving legacy attachment for contract`() { + val provider = newCordappProvider(setOf(currentFinanceContractsJar), setOf(legacyFinanceContractsJar)) + val (current, legacy) = provider.getContractAttachments(Cash::class.java.name)!! + assertThat(current.id).isEqualTo(currentFinanceContractsJar.hash) + assertThat(legacy?.id).isEqualTo(legacyFinanceContractsJar.hash) + // getContractAttachmentID should always return the non-legacy attachment ID + assertThat(provider.getContractAttachmentID(Cash::class.java.name)).isEqualTo(currentFinanceContractsJar.hash) + } + @Test(timeout=300_000) fun `test fixup rule that adds attachment`() { val fixupJar = File.createTempFile("fixup", ".jar") .writeFixupRules("$ID1 => $ID2, $ID3") - val fixedIDs = with(newCordappProvider(fixupJar.toURI().toURL())) { - start() - fixupAttachmentIds(listOf(ID1)) + val fixedIDs = with(newCordappProvider(setOf(fixupJar.toPath()))) { + attachmentFixups.fixupAttachmentIds(listOf(ID1)) } assertThat(fixedIDs).containsExactly(ID2, ID3) } @@ -131,9 +157,8 @@ class CordappProviderImplTests { fun `test fixup rule that deletes attachment`() { val fixupJar = File.createTempFile("fixup", ".jar") .writeFixupRules("$ID1 =>") - val fixedIDs = with(newCordappProvider(fixupJar.toURI().toURL())) { - start() - fixupAttachmentIds(listOf(ID1)) + val fixedIDs = with(newCordappProvider(setOf(fixupJar.toPath()))) { + attachmentFixups.fixupAttachmentIds(listOf(ID1)) } assertThat(fixedIDs).isEmpty() } @@ -143,7 +168,7 @@ class CordappProviderImplTests { val fixupJar = File.createTempFile("fixup", ".jar") .writeFixupRules(" => $ID2") val ex = assertFailsWith { - newCordappProvider(fixupJar.toURI().toURL()).start() + newCordappProvider(setOf(fixupJar.toPath())) } assertThat(ex).hasMessageContaining( "Forbidden empty list of source attachment IDs in '${fixupJar.absolutePath}'" @@ -156,7 +181,7 @@ class CordappProviderImplTests { val fixupJar = File.createTempFile("fixup", ".jar") .writeFixupRules(rule) val ex = assertFailsWith { - newCordappProvider(fixupJar.toURI().toURL()).start() + newCordappProvider(setOf(fixupJar.toPath())) } assertThat(ex).hasMessageContaining( "Invalid fix-up line '${rule.trim()}' in '${fixupJar.absolutePath}'" @@ -169,7 +194,7 @@ class CordappProviderImplTests { val fixupJar = File.createTempFile("fixup", ".jar") .writeFixupRules(rule) val ex = assertFailsWith { - newCordappProvider(fixupJar.toURI().toURL()).start() + newCordappProvider(setOf(fixupJar.toPath())) } assertThat(ex).hasMessageContaining( "Invalid fix-up line '${rule.trim()}' in '${fixupJar.absolutePath}'" @@ -185,46 +210,12 @@ class CordappProviderImplTests { "", "$ID3 => $ID4" ) - val fixedIDs = with(newCordappProvider(fixupJar.toURI().toURL())) { - start() - fixupAttachmentIds(listOf(ID2, ID1)) + val fixedIDs = with(newCordappProvider(setOf(fixupJar.toPath()))) { + attachmentFixups.fixupAttachmentIds(listOf(ID2, ID1)) } assertThat(fixedIDs).containsExactlyInAnyOrder(ID2, ID4) } - @Test(timeout=300_000) - fun `test an exception is raised when we have two jars with the same hash`() { - - SelfCleaningDir().use { file -> - val jarAndSigner = ContractJarTestUtils.makeTestSignedContractJar(file.path, "com.example.MyContract") - val signedJarPath = jarAndSigner.first - val duplicateJarPath = signedJarPath.parent.resolve("duplicate-" + signedJarPath.fileName) - - Files.copy(signedJarPath, duplicateJarPath) - val urls = asList(signedJarPath.toUri().toURL(), duplicateJarPath.toUri().toURL()) - JarScanningCordappLoader.fromJarUrls(urls, VersionInfo.UNKNOWN).use { - assertFailsWith { - CordappProviderImpl(it, stubConfigProvider, attachmentStore).apply { start() } - } - } - } - } - - @Test(timeout=300_000) - fun `test an exception is raised when two jars share a contract`() { - - SelfCleaningDir().use { file -> - val jarA = ContractJarTestUtils.makeTestContractJar(file.path, listOf("com.example.MyContract", "com.example.AnotherContractForA"), generateManifest = false, jarFileName = "sampleA.jar") - val jarB = ContractJarTestUtils.makeTestContractJar(file.path, listOf("com.example.MyContract", "com.example.AnotherContractForB"), generateManifest = false, jarFileName = "sampleB.jar") - val urls = asList(jarA.toUri().toURL(), jarB.toUri().toURL()) - JarScanningCordappLoader.fromJarUrls(urls, VersionInfo.UNKNOWN).use { - assertFailsWith { - CordappProviderImpl(it, stubConfigProvider, attachmentStore).apply { start() } - } - } - } - } - private fun File.writeFixupRules(vararg lines: String): File { JarOutputStream(FileOutputStream(this)).use { jar -> jar.setMethod(DEFLATED) @@ -233,15 +224,17 @@ class CordappProviderImplTests { jar.putNextEntry(fileEntry("META-INF/Corda-Fixups")) for (line in lines) { jar.write(line.toByteArray()) - jar.write('\r'.toInt()) - jar.write('\n'.toInt()) + jar.write('\r'.code) + jar.write('\n'.code) } } return this } - private fun newCordappProvider(vararg urls: URL): CordappProviderImpl { - val loader = JarScanningCordappLoader.fromJarUrls(urls.toList(), VersionInfo.UNKNOWN) - return CordappProviderImpl(loader, stubConfigProvider, attachmentStore).apply { start() } + private fun newCordappProvider(cordappJars: Set, + legacyContractJars: Set = emptySet(), + cordappConfigProvider: CordappConfigProvider = stubConfigProvider): CordappProviderImpl { + val loader = JarScanningCordappLoader(cordappJars, legacyContractJars) + return CordappProviderImpl(loader, cordappConfigProvider, attachmentStore).apply { start() } } } diff --git a/node/src/test/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoaderTest.kt b/node/src/test/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoaderTest.kt index 9bc3f15efe..956f2bd3fd 100644 --- a/node/src/test/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoaderTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoaderTest.kt @@ -1,17 +1,48 @@ package net.corda.node.internal.cordapp import co.paralleluniverse.fibers.Suspendable -import net.corda.core.flows.* -import net.corda.core.internal.JavaVersion +import net.corda.core.cordapp.Cordapp +import net.corda.core.flows.FlowLogic +import net.corda.core.flows.FlowSession +import net.corda.core.flows.InitiatedBy +import net.corda.core.flows.InitiatingFlow +import net.corda.core.flows.SchedulableFlow +import net.corda.core.flows.StartableByRPC +import net.corda.core.internal.packageName_ +import net.corda.core.internal.toPath +import net.corda.coretesting.internal.delete +import net.corda.coretesting.internal.modifyJarManifest +import net.corda.finance.contracts.CommercialPaper +import net.corda.finance.contracts.asset.Cash +import net.corda.finance.flows.CashIssueFlow +import net.corda.finance.flows.CashPaymentFlow +import net.corda.finance.internal.ConfigHolder +import net.corda.finance.schemas.CashSchemaV1 +import net.corda.finance.schemas.CommercialPaperSchemaV1 import net.corda.node.VersionInfo import net.corda.nodeapi.internal.DEV_PUB_KEY_HASHES +import net.corda.serialization.internal.DefaultWhitelist +import net.corda.testing.core.ALICE_NAME +import net.corda.testing.core.internal.ContractJarTestUtils.makeTestContractJar +import net.corda.testing.core.internal.JarSignatureTestUtils.generateKey +import net.corda.testing.core.internal.JarSignatureTestUtils.getJarSigners +import net.corda.testing.core.internal.JarSignatureTestUtils.signJar +import net.corda.testing.core.internal.JarSignatureTestUtils.unsignJar +import net.corda.testing.internal.LogHelper import net.corda.testing.node.internal.cordappWithPackages import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.assertj.core.api.Assertions.assertThatIllegalStateException +import org.junit.Rule import org.junit.Test +import org.junit.rules.TemporaryFolder +import java.nio.file.Path import java.nio.file.Paths -import net.corda.core.internal.packageName_ -import org.junit.Assume -import java.lang.IllegalStateException +import java.util.jar.Manifest +import kotlin.io.path.absolutePathString +import kotlin.io.path.copyTo +import kotlin.io.path.name +import kotlin.test.assertFailsWith @InitiatingFlow class DummyFlow : FlowLogic() { @@ -39,10 +70,19 @@ class DummyRPCFlow : FlowLogic() { class JarScanningCordappLoaderTest { private companion object { - const val isolatedContractId = "net.corda.isolated.contracts.AnotherDummyContract" - const val isolatedFlowName = "net.corda.isolated.workflows.IsolatedIssuanceFlow" + val legacyFinanceContractsJar = this::class.java.getResource("/corda-finance-contracts-4.11.jar")!!.toPath() + val currentFinanceContractsJar = this::class.java.getResource("/corda-finance-contracts.jar")!!.toPath() + val currentFinanceWorkflowsJar = this::class.java.getResource("/corda-finance-workflows.jar")!!.toPath() + + init { + LogHelper.setLevel(JarScanningCordappLoaderTest::class) + } } + @Rule + @JvmField + val tempFolder = TemporaryFolder() + @Test(timeout=300_000) fun `classes that aren't in cordapps aren't loaded`() { // Basedir will not be a corda node directory so the dummy flow shouldn't be recognised as a part of a cordapp @@ -51,44 +91,47 @@ class JarScanningCordappLoaderTest { } @Test(timeout=300_000) - fun `isolated JAR contains a CorDapp with a contract and plugin`() { - val isolatedJAR = JarScanningCordappLoaderTest::class.java.getResource("/isolated.jar") - val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR)) + fun `constructed CordappImpls contains the right classes`() { + val loader = JarScanningCordappLoader(setOf(currentFinanceContractsJar, currentFinanceWorkflowsJar)) + val (contractsCordapp, workflowsCordapp) = loader.cordapps - assertThat(loader.cordapps).hasSize(1) + assertThat(contractsCordapp.contractClassNames).contains(Cash::class.java.name, CommercialPaper::class.java.name) + assertThat(contractsCordapp.customSchemas).contains(CashSchemaV1, CommercialPaperSchemaV1) + assertThat(contractsCordapp.info).isInstanceOf(Cordapp.Info.Contract::class.java) + assertThat(contractsCordapp.allFlows).isEmpty() + assertThat(contractsCordapp.jarFile).isEqualTo(currentFinanceContractsJar) - val actualCordapp = loader.cordapps.single() - assertThat(actualCordapp.contractClassNames).isEqualTo(listOf(isolatedContractId)) - assertThat(actualCordapp.initiatedFlows).isEmpty() - assertThat(actualCordapp.rpcFlows.first().name).isEqualTo(isolatedFlowName) - assertThat(actualCordapp.schedulableFlows).isEmpty() - assertThat(actualCordapp.services).isEmpty() - assertThat(actualCordapp.serializationWhitelists).hasSize(1) - assertThat(actualCordapp.serializationWhitelists.first().javaClass.name).isEqualTo("net.corda.serialization.internal.DefaultWhitelist") - assertThat(actualCordapp.jarPath).isEqualTo(isolatedJAR) + assertThat(workflowsCordapp.allFlows).contains(CashIssueFlow::class.java, CashPaymentFlow::class.java) + assertThat(workflowsCordapp.services).contains(ConfigHolder::class.java) + assertThat(workflowsCordapp.info).isInstanceOf(Cordapp.Info.Workflow::class.java) + assertThat(workflowsCordapp.contractClassNames).isEmpty() + assertThat(workflowsCordapp.jarFile).isEqualTo(currentFinanceWorkflowsJar) + + for (actualCordapp in loader.cordapps) { + assertThat(actualCordapp.cordappClasses) + .containsAll(actualCordapp.contractClassNames) + .containsAll(actualCordapp.initiatedFlows.map { it.name }) + .containsAll(actualCordapp.rpcFlows.map { it.name }) + .containsAll(actualCordapp.serviceFlows.map { it.name }) + .containsAll(actualCordapp.schedulableFlows.map { it.name }) + .containsAll(actualCordapp.services.map { it.name }) + .containsAll(actualCordapp.telemetryComponents.map { it.name }) + .containsAll(actualCordapp.serializationCustomSerializers.map { it.javaClass.name }) + .containsAll(actualCordapp.checkpointCustomSerializers.map { it.javaClass.name }) + .containsAll(actualCordapp.customSchemas.map { it.name }) + assertThat(actualCordapp.serializationWhitelists).contains(DefaultWhitelist) + } } @Test(timeout=300_000) - fun `constructed CordappImpl contains the right cordapp classes`() { - val isolatedJAR = JarScanningCordappLoaderTest::class.java.getResource("/isolated.jar") - val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR)) - - val actualCordapp = loader.cordapps.single() - val cordappClasses = actualCordapp.cordappClasses - assertThat(cordappClasses).contains(isolatedFlowName) - val serializationWhitelistedClasses = actualCordapp.serializationWhitelists.flatMap { it.whitelist }.map { it.name } - assertThat(cordappClasses).containsAll(serializationWhitelistedClasses) - } - - @Test(timeout=300_000) - fun `flows are loaded by loader`() { + fun `flows are loaded by loader`() { val jarFile = cordappWithPackages(javaClass.packageName_).jarFile - val loader = JarScanningCordappLoader.fromJarUrls(listOf(jarFile.toUri().toURL())) + val loader = JarScanningCordappLoader(setOf(jarFile)) // One cordapp from this source tree. In gradle it will also pick up the node jar. assertThat(loader.cordapps).isNotEmpty - val actualCordapp = loader.cordapps.single { !it.initiatedFlows.isEmpty() } + val actualCordapp = loader.cordapps.single { it.initiatedFlows.isNotEmpty() } assertThat(actualCordapp.initiatedFlows.first()).hasSameClassAs(DummyFlow::class.java) assertThat(actualCordapp.rpcFlows).first().hasSameClassAs(DummyRPCFlow::class.java) assertThat(actualCordapp.schedulableFlows).first().hasSameClassAs(DummySchedulableFlow::class.java) @@ -97,18 +140,16 @@ class JarScanningCordappLoaderTest { // This test exists because the appClassLoader is used by serialisation and we need to ensure it is the classloader // being used internally. Later iterations will use a classloader per cordapp and this test can be retired. @Test(timeout=300_000) - fun `cordapp classloader can load cordapp classes`() { - val isolatedJAR = JarScanningCordappLoaderTest::class.java.getResource("/isolated.jar") - val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR), VersionInfo.UNKNOWN) + fun `cordapp classloader can load cordapp classes`() { + val testJar = this::class.java.getResource("/testing-cashobservers-cordapp.jar")!!.toPath() + val loader = JarScanningCordappLoader(setOf(testJar)) - loader.appClassLoader.loadClass(isolatedContractId) - loader.appClassLoader.loadClass(isolatedFlowName) + loader.appClassLoader.loadClass("net.corda.finance.test.flows.CashIssueWithObserversFlow") } @Test(timeout=300_000) - fun `cordapp classloader sets target and min version to 1 if not specified`() { - val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/no-min-or-target-version.jar")!! - val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN) + fun `sets target and min version to 1 if not specified`() { + val loader = JarScanningCordappLoader(setOf(minAndTargetCordapp(minVersion = null, targetVersion = null))) loader.cordapps.forEach { assertThat(it.targetPlatformVersion).isEqualTo(1) assertThat(it.minimumPlatformVersion).isEqualTo(1) @@ -116,79 +157,185 @@ class JarScanningCordappLoaderTest { } @Test(timeout=300_000) - fun `cordapp classloader returns correct values for minPlatformVersion and targetVersion`() { - // load jar with min and target version in manifest - // make sure classloader extracts correct values - val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!! - val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN) + fun `returns correct values for minPlatformVersion and targetVersion`() { + val loader = JarScanningCordappLoader(setOf(minAndTargetCordapp(minVersion = 2, targetVersion = 3))) val cordapp = loader.cordapps.first() assertThat(cordapp.targetPlatformVersion).isEqualTo(3) assertThat(cordapp.minimumPlatformVersion).isEqualTo(2) } @Test(timeout=300_000) - fun `cordapp classloader sets target version to min version if target version is not specified`() { - // load jar with minVersion but not targetVersion in manifest - val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-no-target.jar")!! - val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN) + fun `sets target version to min version if target version is not specified`() { + val loader = JarScanningCordappLoader(setOf(minAndTargetCordapp(minVersion = 2, targetVersion = null))) // exclude the core cordapp val cordapp = loader.cordapps.first() assertThat(cordapp.targetPlatformVersion).isEqualTo(2) assertThat(cordapp.minimumPlatformVersion).isEqualTo(2) } - @Test(expected = InvalidCordappException::class, timeout = 300_000) - fun `cordapp classloader does not load apps when their min platform version is greater than the node platform version`() { - val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-no-target.jar")!! - JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1)).cordapps + @Test(timeout = 300_000) + fun `does not load apps when their min platform version is greater than the node platform version`() { + val jar = minAndTargetCordapp(minVersion = 2, targetVersion = null) + val cordappLoader = JarScanningCordappLoader(setOf(jar), versionInfo = VersionInfo.UNKNOWN.copy(platformVersion = 1)) + assertThatExceptionOfType(InvalidCordappException::class.java).isThrownBy { + cordappLoader.cordapps + } } @Test(timeout=300_000) - fun `cordapp classloader does load apps when their min platform version is less than the platform version`() { - val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!! - val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1000)) + fun `does load apps when their min platform version is less than the platform version`() { + val jar = minAndTargetCordapp(minVersion = 2, targetVersion = 3) + val loader = JarScanningCordappLoader(setOf(jar), versionInfo = VersionInfo.UNKNOWN.copy(platformVersion = 1000)) assertThat(loader.cordapps).hasSize(1) } @Test(timeout=300_000) - fun `cordapp classloader does load apps when their min platform version is equal to the platform version`() { - val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!! - val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 2)) + fun `does load apps when their min platform version is equal to the platform version`() { + val jar = minAndTargetCordapp(minVersion = 2, targetVersion = 3) + val loader = JarScanningCordappLoader(setOf(jar), versionInfo = VersionInfo.UNKNOWN.copy(platformVersion = 2)) assertThat(loader.cordapps).hasSize(1) } @Test(timeout=300_000) - fun `cordapp classloader loads app signed by allowed certificate`() { - val jar = JarScanningCordappLoaderTest::class.java.getResource("signed/signed-by-dev-key.jar")!! - val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), cordappsSignerKeyFingerprintBlacklist = emptyList()) + fun `loads app signed by allowed certificate`() { + val loader = JarScanningCordappLoader(setOf(currentFinanceContractsJar), signerKeyFingerprintBlacklist = emptyList()) assertThat(loader.cordapps).hasSize(1) } - @Test(expected = InvalidCordappException::class, timeout = 300_000) - fun `cordapp classloader does not load app signed by blacklisted certificate`() { - val jar = JarScanningCordappLoaderTest::class.java.getResource("signed/signed-by-dev-key.jar")!! - JarScanningCordappLoader.fromJarUrls(listOf(jar), cordappsSignerKeyFingerprintBlacklist = DEV_PUB_KEY_HASHES).cordapps + @Test(timeout = 300_000) + fun `does not load app signed by blacklisted certificate`() { + val cordappLoader = JarScanningCordappLoader(setOf(currentFinanceContractsJar), signerKeyFingerprintBlacklist = DEV_PUB_KEY_HASHES) + assertThatExceptionOfType(InvalidCordappException::class.java).isThrownBy { + cordappLoader.cordapps + } } @Test(timeout=300_000) - fun `cordapp classloader loads app signed by both allowed and non-blacklisted certificate`() { - val jar = JarScanningCordappLoaderTest::class.java.getResource("signed/signed-by-two-keys.jar")!! - val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), cordappsSignerKeyFingerprintBlacklist = DEV_PUB_KEY_HASHES) + fun `does not load legacy contract CorDapp signed by blacklisted certificate`() { + val unsignedJar = currentFinanceContractsJar.duplicate { unsignJar() } + val loader = JarScanningCordappLoader(setOf(unsignedJar), setOf(legacyFinanceContractsJar), signerKeyFingerprintBlacklist = DEV_PUB_KEY_HASHES) + assertThatExceptionOfType(InvalidCordappException::class.java) + .isThrownBy { loader.cordapps } + .withMessageContaining("Corresponding contracts are signed by blacklisted key(s)") + .withMessageContaining(legacyFinanceContractsJar.name) + } + + @Test(timeout=300_000) + fun `does not load duplicate CorDapps`() { + val duplicateJar = currentFinanceWorkflowsJar.duplicate() + val loader = JarScanningCordappLoader(setOf(currentFinanceWorkflowsJar, duplicateJar)) + assertFailsWith { + loader.cordapps + } + } + + @Test(timeout=300_000) + fun `does not load contract shared across CorDapps`() { + val cordappJars = (1..2).map { + makeTestContractJar( + tempFolder.root.toPath(), + listOf("com.example.MyContract", "com.example.AnotherContractFor$it"), + generateManifest = false, + jarFileName = "sample$it.jar" + ) + }.toSet() + val loader = JarScanningCordappLoader(cordappJars) + assertThatIllegalStateException() + .isThrownBy { loader.cordapps } + .withMessageContaining("Contract com.example.MyContract occuring in multiple CorDapps") + } + + @Test(timeout=300_000) + fun `loads app signed by both allowed and non-blacklisted certificate`() { + val jar = currentFinanceWorkflowsJar.duplicate { + tempFolder.root.toPath().generateKey("testAlias", "testPassword", ALICE_NAME.toString()) + tempFolder.root.toPath().signJar(absolutePathString(), "testAlias", "testPassword") + } + assertThat(jar.parent.getJarSigners(jar.name)).hasSize(2) + val loader = JarScanningCordappLoader(setOf(jar), signerKeyFingerprintBlacklist = DEV_PUB_KEY_HASHES) assertThat(loader.cordapps).hasSize(1) } @Test(timeout=300_000) - fun `cordapp classloader successfully loads app containing only flow classes at java class version 55`() { - Assume.assumeTrue(JavaVersion.isVersionAtLeast(JavaVersion.Java_11)) - val jar = JarScanningCordappLoaderTest::class.java.getResource("/workflowClassAtVersion55.jar")!! - val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar)) - assertThat(loader.cordapps).hasSize(1) + fun `loads both legacy and current versions of the same contracts CorDapp`() { + val loader = JarScanningCordappLoader(setOf(currentFinanceContractsJar), setOf(legacyFinanceContractsJar)) + assertThat(loader.cordapps).hasSize(1) // Legacy contract CorDapps are not part of the main list + assertThat(loader.legacyContractCordapps).hasSize(1) + assertThat(loader.legacyContractCordapps.single().jarFile).isEqualTo(legacyFinanceContractsJar) } - @Test(expected = IllegalStateException::class, timeout=300_000) - fun `cordapp classloader raises exception when loading contract class at class version 55`() { - Assume.assumeTrue(JavaVersion.isVersionAtLeast(JavaVersion.Java_11)) - val jar = JarScanningCordappLoaderTest::class.java.getResource("/contractClassAtVersion55.jar")!! - JarScanningCordappLoader.fromJarUrls(listOf(jar)).cordapps + @Test(timeout=300_000) + fun `exception raised if legacy and non legacy version of same contract signed by differet keys`() { + val jar = currentFinanceContractsJar.duplicate { + tempFolder.root.toPath().generateKey("testAlias", "testPassword", ALICE_NAME.toString()) + tempFolder.root.toPath().signJar(absolutePathString(), "testAlias", "testPassword") + } + assertThatIllegalStateException() + .isThrownBy { JarScanningCordappLoader(setOf(jar), setOf(legacyFinanceContractsJar)).cordapps } + .withMessageContaining("signers do not match legacy contract CorDapp") + } + + @Test(timeout=300_000) + fun `loads legacy and non legacy version of same contract both signed by 2 keys`() { + val jar = currentFinanceContractsJar.duplicate { + tempFolder.root.toPath().generateKey("testAlias", "testPassword", ALICE_NAME.toString()) + tempFolder.root.toPath().signJar(absolutePathString(), "testAlias", "testPassword") + } + val legacyJar = legacyFinanceContractsJar.duplicate(name = "duplicate2.jar") { + tempFolder.root.toPath().signJar(absolutePathString(), "testAlias", "testPassword") + } + val loader = JarScanningCordappLoader(setOf(jar), setOf(legacyJar)) + assertThat(jar.parent.getJarSigners(jar.name)).hasSize(2) + assertThat(legacyJar.parent.getJarSigners(legacyJar.name)).hasSize(2) + assertThat(loader.cordapps).hasSize(1) + assertThat(loader.legacyContractCordapps).hasSize(1) + } + + @Test(timeout=300_000) + fun `does not load legacy contracts CorDapp without the corresponding current version`() { + val loader = JarScanningCordappLoader(setOf(currentFinanceWorkflowsJar), setOf(legacyFinanceContractsJar)) + assertThatIllegalStateException() + .isThrownBy { loader.legacyContractCordapps } + .withMessageContaining("does not have a corresponding newer version (4.12 or later). Please add this corresponding CorDapp or remove the legacy one.") + } + + @Test(timeout=300_000) + fun `checks if legacy contract CorDapp is actually legacy`() { + val loader = JarScanningCordappLoader(setOf(currentFinanceContractsJar), setOf(currentFinanceContractsJar)) + assertThatIllegalStateException() + .isThrownBy { loader.legacyContractCordapps } + .withMessageContaining("${currentFinanceContractsJar.name} is not legacy; please remove or place it in the node's CorDapps directory.") + } + + @Test(timeout=300_000) + fun `does not load if legacy CorDapp present in general list`() { + val loader = JarScanningCordappLoader(setOf(legacyFinanceContractsJar)) + assertThatIllegalStateException() + .isThrownBy { loader.cordapps } + .withMessageContaining("${legacyFinanceContractsJar.name} is legacy contracts; please place it in the node's 'legacy-contracts' directory.") + } + + private inline fun Path.duplicate(name: String = "duplicate.jar", modify: Path.() -> Unit = { }): Path { + val copy = tempFolder.newFile(name).toPath() + copyTo(copy, overwrite = true) + modify(copy) + return copy + } + + private fun minAndTargetCordapp(minVersion: Int?, targetVersion: Int?): Path { + return currentFinanceWorkflowsJar.duplicate { + modifyJarManifest { manifest -> + manifest.setOrDeleteAttribute("Min-Platform-Version", minVersion?.toString()) + manifest.setOrDeleteAttribute("Target-Platform-Version", targetVersion?.toString()) + } + } + } + + private fun Manifest.setOrDeleteAttribute(name: String, value: String?) { + if (value != null) { + mainAttributes.putValue(name, value.toString()) + } else { + mainAttributes.delete(name) + } } } diff --git a/node/src/test/kotlin/net/corda/node/internal/cordapp/TypesafeCordappConfigTests.kt b/node/src/test/kotlin/net/corda/node/internal/cordapp/TypesafeCordappConfigTests.kt index 18f20d6ad2..7034c17139 100644 --- a/node/src/test/kotlin/net/corda/node/internal/cordapp/TypesafeCordappConfigTests.kt +++ b/node/src/test/kotlin/net/corda/node/internal/cordapp/TypesafeCordappConfigTests.kt @@ -4,6 +4,7 @@ import com.typesafe.config.ConfigFactory import net.corda.core.cordapp.CordappConfigException import org.junit.Test import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType class TypesafeCordappConfigTests { @Test(timeout=300_000) @@ -37,11 +38,12 @@ class TypesafeCordappConfigTests { assertThat(cordappConf.exists("notexists")).isFalse() } - @Test(expected = CordappConfigException::class, timeout=300_000) + @Test(timeout=300_000) fun `test that an exception is thrown when trying to access a non-extant field`() { val config = ConfigFactory.empty() val cordappConf = TypesafeCordappConfig(config) - - cordappConf.get("anything") + assertThatExceptionOfType(CordappConfigException::class.java).isThrownBy { + cordappConf.get("anything") + } } } \ No newline at end of file diff --git a/node/src/test/kotlin/net/corda/node/internal/rpc/proxies/ThreadContextAdjustingRpcOpsProxyTest.kt b/node/src/test/kotlin/net/corda/node/internal/rpc/proxies/ThreadContextAdjustingRpcOpsProxyTest.kt index 368bc45627..c4ef81649d 100644 --- a/node/src/test/kotlin/net/corda/node/internal/rpc/proxies/ThreadContextAdjustingRpcOpsProxyTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/rpc/proxies/ThreadContextAdjustingRpcOpsProxyTest.kt @@ -1,7 +1,7 @@ package net.corda.node.internal.rpc.proxies -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.mock +import org.mockito.kotlin.any +import org.mockito.kotlin.mock import net.corda.core.flows.StateMachineRunId import net.corda.core.messaging.CordaRPCOps import org.assertj.core.api.Assertions.assertThat @@ -28,4 +28,4 @@ class ThreadContextAdjustingRpcOpsProxyTest { proxy.killFlow(StateMachineRunId.createRandom()) assertThat(Thread.currentThread().contextClassLoader).isNotEqualTo(mockClassloader) } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/internal/security/RPCPermissionResolverTest.kt b/node/src/test/kotlin/net/corda/node/internal/security/RPCPermissionResolverTest.kt index 0881e03028..83c74eafbb 100644 --- a/node/src/test/kotlin/net/corda/node/internal/security/RPCPermissionResolverTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/security/RPCPermissionResolverTest.kt @@ -5,6 +5,7 @@ import net.corda.node.internal.rpc.proxies.RpcAuthHelper.methodFullName import org.junit.Test import java.time.ZonedDateTime +import java.util.Locale import kotlin.test.assertEquals class RPCPermissionResolverTest { @@ -29,7 +30,7 @@ class RPCPermissionResolverTest { } private val readAlphaMethod = methodFullName(Alpha::class.java.getMethod("readAlpha")) - private val readAlphaMethodKey = readAlphaMethod.toLowerCase() + private val readAlphaMethodKey = readAlphaMethod.lowercase(Locale.getDefault()) @Test(timeout=300_000) fun `test Alpha`() { diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt index 2bdfc69e5f..5ba84aad24 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -26,6 +26,7 @@ import net.corda.core.identity.AnonymousParty import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.FlowStateMachine +import net.corda.core.internal.concurrent.flatMap import net.corda.core.internal.concurrent.map import net.corda.core.internal.rootCause import net.corda.core.messaging.DataFeed @@ -67,7 +68,6 @@ import net.corda.testing.core.singleIdentity import net.corda.testing.dsl.LedgerDSL import net.corda.testing.dsl.TestLedgerDSLInterpreter import net.corda.testing.dsl.TestTransactionDSLInterpreter -import net.corda.testing.internal.IS_OPENJ9 import net.corda.testing.internal.LogHelper import net.corda.testing.internal.vault.VaultFiller import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP @@ -78,22 +78,20 @@ import net.corda.testing.node.internal.TestStartedNode import net.corda.testing.node.internal.startFlow import net.corda.testing.node.ledger import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After -import org.junit.Assume import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import rx.Observable import java.io.ByteArrayOutputStream -import java.util.ArrayList import java.util.Collections import java.util.Currency import java.util.Random import java.util.UUID import java.util.jar.JarOutputStream import java.util.zip.ZipEntry -import kotlin.streams.toList import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertTrue @@ -189,7 +187,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) { } } - @Test(expected = InsufficientBalanceException::class, timeout=300_000) + @Test(timeout=300_000) fun `trade cash for commercial paper fails using soft locking`() { mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP), threadPerNode = true) val notaryNode = mockNet.defaultNotaryNode @@ -229,7 +227,13 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) { val (bobStateMachine, aliceResult) = runBuyerAndSeller(notary, bob, aliceNode, bobNode, "alice's paper".outputStateAndRef()) - assertEquals(aliceResult.getOrThrow(), bobStateMachine.getOrThrow().resultFuture.getOrThrow()) + assertThatExceptionOfType(InsufficientBalanceException::class.java).isThrownBy { + bobStateMachine.flatMap { it.resultFuture }.getOrThrow() + } + + assertThatExceptionOfType(InsufficientBalanceException::class.java).isThrownBy { + aliceResult.getOrThrow() + } aliceNode.dispose() bobNode.dispose() @@ -247,7 +251,6 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) { @Test(timeout=300_000) fun `shutdown and restore`() { - Assume.assumeTrue(!IS_OPENJ9) mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP, FINANCE_WORKFLOWS_CORDAPP)) val notaryNode = mockNet.defaultNotaryNode val notary = mockNet.defaultNotaryIdentity @@ -738,7 +741,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) { } val eb3Txns = insertFakeTransactions(listOf(bc2), node, identity, notaryNode, *extraSigningNodes) - val vault = Vault(listOf("bob cash 1".outputStateAndRef(), "bob cash 2".outputStateAndRef())) + val vault = Vault(listOf("bob cash 1".outputStateAndRef(), "bob cash 2".outputStateAndRef())) return Triple(vault, listOf(eb1, bc1, bc2), eb1Txns + eb2Txns + eb3Txns) } @@ -751,10 +754,10 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) { notary: Party): Pair, List> { val ap = transaction(transactionBuilder = TransactionBuilder(notary = notary)) { output(CommercialPaper.CP_PROGRAM_ID, "alice's paper", notary = notary, - contractState = CommercialPaper.State(issuer, owner, amount, net.corda.coretesting.internal.TEST_TX_TIME + 7.days)) + contractState = CommercialPaper.State(issuer, owner, amount, TEST_TX_TIME + 7.days)) command(issuer.party.owningKey, CommercialPaper.Commands.Issue()) if (!withError) - timeWindow(time = net.corda.coretesting.internal.TEST_TX_TIME) + timeWindow(time = TEST_TX_TIME) if (attachmentID != null) attachment(attachmentID) if (withError) { @@ -764,7 +767,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) { } } - val vault = Vault(listOf("alice's paper".outputStateAndRef())) + val vault = Vault(listOf("alice's paper".outputStateAndRef())) return Pair(vault, listOf(ap)) } @@ -790,7 +793,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) { } } - val records: MutableList = Collections.synchronizedList(ArrayList()) + val records: MutableList = Collections.synchronizedList(ArrayList()) override val updates: Observable get() = delegate.updates diff --git a/node/src/test/kotlin/net/corda/node/migration/IdenityServiceKeyRotationMigrationTest.kt b/node/src/test/kotlin/net/corda/node/migration/IdenityServiceKeyRotationMigrationTest.kt index 68a1347db7..9e43133154 100644 --- a/node/src/test/kotlin/net/corda/node/migration/IdenityServiceKeyRotationMigrationTest.kt +++ b/node/src/test/kotlin/net/corda/node/migration/IdenityServiceKeyRotationMigrationTest.kt @@ -1,7 +1,7 @@ package net.corda.node.migration -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import liquibase.Contexts import liquibase.Liquibase import liquibase.database.Database @@ -114,4 +114,4 @@ class IdenityServiceKeyRotationMigrationTest { assertEquals(results[bob2.publicKey.toStringShort()], BOB_NAME to bob.publicKey.toStringShort()) assertEquals(results[charlie2.publicKey.toStringShort()], CHARLIE_NAME to dummyKey.toStringShort()) } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/migration/IdentityServiceToStringShortMigrationTest.kt b/node/src/test/kotlin/net/corda/node/migration/IdentityServiceToStringShortMigrationTest.kt index 5f9d7f4785..3dd068dc8a 100644 --- a/node/src/test/kotlin/net/corda/node/migration/IdentityServiceToStringShortMigrationTest.kt +++ b/node/src/test/kotlin/net/corda/node/migration/IdentityServiceToStringShortMigrationTest.kt @@ -1,7 +1,7 @@ package net.corda.node.migration -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import liquibase.database.core.H2Database import liquibase.database.jvm.JdbcConnection import net.corda.core.crypto.toStringShort @@ -19,9 +19,11 @@ import net.corda.testing.internal.configureDatabase import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import org.hamcrest.CoreMatchers import org.hamcrest.Matcher -import org.hamcrest.Matchers.* +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.anyOf +import org.hamcrest.Matchers.`is` +import org.hamcrest.number.OrderingComparison.greaterThan import org.junit.After -import org.junit.Assert import org.junit.Before import org.junit.Test @@ -100,9 +102,9 @@ class IdentityServiceToStringShortMigrationTest { val hashToIdentityResultSet = hashToIdentityStatement.executeQuery() //check that there is a row for every "new" hash - Assert.assertThat(hashToIdentityResultSet.next(), `is`(true)) + assertThat(hashToIdentityResultSet.next(), `is`(true)) //check that the pk_hash actually matches what we expect (kinda redundant, but deserializing the whole PartyAndCertificate feels like overkill) - Assert.assertThat(hashToIdentityResultSet.getString(1), `is`(it.owningKey.toStringShort())) + assertThat(hashToIdentityResultSet.getString(1), `is`(it.owningKey.toStringShort())) val nameToHashStatement = connection.prepareStatement("SELECT name FROM node_named_identities WHERE pk_hash=?") nameToHashStatement.setString(1, it.owningKey.toStringShort()) @@ -110,7 +112,7 @@ class IdentityServiceToStringShortMigrationTest { //if there is no result for this key, this means its an identity that is not stored in the DB (IE, it's been seen after another identity has already been mapped to it) if (nameToHashResultSet.next()) { - Assert.assertThat(nameToHashResultSet.getString(1), `is`(anyOf(groupedByNameIdentities.getValue(it.name).map?> { identity -> CoreMatchers.equalTo(identity.name.toString()) }))) + assertThat(nameToHashResultSet.getString(1), `is`(anyOf(groupedByNameIdentities.getValue(it.name).map?> { identity -> CoreMatchers.equalTo(identity.name.toString()) }))) } else { logger.warn("did not find a PK_HASH for ${it.name}") listOfNamesWithoutPkHash.add(it.name) @@ -121,7 +123,7 @@ class IdentityServiceToStringShortMigrationTest { listOfNamesWithoutPkHash.forEach { //the only time an identity name does not have a PK_HASH is if there are multiple identities associated with that name - Assert.assertThat(groupedByNameIdentities[it]?.size, `is`(greaterThan(1))) + assertThat(groupedByNameIdentities[it]?.size!!, greaterThan(1)) } } } diff --git a/node/src/test/kotlin/net/corda/node/migration/PersistentIdentityMigrationNewTableTest.kt b/node/src/test/kotlin/net/corda/node/migration/PersistentIdentityMigrationNewTableTest.kt index 2e65364932..19505e1a43 100644 --- a/node/src/test/kotlin/net/corda/node/migration/PersistentIdentityMigrationNewTableTest.kt +++ b/node/src/test/kotlin/net/corda/node/migration/PersistentIdentityMigrationNewTableTest.kt @@ -1,7 +1,7 @@ package net.corda.node.migration -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import liquibase.database.core.H2Database import liquibase.database.jvm.JdbcConnection import net.corda.core.crypto.Crypto @@ -96,4 +96,4 @@ class PersistentIdentityMigrationNewTableTest { session.createQuery(criteria).resultList } } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/migration/VaultStateMigrationTest.kt b/node/src/test/kotlin/net/corda/node/migration/VaultStateMigrationTest.kt deleted file mode 100644 index 9688afca81..0000000000 --- a/node/src/test/kotlin/net/corda/node/migration/VaultStateMigrationTest.kt +++ /dev/null @@ -1,601 +0,0 @@ -package net.corda.node.migration - -import liquibase.database.Database -import liquibase.database.jvm.JdbcConnection -import net.corda.core.contracts.* -import net.corda.core.crypto.* -import net.corda.core.identity.AbstractParty -import net.corda.core.identity.CordaX500Name -import net.corda.core.identity.PartyAndCertificate -import net.corda.core.internal.NotaryChangeTransactionBuilder -import net.corda.core.internal.packageName -import net.corda.core.internal.signWithCert -import net.corda.core.node.NetworkParameters -import net.corda.core.node.NotaryInfo -import net.corda.core.node.services.Vault -import net.corda.core.schemas.PersistentStateRef -import net.corda.core.serialization.SerializationDefaults -import net.corda.core.serialization.serialize -import net.corda.core.transactions.SignedTransaction -import net.corda.core.transactions.TransactionBuilder -import net.corda.core.utilities.contextLogger -import net.corda.finance.DOLLARS -import net.corda.finance.contracts.Commodity -import net.corda.finance.contracts.asset.Cash -import net.corda.finance.contracts.asset.Obligation -import net.corda.finance.contracts.asset.OnLedgerAsset -import net.corda.finance.schemas.CashSchemaV1 -import net.corda.node.internal.DBNetworkParametersStorage -import net.corda.node.internal.schemas.NodeInfoSchemaV1 -import net.corda.node.services.identity.PersistentIdentityService -import net.corda.node.services.keys.BasicHSMKeyManagementService -import net.corda.node.services.persistence.DBTransactionStorage -import net.corda.node.services.vault.VaultSchemaV1 -import net.corda.nodeapi.internal.crypto.X509Utilities -import net.corda.nodeapi.internal.persistence.CordaPersistence -import net.corda.nodeapi.internal.persistence.DatabaseConfig -import net.corda.nodeapi.internal.persistence.contextTransactionOrNull -import net.corda.nodeapi.internal.persistence.currentDBSession -import net.corda.testing.core.* -import net.corda.testing.internal.configureDatabase -import net.corda.testing.internal.vault.CommodityState -import net.corda.testing.internal.vault.DUMMY_LINEAR_CONTRACT_PROGRAM_ID -import net.corda.testing.internal.vault.DummyLinearContract -import net.corda.testing.internal.vault.DummyLinearStateSchemaV1 -import net.corda.testing.node.MockServices -import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties -import net.corda.testing.node.TestClock -import net.corda.testing.node.makeTestIdentityService -import org.junit.* -import org.mockito.Mockito -import java.security.KeyPair -import java.time.Clock -import java.time.Duration -import java.time.Instant -import java.util.* -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith -import kotlin.test.assertFalse - -/** - * These tests aim to verify that migrating vault states from V3 to later versions works correctly. While these unit tests verify the - * migrating behaviour is correct (tables populated, columns updated for the right states), it comes with a caveat: they do not test that - * deserialising states with the attachment classloader works correctly. - * - * The reason for this is that it is impossible to do so. There is no real way of writing a unit or integration test to upgrade from one - * version to another (at the time of writing). These tests simulate a small part of the upgrade process by directly using hibernate to - * populate a database as a V3 node would, then running the migration class. However, it is impossible to do this for attachments as there - * is no contract state jar to serialise. - */ -class VaultStateMigrationTest { - companion object { - val alice = TestIdentity(ALICE_NAME, 70) - val bankOfCorda = TestIdentity(BOC_NAME) - val bob = TestIdentity(BOB_NAME, 80) - private val charlie = TestIdentity(CHARLIE_NAME, 90) - val dummyCashIssuer = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10) - val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20) - val ALICE get() = alice.party - val ALICE_IDENTITY get() = alice.identity - val BOB get() = bob.party - val BOB_IDENTITY get() = bob.identity - val BOC_IDENTITY get() = bankOfCorda.identity - val BOC_KEY get() = bankOfCorda.keyPair - val CHARLIE get() = charlie.party - val DUMMY_NOTARY get() = dummyNotary.party - val bob2 = TestIdentity(BOB_NAME, 40) - val BOB2 = bob2.party - val BOB2_IDENTITY = bob2.identity - - val clock: TestClock = TestClock(Clock.systemUTC()) - - @ClassRule - @JvmField - val testSerialization = SerializationEnvironmentRule() - - val logger = contextLogger() - } - - val cordappPackages = listOf( - "net.corda.finance.contracts", - CashSchemaV1::class.packageName, - DummyLinearStateSchemaV1::class.packageName) - - lateinit var liquibaseDB: Database - lateinit var cordaDB: CordaPersistence - lateinit var notaryServices: MockServices - - @Before - fun setUp() { - val identityService = makeTestIdentityService(dummyNotary.identity, BOB_IDENTITY, ALICE_IDENTITY) - notaryServices = MockServices(cordappPackages, dummyNotary, identityService, dummyCashIssuer.keyPair, BOC_KEY) - cordaDB = configureDatabase( - makeTestDataSourceProperties(), - DatabaseConfig(), - notaryServices.identityService::wellKnownPartyFromX500Name, - notaryServices.identityService::wellKnownPartyFromAnonymous, - ourName = BOB_IDENTITY.name) - val liquibaseConnection = Mockito.mock(JdbcConnection::class.java) - Mockito.`when`(liquibaseConnection.url).thenReturn(cordaDB.jdbcUrl) - Mockito.`when`(liquibaseConnection.wrappedConnection).thenReturn(cordaDB.dataSource.connection) - liquibaseDB = Mockito.mock(Database::class.java) - Mockito.`when`(liquibaseDB.connection).thenReturn(liquibaseConnection) - - saveOurKeys(listOf(bob.keyPair, bob2.keyPair)) - saveAllIdentities(listOf(BOB_IDENTITY, ALICE_IDENTITY, BOC_IDENTITY, dummyNotary.identity, BOB2_IDENTITY)) - addNetworkParameters() - } - - @After - fun close() { - contextTransactionOrNull?.close() - cordaDB.close() - } - - private fun addNetworkParameters() { - cordaDB.transaction { - val clock = Clock.systemUTC() - val params = NetworkParameters( - 1, - listOf(NotaryInfo(DUMMY_NOTARY, false), NotaryInfo(CHARLIE, false)), - 1, - 1, - clock.instant(), - 1, - mapOf(), - Duration.ZERO, - mapOf() - ) - val signedParams = params.signWithCert(bob.keyPair.private, BOB_IDENTITY.certificate) - val persistentParams = DBNetworkParametersStorage.PersistentNetworkParameters( - SecureHash.allOnesHash.toString(), - params.epoch, - signedParams.raw.bytes, - signedParams.sig.bytes, - signedParams.sig.by.encoded, - X509Utilities.buildCertPath(signedParams.sig.parentCertsChain).encoded - ) - session.save(persistentParams) - } - } - - private fun createCashTransaction(cash: Cash, value: Amount, owner: AbstractParty): SignedTransaction { - val tx = TransactionBuilder(DUMMY_NOTARY) - cash.generateIssue(tx, Amount(value.quantity, Issued(bankOfCorda.ref(1), value.token)), owner, DUMMY_NOTARY) - return notaryServices.signInitialTransaction(tx, bankOfCorda.party.owningKey) - } - - private fun createVaultStatesFromTransaction(tx: SignedTransaction, stateStatus: Vault.StateStatus = Vault.StateStatus.UNCONSUMED) { - cordaDB.transaction { - tx.coreTransaction.outputs.forEachIndexed { index, state -> - val constraintInfo = Vault.ConstraintInfo(state.constraint) - val persistentState = VaultSchemaV1.VaultStates( - notary = state.notary, - contractStateClassName = state.data.javaClass.name, - stateStatus = stateStatus, - recordedTime = clock.instant(), - relevancyStatus = Vault.RelevancyStatus.RELEVANT, //Always persist as relevant to mimic V3 - constraintType = constraintInfo.type(), - constraintData = constraintInfo.data() - ) - persistentState.stateRef = PersistentStateRef(tx.id.toString(), index) - session.save(persistentState) - } - } - } - - private fun saveOurKeys(keys: List) { - cordaDB.transaction { - keys.forEach { - val persistentKey = BasicHSMKeyManagementService.PersistentKey(it.public, it.private) - session.save(persistentKey) - } - } - } - - private fun saveAllIdentities(identities: List) { - cordaDB.transaction { - identities.groupBy { it.name }.forEach { (_, certs) -> - val persistentIDs = certs.map { PersistentIdentityService.PersistentPublicKeyHashToCertificate(it.owningKey.toStringShort(), it.certPath.encoded) } - persistentIDs.forEach { session.save(it) } - val networkIdentity = NodeInfoSchemaV1.DBPartyAndCertificate(certs.first(), true) - val persistentNodeInfo = NodeInfoSchemaV1.PersistentNodeInfo(0, "", listOf(), listOf(networkIdentity), 0, 0) - session.save(persistentNodeInfo) - } - } - } - - private fun storeTransaction(tx: SignedTransaction) { - cordaDB.transaction { - val persistentTx = DBTransactionStorage.DBTransaction( - txId = tx.id.toString(), - stateMachineRunId = null, - transaction = tx.serialize(context = SerializationDefaults.STORAGE_CONTEXT).bytes, - status = DBTransactionStorage.TransactionStatus.VERIFIED, - timestamp = Instant.now(), - signatures = null - ) - session.save(persistentTx) - } - } - - private fun getVaultStateCount(relevancyStatus: Vault.RelevancyStatus = Vault.RelevancyStatus.ALL): Long { - return cordaDB.transaction { - val criteriaBuilder = cordaDB.entityManagerFactory.criteriaBuilder - val criteriaQuery = criteriaBuilder.createQuery(Long::class.java) - val queryRootStates = criteriaQuery.from(VaultSchemaV1.VaultStates::class.java) - criteriaQuery.select(criteriaBuilder.count(queryRootStates)) - if (relevancyStatus != Vault.RelevancyStatus.ALL) { - criteriaQuery.where(criteriaBuilder.equal(queryRootStates.get("relevancyStatus"), relevancyStatus)) - } - val query = session.createQuery(criteriaQuery) - query.singleResult - } - } - - private fun getStatePartyCount(): Long { - return cordaDB.transaction { - val criteriaBuilder = cordaDB.entityManagerFactory.criteriaBuilder - val criteriaQuery = criteriaBuilder.createQuery(Long::class.java) - val queryRootStates = criteriaQuery.from(VaultSchemaV1.PersistentParty::class.java) - criteriaQuery.select(criteriaBuilder.count(queryRootStates)) - val query = session.createQuery(criteriaQuery) - query.singleResult - } - } - - private fun addCashStates(statesToAdd: Int, owner: AbstractParty, stateStatus: Vault.StateStatus = Vault.StateStatus.UNCONSUMED) { - val cash = Cash() - cordaDB.transaction { - (1..statesToAdd).map { createCashTransaction(cash, it.DOLLARS, owner) }.forEach { - storeTransaction(it) - createVaultStatesFromTransaction(it, stateStatus) - } - } - } - - private fun createLinearStateTransaction(idString: String, - parties: List = listOf(), - linearString: String = "foo", - linearNumber: Long = 0L, - linearBoolean: Boolean = false): SignedTransaction { - val tx = TransactionBuilder(notary = dummyNotary.party).apply { - addOutputState(DummyLinearContract.State( - linearId = UniqueIdentifier(idString), - participants = parties, - linearString = linearString, - linearNumber = linearNumber, - linearBoolean = linearBoolean, - linearTimestamp = clock.instant()), DUMMY_LINEAR_CONTRACT_PROGRAM_ID - ) - addCommand(dummyCommand()) - } - return notaryServices.signInitialTransaction(tx) - } - - private fun addLinearStates(statesToAdd: Int, parties: List) { - cordaDB.transaction { - (1..statesToAdd).map { createLinearStateTransaction("A".repeat(it), parties) }.forEach { - storeTransaction(it) - createVaultStatesFromTransaction(it) - } - } - } - - private fun createCommodityTransaction(amount: Amount>, owner: AbstractParty): SignedTransaction { - val txBuilder = TransactionBuilder(notary = dummyNotary.party) - OnLedgerAsset.generateIssue(txBuilder, TransactionState(CommodityState(amount, owner), Obligation.PROGRAM_ID, dummyNotary.party), Obligation.Commands.Issue()) - return notaryServices.signInitialTransaction(txBuilder) - } - - private fun addCommodityStates(statesToAdd: Int, owner: AbstractParty) { - cordaDB.transaction { - (1..statesToAdd).map { - createCommodityTransaction(Amount(it.toLong(), Issued(bankOfCorda.ref(2), Commodity.getInstance("FCOJ")!!)), owner) - }.forEach { - storeTransaction(it) - createVaultStatesFromTransaction(it) - } - } - } - - private fun createNotaryChangeTransaction(inputs: List, paramsHash: SecureHash): SignedTransaction { - val notaryTx = NotaryChangeTransactionBuilder(inputs, DUMMY_NOTARY, CHARLIE, paramsHash).build() - val notaryKey = DUMMY_NOTARY.owningKey - val signableData = SignableData(notaryTx.id, SignatureMetadata(3, Crypto.findSignatureScheme(notaryKey).schemeNumberID)) - val notarySignature = notaryServices.keyManagementService.sign(signableData, notaryKey) - return SignedTransaction(notaryTx, listOf(notarySignature)) - } - - private fun createVaultStatesFromNotaryChangeTransaction(tx: SignedTransaction, inputs: List>) { - cordaDB.transaction { - inputs.forEachIndexed { index, state -> - val constraintInfo = Vault.ConstraintInfo(state.constraint) - val persistentState = VaultSchemaV1.VaultStates( - notary = tx.notary!!, - contractStateClassName = state.data.javaClass.name, - stateStatus = Vault.StateStatus.UNCONSUMED, - recordedTime = clock.instant(), - relevancyStatus = Vault.RelevancyStatus.RELEVANT, //Always persist as relevant to mimic V3 - constraintType = constraintInfo.type(), - constraintData = constraintInfo.data() - ) - persistentState.stateRef = PersistentStateRef(tx.id.toString(), index) - session.save(persistentState) - } - } - } - - private fun getState(clazz: Class): T { - return cordaDB.transaction { - val criteriaBuilder = cordaDB.entityManagerFactory.criteriaBuilder - val criteriaQuery = criteriaBuilder.createQuery(clazz) - val queryRootStates = criteriaQuery.from(clazz) - criteriaQuery.select(queryRootStates) - val query = session.createQuery(criteriaQuery) - query.singleResult - } - } - - private fun checkStatesEqual(expected: VaultSchemaV1.VaultStates, actual: VaultSchemaV1.VaultStates) { - assertEquals(expected.notary, actual.notary) - assertEquals(expected.stateStatus, actual.stateStatus) - assertEquals(expected.relevancyStatus, actual.relevancyStatus) - } - - private fun addToStatePartyTable(stateAndRef: StateAndRef) { - cordaDB.transaction { - val persistentStateRef = PersistentStateRef(stateAndRef.ref.txhash.toString(), stateAndRef.ref.index) - val session = currentDBSession() - stateAndRef.state.data.participants.forEach { - val persistentParty = VaultSchemaV1.PersistentParty( - persistentStateRef, - it - ) - session.save(persistentParty) - } - } - } - - @Test(timeout=300_000) - fun `Check a simple migration works`() { - addCashStates(10, BOB) - addCashStates(10, ALICE) - assertEquals(20, getVaultStateCount()) - assertEquals(0, getStatePartyCount()) - val migration = VaultStateMigration() - migration.execute(liquibaseDB) - assertEquals(20, getVaultStateCount()) - assertEquals(20, getStatePartyCount()) - assertEquals(10, getVaultStateCount(Vault.RelevancyStatus.RELEVANT)) - } - - @Test(timeout=300_000) - fun `Check state paging works`() { - addCashStates(1010, BOB) - - assertEquals(0, getStatePartyCount()) - val migration = VaultStateMigration() - migration.execute(liquibaseDB) - assertEquals(1010, getStatePartyCount()) - assertEquals(1010, getVaultStateCount()) - assertEquals(0, getVaultStateCount(Vault.RelevancyStatus.NOT_RELEVANT)) - } - - @Test(timeout=300_000) - fun `Check state fields are correct`() { - val tx = createCashTransaction(Cash(), 100.DOLLARS, ALICE) - storeTransaction(tx) - createVaultStatesFromTransaction(tx) - val expectedPersistentParty = VaultSchemaV1.PersistentParty( - PersistentStateRef(tx.id.toString(), 0), - ALICE - ) - val state = tx.coreTransaction.outputs.first() - val constraintInfo = Vault.ConstraintInfo(state.constraint) - val expectedPersistentState = VaultSchemaV1.VaultStates( - notary = state.notary, - contractStateClassName = state.data.javaClass.name, - stateStatus = Vault.StateStatus.UNCONSUMED, - recordedTime = clock.instant(), - relevancyStatus = Vault.RelevancyStatus.NOT_RELEVANT, - constraintType = constraintInfo.type(), - constraintData = constraintInfo.data() - ) - - val migration = VaultStateMigration() - migration.execute(liquibaseDB) - val persistentStateParty = getState(VaultSchemaV1.PersistentParty::class.java) - val persistentState = getState(VaultSchemaV1.VaultStates::class.java) - checkStatesEqual(expectedPersistentState, persistentState) - assertEquals(expectedPersistentParty.x500Name, persistentStateParty.x500Name) - assertEquals(expectedPersistentParty.compositeKey, persistentStateParty.compositeKey) - } - - @Test(timeout=300_000) - fun `Check the connection is open post migration`() { - // Liquibase automatically closes the database connection when doing an actual migration. This test ensures the custom migration - // leaves it open. - addCashStates(12, ALICE) - - val migration = VaultStateMigration() - migration.execute(liquibaseDB) - assertFalse(cordaDB.dataSource.connection.isClosed) - } - - @Test(timeout=300_000) - fun `All parties added to state party table`() { - val stx = createLinearStateTransaction("test", parties = listOf(ALICE, BOB, CHARLIE)) - storeTransaction(stx) - createVaultStatesFromTransaction(stx) - - val migration = VaultStateMigration() - migration.execute(liquibaseDB) - assertEquals(3, getStatePartyCount()) - assertEquals(1, getVaultStateCount()) - assertEquals(0, getVaultStateCount(Vault.RelevancyStatus.NOT_RELEVANT)) - } - - @Test(timeout=300_000) - fun `State with corresponding transaction missing fails migration`() { - val cash = Cash() - val unknownTx = createCashTransaction(cash, 100.DOLLARS, BOB) - createVaultStatesFromTransaction(unknownTx) - - addCashStates(10, BOB) - val migration = VaultStateMigration() - assertFailsWith { migration.execute(liquibaseDB) } - assertEquals(10, getStatePartyCount()) - - // Now add the missing transaction and ensure that the migration succeeds - storeTransaction(unknownTx) - migration.execute(liquibaseDB) - assertEquals(11, getStatePartyCount()) - } - - @Test(timeout=300_000) - fun `State with unknown ID is handled correctly`() { - addCashStates(1, CHARLIE) - addCashStates(10, BOB) - val migration = VaultStateMigration() - migration.execute(liquibaseDB) - assertEquals(11, getStatePartyCount()) - assertEquals(1, getVaultStateCount(Vault.RelevancyStatus.NOT_RELEVANT)) - assertEquals(10, getVaultStateCount(Vault.RelevancyStatus.RELEVANT)) - } - - @Test(expected = VaultStateMigrationException::class) - fun `Null database causes migration to fail`() { - val migration = VaultStateMigration() - // Just check this does not throw an exception - migration.execute(null) - } - - @Test(timeout=300_000) - fun `State with non-owning key for our name marked as relevant`() { - val tx = createCashTransaction(Cash(), 100.DOLLARS, BOB2) - storeTransaction(tx) - createVaultStatesFromTransaction(tx) - val state = tx.coreTransaction.outputs.first() - val constraintInfo = Vault.ConstraintInfo(state.constraint) - val expectedPersistentState = VaultSchemaV1.VaultStates( - notary = state.notary, - contractStateClassName = state.data.javaClass.name, - stateStatus = Vault.StateStatus.UNCONSUMED, - recordedTime = clock.instant(), - relevancyStatus = Vault.RelevancyStatus.RELEVANT, - constraintType = constraintInfo.type(), - constraintData = constraintInfo.data() - ) - val migration = VaultStateMigration() - migration.execute(liquibaseDB) - val persistentState = getState(VaultSchemaV1.VaultStates::class.java) - checkStatesEqual(expectedPersistentState, persistentState) - } - - @Test(timeout=300_000) - fun `State already in state party table is excluded`() { - val tx = createCashTransaction(Cash(), 100.DOLLARS, BOB) - storeTransaction(tx) - createVaultStatesFromTransaction(tx) - addToStatePartyTable(tx.coreTransaction.outRef(0)) - addCashStates(5, BOB) - assertEquals(1, getStatePartyCount()) - val migration = VaultStateMigration() - migration.execute(liquibaseDB) - assertEquals(6, getStatePartyCount()) - } - - @Test(timeout=300_000) - fun `Consumed states are not migrated`() { - addCashStates(1010, BOB, Vault.StateStatus.CONSUMED) - assertEquals(0, getStatePartyCount()) - val migration = VaultStateMigration() - migration.execute(liquibaseDB) - assertEquals(0, getStatePartyCount()) - } - - @Test(timeout=300_000) - fun `State created with notary change transaction can be migrated`() { - // This test is a little bit of a hack - it checks that these states are migrated correctly by looking at params in the database, - // but these will not be there for V3 nodes. Handling for this must be tested manually. - val cashTx = createCashTransaction(Cash(), 5.DOLLARS, BOB) - val cashTx2 = createCashTransaction(Cash(), 10.DOLLARS, BOB) - val notaryTx = createNotaryChangeTransaction(listOf(StateRef(cashTx.id, 0), StateRef(cashTx2.id, 0)), SecureHash.allOnesHash) - createVaultStatesFromTransaction(cashTx, stateStatus = Vault.StateStatus.CONSUMED) - createVaultStatesFromTransaction(cashTx2, stateStatus = Vault.StateStatus.CONSUMED) - createVaultStatesFromNotaryChangeTransaction(notaryTx, cashTx.coreTransaction.outputs + cashTx2.coreTransaction.outputs) - storeTransaction(cashTx) - storeTransaction(cashTx2) - storeTransaction(notaryTx) - val migration = VaultStateMigration() - migration.execute(liquibaseDB) - assertEquals(2, getStatePartyCount()) - } - - // Used to test migration performance - @Test(timeout=300_000) -@Ignore - fun `Migrate large database`() { - val statesAtOnce = 500L - val stateMultiplier = 300L - logger.info("Start adding states to vault") - (1..stateMultiplier).forEach { - addCashStates(statesAtOnce.toInt(), BOB) - } - logger.info("Finish adding states to vault") - val migration = VaultStateMigration() - migration.execute(liquibaseDB) - assertEquals((statesAtOnce * stateMultiplier), getStatePartyCount()) - } - - private fun makePersistentDataSourceProperties(): Properties { - val props = Properties() - props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource") - props.setProperty("dataSource.url", "jdbc:h2:~/test/persistence;DB_CLOSE_ON_EXIT=TRUE") - props.setProperty("dataSource.user", "sa") - props.setProperty("dataSource.password", "") - return props - } - - // Used to generate a persistent database for further testing. - @Test(timeout=300_000) -@Ignore - fun `Create persistent DB`() { - val cashStatesToAdd = 1000 - val linearStatesToAdd = 0 - val commodityStatesToAdd = 0 - val stateMultiplier = 10 - - cordaDB = configureDatabase(makePersistentDataSourceProperties(), DatabaseConfig(), notaryServices.identityService::wellKnownPartyFromX500Name, notaryServices.identityService::wellKnownPartyFromAnonymous) - - // Starting the database this way runs the migration under test. This is fine for the unit tests (as the changelog table is ignored), - // but when starting an actual node using these databases the migration will be skipped, as it has an entry in the changelog table. - // This must therefore be removed. - cordaDB.dataSource.connection.createStatement().use { - it.execute("DELETE FROM DATABASECHANGELOG WHERE FILENAME IN ('migration/vault-schema.changelog-v9.xml')") - } - - for (i in 1..stateMultiplier) { - addCashStates(cashStatesToAdd, BOB) - addLinearStates(linearStatesToAdd, listOf(BOB, ALICE)) - addCommodityStates(commodityStatesToAdd, BOB) - } - saveOurKeys(listOf(bob.keyPair)) - saveAllIdentities(listOf(BOB_IDENTITY, ALICE_IDENTITY, BOC_IDENTITY, dummyNotary.identity)) - cordaDB.close() - } - - @Test(timeout=300_000) -@Ignore - fun `Run on persistent DB`() { - cordaDB = configureDatabase(makePersistentDataSourceProperties(), DatabaseConfig(), notaryServices.identityService::wellKnownPartyFromX500Name, notaryServices.identityService::wellKnownPartyFromAnonymous) - val connection = (liquibaseDB.connection as JdbcConnection) - Mockito.`when`(connection.url).thenReturn(cordaDB.jdbcUrl) - Mockito.`when`(connection.wrappedConnection).thenReturn(cordaDB.dataSource.connection) - val migration = VaultStateMigration() - migration.execute(liquibaseDB) - cordaDB.close() - } -} - diff --git a/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt b/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt index 44b44bcf40..2da031f5b2 100644 --- a/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt @@ -9,6 +9,7 @@ import net.corda.core.flows.NotaryFlow import net.corda.core.flows.StateReplacementException import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party +import net.corda.core.internal.getRequiredTransaction import net.corda.core.node.ServiceHub import net.corda.core.node.StatesToRecord import net.corda.core.transactions.TransactionBuilder @@ -116,7 +117,7 @@ class NotaryChangeTests { val newState = future.getOrThrow() assertEquals(newState.state.notary, newNotary) - val recordedTx = clientNodeA.services.validatedTransactions.getTransaction(newState.ref.txhash)!! + val recordedTx = clientNodeA.services.getRequiredTransaction(newState.ref.txhash) val notaryChangeTx = recordedTx.resolveNotaryChangeTransaction(clientNodeA.services) // Check that all encumbrances have been propagated to the outputs @@ -140,7 +141,7 @@ class NotaryChangeTests { // We don't to tx resolution when moving state to another node, so need to add the issue transaction manually // to node B. The resolution process is tested later during notarisation. - clientNodeB.services.recordTransactions(clientNodeA.services.validatedTransactions.getTransaction(issued.ref.txhash)!!) + clientNodeB.services.recordTransactions(clientNodeA.services.getRequiredTransaction(issued.ref.txhash)) val changedNotary = changeNotary(moved, clientNodeB, newNotaryParty) val movedBack = moveState(changedNotary, clientNodeB, clientNodeA) diff --git a/node/src/test/kotlin/net/corda/node/services/TimedFlowTests.kt b/node/src/test/kotlin/net/corda/node/services/TimedFlowTests.kt index df1fa5aa64..844d8db005 100644 --- a/node/src/test/kotlin/net/corda/node/services/TimedFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/TimedFlowTests.kt @@ -1,9 +1,9 @@ package net.corda.node.services import co.paralleluniverse.fibers.Suspendable -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import net.corda.core.concurrent.CordaFuture import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint import net.corda.core.contracts.StateRef diff --git a/node/src/test/kotlin/net/corda/node/services/attachments/AttachmentTrustCalculatorTest.kt b/node/src/test/kotlin/net/corda/node/services/attachments/AttachmentTrustCalculatorTest.kt index 315e401f2c..6febdb3311 100644 --- a/node/src/test/kotlin/net/corda/node/services/attachments/AttachmentTrustCalculatorTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/attachments/AttachmentTrustCalculatorTest.kt @@ -1,12 +1,13 @@ package net.corda.node.services.attachments import com.codahale.metrics.MetricRegistry -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.crypto.SecureHash -import net.corda.core.crypto.sha256 -import net.corda.core.internal.* -import net.corda.core.node.ServicesForResolution +import net.corda.core.internal.AttachmentTrustCalculator +import net.corda.core.internal.AttachmentTrustInfo +import net.corda.core.internal.hash +import net.corda.core.internal.read +import net.corda.core.internal.verification.NodeVerificationSupport +import net.corda.coretesting.internal.rigorousMock import net.corda.node.services.persistence.NodeAttachmentService import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.DatabaseConfig @@ -17,7 +18,6 @@ import net.corda.testing.core.internal.JarSignatureTestUtils.signJar import net.corda.testing.core.internal.SelfCleaningDir import net.corda.testing.internal.TestingNamedCacheFactory import net.corda.testing.internal.configureDatabase -import net.corda.coretesting.internal.rigorousMock import net.corda.testing.node.MockServices import org.assertj.core.api.Assertions.assertThat import org.junit.After @@ -25,9 +25,14 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths +import kotlin.io.path.deleteExisting +import kotlin.io.path.div +import kotlin.io.path.outputStream import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertNotEquals @@ -42,7 +47,7 @@ class AttachmentTrustCalculatorTest { private lateinit var database: CordaPersistence private lateinit var storage: NodeAttachmentService private lateinit var attachmentTrustCalculator: AttachmentTrustCalculator - private val services = rigorousMock().also { + private val nodeVerificationSupport = rigorousMock().also { doReturn(testNetworkParameters()).whenever(it).networkParameters } private val cacheFactory = TestingNamedCacheFactory() @@ -56,7 +61,7 @@ class AttachmentTrustCalculatorTest { it.start() } } - storage.servicesForResolution = services + storage.nodeVerificationSupport = nodeVerificationSupport attachmentTrustCalculator = NodeAttachmentTrustCalculator(storage, database, cacheFactory) } @@ -271,8 +276,8 @@ class AttachmentTrustCalculatorTest { val jarV1 = ContractJarTestUtils.makeTestContractJar(path, "foo.bar.DummyContract") path.generateKey(alias, password) val key1 = path.signJar(jarV1.toAbsolutePath().toString(), alias, password) - (path / "_shredder").delete() - (path / "_teststore").delete() + (path / "_shredder").deleteExisting() + (path / "_teststore").deleteExisting() path.generateKey(alias, password) val jarV2 = ContractJarTestUtils.makeTestContractJar( path, @@ -624,6 +629,6 @@ class AttachmentTrustCalculatorTest { counter++ val file = Paths.get((tempFolder.root.toPath() / "$counter.jar").toString()) ContractJarTestUtils.makeTestJar(Files.newOutputStream(file), entries) - return Pair(file, file.readAll().sha256()) + return Pair(file, file.hash) } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/services/config/ConfigHelperTests.kt b/node/src/test/kotlin/net/corda/node/services/config/ConfigHelperTests.kt index eacbdf82c3..11d77da6aa 100644 --- a/node/src/test/kotlin/net/corda/node/services/config/ConfigHelperTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/config/ConfigHelperTests.kt @@ -1,23 +1,20 @@ package net.corda.node.services.config -import com.nhaarman.mockito_kotlin.spy -import com.nhaarman.mockito_kotlin.verify import com.typesafe.config.Config import com.typesafe.config.ConfigFactory -import net.corda.core.internal.delete -import net.corda.core.internal.div -import net.corda.node.internal.Node +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After import org.junit.Assert import org.junit.Before import org.junit.Test -import org.mockito.ArgumentMatchers.contains -import org.slf4j.Logger -import java.lang.reflect.Field -import java.lang.reflect.Modifier +import java.io.ByteArrayOutputStream +import java.io.PrintStream import java.nio.file.Files import java.nio.file.Path +import kotlin.io.path.deleteExisting +import kotlin.io.path.div import kotlin.test.assertFalse +import kotlin.test.assertTrue class ConfigHelperTests { private var baseDir: Path? = null @@ -29,7 +26,7 @@ class ConfigHelperTests { @After fun cleanup() { - baseDir?.delete() + baseDir?.deleteExisting() } @Test(timeout = 300_000) @@ -59,30 +56,28 @@ class ConfigHelperTests { Assert.assertEquals(sshPort, config?.getLong("sshd.port")) } - @Test(timeout = 300_000, expected = ShadowingException::class) + @Test(timeout = 300_000) fun `shadowing is forbidden`() { val sshPort: Long = 12000 - loadConfig("CORDA_sshd_port" to sshPort.toString(), - "corda.sshd.port" to sshPort.toString()) + assertThatExceptionOfType(ShadowingException::class.java).isThrownBy { + loadConfig("CORDA_sshd_port" to sshPort.toString(), + "corda.sshd.port" to sshPort.toString()) + } } + @Test(timeout = 300_000) fun `bad keys are ignored and warned for`() { - val loggerField = Node::class.java.getDeclaredField("staticLog") - loggerField.isAccessible = true - val modifiersField = Field::class.java.getDeclaredField("modifiers") - modifiersField.isAccessible = true - modifiersField.setInt(loggerField, loggerField.modifiers and Modifier.FINAL.inv()) - val originalLogger = loggerField.get(null) as Logger - val spyLogger = spy(originalLogger) - loggerField.set(null, spyLogger) - - val config = loadConfig("corda_bad_key" to "2077") - - verify(spyLogger).warn(contains("(property or environment variable) cannot be mapped to an existing Corda")) - assertFalse(config?.hasPath("corda_bad_key") ?: true) - - loggerField.set(null, originalLogger) + val originalOut = System.out + try { + val outContent = ByteArrayOutputStream() + System.setOut(PrintStream(outContent)); + val config = loadConfig("corda_bad_key" to "2077") + assertTrue(outContent.toString().contains("(property or environment variable) cannot be mapped to an existing Corda")) + assertFalse(config?.hasPath("corda_bad_key") ?: true) + } finally { + System.setOut(originalOut); + } } /** diff --git a/node/src/test/kotlin/net/corda/node/services/config/NodeConfigurationImplTest.kt b/node/src/test/kotlin/net/corda/node/services/config/NodeConfigurationImplTest.kt index 62134b7703..9148c1d784 100644 --- a/node/src/test/kotlin/net/corda/node/services/config/NodeConfigurationImplTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/config/NodeConfigurationImplTest.kt @@ -1,12 +1,10 @@ package net.corda.node.services.config -import com.nhaarman.mockito_kotlin.mock import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigParseOptions import com.typesafe.config.ConfigValueFactory import net.corda.common.configuration.parsing.internal.Configuration -import net.corda.core.internal.div import net.corda.core.internal.toPath import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.seconds @@ -21,11 +19,13 @@ import org.junit.Assert.assertNotNull import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import org.mockito.kotlin.mock import java.io.File import java.net.URI import java.net.URL import java.nio.file.Paths import javax.security.auth.x500.X500Principal +import kotlin.io.path.div import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -116,7 +116,7 @@ class NodeConfigurationImplTest { } private fun getConfig(cfgName: String, overrides: Config = ConfigFactory.empty()): Config { - val path = this::class.java.classLoader.getResource(cfgName).toPath() + val path = this::class.java.classLoader.getResource(cfgName)!!.toPath() return ConfigHelper.loadConfig( baseDirectory = path.parent, configFile = path, @@ -226,36 +226,34 @@ class NodeConfigurationImplTest { @Test(timeout=6_000) fun `relative base dir leads to correct cordapp directories`() { - val path = tempFolder.root.relativeTo(tempFolder.root.parentFile).toString() - val fullPath = File(".").resolve(path).toString() + val path = tempFolder.root.relativeTo(tempFolder.root.parentFile).toPath() // Override base directory to have predictable experience on diff OSes val finalConfig = configOf( // Add substitution values here - "baseDirectory" to fullPath) + "baseDirectory" to path.toString()) .withFallback(rawConfig) .resolve() val nodeConfiguration = finalConfig.parseAsNodeConfiguration() assertTrue(nodeConfiguration.isValid) - assertEquals(listOf(fullPath / "./myCorDapps1", fullPath / "./myCorDapps2"), nodeConfiguration.value().cordappDirectories) + assertEquals(listOf(path / "./myCorDapps1", path / "./myCorDapps2"), nodeConfiguration.value().cordappDirectories) } @Test(timeout=6_000) fun `relative base dir leads to correct default cordapp directory`() { - val path = tempFolder.root.relativeTo(tempFolder.root.parentFile).toString() - val fullPath = File(".").resolve(path).toString() + val path = tempFolder.root.relativeTo(tempFolder.root.parentFile).toPath() // Override base directory to have predictable experience on diff OSes val finalConfig = configOf( // Add substitution values here - "baseDirectory" to fullPath) + "baseDirectory" to path.toString()) .withFallback(rawConfigNoCordapps) .resolve() val nodeConfiguration = finalConfig.parseAsNodeConfiguration() assertTrue(nodeConfiguration.isValid) - assertEquals(listOf(fullPath / "cordapps"), nodeConfiguration.value().cordappDirectories) + assertEquals(listOf(path / "cordapps"), nodeConfiguration.value().cordappDirectories) } @Test(timeout=6_000) diff --git a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt index 08f17a2b32..bc0f8f011a 100644 --- a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt @@ -1,6 +1,6 @@ package net.corda.node.services.events -import com.nhaarman.mockito_kotlin.* +import org.mockito.kotlin.* import net.corda.core.contracts.* import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash @@ -256,6 +256,7 @@ class NodeSchedulerServiceTest : NodeSchedulerServiceTestBase() { } } +@Ignore("TODO JDK17: Flaky test") class NodeSchedulerPersistenceTest : NodeSchedulerServiceTestBase() { private val databaseConfig: DatabaseConfig = DatabaseConfig() diff --git a/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt index 445da1b8a4..3d66a60e17 100644 --- a/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt @@ -396,4 +396,4 @@ class PersistentIdentityServiceTests { newIdentityService.verifyAndRegisterIdentity(charlie3) } } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/services/network/DBNetworkParametersStorageTest.kt b/node/src/test/kotlin/net/corda/node/services/network/DBNetworkParametersStorageTest.kt index fe1aeb868a..7c796857a8 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/DBNetworkParametersStorageTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/DBNetworkParametersStorageTest.kt @@ -1,9 +1,9 @@ package net.corda.node.services.network -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.times -import com.nhaarman.mockito_kotlin.verify +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import net.corda.core.crypto.SecureHash import net.corda.core.internal.SignedDataWithCert import net.corda.core.node.NetworkParameters diff --git a/node/src/test/kotlin/net/corda/node/services/network/NetworkMapCacheTest.kt b/node/src/test/kotlin/net/corda/node/services/network/NetworkMapCacheTest.kt index 5c87059305..2e19cb29a1 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/NetworkMapCacheTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/NetworkMapCacheTest.kt @@ -15,7 +15,6 @@ import net.corda.testing.node.internal.TestStartedNode import org.assertj.core.api.Assertions.assertThat import org.junit.After import org.junit.Assert -import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test import java.math.BigInteger diff --git a/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt b/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt index 8f5c794e1c..5e1062c39b 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt @@ -2,12 +2,6 @@ package net.corda.node.services.network import com.google.common.jimfs.Configuration.unix import com.google.common.jimfs.Jimfs -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.atLeast -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.never -import com.nhaarman.mockito_kotlin.times -import com.nhaarman.mockito_kotlin.verify import net.corda.core.crypto.Crypto import net.corda.core.crypto.SecureHash import net.corda.core.crypto.generateKeyPair @@ -19,10 +13,6 @@ import net.corda.core.internal.NODE_INFO_DIRECTORY import net.corda.core.internal.NetworkParametersStorage import net.corda.core.internal.bufferUntilSubscribed import net.corda.core.internal.concurrent.openFuture -import net.corda.core.internal.createDirectory -import net.corda.core.internal.delete -import net.corda.core.internal.div -import net.corda.core.internal.exists import net.corda.core.internal.readObject import net.corda.core.internal.sign import net.corda.core.messaging.ParametersUpdateInfo @@ -58,10 +48,15 @@ import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy import org.hamcrest.collection.IsIterableContainingInAnyOrder import org.junit.After -import org.junit.Assert import org.junit.Before import org.junit.Rule import org.junit.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.atLeast +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import rx.schedulers.TestScheduler import java.io.IOException import java.net.URL @@ -70,12 +65,18 @@ import java.nio.file.Path import java.security.KeyPair import java.time.Instant import java.time.temporal.ChronoUnit -import java.util.* +import java.util.UUID import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.TimeUnit +import kotlin.io.path.createDirectory +import kotlin.io.path.deleteExisting +import kotlin.io.path.div +import kotlin.io.path.exists import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue +import org.hamcrest.MatcherAssert.assertThat + class NetworkMapUpdaterTest { @Rule @@ -161,7 +162,7 @@ class NetworkMapUpdaterTest { //TODO: Remove sleep in unit test. Thread.sleep(2L * cacheExpiryMs) - Assert.assertThat(networkMapCache.allNodeHashes, IsIterableContainingInAnyOrder.containsInAnyOrder(signedNodeInfo1.raw.hash, signedNodeInfo2.raw.hash)) + assertThat(networkMapCache.allNodeHashes, IsIterableContainingInAnyOrder.containsInAnyOrder(signedNodeInfo1.raw.hash, signedNodeInfo2.raw.hash)) assertThat(nodeReadyFuture).isDone() @@ -173,7 +174,7 @@ class NetworkMapUpdaterTest { Thread.sleep(2L * cacheExpiryMs) //4 node info from network map, and 1 from file. - Assert.assertThat(networkMapCache.allNodeHashes, IsIterableContainingInAnyOrder.containsInAnyOrder( + assertThat(networkMapCache.allNodeHashes, IsIterableContainingInAnyOrder.containsInAnyOrder( signedNodeInfo1.raw.hash, signedNodeInfo2.raw.hash, signedNodeInfo3.raw.hash, @@ -204,7 +205,7 @@ class NetworkMapUpdaterTest { Thread.sleep(2L * cacheExpiryMs) - Assert.assertThat(networkMapCache.allNodeHashes, IsIterableContainingInAnyOrder.containsInAnyOrder( + assertThat(networkMapCache.allNodeHashes, IsIterableContainingInAnyOrder.containsInAnyOrder( signedNodeInfo1.raw.hash, signedNodeInfo2.raw.hash, signedNodeInfo3.raw.hash, @@ -248,7 +249,7 @@ class NetworkMapUpdaterTest { //TODO: Remove sleep in unit test. Thread.sleep(2L * cacheExpiryMs) - Assert.assertThat(networkMapCache.allNodeHashes, IsIterableContainingInAnyOrder.containsInAnyOrder( + assertThat(networkMapCache.allNodeHashes, IsIterableContainingInAnyOrder.containsInAnyOrder( signedNodeInfo1.raw.hash, signedNodeInfo2.raw.hash )) @@ -300,7 +301,7 @@ class NetworkMapUpdaterTest { // Not subscribed yet verify(networkMapCache, times(0)).addOrUpdateNode(any()) - nodeInfoDir.delete() + nodeInfoDir.deleteExisting() assertFalse(nodeInfoDir.exists()) // Observable will get a NoSuchFileException and log it @@ -516,7 +517,7 @@ class NetworkMapUpdaterTest { assertThat(networkMapCache.allNodeHashes).containsExactlyInAnyOrder(fileNodeInfoAndSigned1.signed.raw.hash, fileNodeInfoAndSigned2.signed.raw.hash) //Remove one of the nodes val fileName1 = "${NodeInfoFilesCopier.NODE_INFO_FILE_NAME_PREFIX}${fileNodeInfoAndSigned1.nodeInfo.legalIdentities[0].name.serialize().hash}" - (nodeInfoDir / fileName1).delete() + (nodeInfoDir / fileName1).deleteExisting() advanceTime() verify(networkMapCache, times(1)).removeNode(any()) verify(networkMapCache, times(1)).removeNode(fileNodeInfoAndSigned1.nodeInfo) @@ -545,7 +546,7 @@ class NetworkMapUpdaterTest { //Node from file has higher serial than the one from NetworkMapServer assertThat(networkMapCache.allNodeHashes).containsOnly(localSignedNodeInfo.signed.raw.hash) val fileName = "${NodeInfoFilesCopier.NODE_INFO_FILE_NAME_PREFIX}${localNodeInfo.legalIdentities[0].name.serialize().hash}" - (nodeInfoDir / fileName).delete() + (nodeInfoDir / fileName).deleteExisting() advanceTime() verify(networkMapCache, times(1)).removeNode(any()) verify(networkMapCache).removeNode(localNodeInfo) diff --git a/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersHotloaderTest.kt b/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersHotloaderTest.kt index 66ab2428d9..06d936f13d 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersHotloaderTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersHotloaderTest.kt @@ -1,8 +1,8 @@ package net.corda.node.services.network -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.never -import com.nhaarman.mockito_kotlin.verify +import org.mockito.kotlin.any +import org.mockito.kotlin.never +import org.mockito.kotlin.verify import net.corda.core.identity.Party import net.corda.core.internal.NetworkParametersStorage import net.corda.core.node.NetworkParameters diff --git a/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersReaderTest.kt b/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersReaderTest.kt index 792eb7ebb5..6f3d3458f4 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersReaderTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersReaderTest.kt @@ -2,23 +2,27 @@ package net.corda.node.services.network import com.google.common.jimfs.Configuration import com.google.common.jimfs.Jimfs -import net.corda.core.identity.CordaX500Name import net.corda.core.crypto.Crypto -import net.corda.core.internal.* +import net.corda.core.identity.CordaX500Name +import net.corda.core.internal.readObject import net.corda.core.serialization.deserialize import net.corda.core.utilities.days import net.corda.core.utilities.seconds import net.corda.coretesting.internal.DEV_INTERMEDIATE_CA +import net.corda.coretesting.internal.DEV_ROOT_CA import net.corda.node.VersionInfo import net.corda.node.internal.NetworkParametersReader -import net.corda.nodeapi.internal.network.* -import net.corda.testing.common.internal.testNetworkParameters -import net.corda.testing.core.SerializationEnvironmentRule -import net.corda.coretesting.internal.DEV_ROOT_CA import net.corda.nodeapi.internal.createDevNetworkMapCa import net.corda.nodeapi.internal.createDevNetworkParametersCa import net.corda.nodeapi.internal.createDevNodeCa import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair +import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME +import net.corda.nodeapi.internal.network.NETWORK_PARAMS_UPDATE_FILE_NAME +import net.corda.nodeapi.internal.network.NetworkParametersCopier +import net.corda.nodeapi.internal.network.SignedNetworkParameters +import net.corda.nodeapi.internal.network.verifiedNetworkParametersCert +import net.corda.testing.common.internal.testNetworkParameters +import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.TestIdentity import net.corda.testing.node.internal.network.NetworkMapServer import org.assertj.core.api.Assertions.assertThat @@ -28,6 +32,9 @@ import org.junit.Rule import org.junit.Test import java.net.URL import java.nio.file.FileSystem +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.exists import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertFalse diff --git a/node/src/test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt b/node/src/test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt index 0668bfb431..7ab5746e11 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt @@ -4,13 +4,10 @@ import com.google.common.jimfs.Configuration import com.google.common.jimfs.Jimfs import net.corda.core.crypto.Crypto import net.corda.core.internal.NODE_INFO_DIRECTORY -import net.corda.core.internal.createDirectories -import net.corda.core.internal.div -import net.corda.core.internal.size import net.corda.core.node.services.KeyManagementService import net.corda.coretesting.internal.createNodeInfoAndSigned import net.corda.nodeapi.internal.NodeInfoAndSigned -import net.corda.nodeapi.internal.network.NodeInfoFilesCopier +import net.corda.nodeapi.internal.network.NodeInfoFilesCopier.Companion.NODE_INFO_FILE_NAME_PREFIX import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.node.internal.MockKeyManagementService @@ -26,8 +23,12 @@ import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths import java.util.concurrent.TimeUnit +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.fileSize +import kotlin.io.path.name +import kotlin.io.path.useDirectoryEntries import kotlin.test.assertEquals -import kotlin.test.assertTrue class NodeInfoWatcherTest { @Rule @@ -63,17 +64,20 @@ class NodeInfoWatcherTest { @Test(timeout=300_000) fun `save a NodeInfo`() { - assertEquals(0, - tempFolder.root.list().filter { it.startsWith(NodeInfoFilesCopier.NODE_INFO_FILE_NAME_PREFIX) }.size) + assertThat(nodeInfoFiles()).isEmpty() + NodeInfoWatcher.saveToFile(tempFolder.root.toPath(), nodeInfoAndSigned) - val nodeInfoFiles = tempFolder.root.list().filter { it.startsWith(NodeInfoFilesCopier.NODE_INFO_FILE_NAME_PREFIX) } - assertEquals(1, nodeInfoFiles.size) - val fileName = nodeInfoFiles.first() - assertTrue(fileName.startsWith(NodeInfoFilesCopier.NODE_INFO_FILE_NAME_PREFIX)) - val file = (tempFolder.root.path / fileName) + val nodeInfoFiles = nodeInfoFiles() + assertThat(nodeInfoFiles).hasSize(1) // Just check that something is written, another tests verifies that the written value can be read back. - assertThat(file.size).isGreaterThan(0) + assertThat(nodeInfoFiles[0].fileSize()).isGreaterThan(0) + } + + private fun nodeInfoFiles(): List { + return tempFolder.root.toPath().useDirectoryEntries { paths -> + paths.filter { it.name.startsWith(NODE_INFO_FILE_NAME_PREFIX) }.toList() + } } @Test(timeout=300_000) diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt index 3141d97972..a0ea98fd67 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt @@ -45,7 +45,6 @@ import org.junit.Rule import org.junit.Test import java.time.Clock import java.util.* -import kotlin.streams.toList import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -455,7 +454,7 @@ class DBCheckpointStorageTests { val deserializedException = exceptionDetails.value?.let { SerializedBytes(it) }?.deserialize(context = SerializationDefaults.STORAGE_CONTEXT) // IllegalStateException does not implement [CordaThrowable] therefore gets deserialized as a [CordaRuntimeException] assertTrue(deserializedException is CordaRuntimeException) - val cordaRuntimeException = deserializedException as CordaRuntimeException + val cordaRuntimeException = deserializedException assertEquals(IllegalStateException::class.java.name, cordaRuntimeException.originalExceptionClassName) assertEquals("I am a naughty exception", cordaRuntimeException.originalMessage!!) } diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageLedgerRecoveryTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageLedgerRecoveryTests.kt index 0df955e0f1..3eeb502392 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageLedgerRecoveryTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageLedgerRecoveryTests.kt @@ -173,10 +173,11 @@ class DBTransactionStorageLedgerRecoveryTests { @Test(timeout = 300_000) fun `test lightweight serialization and deserialization of hashed distribution list payload`() { + val hashedDistList = HashedDistributionList( ALL_VISIBLE, mapOf(SecureHash.sha256(BOB.name.toString()) to NONE, SecureHash.sha256(CHARLIE_NAME.toString()) to ONLY_RELEVANT), - HashedDistributionList.PublicHeader(now(), 1) + HashedDistributionList.PublicHeader(Instant.ofEpochMilli(now().toEpochMilli()), 1) ) val roundtrip = HashedDistributionList.decrypt(hashedDistList.encrypt(encryptionService), encryptionService) assertThat(roundtrip).isEqualTo(hashedDistList) diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt index 30cdbe7f59..f1c45cf30d 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt @@ -1,6 +1,5 @@ package net.corda.node.services.persistence -import com.nhaarman.mockito_kotlin.* import net.corda.core.contracts.Amount import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.StateRef @@ -10,6 +9,7 @@ import net.corda.core.crypto.generateKeyPair import net.corda.core.identity.AbstractParty import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party +import net.corda.core.internal.verification.toVerifyingServiceHub import net.corda.core.node.StatesToRecord import net.corda.core.node.services.IdentityService import net.corda.core.node.services.Vault @@ -28,7 +28,6 @@ import net.corda.finance.schemas.CashSchemaV1 import net.corda.finance.test.SampleCashSchemaV1 import net.corda.finance.test.SampleCashSchemaV2 import net.corda.finance.test.SampleCashSchemaV3 -import net.corda.node.internal.NodeServicesForResolution import net.corda.node.services.api.WritableTransactionStorage import net.corda.node.services.schema.ContractStateAndRef import net.corda.node.services.schema.NodeSchemaService @@ -41,7 +40,14 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.DatabaseConfig import net.corda.nodeapi.internal.persistence.HibernateConfiguration import net.corda.nodeapi.internal.persistence.HibernateSchemaChangeException -import net.corda.testing.core.* +import net.corda.testing.core.ALICE_NAME +import net.corda.testing.core.BOB_NAME +import net.corda.testing.core.BOC_NAME +import net.corda.testing.core.CHARLIE_NAME +import net.corda.testing.core.DUMMY_NOTARY_NAME +import net.corda.testing.core.SerializationEnvironmentRule +import net.corda.testing.core.TestIdentity +import net.corda.testing.core.singleIdentity import net.corda.testing.internal.configureDatabase import net.corda.testing.internal.vault.DummyDealStateSchemaV1 import net.corda.testing.internal.vault.DummyLinearStateSchemaV1 @@ -49,15 +55,25 @@ import net.corda.testing.internal.vault.DummyLinearStateSchemaV2 import net.corda.testing.internal.vault.VaultFiller import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties -import org.assertj.core.api.Assertions import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy import org.hibernate.SessionFactory -import org.junit.* +import org.junit.After +import org.junit.Assert +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.argThat +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import java.math.BigDecimal import java.time.Clock import java.time.Instant -import java.util.* +import java.util.Currency +import java.util.Random +import java.util.UUID import javax.persistence.EntityManager import javax.persistence.Tuple import javax.persistence.criteria.CriteriaBuilder @@ -85,7 +101,7 @@ class HibernateConfigurationTest { val vault: VaultService get() = services.vaultService // Hibernate configuration objects - lateinit var hibernateConfig: HibernateConfiguration + private lateinit var hibernateConfig: HibernateConfiguration private lateinit var hibernatePersister: PersistentStateService private lateinit var sessionFactory: SessionFactory private lateinit var entityManager: EntityManager @@ -126,7 +142,7 @@ class HibernateConfigurationTest { override val vaultService = NodeVaultService( Clock.systemUTC(), keyManagementService, - servicesForResolution as NodeServicesForResolution, + toVerifyingServiceHub(), database, schemaService, cordappClassloader @@ -236,7 +252,7 @@ class HibernateConfigurationTest { // execute query val queryResults = entityManager.createQuery(criteriaQuery).resultList - Assertions.assertThat(queryResults.size).isEqualTo(3) + assertThat(queryResults.size).isEqualTo(3) } @Test(timeout=300_000) @@ -327,7 +343,7 @@ class HibernateConfigurationTest { // execute query val queryResults = query.resultList - Assertions.assertThat(queryResults.size).isEqualTo(15) + assertThat(queryResults.size).isEqualTo(15) // try towards end query.firstResult = 100 @@ -335,7 +351,7 @@ class HibernateConfigurationTest { val lastQueryResults = query.resultList - Assertions.assertThat(lastQueryResults.size).isEqualTo(10) + assertThat(lastQueryResults.size).isEqualTo(10) } /** diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt index 7c52587a3f..79c17fe120 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt @@ -4,24 +4,29 @@ import co.paralleluniverse.fibers.Suspendable import com.codahale.metrics.MetricRegistry import com.google.common.jimfs.Configuration import com.google.common.jimfs.Jimfs -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.contracts.ContractAttachment import net.corda.core.crypto.Crypto import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash import net.corda.core.crypto.randomHash -import net.corda.core.crypto.sha256 import net.corda.core.flows.FlowLogic -import net.corda.core.internal.* +import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER +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.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION -import net.corda.core.node.ServicesForResolution +import net.corda.core.internal.hash +import net.corda.core.internal.read +import net.corda.core.internal.readFully +import net.corda.core.internal.verification.NodeVerificationSupport import net.corda.core.node.services.AttachmentId import net.corda.core.node.services.vault.AttachmentQueryCriteria.AttachmentsQueryCriteria import net.corda.core.node.services.vault.AttachmentSort import net.corda.core.node.services.vault.Builder import net.corda.core.node.services.vault.Sort import net.corda.core.utilities.getOrThrow +import net.corda.coretesting.internal.rigorousMock import net.corda.node.services.transactions.PersistentUniquenessProvider import net.corda.nodeapi.exceptions.DuplicateAttachmentException import net.corda.nodeapi.internal.persistence.CordaPersistence @@ -36,16 +41,20 @@ import net.corda.testing.core.internal.SelfCleaningDir import net.corda.testing.internal.LogHelper import net.corda.testing.internal.TestingNamedCacheFactory import net.corda.testing.internal.configureDatabase -import net.corda.coretesting.internal.rigorousMock import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.startFlow -import org.assertj.core.api.Assertions.* +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException +import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.After import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Ignore import org.junit.Test +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.InputStream @@ -54,13 +63,19 @@ import java.nio.charset.StandardCharsets import java.nio.file.FileAlreadyExistsException import java.nio.file.FileSystem import java.nio.file.Path -import java.util.* +import java.util.Random import java.util.jar.JarEntry import java.util.jar.JarInputStream import java.util.jar.JarOutputStream import java.util.jar.Manifest -import kotlin.streams.toList -import kotlin.test.* +import kotlin.io.path.div +import kotlin.io.path.outputStream +import kotlin.io.path.readBytes +import kotlin.io.path.writeLines +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertNotEquals +import kotlin.test.assertNull class NodeAttachmentServiceTest { @@ -69,7 +84,7 @@ class NodeAttachmentServiceTest { private lateinit var database: CordaPersistence private lateinit var storage: NodeAttachmentService private lateinit var devModeStorage: NodeAttachmentService - private val services = rigorousMock().also { + private val nodeVerificationSupport = rigorousMock().also { doReturn(testNetworkParameters()).whenever(it).networkParameters } @@ -90,13 +105,13 @@ class NodeAttachmentServiceTest { it.start() } } - storage.servicesForResolution = services + storage.nodeVerificationSupport = nodeVerificationSupport devModeStorage = NodeAttachmentService(MetricRegistry(), TestingNamedCacheFactory(), database, true).also { database.transaction { it.start() } } - devModeStorage.servicesForResolution = services + devModeStorage.nodeVerificationSupport = nodeVerificationSupport } @After @@ -110,7 +125,7 @@ class NodeAttachmentServiceTest { SelfCleaningDir().use { file -> val jarAndSigner = makeTestSignedContractJar(file.path, "com.example.MyContract") val signedJar = jarAndSigner.first - signedJar.inputStream().use { jarStream -> + signedJar.read { jarStream -> val attachmentId = storage.importAttachment(jarStream, "test", null) assertEquals(listOf(jarAndSigner.second.hash), storage.openAttachment(attachmentId)!!.signerKeys.map { it.hash }) } @@ -121,7 +136,7 @@ class NodeAttachmentServiceTest { fun `importing a non-signed jar will save no signers`() { SelfCleaningDir().use { val jarName = makeTestContractJar(it.path, "com.example.MyContract") - it.path.resolve(jarName).inputStream().use { jarStream -> + (it.path / jarName).read { jarStream -> val attachmentId = storage.importAttachment(jarStream, "test", null) assertEquals(0, storage.openAttachment(attachmentId)!!.signerKeys.size) } @@ -157,7 +172,7 @@ class NodeAttachmentServiceTest { SelfCleaningDir().use { file -> val contractJarName = makeTestContractJar(file.path, "com.example.MyContract") val attachment = file.path.resolve(contractJarName) - val expectedAttachmentId = attachment.readAll().sha256() + val expectedAttachmentId = attachment.hash val initialUploader = "test" val attachmentId = attachment.read { storage.privilegedImportAttachment(it, initialUploader, null) } @@ -177,7 +192,7 @@ class NodeAttachmentServiceTest { SelfCleaningDir().use { file -> val contractJarName = makeTestContractJar(file.path, "com.example.MyContract") val attachment = file.path.resolve(contractJarName) - val expectedAttachmentId = attachment.readAll().sha256() + val expectedAttachmentId = attachment.hash val trustedUploader = TRUSTED_UPLOADERS.randomOrNull()!! val attachmentId = attachment.read { storage.privilegedImportAttachment(it, trustedUploader, null) } @@ -194,7 +209,7 @@ class NodeAttachmentServiceTest { SelfCleaningDir().use { file -> val contractJarName = makeTestContractJar(file.path, "com.example.MyContract") val testJar = file.path.resolve(contractJarName) - val expectedHash = testJar.readAll().sha256() + val expectedHash = testJar.hash // PRIVILEGED_UPLOADERS = listOf(DEPLOYED_CORDAPP_UPLOADER, RPC_UPLOADER, P2P_UPLOADER, UNKNOWN_UPLOADER) // TRUSTED_UPLOADERS = listOf(DEPLOYED_CORDAPP_UPLOADER, RPC_UPLOADER) @@ -560,7 +575,7 @@ class NodeAttachmentServiceTest { val id = testJar.read { storage.importAttachment(it, "test", null) } // Corrupt the file in the store. - val bytes = testJar.readAll() + val bytes = testJar.readBytes() val corruptBytes = "arggghhhh".toByteArray() System.arraycopy(corruptBytes, 0, bytes, 0, corruptBytes.size) val corruptAttachment = NodeAttachmentService.DBAttachment(attId = id.toString(), content = bytes, version = DEFAULT_CORDAPP_VERSION) @@ -751,16 +766,16 @@ class NodeAttachmentServiceTest { fun `The strict JAR verification function fails signed JARs with removed or extra files that are valid according to the usual jarsigner`() { // Signed jar that has a modified file. - val changedFileJAR = this::class.java.getResource("/changed-file-signed-jar.jar") + val changedFileJAR = this::class.java.getResource("/changed-file-signed-jar.jar")!! // Signed jar with removed files. - val removedFilesJAR = this::class.java.getResource("/removed-files-signed-jar.jar") + val removedFilesJAR = this::class.java.getResource("/removed-files-signed-jar.jar")!! // Signed jar with extra files. - val extraFilesJAR = this::class.java.getResource("/extra-files-signed-jar.jar") + val extraFilesJAR = this::class.java.getResource("/extra-files-signed-jar.jar")!! // Valid signed jar with all files. - val legalJAR = this::class.java.getResource("/legal-signed-jar.jar") + val legalJAR = this::class.java.getResource("/legal-signed-jar.jar")!! fun URL.standardVerifyJar() = JarInputStream(this.openStream(), true).use { jar -> while (true) { @@ -1060,6 +1075,6 @@ class NodeAttachmentServiceTest { counter++ val file = fs.getPath("$counter.jar") makeTestJar(file.outputStream(), entries) - return Pair(file, file.readAll().sha256()) + return Pair(file, file.hash) } } diff --git a/node/src/test/kotlin/net/corda/node/services/rpc/CheckpointDumperImplTest.kt b/node/src/test/kotlin/net/corda/node/services/rpc/CheckpointDumperImplTest.kt index 30eddb23ff..37a3b08afc 100644 --- a/node/src/test/kotlin/net/corda/node/services/rpc/CheckpointDumperImplTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/rpc/CheckpointDumperImplTest.kt @@ -2,22 +2,14 @@ package net.corda.node.services.rpc import com.natpryce.hamkrest.assertion.assertThat import com.natpryce.hamkrest.containsSubstring -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever import junit.framework.TestCase.assertNull import net.corda.core.context.InvocationContext import net.corda.core.flows.FlowLogic import net.corda.core.flows.StateMachineRunId import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.createDirectories -import net.corda.core.internal.deleteIfExists import net.corda.core.internal.deleteRecursively -import net.corda.core.internal.div -import net.corda.core.internal.inputStream import net.corda.core.internal.readFully import net.corda.core.node.ServiceHub -import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.internal.CheckpointSerializationDefaults import net.corda.core.serialization.internal.checkpointSerialize @@ -40,11 +32,18 @@ import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import java.nio.file.Files import java.nio.file.Paths import java.time.Clock import java.time.Instant import java.util.zip.ZipInputStream +import kotlin.io.path.createDirectories +import kotlin.io.path.deleteIfExists +import kotlin.io.path.div +import kotlin.io.path.inputStream class CheckpointDumperImplTest { @@ -64,13 +63,13 @@ class CheckpointDumperImplTest { private lateinit var services: ServiceHub private lateinit var checkpointStorage: DBCheckpointStorage - private val mockAfterStartEvent = { + private val mockAfterStartEvent = run { val nodeServicesContextMock = mock() - whenever(nodeServicesContextMock.tokenizableServices).doReturn(emptyList()) + whenever(nodeServicesContextMock.tokenizableServices).doReturn(emptyList()) val eventMock = mock>() whenever(eventMock.nodeServicesContext).doReturn(nodeServicesContextMock) eventMock - }() + } @Before fun setUp() { @@ -140,7 +139,7 @@ class CheckpointDumperImplTest { private fun checkDumpFile() { ZipInputStream(file.inputStream()).use { zip -> - val entry = zip.nextEntry + val entry = zip.nextEntry!! assertThat(entry.name, containsSubstring("json")) val content = zip.readFully() assertThat(String(content), containsSubstring(organisation)) diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowClientIdTests.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowClientIdTests.kt index 3ff6916e10..62d7ce6bcb 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowClientIdTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowClientIdTests.kt @@ -598,7 +598,7 @@ class FlowClientIdTests { @Test(timeout = 300_000) fun `flow that fails does not retain its checkpoint nor its exception in the database if not started with a client id`() { assertFailsWith { - aliceNode.services.startFlow(ExceptionFlow { IllegalStateException("another exception") }).resultFuture.getOrThrow() + aliceNode.services.startFlow(ExceptionFlow { IllegalStateException("another exception") }).resultFuture.getOrThrow() } aliceNode.services.database.transaction { @@ -915,4 +915,4 @@ class FlowClientIdTests { throw HospitalizeFlowException("time to go to the doctors") } } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt index 9c2628ff45..60f0c76f09 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt @@ -54,7 +54,6 @@ import net.corda.testing.core.BOB_NAME import net.corda.testing.core.dummyCommand import net.corda.testing.core.singleIdentity import net.corda.testing.flows.registerCordappFlowFactory -import net.corda.testing.internal.IS_OPENJ9 import net.corda.testing.internal.LogHelper import net.corda.testing.node.InMemoryMessagingNetwork.MessageTransfer import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin @@ -76,7 +75,6 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertNotEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull -import org.junit.Assume import org.junit.Before import org.junit.Test import rx.Notification @@ -91,7 +89,6 @@ import java.util.concurrent.TimeoutException import java.util.function.Predicate import kotlin.concurrent.thread import kotlin.reflect.KClass -import kotlin.streams.toList import kotlin.test.assertFailsWith import kotlin.test.assertTrue @@ -388,7 +385,6 @@ class FlowFrameworkTests { @Test(timeout = 300_000) fun `Flow metadata finish time is set in database when the flow finishes`() { - Assume.assumeTrue(!IS_OPENJ9) val terminationSignal = Semaphore(0) val clientId = UUID.randomUUID().toString() val flow = aliceNode.services.startFlowWithClientId(clientId, NoOpFlow(terminateUponSignal = terminationSignal)) @@ -779,7 +775,7 @@ class FlowFrameworkTests { assertFailsWith { val fiber = aliceNode.services.startFlow(ExceptionFlow { HospitalizeFlowException("Overnight observation") }) flowId = fiber.id - fiber.resultFuture.getOrThrow(10.seconds) + fiber.resultFuture.getOrThrow(10.seconds) } aliceNode.database.transaction { @@ -824,8 +820,9 @@ class FlowFrameworkTests { } // When ported to ENT use the existing API there to properly retry the flow + @Suppress("FunctionNaming") // For some reason this test produces invalid class names if the function name contains spaces @Test(timeout=300_000) - fun `Hospitalized flow, resets to 'RUNNABLE' and clears exception when retried`() { + fun Hospitalized_flow_resets_to_RUNNABLE_and_clears_exception_when_retried() { var firstRun = true var counter = 0 val waitUntilHospitalizedTwice = Semaphore(-1) diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowLogicRefFactoryImplTest.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowLogicRefFactoryImplTest.kt index a780bfbf2f..001f5af43b 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowLogicRefFactoryImplTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowLogicRefFactoryImplTest.kt @@ -3,6 +3,7 @@ package net.corda.node.services.statemachine import net.corda.core.flows.FlowLogic import net.corda.core.flows.IllegalFlowLogicException import net.corda.core.flows.SchedulableFlow +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Test import java.time.Duration import kotlin.reflect.jvm.jvmName @@ -77,8 +78,10 @@ class FlowLogicRefFactoryImplTest { flowLogicRefFactory.createKotlin(KotlinFlowLogic::class.java, args) } - @Test(expected = IllegalFlowLogicException::class, timeout=300_000) + @Test(timeout=300_000) fun `create for non-schedulable flow logic`() { - flowLogicRefFactory.create(NonSchedulableFlow::class.jvmName) + assertThatExceptionOfType(IllegalFlowLogicException::class.java).isThrownBy { + flowLogicRefFactory.create(NonSchedulableFlow::class.jvmName) + } } } diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowMetadataRecordingTest.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowMetadataRecordingTest.kt index 457693d4ac..ab7bf7de13 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowMetadataRecordingTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowMetadataRecordingTest.kt @@ -412,7 +412,7 @@ class FlowMetadataRecordingTest { metadata!!.let { assertNull(it.finishInstant) assertNotNull(finishTime) - assertTrue(finishTime!! >= it.startInstant) + assertTrue(finishTime >= it.startInstant) } } } diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowOperatorTests.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowOperatorTests.kt index 7bea95fe4d..29d55aa2ce 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowOperatorTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowOperatorTests.kt @@ -579,7 +579,6 @@ class FlowOperatorTests { private val expectedPayload: String, private val future: CompletableFuture ) : MessagingServiceSpy() { - @Suppress("TooGenericExceptionCaught") override fun send(message: Message, target: MessageRecipients, sequenceKey: Any) { try { val sessionMessage = message.data.bytes.deserialize() diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowParallelMessagingTests.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowParallelMessagingTests.kt index fd0e161255..0bd22914fd 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowParallelMessagingTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowParallelMessagingTests.kt @@ -11,6 +11,7 @@ import net.corda.core.flows.StartableByRPC import net.corda.core.flows.UnexpectedFlowEndException import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate +import net.corda.core.internal.mapToSet import net.corda.core.serialization.CordaSerializable import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.unwrap @@ -160,10 +161,10 @@ class FlowParallelMessagingTests { class SenderFlow(private val parties: Map): FlowLogic() { @Suspendable override fun call(): String { - val messagesPerSession = parties.toList().map { (party, messageType) -> + val messagesPerSession = parties.toList().associate { (party, messageType) -> val session = initiateFlow(party) Pair(session, messageType) - }.toMap() + } sendAllMap(messagesPerSession) val messages = receiveAll(String::class.java, messagesPerSession.keys.toList()) @@ -199,7 +200,7 @@ class FlowParallelMessagingTests { throw IllegalArgumentException("at least two parties required for staged execution") } - val sessions = parties.map { initiateFlow(it) }.toSet() + val sessions = parties.mapToSet(::initiateFlow) sessions.first().send(StagedMessageType.INITIAL_RECIPIENT) sessions.first().receive().unwrap{ payload -> assertEquals("pong", payload) } diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/IdempotentFlowTests.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/IdempotentFlowTests.kt index 7883c1513b..1f0f4b181b 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/IdempotentFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/IdempotentFlowTests.kt @@ -1,8 +1,8 @@ package net.corda.node.services.statemachine import co.paralleluniverse.fibers.Suspendable -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatingFlow @@ -86,4 +86,4 @@ class IdempotentFlowTests { waitForLedgerCommit(SecureHash.zeroHash) } } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/RetryFlowMockTest.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/RetryFlowMockTest.kt index 608d1ad7f4..39891c2539 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/RetryFlowMockTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/RetryFlowMockTest.kt @@ -23,7 +23,6 @@ import net.corda.node.services.messaging.Message import net.corda.node.services.persistence.DBTransactionStorage import net.corda.nodeapi.internal.persistence.contextTransaction import net.corda.testing.core.TestIdentity -import net.corda.testing.internal.IS_OPENJ9 import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.MessagingServiceSpy import net.corda.testing.node.internal.TestStartedNode @@ -34,7 +33,6 @@ import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.h2.util.Utils import org.junit.After import org.junit.Assert.assertTrue -import org.junit.Assume import org.junit.Before import org.junit.Ignore import org.junit.Test @@ -135,7 +133,6 @@ class RetryFlowMockTest { @Test(timeout=300_000) fun `Early end session message does not hang receiving flow`() { - Assume.assumeTrue(!IS_OPENJ9) val partyB = nodeB.info.legalIdentities.first() assertThatExceptionOfType(UnexpectedFlowEndException::class.java).isThrownBy { nodeA.startFlow(UnbalancedSendAndReceiveFlow(partyB)).getOrThrow(60.seconds) diff --git a/node/src/test/kotlin/net/corda/node/services/transactions/PathManagerTests.kt b/node/src/test/kotlin/net/corda/node/services/transactions/PathManagerTests.kt index f7a28fcc2c..d07ec83511 100644 --- a/node/src/test/kotlin/net/corda/node/services/transactions/PathManagerTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/transactions/PathManagerTests.kt @@ -1,8 +1,8 @@ package net.corda.node.services.transactions -import net.corda.core.internal.exists import org.junit.Test import java.nio.file.Files +import kotlin.io.path.exists import kotlin.test.assertFailsWith import kotlin.test.assertFalse import kotlin.test.assertTrue diff --git a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt index 35691970c7..03d8323ca4 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt @@ -1,9 +1,9 @@ package net.corda.node.services.vault import co.paralleluniverse.fibers.Suspendable -import com.nhaarman.mockito_kotlin.argThat -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.argThat +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import net.corda.core.contracts.* import net.corda.core.crypto.NullKeys import net.corda.core.crypto.SecureHash @@ -35,7 +35,6 @@ import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyState import net.corda.testing.core.* -import net.corda.testing.internal.IS_OPENJ9 import net.corda.testing.internal.LogHelper import net.corda.testing.internal.vault.* import net.corda.testing.node.MockServices @@ -469,7 +468,6 @@ class NodeVaultServiceTest { @Test(timeout=300_000) fun `unconsumedStatesForSpending from two issuer parties`() { - Assume.assumeTrue(!IS_OPENJ9) // openj9 OOM issue database.transaction { vaultFiller.fillWithSomeTestCash(100.DOLLARS, issuerServices, 1, DUMMY_CASH_ISSUER) vaultFiller.fillWithSomeTestCash(100.DOLLARS, bocServices, 1, BOC.ref(1)) @@ -1022,4 +1020,4 @@ class NodeVaultServiceTest { service.shutdown() } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryExceptionsTests.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryExceptionsTests.kt index 2dbd77b3ed..735c965d22 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryExceptionsTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryExceptionsTests.kt @@ -11,7 +11,6 @@ import net.corda.testing.core.* import net.corda.testing.internal.vault.DummyLinearStateSchemaV1 import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.* -import org.junit.rules.ExpectedException class VaultQueryExceptionsTests : VaultQueryParties by rule { @@ -30,10 +29,6 @@ class VaultQueryExceptionsTests : VaultQueryParties by rule { } } - @Rule - @JvmField - val expectedEx: ExpectedException = ExpectedException.none() - @Rule @JvmField val rollbackRule = VaultQueryRollbackRule(this) diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryJoinTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryJoinTest.kt index 4cca24dd3c..9deb9850f3 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryJoinTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryJoinTest.kt @@ -25,9 +25,7 @@ import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetworkParameters import net.corda.testing.node.StartedMockNode import net.corda.testing.node.internal.cordappsForPackages -import org.apache.commons.lang3.SystemUtils import org.junit.AfterClass -import org.junit.Assume import org.junit.BeforeClass import org.junit.Test import org.junit.jupiter.api.condition.DisabledOnJre @@ -51,7 +49,6 @@ class VaultQueryJoinTest { @BeforeClass @JvmStatic fun setup() { - Assume.assumeTrue(!SystemUtils.IS_JAVA_11) mockNetwork = MockNetwork( MockNetworkParameters( cordappsForAllNodes = cordappsForPackages( @@ -175,4 +172,4 @@ class DummyContract : Contract { interface Commands : CommandData { class AddDummy : Commands } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt index b256651f00..99be985de9 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt @@ -1,6 +1,6 @@ package net.corda.node.services.vault -import com.nhaarman.mockito_kotlin.mock +import org.mockito.kotlin.mock import net.corda.core.contracts.* import net.corda.core.crypto.* import net.corda.core.identity.AbstractParty @@ -32,7 +32,6 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.DatabaseConfig import net.corda.nodeapi.internal.persistence.DatabaseTransaction import net.corda.testing.core.* -import net.corda.testing.internal.IS_OPENJ9 import net.corda.testing.internal.chooseIdentity import net.corda.testing.internal.configureDatabase import net.corda.testing.internal.vault.* @@ -42,12 +41,12 @@ import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndPersiste import net.corda.testing.node.makeTestIdentityService import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatCode -import org.junit.Assume import org.junit.ClassRule import org.junit.Ignore import org.junit.Rule import org.junit.Test -import org.junit.rules.ExpectedException +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.assertThrows import org.junit.rules.ExternalResource import java.time.Duration import java.time.Instant @@ -150,7 +149,7 @@ open class VaultQueryTestRule(private val persistentServices: Boolean) : Externa cordappPackages, makeTestIdentityService(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, dummyCashIssuer.identity, dummyNotary.identity), megaCorp, - moreKeys = *arrayOf(DUMMY_NOTARY_KEY) + moreKeys = arrayOf(DUMMY_NOTARY_KEY) ) } database = databaseAndServices.first @@ -186,10 +185,6 @@ class VaultQueryRollbackRule(private val vaultQueryParties: VaultQueryParties) : abstract class VaultQueryTestsBase : VaultQueryParties { - @Rule - @JvmField - val expectedEx: ExpectedException = ExpectedException.none() - companion object { @ClassRule @JvmField val testSerialization = SerializationEnvironmentRule() @@ -1008,10 +1003,11 @@ abstract class VaultQueryTestsBase : VaultQueryParties { assertThat(resultsUnlockedAndByLockIds.states).hasSize(5) // missing lockId - expectedEx.expect(VaultQueryException::class.java) - expectedEx.expectMessage("Must specify one or more lockIds") - val criteriaMissingLockId = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.UNLOCKED_AND_SPECIFIED)) - vaultService.queryBy(criteriaMissingLockId) + val anException = assertThrows { + val criteriaMissingLockId = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.UNLOCKED_AND_SPECIFIED)) + vaultService.queryBy(criteriaMissingLockId) + } + anException.message?.let { assertTrue(it.contains("Must specify one or more lockIds")) } } } @@ -1709,45 +1705,43 @@ abstract class VaultQueryTestsBase : VaultQueryParties { // pagination: invalid page number @Test(timeout=300_000) fun `invalid page number`() { - Assume.assumeTrue(!IS_OPENJ9) // openj9 OOM issue - expectedEx.expect(VaultQueryException::class.java) - expectedEx.expectMessage("Page specification: invalid page number") - - database.transaction { - vaultFiller.fillWithSomeTestCash(100.DOLLARS, notaryServices, 100, DUMMY_CASH_ISSUER) - val pagingSpec = PageSpecification(0, 10) - - val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) - vaultService.queryBy(criteria, paging = pagingSpec) + val anException = assertThrows { + database.transaction { + vaultFiller.fillWithSomeTestCash(100.DOLLARS, notaryServices, 100, DUMMY_CASH_ISSUER) + val pagingSpec = PageSpecification(0, 10) + val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) + vaultService.queryBy(criteria, paging = pagingSpec) + } } + anException.message?.let { assertTrue(it.contains("Page specification: invalid page number")) } } // pagination: invalid page size @Suppress("INTEGER_OVERFLOW") @Test(timeout=300_000) fun `invalid page size`() { - expectedEx.expect(VaultQueryException::class.java) - expectedEx.expectMessage("Page specification: invalid page size") - - database.transaction { - vaultFiller.fillWithSomeTestCash(100.DOLLARS, notaryServices, 100, DUMMY_CASH_ISSUER) - val pagingSpec = PageSpecification(DEFAULT_PAGE_NUM, Integer.MAX_VALUE + 1) // overflow = -2147483648 - val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) - vaultService.queryBy(criteria, paging = pagingSpec) + val anException = assertThrows { + database.transaction { + vaultFiller.fillWithSomeTestCash(100.DOLLARS, notaryServices, 100, DUMMY_CASH_ISSUER) + val pagingSpec = PageSpecification(DEFAULT_PAGE_NUM, Integer.MAX_VALUE + 1) // overflow = -2147483648 + val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) + vaultService.queryBy(criteria, paging = pagingSpec) + } } + anException.message?.let { assertTrue(it.contains("Page specification: invalid page size")) } } // pagination not specified but more than DEFAULT_PAGE_SIZE results available (fail-fast test) @Test(timeout=300_000) fun `pagination not specified but more than default results available`() { - expectedEx.expect(VaultQueryException::class.java) - expectedEx.expectMessage("provide a PageSpecification") - - database.transaction { - vaultFiller.fillWithSomeTestCash(201.DOLLARS, notaryServices, 201, DUMMY_CASH_ISSUER) - val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) - vaultService.queryBy(criteria) + val anException = assertThrows { + database.transaction { + vaultFiller.fillWithSomeTestCash(201.DOLLARS, notaryServices, 201, DUMMY_CASH_ISSUER) + val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) + vaultService.queryBy(criteria) + } } + anException.message?.let { assertTrue(it.contains("provide a PageSpecification")) } } // example of querying states with paging using totalStatesAvailable @@ -2328,7 +2322,6 @@ abstract class VaultQueryTestsBase : VaultQueryParties { @Test(timeout=300_000) fun `unconsumed fungible states for owners`() { - Assume.assumeTrue(!IS_OPENJ9) // openj9 OOM issue database.transaction { vaultFillerCashNotary.fillWithSomeTestCash(100.DOLLARS, notaryServices, 1, DUMMY_CASH_ISSUER) vaultFiller.fillWithSomeTestCash(100.DOLLARS, notaryServices, 1, MEGA_CORP.ref(0), MEGA_CORP) @@ -2383,7 +2376,6 @@ abstract class VaultQueryTestsBase : VaultQueryParties { @Test(timeout=300_000) fun `unconsumed cash balances for all currencies`() { - Assume.assumeTrue(!IS_OPENJ9) // openj9 OOM issue database.transaction { listOf(100.DOLLARS, 200.DOLLARS, 300.POUNDS, 400.POUNDS, 500.SWISS_FRANCS, 600.SWISS_FRANCS).zip(1..6).forEach { (howMuch, states) -> vaultFiller.fillWithSomeTestCash(howMuch, notaryServices, states, DUMMY_CASH_ISSUER) @@ -2566,7 +2558,6 @@ abstract class VaultQueryTestsBase : VaultQueryParties { // specifying Query on Linear state attributes @Test(timeout=300_000) fun `unconsumed linear heads for linearId between two timestamps`() { - Assume.assumeTrue(!IS_OPENJ9) // openj9 OOM issue database.transaction { val start = services.clock.instant() vaultFiller.fillWithSomeTestLinearStates(1, "TEST") @@ -3208,7 +3199,6 @@ class VaultQueryTests : VaultQueryTestsBase(), VaultQueryParties by delegate { } } - class PersistentServicesVaultQueryTests : VaultQueryParties by delegate { companion object { val delegate = VaultQueryTestRule(persistentServices = true) diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultSoftLockManagerTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultSoftLockManagerTest.kt index ac621c9bff..424d6810f2 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultSoftLockManagerTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultSoftLockManagerTest.kt @@ -1,7 +1,7 @@ package net.corda.node.services.vault import co.paralleluniverse.fibers.Suspendable -import com.nhaarman.mockito_kotlin.* +import org.mockito.kotlin.* import net.corda.core.contracts.* import net.corda.core.flows.FinalityFlow import net.corda.core.flows.FlowLogic @@ -28,7 +28,6 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.testing.core.singleIdentity import net.corda.testing.flows.registerCoreFlowFactory import net.corda.coretesting.internal.rigorousMock -import net.corda.node.internal.NodeServicesForResolution import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.enclosedCordapp import net.corda.testing.node.internal.startFlow @@ -86,11 +85,10 @@ class VaultSoftLockManagerTest { private val mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(enclosedCordapp()), defaultFactory = { args -> object : InternalMockNetwork.MockNode(args) { override fun makeVaultService(keyManagementService: KeyManagementService, - services: NodeServicesForResolution, database: CordaPersistence, cordappLoader: CordappLoader): VaultServiceInternal { val node = this - val realVault = super.makeVaultService(keyManagementService, services, database, cordappLoader) + val realVault = super.makeVaultService(keyManagementService, database, cordappLoader) return object : SingletonSerializeAsToken(), VaultServiceInternal by realVault { override fun softLockRelease(lockId: UUID, stateRefs: NonEmptySet?) { // Should be called before flow is removed diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt index 6e7dabd747..0177169fb5 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt @@ -1,6 +1,6 @@ package net.corda.node.services.vault -import com.nhaarman.mockito_kotlin.mock +import org.mockito.kotlin.mock import net.corda.core.contracts.ContractState import net.corda.core.contracts.InsufficientBalanceException import net.corda.core.contracts.LinearState @@ -83,7 +83,7 @@ class VaultWithCashTest { makeTestIdentityService(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, dummyCashIssuer.identity, dummyNotary.identity), TestIdentity(MEGA_CORP.name, servicesKey), networkParameters, - moreKeys = *arrayOf(dummyNotary.keyPair)) + moreKeys = arrayOf(dummyNotary.keyPair)) database = databaseAndServices.first services = databaseAndServices.second vaultFiller = VaultFiller(services, dummyNotary) diff --git a/node/src/test/kotlin/net/corda/node/utilities/ClockUtilsTest.kt b/node/src/test/kotlin/net/corda/node/utilities/ClockUtilsTest.kt index 2a755389b9..e903e03047 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/ClockUtilsTest.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/ClockUtilsTest.kt @@ -1,6 +1,5 @@ package net.corda.node.utilities - import co.paralleluniverse.fibers.FiberExecutorScheduler import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.strands.Strand @@ -12,6 +11,7 @@ import net.corda.node.CordaClock import net.corda.node.SimpleClock import net.corda.node.services.events.NodeSchedulerService import net.corda.testing.node.TestClock +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After import org.junit.Before import org.junit.Test @@ -22,13 +22,11 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import kotlin.test.assertFalse import kotlin.test.assertTrue -import kotlin.test.fail class ClockUtilsTest { - - lateinit var realClock: Clock - lateinit var stoppedClock: CordaClock - lateinit var executor: ExecutorService + private lateinit var realClock: Clock + private lateinit var stoppedClock: CordaClock + private lateinit var executor: ExecutorService @Before fun setup() { @@ -133,53 +131,51 @@ class ClockUtilsTest { val testClock = TestClock(stoppedClock) val advancedClock = Clock.offset(stoppedClock, 10.hours) - try { + assertThatExceptionOfType(InterruptedException::class.java).isThrownBy { NodeSchedulerService.awaitWithDeadline(testClock, advancedClock.instant(), SettableFuture.create()) - fail("Expected InterruptedException") - } catch (exception: InterruptedException) { } } @Test(timeout=300_000) -@Suspendable - fun `test waiting for a deadline with multiple clock advance and incomplete JDK8 future on Fibers`() { + @Suspendable + fun `test waiting for a deadline with multiple clock advance and incomplete JDK future on Fibers`() { val advancedClock = Clock.offset(stoppedClock, 1.hours) val testClock = TestClock(stoppedClock) val future = CompletableFuture() val scheduler = FiberExecutorScheduler("test", executor) - val fiber = scheduler.newFiber(@Suspendable { + val fiber = scheduler.newFiber @Suspendable { future.complete(NodeSchedulerService.awaitWithDeadline(testClock, advancedClock.instant(), future)) - }).start() + }.start() for (advance in 1..6) { - scheduler.newFiber(@Suspendable { + scheduler.newFiber @Suspendable { // Wait until fiber is waiting while (fiber.state != Strand.State.TIMED_WAITING) { Strand.sleep(1) } testClock.advanceBy(10.minutes) - }).start() + }.start() } assertFalse(future.getOrThrow(), "Should have reached deadline") } @Test(timeout=300_000) -@Suspendable + @Suspendable fun `test waiting for a deadline with multiple clock advance and incomplete Guava future on Fibers`() { val advancedClock = Clock.offset(stoppedClock, 1.hours) val testClock = TestClock(stoppedClock) val future = SettableFuture.create() val scheduler = FiberExecutorScheduler("test", executor) - val fiber = scheduler.newFiber(@Suspendable { + val fiber = scheduler.newFiber @Suspendable { future.set(NodeSchedulerService.awaitWithDeadline(testClock, advancedClock.instant(), future)) - }).start() + }.start() for (advance in 1..6) { - scheduler.newFiber(@Suspendable { + scheduler.newFiber @Suspendable { // Wait until fiber is waiting while (fiber.state != Strand.State.TIMED_WAITING) { Strand.sleep(1) } testClock.advanceBy(10.minutes) - }).start() + }.start() } assertFalse(future.getOrThrow(), "Should have reached deadline") } diff --git a/node/src/test/kotlin/net/corda/node/utilities/TLSAuthenticationTests.kt b/node/src/test/kotlin/net/corda/node/utilities/TLSAuthenticationTests.kt index abd7abe80f..7a41393df9 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/TLSAuthenticationTests.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/TLSAuthenticationTests.kt @@ -4,8 +4,11 @@ import net.corda.core.crypto.Crypto import net.corda.core.crypto.SignatureScheme import net.corda.core.crypto.newSecureRandom import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.* -import net.corda.nodeapi.internal.crypto.* +import net.corda.nodeapi.internal.crypto.CertificateType +import net.corda.nodeapi.internal.crypto.X509Utilities +import net.corda.nodeapi.internal.crypto.addOrReplaceCertificate +import net.corda.nodeapi.internal.crypto.addOrReplaceKey +import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder @@ -17,10 +20,20 @@ import java.net.InetSocketAddress import java.net.ServerSocket import java.nio.file.Path import java.security.KeyStore -import javax.net.ssl.* +import javax.net.ssl.KeyManagerFactory +import javax.net.ssl.SSLContext +import javax.net.ssl.SSLParameters +import javax.net.ssl.SSLServerSocket +import javax.net.ssl.SSLServerSocketFactory +import javax.net.ssl.SSLSocket +import javax.net.ssl.SSLSocketFactory +import javax.net.ssl.TrustManagerFactory import javax.security.auth.x500.X500Principal import kotlin.concurrent.thread -import kotlin.test.* +import kotlin.io.path.div +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue /** * Various tests for mixed-scheme mutual TLS authentication, such as: diff --git a/node/src/test/kotlin/net/corda/node/utilities/registration/HTTPNetworkRegistrationServiceTest.kt b/node/src/test/kotlin/net/corda/node/utilities/registration/HTTPNetworkRegistrationServiceTest.kt index 52db6d3e84..0d11b8a6b6 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/registration/HTTPNetworkRegistrationServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/registration/HTTPNetworkRegistrationServiceTest.kt @@ -1,9 +1,9 @@ package net.corda.node.utilities.registration -import com.nhaarman.mockito_kotlin.anyOrNull -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import net.corda.node.VersionInfo import net.corda.node.services.config.NetworkServicesConfig import net.corda.coretesting.internal.rigorousMock diff --git a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperTest.kt b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperTest.kt index 7990cf7502..3e434cf76b 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperTest.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperTest.kt @@ -2,35 +2,34 @@ package net.corda.node.utilities.registration import com.google.common.jimfs.Configuration.unix import com.google.common.jimfs.Jimfs -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.doAnswer -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.crypto.Crypto import net.corda.core.crypto.SecureHash import net.corda.core.identity.CordaX500Name import net.corda.core.internal.CertRole -import net.corda.core.internal.createDirectories -import net.corda.core.internal.div import net.corda.core.internal.safeSymbolicRead import net.corda.core.internal.toX500Name import net.corda.core.utilities.seconds +import net.corda.coretesting.internal.rigorousMock +import net.corda.coretesting.internal.stubs.CertificateStoreStubs import net.corda.node.NodeRegistrationOption import net.corda.node.services.config.NodeConfiguration +import net.corda.node.services.config.NotaryConfig import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.X509KeyStore import net.corda.nodeapi.internal.crypto.X509Utilities +import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_CLIENT_CA +import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_CLIENT_TLS +import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_INTERMEDIATE_CA import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA import net.corda.nodeapi.internal.crypto.X509Utilities.DISTRIBUTED_NOTARY_KEY_ALIAS import net.corda.nodeapi.internal.crypto.X509Utilities.createSelfSignedCACertificate import net.corda.testing.core.ALICE_NAME -import net.corda.testing.internal.createDevIntermediateCaCertPath -import net.corda.coretesting.internal.rigorousMock -import net.corda.coretesting.internal.stubs.CertificateStoreStubs -import net.corda.node.services.config.NotaryConfig import net.corda.testing.core.DUMMY_NOTARY_NAME -import org.assertj.core.api.Assertions.* +import net.corda.testing.internal.createDevIntermediateCaCertPath +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.assertj.core.api.Assertions.assertThatThrownBy import org.bouncycastle.asn1.x509.GeneralName import org.bouncycastle.asn1.x509.GeneralSubtree import org.bouncycastle.asn1.x509.NameConstraints @@ -39,13 +38,18 @@ import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest import org.junit.After import org.junit.Before import org.junit.Test -import java.lang.IllegalStateException -import java.nio.file.Files +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import java.nio.file.FileSystem +import java.nio.file.Files import java.security.PublicKey import java.security.cert.CertPathValidatorException import java.security.cert.X509Certificate import javax.security.auth.x500.X500Principal +import kotlin.io.path.createDirectories +import kotlin.io.path.div import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -104,17 +108,17 @@ class NetworkRegistrationHelperTest { val trustStore = config.p2pSslOptions.trustStore.get() nodeKeystore.run { - assertFalse(contains(X509Utilities.CORDA_INTERMEDIATE_CA)) - assertFalse(contains(X509Utilities.CORDA_ROOT_CA)) - assertFalse(contains(X509Utilities.CORDA_CLIENT_TLS)) - assertThat(CertRole.extract(this[X509Utilities.CORDA_CLIENT_CA])).isEqualTo(CertRole.NODE_CA) + assertFalse(contains(CORDA_INTERMEDIATE_CA)) + assertFalse(contains(CORDA_ROOT_CA)) + assertFalse(contains(CORDA_CLIENT_TLS)) + assertThat(CertRole.extract(this[CORDA_CLIENT_CA])).isEqualTo(CertRole.NODE_CA) } sslKeystore.run { - assertFalse(contains(X509Utilities.CORDA_CLIENT_CA)) - assertFalse(contains(X509Utilities.CORDA_INTERMEDIATE_CA)) - assertFalse(contains(X509Utilities.CORDA_ROOT_CA)) - val nodeTlsCertChain = query { getCertificateChain(X509Utilities.CORDA_CLIENT_TLS) } + assertFalse(contains(CORDA_CLIENT_CA)) + assertFalse(contains(CORDA_INTERMEDIATE_CA)) + assertFalse(contains(CORDA_ROOT_CA)) + val nodeTlsCertChain = query { getCertificateChain(CORDA_CLIENT_TLS) } assertThat(nodeTlsCertChain).hasSize(4) // The TLS cert has the same subject as the node CA cert assertThat(CordaX500Name.build(nodeTlsCertChain[0].subjectX500Principal)).isEqualTo(nodeLegalName) @@ -122,9 +126,9 @@ class NetworkRegistrationHelperTest { } trustStore.run { - assertFalse(contains(X509Utilities.CORDA_CLIENT_CA)) - assertFalse(contains(X509Utilities.CORDA_INTERMEDIATE_CA)) - assertThat(this[X509Utilities.CORDA_ROOT_CA]).isEqualTo(rootAndIntermediateCA.first.certificate) + assertFalse(contains(CORDA_CLIENT_CA)) + assertFalse(contains(CORDA_INTERMEDIATE_CA)) + assertThat(this[CORDA_ROOT_CA]).isEqualTo(rootAndIntermediateCA.first.certificate) } } @@ -208,10 +212,10 @@ class NetworkRegistrationHelperTest { val serviceIdentityAlias = DISTRIBUTED_NOTARY_KEY_ALIAS nodeKeystore.run { - assertFalse(contains(X509Utilities.CORDA_INTERMEDIATE_CA)) - assertFalse(contains(X509Utilities.CORDA_ROOT_CA)) - assertFalse(contains(X509Utilities.CORDA_CLIENT_TLS)) - assertFalse(contains(X509Utilities.CORDA_CLIENT_CA)) + assertFalse(contains(CORDA_INTERMEDIATE_CA)) + assertFalse(contains(CORDA_ROOT_CA)) + assertFalse(contains(CORDA_CLIENT_TLS)) + assertFalse(contains(CORDA_CLIENT_CA)) assertThat(CertRole.extract(this[serviceIdentityAlias])).isEqualTo(CertRole.SERVICE_IDENTITY) } } @@ -242,12 +246,12 @@ class NetworkRegistrationHelperTest { // Mock out the registration service to ensure notary service registration is handled correctly createRegistrationHelper(CertRole.NODE_CA, notaryNodeConfig) { - when { - it.subject == nodeLegalName.toX500Name() -> { + when (it.subject) { + nodeLegalName.toX500Name() -> { val certType = CertificateType.values().first { it.role == CertRole.NODE_CA } createCertPath(rootAndIntermediateCA = rootAndIntermediateCA, publicKey = it.publicKey, type = certType) } - it.subject == notaryServiceLegalName.toX500Name() -> { + notaryServiceLegalName.toX500Name() -> { val certType = CertificateType.values().first { it.role == CertRole.SERVICE_IDENTITY } createCertPath(rootAndIntermediateCA = rootAndIntermediateCA, publicKey = it.publicKey, type = certType, legalName = notaryServiceLegalName) } @@ -258,10 +262,10 @@ class NetworkRegistrationHelperTest { val nodeKeystore = config.signingCertificateStore.get() nodeKeystore.run { - assertFalse(contains(X509Utilities.CORDA_INTERMEDIATE_CA)) + assertFalse(contains(CORDA_INTERMEDIATE_CA)) assertFalse(contains(CORDA_ROOT_CA)) - assertFalse(contains(X509Utilities.CORDA_CLIENT_TLS)) - assertThat(CertRole.extract(this[X509Utilities.CORDA_CLIENT_CA])).isEqualTo(CertRole.NODE_CA) + assertFalse(contains(CORDA_CLIENT_TLS)) + assertThat(CertRole.extract(this[CORDA_CLIENT_CA])).isEqualTo(CertRole.NODE_CA) assertThat(CertRole.extract(this[DISTRIBUTED_NOTARY_KEY_ALIAS])).isEqualTo(CertRole.SERVICE_IDENTITY) } } diff --git a/node/src/test/kotlin/net/corda/notary/experimental/bftsmart/BFTNotaryServiceTests.kt b/node/src/test/kotlin/net/corda/notary/experimental/bftsmart/BFTNotaryServiceTests.kt index ce18b11dd2..0497b452c4 100644 --- a/node/src/test/kotlin/net/corda/notary/experimental/bftsmart/BFTNotaryServiceTests.kt +++ b/node/src/test/kotlin/net/corda/notary/experimental/bftsmart/BFTNotaryServiceTests.kt @@ -1,19 +1,18 @@ package net.corda.notary.experimental.bftsmart -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint import net.corda.core.contracts.ContractState import net.corda.core.contracts.StateRef import net.corda.core.contracts.TimeWindow -import net.corda.core.crypto.* +import net.corda.core.crypto.CompositeKey +import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.TransactionSignature +import net.corda.core.crypto.isFulfilledBy import net.corda.core.flows.NotaryError import net.corda.core.flows.NotaryException import net.corda.core.flows.NotaryFlow import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party -import net.corda.core.internal.deleteIfExists -import net.corda.core.internal.div import net.corda.core.node.NotaryInfo import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder @@ -29,19 +28,26 @@ import net.corda.testing.contracts.DummyContract import net.corda.testing.core.dummyCommand import net.corda.testing.core.singleIdentity import net.corda.testing.node.TestClock -import net.corda.testing.node.internal.* -import org.hamcrest.Matchers.instanceOf +import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP +import net.corda.testing.node.internal.InternalMockNetwork +import net.corda.testing.node.internal.InternalMockNodeParameters +import net.corda.testing.node.internal.TestStartedNode +import net.corda.testing.node.internal.startFlow +import org.assertj.core.api.Assertions.assertThat import org.junit.AfterClass -import org.junit.Assert.assertThat import org.junit.BeforeClass import org.junit.Ignore import org.junit.Test +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import java.nio.file.Paths import java.time.Duration import java.time.Instant import java.util.concurrent.ExecutionException import kotlin.collections.component1 import kotlin.collections.component2 +import kotlin.io.path.deleteIfExists +import kotlin.io.path.div import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertTrue @@ -70,7 +76,7 @@ class BFTNotaryServiceTests { mockNet.stopNodes() } - fun startBftClusterAndNode(clusterSize: Int, mockNet: InternalMockNetwork, exposeRaces: Boolean = false): Pair { + private fun startBftClusterAndNode(clusterSize: Int, mockNet: InternalMockNetwork, exposeRaces: Boolean = false): Pair { (Paths.get("config") / "currentView").deleteIfExists() // XXX: Make config object warn if this exists? val replicaIds = (0 until clusterSize) val serviceLegalName = CordaX500Name("BFT", "Zurich", "CH") @@ -162,9 +168,9 @@ class BFTNotaryServiceTests { val resultFuture = services.startFlow(flow).resultFuture mockNet.runNetwork() val exception = assertFailsWith { resultFuture.get() } - assertThat(exception.cause, instanceOf(NotaryException::class.java)) + assertThat(exception.cause).isInstanceOf(NotaryException::class.java) val error = (exception.cause as NotaryException).error - assertThat(error, instanceOf(NotaryError.TimeWindowInvalid::class.java)) + assertThat(error).isInstanceOf(NotaryError.TimeWindowInvalid::class.java) } } diff --git a/node/src/test/kotlin/net/corda/notary/experimental/raft/RaftNotaryServiceTests.kt b/node/src/test/kotlin/net/corda/notary/experimental/raft/RaftNotaryServiceTests.kt index cde76833d9..9c69d86b17 100644 --- a/node/src/test/kotlin/net/corda/notary/experimental/raft/RaftNotaryServiceTests.kt +++ b/node/src/test/kotlin/net/corda/notary/experimental/raft/RaftNotaryServiceTests.kt @@ -1,19 +1,17 @@ package net.corda.notary.experimental.raft import net.corda.core.contracts.StateAndRef -import net.corda.core.contracts.StateRef import net.corda.core.flows.NotaryError import net.corda.core.flows.NotaryException import net.corda.core.flows.NotaryFlow import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.concurrent.map -import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.seconds import net.corda.testing.contracts.DummyContract +import net.corda.testing.contracts.DummyContract.SingleOwnerState import net.corda.testing.core.DUMMY_BANK_A_NAME -import net.corda.testing.core.dummyCommand import net.corda.testing.core.singleIdentity import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.InProcess @@ -22,7 +20,7 @@ import net.corda.testing.node.ClusterSpec import net.corda.testing.node.NotarySpec import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP import org.junit.Test -import java.util.* +import java.util.Random import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -39,20 +37,13 @@ class RaftNotaryServiceTests { val bankA = startNode(providedName = DUMMY_BANK_A_NAME).map { (it as InProcess) }.getOrThrow() val inputState = issueState(bankA, defaultNotaryIdentity) - val firstTxBuilder = TransactionBuilder(defaultNotaryIdentity) - .addInputState(inputState) - .addCommand(dummyCommand(bankA.services.myInfo.singleIdentity().owningKey)) + val firstTxBuilder = DummyContract.move(inputState, bankA.services.myInfo.singleIdentity()) val firstSpendTx = bankA.services.signInitialTransaction(firstTxBuilder) val firstSpend = bankA.startFlow(NotaryFlow.Client(firstSpendTx)) firstSpend.getOrThrow() - val secondSpendBuilder = TransactionBuilder(defaultNotaryIdentity).withItems(inputState).run { - val dummyState = DummyContract.SingleOwnerState(0, bankA.services.myInfo.singleIdentity()) - addOutputState(dummyState, DummyContract.PROGRAM_ID) - addCommand(dummyCommand(bankA.services.myInfo.singleIdentity().owningKey)) - this - } + val secondSpendBuilder = DummyContract.move(inputState, bankA.services.myInfo.singleIdentity()) val secondSpendTx = bankA.services.signInitialTransaction(secondSpendBuilder) val secondSpend = bankA.startFlow(NotaryFlow.Client(secondSpendTx)) @@ -78,10 +69,10 @@ class RaftNotaryServiceTests { } } - private fun issueState(nodeHandle: InProcess, notary: Party): StateAndRef<*> { + private fun issueState(nodeHandle: InProcess, notary: Party): StateAndRef { val builder = DummyContract.generateInitial(Random().nextInt(), notary, nodeHandle.services.myInfo.singleIdentity().ref(0)) val stx = nodeHandle.services.signInitialTransaction(builder) nodeHandle.services.recordTransactions(stx) - return StateAndRef(stx.coreTransaction.outputs.first(), StateRef(stx.id, 0)) + return stx.coreTransaction.outRef(0) } } diff --git a/node/src/test/kotlin/net/corda/notary/experimental/raft/RaftTransactionCommitLogTests.kt b/node/src/test/kotlin/net/corda/notary/experimental/raft/RaftTransactionCommitLogTests.kt index 8dc0f61056..21e55d7d32 100644 --- a/node/src/test/kotlin/net/corda/notary/experimental/raft/RaftTransactionCommitLogTests.kt +++ b/node/src/test/kotlin/net/corda/notary/experimental/raft/RaftTransactionCommitLogTests.kt @@ -26,9 +26,9 @@ import net.corda.testing.internal.LogHelper import net.corda.testing.internal.TestingNamedCacheFactory import net.corda.testing.internal.configureDatabase import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties +import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.instanceOf import org.junit.After -import org.junit.Assert.assertThat import org.junit.Before import org.junit.Rule import org.junit.Test @@ -179,4 +179,4 @@ class RaftTransactionCommitLogTests { .build() return serverInitFuture.thenCompose { client.connect(address) }.thenApply { Member(it, server) } } -} \ No newline at end of file +} diff --git a/node/src/test/resources/contractClassAtVersion55.jar b/node/src/test/resources/contractClassAtVersion55.jar deleted file mode 100644 index 0dd4f648fc..0000000000 Binary files a/node/src/test/resources/contractClassAtVersion55.jar and /dev/null differ diff --git a/node/src/test/resources/isolated.jar b/node/src/test/resources/isolated.jar deleted file mode 100644 index 3df99a710f..0000000000 Binary files a/node/src/test/resources/isolated.jar and /dev/null differ diff --git a/node/src/test/resources/net/corda/node/internal/cordapp/signed/signed-by-dev-key.jar b/node/src/test/resources/net/corda/node/internal/cordapp/signed/signed-by-dev-key.jar deleted file mode 100644 index beb401a992..0000000000 Binary files a/node/src/test/resources/net/corda/node/internal/cordapp/signed/signed-by-dev-key.jar and /dev/null differ diff --git a/node/src/test/resources/net/corda/node/internal/cordapp/signed/signed-by-two-keys.jar b/node/src/test/resources/net/corda/node/internal/cordapp/signed/signed-by-two-keys.jar deleted file mode 100644 index c5360a0576..0000000000 Binary files a/node/src/test/resources/net/corda/node/internal/cordapp/signed/signed-by-two-keys.jar and /dev/null differ diff --git a/node/src/test/resources/net/corda/node/internal/cordapp/versions/min-2-no-target.jar b/node/src/test/resources/net/corda/node/internal/cordapp/versions/min-2-no-target.jar deleted file mode 100644 index 4496915841..0000000000 Binary files a/node/src/test/resources/net/corda/node/internal/cordapp/versions/min-2-no-target.jar and /dev/null differ diff --git a/node/src/test/resources/net/corda/node/internal/cordapp/versions/min-2-target-3.jar b/node/src/test/resources/net/corda/node/internal/cordapp/versions/min-2-target-3.jar deleted file mode 100644 index 1b66fba425..0000000000 Binary files a/node/src/test/resources/net/corda/node/internal/cordapp/versions/min-2-target-3.jar and /dev/null differ diff --git a/node/src/test/resources/net/corda/node/internal/cordapp/versions/no-min-or-target-version.jar b/node/src/test/resources/net/corda/node/internal/cordapp/versions/no-min-or-target-version.jar deleted file mode 100644 index 408e70145d..0000000000 Binary files a/node/src/test/resources/net/corda/node/internal/cordapp/versions/no-min-or-target-version.jar and /dev/null differ diff --git a/node/src/test/resources/workflowClassAtVersion55.jar b/node/src/test/resources/workflowClassAtVersion55.jar deleted file mode 100644 index bd33833e13..0000000000 Binary files a/node/src/test/resources/workflowClassAtVersion55.jar and /dev/null differ diff --git a/opentelemetry/build.gradle b/opentelemetry/build.gradle index 779d7839d0..3c58f6742a 100644 --- a/opentelemetry/build.gradle +++ b/opentelemetry/build.gradle @@ -1,19 +1,12 @@ -import static org.gradle.api.JavaVersion.VERSION_1_8 - plugins { id 'org.jetbrains.kotlin.jvm' id 'java-library' - id 'net.corda.plugins.publish-utils' - id 'com.jfrog.artifactory' + id 'corda.common-publishing' } description 'OpenTelemetry SDK Bundle' -// This driver is required by core, so must always be 1.8. See core build.gradle. -targetCompatibility = VERSION_1_8 - dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation platform("io.opentelemetry:opentelemetry-bom:$open_telemetry_version") implementation "io.opentelemetry:opentelemetry-sdk" implementation "io.opentelemetry:opentelemetry-exporter-otlp" @@ -23,7 +16,12 @@ dependencies { } } -publish { - name 'corda-opentelemetry' +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-opentelemetry' + from components.java + } + } } diff --git a/opentelemetry/opentelemetry-driver/build.gradle b/opentelemetry/opentelemetry-driver/build.gradle index 1b7e768696..b8fc145051 100644 --- a/opentelemetry/opentelemetry-driver/build.gradle +++ b/opentelemetry/opentelemetry-driver/build.gradle @@ -1,39 +1,32 @@ -import static org.gradle.api.JavaVersion.VERSION_1_8 - plugins { id 'org.jetbrains.kotlin.jvm' id 'java-library' id 'com.github.johnrengelman.shadow' - id 'net.corda.plugins.publish-utils' - id 'com.jfrog.artifactory' + id 'corda.common-publishing' } description 'OpenTelemetry Driver' -// This driver is required by core, so must always be 1.8. See core build.gradle. -targetCompatibility = VERSION_1_8 - dependencies { implementation project(":opentelemetry") } shadowJar { archiveClassifier = null - classifier = null exclude "**/Log4j2Plugins.dat" zip64 true } -artifacts { - archives shadowJar - publish shadowJar -} - jar { enabled = false } -publish { - disableDefaultJar = true - name 'corda-opentelemetry-driver' -} \ No newline at end of file +publishing { + publications { + shadow(MavenPublication) { publication -> + artifactId 'corda-opentelemetry-driver' + artifact shadowJar + from components.java + } + } +} diff --git a/samples/attachment-demo/build.gradle b/samples/attachment-demo/build.gradle index 02fa732184..f476cce723 100644 --- a/samples/attachment-demo/build.gradle +++ b/samples/attachment-demo/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordapp' @@ -7,12 +7,7 @@ apply plugin: 'net.corda.plugins.cordformation' description 'Corda attachment demo' cordapp { - info { - name "Corda Attachment Demo" - vendor "R3" - targetPlatformVersion corda_platform_version.toInteger() - minimumPlatformVersion 1 - } + targetPlatformVersion corda_platform_version.toInteger() } sourceSets { @@ -26,36 +21,40 @@ sourceSets { } configurations { - integrationTestCompile.extendsFrom testCompile + integrationTestImplementation.extendsFrom testImplementation integrationTestRuntimeOnly.extendsFrom testRuntimeOnly } dependencies { if (System.getProperty('excludeShell') == null) { - cordaDriver "net.corda:corda-shell:$corda_release_version" + cordaDriver "net.corda:corda-shell:$corda_shell_version" } - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - compile "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" - compile "javax.servlet:javax.servlet-api:${servlet_version}" - compile "javax.ws.rs:javax.ws.rs-api:2.1.1" - cordaCompile project(':client:rpc') + + cordaProvided project(':core') + cordaProvided project(':client:rpc') + + implementation "io.reactivex:rxjava:$rxjava_version" + implementation "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" + implementation "javax.servlet:javax.servlet-api:${servlet_version}" + implementation "javax.ws.rs:javax.ws.rs-api:2.1.1" // Cordformation needs a SLF4J implementation when executing the Network // Bootstrapper, but Log4J doesn't shutdown completely from within Gradle. // Use a much simpler SLF4J implementation here instead. - cordaRuntime "org.slf4j:slf4j-simple:$slf4j_version" + cordaBootstrapper "org.slf4j:slf4j-simple:$slf4j_version" + cordaBootstrapper project(":node-api") // Corda integration dependencies - cordaRuntime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - cordaRuntime project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts') + corda project(path: ":node:capsule", configuration: 'runtimeArtifacts') + corda project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts') cordapp project(':samples:attachment-demo:contracts') cordapp project(':samples:attachment-demo:workflows') - testCompile(project(':node-driver')) { + testImplementation(project(':node-driver')) { // We already have a SLF4J implementation on our runtime classpath, // and we don't need another one. - exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j-impl' + exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j2-impl' } testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" @@ -65,9 +64,15 @@ dependencies { testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile "org.assertj:assertj-core:$assertj_version" + testImplementation "org.assertj:assertj-core:$assertj_version" - integrationTestCompile project(':testing:testserver') + integrationTestImplementation project(':core') + integrationTestImplementation project(':node') + integrationTestImplementation project(':client:rpc') + integrationTestImplementation project(':core-test-utils') + integrationTestImplementation project(':testing:testserver') + + integrationTestImplementation "junit:junit:$junit_version" } task integrationTest(type: Test, dependsOn: []) { @@ -77,16 +82,21 @@ task integrationTest(type: Test, dependsOn: []) { def nodeTask = tasks.getByPath(':node:capsule:assemble') def webTask = tasks.getByPath(':testing:testserver:testcapsule::assemble') +configurations.cordaCordapp.canBeResolved = true task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, webTask]) { - ext.rpcUsers = [['username': "demo", 'password': "demo", 'permissions': ["StartFlow.net.corda.attachmentdemo.AttachmentDemoFlow", - "InvokeRpc.partiesFromName", - "InvokeRpc.notaryPartyFromX500Name", - "InvokeRpc.attachmentExists", - "InvokeRpc.openAttachment", - "InvokeRpc.uploadAttachment", - "InvokeRpc.internalVerifiedTransactionsFeed", - "InvokeRpc.startTrackedFlowDynamic", - "InvokeRpc.nodeInfo"]]] + def users = [ + ['username': "demo", 'password': "demo", 'permissions': [ + "StartFlow.net.corda.attachmentdemo.AttachmentDemoFlow", + "InvokeRpc.partiesFromName", + "InvokeRpc.notaryPartyFromX500Name", + "InvokeRpc.attachmentExists", + "InvokeRpc.openAttachment", + "InvokeRpc.uploadAttachment", + "InvokeRpc.internalVerifiedTransactionsFeed", + "InvokeRpc.startTrackedFlowDynamic", + "InvokeRpc.nodeInfo"] + ] + ] nodeDefaults { projectCordapp { @@ -95,6 +105,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, cordapp project(':samples:attachment-demo:contracts') cordapp project(':samples:attachment-demo:workflows') runSchemaMigration = true + rpcUsers = users } node { name "O=Notary Node,L=Zurich,C=CH" @@ -102,8 +113,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, serviceLegalName: "O=Notary Service,L=Zurich,C=CH" ] p2pPort 10002 - cordapps = [] - rpcUsers = ext.rpcUsers rpcSettings { address "localhost:10003" adminAddress "localhost:10004" @@ -113,8 +122,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, node { name "O=Bank A,L=London,C=GB" p2pPort 10005 - cordapps = [] - rpcUsers = ext.rpcUsers rpcSettings { address "localhost:10006" adminAddress "localhost:10007" @@ -129,8 +136,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, adminAddress "localhost:10011" } webPort 10010 - cordapps = [] - rpcUsers = ext.rpcUsers extraConfig = ['h2Settings.address': 'localhost:10014'] } } @@ -138,6 +143,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, task runSender(type: JavaExec, dependsOn: jar) { classpath = sourceSets.main.runtimeClasspath main = 'net.corda.attachmentdemo.AttachmentDemoKt' + args '--role' args 'SENDER' } @@ -145,6 +151,7 @@ task runSender(type: JavaExec, dependsOn: jar) { task runRecipient(type: JavaExec, dependsOn: jar) { classpath = sourceSets.main.runtimeClasspath main = 'net.corda.attachmentdemo.AttachmentDemoKt' + args '--role' args 'RECIPIENT' } diff --git a/samples/attachment-demo/contracts/build.gradle b/samples/attachment-demo/contracts/build.gradle index c34d232331..00071a2305 100644 --- a/samples/attachment-demo/contracts/build.gradle +++ b/samples/attachment-demo/contracts/build.gradle @@ -1,11 +1,10 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.cordapp' description 'Corda attachment demo - contracts' dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - cordaCompile project(':core') + cordaProvided project(':core') } cordapp { @@ -21,4 +20,4 @@ cordapp { jar { baseName 'corda-attachment-demo-contracts' -} \ No newline at end of file +} diff --git a/samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt b/samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt index b60e813471..b2e0072570 100644 --- a/samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt +++ b/samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt @@ -5,28 +5,23 @@ import net.corda.core.utilities.getOrThrow import net.corda.node.services.Permissions.Companion.all import net.corda.testing.core.DUMMY_BANK_A_NAME import net.corda.testing.core.DUMMY_BANK_B_NAME -import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.driver import net.corda.testing.driver.internal.incrementalPortAllocation -import net.corda.testing.node.NotarySpec import net.corda.testing.node.User -import net.corda.testing.node.internal.DummyClusterSpec import net.corda.testing.node.internal.findCordapp import org.junit.Test import java.util.concurrent.CompletableFuture.supplyAsync class AttachmentDemoTest { - // run with a 10,000,000 bytes in-memory zip file. In practice, a slightly bigger file will be used (~10,002,000 bytes). @Test(timeout=300_000) fun `attachment demo using a 10MB zip file`() { val numOfExpectedBytes = 10_000_000 driver(DriverParameters( portAllocation = incrementalPortAllocation(), startNodesInProcess = true, - cordappsForAllNodes = listOf(findCordapp("net.corda.attachmentdemo.contracts"), findCordapp("net.corda.attachmentdemo.workflows")), - notarySpecs = listOf(NotarySpec(name = DUMMY_NOTARY_NAME, cluster = DummyClusterSpec(clusterSize = 1)))) - ) { + cordappsForAllNodes = listOf(findCordapp("net.corda.attachmentdemo.contracts"), findCordapp("net.corda.attachmentdemo.workflows")) + )) { val demoUser = listOf(User("demo", "demo", setOf(all()))) val (nodeA, nodeB) = listOf( startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = demoUser, maximumHeapSize = "1g"), diff --git a/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt b/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt index 2851a3c654..e8243b84c7 100644 --- a/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt +++ b/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt @@ -7,7 +7,7 @@ import net.corda.client.rpc.CordaRPCClient import net.corda.core.crypto.SecureHash import net.corda.core.identity.CordaX500Name import net.corda.core.internal.Emoji -import net.corda.core.internal.InputStreamAndHash +import net.corda.core.internal.hash import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startTrackedFlow import net.corda.core.utilities.NetworkHostAndPort @@ -16,9 +16,14 @@ import java.io.InputStream import java.net.HttpURLConnection import java.net.URL import java.util.jar.JarInputStream +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream import javax.servlet.http.HttpServletResponse.SC_OK import javax.ws.rs.core.HttpHeaders.CONTENT_DISPOSITION import javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM +import kotlin.io.path.createTempFile +import kotlin.io.path.inputStream +import kotlin.io.path.outputStream import kotlin.system.exitProcess internal enum class Role { @@ -57,11 +62,16 @@ fun main(args: Array) { } } -/** An in memory test zip attachment of at least numOfClearBytes size, will be used. */ +/** A temp zip file attachment of at least numOfClearBytes size, will be used. */ // DOCSTART 2 fun sender(rpc: CordaRPCOps, numOfClearBytes: Int = 1024) { // default size 1K. - val (inputStream, hash) = InputStreamAndHash.createInMemoryTestZip(numOfClearBytes, 0) - sender(rpc, inputStream, hash) + val attachmentFile = createTempFile("attachment-demo").apply { toFile().deleteOnExit() } + ZipOutputStream(attachmentFile.outputStream()).use { zip -> + zip.putNextEntry(ZipEntry("test")) + zip.write(ByteArray(numOfClearBytes)) + zip.closeEntry() + } + sender(rpc, attachmentFile.inputStream(), attachmentFile.hash) } private fun sender(rpc: CordaRPCOps, inputStream: InputStream, hash: SecureHash.SHA256) { diff --git a/samples/attachment-demo/workflows/build.gradle b/samples/attachment-demo/workflows/build.gradle index 09d4f45d55..9fd6e6b42f 100644 --- a/samples/attachment-demo/workflows/build.gradle +++ b/samples/attachment-demo/workflows/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordapp' @@ -6,10 +6,8 @@ apply plugin: 'net.corda.plugins.cordapp' description 'Corda attachment demo - workflows' dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - // Corda integration dependencies - cordaCompile project(':core') + cordaProvided project(':core') cordapp project(':samples:attachment-demo:contracts') } @@ -33,4 +31,4 @@ cordapp { jar { baseName 'corda-attachment-demo-workflows' -} \ No newline at end of file +} diff --git a/samples/bank-of-corda-demo/build.gradle b/samples/bank-of-corda-demo/build.gradle index 11d398ce8b..41229b1ad1 100644 --- a/samples/bank-of-corda-demo/build.gradle +++ b/samples/bank-of-corda-demo/build.gradle @@ -1,5 +1,6 @@ -apply plugin: 'java' -apply plugin: 'kotlin' +import net.corda.plugins.Cordform + +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordapp' @@ -7,9 +8,12 @@ apply plugin: 'net.corda.plugins.cordformation' dependencies { if (System.getProperty('excludeShell') == null) { - cordaDriver "net.corda:corda-shell:$corda_release_version" + cordaDriver "net.corda:corda-shell:$corda_shell_version" } - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + + implementation project(":core-test-utils") + implementation project(":test-utils") + implementation "org.slf4j:slf4j-api:$slf4j_version" // The bank of corda CorDapp depends upon Cash CorDapp features cordapp project(':finance:contracts') @@ -18,23 +22,30 @@ dependencies { // Cordformation needs a SLF4J implementation when executing the Network // Bootstrapper, but Log4J doesn't shutdown completely from within Gradle. // Use a much simpler SLF4J implementation here instead. - cordaRuntime "org.slf4j:slf4j-simple:$slf4j_version" + cordaRuntimeOnly "org.slf4j:slf4j-simple:$slf4j_version" // Corda integration dependencies - cordaRuntime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - cordaRuntime project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts') - cordaCompile project(':core') - cordaCompile project(':client:jfx') - cordaCompile project(':client:rpc') - cordaCompile(project(':testing:testserver')) { + corda project(path: ":node:capsule", configuration: 'runtimeArtifacts') + corda project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts') + + cordaProvided project(':core') + cordaProvided project(':client:jfx') + cordaProvided project(':client:rpc') + cordaProvided(project(':testing:testserver')) { exclude group: "org.apache.logging.log4j" } - cordaCompile (project(':node-driver')) { + cordaProvided (project(':node-driver')) { exclude group: "org.apache.logging.log4j" } + cordaBootstrapper "org.slf4j:slf4j-simple:$slf4j_version" + cordaBootstrapper project(":node-api") + // Javax is required for webapis - compile "org.glassfish.jersey.core:jersey-server:${jersey_version}" + implementation "org.glassfish.jersey.core:jersey-server:${jersey_version}" + implementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version" + implementation "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" // Test dependencies testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" @@ -45,9 +56,9 @@ dependencies { testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" } -def nodeTask = tasks.getByPath(':node:capsule:assemble') -def webTask = tasks.getByPath(':testing:testserver:testcapsule::assemble') -task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, webTask]) { +configurations.cordaCordapp.canBeResolved = true +tasks.register('deployNodes', Cordform) { + dependsOn('jar', ':node:capsule:assemble', ':testing:testserver:testcapsule::assemble') nodeDefaults { cordapp project(':finance:workflows') cordapp project(':finance:contracts') @@ -55,7 +66,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, } node { name "O=Notary Node,L=Zurich,C=CH" - notary = [validating: true, + notary = [validating : true, serviceLegalName: "O=Notary Service,L=Zurich,C=CH" ] p2pPort 10002 @@ -103,38 +114,28 @@ idea { } } -task runRPCCashIssue(type: JavaExec) { +tasks.register('runRPCCashIssue', JavaExec) { classpath = sourceSets.main.runtimeClasspath - main = 'net.corda.bank.IssueCash' + mainClass = 'net.corda.bank.IssueCash' + args '--role' args 'ISSUE_CASH_RPC' args '--quantity' args 20000 args '--currency' args 'USD' - if (JavaVersion.current() == JavaVersion.VERSION_11) { - jvmArgs '--add-opens' - jvmArgs 'java.base/java.time=ALL-UNNAMED' - jvmArgs '--add-opens' - jvmArgs 'java.base/java.io=ALL-UNNAMED' - } } -task runWebCashIssue(type: JavaExec) { +tasks.register('runWebCashIssue', JavaExec) { classpath = sourceSets.main.runtimeClasspath - main = 'net.corda.bank.IssueCash' + mainClass = 'net.corda.bank.IssueCash' + args '--role' args 'ISSUE_CASH_WEB' args '--quantity' args 30000 args '--currency' args 'GBP' - if (JavaVersion.current() == JavaVersion.VERSION_11) { - jvmArgs '--add-opens' - jvmArgs 'java.base/java.time=ALL-UNNAMED' - jvmArgs '--add-opens' - jvmArgs 'java.base/java.io=ALL-UNNAMED' - } } jar { @@ -147,10 +148,4 @@ jar { cordapp { targetPlatformVersion corda_platform_version.toInteger() - minimumPlatformVersion 1 - info { - name "Bank of Corda Demo" - version "1" - vendor "R3" - } } diff --git a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/api/BankOfCordaWebApi.kt b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/api/BankOfCordaWebApi.kt index 25daa53476..d20a3f2acc 100644 --- a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/api/BankOfCordaWebApi.kt +++ b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/api/BankOfCordaWebApi.kt @@ -1,5 +1,12 @@ package net.corda.bank.api +import jakarta.ws.rs.Consumes +import jakarta.ws.rs.GET +import jakarta.ws.rs.POST +import jakarta.ws.rs.Path +import jakarta.ws.rs.Produces +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response import net.corda.core.contracts.Amount import net.corda.core.identity.CordaX500Name import net.corda.core.messaging.CordaRPCOps @@ -10,9 +17,6 @@ import net.corda.core.utilities.getOrThrow import net.corda.finance.flows.CashIssueAndPaymentFlow import java.time.LocalDateTime import java.util.* -import javax.ws.rs.* -import javax.ws.rs.core.MediaType -import javax.ws.rs.core.Response // API is accessible from /api/bank. All paths specified below are relative to it. @Path("bank") diff --git a/samples/cordapp-configuration/build.gradle b/samples/cordapp-configuration/build.gradle index 5f1155c184..ab72adf343 100644 --- a/samples/cordapp-configuration/build.gradle +++ b/samples/cordapp-configuration/build.gradle @@ -1,26 +1,33 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' +apply plugin: 'net.corda.plugins.cordapp' apply plugin: 'net.corda.plugins.cordformation' +cordapp { + targetPlatformVersion corda_platform_version.toInteger() +} + +jar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + dependencies { if (System.getProperty('excludeShell') == null) { - cordaDriver "net.corda:corda-shell:$corda_release_version" + cordaDriver "net.corda:corda-shell:$corda_shell_version" } - runtimeOnly project(':node-api') - // Cordformation needs a SLF4J implementation when executing the Network - // Bootstrapper, but Log4J doesn't shutdown completely from within Gradle. - // Use a much simpler SLF4J implementation here instead. - cordaRuntime "org.slf4j:slf4j-simple:$slf4j_version" + + cordaBootstrapper "org.slf4j:slf4j-simple:$slf4j_version" + cordaBootstrapper project(":node-api") // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') + corda project(path: ":node:capsule", configuration: 'runtimeArtifacts') + corda project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts') cordapp project(':samples:cordapp-configuration:workflows') } -def nodeTask = tasks.getByPath(':node:capsule:assemble') -def webTask = tasks.getByPath(':testing:testserver:testcapsule::assemble') -task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, webTask]) { +configurations.cordaCordapp.canBeResolved = true +task deployNodes(type: net.corda.plugins.Cordform) { directory file("$buildDir/nodes") nodeDefaults { projectCordapp { diff --git a/samples/cordapp-configuration/src/main/resources/log4j2.xml b/samples/cordapp-configuration/src/main/resources/log4j2.xml index 986f04813e..b6f56a2101 100644 --- a/samples/cordapp-configuration/src/main/resources/log4j2.xml +++ b/samples/cordapp-configuration/src/main/resources/log4j2.xml @@ -4,9 +4,9 @@ - build/logs - cordapp-${hostName} - ${log-path}/archive + build/logs + cordapp-${hostName} + ${log_path}/archive @@ -24,8 +24,8 @@ + fileName="${log_path}/${log_name}.log" + filePattern="${archive}/${log_name}.%date{yyyy-MM-dd}-%i.log.gz"> @@ -36,7 +36,7 @@ - + diff --git a/samples/cordapp-configuration/workflows/build.gradle b/samples/cordapp-configuration/workflows/build.gradle index 4e9f698afc..dd15f8658b 100644 --- a/samples/cordapp-configuration/workflows/build.gradle +++ b/samples/cordapp-configuration/workflows/build.gradle @@ -1,8 +1,9 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.cordapp' dependencies { - cordaCompile project(':core') + cordaProvided project(':core') + implementation "co.paralleluniverse:quasar-core:$quasar_version" } cordapp { @@ -14,4 +15,4 @@ cordapp { vendor "R3" licence "Open Source (Apache 2)" } -} \ No newline at end of file +} diff --git a/samples/irs-demo/build.gradle b/samples/irs-demo/build.gradle index 0cf5896f9a..149b84f893 100644 --- a/samples/irs-demo/build.gradle +++ b/samples/irs-demo/build.gradle @@ -1,6 +1,5 @@ plugins { - id "org.springframework.boot" version "1.5.21.RELEASE" - id 'io.spring.dependency-management' version '1.0.9.RELEASE' apply false + id "org.springframework.boot" version '3.0.4' } // Spring Boot plugin adds a numerous hardcoded dependencies in the version much lower then Corda expects @@ -14,7 +13,7 @@ ext['jackson.version'] = "$jackson_kotlin_version" ext['dropwizard-metrics.version'] = "$metrics_version" ext['mockito.version'] = "$mockito_version" -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'application' @@ -39,24 +38,24 @@ sourceSets { } configurations { - slowIntegrationTestCompile.extendsFrom testCompile + slowIntegrationTestCompile.extendsFrom testImplementation slowIntegrationTestRuntimeOnly.extendsFrom testRuntimeOnly demoArtifacts.extendsFrom testRuntimeClasspath - systemTestCompile.extendsFrom testCompile + systemTestCompile.extendsFrom testImplementation } evaluationDependsOn("cordapp") evaluationDependsOn("web") dependencies { - compile "commons-io:commons-io:$commons_io_version" - compile project(":samples:irs-demo:web") - compile('org.springframework.boot:spring-boot-starter-web') { + implementation "commons-io:commons-io:$commons_io_version" + implementation project(":samples:irs-demo:web") + implementation('org.springframework.boot:spring-boot-starter-web:3.0.4') { exclude module: "spring-boot-starter-logging" exclude module: "logback-classic" } - testCompile project(':node-driver') + testImplementation project(':node-driver') testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" @@ -65,15 +64,15 @@ dependencies { testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile "org.assertj:assertj-core:${assertj_version}" + testImplementation "org.assertj:assertj-core:${assertj_version}" slowIntegrationTestCompile project(path: ":samples:irs-demo:web", configuration: "demoArtifacts") - testCompile "com.palantir.docker.compose:docker-compose-rule-junit4:$docker_compose_rule_version" - testCompile "org.seleniumhq.selenium:selenium-java:$selenium_version" - testCompile "com.github.detro:ghostdriver:$ghostdriver_version" + testImplementation "com.palantir.docker.compose:docker-compose-rule-junit4:$docker_compose_rule_version" + testImplementation "org.seleniumhq.selenium:selenium-java:$selenium_version" + testImplementation "com.github.detro:ghostdriver:$ghostdriver_version" } -bootRepackage { +bootJar { enabled = false } diff --git a/samples/irs-demo/cordapp/build.gradle b/samples/irs-demo/cordapp/build.gradle index 71d0428949..5386160bd0 100644 --- a/samples/irs-demo/cordapp/build.gradle +++ b/samples/irs-demo/cordapp/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordformation' @@ -7,6 +7,10 @@ apply plugin: 'application' mainClassName = 'net.corda.irs.IRSDemo' +cordapp { + targetPlatformVersion corda_platform_version.toInteger() +} + sourceSets { integrationTest { kotlin { @@ -17,25 +21,16 @@ sourceSets { } } -cordapp { - info { - name "Corda IRS Demo" - vendor "R3" - targetPlatformVersion corda_platform_version.toInteger() - minimumPlatformVersion 1 - } -} - dependencies { if (System.getProperty('excludeShell') == null) { - cordaDriver "net.corda:corda-shell:$corda_release_version" + cordaDriver "net.corda:corda-shell:$corda_shell_version" } cordapp project(':finance:contracts') cordapp project(':finance:workflows') // Corda integration dependencies - cordaRuntime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - cordaRuntime "org.slf4j:slf4j-simple:$slf4j_version" + cordaRuntimeOnly project(path: ":node:capsule", configuration: 'runtimeArtifacts') + cordaRuntimeOnly "org.slf4j:slf4j-simple:$slf4j_version" cordapp project(':samples:irs-demo:cordapp:contracts-irs') cordapp project(':samples:irs-demo:cordapp:workflows-irs') @@ -56,6 +51,7 @@ def rpcUsersList = [ ] def nodeTask = tasks.getByPath(':node:capsule:assemble') +configurations.cordaCordapp.canBeResolved = true task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) { nodeDefaults{ projectCordapp { @@ -75,7 +71,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) address("localhost:10003") adminAddress("localhost:10023") } - cordapps = ["${project(":finance").group}:contracts:$corda_release_version", "${project(":finance").group}:workflows:$corda_release_version"] + cordapp "${project(":finance").group}:contracts:$corda_release_version" + cordapp "${project(":finance").group}:workflows:$corda_release_version" rpcUsers = rpcUsersList useTestClock true extraConfig = ['h2Settings.address' : 'localhost:10024'] @@ -87,7 +84,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) address("localhost:10006") adminAddress("localhost:10026") } - cordapps = ["${project(":finance").group}:contracts:$corda_release_version", "${project(":finance").group}:workflows:$corda_release_version"] + cordapp "${project(":finance").group}:contracts:$corda_release_version" + cordapp "${project(":finance").group}:workflows:$corda_release_version" rpcUsers = rpcUsersList useTestClock true extraConfig = ['h2Settings.address' : 'localhost:10027'] @@ -99,7 +97,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) address("localhost:10009") adminAddress("localhost:10029") } - cordapps = ["${project.group}:contracts:$corda_release_version", "${project.group}:workflows:$corda_release_version"] + cordapp "${project.group}:contracts:$corda_release_version" + cordapp "${project.group}:workflows:$corda_release_version" rpcUsers = rpcUsersList useTestClock true extraConfig = ['h2Settings.address' : 'localhost:10030'] @@ -111,8 +110,10 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) address("localhost:10012") adminAddress("localhost:10032") } - cordapps = ["${project.group}:contracts:$corda_release_version", "${project.group}:workflows:$corda_release_version"] - cordapps = ["${project(":finance").group}:contracts:$corda_release_version", "${project(":finance").group}:workflows:$corda_release_version"] + cordapp "${project.group}:contracts:$corda_release_version" + cordapp "${project.group}:workflows:$corda_release_version" + cordapp "${project(":finance").group}:contracts:$corda_release_version" + cordapp "${project(":finance").group}:workflows:$corda_release_version" rpcUsers = rpcUsersList useTestClock true extraConfig = ['h2Settings.address' : 'localhost:10033'] @@ -130,25 +131,29 @@ task prepareDockerNodes(type: net.corda.plugins.Dockerform, dependsOn: ['jar', n notary = [validating : true, serviceLegalName: "O=Notary Service,L=Zurich,C=CH" ] - cordapps = ["${project(":finance").group}:contracts:$corda_release_version", "${project(":finance").group}:workflows:$corda_release_version"] + cordapp "${project(":finance").group}:contracts:$corda_release_version" + cordapp "${project(":finance").group}:workflows:$corda_release_version" rpcUsers = rpcUsersList useTestClock true } node { name "O=Bank A,L=London,C=GB" - cordapps = ["${project(":finance").group}:contracts:$corda_release_version", "${project(":finance").group}:workflows:$corda_release_version"] + cordapp "${project(":finance").group}:contracts:$corda_release_version" + cordapp "${project(":finance").group}:workflows:$corda_release_version" rpcUsers = rpcUsersList useTestClock true } node { name "O=Bank B,L=New York,C=US" - cordapps = ["${project(":finance").group}:contracts:$corda_release_version", "${project(":finance").group}:workflows:$corda_release_version"] + cordapp "${project(":finance").group}:contracts:$corda_release_version" + cordapp "${project(":finance").group}:workflows:$corda_release_version" rpcUsers = rpcUsersList useTestClock true } node { name "O=Regulator,L=Moscow,C=RU" - cordapps = ["${project.group}:contracts:$corda_release_version", "${project.group}:workflows:$corda_release_version"] + cordapp "${project.group}:contracts:$corda_release_version" + cordapp "${project.group}:workflows:$corda_release_version" rpcUsers = rpcUsersList useTestClock true } diff --git a/samples/irs-demo/cordapp/contracts-irs/build.gradle b/samples/irs-demo/cordapp/contracts-irs/build.gradle index 35b5dfcfe0..fe2ea92c90 100644 --- a/samples/irs-demo/cordapp/contracts-irs/build.gradle +++ b/samples/irs-demo/cordapp/contracts-irs/build.gradle @@ -1,19 +1,19 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' apply plugin: 'net.corda.plugins.cordapp' dependencies { // The irs demo CorDapp depends upon Cash CorDapp features - cordaCompile project(':core') - cordaRuntime project(':node-api') + cordaProvided project(':core') + cordaRuntimeOnly project(':node-api') cordapp project(':finance:contracts') // Apache JEXL: An embeddable expression evaluation library. - compile "org.apache.commons:commons-jexl3:3.1" + implementation "org.apache.commons:commons-jexl3:3.1" - compile "com.fasterxml.jackson.core:jackson-annotations:${jackson_version}" + implementation "com.fasterxml.jackson.core:jackson-annotations:${jackson_version}" - testCompile project(':node-driver') + testImplementation project(':node-driver') testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" diff --git a/samples/irs-demo/cordapp/contracts-irs/src/test/kotlin/net/corda/irs/contract/IRSTests.kt b/samples/irs-demo/cordapp/contracts-irs/src/test/kotlin/net/corda/irs/contract/IRSTests.kt index 200aa422db..6fb60df0aa 100644 --- a/samples/irs-demo/cordapp/contracts-irs/src/test/kotlin/net/corda/irs/contract/IRSTests.kt +++ b/samples/irs-demo/cordapp/contracts-irs/src/test/kotlin/net/corda/irs/contract/IRSTests.kt @@ -1,8 +1,8 @@ package net.corda.irs.contract -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import net.corda.core.contracts.Amount import net.corda.core.contracts.UniqueIdentifier import net.corda.core.crypto.generateKeyPair diff --git a/samples/irs-demo/cordapp/workflows-irs/build.gradle b/samples/irs-demo/cordapp/workflows-irs/build.gradle index ff88428b24..dfee6312f3 100644 --- a/samples/irs-demo/cordapp/workflows-irs/build.gradle +++ b/samples/irs-demo/cordapp/workflows-irs/build.gradle @@ -1,10 +1,10 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordapp' configurations { - demoArtifacts.extendsFrom testRuntimeClasspath + demoArtifacts.extendsFrom testRuntimeOnlyClasspath } dependencies { @@ -13,20 +13,25 @@ dependencies { cordapp project(':finance:workflows') // Corda integration dependencies - cordaCompile project(':core') - + cordaProvided project(':core') + + implementation "com.google.code.findbugs:jsr305:$jsr305_version" + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version") + implementation "org.slf4j:slf4j-api:$slf4j_version" + implementation "com.google.guava:guava-testlib:$guava_version" - compile("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version") - // only included to control the `DemoClock` as part of the demo application // normally `:node` should not be depended on in any CorDapps - compileOnly project(':node') + implementation project(':node') + implementation project(':node-api') + implementation project(':core-test-utils') + implementation project(':test-utils') // Cordapp dependencies // Specify your cordapp's dependencies below, including dependent cordapps - compile "commons-io:commons-io:$commons_io_version" + implementation "commons-io:commons-io:$commons_io_version" - testCompile project(':node-driver') + testImplementation project(':node-driver') testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" @@ -35,7 +40,7 @@ dependencies { testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile "org.assertj:assertj-core:${assertj_version}" + testImplementation "org.assertj:assertj-core:${assertj_version}" cordapp project(':samples:irs-demo:cordapp:contracts-irs') } @@ -53,6 +58,7 @@ cordapp { jar { baseName 'corda-irs-demo-workflows' + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } task testJar(type: Jar) { diff --git a/samples/irs-demo/web/build.gradle b/samples/irs-demo/web/build.gradle index b887d036cb..89d2fa8f6e 100644 --- a/samples/irs-demo/web/build.gradle +++ b/samples/irs-demo/web/build.gradle @@ -2,26 +2,17 @@ import java.nio.charset.StandardCharsets import java.nio.file.Files import org.yaml.snakeyaml.DumperOptions -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath "org.yaml:snakeyaml:1.24" - } -} - plugins { id 'com.craigburke.client-dependencies' version '1.4.0' + id 'org.springframework.boot' version '3.0.4' id 'io.spring.dependency-management' - id 'org.springframework.boot' } group = "${parent.group}.irs-demo" dependencyManagement { dependencies { - dependency "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version" + dependency "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version" dependency "org.apache.logging.log4j:log4j-core:$log4j_version" dependency "org.apache.logging.log4j:log4j-api:$log4j_version" } @@ -29,16 +20,16 @@ dependencyManagement { clientDependencies { registry 'realBower', type:'bower', url:'https://registry.bower.io' - realBower { - "angular"("1.5.8") - "jquery"("^3.0.0") - "angular-route"("1.5.8") - "lodash"("^4.13.1") - "angular-fcsa-number"("^1.5.3") - "jquery.maskedinput"("^1.4.1") - "requirejs"("^2.2.0") - "semantic-ui"("^2.2.2", into: "semantic") - } +// realBower { +// "angular"("1.5.8") +// "jquery"("^3.0.0") +// "angular-route"("1.5.8") +// "lodash"("^4.13.1") +// "angular-fcsa-number"("^1.5.3") +// "jquery.maskedinput"("^1.4.1") +// "requirejs"("^2.2.0") +// "semantic-ui"("^2.2.2", into: "semantic") +// } // put the JS dependencies into src directory so it can easily be referenced // from HTML files in webapp frontend, useful for testing/development @@ -53,37 +44,31 @@ ext['artemis.version'] = artemis_version ext['hibernate.version'] = hibernate_version ext['jackson.version'] = jackson_version -apply plugin: 'kotlin' -apply plugin: 'kotlin-spring' -apply plugin: 'eclipse' -apply plugin: 'project-report' -apply plugin: 'application' - configurations { - demoArtifacts.extendsFrom testRuntime + demoArtifacts.extendsFrom testRuntimeOnly } dependencies { - compile('org.springframework.boot:spring-boot-starter-web') { + implementation('org.springframework.boot:spring-boot-starter-web:3.0.4') { exclude module: "spring-boot-starter-logging" exclude module: "logback-classic" } - compile('org.springframework.boot:spring-boot-starter-log4j2') + implementation('org.springframework.boot:spring-boot-starter-log4j2') runtimeOnly("org.apache.logging.log4j:log4j-web:$log4j_version") - compile("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version") - compile project(":client:rpc") - compile project(":client:jackson") - compile project(":finance:workflows") + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version") + implementation project(":client:rpc") + implementation project(":client:jackson") + implementation project(":finance:workflows") // TODO In the future remove -irs bit from the directory name. Currently it clashes with :finance:workflows (same for contracts). - compile project(":samples:irs-demo:cordapp:workflows-irs") + implementation project(":samples:irs-demo:cordapp:workflows-irs") - testCompile project(":test-utils") - testCompile project(path: ":samples:irs-demo:cordapp:workflows-irs", configuration: "demoArtifacts") + testImplementation project(":test-utils") + testImplementation project(path: ":samples:irs-demo:cordapp:workflows-irs", configuration: "demoArtifacts") // JOpt: for command line flags. - compile "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" + implementation "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" - testCompile('org.springframework.boot:spring-boot-starter-test') { + testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude module: "spring-boot-starter-logging" exclude module: "logback-classic" } @@ -97,7 +82,7 @@ jar { def docker_dir = file("$project.buildDir/docker") -task deployWebapps(type: Copy, dependsOn: ['jar', 'bootRepackage']) { +task deployWebapps(type: Copy, dependsOn: ['jar', 'bootJar']) { ext.webappDir = file("build/webapps") from(jar.outputs) @@ -119,7 +104,7 @@ artifacts { demoArtifacts demoJar } -task createDockerfile(type: com.bmuschko.gradle.docker.tasks.image.Dockerfile, dependsOn: [bootRepackage]) { +task createDockerfile(type: com.bmuschko.gradle.docker.tasks.image.Dockerfile, dependsOn: [bootJar]) { destFile = file("$docker_dir/Dockerfile") from 'azul/zulu-openjdk-alpine:8u152' @@ -128,7 +113,7 @@ task createDockerfile(type: com.bmuschko.gradle.docker.tasks.image.Dockerfile, d defaultCommand "sh", "-c", "java -Dcorda.host=\$CORDA_HOST -jar ${jar.archiveName}" } -task prepareDockerDir(type: Copy, dependsOn: [bootRepackage, createDockerfile]) { +task prepareDockerDir(type: Copy, dependsOn: [bootJar, createDockerfile]) { from jar into docker_dir } diff --git a/samples/irs-demo/web/src/main/resources/log4j2.xml b/samples/irs-demo/web/src/main/resources/log4j2.xml index 1c4164a050..8ecd6ff186 100644 --- a/samples/irs-demo/web/src/main/resources/log4j2.xml +++ b/samples/irs-demo/web/src/main/resources/log4j2.xml @@ -2,9 +2,9 @@ - logs - node-${hostName} - ${log-path}/archive + logs + node-${hostName} + ${log_path}/archive @@ -22,8 +22,8 @@ + fileName="${log_path}/${log_name}.log" + filePattern="${archive}/${log_name}.%date{yyyy-MM-dd}-%i.log.gz"> @@ -34,7 +34,7 @@ - + diff --git a/samples/network-verifier/build.gradle b/samples/network-verifier/build.gradle index 1cd1c9f4b8..29b41f8df4 100644 --- a/samples/network-verifier/build.gradle +++ b/samples/network-verifier/build.gradle @@ -1,38 +1,34 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.cordapp' apply plugin: 'net.corda.plugins.cordformation' cordapp { - info { - name "Corda Network Verifier" - vendor "R3" - targetPlatformVersion corda_platform_version.toInteger() - minimumPlatformVersion 1 - } + targetPlatformVersion corda_platform_version.toInteger() +} + +jar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } dependencies { if (System.getProperty('excludeShell') == null) { - cordaDriver "net.corda:corda-shell:$corda_release_version" + cordaDriver "net.corda:corda-shell:$corda_shell_version" } - // Cordformation needs this for the Network Bootstrapper. - runtimeOnly project(':node-api') - // Cordformation needs a SLF4J implementation when executing the Network - // Bootstrapper, but Log4J doesn't shutdown completely from within Gradle. - // Use a much simpler SLF4J implementation here instead. - cordaRuntime "org.slf4j:slf4j-simple:$slf4j_version" + cordaBootstrapper "org.slf4j:slf4j-simple:$slf4j_version" + cordaBootstrapper project(":node-api") // Corda integration dependencies - cordaRuntime project(path: ":node:capsule", configuration: 'runtimeArtifacts') + corda project(path: ":node:capsule", configuration: 'runtimeArtifacts') + corda project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts') cordapp project(':samples:network-verifier:contracts') cordapp project(':samples:network-verifier:workflows') } -def nodeTask = tasks.getByPath(':node:capsule:assemble') -task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) { - ext.rpcUsers = [['username': "default", 'password': "default", 'permissions': [ 'ALL' ]]] +configurations.cordaCordapp.canBeResolved = true +task deployNodes(type: net.corda.plugins.Cordform) { + def users = [['username': "default", 'password': "default", 'permissions': [ 'ALL' ]]] nodeDefaults{ projectCordapp { deploy = false @@ -56,8 +52,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) node { name "O=Bank A,L=London,C=GB" p2pPort 10005 - cordapps = [] - rpcUsers = ext.rpcUsers + rpcUsers = users rpcSettings { port 10007 adminPort 10008 @@ -67,8 +62,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) node { name "O=Bank B,L=New York,C=US" p2pPort 10009 - cordapps = [] - rpcUsers = ext.rpcUsers + rpcUsers = users rpcSettings { port 10011 adminPort 10012 diff --git a/samples/network-verifier/contracts/build.gradle b/samples/network-verifier/contracts/build.gradle index 5a4013e8dd..ab7c8313d1 100644 --- a/samples/network-verifier/contracts/build.gradle +++ b/samples/network-verifier/contracts/build.gradle @@ -1,10 +1,10 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.cordapp' description 'Corda Network Verifier - Contracts' dependencies { - cordaCompile project(':core') + cordaProvided project(':core') } cordapp { @@ -20,4 +20,4 @@ cordapp { jar { baseName 'corda-network-verifier-contracts' -} \ No newline at end of file +} diff --git a/samples/network-verifier/workflows/build.gradle b/samples/network-verifier/workflows/build.gradle index 0f0c1c5bff..57498f7a81 100644 --- a/samples/network-verifier/workflows/build.gradle +++ b/samples/network-verifier/workflows/build.gradle @@ -1,14 +1,16 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.cordapp' description 'Corda Network Verifier - Workflows' dependencies { - cordaCompile project(':core') + cordaProvided project(':core') cordapp project(':samples:network-verifier:contracts') - testCompile project(":test-utils") - testCompile "junit:junit:$junit_version" + implementation "co.paralleluniverse:quasar-core:$quasar_version" + + testImplementation project(":core-test-utils") + testImplementation "junit:junit:$junit_version" } cordapp { @@ -24,4 +26,4 @@ cordapp { jar { baseName 'corda-network-verifier-workflows' -} \ No newline at end of file +} diff --git a/samples/notary-demo/build.gradle b/samples/notary-demo/build.gradle index e448345573..f5c22ffcd0 100644 --- a/samples/notary-demo/build.gradle +++ b/samples/notary-demo/build.gradle @@ -1,44 +1,38 @@ import net.corda.plugins.Cordform -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' apply plugin: 'net.corda.plugins.cordapp' apply plugin: 'net.corda.plugins.cordformation' cordapp { - info { - name "Corda Notary Demo" - vendor "R3" - targetPlatformVersion corda_platform_version.toInteger() - minimumPlatformVersion 1 - } + targetPlatformVersion corda_platform_version.toInteger() } dependencies { if (System.getProperty('excludeShell') == null) { - cordaDriver "net.corda:corda-shell:$corda_release_version" + cordaDriver "net.corda:corda-shell:$corda_shell_version" } - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - cordaCompile project(':client:rpc') - // Corda integration dependencies - cordaRuntime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - // Cordformation needs a SLF4J implementation when executing the Network - // Bootstrapper, but Log4J doesn't shutdown completely from within Gradle. - // Use a much simpler SLF4J implementation here instead. - cordaRuntime "org.slf4j:slf4j-simple:$slf4j_version" + cordaProvided project(':core') + cordaProvided project(':client:rpc') + + cordaBootstrapper "org.slf4j:slf4j-simple:$slf4j_version" + cordaBootstrapper project(":node-api") + + // Corda integration dependencies + corda project(path: ":node:capsule", configuration: 'runtimeArtifacts') + corda project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts') // Notary implementations cordapp project(':samples:notary-demo:contracts') cordapp project(':samples:notary-demo:workflows') } -def nodeTask = tasks.getByPath(':node:capsule:assemble') -def webTask = tasks.getByPath(':testing:testserver:testcapsule::assemble') - task deployNodes(dependsOn: ['deployNodesSingle', 'deployNodesRaft', 'deployNodesBFT', 'deployNodesCustom']) -task deployNodesSingle(type: Cordform, dependsOn: ['jar', nodeTask, webTask]) { +configurations.cordaCordapp.canBeResolved = true +task deployNodesSingle(type: Cordform) { directory file("$buildDir/nodes/nodesSingle") nodeDefaults { projectCordapp { @@ -80,7 +74,7 @@ task deployNodesSingle(type: Cordform, dependsOn: ['jar', nodeTask, webTask]) { } } -task deployNodesCustom(type: Cordform, dependsOn: ['jar', nodeTask, webTask]) { +task deployNodesCustom(type: Cordform) { directory file("$buildDir/nodes/nodesCustom") nodeDefaults { projectCordapp { @@ -123,7 +117,7 @@ task deployNodesCustom(type: Cordform, dependsOn: ['jar', nodeTask, webTask]) { } } -task deployNodesRaft(type: Cordform, dependsOn: ['jar', nodeTask, webTask]) { +task deployNodesRaft(type: Cordform) { directory file("$buildDir/nodes/nodesRaft") nodeDefaults { projectCordapp { @@ -200,7 +194,7 @@ task deployNodesRaft(type: Cordform, dependsOn: ['jar', nodeTask, webTask]) { } } -task deployNodesBFT(type: Cordform, dependsOn: ['jar', nodeTask, webTask]) { +task deployNodesBFT(type: Cordform) { def clusterAddresses = ["localhost:11000", "localhost:11010", "localhost:11020", "localhost:11030"] directory file("$buildDir/nodes/nodesBFT") nodeDefaults { diff --git a/samples/notary-demo/contracts/build.gradle b/samples/notary-demo/contracts/build.gradle index 584ed6fee5..66c6655aa4 100644 --- a/samples/notary-demo/contracts/build.gradle +++ b/samples/notary-demo/contracts/build.gradle @@ -1,10 +1,10 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.cordapp' description 'Corda Notary Demo - Contracts' dependencies { - cordaCompile project(':core') + cordaProvided project(':core') } cordapp { @@ -20,4 +20,4 @@ cordapp { jar { baseName 'corda-notary-demo-contracts' -} \ No newline at end of file +} diff --git a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/client/Notarise.kt b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/client/Notarise.kt index 711f7042fd..5b36c80c69 100644 --- a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/client/Notarise.kt +++ b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/client/Notarise.kt @@ -13,6 +13,7 @@ import net.corda.notarydemo.flows.DummyIssueAndMove import net.corda.notarydemo.flows.RPCStartableNotaryFlowClient import java.util.concurrent.Future +@Suppress("UNUSED_PARAMETER") fun main(args: Array) { val address = NetworkHostAndPort("localhost", 10003) println("Connecting to the recipient node ($address)") diff --git a/samples/notary-demo/workflows/build.gradle b/samples/notary-demo/workflows/build.gradle index 4113819912..3892e30bc7 100644 --- a/samples/notary-demo/workflows/build.gradle +++ b/samples/notary-demo/workflows/build.gradle @@ -1,18 +1,21 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.cordapp' description 'Corda Notary Demo - Workflows' dependencies { - cordaCompile project(':core') - cordaCompile project(':client:rpc') + cordaProvided project(':core') + cordaProvided project(':client:rpc') - // We need to compile against the Node, but also DO NOT + // We need to implementation against the Node, but also DO NOT // want the Node bundled inside the CorDapp or added to // Gradle's runtime classpath. - compileOnly project(':node') + cordaProvided project(':node') + cordaProvided project(':node-api') cordapp project(':samples:notary-demo:contracts') + + implementation "co.paralleluniverse:quasar-core:$quasar_version" } cordapp { @@ -28,4 +31,5 @@ cordapp { jar { baseName 'corda-notary-demo-workflows' -} \ No newline at end of file + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} diff --git a/samples/simm-valuation-demo/build.gradle b/samples/simm-valuation-demo/build.gradle index 0609747f93..db7d765146 100644 --- a/samples/simm-valuation-demo/build.gradle +++ b/samples/simm-valuation-demo/build.gradle @@ -4,7 +4,7 @@ allprojects { } } -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordapp' @@ -20,72 +20,80 @@ sourceSets { } } +compileKotlin.dependsOn(":samples:simm-valuation-demo:contracts-states:shrink") + configurations { - integrationTestCompile.extendsFrom testCompile + integrationTestImplementation.extendsFrom testImplementation integrationTestRuntimeOnly.extendsFrom testRuntimeOnly } dependencies { if (System.getProperty('excludeShell') == null) { - cordaDriver "net.corda:corda-shell:$corda_release_version" + cordaDriver "net.corda:corda-shell:$corda_shell_version" } - cordaCompile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + + implementation project(':core-test-utils') + // The SIMM demo CorDapp depends upon Cash CorDapp features cordapp project(':finance:contracts') cordapp project(':finance:workflows') cordapp project(path: ':samples:simm-valuation-demo:contracts-states', configuration: 'shrinkArtifacts') cordapp project(':samples:simm-valuation-demo:flows') - // Cordformation needs a SLF4J implementation when executing the Network - // Bootstrapper, but Log4J doesn't shutdown completely from within Gradle. - // Use a much simpler SLF4J implementation here instead. - cordaRuntime "org.slf4j:slf4j-simple:$slf4j_version" + cordaBootstrapper "org.slf4j:slf4j-simple:$slf4j_version" + cordaBootstrapper project(":node-api") // Corda integration dependencies - cordaRuntime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - cordaRuntime project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts') - cordaCompile project(':core') - cordaCompile(project(':testing:testserver')) { + corda project(path: ":node:capsule", configuration: 'runtimeArtifacts') + corda project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts') + + cordaProvided project(':core') + cordaProvided(project(':testing:testserver')) { exclude group: "org.apache.logging.log4j" } // Javax is required for webapis - compile "org.glassfish.jersey.core:jersey-server:$jersey_version" + implementation "org.glassfish.jersey.core:jersey-server:$jersey_version" + implementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version" // Cordapp dependencies // Specify your cordapp's dependencies below, including dependent cordapps - compile "com.opengamma.strata:strata-basics:$strata_version" - compile "com.opengamma.strata:strata-product:$strata_version" - compile "com.opengamma.strata:strata-data:$strata_version" - compile "com.opengamma.strata:strata-calc:$strata_version" - compile "com.opengamma.strata:strata-pricer:$strata_version" - compile "com.opengamma.strata:strata-report:$strata_version" - compile "com.opengamma.strata:strata-market:$strata_version" - compile "com.opengamma.strata:strata-collect:$strata_version" - compile "com.opengamma.strata:strata-loader:$strata_version" - compile "com.opengamma.strata:strata-math:$strata_version" + implementation "com.opengamma.strata:strata-basics:$strata_version" + implementation "com.opengamma.strata:strata-product:$strata_version" + implementation "com.opengamma.strata:strata-data:$strata_version" + implementation "com.opengamma.strata:strata-calc:$strata_version" + implementation "com.opengamma.strata:strata-pricer:$strata_version" + implementation "com.opengamma.strata:strata-report:$strata_version" + implementation "com.opengamma.strata:strata-market:$strata_version" + implementation "com.opengamma.strata:strata-collect:$strata_version" + implementation "com.opengamma.strata:strata-loader:$strata_version" + implementation "com.opengamma.strata:strata-math:$strata_version" // Test dependencies - testCompile project(':node-driver') + testImplementation project(':core') + testImplementation project(':node-driver') + testImplementation project(':core-test-utils') + testImplementation project(':test-utils') testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" + testImplementation "org.assertj:assertj-core:$assertj_version" + testImplementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile "org.assertj:assertj-core:$assertj_version" } jar { // A CorDapp does not configure the Node's logging! exclude "**/log4j2*.xml" + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } -def nodeTask = tasks.getByPath(':node:capsule:assemble') -def webTask = tasks.getByPath(':testing:testserver:testcapsule::assemble') -task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, webTask]) { +configurations.cordaCordapp.canBeResolved = true +task deployNodes(type: net.corda.plugins.Cordform) { directory file("$buildDir/nodes") nodeDefaults { cordapp project(':finance:contracts') diff --git a/samples/simm-valuation-demo/contracts-states/build.gradle b/samples/simm-valuation-demo/contracts-states/build.gradle index 3bb992cf4b..8cb0806485 100644 --- a/samples/simm-valuation-demo/contracts-states/build.gradle +++ b/samples/simm-valuation-demo/contracts-states/build.gradle @@ -1,10 +1,15 @@ +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.cordapp' def javaHome = System.getProperty('java.home') def shrinkJar = file("$buildDir/libs/${project.name}-${project.version}-tiny.jar") -import java.security.NoSuchAlgorithmException + +import net.corda.plugins.SignJar +import proguard.gradle.ProGuardTask + import java.security.MessageDigest +import java.security.NoSuchAlgorithmException static String sha256(File jarFile) throws FileNotFoundException, NoSuchAlgorithmException { InputStream input = new FileInputStream(jarFile) @@ -45,24 +50,23 @@ configurations { } dependencies { - cordaCompile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - // The SIMM demo CorDapp depends upon Cash CorDapp features cordapp project(':finance:contracts') // Corda integration dependencies - cordaCompile project(':core') + cordaProvided project(':core') // Cordapp dependencies // Specify your cordapp's dependencies below, including dependent cordapps - compile "com.opengamma.strata:strata-product:$strata_version" - compile "com.opengamma.strata:strata-market:$strata_version" + implementation "com.opengamma.strata:strata-product:$strata_version" + implementation "com.opengamma.strata:strata-market:$strata_version" } -def cordappDependencies = file("${sourceSets['main'].output.resourcesDir}/META-INF/Cordapp-Dependencies") -task generateDependencies { +configurations.cordapp.canBeResolved = true +tasks.register('generateDependencies') { dependsOn project(':finance:contracts').tasks.jar + def cordappDependencies = file("${sourceSets.main.output.resourcesDir}/META-INF/Cordapp-Dependencies") inputs.files(configurations.cordapp) outputs.files(cordappDependencies) doLast { @@ -74,22 +78,18 @@ task generateDependencies { } } processResources.finalizedBy generateDependencies +jar.dependsOn generateDependencies jar { - classifier = 'fat' + // Test CorDapp filters out *-tests.jar. We only want the shrinked jar not this one. + archiveClassifier = 'tests' } -import proguard.gradle.ProGuardTask -task shrink(type: ProGuardTask) { +tasks.register('shrink', ProGuardTask) { injars jar outjars shrinkJar - if (JavaVersion.current().isJava9Compatible()) { - libraryjars "$javaHome/jmods" - } else { - libraryjars "$javaHome/lib/rt.jar" - libraryjars "$javaHome/lib/jce.jar" - } + libraryjars "$javaHome/jmods" configurations.runtimeClasspath.forEach { libraryjars it.path, filter: '!META-INF/versions/**' } @@ -109,18 +109,18 @@ task shrink(type: ProGuardTask) { verbose // These are our CorDapp classes, so don't change these. - keep 'class net.corda.vega.** { *; }', includedescriptorclasses:true + keep 'class net.corda.vega.** { *; }', includedescriptorclasses: true // Until CorDapps are isolated from each other, we need to ensure that the // versions of the classes that this CorDapp needs are still usable by other // CorDapps. Unfortunately, this means that we cannot shrink them as much as // we'd like to. - keepclassmembers 'class com.opengamma.strata.** { *; }', includedescriptorclasses:true - keepclassmembers 'class com.google.** { *; }', includedescriptorclasses:true - keepclassmembers 'class org.joda.** { *; }', includedescriptorclasses:true + keepclassmembers 'class com.opengamma.strata.** { *; }', includedescriptorclasses: true + keepclassmembers 'class com.google.** { *; }', includedescriptorclasses: true + keepclassmembers 'class org.joda.** { *; }', includedescriptorclasses: true } -task sign(type: net.corda.plugins.SignJar) { +tasks.register('sign', SignJar) { inputJars shrink } @@ -128,5 +128,5 @@ jar.finalizedBy shrink shrink.finalizedBy sign artifacts { - shrinkArtifacts file: sign.outputJars.singleFile, name: project.name, type: 'jar', extension: 'jar', classifier: 'tiny', builtBy: sign + shrinkArtifacts shrinkJar } diff --git a/samples/simm-valuation-demo/flows/build.gradle b/samples/simm-valuation-demo/flows/build.gradle index 46036b5b15..5aab71f79f 100644 --- a/samples/simm-valuation-demo/flows/build.gradle +++ b/samples/simm-valuation-demo/flows/build.gradle @@ -1,3 +1,6 @@ +import net.corda.plugins.SignJar + +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordapp' @@ -14,33 +17,40 @@ cordapp { vendor "R3" licence "Open Source (Apache 2)" } + signing { + enabled false + } } dependencies { - cordaCompile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - // The SIMM demo CorDapp depends upon Cash CorDapp features cordapp project(':finance:workflows') cordapp project(':finance:contracts') - cordapp project(path: ':samples:simm-valuation-demo:contracts-states', configuration: 'shrinkArtifacts') + cordapp project(':samples:simm-valuation-demo:contracts-states') // Corda integration dependencies - cordaCompile project(':core') + cordaProvided project(':core') // Cordapp dependencies // Specify your cordapp's dependencies below, including dependent cordapps - compile "com.opengamma.strata:strata-basics:$strata_version" - compile "com.opengamma.strata:strata-product:$strata_version" - compile "com.opengamma.strata:strata-data:$strata_version" - compile "com.opengamma.strata:strata-calc:$strata_version" - compile "com.opengamma.strata:strata-pricer:$strata_version" - compile "com.opengamma.strata:strata-report:$strata_version" - compile "com.opengamma.strata:strata-market:$strata_version" - compile "com.opengamma.strata:strata-collect:$strata_version" - compile "com.opengamma.strata:strata-loader:$strata_version" - compile "com.opengamma.strata:strata-math:$strata_version" + implementation "com.opengamma.strata:strata-basics:$strata_version" + implementation "com.opengamma.strata:strata-product:$strata_version" + implementation "com.opengamma.strata:strata-data:$strata_version" + implementation "com.opengamma.strata:strata-calc:$strata_version" + implementation "com.opengamma.strata:strata-pricer:$strata_version" + implementation "com.opengamma.strata:strata-report:$strata_version" + implementation "com.opengamma.strata:strata-market:$strata_version" + implementation "com.opengamma.strata:strata-collect:$strata_version" + implementation "com.opengamma.strata:strata-loader:$strata_version" + implementation "com.opengamma.strata:strata-math:$strata_version" } jar { duplicatesStrategy = DuplicatesStrategy.EXCLUDE -} \ No newline at end of file +} + +tasks.register('sign', SignJar) { + inputJars jar +} + +jar.finalizedBy sign \ No newline at end of file diff --git a/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/analytics/example/OGSwapPricingCcpExample.kt b/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/analytics/example/OGSwapPricingCcpExample.kt index 60169d26a9..768a649a6b 100644 --- a/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/analytics/example/OGSwapPricingCcpExample.kt +++ b/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/analytics/example/OGSwapPricingCcpExample.kt @@ -32,11 +32,11 @@ import com.opengamma.strata.product.common.BuySell import com.opengamma.strata.product.swap.type.FixedIborSwapConventions import com.opengamma.strata.report.ReportCalculationResults import com.opengamma.strata.report.trade.TradeReport -import net.corda.core.internal.div -import net.corda.core.internal.exists import net.corda.core.internal.toPath import java.nio.file.Path import java.time.LocalDate +import kotlin.io.path.Path +import kotlin.io.path.exists /** * Example to illustrate using the engine to price a swap. @@ -65,8 +65,8 @@ class SwapPricingCcpExample { */ private val resourcesUri = run { // Find src/main/resources by walking up the directory tree starting at a classpath root: - var module = javaClass.getResource("/").toPath() - val relative = "src" / "main" / "resources" + var module = javaClass.getResource("/")!!.toPath() + val relative = Path("src", "main", "resources") var path: Path while (true) { path = module.resolve(relative) diff --git a/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/analytics/example/OGSwapPricingExample.kt b/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/analytics/example/OGSwapPricingExample.kt index 9f224e6ffd..aa91c6c5f4 100644 --- a/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/analytics/example/OGSwapPricingExample.kt +++ b/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/analytics/example/OGSwapPricingExample.kt @@ -51,6 +51,7 @@ import java.time.LocalDate */ +@Suppress("UNUSED_PARAMETER") fun main(args: Array) { val swapPricingExample = SwapPricingExample() swapPricingExample.main() diff --git a/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt b/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt index 2424101214..1ecec4aec4 100644 --- a/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt +++ b/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt @@ -131,7 +131,7 @@ object SimmFlow { val valuer = serviceHub.identityService.wellKnownPartyFromAnonymous(state.valuer) require(valuer != null) { "Valuer party must be known to this node" } - val valuation = agreeValuation(portfolio, valuationDate, valuer!!) + val valuation = agreeValuation(portfolio, valuationDate, valuer) val update = PortfolioState.Update(valuation = valuation) return subFlow(StateRevisionFlowRequester(otherPartySession, stateRef, update)).state.data } diff --git a/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/flows/SimmRevaluation.kt b/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/flows/SimmRevaluation.kt index 599e9d4345..edbbabca2f 100644 --- a/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/flows/SimmRevaluation.kt +++ b/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/flows/SimmRevaluation.kt @@ -25,7 +25,7 @@ object SimmRevaluation { if (ourIdentity == curState.participants[0]) { val otherParty = serviceHub.identityService.wellKnownPartyFromAnonymous(curState.participants[1]) require(otherParty != null) { "Other party must be known by this node" } - subFlow(SimmFlow.Requester(otherParty!!, valuationDate, stateAndRef)) + subFlow(SimmFlow.Requester(otherParty, valuationDate, stateAndRef)) } } } diff --git a/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/portfolio/Portfolio.kt b/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/portfolio/Portfolio.kt index f61995da92..79a8246109 100644 --- a/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/portfolio/Portfolio.kt +++ b/samples/simm-valuation-demo/flows/src/main/kotlin/net/corda/vega/portfolio/Portfolio.kt @@ -1,8 +1,9 @@ package net.corda.vega.portfolio -import net.corda.core.contracts.* +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.StateAndRef +import net.corda.core.contracts.StateRef import net.corda.core.identity.Party -import net.corda.core.internal.sum import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.vaultQueryBy import net.corda.core.node.services.vault.QueryCriteria @@ -23,7 +24,7 @@ data class Portfolio(private val tradeStateAndRefs: List>, val swaps: List by lazy { trades.map { it.swap } } val refs: List by lazy { tradeStateAndRefs.map { it.ref } } - fun getNotionalForParty(party: Party): BigDecimal = trades.map { it.swap.getLegForParty(party).notional }.sum() + fun getNotionalForParty(party: Party): BigDecimal = trades.sumOf { it.swap.getLegForParty(party).notional } fun update(curTrades: List>): Portfolio { return copy(tradeStateAndRefs = curTrades) diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt index a8ffecff93..e0f2f9a7b0 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt @@ -1,6 +1,15 @@ package net.corda.vega.api import com.opengamma.strata.basics.currency.MultiCurrencyAmount +import jakarta.ws.rs.Consumes +import jakarta.ws.rs.GET +import jakarta.ws.rs.POST +import jakarta.ws.rs.PUT +import jakarta.ws.rs.Path +import jakarta.ws.rs.PathParam +import jakarta.ws.rs.Produces +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response import net.corda.core.contracts.StateAndRef import net.corda.core.utilities.parsePublicKeyBase58 import net.corda.core.utilities.toBase58String @@ -24,9 +33,6 @@ import net.corda.vega.portfolio.toStateAndRef import java.time.LocalDate import java.time.LocalDateTime import java.time.ZoneId -import javax.ws.rs.* -import javax.ws.rs.core.MediaType -import javax.ws.rs.core.Response //TODO: Change import namespaces vega -> .... @@ -135,7 +141,7 @@ class PortfolioApi(val rpc: CordaRPCOps) { it.toView(ownParty, latestPortfolioStateData?.portfolio?.toStateAndRef(rpc)?.toPortfolio(), PVs?.get(it.id.second) ?: MultiCurrencyAmount.empty(), - IMs?.get(it.id.second) ?: InitialMarginTriple.zero() + IMs?.get(it.id.second) ?: InitialMarginTriple(0.0, 0.0, 0.0) ) }).build() } diff --git a/samples/simm-valuation-demo/src/main/resources/log4j2.xml b/samples/simm-valuation-demo/src/main/resources/log4j2.xml index 00795edc45..27a733cff5 100644 --- a/samples/simm-valuation-demo/src/main/resources/log4j2.xml +++ b/samples/simm-valuation-demo/src/main/resources/log4j2.xml @@ -2,9 +2,9 @@ - build/logs - simm-valuation-${hostName} - ${log-path}/archive + build/logs + simm-valuation-${hostName} + ${log_path}/archive @@ -22,8 +22,8 @@ + fileName="${log_path}/${log_name}.log" + filePattern="${archive}/${log_name}.%date{yyyy-MM-dd}-%i.log.gz"> @@ -34,7 +34,7 @@ - + diff --git a/samples/simm-valuation-demo/src/test/kotlin/net/corda/vega/Main.kt b/samples/simm-valuation-demo/src/test/kotlin/net/corda/vega/Main.kt index b75102c013..9a64fbd199 100644 --- a/samples/simm-valuation-demo/src/test/kotlin/net/corda/vega/Main.kt +++ b/samples/simm-valuation-demo/src/test/kotlin/net/corda/vega/Main.kt @@ -12,6 +12,7 @@ import net.corda.testing.driver.driver * This does not start any tests but has the nodes running in preparation for a live web demo or to receive commands * via the web api. */ +@Suppress("UNUSED_PARAMETER") fun main(args: Array) { driver(DriverParameters(waitForAllNodesToFinish = true)) { val (nodeA, nodeB, nodeC) = listOf( diff --git a/samples/trader-demo/build.gradle b/samples/trader-demo/build.gradle index 0b5272f7a7..30554f4184 100644 --- a/samples/trader-demo/build.gradle +++ b/samples/trader-demo/build.gradle @@ -1,16 +1,11 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordapp' apply plugin: 'net.corda.plugins.cordformation' cordapp { - info { - name "Trader Demo" - vendor "R3" - targetPlatformVersion corda_platform_version.toInteger() - minimumPlatformVersion 1 - } + targetPlatformVersion corda_platform_version.toInteger() } sourceSets { @@ -27,42 +22,44 @@ sourceSets { } configurations { - integrationTestCompile.extendsFrom testCompile + integrationTestImplementation.extendsFrom testImplementation integrationTestRuntimeOnly.extendsFrom testRuntimeOnly } dependencies { if (System.getProperty('excludeShell') == null) { - cordaDriver "net.corda:corda-shell:$corda_release_version" + cordaDriver "net.corda:corda-shell:$corda_shell_version" } - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - compile "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" - cordaCompile project(':client:rpc') - // Cordformation needs a SLF4J implementation when executing the Network - // Bootstrapper, but Log4J doesn't shutdown completely from within Gradle. - // Use a much simpler SLF4J implementation here instead. - cordaRuntime "org.slf4j:slf4j-simple:$slf4j_version" + cordaProvided project(':core') + cordaProvided project(':node') + cordaProvided project(':client:rpc') + cordaProvided project(':core-test-utils') + implementation project(':test-utils') - // We only need this for its DUMMY_BANK constants, and - // DO NOT want it added to Gradle's runtime classpath. - compileOnly project(':test-utils') + implementation "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" + + cordaBootstrapper "org.slf4j:slf4j-simple:$slf4j_version" + cordaBootstrapper project(":node-api") + + // Corda integration dependencies + corda project(path: ":node:capsule", configuration: 'runtimeArtifacts') // The trader demo CorDapp depends upon Cash CorDapp features cordapp project(':finance:contracts') cordapp project(':finance:workflows') cordapp project(':samples:trader-demo:workflows-trader') - // Corda integration dependencies - cordaRuntime project(path: ":node:capsule", configuration: 'runtimeArtifacts') + implementation "org.slf4j:slf4j-api:$slf4j_version" - testCompile "org.slf4j:slf4j-simple:$slf4j_version" - testCompile(project(':node-driver')) { + testImplementation "org.slf4j:slf4j-simple:$slf4j_version" + testImplementation(project(':node-driver')) { // We already have a SLF4J implementation on our runtime classpath, // and we don't need another one. - exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j-impl' + exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j2-impl' } - + + testImplementation "io.reactivex:rxjava:$rxjava_version" testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" @@ -70,7 +67,7 @@ dependencies { testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile "org.assertj:assertj-core:$assertj_version" + testImplementation "org.assertj:assertj-core:$assertj_version" } task integrationTest(type: Test, dependsOn: []) { @@ -78,9 +75,9 @@ task integrationTest(type: Test, dependsOn: []) { classpath = sourceSets.integrationTest.runtimeClasspath } -def nodeTask = tasks.getByPath(':node:capsule:assemble') -task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) { - ext.rpcUsers = [['username': "demo", 'password': "demo", 'permissions': ["ALL"]]] +configurations.cordaCordapp.canBeResolved = true +task deployNodes(type: net.corda.plugins.Cordform) { + def users = [['username': "demo", 'password': "demo", 'permissions': ["ALL"]]] nodeDefaults { projectCordapp { deploy = false // TODO This is a bug, project cordapp should be disabled if no cordapp plugin is applied. @@ -105,7 +102,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) node { name "O=Bank A,L=London,C=GB" p2pPort 10005 - rpcUsers = ext.rpcUsers + rpcUsers = users rpcSettings { address "localhost:10006" adminAddress "localhost:10007" @@ -115,7 +112,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) node { name "O=Bank B,L=New York,C=US" p2pPort 10008 - rpcUsers = ext.rpcUsers + rpcUsers = users rpcSettings { address "localhost:10009" adminAddress "localhost:10010" @@ -125,7 +122,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) node { name "O=BankOfCorda,L=New York,C=US" p2pPort 10011 - rpcUsers = ext.rpcUsers + rpcUsers = users rpcSettings { address "localhost:10012" adminAddress "localhost:10013" @@ -137,7 +134,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) node { name "O=NonLogging Bank,L=London,C=GB" p2pPort 10025 - rpcUsers = ext.rpcUsers + rpcUsers = users rpcSettings { address "localhost:10026" adminAddress "localhost:10027" @@ -147,6 +144,10 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask]) } } +jar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + idea { module { downloadJavadoc = true // defaults to false diff --git a/samples/trader-demo/workflows-trader/build.gradle b/samples/trader-demo/workflows-trader/build.gradle index af65fecbaf..ec0662e03a 100644 --- a/samples/trader-demo/workflows-trader/build.gradle +++ b/samples/trader-demo/workflows-trader/build.gradle @@ -1,17 +1,20 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordapp' dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - cordaCompile project(':core') + cordaProvided project(':core') // The trader demo CorDapp depends upon Cash CorDapp features cordapp project(':finance:contracts') cordapp project(':finance:workflows') - testCompile project(':node-driver') - + testImplementation project(':node') + testImplementation project(':node-driver') + testImplementation project(':test-utils') + testImplementation project(':core-test-utils') + + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" @@ -19,7 +22,7 @@ dependencies { testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile "org.assertj:assertj-core:$assertj_version" + testImplementation "org.assertj:assertj-core:$assertj_version" } jar { diff --git a/samples/trader-demo/workflows-trader/src/test/kotlin/net/corda/traderdemo/Main.kt b/samples/trader-demo/workflows-trader/src/test/kotlin/net/corda/traderdemo/Main.kt index 86153de552..ab6f1e429c 100644 --- a/samples/trader-demo/workflows-trader/src/test/kotlin/net/corda/traderdemo/Main.kt +++ b/samples/trader-demo/workflows-trader/src/test/kotlin/net/corda/traderdemo/Main.kt @@ -1,6 +1,5 @@ package net.corda.traderdemo -import net.corda.core.internal.div import net.corda.finance.flows.CashIssueFlow import net.corda.node.services.Permissions.Companion.all import net.corda.node.services.Permissions.Companion.startFlow @@ -12,18 +11,19 @@ import net.corda.testing.driver.driver import net.corda.testing.node.User import net.corda.traderdemo.flow.CommercialPaperIssueFlow import net.corda.traderdemo.flow.SellerFlow +import kotlin.io.path.Path /** * This file is exclusively for being able to run your nodes through an IDE (as opposed to running deployNodes) * Do not use in a production environment. */ -fun main(args: Array) { +fun main() { val permissions = setOf( startFlow(), startFlow(), all()) val demoUser = listOf(User("demo", "demo", permissions)) - driver(DriverParameters(driverDirectory = "build" / "trader-demo-nodes", waitForAllNodesToFinish = true)) { + driver(DriverParameters(driverDirectory = Path("build", "trader-demo-nodes"), waitForAllNodesToFinish = true)) { val user = User("user1", "test", permissions = setOf(startFlow(), startFlow(), startFlow())) diff --git a/serialization-1.2/README.md b/serialization-1.2/README.md new file mode 100644 index 0000000000..58313da830 --- /dev/null +++ b/serialization-1.2/README.md @@ -0,0 +1,5 @@ +This is a Kotlin 1.2 version of the `serialization` module, which is consumed by the `verifier` module, for verifying contracts written in +Kotlin 1.2. This is just a "shell" module which uses the existing the code in `serialization` and compiles it with the 1.2 compiler. + +To allow `serialization` to benefit from new APIs introduced since 1.2, those APIs much be copied into the `core-1.2` module with the same +`kotlin` package. diff --git a/serialization-1.2/build.gradle b/serialization-1.2/build.gradle new file mode 100644 index 0000000000..842f3897cb --- /dev/null +++ b/serialization-1.2/build.gradle @@ -0,0 +1,39 @@ +apply plugin: "corda.kotlin-1.2" +apply plugin: "corda.common-publishing" + +description 'Corda serialization built with Kotlin 1.2' + +sourceSets { + main { + java.srcDir("../serialization/src/main/java") + kotlin.srcDir("../serialization/src/main/kotlin") + } +} + +dependencies { + implementation project(":core-1.2") + // Use the same dependencies as serialization (minus Kotlin and core) + implementation(project(path: ":serialization", configuration: "resolvableImplementation")) { + exclude(module: "core") + exclude(group: "org.jetbrains.kotlin") + } + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_1_2_version" +} + +jar { + archiveBaseName = 'corda-serialization-1.2' +} + +tasks.withType(Javadoc).configureEach { + enabled = false +} + +// TODO Don't publish publicly as it's only needed by the `verifier` module which consumes this into a fat jar. +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-serialization-1.2' + from components.java + } + } +} diff --git a/serialization-tests/build.gradle b/serialization-tests/build.gradle index 0e2e82a1b8..7a9f0ed86e 100644 --- a/serialization-tests/build.gradle +++ b/serialization-tests/build.gradle @@ -1,24 +1,37 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' // Any serialization tests that require further Corda dependencies (other than `core`) should be added to this module. description 'Corda serialization tests' dependencies { - testCompile project(":serialization") - testCompile project(path: ':serialization', configuration: 'testArtifacts') - testCompile project(':node-driver') + testImplementation project(":serialization") + testImplementation project(path: ':serialization', configuration: 'testArtifacts') + testImplementation project(':node') + testImplementation project(':node-driver') + testImplementation project(':node-api') + testImplementation project(':finance:contracts') + testImplementation project(':client:rpc') + testImplementation project(':core-test-utils') + testImplementation project(':test-utils') + + // Bouncy castle support needed for X509 certificate manipulation + testImplementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}" + testImplementation "org.bouncycastle:bcpkix-lts8on:${bouncycastle_version}" testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" + testImplementation "com.esotericsoftware:kryo:$kryo_version" + testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - - testCompile "org.assertj:assertj-core:$assertj_version" - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + + testImplementation "org.assertj:assertj-core:$assertj_version" + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + testImplementation "org.apache.commons:commons-lang3:$commons_lang3_version" } configurations { - testArtifacts.extendsFrom testRuntimeClasspath + testArtifacts.extendsFrom testRuntimeOnlyClasspath } diff --git a/serialization-tests/src/test/kotlin/net/corda/serialization/internal/CordaClassResolverTests.kt b/serialization-tests/src/test/kotlin/net/corda/serialization/internal/CordaClassResolverTests.kt index 1fc4023ff9..386d2abe7f 100644 --- a/serialization-tests/src/test/kotlin/net/corda/serialization/internal/CordaClassResolverTests.kt +++ b/serialization-tests/src/test/kotlin/net/corda/serialization/internal/CordaClassResolverTests.kt @@ -1,35 +1,40 @@ package net.corda.serialization.internal -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.Serializer import com.esotericsoftware.kryo.io.Input import com.esotericsoftware.kryo.io.Output import com.esotericsoftware.kryo.util.DefaultClassResolver import com.esotericsoftware.kryo.util.MapReferenceResolver -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.verify -import com.nhaarman.mockito_kotlin.whenever -import net.corda.core.contracts.TransactionVerificationException +import net.corda.core.contracts.TransactionVerificationException.UntrustedAttachmentsException import net.corda.core.crypto.SecureHash import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER +import net.corda.core.node.services.AttachmentId import net.corda.core.node.services.AttachmentStorage import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.internal.AttachmentsClassLoader import net.corda.core.serialization.internal.CheckpointSerializationContext +import net.corda.coretesting.internal.rigorousMock +import net.corda.node.services.attachments.NodeAttachmentTrustCalculator +import net.corda.node.services.persistence.toInternal import net.corda.nodeapi.internal.serialization.kryo.CordaClassResolver import net.corda.nodeapi.internal.serialization.kryo.CordaKryo -import net.corda.node.services.attachments.NodeAttachmentTrustCalculator import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.internal.TestingNamedCacheFactory -import net.corda.coretesting.internal.rigorousMock -import net.corda.testing.internal.services.InternalMockAttachmentStorage import net.corda.testing.services.MockAttachmentStorage -import org.junit.Rule +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Test -import org.junit.rules.ExpectedException +import org.junit.jupiter.api.assertThrows +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.net.URL import java.sql.Connection -import java.util.* +import java.util.Collections import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertNull @@ -104,7 +109,7 @@ class DefaultSerializableSerializer : Serializer() { override fun write(kryo: Kryo, output: Output, obj: DefaultSerializable) { } - override fun read(kryo: Kryo, input: Input, type: Class): DefaultSerializable { + override fun read(kryo: Kryo, input: Input, type: Class): DefaultSerializable { return DefaultSerializable() } } @@ -114,7 +119,7 @@ class CordaClassResolverTests { val emptyListClass = listOf().javaClass val emptySetClass = setOf().javaClass val emptyMapClass = mapOf().javaClass - val ISOLATED_CONTRACTS_JAR_PATH: URL = CordaClassResolverTests::class.java.getResource("/isolated.jar") + val ISOLATED_CONTRACTS_JAR_PATH: URL = CordaClassResolverTests::class.java.getResource("/isolated.jar")!! } private val emptyWhitelistContext: CheckpointSerializationContext = CheckpointSerializationContextImpl(this.javaClass.classLoader, EmptyWhitelist, emptyMap(), true, null) @@ -125,9 +130,11 @@ class CordaClassResolverTests { CordaClassResolver(emptyWhitelistContext).getRegistration(Foo.Bar::class.java) } - @Test(expected = KryoException::class, timeout=300_000) + @Test(timeout=300_000) fun `Unannotated specialised enum does not work`() { - CordaClassResolver(emptyWhitelistContext).getRegistration(BadFood.Mud::class.java) + assertThatExceptionOfType(KryoException::class.java).isThrownBy { + CordaClassResolver(emptyWhitelistContext).getRegistration(BadFood.Mud::class.java) + } } @Test(timeout=300_000) @@ -135,9 +142,11 @@ class CordaClassResolverTests { CordaClassResolver(emptyWhitelistContext).getRegistration(Simple.Easy::class.java) } - @Test(expected = KryoException::class, timeout=300_000) + @Test(timeout=300_000) fun `Unannotated simple enum does not work`() { - CordaClassResolver(emptyWhitelistContext).getRegistration(BadSimple.Nasty::class.java) + assertThatExceptionOfType(KryoException::class.java).isThrownBy { + CordaClassResolver(emptyWhitelistContext).getRegistration(BadSimple.Nasty::class.java) + } } @Test(timeout=300_000) @@ -146,10 +155,12 @@ class CordaClassResolverTests { CordaClassResolver(emptyWhitelistContext).getRegistration(values.javaClass) } - @Test(expected = KryoException::class, timeout=300_000) + @Test(timeout=300_000) fun `Unannotated array elements do not work`() { val values = arrayOf(NotSerializable()) - CordaClassResolver(emptyWhitelistContext).getRegistration(values.javaClass) + assertThatExceptionOfType(KryoException::class.java).isThrownBy { + CordaClassResolver(emptyWhitelistContext).getRegistration(values.javaClass) + } } @Test(timeout=300_000) @@ -168,15 +179,19 @@ class CordaClassResolverTests { kryo.register(NotSerializable::class.java) } - @Test(expected = KryoException::class, timeout=300_000) + @Test(timeout=300_000) fun `Calling register method on unmodified Kryo does consult the whitelist`() { val kryo = Kryo(CordaClassResolver(emptyWhitelistContext), MapReferenceResolver()) - kryo.register(NotSerializable::class.java) + assertThatExceptionOfType(KryoException::class.java).isThrownBy { + kryo.register(NotSerializable::class.java) + } } - @Test(expected = KryoException::class, timeout=300_000) + @Test(timeout=300_000) fun `Annotation is needed without whitelisting`() { - CordaClassResolver(emptyWhitelistContext).getRegistration(NotSerializable::class.java) + assertThatExceptionOfType(KryoException::class.java).isThrownBy { + CordaClassResolver(emptyWhitelistContext).getRegistration(NotSerializable::class.java) + } } @Test(timeout=300_000) @@ -195,36 +210,54 @@ class CordaClassResolverTests { CordaClassResolver(emptyWhitelistContext).getRegistration(Integer.TYPE) } - @Test(expected = KryoException::class, timeout=300_000) + @Test(timeout=300_000) fun `Annotation does not work for custom serializable`() { - CordaClassResolver(emptyWhitelistContext).getRegistration(CustomSerializable::class.java) + assertThatExceptionOfType(KryoException::class.java).isThrownBy { + CordaClassResolver(emptyWhitelistContext).getRegistration(CustomSerializable::class.java) + } } - @Test(expected = KryoException::class, timeout=300_000) + @Test(timeout=300_000) fun `Annotation does not work in conjunction with Kryo annotation`() { - CordaClassResolver(emptyWhitelistContext).getRegistration(DefaultSerializable::class.java) + assertThatExceptionOfType(KryoException::class.java).isThrownBy { + CordaClassResolver(emptyWhitelistContext).getRegistration(DefaultSerializable::class.java) + } } - private fun importJar(storage: AttachmentStorage, uploader: String = DEPLOYED_CORDAPP_UPLOADER) = ISOLATED_CONTRACTS_JAR_PATH.openStream().use { storage.importAttachment(it, uploader, "") } + private fun importJar(storage: AttachmentStorage, uploader: String = DEPLOYED_CORDAPP_UPLOADER): AttachmentId { + return ISOLATED_CONTRACTS_JAR_PATH.openStream().use { storage.importAttachment(it, uploader, "") } + } - @Test(expected = KryoException::class, timeout=300_000) + @Test(timeout=300_000) fun `Annotation does not work in conjunction with AttachmentClassLoader annotation`() { - val storage = InternalMockAttachmentStorage(MockAttachmentStorage()) + val storage = MockAttachmentStorage().toInternal() val attachmentTrustCalculator = NodeAttachmentTrustCalculator(storage, TestingNamedCacheFactory()) val attachmentHash = importJar(storage) - val classLoader = AttachmentsClassLoader(arrayOf(attachmentHash).map { storage.openAttachment(it)!! }, testNetworkParameters(), SecureHash.zeroHash, { attachmentTrustCalculator.calculate(it) }) + val classLoader = AttachmentsClassLoader( + arrayOf(attachmentHash).map { storage.openAttachment(it)!! }, + testNetworkParameters(), + SecureHash.zeroHash, + { attachmentTrustCalculator.calculate(it) } + ) val attachedClass = Class.forName("net.corda.isolated.contracts.AnotherDummyContract", true, classLoader) - CordaClassResolver(emptyWhitelistContext).getRegistration(attachedClass) + assertThatExceptionOfType(KryoException::class.java).isThrownBy { + CordaClassResolver(emptyWhitelistContext).getRegistration(attachedClass) + } } - @Test(expected = TransactionVerificationException.UntrustedAttachmentsException::class, timeout=300_000) + @Test(timeout=300_000) fun `Attempt to load contract attachment with untrusted uploader should fail with UntrustedAttachmentsException`() { - val storage = InternalMockAttachmentStorage(MockAttachmentStorage()) + val storage = MockAttachmentStorage().toInternal() val attachmentTrustCalculator = NodeAttachmentTrustCalculator(storage, TestingNamedCacheFactory()) val attachmentHash = importJar(storage, "some_uploader") - val classLoader = AttachmentsClassLoader(arrayOf(attachmentHash).map { storage.openAttachment(it)!! }, testNetworkParameters(), SecureHash.zeroHash, { attachmentTrustCalculator.calculate(it) }) - val attachedClass = Class.forName("net.corda.isolated.contracts.AnotherDummyContract", true, classLoader) - CordaClassResolver(emptyWhitelistContext).getRegistration(attachedClass) + assertThatExceptionOfType(UntrustedAttachmentsException::class.java).isThrownBy { + AttachmentsClassLoader( + arrayOf(attachmentHash).map { storage.openAttachment(it)!! }, + testNetworkParameters(), + SecureHash.zeroHash, + { attachmentTrustCalculator.calculate(it) } + ) + } } @Test(timeout=300_000) @@ -241,16 +274,15 @@ class CordaClassResolverTests { } // Blacklist tests. Note: leave the variable public or else expected messages do not work correctly - @get:Rule - val expectedEx = ExpectedException.none()!! @Test(timeout=300_000) fun `Check blacklisted class`() { - expectedEx.expect(IllegalStateException::class.java) - expectedEx.expectMessage("Class java.util.HashSet is blacklisted, so it cannot be used in serialization.") - val resolver = CordaClassResolver(allButBlacklistedContext) - // HashSet is blacklisted. - resolver.getRegistration(HashSet::class.java) + val anException = assertThrows { + val resolver = CordaClassResolver(allButBlacklistedContext) + // HashSet is blacklisted. + resolver.getRegistration(HashSet::class.java) + } + assertEquals("Class java.util.HashSet is blacklisted, so it cannot be used in serialization.", anException.message) } @Test(timeout=300_000) @@ -323,33 +355,37 @@ class CordaClassResolverTests { @Test(timeout=300_000) fun `Check blacklisted subclass`() { - expectedEx.expect(IllegalStateException::class.java) - expectedEx.expectMessage("The superclass java.util.HashSet of net.corda.serialization.internal.CordaClassResolverTests\$SubHashSet is blacklisted, so it cannot be used in serialization.") - val resolver = CordaClassResolver(allButBlacklistedContext) - // SubHashSet extends the blacklisted HashSet. - resolver.getRegistration(SubHashSet::class.java) + val anException = assertThrows { + val resolver = CordaClassResolver(allButBlacklistedContext) + // SubHashSet extends the blacklisted HashSet. + resolver.getRegistration(SubHashSet::class.java) + } + assertEquals("The superclass java.util.HashSet of net.corda.serialization.internal.CordaClassResolverTests\$SubHashSet is blacklisted, so it cannot be used in serialization.", anException.message) } class SubSubHashSet : SubHashSet() @Test(timeout=300_000) fun `Check blacklisted subsubclass`() { - expectedEx.expect(IllegalStateException::class.java) - expectedEx.expectMessage("The superclass java.util.HashSet of net.corda.serialization.internal.CordaClassResolverTests\$SubSubHashSet is blacklisted, so it cannot be used in serialization.") - val resolver = CordaClassResolver(allButBlacklistedContext) - // SubSubHashSet extends SubHashSet, which extends the blacklisted HashSet. - resolver.getRegistration(SubSubHashSet::class.java) + val anException = assertThrows { + val resolver = CordaClassResolver(allButBlacklistedContext) + // SubSubHashSet extends SubHashSet, which extends the blacklisted HashSet. + resolver.getRegistration(SubSubHashSet::class.java) + } + assertEquals("The superclass java.util.HashSet of net.corda.serialization.internal.CordaClassResolverTests\$SubSubHashSet is blacklisted, so it cannot be used in serialization.", anException.message) + } class ConnectionImpl(private val connection: Connection) : Connection by connection @Test(timeout=300_000) fun `Check blacklisted interface impl`() { - expectedEx.expect(IllegalStateException::class.java) - expectedEx.expectMessage("The superinterface java.sql.Connection of net.corda.serialization.internal.CordaClassResolverTests\$ConnectionImpl is blacklisted, so it cannot be used in serialization.") - val resolver = CordaClassResolver(allButBlacklistedContext) - // ConnectionImpl implements blacklisted Connection. - resolver.getRegistration(ConnectionImpl::class.java) + val anException = assertThrows { + val resolver = CordaClassResolver(allButBlacklistedContext) + // ConnectionImpl implements blacklisted Connection. + resolver.getRegistration(ConnectionImpl::class.java) + } + assertEquals("The superinterface java.sql.Connection of net.corda.serialization.internal.CordaClassResolverTests\$ConnectionImpl is blacklisted, so it cannot be used in serialization.", anException.message) } interface SubConnection : Connection @@ -357,11 +393,13 @@ class CordaClassResolverTests { @Test(timeout=300_000) fun `Check blacklisted super-interface impl`() { - expectedEx.expect(IllegalStateException::class.java) - expectedEx.expectMessage("The superinterface java.sql.Connection of net.corda.serialization.internal.CordaClassResolverTests\$SubConnectionImpl is blacklisted, so it cannot be used in serialization.") - val resolver = CordaClassResolver(allButBlacklistedContext) - // SubConnectionImpl implements SubConnection, which extends the blacklisted Connection. - resolver.getRegistration(SubConnectionImpl::class.java) + val anException = assertThrows { + val resolver = CordaClassResolver(allButBlacklistedContext) + // SubConnectionImpl implements SubConnection, which extends the blacklisted Connection. + resolver.getRegistration(SubConnectionImpl::class.java) + } + assertEquals("The superinterface java.sql.Connection of net.corda.serialization.internal.CordaClassResolverTests\$SubConnectionImpl is blacklisted, so it cannot be used in serialization.", anException.message) + } @Test(timeout=300_000) @@ -376,10 +414,11 @@ class CordaClassResolverTests { @Test(timeout=300_000) fun `Check blacklist precedes CordaSerializable`() { - expectedEx.expect(IllegalStateException::class.java) - expectedEx.expectMessage("The superclass java.util.HashSet of net.corda.serialization.internal.CordaClassResolverTests\$CordaSerializableHashSet is blacklisted, so it cannot be used in serialization.") - val resolver = CordaClassResolver(allButBlacklistedContext) - // CordaSerializableHashSet is @CordaSerializable, but extends the blacklisted HashSet. - resolver.getRegistration(CordaSerializableHashSet::class.java) + val anException = assertThrows { + val resolver = CordaClassResolver(allButBlacklistedContext) + // CordaSerializableHashSet is @CordaSerializable, but extends the blacklisted HashSet. + resolver.getRegistration(CordaSerializableHashSet::class.java) + } + assertEquals("The superclass java.util.HashSet of net.corda.serialization.internal.CordaClassResolverTests\$CordaSerializableHashSet is blacklisted, so it cannot be used in serialization.", anException.message) } -} \ No newline at end of file +} diff --git a/serialization-tests/src/test/kotlin/net/corda/serialization/internal/SerializationTokenTest.kt b/serialization-tests/src/test/kotlin/net/corda/serialization/internal/SerializationTokenTest.kt index 2fc36c8976..367b1441de 100644 --- a/serialization-tests/src/test/kotlin/net/corda/serialization/internal/SerializationTokenTest.kt +++ b/serialization-tests/src/test/kotlin/net/corda/serialization/internal/SerializationTokenTest.kt @@ -3,18 +3,24 @@ package net.corda.serialization.internal import com.esotericsoftware.kryo.Kryo import com.esotericsoftware.kryo.KryoException import com.esotericsoftware.kryo.io.Output -import net.corda.core.serialization.* +import net.corda.core.serialization.SerializationToken +import net.corda.core.serialization.SerializeAsToken +import net.corda.core.serialization.SerializeAsTokenContext +import net.corda.core.serialization.SerializedBytes +import net.corda.core.serialization.SingletonSerializationToken +import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.internal.CheckpointSerializationContext import net.corda.core.serialization.internal.checkpointDeserialize import net.corda.core.serialization.internal.checkpointSerialize import net.corda.core.utilities.OpaqueBytes +import net.corda.coretesting.internal.rigorousMock import net.corda.nodeapi.internal.serialization.kryo.CordaClassResolver import net.corda.nodeapi.internal.serialization.kryo.CordaKryo import net.corda.nodeapi.internal.serialization.kryo.DefaultKryoCustomizer import net.corda.nodeapi.internal.serialization.kryo.kryoMagic -import net.corda.coretesting.internal.rigorousMock import net.corda.testing.core.internal.CheckpointSerializationEnvironmentRule import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Before import org.junit.Rule import org.junit.Test @@ -70,30 +76,35 @@ class SerializationTokenTest { assertThat(tokenizableAfter).isSameAs(tokenizableBefore) } - @Test(expected = UnsupportedOperationException::class, timeout=300_000) + @Test(timeout=300_000) fun `new token encountered after context init`() { val tokenizableBefore = UnitSerializeAsToken() val context = serializeAsTokenContext(emptyList()) val testContext = this.context.withTokenContext(context) - tokenizableBefore.checkpointSerialize(testContext) + assertThatExceptionOfType(UnsupportedOperationException::class.java).isThrownBy { + tokenizableBefore.checkpointSerialize(testContext) + } } - @Test(expected = UnsupportedOperationException::class, timeout=300_000) + @Test(timeout=300_000) fun `deserialize unregistered token`() { val tokenizableBefore = UnitSerializeAsToken() val context = serializeAsTokenContext(emptyList()) val testContext = this.context.withTokenContext(context) - val serializedBytes = tokenizableBefore.toToken(serializeAsTokenContext(emptyList())).checkpointSerialize(testContext) - serializedBytes.checkpointDeserialize(testContext) + assertThatExceptionOfType(UnsupportedOperationException::class.java).isThrownBy { + tokenizableBefore.toToken(serializeAsTokenContext(emptyList())).checkpointSerialize(testContext) + } } - @Test(expected = KryoException::class, timeout=300_000) + @Test(timeout=300_000) fun `no context set`() { val tokenizableBefore = UnitSerializeAsToken() - tokenizableBefore.checkpointSerialize(context) + assertThatExceptionOfType(KryoException::class.java).isThrownBy { + tokenizableBefore.checkpointSerialize(context) + } } - @Test(expected = KryoException::class, timeout=300_000) + @Test(timeout=300_000) fun `deserialize non-token`() { val tokenizableBefore = UnitSerializeAsToken() val context = serializeAsTokenContext(tokenizableBefore) @@ -108,7 +119,9 @@ class SerializationTokenTest { kryo.writeObject(it, emptyList()) } val serializedBytes = SerializedBytes(stream.toByteArray()) - serializedBytes.checkpointDeserialize(testContext) + assertThatExceptionOfType(KryoException::class.java).isThrownBy { + serializedBytes.checkpointDeserialize(testContext) + } } private class WrongTypeSerializeAsToken : SerializeAsToken { @@ -119,12 +132,14 @@ class SerializationTokenTest { override fun toToken(context: SerializeAsTokenContext): SerializationToken = UnitSerializationToken } - @Test(expected = KryoException::class, timeout=300_000) + @Test(timeout=300_000) fun `token returns unexpected type`() { val tokenizableBefore = WrongTypeSerializeAsToken() val context = serializeAsTokenContext(tokenizableBefore) val testContext = this.context.withTokenContext(context) val serializedBytes = tokenizableBefore.checkpointSerialize(testContext) - serializedBytes.checkpointDeserialize(testContext) + assertThatExceptionOfType(KryoException::class.java).isThrownBy { + serializedBytes.checkpointDeserialize(testContext) + } } } diff --git a/serialization-tests/src/test/kotlin/net/corda/serialization/internal/amqp/AbstractAMQPSerializationSchemeTest.kt b/serialization-tests/src/test/kotlin/net/corda/serialization/internal/amqp/AbstractAMQPSerializationSchemeTest.kt index 095cf8785e..0a9844442b 100644 --- a/serialization-tests/src/test/kotlin/net/corda/serialization/internal/amqp/AbstractAMQPSerializationSchemeTest.kt +++ b/serialization-tests/src/test/kotlin/net/corda/serialization/internal/amqp/AbstractAMQPSerializationSchemeTest.kt @@ -12,7 +12,7 @@ import net.corda.coretesting.internal.createTestSerializationEnv import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers.`is` import org.hamcrest.Matchers -import org.junit.Assert +import org.hamcrest.MatcherAssert.assertThat import org.junit.Test import java.net.URLClassLoader import java.util.concurrent.ThreadLocalRandom @@ -25,7 +25,7 @@ class AbstractAMQPSerializationSchemeTest { @Test(timeout=300_000) fun `number of cached factories must be bounded by maxFactories`() { val genesisContext = SerializationContextImpl( - ByteSequence.of(byteArrayOf('c'.toByte(), 'o'.toByte(), 'r'.toByte(), 'd'.toByte(), 'a'.toByte(), 0.toByte(), 0.toByte(), 1.toByte())), + ByteSequence.of(byteArrayOf('c'.code.toByte(), 'o'.code.toByte(), 'r'.code.toByte(), 'd'.code.toByte(), 'a'.code.toByte(), 0.toByte(), 0.toByte(), 1.toByte())), ClassLoader.getSystemClassLoader(), AllWhitelist, serializationProperties, @@ -61,10 +61,10 @@ class AbstractAMQPSerializationSchemeTest { val testString = "TEST${ThreadLocalRandom.current().nextInt()}" val serialized = scheme.serialize(testString, context) val deserialized = serialized.deserialize(context = context, serializationFactory = serializationEnvironment.serializationFactory) - Assert.assertThat(testString, `is`(deserialized)) - Assert.assertThat(backingMap.size, `is`(Matchers.lessThanOrEqualTo(maxFactories))) + assertThat(testString, `is`(deserialized)) + assertThat(backingMap.size, `is`(Matchers.lessThanOrEqualTo(maxFactories))) } - Assert.assertThat(backingMap.size, CoreMatchers.`is`(Matchers.lessThanOrEqualTo(maxFactories))) + assertThat(backingMap.size, CoreMatchers.`is`(Matchers.lessThanOrEqualTo(maxFactories))) } } diff --git a/serialization-tests/src/test/kotlin/net/corda/serialization/internal/amqp/SerializationOutputTests.kt b/serialization-tests/src/test/kotlin/net/corda/serialization/internal/amqp/SerializationOutputTests.kt index 0022030f82..07507ae219 100644 --- a/serialization-tests/src/test/kotlin/net/corda/serialization/internal/amqp/SerializationOutputTests.kt +++ b/serialization-tests/src/test/kotlin/net/corda/serialization/internal/amqp/SerializationOutputTests.kt @@ -2,8 +2,6 @@ package net.corda.serialization.internal.amqp -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever import net.corda.client.rpc.RPCException import net.corda.core.CordaException import net.corda.core.CordaRuntimeException @@ -58,18 +56,24 @@ import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.catchThrowable +import org.assertj.core.api.Assumptions.assumeThat import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509v2CRLBuilder import org.bouncycastle.cert.jcajce.JcaX509CRLConverter import org.bouncycastle.jce.provider.BouncyCastleProvider -import org.junit.Assert.* +import org.junit.Assert.assertArrayEquals +import org.junit.Assert.assertNotSame +import org.junit.Assert.assertSame import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.junit.runners.Parameterized.Parameters +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import java.io.IOException +import java.io.InputStream import java.io.NotSerializableException import java.math.BigDecimal import java.math.BigInteger @@ -89,14 +93,11 @@ import java.time.Year import java.time.YearMonth import java.time.ZonedDateTime import java.time.temporal.ChronoUnit -import java.util.ArrayList -import java.util.Arrays import java.util.BitSet import java.util.Currency import java.util.Date import java.util.EnumMap import java.util.EnumSet -import java.util.HashMap import java.util.NavigableMap import java.util.Objects import java.util.Random @@ -139,7 +140,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi val MINI_CORP_PUBKEY get() = miniCorp.publicKey @Parameters(name = "{0}") @JvmStatic - fun compression() = arrayOf(null) + CordaSerializationEncoding.values() + fun compression(): List = CordaSerializationEncoding.entries + null } @Rule @@ -148,13 +149,13 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi data class Foo(val bar: String, val pub: Int) - data class testFloat(val f: Float) + data class TestFloat(val f: Float) - data class testDouble(val d: Double) + data class TestDouble(val d: Double) - data class testShort(val s: Short) + data class TestShort(val s: Short) - data class testBoolean(val b: Boolean) + data class TestBoolean(val b: Boolean) interface FooInterface { val pub: Int @@ -294,14 +295,14 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi } val des = DeserializationInput(freshDeserializationFactory) val desObj = des.deserialize(bytes, testSerializationContext.withEncodingWhitelist(encodingWhitelist)) - assertTrue(deepEquals(obj, desObj) == expectedEqual) + assertEquals(deepEquals(obj, desObj), expectedEqual) // Now repeat with a re-used factory val ser2 = SerializationOutput(factory) val des2 = DeserializationInput(factory) val desObj2 = des2.deserialize(ser2.serialize(obj, compression), testSerializationContext.withEncodingWhitelist(encodingWhitelist)) - assertTrue(deepEquals(obj, desObj2) == expectedEqual) - assertTrue(deepEquals(desObj, desObj2) == expectDeserializedEqual) + assertEquals(deepEquals(obj, desObj2), expectedEqual) + assertEquals(deepEquals(desObj, desObj2), expectDeserializedEqual) // TODO: add some schema assertions to check correctly formed. return desObj @@ -340,25 +341,25 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi @Test(timeout=300_000) fun `test float`() { - val obj = testFloat(10.0F) + val obj = TestFloat(10.0F) serdes(obj) } @Test(timeout=300_000) fun `test double`() { - val obj = testDouble(10.0) + val obj = TestDouble(10.0) serdes(obj) } @Test(timeout=300_000) fun `test short`() { - val obj = testShort(1) + val obj = TestShort(1) serdes(obj) } @Test(timeout=300_000) fun `test bool`() { - val obj = testBoolean(true) + val obj = TestBoolean(true) serdes(obj) } @@ -374,10 +375,12 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi serdes(obj) } - @Test(expected = IllegalArgumentException::class, timeout=300_000) + @Test(timeout=300_000) fun `test dislike of HashMap`() { val obj = WrapHashMap(HashMap()) - serdes(obj) + assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy { + serdes(obj) + } } @Test(timeout=300_000) @@ -416,12 +419,14 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi serdes(obj) } - @Test(expected = NotSerializableException::class, timeout=300_000) + @Test(timeout=300_000) fun `test whitelist`() { val obj = Woo2(4) - serdes(obj, SerializerFactoryBuilder.build(EmptyWhitelist, - ClassCarpenterImpl(EmptyWhitelist, ClassLoader.getSystemClassLoader()) - )) + assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy { + serdes(obj, SerializerFactoryBuilder.build(EmptyWhitelist, + ClassCarpenterImpl(EmptyWhitelist, ClassLoader.getSystemClassLoader()) + )) + } } @Test(timeout=300_000) @@ -432,10 +437,12 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi )) } - @Test(expected = NotSerializableException::class, timeout=300_000) + @Test(timeout=300_000) fun `test generic list subclass is not supported`() { val obj = FooList() - serdes(obj) + assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy { + serdes(obj) + } } @Test(timeout=300_000) @@ -498,33 +505,37 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi @Test(timeout=300_000) fun `test NavigableMap property`() { - val obj = NavigableMapWrapper(TreeMap()) + val obj = NavigableMapWrapper(TreeMap()) obj.tree[456] = Foo("Fred", 123) serdes(obj) } @Test(timeout=300_000) fun `test SortedSet property`() { - val obj = SortedSetWrapper(TreeSet()) + val obj = SortedSetWrapper(TreeSet()) obj.set += 456 serdes(obj) } - @Test(expected = NotSerializableException::class, timeout=300_000) + @Test(timeout=300_000) fun `test mismatched property and constructor naming`() { val obj = Mismatch(456) - serdes(obj) + assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy { + serdes(obj) + } } - @Test(expected = NotSerializableException::class, timeout=300_000) + @Test(timeout=300_000) fun `test mismatched property and constructor type`() { val obj = MismatchType(456) - serdes(obj) + assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy { + serdes(obj) + } } @Test(timeout=300_000) fun `class constructor is invoked on deserialisation`() { - compression == null || return // Manipulation of serialized bytes is invalid if they're compressed. + assumeThat(compression).isNull() val serializerFactory = SerializerFactoryBuilder.build(AllWhitelist, ClassCarpenterImpl(AllWhitelist, ClassLoader.getSystemClassLoader()) ) @@ -575,7 +586,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi @Test(timeout=300_000) fun `generics from java are supported`() { - val obj = DummyOptional("YES") + val obj = DummyOptional("YES") serdes(obj, SerializerFactoryBuilder.build(EmptyWhitelist, ClassCarpenterImpl(EmptyWhitelist, ClassLoader.getSystemClassLoader()) )) @@ -630,12 +641,10 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi private fun assertSerializedThrowableEquivalent(t: Throwable, desThrowable: Throwable) { assertTrue(desThrowable is CordaRuntimeException) // Since we don't handle the other case(s) yet - if (desThrowable is CordaRuntimeException) { - assertEquals("${t.javaClass.name}: ${t.message}", desThrowable.message) - assertTrue(Objects.deepEquals(t.stackTrace.toStackTraceBasic, desThrowable.stackTrace.toStackTraceBasic)) - assertEquals(t.suppressed.size, desThrowable.suppressed.size) - t.suppressed.zip(desThrowable.suppressed).forEach { (before, after) -> assertSerializedThrowableEquivalent(before, after) } - } + assertEquals("${t.javaClass.name}: ${t.message}", desThrowable.message) + assertTrue(Objects.deepEquals(t.stackTrace.map(::BasicStrackTraceElement), desThrowable.stackTrace.map(::BasicStrackTraceElement))) + assertEquals(t.suppressed.size, desThrowable.suppressed.size) + t.suppressed.zip(desThrowable.suppressed).forEach { (before, after) -> assertSerializedThrowableEquivalent(before, after) } } @Test(timeout=300_000) @@ -762,8 +771,8 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi val desState = serdes(state, factory, factory2, expectedEqual = false, expectDeserializedEqual = false) assertTrue((desState as TransactionState<*>).data is FooState) - assertTrue(desState.notary == state.notary) - assertTrue(desState.encumbrance == state.encumbrance) + assertEquals(desState.notary, state.notary) + assertEquals(desState.encumbrance, state.encumbrance) } @Test(timeout=300_000) @@ -1091,7 +1100,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi @Ignore("Ignored due to cyclic graphs not currently supported by AMQP serialization") fun `test serialization of cyclic graph`() { val nodeA = TestNode("A") - val nodeB = TestNode("B", ArrayList(Arrays.asList(nodeA))) + val nodeB = TestNode("B", ArrayList(listOf(nodeA))) nodeA.children.add(nodeB) // Also blows with StackOverflow error @@ -1267,7 +1276,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi ) factory2.register(net.corda.serialization.internal.amqp.custom.SimpleStringSerializer) - val obj = SimpleString("Bob") + val obj = SimpleString.of("Bob") serdes(obj, factory, factory2) } @@ -1295,7 +1304,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi ) factory2.register(net.corda.serialization.internal.amqp.custom.InputStreamSerializer) val bytes = ByteArray(10) { it.toByte() } - val obj = bytes.inputStream() + val obj: InputStream = bytes.inputStream() val obj2 = serdes(obj, factory, factory2, expectedEqual = false, expectDeserializedEqual = false) val obj3 = bytes.inputStream() // Can't use original since the stream pointer has moved. assertEquals(obj3.available(), obj2.available()) @@ -1330,7 +1339,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi ) factory2.register(net.corda.serialization.internal.amqp.custom.BitSetSerializer(factory2)) - val obj = BitSet.valueOf(kotlin.ByteArray(16) { it.toByte() }).get(0, 123) + val obj = BitSet.valueOf(ByteArray(16) { it.toByte() }).get(0, 123) serdes(obj, factory, factory2) } @@ -1574,35 +1583,19 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi assertEquals(1018, compressedSize) } - // JDK11: backwards compatibility function to deal with StacktraceElement comparison pre-JPMS private fun deepEquals(a: Any?, b: Any?): Boolean { - return if (a === b) - true - else if (a == null || b == null) - false - else { - if (a is Exception && b is Exception) - (a.cause == b.cause && a.localizedMessage == b.localizedMessage && a.message == b.message) && - Objects.deepEquals(a.stackTrace.toStackTraceBasic, b.stackTrace.toStackTraceBasic) - else - Objects.deepEquals(a, b) + return when { + a is Throwable && b is Throwable -> BasicThrowable(a) == BasicThrowable(b) + else -> Objects.deepEquals(a, b) } } - private val Array.toStackTraceBasic: Unit - get() { - this.map { StackTraceElementBasic(it as StackTraceElement) } - } + private data class BasicThrowable(val cause: BasicThrowable?, val message: String?, val stackTrace: List) { + constructor(t: Throwable) : this(t.cause?.let(::BasicThrowable), t.message, t.stackTrace.map(::BasicStrackTraceElement)) + } // JPMS adds additional fields that are not equal according to classloader/module hierarchy - data class StackTraceElementBasic(val ste: StackTraceElement) { - override fun equals(other: Any?): Boolean { - return if (other is StackTraceElementBasic) - (ste.className == other.ste.className) && - (ste.methodName == other.ste.methodName) && - (ste.fileName == other.ste.fileName) && - (ste.lineNumber == other.ste.lineNumber) - else false - } + private data class BasicStrackTraceElement(val className: String, val methodName: String, val fileName: String?, val lineNumber: Int) { + constructor(ste: StackTraceElement) : this(ste.className, ste.methodName, ste.fileName, ste.lineNumber) } -} \ No newline at end of file +} diff --git a/serialization-tests/src/test/kotlin/net/corda/serialization/internal/verifier/ExternalVerifierTypesTest.kt b/serialization-tests/src/test/kotlin/net/corda/serialization/internal/verifier/ExternalVerifierTypesTest.kt new file mode 100644 index 0000000000..37453e0fb1 --- /dev/null +++ b/serialization-tests/src/test/kotlin/net/corda/serialization/internal/verifier/ExternalVerifierTypesTest.kt @@ -0,0 +1,39 @@ +package net.corda.serialization.internal.verifier + +import net.corda.core.crypto.SecureHash +import net.corda.core.internal.concurrent.openFuture +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerifierRequest.GetAttachments +import net.corda.testing.core.SerializationEnvironmentRule +import org.assertj.core.api.Assertions.assertThat +import org.junit.Rule +import org.junit.Test +import java.net.InetSocketAddress +import java.nio.channels.ServerSocketChannel +import java.nio.channels.SocketChannel +import kotlin.concurrent.thread + +class ExternalVerifierTypesTest { + @get:Rule + val testSerialization = SerializationEnvironmentRule() + + @Test(timeout=300_000) + fun `socket channel read-write`() { + val payload = GetAttachments(setOf(SecureHash.randomSHA256(), SecureHash.randomSHA256())) + + val serverChannel = ServerSocketChannel.open() + serverChannel.bind(null) + + val future = openFuture() + thread { + SocketChannel.open().use { + it.connect(InetSocketAddress(serverChannel.socket().localPort)) + val received = it.readCordaSerializable(GetAttachments::class) + future.set(received) + } + } + + serverChannel.use { it.accept().writeCordaSerializable(payload) } + + assertThat(future.get()).isEqualTo(payload) + } +} diff --git a/serialization/build.gradle b/serialization/build.gradle index a65ff2da15..757c020d90 100644 --- a/serialization/build.gradle +++ b/serialization/build.gradle @@ -1,36 +1,29 @@ -import static org.gradle.api.JavaVersion.VERSION_1_8 - -apply plugin: 'kotlin' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'corda.common-publishing' description 'Corda serialization' -targetCompatibility = VERSION_1_8 +configurations { + resolvableImplementation.extendsFrom implementation + + testArtifacts.extendsFrom testRuntimeClasspath +} dependencies { - compile project(":core") - - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - - compile "org.apache.activemq:artemis-commons:${artemis_version}" - - compile "org.ow2.asm:asm:$asm_version" - - compile "com.google.guava:guava:$guava_version" - + implementation project(":core") + implementation "io.reactivex:rxjava:$rxjava_version" + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + implementation "org.apache.activemq:artemis-commons:${artemis_version}" + implementation "org.ow2.asm:asm:$asm_version" + implementation "com.google.guava:guava:$guava_version" // For AMQP serialisation. - compile "org.apache.qpid:proton-j:$protonj_version" - + implementation "org.apache.qpid:proton-j:$protonj_version" // ClassGraph: classpath scanning - compile "io.github.classgraph:classgraph:$class_graph_version" - + implementation "io.github.classgraph:classgraph:$class_graph_version" // Pure-Java Snappy compression - compile "org.iq80.snappy:snappy:$snappy_version" - + implementation "org.iq80.snappy:snappy:$snappy_version" // For caches rather than guava - compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version" + implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version" testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" @@ -40,15 +33,11 @@ dependencies { testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" testRuntimeOnly "org.slf4j:slf4j-simple:$slf4j_version" - testCompile "org.assertj:assertj-core:$assertj_version" - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - testCompile "org.mockito:mockito-core:$mockito_version" - testCompile 'org.hamcrest:hamcrest-library:2.1' - testCompile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" -} - -configurations { - testArtifacts.extendsFrom testRuntimeClasspath + testImplementation "org.assertj:assertj-core:$assertj_version" + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + testImplementation "org.mockito:mockito-core:$mockito_version" + testImplementation 'org.hamcrest:hamcrest-library:2.1' + testImplementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" } tasks.withType(Javadoc).configureEach { @@ -56,14 +45,13 @@ tasks.withType(Javadoc).configureEach { enabled = false } -task testJar(type: Jar) { +tasks.register('testJar', Jar) { archiveClassifier = 'tests' from sourceSets.test.output } artifacts { testArtifacts testJar - publish testJar } jar { @@ -71,6 +59,12 @@ jar { archiveClassifier = '' } -publish { - name jar.archiveBaseName +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-serialization' + artifact(testJar) + from components.java + } + } } diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/AllButBlacklisted.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/AllButBlacklisted.kt index e0579b04ca..6ca60cce89 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/AllButBlacklisted.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/AllButBlacklisted.kt @@ -11,7 +11,6 @@ import java.net.DatagramSocket import java.net.ServerSocket import java.net.Socket import java.net.URLConnection -import java.security.AccessController import java.security.KeyStore import java.security.Permission import java.security.Provider @@ -30,7 +29,7 @@ import kotlin.collections.LinkedHashSet * Inheritance works for blacklisted items, but one can specifically exclude classes from blacklisting as well. * Note: Custom serializer registration trumps white/black lists. So if a given type has a custom serializer and has its name * in the blacklist - it will still be serialized as specified by custom serializer. - * For more details, see [net.corda.serialization.internal.CordaClassResolver.getRegistration] + * For more details, see [net.corda.nodeapi.internal.serialization.kryo.CordaClassResolver.getRegistration] */ object AllButBlacklisted : ClassWhitelist { @@ -48,7 +47,6 @@ object AllButBlacklisted : ClassWhitelist { Runtime::class.java.name, ZipFile::class.java.name, Provider::class.java.name, - SecurityManager::class.java.name, Random::class.java.name, // Known blacklisted interfaces. @@ -57,7 +55,6 @@ object AllButBlacklisted : ClassWhitelist { // java.security. KeyStore::class.java.name, - AccessController::class.java.name, Permission::class.java.name, // java.net. diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/ByteBufferStreams.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/ByteBufferStreams.kt index 8068cdf1a3..13774be072 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/ByteBufferStreams.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/ByteBufferStreams.kt @@ -43,14 +43,8 @@ class ByteBufferInputStream(val byteBuffer: ByteBuffer) : InputStream() { } class ByteBufferOutputStream(size: Int) : ByteArrayOutputStream(size) { - companion object { - private val ensureCapacity = ByteArrayOutputStream::class.java.getDeclaredMethod("ensureCapacity", Int::class.java).apply { - isAccessible = true - } - } - fun alsoAsByteBuffer(remaining: Int, task: (ByteBuffer) -> T): T { - ensureCapacity.invoke(this, count + remaining) + ensureCapacity(count + remaining) val buffer = ByteBuffer.wrap(buf, count, remaining) val result = task(buffer) count = buffer.position() @@ -60,4 +54,10 @@ class ByteBufferOutputStream(size: Int) : ByteArrayOutputStream(size) { fun copyTo(stream: OutputStream) { stream.write(buf, 0, count) } + + private fun ensureCapacity(minCapacity: Int) { + if (minCapacity > buf.size) { + buf = buf.copyOf(minCapacity) + } + } } diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/OrdinalIO.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/OrdinalIO.kt index 8b297b4f4f..8c6aa486a4 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/OrdinalIO.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/OrdinalIO.kt @@ -8,9 +8,9 @@ import java.nio.ByteBuffer class OrdinalBits(private val ordinal: Int) { interface OrdinalWriter { val bits: OrdinalBits - @JvmDefault val encodedSize: Int get() = 1 - @JvmDefault fun writeTo(stream: OutputStream) = stream.write(bits.ordinal) - @JvmDefault fun putTo(buffer: ByteBuffer) = buffer.put(bits.ordinal.toByte())!! + val encodedSize: Int get() = 1 + fun writeTo(stream: OutputStream) = stream.write(bits.ordinal) + fun putTo(buffer: ByteBuffer) = buffer.put(bits.ordinal.toByte())!! } init { diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationScheme.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationScheme.kt index 2ec5e8d9b8..45ed28ac32 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationScheme.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationScheme.kt @@ -37,7 +37,7 @@ data class SerializationContextImpl @JvmOverloads constructor(override val prefe /** * {@inheritDoc} */ - @Suppress("OverridingDeprecatedMember") + @Suppress("OVERRIDE_DEPRECATION") override fun withAttachmentsClassLoader(attachmentHashes: List): SerializationContext { return this } diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationUtils.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationUtils.kt new file mode 100644 index 0000000000..3e7305e136 --- /dev/null +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationUtils.kt @@ -0,0 +1,8 @@ +package net.corda.serialization.internal + +import java.io.NotSerializableException + +@Suppress("FunctionNaming") +fun NotSerializableException(message: String?, cause: Throwable?): NotSerializableException { + return NotSerializableException(message).apply { initCause(cause) } +} diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPExceptions.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPExceptions.kt index e4655d8f34..d1a8a37c93 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPExceptions.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPExceptions.kt @@ -1,19 +1,11 @@ package net.corda.serialization.internal.amqp import net.corda.core.internal.VisibleForTesting +import net.corda.serialization.internal.NotSerializableException import org.slf4j.Logger import java.io.NotSerializableException import java.lang.reflect.Type -/** - * Not a public property so will have to use reflection - */ -private fun Throwable.setMessage(newMsg: String) { - val detailMessageField = Throwable::class.java.getDeclaredField("detailMessage") - detailMessageField.isAccessible = true - detailMessageField.set(this, newMsg) -} - /** * Utility function which helps tracking the path in the object graph when exceptions are thrown. * Since there might be a chain of nested calls it is useful to record which part of the graph caused an issue. @@ -22,15 +14,13 @@ private fun Throwable.setMessage(newMsg: String) { internal inline fun ifThrowsAppend(strToAppendFn: () -> String, block: () -> T): T { try { return block() - } catch (th: Throwable) { - when (th) { - is AMQPNotSerializableException -> th.classHierarchy.add(strToAppendFn()) - // Do not overwrite the message of these exceptions as it may be used. - is ClassNotFoundException -> {} - is NoClassDefFoundError -> {} - else -> th.setMessage("${strToAppendFn()} -> ${th.message}") - } - throw th + } catch (e: AMQPNotSerializableException) { + e.classHierarchy += strToAppendFn() + throw e + } catch (e: Exception) { + // Avoid creating heavily nested NotSerializableExceptions + val cause = if (e.message?.contains(" -> ") == true) { e.cause ?: e } else { e } + throw NotSerializableException("${strToAppendFn()} -> ${e.message}", cause) } } @@ -77,8 +67,3 @@ open class AMQPNotSerializableException( logger.debug("", cause) } } - -class SyntheticParameterException(type: Type) : AMQPNotSerializableException( - type, - "Type '${type.typeName} has synthetic " - + "fields and is likely a nested inner class. This is not support by the Corda AMQP serialization framework") \ No newline at end of file diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPSerializer.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPSerializer.kt index 283b997a84..f1d2f344d5 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPSerializer.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPSerializer.kt @@ -31,7 +31,6 @@ interface AMQPSerializer { /** * Write the given object, with declared type, to the output. */ - @JvmDefault fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext, debugIndent: Int = 0) diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/ComposableTypePropertySerializer.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/ComposableTypePropertySerializer.kt index 254dc1f422..32d14eac7b 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/ComposableTypePropertySerializer.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/ComposableTypePropertySerializer.kt @@ -255,7 +255,7 @@ object AMQPCharPropertyReadStrategy : PropertyReadStrategy { override fun readProperty(obj: Any?, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext ): Any? { - return if (obj == null) null else (obj as Short).toChar() + return if (obj == null) null else (obj as Short).toInt().toChar() } } @@ -266,6 +266,6 @@ class AMQPCharPropertyWriteStategy(private val reader: PropertyReader) : Propert context: SerializationContext, debugIndent: Int ) { val input = reader.read(obj) - if (input != null) data.putShort((input as Char).toShort()) else data.putNull() + if (input != null) data.putShort((input as Char).code.toShort()) else data.putNull() } } \ No newline at end of file diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/DeserializationInput.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/DeserializationInput.kt index 6ee023d1a1..62a37410b3 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/DeserializationInput.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/DeserializationInput.kt @@ -11,6 +11,7 @@ import net.corda.core.utilities.loggerFor import net.corda.core.utilities.trace import net.corda.serialization.internal.ByteBufferInputStream import net.corda.serialization.internal.CordaSerializationEncoding +import net.corda.serialization.internal.NotSerializableException import net.corda.serialization.internal.NullEncodingWhitelist import net.corda.serialization.internal.SectionId import net.corda.serialization.internal.encodingNotPermittedFormat @@ -120,11 +121,11 @@ class DeserializationInput constructor( return generator() } catch (amqp : AMQPNotSerializableException) { amqp.log("Deserialize", logger) - throw NotSerializableException(amqp.mitigation) + throw NotSerializableException(amqp.mitigation, amqp) } catch (nse: NotSerializableException) { throw nse } catch (e: Exception) { - throw NotSerializableException("Internal deserialization failure: ${e.javaClass.name}: ${e.message}").apply { initCause(e) } + throw NotSerializableException("Internal deserialization failure: ${e.javaClass.name}: ${e.message}", e) } finally { objectHistory.clear() } diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/LocalSerializerFactory.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/LocalSerializerFactory.kt index 48e82e1a2f..2106818434 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/LocalSerializerFactory.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/LocalSerializerFactory.kt @@ -48,7 +48,6 @@ interface LocalSerializerFactory { /** * Obtain an [AMQPSerializer] for the [declaredType]. */ - @JvmDefault fun get(declaredType: Type): AMQPSerializer = get(getTypeInformation(declaredType)) /** @@ -71,7 +70,6 @@ interface LocalSerializerFactory { /** * Use the [FingerPrinter] to create a type descriptor for the given [type]. */ - @JvmDefault fun createDescriptor(type: Type): Symbol = createDescriptor(getTypeInformation(type)) /** diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/ObjectBuilder.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/ObjectBuilder.kt index ffc2fae5b5..76f15df55c 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/ObjectBuilder.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/ObjectBuilder.kt @@ -1,5 +1,6 @@ package net.corda.serialization.internal.amqp +import net.corda.serialization.internal.NotSerializableException import net.corda.serialization.internal.model.LocalConstructorInformation import net.corda.serialization.internal.model.LocalPropertyInformation import net.corda.serialization.internal.model.LocalTypeInformation @@ -32,17 +33,12 @@ private class ConstructorCaller(private val javaConstructor: Constructor) : try { javaConstructor.newInstance(*parameters) } catch (e: InvocationTargetException) { - @Suppress("DEPRECATION") // JDK11: isAccessible() should be replaced with canAccess() (since 9) throw NotSerializableException( - "Constructor for ${javaConstructor.declaringClass} (isAccessible=${javaConstructor.isAccessible}) " + - "failed when called with parameters ${parameters.toList()}: ${e.cause!!.message}" + "Constructor for ${javaConstructor.declaringClass.name} failed when called with parameters ${parameters.asList()}: ${e.cause?.message}", + e.cause ) } catch (e: IllegalAccessException) { - @Suppress("DEPRECATION") // JDK11: isAccessible() should be replaced with canAccess() (since 9) - throw NotSerializableException( - "Constructor for ${javaConstructor.declaringClass} (isAccessible=${javaConstructor.isAccessible}) " + - "not accessible: ${e.message}" - ) + throw NotSerializableException("Constructor for ${javaConstructor.declaringClass.name} not accessible: ${e.message}") } } @@ -54,17 +50,11 @@ private class SetterCaller(val setter: Method) : (Any, Any?) -> Unit { try { setter.invoke(target, value) } catch (e: InvocationTargetException) { - @Suppress("DEPRECATION") // JDK11: isAccessible() should be replaced with canAccess() (since 9) throw NotSerializableException( - "Setter ${setter.declaringClass}.${setter.name} (isAccessible=${setter.isAccessible} " + - "failed when called with parameter $value: ${e.cause!!.message}" + "Setter ${setter.declaringClass}.${setter.name} failed when called with parameter $value: ${e.cause?.message}" ) } catch (e: IllegalAccessException) { - @Suppress("DEPRECATION") // JDK11: isAccessible() should be replaced with canAccess() (since 9) - throw NotSerializableException( - "Setter ${setter.declaringClass}.${setter.name} (isAccessible=${setter.isAccessible} " + - "not accessible: ${e.message}" - ) + throw NotSerializableException("Setter ${setter.declaringClass}.${setter.name} not accessible: ${e.message}") } } } @@ -210,7 +200,7 @@ private class SetterBasedObjectBuilder( * and calling a constructor with those parameters to obtain the configured object instance. */ private class ConstructorBasedObjectBuilder( - private val constructorInfo: LocalConstructorInformation, + constructorInfo: LocalConstructorInformation, private val slotToCtorArgIdx: IntArray ) : ObjectBuilder { diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/PropertyDescriptor.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/PropertyDescriptor.kt index 39c8103fb8..074845be59 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/PropertyDescriptor.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/PropertyDescriptor.kt @@ -1,6 +1,7 @@ package net.corda.serialization.internal.amqp import com.google.common.reflect.TypeToken +import net.corda.core.internal.decapitalize import net.corda.core.internal.isPublic import net.corda.core.serialization.SerializableCalculatedProperty import net.corda.serialization.internal.amqp.MethodClassifier.* @@ -20,9 +21,9 @@ import java.util.* */ data class PropertyDescriptor(val field: Field?, val setter: Method?, val getter: Method?) { override fun toString() = StringBuilder("").apply { - appendln("Property - ${field?.name ?: "null field"}\n") - appendln(" getter - ${getter?.name ?: "no getter"}") - appendln(" setter - ${setter?.name ?: "no setter"}") + appendLine("Property - ${field?.name ?: "null field"}\n") + appendLine(" getter - ${getter?.name ?: "no getter"}") + appendLine(" setter - ${setter?.name ?: "no setter"}") }.toString() /** @@ -159,7 +160,7 @@ private fun getPropertyNamedMethod(method: Method): PropertyNamedMethod? { return propertyMethodRegex.find(method.name)?.let { result -> PropertyNamedMethod( result.groups[2]!!.value, - MethodClassifier.valueOf(result.groups[1]!!.value.toUpperCase()), + MethodClassifier.valueOf(result.groups[1]!!.value.uppercase(Locale.getDefault())), method) } } diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/TransformsSchema.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/TransformsSchema.kt index 3cfc0cd69f..212ea85dd2 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/TransformsSchema.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/TransformsSchema.kt @@ -322,22 +322,22 @@ data class TransformsSchema(val types: Map") + sb.appendLine("$indent") types.forEach { type -> val indent = Indent(indent) - sb.appendln("$indent") + sb.appendLine("$indent") type.value.forEach { transform -> val indent = Indent(indent) - sb.appendln("$indent") + sb.appendLine("$indent") transform.value.forEach { val indent = Indent(indent) - sb.appendln("$indent") + sb.appendLine("$indent") } - sb.appendln("$indent") + sb.appendLine("$indent") } - sb.appendln("$indent") + sb.appendLine("$indent") } - sb.appendln("$indent") + sb.appendLine("$indent") return sb.toString() } diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/CertPathSerializer.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/CertPathSerializer.kt index b234447fb2..f7234c4c70 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/CertPathSerializer.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/CertPathSerializer.kt @@ -2,9 +2,9 @@ package net.corda.serialization.internal.amqp.custom import net.corda.core.serialization.DESERIALIZATION_CACHE_PROPERTY import net.corda.core.serialization.SerializationContext +import net.corda.serialization.internal.NotSerializableException import net.corda.serialization.internal.amqp.CustomSerializer import net.corda.serialization.internal.amqp.SerializerFactory -import java.io.NotSerializableException import java.security.cert.CertPath import java.security.cert.CertificateException import java.security.cert.CertificateFactory @@ -23,9 +23,7 @@ class CertPathSerializer( val cf = CertificateFactory.getInstance(proxy.type) return cf.generateCertPath(proxy.encoded.inputStream()) } catch (ce: CertificateException) { - val nse = NotSerializableException("java.security.cert.CertPath: $type") - nse.initCause(ce) - throw nse + throw NotSerializableException("java.security.cert.CertPath: $type", ce) } } diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/InputStreamSerializer.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/InputStreamSerializer.kt index 0e2d9ab1f8..6a9cbfcddd 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/InputStreamSerializer.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/InputStreamSerializer.kt @@ -11,12 +11,7 @@ import java.lang.reflect.Type /** * A serializer that writes out the content of an input stream as bytes and deserializes into a [ByteArrayInputStream]. */ -object InputStreamSerializer - : CustomSerializer.Implements( - InputStream::class.java -) { - override val revealSubclassesInSchema: Boolean = true - +object InputStreamSerializer : CustomSerializer.Implements(InputStream::class.java) { override val schemaForDocumentation = Schema( listOf( RestrictedType( diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/ThrowableSerializer.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/ThrowableSerializer.kt index 323f5a20a4..a88380dc2d 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/ThrowableSerializer.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/ThrowableSerializer.kt @@ -2,6 +2,7 @@ package net.corda.serialization.internal.amqp.custom import net.corda.core.CordaRuntimeException import net.corda.core.CordaThrowable +import net.corda.core.internal.capitalize import net.corda.core.serialization.SerializationFactory import net.corda.core.utilities.contextLogger import net.corda.serialization.internal.amqp.* diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/ZonedDateTimeSerializer.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/ZonedDateTimeSerializer.kt index 04ce52a65e..ac53979a0b 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/ZonedDateTimeSerializer.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/custom/ZonedDateTimeSerializer.kt @@ -2,7 +2,6 @@ package net.corda.serialization.internal.amqp.custom import net.corda.serialization.internal.amqp.CustomSerializer import net.corda.serialization.internal.amqp.SerializerFactory -import java.lang.reflect.Method import java.time.LocalDateTime import java.time.ZoneId import java.time.ZoneOffset @@ -18,21 +17,6 @@ class ZonedDateTimeSerializer( ZonedDateTimeProxy::class.java, factory ) { - // Java deserialization of `ZonedDateTime` uses a private method. We will resolve this somewhat statically - // so that any change to internals of `ZonedDateTime` is detected early. - companion object { - val ofLenient: Method = ZonedDateTime::class.java.getDeclaredMethod( - "ofLenient", - LocalDateTime::class.java, - ZoneOffset::class.java, - ZoneId::class.java - ) - - init { - ofLenient.isAccessible = true - } - } - override val additionalSerializers: Iterable> = listOf( LocalDateTimeSerializer(factory), ZoneIdSerializer(factory) @@ -40,12 +24,7 @@ class ZonedDateTimeSerializer( override fun toProxy(obj: ZonedDateTime): ZonedDateTimeProxy = ZonedDateTimeProxy(obj.toLocalDateTime(), obj.offset, obj.zone) - override fun fromProxy(proxy: ZonedDateTimeProxy): ZonedDateTime = ofLenient.invoke( - null, - proxy.dateTime, - proxy.offset, - proxy.zone - ) as ZonedDateTime + override fun fromProxy(proxy: ZonedDateTimeProxy): ZonedDateTime = ZonedDateTime.ofLocal(proxy.dateTime, proxy.zone, proxy.offset) data class ZonedDateTimeProxy(val dateTime: LocalDateTime, val offset: ZoneOffset, val zone: ZoneId) -} \ No newline at end of file +} diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenter.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenter.kt index aea420e237..4a3373775b 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenter.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenter.kt @@ -2,6 +2,8 @@ package net.corda.serialization.internal.carpenter import com.google.common.base.MoreObjects +import net.corda.core.internal.capitalize +import net.corda.core.internal.decapitalize import net.corda.core.serialization.ClassWhitelist import net.corda.core.serialization.CordaSerializable import net.corda.core.utilities.contextLogger @@ -29,10 +31,6 @@ class CarpenterClassLoader(private val parentClassLoader: ClassLoader = Thread.c @Throws(ClassNotFoundException::class) override fun loadClass(name: String?, resolve: Boolean): Class<*>? { return synchronized(getClassLoadingLock(name)) { - /** - * Search parent classloaders using lock-less [Class.forName], - * bypassing [parent] to avoid its [SecurityManager] overhead. - */ (findLoadedClass(name) ?: Class.forName(name, false, parentClassLoader)).also { clazz -> if (resolve) { resolveClass(clazz) @@ -292,7 +290,7 @@ class ClassCarpenterImpl @JvmOverloads constructor (override val whitelist: Clas visitFieldInsn(GETFIELD, schema.jvmName, name, type.descriptor) when (type.field) { java.lang.Boolean.TYPE, Integer.TYPE, java.lang.Short.TYPE, java.lang.Byte.TYPE, - java.lang.Character.TYPE -> visitInsn(IRETURN) + Character.TYPE -> visitInsn(IRETURN) java.lang.Long.TYPE -> visitInsn(LRETURN) java.lang.Double.TYPE -> visitInsn(DRETURN) java.lang.Float.TYPE -> visitInsn(FRETURN) @@ -421,7 +419,7 @@ class ClassCarpenterImpl @JvmOverloads constructor (override val whitelist: Clas private fun MethodVisitor.load(slot: Int, type: Field): Int { when (type.field) { java.lang.Boolean.TYPE, Integer.TYPE, java.lang.Short.TYPE, java.lang.Byte.TYPE, - java.lang.Character.TYPE -> visitVarInsn(ILOAD, slot) + Character.TYPE -> visitVarInsn(ILOAD, slot) java.lang.Long.TYPE -> visitVarInsn(LLOAD, slot) java.lang.Double.TYPE -> visitVarInsn(DLOAD, slot) java.lang.Float.TYPE -> visitVarInsn(FLOAD, slot) diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/model/LocalTypeInformationBuilder.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/model/LocalTypeInformationBuilder.kt index c868193354..0ba60d915b 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/model/LocalTypeInformationBuilder.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/model/LocalTypeInformationBuilder.kt @@ -1,19 +1,27 @@ package net.corda.serialization.internal.model +import net.corda.core.internal.decapitalize import net.corda.core.internal.isAbstractClass import net.corda.core.internal.isConcreteClass +import net.corda.core.internal.isJdkClass import net.corda.core.internal.kotlinObjectInstance import net.corda.core.serialization.ConstructorForDeserialization import net.corda.core.serialization.DeprecatedConstructorForDeserialization +import net.corda.core.utilities.loggerFor import net.corda.serialization.internal.NotSerializableDetailedException -import net.corda.serialization.internal.amqp.* +import net.corda.serialization.internal.amqp.PropertyDescriptor +import net.corda.serialization.internal.amqp.TransformsAnnotationProcessor +import net.corda.serialization.internal.amqp.asClass +import net.corda.serialization.internal.amqp.calculatedPropertyDescriptors +import net.corda.serialization.internal.amqp.componentType +import net.corda.serialization.internal.amqp.propertyDescriptors +import net.corda.serialization.internal.model.LocalTypeInformation.ACollection +import net.corda.serialization.internal.model.LocalTypeInformation.AMap import net.corda.serialization.internal.model.LocalTypeInformation.Abstract import net.corda.serialization.internal.model.LocalTypeInformation.AnArray import net.corda.serialization.internal.model.LocalTypeInformation.AnEnum import net.corda.serialization.internal.model.LocalTypeInformation.AnInterface import net.corda.serialization.internal.model.LocalTypeInformation.Atomic -import net.corda.serialization.internal.model.LocalTypeInformation.ACollection -import net.corda.serialization.internal.model.LocalTypeInformation.AMap import net.corda.serialization.internal.model.LocalTypeInformation.Composable import net.corda.serialization.internal.model.LocalTypeInformation.Cycle import net.corda.serialization.internal.model.LocalTypeInformation.NonComposable @@ -22,11 +30,12 @@ import net.corda.serialization.internal.model.LocalTypeInformation.Singleton import net.corda.serialization.internal.model.LocalTypeInformation.Top import net.corda.serialization.internal.model.LocalTypeInformation.Unknown import java.io.NotSerializableException +import java.lang.reflect.InaccessibleObjectException import java.lang.reflect.Method import java.lang.reflect.ParameterizedType import java.lang.reflect.Type -import kotlin.collections.LinkedHashMap import kotlin.reflect.KFunction +import kotlin.reflect.KVisibility import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.memberProperties import kotlin.reflect.full.primaryConstructor @@ -298,7 +307,7 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup, private fun propertiesSatisfyConstructor(constructorInformation: LocalConstructorInformation, properties: Map): Boolean { if (!constructorInformation.hasParameters) return true - val indicesAddressedByProperties = properties.values.asSequence().mapNotNullTo(LinkedHashSet()) { + val indicesAddressedByProperties = properties.values.mapNotNullTo(LinkedHashSet()) { when (it) { is LocalPropertyInformation.ConstructorPairedProperty -> it.constructorSlot.parameterIndex is LocalPropertyInformation.PrivateConstructorPairedProperty -> it.constructorSlot.parameterIndex @@ -317,7 +326,7 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup, ): List { if (!constructorInformation.hasParameters) return emptyList() - val indicesAddressedByProperties = properties.values.asSequence().mapNotNullTo(LinkedHashSet()) { + val indicesAddressedByProperties = properties.values.mapNotNullTo(LinkedHashSet()) { when (it) { is LocalPropertyInformation.ConstructorPairedProperty -> it.constructorSlot.parameterIndex is LocalPropertyInformation.PrivateConstructorPairedProperty -> it.constructorSlot.parameterIndex @@ -520,8 +529,7 @@ private fun constructorForDeserialization(type: Type): KFunction? { val defaultCtor = kotlinCtors.firstOrNull { it.parameters.isEmpty() } val nonDefaultCtors = kotlinCtors.filter { it != defaultCtor } - val preferredCandidate = clazz.kotlin.primaryConstructor ?: - when(nonDefaultCtors.size) { + val preferredCandidate = clazz.kotlin.primaryConstructor ?: when (nonDefaultCtors.size) { 1 -> nonDefaultCtors.first() 0 -> defaultCtor else -> null @@ -531,6 +539,19 @@ private fun constructorForDeserialization(type: Type): KFunction? { preferredCandidate.apply { isAccessible = true } } catch (e: SecurityException) { null + } catch (e: InaccessibleObjectException) { + if (!clazz.isJdkClass || preferredCandidate.visibility == KVisibility.PUBLIC) { + // We shouldn't be using private JDK constructors. For non-JDK classes, then re-throw as the client may need to open up that + // module to us. Also throw if we can't get access to a public JDK constructor, which can probably happen if the class is not + // exported (i.e. internal API). + throw e + } + with(loggerFor()) { + if (isTraceEnabled) { + trace("Ignoring private JDK constructor", e) + } + } + null } } diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/model/RemoteTypeCarpenter.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/model/RemoteTypeCarpenter.kt index e7b97cf45b..df90dbc534 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/model/RemoteTypeCarpenter.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/model/RemoteTypeCarpenter.kt @@ -32,7 +32,7 @@ class SchemaBuildingRemoteTypeCarpenter(private val carpenter: ClassCarpenter): } // Anything else, such as arrays, will be taken care of by the above } } catch (e: ClassCarpenterException) { - throw NotSerializableException("${typeInformation.typeIdentifier.name}: ${e.message}") + throw NotSerializableException("${typeInformation.typeIdentifier.name}: ${e.message}").apply { initCause(e) } } return try { @@ -40,7 +40,7 @@ class SchemaBuildingRemoteTypeCarpenter(private val carpenter: ClassCarpenter): } catch (e: ClassNotFoundException) { // This might happen if we've been asked to carpent up a parameterised type, and it's the rawtype itself // rather than any of its type parameters that were missing. - throw NotSerializableException("Could not carpent ${typeInformation.typeIdentifier.prettyPrint(false)}") + throw NotSerializableException("Could not carpent ${typeInformation.typeIdentifier.prettyPrint(false)}").apply { initCause(e) } } } @@ -87,6 +87,6 @@ class SchemaBuildingRemoteTypeCarpenter(private val carpenter: ClassCarpenter): } private fun RemoteTypeInformation.AnEnum.carpentEnum() { - carpenter.build(EnumSchema(name = typeIdentifier.name, fields = members.associate { it to EnumField() })) + carpenter.build(EnumSchema(name = typeIdentifier.name, fields = members.associateWith { EnumField() })) } -} \ No newline at end of file +} diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/CustomSerializationSchemeAdapter.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/verifier/CustomSerializationSchemeAdapter.kt similarity index 66% rename from node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/CustomSerializationSchemeAdapter.kt rename to serialization/src/main/kotlin/net/corda/serialization/internal/verifier/CustomSerializationSchemeAdapter.kt index f656f81502..3bbdb170a9 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/CustomSerializationSchemeAdapter.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/verifier/CustomSerializationSchemeAdapter.kt @@ -1,8 +1,10 @@ -package net.corda.nodeapi.internal.serialization +package net.corda.serialization.internal.verifier -import net.corda.core.serialization.SerializationSchemeContext +import net.corda.core.CordaException +import net.corda.core.internal.loadClassOfType import net.corda.core.serialization.CustomSerializationScheme import net.corda.core.serialization.SerializationContext +import net.corda.core.serialization.SerializationSchemeContext import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.internal.CustomSerializationSchemeUtils.Companion.getCustomSerializationMagicFromSchemeId import net.corda.core.utilities.ByteSequence @@ -12,8 +14,7 @@ import java.io.ByteArrayOutputStream import java.io.NotSerializableException class CustomSerializationSchemeAdapter(private val customScheme: CustomSerializationScheme): SerializationScheme { - - val serializationSchemeMagic = getCustomSerializationMagicFromSchemeId(customScheme.getSchemeId()) + private val serializationSchemeMagic = getCustomSerializationMagicFromSchemeId(customScheme.getSchemeId()) override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean { return magic == serializationSchemeMagic @@ -44,4 +45,21 @@ class CustomSerializationSchemeAdapter(private val customScheme: CustomSerializa override val whitelist = context.whitelist override val properties = context.properties } -} \ No newline at end of file +} + +@Suppress("ThrowsCount") +fun loadCustomSerializationScheme(className: String, classLoader: ClassLoader): SerializationScheme { + val schemeClass = try { + loadClassOfType(className, false, classLoader) + } catch (e: ClassNotFoundException) { + throw CordaException("$className was declared as a custom serialization scheme but could not be found.") + } catch (e: ClassCastException) { + throw CordaException("$className was declared as a custom serialization scheme but does not implement CustomSerializationScheme") + } + val constructor = try { + schemeClass.getDeclaredConstructor() + } catch (e: NoSuchMethodException) { + throw CordaException("$className was declared as a custom serialization scheme but does not have a no argument constructor.") + } + return CustomSerializationSchemeAdapter(constructor.newInstance()) +} diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/verifier/ExternalVerifierTypes.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/verifier/ExternalVerifierTypes.kt new file mode 100644 index 0000000000..7d5344bbd1 --- /dev/null +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/verifier/ExternalVerifierTypes.kt @@ -0,0 +1,111 @@ +package net.corda.serialization.internal.verifier + +import net.corda.core.contracts.Attachment +import net.corda.core.contracts.StateRef +import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.toStringShort +import net.corda.core.identity.Party +import net.corda.core.internal.SerializedTransactionState +import net.corda.core.node.NetworkParameters +import net.corda.core.serialization.CordaSerializable +import net.corda.core.serialization.SerializationFactory +import net.corda.core.serialization.SerializedBytes +import net.corda.core.serialization.deserialize +import net.corda.core.serialization.serialize +import net.corda.core.transactions.CoreTransaction +import net.corda.core.utilities.Try +import net.corda.core.utilities.sequence +import java.io.EOFException +import java.nio.ByteBuffer +import java.nio.channels.SocketChannel +import java.security.PublicKey +import kotlin.math.min +import kotlin.reflect.KClass + +typealias SerializedNetworkParameters = SerializedBytes + +@CordaSerializable +sealed class ExternalVerifierInbound { + data class Initialisation( + val customSerializerClassNames: Set, + val serializationWhitelistClassNames: Set, + val customSerializationSchemeClassName: String?, + val serializedCurrentNetworkParameters: SerializedNetworkParameters + ) : ExternalVerifierInbound() { + val currentNetworkParameters: NetworkParameters by lazy { serializedCurrentNetworkParameters.deserialize() } + + override fun toString(): String { + return "Initialisation(" + + "customSerializerClassNames=$customSerializerClassNames, " + + "serializationWhitelistClassNames=$serializationWhitelistClassNames, " + + "customSerializationSchemeClassName=$customSerializationSchemeClassName, " + + "currentNetworkParameters=$currentNetworkParameters)" + } + } + + data class VerificationRequest( + val ctx: CoreTransaction, + val ctxInputsAndReferences: Map + ) : ExternalVerifierInbound() { + override fun toString(): String = "VerificationRequest(ctx=$ctx)" + } + + data class PartiesResult(val parties: List) : ExternalVerifierInbound() + data class AttachmentResult(val attachment: AttachmentWithTrust?) : ExternalVerifierInbound() + data class AttachmentsResult(val attachments: List) : ExternalVerifierInbound() + data class NetworkParametersResult(val networkParameters: NetworkParameters?) : ExternalVerifierInbound() + data class TrustedClassAttachmentsResult(val ids: List) : ExternalVerifierInbound() +} + +@CordaSerializable +data class AttachmentWithTrust(val attachment: Attachment, val isTrusted: Boolean) + +@CordaSerializable +sealed class ExternalVerifierOutbound { + sealed class VerifierRequest : ExternalVerifierOutbound() { + data class GetParties(val keys: Set) : VerifierRequest() { + override fun toString(): String = "GetParties(keys=${keys.map { it.toStringShort() }}})" + } + data class GetAttachment(val id: SecureHash) : VerifierRequest() + data class GetAttachments(val ids: Set) : VerifierRequest() + data class GetNetworkParameters(val id: SecureHash) : VerifierRequest() + data class GetTrustedClassAttachments(val className: String) : VerifierRequest() + } + + data class VerificationResult(val result: Try) : ExternalVerifierOutbound() +} + +fun SocketChannel.writeCordaSerializable(payload: Any) { + val serialised = payload.serialize() + val buffer = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE) + buffer.putInt(serialised.size) + var writtenSoFar = 0 + while (writtenSoFar < serialised.size) { + val length = min(buffer.remaining(), serialised.size - writtenSoFar) + serialised.subSequence(writtenSoFar, length).putTo(buffer) + buffer.flip() + write(buffer) + writtenSoFar += length + buffer.clear() + } +} + +fun SocketChannel.readCordaSerializable(clazz: KClass): T { + val length = ByteBuffer.wrap(read(clazz, Integer.BYTES)).getInt() + val bytes = read(clazz, length) + return SerializationFactory.defaultFactory.deserialize(bytes.sequence(), clazz.java, SerializationFactory.defaultFactory.defaultContext) +} + +private fun SocketChannel.read(clazz: KClass<*>, length: Int): ByteArray { + val bytes = ByteArray(length) + var readSoFar = 0 + while (readSoFar < bytes.size) { + // Wrap a ByteBuffer around the byte array to read directly into it + val n = read(ByteBuffer.wrap(bytes, readSoFar, bytes.size - readSoFar)) + if (n == -1) { + throw EOFException("Incomplete read of ${clazz.java.name}") + } + readSoFar += n + } + return bytes +} diff --git a/serialization/src/test/java/net/corda/serialization/internal/amqp/JavaGenericsTest.java b/serialization/src/test/java/net/corda/serialization/internal/amqp/JavaGenericsTest.java index 2480c7966f..dc573867c1 100644 --- a/serialization/src/test/java/net/corda/serialization/internal/amqp/JavaGenericsTest.java +++ b/serialization/src/test/java/net/corda/serialization/internal/amqp/JavaGenericsTest.java @@ -6,7 +6,6 @@ import net.corda.serialization.internal.amqp.custom.BigIntegerSerializer; import net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt; import net.corda.serialization.internal.amqp.testutils.TestSerializationContext; import org.hamcrest.CoreMatchers; -import org.junit.Assert; import org.junit.Test; import java.io.NotSerializableException; @@ -14,6 +13,7 @@ import java.math.BigInteger; import java.util.*; import static net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt.testDefaultFactory; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @SuppressWarnings("unchecked") @@ -160,7 +160,7 @@ public class JavaGenericsTest { SerializedBytes bytes = ser.serialize(genericList, TestSerializationContext.testSerializationContext); DeserializationInput des = new DeserializationInput(factory); HolderOfGeneric> genericList2 = des.deserialize(bytes, HolderOfGeneric.class, TestSerializationContext.testSerializationContext); - Assert.assertThat(genericList, CoreMatchers.is(CoreMatchers.equalTo(genericList2))); + assertThat(genericList, CoreMatchers.is(CoreMatchers.equalTo(genericList2))); } @@ -174,7 +174,7 @@ public class JavaGenericsTest { SerializedBytes bytes = ser.serialize(genericMap, TestSerializationContext.testSerializationContext); DeserializationInput des = new DeserializationInput(factory); GenericClassWithMap genericMap2 = des.deserialize(bytes, GenericClassWithMap.class, TestSerializationContext.testSerializationContext); - Assert.assertThat(genericMap2, CoreMatchers.is(CoreMatchers.equalTo(genericMap2))); + assertThat(genericMap2, CoreMatchers.is(CoreMatchers.equalTo(genericMap2))); } @Test diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/AMQPTypeIdentifierParserTests.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/AMQPTypeIdentifierParserTests.kt index ff7825da1d..5fb36c0c7f 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/AMQPTypeIdentifierParserTests.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/AMQPTypeIdentifierParserTests.kt @@ -1,16 +1,18 @@ package net.corda.serialization.internal.amqp import com.google.common.reflect.TypeToken +import net.corda.serialization.internal.MAX_TYPE_PARAM_DEPTH import net.corda.serialization.internal.model.TypeIdentifier import org.apache.qpid.proton.amqp.UnsignedShort +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Test import java.io.NotSerializableException import java.lang.reflect.Type import java.time.LocalDateTime -import java.util.* +import java.util.Date +import java.util.UUID import kotlin.test.assertEquals import kotlin.test.assertFailsWith -import net.corda.serialization.internal.MAX_TYPE_PARAM_DEPTH class AMQPTypeIdentifierParserTests { @@ -100,49 +102,49 @@ class AMQPTypeIdentifierParserTests { verify("java.util.List>>") } - @Test(expected = NotSerializableException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `test trailing text`() { - verify("java.util.Mapfoo") + verifyInvalid("java.util.Mapfoo") } - @Test(expected = NotSerializableException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `test trailing comma`() { - verify("java.util.Map") + verifyInvalid("java.util.Map") } - @Test(expected = NotSerializableException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `test leading comma`() { - verify("java.util.Map<,java.lang.String, java.lang.Integer>") + verifyInvalid("java.util.Map<,java.lang.String, java.lang.Integer>") } - @Test(expected = NotSerializableException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `test middle comma`() { - verify("java.util.Map<,java.lang.String,, java.lang.Integer>") + verifyInvalid("java.util.Map<,java.lang.String,, java.lang.Integer>") } - @Test(expected = NotSerializableException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `test trailing close`() { - verify("java.util.Map>") + verifyInvalid("java.util.Map>") } - @Test(expected = NotSerializableException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `test empty params`() { - verify("java.util.Map<>") + verifyInvalid("java.util.Map<>") } - @Test(expected = NotSerializableException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `test mid whitespace`() { - verify("java.u til.List") + verifyInvalid("java.u til.List") } - @Test(expected = NotSerializableException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `test mid whitespace2`() { - verify("java.util.List") + verifyInvalid("java.util.List") } - @Test(expected = NotSerializableException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `test wrong number of parameters`() { - verify("java.util.List") + verifyInvalid("java.util.List") } @Test(timeout=300_000) @@ -150,18 +152,18 @@ class AMQPTypeIdentifierParserTests { verify("java.lang.String") } - @Test(expected = NotSerializableException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `test parameters on non-generic type`() { - verify("java.lang.String") + verifyInvalid("java.lang.String") } - @Test(expected = NotSerializableException::class, timeout = 300_000) + @Test(timeout = 300_000) fun `test excessive nesting`() { var nested = "java.lang.Integer" for (i in 1..MAX_TYPE_PARAM_DEPTH) { nested = "java.util.List<$nested>" } - verify(nested) + verifyInvalid(nested) } private inline fun assertParseResult(typeString: String) { @@ -195,4 +197,10 @@ class AMQPTypeIdentifierParserTests { val type = AMQPTypeIdentifierParser.parse(typeName).getLocalType() assertEquals(normalise(typeName), normalise(type.typeName)) } + + private fun verifyInvalid(typeName: String) { + assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy { + AMQPTypeIdentifierParser.parse(typeName).getLocalType() + } + } } \ No newline at end of file diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeMapTests.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeMapTests.kt index f40e776cd8..1893271710 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeMapTests.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeMapTests.kt @@ -2,11 +2,18 @@ package net.corda.serialization.internal.amqp import net.corda.serialization.internal.amqp.testutils.TestSerializationOutput import net.corda.serialization.internal.amqp.testutils.deserialize -import net.corda.serialization.internal.amqp.testutils.serialize import net.corda.serialization.internal.amqp.testutils.testDefaultFactoryNoEvolution -import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Test -import java.util.* +import java.io.NotSerializableException +import java.util.AbstractMap +import java.util.Dictionary +import java.util.Hashtable +import java.util.NavigableMap +import java.util.SortedMap +import java.util.TreeMap +import java.util.WeakHashMap class DeserializeMapTests { companion object { @@ -28,24 +35,26 @@ class DeserializeMapTests { DeserializationInput(sf).deserialize(serialisedBytes) } - @Test(expected = java.io.NotSerializableException::class, timeout=300_000) + @Test(timeout=300_000) fun abstractMapFromMapOf() { data class C(val c: AbstractMap) val c = C(mapOf("A" to 1, "B" to 2) as AbstractMap) - val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c) - DeserializationInput(sf).deserialize(serialisedBytes) + assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy { + TestSerializationOutput(VERBOSE, sf).serialize(c) + } } - @Test(expected = java.io.NotSerializableException::class, timeout=300_000) + @Test(timeout=300_000) fun abstractMapFromTreeMap() { data class C(val c: AbstractMap) val c = C(TreeMap(mapOf("A" to 1, "B" to 2))) - val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c) - DeserializationInput(sf).deserialize(serialisedBytes) + assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy { + TestSerializationOutput(VERBOSE, sf).serialize(c) + } } @Test(timeout=300_000) @@ -77,8 +86,9 @@ class DeserializeMapTests { val c = C(v) // expected to throw - Assertions.assertThatThrownBy { TestSerializationOutput(VERBOSE, sf).serialize(c) } - .isInstanceOf(IllegalArgumentException::class.java).hasMessageContaining("Unable to serialise deprecated type class java.util.Dictionary.") + assertThatThrownBy { TestSerializationOutput(VERBOSE, sf).serialize(c) } + .isInstanceOf(NotSerializableException::class.java) + .hasMessageContaining("Unable to serialise deprecated type class java.util.Dictionary.") } @Test(timeout=300_000) @@ -91,7 +101,7 @@ class DeserializeMapTests { val c = C(v) // expected to throw - Assertions.assertThatThrownBy { TestSerializationOutput(VERBOSE, sf).serialize(c) } + assertThatThrownBy { TestSerializationOutput(VERBOSE, sf).serialize(c) } .isInstanceOf(IllegalArgumentException::class.java).hasMessageContaining("Unable to serialise deprecated type class java.util.Hashtable. Suggested fix: prefer java.util.map implementations") } @@ -102,7 +112,7 @@ class DeserializeMapTests { val c = C(HashMap(mapOf("A" to 1, "B" to 2))) // expect this to throw - Assertions.assertThatThrownBy { TestSerializationOutput(VERBOSE, sf).serialize(c) } + assertThatThrownBy { TestSerializationOutput(VERBOSE, sf).serialize(c) } .isInstanceOf(IllegalArgumentException::class.java).hasMessageContaining("Map type class java.util.HashMap is unstable under iteration. Suggested fix: use java.util.LinkedHashMap instead.") } @@ -112,7 +122,7 @@ class DeserializeMapTests { val c = C(WeakHashMap(mapOf("A" to 1, "B" to 2))) - Assertions.assertThatThrownBy { TestSerializationOutput(VERBOSE, sf).serialize(c) } + assertThatThrownBy { TestSerializationOutput(VERBOSE, sf).serialize(c) } .isInstanceOf(IllegalArgumentException::class.java).hasMessageContaining("Weak references with map types not supported. Suggested fix: use java.util.LinkedHashMap instead.") } diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeNeedingCarpentryOfEnumsTest.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeNeedingCarpentryOfEnumsTest.kt index 6f29d0bf9d..0dc77bfb4a 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeNeedingCarpentryOfEnumsTest.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeNeedingCarpentryOfEnumsTest.kt @@ -22,7 +22,7 @@ class DeserializeNeedingCarpentryOfEnumsTest : AmqpCarpenterBase(AllWhitelist) { val setupFactory = testDefaultFactoryNoEvolution() val classCarpenter = ClassCarpenterImpl(AllWhitelist, ClassLoader.getSystemClassLoader()) val enumConstants = listOf("AAA", "BBB", "CCC", "DDD", "EEE", "FFF", - "GGG", "HHH", "III", "JJJ").associateBy({ it }, { EnumField() }) + "GGG", "HHH", "III", "JJJ").associateWith { EnumField() } // create the enum val testEnumType = classCarpenter.build(EnumSchema("test.testEnumType", enumConstants)) @@ -61,7 +61,7 @@ class DeserializeNeedingCarpentryOfEnumsTest : AmqpCarpenterBase(AllWhitelist) { val setupFactory = testDefaultFactoryNoEvolution() val classCarpenter = ClassCarpenterImpl(AllWhitelist, ClassLoader.getSystemClassLoader()) val enumConstants = listOf("AAA", "BBB", "CCC", "DDD", "EEE", "FFF", - "GGG", "HHH", "III", "JJJ").associateBy({ it }, { EnumField() }) + "GGG", "HHH", "III", "JJJ").associateWith { EnumField() } // create the enum val testEnumType1 = classCarpenter.build(EnumSchema("test.testEnumType1", enumConstants)) diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeNeedingCarpentrySimpleTypesTest.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeNeedingCarpentrySimpleTypesTest.kt index c12c0fe82d..cb3fa4fd52 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeNeedingCarpentrySimpleTypesTest.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeNeedingCarpentrySimpleTypesTest.kt @@ -364,7 +364,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest : AmqpCarpenterBase(AllWhitelis assertNotEquals(clazz, deserializedObj::class.java) assertTrue(deserializedObj is I) - assertEquals(testVal, (deserializedObj as I).getName()) + assertEquals(testVal, deserializedObj.getName()) } @Test(timeout=300_000) diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeNeedingCarpentryTests.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeNeedingCarpentryTests.kt index cf824157c4..eef8cb46b7 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeNeedingCarpentryTests.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/DeserializeNeedingCarpentryTests.kt @@ -133,7 +133,7 @@ class DeserializeNeedingCarpentryTests : AmqpCarpenterBase(AllWhitelist) { val deserializedObj = DeserializationInput(sf2).deserializeWithoutAndWithCarpenter(serialisedBytes) assertTrue(deserializedObj is I) - assertEquals(testVal, (deserializedObj as I).getName()) + assertEquals(testVal, deserializedObj.getName()) } @Test(timeout=300_000) @@ -270,7 +270,7 @@ class DeserializeNeedingCarpentryTests : AmqpCarpenterBase(AllWhitelist) { val deserializedObj = DeserializationInput(sf2).deserializeWithoutAndWithCarpenter(serialisedBytes) assertTrue(deserializedObj is I) - assertEquals("timmy", (deserializedObj as I).getName()) + assertEquals("timmy", deserializedObj.getName()) assertEquals("timmy", deserializedObj::class.java.getMethod("getName").invoke(deserializedObj)) assertEquals(12, deserializedObj::class.java.getMethod("getAge").invoke(deserializedObj)) } diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/EnumTests.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/EnumTests.kt index 0a76f19751..b612325da5 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/EnumTests.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/EnumTests.kt @@ -12,10 +12,12 @@ import net.corda.serialization.internal.amqp.testutils.testDefaultFactoryNoEvolu import net.corda.serialization.internal.amqp.testutils.testName import net.corda.serialization.internal.carpenter.ClassCarpenterImpl import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Assert.assertNotSame import org.junit.Test import java.io.NotSerializableException import java.time.DayOfWeek +import java.util.Locale import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -157,7 +159,7 @@ class EnumTests { assertEquals(c.c, obj.c) } - @Test(expected = NotSerializableException::class, timeout=300_000) + @Test(timeout=300_000) fun changedEnum1() { val url = EnumTests::class.java.getResource("EnumTests.changedEnum1") @@ -173,10 +175,12 @@ class EnumTests { val sc2 = url.readBytes() // we expect this to throw - DeserializationInput(sf1).deserialize(SerializedBytes(sc2)) + assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy { + DeserializationInput(sf1).deserialize(SerializedBytes(sc2)) + } } - @Test(expected = NotSerializableException::class, timeout=300_000) + @Test(timeout=300_000) fun changedEnum2() { val url = EnumTests::class.java.getResource("EnumTests.changedEnum2") @@ -195,7 +199,9 @@ class EnumTests { val sc2 = url.readBytes() // we expect this to throw - DeserializationInput(sf1).deserialize(SerializedBytes(sc2)) + assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy { + DeserializationInput(sf1).deserialize(SerializedBytes(sc2)) + } } @Test(timeout=300_000) @@ -303,7 +309,7 @@ class EnumTests { THREE; override fun toString(): String { - return "[${name.toLowerCase()}]" + return "[${name.lowercase(Locale.getDefault())}]" } } diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/EvolvabilityTests.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/EvolvabilityTests.kt index 0c2ecdb8c9..fefc3ccec0 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/EvolvabilityTests.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/EvolvabilityTests.kt @@ -15,6 +15,7 @@ import net.corda.core.serialization.DeprecatedConstructorForDeserialization import net.corda.core.serialization.SerializableCalculatedProperty import net.corda.core.serialization.SerializedBytes import net.corda.serialization.internal.amqp.custom.InstantSerializer +import net.corda.serialization.internal.amqp.custom.PublicKeySerializer import net.corda.serialization.internal.amqp.testutils.ProjectStructure.projectRootDir import net.corda.serialization.internal.amqp.testutils.TestSerializationOutput import net.corda.serialization.internal.amqp.testutils.deserialize @@ -23,6 +24,7 @@ import net.corda.serialization.internal.amqp.testutils.serializeAndReturnSchema import net.corda.serialization.internal.amqp.testutils.testDefaultFactory import net.corda.serialization.internal.amqp.testutils.testName import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Ignore import org.junit.Test import org.junit.jupiter.api.Assertions.assertNotSame @@ -68,7 +70,7 @@ class EvolvabilityTests { // new version of the class, in this case the order of the parameters has been swapped data class C(val b: Int, val a: Int) - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserializedC = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -90,7 +92,7 @@ class EvolvabilityTests { // new version of the class, in this case the order of the parameters has been swapped data class C(val b: String, val a: Int) - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserializedC = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -110,7 +112,7 @@ class EvolvabilityTests { data class C(val a: Int, val b: Int?) - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserializedC = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -118,10 +120,10 @@ class EvolvabilityTests { assertEquals(null, deserializedC.b) } - @Test(expected = NotSerializableException::class, timeout=300_000) + @Test(timeout=300_000) fun addAdditionalParam() { val sf = testDefaultFactory() - val url = EvolvabilityTests::class.java.getResource("EvolvabilityTests.addAdditionalParam") + val url = EvolvabilityTests::class.java.getResource("EvolvabilityTests.addAdditionalParam")!! @Suppress("UNUSED_VARIABLE") val A = 1 @@ -140,7 +142,9 @@ class EvolvabilityTests { // Expected to throw as we can't construct the new type as it contains a newly // added parameter that isn't optional, i.e. not nullable and there isn't // a constructor that takes the old parameters - DeserializationInput(sf).deserialize(SerializedBytes(sc2)) + assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy { + DeserializationInput(sf).deserialize(SerializedBytes(sc2)) + } } @Suppress("UNUSED_VARIABLE") @@ -159,7 +163,7 @@ class EvolvabilityTests { data class CC(val b: String, val d: Int) - val url = EvolvabilityTests::class.java.getResource("EvolvabilityTests.removeParameters") + val url = EvolvabilityTests::class.java.getResource("EvolvabilityTests.removeParameters")!! val sc2 = url.readBytes() val deserializedCC = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -167,7 +171,6 @@ class EvolvabilityTests { assertEquals(D, deserializedCC.d) } - @Suppress("UNUSED_VARIABLE") @Test(timeout=300_000) fun removeParameterWithCalculatedParameter() { val sf = testDefaultFactory() @@ -186,7 +189,7 @@ class EvolvabilityTests { val e: String get() = "$b sailor" } - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserializedCC = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -213,7 +216,7 @@ class EvolvabilityTests { data class CC(val a: Int, val e: Boolean?, val d: Int) - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserializedCC = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -238,7 +241,7 @@ class EvolvabilityTests { constructor (a: Int) : this(a, "hello") } - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserializedCC = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -263,7 +266,7 @@ class EvolvabilityTests { constructor (z: Int, y: Int) : this(z, y, "10") } - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val deserializedCC = DeserializationInput(sf).deserialize(SerializedBytes(url.readBytes())) assertEquals("10", deserializedCC.a) @@ -322,16 +325,16 @@ class EvolvabilityTests { // 9, // mapOf("A" to listOf(1, 2, 3), "B" to listOf (4, 5, 6)))).bytes) - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! DeserializationInput(factory).deserialize(SerializedBytes(url.readBytes())) } - @Test(expected = NotSerializableException::class, timeout=300_000) + @Test(timeout=300_000) @Suppress("UNUSED") fun addMandatoryFieldWithAltConstructorUnAnnotated() { val sf = testDefaultFactory() val url = EvolvabilityTests::class.java.getResource( - "EvolvabilityTests.addMandatoryFieldWithAltConstructorUnAnnotated") + "EvolvabilityTests.addMandatoryFieldWithAltConstructorUnAnnotated")!! @Suppress("UNUSED_VARIABLE") val A = 1 @@ -349,7 +352,9 @@ class EvolvabilityTests { // we expect this to throw as we should not find any constructors // capable of dealing with this - DeserializationInput(sf).deserialize(SerializedBytes(url.readBytes())) + assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy { + DeserializationInput(sf).deserialize(SerializedBytes(url.readBytes())) + } } @Test(timeout=300_000) @@ -372,7 +377,7 @@ class EvolvabilityTests { constructor (c: String, a: Int, b: Int) : this(a, b, c, "wibble") } - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserializedCC = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -404,7 +409,7 @@ class EvolvabilityTests { constructor (c: String, a: Int) : this(a, c, "wibble") } - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserializedCC = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -451,9 +456,9 @@ class EvolvabilityTests { constructor (a: Int, b: Int, c: Int, d: Int) : this(-1, c, b, a, d) } - val url1 = EvolvabilityTests::class.java.getResource(resource1) - val url2 = EvolvabilityTests::class.java.getResource(resource2) - val url3 = EvolvabilityTests::class.java.getResource(resource3) + val url1 = EvolvabilityTests::class.java.getResource(resource1)!! + val url2 = EvolvabilityTests::class.java.getResource(resource2)!! + val url3 = EvolvabilityTests::class.java.getResource(resource3)!! val sb1 = url1.readBytes() val db1 = DeserializationInput(sf).deserialize(SerializedBytes(sb1)) @@ -500,7 +505,7 @@ class EvolvabilityTests { data class Outer(val a: Int, val b: Inner) - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val outer = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -565,9 +570,9 @@ class EvolvabilityTests { constructor (b: Int, c: Int, d: Int, e: Int, f: Int) : this(b, c, d, e, f, -1) } - val url1 = EvolvabilityTests::class.java.getResource(resource1) - val url2 = EvolvabilityTests::class.java.getResource(resource2) - val url3 = EvolvabilityTests::class.java.getResource(resource3) + val url1 = EvolvabilityTests::class.java.getResource(resource1)!! + val url2 = EvolvabilityTests::class.java.getResource(resource2)!! + val url3 = EvolvabilityTests::class.java.getResource(resource3)!! val sb1 = url1.readBytes() val db1 = DeserializationInput(sf).deserialize(SerializedBytes(sb1)) @@ -616,8 +621,8 @@ class EvolvabilityTests { @Ignore("Test fails after moving NetworkParameters and NotaryInfo into core from node-api") fun readBrokenNetworkParameters() { val sf = testDefaultFactory() - sf.register(net.corda.serialization.internal.amqp.custom.InstantSerializer(sf)) - sf.register(net.corda.serialization.internal.amqp.custom.PublicKeySerializer) + sf.register(InstantSerializer(sf)) + sf.register(PublicKeySerializer) // // filename breakdown @@ -627,7 +632,7 @@ class EvolvabilityTests { // val resource = "networkParams.r3corda.6a6b6f256" - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserializedC = DeserializationInput(sf).deserialize(SerializedBytes>(sc2)) val networkParams = DeserializationInput(sf).deserialize(deserializedC.raw) @@ -654,8 +659,8 @@ class EvolvabilityTests { @Test(timeout=300_000) fun `read corda 4-11 network parameters`() { val sf = testDefaultFactory() - sf.register(net.corda.serialization.internal.amqp.custom.InstantSerializer(sf)) - sf.register(net.corda.serialization.internal.amqp.custom.PublicKeySerializer) + sf.register(InstantSerializer(sf)) + sf.register(PublicKeySerializer) sf.register(net.corda.serialization.internal.amqp.custom.DurationSerializer(sf)) // @@ -666,7 +671,7 @@ class EvolvabilityTests { // val resource = "networkParams.4.11.58ecce1" - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserializedC = DeserializationInput(sf).deserialize(SerializedBytes>(sc2)) val networkParams = DeserializationInput(sf).deserialize(deserializedC.raw) @@ -691,8 +696,8 @@ class EvolvabilityTests { 3, listOf(NotaryInfo(DUMMY_NOTARY_PARTY, false)), 1000, 1000, Instant.EPOCH, 1, emptyMap()) val sf = testDefaultFactory() - sf.register(net.corda.serialization.internal.amqp.custom.InstantSerializer(sf)) - sf.register(net.corda.serialization.internal.amqp.custom.PublicKeySerializer) + sf.register(InstantSerializer(sf)) + sf.register(PublicKeySerializer) val testOutput = TestSerializationOutput(true, sf) val serialized = testOutput.serialize(networkParameters) @@ -704,7 +709,6 @@ class EvolvabilityTests { File(URI("$localPath/$resource")).writeBytes(signedAndSerialized.bytes) } - @Suppress("UNCHECKED_CAST") @Test(timeout=300_000) fun getterSetterEvolver1() { val resource = "EvolvabilityTests.getterSetterEvolver1" @@ -734,7 +738,7 @@ class EvolvabilityTests { constructor() : this(0, 0, 0, 0) } - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserializedC = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -759,7 +763,7 @@ class EvolvabilityTests { // Uncomment to recreate // File(URI("$localPath/$resource")).writeBytes(SerializationOutput(sf).serialize(Evolved("dronf", NewEnum.BUCKLE_MY_SHOE)).bytes) - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserialized = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -786,7 +790,7 @@ class EvolvabilityTests { // Uncomment to recreate // File(URI("$localPath/$resource")).writeBytes(SerializationOutput(sf).serialize(ParameterizedContainer(Parameterized(10, setOf(20)))).bytes) - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserialized = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) @@ -900,7 +904,7 @@ class EvolvabilityTests { File(URI("$localPath/$resource")).writeBytes(currentForm.bytes) */ - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val previousForm = SerializedBytes(sc2) val deserialized = DeserializationInput(sf).deserialize(previousForm) @@ -932,7 +936,7 @@ class EvolvabilityTests { //val A = MaybeSerializedSignedTransaction(SecureHash.randomSHA256(), null, null) //File(URI("$localPath/$resource")).writeBytes(SerializationOutput(sf).serialize(A).bytes) - val url = EvolvabilityTests::class.java.getResource(resource) + val url = EvolvabilityTests::class.java.getResource(resource)!! val sc2 = url.readBytes() val deserializedA = DeserializationInput(sf).deserialize(SerializedBytes(sc2)) diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/OptionalSerializationTests.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/OptionalSerializationTests.kt index 6a6264b900..4ba53edcdf 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/OptionalSerializationTests.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/OptionalSerializationTests.kt @@ -6,34 +6,29 @@ import net.corda.serialization.internal.amqp.testutils.TestSerializationOutput import net.corda.serialization.internal.amqp.testutils.deserialize import net.corda.serialization.internal.amqp.testutils.testDefaultFactory import net.corda.serialization.internal.carpenter.ClassCarpenterImpl -import org.hamcrest.Matchers.`is` import org.hamcrest.Matchers.equalTo -import org.junit.Assert +import org.hamcrest.Matchers.`is` import org.junit.Test -import java.util.* +import java.util.Optional +import org.hamcrest.MatcherAssert.assertThat class OptionalSerializationTests { - @Test(timeout=300_000) - fun setupEnclosedSerializationTest() { - @Test(timeout=300_000) - fun `java optionals should serialize`() { - val factory = SerializerFactoryBuilder.build(AllWhitelist, - ClassCarpenterImpl(AllWhitelist, ClassLoader.getSystemClassLoader()) - ) - factory.register(OptionalSerializer(factory)) - val obj = Optional.ofNullable("YES") - val bytes = TestSerializationOutput(true, factory).serialize(obj) - val deserializerFactory = testDefaultFactory().apply { - register(OptionalSerializer(this)) - } - - val deserialized = DeserializationInput(factory).deserialize(bytes) - val deserialized2 = DeserializationInput(deserializerFactory).deserialize(bytes) - Assert.assertThat(deserialized, `is`(equalTo(deserialized2))) - Assert.assertThat(obj, `is`(equalTo(deserialized2))) + @Test(timeout = 300_000) + fun `java optionals should serialize`() { + val factory = SerializerFactoryBuilder.build(AllWhitelist, + ClassCarpenterImpl(AllWhitelist, ClassLoader.getSystemClassLoader()) + ) + factory.register(OptionalSerializer(factory)) + val obj = Optional.ofNullable("YES") + val bytes = TestSerializationOutput(true, factory).serialize(obj) + val deserializerFactory = testDefaultFactory().apply { + register(OptionalSerializer(this)) } - `java optionals should serialize`() + val deserialized = DeserializationInput(factory).deserialize(bytes) + val deserialized2 = DeserializationInput(deserializerFactory).deserialize(bytes) + assertThat(deserialized, `is`(equalTo(deserialized2))) + assertThat(obj, `is`(equalTo(deserialized2))) } -} \ No newline at end of file +} diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/StaticInitialisationOfSerializedObjectTest.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/StaticInitialisationOfSerializedObjectTest.kt index bcdf0ee1e4..1e1dd94422 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/StaticInitialisationOfSerializedObjectTest.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/StaticInitialisationOfSerializedObjectTest.kt @@ -5,6 +5,7 @@ import net.corda.core.serialization.SerializedBytes import net.corda.serialization.internal.AllWhitelist import net.corda.serialization.internal.amqp.testutils.deserialize import net.corda.serialization.internal.carpenter.ClassCarpenterImpl +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.Ignore import org.junit.Test @@ -40,9 +41,11 @@ class C2(var b: Int) { } class StaticInitialisationOfSerializedObjectTest { - @Test(expected = java.lang.ExceptionInInitializerError::class, timeout=300_000) + @Test(timeout=300_000) fun itBlowsUp() { - C() + assertThatExceptionOfType(ExceptionInInitializerError::class.java).isThrownBy { + C() + } } @Ignore("Suppressing this, as it depends on obtaining internal access to serialiser cache") diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/custom/OptionalSerializerTest.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/custom/OptionalSerializerTest.kt index 5692c31b37..ac84d23273 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/custom/OptionalSerializerTest.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/custom/OptionalSerializerTest.kt @@ -3,10 +3,10 @@ package net.corda.serialization.internal.amqp.custom import net.corda.serialization.internal.amqp.SerializerFactory import org.hamcrest.CoreMatchers.`is` import org.hamcrest.CoreMatchers.nullValue -import org.junit.Assert.assertThat import org.junit.Test import org.mockito.Mockito import java.util.* +import org.hamcrest.MatcherAssert.assertThat class OptionalSerializerTest { @Test(timeout=300_000) diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/testutils/AMQPTestUtils.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/testutils/AMQPTestUtils.kt index 7fc2a9d4d0..e715d130e6 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/testutils/AMQPTestUtils.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/testutils/AMQPTestUtils.kt @@ -15,6 +15,8 @@ import java.io.File.separatorChar import java.io.NotSerializableException import java.nio.file.Path import java.nio.file.StandardCopyOption.REPLACE_EXISTING +import kotlin.io.path.div +import kotlin.io.path.isDirectory /** * For tests that want to see inside the serializer registry @@ -99,7 +101,7 @@ fun Any.testResourceName(): String = "${javaClass.simpleName}.${testName()}" internal object ProjectStructure { val projectRootDir: Path = run { - var dir = javaClass.getResource("/").toPath() + var dir = javaClass.getResource("/")!!.toPath() while (!(dir / ".git").isDirectory()) { dir = dir.parent } @@ -112,7 +114,7 @@ fun Any.writeTestResource(bytes: OpaqueBytes) { bytes.open().copyTo(dir / testResourceName(), REPLACE_EXISTING) } -fun Any.readTestResource(): ByteArray = javaClass.getResourceAsStream(testResourceName()).readBytes() +fun Any.readTestResource(): ByteArray = javaClass.getResourceAsStream(testResourceName())!!.readFully() @Throws(NotSerializableException::class) inline fun DeserializationInput.deserializeAndReturnEnvelope( diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenterTest.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenterTest.kt index 1c315f1c5f..47ce185a73 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenterTest.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenterTest.kt @@ -3,9 +3,11 @@ package net.corda.serialization.internal.carpenter import net.corda.core.internal.uncheckedCast import net.corda.serialization.internal.AllWhitelist import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException import org.junit.Test import java.beans.Introspector import java.lang.reflect.Field +import java.lang.reflect.InvocationTargetException import java.lang.reflect.Method import javax.annotation.Nonnull import javax.annotation.Nullable @@ -95,10 +97,12 @@ class ClassCarpenterTest { assertEquals("Person{age=32, name=Mike}", i.toString()) } - @Test(expected = DuplicateNameException::class, timeout=300_000) + @Test(timeout=300_000) fun duplicates() { cc.build(ClassSchema("gen.EmptyClass", emptyMap())) - cc.build(ClassSchema("gen.EmptyClass", emptyMap())) + assertThatExceptionOfType(DuplicateNameException::class.java).isThrownBy { + cc.build(ClassSchema("gen.EmptyClass", emptyMap())) + } } @Test(timeout=300_000) @@ -301,7 +305,7 @@ class ClassCarpenterTest { assertEquals(testD, i["d"]) } - @Test(expected = java.lang.IllegalArgumentException::class, timeout=300_000) + @Test(timeout=300_000) fun `null parameter small int`() { val className = "iEnjoySwede" val schema = ClassSchema( @@ -310,17 +314,16 @@ class ClassCarpenterTest { val clazz = cc.build(schema) val a: Int? = null - clazz.constructors[0].newInstance(a) + assertThatIllegalArgumentException().isThrownBy { + clazz.constructors[0].newInstance(a) + } } - @Test(expected = NullablePrimitiveException::class, timeout=300_000) + @Test(timeout=300_000) fun `nullable parameter small int`() { - val className = "iEnjoySwede" - val schema = ClassSchema( - "gen.$className", - mapOf("a" to NullableField(Int::class.java))) - - cc.build(schema) + assertThatExceptionOfType(NullablePrimitiveException::class.java).isThrownBy { + NullableField(Int::class.java) + } } @Test(timeout=300_000) @@ -351,7 +354,7 @@ class ClassCarpenterTest { clazz.constructors[0].newInstance(a) } - @Test(expected = java.lang.reflect.InvocationTargetException::class, timeout=300_000) + @Test(timeout=300_000) fun `non nullable parameter integer with null`() { val className = "iEnjoyWibble" val schema = ClassSchema( @@ -361,7 +364,9 @@ class ClassCarpenterTest { val clazz = cc.build(schema) val a: Int? = null - clazz.constructors[0].newInstance(a) + assertThatExceptionOfType(InvocationTargetException::class.java).isThrownBy { + clazz.constructors[0].newInstance(a) + }.withCauseInstanceOf(NullPointerException::class.java) } @Test(timeout=300_000) @@ -383,7 +388,7 @@ class ClassCarpenterTest { assertEquals("$className{a=[1, 2, 3]}", i.toString()) } - @Test(expected = java.lang.reflect.InvocationTargetException::class, timeout=300_000) + @Test(timeout=300_000) fun `nullable int array throws`() { val className = "iEnjoySwede" val schema = ClassSchema( @@ -393,7 +398,9 @@ class ClassCarpenterTest { val clazz = cc.build(schema) val a: IntArray? = null - clazz.constructors[0].newInstance(a) + assertThatExceptionOfType(InvocationTargetException::class.java).isThrownBy { + clazz.constructors[0].newInstance(a) + }.withCauseInstanceOf(NullPointerException::class.java) } @Test(timeout=300_000) diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenterTestUtils.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenterTestUtils.kt index 334bd18b22..c58d07ccf2 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenterTestUtils.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenterTestUtils.kt @@ -1,6 +1,7 @@ package net.corda.serialization.internal.carpenter import com.google.common.reflect.TypeToken +import net.corda.core.internal.capitalize import net.corda.core.serialization.ClassWhitelist import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializedBytes diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/EnumClassTests.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/EnumClassTests.kt index 02092e6416..fa26707c1f 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/EnumClassTests.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/EnumClassTests.kt @@ -50,7 +50,7 @@ class EnumClassTests : AmqpCarpenterBase(AllWhitelist) { @Test(timeout=300_000) fun manyValues() { val enumConstants = listOf("AAA", "BBB", "CCC", "DDD", "EEE", "FFF", - "GGG", "HHH", "III", "JJJ").associateBy({ it }, { EnumField() }) + "GGG", "HHH", "III", "JJJ").associateWith { EnumField() } val schema = EnumSchema("gen.enum", enumConstants) val clazz = cc.build(schema) @@ -67,7 +67,7 @@ class EnumClassTests : AmqpCarpenterBase(AllWhitelist) { @Test(timeout=300_000) fun assignment() { - val enumConstants = listOf("AAA", "BBB", "CCC", "DDD", "EEE", "FFF").associateBy({ it }, { EnumField() }) + val enumConstants = listOf("AAA", "BBB", "CCC", "DDD", "EEE", "FFF").associateWith { EnumField() } val schema = EnumSchema("gen.enum", enumConstants) val clazz = cc.build(schema) @@ -88,7 +88,7 @@ class EnumClassTests : AmqpCarpenterBase(AllWhitelist) { val cc2 = ClassCarpenterImpl(whitelist = AllWhitelist) val schema1 = EnumSchema("gen.enum", - listOf("AAA", "BBB", "CCC", "DDD", "EEE", "FFF").associateBy({ it }, { EnumField() })) + listOf("AAA", "BBB", "CCC", "DDD", "EEE", "FFF").associateWith { EnumField() }) val enumClazz = cc2.build(schema1) diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/model/LocalTypeModelTests.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/model/LocalTypeModelTests.kt index 8d74f3eef8..aebe26a7f7 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/model/LocalTypeModelTests.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/model/LocalTypeModelTests.kt @@ -214,7 +214,7 @@ class LocalTypeModelTests { TWO; override fun toString(): String { - return "[${name.toLowerCase()}]" + return "[${name.lowercase(Locale.getDefault())}]" } } diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/model/TypeIdentifierTests.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/model/TypeIdentifierTests.kt index 9792b5416f..6c04bafc7e 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/model/TypeIdentifierTests.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/model/TypeIdentifierTests.kt @@ -1,7 +1,6 @@ package net.corda.serialization.internal.model import com.google.common.reflect.TypeToken -import net.corda.serialization.internal.model.TypeIdentifier.* import org.junit.Test import java.lang.reflect.Type import kotlin.test.assertEquals @@ -71,4 +70,4 @@ class TypeIdentifierTests { val localType = identifier.getLocalType(classLoader = ClassLoader.getSystemClassLoader()) assertIdentified(localType, identifier.prettyPrint()) } -} \ No newline at end of file +} diff --git a/settings.gradle b/settings.gradle index eb8a9cc0ec..6193fd6ef2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -23,8 +23,15 @@ pluginManagement { mavenLocal() gradlePluginPortal() maven { url "${publicArtifactURL}/corda-dependencies" } + maven { url "${publicArtifactURL}/corda-dependencies-dev" } } } + + plugins { + id 'org.jetbrains.kotlin.jvm' version kotlin_version + id 'org.jetbrains.kotlin.plugin.allopen' version kotlin_version + id 'org.jetbrains.kotlin.plugin.jpa' version kotlin_version + } } // The project is named 'corda-project' and not 'corda' because if this is named the same as the // output JAR from the capsule then the buildCordaJAR task goes into an infinite loop. @@ -35,12 +42,14 @@ include 'confidential-identities' include 'finance:contracts' include 'finance:workflows' include 'core' +include 'core-1.2' include 'core-tests' include 'docs' include 'node-api' include 'node-api-tests' include 'node' include 'node:capsule' +include 'verifier' include 'client:jackson' include 'client:jfx' include 'client:mock' @@ -68,7 +77,7 @@ include 'core-test-utils' } include 'tools:explorer' include 'tools:explorer:capsule' -include 'tools:demobench' +//include 'tools:demobench' include 'tools:loadtest' include 'tools:graphs' include 'tools:bootstrapper' @@ -94,12 +103,14 @@ include 'samples:cordapp-configuration:workflows' include 'samples:network-verifier:contracts' include 'samples:network-verifier:workflows' include 'serialization' +include 'serialization-1.2' include 'serialization-tests' include 'testing:cordapps:dbfailure:dbfcontracts' include 'testing:cordapps:dbfailure:dbfworkflows' include 'testing:cordapps:missingmigration' include 'testing:cordapps:sleeping' include 'testing:cordapps:cashobservers' +include 'testing:cordapps:4.11-workflows' // Common libraries - start include 'common-validation' @@ -113,24 +124,8 @@ include 'common-logging' project(":common-logging").projectDir = new File("$settingsDir/common/logging") // Common libraries - end +apply from: 'buildCacheSettings.gradle' include 'detekt-plugins' include 'tools:error-tool' -buildCache { - local { enabled = false } - remote(HttpBuildCache) { - url = "${gradleEnterpriseUrl}/cache/" - credentials { - username = settings.ext.find('BUILD_CACHE_CREDENTIALS_USR') ?: System.getenv('BUILD_CACHE_CREDENTIALS_USR') - password = settings.ext.find('BUILD_CACHE_CREDENTIALS_PSW') ?: System.getenv('BUILD_CACHE_CREDENTIALS_PSW') - } - if (System.getenv().containsKey("JENKINS_URL")) { - push = true - enabled = true - } else { - push = false - enabled = false - } - } -} diff --git a/testing/DockerfileBase b/testing/DockerfileBase index 25f77adf2d..425779948e 100644 --- a/testing/DockerfileBase +++ b/testing/DockerfileBase @@ -3,17 +3,10 @@ ENV GRADLE_USER_HOME=/tmp/gradle RUN mkdir /tmp/gradle && mkdir -p /home/root/.m2/repository RUN apt-get update && apt-get install -y curl libatomic1 && \ - curl -O https://cdn.azul.com/zulu/bin/zulu8.40.0.25-ca-jdk8.0.222-linux_amd64.deb && \ - apt-get install -y java-common && apt install -y ./zulu8.40.0.25-ca-jdk8.0.222-linux_amd64.deb && \ + curl -O https://cdn.azul.com/zulu/bin/zulu17.46.19-ca-jdk17.0.9-linux_amd64.deb && \ + apt-get install -y java-common && apt install -y ./zulu17.46.19-ca-jdk17.0.9-linux_amd64.deb && \ apt-get clean && \ - rm -f zulu8.40.0.25-ca-jdk8.0.222-linux_amd64.deb && \ - curl -O https://cdn.azul.com/zulu/bin/zulu8.40.0.25-ca-fx-jdk8.0.222-linux_x64.tar.gz && \ - mv /zulu8.40.0.25-ca-fx-jdk8.0.222-linux_x64.tar.gz /usr/lib/jvm/ && \ - cd /usr/lib/jvm/ && \ - tar -zxvf zulu8.40.0.25-ca-fx-jdk8.0.222-linux_x64.tar.gz && \ - rm -rf zulu-8-amd64 && \ - mv zulu8.40.0.25-ca-fx-jdk8.0.222-linux_x64 zulu-8-amd64 && \ - rm -f zulu8.40.0.25-ca-fx-jdk8.0.222-linux_x64.tar.gz && \ + rm -f zulu17.46.19-ca-jdk17.0.9-linux_amd64.deb && \ cd / && mkdir -p /tmp/source diff --git a/testing/DockerfileJDK11Azul b/testing/DockerfileJDK11Azul deleted file mode 100644 index 655e49406d..0000000000 --- a/testing/DockerfileJDK11Azul +++ /dev/null @@ -1,3 +0,0 @@ -FROM stefanotestingcr.azurecr.io/buildbase:11latest -COPY . /tmp/source -CMD cd /tmp/source && GRADLE_USER_HOME=/tmp/gradle ./gradlew clean testClasses integrationTestClasses --parallel --info diff --git a/testing/cordapps/4.11-workflows/build.gradle b/testing/cordapps/4.11-workflows/build.gradle new file mode 100644 index 0000000000..86b1ff21e5 --- /dev/null +++ b/testing/cordapps/4.11-workflows/build.gradle @@ -0,0 +1,17 @@ +apply plugin: 'corda.kotlin-1.2' + +dependencies { + compileOnly "net.corda:corda-core:4.11.+" + compileOnly "net.corda:corda-finance-contracts:4.11.+" + compileOnly "net.corda:corda-finance-workflows:4.11.+" +} + +jar { + archiveBaseName = "4.11-workflows-cordapp" + archiveVersion = "" + manifest { + // This JAR is part of Corda's testing framework. + // Driver will not include it as part of an out-of-process node. + attributes('Corda-Testing': true) + } +} diff --git a/testing/cordapps/4.11-workflows/src/main/kotlin/net/corda/testing/cordapps/workflows411/IssueAndChangeNotaryFlow.kt b/testing/cordapps/4.11-workflows/src/main/kotlin/net/corda/testing/cordapps/workflows411/IssueAndChangeNotaryFlow.kt new file mode 100644 index 0000000000..ccbcf5b3ee --- /dev/null +++ b/testing/cordapps/4.11-workflows/src/main/kotlin/net/corda/testing/cordapps/workflows411/IssueAndChangeNotaryFlow.kt @@ -0,0 +1,30 @@ +package net.corda.testing.cordapps.workflows411 + +import co.paralleluniverse.fibers.Suspendable +import net.corda.core.crypto.SecureHash +import net.corda.core.flows.FlowLogic +import net.corda.core.flows.NotaryChangeFlow +import net.corda.core.flows.StartableByRPC +import net.corda.core.identity.Party +import net.corda.core.transactions.NotaryChangeWireTransaction +import net.corda.core.utilities.OpaqueBytes +import net.corda.finance.DOLLARS +import net.corda.finance.contracts.asset.Cash +import net.corda.finance.flows.CashIssueFlow + +// We need a separate flow as NotaryChangeFlow is not StartableByRPC +@StartableByRPC +class IssueAndChangeNotaryFlow(private val oldNotary: Party, private val newNotary: Party) : FlowLogic() { + @Suppress("MagicNumber") + @Suspendable + override fun call(): SecureHash { + subFlow(CashIssueFlow(10.DOLLARS, OpaqueBytes.of(0x01), oldNotary)) + val oldState = serviceHub.vaultService.queryBy(Cash.State::class.java).states.single() + check(oldState.state.notary == oldNotary) { oldState.state.notary } + val newState = subFlow(NotaryChangeFlow(oldState, newNotary)) + check(newState.state.notary == newNotary) { newState.state.notary } + val notaryChangeTx = checkNotNull(serviceHub.validatedTransactions.getTransaction(newState.ref.txhash)) + check(notaryChangeTx.coreTransaction is NotaryChangeWireTransaction) { notaryChangeTx.coreTransaction } + return notaryChangeTx.id + } +} diff --git a/testing/cordapps/cashobservers/build.gradle b/testing/cordapps/cashobservers/build.gradle index 8222caae16..4479fab334 100644 --- a/testing/cordapps/cashobservers/build.gradle +++ b/testing/cordapps/cashobservers/build.gradle @@ -1,10 +1,13 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.cordapp' -//apply plugin: 'net.corda.plugins.quasar-utils' +apply plugin: 'net.corda.plugins.quasar-utils' dependencies { - cordaCompile project(":core") + cordaProvided project(":core") + cordapp project(':finance:contracts') cordapp project(':finance:workflows') + + cordaProvided "org.slf4j:slf4j-api:$slf4j_version" } jar { @@ -14,6 +17,7 @@ jar { // Driver will not include it as part of an out-of-process node. attributes('Corda-Testing': true) } + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } cordapp { @@ -28,4 +32,4 @@ cordapp { signing { enabled false } -} \ No newline at end of file +} diff --git a/testing/cordapps/dbfailure/dbfcontracts/build.gradle b/testing/cordapps/dbfailure/dbfcontracts/build.gradle index 886a9f9728..5426c1a8ef 100644 --- a/testing/cordapps/dbfailure/dbfcontracts/build.gradle +++ b/testing/cordapps/dbfailure/dbfcontracts/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' //apply plugin: 'net.corda.plugins.cordapp' //apply plugin: 'net.corda.plugins.quasar-utils' @@ -10,7 +10,9 @@ repositories { } dependencies { - compile project(":core") + implementation project(":core") + + api "javax.persistence:javax.persistence-api:2.2" } jar { @@ -20,4 +22,4 @@ jar { // Driver will not include it as part of an out-of-process node. attributes('Corda-Testing': true) } -} \ No newline at end of file +} diff --git a/testing/cordapps/dbfailure/dbfworkflows/build.gradle b/testing/cordapps/dbfailure/dbfworkflows/build.gradle index 221b063236..ba34f293dc 100644 --- a/testing/cordapps/dbfailure/dbfworkflows/build.gradle +++ b/testing/cordapps/dbfailure/dbfworkflows/build.gradle @@ -1,10 +1,15 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.cordapp' -//apply plugin: 'net.corda.plugins.quasar-utils' +apply plugin: 'net.corda.plugins.quasar-utils' dependencies { - cordaCompile project(":core") + cordaProvided project(":core") cordapp project(":testing:cordapps:dbfailure:dbfcontracts") + + cordaProvided "org.hibernate:hibernate-core:$hibernate_version" + cordaProvided "io.reactivex:rxjava:$rxjava_version" + cordaProvided "org.slf4j:slf4j-api:$slf4j_version" + cordaProvided "co.paralleluniverse:quasar-core:$quasar_version" } jar { @@ -28,4 +33,4 @@ cordapp { signing { enabled false } -} \ No newline at end of file +} diff --git a/testing/cordapps/dbfailure/dbfworkflows/src/main/kotlin/com/r3/dbfailure/workflows/CreateStateFlow.kt b/testing/cordapps/dbfailure/dbfworkflows/src/main/kotlin/com/r3/dbfailure/workflows/CreateStateFlow.kt index af1d9a20bd..eb02cc4a2c 100644 --- a/testing/cordapps/dbfailure/dbfworkflows/src/main/kotlin/com/r3/dbfailure/workflows/CreateStateFlow.kt +++ b/testing/cordapps/dbfailure/dbfworkflows/src/main/kotlin/com/r3/dbfailure/workflows/CreateStateFlow.kt @@ -36,25 +36,25 @@ object CreateStateFlow { } fun errorTargetsToNum(vararg targets: ErrorTarget): Int { - return targets.map { it.targetNumber }.sum() + return targets.sumOf { it.targetNumber } } private val targetMap = ErrorTarget.values().associateBy(ErrorTarget::targetNumber) fun getServiceTarget(target: Int?): ErrorTarget { - return target?.let { targetMap.getValue(((it/10000) % 1000)*10000) } ?: CreateStateFlow.ErrorTarget.NoError + return target?.let { targetMap.getValue(((it/10000) % 1000)*10000) } ?: ErrorTarget.NoError } fun getServiceExceptionHandlingTarget(target: Int?): ErrorTarget { - return target?.let { targetMap.getValue(((it / 1000) % 10) * 1000) } ?: CreateStateFlow.ErrorTarget.NoError + return target?.let { targetMap.getValue(((it / 1000) % 10) * 1000) } ?: ErrorTarget.NoError } fun getTxTarget(target: Int?): ErrorTarget { - return target?.let { targetMap.getValue(((it / 10) % 10) * 10) } ?: CreateStateFlow.ErrorTarget.NoError + return target?.let { targetMap.getValue(((it / 10) % 10) * 10) } ?: ErrorTarget.NoError } fun getFlowTarget(target: Int?): ErrorTarget { - return target?.let { targetMap.getValue(((it / 100) % 10) * 100) } ?: CreateStateFlow.ErrorTarget.NoError + return target?.let { targetMap.getValue(((it / 100) % 10) * 100) } ?: ErrorTarget.NoError } @InitiatingFlow @@ -73,7 +73,7 @@ object CreateStateFlow { val state = DbFailureContract.TestState( UniqueIdentifier(), listOf(ourIdentity), - if (txTarget == CreateStateFlow.ErrorTarget.TxInvalidState) null else randomValue, + if (txTarget == ErrorTarget.TxInvalidState) null else randomValue, errorTarget, ourIdentity ) val txCommand = Command(DbFailureContract.Commands.Create(), ourIdentity.owningKey) @@ -88,12 +88,11 @@ object CreateStateFlow { val signedTx = serviceHub.signInitialTransaction(txBuilder) - @Suppress("TooGenericExceptionCaught") // this is fully intentional here, to allow twiddling with exceptions according to config try { logger.info("Test flow: recording transaction") serviceHub.recordTransactions(signedTx) } catch (t: Throwable) { - if (getFlowTarget(errorTarget) == CreateStateFlow.ErrorTarget.FlowSwallowErrors) { + if (getFlowTarget(errorTarget) == ErrorTarget.FlowSwallowErrors) { logger.info("Test flow: Swallowing all exception! Muahahaha!", t) } else { logger.info("Test flow: caught exception - rethrowing") diff --git a/testing/cordapps/dbfailure/dbfworkflows/src/main/kotlin/com/r3/dbfailure/workflows/DbListenerService.kt b/testing/cordapps/dbfailure/dbfworkflows/src/main/kotlin/com/r3/dbfailure/workflows/DbListenerService.kt index d28f9f9bd1..aa8ca2efcb 100644 --- a/testing/cordapps/dbfailure/dbfworkflows/src/main/kotlin/com/r3/dbfailure/workflows/DbListenerService.kt +++ b/testing/cordapps/dbfailure/dbfworkflows/src/main/kotlin/com/r3/dbfailure/workflows/DbListenerService.kt @@ -44,7 +44,6 @@ class DbListenerService(services: AppServiceHub) : SingletonSerializeAsToken() { produced.forEach { val contractState = it.state.data as? DbFailureContract.TestState - @Suppress("TooGenericExceptionCaught") // this is fully intentional here, to allow twiddling with exceptions try { when (CreateStateFlow.getServiceTarget(contractState?.errorTarget)) { CreateStateFlow.ErrorTarget.ServiceSqlSyntaxError -> { @@ -161,7 +160,7 @@ class DbListenerService(services: AppServiceHub) : SingletonSerializeAsToken() { } if (onError != null) { - val onErrorWrapper: ((Throwable) -> Unit)? = { + val onErrorWrapper: (Throwable) -> Unit = { onErrorVisited?.let { it(services.myInfo.legalIdentities.first()) } diff --git a/testing/cordapps/missingmigration/build.gradle b/testing/cordapps/missingmigration/build.gradle index e004a34255..9be966f4df 100644 --- a/testing/cordapps/missingmigration/build.gradle +++ b/testing/cordapps/missingmigration/build.gradle @@ -1,9 +1,11 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' //apply plugin: 'net.corda.plugins.cordapp' //apply plugin: 'net.corda.plugins.quasar-utils' dependencies { - compile project(":core") + implementation project(":core") + implementation "javax.persistence:javax.persistence-api:2.2" + implementation "org.slf4j:slf4j-api:$slf4j_version" } jar { @@ -13,4 +15,4 @@ jar { // Driver will not include it as part of an out-of-process node. attributes('Corda-Testing': true) } -} \ No newline at end of file +} diff --git a/testing/cordapps/sleeping/build.gradle b/testing/cordapps/sleeping/build.gradle index 04ee3472a8..b32ca93417 100644 --- a/testing/cordapps/sleeping/build.gradle +++ b/testing/cordapps/sleeping/build.gradle @@ -1,7 +1,8 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' dependencies { - compile project(":core") + implementation project(":core") + implementation "co.paralleluniverse:quasar-core:$quasar_version" } jar { @@ -11,4 +12,4 @@ jar { // Driver will not include it as part of an out-of-process node. attributes('Corda-Testing': true) } -} \ No newline at end of file +} diff --git a/testing/core-test-utils/build.gradle b/testing/core-test-utils/build.gradle index 5d44264336..84e754f61f 100644 --- a/testing/core-test-utils/build.gradle +++ b/testing/core-test-utils/build.gradle @@ -1,17 +1,39 @@ plugins { id 'org.jetbrains.kotlin.jvm' - id 'net.corda.plugins.publish-utils' id 'net.corda.plugins.api-scanner' - id 'com.jfrog.artifactory' id 'java-library' + id 'corda.common-publishing' } description 'Core test types and helpers for testing Corda' dependencies { implementation project(':core') + implementation project(':node-api') + implementation project(':serialization') api project(':test-common') + implementation "io.netty:netty-handler-proxy:$netty_version" + api "org.jetbrains.kotlin:kotlin-test" + + // Bouncy castle support needed for X509 certificate manipulation + implementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}" + implementation "org.bouncycastle:bcpkix-lts8on:${bouncycastle_version}" + + implementation "org.slf4j:slf4j-api:$slf4j_version" + implementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" + implementation "org.mockito:mockito-core:$mockito_version" + implementation "com.natpryce:hamkrest:$hamkrest_version" + implementation "com.google.guava:guava-testlib:$guava_version" + implementation "io.reactivex:rxjava:$rxjava_version" + implementation "junit:junit:$junit_version" + implementation("org.apache.activemq:artemis-server:${artemis_version}") { + exclude group: 'org.apache.commons', module: 'commons-dbcp2' + exclude group: 'org.jgroups', module: 'jgroups' + } + + testImplementation "org.assertj:assertj-core:${assertj_version}" + testImplementation 'org.hamcrest:hamcrest-library:2.1' } jar { @@ -23,6 +45,11 @@ jar { } } -publish { - name jar.baseName -} \ No newline at end of file +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } +} diff --git a/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/CoreTestUtils.kt b/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/CoreTestUtils.kt index 66b8810232..b8c5d71d4d 100644 --- a/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/CoreTestUtils.kt +++ b/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/CoreTestUtils.kt @@ -5,10 +5,19 @@ import net.corda.coretesting.internal.stubs.CertificateStoreStubs import net.corda.nodeapi.internal.config.MutualSslConfiguration import net.corda.nodeapi.internal.loadDevCaTrustStore import net.corda.nodeapi.internal.registerDevP2pCertificates +import java.nio.file.FileSystem +import java.nio.file.FileSystems import java.nio.file.Files +import java.nio.file.Path +import java.util.jar.Attributes +import java.util.jar.JarOutputStream +import java.util.jar.Manifest +import kotlin.io.path.exists +import kotlin.io.path.fileSize +import kotlin.io.path.inputStream +import kotlin.io.path.outputStream fun configureTestSSL(legalName: CordaX500Name): MutualSslConfiguration { - val certificatesDirectory = Files.createTempDirectory("certs") val config = CertificateStoreStubs.P2P.withCertificatesDirectory(certificatesDirectory) if (config.trustStore.getOptional() == null) { @@ -19,3 +28,24 @@ fun configureTestSSL(legalName: CordaX500Name): MutualSslConfiguration { } return config } + +inline fun Path.useZipFile(block: (FileSystem) -> T): T { + if (fileSize() == 0L) { + // Need to first create an empty jar before it can be opened + JarOutputStream(outputStream()).close() + } + return FileSystems.newFileSystem(this).use(block) +} + +inline fun Path.modifyJarManifest(block: (Manifest) -> T): T? { + return useZipFile { zipFs -> + val manifestFile = zipFs.getPath("META-INF", "MANIFEST.MF") + if (!manifestFile.exists()) return null + val manifest = manifestFile.inputStream().use(::Manifest) + val result = block(manifest) + manifestFile.outputStream().use(manifest::write) + result + } +} + +fun Attributes.delete(name: String): String? = remove(Attributes.Name(name)) as String? diff --git a/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/InternalSerializationTestHelpers.kt b/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/InternalSerializationTestHelpers.kt index 6345dd7549..28cf91fc2b 100644 --- a/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/InternalSerializationTestHelpers.kt +++ b/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/InternalSerializationTestHelpers.kt @@ -7,7 +7,7 @@ import net.corda.core.serialization.CustomSerializationScheme import net.corda.core.serialization.SerializationCustomSerializer import net.corda.core.serialization.SerializationWhitelist import net.corda.core.serialization.internal.SerializationEnvironment -import net.corda.nodeapi.internal.serialization.CustomSerializationSchemeAdapter +import net.corda.serialization.internal.verifier.CustomSerializationSchemeAdapter import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme import net.corda.nodeapi.internal.serialization.kryo.KRYO_CHECKPOINT_CONTEXT import net.corda.nodeapi.internal.serialization.kryo.KryoCheckpointSerializer diff --git a/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/RigorousMock.kt b/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/RigorousMock.kt index fcd9b085aa..4a9f4c7e5d 100644 --- a/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/RigorousMock.kt +++ b/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/RigorousMock.kt @@ -1,7 +1,7 @@ @file: Suppress("MatchingDeclarationName") package net.corda.coretesting.internal -import com.nhaarman.mockito_kotlin.doAnswer +import org.mockito.kotlin.doAnswer import net.corda.core.utilities.contextLogger import org.mockito.Mockito import org.mockito.exceptions.base.MockitoException @@ -17,7 +17,7 @@ import java.util.concurrent.ConcurrentHashMap /** * A method on a mock was called, but no behaviour was previously specified for that method. - * You can use [com.nhaarman.mockito_kotlin.doReturn] or similar to specify behaviour, see Mockito documentation for details. + * You can use [org.mockito.kotlin.doReturn] or similar to specify behaviour, see Mockito documentation for details. */ class UndefinedMockBehaviorException(message: String) : RuntimeException(message) @@ -79,7 +79,7 @@ private class SpectatorDefaultAnswer : DefaultAnswer() { ?: method.returnType!! } - private fun newSpectator(invocation: InvocationOnMock) = spectator(type)!!.also { log.info("New spectator {} for: {}", it, invocation.arguments) } + private fun newSpectator(invocation: InvocationOnMock) = spectator(type).also { log.info("New spectator {} for: {}", it, invocation.arguments) } private val spectators = try { val first = newSpectator(invocation) ConcurrentHashMap().apply { put(invocation, first) } diff --git a/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/performance/Rate.kt b/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/performance/Rate.kt index 0f880d962e..113e91bf70 100644 --- a/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/performance/Rate.kt +++ b/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/performance/Rate.kt @@ -2,6 +2,7 @@ package net.corda.coretesting.internal.performance import java.time.Duration import java.time.temporal.ChronoUnit +import java.util.Locale import java.util.concurrent.TimeUnit /** @@ -23,7 +24,7 @@ data class Rate( */ operator fun times(inUnit: TimeUnit): Long = inUnit.convert(numberOfEvents, perTimeUnit) - override fun toString(): String = "$numberOfEvents / ${perTimeUnit.name.dropLast(1).toLowerCase()}" // drop the "s" at the end + override fun toString(): String = "$numberOfEvents / ${perTimeUnit.name.dropLast(1).lowercase(Locale.getDefault())}" // drop the "s" at the end } operator fun Long.div(timeUnit: TimeUnit) = Rate(this, timeUnit) diff --git a/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/stubs/CertificateStoreStubs.kt b/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/stubs/CertificateStoreStubs.kt index 2f90555c44..a84e51f32a 100644 --- a/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/stubs/CertificateStoreStubs.kt +++ b/testing/core-test-utils/src/main/kotlin/net/corda/coretesting/internal/stubs/CertificateStoreStubs.kt @@ -1,6 +1,5 @@ package net.corda.coretesting.internal.stubs -import net.corda.core.internal.div import net.corda.nodeapi.internal.DEV_CA_KEY_STORE_PASS import net.corda.nodeapi.internal.DEV_CA_TRUST_STORE_PASS import net.corda.nodeapi.internal.DEV_CA_TRUST_STORE_PRIVATE_KEY_PASS @@ -9,6 +8,7 @@ import net.corda.nodeapi.internal.config.MutualSslConfiguration import net.corda.nodeapi.internal.config.SslConfiguration import java.nio.file.Path import java.time.Duration +import kotlin.io.path.div class CertificateStoreStubs { diff --git a/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/SerializationEnvironmentRule.kt b/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/SerializationEnvironmentRule.kt index 7052bae391..4fa8b80a61 100644 --- a/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/SerializationEnvironmentRule.kt +++ b/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/SerializationEnvironmentRule.kt @@ -1,8 +1,8 @@ package net.corda.testing.core -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.doAnswer -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.whenever import net.corda.core.internal.staticField import net.corda.core.serialization.SerializationFactory import net.corda.core.serialization.internal.SerializationEnvironment diff --git a/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/TestUtils.kt b/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/TestUtils.kt index 175f52f5ae..43e12ece4f 100644 --- a/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/TestUtils.kt +++ b/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/TestUtils.kt @@ -1,5 +1,5 @@ @file:JvmName("TestUtils") -@file:Suppress("TooGenericExceptionCaught", "MagicNumber", "ComplexMethod", "LongParameterList") +@file:Suppress("MagicNumber", "ComplexMethod", "LongParameterList") package net.corda.testing.core diff --git a/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/internal/CheckpointSerializationTestHelpers.kt b/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/internal/CheckpointSerializationTestHelpers.kt index 78157094e8..06ca8bb66e 100644 --- a/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/internal/CheckpointSerializationTestHelpers.kt +++ b/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/internal/CheckpointSerializationTestHelpers.kt @@ -1,8 +1,8 @@ package net.corda.testing.core.internal -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.doAnswer -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.whenever import net.corda.core.internal.staticField import net.corda.core.serialization.internal.SerializationEnvironment import net.corda.core.serialization.internal.effectiveSerializationEnv diff --git a/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/internal/ContractJarTestUtils.kt b/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/internal/ContractJarTestUtils.kt index 3ba57fa20a..4713400493 100644 --- a/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/internal/ContractJarTestUtils.kt +++ b/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/internal/ContractJarTestUtils.kt @@ -1,8 +1,6 @@ package net.corda.testing.core.internal import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_VERSION -import net.corda.core.internal.delete -import net.corda.core.internal.div import net.corda.core.internal.toPath import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.internal.JarSignatureTestUtils.addManifest @@ -24,6 +22,8 @@ import javax.tools.JavaFileObject import javax.tools.SimpleJavaFileObject import javax.tools.StandardLocation import javax.tools.ToolProvider +import kotlin.io.path.deleteExisting +import kotlin.io.path.div object ContractJarTestUtils { @@ -47,8 +47,8 @@ object ContractJarTestUtils { val pwd = "testPassword" this.generateKey(alias, pwd, ALICE_NAME.toString()) val signer = this.signJar(jarName.toAbsolutePath().toString(), alias, pwd) - (this / "_shredder").delete() - (this / "_teststore").delete() + (this / "_shredder").deleteExisting() + (this / "_teststore").deleteExisting() return signer } @@ -133,8 +133,8 @@ object ContractJarTestUtils { } else keyStoreDir val signer = workingDir.signJar(jarName.toAbsolutePath().toString(), alias, pwd) - (workingDir / "_shredder").delete() - (workingDir / "_teststore").delete() + (workingDir / "_shredder").deleteExisting() + (workingDir / "_teststore").deleteExisting() return workingDir.resolve(jarName) to signer } } \ No newline at end of file diff --git a/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/internal/JarSignatureTestUtils.kt b/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/internal/JarSignatureTestUtils.kt index 4c21340f84..694aa6ce49 100644 --- a/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/internal/JarSignatureTestUtils.kt +++ b/testing/core-test-utils/src/main/kotlin/net/corda/testing/core/internal/JarSignatureTestUtils.kt @@ -3,7 +3,8 @@ package net.corda.testing.core.internal import net.corda.core.identity.CordaX500Name import net.corda.core.internal.JarSignatureCollector import net.corda.core.internal.deleteRecursively -import net.corda.core.internal.div +import net.corda.coretesting.internal.modifyJarManifest +import net.corda.coretesting.internal.useZipFile import net.corda.nodeapi.internal.crypto.loadKeyStore import java.io.Closeable import java.io.FileInputStream @@ -18,6 +19,10 @@ import java.util.jar.Attributes import java.util.jar.JarInputStream import java.util.jar.JarOutputStream import java.util.jar.Manifest +import kotlin.io.path.deleteExisting +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.listDirectoryEntries import kotlin.test.assertEquals /** @@ -31,12 +36,11 @@ class SelfCleaningDir : Closeable { } object JarSignatureTestUtils { - val bin = Paths.get(System.getProperty("java.home")).let { if (it.endsWith("jre")) it.parent else it } / "bin" + private val bin = Paths.get(System.getProperty("java.home")).let { if (it.endsWith("jre")) it.parent else it } / "bin" - fun Path.executeProcess(vararg command: String) { + private fun Path.executeProcess(vararg command: String) { val shredder = (this / "_shredder").toFile() // No need to delete after each test. assertEquals(0, ProcessBuilder() - .inheritIO() .redirectOutput(shredder) .redirectError(shredder) .directory(this.toFile()) @@ -45,7 +49,7 @@ object JarSignatureTestUtils { .waitFor()) } - val CODE_SIGNER = CordaX500Name("Test Code Signing Service", "London", "GB") + private val CODE_SIGNER = CordaX500Name("Test Code Signing Service", "London", "GB") fun Path.generateKey(alias: String = "Test", storePassword: String = "secret!", name: String = CODE_SIGNER.toString(), keyalg: String = "RSA", keyPassword: String = storePassword, storeName: String = "_teststore") : PublicKey { executeProcess("keytool", "-genkeypair", "-keystore", storeName, "-storepass", storePassword, "-keyalg", keyalg, "-alias", alias, "-keypass", keyPassword, "-dname", name) @@ -69,6 +73,17 @@ object JarSignatureTestUtils { return ks.getCertificate(alias).publicKey } + fun Path.unsignJar() { + // Remove the signatures + useZipFile { zipFs -> + zipFs.getPath("META-INF").takeIf { it.exists() }?.listDirectoryEntries("*.{SF,DSA,RSA,EC}")?.forEach(Path::deleteExisting) + } + // Remove all the hash information of the jar contents + modifyJarManifest { manifest -> + manifest.entries.clear() + } + } + fun Path.getPublicKey(alias: String, storeName: String, storePassword: String) : PublicKey { val ks = loadKeyStore(this.resolve(storeName), storePassword) return ks.getCertificate(alias).publicKey diff --git a/testing/core-test-utils/src/test/kotlin/net/corda/coretesting/internal/RigorousMockTest.kt b/testing/core-test-utils/src/test/kotlin/net/corda/coretesting/internal/RigorousMockTest.kt index b2c9128544..0d01095725 100644 --- a/testing/core-test-utils/src/test/kotlin/net/corda/coretesting/internal/RigorousMockTest.kt +++ b/testing/core-test-utils/src/test/kotlin/net/corda/coretesting/internal/RigorousMockTest.kt @@ -2,7 +2,7 @@ package net.corda.coretesting.internal import org.assertj.core.api.Assertions.catchThrowable import org.hamcrest.Matchers.isA -import org.junit.Assert.assertThat +import org.hamcrest.MatcherAssert.assertThat import org.junit.Test import java.io.Closeable import java.io.InputStream @@ -44,7 +44,6 @@ class RigorousMockTest { fun `callRealMethod is preferred by rigorousMock`() { rigorousMock().let { m -> assertSame(UndefinedMockBehaviorException::class.java, catchThrowable { m.abstractFun() }.javaClass) - assertSame(UndefinedMockBehaviorException::class.java, catchThrowable { m.kotlinDefaultFun() }.javaClass) } rigorousMock().let { m -> assertSame(UndefinedMockBehaviorException::class.java, catchThrowable { m.abstractFun() }.javaClass) diff --git a/testing/node-driver/build.gradle b/testing/node-driver/build.gradle index 772813c41b..8d1a6f8b31 100644 --- a/testing/node-driver/build.gradle +++ b/testing/node-driver/build.gradle @@ -1,14 +1,15 @@ -apply plugin: 'kotlin' -apply plugin: 'kotlin-jpa' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'org.jetbrains.kotlin.plugin.jpa' apply plugin: 'net.corda.plugins.quasar-utils' -apply plugin: 'net.corda.plugins.publish-utils' apply plugin: 'net.corda.plugins.api-scanner' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' + +description 'Corda Node Driver module' //noinspection GroovyAssignabilityCheck configurations { - integrationTestCompile.extendsFrom testCompile - integrationTestRuntime.extendsFrom testRuntime + integrationTestImplementation.extendsFrom testImplementation + integrationTestRuntime.extendsFrom testRuntimeOnly } sourceSets { @@ -25,14 +26,33 @@ sourceSets { } dependencies { - compile project(':test-utils') + implementation project(':core') + implementation project(':node') + implementation project(':node-api') + implementation project(':serialization') + implementation project(':client:rpc') + implementation project(':client:mock') + implementation project(':common-configuration-parsing') + implementation project(':common-validation') + implementation project(':core-test-utils') + implementation project(':test-common') + implementation project(':test-utils') + implementation project(':tools:cliutils') - compile group: 'org.apache.sshd', name: 'sshd-common', version: '2.9.2' + implementation group: 'org.apache.sshd', name: 'sshd-common', version: '2.12.1' + implementation "javax.persistence:javax.persistence-api:2.2" // Integration test helpers - testCompile "org.assertj:assertj-core:$assertj_version" + testImplementation "org.assertj:assertj-core:$assertj_version" + + integrationTestImplementation project(":client:jackson") integrationTestImplementation "junit:junit:$junit_version" integrationTestImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" + integrationTestImplementation "info.picocli:picocli:$picocli_version" + integrationTestImplementation "com.google.guava:guava:$guava_version" + integrationTestImplementation 'com.googlecode.json-simple:json-simple:1.1.1' + integrationTestImplementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + integrationTestImplementation 'org.hamcrest:hamcrest-library:2.1' integrationTestRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" integrationTestRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" @@ -40,24 +60,60 @@ dependencies { // Jetty dependencies for NetworkMapClient test. // Web stuff: for HTTP[S] servlets - compile "org.eclipse.jetty:jetty-servlet:${jetty_version}" - compile "org.eclipse.jetty:jetty-webapp:${jetty_version}" - compile "javax.servlet:javax.servlet-api:${servlet_version}" + implementation "org.eclipse.jetty.ee10:jetty-ee10-servlet:${jetty_version}" + implementation "org.eclipse.jetty.ee10:jetty-ee10-webapp:${jetty_version}" + implementation "javax.servlet:javax.servlet-api:${servlet_version}" + + implementation "org.gradle:gradle-tooling-api:7.1" - compile "org.gradle:gradle-tooling-api:${gradle.gradleVersion}" - // Jersey for JAX-RS implementation for use in Jetty - compile "org.glassfish.jersey.core:jersey-server:${jersey_version}" - compile "org.glassfish.jersey.containers:jersey-container-servlet-core:${jersey_version}" - compile "org.glassfish.jersey.containers:jersey-container-jetty-http:${jersey_version}" + implementation "org.glassfish.jersey.core:jersey-server:${jersey_version}" + implementation "org.glassfish.jersey.containers:jersey-container-servlet-core:${jersey_version}" + implementation "org.glassfish.jersey.containers:jersey-container-jetty-http:${jersey_version}" + implementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version" + + implementation "io.reactivex:rxjava:$rxjava_version" + implementation("org.apache.activemq:artemis-core-client:${artemis_version}") { + exclude group: 'org.jgroups', module: 'jgroups' + } + + // Bouncy castle support needed for X509 certificate manipulation + implementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}" + implementation "org.bouncycastle:bcpkix-lts8on:${bouncycastle_version}" + implementation "org.bouncycastle:bcutil-lts8on:${bouncycastle_version}" + + implementation "com.google.code.findbugs:jsr305:$jsr305_version" + implementation "com.google.jimfs:jimfs:1.1" + implementation group: "com.typesafe", name: "config", version: typesafe_config_version + implementation "io.github.classgraph:classgraph:$class_graph_version" + implementation "com.squareup.okhttp3:okhttp:$okhttp_version" + implementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" + implementation "com.esotericsoftware:kryo:$kryo_version" + implementation "io.dropwizard.metrics:metrics-jmx:$metrics_version" + implementation "org.apache.commons:commons-lang3:$commons_lang3_version" + implementation "org.assertj:assertj-core:${assertj_version}" + implementation "org.apache.logging.log4j:log4j-core:$log4j_version" + implementation "junit:junit:$junit_version" + + implementation("org.apache.activemq:artemis-server:${artemis_version}") { + exclude group: 'org.apache.commons', module: 'commons-dbcp2' + exclude group: 'org.jgroups', module: 'jgroups' + } + + implementation "co.paralleluniverse:quasar-core:$quasar_version" } compileJava { doFirst { - if (JavaVersion.current() == JavaVersion.VERSION_11) - options.compilerArgs = [ - '--add-exports', 'java.base/sun.nio.ch=ALL-UNNAMED' - ] + options.compilerArgs = [ + '--add-modules', 'jdk.incubator.foreign' + ] + } +} + +processResources { + from(project(":node:capsule").files("src/main/resources/node-jvm-args.txt")) { + into("net/corda/testing/node/internal") } } @@ -75,20 +131,10 @@ jar { } } - -tasks.named('javadocJar', Jar) { - from 'README.md' - include 'README.md' -} - tasks.named('javadoc', Javadoc) { enabled = false } -publish { - name jar.baseName -} - scanApi { //Constructors that are synthesized by Kotlin unexpectedly excludeMethods = [ @@ -99,4 +145,13 @@ scanApi { "(Lnet/corda/testing/node/InMemoryMessagingNetwork\$PeerHandle;Lnet/corda/node/services/messaging/Message;Lnet/corda/core/messaging/MessageRecipients;Lkotlin/jvm/internal/DefaultConstructorMarker;)V" ] ] -} \ No newline at end of file +} + +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } +} diff --git a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt index 5e5f10f74a..f9c0a14e1b 100644 --- a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt +++ b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt @@ -6,10 +6,6 @@ import net.corda.core.internal.CertRole import net.corda.core.internal.concurrent.fork import net.corda.core.internal.concurrent.openFuture import net.corda.core.internal.concurrent.transpose -import net.corda.core.internal.div -import net.corda.core.internal.isRegularFile -import net.corda.core.internal.list -import net.corda.core.internal.readLines import net.corda.core.utilities.getOrThrow import net.corda.node.internal.NodeStartup import net.corda.testing.common.internal.ProjectStructure.projectRootDir @@ -26,12 +22,16 @@ import org.assertj.core.api.Assertions.assertThatCode import org.assertj.core.api.Assertions.assertThatIllegalArgumentException import org.json.simple.JSONObject import org.junit.Test -import java.util.* +import java.util.LinkedList import java.util.concurrent.CountDownLatch import java.util.concurrent.Executors import java.util.concurrent.ForkJoinPool import java.util.concurrent.ScheduledExecutorService -import kotlin.streams.toList +import kotlin.io.path.div +import kotlin.io.path.isRegularFile +import kotlin.io.path.name +import kotlin.io.path.useDirectoryEntries +import kotlin.io.path.useLines import kotlin.test.assertEquals class DriverTests { @@ -99,8 +99,8 @@ class DriverTests { systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString()) )) { val baseDirectory = startNode(providedName = DUMMY_BANK_A_NAME).getOrThrow().baseDirectory - val logFile = (baseDirectory / NodeStartup.LOGS_DIRECTORY_NAME).list { it.filter { a -> a.isRegularFile() && a.fileName.toString().startsWith("node") }.findFirst().get() } - val debugLinesPresent = logFile.readLines { lines -> lines.anyMatch { line -> line.startsWith("[DEBUG]") } } + val logFile = (baseDirectory / NodeStartup.LOGS_DIRECTORY_NAME).useDirectoryEntries { it.single { a -> a.isRegularFile() && a.name.startsWith("node") } } + val debugLinesPresent = logFile.useLines { lines -> lines.any { line -> line.startsWith("[DEBUG]") } } assertThat(debugLinesPresent).isTrue() } } @@ -185,5 +185,5 @@ class DriverTests { testFuture.getOrThrow() } - private fun DriverDSL.newNode(name: CordaX500Name) = { startNode(NodeParameters(providedName = name)) } -} \ No newline at end of file + private fun DriverDSL.newNode(name: CordaX500Name): () -> CordaFuture = { startNode(NodeParameters(providedName = name)) } +} diff --git a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/FlowStackSnapshotTest.kt b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/FlowStackSnapshotTest.kt index 3dc7dce4d5..f3e188af50 100644 --- a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/FlowStackSnapshotTest.kt +++ b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/FlowStackSnapshotTest.kt @@ -3,9 +3,13 @@ package net.corda.testing.node import co.paralleluniverse.fibers.Suspendable import net.corda.client.jackson.JacksonSupport import net.corda.client.rpc.CordaRPCClient -import net.corda.core.flows.* -import net.corda.core.internal.div -import net.corda.core.internal.list +import net.corda.core.flows.FlowLogic +import net.corda.core.flows.FlowSession +import net.corda.core.flows.FlowStackSnapshot +import net.corda.core.flows.InitiatedBy +import net.corda.core.flows.InitiatingFlow +import net.corda.core.flows.StartableByRPC +import net.corda.core.flows.StateMachineRunId import net.corda.core.internal.read import net.corda.core.messaging.startFlow import net.corda.core.serialization.CordaSerializable @@ -16,6 +20,8 @@ import org.junit.Ignore import org.junit.Test import java.nio.file.Path import java.time.LocalDate +import kotlin.io.path.div +import kotlin.io.path.useDirectoryEntries import kotlin.test.assertEquals import kotlin.test.assertNull import kotlin.test.assertTrue @@ -29,11 +35,11 @@ data class StackSnapshotFrame(val method: String, val clazz: String, val dataTyp * an empty list the frame is considered to be full. */ fun convertToStackSnapshotFrames(snapshot: FlowStackSnapshot): List { - return snapshot.stackFrames.map { - val dataTypes = it.stackObjects.map { + return snapshot.stackFrames.map { frame -> + val dataTypes = frame.stackObjects.map { if (it == null) null else it::class.qualifiedName } - val stackTraceElement = it.stackTraceElement + val stackTraceElement = frame.stackTraceElement StackSnapshotFrame(stackTraceElement.methodName, stackTraceElement.className, dataTypes) } } @@ -48,7 +54,7 @@ fun convertToStackSnapshotFrames(snapshot: FlowStackSnapshot): List>() { - var sideEffectField = "" + private var sideEffectField = "" @Suspendable override fun call(): List { @@ -155,7 +161,7 @@ class PersistingSideEffectFlow : FlowLogic() { * Similar to [PersistingSideEffectFlow] but aims to produce multiple snapshot files. */ @StartableByRPC -class MultiplePersistingSideEffectFlow(val persistCallCount: Int) : FlowLogic() { +class MultiplePersistingSideEffectFlow(private val persistCallCount: Int) : FlowLogic() { @Suspendable override fun call(): StateMachineRunId { @@ -212,7 +218,7 @@ private fun flowSnapshotDir(baseDir: Path, flowId: StateMachineRunId): Path { } fun countFilesInDir(baseDir: Path, flowId: StateMachineRunId): Int { - return flowSnapshotDir(baseDir, flowId).list { it.count().toInt() } + return flowSnapshotDir(baseDir, flowId).useDirectoryEntries { it.count() } } fun assertFrame(expectedMethod: String, expectedEmpty: Boolean, frame: StackSnapshotFrame) { @@ -311,9 +317,9 @@ class FlowStackSnapshotTest { val snapshotFromFile = readFlowStackSnapshotFromDir(a.baseDirectory, flowId) var inCallCount = 0 var inPersistCount = 0 - snapshotFromFile.stackFrames.forEach { - val trace = it.stackTraceElement - it.stackObjects.forEach { + snapshotFromFile.stackFrames.forEach { frame -> + val trace = frame.stackTraceElement + frame.stackObjects.forEach { when (it) { Constants.IN_CALL_VALUE -> { assertEquals(PersistingSideEffectFlow::call.name, trace.methodName) diff --git a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/MockNetworkIntegrationTests.kt b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/MockNetworkIntegrationTests.kt index 8de9f6e61d..e59e699c58 100644 --- a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/MockNetworkIntegrationTests.kt +++ b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/MockNetworkIntegrationTests.kt @@ -1,10 +1,14 @@ package net.corda.testing.node -import net.corda.core.internal.div +import net.corda.core.internal.deleteRecursively import net.corda.testing.common.internal.ProjectStructure.projectRootDir import net.corda.testing.node.internal.ProcessUtilities.startJavaProcess +import net.corda.testing.node.internal.nodeJvmArgs +import org.assertj.core.api.Assertions.assertThat import org.junit.Test -import kotlin.test.assertEquals +import kotlin.io.path.Path +import kotlin.io.path.createDirectories +import kotlin.io.path.div class MockNetworkIntegrationTests { companion object { @@ -21,6 +25,17 @@ class MockNetworkIntegrationTests { @Test(timeout=300_000) fun `does not leak non-daemon threads`() { val quasar = projectRootDir / "lib" / "quasar.jar" - assertEquals(0, startJavaProcess(emptyList(), extraJvmArguments = listOf("-javaagent:$quasar")).waitFor()) + val quasarOptions = "m" + + val workingDirectory = Path("build", "MockNetworkIntegrationTests").apply { + deleteRecursively() + createDirectories() + } + val process = startJavaProcess( + emptyList(), + workingDirectory = workingDirectory, + extraJvmArguments = listOf("-javaagent:$quasar=$quasarOptions") + nodeJvmArgs + ) + assertThat(process.waitFor()).isZero() } } diff --git a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/internal/CordaCliWrapperErrorHandlingTests.kt b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/internal/CordaCliWrapperErrorHandlingTests.kt index 6a4c572349..bf483cca3d 100644 --- a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/internal/CordaCliWrapperErrorHandlingTests.kt +++ b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/internal/CordaCliWrapperErrorHandlingTests.kt @@ -1,9 +1,7 @@ package net.corda.testing.node.internal -import net.corda.testing.internal.IS_OPENJ9 import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.matchesPattern -import org.junit.Assume import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @@ -11,7 +9,6 @@ import java.io.BufferedReader import java.io.InputStreamReader import java.util.stream.Collectors - @RunWith(value = Parameterized::class) class CordaCliWrapperErrorHandlingTests(val arguments: List, val outputRegexPattern: String) { @@ -33,22 +30,19 @@ class CordaCliWrapperErrorHandlingTests(val arguments: List, val outputR @Test(timeout=300_000) fun `Run CordaCliWrapper sample app with arguments and check error output matches regExp`() { - // For openj9 the process error output appears sometimes to be garbled. - Assume.assumeTrue(!IS_OPENJ9) - val process = ProcessUtilities.startJavaProcess( - className = className, - arguments = arguments, - inheritIO = false) + val process = ProcessUtilities.startJavaProcess(className = className, arguments = arguments) process.waitFor() val processErrorOutput = BufferedReader( InputStreamReader(process.errorStream)) .lines() - .filter { !it.startsWith("Warning: Nashorn") } + .filter { it.contains("Exception") || + it.contains("at ") || + it.contains("exception") } .collect(Collectors.joining("\n")) .toString() assertThat(processErrorOutput, matchesPattern(outputRegexPattern)) } -} \ No newline at end of file +} diff --git a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/internal/InternalMockNetworkIntegrationTests.kt b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/internal/InternalMockNetworkIntegrationTests.kt index 09aae1a587..4d93f55d6c 100644 --- a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/internal/InternalMockNetworkIntegrationTests.kt +++ b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/internal/InternalMockNetworkIntegrationTests.kt @@ -1,10 +1,13 @@ package net.corda.testing.node.internal -import net.corda.core.internal.div +import net.corda.core.internal.deleteRecursively import net.corda.testing.common.internal.ProjectStructure.projectRootDir import net.corda.testing.node.internal.ProcessUtilities.startJavaProcess +import org.assertj.core.api.Assertions.assertThat import org.junit.Test -import kotlin.test.assertEquals +import kotlin.io.path.Path +import kotlin.io.path.createDirectories +import kotlin.io.path.div class InternalMockNetworkIntegrationTests { companion object { @@ -21,6 +24,17 @@ class InternalMockNetworkIntegrationTests { @Test(timeout=300_000) fun `does not leak non-daemon threads`() { val quasar = projectRootDir / "lib" / "quasar.jar" - assertEquals(0, startJavaProcess(emptyList(), extraJvmArguments = listOf("-javaagent:$quasar")).waitFor()) + val quasarOptions = "m" + + val workingDirectory = Path("build", "InternalMockNetworkIntegrationTests").apply { + deleteRecursively() + createDirectories() + } + val process = startJavaProcess( + emptyList(), + workingDirectory = workingDirectory, + extraJvmArguments = listOf("-javaagent:$quasar=$quasarOptions") + nodeJvmArgs + ) + assertThat(process.waitFor()).isZero() } } diff --git a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/internal/ProcessUtilitiesTests.kt b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/internal/ProcessUtilitiesTests.kt index 9145839b3e..612b3704fb 100644 --- a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/internal/ProcessUtilitiesTests.kt +++ b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/internal/ProcessUtilitiesTests.kt @@ -1,12 +1,12 @@ package net.corda.testing.node.internal -import net.corda.core.internal.readText -import net.corda.core.internal.writeText import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder import java.nio.file.Paths import java.util.concurrent.TimeUnit +import kotlin.io.path.readText +import kotlin.io.path.writeText import kotlin.test.assertEquals import kotlin.test.assertTrue diff --git a/testing/node-driver/src/main/java/net/corda/testing/driver/SharedMemoryIncremental.java b/testing/node-driver/src/main/java/net/corda/testing/driver/SharedMemoryIncremental.java index 88e6e726d7..8c70cbea87 100644 --- a/testing/node-driver/src/main/java/net/corda/testing/driver/SharedMemoryIncremental.java +++ b/testing/node-driver/src/main/java/net/corda/testing/driver/SharedMemoryIncremental.java @@ -1,97 +1,108 @@ package net.corda.testing.driver; -import sun.misc.Unsafe; -import sun.nio.ch.DirectBuffer; +import jdk.incubator.foreign.MemoryHandles; +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.ResourceScope; +import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.RandomAccessFile; -import java.lang.reflect.Field; +import java.io.UncheckedIOException; +import java.lang.invoke.VarHandle; import java.net.ServerSocket; +import java.nio.ByteOrder; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; -/** - * JDK11 upgrade: rewritten in Java to gain access to private internal JDK classes via module directives (not available to Kotlin compiler): - * import sun.misc.Unsafe; - * import sun.nio.ch.DirectBuffer; - */ +import static java.nio.file.StandardOpenOption.READ; +import static java.nio.file.StandardOpenOption.WRITE; + +// This was originally (re)written in Java to access internal JDK APIs. Since it's no longer doing that, this can be converted back to Kotlin. public class SharedMemoryIncremental extends PortAllocation { + private static final int DEFAULT_START_PORT = 10_000; + private static final int FIRST_EPHEMERAL_PORT = 30_000; - static private final int DEFAULT_START_PORT = 10_000; - static private final int FIRST_EPHEMERAL_PORT = 30_000; + private final int startPort; + private final int endPort; - private int startPort; - private int endPort; - - private MappedByteBuffer mb; - private Long startingAddress; - - private File file = new File(System.getProperty("user.home"), "corda-" + startPort + "-to-" + endPort + "-port-allocator.bin"); - private RandomAccessFile backingFile; - { - try { - backingFile = new RandomAccessFile(file, "rw"); - } catch (FileNotFoundException e) { - throw new RuntimeException(e); - } - } + private final MemorySegment memorySegment; + private final VarHandle intHandle; + private final MappedByteBuffer unsafeBuffer; private SharedMemoryIncremental(int startPort, int endPort) { this.startPort = startPort; this.endPort = endPort; + Path file = Path.of(System.getProperty("user.home"), "corda-" + startPort + "-to-" + endPort + "-port-allocator.bin"); try { - mb = backingFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 16); - startingAddress = ((DirectBuffer) mb).address(); + try { + Files.createFile(file); + } catch (FileAlreadyExistsException ignored) {} + if (isFfmAvailable()) { + memorySegment = MemorySegment.mapFile(file, 0, Integer.SIZE, MapMode.READ_WRITE, ResourceScope.globalScope()); + intHandle = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder()); + unsafeBuffer = null; + } else { + LoggerFactory.getLogger(getClass()).warn("Using unsafe port allocator which may lead to the same port being allocated " + + "twice. Consider adding --add-modules=jdk.incubator.foreign to the test JVM."); + memorySegment = null; + intHandle = null; + unsafeBuffer = FileChannel.open(file, READ, WRITE).map(MapMode.READ_WRITE, 0, Integer.SIZE); + } } catch (IOException e) { - e.printStackTrace(); + throw new UncheckedIOException(e); + } + } + + private static boolean isFfmAvailable() { + try { + Class.forName("jdk.incubator.foreign.MemorySegment"); + return true; + } catch (ClassNotFoundException e) { + return false; } } public static SharedMemoryIncremental INSTANCE = new SharedMemoryIncremental(DEFAULT_START_PORT, FIRST_EPHEMERAL_PORT); - static private Unsafe UNSAFE = getUnsafe(); - - static private Unsafe getUnsafe() { - try { - Field f = Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - return (Unsafe) f.get(null); - } catch (NoSuchFieldException | IllegalAccessException e) { - e.printStackTrace(); - return null; - } - } @Override public int nextPort() { - long oldValue; - long newValue; - boolean loopSuccess; - do { - oldValue = UNSAFE.getLongVolatile(null, startingAddress); + while (true) { + int oldValue; + if (intHandle != null) { + oldValue = (int) intHandle.getVolatile(memorySegment, 0L); + } else { + oldValue = unsafeBuffer.getInt(0); + } + int newValue; if (oldValue + 1 >= endPort || oldValue < startPort) { newValue = startPort; } else { newValue = (oldValue + 1); } - boolean reserveSuccess = UNSAFE.compareAndSwapLong(null, startingAddress, oldValue, newValue); - loopSuccess = reserveSuccess && isLocalPortAvailable(newValue); - } while (!loopSuccess); - - return (int) newValue; + if (intHandle != null) { + if (!intHandle.compareAndSet(memorySegment, 0L, oldValue, newValue)) { + continue; + } + } else { + unsafeBuffer.putInt(0, newValue); + } + if (isLocalPortAvailable(newValue)) { + return newValue; + } + } } - - private boolean isLocalPortAvailable(Long portToTest) { - try (ServerSocket serverSocket = new ServerSocket(Math.toIntExact(portToTest))) { + private boolean isLocalPortAvailable(int portToTest) { + try (ServerSocket ignored = new ServerSocket(portToTest)) { + return true; } catch (IOException e) { // Don't catch anything other than IOException here in case we // accidentally create an infinite loop. For example, installing // a SecurityManager could throw AccessControlException. return false; } - return true; } - } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt index 4e5cf3893a..e1b5d43e83 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt @@ -6,7 +6,6 @@ import net.corda.core.DoNotImplement import net.corda.core.concurrent.CordaFuture import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party -import net.corda.core.internal.div import net.corda.core.internal.uncheckedCast import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.NetworkParameters @@ -31,6 +30,7 @@ import java.nio.file.Path import java.nio.file.Paths import java.time.Duration import java.util.concurrent.atomic.AtomicInteger +import kotlin.io.path.div /** * Object ecapsulating a notary started automatically by the driver. @@ -98,7 +98,6 @@ interface InProcess : NodeHandle { /** * Starts an already constructed flow. Note that you must be on the server thread to call this method. - * @param context indicates who started the flow, see: [InvocationContext]. */ fun startFlow(logic: FlowLogic): CordaFuture = internalServices.startFlow(logic, internalServices.newContext()) .getOrThrow().resultFuture @@ -628,7 +627,7 @@ data class DriverParameters( waitForAllNodesToFinish: Boolean, notarySpecs: List, extraCordappPackagesToScan: List, - @Suppress("DEPRECATION") jmxPolicy: JmxPolicy, + jmxPolicy: JmxPolicy, networkParameters: NetworkParameters, notaryCustomOverrides: Map, inMemoryDB: Boolean, diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/NodeParameters.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/NodeParameters.kt index 12b55fc146..1da7174028 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/NodeParameters.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/NodeParameters.kt @@ -25,7 +25,7 @@ import net.corda.testing.node.User * log level argument. * @property rpcAddress optional override for RPC address on which node will be accepting RPC connections from the clients. Port provided must be vacant. */ -@Suppress("unused") +@Suppress("unused", "TooManyFunctions") data class NodeParameters( val providedName: CordaX500Name? = null, val rpcUsers: List = emptyList(), @@ -37,7 +37,8 @@ data class NodeParameters( val flowOverrides: Map>, Class>> = emptyMap(), val logLevelOverride: String? = null, val rpcAddress: NetworkHostAndPort? = null, - val systemProperties: Map = emptyMap() + val systemProperties: Map = emptyMap(), + val legacyContracts: Collection = emptySet() ) { /** * Create a new node parameters object with default values. Each parameter can be specified with its wither method which returns a copy @@ -54,6 +55,9 @@ data class NodeParameters( fun withAdditionalCordapps(additionalCordapps: Set): NodeParameters = copy(additionalCordapps = additionalCordapps) fun withFlowOverrides(flowOverrides: Map>, Class>>): NodeParameters = copy(flowOverrides = flowOverrides) fun withLogLevelOverride(logLevelOverride: String?): NodeParameters = copy(logLevelOverride = logLevelOverride) + fun withRpcAddress(rpcAddress: NetworkHostAndPort?): NodeParameters = copy(rpcAddress = rpcAddress) + fun withSystemProperties(systemProperties: Map): NodeParameters = copy(systemProperties = systemProperties) + fun withLegacyContracts(legacyContracts: Collection): NodeParameters = copy(legacyContracts = legacyContracts) constructor( providedName: CordaX500Name?, @@ -221,4 +225,58 @@ data class NodeParameters( logLevelOverride = logLevelOverride, rpcAddress = rpcAddress, systemProperties = systemProperties) + + constructor( + providedName: CordaX500Name?, + rpcUsers: List, + verifierType: VerifierType, + customOverrides: Map, + startInSameProcess: Boolean?, + maximumHeapSize: String, + additionalCordapps: Collection = emptySet(), + flowOverrides: Map>, Class>>, + logLevelOverride: String? = null, + rpcAddress: NetworkHostAndPort? = null, + systemProperties: Map = emptyMap() + ) : this( + providedName, + rpcUsers, + verifierType, + customOverrides, + startInSameProcess, + maximumHeapSize, + additionalCordapps, + flowOverrides, + logLevelOverride, + rpcAddress, + systemProperties, + legacyContracts = emptySet()) + + @Suppress("LongParameterList") + fun copy( + providedName: CordaX500Name?, + rpcUsers: List, + verifierType: VerifierType, + customOverrides: Map, + startInSameProcess: Boolean?, + maximumHeapSize: String, + additionalCordapps: Collection = emptySet(), + flowOverrides: Map>, Class>>, + logLevelOverride: String? = null, + rpcAddress: NetworkHostAndPort? = null, + systemProperties: Map = emptyMap() + ) = this.copy( + providedName = providedName, + rpcUsers = rpcUsers, + verifierType = verifierType, + customOverrides = customOverrides, + startInSameProcess = startInSameProcess, + maximumHeapSize = maximumHeapSize, + additionalCordapps = additionalCordapps, + flowOverrides = flowOverrides, + logLevelOverride = logLevelOverride, + rpcAddress = rpcAddress, + systemProperties = systemProperties, + legacyContracts = legacyContracts) + } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/internal/DriverInternal.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/internal/DriverInternal.kt index c761b96498..5f7f640028 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/internal/DriverInternal.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/internal/DriverInternal.kt @@ -1,5 +1,6 @@ package net.corda.testing.driver.internal +import jakarta.validation.constraints.NotNull import net.corda.core.flows.FlowLogic import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.NodeInfo @@ -14,7 +15,6 @@ import net.corda.testing.driver.OutOfProcess import net.corda.testing.node.User import rx.Observable import java.nio.file.Path -import javax.validation.constraints.NotNull interface NodeHandleInternal : NodeHandle { val configuration: NodeConfiguration diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt index 7c19eb0265..50febd80e1 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -1,21 +1,31 @@ package net.corda.testing.node import com.google.common.collect.MutableClassToInstanceMap +import net.corda.core.CordaInternal import net.corda.core.contracts.Attachment import net.corda.core.contracts.ContractClassName +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TransactionState import net.corda.core.cordapp.CordappProvider import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.sha256 import net.corda.core.flows.FlowLogic import net.corda.core.flows.StateMachineRunId import net.corda.core.identity.CordaX500Name -import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate +import net.corda.core.internal.AbstractAttachment import net.corda.core.internal.PLATFORM_VERSION import net.corda.core.internal.VisibleForTesting +import net.corda.core.internal.cordapp.CordappProviderInternal +import net.corda.core.internal.getRequiredTransaction +import net.corda.core.internal.mapToSet import net.corda.core.internal.requireSupportedHashType import net.corda.core.internal.telemetry.TelemetryComponent import net.corda.core.internal.telemetry.TelemetryServiceImpl +import net.corda.core.internal.verification.ExternalVerifierHandle +import net.corda.core.internal.verification.VerifyingServiceHub import net.corda.core.messaging.DataFeed import net.corda.core.messaging.FlowHandle import net.corda.core.messaging.FlowProgressHandle @@ -34,33 +44,34 @@ import net.corda.core.node.services.NetworkMapCache import net.corda.core.node.services.NetworkParametersService import net.corda.core.node.services.ServiceLifecycleObserver import net.corda.core.node.services.TransactionStorage -import net.corda.core.node.services.TransactionVerifierService import net.corda.core.node.services.VaultService import net.corda.core.node.services.diagnostics.DiagnosticsService import net.corda.core.node.services.vault.CordaTransactionSupport import net.corda.core.serialization.SerializeAsToken +import net.corda.core.serialization.internal.AttachmentsClassLoaderCacheImpl import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.NetworkHostAndPort +import net.corda.core.utilities.loggerFor import net.corda.coretesting.internal.DEV_ROOT_CA import net.corda.node.VersionInfo -import net.corda.node.internal.ServicesForResolutionImpl -import net.corda.node.internal.NodeServicesForResolution import net.corda.node.internal.cordapp.JarScanningCordappLoader import net.corda.node.services.api.SchemaService import net.corda.node.services.api.ServiceHubInternal import net.corda.node.services.api.StateMachineRecordedTransactionMappingStorage import net.corda.node.services.api.VaultServiceInternal import net.corda.node.services.api.WritableTransactionStorage +import net.corda.node.services.attachments.NodeAttachmentTrustCalculator import net.corda.node.services.diagnostics.NodeDiagnosticsService import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.identity.PersistentIdentityService import net.corda.node.services.keys.BasicHSMKeyManagementService import net.corda.node.services.network.PersistentNetworkMapCache import net.corda.node.services.persistence.PublicKeyToOwningIdentityCacheImpl +import net.corda.node.services.persistence.toInternal import net.corda.node.services.schema.NodeSchemaService -import net.corda.node.services.transactions.InMemoryTransactionVerifierService import net.corda.node.services.vault.NodeVaultService import net.corda.nodeapi.internal.cordapp.CordappLoader +import net.corda.nodeapi.internal.cordapp.cordappSchemas import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.DatabaseConfig import net.corda.nodeapi.internal.persistence.contextTransaction @@ -69,7 +80,6 @@ import net.corda.testing.core.TestIdentity import net.corda.testing.internal.MockCordappProvider import net.corda.testing.internal.TestingNamedCacheFactory import net.corda.testing.internal.configureDatabase -import net.corda.testing.node.internal.DriverDSLImpl import net.corda.testing.node.internal.MockCryptoService import net.corda.testing.node.internal.MockKeyManagementService import net.corda.testing.node.internal.MockNetworkParametersStorage @@ -78,6 +88,7 @@ import net.corda.testing.node.internal.cordappsForPackages import net.corda.testing.node.internal.getCallerPackage import net.corda.testing.services.MockAttachmentStorage import java.io.ByteArrayOutputStream +import java.nio.file.FileAlreadyExistsException import java.nio.file.Paths import java.security.KeyPair import java.sql.Connection @@ -116,10 +127,9 @@ open class MockServices private constructor( *arrayOf(initialIdentity.keyPair) + moreKeys ) ) : ServiceHub { - companion object { private fun cordappLoaderForPackages(packages: Iterable, versionInfo: VersionInfo = VersionInfo.UNKNOWN): CordappLoader { - return JarScanningCordappLoader.fromJarUrls(cordappsForPackages(packages).map { it.jarFile.toUri().toURL() }, versionInfo) + return JarScanningCordappLoader(cordappsForPackages(packages).mapToSet { it.jarFile }, versionInfo = versionInfo) } /** @@ -135,8 +145,8 @@ open class MockServices private constructor( val dbPath = dbDir.resolve("persistence") try { DatabaseSnapshot.copyDatabaseSnapshot(dbDir) - } catch (ex: java.nio.file.FileAlreadyExistsException) { - DriverDSLImpl.log.warn("Database already exists on disk, not attempting to pre-migrate database.") + } catch (e: FileAlreadyExistsException) { + loggerFor().warn("Database already exists on disk, not attempting to pre-migrate database.") } val props = Properties() props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource") @@ -295,22 +305,19 @@ open class MockServices private constructor( // Because Kotlin is dumb and makes not publicly visible objects public, thus changing the public API. private val mockStateMachineRecordedTransactionMappingStorage = MockStateMachineRecordedTransactionMappingStorage() - private val dummyAttachment by lazy { - val inputStream = ByteArrayOutputStream().apply { - ZipOutputStream(this).use { - with(it) { - putNextEntry(ZipEntry(JarFile.MANIFEST_NAME)) - } - } - }.toByteArray().inputStream() - val attachment = object : Attachment { - override val id get() = throw UnsupportedOperationException() - override fun open() = inputStream - override val signerKeys get() = throw UnsupportedOperationException() - override val signers: List get() = throw UnsupportedOperationException() - override val size: Int = 512 + private val dummyAttachment: Attachment by lazy { + object : AbstractAttachment( + { + val baos = ByteArrayOutputStream() + ZipOutputStream(baos).use { zip -> + zip.putNextEntry(ZipEntry(JarFile.MANIFEST_NAME)) + } + baos.toByteArray() + }, + null + ) { + override val id: SecureHash by lazy(attachmentData::sha256) } - attachment } } @@ -482,27 +489,23 @@ open class MockServices private constructor( get() { return NodeInfo(listOf(NetworkHostAndPort("mock.node.services", 10000)), listOf(initialIdentity.identity), 1, serial = 1L) } - private val mockCordappProvider: MockCordappProvider = MockCordappProvider(cordappLoader, attachments).also { + private val mockCordappProvider: MockCordappProvider = MockCordappProvider(cordappLoader, attachments.toInternal()).also { it.start() } - override val transactionVerifierService: TransactionVerifierService - get() = InMemoryTransactionVerifierService( - numberOfWorkers = 2, - cordappProvider = mockCordappProvider, - attachments = attachments - ) override val cordappProvider: CordappProvider get() = mockCordappProvider override var networkParametersService: NetworkParametersService = MockNetworkParametersStorage(initialNetworkParameters) override val diagnosticsService: DiagnosticsService = NodeDiagnosticsService() - protected val servicesForResolution: ServicesForResolution - get() = ServicesForResolutionImpl(identityService, attachments, cordappProvider, networkParametersService, validatedTransactions) + // This is kept here for backwards compatibility, otherwise this has no extra utility. + protected val servicesForResolution: ServicesForResolution get() = verifyingView + + private val verifyingView: VerifyingServiceHub by lazy { VerifyingView(this) } internal fun makeVaultService(schemaService: SchemaService, database: CordaPersistence, cordappLoader: CordappLoader): VaultServiceInternal { return NodeVaultService( clock, keyManagementService, - servicesForResolution as NodeServicesForResolution, + verifyingView, database, schemaService, cordappLoader.appClassLoader @@ -511,9 +514,9 @@ open class MockServices private constructor( // This needs to be internal as MutableClassToInstanceMap is a guava type and shouldn't be part of our public API /** A map of available [CordaService] implementations */ - internal val cordappServices: MutableClassToInstanceMap = MutableClassToInstanceMap.create() + internal val cordappServices: MutableClassToInstanceMap = MutableClassToInstanceMap.create() - internal val cordappTelemetryComponents: MutableClassToInstanceMap = MutableClassToInstanceMap.create() + private val cordappTelemetryComponents: MutableClassToInstanceMap = MutableClassToInstanceMap.create() override fun cordaService(type: Class): T { require(type.isAnnotationPresent(CordaService::class.java)) { "${type.name} is not a Corda service" } @@ -543,19 +546,46 @@ open class MockServices private constructor( mockCordappProvider.addMockCordapp(contractClassName, attachments) } - override fun loadState(stateRef: StateRef) = servicesForResolution.loadState(stateRef) - override fun loadStates(stateRefs: Set) = servicesForResolution.loadStates(stateRefs) + override fun loadState(stateRef: StateRef): TransactionState { + return getRequiredTransaction(stateRef.txhash).resolveBaseTransaction(this).outputs[stateRef.index] + } + + override fun loadStates(stateRefs: Set): Set> = stateRefs.mapToSet(::toStateAndRef) /** Returns a dummy Attachment, in context of signature constrains non-downgrade rule this default to contract class version `1`. */ override fun loadContractAttachment(stateRef: StateRef) = dummyAttachment -} -/** - * Function which can be used to create a mock [CordaService] for use within testing, such as an Oracle. - */ -fun createMockCordaService(serviceHub: MockServices, serviceConstructor: (AppServiceHub) -> T): T { - class MockAppServiceHubImpl(val serviceHub: MockServices, serviceConstructor: (AppServiceHub) -> T) : AppServiceHub, ServiceHub by serviceHub { - val serviceInstance: T = serviceConstructor(this) + + /** + * All [ServiceHub]s must also implement [VerifyingServiceHub]. However, since [MockServices] is part of the public API, making it + * extend [VerifyingServiceHub] would leak internal APIs. Instead we have this private view class and have the `toVerifyingServiceHub` + * extension method return it. + */ + private class VerifyingView(private val mockServices: MockServices) : VerifyingServiceHub, ServiceHub by mockServices { + override val attachmentTrustCalculator = NodeAttachmentTrustCalculator( + attachmentStorage = mockServices.attachments.toInternal(), + cacheFactory = TestingNamedCacheFactory() + ) + + override val attachmentsClassLoaderCache = AttachmentsClassLoaderCacheImpl(TestingNamedCacheFactory()) + + override val cordappProvider: CordappProviderInternal get() = mockServices.mockCordappProvider + + override fun loadContractAttachment(stateRef: StateRef): Attachment = mockServices.loadContractAttachment(stateRef) + + override fun loadState(stateRef: StateRef): TransactionState<*> = mockServices.loadState(stateRef) + + override fun loadStates(stateRefs: Set): Set> = mockServices.loadStates(stateRefs) + + override val externalVerifierHandle: ExternalVerifierHandle + get() = throw UnsupportedOperationException("`Verification of legacy transactions is not supported by MockServices. Use MockNode instead.") + } + + + @CordaInternal + internal class MockAppServiceHubImpl(serviceHub: MockServices, serviceConstructor: (AppServiceHub) -> T) : + AppServiceHub, VerifyingServiceHub by serviceHub.verifyingView { + internal val serviceInstance: T = serviceConstructor(this) init { serviceHub.cordappServices.putInstance(serviceInstance.javaClass, serviceInstance) @@ -576,5 +606,11 @@ fun createMockCordaService(serviceHub: MockServices, serv throw UnsupportedOperationException() } } - return MockAppServiceHubImpl(serviceHub, serviceConstructor).serviceInstance +} + +/** + * Function which can be used to create a mock [CordaService] for use within testing, such as an Oracle. + */ +fun createMockCordaService(serviceHub: MockServices, serviceConstructor: (AppServiceHub) -> T): T { + return MockServices.MockAppServiceHubImpl(serviceHub, serviceConstructor).serviceInstance } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/TestCordapp.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/TestCordapp.kt index 92cc1f1a78..7d2356e0a4 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/TestCordapp.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/TestCordapp.kt @@ -3,7 +3,10 @@ package net.corda.testing.node import net.corda.core.DoNotImplement import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.NodeParameters -import net.corda.testing.node.internal.TestCordappImpl +import net.corda.testing.node.internal.ScanPackageTestCordapp +import net.corda.testing.node.internal.UriTestCordapp +import java.net.URI +import java.nio.file.Path /** * Encapsulates a CorDapp that exists on the current classpath, which can be pulled in for testing. Use [TestCordapp.findCordapp] @@ -25,6 +28,12 @@ abstract class TestCordapp { /** Returns a copy of this [TestCordapp] but with the specified CorDapp config. */ abstract fun withConfig(config: Map): TestCordapp + /** + * Returns a copy of this [TestCordapp] signed with a development signing key. The same signing key will be used for all signed + * [TestCordapp]s. If the CorDapp jar is already signed, then the new jar created will its signing key replaced by the development key. + */ + abstract fun asSigned(): TestCordapp + companion object { /** * Scans the current classpath to find the CorDapp that contains the given package. All the CorDapp's metdata present in its @@ -34,6 +43,14 @@ abstract class TestCordapp { * @param scanPackage The package name used to find the CorDapp. This does not need to be the root package of the CorDapp. */ @JvmStatic - fun findCordapp(scanPackage: String): TestCordapp = TestCordappImpl(scanPackage = scanPackage, config = emptyMap()) + fun findCordapp(scanPackage: String): TestCordapp = ScanPackageTestCordapp(scanPackage) + + /** + * [URI] location to a CorDapp jar. This may be a path on the local file system or a URL to an external resource. + * + * A [Path] can be converted into a [URI] with [Path.toUri]. + */ + @JvmStatic + fun of(uri: URI): TestCordapp = UriTestCordapp(uri) } } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/CustomCordapp.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/CustomCordapp.kt index d3cdc7043e..6a24ee74b2 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/CustomCordapp.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/CustomCordapp.kt @@ -1,27 +1,29 @@ package net.corda.testing.node.internal import io.github.classgraph.ClassGraph -import net.corda.core.internal.* +import net.corda.core.internal.PLATFORM_VERSION +import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.cordapp.CordappImpl import net.corda.core.internal.cordapp.set +import net.corda.core.internal.pooledScan import net.corda.core.node.services.AttachmentFixup import net.corda.core.serialization.SerializationWhitelist import net.corda.core.utilities.contextLogger import net.corda.core.utilities.debug -import net.corda.testing.core.internal.JarSignatureTestUtils.generateKey -import net.corda.testing.core.internal.JarSignatureTestUtils.containsKey -import net.corda.testing.core.internal.JarSignatureTestUtils.signJar import java.nio.file.Path import java.nio.file.Paths import java.nio.file.attribute.FileTime import java.time.Instant -import java.util.* +import java.util.UUID import java.util.concurrent.ConcurrentHashMap import java.util.jar.Attributes import java.util.jar.JarFile import java.util.jar.JarOutputStream import java.util.jar.Manifest import java.util.zip.ZipEntry +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.outputStream /** * Represents a completely custom CorDapp comprising of resources taken from packages on the existing classpath, even including individual @@ -44,6 +46,8 @@ data class CustomCordapp( override fun withOnlyJarContents(): CustomCordapp = CustomCordapp(packages = packages, classes = classes, fixups = fixups) + override fun asSigned(): CustomCordapp = signed() + fun signed(keyStorePath: Path? = null, numberOfSignatures: Int = 1, keyAlgorithm: String = "RSA"): CustomCordapp = copy(signingInfo = SigningInfo(keyStorePath, numberOfSignatures, keyAlgorithm)) @@ -109,23 +113,6 @@ data class CustomCordapp( } } - private fun signJar(jarFile: Path) { - if (signingInfo != null) { - val keyStorePathToUse = signingInfo.keyStorePath ?: defaultJarSignerDirectory.createDirectories() - for (i in 1 .. signingInfo.numberOfSignatures) { - val alias = "alias$i" - val pwd = "secret!" - if (!keyStorePathToUse.containsKey(alias, pwd)) { - keyStorePathToUse.generateKey(alias, pwd, "O=Test Company Ltd $i,OU=Test,L=London,C=GB", signingInfo.keyAlgorithm) - } - val pk = keyStorePathToUse.signJar(jarFile.toString(), alias, pwd) - logger.debug { "Signed Jar: $jarFile with public key $pk" } - } - } else { - logger.debug { "Unsigned Jar: $jarFile" } - } - } - private fun createTestManifest(name: String, versionId: Int, targetPlatformVersion: Int): Manifest { val manifest = Manifest() @@ -155,13 +142,12 @@ data class CustomCordapp( } } - data class SigningInfo(val keyStorePath: Path?, val numberOfSignatures: Int, val keyAlgorithm: String) + data class SigningInfo(val keyStorePath: Path?, val signatureCount: Int, val algorithm: String) companion object { private val logger = contextLogger() private val epochFileTime = FileTime.from(Instant.EPOCH) private val cordappsDirectory: Path - private val defaultJarSignerDirectory: Path private val whitespace = "\\s++".toRegex() private val cache = ConcurrentHashMap() @@ -169,7 +155,6 @@ data class CustomCordapp( val buildDir = Paths.get("build").toAbsolutePath() val timeDirName = getTimestampAsDirectoryName() cordappsDirectory = buildDir / "generated-custom-cordapps" / timeDirName - defaultJarSignerDirectory = buildDir / "jar-signer" / timeDirName } fun getJarFile(cordapp: CustomCordapp): Path { @@ -179,10 +164,12 @@ data class CustomCordapp( val jarFile = cordappsDirectory.createDirectories() / filename if (it.fixups.isNotEmpty()) { it.createFixupJar(jarFile) - } else if(it.packages.isNotEmpty() || it.classes.isNotEmpty() || it.fixups.isNotEmpty()) { - it.packageAsJar(jarFile) + } else if (it.packages.isNotEmpty() || it.classes.isNotEmpty()) { + it.packageAsJar(jarFile) + } + if (it.signingInfo != null) { + TestCordappSigner.signJar(jarFile, it.signingInfo.keyStorePath, it.signingInfo.signatureCount, it.signingInfo.algorithm) } - it.signJar(jarFile) logger.debug { "$it packaged into $jarFile" } jarFile } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt index 6ce7a2e419..2d7b467d83 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt @@ -7,7 +7,6 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigRenderOptions -import com.typesafe.config.ConfigValue import com.typesafe.config.ConfigValueFactory import net.corda.client.rpc.CordaRPCClient import net.corda.client.rpc.RPCException @@ -24,6 +23,7 @@ import net.corda.core.internal.concurrent.fork import net.corda.core.internal.concurrent.map import net.corda.core.internal.concurrent.openFuture import net.corda.core.internal.concurrent.transpose +import net.corda.core.internal.copyToDirectory import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_LICENCE import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_NAME import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_VENDOR @@ -35,24 +35,18 @@ import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_WORKFLOW_VE import net.corda.core.internal.cordapp.CordappImpl.Companion.MIN_PLATFORM_VERSION import net.corda.core.internal.cordapp.CordappImpl.Companion.TARGET_PLATFORM_VERSION import net.corda.core.internal.cordapp.get -import net.corda.core.internal.createDirectories -import net.corda.core.internal.deleteIfExists -import net.corda.core.internal.div -import net.corda.core.internal.isRegularFile -import net.corda.core.internal.list import net.corda.core.internal.packageName_ import net.corda.core.internal.readObject -import net.corda.core.internal.readText import net.corda.core.internal.toPath -import net.corda.core.internal.uncheckedCast -import net.corda.core.internal.writeText import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.NetworkParameters import net.corda.core.node.NotaryInfo import net.corda.core.node.services.NetworkMapCache import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.contextLogger +import net.corda.core.utilities.debug import net.corda.core.utilities.getOrThrow +import net.corda.core.utilities.loggerFor import net.corda.core.utilities.millis import net.corda.core.utilities.toHexString import net.corda.coretesting.internal.stubs.CertificateStoreStubs @@ -62,6 +56,7 @@ import net.corda.node.internal.DataSourceFactory import net.corda.node.internal.Node import net.corda.node.internal.NodeWithInfo import net.corda.node.internal.clientSslOptionsCompatibleWith +import net.corda.node.internal.cordapp.JarScanningCordappLoader.Companion.LEGACY_CONTRACTS_DIR_NAME import net.corda.node.services.Permissions import net.corda.node.services.config.ConfigHelper import net.corda.node.services.config.FlowOverride @@ -118,8 +113,9 @@ import java.time.Instant import java.time.ZoneOffset.UTC import java.time.ZonedDateTime import java.time.format.DateTimeFormatter -import java.util.* import java.util.Collections.unmodifiableList +import java.util.Random +import java.util.UUID import java.util.concurrent.Executors import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.TimeUnit @@ -127,10 +123,15 @@ import java.util.concurrent.TimeoutException import java.util.concurrent.atomic.AtomicInteger import java.util.jar.JarInputStream import java.util.jar.Manifest -import kotlin.collections.ArrayList -import kotlin.collections.HashMap -import kotlin.collections.HashSet import kotlin.concurrent.thread +import kotlin.io.path.createDirectories +import kotlin.io.path.deleteIfExists +import kotlin.io.path.div +import kotlin.io.path.isRegularFile +import kotlin.io.path.name +import kotlin.io.path.readText +import kotlin.io.path.useDirectoryEntries +import kotlin.io.path.writeText import net.corda.nodeapi.internal.config.User as InternalUser class DriverDSLImpl( @@ -266,7 +267,7 @@ class DriverDSLImpl( override fun startNode(parameters: NodeParameters, bytemanPort: Int?): CordaFuture { val p2pAddress = portAllocation.nextHostAndPort() // TODO: Derive name from the full picked name, don't just wrap the common name - val name = parameters.providedName ?: CordaX500Name("${oneOf(names).organisation}-${p2pAddress.port}", "London", "GB") + val name = parameters.providedName ?: CordaX500Name("${names.random().organisation}-${p2pAddress.port}", "London", "GB") val config = createConfig(name, parameters, p2pAddress) if (isH2Database(config) && !inMemoryDB) { @@ -414,11 +415,11 @@ class DriverDSLImpl( while (process.isAlive) try { val response = client.newCall(Request.Builder().url(url).build()).execute() - if (response.isSuccessful && (response.body()?.string() == "started")) { + if (response.isSuccessful && (response.body?.string() == "started")) { return WebserverHandle(handle.webAddress, process) } } catch (e: ConnectException) { - log.debug("Retrying webserver info at ${handle.webAddress}") + log.debug { "Retrying webserver info at ${handle.webAddress}" } } throw IllegalStateException("Webserver at ${handle.webAddress} has died") @@ -577,9 +578,8 @@ class DriverDSLImpl( // This causes two node info files to be generated. startOutOfProcessMiniNode(config, arrayOf("generate-node-info")).map { // Once done we have to read the signed node info file that's been generated - val nodeInfoFile = config.corda.baseDirectory.list { paths -> - paths.filter { it.fileName.toString().startsWith(NodeInfoFilesCopier.NODE_INFO_FILE_NAME_PREFIX) }.findFirst() - .get() + val nodeInfoFile = config.corda.baseDirectory.useDirectoryEntries { paths -> + paths.single { it.name.startsWith(NodeInfoFilesCopier.NODE_INFO_FILE_NAME_PREFIX) } } val nodeInfo = nodeInfoFile.readObject().verified() Pair(config.withNotaryDefinition(spec.validating), NotaryInfo(nodeInfo.legalIdentities[0], spec.validating)) @@ -718,6 +718,11 @@ class DriverDSLImpl( extraCustomCordapps + (cordappsForAllNodes ?: emptySet()) ) + if (parameters.legacyContracts.isNotEmpty()) { + val legacyContractsDir = (baseDirectory / LEGACY_CONTRACTS_DIR_NAME).createDirectories() + parameters.legacyContracts.forEach { (it as TestCordappInternal).jarFile.copyToDirectory(legacyContractsDir) } + } + val nodeFuture = if (parameters.startInSameProcess ?: startNodesInProcess) { val nodeAndThreadFuture = startInProcessNode(executorService, config, allowHibernateToManageAppSchema) shutdownManager.registerShutdown( @@ -848,7 +853,7 @@ class DriverDSLImpl( companion object { private val RPC_CONNECT_POLL_INTERVAL: Duration = 100.millis - internal val log = contextLogger() + private val log = contextLogger() // While starting with inProcess mode, we need to have different names to avoid clashes private val inMemoryCounter = AtomicInteger() @@ -890,18 +895,6 @@ class DriverDSLImpl( CORDAPP_WORKFLOW_VERSION )) - private inline fun Config.withOptionalValue(key: String, obj: T?, body: (T) -> ConfigValue): Config { - return if (obj == null) { - this - } else { - withValue(key, body(obj)) - } - } - - private fun valueFor(any: T): ConfigValue = ConfigValueFactory.fromAnyRef(any) - - private fun oneOf(array: Array) = array[Random().nextInt(array.size)] - private fun startInProcessNode( executorService: ScheduledExecutorService, config: NodeConfig, @@ -969,15 +962,15 @@ class DriverDSLImpl( val excludePackagePattern = "x(antlr**;bftsmart**;ch**;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**;joptsimple**;junit**;kotlin**;net.bytebuddy**;" + - "net.i2p**;org.apache**;" + + "io.github**;io.netty**;jdk**;joptsimple**;junit**;kotlin**;net.bytebuddy**;org.apache**;" + "org.assertj**;org.bouncycastle**;org.codehaus**;org.crsh**;org.dom4j**;org.fusesource**;org.h2**;" + "org.hamcrest**;org.hibernate**;org.jboss**;org.jcp**;org.joda**;org.junit**;org.mockito**;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**;)" val excludeClassloaderPattern = "l(net.corda.core.serialization.internal.**)" + val quasarOptions = "m" val extraJvmArguments = systemProperties.removeResolvedClasspath().map { "-D${it.key}=${it.value}" } + - "-javaagent:$quasarJarPath=$excludePackagePattern$excludeClassloaderPattern" + "-javaagent:$quasarJarPath=$quasarOptions$excludePackagePattern$excludeClassloaderPattern" val loggingLevel = when { logLevelOverride != null -> logLevelOverride @@ -992,26 +985,27 @@ class DriverDSLImpl( it.addAll(extraCmdLineFlag) }.toList() - val bytemanJvmArgs = { - val bytemanAgent = bytemanJarPath?.let { - bytemanPort?.let { - "-javaagent:$bytemanJarPath=port:$bytemanPort,listener:true" - } + val bytemanAgent = bytemanJarPath?.let { + bytemanPort?.let { + "-javaagent:$bytemanJarPath=port:$bytemanPort,listener:true" } - listOfNotNull(bytemanAgent) + - if (bytemanAgent != null && debugPort != null) listOf( + } + val bytemanJvmArgs = listOfNotNull(bytemanAgent) + + if (bytemanAgent != null && debugPort != null) { + listOf( "-Dorg.jboss.byteman.verbose=true", "-Dorg.jboss.byteman.debug=true" ) - else emptyList() - }.invoke() + } else { + emptyList() + } // The following dependencies are excluded from the classpath of the created JVM, // so that the environment resembles a real one as close as possible. val cp = ProcessUtilities.defaultClassPath.filter { cpEntry -> val cpPathEntry = Paths.get(cpEntry) cpPathEntry.isRegularFile() - && !isTestArtifact(cpPathEntry.fileName.toString()) + && !isTestArtifact(cpPathEntry.name) && !cpPathEntry.isExcludedJar } @@ -1019,7 +1013,7 @@ class DriverDSLImpl( className = "net.corda.node.Corda", // cannot directly get class for this, so just use string arguments = arguments, jdwpPort = debugPort, - extraJvmArguments = extraJvmArguments + bytemanJvmArgs + "-Dnet.corda.node.printErrorsToStdErr=true", + extraJvmArguments = extraJvmArguments + bytemanJvmArgs + nodeJvmArgs + "-Dnet.corda.node.printErrorsToStdErr=true", workingDirectory = config.corda.baseDirectory, maximumHeapSize = maximumHeapSize, classPath = cp, @@ -1066,10 +1060,10 @@ class DriverDSLImpl( } private fun startWebserver(handle: NodeHandleInternal, debugPort: Int?, maximumHeapSize: String): Process { - val className = "net.corda.webserver.WebServer" writeConfig(handle.baseDirectory, "web-server.conf", handle.toWebServerConfig()) return ProcessUtilities.startJavaProcess( - className = className, // cannot directly get class for this, so just use string + className = "net.corda.webserver.WebServer", // cannot directly get class for this, so just use string + workingDirectory = handle.baseDirectory, arguments = listOf(BASE_DIR, handle.baseDirectory.toString()), jdwpPort = debugPort, extraJvmArguments = listOf("-Dname=node-${handle.p2pAddress}-webserver") + @@ -1092,12 +1086,11 @@ class DriverDSLImpl( } private fun NodeHandleInternal.toWebServerConfig(): Config { - var config = ConfigFactory.empty() config += "webAddress" to webAddress.toString() config += "myLegalName" to configuration.myLegalName.toString() config += "rpcAddress" to configuration.rpcOptions.address.toString() - config += "rpcUsers" to configuration.toConfig().getValue("rpcUsers") + config += "rpcUsers" to configuration.rpcUsers.map { it.toConfig().root().unwrapped() } config += "useHTTPS" to useHTTPS config += "baseDirectory" to configuration.baseDirectory.toAbsolutePath().toString() @@ -1111,7 +1104,7 @@ class DriverDSLImpl( } private fun createCordappsClassLoader(cordapps: Collection?): URLClassLoader? { - if (cordapps == null || cordapps.isEmpty()) { + if (cordapps.isNullOrEmpty()) { return null } return URLClassLoader(cordapps.map { it.jarFile.toUri().toURL() }.toTypedArray()) @@ -1267,59 +1260,7 @@ fun genericDriver( driverDsl.start() return dsl(coerce(driverDsl)) } catch (exception: Throwable) { - DriverDSLImpl.log.error("Driver shutting down because of exception", exception) - throw exception - } finally { - driverDsl.shutdown() - shutdownHook.cancel() - } - } -} - -/** - * This is a helper method to allow extending of the DSL, along the lines of - * interface SomeOtherExposedDSLInterface : DriverDSL - * interface SomeOtherInternalDSLInterface : InternalDriverDSL, SomeOtherExposedDSLInterface - * class SomeOtherDSL(val driverDSL : DriverDSLImpl) : InternalDriverDSL by driverDSL, SomeOtherInternalDSLInterface - * - * @param coerce We need this explicit coercion witness because we can't put an extra DI : D bound in a `where` clause. - */ -fun genericDriver( - defaultParameters: DriverParameters = DriverParameters(), - driverDslWrapper: (DriverDSLImpl) -> D, - coerce: (D) -> DI, dsl: DI.() -> A -): A { - setDriverSerialization().use { _ -> - val driverDsl = driverDslWrapper( - DriverDSLImpl( - portAllocation = defaultParameters.portAllocation, - debugPortAllocation = defaultParameters.debugPortAllocation, - systemProperties = defaultParameters.systemProperties, - driverDirectory = defaultParameters.driverDirectory.toAbsolutePath(), - useTestClock = defaultParameters.useTestClock, - isDebug = defaultParameters.isDebug, - startNodesInProcess = defaultParameters.startNodesInProcess, - waitForAllNodesToFinish = defaultParameters.waitForAllNodesToFinish, - extraCordappPackagesToScan = @Suppress("DEPRECATION") defaultParameters.extraCordappPackagesToScan, - jmxPolicy = defaultParameters.jmxPolicy, - notarySpecs = defaultParameters.notarySpecs, - compatibilityZone = null, - networkParameters = defaultParameters.networkParameters, - notaryCustomOverrides = defaultParameters.notaryCustomOverrides, - inMemoryDB = defaultParameters.inMemoryDB, - cordappsForAllNodes = uncheckedCast(defaultParameters.cordappsForAllNodes), - environmentVariables = defaultParameters.environmentVariables, - allowHibernateToManageAppSchema = defaultParameters.allowHibernateToManageAppSchema, - premigrateH2Database = defaultParameters.premigrateH2Database, - notaryHandleTimeout = defaultParameters.notaryHandleTimeout - ) - ) - val shutdownHook = addShutdownHook(driverDsl::shutdown) - try { - driverDsl.start() - return dsl(coerce(driverDsl)) - } catch (exception: Throwable) { - DriverDSLImpl.log.error("Driver shutting down because of exception", exception) + loggerFor().error("Driver shutting down because of exception", exception) throw exception } finally { driverDsl.shutdown() @@ -1334,7 +1275,7 @@ fun genericDriver( * @property publishNotaries Hook for a network map server to capture the generated [NotaryInfo] objects needed for * creating the network parameters. This is needed as the network map server is expected to distribute it. The callback * will occur on a different thread to the driver-calling thread. - * @property rootCert If specified then the nodes will register themselves with the doorman service using [url] and expect + * @property rootCert If specified then the nodes will register themselves with the doorman service using [SharedCompatibilityZoneParams.url] and expect * the registration response to be rooted at this cert. If not specified then no registration is performed and the dev * root cert is used as normal. * diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt index a844684510..aaadddf5b3 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt @@ -1,7 +1,5 @@ package net.corda.testing.node.internal -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever import net.corda.common.configuration.parsing.internal.ConfigurationWithOptions import net.corda.core.DoNotImplement import net.corda.core.crypto.SecureHash @@ -15,10 +13,8 @@ import net.corda.core.internal.FlowIORequest import net.corda.core.internal.NetworkParametersStorage import net.corda.core.internal.PLATFORM_VERSION import net.corda.core.internal.VisibleForTesting -import net.corda.core.internal.createDirectories -import net.corda.core.internal.deleteIfExists -import net.corda.core.internal.div import net.corda.core.internal.notary.NotaryService +import net.corda.core.internal.telemetry.TelemetryServiceImpl import net.corda.core.internal.uncheckedCast import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.MessageRecipients @@ -27,7 +23,6 @@ import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.NetworkParameters import net.corda.core.node.NodeInfo import net.corda.core.node.NotaryInfo -import net.corda.core.internal.telemetry.TelemetryServiceImpl import net.corda.core.serialization.SerializationWhitelist import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.contextLogger @@ -74,6 +69,8 @@ import net.corda.testing.node.MockServices.Companion.makeTestDataSourcePropertie import net.corda.testing.node.TestClock import org.apache.activemq.artemis.utils.ReusableLatch import org.apache.sshd.common.util.security.SecurityUtils +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import rx.Observable import rx.Scheduler import rx.internal.schedulers.CachedThreadScheduler @@ -85,6 +82,9 @@ import java.time.Clock import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicReference +import kotlin.io.path.createDirectories +import kotlin.io.path.deleteIfExists +import kotlin.io.path.div val MOCK_VERSION_INFO = VersionInfo(PLATFORM_VERSION, "Mock release", "Mock revision", "Mock Vendor") @@ -116,9 +116,6 @@ data class InternalMockNodeParameters( ) } -/** - * A [StartedNode] which exposes its internal [InternalMockNetwork.MockNode] for testing. - */ interface TestStartedNode { val internals: InternalMockNetwork.MockNode val info: NodeInfo @@ -170,7 +167,7 @@ open class InternalMockNetwork(cordappPackages: List = emptyList(), val autoVisibleNodes: Boolean = true) : AutoCloseable { companion object { fun createCordappClassLoader(cordapps: Collection?): URLClassLoader? { - if (cordapps == null || cordapps.isEmpty()) { + if (cordapps.isNullOrEmpty()) { return null } return URLClassLoader(cordapps.map { it.jarFile.toUri().toURL() }.toTypedArray()) @@ -352,7 +349,6 @@ open class InternalMockNetwork(cordappPackages: List = emptyList(), private val entropyCounter = AtomicReference(args.entropyRoot) override val log get() = staticLog - override val transactionVerifierWorkerCount: Int get() = 1 private var _rxIoScheduler: Scheduler? = null override val rxIoScheduler: Scheduler @@ -455,18 +451,15 @@ open class InternalMockNetwork(cordappPackages: List = emptyList(), return if (track) { smm.changes.filter { it is StateMachineManager.Change.Add }.map { it.logic }.ofType(initiatedFlowClass) } else { - Observable.empty() + Observable.empty() } } override fun makeNetworkParametersStorage(): NetworkParametersStorage = MockNetworkParametersStorage() } - fun createUnstartedNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters()): MockNode { - return createUnstartedNode(parameters, defaultFactory) - } - - fun createUnstartedNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs) -> MockNode): MockNode { + fun createUnstartedNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), + nodeFactory: (MockNodeArgs) -> MockNode = defaultFactory): MockNode { return createNodeImpl(parameters, nodeFactory, false) } @@ -681,16 +674,17 @@ private fun mockNodeConfiguration(certificatesDirectory: Path): NodeConfiguratio } class MockNodeFlowManager : NodeFlowManager() { - val testingRegistrations = HashMap>, InitiatedFlowFactory<*>>() + private val testingRegistrations = HashMap>, InitiatedFlowFactory<*>>() + override fun getFlowFactoryForInitiatingFlow(initiatedFlowClass: Class>): InitiatedFlowFactory<*>? { if (initiatedFlowClass in testingRegistrations) { - return testingRegistrations.get(initiatedFlowClass) + return testingRegistrations[initiatedFlowClass] } return super.getFlowFactoryForInitiatingFlow(initiatedFlowClass) } fun registerTestingFactory(initiator: Class>, factory: InitiatedFlowFactory<*>) { - testingRegistrations.put(initiator, factory) + testingRegistrations[initiator] = factory } } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetworkConfigOverrides.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetworkConfigOverrides.kt index 15c4755e7e..744116e56f 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetworkConfigOverrides.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetworkConfigOverrides.kt @@ -1,7 +1,7 @@ package net.corda.testing.node.internal -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever import net.corda.node.services.config.FlowTimeoutConfiguration import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NotaryConfig @@ -18,4 +18,4 @@ fun MockNodeConfigOverrides.applyMockNodeOverrides(config: NodeConfiguration) { this.extraDataSourceProperties?.forEach { k, v -> it.dataSourceProperties.put(k, v) } this.flowTimeout?.also { fto -> doReturn(FlowTimeoutConfiguration(fto.timeout, fto.maxRestartCount, fto.backoffBase)).whenever(config).flowTimeout } } -} \ No newline at end of file +} diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalTestUtils.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalTestUtils.kt index 32cd878b88..df908b5bab 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalTestUtils.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalTestUtils.kt @@ -10,8 +10,6 @@ import net.corda.core.identity.CordaX500Name import net.corda.core.internal.FlowStateMachineHandle import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.concurrent.openFuture -import net.corda.core.internal.div -import net.corda.core.internal.readText import net.corda.core.internal.times import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.services.AttachmentFixup @@ -22,14 +20,14 @@ import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.millis import net.corda.core.utilities.seconds +import net.corda.coretesting.internal.createTestSerializationEnv +import net.corda.coretesting.internal.inVMExecutors import net.corda.node.services.api.StartedNodeServices import net.corda.node.services.messaging.Message import net.corda.node.services.statemachine.Checkpoint import net.corda.testing.driver.DriverDSL import net.corda.testing.driver.NodeHandle import net.corda.testing.internal.chooseIdentity -import net.corda.coretesting.internal.createTestSerializationEnv -import net.corda.coretesting.internal.inVMExecutors import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.TestCordapp import net.corda.testing.node.User @@ -50,6 +48,8 @@ import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.TimeUnit import java.util.jar.JarOutputStream import java.util.zip.ZipEntry +import kotlin.io.path.div +import kotlin.io.path.readText import kotlin.reflect.KClass private val log = LoggerFactory.getLogger("net.corda.testing.internal.InternalTestUtils") @@ -61,7 +61,7 @@ private val log = LoggerFactory.getLogger("net.corda.testing.internal.InternalTe * You will probably need to use [FINANCE_CORDAPPS] instead to get access to the flows as well. */ @JvmField -val FINANCE_CONTRACTS_CORDAPP: TestCordappImpl = findCordapp("net.corda.finance.contracts") +val FINANCE_CONTRACTS_CORDAPP: ScanPackageTestCordapp = findCordapp("net.corda.finance.contracts") /** * Reference to the finance-workflows CorDapp in this repo. The metadata is taken directly from finance/workflows/build.gradle, including the @@ -70,10 +70,10 @@ val FINANCE_CONTRACTS_CORDAPP: TestCordappImpl = findCordapp("net.corda.finance. * You will probably need to use [FINANCE_CORDAPPS] instead to get access to the contract classes as well. */ @JvmField -val FINANCE_WORKFLOWS_CORDAPP: TestCordappImpl = findCordapp("net.corda.finance.workflows") +val FINANCE_WORKFLOWS_CORDAPP: ScanPackageTestCordapp = findCordapp("net.corda.finance.workflows") @JvmField -val FINANCE_CORDAPPS: Set = setOf(FINANCE_CONTRACTS_CORDAPP, FINANCE_WORKFLOWS_CORDAPP) +val FINANCE_CORDAPPS: Set = setOf(FINANCE_CONTRACTS_CORDAPP, FINANCE_WORKFLOWS_CORDAPP) /** * *Custom* CorDapp containing the contents of the `net.corda.testing.contracts` package, i.e. the dummy contracts. This is not a real CorDapp @@ -105,9 +105,9 @@ fun cordappWithFixups(fixups: List) = CustomCordapp(fixups = fi /** * Find the single CorDapp jar on the current classpath which contains the given package. This is a convenience method for - * [TestCordapp.findCordapp] but returns the internal [TestCordappImpl]. + * [TestCordapp.findCordapp] but returns the internal [ScanPackageTestCordapp]. */ -fun findCordapp(scanPackage: String): TestCordappImpl = TestCordapp.findCordapp(scanPackage) as TestCordappImpl +fun findCordapp(scanPackage: String): ScanPackageTestCordapp = TestCordapp.findCordapp(scanPackage) as ScanPackageTestCordapp /** Create a *custom* CorDapp which just contains the enclosed classes of the receiver class. */ fun Any.enclosedCordapp(): CustomCordapp { @@ -169,8 +169,7 @@ fun addressMustBeBoundFuture(executorService: ScheduledExecutorService, hostAndP } try { Socket(hostAndPort.host, hostAndPort.port).close() - Unit - } catch (_exception: SocketException) { + } catch (_: SocketException) { null } } @@ -188,7 +187,7 @@ fun nodeMustBeStartedFuture( throw exception() } when { - logFile.readText().contains("Running P2PMessaging loop") -> { + "Running P2PMessaging loop" in logFile.readText() -> { Unit } Instant.now().isAfter(stopPolling) -> { @@ -217,9 +216,7 @@ fun addressMustNotBeBoundFuture(executorService: ScheduledExecutorService, hostA try { Socket(hostAndPort.host, hostAndPort.port).close() null - } catch (_exception: SocketException) { - Unit - } + } catch (_: SocketException) { } } } @@ -304,6 +301,10 @@ fun DriverDSL.assertUncompletedCheckpoints(name: CordaX500Name, expected: Long) } } +val nodeJvmArgs: List by lazy { + DriverDSLImpl::class.java.getResourceAsStream("node-jvm-args.txt")!!.use { it.bufferedReader().readLines() } +} + /** * Should only be used by Driver and MockNode. */ diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt index 97a354c8fd..bae489c841 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt @@ -5,26 +5,27 @@ import net.corda.core.identity.Party import net.corda.core.internal.PLATFORM_VERSION import net.corda.core.internal.concurrent.fork import net.corda.core.internal.concurrent.transpose -import net.corda.core.internal.createDirectories -import net.corda.core.internal.div -import net.corda.core.node.NodeInfo import net.corda.core.node.NotaryInfo import net.corda.core.utilities.getOrThrow +import net.corda.coretesting.internal.testThreadFactory import net.corda.node.VersionInfo import net.corda.node.internal.FlowManager import net.corda.node.internal.Node import net.corda.node.internal.NodeFlowManager import net.corda.node.internal.NodeWithInfo -import net.corda.node.services.config.* +import net.corda.node.services.config.ConfigHelper +import net.corda.node.services.config.FlowOverrideConfig +import net.corda.node.services.config.NodeConfiguration +import net.corda.node.services.config.configOf +import net.corda.node.services.config.parseAsNodeConfiguration +import net.corda.node.services.config.plus import net.corda.nodeapi.internal.DevIdentityGenerator import net.corda.nodeapi.internal.config.toConfig import net.corda.nodeapi.internal.network.NetworkParametersCopier import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.driver.internal.incrementalPortAllocation -import net.corda.coretesting.internal.testThreadFactory import net.corda.testing.node.User -import org.apache.commons.lang3.SystemUtils import org.apache.logging.log4j.Level import org.junit.After import org.junit.Before @@ -34,7 +35,8 @@ import rx.internal.schedulers.CachedThreadScheduler import java.nio.file.Path import java.util.concurrent.Executors import kotlin.concurrent.thread -import kotlin.test.assertFalse +import kotlin.io.path.createDirectories +import kotlin.io.path.div // TODO Some of the logic here duplicates what's in the driver - the reason why it's not straightforward to replace it by // using DriverDSLImpl in `init()` and `stopAllNodes()` is because of the platform version passed to nodes (driver doesn't @@ -60,7 +62,7 @@ abstract class NodeBasedTest @JvmOverloads constructor( private val portAllocation = incrementalPortAllocation() init { - System.setProperty("consoleLogLevel", Level.DEBUG.name().toLowerCase()) + System.setProperty("consoleLogLevel", Level.DEBUG.name().lowercase()) } @Before @@ -161,12 +163,9 @@ class InProcessNode( configuration: NodeConfiguration, versionInfo: VersionInfo, flowManager: FlowManager = NodeFlowManager(configuration.flowOverrides), - allowHibernateToManageAppSchema: Boolean = true) : Node(configuration, versionInfo, false, flowManager = flowManager, allowHibernateToManageAppSchema = allowHibernateToManageAppSchema) { + allowHibernateToManageAppSchema: Boolean = true +) : Node(configuration, versionInfo, false, flowManager = flowManager, allowHibernateToManageAppSchema = allowHibernateToManageAppSchema) { override val runMigrationScripts: Boolean = true - override fun start(): NodeInfo { - assertFalse(isInvalidJavaVersion(), "You are using a version of Java that is not supported (${SystemUtils.JAVA_VERSION}). Please upgrade to the latest version of Java 8.") - return super.start() - } override val rxIoScheduler get() = CachedThreadScheduler(testThreadFactory()).also { runOnStop += it::shutdown } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/ProcessUtilities.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/ProcessUtilities.kt index c4a04ecb2a..00fea1ce6c 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/ProcessUtilities.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/ProcessUtilities.kt @@ -1,8 +1,9 @@ package net.corda.testing.node.internal -import net.corda.core.internal.div import java.io.File import java.nio.file.Path +import kotlin.io.path.Path +import kotlin.io.path.div object ProcessUtilities { @Suppress("LongParameterList") @@ -38,19 +39,16 @@ object ProcessUtilities { maximumHeapSize: String? = null, identifier: String = "", environmentVariables: Map = emptyMap(), - inheritIO: Boolean = true ): Process { val command = mutableListOf().apply { add(javaPath) (jdwpPort != null) && add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$jdwpPort") if (maximumHeapSize != null) add("-Xmx$maximumHeapSize") - add("-XX:+UseG1GC") addAll(extraJvmArguments) add(className) addAll(arguments) } return ProcessBuilder(command).apply { - if (inheritIO) inheritIO() environment().putAll(environmentVariables) environment()["CLASSPATH"] = classPath.joinToString(File.pathSeparator) if (workingDirectory != null) { @@ -63,7 +61,7 @@ object ProcessUtilities { }.start() } - private val javaPath = (System.getProperty("java.home") / "bin" / "java").toString() + private val javaPath = Path(System.getProperty("java.home"), "bin", "java").toString() val defaultClassPath: List = System.getProperty("java.class.path").split(File.pathSeparator) -} \ No newline at end of file +} diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt index dcb12782c5..d4aaf87130 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt @@ -14,7 +14,6 @@ import net.corda.core.identity.CordaX500Name import net.corda.core.internal.concurrent.doneFuture import net.corda.core.internal.concurrent.fork import net.corda.core.internal.concurrent.map -import net.corda.core.internal.div import net.corda.core.internal.uncheckedCast import net.corda.core.messaging.RPCOps import net.corda.core.node.NetworkParameters @@ -59,6 +58,7 @@ import java.nio.file.Path import java.nio.file.Paths import java.time.Duration import java.util.* +import kotlin.io.path.div import net.corda.nodeapi.internal.config.User as InternalUser inline fun RPCDriverDSL.startInVmRpcClient( @@ -188,23 +188,23 @@ data class RPCDriverDSL( private val driverDSL: DriverDSLImpl, private val externalTrace: Trace? ) : InternalDriverDSL by driverDSL { private companion object { - const val notificationAddress = "notifications" + const val NOTIFICATION_ADDRESS = "notifications" private fun ConfigurationImpl.configureCommonSettings(maxFileSize: Int, maxBufferedBytesPerClient: Long) { name = "RPCDriver" - managementNotificationAddress = SimpleString(notificationAddress) + managementNotificationAddress = SimpleString.of(NOTIFICATION_ADDRESS) isPopulateValidatedUser = true journalBufferSize_NIO = maxFileSize journalBufferSize_AIO = maxFileSize journalFileSize = maxFileSize queueConfigs = listOf( - QueueConfiguration(RPCApi.RPC_SERVER_QUEUE_NAME).setAddress(RPCApi.RPC_SERVER_QUEUE_NAME).setDurable(false), - QueueConfiguration(RPCApi.RPC_CLIENT_BINDING_REMOVALS).setAddress(notificationAddress) + QueueConfiguration.of(RPCApi.RPC_SERVER_QUEUE_NAME).setAddress(RPCApi.RPC_SERVER_QUEUE_NAME).setDurable(false), + QueueConfiguration.of(RPCApi.RPC_CLIENT_BINDING_REMOVALS).setAddress(NOTIFICATION_ADDRESS) .setFilterString(RPCApi.RPC_CLIENT_BINDING_REMOVAL_FILTER_EXPRESSION).setDurable(false), - QueueConfiguration(RPCApi.RPC_CLIENT_BINDING_ADDITIONS).setAddress(notificationAddress) + QueueConfiguration.of(RPCApi.RPC_CLIENT_BINDING_ADDITIONS).setAddress(NOTIFICATION_ADDRESS) .setFilterString(RPCApi.RPC_CLIENT_BINDING_ADDITION_FILTER_EXPRESSION).setDurable(false) ) - addressesSettings = mapOf( + addressSettings = mapOf( "${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.#" to AddressSettings().apply { maxSizeBytes = maxBufferedBytesPerClient addressFullMessagePolicy = AddressFullMessagePolicy.PAGE diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappImpl.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/ScanPackageTestCordapp.kt similarity index 63% rename from testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappImpl.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/ScanPackageTestCordapp.kt index 68b37b5247..ea55c4ceda 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappImpl.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/ScanPackageTestCordapp.kt @@ -1,7 +1,9 @@ package net.corda.testing.node.internal import io.github.classgraph.ClassGraph -import net.corda.core.internal.* +import net.corda.core.internal.attributes +import net.corda.core.internal.mapToSet +import net.corda.core.internal.pooledScan import net.corda.core.utilities.contextLogger import net.corda.testing.node.TestCordapp import org.gradle.tooling.GradleConnector @@ -9,9 +11,10 @@ import org.gradle.tooling.ProgressEvent import java.io.File import java.io.RandomAccessFile import java.nio.file.Path -import java.util.* import java.util.concurrent.ConcurrentHashMap -import kotlin.streams.toList +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.useDirectoryEntries /** * Implementation of the public [TestCordapp] API. @@ -21,39 +24,43 @@ import kotlin.streams.toList * the [scanPackage] may reference a gradle CorDapp project on the local system. In this scenerio the project's "jar" task is executed to * build the CorDapp jar. This allows us to inherit the CorDapp's MANIFEST information without having to do any extra processing. */ -data class TestCordappImpl(val scanPackage: String, override val config: Map) : TestCordappInternal() { - override fun withConfig(config: Map): TestCordappImpl = copy(config = config) +data class ScanPackageTestCordapp(val scanPackage: String, + override val config: Map = emptyMap(), + val signed: Boolean = false) : TestCordappInternal() { + override fun withConfig(config: Map): ScanPackageTestCordapp = copy(config = config) - override fun withOnlyJarContents(): TestCordappImpl = copy(config = emptyMap()) + override fun asSigned(): TestCordapp = copy(signed = true) - override val jarFile: Path - get() { - val jars = findJars(scanPackage) - when (jars.size) { - 0 -> throw IllegalArgumentException("There are no CorDapps containing the package $scanPackage on the classpath. Make sure " + - "the package name is correct and that the CorDapp is added as a gradle dependency.") - 1 -> return jars.first() - else -> throw IllegalArgumentException("There is more than one CorDapp containing the package $scanPackage on the classpath " + - "$jars. Specify a package name which is unique to the CorDapp.") - } + override fun withOnlyJarContents(): ScanPackageTestCordapp = copy(config = emptyMap(), signed = false) + + override val jarFile: Path by lazy { + val jars = findJars() + val jar = when (jars.size) { + 0 -> throw IllegalArgumentException("There are no CorDapps containing the package $scanPackage on the classpath. Make sure " + + "the package name is correct and that the CorDapp is added as a gradle dependency.") + 1 -> jars.first() + else -> throw IllegalArgumentException("There is more than one CorDapp containing the package $scanPackage on the classpath " + + "$jars. Specify a package name which is unique to the CorDapp.") } + if (signed) TestCordappSigner.signJarCopy(jar) else jar + } + + private fun findJars(): Set { + val rootPaths = findRootPaths(scanPackage) + return if (rootPaths.all { it.toString().endsWith(".jar") }) { + // We don't need to do anything more if all the root paths are jars + rootPaths + } else { + // Otherwise we need to build those paths which are local projects and extract the built jar from them + rootPaths.mapToSet { if (it.toString().endsWith(".jar")) it else buildCordappJar(it) } + } + } companion object { private val packageToRootPaths = ConcurrentHashMap>() private val projectRootToBuiltJar = ConcurrentHashMap() private val log = contextLogger() - fun findJars(scanPackage: String): Set { - val rootPaths = findRootPaths(scanPackage) - return if (rootPaths.all { it.toString().endsWith(".jar") }) { - // We don't need to do anything more if all the root paths are jars - rootPaths - } else { - // Otherwise we need to build those paths which are local projects and extract the built jar from them - rootPaths.mapTo(HashSet()) { if (it.toString().endsWith(".jar")) it else buildCordappJar(it) } - } - } - private fun findRootPaths(scanPackage: String): Set { return packageToRootPaths.computeIfAbsent(scanPackage) { val classGraph = ClassGraph().acceptPaths(scanPackage.replace('.', '/')) @@ -87,11 +94,8 @@ data class TestCordappImpl(val scanPackage: String, override val config: Map + jars.filter { !it.toString().endsWith("sources.jar") && !it.toString().endsWith("javadoc.jar") }.toList() }.sortedBy { it.attributes().creationTime() } checkNotNull(jars.lastOrNull()) { "No jars were built in $libs" } } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappInternal.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappInternal.kt index d04eb9f147..8a485a0352 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappInternal.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappInternal.kt @@ -2,12 +2,13 @@ package net.corda.testing.node.internal import com.typesafe.config.ConfigValueFactory import net.corda.core.internal.copyToDirectory -import net.corda.core.internal.createDirectories -import net.corda.core.internal.div -import net.corda.core.internal.writeText import net.corda.testing.node.TestCordapp import java.nio.file.FileAlreadyExistsException import java.nio.file.Path +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.name +import kotlin.io.path.writeText /** * Extends the public [TestCordapp] API with internal extensions for use within the testing framework and for internal testing of the platform. @@ -45,7 +46,7 @@ abstract class TestCordappInternal : TestCordapp() { // Ignore if the node already has the same CorDapp jar. This can happen if the node is being restarted. } val configString = ConfigValueFactory.fromMap(cordapp.config).toConfig().root().render() - (configDir / "${jar.fileName.toString().removeSuffix(".jar")}.conf").writeText(configString) + (configDir / "${jar.name.removeSuffix(".jar")}.conf").writeText(configString) } } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappSigner.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappSigner.kt new file mode 100644 index 0000000000..e9159e7330 --- /dev/null +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappSigner.kt @@ -0,0 +1,45 @@ +package net.corda.testing.node.internal + +import net.corda.core.internal.deleteRecursively +import net.corda.testing.core.internal.JarSignatureTestUtils.containsKey +import net.corda.testing.core.internal.JarSignatureTestUtils.generateKey +import net.corda.testing.core.internal.JarSignatureTestUtils.signJar +import net.corda.testing.core.internal.JarSignatureTestUtils.unsignJar +import java.nio.file.Files +import java.nio.file.Path +import kotlin.io.path.absolutePathString +import kotlin.io.path.copyTo +import kotlin.io.path.name + +object TestCordappSigner { + private val defaultSignerDir = Files.createTempDirectory("testcordapp-signer") + + init { + defaultSignerDir.generateKey(alias = "testcordapp") + Runtime.getRuntime().addShutdownHook(Thread(defaultSignerDir::deleteRecursively)) + } + + fun signJarCopy(jar: Path, signerDir: Path? = null, signatureCount: Int = 1, algorithm: String = "RSA"): Path { + val copy = Files.createTempFile(jar.name, ".jar") + copy.toFile().deleteOnExit() + jar.copyTo(copy, overwrite = true) + signJar(copy, signerDir, signatureCount, algorithm) + return copy + } + + fun signJar(jar: Path, signerDir: Path? = null, signatureCount: Int = 1, algorithm: String = "RSA") { + jar.unsignJar() + val signerDirToUse = signerDir ?: defaultSignerDir + for (i in 1 .. signatureCount) { + // Note in the jarsigner tool if -sigfile is not specified then the first 8 chars of alias are used as the file + // name for the .SF and .DSA files. (See jarsigner doc). So $i below needs to be at beginning so unique files are + // created. + val alias = "$i-testcordapp-$algorithm" + val password = "secret!" + if (!signerDirToUse.containsKey(alias, password)) { + signerDirToUse.generateKey(alias, password, "O=Test Company Ltd $i,OU=Test,L=London,C=GB", algorithm) + } + signerDirToUse.signJar(jar.absolutePathString(), alias, password) + } + } +} diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/UriTestCordapp.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/UriTestCordapp.kt new file mode 100644 index 0000000000..e66c2c3032 --- /dev/null +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/UriTestCordapp.kt @@ -0,0 +1,39 @@ +package net.corda.testing.node.internal + +import net.corda.core.internal.copyTo +import net.corda.core.utilities.Try +import net.corda.core.utilities.Try.Failure +import net.corda.core.utilities.Try.Success +import net.corda.testing.node.TestCordapp +import java.net.URI +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.StandardCopyOption.REPLACE_EXISTING +import kotlin.io.path.toPath + +data class UriTestCordapp(val uri: URI, + override val config: Map = emptyMap(), + val signed: Boolean = false) : TestCordappInternal() { + override fun withConfig(config: Map): TestCordapp = copy(config = config) + + override fun asSigned(): TestCordapp = copy(signed = true) + + override fun withOnlyJarContents(): TestCordappInternal = copy(config = emptyMap(), signed = false) + + override val jarFile: Path by lazy { + val toPathAttempt = Try.on(uri::toPath) + when (toPathAttempt) { + is Success -> if (signed) TestCordappSigner.signJarCopy(toPathAttempt.value) else toPathAttempt.value + is Failure -> { + // URI is not a local path, so we copy it to a temp file and use that. + val downloaded = Files.createTempFile("test-cordapp-${uri.path.substringAfterLast("/").substringBeforeLast(".jar")}", ".jar") + downloaded.toFile().deleteOnExit() + uri.toURL().openStream().use { it.copyTo(downloaded, REPLACE_EXISTING) } + if (signed) { + TestCordappSigner.signJar(downloaded) + } + downloaded + } + } + } +} diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/network/CrlServer.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/network/CrlServer.kt index b6dee805fa..48cd6279ac 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/network/CrlServer.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/network/CrlServer.kt @@ -2,6 +2,10 @@ package net.corda.testing.node.internal.network +import jakarta.ws.rs.GET +import jakarta.ws.rs.Path +import jakarta.ws.rs.Produces +import jakarta.ws.rs.core.Response import net.corda.core.crypto.Crypto import net.corda.core.internal.CertRole import net.corda.core.internal.toX500Name @@ -24,11 +28,11 @@ import org.bouncycastle.asn1.x509.DistributionPointName import org.bouncycastle.asn1.x509.Extension import org.bouncycastle.asn1.x509.GeneralName import org.bouncycastle.asn1.x509.GeneralNames +import org.eclipse.jetty.ee10.servlet.ServletContextHandler +import org.eclipse.jetty.ee10.servlet.ServletHolder import org.eclipse.jetty.server.Server import org.eclipse.jetty.server.ServerConnector -import org.eclipse.jetty.server.handler.HandlerCollection -import org.eclipse.jetty.servlet.ServletContextHandler -import org.eclipse.jetty.servlet.ServletHolder +import org.eclipse.jetty.server.handler.ContextHandlerCollection import org.glassfish.jersey.server.ResourceConfig import org.glassfish.jersey.servlet.ServletContainer import java.io.Closeable @@ -40,10 +44,6 @@ import java.security.cert.X509Certificate import java.time.Duration import java.util.* import javax.security.auth.x500.X500Principal -import javax.ws.rs.GET -import javax.ws.rs.Path -import javax.ws.rs.Produces -import javax.ws.rs.core.Response import kotlin.collections.ArrayList class CrlServer(hostAndPort: NetworkHostAndPort) : Closeable { @@ -79,7 +79,7 @@ class CrlServer(hostAndPort: NetworkHostAndPort) : Closeable { } private val server: Server = Server(InetSocketAddress(hostAndPort.host, hostAndPort.port)).apply { - handler = HandlerCollection().apply { + handler = ContextHandlerCollection().apply { addHandler(buildServletContextHandler()) } } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/network/NetworkMapServer.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/network/NetworkMapServer.kt index fe24c77248..0c6986707b 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/network/NetworkMapServer.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/network/NetworkMapServer.kt @@ -1,5 +1,15 @@ package net.corda.testing.node.internal.network +import jakarta.ws.rs.Consumes +import jakarta.ws.rs.GET +import jakarta.ws.rs.POST +import jakarta.ws.rs.Path +import jakarta.ws.rs.PathParam +import jakarta.ws.rs.Produces +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response +import jakarta.ws.rs.core.Response.ok +import jakarta.ws.rs.core.Response.status import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SignedData import net.corda.core.identity.CordaX500Name @@ -14,11 +24,11 @@ import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair import net.corda.nodeapi.internal.network.NetworkMap import net.corda.nodeapi.internal.network.ParametersUpdate import net.corda.testing.common.internal.testNetworkParameters +import org.eclipse.jetty.ee10.servlet.ServletContextHandler +import org.eclipse.jetty.ee10.servlet.ServletHolder import org.eclipse.jetty.server.Server import org.eclipse.jetty.server.ServerConnector -import org.eclipse.jetty.server.handler.HandlerCollection -import org.eclipse.jetty.servlet.ServletContextHandler -import org.eclipse.jetty.servlet.ServletHolder +import org.eclipse.jetty.server.handler.ContextHandlerCollection import org.glassfish.jersey.server.ResourceConfig import org.glassfish.jersey.servlet.ServletContainer import java.io.Closeable @@ -29,11 +39,6 @@ import java.security.SignatureException import java.time.Duration import java.time.Instant import java.util.* -import javax.ws.rs.* -import javax.ws.rs.core.MediaType -import javax.ws.rs.core.Response -import javax.ws.rs.core.Response.ok -import javax.ws.rs.core.Response.status class NetworkMapServer(private val pollInterval: Duration, hostAndPort: NetworkHostAndPort = NetworkHostAndPort("localhost", 0), @@ -54,7 +59,7 @@ class NetworkMapServer(private val pollInterval: Duration, init { server = Server(InetSocketAddress(hostAndPort.host, hostAndPort.port)).apply { - handler = HandlerCollection().apply { + handler = ContextHandlerCollection().apply { addHandler(ServletContextHandler().apply { contextPath = "/" val resourceConfig = ResourceConfig().apply { @@ -232,7 +237,7 @@ class NetworkMapServer(private val pollInterval: Duration, null } requireNotNull(requestedParameters) - return Response.ok(requestedParameters!!.serialize().bytes).build() + return Response.ok(requestedParameters.serialize().bytes).build() } @GET diff --git a/testing/node-driver/src/test/kotlin/net/corda/testing/node/CustomNotaryTest.kt b/testing/node-driver/src/test/kotlin/net/corda/testing/node/CustomNotaryTest.kt index 91ccdd05c5..dec447977b 100644 --- a/testing/node-driver/src/test/kotlin/net/corda/testing/node/CustomNotaryTest.kt +++ b/testing/node-driver/src/test/kotlin/net/corda/testing/node/CustomNotaryTest.kt @@ -14,11 +14,12 @@ import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.singleIdentity import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP import net.corda.testing.node.internal.enclosedCordapp +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After import org.junit.Before import org.junit.Test import java.security.PublicKey -import java.util.* +import java.util.Random class CustomNotaryTest { private lateinit var mockNet: MockNetwork @@ -50,13 +51,15 @@ class CustomNotaryTest { mockNet.stopNodes() } - @Test(expected = CustomNotaryException::class, timeout=300_000) + @Test(timeout=300_000) fun `custom notary service is active`() { val tx = DummyContract.generateInitial(Random().nextInt(), notary, alice.ref(0)) val stx = aliceNode.services.signInitialTransaction(tx) val future = aliceNode.startFlow(NotaryFlow.Client(stx)) mockNet.runNetwork() - future.getOrThrow() + assertThatExceptionOfType(CustomNotaryException::class.java).isThrownBy { + future.getOrThrow() + } } class CustomNotaryService(override val services: ServiceHubInternal, override val notaryIdentityKey: PublicKey) : NotaryService() { diff --git a/testing/node-driver/src/test/kotlin/net/corda/testing/node/internal/CustomCordappTest.kt b/testing/node-driver/src/test/kotlin/net/corda/testing/node/internal/CustomCordappTest.kt index fc266a3d0b..5cf2062394 100644 --- a/testing/node-driver/src/test/kotlin/net/corda/testing/node/internal/CustomCordappTest.kt +++ b/testing/node-driver/src/test/kotlin/net/corda/testing/node/internal/CustomCordappTest.kt @@ -2,13 +2,13 @@ package net.corda.testing.node.internal import net.corda.core.internal.cordapp.CordappImpl import net.corda.core.internal.cordapp.get -import net.corda.core.internal.inputStream import org.assertj.core.api.Assertions.assertThat import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder import java.nio.file.Path import java.util.jar.JarInputStream +import kotlin.io.path.inputStream class CustomCordappTest { @Rule diff --git a/testing/smoke-test-utils/build.gradle b/testing/smoke-test-utils/build.gradle index 0a1023a061..f573cffee5 100644 --- a/testing/smoke-test-utils/build.gradle +++ b/testing/smoke-test-utils/build.gradle @@ -1,11 +1,18 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' description 'Utilities needed for smoke tests in Corda' dependencies { + api project(':test-common') + // Smoke tests do NOT have any Node code on the classpath! - compile project(':test-common') - compile project(':client:rpc') + implementation project(':core') + implementation project(':node-api') + implementation project(':client:rpc') + + implementation "com.google.guava:guava:$guava_version" + implementation "com.typesafe:config:$typesafe_config_version" + implementation "org.slf4j:slf4j-api:$slf4j_version" } tasks.named('jar', Jar) { @@ -14,4 +21,4 @@ tasks.named('jar', Jar) { // Driver will not include it as part of an out-of-process node. attributes('Corda-Testing': true) } -} \ No newline at end of file +} diff --git a/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeConfig.kt b/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeParams.kt similarity index 71% rename from testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeConfig.kt rename to testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeParams.kt index 120faa5314..4eb065d787 100644 --- a/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeConfig.kt +++ b/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeParams.kt @@ -1,22 +1,28 @@ package net.corda.smoketesting -import com.typesafe.config.Config import com.typesafe.config.ConfigFactory.empty import com.typesafe.config.ConfigRenderOptions import com.typesafe.config.ConfigValue import com.typesafe.config.ConfigValueFactory +import net.corda.client.rpc.CordaRPCClientConfiguration import net.corda.core.identity.CordaX500Name import net.corda.nodeapi.internal.config.User import net.corda.nodeapi.internal.config.toConfig +import java.nio.file.Path +import kotlin.io.path.absolutePathString -class NodeConfig( +class NodeParams @JvmOverloads constructor( val legalName: CordaX500Name, val p2pPort: Int, val rpcPort: Int, val rpcAdminPort: Int, - val isNotary: Boolean, val users: List, - val devMode: Boolean = true + val cordappJars: List = emptyList(), + val legacyContractJars: List = emptyList(), + val jarDirs: List = emptyList(), + val clientRpcConfig: CordaRPCClientConfiguration = CordaRPCClientConfiguration.DEFAULT, + val devMode: Boolean = true, + val version: String? = null ) { companion object { val renderOptions: ConfigRenderOptions = ConfigRenderOptions.defaults().setOriginComments(false) @@ -24,12 +30,7 @@ class NodeConfig( val commonName: String get() = legalName.organisation - /* - * The configuration object depends upon the networkMap, - * which is mutable. - */ - //TODO Make use of Any.toConfig - private fun toFileConfig(): Config { + fun createNodeConfig(isNotary: Boolean): String { val config = empty() .withValue("myLegalName", valueFor(legalName.toString())) .withValue("p2pAddress", addressValueFor(p2pPort)) @@ -39,16 +40,15 @@ class NodeConfig( .root()) .withValue("rpcUsers", valueFor(users.map { it.toConfig().root().unwrapped() }.toList())) .withValue("useTestClock", valueFor(true)) + .withValue("jarDirs", valueFor(jarDirs.map(Path::absolutePathString))) .withValue("devMode", valueFor(devMode)) return if (isNotary) { config.withValue("notary", ConfigValueFactory.fromMap(mapOf("validating" to true))) } else { config - } + }.root().render(renderOptions) } - fun toText(): String = toFileConfig().root().render(renderOptions) - private fun valueFor(any: T): ConfigValue? = ConfigValueFactory.fromAnyRef(any) private fun addressValueFor(port: Int) = valueFor("localhost:$port") diff --git a/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeProcess.kt b/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeProcess.kt index 1daa51ae94..4b0a42dde2 100644 --- a/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeProcess.kt +++ b/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeProcess.kt @@ -1,19 +1,20 @@ package net.corda.smoketesting +import com.google.common.collect.Lists import net.corda.client.rpc.CordaRPCClient import net.corda.client.rpc.CordaRPCConnection -import net.corda.core.identity.Party -import net.corda.core.internal.createDirectories +import net.corda.core.internal.PLATFORM_VERSION +import net.corda.core.internal.copyToDirectory import net.corda.core.internal.deleteRecursively -import net.corda.core.internal.div import net.corda.core.internal.toPath -import net.corda.core.internal.writeText +import net.corda.core.node.NetworkParameters import net.corda.core.node.NotaryInfo import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.contextLogger import net.corda.nodeapi.internal.DevIdentityGenerator import net.corda.nodeapi.internal.config.User import net.corda.nodeapi.internal.network.NetworkParametersCopier +import net.corda.nodeapi.internal.network.NodeInfoFilesCopier import net.corda.nodeapi.internal.rpc.client.AMQPClientSerializationScheme import net.corda.testing.common.internal.asContextEnv import net.corda.testing.common.internal.checkNotOnClasspath @@ -23,12 +24,18 @@ import java.nio.file.Paths import java.time.Instant import java.time.ZoneId.systemDefault import java.time.format.DateTimeFormatter +import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.Executors import java.util.concurrent.TimeUnit.SECONDS +import kotlin.io.path.Path +import kotlin.io.path.createDirectories +import kotlin.io.path.createDirectory +import kotlin.io.path.div +import kotlin.io.path.writeText class NodeProcess( - private val config: NodeConfig, - private val nodeDir: Path, + private val config: NodeParams, + val nodeDir: Path, private val node: Process, private val client: CordaRPCClient ) : AutoCloseable { @@ -43,6 +50,7 @@ class NodeProcess( } override fun close() { + if (!node.isAlive) return log.info("Stopping node '${config.commonName}'") node.destroy() if (!node.waitFor(60, SECONDS)) { @@ -56,65 +64,98 @@ class NodeProcess( // TODO All use of this factory have duplicate code which is either bundling the calling module or a 3rd party module // as a CorDapp for the nodes. - class Factory(private val buildDirectory: Path = Paths.get("build")) { - val cordaJar: Path by lazy { - val cordaJarUrl = requireNotNull(this::class.java.getResource("/corda.jar")) { - "corda.jar could not be found in classpath" - } - cordaJarUrl.toPath() - } + class Factory( + private val baseNetworkParameters: NetworkParameters = testNetworkParameters(minimumPlatformVersion = PLATFORM_VERSION), + private val buildDirectory: Path = Paths.get("build") + ) : AutoCloseable { + companion object { + private val formatter = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss.SSS").withZone(systemDefault()) + private val cordaJars = ConcurrentHashMap() - private companion object { - val javaPath: Path = Paths.get(System.getProperty("java.home"), "bin", "java") - val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss.SSS").withZone(systemDefault()) init { checkNotOnClasspath("net.corda.node.Corda") { "Smoke test has the node in its classpath. Please remove the offending dependency." } } + + @Suppress("MagicNumber") + private fun getCordaJarInfo(version: String): CordaJar { + return cordaJars.computeIfAbsent(version) { + val (javaHome, versionSuffix) = if (version.isEmpty()) { + System.getProperty("java.home") to "" + } else { + val javaHome = if (version.split(".")[1].toInt() > 11) { + System.getProperty("java.home") + } else { + // 4.11 and below need JDK 8 to run + checkNotNull(System.getenv("JAVA_8_HOME")) { "Please set JAVA_8_HOME env variable to home directory of JDK 8" } + } + javaHome to "-$version" + } + val cordaJar = this::class.java.getResource("/corda$versionSuffix.jar")!!.toPath() + CordaJar(cordaJar, Path(javaHome, "bin", "java")) + } + } + + fun getCordaJar(version: String? = null): Path = getCordaJarInfo(version ?: "").jarPath } + private val nodesDirectory: Path = (buildDirectory / "smoke-testing" / formatter.format(Instant.now())).createDirectories() + private val nodeInfoFilesCopier = NodeInfoFilesCopier() + private var nodes: MutableList? = ArrayList() private lateinit var networkParametersCopier: NetworkParametersCopier - private val nodesDirectory = (buildDirectory / formatter.format(Instant.now())).createDirectories() + fun baseDirectory(config: NodeParams): Path = nodesDirectory / config.commonName - private var notaryParty: Party? = null + fun createNotaries(first: NodeParams, vararg rest: NodeParams): List { + check(!::networkParametersCopier.isInitialized) { "Notaries have already been created" } - private fun createNetworkParameters(notaryInfo: NotaryInfo, nodeDir: Path) { - try { - networkParametersCopier = NetworkParametersCopier(testNetworkParameters(notaries = listOf(notaryInfo))) + val notariesParams = Lists.asList(first, rest) + val notaryInfos = notariesParams.map { notaryParams -> + val nodeDir = baseDirectory(notaryParams).createDirectories() + val notaryParty = DevIdentityGenerator.installKeyStoreWithNodeIdentity(nodeDir, notaryParams.legalName) + NotaryInfo(notaryParty, true) + } + val networkParameters = baseNetworkParameters.copy(notaries = notaryInfos) + networkParametersCopier = try { + NetworkParametersCopier(networkParameters) } catch (_: IllegalStateException) { // Assuming serialization env not in context. AMQPClientSerializationScheme.createSerializationEnv().asContextEnv { - networkParametersCopier = NetworkParametersCopier(testNetworkParameters(notaries = listOf(notaryInfo))) + NetworkParametersCopier(networkParameters) } } - networkParametersCopier.install(nodeDir) + + return notariesParams.map { createNode(it, isNotary = true) } } - fun baseDirectory(config: NodeConfig): Path = nodesDirectory / config.commonName + fun createNode(params: NodeParams): NodeProcess = createNode(params, isNotary = false) - fun create(config: NodeConfig): NodeProcess { - val nodeDir = baseDirectory(config).createDirectories() + private fun createNode(params: NodeParams, isNotary: Boolean): NodeProcess { + check(::networkParametersCopier.isInitialized) { "Notary not created. Please call `creatNotaries` first." } + + val nodeDir = baseDirectory(params).createDirectories() log.info("Node directory: {}", nodeDir) - if (config.isNotary) { - require(notaryParty == null) { "Only one notary can be created." } - notaryParty = DevIdentityGenerator.installKeyStoreWithNodeIdentity(nodeDir, config.legalName) - } else { - require(notaryParty != null) { "Notary not created. Please call `create` with a notary config first." } + val cordappsDir = (nodeDir / CORDAPPS_DIR_NAME).createDirectory() + params.cordappJars.forEach { it.copyToDirectory(cordappsDir) } + if (params.legacyContractJars.isNotEmpty()) { + val legacyContractsDir = (nodeDir / "legacy-contracts").createDirectories() + params.legacyContractJars.forEach { it.copyToDirectory(legacyContractsDir) } } + (nodeDir / "node.conf").writeText(params.createNodeConfig(isNotary)) + networkParametersCopier.install(nodeDir) + nodeInfoFilesCopier.addConfig(nodeDir) - (nodeDir / "node.conf").writeText(config.toText()) - createNetworkParameters(NotaryInfo(notaryParty!!, true), nodeDir) - - createSchema(nodeDir) - val process = startNode(nodeDir) - val client = CordaRPCClient(NetworkHostAndPort("localhost", config.rpcPort)) - waitForNode(process, config, client) - return NodeProcess(config, nodeDir, process, client) + createSchema(nodeDir, params.version) + val process = startNode(nodeDir, params.version) + val client = CordaRPCClient(NetworkHostAndPort("localhost", params.rpcPort), params.clientRpcConfig) + waitForNode(process, params, client) + val nodeProcess = NodeProcess(params, nodeDir, process, client) + nodes!! += nodeProcess + return nodeProcess } - private fun waitForNode(process: Process, config: NodeConfig, client: CordaRPCClient) { + private fun waitForNode(process: Process, config: NodeParams, client: CordaRPCClient) { val executor = Executors.newSingleThreadScheduledExecutor() try { executor.scheduleWithFixedDelay({ @@ -129,7 +170,7 @@ class NodeProcess( // Cancel the "setup" task now that we've created the RPC client. executor.shutdown() } catch (e: Exception) { - log.warn("Node '{}' not ready yet (Error: {})", config.commonName, e.message) + log.debug("Node '{}' not ready yet (Error: {})", config.commonName, e.message) } }, 5, 1, SECONDS) @@ -147,30 +188,42 @@ class NodeProcess( class SchemaCreationFailedError(nodeDir: Path) : Exception("Creating node schema failed for $nodeDir") - private fun createSchema(nodeDir: Path){ - val process = startNode(nodeDir, arrayOf("run-migration-scripts", "--core-schemas", "--app-schemas")) + private fun createSchema(nodeDir: Path, version: String?) { + val process = startNode(nodeDir, version, "run-migration-scripts", "--core-schemas", "--app-schemas") if (!process.waitFor(schemaCreationTimeOutSeconds, SECONDS)) { - process.destroy() + process.destroyForcibly() throw SchemaCreationTimedOutError(nodeDir) } - if (process.exitValue() != 0){ + if (process.exitValue() != 0) { throw SchemaCreationFailedError(nodeDir) } } - @Suppress("SpreadOperator") - private fun startNode(nodeDir: Path, extraArgs: Array = emptyArray()): Process { + private fun startNode(nodeDir: Path, version: String?, vararg extraArgs: String): Process { + val cordaJar = getCordaJarInfo(version ?: "") + val command = arrayListOf("${cordaJar.javaPath}", "-Dcapsule.log=verbose", "-jar", "${cordaJar.jarPath}", "--logging-level=debug") + command += extraArgs + val now = formatter.format(Instant.now()) val builder = ProcessBuilder() - .command(javaPath.toString(), "-Dcapsule.log=verbose", "-jar", cordaJar.toString(), *extraArgs) + .command(command) .directory(nodeDir.toFile()) - .redirectError(ProcessBuilder.Redirect.INHERIT) - .redirectOutput(ProcessBuilder.Redirect.INHERIT) - + .redirectError((nodeDir / "$now-stderr.log").toFile()) + .redirectOutput((nodeDir / "$now-stdout.log").toFile()) builder.environment().putAll(mapOf( "CAPSULE_CACHE_DIR" to (buildDirectory / "capsule").toString() )) - return builder.start() + val process = builder.start() + Runtime.getRuntime().addShutdownHook(Thread(process::destroyForcibly)) + return process } + + override fun close() { + nodes?.parallelStream()?.forEach { it.close() } + nodes = null + nodeInfoFilesCopier.close() + } + + private data class CordaJar(val jarPath: Path, val javaPath: Path) } } diff --git a/testing/test-cli/build.gradle b/testing/test-cli/build.gradle index d4de7deba0..9016202d1d 100644 --- a/testing/test-cli/build.gradle +++ b/testing/test-cli/build.gradle @@ -1,15 +1,14 @@ -apply plugin: 'java' -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' dependencies { - compile "info.picocli:picocli:$picocli_version" - compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - compile "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jackson_version" - compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" - compile "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version" + implementation "info.picocli:picocli:$picocli_version" + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + implementation "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version" - compile "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" - compile "junit:junit:${junit_version}" + implementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" + implementation "junit:junit:${junit_version}" testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" @@ -22,4 +21,4 @@ tasks.named('jar', Jar) { // Driver will not include it as part of an out-of-process node. attributes('Corda-Testing': true) } -} \ No newline at end of file +} diff --git a/testing/test-common/build.gradle b/testing/test-common/build.gradle index a4ff51fd80..83b4d6758b 100644 --- a/testing/test-common/build.gradle +++ b/testing/test-common/build.gradle @@ -1,24 +1,27 @@ -apply plugin: 'net.corda.plugins.publish-utils' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'net.corda.plugins.api-scanner' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' + +description 'Corda Test Common module' dependencies { - compile project(':core') - compile project(':node-api') + implementation project(':core') + implementation project(':node-api') // Unit testing helpers. - compile "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" - compile "junit:junit:$junit_version" + implementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" + implementation "junit:junit:$junit_version" + implementation "org.slf4j:slf4j-api:$slf4j_version" runtimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" runtimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" runtimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - compile 'org.hamcrest:hamcrest-library:2.1' - compile "com.nhaarman:mockito-kotlin:$mockito_kotlin_version" - compile "org.mockito:mockito-core:$mockito_version" - compile "org.assertj:assertj-core:$assertj_version" - compile "com.natpryce:hamkrest:$hamkrest_version" + implementation 'org.hamcrest:hamcrest-library:2.1' + implementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" + implementation "org.mockito:mockito-core:$mockito_version" + implementation "org.assertj:assertj-core:$assertj_version" + implementation "com.natpryce:hamkrest:$hamkrest_version" } jar { @@ -30,6 +33,11 @@ jar { } } -publish { - name jar.baseName +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } } diff --git a/testing/test-common/src/main/kotlin/net/corda/testing/common/internal/ProjectStructure.kt b/testing/test-common/src/main/kotlin/net/corda/testing/common/internal/ProjectStructure.kt index 43e6767ebc..f4dad77768 100644 --- a/testing/test-common/src/main/kotlin/net/corda/testing/common/internal/ProjectStructure.kt +++ b/testing/test-common/src/main/kotlin/net/corda/testing/common/internal/ProjectStructure.kt @@ -1,13 +1,13 @@ package net.corda.testing.common.internal -import net.corda.core.internal.div -import net.corda.core.internal.isDirectory import net.corda.core.internal.toPath import java.nio.file.Path +import kotlin.io.path.div +import kotlin.io.path.isDirectory object ProjectStructure { val projectRootDir: Path = run { - var dir = javaClass.getResource("/").toPath() + var dir = javaClass.getResource("/")!!.toPath() while (!(dir / ".git").isDirectory()) { dir = dir.parent } diff --git a/testing/test-common/src/main/resources/log4j2-test.xml b/testing/test-common/src/main/resources/log4j2-test.xml index 12041ff680..1848607488 100644 --- a/testing/test-common/src/main/resources/log4j2-test.xml +++ b/testing/test-common/src/main/resources/log4j2-test.xml @@ -2,31 +2,17 @@ - ${sys:log-path:-logs} - node-${hostName} - ${log-path}/archive - ${sys:defaultLogLevel:-info} + ${sys:log-path:-logs} + node-${hostName} + ${log_path}/archive + ${sys:defaultLogLevel:-info} - - - - - - + @@ -38,8 +24,8 @@ + fileName="${log_path}/${log_name}.log" + filePattern="${archive}/${log_name}.%date{yyyy-MM-dd}-%i.log.gz"> @@ -50,7 +36,7 @@ - + @@ -78,7 +64,7 @@ - + diff --git a/testing/test-db/build.gradle b/testing/test-db/build.gradle index 3be30d52fe..678370f38b 100644 --- a/testing/test-db/build.gradle +++ b/testing/test-db/build.gradle @@ -1,9 +1,9 @@ -apply plugin: 'net.corda.plugins.publish-utils' apply plugin: 'net.corda.plugins.api-scanner' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' + +description 'Corda test-db module' dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" implementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" @@ -11,7 +11,7 @@ dependencies { testImplementation "org.assertj:assertj-core:$assertj_version" testImplementation "org.slf4j:slf4j-api:$slf4j_version" - testRuntimeOnly "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version" + testRuntimeOnly "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version" } jar { @@ -23,6 +23,11 @@ jar { } } -publish { - name jar.baseName -} \ No newline at end of file +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } +} diff --git a/testing/test-db/src/test/resources/log4j2-test.xml b/testing/test-db/src/test/resources/log4j2-test.xml index 35b51709ed..f5dbd8be84 100644 --- a/testing/test-db/src/test/resources/log4j2-test.xml +++ b/testing/test-db/src/test/resources/log4j2-test.xml @@ -2,33 +2,17 @@ - ${sys:log-path:-logs} - node-${hostName} - ${log-path}/archive - ${sys:defaultLogLevel:-info} + ${sys:log-path:-logs} + node-${hostName} + ${log_path}/archive + ${sys:defaultLogLevel:-info} - - - - - - + @@ -40,8 +24,8 @@ + fileName="${log_path}/${log_name}.log" + filePattern="${archive}/${log_name}.%date{yyyy-MM-dd}-%i.log.gz"> @@ -52,7 +36,7 @@ - + @@ -80,7 +64,7 @@ - + diff --git a/testing/test-utils/build.gradle b/testing/test-utils/build.gradle index 61460f2378..b05805ff98 100644 --- a/testing/test-utils/build.gradle +++ b/testing/test-utils/build.gradle @@ -1,34 +1,50 @@ -apply plugin: 'kotlin' -apply plugin: 'kotlin-jpa' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'org.jetbrains.kotlin.plugin.jpa' apply plugin: 'net.corda.plugins.quasar-utils' -apply plugin: 'net.corda.plugins.publish-utils' apply plugin: 'net.corda.plugins.api-scanner' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' description 'Testing utilities for Corda' dependencies { - compile project(':test-common') - compile project(':core-test-utils') - compile(project(':node')) { - // The Node only needs this for binary compatibility with Cordapps written in Kotlin 1.1. - exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jre8' - } - compile project(':client:mock') + implementation project(':core') + implementation project(':test-common') + implementation project(':core-test-utils') + implementation project(':node') + implementation project(':node-api') + implementation project(':serialization') + implementation project(':client:jackson') + implementation project(':client:mock') + implementation project(':confidential-identities') - compile "com.google.guava:guava:$guava_version" + implementation "com.google.guava:guava:$guava_version" // Guava: Google test library (collections test suite) - compile "com.google.guava:guava-testlib:$guava_version" + implementation "com.google.guava:guava-testlib:$guava_version" + + implementation "org.hibernate:hibernate-core:$hibernate_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" // OkHTTP: Simple HTTP library. - compile "com.squareup.okhttp3:okhttp:$okhttp_version" - compile project(':confidential-identities') + implementation "com.squareup.okhttp3:okhttp:$okhttp_version" + + implementation "io.reactivex:rxjava:$rxjava_version" + implementation project(':finance:contracts') + implementation project(':finance:workflows') // JimFS: in memory java.nio filesystem. Used for test and simulation utilities. - compile "com.google.jimfs:jimfs:1.1" + implementation "com.google.jimfs:jimfs:1.1" + implementation "io.dropwizard.metrics:metrics-jmx:$metrics_version" + implementation "org.apache.logging.log4j:log4j-core:$log4j_version" + implementation group: "com.typesafe", name: "config", version: typesafe_config_version + implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version" - testCompile "org.apache.commons:commons-lang3:3.9" + // Bouncy castle support needed for X509 certificate manipulation + implementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}" + implementation "org.bouncycastle:bcpkix-lts8on:${bouncycastle_version}" + + testImplementation "org.apache.commons:commons-lang3:$commons_lang3_version" + testImplementation "org.assertj:assertj-core:$assertj_version" } jar { @@ -40,6 +56,11 @@ jar { } } -publish { - name jar.baseName +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } } diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/LedgerDSLInterpreter.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/LedgerDSLInterpreter.kt index 89e9ecb202..940ef6aea4 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/LedgerDSLInterpreter.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/LedgerDSLInterpreter.kt @@ -10,6 +10,7 @@ import net.corda.core.internal.uncheckedCast import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.WireTransaction import java.io.InputStream +import java.util.Locale /** * This interface defines output state lookup by label. It is split from the interpreter interfaces so that outputs may @@ -52,7 +53,7 @@ interface Verifies { "Expected exception containing '$expectedMessage' but raised exception had no message", exception ) - } else if (!exceptionMessage.toLowerCase().contains(expectedMessage.toLowerCase())) { + } else if (!exceptionMessage.lowercase(Locale.getDefault()).contains(expectedMessage.lowercase(Locale.getDefault()))) { throw AssertionError( "Expected exception containing '$expectedMessage' but raised exception was '$exception'", exception diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TestDSL.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TestDSL.kt index b460d02f30..3280a456c8 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TestDSL.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TestDSL.kt @@ -3,7 +3,6 @@ package net.corda.testing.dsl import com.google.common.util.concurrent.ThreadFactoryBuilder import net.corda.core.DoNotImplement import net.corda.core.contracts.* -import net.corda.core.cordapp.CordappProvider import net.corda.core.crypto.NullKeys.NULL_SIGNATURE import net.corda.core.crypto.SecureHash import net.corda.core.crypto.TransactionSignature @@ -12,7 +11,9 @@ import net.corda.core.flows.TransactionMetadata import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.* +import net.corda.core.internal.cordapp.CordappProviderInternal import net.corda.core.internal.notary.NotaryService +import net.corda.core.internal.verification.ExternalVerifierHandle import net.corda.core.node.ServiceHub import net.corda.core.node.ServicesForResolution import net.corda.core.node.StatesToRecord @@ -26,11 +27,10 @@ import net.corda.core.transactions.WireTransaction import net.corda.node.services.DbTransactionsResolver import net.corda.node.services.api.WritableTransactionStorage import net.corda.node.services.attachments.NodeAttachmentTrustCalculator -import net.corda.node.services.persistence.AttachmentStorageInternal +import net.corda.node.services.persistence.toInternal import net.corda.testing.core.dummyCommand import net.corda.testing.internal.MockCordappProvider import net.corda.testing.internal.TestingNamedCacheFactory -import net.corda.testing.internal.services.InternalMockAttachmentStorage import net.corda.testing.services.MockAttachmentStorage import java.io.InputStream import java.security.PublicKey @@ -95,7 +95,6 @@ data class TestTransactionDSLInterpreter private constructor( // Implementing [ServiceHubCoreInternal] allows better use in internal Corda tests val services: ServicesForResolution = object : ServiceHubCoreInternal, ServiceHub by ledgerInterpreter.services { - // [validatedTransactions.getTransaction] needs overriding as there are no calls to // [ServiceHub.recordTransactions] in the test dsl override val validatedTransactions: TransactionStorage = @@ -113,14 +112,7 @@ data class TestTransactionDSLInterpreter private constructor( ledgerInterpreter.services.attachments.let { // Wrapping to a [InternalMockAttachmentStorage] is needed to prevent leaking internal api // while still allowing the tests to work - NodeAttachmentTrustCalculator( - attachmentStorage = if (it is MockAttachmentStorage) { - InternalMockAttachmentStorage(it) - } else { - it as AttachmentStorageInternal - }, - cacheFactory = TestingNamedCacheFactory() - ) + NodeAttachmentTrustCalculator(attachmentStorage = it.toInternal(), cacheFactory = TestingNamedCacheFactory()) } override fun createTransactionsResolver(flow: ResolveTransactionsFlow): TransactionsResolver = @@ -130,16 +122,23 @@ data class TestTransactionDSLInterpreter private constructor( ledgerInterpreter.resolveStateRef(stateRef) override fun loadStates(stateRefs: Set): Set> { - return stateRefs.map { StateAndRef(loadState(it), it) }.toSet() + return ledgerInterpreter.services.loadStates(stateRefs) } - override val cordappProvider: CordappProvider = - ledgerInterpreter.services.cordappProvider + override val cordappProvider: CordappProviderInternal + get() = ledgerInterpreter.services.cordappProvider as CordappProviderInternal override val notaryService: NotaryService? = null override val attachmentsClassLoaderCache: AttachmentsClassLoaderCache = AttachmentsClassLoaderCacheImpl(TestingNamedCacheFactory()) + override fun loadContractAttachment(stateRef: StateRef): Attachment { + return ledgerInterpreter.services.loadContractAttachment(stateRef) + } + + override val externalVerifierHandle: ExternalVerifierHandle + get() = throw UnsupportedOperationException("Verification of legacy transactions is not supported by TestTransactionDSLInterpreter") + override fun recordUnnotarisedTransaction(txn: SignedTransaction) {} override fun removeUnnotarisedTransaction(id: SecureHash) {} @@ -169,7 +168,6 @@ data class TestTransactionDSLInterpreter private constructor( override fun reference(stateRef: StateRef) { val state = ledgerInterpreter.resolveStateRef(stateRef) - @Suppress("DEPRECATION") // Will remove when feature finalised. transactionBuilder.addReferenceState(StateAndRef(state, stateRef).referenced()) } diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/http/HttpUtils.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/http/HttpUtils.kt index 4f4675a0fe..82872a7ae4 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/http/HttpUtils.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/http/HttpUtils.kt @@ -1,10 +1,10 @@ package net.corda.testing.http import com.fasterxml.jackson.databind.ObjectMapper -import okhttp3.MediaType +import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.OkHttpClient import okhttp3.Request -import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody import java.io.IOException import java.net.URL import java.util.concurrent.TimeUnit @@ -24,17 +24,17 @@ object HttpUtils { } fun putJson(url: URL, data: String) { - val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), data) + val body = data.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull()) makeRequest(Request.Builder().url(url).header("Content-Type", "application/json").put(body).build()) } fun postJson(url: URL, data: String) { - val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), data) + val body = data.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull()) makeRequest(Request.Builder().url(url).header("Content-Type", "application/json").post(body).build()) } fun postPlain(url: URL, data: String) { - val body = RequestBody.create(MediaType.parse("text/plain; charset=utf-8"), data) + val body = data.toRequestBody("text/plain; charset=utf-8".toMediaTypeOrNull()) makeRequest(Request.Builder().url(url).post(body).build()) } @@ -47,7 +47,7 @@ object HttpUtils { private fun makeRequest(request: Request) { val response = client.newCall(request).execute() if (!response.isSuccessful) { - throw IOException("${request.method()} to ${request.url()} returned a ${response.code()}: ${response.body()?.string()}") + throw IOException("${request.method} to ${request.url} returned a ${response.code}: ${response.body?.string()}") } } } diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/FlowStackSnapshot.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/FlowStackSnapshot.kt index 9bb806d7d5..4fe36e4902 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/FlowStackSnapshot.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/FlowStackSnapshot.kt @@ -1,7 +1,6 @@ package net.corda.testing.internal import co.paralleluniverse.fibers.Fiber -import co.paralleluniverse.fibers.Instrumented import co.paralleluniverse.fibers.Stack import co.paralleluniverse.fibers.Suspendable import com.fasterxml.jackson.annotation.JsonInclude @@ -12,7 +11,6 @@ import net.corda.core.flows.FlowStackSnapshot.Frame import net.corda.core.flows.StackFrameDataToken import net.corda.core.flows.StateMachineRunId import net.corda.core.internal.FlowStateMachine -import net.corda.core.internal.div import net.corda.core.internal.write import net.corda.core.serialization.SerializeAsToken import net.corda.client.jackson.JacksonSupport @@ -21,8 +19,29 @@ import net.corda.node.services.statemachine.FlowStackSnapshotFactory import java.nio.file.Path import java.time.Instant import java.time.LocalDate +import kotlin.io.path.div class FlowStackSnapshotFactoryImpl : FlowStackSnapshotFactory { + private companion object { + private const val QUASAR_0_7_INSTRUMENTED_CLASS_NAME = "co.paralleluniverse.fibers.Instrumented" + private const val QUASAR_0_8_INSTRUMENTED_CLASS_NAME = "co.paralleluniverse.fibers.suspend.Instrumented" + + // @Instrumented is an internal Quasar class that should not be referenced directly. + // We have needed to change its package for Quasar 0.8.x. + @Suppress("unchecked_cast") + private val instrumentedAnnotationClass: Class = try { + Class.forName(QUASAR_0_7_INSTRUMENTED_CLASS_NAME, false, this::class.java.classLoader) + } catch (_: ClassNotFoundException) { + Class.forName(QUASAR_0_8_INSTRUMENTED_CLASS_NAME, false, this::class.java.classLoader) + } as Class + + private val methodOptimized = instrumentedAnnotationClass.getMethod("methodOptimized") + + private fun isMethodOptimized(annotation: Annotation): Boolean { + return instrumentedAnnotationClass.isInstance(annotation) && (methodOptimized.invoke(annotation) as Boolean) + } + } + @Suspendable override fun getFlowStackSnapshot(flowClass: Class>): FlowStackSnapshot { var snapshot: FlowStackSnapshot? = null @@ -68,7 +87,7 @@ class FlowStackSnapshotFactoryImpl : FlowStackSnapshotFactory { val frames = stackTraceToAnnotation.reversed().map { (element, annotation) -> // If annotation is null then the case indicates that this is an entry point - i.e. // the net.corda.node.services.statemachine.FlowStateMachineImpl.run method - val stackObjects = if (frameObjectsIterator.hasNext() && (annotation == null || !annotation.methodOptimized)) { + val stackObjects = if (frameObjectsIterator.hasNext() && (annotation == null || !isMethodOptimized(annotation))) { frameObjectsIterator.next() } else { emptyList() @@ -78,11 +97,11 @@ class FlowStackSnapshotFactoryImpl : FlowStackSnapshotFactory { return FlowStackSnapshot(Instant.now(), flowClass.name, frames) } - private val StackTraceElement.instrumentedAnnotation: Instrumented? + private val StackTraceElement.instrumentedAnnotation: Annotation? get() { - Class.forName(className).methods.forEach { - if (it.name == methodName && it.isAnnotationPresent(Instrumented::class.java)) { - return it.getAnnotation(Instrumented::class.java) + Class.forName(className, false, this::class.java.classLoader).methods.forEach { + if (it.name == methodName && it.isAnnotationPresent(instrumentedAnnotationClass)) { + return it.getAnnotation(instrumentedAnnotationClass) } } return null @@ -105,7 +124,7 @@ class FlowStackSnapshotFactoryImpl : FlowStackSnapshotFactory { private fun filterOutStackDump(flowStackSnapshot: FlowStackSnapshot): FlowStackSnapshot { val framesFilteredByStackTraceElement = flowStackSnapshot.stackFrames.filter { - !FlowStateMachine::class.java.isAssignableFrom(Class.forName(it.stackTraceElement.className)) + !FlowStateMachine::class.java.isAssignableFrom(Class.forName(it.stackTraceElement.className, false, this::class.java.classLoader)) } val framesFilteredByObjects = framesFilteredByStackTraceElement.map { it.copy(stackObjects = it.stackObjects.map { diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/InternalTestUtils.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/InternalTestUtils.kt index ab080c3d7e..a8bd092de6 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/InternalTestUtils.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/InternalTestUtils.kt @@ -7,7 +7,6 @@ import net.corda.core.contracts.StateRef import net.corda.core.contracts.TimeWindow import net.corda.core.contracts.TransactionState import net.corda.core.crypto.Crypto -import net.corda.core.crypto.Crypto.generateKeyPair import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash import net.corda.core.identity.AbstractParty @@ -49,13 +48,11 @@ import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.TestIdentity import java.io.ByteArrayOutputStream -import java.io.IOException -import java.net.ServerSocket import java.nio.file.Path import java.security.KeyPair import java.security.cert.X509CRL import java.security.cert.X509Certificate -import java.util.* +import java.util.Properties import java.util.jar.JarOutputStream import java.util.jar.Manifest import java.util.zip.ZipEntry @@ -111,7 +108,7 @@ fun createDevIntermediateCaCertPath( */ fun createDevNodeCaCertPath( legalName: CordaX500Name, - nodeKeyPair: KeyPair = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME), + nodeKeyPair: KeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME), rootCaName: X500Principal = defaultRootCaName, intermediateCaName: X500Principal = defaultIntermediateCaName ): Triple { @@ -156,7 +153,6 @@ fun fixedCrlSource(crls: Set): CrlSource { } } -/** This is the same as the deprecated [WireTransaction] c'tor but avoids the deprecation warning. */ @SuppressWarnings("LongParameterList") fun createWireTransaction(inputs: List, attachments: List, @@ -164,9 +160,10 @@ fun createWireTransaction(inputs: List, commands: List>, notary: Party?, timeWindow: TimeWindow?, + legacyAttachments: List = emptyList(), privacySalt: PrivacySalt = PrivacySalt(), digestService: DigestService = DigestService.default): WireTransaction { - val componentGroups = createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow, emptyList(), null) + val componentGroups = createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow, emptyList(), null, legacyAttachments) return WireTransaction(componentGroups, privacySalt, digestService) } @@ -251,23 +248,5 @@ fun withTestSerializationEnvIfNotSet(block: () -> R): R { } } -/** - * Used to check if particular port is already bound i.e. not vacant - */ -fun isLocalPortBound(port: Int): Boolean { - return try { - ServerSocket(port).use { - // Successful means that the port was vacant - false - } - } catch (e: IOException) { - // Failed to open server socket means that it is already bound by someone - true - } -} - @JvmField -val IS_OPENJ9 = System.getProperty("java.vm.name").toLowerCase().contains("openj9") - -@JvmField -val IS_S390X = System.getProperty("os.arch") == "s390x" \ No newline at end of file +val IS_S390X = System.getProperty("os.arch") == "s390x" diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/MockCordappProvider.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/MockCordappProvider.kt index 2ce9ef53ea..152dab8b11 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/MockCordappProvider.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/MockCordappProvider.kt @@ -5,16 +5,16 @@ import net.corda.core.cordapp.Cordapp import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER import net.corda.core.internal.cordapp.CordappImpl import net.corda.core.node.services.AttachmentId -import net.corda.core.node.services.AttachmentStorage -import net.corda.nodeapi.internal.cordapp.CordappLoader import net.corda.node.internal.cordapp.CordappProviderImpl +import net.corda.node.services.persistence.AttachmentStorageInternal +import net.corda.nodeapi.internal.cordapp.CordappLoader import net.corda.testing.services.MockAttachmentStorage import java.security.PublicKey import java.util.jar.Attributes class MockCordappProvider( cordappLoader: CordappLoader, - attachmentStorage: AttachmentStorage, + attachmentStorage: AttachmentStorageInternal, cordappConfigProvider: MockCordappConfigProvider = MockCordappConfigProvider() ) : CordappProviderImpl(cordappLoader, cordappConfigProvider, attachmentStorage) { diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/TestingNamedCacheFactory.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/TestingNamedCacheFactory.kt index 402b3757c0..d633af5283 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/TestingNamedCacheFactory.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/TestingNamedCacheFactory.kt @@ -16,12 +16,12 @@ class TestingNamedCacheFactory private constructor(private val sizeOverride: Lon override fun bindWithMetrics(metricRegistry: MetricRegistry): BindableNamedCacheFactory = TestingNamedCacheFactory(sizeOverride, metricRegistry, this.nodeConfiguration) override fun bindWithConfig(nodeConfiguration: NodeConfiguration): BindableNamedCacheFactory = TestingNamedCacheFactory(sizeOverride, this.metricRegistry, nodeConfiguration) - override fun buildNamed(caffeine: Caffeine, name: String): Cache { + override fun buildNamed(caffeine: Caffeine, name: String): Cache { // Does not check metricRegistry or nodeConfiguration, because for tests we don't care. return caffeine.maximumSize(sizeOverride).build() } - override fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache { + override fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache { // Does not check metricRegistry or nodeConfiguration, because for tests we don't care. val configuredCaffeine = when (name) { "DBTransactionStorage_transactions" -> caffeine.maximumWeight(1.MB) diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/services/InternalMockAttachmentStorage.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/services/InternalMockAttachmentStorage.kt deleted file mode 100644 index 26471237ec..0000000000 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/services/InternalMockAttachmentStorage.kt +++ /dev/null @@ -1,43 +0,0 @@ -package net.corda.testing.internal.services - -import net.corda.core.contracts.Attachment -import net.corda.core.node.services.AttachmentId -import net.corda.core.node.services.AttachmentStorage -import net.corda.core.node.services.vault.AttachmentQueryCriteria -import net.corda.node.services.persistence.AttachmentStorageInternal -import net.corda.testing.services.MockAttachmentStorage -import java.io.InputStream -import java.util.stream.Stream - -/** - * Internal version of [MockAttachmentStorage] that implements [AttachmentStorageInternal] for use - * in internal tests where [AttachmentStorageInternal] functions are needed. - */ -class InternalMockAttachmentStorage(storage: MockAttachmentStorage) : AttachmentStorageInternal, - AttachmentStorage by storage { - - override fun privilegedImportAttachment( - jar: InputStream, - uploader: String, - filename: String? - ): AttachmentId = importAttachment(jar, uploader, filename) - - override fun privilegedImportOrGetAttachment( - jar: InputStream, - uploader: String, - filename: String? - ): AttachmentId { - return try { - importAttachment(jar, uploader, filename) - } catch (faee: java.nio.file.FileAlreadyExistsException) { - AttachmentId.create(faee.message!!) - } - } - - override fun getAllAttachmentsByCriteria(criteria: AttachmentQueryCriteria): Stream> { - return queryAttachments(criteria) - .map(this::openAttachment) - .map { null as String? to it!! } - .stream() - } -} \ No newline at end of file diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/services/MockAttachmentStorage.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/services/MockAttachmentStorage.kt index c220bcfb1b..7b589f5602 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/services/MockAttachmentStorage.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/services/MockAttachmentStorage.kt @@ -12,12 +12,16 @@ import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VER import net.corda.core.internal.readFully import net.corda.core.node.services.AttachmentId import net.corda.core.node.services.AttachmentStorage -import net.corda.core.node.services.vault.* +import net.corda.core.node.services.vault.AttachmentQueryCriteria +import net.corda.core.node.services.vault.AttachmentSort +import net.corda.core.node.services.vault.Builder +import net.corda.core.node.services.vault.ColumnPredicate +import net.corda.core.node.services.vault.Sort import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.nodeapi.internal.withContractsInJar import java.io.InputStream +import java.nio.file.FileAlreadyExistsException import java.security.PublicKey -import java.util.* import java.util.jar.Attributes import java.util.jar.JarInputStream @@ -33,7 +37,7 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() { /** A map of the currently stored files by their [SecureHash] */ val files: Map> get() = _files - @Suppress("OverridingDeprecatedMember") + @Suppress("OVERRIDE_DEPRECATION") override fun importAttachment(jar: InputStream): AttachmentId = importAttachment(jar, UNKNOWN_UPLOADER, null) override fun importAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId { @@ -78,11 +82,11 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() { override fun hasAttachment(attachmentId: AttachmentId) = files.containsKey(attachmentId) - @Suppress("OverridingDeprecatedMember") + @Suppress("OVERRIDE_DEPRECATION") override fun importOrGetAttachment(jar: InputStream): AttachmentId { return try { importAttachment(jar, UNKNOWN_UPLOADER, null) - } catch (e: java.nio.file.FileAlreadyExistsException) { + } catch (e: FileAlreadyExistsException) { AttachmentId.create(e.message!!) } } @@ -109,7 +113,7 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() { val baseAttachment = MockAttachment({ bytes }, sha256, signers, uploader) val version = try { Integer.parseInt(baseAttachment.openAsJAR().manifest?.mainAttributes?.getValue(Attributes.Name.IMPLEMENTATION_VERSION)) } catch (e: Exception) { DEFAULT_CORDAPP_VERSION } val attachment = - if (contractClassNames == null || contractClassNames.isEmpty()) baseAttachment + if (contractClassNames.isNullOrEmpty()) baseAttachment else { contractClassNames.map {contractClassName -> val contractClassMetadata = ContractAttachmentMetadata(contractClassName, version, signers.isNotEmpty(), signers, uploader) diff --git a/testing/test-utils/src/test/kotlin/net/corda/testing/core/JarSignatureCollectorTest.kt b/testing/test-utils/src/test/kotlin/net/corda/testing/core/JarSignatureCollectorTest.kt index ab7946e768..0f1c431673 100644 --- a/testing/test-utils/src/test/kotlin/net/corda/testing/core/JarSignatureCollectorTest.kt +++ b/testing/test-utils/src/test/kotlin/net/corda/testing/core/JarSignatureCollectorTest.kt @@ -1,14 +1,13 @@ package net.corda.testing.core +import net.corda.core.internal.InvalidJarSignersException +import net.corda.core.internal.deleteRecursively +import net.corda.testing.core.internal.JarSignatureTestUtils.addIndexList import net.corda.testing.core.internal.JarSignatureTestUtils.createJar import net.corda.testing.core.internal.JarSignatureTestUtils.generateKey import net.corda.testing.core.internal.JarSignatureTestUtils.getJarSigners import net.corda.testing.core.internal.JarSignatureTestUtils.signJar import net.corda.testing.core.internal.JarSignatureTestUtils.updateJar -import net.corda.testing.core.internal.JarSignatureTestUtils.addIndexList -import net.corda.core.identity.Party -import net.corda.core.internal.* -import org.apache.commons.lang3.SystemUtils import org.assertj.core.api.Assertions.assertThat import org.junit.After import org.junit.AfterClass @@ -17,6 +16,12 @@ import org.junit.Test import java.nio.file.Files import java.nio.file.Path import java.security.PublicKey +import kotlin.io.path.createDirectory +import kotlin.io.path.div +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.name +import kotlin.io.path.useDirectoryEntries +import kotlin.io.path.writeLines import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -51,14 +56,12 @@ class JarSignatureCollectorTest { } } - private val List.keys get() = map { it.owningKey } - @After fun tearDown() { - dir.list { - it.filter { !it.fileName.toString().startsWith("_") }.forEach(Path::deleteRecursively) + dir.useDirectoryEntries { paths -> + paths.filter { !it.name.startsWith("_") }.forEach(Path::deleteRecursively) } - assertThat(dir.list()).hasSize(5) + assertThat(dir.listDirectoryEntries()).hasSize(5) } @Test(timeout=300_000) @@ -136,7 +139,7 @@ class JarSignatureCollectorTest { fun `one signer with EC algorithm`() { dir.createJar(FILENAME, "_signable1", "_signable2") // JDK11: Warning: Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified -keypass value. - val key = signAs(CHARLIE, CHARLIE_PASS) + val key = signAs(CHARLIE) assertEquals(listOf(key), dir.getJarSigners(FILENAME)) // We only used CHARLIE's distinguished name, so the keys will be different. } @@ -148,15 +151,12 @@ class JarSignatureCollectorTest { assertEquals(listOf(key), dir.getJarSigners(FILENAME)) } - private fun signAsAlice() = signAs(ALICE, ALICE_PASS) - private fun signAsBob() = signAs(BOB, BOB_PASS) + private fun signAsAlice() = signAs(ALICE) + private fun signAsBob() = signAs(BOB) // JDK11: Warning: Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified -keypass value. // TODO: use programmatic API support to implement signing (see https://docs.oracle.com/javase/9/docs/api/jdk/security/jarsigner/JarSigner.html) - private fun signAs(alias: String, keyPassword: String = alias) : PublicKey { - return if (SystemUtils.IS_JAVA_11) - dir.signJar(FILENAME, alias, "storepass", "storepass") - else - dir.signJar(FILENAME, alias, "storepass", keyPassword) + private fun signAs(alias: String) : PublicKey { + return dir.signJar(FILENAME, alias, "storepass", "storepass") } } diff --git a/testing/testserver/build.gradle b/testing/testserver/build.gradle index 5496288d78..2059acf764 100644 --- a/testing/testserver/build.gradle +++ b/testing/testserver/build.gradle @@ -1,13 +1,11 @@ -apply plugin: 'kotlin' -apply plugin: 'java' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'corda.common-publishing' description 'Corda node web server' configurations { - integrationTestCompile.extendsFrom testCompile - integrationTestRuntime.extendsFrom testRuntime + integrationTestImplementation.extendsFrom testImplementation + integrationTestRuntime.extendsFrom testRuntimeOnly } sourceSets { @@ -25,42 +23,46 @@ processResources { } dependencies { - compile project(':core') - compile project(':client:rpc') - compile project(':client:jackson') - compile project(':tools:cliutils') - compile project(":common-logging") + implementation project(':core') + implementation project(':node-api') + implementation project(':client:rpc') + implementation project(':client:jackson') + implementation project(':tools:cliutils') + implementation project(":common-logging") // Web stuff: for HTTP[S] servlets - compile "org.eclipse.jetty:jetty-servlet:$jetty_version" - compile "org.eclipse.jetty:jetty-webapp:$jetty_version" - compile "javax.servlet:javax.servlet-api:${servlet_version}" - compile "commons-fileupload:commons-fileupload:$fileupload_version" + implementation "org.eclipse.jetty.ee10:jetty-ee10-servlet:$jetty_version" + implementation "org.eclipse.jetty.ee10:jetty-ee10-webapp:$jetty_version" + //implementation "javax.servlet:javax.servlet-api:${servlet_version}" + implementation "org.apache.commons:commons-fileupload2-jakarta:$fileupload_version" // Log4J: logging framework (with SLF4J bindings) - compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version" - compile "org.apache.logging.log4j:log4j-core:$log4j_version" + implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version" + implementation "org.apache.logging.log4j:log4j-core:$log4j_version" // JOpt: for command line flags. - compile "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" + implementation "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" - // Jersey for JAX-RS implementation for use in Jetty - // TODO: remove force upgrade when jersey catches up - compile "org.eclipse.jetty:jetty-continuation:${jetty_version}" - - compile "org.glassfish.jersey.core:jersey-server:$jersey_version" - compile "org.glassfish.jersey.containers:jersey-container-servlet:$jersey_version" - compile "org.glassfish.jersey.containers:jersey-container-jetty-http:$jersey_version" - compile "org.glassfish.jersey.media:jersey-media-json-jackson:$jersey_version" + implementation "org.glassfish.jersey.core:jersey-server:$jersey_version" + implementation "org.glassfish.jersey.containers:jersey-container-servlet:$jersey_version" + implementation "org.glassfish.jersey.containers:jersey-container-jetty-http:$jersey_version" + implementation "org.glassfish.jersey.media:jersey-media-json-jackson:$jersey_version" + implementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version" // For rendering the index page. - compile "org.jetbrains.kotlinx:kotlinx-html-jvm:0.6.12" + implementation "org.jetbrains.kotlinx:kotlinx-html-jvm:0.6.12" // Capsule is a library for building independently executable fat JARs. - // We only need this dependency to compile our Caplet against. - compileOnly "co.paralleluniverse:capsule:$capsule_version" + // We only need this dependency to implementation our Caplet against. + implementation "co.paralleluniverse:capsule:$capsule_version" - integrationTestCompile project(':node-driver') + implementation group: "com.typesafe", name: "config", version: typesafe_config_version + implementation "com.google.guava:guava:$guava_version" + + implementation "io.netty:netty-transport-native-unix-common:4.1.77.Final.jar" + + + testImplementation project(":core-test-utils") testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testImplementation "junit:junit:$junit_version" @@ -68,9 +70,11 @@ dependencies { testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" + + integrationTestImplementation project(':node-driver') } -task integrationTest(type: Test) { +tasks.register('integrationTest', Test) { testClassesDirs = sourceSets.integrationTest.output.classesDirs classpath = sourceSets.integrationTest.runtimeClasspath } @@ -79,6 +83,14 @@ jar { baseName 'corda-testserver-impl' } -publish { - name jar.baseName +compileJava.dependsOn ':node:capsule:buildCordaJAR' +javadoc.dependsOn ':testing:testserver:testcapsule:buildWebserverJar' + +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } } diff --git a/testing/testserver/src/main/java/CordaWebserverCaplet.java b/testing/testserver/src/main/java/CordaWebserverCaplet.java index ba0fbb7054..69bef1e916 100644 --- a/testing/testserver/src/main/java/CordaWebserverCaplet.java +++ b/testing/testserver/src/main/java/CordaWebserverCaplet.java @@ -2,14 +2,22 @@ // must also be in the default package. When using Kotlin there are a whole host of exceptions // trying to construct this from Capsule, so it is written in Java. -import com.typesafe.config.*; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigException; +import com.typesafe.config.ConfigFactory; +import com.typesafe.config.ConfigParseOptions; +import com.typesafe.config.ConfigValue; import sun.misc.Signal; import java.io.File; -import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Stream; public class CordaWebserverCaplet extends Capsule { @@ -37,11 +45,6 @@ public class CordaWebserverCaplet extends Capsule { } } - File getConfigFile(List args, String baseDir) { - String config = getOptionMultiple(args, Arrays.asList("--config-file", "-f")); - return (config == null || config.equals("")) ? new File(baseDir, "node.conf") : new File(config); - } - String getBaseDirectory(List args) { String baseDir = getOptionMultiple(args, Arrays.asList("--base-directory", "-b")); return Paths.get((baseDir == null) ? "." : baseDir).toAbsolutePath().normalize().toString(); @@ -69,7 +72,7 @@ public class CordaWebserverCaplet extends Capsule { } if (arg.toLowerCase().startsWith(lowerCaseOption)) { - if (arg.length() > option.length() && arg.substring(option.length(), option.length() + 1).equals("=")) { + if (arg.length() > option.length() && arg.charAt(option.length()) == '=') { return arg.substring(option.length() + 1); } else { return null; @@ -87,23 +90,6 @@ public class CordaWebserverCaplet extends Capsule { return super.prelaunch(jvmArgs, args); } - // Capsule does not handle multiple instances of same option hence we add in the args here to process builder - // For multiple instances Capsule jvm args handling works on basis that one overrides the other. - @Override - protected int launch(ProcessBuilder pb) throws IOException, InterruptedException { - if (isAtLeastJavaVersion11()) { - List args = pb.command(); - List myArgs = Arrays.asList( - "--add-opens=java.base/java.lang=ALL-UNNAMED", - "--add-opens=java.base/java.time=ALL-UNNAMED", - "--add-opens=java.base/java.io=ALL-UNNAMED", - "--add-opens=java.base/java.nio=ALL-UNNAMED"); - args.addAll(1, myArgs); - pb.command(args); - } - return super.launch(pb); - } - // Add working directory variable to capsules string replacement variables. @Override protected String getVarValue(String var) { @@ -157,9 +143,6 @@ public class CordaWebserverCaplet extends Capsule { } catch (ConfigException e) { log(LOG_QUIET, e); } - if (isAtLeastJavaVersion11()) { - jvmArgs.add("-Dnashorn.args=--no-deprecation-warning"); - } return (T) jvmArgs; } else if (ATTR_SYSTEM_PROPERTIES == attr) { // Add system properties, if specified, from the config. @@ -196,20 +179,12 @@ public class CordaWebserverCaplet extends Capsule { private static void checkJavaVersion() { String version = System.getProperty("java.version"); - if (version == null || Stream.of("1.8", "11").noneMatch(version::startsWith)) { - System.err.printf("Error: Unsupported Java version %s; currently only version 1.8 or 11 is supported.\n", version); + if (version == null || Stream.of("17").noneMatch(version::startsWith)) { + System.err.printf("Error: Unsupported Java version %s; currently only version 17 is supported.\n", version); System.exit(1); } } - private static boolean isAtLeastJavaVersion11() { - String version = System.getProperty("java.specification.version"); - if (version != null) { - return Float.parseFloat(version) >= 11f; - } - return false; - } - private Boolean checkIfCordappDirExists(File dir) { try { if (!dir.mkdir() && !dir.exists()) { // It is unlikely to enter this if-branch, but just in case. diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/WebArgsParser.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/WebArgsParser.kt index a627e46d5c..a534f679a3 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/WebArgsParser.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/WebArgsParser.kt @@ -6,12 +6,12 @@ import com.typesafe.config.ConfigParseOptions import com.typesafe.config.ConfigRenderOptions import joptsimple.OptionParser import joptsimple.util.EnumConverter -import net.corda.core.internal.div import net.corda.core.utilities.loggerFor import org.slf4j.event.Level import java.io.PrintStream import java.nio.file.Path import java.nio.file.Paths +import kotlin.io.path.div // NOTE: Do not use any logger in this class as args parsing is done before the logger is setup. class ArgsParser { diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/WebServer.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/WebServer.kt index 203e6c65da..55ff477283 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/WebServer.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/WebServer.kt @@ -3,7 +3,6 @@ package net.corda.webserver import com.typesafe.config.ConfigException -import net.corda.core.internal.div import net.corda.core.internal.errors.AddressBindingException import net.corda.core.internal.location import net.corda.core.internal.rootCause @@ -11,6 +10,7 @@ import net.corda.webserver.internal.NodeWebServer import org.slf4j.LoggerFactory import java.lang.management.ManagementFactory import java.net.InetAddress +import kotlin.io.path.div import kotlin.system.exitProcess fun main(args: Array) { @@ -36,7 +36,7 @@ fun main(args: Array) { System.setProperty("consoleLogLevel", "info") } - System.setProperty("log-path", (cmdlineOptions.baseDirectory / "logs/web").toString()) + System.setProperty("log-path", (cmdlineOptions.baseDirectory / "logs" / "web").toString()) val log = LoggerFactory.getLogger("Main") println("This Corda-specific web server is deprecated and will be removed in future.") println("Please switch to a regular web framework like Spring, J2EE or Play Framework.") @@ -54,8 +54,6 @@ fun main(args: Array) { val info = ManagementFactory.getRuntimeMXBean() log.info("CommandLine Args: ${info.inputArguments.joinToString(" ")}") log.info("Application Args: ${args.joinToString(" ")}") - // JDK 11 (bootclasspath no longer supported from JDK 9) - if (info.isBootClassPathSupported) log.info("bootclasspath: ${info.bootClassPath}") log.info("classpath: ${info.classPath}") log.info("VM ${info.vmName} ${info.vmVendor} ${info.vmVersion}") log.info("Machine: ${InetAddress.getLocalHost().hostName}") diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt index 69569e8dbf..3411bf2b5f 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt @@ -1,7 +1,6 @@ package net.corda.webserver import com.typesafe.config.Config -import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort import net.corda.nodeapi.internal.config.User import net.corda.nodeapi.internal.config.getValue diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/api/APIServer.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/api/APIServer.kt index 1476cd6982..e217eece0b 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/api/APIServer.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/api/APIServer.kt @@ -1,15 +1,15 @@ package net.corda.webserver.api +import jakarta.ws.rs.GET +import jakarta.ws.rs.Path +import jakarta.ws.rs.Produces +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response import net.corda.core.contracts.ContractState import net.corda.core.contracts.StateAndRef import net.corda.core.identity.Party import net.corda.core.utilities.NetworkHostAndPort import java.time.LocalDateTime -import javax.ws.rs.GET -import javax.ws.rs.Path -import javax.ws.rs.Produces -import javax.ws.rs.core.MediaType -import javax.ws.rs.core.Response /** * Top level interface to external interaction with the distributed ledger. diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/converters/Converters.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/converters/Converters.kt index f0e20a037e..a4e907e0a3 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/converters/Converters.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/converters/Converters.kt @@ -1,11 +1,10 @@ package net.corda.webserver.converters +import jakarta.ws.rs.ext.ParamConverter +import jakarta.ws.rs.ext.ParamConverterProvider +import jakarta.ws.rs.ext.Provider import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.uncheckedCast import java.lang.reflect.Type -import javax.ws.rs.ext.ParamConverter -import javax.ws.rs.ext.ParamConverterProvider -import javax.ws.rs.ext.Provider object CordaX500NameConverter : ParamConverter { override fun toString(value: CordaX500Name) = value.toString() @@ -14,10 +13,11 @@ object CordaX500NameConverter : ParamConverter { @Provider object CordaConverterProvider : ParamConverterProvider { + @Suppress("UNCHECKED_CAST") override fun getConverter(rawType: Class, genericType: Type?, annotations: Array?): ParamConverter? { if (rawType == CordaX500Name::class.java) { - return uncheckedCast(CordaX500NameConverter) + return CordaX500NameConverter as ParamConverter? } return null } -} \ No newline at end of file +} diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/internal/APIServerImpl.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/internal/APIServerImpl.kt index b166a143ea..7e9cbe21c9 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/internal/APIServerImpl.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/internal/APIServerImpl.kt @@ -1,12 +1,12 @@ package net.corda.webserver.internal +import jakarta.ws.rs.core.Response import net.corda.core.contracts.ContractState import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.vaultQueryBy import net.corda.webserver.api.APIServer import java.time.LocalDateTime import java.time.ZoneId -import javax.ws.rs.core.Response class APIServerImpl(val rpcOps: CordaRPCOps) : APIServer { override fun serverTime(): LocalDateTime { diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/internal/AllExceptionMapper.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/internal/AllExceptionMapper.kt index 3530b74e56..3760c3e54c 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/internal/AllExceptionMapper.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/internal/AllExceptionMapper.kt @@ -1,9 +1,9 @@ package net.corda.webserver.internal +import jakarta.ws.rs.core.Response +import jakarta.ws.rs.ext.ExceptionMapper +import jakarta.ws.rs.ext.Provider import net.corda.core.utilities.loggerFor -import javax.ws.rs.core.Response -import javax.ws.rs.ext.ExceptionMapper -import javax.ws.rs.ext.Provider // Provides basic exception logging to all APIs @Provider diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/internal/NodeWebServer.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/internal/NodeWebServer.kt index 52dce3a5b7..076437e774 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/internal/NodeWebServer.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/internal/NodeWebServer.kt @@ -14,12 +14,12 @@ import net.corda.webserver.WebServerConfig import net.corda.webserver.converters.CordaConverterProvider import net.corda.webserver.services.WebServerPluginRegistry import net.corda.webserver.servlets.* +import org.eclipse.jetty.ee10.servlet.DefaultServlet +import org.eclipse.jetty.ee10.servlet.ServletContextHandler +import org.eclipse.jetty.ee10.servlet.ServletHolder import org.eclipse.jetty.server.* +import org.eclipse.jetty.server.handler.ContextHandlerCollection import org.eclipse.jetty.server.handler.ErrorHandler -import org.eclipse.jetty.server.handler.HandlerCollection -import org.eclipse.jetty.servlet.DefaultServlet -import org.eclipse.jetty.servlet.ServletContextHandler -import org.eclipse.jetty.servlet.ServletHolder import org.eclipse.jetty.util.ssl.SslContextFactory import org.glassfish.jersey.server.ResourceConfig import org.glassfish.jersey.server.ServerProperties @@ -30,7 +30,6 @@ import java.io.Writer import java.lang.reflect.InvocationTargetException import java.net.BindException import java.util.* -import javax.servlet.http.HttpServletRequest class NodeWebServer(val config: WebServerConfig) { private companion object { @@ -60,7 +59,7 @@ class NodeWebServer(val config: WebServerConfig) { private fun initWebServer(localRpc: CordaRPCOps): Server { // Note that the web server handlers will all run concurrently, and not on the node thread. - val handlerCollection = HandlerCollection() + val handlerCollection = ContextHandlerCollection() // API, data upload and download to services (attachments, rates oracles etc) handlerCollection.addHandler(buildServletContextHandler(localRpc)) @@ -72,7 +71,7 @@ class NodeWebServer(val config: WebServerConfig) { httpsConfiguration.outputBufferSize = 32768 httpsConfiguration.addCustomizer(SecureRequestCustomizer()) @Suppress("DEPRECATION") - val sslContextFactory = SslContextFactory() + val sslContextFactory = SslContextFactory.Server() sslContextFactory.keyStorePath = config.keyStorePath sslContextFactory.setKeyStorePassword(config.keyStorePassword) sslContextFactory.setKeyManagerPassword(config.keyStorePassword) @@ -118,15 +117,15 @@ class NodeWebServer(val config: WebServerConfig) { contextPath = "/" errorHandler = object : ErrorHandler() { @Throws(IOException::class) - override fun writeErrorPageHead(request: HttpServletRequest, writer: Writer, code: Int, message: String) { - writer.write("\n") - writer.write("Corda $safeLegalName : Error $code\n") + override fun writeErrorHtmlHead(request: Request?, writer: Writer?, code: Int, message: String?) { + writer?.write("\n") + writer?.write("Corda $safeLegalName : Error $code\n") } @Throws(IOException::class) - override fun writeErrorPageMessage(request: HttpServletRequest, writer: Writer, code: Int, message: String, uri: String) { - writer.write("

    Corda $safeLegalName

    \n") - super.writeErrorPageMessage(request, writer, code, message, uri) + override fun writeErrorHtmlMessage(request: Request?, writer: Writer?, code: Int, message: String?, cause: Throwable?, uri: String?) { + writer?.write("

    Corda $safeLegalName

    \n") + super.writeErrorHtmlMessage(request, writer, code, message, cause, uri) } } setAttribute("rpc", localRpc) diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/AttachmentDownloadServlet.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/AttachmentDownloadServlet.kt index 9bfc69b641..7622e2bfd1 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/AttachmentDownloadServlet.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/AttachmentDownloadServlet.kt @@ -1,17 +1,18 @@ package net.corda.webserver.servlets +import jakarta.servlet.http.HttpServlet +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import jakarta.ws.rs.core.HttpHeaders +import jakarta.ws.rs.core.MediaType import net.corda.core.internal.extractFile import net.corda.core.crypto.SecureHash import net.corda.core.messaging.CordaRPCOps import net.corda.core.utilities.contextLogger import java.io.FileNotFoundException import java.io.IOException +import java.util.Locale import java.util.jar.JarInputStream -import javax.servlet.http.HttpServlet -import javax.servlet.http.HttpServletRequest -import javax.servlet.http.HttpServletResponse -import javax.ws.rs.core.HttpHeaders -import javax.ws.rs.core.MediaType /** * Allows the node administrator to either download full attachment zips, or individual files within those zips. @@ -43,7 +44,7 @@ class AttachmentDownloadServlet : HttpServlet() { val attachment = rpc.openAttachment(hash) // Don't allow case sensitive matches inside the jar, it'd just be confusing. - val subPath = reqPath.substringAfter('/', missingDelimiterValue = "").toLowerCase() + val subPath = reqPath.substringAfter('/', missingDelimiterValue = "").lowercase(Locale.getDefault()) resp.contentType = MediaType.APPLICATION_OCTET_STREAM if (subPath.isEmpty()) { diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/CorDappInfoServlet.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/CorDappInfoServlet.kt index 4f51255e8b..46267cba24 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/CorDappInfoServlet.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/CorDappInfoServlet.kt @@ -1,5 +1,8 @@ package net.corda.webserver.servlets +import jakarta.servlet.http.HttpServlet +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse import kotlinx.html.* import kotlinx.html.stream.appendHTML import net.corda.core.messaging.CordaRPCOps @@ -7,9 +10,6 @@ import net.corda.webserver.services.WebServerPluginRegistry import org.glassfish.jersey.server.model.Resource import org.glassfish.jersey.server.model.ResourceMethod import java.io.IOException -import javax.servlet.http.HttpServlet -import javax.servlet.http.HttpServletRequest -import javax.servlet.http.HttpServletResponse /** * Dumps some data about the installed CorDapps. diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/DataUploadServlet.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/DataUploadServlet.kt index d860d5d5a5..0db503edb0 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/DataUploadServlet.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/DataUploadServlet.kt @@ -1,13 +1,13 @@ package net.corda.webserver.servlets +import jakarta.servlet.http.HttpServlet +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse import net.corda.core.messaging.CordaRPCOps import net.corda.core.utilities.contextLogger -import org.apache.commons.fileupload.servlet.ServletFileUpload +import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload import java.io.IOException import java.util.* -import javax.servlet.http.HttpServlet -import javax.servlet.http.HttpServletRequest -import javax.servlet.http.HttpServletResponse /** * Uploads to the node via the [CordaRPCOps] uploadFile interface. @@ -19,7 +19,7 @@ class DataUploadServlet : HttpServlet() { @Throws(IOException::class) override fun doPost(req: HttpServletRequest, resp: HttpServletResponse) { - val isMultipart = ServletFileUpload.isMultipartContent(req) + val isMultipart = JakartaServletFileUpload.isMultipartContent(req) val rpc = servletContext.getAttribute("rpc") as CordaRPCOps if (!isMultipart) { @@ -27,7 +27,7 @@ class DataUploadServlet : HttpServlet() { return } - val upload = ServletFileUpload() + val upload = JakartaServletFileUpload() val iterator = upload.getItemIterator(req) val messages = ArrayList() @@ -48,7 +48,7 @@ class DataUploadServlet : HttpServlet() { continue } try { - messages += rpc.uploadAttachment(item.openStream()).toString() + messages += rpc.uploadAttachment(item.inputStream).toString() } catch (e: RuntimeException) { reportError(e.toString()) continue diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/ObjectMapperConfig.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/ObjectMapperConfig.kt index 8dc7635944..504b9e5d63 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/ObjectMapperConfig.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/ObjectMapperConfig.kt @@ -1,8 +1,8 @@ package net.corda.webserver.servlets import com.fasterxml.jackson.databind.ObjectMapper -import javax.ws.rs.ext.ContextResolver -import javax.ws.rs.ext.Provider +import jakarta.ws.rs.ext.ContextResolver +import jakarta.ws.rs.ext.Provider /** * Primary purpose is to install Kotlin extensions for Jackson ObjectMapper so data classes work diff --git a/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/ResponseFilter.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/ResponseFilter.kt index ccb7c4d6e3..2b86d9b72e 100644 --- a/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/ResponseFilter.kt +++ b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/ResponseFilter.kt @@ -1,10 +1,10 @@ package net.corda.webserver.servlets +import jakarta.ws.rs.container.ContainerRequestContext +import jakarta.ws.rs.container.ContainerResponseContext +import jakarta.ws.rs.container.ContainerResponseFilter +import jakarta.ws.rs.ext.Provider import java.io.IOException -import javax.ws.rs.container.ContainerRequestContext -import javax.ws.rs.container.ContainerResponseContext -import javax.ws.rs.container.ContainerResponseFilter -import javax.ws.rs.ext.Provider /** * This adds headers needed for cross site scripting on API clients. diff --git a/testing/testserver/testcapsule/build.gradle b/testing/testserver/testcapsule/build.gradle index f231f12c68..d97e8446d1 100644 --- a/testing/testserver/testcapsule/build.gradle +++ b/testing/testserver/testcapsule/build.gradle @@ -2,9 +2,8 @@ * This build.gradle exists to publish our capsule (executable fat jar) to maven. It cannot be placed in the * webserver project because the bintray plugin cannot publish two modules from one project. */ -apply plugin: 'net.corda.plugins.publish-utils' apply plugin: 'us.kirchmeier.capsule' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' description 'Corda node web server capsule' @@ -24,29 +23,29 @@ capsule { version capsule_version } -task buildWebserverJar(type: FatCapsule, dependsOn: project(':node').tasks.jar) { +configurations.runtimeOnly.canBeResolved = true +tasks.register('buildWebserverJar', FatCapsule) { + dependsOn project(':node').tasks.jar applicationClass 'net.corda.webserver.WebServer' archiveBaseName = 'corda-testserver' archiveVersion = corda_release_version - archiveClassifier = jdkClassifier archiveName = archiveFileName.get() applicationSource = files( - project(':testing:testserver').configurations.runtimeClasspath, - project(':testing:testserver').tasks.jar, - project(':testing:testserver').sourceSets.main.java.outputDir.toString() + '/CordaWebserverCaplet.class', - project(':testing:testserver').sourceSets.main.java.outputDir.toString() + '/CordaWebserverCaplet$1.class', - project(':node').buildDir.toString() + '/resources/main/corda-reference.conf', - "$rootDir/config/dev/log4j2.xml", - project(':node:capsule').projectDir.toString() + '/NOTICE' // Copy CDDL notice + project(':testing:testserver').configurations.runtimeClasspath, + project(':testing:testserver').tasks.jar, + project(':testing:testserver').sourceSets.main.java.outputDir.toString() + '/CordaWebserverCaplet.class', + project(':testing:testserver').sourceSets.main.java.outputDir.toString() + '/CordaWebserverCaplet$1.class', + project(':node').buildDir.toString() + '/resources/main/corda-reference.conf', + "$rootDir/config/dev/log4j2.xml", + project(':node:capsule').projectDir.toString() + '/NOTICE' // Copy CDDL notice ) from configurations.capsuleRuntime.files.collect { zipTree(it) } capsuleManifest { applicationVersion = corda_release_version - javaAgents = quasar_classifier ? ["quasar-core-${quasar_version}-${quasar_classifier}.jar"] : ["quasar-core-${quasar_version}.jar"] + javaAgents = quasar_classifier ? ["quasar-core-${quasar_version}-${quasar_classifier}.jar=m"] : ["quasar-core-${quasar_version}.jar=m"] systemProperties['visualvm.display.name'] = 'Corda Webserver' - minJavaVersion = '1.8.0' - minUpdateVersion['1.8'] = java8_minUpdateVersion + minJavaVersion = '17.0' caplets = ['CordaWebserverCaplet'] // JVM configuration: @@ -54,25 +53,22 @@ task buildWebserverJar(type: FatCapsule, dependsOn: project(':node').tasks.jar) // - Switch to the G1 GC which is going to be the default in Java 9 and gives low pause times/string dedup. // // If you change these flags, please also update Driver.kt - jvmArgs = ['-Xmx200m', '-XX:+UseG1GC'] - } - - manifest { - if (JavaVersion.current() == JavaVersion.VERSION_11) { - attributes('Add-Opens': 'java.management/com.sun.jmx.mbeanserver java.base/java.lang') - } + jvmArgs = ['-Xmx200m'] } } artifacts { - archives buildWebserverJar runtimeArtifacts buildWebserverJar - publish buildWebserverJar { - classifier '' - } } -publish { - disableDefaultJar = true - name 'corda-testserver' +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-testserver' + artifact(buildWebserverJar) { + classifier '' + } + from components.java + } + } } diff --git a/tools/blobinspector/build.gradle b/tools/blobinspector/build.gradle index 1e7b6d0b22..1e34fcd8e3 100644 --- a/tools/blobinspector/build.gradle +++ b/tools/blobinspector/build.gradle @@ -1,24 +1,41 @@ -apply plugin: 'java' -apply plugin: 'kotlin' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'corda.common-publishing' + +description 'Corda blob inspector module' dependencies { - compile project(':client:jackson') - compile project(':tools:cliutils') - compile project(":common-logging") - compile "org.slf4j:jul-to-slf4j:$slf4j_version" - compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version" - compile "com.jcabi:jcabi-manifests:$jcabi_manifests_version" + implementation project(':core') + implementation project(':serialization') + implementation project(':client:jackson') + implementation project(':tools:cliutils') + implementation project(":common-logging") - testCompile(project(':test-utils')) { + implementation "org.slf4j:jul-to-slf4j:$slf4j_version" + implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version" + implementation "com.jcabi:jcabi-manifests:$jcabi_manifests_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jackson_version" + implementation "info.picocli:picocli:$picocli_version" + implementation "org.apache.qpid:proton-j:$protonj_version" + + testImplementation(project(':test-utils')) { exclude module: 'node-api' exclude module: 'contracts' } + + testImplementation(project(':core-test-utils')) { + exclude module: 'node-api' + } + + testImplementation "commons-io:commons-io:$commons_io_version" + testImplementation "org.assertj:assertj-core:${assertj_version}" + testImplementation "junit:junit:$junit_version" } +configurations.implementation.canBeResolved = true + jar { - from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) { + from(configurations.implementation.collect { it.isDirectory() ? it : zipTree(it) }) { exclude "META-INF/*.SF" exclude "META-INF/*.DSA" exclude "META-INF/*.RSA" @@ -29,8 +46,14 @@ jar { 'Main-Class': 'net.corda.blobinspector.BlobInspectorKt' ) } + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } -publish { - name 'corda-tools-blob-inspector' +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-tools-blob-inspector' + from components.java + } + } } diff --git a/tools/blobinspector/src/main/kotlin/net/corda/blobinspector/BlobInspector.kt b/tools/blobinspector/src/main/kotlin/net/corda/blobinspector/BlobInspector.kt index 00b29d5ff5..f5c8d480b5 100644 --- a/tools/blobinspector/src/main/kotlin/net/corda/blobinspector/BlobInspector.kt +++ b/tools/blobinspector/src/main/kotlin/net/corda/blobinspector/BlobInspector.kt @@ -6,7 +6,6 @@ import net.corda.client.jackson.JacksonSupport import net.corda.cliutils.CordaCliWrapper import net.corda.cliutils.ExitCodes import net.corda.cliutils.start -import net.corda.core.internal.isRegularFile import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationDefaults import net.corda.core.serialization.deserialize @@ -22,11 +21,14 @@ import net.corda.serialization.internal.SerializationFactoryImpl import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme import net.corda.serialization.internal.amqp.DeserializationInput import net.corda.serialization.internal.amqp.amqpMagic -import picocli.CommandLine.* +import picocli.CommandLine.ITypeConverter +import picocli.CommandLine.Option +import picocli.CommandLine.Parameters import java.io.PrintStream import java.net.MalformedURLException import java.net.URL import java.nio.file.Paths +import kotlin.io.path.isRegularFile fun main(args: Array) { BlobInspector().start(args) diff --git a/tools/blobinspector/src/main/resources/log4j2.xml b/tools/blobinspector/src/main/resources/log4j2.xml index b7a8bfcd2f..40ec04ee35 100644 --- a/tools/blobinspector/src/main/resources/log4j2.xml +++ b/tools/blobinspector/src/main/resources/log4j2.xml @@ -1,8 +1,8 @@ - ${sys:consoleLogLevel:-error} - ${sys:defaultLogLevel:-info} + ${sys:consoleLogLevel:-error} + ${sys:defaultLogLevel:-info} @@ -14,4 +14,4 @@ - \ No newline at end of file +
    diff --git a/tools/bootstrapper/build.gradle b/tools/bootstrapper/build.gradle index ae708803aa..16d26584ad 100644 --- a/tools/bootstrapper/build.gradle +++ b/tools/bootstrapper/build.gradle @@ -1,23 +1,30 @@ -apply plugin: 'kotlin' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'corda.common-publishing' description 'Network bootstrapper' dependencies { - compile project(':node-api') - compile project(':tools:cliutils') - compile project(":common-logging") - compile project(':common-configuration-parsing') - compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version" + implementation project(':core') + implementation project(':node-api') + implementation project(':tools:cliutils') + implementation project(":common-logging") + implementation project(':common-configuration-parsing') + implementation project(':common-validation') - testCompile(project(':test-utils')) { - exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j-impl' + implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version" + implementation "com.typesafe:config:$typesafe_config_version" + implementation "info.picocli:picocli:$picocli_version" + + testImplementation(project(':test-utils')) { + exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j2-impl' } - testCompile(project(':test-cli')) - testCompile "com.nhaarman:mockito-kotlin:$mockito_kotlin_version" - testCompile "org.mockito:mockito-core:$mockito_version" + testImplementation(project(':core-test-utils')) + testImplementation(project(':test-cli')) + + testImplementation "junit:junit:$junit_version" + testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" + testImplementation "org.mockito:mockito-core:$mockito_version" } processResources { @@ -39,8 +46,16 @@ jar { 'Main-Class': 'net.corda.bootstrapper.MainKt' ) } + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } -publish { - name 'corda-tools-network-bootstrapper' +jar.dependsOn ':testing:testserver:testcapsule:buildWebserverJar' + +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-tools-network-bootstrapper' + from components.java + } + } } diff --git a/tools/bootstrapper/src/main/kotlin/net/corda/bootstrapper/Main.kt b/tools/bootstrapper/src/main/kotlin/net/corda/bootstrapper/Main.kt index bb15468241..15e1768142 100644 --- a/tools/bootstrapper/src/main/kotlin/net/corda/bootstrapper/Main.kt +++ b/tools/bootstrapper/src/main/kotlin/net/corda/bootstrapper/Main.kt @@ -2,18 +2,27 @@ package net.corda.bootstrapper import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigParseOptions -import net.corda.cliutils.* +import net.corda.cliutils.CordaCliWrapper +import net.corda.cliutils.ExitCodes +import net.corda.cliutils.printError +import net.corda.cliutils.printWarning +import net.corda.cliutils.start import net.corda.common.configuration.parsing.internal.Configuration import net.corda.core.internal.PLATFORM_VERSION -import net.corda.core.internal.exists -import net.corda.nodeapi.internal.network.* +import net.corda.nodeapi.internal.network.CopyCordapps +import net.corda.nodeapi.internal.network.NetworkBootstrapper import net.corda.nodeapi.internal.network.NetworkBootstrapper.Companion.DEFAULT_MAX_MESSAGE_SIZE import net.corda.nodeapi.internal.network.NetworkBootstrapper.Companion.DEFAULT_MAX_TRANSACTION_SIZE +import net.corda.nodeapi.internal.network.NetworkBootstrapperWithOverridableParameters +import net.corda.nodeapi.internal.network.NetworkParametersOverrides +import net.corda.nodeapi.internal.network.Valid +import net.corda.nodeapi.internal.network.parseAsNetworkParametersConfiguration import picocli.CommandLine.Option import java.io.FileNotFoundException import java.nio.file.Path import java.nio.file.Paths import java.time.Duration +import kotlin.io.path.exists fun main(args: Array) { NetworkBootstrapperRunner().start(args) diff --git a/tools/bootstrapper/src/test/kotlin/net/corda/bootstrapper/NetworkBootstrapperRunnerTests.kt b/tools/bootstrapper/src/test/kotlin/net/corda/bootstrapper/NetworkBootstrapperRunnerTests.kt index 9336327436..e6607b58ab 100644 --- a/tools/bootstrapper/src/test/kotlin/net/corda/bootstrapper/NetworkBootstrapperRunnerTests.kt +++ b/tools/bootstrapper/src/test/kotlin/net/corda/bootstrapper/NetworkBootstrapperRunnerTests.kt @@ -1,10 +1,7 @@ package net.corda.bootstrapper -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify -import net.corda.core.internal.copyTo +import net.corda.core.internal.copyToDirectory import net.corda.core.internal.deleteRecursively -import net.corda.core.internal.div import net.corda.core.utilities.days import net.corda.nodeapi.internal.network.CopyCordapps import net.corda.nodeapi.internal.network.NetworkBootstrapperWithOverridableParameters @@ -13,7 +10,13 @@ import net.corda.nodeapi.internal.network.PackageOwner import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.internal.JarSignatureTestUtils.generateKey import net.corda.testing.core.internal.JarSignatureTestUtils.getPublicKey -import org.junit.* +import org.junit.After +import org.junit.AfterClass +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Test +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify import java.io.ByteArrayOutputStream import java.io.FileNotFoundException import java.io.PrintStream @@ -21,6 +24,9 @@ import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths import java.security.PublicKey +import kotlin.io.path.Path +import kotlin.io.path.createTempDirectory +import kotlin.io.path.div import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -58,11 +64,7 @@ class NetworkBootstrapperRunnerTests { private lateinit var alicePublicKeyEC: PublicKey private lateinit var alicePublicKeyDSA: PublicKey - private val resourceDirectory = Paths.get(".") / "src" / "test" / "resources" - - private fun String.copyToTestDir(dir: Path = dirAlice): Path { - return (resourceDirectory / this).copyTo(dir / this) - } + private fun String.copyToTestDir(dir: Path = dirAlice): Path = Path("src", "test", "resources", this).copyToDirectory(dir) @BeforeClass @JvmStatic @@ -98,7 +100,7 @@ class NetworkBootstrapperRunnerTests { @Test(timeout=300_000) fun `test when base directory is specified it is passed through to the bootstrapper`() { val (runner, mockBootstrapper) = getRunner() - val tempDir = createTempDir() + val tempDir = createTempDirectory().toFile() runner.dir = tempDir.toPath() val exitCode = runner.runProgram() verify(mockBootstrapper).bootstrap(tempDir.toPath().toAbsolutePath().normalize(), CopyCordapps.FirstRunOnly, NetworkParametersOverrides()) @@ -260,4 +262,4 @@ class NetworkBootstrapperRunnerTests { val exception = assertFailsWith { runner.runProgram() } assert(exception.message!!.startsWith("Unable to find specified network parameters config file at")) } -} \ No newline at end of file +} diff --git a/tools/checkpoint-agent/build.gradle b/tools/checkpoint-agent/build.gradle index 838d70c652..d32317db49 100644 --- a/tools/checkpoint-agent/build.gradle +++ b/tools/checkpoint-agent/build.gradle @@ -1,29 +1,28 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' description 'A javaagent to allow hooking into Kryo checkpoints' dependencies { - compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" compileOnly "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - compileOnly "org.javassist:javassist:$javaassist_version" + implementation "org.javassist:javassist:$javaassist_version" compileOnly "com.esotericsoftware:kryo:$kryo_version" compileOnly "co.paralleluniverse:quasar-core:$quasar_version" - compileOnly (project(':core')) { + implementation (project(':core')) { transitive = false } // Unit testing helpers. - testCompile "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" - testCompile "junit:junit:$junit_version" + testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" + testImplementation "junit:junit:$junit_version" // SLF4J: commons-logging bindings for a SLF4J back end - compileOnly "org.slf4j:slf4j-api:$slf4j_version" + implementation "org.slf4j:slf4j-api:$slf4j_version" } +configurations.implementation.canBeResolved = true jar { archiveBaseName = "${project.name}" manifest { @@ -36,9 +35,15 @@ jar { 'Implementation-Version': rootProject.version ) } - from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + from { configurations.implementation.collect { it.isDirectory() ? it : zipTree(it) } } + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } -publish { - name 'corda-tools-checkpoint-agent' +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-tools-checkpoint-agent' + from components.java + } + } } diff --git a/tools/checkpoint-agent/src/main/kotlin/net/corda/tools/CheckpointAgent.kt b/tools/checkpoint-agent/src/main/kotlin/net/corda/tools/CheckpointAgent.kt index f6d5eb41cc..1207e1504c 100644 --- a/tools/checkpoint-agent/src/main/kotlin/net/corda/tools/CheckpointAgent.kt +++ b/tools/checkpoint-agent/src/main/kotlin/net/corda/tools/CheckpointAgent.kt @@ -72,7 +72,7 @@ class CheckpointAgent { when (nvpItem[0].trim()) { "instrumentClassname" -> instrumentClassname = nvpItem[1] "instrumentType" -> try { - instrumentType = InstrumentationType.valueOf(nvpItem[1].toUpperCase()) + instrumentType = InstrumentationType.valueOf(nvpItem[1].uppercase(Locale.getDefault())) } catch (e: Exception) { display("Invalid value: ${nvpItem[1]}. Please specify read or write.") } @@ -127,7 +127,9 @@ object CheckpointHook : ClassFileTransformer { protectionDomain: ProtectionDomain?, classfileBuffer: ByteArray ): ByteArray? { - if (className.startsWith("java") || className.startsWith("javassist") || className.startsWith("kotlin")) { + @Suppress("ComplexCondition") + if (className.startsWith("java") || className.startsWith("javassist") || className.startsWith("kotlin") + || className.startsWith("jdk")) { return null } return try { @@ -192,7 +194,7 @@ object CheckpointHook : ClassFileTransformer { @JvmStatic fun readFieldEnter(that: Any) { - if (that is FieldSerializer.CachedField<*>) { + if (that is FieldSerializer.CachedField) { log.debug { "readFieldEnter object: ${that.field.name}:${that.field.type}" } val (list, _) = events.getOrPut(Strand.currentStrand().id) { Pair(ArrayList(), AtomicInteger(0)) } list.add(StatsEvent.EnterField(that.field.name, that.field.type)) @@ -201,7 +203,7 @@ object CheckpointHook : ClassFileTransformer { @JvmStatic fun readFieldExit(obj: Any?, that: Any) { - if (that is FieldSerializer.CachedField<*>) { + if (that is FieldSerializer.CachedField) { val (list, _) = events.getOrPut(Strand.currentStrand().id) { Pair(ArrayList(), AtomicInteger(0)) } val value = that.field.get(obj) val arrayValue = getArrayValue(that.field.type, value) @@ -389,6 +391,7 @@ object CheckpointHook : ClassFileTransformer { builder.append("\n") } } + is StatsTree.Loop -> log.info("StatsTree.Loop ignored") } } } diff --git a/tools/cliutils/build.gradle b/tools/cliutils/build.gradle index 2ab54773ae..a4463a41d9 100644 --- a/tools/cliutils/build.gradle +++ b/tools/cliutils/build.gradle @@ -1,29 +1,32 @@ -apply plugin: 'java' -apply plugin: 'kotlin' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'corda.common-publishing' description 'CLI Utilities' dependencies { - compile project(":core") - compile project(":common-logging") - - compile "info.picocli:picocli:$picocli_version" - compile "commons-io:commons-io:$commons_io_version" - compile "com.jcabi:jcabi-manifests:$jcabi_manifests_version" + implementation project(":core") + implementation project(":common-logging") + + implementation "org.apache.commons:commons-lang3:$commons_lang3_version" + implementation "info.picocli:picocli:$picocli_version" + implementation "commons-io:commons-io:$commons_io_version" + implementation "com.jcabi:jcabi-manifests:$jcabi_manifests_version" // JAnsi: for drawing things to the terminal in nicely coloured ways. - compile "org.fusesource.jansi:jansi:$jansi_version" + implementation "org.fusesource.jansi:jansi:$jansi_version" - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + implementation "org.slf4j:slf4j-api:$slf4j_version" } jar { - baseName = "corda-tools-cliutils" + archiveBaseName = "corda-tools-cliutils" } -publish { - name jar.baseName +publishing { + publications { + maven(MavenPublication) { + artifactId jar.baseName + from components.java + } + } } - diff --git a/tools/cliutils/src/main/kotlin/net/corda/cliutils/CordaCliWrapper.kt b/tools/cliutils/src/main/kotlin/net/corda/cliutils/CordaCliWrapper.kt index 8bb9cb6432..534021ab6c 100644 --- a/tools/cliutils/src/main/kotlin/net/corda/cliutils/CordaCliWrapper.kt +++ b/tools/cliutils/src/main/kotlin/net/corda/cliutils/CordaCliWrapper.kt @@ -154,7 +154,7 @@ abstract class CliWrapperBase(val alias: String, val description: String) : Call } val specifiedLogLevel: String by lazy { - System.getProperty("log4j2.level")?.toLowerCase(Locale.ENGLISH) ?: loggingLevel.name.toLowerCase(Locale.ENGLISH) + System.getProperty("log4j2.level")?.lowercase(Locale.ENGLISH) ?: loggingLevel.name.lowercase(Locale.ENGLISH) } } @@ -219,7 +219,7 @@ object CommonCliConstants { */ class LoggingLevelConverter : ITypeConverter { override fun convert(value: String?): Level { - return value?.let { Level.valueOf(it.toUpperCase()) } + return value?.let { Level.valueOf(it.uppercase(Locale.getDefault())) } ?: throw TypeConversionException("Unknown option for --logging-level: $value") } diff --git a/tools/cliutils/src/main/kotlin/net/corda/cliutils/InstallShellExtensionsParser.kt b/tools/cliutils/src/main/kotlin/net/corda/cliutils/InstallShellExtensionsParser.kt index 71546f4895..c7b876f85e 100644 --- a/tools/cliutils/src/main/kotlin/net/corda/cliutils/InstallShellExtensionsParser.kt +++ b/tools/cliutils/src/main/kotlin/net/corda/cliutils/InstallShellExtensionsParser.kt @@ -1,6 +1,8 @@ package net.corda.cliutils -import net.corda.core.internal.* +import net.corda.common.logging.CordaVersion +import net.corda.core.internal.location +import net.corda.core.internal.toPath import net.corda.core.utilities.loggerFor import org.apache.commons.io.IOUtils import org.apache.commons.lang3.SystemUtils @@ -8,9 +10,14 @@ import picocli.CommandLine import picocli.CommandLine.Command import java.nio.file.Path import java.nio.file.Paths -import java.nio.file.StandardCopyOption -import java.util.* -import net.corda.common.logging.CordaVersion +import java.util.Collections +import kotlin.io.path.copyTo +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.useLines +import kotlin.io.path.writeLines +import kotlin.io.path.writeText private class ShellExtensionsGenerator(val parent: CordaCliWrapper) { private companion object { @@ -54,7 +61,7 @@ private class ShellExtensionsGenerator(val parent: CordaCliWrapper) { if (fileModified) { val backupFilePath = filePath.parent / "${filePath.fileName}.backup" println("Updating settings in ${filePath.fileName} - existing settings file has been backed up to $backupFilePath") - if (filePath.exists()) filePath.copyTo(backupFilePath, StandardCopyOption.REPLACE_EXISTING) + if (filePath.exists()) filePath.copyTo(backupFilePath, overwrite = true) filePath.writeLines(lines) } } @@ -166,9 +173,7 @@ private class ShellExtensionsGenerator(val parent: CordaCliWrapper) { // If no autocomplete file, it hasn't been installed, so don't do anything if (!autoCompleteFile.exists()) return - var lastLine = "" - autoCompleteFile.toFile().forEachLine { lastLine = it } - + val lastLine = autoCompleteFile.useLines { it.last() } if (lastLine != jarVersion(parent.alias)) { println("Old auto completion file detected... regenerating") generateAutoCompleteFile(parent.alias) @@ -178,7 +183,7 @@ private class ShellExtensionsGenerator(val parent: CordaCliWrapper) { } @Command(helpCommand = true) -class InstallShellExtensionsParser(private val cliWrapper: CordaCliWrapper) : CliWrapperBase("install-shell-extensions", "Install alias and autocompletion for bash and zsh") { +class InstallShellExtensionsParser(cliWrapper: CordaCliWrapper) : CliWrapperBase("install-shell-extensions", "Install alias and autocompletion for bash and zsh") { private val generator = ShellExtensionsGenerator(cliWrapper) override fun runProgram(): Int { return generator.installShellExtensions() diff --git a/tools/demobench/build.gradle b/tools/demobench/build.gradle index be75806d58..446993f7c2 100644 --- a/tools/demobench/build.gradle +++ b/tools/demobench/build.gradle @@ -3,15 +3,14 @@ plugins { id 'org.openjfx.javafxplugin' version '0.0.7' apply false } -if (JavaVersion.current().isJava9Compatible()) { - apply plugin: 'org.openjfx.javafxplugin' - javafx { - version = "11.0.2" - modules = ['javafx.controls', - 'javafx.fxml', - 'javafx.swing' - ] - } +apply plugin: 'org.openjfx.javafxplugin' +javafx { + version = "11.0.2" + modules = [ + 'javafx.controls', + 'javafx.fxml', + 'javafx.swing' + ] } ext { @@ -28,8 +27,7 @@ ext { pkg_macosxKeyUserName = 'R3CEV' } -apply plugin: 'java' -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'application' evaluationDependsOn(':tools:explorer:capsule') @@ -42,52 +40,62 @@ applicationDefaultJvmArgs = [ ] configurations { - compile { + implementation { // We don't need Hibernate just for its @Type annotation. exclude group: 'org.hibernate', module: 'hibernate-core' } } dependencies { - compile project(':client:rpc') - compile project(':finance:contracts') - compile project(':finance:workflows') - compile project(':tools:worldmap') + implementation project(':core') + implementation project(':node') + implementation project(':node-api') + implementation project(':serialization') + implementation project(':common-configuration-parsing') + implementation project(':common-validation') + implementation project(':client:rpc') + + implementation project(':finance:contracts') + implementation project(':finance:workflows') + implementation project(':tools:worldmap') // TornadoFX: A lightweight Kotlin framework for working with JavaFX UI's. - compile "no.tornado:tornadofx:$tornadofx_version" + implementation "no.tornado:tornadofx:$tornadofx_version" // Controls FX: more java FX components http://fxexperience.com/controlsfx/ - compile "org.controlsfx:controlsfx:$controlsfx_version" + implementation "org.controlsfx:controlsfx:$controlsfx_version" - compile "com.h2database:h2:$h2_version" - compile "net.java.dev.jna:jna-platform:$jna_version" - compile "com.google.guava:guava:$guava_version" + implementation "com.h2database:h2:$h2_version" + implementation "net.java.dev.jna:jna-platform:$jna_version" + implementation "com.google.guava:guava:$guava_version" + implementation "io.reactivex:rxjava:$rxjava_version" - compile "org.slf4j:log4j-over-slf4j:$slf4j_version" - compile "org.slf4j:jul-to-slf4j:$slf4j_version" - compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version" - compile "org.apache.logging.log4j:log4j-core:$log4j_version" - compile "com.typesafe:config:$typesafe_config_version" + implementation "org.slf4j:log4j-over-slf4j:$slf4j_version" + implementation "org.slf4j:jul-to-slf4j:$slf4j_version" + implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version" + implementation "org.apache.logging.log4j:log4j-core:$log4j_version" + implementation "com.typesafe:config:$typesafe_config_version" // FontAwesomeFX: icons in the form of a font. - compile "de.jensd:fontawesomefx-fontawesome:$fontawesomefx_fontawesome_version" - compile "de.jensd:fontawesomefx-commons:$fontawesomefx_commons_version" + implementation "de.jensd:fontawesomefx-fontawesome:$fontawesomefx_fontawesome_version" + implementation "de.jensd:fontawesomefx-commons:$fontawesomefx_commons_version" - compile "org.jetbrains.jediterm:jediterm-pty:$jediterm_version" - compile("org.jetbrains.pty4j:pty4j:$pty4j_version") { + implementation "org.jetbrains.jediterm:jediterm-pty:$jediterm_version" + implementation("org.jetbrains.pty4j:pty4j:$pty4j_version") { exclude group: 'log4j' } - testCompile project(':test-utils') - testCompile project(':testing:testserver') + testImplementation project(':core-test-utils') + testImplementation project(':test-utils') + testImplementation project(':testing:testserver') testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - testCompile "org.assertj:assertj-core:$assertj_version" - testCompile "junit:junit:$junit_version" + testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + testImplementation "org.assertj:assertj-core:$assertj_version" + testImplementation "junit:junit:$junit_version" } tasks.withType(JavaCompile).configureEach { @@ -102,8 +110,10 @@ jar { 'Class-Path': configurations.runtimeClasspath.collect { it.name }.join(' '), ) } + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } + test { systemProperty 'java.util.logging.config.class', 'net.corda.demobench.config.LoggingConfig' systemProperty 'org.jboss.logging.provider', 'slf4j' @@ -145,7 +155,8 @@ distributions { * Bundles the application using JavaPackager, * using the ZIP distribution as source. */ -task javapackage(dependsOn: distZip) { +tasks.register('javapackage') { + dependsOn distZip doLast { delete([pkg_source, pkg_outDir]) @@ -179,15 +190,14 @@ task javapackage(dependsOn: distZip) { include '**/*.manifest' } filter { line -> - line.replaceAll('@pkg_version@', pkg_version) - .replaceAll('@signingKeyUserName@', pkg_macosxKeyUserName) + line.replaceAll('@pkg_version@', pkg_version).replaceAll('@signingKeyUserName@', pkg_macosxKeyUserName) } into "$pkg_source/package" } ant.taskdef( - resource: 'com/sun/javafx/tools/ant/antlib.xml', - classpath: "$pkg_source:$java_home/../lib/ant-javafx.jar" + resource: 'com/sun/javafx/tools/ant/antlib.xml', + classpath: "$pkg_source:$java_home/../lib/ant-javafx.jar" ) ant.deploy(nativeBundles: packageType, outdir: pkg_outDir, outfile: 'DemoBench', verbose: 'true') { diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/explorer/Explorer.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/explorer/Explorer.kt index 7baabdb8fe..91c6926c10 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/explorer/Explorer.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/explorer/Explorer.kt @@ -2,7 +2,6 @@ package net.corda.demobench.explorer import net.corda.core.internal.copyTo import net.corda.core.internal.createDirectories -import net.corda.core.internal.div import net.corda.core.internal.list import net.corda.core.utilities.contextLogger import net.corda.demobench.model.JVMConfig diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt index 68c5e0a42b..f20d442048 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt @@ -2,7 +2,6 @@ package net.corda.demobench.model import com.typesafe.config.Config import net.corda.core.internal.deleteRecursively -import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort import net.corda.nodeapi.internal.config.UnknownConfigKeysPolicy import net.corda.nodeapi.internal.config.parseAs diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt index 86787676f5..d7c5c0bbca 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt @@ -10,7 +10,6 @@ import net.corda.core.identity.CordaX500Name import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.copyToDirectory import net.corda.core.internal.createDirectories -import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort import net.corda.nodeapi.internal.config.User import net.corda.nodeapi.internal.config.toConfig diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt index bfd2747f05..381f5ca947 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt @@ -8,7 +8,6 @@ import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.copyToDirectory import net.corda.core.internal.createDirectories -import net.corda.core.internal.div import net.corda.core.internal.noneOrSingle import net.corda.core.internal.writeText import net.corda.core.node.NetworkParameters diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/profile/ProfileController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/profile/ProfileController.kt index 4c8bfeb02d..b5328387b6 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/profile/ProfileController.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/profile/ProfileController.kt @@ -92,7 +92,7 @@ class ProfileController : Controller() { val configs = LinkedList() - FileSystems.newFileSystem(chosen.toPath(), null).use { fs -> + FileSystems.newFileSystem(chosen.toPath()).use { fs -> // Identify the nodes first... StreamSupport.stream(fs.rootDirectories.spliterator(), false) .flatMap { Files.find(it, 2, BiPredicate { p, attr -> "node.conf" == p?.fileName.toString() && attr.isRegularFile }) } diff --git a/tools/demobench/src/main/resources/log4j2.xml b/tools/demobench/src/main/resources/log4j2.xml index fc1846617f..b85030ca91 100644 --- a/tools/demobench/src/main/resources/log4j2.xml +++ b/tools/demobench/src/main/resources/log4j2.xml @@ -2,11 +2,11 @@ - ${sys:user.home}/demobench - demobench + ${sys:user.home}/demobench + demobench ${sys:log-path}/archive - error - info + error + info @@ -15,8 +15,8 @@ + fileName="${sys:log_path}/${log_name}.log" + filePattern="${archive}/${log_name}.%date{yyyy-MM-dd}-%i.log.gz"> @@ -27,7 +27,7 @@ - + diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/pty/ZeroFilterTest.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/pty/ZeroFilterTest.kt index 063efa3a2a..7350fc1729 100644 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/pty/ZeroFilterTest.kt +++ b/tools/demobench/src/test/kotlin/net/corda/demobench/pty/ZeroFilterTest.kt @@ -1,8 +1,8 @@ package net.corda.demobench.pty -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.verify -import com.nhaarman.mockito_kotlin.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import net.corda.coretesting.internal.rigorousMock import org.junit.Assert.assertEquals import org.junit.Before diff --git a/tools/error-tool/build.gradle b/tools/error-tool/build.gradle index 908775f7c2..7d886bcafa 100644 --- a/tools/error-tool/build.gradle +++ b/tools/error-tool/build.gradle @@ -1,22 +1,23 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'com.github.johnrengelman.shadow' dependencies { implementation project(":common-logging") implementation project(":tools:cliutils") implementation "info.picocli:picocli:$picocli_version" - implementation "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version" + implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version" testImplementation "junit:junit:$junit_version" + testImplementation "org.assertj:assertj-core:$assertj_version" } jar { enabled = false - classifier = 'ignore' + archiveClassifier = 'ignore' } shadowJar { - baseName = "corda-tools-error-utils" + archiveBaseName = "corda-tools-error-utils" manifest { attributes( 'Main-Class': "net.corda.errorUtilities.ErrorToolKt" diff --git a/tools/error-tool/src/main/kotlin/net/corda/errorUtilities/resourceGenerator/ResourceGenerator.kt b/tools/error-tool/src/main/kotlin/net/corda/errorUtilities/resourceGenerator/ResourceGenerator.kt index 2cb34684dd..bcf0cedadf 100644 --- a/tools/error-tool/src/main/kotlin/net/corda/errorUtilities/resourceGenerator/ResourceGenerator.kt +++ b/tools/error-tool/src/main/kotlin/net/corda/errorUtilities/resourceGenerator/ResourceGenerator.kt @@ -49,8 +49,8 @@ class ResourceGenerator(private val locales: List) { throw ClassDoesNotExistException(it) } if (ErrorCodes::class.java.isAssignableFrom(clazz) && clazz != ErrorCodes::class.java) { - val namespace = (clazz.enumConstants.first() as ErrorCodes).namespace.toLowerCase() - clazz.enumConstants.map { code -> "${namespace}-${code.toString().toLowerCase().replace("_", "-")}"} + val namespace = (clazz.enumConstants.first() as ErrorCodes).namespace.lowercase(Locale.getDefault()) + clazz.enumConstants.map { code -> "${namespace}-${code.toString().lowercase(Locale.getDefault()).replace("_", "-")}"} } else { listOf() } diff --git a/tools/error-tool/src/main/resources/log4j2.xml b/tools/error-tool/src/main/resources/log4j2.xml index be842b0fa0..e794016bdf 100644 --- a/tools/error-tool/src/main/resources/log4j2.xml +++ b/tools/error-tool/src/main/resources/log4j2.xml @@ -1,8 +1,8 @@ - ${sys:defaultLogLevel:-info} - ${sys:consoleLogLevel:-error} + ${sys:defaultLogLevel:-info} + ${sys:consoleLogLevel:-error} @@ -11,8 +11,8 @@ - - + + diff --git a/tools/error-tool/src/test/kotlin/net/corda/errorUtilities/docsTable/DocsTableGeneratorTest.kt b/tools/error-tool/src/test/kotlin/net/corda/errorUtilities/docsTable/DocsTableGeneratorTest.kt index 59ca2ed17f..164344a395 100644 --- a/tools/error-tool/src/test/kotlin/net/corda/errorUtilities/docsTable/DocsTableGeneratorTest.kt +++ b/tools/error-tool/src/test/kotlin/net/corda/errorUtilities/docsTable/DocsTableGeneratorTest.kt @@ -1,10 +1,10 @@ package net.corda.errorUtilities.docsTable import junit.framework.TestCase.assertEquals +import org.assertj.core.api.Assertions.assertThatIllegalArgumentException import org.junit.Test -import java.lang.IllegalArgumentException import java.nio.file.Paths -import java.util.* +import java.util.Locale class DocsTableGeneratorTest { @@ -37,9 +37,11 @@ class DocsTableGeneratorTest { assertEquals(irishTable.split("\n").joinToString(System.lineSeparator()), table) } - @Test(expected = IllegalArgumentException::class, timeout = 1000) + @Test(timeout = 1000) fun `error thrown if unknown directory passed to generator`() { val generator = DocsTableGenerator(Paths.get("not/a/directory"), Locale.getDefault()) - generator.generateMarkdown() + assertThatIllegalArgumentException().isThrownBy { + generator.generateMarkdown() + } } } \ No newline at end of file diff --git a/tools/error-tool/src/test/kotlin/net/corda/errorUtilities/resourceGenerator/ResourceGeneratorTest.kt b/tools/error-tool/src/test/kotlin/net/corda/errorUtilities/resourceGenerator/ResourceGeneratorTest.kt index 8f20d5988c..5f0de9c317 100644 --- a/tools/error-tool/src/test/kotlin/net/corda/errorUtilities/resourceGenerator/ResourceGeneratorTest.kt +++ b/tools/error-tool/src/test/kotlin/net/corda/errorUtilities/resourceGenerator/ResourceGeneratorTest.kt @@ -4,14 +4,17 @@ import junit.framework.TestCase.assertEquals import net.corda.common.logging.errorReporting.ResourceBundleProperties import org.junit.Test import java.util.* +import kotlin.io.path.createTempDirectory class ResourceGeneratorTest { private val classes = listOf(TestCodes1::class.qualifiedName!!, TestCodes2::class.qualifiedName!!) private fun expectedCodes() : List { - val codes1 = TestCodes1.values().map { "${it.namespace.toLowerCase()}-${it.name.replace("_", "-").toLowerCase()}" } - val codes2 = TestCodes2.values().map { "${it.namespace.toLowerCase()}-${it.name.replace("_", "-").toLowerCase()}" } + val codes1 = TestCodes1.values().map { "${it.namespace.lowercase(Locale.getDefault())}-${it.name.replace("_", "-") + .lowercase(Locale.getDefault())}" } + val codes2 = TestCodes2.values().map { "${it.namespace.lowercase(Locale.getDefault())}-${it.name.replace("_", "-") + .lowercase(Locale.getDefault())}" } return codes1 + codes2 } @@ -40,7 +43,7 @@ class ResourceGeneratorTest { assertEquals(expectedCodes().map { "$it.properties" }.toSet(), missing.toSet()) // Now check that all resource files that should be created are - val tempDir = createTempDir() + val tempDir = createTempDirectory().toFile() resourceGenerator.createResources(missing, tempDir.toPath()) val createdFiles = tempDir.walkTopDown().filter { it.isFile && it.extension == "properties" }.map { it.name }.toSet() assertEquals(missing.toSet(), createdFiles) diff --git a/tools/explorer/build.gradle b/tools/explorer/build.gradle index 82838e5c80..2dd2a3ae19 100644 --- a/tools/explorer/build.gradle +++ b/tools/explorer/build.gradle @@ -3,74 +3,77 @@ plugins { id 'org.openjfx.javafxplugin' version '0.0.7' apply false } -if (JavaVersion.current().isJava9Compatible()) { - apply plugin: 'org.openjfx.javafxplugin' - javafx { - version = "11.0.2" - modules = ['javafx.controls', - 'javafx.fxml', - 'javafx.swing' - ] - } +apply plugin: 'org.openjfx.javafxplugin' +javafx { + version = "11.0.2" + modules = [ + 'javafx.controls', + 'javafx.fxml', + 'javafx.swing' + ] } -apply plugin: 'java' -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'application' -sourceCompatibility = 1.8 mainClassName = 'net.corda.explorer.Main' dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - testImplementation "junit:junit:$junit_version" testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}" testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}" - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" // TornadoFX: A lightweight Kotlin framework for working with JavaFX UI's. - compile 'no.tornado:tornadofx:1.5.9' + implementation 'no.tornado:tornadofx:1.5.9' // Corda Core: Data structures and basic types needed to work with Corda. - compile project(':core') - compile project(':client:jfx') - compile project(':finance:contracts') - compile project(':finance:workflows') - compile project(':tools:worldmap') - compile project(':common-logging') + implementation project(':core') + implementation project(':client:rpc') + implementation project(':client:jfx') + implementation project(':finance:contracts') + implementation project(':finance:workflows') + implementation project(':tools:worldmap') + implementation project(':common-logging') // Log4J: logging framework (with SLF4J bindings) - compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version" + implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version" // Capsule is a library for building independently executable fat JARs. - // We only need this dependency to compile our Caplet against. - compileOnly "co.paralleluniverse:capsule:$capsule_version" + // We only need this dependency to implementation our Caplet against. + implementation "co.paralleluniverse:capsule:$capsule_version" // FontAwesomeFX: The "FontAwesome" icon library. - compile "de.jensd:fontawesomefx-fontawesome:$fontawesomefx_fontawesome_version" - compile "de.jensd:fontawesomefx-commons:$fontawesomefx_commons_version" + implementation "de.jensd:fontawesomefx-fontawesome:$fontawesomefx_fontawesome_version" + implementation "de.jensd:fontawesomefx-commons:$fontawesomefx_commons_version" // ReactFX: Functional reactive UI programming. - compile 'org.reactfx:reactfx:2.0-M5' - compile 'org.fxmisc.easybind:easybind:1.0.3' + implementation 'org.reactfx:reactfx:2.0-M5' + implementation 'org.fxmisc.easybind:easybind:1.0.3' - compile 'org.jfxtras:jfxtras-font-roboto:8.0-r6' + implementation 'org.jfxtras:jfxtras-font-roboto:8.0-r6' // Humanize: formatting - compile 'com.github.mfornos:humanize-icu:1.2.2' + implementation 'com.github.mfornos:humanize-icu:1.2.2' // Controls FX: more java FX components http://fxexperience.com/controlsfx/ - compile "org.controlsfx:controlsfx:$controlsfx_version" + implementation "org.controlsfx:controlsfx:$controlsfx_version" // This provide com.apple.eawt stub for non-mac system. - compile 'com.yuvimasory:orange-extensions:1.3.0' + implementation 'com.yuvimasory:orange-extensions:1.3.0' // JOpt: for command line flags. - compile "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" + implementation "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" + + implementation "org.apache.commons:commons-lang3:$commons_lang3_version" + implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version" } +compileJava.dependsOn ':testing:testserver:testcapsule:buildWebserverJar' +startScripts.dependsOn ':testing:testserver:testcapsule:buildWebserverJar' +startScripts.dependsOn ':node:capsule:buildCordaJAR' + tasks.withType(JavaCompile).configureEach { // Resolves a Gradle warning about not scanning for pre-processors. options.compilerArgs << '-proc:none' diff --git a/tools/explorer/capsule/build.gradle b/tools/explorer/capsule/build.gradle index 56b5f3a5de..75a019f15b 100644 --- a/tools/explorer/capsule/build.gradle +++ b/tools/explorer/capsule/build.gradle @@ -2,8 +2,7 @@ * This build.gradle exists to package Node Explorer as an executable fat jar. */ apply plugin: 'us.kirchmeier.capsule' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' +apply plugin: 'corda.common-publishing' description 'Node Explorer' @@ -15,37 +14,24 @@ capsule { version capsule_version } -task buildExplorerJAR(type: FatCapsule, dependsOn: project(':tools:explorer').tasks.jar) { +configurations.runtimeOnly.canBeResolved = true +tasks.register('buildExplorerJAR', FatCapsule) { + dependsOn project(':tools:explorer').tasks.jar applicationClass 'net.corda.explorer.Main' archiveBaseName = 'node-explorer' archiveVersion = corda_release_version - archiveClassifier = jdkClassifier archiveName = archiveFileName.get() applicationSource = files( - project(':tools:explorer').configurations.runtimeClasspath, - project(':tools:explorer').tasks.jar, - project(':tools:explorer').sourceSets.main.java.outputDir.toString() + '/ExplorerCaplet.class' + project(':tools:explorer').configurations.runtimeClasspath, + project(':tools:explorer').tasks.jar, + project(':tools:explorer').sourceSets.main.java.outputDir.toString() + '/ExplorerCaplet.class' ) capsuleManifest { applicationVersion = corda_release_version systemProperties['visualvm.display.name'] = 'Node Explorer' - minJavaVersion = '1.8.0' - minUpdateVersion['1.8'] = java8_minUpdateVersion + minJavaVersion = '17.0' caplets = ['ExplorerCaplet'] - - // JVM configuration: - // - Switch to the G1 GC which is going to be the default in Java 9 and gives low pause times/string dedup. - // - jvmArgs = ['-XX:+UseG1GC'] - } -} - -artifacts { - archives buildExplorerJAR - runtimeArtifacts buildExplorerJAR - publish buildExplorerJAR { - classifier "" } } @@ -54,7 +40,14 @@ jar { enabled = false } -publish { - disableDefaultJar = true - name 'corda-tools-explorer' +publishing { + publications { + maven(MavenPublication) { + artifactId 'corda-tools-explorer' + artifact(buildExplorerJAR) { + classifier '' + } + from components.java + } + } } diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/model/IssuerModel.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/model/IssuerModel.kt index 08fa114c0e..420673dd9c 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/model/IssuerModel.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/model/IssuerModel.kt @@ -4,12 +4,12 @@ import javafx.collections.FXCollections import net.corda.client.jfx.model.NodeMonitorModel import net.corda.client.jfx.model.observableValue import net.corda.client.jfx.utils.ChosenList -import net.corda.client.jfx.utils.map import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow import net.corda.finance.internal.CashConfigDataFlow import tornadofx.* import java.util.* +import net.corda.client.jfx.utils.map class IssuerModel { diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/model/SettingsModel.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/model/SettingsModel.kt index 9aee44c69b..51fae22acc 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/model/SettingsModel.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/model/SettingsModel.kt @@ -4,11 +4,17 @@ import javafx.beans.InvalidationListener import javafx.beans.Observable import javafx.beans.property.ObjectProperty import javafx.beans.property.SimpleObjectProperty -import net.corda.core.internal.* +import net.corda.core.internal.read +import net.corda.core.internal.uncheckedCast +import net.corda.core.internal.write import tornadofx.* import java.nio.file.Path import java.nio.file.Paths -import java.util.* +import java.util.Currency +import java.util.Properties +import kotlin.io.path.createDirectories +import kotlin.io.path.div +import kotlin.io.path.exists import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KProperty import kotlin.reflect.jvm.javaType diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/ui/TableViewUtilities.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/ui/TableViewUtilities.kt index 879b620a93..e536b1a5b6 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/ui/TableViewUtilities.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/ui/TableViewUtilities.kt @@ -14,13 +14,14 @@ import org.fxmisc.easybind.EasyBind fun TableView.setColumnPrefWidthPolicy( getColumnWidth: (tableWidthWithoutPaddingAndBorder: Number, column: TableColumn) -> Number ) { + @Suppress("SpreadOperator") val tableWidthWithoutPaddingAndBorder = Bindings.createDoubleBinding({ val padding = padding val borderInsets = border?.insets width - (if (padding != null) padding.left + padding.right else 0.0) - (if (borderInsets != null) borderInsets.left + borderInsets.right else 0.0) - }, arrayOf(columns, widthProperty(), paddingProperty(), borderProperty())) + }, *arrayOf(columns, widthProperty(), paddingProperty(), borderProperty())) columns.forEach { it.setPrefWidthPolicy(tableWidthWithoutPaddingAndBorder, getColumnWidth) @@ -49,13 +50,14 @@ fun Formatter.toTableCellFactory() = Callback, Tabl } } +@Suppress("SpreadOperator") fun TableView.singleRowSelection(): ObjectBinding> = Bindings.createObjectBinding({ if (selectionModel.selectedItems.size == 0) { SingleRowSelection.None() } else { SingleRowSelection.Selected(selectionModel.selectedItems[0]) } -}, arrayOf(selectionModel.selectedItems)) +}, *arrayOf(selectionModel.selectedItems)) fun TableColumn.setCustomCellFactory(toNode: (T) -> Node) { setCellFactory { diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/ui/TreeTableViewUtilities.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/ui/TreeTableViewUtilities.kt index 92e0d46a46..55f3593820 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/ui/TreeTableViewUtilities.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/ui/TreeTableViewUtilities.kt @@ -12,13 +12,14 @@ import org.fxmisc.easybind.EasyBind fun TreeTableView.setColumnPrefWidthPolicy( getColumnWidth: (tableWidthWithoutPaddingAndBorder: Number, column: TreeTableColumn) -> Number ) { + @Suppress("SpreadOperator") val tableWidthWithoutPaddingAndBorder = Bindings.createDoubleBinding({ val padding = padding val borderInsets = border?.insets width - (if (padding != null) padding.left + padding.right else 0.0) - (if (borderInsets != null) borderInsets.left + borderInsets.right else 0.0) - }, arrayOf(columns, widthProperty(), paddingProperty(), borderProperty())) + }, *arrayOf(columns, widthProperty(), paddingProperty(), borderProperty())) columns.forEach { it.setPrefWidthPolicy(tableWidthWithoutPaddingAndBorder, getColumnWidth) @@ -47,6 +48,7 @@ fun Formatter.toTreeTableCellFactory() = Callback TreeTableView.singleRowSelection(): ObservableValue> = Bindings.createObjectBinding({ if (selectionModel.selectedItems.size == 0) { @@ -54,4 +56,4 @@ fun TreeTableView.singleRowSelection(): ObservableValue(private val data: ObservableList, vararg filterCriteria: private val searchCategory by fxid>() private val ALL = "All" + @Suppress("SpreadOperator") val filteredData = ChosenList(Bindings.createObjectBinding({ val text = textField.text val category = searchCategory.value @@ -40,7 +42,7 @@ class SearchField(private val data: ObservableList, vararg filterCriteria: filterCriteria.toMap()[category]?.invoke(data, text) == true } } - }, arrayOf(textField.textProperty(), searchCategory.valueProperty())), "filteredData") + }, *arrayOf(textField.textProperty(), searchCategory.valueProperty())), "filteredData") init { clearButton.setOnMouseClicked { event: MouseEvent -> @@ -67,11 +69,11 @@ class SearchField(private val data: ObservableList, vararg filterCriteria: }) textField.promptTextProperty().bind(searchCategory.valueProperty().map { val category = if (it == ALL) { - filterCriteria.joinToString(", ") { it.first.toLowerCase() } + filterCriteria.joinToString(", ") { it.first.lowercase(Locale.getDefault()) } } else { - it.toLowerCase() + it.lowercase(Locale.getDefault()) } "Filter by $category." }) } -} \ No newline at end of file +} diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/views/Settings.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/views/Settings.kt index 6a596b44bd..62bd348ed5 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/views/Settings.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/views/Settings.kt @@ -1,7 +1,6 @@ package net.corda.explorer.views import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon -import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView import javafx.scene.Node import javafx.scene.Parent import javafx.scene.control.CheckBox @@ -10,7 +9,6 @@ import javafx.scene.control.Label import javafx.scene.control.TextField import net.corda.client.jfx.model.objectProperty import net.corda.client.jfx.model.observableList -import net.corda.client.jfx.utils.map import net.corda.explorer.model.CordaView import net.corda.explorer.model.IssuerModel import net.corda.explorer.model.SettingsModel @@ -61,9 +59,6 @@ class Settings : CordaView() { getModel().commit() clientPane.isDisable = true } - save.visibleProperty().bind(clientPane.disableProperty().map { !it }) - editCancel.textProperty().bind(clientPane.disableProperty().map { if (!it) "Cancel" else "Edit" }) - editCancel.graphicProperty().bind(clientPane.disableProperty() - .map { if (!it) FontAwesomeIconView(FontAwesomeIcon.TIMES) else FontAwesomeIconView(FontAwesomeIcon.EDIT) }) + clientPane.disableProperty() } -} \ No newline at end of file +} diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/views/TransactionViewer.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/views/TransactionViewer.kt index da9cf4c585..418e153235 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/views/TransactionViewer.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/views/TransactionViewer.kt @@ -57,7 +57,7 @@ class TransactionViewer : CordaView("Transactions") { override val widgets = listOf(CordaWidget(title, TransactionWidget(), icon)).observable() private var scrollPosition: Int = 0 - private lateinit var expander: ExpanderColumn + private var expander: ExpanderColumn private var txIdToScroll: SecureHash? = null // Passed as param. /** diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/views/cordapps/cash/NewTransaction.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/views/cordapps/cash/NewTransaction.kt index 27ee243651..4e547fabcc 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/views/cordapps/cash/NewTransaction.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/views/cordapps/cash/NewTransaction.kt @@ -168,7 +168,8 @@ class NewTransaction : Fragment() { init { // Disable everything when not connected to node. - val notariesNotNullBinding = Bindings.createBooleanBinding({ notaries.isNotEmpty() }, arrayOf(notaries)) + @Suppress("SpreadOperator") + val notariesNotNullBinding = Bindings.createBooleanBinding({ notaries.isNotEmpty() }, *arrayOf(notaries)) val enableProperty = myIdentity.isNotNull().and(rpcProxy.isNotNull()).and(notariesNotNullBinding) root.disableProperty().bind(enableProperty.not()) @@ -213,16 +214,18 @@ class NewTransaction : Fragment() { // TODO : Create a currency model to store these values currencyChoiceBox.items = currencyItems currencyChoiceBox.visibleProperty().bind(transactionTypeCB.valueProperty().isNotNull) - val issuer = Bindings.createObjectBinding({ if (issuerChoiceBox.isVisible) issuerChoiceBox.value else myIdentity.value }, arrayOf(myIdentity, issuerChoiceBox.visibleProperty(), issuerChoiceBox.valueProperty())) + @Suppress("SpreadOperator") + val issuer = Bindings.createObjectBinding({ if (issuerChoiceBox.isVisible) issuerChoiceBox.value else myIdentity.value }, *arrayOf(myIdentity, issuerChoiceBox.visibleProperty(), issuerChoiceBox.valueProperty())) availableAmount.visibleProperty().bind( issuer.isNotNull.and(currencyChoiceBox.valueProperty().isNotNull).and(transactionTypeCB.valueProperty().booleanBinding(transactionTypeCB.valueProperty()) { it != CashTransaction.Issue }) ) + @Suppress("SpreadOperator") availableAmount.textProperty() .bind(Bindings.createStringBinding({ val filteredCash = cash.filtered { it.token.issuer.party == issuer.value && it.token.product == currencyChoiceBox.value } .map { it.withoutIssuer() }.sumOrNull() "${filteredCash ?: "None"} Available" - }, arrayOf(currencyChoiceBox.valueProperty(), issuerChoiceBox.valueProperty()))) + }, *arrayOf(currencyChoiceBox.valueProperty(), issuerChoiceBox.valueProperty()))) // Amount amountLabel.visibleProperty().bind(transactionTypeCB.valueProperty().isNotNull) amountTextField.textFormatter = bigDecimalFormatter().apply { amount.bind(this.valueProperty()) } diff --git a/tools/explorer/src/main/resources/log4j2.xml b/tools/explorer/src/main/resources/log4j2.xml index f88bdd29ff..9d8ad04556 100644 --- a/tools/explorer/src/main/resources/log4j2.xml +++ b/tools/explorer/src/main/resources/log4j2.xml @@ -1,28 +1,14 @@ - info + info - - - - - - + @@ -32,4 +18,4 @@ - \ No newline at end of file + diff --git a/tools/explorer/src/test/kotlin/net/corda/explorer/model/SettingsModelTest.kt b/tools/explorer/src/test/kotlin/net/corda/explorer/model/SettingsModelTest.kt index 0a5dbfaebd..60ee430e3e 100644 --- a/tools/explorer/src/test/kotlin/net/corda/explorer/model/SettingsModelTest.kt +++ b/tools/explorer/src/test/kotlin/net/corda/explorer/model/SettingsModelTest.kt @@ -1,10 +1,10 @@ package net.corda.explorer.model -import net.corda.core.internal.div -import net.corda.core.internal.exists import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import kotlin.io.path.div +import kotlin.io.path.exists import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue diff --git a/tools/graphs/build.gradle b/tools/graphs/build.gradle index 01a4da9637..523b01dc15 100644 --- a/tools/graphs/build.gradle +++ b/tools/graphs/build.gradle @@ -10,7 +10,7 @@ class GraphProject { this.project = project } def getCompileDeps() { - ['compile', 'cordaCompile'].collect { + ['implementation', 'cordaCompile'].collect { try { project.configurations[it].dependencies.matching { it in ProjectDependency }.collect { projects[it.dependencyProject] } } catch (org.gradle.api.artifacts.UnknownConfigurationException e) { @@ -86,4 +86,4 @@ jar { 'Automatic-Module-Name': 'net.corda.tools.graphs' ) } -} \ No newline at end of file +} diff --git a/tools/loadtest/build.gradle b/tools/loadtest/build.gradle index c55a2e2692..534702ecba 100644 --- a/tools/loadtest/build.gradle +++ b/tools/loadtest/build.gradle @@ -1,24 +1,29 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'application' mainClassName = 'net.corda.loadtest.MainKt' dependencies { - compile project(':client:mock') - compile project(':client:rpc') - compile project(':node-driver') + implementation project(':core') + implementation project(':node-api') + implementation project(':client:mock') + implementation project(':client:rpc') + implementation project(':node-driver') - // https://mvnrepository.com/artifact/com.jcraft/jsch - compile "com.jcraft:jsch:$jsch_version" - compile group: 'com.jcraft', name: 'jsch.agentproxy.core', version: '0.0.9' - compile group: 'com.jcraft', name: 'jsch.agentproxy.sshagent', version: '0.0.9' - compile group: 'com.jcraft', name: 'jsch.agentproxy.usocket-jna', version: '0.0.9' + implementation project(':finance:contracts') + implementation project(':finance:workflows') + + implementation "com.jcraft:jsch:$jsch_version" + implementation "com.google.guava:guava:$guava_version" + implementation group: 'com.jcraft', name: 'jsch.agentproxy.core', version: '0.0.9' + implementation group: 'com.jcraft', name: 'jsch.agentproxy.sshagent', version: '0.0.9' + implementation group: 'com.jcraft', name: 'jsch.agentproxy.usocket-jna', version: '0.0.9' // https://mvnrepository.com/artifact/de.danielbechler/java-object-diff - compile group: 'de.danielbechler', name: 'java-object-diff', version: '0.10.2' + implementation group: 'de.danielbechler', name: 'java-object-diff', version: '0.10.2' // TypeSafe Config: for simple and human friendly config files. - compile "com.typesafe:config:$typesafe_config_version" + implementation "com.typesafe:config:$typesafe_config_version" } run { diff --git a/tools/loadtest/src/main/kotlin/net/corda/loadtest/ConnectionManager.kt b/tools/loadtest/src/main/kotlin/net/corda/loadtest/ConnectionManager.kt index e28f95fc83..00a86feccb 100644 --- a/tools/loadtest/src/main/kotlin/net/corda/loadtest/ConnectionManager.kt +++ b/tools/loadtest/src/main/kotlin/net/corda/loadtest/ConnectionManager.kt @@ -11,7 +11,6 @@ import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.loggerFor import net.corda.testing.driver.PortAllocation import java.util.* -import kotlin.streams.toList private val log = loggerFor() @@ -45,7 +44,7 @@ fun setupJSchWithSshAgent(): JSch { override fun getName() = String(identity.comment) override fun isEncrypted() = false override fun getSignature(data: ByteArray?) = agentProxy.sign(identity.blob, data) - @Suppress("OverridingDeprecatedMember") + @Suppress("OVERRIDE_DEPRECATION") override fun decrypt() = true override fun getPublicKeyBlob() = identity.blob diff --git a/tools/loadtest/src/main/kotlin/net/corda/loadtest/NodeConnection.kt b/tools/loadtest/src/main/kotlin/net/corda/loadtest/NodeConnection.kt index 620cc92d99..3771aea1c4 100644 --- a/tools/loadtest/src/main/kotlin/net/corda/loadtest/NodeConnection.kt +++ b/tools/loadtest/src/main/kotlin/net/corda/loadtest/NodeConnection.kt @@ -47,7 +47,7 @@ class NodeConnection(val remoteNode: RemoteNode, private val jSchSession: Sessio val connection = rpcConnection require(connection != null) { "doWhileClientStopped called with no running client" } log.info("Stopping RPC proxy to ${remoteNode.hostname}, tunnel at $localTunnelAddress") - connection!!.close() + connection.close() try { return action() } finally { diff --git a/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/CrossCashTest.kt b/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/CrossCashTest.kt index ea4b03d9ca..5fa8d56ed9 100644 --- a/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/CrossCashTest.kt +++ b/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/CrossCashTest.kt @@ -242,7 +242,7 @@ val crossCashTest = LoadTest( val (consistentVaults, diffQueues) = if (previousState == null) { Pair(currentNodeVaults, mapOf>>>()) } else { - log.info("${previousState.diffQueues.values.sumBy { it.values.sumBy { it.size } }} txs in limbo") + log.info("${previousState.diffQueues.values.sumOf { it.values.sumOf { it.size } }} txs in limbo") val newDiffQueues = previousState.copyQueues() val newConsistentVault = previousState.copyVaults() previousState.diffQueues.forEach { entry -> diff --git a/tools/network-builder/build.gradle b/tools/network-builder/build.gradle index 51ec4d6339..3a22036a10 100644 --- a/tools/network-builder/build.gradle +++ b/tools/network-builder/build.gradle @@ -1,65 +1,71 @@ // JDK 11 JavaFX plugins { id 'org.openjfx.javafxplugin' version '0.0.7' apply false + id 'corda.common-publishing' } -if (JavaVersion.current().isJava9Compatible()) { - apply plugin: 'org.openjfx.javafxplugin' - javafx { - version = "11.0.2" - modules = ['javafx.controls', - 'javafx.fxml', - 'javafx.swing' - ] - } +description 'Corda Network Builder module' + +apply plugin: 'org.openjfx.javafxplugin' + +javafx { + version = "11.0.2" + modules = [ + 'javafx.controls', + 'javafx.fxml', + 'javafx.swing' + ] } ext { tornadofx_version = '1.7.15' } -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'idea' -apply plugin: 'java' apply plugin: 'application' // We need to set mainClassName before applying the shadow plugin. mainClassName = 'net.corda.networkbuilder.Main' apply plugin: 'com.github.johnrengelman.shadow' -apply plugin: 'net.corda.plugins.publish-utils' -apply plugin: 'com.jfrog.artifactory' configurations { - compile { + implementation { exclude group: "log4j", module: "log4j" exclude group: "org.apache.logging.log4j" - - // The Node only needs this for binary compatibility with Cordapps written in Kotlin 1.1. - exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jre8' } } dependencies { - compile "com.microsoft.azure:azure:1.22.0" - compile "com.github.docker-java:docker-java:$docker_java_version" + implementation project(':core') + implementation project(':node') + implementation project(':node-api') + implementation project(':serialization') + implementation project(':common-configuration-parsing') + implementation project(':common-validation') - testCompile "org.jetbrains.kotlin:kotlin-test" - testCompile "org.jetbrains.kotlin:kotlin-test-junit" + implementation "com.microsoft.azure:azure:1.22.0" + implementation "com.github.docker-java:docker-java:$docker_java_version" - compile project(':node-api') - compile project(':node') + testImplementation "org.jetbrains.kotlin:kotlin-test" + testImplementation "org.jetbrains.kotlin:kotlin-test-junit" - compile "com.typesafe:config:$typesafe_config_version" - compile "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jackson_version" - compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" - compile "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version" - compile "info.picocli:picocli:$picocli_version" + + implementation "com.typesafe:config:$typesafe_config_version" + implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + implementation "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version" + implementation "info.picocli:picocli:$picocli_version" // TornadoFX: A lightweight Kotlin framework for working with JavaFX UI's. - compile "no.tornado:tornadofx:$tornadofx_version" + implementation "no.tornado:tornadofx:$tornadofx_version" // ControlsFX: Extra controls for JavaFX. - compile "org.controlsfx:controlsfx:$controlsfx_version" + implementation "org.controlsfx:controlsfx:$controlsfx_version" + + implementation("org.apache.activemq:artemis-core-client:${artemis_version}") { + exclude group: 'org.jgroups', module: 'jgroups' + } } tasks.withType(JavaCompile).configureEach { @@ -72,9 +78,8 @@ processResources { } shadowJar { - baseName = 'network-builder' - archiveClassifier = jdkClassifier - version = null + archiveBaseName = 'network-builder' + archiveVersion = null zip64 true } @@ -82,16 +87,15 @@ tasks.register('buildNetworkBuilder') { dependsOn shadowJar } -artifacts { - archives shadowJar - publish shadowJar -} - jar { enabled = false } -publish { - disableDefaultJar = true - name 'corda-tools-network-builder' +publishing { + publications { + shadow(MavenPublication) { publication -> + artifactId 'corda-tools-network-builder' + project.shadow.component(publication) + } + } } diff --git a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/Constants.kt b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/Constants.kt index 6fb3e962f3..8560c53edf 100644 --- a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/Constants.kt +++ b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/Constants.kt @@ -8,6 +8,7 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory import com.fasterxml.jackson.module.kotlin.registerKotlinModule import com.microsoft.azure.management.resources.ResourceGroup import com.microsoft.azure.management.resources.fluentcore.arm.Region +import java.util.Locale class Constants { @@ -42,7 +43,7 @@ class Constants { const val REGION_ARG_NAME = "REGION" fun ResourceGroup.restFriendlyName(): String { - return this.name().replace(ALPHA_NUMERIC_ONLY_REGEX, "").toLowerCase() + return this.name().replace(ALPHA_NUMERIC_ONLY_REGEX, "").lowercase(Locale.getDefault()) } } } \ No newline at end of file diff --git a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/NetworkBuilder.kt b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/NetworkBuilder.kt index dc2eb8835a..273dd16c95 100644 --- a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/NetworkBuilder.kt +++ b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/NetworkBuilder.kt @@ -5,6 +5,7 @@ import net.corda.networkbuilder.context.Context import net.corda.networkbuilder.nodes.* import net.corda.networkbuilder.notaries.NotaryCopier import java.io.File +import java.util.Locale import java.util.concurrent.CompletableFuture interface NetworkBuilder { @@ -142,7 +143,7 @@ private class NetworkBuilderImpl : NetworkBuilder { val nodeDiscoveryFuture = CompletableFuture.supplyAsync { val foundNodes = nodeFinder.findNodes() - .map { it to nodeCounts.getOrDefault(it.name.toLowerCase(), 1) } + .map { it to nodeCounts.getOrDefault(it.name.lowercase(Locale.getDefault()), 1) } .toMap() foundNodes } diff --git a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/cli/CommandLineInterface.kt b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/cli/CommandLineInterface.kt index 98ce10991f..9d8568a3cb 100644 --- a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/cli/CommandLineInterface.kt +++ b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/cli/CommandLineInterface.kt @@ -11,6 +11,7 @@ import net.corda.networkbuilder.nodes.NodeAdder import net.corda.networkbuilder.nodes.NodeInstantiator import net.corda.networkbuilder.toSingleFuture import java.io.File +import java.util.Locale class CommandLineInterface { @@ -40,7 +41,7 @@ class CommandLineInterface { val (_, instantiator, _) = Backend.fromContext(context, cacheDir) val nodeAdder = NodeAdder(context, NodeInstantiator(instantiator, context)) parsedArgs.nodesToAdd.map { - nodeAdder.addNode(context, Constants.ALPHA_NUMERIC_ONLY_REGEX.replace(it.key.toLowerCase(), ""), CordaX500Name.parse(it.value)) + nodeAdder.addNode(context, Constants.ALPHA_NUMERIC_ONLY_REGEX.replace(it.key.lowercase(Locale.getDefault()), ""), CordaX500Name.parse(it.value)) }.toSingleFuture().getOrThrow() persistContext(contextFile, objectMapper, context) } diff --git a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/containers/push/azure/AzureContainerPusher.kt b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/containers/push/azure/AzureContainerPusher.kt index 940c92cc51..17e22768c6 100644 --- a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/containers/push/azure/AzureContainerPusher.kt +++ b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/containers/push/azure/AzureContainerPusher.kt @@ -8,6 +8,7 @@ import net.corda.networkbuilder.containers.push.azure.RegistryLocator.Companion. import net.corda.networkbuilder.docker.DockerUtils import org.slf4j.LoggerFactory import java.io.Closeable +import java.util.Locale import java.util.concurrent.CompletableFuture class AzureContainerPusher(private val azureRegistry: Registry) : ContainerPusher { @@ -22,7 +23,7 @@ class AzureContainerPusher(private val azureRegistry: Registry) : ContainerPushe registryUser, registryPassword) - val privateRepoUrl = "${azureRegistry.loginServerUrl()}/$remoteImageName".toLowerCase() + val privateRepoUrl = "${azureRegistry.loginServerUrl()}/$remoteImageName".lowercase(Locale.getDefault()) dockerClient.tagImageCmd(localImageId, privateRepoUrl, networkName).exec() val result = CompletableFuture() dockerClient.pushImageCmd("$privateRepoUrl:$networkName") diff --git a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/context/Context.kt b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/context/Context.kt index 1189013be9..8af2ffcfbd 100644 --- a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/context/Context.kt +++ b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/context/Context.kt @@ -5,12 +5,13 @@ import net.corda.networkbuilder.Constants import net.corda.networkbuilder.backends.Backend import net.corda.networkbuilder.nodes.NodeInstanceRequest import org.apache.activemq.artemis.utils.collections.ConcurrentHashSet +import java.util.Locale import java.util.concurrent.ConcurrentHashMap class Context(val networkName: String, val backendType: Backend.BackendType, backendOptions: Map = emptyMap()) { @Volatile - var safeNetworkName: String = networkName.replace(Constants.ALPHA_NUMERIC_ONLY_REGEX, "").toLowerCase() + var safeNetworkName: String = networkName.replace(Constants.ALPHA_NUMERIC_ONLY_REGEX, "").lowercase(Locale.getDefault()) @Volatile var nodes: MutableMap> = ConcurrentHashMap() diff --git a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/nodes/FoundNode.kt b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/nodes/FoundNode.kt index 3fc427d653..f346b1cf05 100644 --- a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/nodes/FoundNode.kt +++ b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/nodes/FoundNode.kt @@ -2,10 +2,11 @@ package net.corda.networkbuilder.nodes import net.corda.networkbuilder.Constants import java.io.File +import java.util.Locale open class FoundNode(open val configFile: File, open val baseDirectory: File = configFile.parentFile, - val name: String = configFile.parentFile.name.toLowerCase().replace(Constants.ALPHA_NUMERIC_ONLY_REGEX, "")) { + val name: String = configFile.parentFile.name.lowercase(Locale.getDefault()).replace(Constants.ALPHA_NUMERIC_ONLY_REGEX, "")) { operator fun component1(): File { return baseDirectory diff --git a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/nodes/NodeCopier.kt b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/nodes/NodeCopier.kt index c94888bd7f..d650927659 100644 --- a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/nodes/NodeCopier.kt +++ b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/nodes/NodeCopier.kt @@ -3,24 +3,24 @@ package net.corda.networkbuilder.nodes import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigRenderOptions import com.typesafe.config.ConfigValue -import net.corda.core.internal.div -import org.slf4j.LoggerFactory +import net.corda.core.utilities.contextLogger import java.io.File import java.nio.file.Files import java.nio.file.Path +import kotlin.io.path.div open class NodeCopier(private val cacheDir: File) { fun copyNode(foundNode: FoundNode): CopiedNode { val nodeCacheDir = File(cacheDir, foundNode.baseDirectory.name) nodeCacheDir.deleteRecursively() - LOG.info("copying: ${foundNode.baseDirectory} to $nodeCacheDir") + log.info("copying: ${foundNode.baseDirectory} to $nodeCacheDir") foundNode.baseDirectory.copyRecursively(nodeCacheDir, overwrite = true) //docker-java lib doesn't copy an empty folder, so if it's empty add a dummy file ensureDirectoryIsNonEmpty(nodeCacheDir.toPath() / ("cordapps")) copyBootstrapperFiles(nodeCacheDir) val configInCacheDir = File(nodeCacheDir, "node.conf") - LOG.info("Applying precanned config $configInCacheDir") + log.info("Applying precanned config $configInCacheDir") val rpcSettings = getDefaultRpcSettings() val sshSettings = getDefaultSshSettings() mergeConfigs(configInCacheDir, rpcSettings, sshSettings) @@ -28,21 +28,21 @@ open class NodeCopier(private val cacheDir: File) { } fun copyBootstrapperFiles(nodeCacheDir: File) { - this.javaClass.classLoader.getResourceAsStream("node-Dockerfile").use { nodeDockerFileInStream -> + this.javaClass.classLoader.getResourceAsStream("node-Dockerfile")!!.use { nodeDockerFileInStream -> val nodeDockerFile = File(nodeCacheDir, "Dockerfile") nodeDockerFile.outputStream().use { nodeDockerFileOutStream -> nodeDockerFileInStream.copyTo(nodeDockerFileOutStream) } } - this.javaClass.classLoader.getResourceAsStream("run-corda-node.sh").use { nodeRunScriptInStream -> + this.javaClass.classLoader.getResourceAsStream("run-corda-node.sh")!!.use { nodeRunScriptInStream -> val nodeRunScriptFile = File(nodeCacheDir, "run-corda.sh") nodeRunScriptFile.outputStream().use { nodeDockerFileOutStream -> nodeRunScriptInStream.copyTo(nodeDockerFileOutStream) } } - this.javaClass.classLoader.getResourceAsStream("node_info_watcher.sh").use { nodeRunScriptInStream -> + this.javaClass.classLoader.getResourceAsStream("node_info_watcher.sh")!!.use { nodeRunScriptInStream -> val nodeInfoWatcherFile = File(nodeCacheDir, "node_info_watcher.sh") nodeInfoWatcherFile.outputStream().use { nodeDockerFileOutStream -> nodeRunScriptInStream.copyTo(nodeDockerFileOutStream) @@ -53,7 +53,7 @@ open class NodeCopier(private val cacheDir: File) { internal fun getDefaultRpcSettings(): ConfigValue { return javaClass .classLoader - .getResourceAsStream("rpc-settings.conf") + .getResourceAsStream("rpc-settings.conf")!! .reader().use { ConfigFactory.parseReader(it) }.getValue("rpcSettings") @@ -62,7 +62,7 @@ open class NodeCopier(private val cacheDir: File) { internal fun getDefaultSshSettings(): ConfigValue { return javaClass .classLoader - .getResourceAsStream("ssh.conf") + .getResourceAsStream("ssh.conf")!! .reader().use { ConfigFactory.parseReader(it) }.getValue("sshd") @@ -106,6 +106,6 @@ open class NodeCopier(private val cacheDir: File) { } companion object { - val LOG = LoggerFactory.getLogger(NodeCopier::class.java) + private val log = contextLogger() } } \ No newline at end of file diff --git a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/nodes/NodeInstantiator.kt b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/nodes/NodeInstantiator.kt index fe404a524a..e287e9ad42 100644 --- a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/nodes/NodeInstantiator.kt +++ b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/nodes/NodeInstantiator.kt @@ -5,6 +5,7 @@ import net.corda.networkbuilder.Constants import net.corda.networkbuilder.containers.instance.InstanceInfo import net.corda.networkbuilder.containers.instance.Instantiator import net.corda.networkbuilder.context.Context +import java.util.Locale import java.util.concurrent.CompletableFuture class NodeInstantiator(val instantiator: Instantiator, @@ -12,9 +13,9 @@ class NodeInstantiator(val instantiator: Instantiator, fun createInstanceRequests(pushedNode: PushedNode, nodeCount: Map): List { - val namedMap = nodeCount.map { it.key.name.toLowerCase() to it.value }.toMap() + val namedMap = nodeCount.map { it.key.name.lowercase(Locale.getDefault()) to it.value }.toMap() - return (0 until (namedMap[pushedNode.name.toLowerCase()] ?: 1)).map { i -> + return (0 until (namedMap[pushedNode.name.lowercase(Locale.getDefault())] ?: 1)).map { i -> createInstanceRequest(pushedNode, i) } } diff --git a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/notaries/NotaryCopier.kt b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/notaries/NotaryCopier.kt index 7e4210d144..fb9af9fd67 100644 --- a/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/notaries/NotaryCopier.kt +++ b/tools/network-builder/src/main/kotlin/net/corda/networkbuilder/notaries/NotaryCopier.kt @@ -1,12 +1,12 @@ package net.corda.networkbuilder.notaries -import net.corda.core.internal.div import net.corda.networkbuilder.nodes.CopiedNode import net.corda.networkbuilder.nodes.FoundNode import net.corda.networkbuilder.nodes.NodeCopier import org.slf4j.LoggerFactory import java.io.File import java.nio.file.Paths +import kotlin.io.path.div class NotaryCopier(private val cacheDir: File) : NodeCopier(cacheDir) { @@ -16,7 +16,7 @@ class NotaryCopier(private val cacheDir: File) : NodeCopier(cacheDir) { LOG.info("copying: ${foundNotary.baseDirectory} to $nodeCacheDir") foundNotary.baseDirectory.copyRecursively(nodeCacheDir, overwrite = true) //docker-java lib doesn't copy an empty folder, so if it's empty add a dummy file - ensureDirectoryIsNonEmpty(nodeCacheDir.toPath() / ("cordapps")) + ensureDirectoryIsNonEmpty(nodeCacheDir.toPath() / "cordapps") copyNotaryBootstrapperFiles(nodeCacheDir) val configInCacheDir = File(nodeCacheDir, "node.conf") LOG.info("Applying precanned config $configInCacheDir") diff --git a/tools/worldmap/build.gradle b/tools/worldmap/build.gradle index 0558f837ba..a66632496a 100644 --- a/tools/worldmap/build.gradle +++ b/tools/worldmap/build.gradle @@ -1,8 +1,7 @@ -apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.kotlin.jvm' dependencies { implementation project(':core') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" testImplementation "org.jetbrains.kotlin:kotlin-test-junit" testImplementation "junit:junit:$junit_version" diff --git a/tools/worldmap/src/main/kotlin/net/corda/worldmap/PhysicalLocationStructures.kt b/tools/worldmap/src/main/kotlin/net/corda/worldmap/PhysicalLocationStructures.kt index 9b4e814aac..7edbc4ee0d 100644 --- a/tools/worldmap/src/main/kotlin/net/corda/worldmap/PhysicalLocationStructures.kt +++ b/tools/worldmap/src/main/kotlin/net/corda/worldmap/PhysicalLocationStructures.kt @@ -9,8 +9,11 @@ data class ScreenCoordinate(val screenX: Double, val screenY: Double) @CordaSerializable data class WorldCoordinate(val latitude: Double, val longitude: Double) { init { - require(latitude in -90..90){"Latitude must be between -90 and +90"} - require(longitude in -180..180){"Longitude must be between -180 and +180"} + @Suppress("MagicNumber") + require(latitude in -90.0..90.0){"Latitude must be between -90 and +90"} + + @Suppress("MagicNumber") + require(longitude in -180.0..180.0){"Longitude must be between -180 and +180"} } /** @@ -63,11 +66,11 @@ object CityDatabase { val matchResult = matcher.matchEntire(name) ?: throw Exception("Could not parse line: $line") val (city, country) = matchResult.destructured val location = WorldMapLocation(WorldCoordinate(lat.toDouble(), lng.toDouble()), city, country) - caseInsensitiveLookups[city.toLowerCase()] = location + caseInsensitiveLookups[city.lowercase(Locale.getDefault())] = location cityMap[city] = location } } } - operator fun get(name: String) = caseInsensitiveLookups[name.toLowerCase()] + operator fun get(name: String) = caseInsensitiveLookups[name.lowercase(Locale.getDefault())] } diff --git a/verifier/README.md b/verifier/README.md new file mode 100644 index 0000000000..7427a3f7f9 --- /dev/null +++ b/verifier/README.md @@ -0,0 +1,6 @@ +This is the external verifier process, which the node kicks off when it needs to verify transactions which itself can't. This will be mainly +due to differences in the Kotlin version used in the transaction contract compared to the Kotlin version used by the node. + +This module is built with Kotlin 1.2 and so is only able to verify transactions which have contracts compiled with Kotlin 1.2. It relies on +specially compiled versions of `core` and `serialization` also compiled with Kotlin 1.2 (`core-1.2` and `serialization-1.2` respectively) +to ensure compatibility. diff --git a/verifier/build.gradle b/verifier/build.gradle new file mode 100644 index 0000000000..74e9451c66 --- /dev/null +++ b/verifier/build.gradle @@ -0,0 +1,18 @@ +plugins { + id "corda.kotlin-1.2" + id "application" + id "com.github.johnrengelman.shadow" +} + +application { + mainClass.set("net.corda.verifier.Main") +} + +dependencies { + implementation project(":core-1.2") + implementation project(":serialization-1.2") + implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version" + implementation "org.slf4j:jul-to-slf4j:$slf4j_version" + + runtimeOnly "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version" +} diff --git a/verifier/src/main/kotlin/net/corda/verifier/ExternalVerificationContext.kt b/verifier/src/main/kotlin/net/corda/verifier/ExternalVerificationContext.kt new file mode 100644 index 0000000000..c410564c0a --- /dev/null +++ b/verifier/src/main/kotlin/net/corda/verifier/ExternalVerificationContext.kt @@ -0,0 +1,42 @@ +package net.corda.verifier + +import net.corda.core.contracts.Attachment +import net.corda.core.contracts.StateRef +import net.corda.core.crypto.SecureHash +import net.corda.core.identity.Party +import net.corda.core.internal.SerializedTransactionState +import net.corda.core.internal.verification.VerificationSupport +import net.corda.core.node.NetworkParameters +import net.corda.core.serialization.internal.AttachmentsClassLoaderCache +import java.security.PublicKey + +class ExternalVerificationContext( + override val appClassLoader: ClassLoader, + override val attachmentsClassLoaderCache: AttachmentsClassLoaderCache, + private val externalVerifier: ExternalVerifier, + private val transactionInputsAndReferences: Map +) : VerificationSupport { + override val isInProcess: Boolean get() = false + + override fun getParties(keys: Collection): List = externalVerifier.getParties(keys) + + override fun getAttachment(id: SecureHash): Attachment? = externalVerifier.getAttachment(id)?.attachment + + override fun getAttachments(ids: Collection): List { + return externalVerifier.getAttachments(ids).map { it?.attachment } + } + + override fun isAttachmentTrusted(attachment: Attachment): Boolean = externalVerifier.getAttachment(attachment.id)!!.isTrusted + + override fun getTrustedClassAttachments(className: String): List { + return externalVerifier.getTrustedClassAttachments(className) + } + + override fun getNetworkParameters(id: SecureHash?): NetworkParameters? = externalVerifier.getNetworkParameters(id) + + override fun getSerializedState(stateRef: StateRef): SerializedTransactionState = transactionInputsAndReferences.getValue(stateRef) + + override fun fixupAttachmentIds(attachmentIds: Collection): Set { + return externalVerifier.fixupAttachmentIds(attachmentIds) + } +} diff --git a/verifier/src/main/kotlin/net/corda/verifier/ExternalVerifier.kt b/verifier/src/main/kotlin/net/corda/verifier/ExternalVerifier.kt new file mode 100644 index 0000000000..398266f33f --- /dev/null +++ b/verifier/src/main/kotlin/net/corda/verifier/ExternalVerifier.kt @@ -0,0 +1,240 @@ +package net.corda.verifier + +import com.github.benmanes.caffeine.cache.Cache +import net.corda.core.contracts.Attachment +import net.corda.core.crypto.SecureHash +import net.corda.core.identity.Party +import net.corda.core.internal.loadClassOfType +import net.corda.core.internal.mapToSet +import net.corda.core.internal.objectOrNewInstance +import net.corda.core.internal.toSimpleString +import net.corda.core.internal.toSynchronised +import net.corda.core.internal.toTypedArray +import net.corda.core.internal.verification.AttachmentFixups +import net.corda.core.node.NetworkParameters +import net.corda.core.serialization.SerializationContext +import net.corda.core.serialization.internal.AttachmentsClassLoaderCache +import net.corda.core.serialization.internal.AttachmentsClassLoaderCacheImpl +import net.corda.core.serialization.internal.SerializationEnvironment +import net.corda.core.serialization.internal._contextSerializationEnv +import net.corda.core.transactions.ContractUpgradeWireTransaction +import net.corda.core.transactions.WireTransaction +import net.corda.core.utilities.Try +import net.corda.core.utilities.contextLogger +import net.corda.core.utilities.debug +import net.corda.serialization.internal.AMQP_P2P_CONTEXT +import net.corda.serialization.internal.CordaSerializationMagic +import net.corda.serialization.internal.SerializationFactoryImpl +import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme +import net.corda.serialization.internal.amqp.AccessOrderLinkedHashMap +import net.corda.serialization.internal.amqp.SerializationFactoryCacheKey +import net.corda.serialization.internal.amqp.SerializerFactory +import net.corda.serialization.internal.amqp.amqpMagic +import net.corda.serialization.internal.verifier.AttachmentWithTrust +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.AttachmentResult +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.AttachmentsResult +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.Initialisation +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.NetworkParametersResult +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.PartiesResult +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.TrustedClassAttachmentsResult +import net.corda.serialization.internal.verifier.ExternalVerifierInbound.VerificationRequest +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerificationResult +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerifierRequest.GetAttachment +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerifierRequest.GetAttachments +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerifierRequest.GetNetworkParameters +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerifierRequest.GetParties +import net.corda.serialization.internal.verifier.ExternalVerifierOutbound.VerifierRequest.GetTrustedClassAttachments +import net.corda.serialization.internal.verifier.loadCustomSerializationScheme +import net.corda.serialization.internal.verifier.readCordaSerializable +import net.corda.serialization.internal.verifier.writeCordaSerializable +import java.net.URLClassLoader +import java.nio.channels.SocketChannel +import java.nio.file.Path +import java.security.PublicKey +import java.util.Optional +import kotlin.io.path.div +import kotlin.io.path.listDirectoryEntries + +@Suppress("MagicNumber") +class ExternalVerifier(private val baseDirectory: Path, private val channel: SocketChannel) { + companion object { + private val log = contextLogger() + } + + private val attachmentsClassLoaderCache: AttachmentsClassLoaderCache + private val attachmentFixups = AttachmentFixups() + private val parties: OptionalCache + private val attachments: OptionalCache + private val networkParametersMap: OptionalCache + private val trustedClassAttachments: Cache> + + private lateinit var appClassLoader: ClassLoader + private lateinit var currentNetworkParameters: NetworkParameters + + init { + val cacheFactory = ExternalVerifierNamedCacheFactory() + attachmentsClassLoaderCache = AttachmentsClassLoaderCacheImpl(cacheFactory) + parties = cacheFactory.buildNamed("ExternalVerifier_parties") + attachments = cacheFactory.buildNamed("ExternalVerifier_attachments") + networkParametersMap = cacheFactory.buildNamed("ExternalVerifier_networkParameters") + trustedClassAttachments = cacheFactory.buildNamed("ExternalVerifier_trustedClassAttachments") + } + + fun run() { + initialise() + while (true) { + val request = channel.readCordaSerializable(VerificationRequest::class) + log.debug { "Received $request" } + verifyTransaction(request) + } + } + + private fun initialise() { + // Use a preliminary serialization context to receive the initialisation message + _contextSerializationEnv.set(SerializationEnvironment.with( + verifierSerializationFactory(), + p2pContext = AMQP_P2P_CONTEXT + )) + + log.info("Waiting for initialisation message from node...") + val initialisation = channel.readCordaSerializable(Initialisation::class) + log.info("Received $initialisation") + + appClassLoader = createAppClassLoader() + + // Then use the initialisation message to create the correct serialization context + _contextSerializationEnv.set(null) + _contextSerializationEnv.set(SerializationEnvironment.with( + verifierSerializationFactory(initialisation, appClassLoader).apply { + initialisation.customSerializationSchemeClassName?.let { + registerScheme(loadCustomSerializationScheme(it, appClassLoader)) + } + }, + p2pContext = AMQP_P2P_CONTEXT.withClassLoader(appClassLoader) + )) + + attachmentFixups.load(appClassLoader) + + currentNetworkParameters = initialisation.currentNetworkParameters + networkParametersMap.put(initialisation.serializedCurrentNetworkParameters.hash, Optional.of(currentNetworkParameters)) + + log.info("External verifier initialised") + } + + private fun createAppClassLoader(): ClassLoader { + val cordappJarUrls = (baseDirectory / "cordapps").listDirectoryEntries("*.jar") + .stream() + .map { it.toUri().toURL() } + .toTypedArray() + log.debug { "CorDapps: ${cordappJarUrls?.joinToString()}" } + return URLClassLoader(cordappJarUrls, javaClass.classLoader) + } + + @Suppress("INVISIBLE_MEMBER") + private fun verifyTransaction(request: VerificationRequest) { + val verificationContext = ExternalVerificationContext(appClassLoader, attachmentsClassLoaderCache, this, request.ctxInputsAndReferences) + val result: Try = try { + val ctx = request.ctx + when (ctx) { + is WireTransaction -> ctx.verifyInProcess(verificationContext) + is ContractUpgradeWireTransaction -> ctx.verifyInProcess(verificationContext) + else -> throw IllegalArgumentException("${ctx.toSimpleString()} not supported") + } + log.info("${ctx.toSimpleString()} verified") + Try.Success(Unit) + } catch (t: Throwable) { + log.info("${request.ctx.toSimpleString()} failed to verify", t) + Try.Failure(t) + } + channel.writeCordaSerializable(VerificationResult(result)) + } + + fun getParties(keys: Collection): List { + return parties.retrieveAll(keys) { + request(GetParties(it)).parties + } + } + + fun getAttachment(id: SecureHash): AttachmentWithTrust? { + return attachments.retrieve(id) { + request(GetAttachment(id)).attachment + } + } + + fun getAttachments(ids: Collection): List { + return attachments.retrieveAll(ids) { + request(GetAttachments(it)).attachments + } + } + + fun getTrustedClassAttachments(className: String): List { + val attachmentIds = trustedClassAttachments.get(className) { + // GetTrustedClassAttachments returns back the attachment IDs, not the whole attachments. This lets us avoid downloading the + // entire attachments again if we already have them. + request(GetTrustedClassAttachments(className)).ids + }!! + return attachmentIds.map { getAttachment(it)!!.attachment } + } + + fun getNetworkParameters(id: SecureHash?): NetworkParameters? { + return if (id == null) { + currentNetworkParameters + } else { + networkParametersMap.retrieve(id) { + request(GetNetworkParameters(id)).networkParameters + } + } + } + + fun fixupAttachmentIds(attachmentIds: Collection): Set = attachmentFixups.fixupAttachmentIds(attachmentIds) + + private inline fun request(request: Any): T { + log.debug { "Sending request to node: $request" } + channel.writeCordaSerializable(request) + val response = channel.readCordaSerializable(T::class) + log.debug { "Received response from node: $response" } + return response + } + + private fun verifierSerializationFactory(initialisation: Initialisation? = null, classLoader: ClassLoader? = null): SerializationFactoryImpl { + val serializationFactory = SerializationFactoryImpl() + serializationFactory.registerScheme(AMQPVerifierSerializationScheme(initialisation, classLoader)) + return serializationFactory + } + + + private class AMQPVerifierSerializationScheme(initialisation: Initialisation?, classLoader: ClassLoader?) : AbstractAMQPSerializationScheme( + initialisation?.customSerializerClassNames.load(classLoader), + initialisation?.serializationWhitelistClassNames.load(classLoader), + AccessOrderLinkedHashMap(128).toSynchronised() + ) { + override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean { + return magic == amqpMagic && target == SerializationContext.UseCase.P2P + } + + override fun rpcClientSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException() + override fun rpcServerSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException() + + companion object { + inline fun Set?.load(classLoader: ClassLoader?): Set { + return this?.mapToSet { loadClassOfType(it, classLoader = classLoader).kotlin.objectOrNewInstance() } ?: emptySet() + } + } + } +} + +private typealias OptionalCache = Cache> + +private fun OptionalCache.retrieve(key: K, request: () -> V?): V? { + return get(key) { Optional.ofNullable(request()) }!!.orElse(null) +} + +@Suppress("UNCHECKED_CAST") +private fun OptionalCache.retrieveAll(keys: Collection, request: (Set) -> List): List { + val optionalResults = getAll(keys) { + val missingKeys = if (it is Set<*>) it as Set else it.toSet() + val response = request(missingKeys) + missingKeys.zip(response) { key, value -> key to Optional.ofNullable(value) }.toMap() + } + return keys.map { optionalResults.getValue(it).orElse(null) } +} diff --git a/verifier/src/main/kotlin/net/corda/verifier/ExternalVerifierNamedCacheFactory.kt b/verifier/src/main/kotlin/net/corda/verifier/ExternalVerifierNamedCacheFactory.kt new file mode 100644 index 0000000000..b147eebd34 --- /dev/null +++ b/verifier/src/main/kotlin/net/corda/verifier/ExternalVerifierNamedCacheFactory.kt @@ -0,0 +1,35 @@ +package net.corda.verifier + +import com.github.benmanes.caffeine.cache.Cache +import com.github.benmanes.caffeine.cache.CacheLoader +import com.github.benmanes.caffeine.cache.Caffeine +import com.github.benmanes.caffeine.cache.LoadingCache +import net.corda.core.internal.NamedCacheFactory + +@Suppress("MagicNumber") +class ExternalVerifierNamedCacheFactory : NamedCacheFactory { + companion object { + private const val DEFAULT_CACHE_SIZE = 1024L + } + + override fun buildNamed(caffeine: Caffeine, name: String): Cache { + checkCacheName(name) + return configure(caffeine, name).build() + } + + override fun buildNamed(caffeine: Caffeine, name: String, loader: CacheLoader): LoadingCache { + checkCacheName(name) + return configure(caffeine, name).build(loader) + } + + private fun configure(caffeine: Caffeine, name: String): Caffeine { + return when (name) { + "AttachmentsClassLoader_cache" -> caffeine.maximumSize(32) + "ExternalVerifier_parties" -> caffeine.maximumSize(DEFAULT_CACHE_SIZE) + "ExternalVerifier_attachments" -> caffeine.maximumSize(DEFAULT_CACHE_SIZE) + "ExternalVerifier_networkParameters" -> caffeine.maximumSize(DEFAULT_CACHE_SIZE) + "ExternalVerifier_trustedClassAttachments" -> caffeine.maximumSize(DEFAULT_CACHE_SIZE) + else -> throw IllegalArgumentException("Unexpected cache name $name. Did you add a new cache?") + } + } +} diff --git a/verifier/src/main/kotlin/net/corda/verifier/Main.kt b/verifier/src/main/kotlin/net/corda/verifier/Main.kt new file mode 100644 index 0000000000..bce3847375 --- /dev/null +++ b/verifier/src/main/kotlin/net/corda/verifier/Main.kt @@ -0,0 +1,43 @@ +package net.corda.verifier + +import net.corda.core.utilities.loggerFor +import org.slf4j.bridge.SLF4JBridgeHandler +import java.net.StandardProtocolFamily +import java.net.UnixDomainSocketAddress +import java.nio.channels.SocketChannel +import java.nio.file.Path +import kotlin.io.path.div +import kotlin.system.exitProcess + +object Main { + @JvmStatic + fun main(args: Array) { + val socketFile = args[0] + val loggingLevel = args[1] + val baseDirectory = Path.of("").toAbsolutePath() + + initLogging(baseDirectory, loggingLevel) + val log = loggerFor
    () + + log.info("External verifier started; PID ${ProcessHandle.current().pid()}") + log.info("Node base directory: $baseDirectory") + + try { + val channel = SocketChannel.open(StandardProtocolFamily.UNIX) + channel.connect(UnixDomainSocketAddress.of(socketFile)) + log.info("Connected to node on UNIX domain file $socketFile") + ExternalVerifier(baseDirectory, channel).run() + } catch (t: Throwable) { + log.error("Unexpected error which has terminated the verifier", t) + exitProcess(1) + } + } + + private fun initLogging(baseDirectory: Path, loggingLevel: String) { + System.setProperty("logPath", (baseDirectory / "logs").toString()) + System.setProperty("defaultLogLevel", loggingLevel) + + SLF4JBridgeHandler.removeHandlersForRootLogger() // The default j.u.l config adds a ConsoleHandler. + SLF4JBridgeHandler.install() + } +} diff --git a/verifier/src/main/resources/log4j2.xml b/verifier/src/main/resources/log4j2.xml new file mode 100644 index 0000000000..684820a3df --- /dev/null +++ b/verifier/src/main/resources/log4j2.xml @@ -0,0 +1,44 @@ + + + + + ${sys:logPath:-logs} + verifier-${hostName} + ${log_path}/archive + ${sys:defaultLogLevel:-info} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • EDDSA_ED25519_SHA512 (EdDSA using the ed25519 twisted Edwards curve and SHA512 as hash algorithm). * */ object Crypto { @@ -95,7 +89,7 @@ object Crypto { listOf(AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, null)), cordaBouncyCastleProvider.name, "RSA", - "SHA256WITHRSA", + "SHA256withRSA", null, 3072, "RSA_SHA256 signature scheme using SHA256 as hash algorithm." @@ -140,13 +134,12 @@ object Crypto { val EDDSA_ED25519_SHA512: SignatureScheme = SignatureScheme( 4, "EDDSA_ED25519_SHA512", - AlgorithmIdentifier(`id-Curve25519ph`, null), - emptyList(), // Both keys and the signature scheme use the same OID in i2p library. - // We added EdDSA to bouncy castle for certificate signing. + AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519, null), + emptyList(), // Both keys and the signature scheme use the same OID. cordaBouncyCastleProvider.name, - "1.3.101.112", - EdDSAEngine.SIGNATURE_ALGORITHM, - EdDSANamedCurveTable.getByName("ED25519"), + "Ed25519", + "Ed25519", + EdDSAParameterSpec(EdDSAParameterSpec.Ed25519), 256, "EdDSA signature scheme using the ed25519 twisted Edwards curve." ) @@ -155,26 +148,6 @@ object Crypto { @JvmField val SHA512_256 = DLSequence(arrayOf(NISTObjectIdentifiers.id_sha512_256)) - /** - * SPHINCS-256 hash-based signature scheme using SHA512 for message hashing. It provides 128bit security against - * post-quantum attackers at the cost of larger key nd signature sizes and loss of compatibility. - */ - // TODO: change val name to SPHINCS256_SHA512. This will break backwards compatibility. - @JvmField - val SPHINCS256_SHA256 = SignatureScheme( - 5, - "SPHINCS-256_SHA512", - AlgorithmIdentifier(BCObjectIdentifiers.sphincs256_with_SHA512, DLSequence(arrayOf(ASN1Integer(0), SHA512_256))), - listOf(AlgorithmIdentifier(BCObjectIdentifiers.sphincs256, DLSequence(arrayOf(ASN1Integer(0), SHA512_256)))), - bouncyCastlePQCProvider.name, - "SPHINCS256", - "SHA512WITHSPHINCS256", - SPHINCS256KeyGenParameterSpec(SPHINCS256KeyGenParameterSpec.SHA512_256), - 256, - "SPHINCS-256 hash-based signature scheme. It provides 128bit security against post-quantum attackers " + - "at the cost of larger key sizes and loss of compatibility." - ) - /** Corda [CompositeKey] signature type. */ // TODO: change the val name to a more descriptive one as it's now confusing and looks like a Key type. @JvmField @@ -204,7 +177,6 @@ object Crypto { ECDSA_SECP256K1_SHA256, ECDSA_SECP256R1_SHA256, EDDSA_ED25519_SHA512, - SPHINCS256_SHA256, COMPOSITE_KEY ).associateBy { it.schemeCodeName } @@ -244,8 +216,9 @@ object Crypto { @JvmStatic fun findSignatureScheme(algorithm: AlgorithmIdentifier): SignatureScheme { - return algorithmMap[normaliseAlgorithmIdentifier(algorithm)] - ?: throw IllegalArgumentException("Unrecognised algorithm: ${algorithm.algorithm.id}") + return requireNotNull(algorithmMap[normaliseAlgorithmIdentifier(algorithm)]) { + "Unrecognised algorithm identifier: ${algorithm.algorithm} ${algorithm.parameters}" + } } /** Find [SignatureScheme] by platform specific schemeNumberID. */ @@ -307,12 +280,11 @@ object Crypto { @JvmStatic fun decodePrivateKey(encodedKey: ByteArray): PrivateKey { val keyInfo = PrivateKeyInfo.getInstance(encodedKey) - if (keyInfo.privateKeyAlgorithm.algorithm == ASN1ObjectIdentifier(CordaOID.ALIAS_PRIVATE_KEY)) { - return convertIfBCEdDSAPrivateKey(decodeAliasPrivateKey(keyInfo)) + return if (keyInfo.privateKeyAlgorithm.algorithm == ASN1ObjectIdentifier(CordaOID.ALIAS_PRIVATE_KEY)) { + decodeAliasPrivateKey(keyInfo) + } else { + findSignatureScheme(keyInfo.privateKeyAlgorithm).keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey)) } - val signatureScheme = findSignatureScheme(keyInfo.privateKeyAlgorithm) - val keyFactory = keyFactory(signatureScheme) - return convertIfBCEdDSAPrivateKey(keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey))) } private fun decodeAliasPrivateKey(keyInfo: PrivateKeyInfo): PrivateKey { @@ -351,8 +323,7 @@ object Crypto { "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" } try { - val keyFactory = keyFactory(signatureScheme) - return convertIfBCEdDSAPrivateKey(keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey))) + return signatureScheme.keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey)) } catch (ikse: InvalidKeySpecException) { throw InvalidKeySpecException("This private key cannot be decoded, please ensure it is PKCS8 encoded and that " + "it corresponds to the input scheme's code name.", ikse) @@ -368,12 +339,11 @@ object Crypto { */ @JvmStatic fun decodePublicKey(encodedKey: ByteArray): PublicKey { - return PublicKeyCache.publicKeyForCachedBytes(ByteSequence.of(encodedKey)) ?: { + return PublicKeyCache.publicKeyForCachedBytes(ByteSequence.of(encodedKey)) ?: run { val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(encodedKey) val signatureScheme = findSignatureScheme(subjectPublicKeyInfo.algorithm) - val keyFactory = keyFactory(signatureScheme) - convertIfBCEdDSAPublicKey(keyFactory.generatePublic(X509EncodedKeySpec(encodedKey))) - }() + internPublicKey(signatureScheme.keyFactory.generatePublic(X509EncodedKeySpec(encodedKey))) + } } @JvmStatic @@ -412,8 +382,7 @@ object Crypto { "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" } try { - val keyFactory = keyFactory(signatureScheme) - return convertIfBCEdDSAPublicKey(keyFactory.generatePublic(X509EncodedKeySpec(encodedKey))) + return signatureScheme.keyFactory.generatePublic(X509EncodedKeySpec(encodedKey)) } catch (ikse: InvalidKeySpecException) { throw InvalidKeySpecException("This public key cannot be decoded, please ensure it is X509 encoded and " + "that it corresponds to the input scheme's code name.", ikse) @@ -471,12 +440,8 @@ object Crypto { return withSignature(signatureScheme) { signature -> // Note that deterministic signature schemes, such as EdDSA, original SPHINCS-256 and RSA PKCS#1, do not require // extra randomness, but we have to ensure that non-deterministic algorithms (i.e., ECDSA) use non-blocking - // SecureRandom implementation. Also, SPHINCS-256 implementation in BouncyCastle 1.60 fails with - // ClassCastException if we invoke initSign with a SecureRandom as an input. - // TODO Although we handle the above issue here, consider updating to BC 1.61+ which provides a fix. - if (signatureScheme == EDDSA_ED25519_SHA512 - || signatureScheme == SPHINCS256_SHA256 - || signatureScheme == RSA_SHA256) { + // SecureRandom implementation. + if (signatureScheme == EDDSA_ED25519_SHA512 || signatureScheme == RSA_SHA256) { signature.initSign(privateKey) } else { // The rest of the algorithms will require a SecureRandom input (i.e., ECDSA or any new algorithm for which @@ -716,8 +681,7 @@ object Crypto { * This operation is currently supported for ECDSA secp256r1 (NIST P-256), ECDSA secp256k1 and EdDSA ed25519. * * Similarly to BIP32, the implemented algorithm uses an HMAC function based on SHA512 and it is actually - * an implementation the HKDF rfc - Step 1: Extract function, - * @see HKDF + * an implementation of the [HKDF rfc - Step 1: Extract function](https://tools.ietf.org/html/rfc5869), * which is practically a variation of the private-parent-key -> private-child-key hardened key generation of BIP32. * * Unlike BIP32, where both private and public keys are extended to prevent deterministically @@ -725,8 +689,8 @@ object Crypto { * without a chain-code and the generated key relies solely on the security of the private key. * * Although without a chain-code we lose the aforementioned property of not depending solely on the key, - * it should be mentioned that the cryptographic strength of the HMAC depends upon the size of the secret key. - * @see HMAC Security + * it should be mentioned that the cryptographic strength of the HMAC depends upon the size of the secret key + * (see [HMAC Security](https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Security)). * Thus, as long as the master key is kept secret and has enough entropy (~256 bits for EC-schemes), the system * is considered secure. * @@ -743,9 +707,9 @@ object Crypto { *