mirror of
https://github.com/corda/corda.git
synced 2024-12-27 08:22:35 +00:00
Merge remote-tracking branch 'open/master' into shams-os-merge-040118
This commit is contained in:
commit
b577b680ff
@ -30,6 +30,7 @@ import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey
|
||||
import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter
|
||||
import org.bouncycastle.jce.ECNamedCurveTable
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec
|
||||
import org.bouncycastle.jce.spec.ECPrivateKeySpec
|
||||
import org.bouncycastle.jce.spec.ECPublicKeySpec
|
||||
@ -808,7 +809,7 @@ object Crypto {
|
||||
/**
|
||||
* Returns a key pair derived from the given [BigInteger] entropy. This is useful for unit tests
|
||||
* and other cases where you want hard-coded private keys.
|
||||
* Currently, [EDDSA_ED25519_SHA512] is the sole scheme supported for this operation.
|
||||
* Currently, the following schemes are supported: [EDDSA_ED25519_SHA512], [ECDSA_SECP256R1_SHA256] and [ECDSA_SECP256K1_SHA256].
|
||||
* @param signatureScheme a supported [SignatureScheme], see [Crypto].
|
||||
* @param entropy a [BigInteger] value.
|
||||
* @return a new [KeyPair] from an entropy input.
|
||||
@ -818,6 +819,7 @@ object Crypto {
|
||||
fun deriveKeyPairFromEntropy(signatureScheme: SignatureScheme, entropy: BigInteger): KeyPair {
|
||||
return when (signatureScheme) {
|
||||
EDDSA_ED25519_SHA512 -> deriveEdDSAKeyPairFromEntropy(entropy)
|
||||
ECDSA_SECP256R1_SHA256, ECDSA_SECP256K1_SHA256 -> deriveECDSAKeyPairFromEntropy(signatureScheme, entropy)
|
||||
else -> throw IllegalArgumentException("Unsupported signature scheme for fixed entropy-based key pair " +
|
||||
"generation: ${signatureScheme.schemeCodeName}")
|
||||
}
|
||||
@ -832,6 +834,9 @@ 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 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.
|
||||
@ -840,6 +845,32 @@ object Crypto {
|
||||
return KeyPair(EdDSAPublicKey(pub), EdDSAPrivateKey(priv))
|
||||
}
|
||||
|
||||
// Custom key pair generator from an entropy required for various tests. It is similar to deriveKeyPairECDSA,
|
||||
// but the accepted range of the input entropy is more relaxed:
|
||||
// 2 <= entropy < N, where N is the order of base-point G.
|
||||
private fun deriveECDSAKeyPairFromEntropy(signatureScheme: SignatureScheme, entropy: BigInteger): KeyPair {
|
||||
val parameterSpec = signatureScheme.algSpec as ECNamedCurveParameterSpec
|
||||
|
||||
// The entropy might be a negative number and/or out of range (e.g. PRNG output).
|
||||
// In such cases we retry with hash(currentEntropy).
|
||||
while (entropy < ECConstants.TWO || entropy >= parameterSpec.n) {
|
||||
return deriveECDSAKeyPairFromEntropy(signatureScheme, BigInteger(1, entropy.toByteArray().sha256().bytes))
|
||||
}
|
||||
|
||||
val privateKeySpec = ECPrivateKeySpec(entropy, parameterSpec)
|
||||
val priv = BCECPrivateKey("EC", privateKeySpec, BouncyCastleProvider.CONFIGURATION)
|
||||
|
||||
val pointQ = FixedPointCombMultiplier().multiply(parameterSpec.g, entropy)
|
||||
while (pointQ.isInfinity) {
|
||||
// Instead of throwing an exception, we retry with hash(entropy).
|
||||
return deriveECDSAKeyPairFromEntropy(signatureScheme, BigInteger(1, entropy.toByteArray().sha256().bytes))
|
||||
}
|
||||
val publicKeySpec = ECPublicKeySpec(pointQ, parameterSpec)
|
||||
val pub = BCECPublicKey("EC", publicKeySpec, BouncyCastleProvider.CONFIGURATION)
|
||||
|
||||
return KeyPair(pub, priv)
|
||||
}
|
||||
|
||||
// Compute the HMAC-SHA512 using a privateKey as the MAC_key and a seed ByteArray.
|
||||
private fun deriveHMAC(privateKey: PrivateKey, seed: ByteArray): ByteArray {
|
||||
// Compute hmac(privateKey, seed).
|
||||
|
@ -118,18 +118,19 @@ fun Iterable<TransactionSignature>.byKeys() = map { it.by }.toSet()
|
||||
|
||||
// Allow Kotlin destructuring:
|
||||
// val (private, public) = keyPair
|
||||
/* The [PrivateKey] of this [KeyPair] .*/
|
||||
/* The [PrivateKey] of this [KeyPair]. */
|
||||
operator fun KeyPair.component1(): PrivateKey = this.private
|
||||
/* The [PublicKey] of this [KeyPair] .*/
|
||||
/* The [PublicKey] of this [KeyPair]. */
|
||||
operator fun KeyPair.component2(): PublicKey = this.public
|
||||
|
||||
/** A simple wrapper that will make it easier to swap out the EC algorithm we use in future. */
|
||||
/** A simple wrapper that will make it easier to swap out the signature algorithm we use in future. */
|
||||
fun generateKeyPair(): KeyPair = Crypto.generateKeyPair()
|
||||
|
||||
/**
|
||||
* Returns a key pair derived from the given private key entropy. This is useful for unit tests and other cases where
|
||||
* you want hard-coded private keys.
|
||||
* This currently works for the default signature scheme EdDSA ed25519 only.
|
||||
* @param entropy a [BigInteger] value.
|
||||
* @return a deterministically generated [KeyPair] for the [Crypto.DEFAULT_SIGNATURE_SCHEME].
|
||||
*/
|
||||
fun entropyToKeyPair(entropy: BigInteger): KeyPair = Crypto.deriveKeyPairFromEntropy(entropy)
|
||||
|
||||
|
@ -10,7 +10,17 @@ import net.corda.core.serialization.CordaSerializable
|
||||
*/
|
||||
@DoNotImplement
|
||||
interface FlowLogicRefFactory {
|
||||
/**
|
||||
* Construct a FlowLogicRef. This is intended for cases where the calling code has the relevant class already
|
||||
* and can provide it directly.
|
||||
*/
|
||||
@Deprecated("This should be avoided, and the version which takes a class name used instead to avoid requiring the class on the classpath to deserialize calling code")
|
||||
fun create(flowClass: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef
|
||||
/**
|
||||
* Construct a FlowLogicRef. This is intended for cases where the calling code does not want to require the flow
|
||||
* class on the classpath for all cases where the calling code is loaded.
|
||||
*/
|
||||
fun create(flowClassName: String, vararg args: Any?): FlowLogicRef
|
||||
fun createForRPC(flowClass: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef
|
||||
fun toFlowLogic(ref: FlowLogicRef): FlowLogic<*>
|
||||
}
|
||||
|
@ -14,21 +14,22 @@ 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.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Test
|
||||
import java.math.BigInteger
|
||||
import java.security.KeyPairGenerator
|
||||
import java.util.*
|
||||
import kotlin.test.*
|
||||
|
||||
/**
|
||||
* Run tests for cryptographic algorithms
|
||||
* Run tests for cryptographic algorithms.
|
||||
*/
|
||||
class CryptoUtilsTest {
|
||||
|
||||
private val testString = "Hello World"
|
||||
private val testBytes = testString.toByteArray()
|
||||
private val testBytes = "Hello World".toByteArray()
|
||||
|
||||
// key generation test
|
||||
@Test
|
||||
@ -781,4 +782,113 @@ class CryptoUtilsTest {
|
||||
assertEquals(dpriv2, dpriv_2)
|
||||
assertEquals(dpub2, dpub_2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `EdDSA ed25519 keyPair from entropy`() {
|
||||
val keyPairPositive = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger("10"))
|
||||
assertEquals("DLBL3iHCp9uRReWhhCGfCsrxZZpfAm9h9GLbfN8ijqXTq", keyPairPositive.public.toStringShort())
|
||||
|
||||
val keyPairNegative = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger("-10"))
|
||||
assertEquals("DLC5HXnYsJAFqmM9hgPj5G8whQ4TpyE9WMBssqCayLBwA2", keyPairNegative.public.toStringShort())
|
||||
|
||||
val keyPairZero = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger("0"))
|
||||
assertEquals("DL4UVhGh4tqu1G86UVoGNaDDNCMsBtNHzE6BSZuNNJN7W2", keyPairZero.public.toStringShort())
|
||||
|
||||
val keyPairOne = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger("1"))
|
||||
assertEquals("DL8EZUdHixovcCynKMQzrMWBnXQAcbVDHi6ArPphqwJVzq", keyPairOne.public.toStringShort())
|
||||
|
||||
val keyPairBiggerThan256bits = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger("2").pow(258).minus(BigInteger.TEN))
|
||||
assertEquals("DLB9K1UiBrWonn481z6NzkqoWHjMBXpfDeaet3wiwRNWSU", keyPairBiggerThan256bits.public.toStringShort())
|
||||
// The underlying implementation uses the first 256 bytes of the entropy. Thus, 2^258-10 and 2^258-50 and 2^514-10 have the same impact.
|
||||
val keyPairBiggerThan256bitsV2 = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger("2").pow(258).minus(BigInteger("50")))
|
||||
assertEquals("DLB9K1UiBrWonn481z6NzkqoWHjMBXpfDeaet3wiwRNWSU", keyPairBiggerThan256bitsV2.public.toStringShort())
|
||||
val keyPairBiggerThan512bits = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger("2").pow(514).minus(BigInteger.TEN))
|
||||
assertEquals("DLB9K1UiBrWonn481z6NzkqoWHjMBXpfDeaet3wiwRNWSU", keyPairBiggerThan512bits.public.toStringShort())
|
||||
|
||||
// Try another big number.
|
||||
val keyPairBiggerThan258bits = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger("2").pow(259).plus(BigInteger.ONE))
|
||||
assertEquals("DL5tEFVMXMGrzwjfCAW34JjkhsRkPfFyJ38iEnmpB6L2Z9", keyPairBiggerThan258bits.public.toStringShort())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ECDSA R1 keyPair from entropy`() {
|
||||
val keyPairPositive = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256R1_SHA256, BigInteger("10"))
|
||||
assertEquals("DLHDcxuSt9J3cbjd2Dsx4rAgYYA7BAP7A8VLrFiq1tH9yy", keyPairPositive.public.toStringShort())
|
||||
// The underlying implementation uses the hash of entropy if it is out of range 2 < entropy < N, where N the order of the group.
|
||||
val keyPairNegative = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256R1_SHA256, BigInteger("-10"))
|
||||
assertEquals("DLBASmjiMZuu1g3EtdHJxfSueXE8PRoUWbkdU61Qcnpamt", keyPairNegative.public.toStringShort())
|
||||
|
||||
val keyPairZero = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256R1_SHA256, BigInteger("0"))
|
||||
assertEquals("DLH2FEHEnsT3MpCJt2gfyNjpqRqcBxeupK4YRPXvDsVEkb", keyPairZero.public.toStringShort())
|
||||
// BigIntenger.Zero is out or range, so 1 and hash(1.toByteArray) would have the same impact.
|
||||
val zeroHashed = BigInteger(1, BigInteger("0").toByteArray().sha256().bytes)
|
||||
// Check oneHashed < N (order of the group), otherwise we would need an extra hash.
|
||||
assertEquals(-1, zeroHashed.compareTo((Crypto.ECDSA_SECP256R1_SHA256.algSpec as ECNamedCurveParameterSpec).n))
|
||||
val keyPairZeroHashed = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256R1_SHA256, zeroHashed)
|
||||
assertEquals("DLH2FEHEnsT3MpCJt2gfyNjpqRqcBxeupK4YRPXvDsVEkb", keyPairZeroHashed.public.toStringShort())
|
||||
|
||||
val keyPairOne = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256R1_SHA256, BigInteger("1"))
|
||||
assertEquals("DLHrtKwjv6onq9HcrQDJPs8Cgtai5mZU5ZU6sb1ivJjx3z", keyPairOne.public.toStringShort())
|
||||
// BigIntenger.ONE is out or range, so 1 and hash(1.toByteArray) would have the same impact.
|
||||
val oneHashed = BigInteger(1, BigInteger("1").toByteArray().sha256().bytes)
|
||||
// Check oneHashed < N (order of the group), otherwise we would need an extra hash.
|
||||
assertEquals(-1, oneHashed.compareTo((Crypto.ECDSA_SECP256R1_SHA256.algSpec as ECNamedCurveParameterSpec).n))
|
||||
val keyPairOneHashed = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256R1_SHA256, oneHashed)
|
||||
assertEquals("DLHrtKwjv6onq9HcrQDJPs8Cgtai5mZU5ZU6sb1ivJjx3z", keyPairOneHashed.public.toStringShort())
|
||||
|
||||
// 2 is in the range.
|
||||
val keyPairTwo = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256R1_SHA256, BigInteger("2"))
|
||||
assertEquals("DLFoz6txJ3vHcKNSM1vFxHJUoEQ69PorBwW64dHsAnEoZB", keyPairTwo.public.toStringShort())
|
||||
|
||||
// Try big numbers that are out of range.
|
||||
val keyPairBiggerThan256bits = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256R1_SHA256, BigInteger("2").pow(258).minus(BigInteger.TEN))
|
||||
assertEquals("DLBv6fZqaCTbE4L7sgjbt19biXHMgU9CzR5s8g8XBJjZ11", keyPairBiggerThan256bits.public.toStringShort())
|
||||
val keyPairBiggerThan256bitsV2 = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256R1_SHA256, BigInteger("2").pow(258).minus(BigInteger("50")))
|
||||
assertEquals("DLANmjhGSVdLyghxcPHrn3KuGatscf6LtvqifUDxw7SGU8", keyPairBiggerThan256bitsV2.public.toStringShort())
|
||||
val keyPairBiggerThan512bits = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256R1_SHA256, BigInteger("2").pow(514).minus(BigInteger.TEN))
|
||||
assertEquals("DL9sKwMExBTD3MnJN6LWGqo496Erkebs9fxZtXLVJUBY9Z", keyPairBiggerThan512bits.public.toStringShort())
|
||||
val keyPairBiggerThan258bits = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256R1_SHA256, BigInteger("2").pow(259).plus(BigInteger.ONE))
|
||||
assertEquals("DLBwjWwPJSF9E7b1NWaSbEJ4oK8CF7RDGWd648TiBhZoL1", keyPairBiggerThan258bits.public.toStringShort())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ECDSA K1 keyPair from entropy`() {
|
||||
val keyPairPositive = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, BigInteger("10"))
|
||||
assertEquals("DL6pYKUgH17az8MLdonvvUtUPN8TqwpCGcdgLr7vg3skCU", keyPairPositive.public.toStringShort())
|
||||
// The underlying implementation uses the hash of entropy if it is out of range 2 <= entropy < N, where N the order of the group.
|
||||
val keyPairNegative = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, BigInteger("-10"))
|
||||
assertEquals("DLnpXhxece69Nyqgm3pPt3yV7ESQYDJKoYxs1hKgfBAEu", keyPairNegative.public.toStringShort())
|
||||
|
||||
val keyPairZero = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, BigInteger("0"))
|
||||
assertEquals("DLBC28e18T6KsYwjTFfUWJfhvHjvYVapyVf6antnqUkbgd", keyPairZero.public.toStringShort())
|
||||
// BigIntenger.Zero is out or range, so 1 and hash(1.toByteArray) would have the same impact.
|
||||
val zeroHashed = BigInteger(1, BigInteger("0").toByteArray().sha256().bytes)
|
||||
// Check oneHashed < N (order of the group), otherwise we would need an extra hash.
|
||||
assertEquals(-1, zeroHashed.compareTo((Crypto.ECDSA_SECP256K1_SHA256.algSpec as ECNamedCurveParameterSpec).n))
|
||||
val keyPairZeroHashed = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, zeroHashed)
|
||||
assertEquals("DLBC28e18T6KsYwjTFfUWJfhvHjvYVapyVf6antnqUkbgd", keyPairZeroHashed.public.toStringShort())
|
||||
|
||||
val keyPairOne = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, BigInteger("1"))
|
||||
assertEquals("DLBimRXdEQhJUTpL6f9ri9woNdsze6mwkRrhsML13Eh7ET", keyPairOne.public.toStringShort())
|
||||
// BigIntenger.ONE is out or range, so 1 and hash(1.toByteArray) would have the same impact.
|
||||
val oneHashed = BigInteger(1, BigInteger("1").toByteArray().sha256().bytes)
|
||||
// Check oneHashed < N (order of the group), otherwise we would need an extra hash.
|
||||
assertEquals(-1, oneHashed.compareTo((Crypto.ECDSA_SECP256K1_SHA256.algSpec as ECNamedCurveParameterSpec).n))
|
||||
val keyPairOneHashed = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, oneHashed)
|
||||
assertEquals("DLBimRXdEQhJUTpL6f9ri9woNdsze6mwkRrhsML13Eh7ET", keyPairOneHashed.public.toStringShort())
|
||||
|
||||
// 2 is in the range.
|
||||
val keyPairTwo = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, BigInteger("2"))
|
||||
assertEquals("DLG32UWaevGw9YY7w1Rf9mmK88biavgpDnJA9bG4GapVPs", keyPairTwo.public.toStringShort())
|
||||
|
||||
// Try big numbers that are out of range.
|
||||
val keyPairBiggerThan256bits = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, BigInteger("2").pow(258).minus(BigInteger.TEN))
|
||||
assertEquals("DLGHsdv2xeAuM7n3sBc6mFfiphXe6VSf3YxqvviKDU6Vbd", keyPairBiggerThan256bits.public.toStringShort())
|
||||
val keyPairBiggerThan256bitsV2 = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, BigInteger("2").pow(258).minus(BigInteger("50")))
|
||||
assertEquals("DL9yJfiNGqteRrKPjGUkRQkeqzuQ4kwcYQWMCi5YKuUHrk", keyPairBiggerThan256bitsV2.public.toStringShort())
|
||||
val keyPairBiggerThan512bits = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, BigInteger("2").pow(514).minus(BigInteger.TEN))
|
||||
assertEquals("DL3Wr5EQGrMTaKBy5XMvG8rvSfKX1AYZLCRU8kixGbxt1E", keyPairBiggerThan512bits.public.toStringShort())
|
||||
val keyPairBiggerThan258bits = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, BigInteger("2").pow(259).plus(BigInteger.ONE))
|
||||
assertEquals("DL7NbssqvuuJ4cqFkkaVYu9j1MsVswESGgCfbqBS9ULwuM", keyPairBiggerThan258bits.public.toStringShort())
|
||||
}
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ import java.util.*
|
||||
class CashExitFlow(private val amount: Amount<Currency>,
|
||||
private val issuerRef: OpaqueBytes,
|
||||
progressTracker: ProgressTracker) : AbstractCashFlow<AbstractCashFlow.Result>(progressTracker) {
|
||||
constructor(amount: Amount<Currency>, issueRef: OpaqueBytes) : this(amount, issueRef, tracker())
|
||||
constructor(request: ExitRequest) : this(request.amount, request.issueRef, tracker())
|
||||
constructor(amount: Amount<Currency>, issuerRef: OpaqueBytes) : this(amount, issuerRef, tracker())
|
||||
constructor(request: ExitRequest) : this(request.amount, request.issuerRef, tracker())
|
||||
|
||||
companion object {
|
||||
fun tracker() = ProgressTracker(GENERATING_TX, SIGNING_TX, FINALISING_TX)
|
||||
@ -78,5 +78,5 @@ class CashExitFlow(private val amount: Amount<Currency>,
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
class ExitRequest(amount: Amount<Currency>, val issueRef: OpaqueBytes) : AbstractRequest(amount)
|
||||
class ExitRequest(amount: Amount<Currency>, val issuerRef: OpaqueBytes) : AbstractRequest(amount)
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ Generates a text summary of Corda's public API that we can check for API-breakin
|
||||
$ gradlew generateApi
|
||||
```
|
||||
|
||||
See [here](../../docs/source/api-index.rst) for Corda's public API strategy. We will need to
|
||||
See [here](../../docs/source/corda-api.rst) for Corda's public API strategy. We will need to
|
||||
apply this plugin to other modules in future Corda releases as those modules' APIs stabilise.
|
||||
|
||||
Basically, this plugin will document a module's `public` and `protected` classes/methods/fields,
|
||||
|
@ -85,7 +85,7 @@ private fun <T : Any> propertiesForSerializationFromConstructor(kotlinConstructo
|
||||
val matchingProperty = properties[name] ?:
|
||||
try {
|
||||
clazz.getDeclaredField(param.name)
|
||||
throw NotSerializableException("Property '$name' or it's getter is non public, this renders class '$clazz' unserializable")
|
||||
throw NotSerializableException("Property '$name' or its getter is non public, this renders class '$clazz' unserializable")
|
||||
} catch (e: NoSuchFieldException) {
|
||||
throw NotSerializableException("No property matching constructor parameter named '$name' of '$clazz'. " +
|
||||
"If using Java, check that you have the -parameters option specified in the Java compiler. " +
|
||||
|
@ -10,7 +10,7 @@ public class ErrorMessageTests {
|
||||
private String errMsg(String property, String testname) {
|
||||
return "Property '"
|
||||
+ property
|
||||
+ "' or it's getter is non public, this renders class 'class "
|
||||
+ "' or its getter is non public, this renders class 'class "
|
||||
+ testname
|
||||
+ "$C' unserializable -> class "
|
||||
+ testname
|
||||
|
@ -10,7 +10,7 @@ class ErrorMessagesTests {
|
||||
}
|
||||
|
||||
private fun errMsg(property:String, testname: String) =
|
||||
"Property '$property' or it's getter is non public, this renders class 'class $testname\$C' unserializable -> class $testname\$C"
|
||||
"Property '$property' or its getter is non public, this renders class 'class $testname\$C' unserializable -> class $testname\$C"
|
||||
|
||||
@Test
|
||||
fun privateProperty() {
|
||||
|
@ -40,6 +40,18 @@ class FlowLogicRefFactoryImpl(private val classloader: ClassLoader) : SingletonS
|
||||
return createForRPC(flowClass, *args)
|
||||
}
|
||||
|
||||
override fun create(flowClassName: String, vararg args: Any?): FlowLogicRef {
|
||||
val flowClass = Class.forName(flowClassName, true, classloader).asSubclass(FlowLogic::class.java)
|
||||
if (flowClass == null) {
|
||||
throw IllegalArgumentException("The class $flowClassName is not a subclass of FlowLogic.")
|
||||
} else {
|
||||
if (!flowClass.isAnnotationPresent(SchedulableFlow::class.java)) {
|
||||
throw IllegalFlowLogicException(flowClass, "because it's not a schedulable flow")
|
||||
}
|
||||
return createForRPC(flowClass, *args)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createForRPC(flowClass: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef {
|
||||
// TODO: This is used via RPC but it's probably better if we pass in argument names and values explicitly
|
||||
// to avoid requiring only a single constructor.
|
||||
|
@ -30,6 +30,7 @@ import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.time.Instant
|
||||
import kotlin.reflect.jvm.jvmName
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class ScheduledFlowTests {
|
||||
@ -52,7 +53,7 @@ class ScheduledFlowTests {
|
||||
override val linearId: UniqueIdentifier = UniqueIdentifier()) : SchedulableState, LinearState {
|
||||
override fun nextScheduledActivity(thisStateRef: StateRef, flowLogicRefFactory: FlowLogicRefFactory): ScheduledActivity? {
|
||||
return if (!processed) {
|
||||
val logicRef = flowLogicRefFactory.create(ScheduledFlow::class.java, thisStateRef)
|
||||
val logicRef = flowLogicRefFactory.create(ScheduledFlow::class.jvmName, thisStateRef)
|
||||
ScheduledActivity(logicRef, creationTime)
|
||||
} else {
|
||||
null
|
||||
|
@ -1,17 +1,20 @@
|
||||
package net.corda.node.services.events
|
||||
package net.corda.node.services.statemachine
|
||||
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.IllegalFlowLogicException
|
||||
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
|
||||
import net.corda.core.flows.SchedulableFlow
|
||||
import org.junit.Test
|
||||
import java.time.Duration
|
||||
import kotlin.reflect.jvm.jvmName
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class FlowLogicRefTest {
|
||||
class FlowLogicRefFactoryImplTest {
|
||||
|
||||
data class ParamType1(val value: Int)
|
||||
data class ParamType2(val value: String)
|
||||
|
||||
@Suppress("UNUSED_PARAMETER", "unused") // Things are used via reflection.
|
||||
@SchedulableFlow
|
||||
class KotlinFlowLogic(A: ParamType1, b: ParamType2) : FlowLogic<Unit>() {
|
||||
constructor() : this(ParamType1(1), ParamType2("2"))
|
||||
|
||||
@ -26,6 +29,7 @@ class FlowLogicRefTest {
|
||||
override fun call() = Unit
|
||||
}
|
||||
|
||||
@SchedulableFlow
|
||||
class KotlinNoArgFlowLogic : FlowLogic<Unit>() {
|
||||
override fun call() = Unit
|
||||
}
|
||||
@ -37,18 +41,18 @@ class FlowLogicRefTest {
|
||||
private val flowLogicRefFactory = FlowLogicRefFactoryImpl(FlowLogicRefFactoryImpl::class.java.classLoader)
|
||||
@Test
|
||||
fun `create kotlin no arg`() {
|
||||
flowLogicRefFactory.createForRPC(KotlinNoArgFlowLogic::class.java)
|
||||
flowLogicRefFactory.create(KotlinNoArgFlowLogic::class.jvmName)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `create kotlin`() {
|
||||
fun `should create kotlin types`() {
|
||||
val args = mapOf(Pair("A", ParamType1(1)), Pair("b", ParamType2("Hello Jack")))
|
||||
flowLogicRefFactory.createKotlin(KotlinFlowLogic::class.java, args)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `create primary`() {
|
||||
flowLogicRefFactory.createForRPC(KotlinFlowLogic::class.java, ParamType1(1), ParamType2("Hello Jack"))
|
||||
flowLogicRefFactory.create(KotlinFlowLogic::class.jvmName, ParamType1(1), ParamType2("Hello Jack"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -76,6 +80,6 @@ class FlowLogicRefTest {
|
||||
|
||||
@Test(expected = IllegalFlowLogicException::class)
|
||||
fun `create for non-schedulable flow logic`() {
|
||||
flowLogicRefFactory.create(NonSchedulableFlow::class.java)
|
||||
flowLogicRefFactory.create(NonSchedulableFlow::class.jvmName)
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ import net.corda.testing.node.startFlow
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
@ -99,6 +100,7 @@ class NotaryServiceTests {
|
||||
assertThat(ex.error).isInstanceOf(NotaryError.TimeWindowInvalid::class.java)
|
||||
}
|
||||
|
||||
@Ignore("Only applies to deterministic signature schemes (e.g. EdDSA) and when deterministic metadata is attached (no timestamps or nonces)")
|
||||
@Test
|
||||
fun `should sign identical transaction multiple times (signing is idempotent)`() {
|
||||
val stx = run {
|
||||
|
@ -616,7 +616,7 @@ class InterestRateSwap : Contract {
|
||||
|
||||
// This is perhaps not how we should determine the time point in the business day, but instead expect the schedule to detail some of these aspects
|
||||
val instant = suggestInterestRateAnnouncementTimeWindow(index = nextFixingOf.name, source = floatingLeg.indexSource, date = nextFixingOf.forDay).fromTime!!
|
||||
return ScheduledActivity(flowLogicRefFactory.create(FixingFlow.FixingRoleDecider::class.java, thisStateRef), instant)
|
||||
return ScheduledActivity(flowLogicRefFactory.create("net.corda.irs.flows.FixingFlow\$FixingRoleDecider", thisStateRef), instant)
|
||||
}
|
||||
// DOCEND 1
|
||||
|
||||
|
@ -7,7 +7,6 @@ import net.corda.core.identity.Party
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.finance.contracts.DealState
|
||||
import net.corda.vega.flows.SimmRevaluation
|
||||
import java.time.LocalDate
|
||||
import java.time.ZoneOffset
|
||||
import java.time.temporal.ChronoUnit
|
||||
@ -32,7 +31,7 @@ data class PortfolioState(val portfolio: List<StateRef>,
|
||||
val valuer: AbstractParty get() = participants[0]
|
||||
|
||||
override fun nextScheduledActivity(thisStateRef: StateRef, flowLogicRefFactory: FlowLogicRefFactory): ScheduledActivity {
|
||||
val flow = flowLogicRefFactory.create(SimmRevaluation.Initiator::class.java, thisStateRef, LocalDate.now())
|
||||
val flow = flowLogicRefFactory.create("net.corda.vega.flows.SimmRevaluation\$Initiator", thisStateRef, LocalDate.now())
|
||||
return ScheduledActivity(flow, LocalDate.now().plus(1, ChronoUnit.DAYS).atStartOfDay().toInstant(ZoneOffset.UTC))
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import com.nhaarman.mockito_kotlin.doReturn
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import net.corda.core.DoNotImplement
|
||||
import net.corda.core.crypto.entropyToKeyPair
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.random63BitValue
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
@ -326,7 +327,8 @@ open class MockNetwork(private val cordappPackages: List<String>,
|
||||
// This is not thread safe, but node construction is done on a single thread, so that should always be fine
|
||||
override fun generateKeyPair(): KeyPair {
|
||||
counter = counter.add(BigInteger.ONE)
|
||||
return entropyToKeyPair(counter)
|
||||
// The MockNode specifically uses EdDSA keys as they are fixed and stored in json files for some tests (e.g IRSSimulation).
|
||||
return Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, counter)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -152,7 +152,7 @@ class ExplorerSimulation(private val options: OptionSet) {
|
||||
it.startFlow(::CashIssueAndPaymentFlow, request).log(i, "${request.amount.token}Issuer")
|
||||
}
|
||||
is ExitRequest -> issuers[request.amount.token]?.let {
|
||||
println("${Instant.now()} [$i] EXITING ${request.amount} with ref ${request.issueRef}")
|
||||
println("${Instant.now()} [$i] EXITING ${request.amount} with ref ${request.issuerRef}")
|
||||
it.startFlow(::CashExitFlow, request).log(i, "${request.amount.token}Exit")
|
||||
}
|
||||
else -> throw IllegalArgumentException("Unsupported command: $request")
|
||||
|
Loading…
Reference in New Issue
Block a user