mirror of
https://github.com/corda/corda.git
synced 2025-06-21 08:40:03 +00:00
Merge remote-tracking branch 'remotes/open/master' into mnesbit-merge-20180530
# Conflicts: # docs/source/changelog.rst
This commit is contained in:
@ -907,6 +907,13 @@ object Crypto {
|
|||||||
return signatureScheme.schemeCodeName in signatureSchemeMap
|
return signatureScheme.schemeCodeName in signatureSchemeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a public key satisfies algorithm specs.
|
||||||
|
* For instance, an ECC key should lie on the curve and not being point-at-infinity.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun validatePublicKey(key: PublicKey): Boolean = validatePublicKey(findSignatureScheme(key), key)
|
||||||
|
|
||||||
// Validate a key, by checking its algorithmic params.
|
// Validate a key, by checking its algorithmic params.
|
||||||
private fun validateKey(signatureScheme: SignatureScheme, key: Key): Boolean {
|
private fun validateKey(signatureScheme: SignatureScheme, key: Key): Boolean {
|
||||||
return when (key) {
|
return when (key) {
|
||||||
@ -920,7 +927,8 @@ object Crypto {
|
|||||||
private fun validatePublicKey(signatureScheme: SignatureScheme, key: PublicKey): Boolean {
|
private fun validatePublicKey(signatureScheme: SignatureScheme, key: PublicKey): Boolean {
|
||||||
return when (key) {
|
return when (key) {
|
||||||
is BCECPublicKey, is EdDSAPublicKey -> publicKeyOnCurve(signatureScheme, key)
|
is BCECPublicKey, is EdDSAPublicKey -> publicKeyOnCurve(signatureScheme, key)
|
||||||
is BCRSAPublicKey, is BCSphincs256PublicKey -> true // TODO: Check if non-ECC keys satisfy params (i.e. approved/valid RSA modulus size).
|
is BCRSAPublicKey -> key.modulus.bitLength() >= 2048 // Although the recommended RSA key size is 3072, we accept any key >= 2048bits.
|
||||||
|
is BCSphincs256PublicKey -> true
|
||||||
else -> throw IllegalArgumentException("Unsupported key type: ${key::class}")
|
else -> throw IllegalArgumentException("Unsupported key type: ${key::class}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ Unreleased
|
|||||||
==========
|
==========
|
||||||
* Introduced a hierarchy of ``DatabaseMigrationException``s, allowing ``NodeStartup`` to gracefully inform users of problems related to database migrations before exiting with a non-zero code.
|
* Introduced a hierarchy of ``DatabaseMigrationException``s, allowing ``NodeStartup`` to gracefully inform users of problems related to database migrations before exiting with a non-zero code.
|
||||||
|
|
||||||
|
* Shell now kills an ongoing flow when CTRL+C is pressed in the terminal.
|
||||||
|
|
||||||
* ``ServiceHub`` and ``CordaRPCOps`` can now safely be used from multiple threads without incurring in database transaction problems.
|
* ``ServiceHub`` and ``CordaRPCOps`` can now safely be used from multiple threads without incurring in database transaction problems.
|
||||||
|
|
||||||
* Doorman and NetworkMap url's can now be configured individually rather than being assumed to be
|
* Doorman and NetworkMap url's can now be configured individually rather than being assumed to be
|
||||||
@ -105,6 +107,15 @@ Unreleased
|
|||||||
(even if JPA annotation nullable=false was absent).
|
(even if JPA annotation nullable=false was absent).
|
||||||
In case your Cordapps use this entity class to persist data in own custom tables as non Primary Key columns refer to :doc:`upgrade-notes` for upgrade instructions.
|
In case your Cordapps use this entity class to persist data in own custom tables as non Primary Key columns refer to :doc:`upgrade-notes` for upgrade instructions.
|
||||||
|
|
||||||
|
* Adding a public method to check if a public key satisfies Corda recommended algorithm specs, `Crypto.validatePublicKey(java.security.PublicKey)`.
|
||||||
|
For instance, this method will check if an ECC key lies on a valid curve or if an RSA key is >= 2048bits. This might
|
||||||
|
be required for extra key validation checks, e.g., for Doorman to check that a CSR key meets the minimum security requirements.
|
||||||
|
|
||||||
|
.. _changelog_v3.1:
|
||||||
|
|
||||||
|
Version 3.1
|
||||||
|
-----------
|
||||||
|
|
||||||
* Update the fast-classpath-scanner dependent library version from 2.0.21 to 2.12.3
|
* Update the fast-classpath-scanner dependent library version from 2.0.21 to 2.12.3
|
||||||
|
|
||||||
* Added `database.hibernateDialect` node configuration option
|
* Added `database.hibernateDialect` node configuration option
|
||||||
|
@ -13,4 +13,8 @@ package net.corda.nodeapi.internal.protonwrapper.netty
|
|||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
|
|
||||||
data class ConnectionChange(val remoteAddress: InetSocketAddress, val remoteCert: X509Certificate?, val connected: Boolean, val badCert: Boolean)
|
data class ConnectionChange(val remoteAddress: InetSocketAddress, val remoteCert: X509Certificate?, val connected: Boolean, val badCert: Boolean) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ConnectionChange remoteAddress: $remoteAddress connected state: $connected cert subject: ${remoteCert?.subjectDN} cert ok: ${!badCert}"
|
||||||
|
}
|
||||||
|
}
|
@ -141,9 +141,10 @@ class NodeVaultService(
|
|||||||
fun makeUpdate(tx: WireTransaction): Vault.Update<ContractState>? {
|
fun makeUpdate(tx: WireTransaction): Vault.Update<ContractState>? {
|
||||||
val ourNewStates = when (statesToRecord) {
|
val ourNewStates = when (statesToRecord) {
|
||||||
StatesToRecord.NONE -> throw AssertionError("Should not reach here")
|
StatesToRecord.NONE -> throw AssertionError("Should not reach here")
|
||||||
StatesToRecord.ONLY_RELEVANT -> tx.outputs.filter { isRelevant(it.data, keyManagementService.filterMyKeys(tx.outputs.flatMap { it.data.participants.map { it.owningKey } }).toSet()) }
|
StatesToRecord.ONLY_RELEVANT -> tx.outputs.withIndex().filter {
|
||||||
StatesToRecord.ALL_VISIBLE -> tx.outputs
|
isRelevant(it.value.data, keyManagementService.filterMyKeys(tx.outputs.flatMap { it.data.participants.map { it.owningKey } }).toSet()) }
|
||||||
}.map { tx.outRef<ContractState>(it.data) }
|
StatesToRecord.ALL_VISIBLE -> tx.outputs.withIndex()
|
||||||
|
}.map { tx.outRef<ContractState>(it.index) }
|
||||||
|
|
||||||
// Retrieve all unconsumed states for this transaction's inputs
|
// Retrieve all unconsumed states for this transaction's inputs
|
||||||
val consumedStates = loadStates(tx.inputs)
|
val consumedStates = loadStates(tx.inputs)
|
||||||
|
@ -14,10 +14,7 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import com.nhaarman.mockito_kotlin.argThat
|
import com.nhaarman.mockito_kotlin.argThat
|
||||||
import com.nhaarman.mockito_kotlin.doNothing
|
import com.nhaarman.mockito_kotlin.doNothing
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.contracts.Issued
|
|
||||||
import net.corda.core.contracts.StateAndRef
|
|
||||||
import net.corda.core.contracts.StateRef
|
|
||||||
import net.corda.core.crypto.NullKeys
|
import net.corda.core.crypto.NullKeys
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.identity.*
|
import net.corda.core.identity.*
|
||||||
@ -697,4 +694,50 @@ class NodeVaultServiceTest {
|
|||||||
}
|
}
|
||||||
assertEquals(currentCashStates + 1, countCash())
|
assertEquals(currentCashStates + 1, countCash())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `insert equal cash states issued by single transaction`() {
|
||||||
|
val nodeIdentity = MEGA_CORP
|
||||||
|
val coins = listOf(1.DOLLARS, 1.DOLLARS).map { it.issuedBy(nodeIdentity.ref(1)) }
|
||||||
|
|
||||||
|
//create single transaction with 2 'identical' cash outputs
|
||||||
|
val txb = TransactionBuilder(DUMMY_NOTARY)
|
||||||
|
coins.map { txb.addOutputState(TransactionState(Cash.State(it, nodeIdentity), Cash.PROGRAM_ID, DUMMY_NOTARY)) }
|
||||||
|
txb.addCommand(Cash.Commands.Issue(), nodeIdentity.owningKey)
|
||||||
|
val issueTx = txb.toWireTransaction(services)
|
||||||
|
|
||||||
|
// ensure transaction contract state is persisted in DBStorage
|
||||||
|
val signedIssuedTx = services.signInitialTransaction(txb)
|
||||||
|
(services.validatedTransactions as WritableTransactionStorage).addTransaction(signedIssuedTx)
|
||||||
|
|
||||||
|
database.transaction { vaultService.notify(StatesToRecord.ONLY_RELEVANT, issueTx) }
|
||||||
|
|
||||||
|
val recordedStates = database.transaction {
|
||||||
|
vaultService.queryBy<Cash.State>().states.size
|
||||||
|
}
|
||||||
|
assertThat(recordedStates).isEqualTo(coins.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `insert different cash states issued by single transaction`() {
|
||||||
|
val nodeIdentity = MEGA_CORP
|
||||||
|
val coins = listOf(2.DOLLARS, 1.DOLLARS).map { it.issuedBy(nodeIdentity.ref(1)) }
|
||||||
|
|
||||||
|
//create single transaction with 2 'identical' cash outputs
|
||||||
|
val txb = TransactionBuilder(DUMMY_NOTARY)
|
||||||
|
coins.map { txb.addOutputState(TransactionState(Cash.State(it, nodeIdentity), Cash.PROGRAM_ID, DUMMY_NOTARY)) }
|
||||||
|
txb.addCommand(Cash.Commands.Issue(), nodeIdentity.owningKey)
|
||||||
|
val issueTx = txb.toWireTransaction(services)
|
||||||
|
|
||||||
|
// ensure transaction contract state is persisted in DBStorage
|
||||||
|
val signedIssuedTx = services.signInitialTransaction(txb)
|
||||||
|
(services.validatedTransactions as WritableTransactionStorage).addTransaction(signedIssuedTx)
|
||||||
|
|
||||||
|
database.transaction { vaultService.notify(StatesToRecord.ONLY_RELEVANT, issueTx) }
|
||||||
|
|
||||||
|
val recordedStates = database.transaction {
|
||||||
|
vaultService.queryBy<Cash.State>().states.size
|
||||||
|
}
|
||||||
|
assertThat(recordedStates).isEqualTo(coins.size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,18 @@ import net.corda.core.CordaException
|
|||||||
import net.corda.core.concurrent.CordaFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.contracts.UniqueIdentifier
|
import net.corda.core.contracts.UniqueIdentifier
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.Emoji
|
||||||
import net.corda.core.internal.concurrent.doneFuture
|
import net.corda.core.internal.concurrent.doneFuture
|
||||||
import net.corda.core.internal.concurrent.openFuture
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
import net.corda.core.messaging.*
|
import net.corda.core.internal.createDirectories
|
||||||
|
import net.corda.core.internal.div
|
||||||
|
import net.corda.core.internal.rootCause
|
||||||
|
import net.corda.core.internal.uncheckedCast
|
||||||
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
|
import net.corda.core.messaging.DataFeed
|
||||||
|
import net.corda.core.messaging.FlowProgressHandle
|
||||||
|
import net.corda.core.messaging.StateMachineUpdate
|
||||||
|
import net.corda.core.messaging.pendingFlowsCount
|
||||||
import net.corda.tools.shell.utlities.ANSIProgressRenderer
|
import net.corda.tools.shell.utlities.ANSIProgressRenderer
|
||||||
import net.corda.tools.shell.utlities.StdoutANSIProgressRenderer
|
import net.corda.tools.shell.utlities.StdoutANSIProgressRenderer
|
||||||
import org.crsh.command.InvocationContext
|
import org.crsh.command.InvocationContext
|
||||||
@ -278,12 +286,19 @@ object InteractiveShell {
|
|||||||
|
|
||||||
val latch = CountDownLatch(1)
|
val latch = CountDownLatch(1)
|
||||||
ansiProgressRenderer.render(stateObservable, { latch.countDown() })
|
ansiProgressRenderer.render(stateObservable, { latch.countDown() })
|
||||||
try {
|
// Wait for the flow to end and the progress tracker to notice. By the time the latch is released
|
||||||
// Wait for the flow to end and the progress tracker to notice. By the time the latch is released
|
// the tracker is done with the screen.
|
||||||
// the tracker is done with the screen.
|
while (!Thread.currentThread().isInterrupted) {
|
||||||
latch.await()
|
try {
|
||||||
} catch (e: InterruptedException) {
|
latch.await()
|
||||||
// TODO: When the flow framework allows us to kill flows mid-flight, do so here.
|
} catch (e: InterruptedException) {
|
||||||
|
try {
|
||||||
|
rpcOps.killFlow(stateObservable.id)
|
||||||
|
} finally {
|
||||||
|
Thread.currentThread().interrupt()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stateObservable.returnValue.get()?.apply {
|
stateObservable.returnValue.get()?.apply {
|
||||||
if (this !is Throwable) {
|
if (this !is Throwable) {
|
||||||
|
Reference in New Issue
Block a user