mirror of
https://github.com/corda/corda.git
synced 2025-01-30 16:14:39 +00:00
Moved the majority of the contents of Utils.kt into either InternalUtils.kt or KotlinUtils.kt.
What remains is being dealt with in another PR.
This commit is contained in:
parent
8acbd86c70
commit
407b467f67
@ -2,7 +2,7 @@ package net.corda.client.jfx
|
|||||||
|
|
||||||
import net.corda.client.jfx.model.NodeMonitorModel
|
import net.corda.client.jfx.model.NodeMonitorModel
|
||||||
import net.corda.client.jfx.model.ProgressTrackingEvent
|
import net.corda.client.jfx.model.ProgressTrackingEvent
|
||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.contracts.USD
|
import net.corda.core.contracts.USD
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.client.rpc.internal
|
package net.corda.client.rpc.internal
|
||||||
|
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.logElapsedTime
|
import net.corda.core.internal.logElapsedTime
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.serialization.SerializationContext
|
import net.corda.core.serialization.SerializationContext
|
||||||
import net.corda.core.serialization.SerializationDefaults
|
import net.corda.core.serialization.SerializationDefaults
|
||||||
|
@ -5,7 +5,7 @@ import com.google.common.hash.HashingInputStream
|
|||||||
import net.corda.client.rpc.CordaRPCConnection
|
import net.corda.client.rpc.CordaRPCConnection
|
||||||
import net.corda.client.rpc.notUsed
|
import net.corda.client.rpc.notUsed
|
||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.InputStreamAndHash
|
import net.corda.core.internal.InputStreamAndHash
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
package net.corda.core
|
|
||||||
|
|
||||||
import java.util.*
|
|
||||||
import java.util.Spliterator.*
|
|
||||||
import java.util.stream.IntStream
|
|
||||||
import java.util.stream.Stream
|
|
||||||
import java.util.stream.StreamSupport
|
|
||||||
import kotlin.streams.asSequence
|
|
||||||
|
|
||||||
private fun IntProgression.spliteratorOfInt(): Spliterator.OfInt {
|
|
||||||
val kotlinIterator = iterator()
|
|
||||||
val javaIterator = object : PrimitiveIterator.OfInt {
|
|
||||||
override fun nextInt() = kotlinIterator.nextInt()
|
|
||||||
override fun hasNext() = kotlinIterator.hasNext()
|
|
||||||
override fun remove() = throw UnsupportedOperationException("remove")
|
|
||||||
}
|
|
||||||
val spliterator = Spliterators.spliterator(
|
|
||||||
javaIterator,
|
|
||||||
(1 + (last - first) / step).toLong(),
|
|
||||||
SUBSIZED or IMMUTABLE or NONNULL or SIZED or ORDERED or SORTED or DISTINCT
|
|
||||||
)
|
|
||||||
return if (step > 0) spliterator else object : Spliterator.OfInt by spliterator {
|
|
||||||
override fun getComparator() = Comparator.reverseOrder<Int>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun IntProgression.stream(): IntStream = StreamSupport.intStream(spliteratorOfInt(), false)
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST") // When toArray has filled in the array, the component type is no longer T? but T (that may itself be nullable).
|
|
||||||
inline fun <reified T> Stream<out T>.toTypedArray() = toArray { size -> arrayOfNulls<T>(size) } as Array<T>
|
|
@ -1,49 +1,18 @@
|
|||||||
// TODO Move out the Kotlin specific stuff into a separate file
|
|
||||||
@file:JvmName("Utils")
|
@file:JvmName("Utils")
|
||||||
|
|
||||||
package net.corda.core
|
package net.corda.core
|
||||||
|
|
||||||
import com.google.common.base.Throwables
|
|
||||||
import com.google.common.io.ByteStreams
|
|
||||||
import com.google.common.util.concurrent.*
|
import com.google.common.util.concurrent.*
|
||||||
import net.corda.core.crypto.SecureHash
|
|
||||||
import net.corda.core.crypto.sha256
|
|
||||||
import net.corda.core.internal.createDirectories
|
|
||||||
import net.corda.core.internal.div
|
|
||||||
import net.corda.core.internal.write
|
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Observer
|
import rx.Observer
|
||||||
import rx.subjects.PublishSubject
|
|
||||||
import rx.subjects.UnicastSubject
|
|
||||||
import java.io.*
|
|
||||||
import java.math.BigDecimal
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.Path
|
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.ExecutionException
|
import java.util.concurrent.ExecutionException
|
||||||
import java.util.concurrent.Future
|
import java.util.concurrent.Future
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.zip.Deflater
|
|
||||||
import java.util.zip.ZipEntry
|
|
||||||
import java.util.zip.ZipInputStream
|
|
||||||
import java.util.zip.ZipOutputStream
|
|
||||||
|
|
||||||
// TODO: Review by EOY2016 if we ever found these utilities helpful.
|
// TODO Delete this file once the Future stuff is out of here
|
||||||
val Int.bd: BigDecimal get() = BigDecimal(this)
|
|
||||||
val Double.bd: BigDecimal get() = BigDecimal(this)
|
|
||||||
val String.bd: BigDecimal get() = BigDecimal(this)
|
|
||||||
val Long.bd: BigDecimal get() = BigDecimal(this)
|
|
||||||
|
|
||||||
fun String.abbreviate(maxWidth: Int): String = if (length <= maxWidth) this else take(maxWidth - 1) + "…"
|
|
||||||
|
|
||||||
/** Like the + operator but throws an exception in case of integer overflow. */
|
|
||||||
infix fun Int.checkedAdd(b: Int) = Math.addExact(this, b)
|
|
||||||
|
|
||||||
/** Like the + operator but throws an exception in case of integer overflow. */
|
|
||||||
@Suppress("unused")
|
|
||||||
infix fun Long.checkedAdd(b: Long) = Math.addExact(this, b)
|
|
||||||
|
|
||||||
/** Same as [Future.get] but with a more descriptive name, and doesn't throw [ExecutionException], instead throwing its cause */
|
/** Same as [Future.get] but with a more descriptive name, and doesn't throw [ExecutionException], instead throwing its cause */
|
||||||
fun <T> Future<T>.getOrThrow(timeout: Duration? = null): T {
|
fun <T> Future<T>.getOrThrow(timeout: Duration? = null): T {
|
||||||
@ -92,163 +61,6 @@ fun <A> ListenableFuture<out A>.toObservable(): Observable<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the index of the given item or throws [IllegalArgumentException] if not found. */
|
|
||||||
fun <T> List<T>.indexOfOrThrow(item: T): Int {
|
|
||||||
val i = indexOf(item)
|
|
||||||
require(i != -1)
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the single element matching the given [predicate], or `null` if element was not found,
|
|
||||||
* or throws if more than one element was found.
|
|
||||||
*/
|
|
||||||
fun <T> Iterable<T>.noneOrSingle(predicate: (T) -> Boolean): T? {
|
|
||||||
var single: T? = null
|
|
||||||
for (element in this) {
|
|
||||||
if (predicate(element)) {
|
|
||||||
if (single == null) {
|
|
||||||
single = element
|
|
||||||
} else throw IllegalArgumentException("Collection contains more than one matching element.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return single
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns single element, or `null` if element was not found, or throws if more than one element was found. */
|
|
||||||
fun <T> Iterable<T>.noneOrSingle(): T? {
|
|
||||||
var single: T? = null
|
|
||||||
for (element in this) {
|
|
||||||
if (single == null) {
|
|
||||||
single = element
|
|
||||||
} else throw IllegalArgumentException("Collection contains more than one matching element.")
|
|
||||||
}
|
|
||||||
return single
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a random element in the list, or null if empty */
|
|
||||||
fun <T> List<T>.randomOrNull(): T? {
|
|
||||||
if (size <= 1) return firstOrNull()
|
|
||||||
val randomIndex = (Math.random() * size).toInt()
|
|
||||||
return get(randomIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a random element in the list matching the given predicate, or null if none found */
|
|
||||||
fun <T> List<T>.randomOrNull(predicate: (T) -> Boolean) = filter(predicate).randomOrNull()
|
|
||||||
|
|
||||||
inline fun elapsedTime(block: () -> Unit): Duration {
|
|
||||||
val start = System.nanoTime()
|
|
||||||
block()
|
|
||||||
val end = System.nanoTime()
|
|
||||||
return Duration.ofNanos(end - start)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 <T> logElapsedTime(label: String, logger: Logger? = null, body: () -> T): T {
|
|
||||||
// Use nanoTime as it's monotonic.
|
|
||||||
val now = System.nanoTime()
|
|
||||||
try {
|
|
||||||
return body()
|
|
||||||
} finally {
|
|
||||||
val elapsed = Duration.ofNanos(System.nanoTime() - now).toMillis()
|
|
||||||
if (logger != null)
|
|
||||||
logger.info("$label took $elapsed msec")
|
|
||||||
else
|
|
||||||
println("$label took $elapsed msec")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> Logger.logElapsedTime(label: String, body: () -> T): T = logElapsedTime(label, this, body)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a path to a zip file, extracts it to the given directory.
|
|
||||||
*/
|
|
||||||
fun extractZipFile(zipFile: Path, toDirectory: Path) = extractZipFile(Files.newInputStream(zipFile), toDirectory)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a zip file input stream, extracts it to the given directory.
|
|
||||||
*/
|
|
||||||
fun extractZipFile(inputStream: InputStream, toDirectory: Path) {
|
|
||||||
val normalisedDirectory = toDirectory.normalize().createDirectories()
|
|
||||||
ZipInputStream(BufferedInputStream(inputStream)).use {
|
|
||||||
while (true) {
|
|
||||||
val e = it.nextEntry ?: break
|
|
||||||
val outPath = (normalisedDirectory / e.name).normalize()
|
|
||||||
|
|
||||||
// Security checks: we should reject a zip that contains tricksy paths that try to escape toDirectory.
|
|
||||||
check(outPath.startsWith(normalisedDirectory)) { "ZIP contained a path that resolved incorrectly: ${e.name}" }
|
|
||||||
|
|
||||||
if (e.isDirectory) {
|
|
||||||
outPath.createDirectories()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
outPath.write { out ->
|
|
||||||
ByteStreams.copy(it, out)
|
|
||||||
}
|
|
||||||
it.closeEntry()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convert a [ByteArrayOutputStream] to [InputStreamAndHash]. */
|
|
||||||
fun ByteArrayOutputStream.getInputStreamAndHash(baos: ByteArrayOutputStream): InputStreamAndHash {
|
|
||||||
val bytes = baos.toByteArray()
|
|
||||||
return InputStreamAndHash(ByteArrayInputStream(bytes), bytes.sha256())
|
|
||||||
}
|
|
||||||
|
|
||||||
data class InputStreamAndHash(val inputStream: InputStream, val sha256: SecureHash.SHA256) {
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Get a valid InputStream from an in-memory zip as required for some tests. The zip consists of a single file
|
|
||||||
* called "z" that contains the given content byte repeated the given number of times.
|
|
||||||
* Note that a slightly bigger than numOfExpectedBytes size is expected.
|
|
||||||
*/
|
|
||||||
@Throws(IllegalArgumentException::class)
|
|
||||||
@JvmStatic
|
|
||||||
fun createInMemoryTestZip(numOfExpectedBytes: Int, content: Byte): InputStreamAndHash {
|
|
||||||
require(numOfExpectedBytes > 0)
|
|
||||||
val baos = ByteArrayOutputStream()
|
|
||||||
ZipOutputStream(baos).use { zos ->
|
|
||||||
val arraySize = 1024
|
|
||||||
val bytes = ByteArray(arraySize) { content }
|
|
||||||
val n = (numOfExpectedBytes - 1) / arraySize + 1 // same as Math.ceil(numOfExpectedBytes/arraySize).
|
|
||||||
zos.setLevel(Deflater.NO_COMPRESSION)
|
|
||||||
zos.putNextEntry(ZipEntry("z"))
|
|
||||||
for (i in 0 until n) {
|
|
||||||
zos.write(bytes, 0, arraySize)
|
|
||||||
}
|
|
||||||
zos.closeEntry()
|
|
||||||
}
|
|
||||||
return baos.getInputStreamAndHash(baos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Generic csv printing utility for clases.
|
|
||||||
|
|
||||||
val Throwable.rootCause: Throwable get() = Throwables.getRootCause(this)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an Observable that buffers events until subscribed.
|
|
||||||
* @see UnicastSubject
|
|
||||||
*/
|
|
||||||
fun <T> Observable<T>.bufferUntilSubscribed(): Observable<T> {
|
|
||||||
val subject = UnicastSubject.create<T>()
|
|
||||||
val subscription = subscribe(subject)
|
|
||||||
return subject.doOnUnsubscribe { subscription.unsubscribe() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy an [Observer] to multiple other [Observer]s.
|
|
||||||
*/
|
|
||||||
fun <T> Observer<T>.tee(vararg teeTo: Observer<T>): Observer<T> {
|
|
||||||
val subject = PublishSubject.create<T>()
|
|
||||||
subject.subscribe(this)
|
|
||||||
teeTo.forEach { subject.subscribe(it) }
|
|
||||||
return subject
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [ListenableFuture] bound to the *first* item emitted by this Observable. The future will complete with a
|
* Returns a [ListenableFuture] bound to the *first* item emitted by this Observable. The future will complete with a
|
||||||
* NoSuchElementException if no items are emitted or any other error thrown by the Observable. If it's cancelled then
|
* NoSuchElementException if no items are emitted or any other error thrown by the Observable. If it's cancelled then
|
||||||
@ -273,15 +85,3 @@ private class ObservableToFuture<T>(observable: Observable<T>) : AbstractFuture<
|
|||||||
|
|
||||||
override fun onCompleted() {}
|
override fun onCompleted() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the sum of an Iterable of [BigDecimal]s. */
|
|
||||||
fun Iterable<BigDecimal>.sum(): BigDecimal = fold(BigDecimal.ZERO) { a, b -> a + b }
|
|
||||||
|
|
||||||
fun <T> Class<T>.checkNotUnorderedHashMap() {
|
|
||||||
if (HashMap::class.java.isAssignableFrom(this) && !LinkedHashMap::class.java.isAssignableFrom(this)) {
|
|
||||||
throw NotSerializableException("Map type $this is unstable under iteration. Suggested fix: use LinkedHashMap instead.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Class<*>.requireExternal(msg: String = "Internal class")
|
|
||||||
= require(!name.startsWith("net.corda.node.") && !name.contains(".internal.")) { "$msg: $name" }
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package net.corda.core.contracts
|
package net.corda.core.contracts
|
||||||
|
|
||||||
|
import net.corda.core.crypto.composite.CompositeKey
|
||||||
|
import net.corda.core.utilities.exactAdd
|
||||||
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
@ -168,7 +171,7 @@ data class Amount<T : Any>(val quantity: Long, val displayTokenSize: BigDecimal,
|
|||||||
*/
|
*/
|
||||||
operator fun plus(other: Amount<T>): Amount<T> {
|
operator fun plus(other: Amount<T>): Amount<T> {
|
||||||
checkToken(other)
|
checkToken(other)
|
||||||
return Amount(Math.addExact(quantity, other.quantity), displayTokenSize, token)
|
return Amount(quantity exactAdd other.quantity, displayTokenSize, token)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -268,9 +271,9 @@ data class SourceAndAmount<T : Any, out P : Any>(val source: P, val amount: Amou
|
|||||||
* but in various scenarios it may be more consistent to allow positive and negative values.
|
* but in various scenarios it may be more consistent to allow positive and negative values.
|
||||||
* For example it is common for a bank to code asset flows as gains and losses from its perspective i.e. always the destination.
|
* For example it is common for a bank to code asset flows as gains and losses from its perspective i.e. always the destination.
|
||||||
* @param token represents the type of asset token as would be used to construct Amount<T> objects.
|
* @param token represents the type of asset token as would be used to construct Amount<T> objects.
|
||||||
* @param source is the [Party], [Account], [CompositeKey], or other identifier of the token source if quantityDelta is positive,
|
* @param source is the [Party], [CompositeKey], or other identifier of the token source if quantityDelta is positive,
|
||||||
* or the token sink if quantityDelta is negative. The type P should support value equality.
|
* or the token sink if quantityDelta is negative. The type P should support value equality.
|
||||||
* @param destination is the [Party], [Account], [CompositeKey], or other identifier of the token sink if quantityDelta is positive,
|
* @param destination is the [Party], [CompositeKey], or other identifier of the token sink if quantityDelta is positive,
|
||||||
* or the token source if quantityDelta is negative. The type P should support value equality.
|
* or the token source if quantityDelta is negative. The type P should support value equality.
|
||||||
*/
|
*/
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
@ -329,7 +332,7 @@ class AmountTransfer<T : Any, P : Any>(val quantityDelta: Long,
|
|||||||
"Only AmountTransfer between the same two parties can be aggregated/netted"
|
"Only AmountTransfer between the same two parties can be aggregated/netted"
|
||||||
}
|
}
|
||||||
return if (other.source == source) {
|
return if (other.source == source) {
|
||||||
AmountTransfer(Math.addExact(quantityDelta, other.quantityDelta), token, source, destination)
|
AmountTransfer(quantityDelta exactAdd other.quantityDelta, token, source, destination)
|
||||||
} else {
|
} else {
|
||||||
AmountTransfer(Math.subtractExact(quantityDelta, other.quantityDelta), token, source, destination)
|
AmountTransfer(Math.subtractExact(quantityDelta, other.quantityDelta), token, source, destination)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import net.corda.core.crypto.composite.CompositeKey.NodeAndWeight
|
|||||||
import net.corda.core.crypto.keys
|
import net.corda.core.crypto.keys
|
||||||
import net.corda.core.crypto.provider.CordaObjectIdentifier
|
import net.corda.core.crypto.provider.CordaObjectIdentifier
|
||||||
import net.corda.core.crypto.toStringShort
|
import net.corda.core.crypto.toStringShort
|
||||||
|
import net.corda.core.utilities.exactAdd
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.utilities.sequence
|
import net.corda.core.utilities.sequence
|
||||||
import org.bouncycastle.asn1.*
|
import org.bouncycastle.asn1.*
|
||||||
@ -126,7 +127,7 @@ class CompositeKey private constructor(val threshold: Int, children: List<NodeAn
|
|||||||
var sum = 0
|
var sum = 0
|
||||||
for ((_, weight) in children) {
|
for ((_, weight) in children) {
|
||||||
require(weight > 0) { "Non-positive weight: $weight detected." }
|
require(weight > 0) { "Non-positive weight: $weight detected." }
|
||||||
sum = Math.addExact(sum, weight) // Add and check for integer overflow.
|
sum = sum exactAdd weight // Add and check for integer overflow.
|
||||||
}
|
}
|
||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package net.corda.core.flows
|
package net.corda.core.flows
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.core.abbreviate
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FlowStateMachine
|
import net.corda.core.internal.FlowStateMachine
|
||||||
|
import net.corda.core.internal.abbreviate
|
||||||
import net.corda.core.messaging.DataFeed
|
import net.corda.core.messaging.DataFeed
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.core.flows
|
package net.corda.core.flows
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.core.checkedAdd
|
import net.corda.core.utilities.exactAdd
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
@ -176,7 +176,7 @@ class ResolveTransactionsFlow(private val txHashes: Set<SecureHash>,
|
|||||||
val inputHashes = downloads.flatMap { it.tx.inputs }.map { it.txhash }
|
val inputHashes = downloads.flatMap { it.tx.inputs }.map { it.txhash }
|
||||||
nextRequests.addAll(inputHashes)
|
nextRequests.addAll(inputHashes)
|
||||||
|
|
||||||
limitCounter = limitCounter checkedAdd nextRequests.size
|
limitCounter = limitCounter exactAdd nextRequests.size
|
||||||
if (limitCounter > limit)
|
if (limitCounter > limit)
|
||||||
throw ExcessivelyLargeTransactionGraph()
|
throw ExcessivelyLargeTransactionGraph()
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,37 @@
|
|||||||
package net.corda.core.internal
|
package net.corda.core.internal
|
||||||
|
|
||||||
|
import com.google.common.base.Throwables
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.crypto.sha256
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import rx.Observable
|
||||||
|
import rx.Observer
|
||||||
|
import rx.subjects.PublishSubject
|
||||||
|
import rx.subjects.UnicastSubject
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
|
import java.math.BigDecimal
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
import java.nio.charset.StandardCharsets.UTF_8
|
import java.nio.charset.StandardCharsets.UTF_8
|
||||||
import java.nio.file.*
|
import java.nio.file.*
|
||||||
import java.nio.file.attribute.FileAttribute
|
import java.nio.file.attribute.FileAttribute
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.temporal.Temporal
|
import java.time.temporal.Temporal
|
||||||
|
import java.util.*
|
||||||
|
import java.util.Spliterator.*
|
||||||
|
import java.util.stream.IntStream
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
import java.util.stream.StreamSupport
|
||||||
|
import java.util.zip.Deflater
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
inline val Throwable.rootCause: Throwable get() = Throwables.getRootCause(this)
|
||||||
|
|
||||||
infix fun Temporal.until(endExclusive: Temporal): Duration = Duration.between(this, endExclusive)
|
infix fun Temporal.until(endExclusive: Temporal): Duration = Duration.between(this, endExclusive)
|
||||||
|
|
||||||
operator fun Duration.div(divider: Long): Duration = dividedBy(divider)
|
operator fun Duration.div(divider: Long): Duration = dividedBy(divider)
|
||||||
@ -24,6 +44,50 @@ operator fun Duration.times(multiplicand: Long): Duration = multipliedBy(multipl
|
|||||||
operator fun Path.div(other: String): Path = resolve(other)
|
operator fun Path.div(other: String): Path = resolve(other)
|
||||||
operator fun String.div(other: String): Path = Paths.get(this) / other
|
operator fun String.div(other: String): Path = Paths.get(this) / other
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the single element matching the given [predicate], or `null` if the collection is empty, or throws exception
|
||||||
|
* if more than one element was found.
|
||||||
|
*/
|
||||||
|
inline fun <T> Iterable<T>.noneOrSingle(predicate: (T) -> Boolean): T? {
|
||||||
|
val iterator = iterator()
|
||||||
|
for (single in iterator) {
|
||||||
|
if (predicate(single)) {
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
if (predicate(iterator.next())) throw IllegalArgumentException("Collection contains more than one matching element.")
|
||||||
|
}
|
||||||
|
return single
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the single element, or `null` if the list is empty, or throws an exception if it has more than one element.
|
||||||
|
*/
|
||||||
|
fun <T> List<T>.noneOrSingle(): T? {
|
||||||
|
return when (size) {
|
||||||
|
0 -> null
|
||||||
|
1 -> this[0]
|
||||||
|
else -> throw IllegalArgumentException("List has more than one element.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a random element in the list, or `null` if empty */
|
||||||
|
fun <T> List<T>.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 <T> List<T>.indexOfOrThrow(item: T): Int {
|
||||||
|
val i = indexOf(item)
|
||||||
|
require(i != -1)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
fun Path.createDirectory(vararg attrs: FileAttribute<*>): Path = Files.createDirectory(this, *attrs)
|
fun Path.createDirectory(vararg attrs: FileAttribute<*>): Path = Files.createDirectory(this, *attrs)
|
||||||
fun Path.createDirectories(vararg attrs: FileAttribute<*>): Path = Files.createDirectories(this, *attrs)
|
fun Path.createDirectories(vararg attrs: FileAttribute<*>): Path = Files.createDirectories(this, *attrs)
|
||||||
fun Path.exists(vararg options: LinkOption): Boolean = Files.exists(this, *options)
|
fun Path.exists(vararg options: LinkOption): Boolean = Files.exists(this, *options)
|
||||||
@ -54,6 +118,112 @@ fun Path.writeLines(lines: Iterable<CharSequence>, charset: Charset = UTF_8, var
|
|||||||
|
|
||||||
fun InputStream.copyTo(target: Path, vararg options: CopyOption): Long = Files.copy(this, target, *options)
|
fun InputStream.copyTo(target: Path, vararg options: CopyOption): Long = Files.copy(this, target, *options)
|
||||||
|
|
||||||
|
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<BigDecimal>.sum(): BigDecimal = fold(BigDecimal.ZERO) { a, b -> a + b }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an Observable that buffers events until subscribed.
|
||||||
|
* @see UnicastSubject
|
||||||
|
*/
|
||||||
|
fun <T> Observable<T>.bufferUntilSubscribed(): Observable<T> {
|
||||||
|
val subject = UnicastSubject.create<T>()
|
||||||
|
val subscription = subscribe(subject)
|
||||||
|
return subject.doOnUnsubscribe { subscription.unsubscribe() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy an [Observer] to multiple other [Observer]s. */
|
||||||
|
fun <T> Observer<T>.tee(vararg teeTo: Observer<T>): Observer<T> {
|
||||||
|
val subject = PublishSubject.create<T>()
|
||||||
|
subject.subscribe(this)
|
||||||
|
teeTo.forEach { subject.subscribe(it) }
|
||||||
|
return subject
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Executes the given code block and returns a [Duration] of how long it took to execute in nanosecond precision. */
|
||||||
|
inline fun elapsedTime(block: () -> Unit): Duration {
|
||||||
|
val start = System.nanoTime()
|
||||||
|
block()
|
||||||
|
val end = System.nanoTime()
|
||||||
|
return Duration.ofNanos(end - start)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun <T> 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 <T> logElapsedTime(label: String, logger: Logger? = null, body: () -> T): T {
|
||||||
|
// Use nanoTime as it's monotonic.
|
||||||
|
val now = System.nanoTime()
|
||||||
|
try {
|
||||||
|
return body()
|
||||||
|
} finally {
|
||||||
|
val elapsed = Duration.ofNanos(System.nanoTime() - now).toMillis()
|
||||||
|
if (logger != null)
|
||||||
|
logger.info("$label took $elapsed msec")
|
||||||
|
else
|
||||||
|
println("$label took $elapsed msec")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert a [ByteArrayOutputStream] to [InputStreamAndHash]. */
|
||||||
|
fun ByteArrayOutputStream.toInputStreamAndHash(): InputStreamAndHash {
|
||||||
|
val bytes = toByteArray()
|
||||||
|
return InputStreamAndHash(ByteArrayInputStream(bytes), bytes.sha256())
|
||||||
|
}
|
||||||
|
|
||||||
|
data class InputStreamAndHash(val inputStream: InputStream, val sha256: SecureHash.SHA256) {
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Get a valid InputStream from an in-memory zip as required for some tests. The zip consists of a single file
|
||||||
|
* called "z" that contains the given content byte repeated the given number of times.
|
||||||
|
* Note that a slightly bigger than numOfExpectedBytes size is expected.
|
||||||
|
*/
|
||||||
|
fun createInMemoryTestZip(numOfExpectedBytes: Int, content: Byte): InputStreamAndHash {
|
||||||
|
require(numOfExpectedBytes > 0)
|
||||||
|
val baos = ByteArrayOutputStream()
|
||||||
|
ZipOutputStream(baos).use { zos ->
|
||||||
|
val arraySize = 1024
|
||||||
|
val bytes = ByteArray(arraySize) { content }
|
||||||
|
val n = (numOfExpectedBytes - 1) / arraySize + 1 // same as Math.ceil(numOfExpectedBytes/arraySize).
|
||||||
|
zos.setLevel(Deflater.NO_COMPRESSION)
|
||||||
|
zos.putNextEntry(ZipEntry("z"))
|
||||||
|
for (i in 0 until n) {
|
||||||
|
zos.write(bytes, 0, arraySize)
|
||||||
|
}
|
||||||
|
zos.closeEntry()
|
||||||
|
}
|
||||||
|
return baos.toInputStreamAndHash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IntIterator.toJavaIterator(): PrimitiveIterator.OfInt {
|
||||||
|
return object : PrimitiveIterator.OfInt {
|
||||||
|
override fun nextInt() = this@toJavaIterator.nextInt()
|
||||||
|
override fun hasNext() = this@toJavaIterator.hasNext()
|
||||||
|
override fun remove() = throw UnsupportedOperationException("remove")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IntProgression.toSpliterator(): Spliterator.OfInt {
|
||||||
|
val spliterator = Spliterators.spliterator(
|
||||||
|
iterator().toJavaIterator(),
|
||||||
|
(1 + (last - first) / step).toLong(),
|
||||||
|
SUBSIZED or IMMUTABLE or NONNULL or SIZED or ORDERED or SORTED or DISTINCT
|
||||||
|
)
|
||||||
|
return if (step > 0) spliterator else object : Spliterator.OfInt by spliterator {
|
||||||
|
override fun getComparator() = Comparator.reverseOrder<Int>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IntProgression.stream(parallel: Boolean = false): IntStream = StreamSupport.intStream(toSpliterator(), parallel)
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST") // When toArray has filled in the array, the component type is no longer T? but T (that may itself be nullable).
|
||||||
|
inline fun <reified T> Stream<out T>.toTypedArray() = toArray { size -> arrayOfNulls<T>(size) } as Array<T>
|
||||||
|
|
||||||
fun <T> Class<T>.castIfPossible(obj: Any): T? = if (isInstance(obj)) cast(obj) else null
|
fun <T> Class<T>.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]. */
|
/** Returns a [DeclaredField] wrapper around the declared (possibly non-public) static field of the receiver [Class]. */
|
||||||
|
@ -6,8 +6,7 @@ import net.corda.core.identity.AbstractParty
|
|||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.messaging.DataFeed
|
import net.corda.core.messaging.DataFeed
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.internal.randomOrNull
|
||||||
import net.corda.core.randomOrNull
|
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
@ -98,9 +97,9 @@ interface NetworkMapCache {
|
|||||||
|
|
||||||
/** Gets a notary identity by the given name. */
|
/** Gets a notary identity by the given name. */
|
||||||
fun getNotary(principal: X500Name): Party? {
|
fun getNotary(principal: X500Name): Party? {
|
||||||
val notaryNode = notaryNodes.randomOrNull {
|
val notaryNode = notaryNodes.filter {
|
||||||
it.advertisedServices.any { it.info.type.isSubTypeOf(ServiceType.notary) && it.info.name == principal }
|
it.advertisedServices.any { it.info.type.isSubTypeOf(ServiceType.notary) && it.info.name == principal }
|
||||||
}
|
}.randomOrNull()
|
||||||
return notaryNode?.notaryIdentity
|
return notaryNode?.notaryIdentity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.corda.core.serialization.amqp
|
package net.corda.core.serialization.amqp
|
||||||
|
|
||||||
import net.corda.core.checkNotUnorderedHashMap
|
|
||||||
import org.apache.qpid.proton.codec.Data
|
import org.apache.qpid.proton.codec.Data
|
||||||
import java.io.NotSerializableException
|
import java.io.NotSerializableException
|
||||||
import java.lang.reflect.ParameterizedType
|
import java.lang.reflect.ParameterizedType
|
||||||
@ -47,9 +46,9 @@ class MapSerializer(val declaredType: ParameterizedType, factory: SerializerFact
|
|||||||
// Write map
|
// Write map
|
||||||
data.putMap()
|
data.putMap()
|
||||||
data.enter()
|
data.enter()
|
||||||
for (entry in obj as Map<*, *>) {
|
for ((key, value) in obj as Map<*, *>) {
|
||||||
output.writeObjectOrNull(entry.key, data, declaredType.actualTypeArguments[0])
|
output.writeObjectOrNull(key, data, declaredType.actualTypeArguments[0])
|
||||||
output.writeObjectOrNull(entry.value, data, declaredType.actualTypeArguments[1])
|
output.writeObjectOrNull(value, data, declaredType.actualTypeArguments[1])
|
||||||
}
|
}
|
||||||
data.exit() // exit map
|
data.exit() // exit map
|
||||||
}
|
}
|
||||||
@ -65,3 +64,9 @@ class MapSerializer(val declaredType: ParameterizedType, factory: SerializerFact
|
|||||||
input.readObjectOrNull(entry.key, schema, declaredType.actualTypeArguments[0]) to
|
input.readObjectOrNull(entry.key, schema, declaredType.actualTypeArguments[0]) to
|
||||||
input.readObjectOrNull(entry.value, schema, declaredType.actualTypeArguments[1])
|
input.readObjectOrNull(entry.value, schema, declaredType.actualTypeArguments[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun Class<*>.checkNotUnorderedHashMap() {
|
||||||
|
if (HashMap::class.java.isAssignableFrom(this) && !LinkedHashMap::class.java.isAssignableFrom(this)) {
|
||||||
|
throw IllegalArgumentException("Map type $this is unstable under iteration. Suggested fix: use java.util.LinkedHashMap instead.")
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@ package net.corda.core.serialization.amqp
|
|||||||
|
|
||||||
import com.google.common.primitives.Primitives
|
import com.google.common.primitives.Primitives
|
||||||
import com.google.common.reflect.TypeResolver
|
import com.google.common.reflect.TypeResolver
|
||||||
import net.corda.core.checkNotUnorderedHashMap
|
|
||||||
import net.corda.core.serialization.AllWhitelist
|
import net.corda.core.serialization.AllWhitelist
|
||||||
import net.corda.core.serialization.ClassWhitelist
|
import net.corda.core.serialization.ClassWhitelist
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
|
@ -2,7 +2,7 @@ package net.corda.core.transactions
|
|||||||
|
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.indexOfOrThrow
|
import net.corda.core.internal.indexOfOrThrow
|
||||||
import net.corda.core.internal.castIfPossible
|
import net.corda.core.internal.castIfPossible
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -8,10 +8,17 @@ import kotlin.reflect.KProperty
|
|||||||
|
|
||||||
//
|
//
|
||||||
// READ ME FIRST:
|
// READ ME FIRST:
|
||||||
// This is a collection of public utilities useful only for Kotlin code. If you're looking to add a public utility that
|
// This is a collection of public utilities useful only for Kotlin code. Think carefully before adding anything here and
|
||||||
// is also relevant to Java then put it in Utils.kt.
|
// make sure it's tested and documented. If you're looking to add a public utility that is also relevant to Java then
|
||||||
|
// don't put it here but in a seperate file called Utils.kt
|
||||||
//
|
//
|
||||||
|
|
||||||
|
/** Like the + operator but throws [ArithmeticException] in case of integer overflow. */
|
||||||
|
infix fun Int.exactAdd(b: Int): Int = Math.addExact(this, b)
|
||||||
|
|
||||||
|
/** Like the + operator but throws [ArithmeticException] in case of integer overflow. */
|
||||||
|
infix fun Long.exactAdd(b: Long): Long = Math.addExact(this, b)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the [Logger] for a class using the syntax
|
* Get the [Logger] for a class using the syntax
|
||||||
*
|
*
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
package net.corda.core
|
|
||||||
|
|
||||||
import org.junit.Test
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.test.assertFailsWith
|
|
||||||
|
|
||||||
class CollectionExtensionTests {
|
|
||||||
@Test
|
|
||||||
fun `noneOrSingle returns a single item`() {
|
|
||||||
val collection = listOf(1)
|
|
||||||
assertEquals(collection.noneOrSingle(), 1)
|
|
||||||
assertEquals(collection.noneOrSingle { it == 1 }, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `noneOrSingle returns null if item not found`() {
|
|
||||||
val collection = emptyList<Int>()
|
|
||||||
assertEquals(collection.noneOrSingle(), null)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `noneOrSingle throws if more than one item found`() {
|
|
||||||
val collection = listOf(1, 2)
|
|
||||||
assertFailsWith<IllegalArgumentException> { collection.noneOrSingle() }
|
|
||||||
assertFailsWith<IllegalArgumentException> { collection.noneOrSingle { it > 0 } }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `indexOfOrThrow returns index of the given item`() {
|
|
||||||
val collection = listOf(1, 2)
|
|
||||||
assertEquals(collection.indexOfOrThrow(1), 0)
|
|
||||||
assertEquals(collection.indexOfOrThrow(2), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `indexOfOrThrow throws if the given item is not found`() {
|
|
||||||
val collection = listOf(1)
|
|
||||||
assertFailsWith<IllegalArgumentException> { collection.indexOfOrThrow(2) }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
package net.corda.core
|
|
||||||
|
|
||||||
import org.junit.Assert.assertArrayEquals
|
|
||||||
import org.junit.Test
|
|
||||||
import java.util.stream.IntStream
|
|
||||||
import java.util.stream.Stream
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
|
|
||||||
class StreamsTest {
|
|
||||||
@Test
|
|
||||||
fun `IntProgression stream works`() {
|
|
||||||
assertArrayEquals(intArrayOf(1, 2, 3, 4), (1..4).stream().toArray())
|
|
||||||
assertArrayEquals(intArrayOf(1, 2, 3, 4), (1 until 5).stream().toArray())
|
|
||||||
assertArrayEquals(intArrayOf(1, 3), (1..4 step 2).stream().toArray())
|
|
||||||
assertArrayEquals(intArrayOf(1, 3), (1..3 step 2).stream().toArray())
|
|
||||||
assertArrayEquals(intArrayOf(), (1..0).stream().toArray())
|
|
||||||
assertArrayEquals(intArrayOf(1, 0), (1 downTo 0).stream().toArray())
|
|
||||||
assertArrayEquals(intArrayOf(3, 1), (3 downTo 0 step 2).stream().toArray())
|
|
||||||
assertArrayEquals(intArrayOf(3, 1), (3 downTo 1 step 2).stream().toArray())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `IntProgression spliterator characteristics and comparator`() {
|
|
||||||
val rangeCharacteristics = IntStream.range(0, 2).spliterator().characteristics()
|
|
||||||
val forward = (0..9 step 3).stream().spliterator()
|
|
||||||
assertEquals(rangeCharacteristics, forward.characteristics())
|
|
||||||
assertEquals(null, forward.comparator)
|
|
||||||
val reverse = (9 downTo 0 step 3).stream().spliterator()
|
|
||||||
assertEquals(rangeCharacteristics, reverse.characteristics())
|
|
||||||
assertEquals(Comparator.reverseOrder(), reverse.comparator)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Stream toTypedArray works`() {
|
|
||||||
val a: Array<String> = Stream.of("one", "two").toTypedArray()
|
|
||||||
assertEquals(Array<String>::class.java, a.javaClass)
|
|
||||||
assertArrayEquals(arrayOf("one", "two"), a)
|
|
||||||
val b: Array<String?> = Stream.of("one", "two", null).toTypedArray()
|
|
||||||
assertEquals(Array<String?>::class.java, b.javaClass)
|
|
||||||
assertArrayEquals(arrayOf("one", "two", null), b)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.core.crypto
|
package net.corda.core.crypto
|
||||||
|
|
||||||
import net.corda.core.toTypedArray
|
import net.corda.core.internal.toTypedArray
|
||||||
import net.corda.node.utilities.KEYSTORE_TYPE
|
import net.corda.node.utilities.KEYSTORE_TYPE
|
||||||
import net.corda.node.utilities.addOrReplaceCertificate
|
import net.corda.node.utilities.addOrReplaceCertificate
|
||||||
import net.corda.node.utilities.addOrReplaceKey
|
import net.corda.node.utilities.addOrReplaceKey
|
||||||
|
@ -5,7 +5,7 @@ import net.corda.core.crypto.Crypto.generateKeyPair
|
|||||||
import net.corda.core.crypto.X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME
|
import net.corda.core.crypto.X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME
|
||||||
import net.corda.core.crypto.X509Utilities.createSelfSignedCACertificate
|
import net.corda.core.crypto.X509Utilities.createSelfSignedCACertificate
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.toTypedArray
|
import net.corda.core.internal.toTypedArray
|
||||||
import net.corda.node.services.config.createKeystoreForCordaNode
|
import net.corda.node.services.config.createKeystoreForCordaNode
|
||||||
import net.corda.node.utilities.*
|
import net.corda.node.utilities.*
|
||||||
import net.corda.testing.MEGA_CORP
|
import net.corda.testing.MEGA_CORP
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
package net.corda.core.internal
|
||||||
|
|
||||||
|
import org.assertj.core.api.Assertions
|
||||||
|
import org.junit.Assert.assertArrayEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import java.util.stream.IntStream
|
||||||
|
import java.util.stream.Stream
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
|
class InternalUtilsTest {
|
||||||
|
@Test
|
||||||
|
fun `noneOrSingle on an empty collection`() {
|
||||||
|
val collection = emptyList<Int>()
|
||||||
|
Assertions.assertThat(collection.noneOrSingle()).isNull()
|
||||||
|
Assertions.assertThat(collection.noneOrSingle { it == 1 }).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `noneOrSingle on a singleton collection`() {
|
||||||
|
val collection = listOf(1)
|
||||||
|
Assertions.assertThat(collection.noneOrSingle()).isEqualTo(1)
|
||||||
|
Assertions.assertThat(collection.noneOrSingle { it == 1 }).isEqualTo(1)
|
||||||
|
Assertions.assertThat(collection.noneOrSingle { it == 2 }).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `noneOrSingle on a collection with two items`() {
|
||||||
|
val collection = listOf(1, 2)
|
||||||
|
assertFailsWith<IllegalArgumentException> { collection.noneOrSingle() }
|
||||||
|
Assertions.assertThat(collection.noneOrSingle { it == 1 }).isEqualTo(1)
|
||||||
|
Assertions.assertThat(collection.noneOrSingle { it == 2 }).isEqualTo(2)
|
||||||
|
Assertions.assertThat(collection.noneOrSingle { it == 3 }).isNull()
|
||||||
|
assertFailsWith<IllegalArgumentException> { collection.noneOrSingle { it > 0 } }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `noneOrSingle on a collection with items 1, 2, 1`() {
|
||||||
|
val collection = listOf(1, 2, 1)
|
||||||
|
assertFailsWith<IllegalArgumentException> { collection.noneOrSingle() }
|
||||||
|
assertFailsWith<IllegalArgumentException> { collection.noneOrSingle { it == 1 } }
|
||||||
|
Assertions.assertThat(collection.noneOrSingle { it == 2 }).isEqualTo(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `indexOfOrThrow returns index of the given item`() {
|
||||||
|
val collection = listOf(1, 2)
|
||||||
|
assertEquals(collection.indexOfOrThrow(1), 0)
|
||||||
|
assertEquals(collection.indexOfOrThrow(2), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `indexOfOrThrow throws if the given item is not found`() {
|
||||||
|
val collection = listOf(1)
|
||||||
|
assertFailsWith<IllegalArgumentException> { collection.indexOfOrThrow(2) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `IntProgression stream works`() {
|
||||||
|
assertArrayEquals(intArrayOf(1, 2, 3, 4), (1..4).stream().toArray())
|
||||||
|
assertArrayEquals(intArrayOf(1, 2, 3, 4), (1 until 5).stream().toArray())
|
||||||
|
assertArrayEquals(intArrayOf(1, 3), (1..4 step 2).stream().toArray())
|
||||||
|
assertArrayEquals(intArrayOf(1, 3), (1..3 step 2).stream().toArray())
|
||||||
|
assertArrayEquals(intArrayOf(), (1..0).stream().toArray())
|
||||||
|
assertArrayEquals(intArrayOf(1, 0), (1 downTo 0).stream().toArray())
|
||||||
|
assertArrayEquals(intArrayOf(3, 1), (3 downTo 0 step 2).stream().toArray())
|
||||||
|
assertArrayEquals(intArrayOf(3, 1), (3 downTo 1 step 2).stream().toArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `IntProgression spliterator characteristics and comparator`() {
|
||||||
|
val rangeCharacteristics = IntStream.range(0, 2).spliterator().characteristics()
|
||||||
|
val forward = (0..9 step 3).stream().spliterator()
|
||||||
|
assertEquals(rangeCharacteristics, forward.characteristics())
|
||||||
|
assertEquals(null, forward.comparator)
|
||||||
|
val reverse = (9 downTo 0 step 3).stream().spliterator()
|
||||||
|
assertEquals(rangeCharacteristics, reverse.characteristics())
|
||||||
|
assertEquals(Comparator.reverseOrder(), reverse.comparator)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Stream toTypedArray works`() {
|
||||||
|
val a: Array<String> = Stream.of("one", "two").toTypedArray()
|
||||||
|
assertEquals(Array<String>::class.java, a.javaClass)
|
||||||
|
assertArrayEquals(arrayOf("one", "two"), a)
|
||||||
|
val b: Array<String?> = Stream.of("one", "two", null).toTypedArray()
|
||||||
|
assertEquals(Array<String?>::class.java, b.javaClass)
|
||||||
|
assertArrayEquals(arrayOf("one", "two", null), b)
|
||||||
|
}
|
||||||
|
}
|
@ -240,7 +240,7 @@ class SerializationOutputTests {
|
|||||||
serdes(obj)
|
serdes(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = NotSerializableException::class)
|
@Test(expected = IllegalArgumentException::class)
|
||||||
fun `test dislike of HashMap`() {
|
fun `test dislike of HashMap`() {
|
||||||
val obj = WrapHashMap(HashMap<String, String>())
|
val obj = WrapHashMap(HashMap<String, String>())
|
||||||
serdes(obj)
|
serdes(obj)
|
||||||
|
@ -12,3 +12,12 @@ This section describes the APIs that are available for the development of CorDap
|
|||||||
* :doc:`api-core-types`
|
* :doc:`api-core-types`
|
||||||
|
|
||||||
Before reading this page, you should be familiar with the :doc:`key concepts of Corda <key-concepts>`.
|
Before reading this page, you should be familiar with the :doc:`key concepts of Corda <key-concepts>`.
|
||||||
|
|
||||||
|
Internal
|
||||||
|
--------
|
||||||
|
|
||||||
|
Code that falls into the following package namespaces are for internal use only and not public. In a future release the
|
||||||
|
node will not load any CorDapp which uses them.
|
||||||
|
|
||||||
|
* Any package in the ``net.corda`` namespace which contains ``.internal``
|
||||||
|
* ``net.corda.node``
|
||||||
|
@ -47,6 +47,9 @@ UNRELEASED
|
|||||||
* Added various query methods to ``LedgerTransaction`` to simplify querying of states and commands. In the same vain
|
* Added various query methods to ``LedgerTransaction`` to simplify querying of states and commands. In the same vain
|
||||||
``Command`` is now parameterised on the ``CommandData`` field.
|
``Command`` is now parameterised on the ``CommandData`` field.
|
||||||
|
|
||||||
|
* Kotlin utilities that we deemed useful enough to keep public have been moved out of ``net.corda.core.Utils`` and into
|
||||||
|
``net.corda.core.utilities.KotlinUtils``. The other utilities have been marked as internal.
|
||||||
|
|
||||||
Milestone 13
|
Milestone 13
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -5,11 +5,10 @@ package net.corda.nodeapi
|
|||||||
import com.esotericsoftware.kryo.Registration
|
import com.esotericsoftware.kryo.Registration
|
||||||
import com.esotericsoftware.kryo.Serializer
|
import com.esotericsoftware.kryo.Serializer
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.requireExternal
|
import net.corda.core.CordaRuntimeException
|
||||||
import net.corda.core.serialization.*
|
import net.corda.core.serialization.*
|
||||||
import net.corda.core.toFuture
|
import net.corda.core.toFuture
|
||||||
import net.corda.core.toObservable
|
import net.corda.core.toObservable
|
||||||
import net.corda.core.CordaRuntimeException
|
|
||||||
import net.corda.nodeapi.config.OldConfig
|
import net.corda.nodeapi.config.OldConfig
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -73,4 +72,8 @@ class RPCKryo(observableSerializer: Serializer<Observable<Any>>, whitelist: Clas
|
|||||||
type.requireExternal("RPC not allowed to deserialise internal classes")
|
type.requireExternal("RPC not allowed to deserialise internal classes")
|
||||||
return super.getRegistration(type)
|
return super.getRegistration(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Class<*>.requireExternal(msg: String) {
|
||||||
|
require(!name.startsWith("net.corda.node.") && !name.contains(".internal.")) { "$msg: $name" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package net.corda.nodeapi.config
|
|||||||
|
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import com.typesafe.config.ConfigUtil
|
import com.typesafe.config.ConfigUtil
|
||||||
import net.corda.core.noneOrSingle
|
import net.corda.core.internal.noneOrSingle
|
||||||
import net.corda.core.utilities.validateX500Name
|
import net.corda.core.utilities.validateX500Name
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.parseNetworkHostAndPort
|
import net.corda.core.utilities.parseNetworkHostAndPort
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.node.services
|
package net.corda.node.services
|
||||||
|
|
||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.POUNDS
|
import net.corda.core.contracts.POUNDS
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.node.services.statemachine
|
package net.corda.node.services.statemachine
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.core.InputStreamAndHash
|
import net.corda.core.internal.InputStreamAndHash
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.*
|
import net.corda.core.flows.*
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
@ -3,8 +3,8 @@ package net.corda.services.messaging
|
|||||||
import com.google.common.util.concurrent.Futures
|
import com.google.common.util.concurrent.Futures
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.elapsedTime
|
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
|
import net.corda.core.internal.elapsedTime
|
||||||
import net.corda.core.internal.times
|
import net.corda.core.internal.times
|
||||||
import net.corda.core.messaging.MessageRecipients
|
import net.corda.core.messaging.MessageRecipients
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
|
@ -6,11 +6,9 @@ import joptsimple.OptionException
|
|||||||
import net.corda.core.*
|
import net.corda.core.*
|
||||||
import net.corda.core.crypto.commonName
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.crypto.orgName
|
import net.corda.core.crypto.orgName
|
||||||
import net.corda.core.internal.createDirectories
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.internal.div
|
|
||||||
import net.corda.node.VersionInfo
|
import net.corda.node.VersionInfo
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.internal.Emoji
|
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.node.ArgsParser
|
import net.corda.node.ArgsParser
|
||||||
import net.corda.node.CmdLineOptions
|
import net.corda.node.CmdLineOptions
|
||||||
|
@ -9,6 +9,7 @@ import net.corda.core.crypto.X509Utilities.CORDA_CLIENT_TLS
|
|||||||
import net.corda.core.crypto.X509Utilities.CORDA_ROOT_CA
|
import net.corda.core.crypto.X509Utilities.CORDA_ROOT_CA
|
||||||
import net.corda.core.internal.ThreadBox
|
import net.corda.core.internal.ThreadBox
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
|
import net.corda.core.internal.noneOrSingle
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.node.services.NetworkMapCache
|
import net.corda.core.node.services.NetworkMapCache
|
||||||
import net.corda.core.node.services.NetworkMapCache.MapChange
|
import net.corda.core.node.services.NetworkMapCache.MapChange
|
||||||
|
@ -3,7 +3,7 @@ package net.corda.node.services.network
|
|||||||
import com.google.common.annotations.VisibleForTesting
|
import com.google.common.annotations.VisibleForTesting
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.map
|
import net.corda.core.map
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.node.services.persistence
|
package net.corda.node.services.persistence
|
||||||
|
|
||||||
import net.corda.core.internal.ThreadBox
|
import net.corda.core.internal.ThreadBox
|
||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.StateMachineRunId
|
import net.corda.core.flows.StateMachineRunId
|
||||||
import net.corda.core.messaging.DataFeed
|
import net.corda.core.messaging.DataFeed
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.node.services.persistence
|
package net.corda.node.services.persistence
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting
|
import com.google.common.annotations.VisibleForTesting
|
||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.messaging.DataFeed
|
import net.corda.core.messaging.DataFeed
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.node.services.persistence
|
package net.corda.node.services.persistence
|
||||||
|
|
||||||
import net.corda.core.internal.ThreadBox
|
import net.corda.core.internal.ThreadBox
|
||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.StateMachineRunId
|
import net.corda.core.flows.StateMachineRunId
|
||||||
import net.corda.core.messaging.DataFeed
|
import net.corda.core.messaging.DataFeed
|
||||||
|
@ -6,12 +6,12 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import co.paralleluniverse.strands.Strand
|
import co.paralleluniverse.strands.Strand
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import net.corda.core.abbreviate
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.flows.*
|
import net.corda.core.flows.*
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FlowStateMachine
|
import net.corda.core.internal.FlowStateMachine
|
||||||
|
import net.corda.core.internal.abbreviate
|
||||||
import net.corda.core.internal.staticField
|
import net.corda.core.internal.staticField
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.utilities.*
|
import net.corda.core.utilities.*
|
||||||
@ -122,7 +122,7 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
|
|||||||
actionOnEnd(Try.Success(result), false)
|
actionOnEnd(Try.Success(result), false)
|
||||||
_resultFuture?.set(result)
|
_resultFuture?.set(result)
|
||||||
logic.progressTracker?.currentStep = ProgressTracker.DONE
|
logic.progressTracker?.currentStep = ProgressTracker.DONE
|
||||||
logger.debug { "Flow finished with result $result" }
|
logger.debug { "Flow finished with result ${result.toString().abbreviate(300)}" }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createTransaction() {
|
private fun createTransaction() {
|
||||||
|
@ -9,7 +9,7 @@ import com.google.common.collect.HashMultimap
|
|||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.google.common.util.concurrent.MoreExecutors
|
import com.google.common.util.concurrent.MoreExecutors
|
||||||
import net.corda.core.internal.ThreadBox
|
import net.corda.core.internal.ThreadBox
|
||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
|
@ -27,7 +27,7 @@ import net.corda.core.serialization.CordaSerializable
|
|||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.toTypedArray
|
import net.corda.core.internal.toTypedArray
|
||||||
import net.corda.core.transactions.FilteredTransaction
|
import net.corda.core.transactions.FilteredTransaction
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.utilities.debug
|
import net.corda.core.utilities.debug
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.node.services.vault
|
package net.corda.node.services.vault
|
||||||
|
|
||||||
import net.corda.core.internal.ThreadBox
|
import net.corda.core.internal.ThreadBox
|
||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.contracts.ContractState
|
import net.corda.core.contracts.ContractState
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
|
@ -13,7 +13,7 @@ import io.requery.query.RowExpression
|
|||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.contracts.asset.OnLedgerAsset
|
import net.corda.contracts.asset.OnLedgerAsset
|
||||||
import net.corda.core.internal.ThreadBox
|
import net.corda.core.internal.ThreadBox
|
||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.containsAny
|
import net.corda.core.crypto.containsAny
|
||||||
@ -30,7 +30,7 @@ import net.corda.core.serialization.SerializationDefaults.STORAGE_CONTEXT
|
|||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.tee
|
import net.corda.core.internal.tee
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
import net.corda.core.utilities.*
|
import net.corda.core.utilities.*
|
||||||
|
@ -12,10 +12,7 @@ import com.google.common.util.concurrent.SettableFuture
|
|||||||
import net.corda.core.*
|
import net.corda.core.*
|
||||||
import net.corda.core.flows.FlowInitiator
|
import net.corda.core.flows.FlowInitiator
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.internal.FlowStateMachine
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.internal.createDirectories
|
|
||||||
import net.corda.core.internal.div
|
|
||||||
import net.corda.core.internal.write
|
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.StateMachineUpdate
|
import net.corda.core.messaging.StateMachineUpdate
|
||||||
import net.corda.core.internal.Emoji
|
import net.corda.core.internal.Emoji
|
||||||
|
@ -19,6 +19,7 @@ import net.corda.core.identity.AnonymousParty
|
|||||||
import net.corda.core.identity.AnonymousPartyAndPath
|
import net.corda.core.identity.AnonymousPartyAndPath
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FlowStateMachine
|
import net.corda.core.internal.FlowStateMachine
|
||||||
|
import net.corda.core.internal.rootCause
|
||||||
import net.corda.core.map
|
import net.corda.core.map
|
||||||
import net.corda.core.messaging.DataFeed
|
import net.corda.core.messaging.DataFeed
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
@ -26,8 +27,6 @@ import net.corda.core.messaging.StateMachineTransactionMapping
|
|||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.rootCause
|
|
||||||
import net.corda.core.serialization.serialize
|
|
||||||
import net.corda.core.toFuture
|
import net.corda.core.toFuture
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.corda.node.utilities
|
package net.corda.node.utilities
|
||||||
|
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.tee
|
import net.corda.core.internal.tee
|
||||||
import net.corda.testing.node.makeTestDataSourceProperties
|
import net.corda.testing.node.makeTestDataSourceProperties
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
|
@ -5,7 +5,7 @@ import com.nhaarman.mockito_kotlin.eq
|
|||||||
import com.nhaarman.mockito_kotlin.mock
|
import com.nhaarman.mockito_kotlin.mock
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.internal.exists
|
import net.corda.core.internal.exists
|
||||||
import net.corda.core.toTypedArray
|
import net.corda.core.internal.toTypedArray
|
||||||
import net.corda.node.utilities.loadKeyStore
|
import net.corda.node.utilities.loadKeyStore
|
||||||
import net.corda.testing.ALICE
|
import net.corda.testing.ALICE
|
||||||
import net.corda.testing.getTestX509Name
|
import net.corda.testing.getTestX509Name
|
||||||
|
@ -3,7 +3,6 @@ package net.corda.attachmentdemo
|
|||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import joptsimple.OptionParser
|
import joptsimple.OptionParser
|
||||||
import net.corda.client.rpc.CordaRPCClient
|
import net.corda.client.rpc.CordaRPCClient
|
||||||
import net.corda.core.InputStreamAndHash
|
|
||||||
import net.corda.core.contracts.Contract
|
import net.corda.core.contracts.Contract
|
||||||
import net.corda.core.contracts.ContractState
|
import net.corda.core.contracts.ContractState
|
||||||
import net.corda.core.contracts.TransactionType
|
import net.corda.core.contracts.TransactionType
|
||||||
@ -15,6 +14,7 @@ import net.corda.core.getOrThrow
|
|||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.Emoji
|
import net.corda.core.internal.Emoji
|
||||||
|
import net.corda.core.internal.InputStreamAndHash
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.startTrackedFlow
|
import net.corda.core.messaging.startTrackedFlow
|
||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
|
@ -6,7 +6,6 @@ import net.corda.contracts.asset.CASH
|
|||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.contracts.asset.`issued by`
|
import net.corda.contracts.asset.`issued by`
|
||||||
import net.corda.contracts.asset.`owned by`
|
import net.corda.contracts.asset.`owned by`
|
||||||
import net.corda.core.bd
|
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.MerkleTreeException
|
import net.corda.core.crypto.MerkleTreeException
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
@ -81,7 +80,7 @@ class NodeInterestRatesTest : TestDependencyInjectionBase() {
|
|||||||
val q = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")
|
val q = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")
|
||||||
val res = oracle.query(listOf(q))
|
val res = oracle.query(listOf(q))
|
||||||
assertEquals(1, res.size)
|
assertEquals(1, res.size)
|
||||||
assertEquals("0.678".bd, res[0].value)
|
assertEquals(BigDecimal("0.678"), res[0].value)
|
||||||
assertEquals(q, res[0].of)
|
assertEquals(q, res[0].of)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,7 +162,7 @@ class NodeInterestRatesTest : TestDependencyInjectionBase() {
|
|||||||
database.transaction {
|
database.transaction {
|
||||||
val tx = makeTX()
|
val tx = makeTX()
|
||||||
val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")
|
val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")
|
||||||
val badFix = Fix(fixOf, "0.6789".bd)
|
val badFix = Fix(fixOf, BigDecimal("0.6789"))
|
||||||
tx.addCommand(badFix, oracle.identity.owningKey)
|
tx.addCommand(badFix, oracle.identity.owningKey)
|
||||||
val wtx = tx.toWireTransaction()
|
val wtx = tx.toWireTransaction()
|
||||||
val ftx = wtx.buildFilteredTransaction(Predicate { x -> fixCmdFilter(x) })
|
val ftx = wtx.buildFilteredTransaction(Predicate { x -> fixCmdFilter(x) })
|
||||||
@ -212,7 +211,7 @@ class NodeInterestRatesTest : TestDependencyInjectionBase() {
|
|||||||
val tx = TransactionType.General.Builder(null)
|
val tx = TransactionType.General.Builder(null)
|
||||||
val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")
|
val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")
|
||||||
val oracle = n2.info.serviceIdentities(NodeInterestRates.Oracle.type).first()
|
val oracle = n2.info.serviceIdentities(NodeInterestRates.Oracle.type).first()
|
||||||
val flow = FilteredRatesFlow(tx, oracle, fixOf, "0.675".bd, "0.1".bd)
|
val flow = FilteredRatesFlow(tx, oracle, fixOf, BigDecimal("0.675"), BigDecimal("0.1"))
|
||||||
LogHelper.setLevel("rates")
|
LogHelper.setLevel("rates")
|
||||||
mockNet.runNetwork()
|
mockNet.runNetwork()
|
||||||
val future = n1.services.startFlow(flow).resultFuture
|
val future = n1.services.startFlow(flow).resultFuture
|
||||||
@ -221,7 +220,7 @@ class NodeInterestRatesTest : TestDependencyInjectionBase() {
|
|||||||
// We should now have a valid fix of our tx from the oracle.
|
// We should now have a valid fix of our tx from the oracle.
|
||||||
val fix = tx.toWireTransaction().commands.map { it.value as Fix }.first()
|
val fix = tx.toWireTransaction().commands.map { it.value as Fix }.first()
|
||||||
assertEquals(fixOf, fix.of)
|
assertEquals(fixOf, fix.of)
|
||||||
assertEquals("0.678".bd, fix.value)
|
assertEquals(BigDecimal("0.678"), fix.value)
|
||||||
mockNet.stopNodes()
|
mockNet.stopNodes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ import net.corda.node.utilities.ServiceIdentityGenerator
|
|||||||
import net.corda.cordform.CordformDefinition
|
import net.corda.cordform.CordformDefinition
|
||||||
import net.corda.cordform.CordformContext
|
import net.corda.cordform.CordformContext
|
||||||
import net.corda.cordform.CordformNode
|
import net.corda.cordform.CordformNode
|
||||||
import net.corda.core.stream
|
import net.corda.core.internal.stream
|
||||||
import net.corda.core.toTypedArray
|
import net.corda.core.internal.toTypedArray
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.node.services.transactions.minCorrectReplicas
|
import net.corda.node.services.transactions.minCorrectReplicas
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
@ -3,11 +3,12 @@ package net.corda.vega.portfolio
|
|||||||
import net.corda.client.rpc.notUsed
|
import net.corda.client.rpc.notUsed
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.internal.sum
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.sum
|
|
||||||
import net.corda.vega.contracts.IRSState
|
import net.corda.vega.contracts.IRSState
|
||||||
import net.corda.vega.contracts.SwapData
|
import net.corda.vega.contracts.SwapData
|
||||||
|
import java.math.BigDecimal
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,7 +23,7 @@ data class Portfolio(private val tradeStateAndRefs: List<StateAndRef<IRSState>>,
|
|||||||
val swaps: List<SwapData> by lazy { trades.map { it.swap } }
|
val swaps: List<SwapData> by lazy { trades.map { it.swap } }
|
||||||
val refs: List<StateRef> by lazy { tradeStateAndRefs.map { it.ref } }
|
val refs: List<StateRef> by lazy { tradeStateAndRefs.map { it.ref } }
|
||||||
|
|
||||||
fun getNotionalForParty(party: Party) = trades.map { it.swap.getLegForParty(party).notional }.sum()
|
fun getNotionalForParty(party: Party): BigDecimal = trades.map { it.swap.getLegForParty(party).notional }.sum()
|
||||||
|
|
||||||
fun update(curTrades: List<StateAndRef<IRSState>>): Portfolio {
|
fun update(curTrades: List<StateAndRef<IRSState>>): Portfolio {
|
||||||
return copy(tradeStateAndRefs = curTrades)
|
return copy(tradeStateAndRefs = curTrades)
|
||||||
|
@ -4,6 +4,7 @@ import net.corda.core.internal.until
|
|||||||
import net.corda.core.serialization.SerializeAsToken
|
import net.corda.core.serialization.SerializeAsToken
|
||||||
import net.corda.core.serialization.SerializeAsTokenContext
|
import net.corda.core.serialization.SerializeAsTokenContext
|
||||||
import net.corda.core.serialization.SingletonSerializationToken.Companion.singletonSerializationToken
|
import net.corda.core.serialization.SingletonSerializationToken.Companion.singletonSerializationToken
|
||||||
|
import net.corda.core.internal.until
|
||||||
import net.corda.node.utilities.MutableClock
|
import net.corda.node.utilities.MutableClock
|
||||||
import java.time.Clock
|
import java.time.Clock
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
@ -4,7 +4,7 @@ package net.corda.webserver
|
|||||||
|
|
||||||
import com.typesafe.config.ConfigException
|
import com.typesafe.config.ConfigException
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.rootCause
|
import net.corda.core.internal.rootCause
|
||||||
import net.corda.webserver.internal.NodeWebServer
|
import net.corda.webserver.internal.NodeWebServer
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.lang.management.ManagementFactory
|
import java.lang.management.ManagementFactory
|
||||||
|
Loading…
x
Reference in New Issue
Block a user