CORDA-3009 - Migrate identity service to use to string short ()

* migrate PersistentIdentityService to use key.toShortString()
update definition of PublicKeyToExternalId mapping to allow fast lookup by externalId/publicKey

* fix misspelled table name

* add test of migration script

* add design document for proposal to move IdentityService to using the correct PK.toStringShort() method for hashing a publickey

* add enterprise testing considerations to design

* address review comments

* fix compilation errors

* modify PublicKeyToOwningIdentityCache to use toStringShort() as it's lookup key

* address syzmon's code review comments
This commit is contained in:
Stefano Franz 2019-08-28 14:16:18 +00:00 committed by GitHub
parent 7f89577f83
commit e35c0c1df7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
104 changed files with 958 additions and 684 deletions
client/rpc/src/integration-test/kotlin/net/corda/client/rpcreconnect
core-tests/src/test
core/src
main/kotlin/net/corda/core
test/kotlin/net/corda/core/internal
docs/source/design/hashing-of-public-keys-in-identity-service
experimental/netparams/src/main/kotlin/net/corda/netparams
node-api/src/main/kotlin/net/corda/nodeapi
node/src
testing
node-driver/src/main/kotlin/net/corda/testing
test-db/src
test-utils/src/main/kotlin/net/corda/testing/contracts
tools
checkpoint-agent/src/main/kotlin/net/corda/tools
network-builder/src/main/kotlin/net/corda/networkbuilder
shell/src/test/kotlin/net/corda/tools/shell/utilities

View File

@ -153,5 +153,4 @@ class CordaRPCClientReconnectionTest {
}
}
}
}

View File

@ -6,8 +6,8 @@ import net.corda.testing.core.SerializationEnvironmentRule;
import org.junit.Rule;
import org.junit.Test;
import static net.corda.core.serialization.internal.CheckpointSerializationAPIKt.checkpointSerialize;
import static net.corda.core.serialization.SerializationAPIKt.serialize;
import static net.corda.core.serialization.internal.CheckpointSerializationAPIKt.checkpointSerialize;
import static org.junit.Assert.assertNull;
/**

View File

@ -377,6 +377,7 @@ class ConstraintsPropagationTests {
SignableData(wireTransaction.id, SignatureMetadata(4, Crypto.findSignatureScheme(nodeKey).schemeNumberID)), nodeKey))
recordTransactions(SignedTransaction(wireTransaction, sigs))
}
@Test
fun `Input state contract version may be incompatible with lower version`() {
ledgerServices.ledger(DUMMY_NOTARY) {

View File

@ -31,7 +31,6 @@ class X509NameConstraintsTest {
private fun makeKeyStores(subjectName: X500Name, nameConstraints: NameConstraints): Pair<X509KeyStore, X509KeyStore> {
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
val trustStore = X509KeyStore(storePassword).apply {
setCertificate(X509Utilities.CORDA_ROOT_CA, rootCa.certificate)
}

View File

@ -156,6 +156,7 @@ class AttachmentTests : WithMockNet {
//region Matchers
private fun noAttachments() = has(FetchDataFlow.Result<Attachment>::fromDisk, isEmpty)
private fun soleAttachment(attachment: Attachment) = has(FetchDataFlow.Result<Attachment>::fromDisk,
hasSize(equalTo(1)) and
hasElement(attachment))

View File

@ -5,12 +5,8 @@ import com.natpryce.hamkrest.assertion.assertThat
import net.corda.core.contracts.Command
import net.corda.core.contracts.StateAndContract
import net.corda.core.contracts.requireThat
import net.corda.core.identity.*
import net.corda.core.flows.*
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.identity.excludeHostNode
import net.corda.core.identity.groupAbstractPartyByWellKnownParty
import net.corda.core.identity.*
import net.corda.core.node.services.IdentityService
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
@ -106,7 +102,8 @@ class CollectSignaturesFlowTests : WithContracts {
val keysToLookup = listOf(bConfidentialIdentity1.owningKey, bConfidentialIdentity2.owningKey, cConfidentialIdentity1.owningKey)
val keysToKeepAnonymous = listOf(cConfidentialIdentity2.owningKey)
val future = aliceNode.startFlow(MixAndMatchAnonymousSessionTestFlow(owners, keysToLookup.toSet(), keysToKeepAnonymous.toSet())).resultFuture
val future = aliceNode.startFlow(MixAndMatchAnonymousSessionTestFlow(owners, keysToLookup.toSet(), keysToKeepAnonymous.toSet()))
.resultFuture
mockNet.runNetwork()
val stx = future.get()
val missingSigners = stx.getMissingSigners()
@ -214,7 +211,6 @@ class AnonymousSessionTestFlow(private val cis: List<PartyAndCertificate>) : Flo
.addOutputState(state)
.addCommand(create, cis.map { it.owningKey })
val ourKey = cis.single { it.name == ourIdentity.name }.owningKey
val signedByUsTx = serviceHub.signInitialTransaction(txBuilder, ourKey)
val sessionsToCollectFrom = cis.filter { it.name != ourIdentity.name }.map { initiateFlow(AnonymousParty(it.owningKey)) }
@ -253,7 +249,6 @@ class MixAndMatchAnonymousSessionTestFlow(private val cis: List<PartyAndCertific
.addOutputState(state)
.addCommand(create, cis.map { it.owningKey })
val ourKey = cis.single { it.name == ourIdentity.name }.owningKey
val signedByUsTx = serviceHub.signInitialTransaction(txBuilder, ourKey)

View File

@ -3,12 +3,12 @@ package net.corda.coretests.flows
import com.natpryce.hamkrest.and
import com.natpryce.hamkrest.assertion.assertThat
import net.corda.core.flows.FinalityFlow
import net.corda.coretests.flows.WithFinality.FinalityInvoker
import net.corda.core.identity.Party
import net.corda.core.internal.cordapp.CordappResolver
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow
import net.corda.coretests.flows.WithFinality.FinalityInvoker
import net.corda.finance.POUNDS
import net.corda.finance.contracts.asset.Cash
import net.corda.finance.issuedBy

View File

@ -9,9 +9,9 @@ import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.finance.GBP
import net.corda.finance.POUNDS
import net.corda.finance.workflows.getCashBalance
import net.corda.finance.flows.CashIssueAndPaymentFlow
import net.corda.finance.flows.CashPaymentReceiverFlow
import net.corda.finance.workflows.getCashBalance
import net.corda.node.services.statemachine.StaffedFlowHospital.*
import net.corda.node.services.statemachine.StaffedFlowHospital.MedicalRecord.Flow
import net.corda.testing.core.ALICE_NAME

View File

@ -59,7 +59,8 @@ class ReferencedStatesFlowTests {
// 4. Try to use the old reference state. This will throw a NotaryException.
val nodeOneIdentity = nodes[1].info.legalIdentities.first()
val useRefTx = nodes[1].services.startFlow(WithReferencedStatesFlow { UseRefState(nodeOneIdentity, newRefState.state.data.linearId) }).resultFuture
val useRefTx = nodes[1].services.startFlow(WithReferencedStatesFlow { UseRefState(nodeOneIdentity, newRefState.state.data.linearId) })
.resultFuture
// 5. Share the update reference state.
nodes[0].services.startFlow(Initiator(updatedRefState)).resultFuture.getOrThrow()
@ -75,7 +76,8 @@ class ReferencedStatesFlowTests {
val newRefTx = nodes[0].services.startFlow(CreateRefState()).resultFuture.getOrThrow()
val newRefState = newRefTx.tx.outRefsOfType<RefState.State>().single()
// 2. Use the "newRefState" a transaction involving another party (nodes[1]) which creates a new state. They should store the new state and the reference state.
val newTx = nodes[0].services.startFlow(UseRefState(nodes[1].info.legalIdentities.first(), newRefState.state.data.linearId)).resultFuture.getOrThrow()
val newTx = nodes[0].services.startFlow(UseRefState(nodes[1].info.legalIdentities.first(), newRefState.state.data.linearId))
.resultFuture.getOrThrow()
// Wait until node 1 stores the new tx.
nodes[1].services.validatedTransactions.trackTransaction(newTx.id).getOrThrow()
// Check that nodes[1] has finished recording the transaction (and updating the vault.. hopefully!).
@ -106,7 +108,8 @@ class ReferencedStatesFlowTests {
val newRefTx = nodes[0].services.startFlow(CreateRefState()).resultFuture.getOrThrow()
val newRefState = newRefTx.tx.outRefsOfType<RefState.State>().single()
// 2. Use the "newRefState" a transaction involving another party (nodes[1]) which creates a new state. They should store the new state and the reference state.
val newTx = nodes[0].services.startFlow(UseRefState(nodes[1].info.legalIdentities.first(), newRefState.state.data.linearId)).resultFuture.getOrThrow()
val newTx = nodes[0].services.startFlow(UseRefState(nodes[1].info.legalIdentities.first(), newRefState.state.data.linearId))
.resultFuture.getOrThrow()
// Wait until node 1 stores the new tx.
nodes[1].services.validatedTransactions.trackTransaction(newTx.id).getOrThrow()
// Check that nodes[1] has finished recording the transaction (and updating the vault.. hopefully!).

View File

@ -430,6 +430,7 @@ class ResolveTransactionsFlowTest {
subFlow(resolveTransactionsFlow)
}
}
@Suppress("unused")
@InitiatedBy(TestFlow::class)
class TestResponseFlow(private val otherSideSession: FlowSession) : FlowLogic<Void?>() {
@ -447,6 +448,7 @@ class ResolveTransactionsFlowTest {
subFlow(DataVendingFlow(session, toVend))
}
}
@Suppress("unused")
@InitiatedBy(TestNoRightsVendingFlow::class)
private open class TestResponseResolveNoRightsFlow(val otherSideSession: FlowSession) : FlowLogic<Unit>() {
@ -454,7 +456,8 @@ class ResolveTransactionsFlowTest {
override fun call() {
val noRightsTx = otherSideSession.receive<SignedTransaction>().unwrap { it }
otherSideSession.receive<Any>().unwrap { it }
otherSideSession.sendAndReceive<Any>(FetchDataFlow.Request.Data(NonEmptySet.of(noRightsTx.inputs.first().txhash), FetchDataFlow.DataType.TRANSACTION)).unwrap { it }
otherSideSession.sendAndReceive<Any>(FetchDataFlow.Request.Data(NonEmptySet.of(noRightsTx.inputs.first().txhash), FetchDataFlow.DataType.TRANSACTION))
.unwrap { it }
otherSideSession.send(FetchDataFlow.Request.End)
}
}
@ -468,6 +471,7 @@ class ResolveTransactionsFlowTest {
subFlow(DataVendingFlow(session, tx))
}
}
@Suppress("unused")
@InitiatedBy(TestResolveTwiceVendingFlow::class)
private open class TestResponseResolveTwiceFlow(val otherSideSession: FlowSession) : FlowLogic<Unit>() {
@ -475,8 +479,10 @@ class ResolveTransactionsFlowTest {
override fun call() {
val tx = otherSideSession.receive<SignedTransaction>().unwrap { it }
val parent1 = tx.inputs.first().txhash
otherSideSession.sendAndReceive<Any>(FetchDataFlow.Request.Data(NonEmptySet.of(parent1), FetchDataFlow.DataType.TRANSACTION)).unwrap { it }
otherSideSession.sendAndReceive<Any>(FetchDataFlow.Request.Data(NonEmptySet.of(parent1), FetchDataFlow.DataType.TRANSACTION)).unwrap { it }
otherSideSession.sendAndReceive<Any>(FetchDataFlow.Request.Data(NonEmptySet.of(parent1), FetchDataFlow.DataType.TRANSACTION))
.unwrap { it }
otherSideSession.sendAndReceive<Any>(FetchDataFlow.Request.Data(NonEmptySet.of(parent1), FetchDataFlow.DataType.TRANSACTION))
.unwrap { it }
otherSideSession.send(FetchDataFlow.Request.End)
}
}

View File

@ -11,7 +11,6 @@ import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class VaultUpdateTests {
private companion object {
const val DUMMY_PROGRAM_ID = "net.corda.coretests.node.VaultUpdateTests\$DummyContract"

View File

@ -3,7 +3,9 @@ package net.corda.coretests.serialization
import co.paralleluniverse.fibers.Suspendable
import net.corda.core.contracts.Attachment
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.*
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowSession
import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.Party
import net.corda.core.internal.FetchAttachmentsFlow
import net.corda.core.internal.FetchDataFlow

View File

@ -2,13 +2,17 @@ package net.corda.coretests.serialization
import com.nhaarman.mockito_kotlin.mock
import net.corda.core.contracts.*
import net.corda.core.crypto.*
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SignatureMetadata
import net.corda.core.crypto.TransactionSignature
import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.node.NotaryInfo
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
import net.corda.core.transactions.*
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.seconds
import net.corda.finance.POUNDS
import net.corda.testing.common.internal.testNetworkParameters

View File

@ -3,10 +3,10 @@ package net.corda.coretests.transactions
import net.corda.core.contracts.*
import net.corda.core.contracts.ComponentGroupEnum.*
import net.corda.core.crypto.*
import net.corda.core.internal.createComponentGroups
import net.corda.core.internal.accessAvailableComponentHashes
import net.corda.core.internal.accessGroupHashes
import net.corda.core.internal.accessGroupMerkleRoots
import net.corda.core.internal.createComponentGroups
import net.corda.core.serialization.serialize
import net.corda.core.transactions.*
import net.corda.core.utilities.OpaqueBytes
@ -17,7 +17,6 @@ import org.junit.Rule
import org.junit.Test
import java.time.Instant
import java.util.function.Predicate
import kotlin.reflect.KVisibility
import kotlin.test.*
class CompatibleTransactionTests {
@ -420,7 +419,6 @@ class CompatibleTransactionTests {
// Required to call the private constructor.
val ftxConstructor = FilteredTransaction::class.constructors.first()
// 1st and 3rd commands require a signature from KEY_1.
val twoCommandsforKey1 = listOf(dummyCommand(DUMMY_KEY_1.public, DUMMY_KEY_2.public), dummyCommand(DUMMY_KEY_2.public), dummyCommand(DUMMY_KEY_1.public))
val componentGroups = listOf(

View File

@ -22,7 +22,7 @@ import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.core.TestIdentity
import net.corda.testing.node.MockServices
import net.corda.testing.node.ledger
import org.assertj.core.api.Assertions.*
import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import org.junit.Rule
import org.junit.Test

View File

@ -2,7 +2,8 @@ package net.corda.coretests.utilities
import com.esotericsoftware.kryo.KryoException
import net.corda.core.crypto.random63BitValue
import net.corda.core.serialization.*
import net.corda.core.serialization.ClassWhitelist
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.internal.checkpointDeserialize
import net.corda.core.serialization.internal.checkpointSerialize
import net.corda.core.utilities.transient

View File

@ -2,7 +2,6 @@ package net.corda.core.internal
import net.corda.core.DeleteForDJVM
import net.corda.core.contracts.Attachment
import net.corda.core.contracts.ContractAttachment
import net.corda.core.contracts.ContractClassName
import net.corda.core.flows.DataVendingFlow
import net.corda.core.flows.FlowLogic

View File

@ -4,7 +4,10 @@ import co.paralleluniverse.strands.Strand
import net.corda.core.CordaInternal
import net.corda.core.DeleteForDJVM
import net.corda.core.contracts.*
import net.corda.core.crypto.*
import net.corda.core.crypto.CompositeKey
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignableData
import net.corda.core.crypto.SignatureMetadata
import net.corda.core.identity.Party
import net.corda.core.internal.*
import net.corda.core.node.NetworkParameters

View File

@ -1,11 +1,9 @@
package net.corda.core.internal
import net.corda.core.contracts.*
import net.corda.core.crypto.MerkleTree
import net.corda.core.crypto.PartialMerkleTree
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.Party
import net.corda.core.internal.SerializedStateAndRef
import net.corda.core.node.NetworkParameters
import net.corda.core.transactions.ComponentGroup
import net.corda.core.transactions.LedgerTransaction
@ -16,6 +14,7 @@ import net.corda.core.transactions.WireTransaction
*/
fun WireTransaction.accessGroupHashes() = this.groupHashes
fun WireTransaction.accessGroupMerkleRoots() = this.groupsMerkleRoots
fun WireTransaction.accessAvailableComponentHashes() = this.availableComponentHashes

View File

@ -0,0 +1,62 @@
# Design doc template
## Overview
We wish to move the `PersistentIdentityService` away from using `PublicKey.hash.toHexString()` to using the correct method
`PublicKey.toStringShort()`
This requires modifying the `PersistentIdentityService` and an accompanying Database Migration.
**It is important to note that the underlying hash function will be sha256 both in the old and new implementations, the only difference is the stored representation.**
## Background
In Corda4 we introduced an ability to map a given `PublicKey` to a UUID. Internally this builds a database table which maintains a mapping
between `H(PublicKey)` -> UUID. Where `H()` is `PublicKey.toStringShort()`.
There is a reasonable requirement that for a given `UUID` you would want to find all the keys that are associated with that UUID.
To do this, we would need to join the `PublicKeyHashToExternalId` table with the `PersistentIdentity` table.
This is currently impossible due to the fact that the two tables use different hashes.
## Goals
* Migrate `PersistentIdentityService` to use `PublicKey.toStringShort()`
* Migrate the existing stored data
## Timeline
* This would be required for usage of Accounts. Therefore, it would need to be included in any release that is intended for clients using Accounts.
## Requirements
* It must be possible to join the `PublicKeyHashToExternalId` table with the `PersistentIdentity` table.
* Existing Identities must be safely migrated to using the new hashing approach.
## Design Decisions
* We will use Liquibase to perform the migration
## Design
The intention is to remove the use of `SecureHash` as an intermediary step in hashing a `PublicKey` and instead directly invoke `toStringShort()`.
This will ensure that for the same PK, all the tables within the node share a joinable column.
Luckily within the `PersistentIdentity` table, we store the full `PartyAndCertificate` which allows us to load the previously stored record,
and obtain the correct hash. We can then use the same `PartyAndCertificate` to calculate the originally stored value,
and perform a simple `UPDATE RECORD SET RECORD.PK_HASH = <new_value> WHERE RECORD.PK_HASH = <old_value>` to safely migrate the data.
### Testing
It is possible to write a simple Unit Test to insert records into the table using the old hashing mechanism, execute the migration.
and then check that the expected value is present within the updated rows. This will give a level of confidence that the migration is safe.
For more extensive testing, we propose to start a node using an unfixed C4 version, insert some Identities (both well known and confidential)
shutdown the node, place a fixed version and then check that the identities are resolvable and present in the database with the correct form of hash.
For enterprise, the testing performed with H2 (start, shutdown, migrate, restart) must be performed for all the supported database engines
both using the DbMigrationTool and by allowing the node to migrate itself.
To see a reference implementation of this design check out: https://github.com/corda/corda/pull/5217/files

View File

@ -5,14 +5,13 @@ import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigParseOptions
import net.corda.cliutils.CordaCliWrapper
import net.corda.cliutils.start
import net.corda.core.crypto.Crypto
import net.corda.core.identity.Party
import net.corda.core.internal.*
import net.corda.core.internal.copyTo
import net.corda.core.internal.readObject
import net.corda.core.internal.signWithCertPath
import net.corda.core.node.NetworkParameters
import net.corda.core.node.NotaryInfo
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializedBytes
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.internal.SerializationEnvironment
import net.corda.core.serialization.internal.nodeSerializationEnv
import net.corda.core.serialization.serialize
@ -20,9 +19,12 @@ import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.createDevNetworkMapCa
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.crypto.X509KeyStore
import net.corda.serialization.internal.*
import net.corda.serialization.internal.amqp.*
import picocli.CommandLine.*
import net.corda.serialization.internal.AMQP_P2P_CONTEXT
import net.corda.serialization.internal.CordaSerializationMagic
import net.corda.serialization.internal.SerializationFactoryImpl
import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme
import net.corda.serialization.internal.amqp.amqpMagic
import picocli.CommandLine.Option
import java.io.File
import java.nio.file.Path
import java.nio.file.StandardCopyOption

View File

@ -1,8 +1,8 @@
package net.corda.nodeapi.exceptions
import net.corda.core.ClientRelevantError
import net.corda.core.CordaRuntimeException
import net.corda.core.crypto.SecureHash
import net.corda.core.ClientRelevantError
import net.corda.core.flows.IdentifiableException
import net.corda.core.serialization.CordaSerializable

View File

@ -3,7 +3,6 @@ package net.corda.nodeapi.internal.config
import net.corda.core.crypto.internal.AliasPrivateKey
import net.corda.core.internal.outputStream
import net.corda.nodeapi.internal.crypto.X509KeyStore
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.addOrReplaceCertificate
import java.io.InputStream
import java.io.OutputStream

View File

@ -3,15 +3,10 @@
package net.corda.nodeapi.internal.crypto
import net.corda.core.crypto.Crypto
import net.corda.core.internal.createDirectories
import net.corda.core.internal.exists
import net.corda.core.internal.read
import net.corda.core.internal.write
import net.corda.core.internal.safeSymbolicRead
import net.corda.core.internal.*
import java.io.IOException
import java.io.InputStream
import java.nio.file.Path
import java.nio.file.Files
import java.security.*
import java.security.cert.Certificate
import java.security.cert.X509Certificate

View File

@ -2,7 +2,6 @@ package net.corda.nodeapi.internal.network
import net.corda.core.internal.*
import net.corda.core.utilities.contextLogger
import net.corda.core.internal.NODE_INFO_DIRECTORY
import net.corda.core.utilities.debug
import rx.Observable
import rx.Scheduler

View File

@ -3,18 +3,13 @@ package net.corda.node.logging
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.internal.div
import net.corda.core.messaging.FlowHandle
import net.corda.core.messaging.startFlow
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.loggerFor
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.driver
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import java.io.File
class ErrorCodeLoggingTests {
@Test

View File

@ -17,6 +17,7 @@ import net.corda.finance.contracts.asset.Cash
import net.corda.finance.flows.CashIssueAndPaymentFlow
import net.corda.finance.schemas.CashSchemaV1
import net.corda.node.services.Permissions
import net.corda.node.services.rpc.RpcReconnectTests.Companion.NUMBER_OF_FLOWS_TO_RUN
import net.corda.testing.core.DUMMY_BANK_A_NAME
import net.corda.testing.core.DUMMY_BANK_B_NAME
import net.corda.testing.driver.DriverParameters

View File

@ -177,7 +177,8 @@ internal class CordaRPCOpsImpl(
vendor = CordaVersion.vendor,
cordapps = services.cordappProvider.cordapps
.filter { !it.jarPath.toString().endsWith("corda-core-${CordaVersion.releaseVersion}.jar") }
.map { CordappInfo(
.map {
CordappInfo(
type = when (it.info) {
is Cordapp.Info.Contract -> "Contract CorDapp"
is Cordapp.Info.Workflow -> "Workflow CorDapp"

View File

@ -2,7 +2,10 @@ package net.corda.node.internal
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.Party
import net.corda.core.internal.*
import net.corda.core.internal.DigitalSignatureWithCert
import net.corda.core.internal.NamedCacheFactory
import net.corda.core.internal.NetworkParametersStorage
import net.corda.core.internal.SignedDataWithCert
import net.corda.core.node.NetworkParameters
import net.corda.core.node.NotaryInfo
import net.corda.core.serialization.SerializedBytes

View File

@ -1,10 +1,10 @@
package net.corda.node.internal
import io.netty.channel.unix.Errors
import net.corda.cliutils.printError
import net.corda.cliutils.CliWrapperBase
import net.corda.cliutils.CordaCliWrapper
import net.corda.cliutils.ExitCodes
import net.corda.cliutils.printError
import net.corda.common.logging.CordaVersion
import net.corda.core.contracts.HashAttachmentConstraint
import net.corda.core.crypto.Crypto
@ -12,7 +12,6 @@ import net.corda.core.internal.*
import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.internal.cordapp.CordappImpl
import net.corda.core.internal.errors.AddressBindingException
import net.corda.core.internal.safeSymbolicRead
import net.corda.core.utilities.Try
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.loggerFor
@ -39,7 +38,6 @@ import java.io.RandomAccessFile
import java.lang.management.ManagementFactory
import java.net.InetAddress
import java.nio.channels.UnresolvedAddressException
import java.nio.file.Files
import java.nio.file.Path
import java.time.DayOfWeek
import java.time.ZonedDateTime

View File

@ -0,0 +1,71 @@
package net.corda.node.migration
import liquibase.change.custom.CustomSqlChange
import liquibase.database.Database
import liquibase.exception.ValidationErrors
import liquibase.resource.ResourceAccessor
import liquibase.statement.SqlStatement
import liquibase.statement.core.UpdateStatement
import net.corda.core.crypto.toStringShort
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.utilities.contextLogger
import net.corda.node.services.identity.PersistentIdentityService
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
class PersistentIdentityMigration : CustomSqlChange {
companion object {
private val logger = contextLogger()
const val PUB_KEY_HASH_TO_PARTY_AND_CERT_TABLE = PersistentIdentityService.HASH_TO_IDENTITY_TABLE_NAME
const val X500_NAME_TO_PUB_KEY_HASH_TABLE = PersistentIdentityService.NAME_TO_HASH_TABLE_NAME
}
override fun validate(database: Database?): ValidationErrors? {
return null
}
override fun getConfirmationMessage(): String? {
return null
}
override fun setFileOpener(resourceAccessor: ResourceAccessor?) {
}
override fun setUp() {
}
override fun generateStatements(database: Database?): Array<SqlStatement> {
val dataSource = MigrationDataSource(database!!)
val connection = dataSource.connection
val statement = connection.prepareStatement("SELECT * FROM $PUB_KEY_HASH_TO_PARTY_AND_CERT_TABLE")
val resultSet = statement.executeQuery()
val generatedStatements = mutableListOf<SqlStatement>()
while (resultSet.next()) {
val oldPkHash = resultSet.getString(1)
val identityBytes = resultSet.getBytes(2)
val partyAndCertificate = PartyAndCertificate(X509CertificateFactory().delegate.generateCertPath(identityBytes.inputStream()))
generatedStatements.addAll(MigrationData(oldPkHash, partyAndCertificate).let { listOf(updateHashToIdentityRow(it, dataSource), updateNameToHashRow(it, dataSource)) })
}
return generatedStatements.toTypedArray()
}
private fun updateHashToIdentityRow(migrationData: MigrationData, dataSource: MigrationDataSource): SqlStatement {
return UpdateStatement(dataSource.connection.catalog, dataSource.connection.schema, PUB_KEY_HASH_TO_PARTY_AND_CERT_TABLE)
.setWhereClause("pk_hash=?")
.addNewColumnValue("pk_hash", migrationData.newPkHash)
.addWhereParameter(migrationData.oldPkHash)
}
private fun updateNameToHashRow(migrationData: MigrationData, dataSource: MigrationDataSource): UpdateStatement {
return UpdateStatement(dataSource.connection.catalog, dataSource.connection.schema, X500_NAME_TO_PUB_KEY_HASH_TABLE)
.setWhereClause("pk_hash=? AND name=?")
.addNewColumnValue("pk_hash", migrationData.newPkHash)
.addWhereParameters(migrationData.oldPkHash, migrationData.x500.toString())
}
data class MigrationData(val oldPkHash: String,
val partyAndCertificate: PartyAndCertificate,
val x500: CordaX500Name = partyAndCertificate.name,
val newPkHash: String = partyAndCertificate.owningKey.toStringShort())
}

View File

@ -1,7 +1,6 @@
package net.corda.node.services.api
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.CertRole
import net.corda.core.node.services.IdentityService
@ -9,7 +8,6 @@ import net.corda.core.utilities.contextLogger
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.x509Certificates
import java.security.InvalidAlgorithmParameterException
import java.security.PublicKey
import java.security.cert.CertPathValidatorException
import java.security.cert.CertificateExpiredException
import java.security.cert.CertificateNotYetValidException

View File

@ -3,14 +3,11 @@ package net.corda.node.services.config.schema.v1
import com.typesafe.config.Config
import com.typesafe.config.ConfigException
import net.corda.common.configuration.parsing.internal.*
import net.corda.common.validation.internal.Validated
import net.corda.common.validation.internal.Validated.Companion.invalid
import net.corda.common.validation.internal.Validated.Companion.valid
import net.corda.node.services.config.JmxReporterType
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.NodeConfigurationImpl
import net.corda.node.services.config.*
import net.corda.node.services.config.NodeConfigurationImpl.Defaults
import net.corda.node.services.config.Valid
import net.corda.node.services.config.VerifierType
import net.corda.node.services.config.schema.parsers.*
internal object V1NodeConfigurationSpec : Configuration.Specification<NodeConfiguration>("NodeConfiguration") {
@ -65,7 +62,7 @@ internal object V1NodeConfigurationSpec : Configuration.Specification<NodeConfig
@Suppress("unused")
private val systemProperties by nestedObject().optional()
override fun parseValid(configuration: Config): Valid<NodeConfiguration> {
override fun parseValid(configuration: Config): Validated<NodeConfiguration, Configuration.Validation.Error> {
val messagingServerExternal = configuration[messagingServerExternal] ?: Defaults.messagingServerExternal(configuration[messagingServerAddress])
val database = configuration[database] ?: Defaults.database(configuration[devMode])
@ -127,7 +124,7 @@ internal object V1NodeConfigurationSpec : Configuration.Specification<NodeConfig
else -> throw e
}
}
return result.mapValid { conf -> Valid.withResult(conf as NodeConfiguration, conf.validate().map(::toError).toSet()) }
return result.mapValid { conf -> Validated.withResult(conf as NodeConfiguration, conf.validate().map(::toError).toSet()) }
}
}

View File

@ -1,9 +1,8 @@
package net.corda.node.services.identity
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.toStringShort
import net.corda.core.identity.*
import net.corda.core.internal.NamedCacheFactory
import net.corda.core.internal.hash
import net.corda.core.internal.toSet
import net.corda.core.node.services.UnknownAnonymousPartyException
import net.corda.core.serialization.SingletonSerializeAsToken
@ -16,7 +15,7 @@ import net.corda.nodeapi.internal.crypto.X509CertificateFactory
import net.corda.nodeapi.internal.crypto.x509Certificates
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
import org.apache.commons.lang3.ArrayUtils.EMPTY_BYTE_ARRAY
import org.hibernate.internal.util.collections.ArrayHelper.EMPTY_BYTE_ARRAY
import java.security.InvalidAlgorithmParameterException
import java.security.PublicKey
import java.security.cert.*
@ -36,62 +35,69 @@ class PersistentIdentityService(cacheFactory: NamedCacheFactory) : SingletonSeri
companion object {
private val log = contextLogger()
fun createPKMap(cacheFactory: NamedCacheFactory): AppendOnlyPersistentMap<SecureHash, PartyAndCertificate, PersistentIdentity, String> {
const val HASH_TO_IDENTITY_TABLE_NAME = "${NODE_DATABASE_PREFIX}identities"
const val NAME_TO_HASH_TABLE_NAME = "${NODE_DATABASE_PREFIX}named_identities"
const val PK_HASH_COLUMN_NAME = "pk_hash"
const val IDENTITY_COLUMN_NAME = "identity_value"
const val NAME_COLUMN_NAME = "name"
fun createPKMap(cacheFactory: NamedCacheFactory): AppendOnlyPersistentMap<String, PartyAndCertificate, PersistentIdentity, String> {
return AppendOnlyPersistentMap(
cacheFactory = cacheFactory,
name = "PersistentIdentityService_partyByKey",
toPersistentEntityKey = { it.toString() },
toPersistentEntityKey = { it },
fromPersistentEntity = {
Pair(
SecureHash.parse(it.publicKeyHash),
it.publicKeyHash,
PartyAndCertificate(X509CertificateFactory().delegate.generateCertPath(it.identity.inputStream()))
)
},
toPersistentEntity = { key: SecureHash, value: PartyAndCertificate ->
PersistentIdentity(key.toString(), value.certPath.encoded)
toPersistentEntity = { key: String, value: PartyAndCertificate ->
PersistentIdentity(key, value.certPath.encoded)
},
persistentEntityClass = PersistentIdentity::class.java
)
}
fun createX500Map(cacheFactory: NamedCacheFactory): AppendOnlyPersistentMap<CordaX500Name, SecureHash, PersistentIdentityNames, String> {
fun createX500Map(cacheFactory: NamedCacheFactory): AppendOnlyPersistentMap<CordaX500Name, String, PersistentIdentityNames, String> {
return AppendOnlyPersistentMap(
cacheFactory = cacheFactory,
name = "PersistentIdentityService_partyByName",
toPersistentEntityKey = { it.toString() },
fromPersistentEntity = { Pair(CordaX500Name.parse(it.name), SecureHash.parse(it.publicKeyHash)) },
toPersistentEntity = { key: CordaX500Name, value: SecureHash ->
PersistentIdentityNames(key.toString(), value.toString())
fromPersistentEntity = {
Pair(CordaX500Name.parse(it.name), it.publicKeyHash)
},
toPersistentEntity = { key: CordaX500Name, value: String ->
PersistentIdentityNames(key.toString(), value)
},
persistentEntityClass = PersistentIdentityNames::class.java
)
}
private fun mapToKey(owningKey: PublicKey) = owningKey.hash
private fun mapToKey(party: PartyAndCertificate) = mapToKey(party.owningKey)
private fun mapToKey(party: PartyAndCertificate) = party.owningKey.toStringShort()
}
@Entity
@javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}identities")
@javax.persistence.Table(name = HASH_TO_IDENTITY_TABLE_NAME)
class PersistentIdentity(
@Id
@Column(name = "pk_hash", length = MAX_HASH_HEX_SIZE, nullable = false)
@Column(name = PK_HASH_COLUMN_NAME, length = MAX_HASH_HEX_SIZE, nullable = false)
var publicKeyHash: String = "",
@Lob
@Column(name = "identity_value", nullable = false)
@Column(name = IDENTITY_COLUMN_NAME, nullable = false)
var identity: ByteArray = EMPTY_BYTE_ARRAY
)
@Entity
@javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}named_identities")
@javax.persistence.Table(name = NAME_TO_HASH_TABLE_NAME)
class PersistentIdentityNames(
@Id
@Column(name = "name", length = 128, nullable = false)
@Column(name = NAME_COLUMN_NAME, length = 128, nullable = false)
var name: String = "",
@Column(name = "pk_hash", length = MAX_HASH_HEX_SIZE, nullable = true)
var publicKeyHash: String? = ""
@Column(name = PK_HASH_COLUMN_NAME, length = MAX_HASH_HEX_SIZE, nullable = false)
var publicKeyHash: String = ""
)
private lateinit var _caCertStore: CertStore
@ -156,11 +162,11 @@ class PersistentIdentityService(cacheFactory: NamedCacheFactory) : SingletonSeri
principalToParties.addWithDuplicatesAllowed(identity.name, key, false)
}
val parentId = mapToKey(identityCertChain[1].publicKey)
val parentId = identityCertChain[1].publicKey.toStringShort()
return keyToParties[parentId]
}
override fun certificateFromKey(owningKey: PublicKey): PartyAndCertificate? = database.transaction { keyToParties[mapToKey(owningKey)] }
override fun certificateFromKey(owningKey: PublicKey): PartyAndCertificate? = database.transaction { keyToParties[owningKey.toStringShort()] }
private fun certificateFromCordaX500Name(name: CordaX500Name): PartyAndCertificate? {
return database.transaction {

View File

@ -81,7 +81,8 @@ class BasicHSMKeyManagementService(cacheFactory: NamedCacheFactory,
}
}
override val keys: Set<PublicKey> get() {
override val keys: Set<PublicKey>
get() {
return database.transaction {
val set = LinkedHashSet<PublicKey>(originalKeysMap.keys)
keysMap.allPersisted.use { it.forEach { set += it.first } }

View File

@ -7,7 +7,6 @@ import net.corda.core.serialization.serialize
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.debug
import net.corda.core.utilities.seconds
import net.corda.core.internal.NODE_INFO_DIRECTORY
import net.corda.nodeapi.internal.NodeInfoAndSigned
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier
import rx.Observable
@ -82,8 +81,10 @@ class NodeInfoWatcher(private val nodePath: Path,
val processedPaths = HashSet<Path>()
val result = nodeInfosDir.list { paths ->
paths
.filter { logger.debug { "Examining $it" }
true}
.filter {
logger.debug { "Examining $it" }
true
}
.filter { it.isRegularFile() }
.filter { file ->
val lastModifiedTime = file.lastModifiedTime()

View File

@ -41,7 +41,6 @@ open class PersistentNetworkMapCache(cacheFactory: NamedCacheFactory,
private val database: CordaPersistence,
private val identityService: IdentityService) : NetworkMapCacheInternal, SingletonSerializeAsToken() {
companion object {
private val logger = contextLogger()
}

View File

@ -223,7 +223,8 @@ class DBTransactionStorage(private val database: CordaPersistence, cacheFactory:
}
@VisibleForTesting
val transactions: List<SignedTransaction> get() = database.transaction { snapshot() }
val transactions: List<SignedTransaction>
get() = database.transaction { snapshot() }
private fun snapshot(): List<SignedTransaction> {
return txStorage.content.allPersisted.use {
@ -241,6 +242,7 @@ class DBTransactionStorage(private val database: CordaPersistence, cacheFactory:
stx.txBits,
Collections.unmodifiableList(stx.sigs),
status)
fun toSignedTx() = SignedTransaction(txBits, sigs)
}
}

View File

@ -7,20 +7,19 @@ import java.util.*
import javax.persistence.*
@Entity
@Table(name = "pk_hash_to_ext_id_map", indexes = [Index(name = "pk_hash_to_xid_idx", columnList = "public_key_hash")])
@Table(name = "pk_hash_to_ext_id_map", indexes = [
Index(name = "ext_id_idx", columnList = "external_id")
])
class PublicKeyHashToExternalId(
@Id
@GeneratedValue
@Column(name = "id", unique = true, nullable = false)
val key: Long?,
@Column(name = "external_id", nullable = false)
@Type(type = "uuid-char")
val externalId: UUID,
@Id
@Column(name = "public_key_hash", nullable = false)
val publicKeyHash: String
) {
constructor(accountId: UUID, publicKey: PublicKey)
: this(null, accountId, publicKey.toStringShort())
: this(accountId, publicKey.toStringShort())
}

View File

@ -35,7 +35,7 @@ class PublicKeyToOwningIdentityCacheImpl(private val database: CordaPersistence,
val queryRoot = criteriaQuery.from(PersistentIdentityService.PersistentIdentity::class.java)
criteriaQuery.select(criteriaBuilder.count(queryRoot))
criteriaQuery.where(
criteriaBuilder.equal(queryRoot.get<String>(PersistentIdentityService.PersistentIdentity::publicKeyHash.name), key.hash.toString())
criteriaBuilder.equal(queryRoot.get<String>(PersistentIdentityService.PersistentIdentity::publicKeyHash.name), key.toStringShort())
)
val query = session.createQuery(criteriaQuery)
query.uniqueResult() > 0

View File

@ -144,8 +144,7 @@ class CheckpointDumper(private val checkpointStorage: CheckpointStorage, private
val instance = checkpointHook.objectOrNewInstance()
val checkpointIdField = instance.declaredField<UUID>(instance.javaClass, "checkpointId")
checkpointIdField.value = checkpointId.uuid
}
catch (e: Exception) {
} catch (e: Exception) {
log.error("Checkpoint agent instrumentation failed for checkpointId: $checkpointId\n. ${e.message}")
}
}
@ -383,6 +382,7 @@ class CheckpointDumper(private val checkpointStorage: CheckpointStorage, private
writeObjectField("ourSessionId", value.sourceSessionId)
}
}
override fun handledType(): Class<FlowSessionImpl> = FlowSessionImpl::class.java
}
@ -402,6 +402,7 @@ class CheckpointDumper(private val checkpointStorage: CheckpointStorage, private
}
gen.writeEndArray()
}
override fun handledType(): Class<Map<Any, Any>> = uncheckedCast(Map::class.java)
}
}

View File

@ -49,7 +49,7 @@ import rx.Observable
import rx.subjects.PublishSubject
import java.lang.Integer.min
import java.security.SecureRandom
import java.util.HashSet
import java.util.*
import java.util.concurrent.*
import javax.annotation.concurrent.ThreadSafe
import kotlin.collections.ArrayList

View File

@ -217,6 +217,7 @@ class NodeVaultService(
processAndNotify(updates, previouslySeen)
batch.clear()
}
fun processTransactions(txs: Iterable<CoreTransaction>, previouslySeen: Boolean) {
for (tx in txs) {
if (batch.isNotEmpty() && tx.javaClass != batch.last().javaClass) {

View File

@ -138,8 +138,8 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
* underlying storage if this races with another database transaction to store a value for the same key.
* @return true if added key was unique, otherwise false
*/
fun addWithDuplicatesAllowed(key: K, value: V, logWarning: Boolean = true): Boolean =
set(key, value, logWarning) { k, v ->
fun addWithDuplicatesAllowed(key: K, value: V, logWarning: Boolean = true): Boolean {
return set(key, value, logWarning) { k, v ->
val session = currentDBSession()
val existingEntry = session.find(persistentEntityClass, toPersistentEntityKey(k))
if (existingEntry == null) {
@ -149,6 +149,7 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
fromPersistentEntity(existingEntry).second
}
}
}
/**
* Associates the specified value with the specified key in this map and persists it.

View File

@ -6,11 +6,11 @@ import net.corda.core.internal.notary.NotaryService
import net.corda.core.utilities.contextLogger
import net.corda.node.SerialFilter
import net.corda.node.VersionInfo
import net.corda.nodeapi.internal.cordapp.CordappLoader
import net.corda.node.internal.cordapp.VirtualCordapp
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.internal.cordapp.CordappLoader
import net.corda.notary.experimental.bftsmart.BFTSmartNotaryService
import net.corda.notary.experimental.raft.RaftNotaryService
import java.lang.reflect.InvocationTargetException

View File

@ -1,13 +1,12 @@
package net.corda.node.utilities.registration
import net.corda.core.crypto.internal.AliasPrivateKey
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.internal.AliasPrivateKey
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.*
import net.corda.core.utilities.contextLogger
import net.corda.node.NodeRegistrationOption
import net.corda.node.services.config.NodeConfiguration
import net.corda.nodeapi.internal.cryptoservice.bouncycastle.BCCryptoService
import net.corda.nodeapi.internal.config.CertificateStore
import net.corda.nodeapi.internal.config.MutualSslConfiguration
import net.corda.nodeapi.internal.crypto.CertificateType
@ -18,9 +17,10 @@ import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_CLIENT_CA
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_CLIENT_TLS
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
import net.corda.nodeapi.internal.crypto.X509Utilities.DEFAULT_VALIDITY_WINDOW
import net.corda.nodeapi.internal.cryptoservice.CryptoService
import net.corda.nodeapi.internal.cryptoservice.CryptoServiceFactory
import net.corda.nodeapi.internal.cryptoservice.SupportedCryptoServices
import net.corda.nodeapi.internal.cryptoservice.CryptoService
import net.corda.nodeapi.internal.cryptoservice.bouncycastle.BCCryptoService
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.openssl.jcajce.JcaPEMWriter
import org.bouncycastle.operator.ContentSigner

View File

@ -1,5 +1,4 @@
# Build constants exported as resource file to make them visible in Node program
# Note: sadly, due to present limitation of IntelliJ-IDEA in processing resource files, these constants cannot be
# imported from top-level 'constants.properties' file
jolokiaAgentVersion=1.6.1

View File

@ -1,8 +1,7 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="1511451595465-1.1" dbms="h2">
<preConditions onFail="MARK_RAN" onSqlOutput="TEST">

View File

@ -14,6 +14,7 @@
<include file="migration/node-core.changelog-v9.xml"/>
<include file="migration/node-core.changelog-v10.xml"/>
<include file="migration/node-core.changelog-v11.xml"/>
<include file="migration/node-core.changelog-v12.xml"/>
<!-- This changeset (which creates extra columns in the transactions tables), must be run before the vault state migration (in
vault-schema.changelog-v9.xml), as that will use the current hibernate mappings, and those require all DB columns to be
created. -->

View File

@ -0,0 +1,29 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"
logicalFilePath="migration/node-services.changelog-init.xml">
<changeSet author="R3.Corda" id="migrate_pk_hash_to_ext_id">
<!-- drop existing "ID" column -->
<dropColumn columnName="id"
tableName="pk_hash_to_ext_id_map"/>
<dropIndex tableName="pk_hash_to_ext_id_map" indexName="pk_hash_to_xid_idx"/>
<!-- create new primary key constraint on key hash -->
<addPrimaryKey columnNames="public_key_hash" constraintName="pubkey_hash_to_external_id_pk" tableName="pk_hash_to_ext_id_map"/>
<createIndex indexName="ext_id_idx" tableName="pk_hash_to_ext_id_map">
<column name="external_id"/>
</createIndex>
</changeSet>
<changeSet author="R3.Corda" id="migrate_identity_service_to_use_publicKey.toShortString()">
<customChange class="net.corda.node.migration.PersistentIdentityMigration">
</customChange>
</changeSet>
</databaseChangeLog>

View File

@ -14,7 +14,6 @@ class ThreadContextAdjustingRpcOpsProxyTest {
private val mockClassloader = mock<ClassLoader>()
private val proxy = ThreadContextAdjustingRpcOpsProxy(coreOps, mockClassloader)
private interface InstrumentedCordaRPCOps : InternalCordaRPCOps {
fun getThreadContextClassLoader(): ClassLoader = Thread.currentThread().contextClassLoader
}

View File

@ -0,0 +1,120 @@
package net.corda.node.migration
import liquibase.database.core.H2Database
import liquibase.database.jvm.JdbcConnection
import net.corda.core.crypto.toStringShort
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.hash
import net.corda.core.utilities.contextLogger
import net.corda.node.services.identity.PersistentIdentityService
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.nodeapi.internal.persistence.contextTransactionOrNull
import net.corda.testing.core.*
import net.corda.testing.internal.configureDatabase
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import org.hamcrest.CoreMatchers
import org.hamcrest.Matcher
import org.hamcrest.Matchers.*
import org.junit.After
import org.junit.Assert
import org.junit.Before
import org.junit.Test
/**
*/
class IdentityServiceToStringShortMigrationTest {
companion object {
val alice = TestIdentity(ALICE_NAME, 70)
val bankOfCorda = TestIdentity(BOC_NAME)
val bob = TestIdentity(BOB_NAME, 80)
val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20)
val ALICE_IDENTITY get() = alice.identity
val BOB get() = bob.party
val BOB_IDENTITY get() = bob.identity
val BOC_IDENTITY get() = bankOfCorda.identity
val bob2 = TestIdentity(BOB_NAME, 40)
val BOB2_IDENTITY = bob2.identity
val logger = contextLogger()
}
lateinit var liquibaseDB: H2Database
lateinit var cordaDB: CordaPersistence
@Before
fun setUp() {
cordaDB = configureDatabase(
makeTestDataSourceProperties(),
DatabaseConfig(),
{ null },
{ null },
ourName = BOB_IDENTITY.name)
liquibaseDB = H2Database()
liquibaseDB.connection = JdbcConnection(cordaDB.dataSource.connection)
liquibaseDB.isAutoCommit = true
}
@After
fun close() {
contextTransactionOrNull?.close()
cordaDB.close()
liquibaseDB.close()
}
private fun saveAllIdentitiesWithOldHashString(identities: List<PartyAndCertificate>) {
cordaDB.transaction {
val groupedIdentities = identities.groupBy { it.name }
groupedIdentities.forEach { name, certs ->
val persistentIDs = certs.map { PersistentIdentityService.PersistentIdentity(it.owningKey.hash.toString(), it.certPath.encoded) }
val persistentName = PersistentIdentityService.PersistentIdentityNames(name.toString(), certs.first().owningKey.hash.toString())
persistentIDs.forEach {
session.persist(it)
}
session.persist(persistentName)
}
}
}
@Test
fun `it should be possible to migrate all existing identities to new hash function`() {
val identities = listOf(BOB_IDENTITY, ALICE_IDENTITY, BOC_IDENTITY, dummyNotary.identity, BOB2_IDENTITY)
val groupedByNameIdentities = identities.groupBy { it.name }
saveAllIdentitiesWithOldHashString(identities)
val migration = PersistentIdentityMigration()
liquibaseDB.execute(migration.generateStatements(liquibaseDB), listOf())
val listOfNamesWithoutPkHash = mutableListOf<CordaX500Name>()
identities.forEach {
logger.info("Checking: ${it.name}")
cordaDB.transaction {
val hashToIdentityStatement = database.dataSource.connection.prepareStatement("SELECT ${PersistentIdentityService.PK_HASH_COLUMN_NAME} FROM ${PersistentIdentityService.HASH_TO_IDENTITY_TABLE_NAME} WHERE pk_hash=?")
hashToIdentityStatement.setString(1, it.owningKey.toStringShort())
val hashToIdentityResultSet = hashToIdentityStatement.executeQuery()
//check that there is a row for every "new" hash
Assert.assertThat(hashToIdentityResultSet.next(), `is`(true))
//check that the pk_hash actually matches what we expect (kinda redundant, but deserializing the whole PartyAndCertificate feels like overkill)
Assert.assertThat(hashToIdentityResultSet.getString(1), `is`(it.owningKey.toStringShort()))
val nameToHashStatement = connection.prepareStatement("SELECT ${PersistentIdentityService.NAME_COLUMN_NAME} FROM ${PersistentIdentityService.NAME_TO_HASH_TABLE_NAME} WHERE pk_hash=?")
nameToHashStatement.setString(1, it.owningKey.toStringShort())
val nameToHashResultSet = nameToHashStatement.executeQuery()
//if there is no result for this key, this means its an identity that is not stored in the DB (IE, it's been seen after another identity has already been mapped to it)
if (nameToHashResultSet.next()) {
Assert.assertThat(nameToHashResultSet.getString(1), `is`(anyOf(groupedByNameIdentities.getValue(it.name).map<PartyAndCertificate, Matcher<String>?> { identity -> CoreMatchers.equalTo(identity.name.toString()) })))
} else {
logger.warn("did not find a PK_HASH for ${it.name}")
listOfNamesWithoutPkHash.add(it.name)
}
}
}
listOfNamesWithoutPkHash.forEach {
//the only time an identity name does not have a PK_HASH is if there are multiple identities associated with that name
Assert.assertThat(groupedByNameIdentities[it]?.size, `is`(greaterThan(1)))
}
}
}

View File

@ -3,15 +3,11 @@ package net.corda.node.migration
import liquibase.database.Database
import liquibase.database.jvm.JdbcConnection
import net.corda.core.contracts.*
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignableData
import net.corda.core.crypto.SignatureMetadata
import net.corda.core.crypto.*
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.NotaryChangeTransactionBuilder
import net.corda.core.internal.hash
import net.corda.core.internal.packageName
import net.corda.core.internal.signWithCert
import net.corda.core.node.NetworkParameters
@ -198,8 +194,8 @@ class VaultStateMigrationTest {
private fun saveAllIdentities(identities: List<PartyAndCertificate>) {
cordaDB.transaction {
identities.groupBy { it.name }.forEach { name, certs ->
val persistentIDs = certs.map { PersistentIdentityService.PersistentIdentity(it.owningKey.hash.toString(), it.certPath.encoded) }
val persistentName = PersistentIdentityService.PersistentIdentityNames(name.toString(), certs.first().owningKey.hash.toString())
val persistentIDs = certs.map { PersistentIdentityService.PersistentIdentity(it.owningKey.toStringShort(), it.certPath.encoded) }
val persistentName = PersistentIdentityService.PersistentIdentityNames(name.toString(), certs.first().owningKey.toStringShort())
persistentIDs.forEach { session.save(it) }
session.save(persistentName)
}

View File

@ -14,8 +14,10 @@ import net.corda.core.internal.*
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
import net.corda.core.node.ServicesForResolution
import net.corda.core.node.services.AttachmentId
import net.corda.core.node.services.vault.*
import net.corda.core.node.services.vault.AttachmentQueryCriteria.AttachmentsQueryCriteria
import net.corda.core.node.services.vault.AttachmentSort
import net.corda.core.node.services.vault.Builder
import net.corda.core.node.services.vault.Sort
import net.corda.core.utilities.getOrThrow
import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.nodeapi.exceptions.DuplicateAttachmentException

View File

@ -58,7 +58,8 @@ class ObserverNodeTransactionTests {
fun sendTransactionToObserver(transactionIdx: Int, node: TestStartedNode, regulator: TestStartedNode) {
val transactionList = node.services.validatedTransactions.track().snapshot
node.services.startFlow(ReportToCounterparty(regulator.info.singleIdentity(), transactionList[transactionIdx])).resultFuture.getOrThrow()
node.services.startFlow(ReportToCounterparty(regulator.info.singleIdentity(), transactionList[transactionIdx]))
.resultFuture.getOrThrow()
}
fun sendTransactionToObserverOnlyRelevant(transactionIdx: Int, node: TestStartedNode, regulator: TestStartedNode) {
@ -79,7 +80,6 @@ class ObserverNodeTransactionTests {
}
}
@Test
fun `Broadcasting an old transaction does not cause 2 unconsumed states`() {
val node = mockNet.createPartyNode(ALICE_NAME)
@ -292,7 +292,6 @@ class ObserverNodeTransactionTests {
val flow = object : SignTransactionFlow(otherSideSession) {
@Suspendable
override fun checkTransaction(stx: SignedTransaction) {
}
}
subFlow(flow)

View File

@ -465,7 +465,8 @@ class FlowFrameworkTests {
@Test
fun `initiating flow using unknown AnonymousParty`() {
val anonymousBob = bobNode.services.keyManagementService.freshKeyAndCert(bobNode.info.legalIdentitiesAndCerts.single(), false).party.anonymise()
val anonymousBob = bobNode.services.keyManagementService.freshKeyAndCert(bobNode.info.legalIdentitiesAndCerts.single(), false)
.party.anonymise()
bobNode.registerCordappFlowFactory(SendAndReceiveFlow::class) { SingleInlinedSubFlow(it) }
val result = aliceNode.services.startFlow(SendAndReceiveFlow(anonymousBob, "Hello")).resultFuture
mockNet.runNetwork()

View File

@ -3,7 +3,10 @@ package net.corda.node.services.vault
import co.paralleluniverse.fibers.Suspendable
import com.nhaarman.mockito_kotlin.*
import net.corda.core.contracts.*
import net.corda.core.flows.*
import net.corda.core.flows.FinalityFlow
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowSession
import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.AbstractParty
import net.corda.core.internal.FlowStateMachine
import net.corda.core.internal.uncheckedCast
@ -19,8 +22,8 @@ import net.corda.core.utilities.NonEmptySet
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap
import net.corda.nodeapi.internal.cordapp.CordappLoader
import net.corda.node.services.api.VaultServiceInternal
import net.corda.nodeapi.internal.cordapp.CordappLoader
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.testing.core.singleIdentity
import net.corda.testing.flows.registerCoreFlowFactory

View File

@ -83,6 +83,7 @@ data class NodeParameters(
maximumHeapSize = maximumHeapSize,
additionalCordapps = additionalCordapps
)
constructor(
providedName: CordaX500Name?,
rpcUsers: List<User>,

View File

@ -39,7 +39,6 @@ import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier
import net.corda.notary.experimental.raft.RaftConfig
import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.DUMMY_BANK_A_NAME

View File

@ -58,8 +58,8 @@ class DBRunnerExtension : Extension, BeforeAllCallback, AfterAllCallback, Before
val rootContext = context?.root ?: return null
val testClass = context.testClass.orElse(null) ?: return null
val annotation = testClass.requiredDb ?:
throw IllegalStateException("Test run with DBRunnerExtension is not annotated with @RequiresDb")
val annotation = testClass.requiredDb
?: throw IllegalStateException("Test run with DBRunnerExtension is not annotated with @RequiresDb")
val groupName = annotation.group
val defaultContextClassName = annotation.defaultContextClassName
@ -88,7 +88,8 @@ class DBRunnerExtension : Extension, BeforeAllCallback, AfterAllCallback, Before
else annotation.annotationClass.java.findAnnotations(annotationClass)
}
private val Annotation.isInternal: Boolean get() = annotationClass.java.name.run {
private val Annotation.isInternal: Boolean
get() = annotationClass.java.name.run {
startsWith("java.lang") ||
startsWith("org.junit") ||
startsWith("kotlin")

View File

@ -16,5 +16,4 @@ class NoOpTestDatabaseContext : TestDatabaseContext {
override fun afterTest(teardownSql: List<String>) {}
override fun close() {}
}

View File

@ -3,7 +3,6 @@ package net.corda.testing.internal.db
import org.assertj.core.api.Assertions.assertThat
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.lang.IllegalStateException
class AssertingTestDatabaseContext : TestDatabaseContext {
@ -57,5 +56,4 @@ class AssertingTestDatabaseContext : TestDatabaseContext {
throw IllegalStateException("Assertion failed: ${e.message}")
}
}
}

View File

@ -15,7 +15,5 @@ class GroupAMoreTests {
@SpecialSql1
@SpecialSql2
fun moreSpecialSqlRequired() {
}
}

View File

@ -14,13 +14,10 @@ class GroupATests {
@Test
fun noSpecialSqlRequired() {
}
@Test
@SpecialSql1
fun someSpecialSqlRequired() {
}
}

View File

@ -13,13 +13,10 @@ class GroupBTests {
@Test
fun noSpecialSqlRequired() {
}
@Test
@SpecialSql1
fun someSpecialSqlRequired() {
}
}

View File

@ -13,7 +13,8 @@
<Appenders>
<Console name="Console-Appender" target="SYSTEM_OUT">
<PatternLayout>
<ScriptPatternSelector defaultPattern="%highlight{[%level{length=5}] %date{HH:mm:ss,SSS} [%t] %c{2}.%method - %msg%n}{INFO=white,WARN=red,FATAL=bright red}">
<ScriptPatternSelector
defaultPattern="%highlight{[%level{length=5}] %date{HH:mm:ss,SSS} [%t] %c{2}.%method - %msg%n}{INFO=white,WARN=red,FATAL=bright red}">
<Script name="MDCSelector" language="javascript"><![CDATA[
result = null;
if (!logEvent.getContextData().size() == 0) {
@ -24,7 +25,8 @@
result;
]]>
</Script>
<PatternMatch key="WithMDC" pattern="%highlight{[%level{length=5}] %date{HH:mm:ss,SSS} [%t] %c{2}.%method - %msg %X%n}{INFO=white,WARN=red,FATAL=bright red}"/>
<PatternMatch key="WithMDC"
pattern="%highlight{[%level{length=5}] %date{HH:mm:ss,SSS} [%t] %c{2}.%method - %msg %X%n}{INFO=white,WARN=red,FATAL=bright red}"/>
</ScriptPatternSelector>
</PatternLayout>
<ThresholdFilter level="trace"/>

View File

@ -15,7 +15,6 @@ class DummyContractV2 : UpgradedContractWithLegacyConstraint<DummyContract.State
companion object {
const val PROGRAM_ID: ContractClassName = "net.corda.testing.contracts.DummyContractV2"
/**
* An overload of move for just one input state.
*/

View File

@ -8,13 +8,13 @@ import javassist.ClassPool
import javassist.CtClass
import net.corda.core.internal.ThreadBox
import net.corda.core.utilities.debug
import net.corda.tools.CheckpointAgent.Companion.graphDepth
import net.corda.tools.CheckpointAgent.Companion.instrumentClassname
import net.corda.tools.CheckpointAgent.Companion.instrumentType
import net.corda.tools.CheckpointAgent.Companion.log
import net.corda.tools.CheckpointAgent.Companion.maximumSize
import net.corda.tools.CheckpointAgent.Companion.minimumSize
import net.corda.tools.CheckpointAgent.Companion.printOnce
import net.corda.tools.CheckpointAgent.Companion.graphDepth
import org.slf4j.LoggerFactory
import java.io.ByteArrayInputStream
import java.lang.instrument.ClassFileTransformer
@ -65,24 +65,34 @@ class CheckpointAgent {
if (nvpItem.size == 2) {
when (nvpItem[0].trim()) {
"instrumentClassname" -> instrumentClassname = nvpItem[1]
"instrumentType" -> try { instrumentType = InstrumentationType.valueOf(nvpItem[1].toUpperCase()) } catch (e: Exception) {
"instrumentType" -> try {
instrumentType = InstrumentationType.valueOf(nvpItem[1].toUpperCase())
} catch (e: Exception) {
display("Invalid value: ${nvpItem[1]}. Please specify read or write.")
}
"minimumSize" -> try { minimumSize = nvpItem[1].toInt() } catch (e: NumberFormatException) {
display("Invalid value: ${nvpItem[1]}. Please specify an integer value.") }
"maximumSize" -> try { maximumSize = nvpItem[1].toInt() } catch (e: NumberFormatException) {
"minimumSize" -> try {
minimumSize = nvpItem[1].toInt()
} catch (e: NumberFormatException) {
display("Invalid value: ${nvpItem[1]}. Please specify an integer value.")
}
"graphDepth" -> try { graphDepth = nvpItem[1].toInt() } catch (e: NumberFormatException) {
"maximumSize" -> try {
maximumSize = nvpItem[1].toInt()
} catch (e: NumberFormatException) {
display("Invalid value: ${nvpItem[1]}. Please specify an integer value.")
}
"printOnce" -> try { printOnce = nvpItem[1].toBoolean() } catch (e: Exception) {
"graphDepth" -> try {
graphDepth = nvpItem[1].toInt()
} catch (e: NumberFormatException) {
display("Invalid value: ${nvpItem[1]}. Please specify an integer value.")
}
"printOnce" -> try {
printOnce = nvpItem[1].toBoolean()
} catch (e: Exception) {
display("Invalid value: ${nvpItem[1]}. Please specify true or false.")
}
else -> display("Invalid argument: $nvpItem")
}
}
else display("Missing value for argument: $nvpItem")
} else display("Missing value for argument: $nvpItem")
}
}
println("Running Checkpoint agent with following arguments: instrumentClassname=$instrumentClassname, instrumentType=$instrumentType, minimumSize=$minimumSize, maximumSize=$maximumSize, graphDepth=$graphDepth, printOnce=$printOnce\n")
@ -207,8 +217,7 @@ object CheckpointHook : ClassFileTransformer {
val numberValue = value as Array<Number>
log.debug { "readFieldExit array of number: $clazz = ${numberValue.joinToString(",")}" }
return numberValue.joinToString(",")
}
else if (clazz == Array<Boolean>::class.java) {
} else if (clazz == Array<Boolean>::class.java) {
val arrayValue = value as Array<Boolean>
log.debug { "readFieldExit array of boolean: $clazz = ${arrayValue.joinToString(",")}" }
return arrayValue.joinToString(",")
@ -226,38 +235,31 @@ object CheckpointHook : ClassFileTransformer {
val arrayValue = value as CharArray
log.debug { "readFieldExit char array: $clazz = ${arrayValue.joinToString("")}" }
return arrayValue.joinToString("")
}
else if (clazz == ByteArray::class.java) {
} else if (clazz == ByteArray::class.java) {
val arrayValue = value as ByteArray
log.debug { "readFieldExit byte array: $clazz = ${byteArrayToHex(arrayValue)}" }
return byteArrayToHex(arrayValue)
}
else if (clazz == ShortArray::class.java) {
} else if (clazz == ShortArray::class.java) {
val arrayValue = value as ShortArray
log.debug { "readFieldExit short array: $clazz = ${arrayValue.joinToString(",")}" }
return arrayValue.joinToString(",")
}
else if (clazz == IntArray::class.java) {
} else if (clazz == IntArray::class.java) {
val arrayValue = value as IntArray
log.debug { "readFieldExit int array: $clazz = ${arrayValue.joinToString(",")}" }
return arrayValue.joinToString(",")
}
else if (clazz == LongArray::class.java) {
} else if (clazz == LongArray::class.java) {
val arrayValue = value as LongArray
log.debug { "readFieldExit long array: $clazz = ${arrayValue.joinToString(",")}" }
return arrayValue.joinToString(",")
}
else if (clazz == FloatArray::class.java) {
} else if (clazz == FloatArray::class.java) {
val arrayValue = value as FloatArray
log.debug { "readFieldExit float array: $clazz = ${arrayValue.joinToString(",")}" }
return arrayValue.joinToString(",")
}
else if (clazz == DoubleArray::class.java) {
} else if (clazz == DoubleArray::class.java) {
val arrayValue = value as DoubleArray
log.debug { "readFieldExit double array: $clazz = ${arrayValue.joinToString(",")}" }
return arrayValue.joinToString(",")
}
else if (clazz == BooleanArray::class.java) {
} else if (clazz == BooleanArray::class.java) {
val arrayValue = value as BooleanArray
log.debug { "readFieldExit boolean array: $clazz = ${arrayValue.joinToString(",")}" }
return arrayValue.joinToString(",")
@ -340,22 +342,18 @@ object CheckpointHook : ClassFileTransformer {
is StatsTree.Object -> {
if (printOnce && identityInfo.refCount > 1) {
log.debug { "Skipping $statsInfo, $statsTree (count:${identityInfo.refCount})" }
}
else if (indent/2 < graphDepth) {
} else if (indent / 2 < graphDepth) {
builder.append(String.format("%03d:", indent / 2))
builder.append(CharArray(indent) { ' ' })
builder.append(" ${statsInfo.fieldName} ")
if (statsInfo.fieldType != null && statsInfo.fieldType.isArray) {
val arrayValue = (statsTree.value as Array<Any?>)
builder.append("${statsInfo.fieldType} (array length:${arrayValue.size})")
}
else if (statsInfo.fieldType != null && statsTree.value is Collection<*>) {
} else if (statsInfo.fieldType != null && statsTree.value is Collection<*>) {
builder.append("${statsInfo.fieldType} (collection size:${statsTree.value.size})")
}
else if (statsInfo.fieldType != null && statsTree.value is Map<*,*>) {
} else if (statsInfo.fieldType != null && statsTree.value is Map<*, *>) {
builder.append("${statsInfo.fieldType} (map size:${statsTree.value.size})")
}
else {
} else {
builder.append("${statsTree.className} (hash:${statsTree.value?.hashCode()}) (count:${identityInfo.refCount})")
}
builder.append(" ")
@ -476,8 +474,7 @@ fun readTrees(events: List<StatsEvent>, index: Int, idMap: IdentityHashMap<Any,
idMap[event.value] = IdentityInfo(identityInfo.tree, identityInfo.refCount + 1)
log.debug { "Skipping repeated StatsEvent.ObjectField: ${event.value} (hashcode:${event.value!!.hashCode()}) (count:${idMap[event.value]?.refCount})" }
identityInfo
}
else {
} else {
IdentityInfo(StatsTree.Loop(0), 1)
}
trees += StatsInfo(event.fieldName, event.fieldType) to identityInfo

View File

@ -22,6 +22,7 @@ interface NetworkBuilder {
fun onNodeInstance(callback: (NodeInstance) -> Unit): NetworkBuilder
/** Sets network name */
fun withNetworkName(networkName: String): NetworkBuilder
fun withBasedir(baseDir: File): NetworkBuilder
fun withBackend(backendType: Backend.BackendType): NetworkBuilder
fun withBackendOptions(options: Map<String, String>): NetworkBuilder

View File

@ -1,6 +1,8 @@
package net.corda.networkbuilder.cli
import com.fasterxml.jackson.databind.ObjectMapper
import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.getOrThrow
import net.corda.networkbuilder.Constants
import net.corda.networkbuilder.NetworkBuilder
import net.corda.networkbuilder.backends.Backend
@ -8,8 +10,6 @@ import net.corda.networkbuilder.context.Context
import net.corda.networkbuilder.nodes.NodeAdder
import net.corda.networkbuilder.nodes.NodeInstantiator
import net.corda.networkbuilder.toSingleFuture
import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.getOrThrow
import java.io.File
class CommandLineInterface {

View File

@ -1,9 +1,9 @@
package net.corda.networkbuilder.context
import net.corda.core.identity.CordaX500Name
import net.corda.networkbuilder.Constants
import net.corda.networkbuilder.backends.Backend
import net.corda.networkbuilder.nodes.NodeInstanceRequest
import net.corda.core.identity.CordaX500Name
import org.apache.activemq.artemis.utils.collections.ConcurrentHashSet
import java.util.concurrent.ConcurrentHashMap

View File

@ -14,6 +14,7 @@ import javafx.scene.layout.HBox
import javafx.scene.layout.Priority
import javafx.scene.layout.VBox
import javafx.stage.DirectoryChooser
import net.corda.core.identity.CordaX500Name
import net.corda.networkbuilder.Constants
import net.corda.networkbuilder.GuiUtils
import net.corda.networkbuilder.NetworkBuilder
@ -21,7 +22,6 @@ import net.corda.networkbuilder.backends.Backend
import net.corda.networkbuilder.baseArgs
import net.corda.networkbuilder.context.Context
import net.corda.networkbuilder.nodes.*
import net.corda.core.identity.CordaX500Name
import org.apache.commons.lang3.RandomStringUtils
import org.controlsfx.control.SegmentedButton
import tornadofx.*
@ -104,6 +104,7 @@ class BootstrapperView : View("Corda Network Builder") {
override fun get(index: Int): String {
return controller.foundNodes[index].id
}
override val size: Int
get() = controller.foundNodes.size
}
@ -291,7 +292,6 @@ class BootstrapperView : View("Corda Network Builder") {
unsortedNodes.add(NodeTemplateInfo(it.name, NodeType.NOTARY))
}
}
}
var baseDir = SimpleObjectProperty<File>(null)
@ -363,7 +363,6 @@ class BootstrapperView : View("Corda Network Builder") {
val locallyReachableAddress: String,
val rpcPort: Int,
val sshPort: Int)
}
data class FoundNodeTableEntry(val id: String, @Volatile var count: Int = 1)

View File

@ -1,7 +1,7 @@
package net.corda.networkbuilder.gui
import javafx.stage.Stage
import tornadofx.App
import tornadofx.*
class Gui : App(BootstrapperView::class) {
override fun start(stage: Stage) {

View File

@ -19,7 +19,6 @@ open class CopiedNode(configFile: File, baseDirectory: File,
return copiedNodeConfig
}
fun builtNode(nodeConfig: NodeConfiguration, imageId: String): BuiltNode {
return BuiltNode(configFile, baseDirectory, copiedNodeConfig, copiedNodeDir, nodeConfig, imageId)
}

View File

@ -1,8 +1,8 @@
package net.corda.networkbuilder.nodes
import net.corda.core.identity.CordaX500Name
import net.corda.networkbuilder.containers.instance.InstanceInfo
import net.corda.networkbuilder.context.Context
import net.corda.core.identity.CordaX500Name
import java.util.concurrent.CompletableFuture
class NodeAdder(val context: Context,
@ -13,7 +13,8 @@ class NodeAdder(val context: Context,
val nodeGroup = context.nodes[nodeGroupName]!!
val nodeInfo = nodeGroup.iterator().next()
val currentNodeSize = nodeGroup.size
val newInstanceX500 = x500ToAdd?.toString() ?: nodeInfo.groupX500!!.copy(commonName = nodeInfo.groupX500.commonName + (currentNodeSize)).toString()
val newInstanceX500 = x500ToAdd?.toString()
?: nodeInfo.groupX500!!.copy(commonName = nodeInfo.groupX500.commonName + (currentNodeSize)).toString()
val newInstanceName = nodeGroupName + (currentNodeSize)
val nextNodeInfo = nodeInfo.copy(
instanceX500 = newInstanceX500,

View File

@ -6,9 +6,9 @@ import com.github.dockerjava.core.command.BuildImageResultCallback
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigValueFactory
import net.corda.networkbuilder.docker.DockerUtils
import net.corda.common.configuration.parsing.internal.Configuration
import net.corda.common.validation.internal.Validated
import net.corda.networkbuilder.docker.DockerUtils
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.parseAsNodeConfiguration
import org.slf4j.LoggerFactory

View File

@ -3,8 +3,8 @@ package net.corda.networkbuilder.nodes
import com.typesafe.config.Config
import com.typesafe.config.ConfigException
import com.typesafe.config.ConfigFactory
import net.corda.networkbuilder.Constants
import net.corda.core.utilities.contextLogger
import net.corda.networkbuilder.Constants
import java.io.File
class NodeFinder(private val dirToSearch: File) {

View File

@ -1,10 +1,10 @@
package net.corda.networkbuilder.nodes
import net.corda.core.identity.CordaX500Name
import net.corda.networkbuilder.Constants
import net.corda.networkbuilder.containers.instance.InstanceInfo
import net.corda.networkbuilder.containers.instance.Instantiator
import net.corda.networkbuilder.context.Context
import net.corda.core.identity.CordaX500Name
import java.util.concurrent.CompletableFuture
class NodeInstantiator(val instantiator: Instantiator,

View File

@ -7,7 +7,6 @@ class CopiedNotary(configFile: File, baseDirectory: File,
copiedNodeConfig: File, copiedNodeDir: File, val nodeInfoFile: File) :
CopiedNode(configFile, baseDirectory, copiedNodeConfig, copiedNodeDir)
fun CopiedNode.toNotary(nodeInfoFile: File): CopiedNotary {
return CopiedNotary(this.configFile, this.baseDirectory, this.copiedNodeConfig, this.copiedNodeDir, nodeInfoFile)
}

View File

@ -2,11 +2,11 @@ package net.corda.networkbuilder.volumes
import com.microsoft.azure.storage.file.CloudFile
import com.typesafe.config.ConfigFactory
import net.corda.networkbuilder.notaries.CopiedNotary
import net.corda.networkbuilder.serialization.SerializationEngine
import net.corda.core.node.NetworkParameters
import net.corda.core.node.NotaryInfo
import net.corda.core.serialization.deserialize
import net.corda.networkbuilder.notaries.CopiedNotary
import net.corda.networkbuilder.serialization.SerializationEngine
import net.corda.nodeapi.internal.DEV_ROOT_CA
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.config.getBooleanCaseInsensitive
@ -28,7 +28,6 @@ interface Volume {
internal val keyPair = networkMapCa.keyPair
}
fun CloudFile.uploadFromByteArray(array: ByteArray) {
this.uploadFromByteArray(array, 0, array.size)
}

View File

@ -4,24 +4,22 @@ import com.microsoft.azure.management.Azure
import com.microsoft.azure.management.resources.ResourceGroup
import com.microsoft.azure.management.storage.StorageAccount
import com.microsoft.azure.storage.CloudStorageAccount
import net.corda.core.internal.signWithCert
import net.corda.core.serialization.serialize
import net.corda.networkbuilder.Constants.Companion.restFriendlyName
import net.corda.networkbuilder.notaries.CopiedNotary
import net.corda.networkbuilder.volumes.Volume
import net.corda.networkbuilder.volumes.Volume.Companion.keyPair
import net.corda.networkbuilder.volumes.Volume.Companion.networkMapCert
import net.corda.core.internal.signWithCert
import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME
import org.slf4j.LoggerFactory
class AzureSmbVolume(private val azure: Azure, private val resourceGroup: ResourceGroup) : Volume {
private val storageAccount = getStorageAccount()
private val accKeys = storageAccount.keys[0]
private val cloudFileShare = CloudStorageAccount.parse(
"DefaultEndpointsProtocol=https;" +
"AccountName=${storageAccount.name()};" +

View File

@ -1,10 +1,10 @@
package net.corda.networkbuilder.volumes.docker
import net.corda.core.internal.signWithCert
import net.corda.core.serialization.serialize
import net.corda.networkbuilder.context.Context
import net.corda.networkbuilder.notaries.CopiedNotary
import net.corda.networkbuilder.volumes.Volume
import net.corda.core.internal.signWithCert
import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME
import org.slf4j.LoggerFactory
import java.io.File
@ -20,7 +20,8 @@ class LocalVolume(scratchDir: File, context: Context) : Volume {
networkParamsDir.mkdirs()
val networkParameters = convertNodeIntoToNetworkParams(notaries.map { it.configFile to it.nodeInfoFile })
val networkParamsFile = File(networkParamsDir, NETWORK_PARAMS_FILE_NAME)
networkParamsFile.outputStream().use { networkParameters.signWithCert(Volume.keyPair.private, Volume.networkMapCert).serialize().writeTo(it) }
networkParamsFile.outputStream()
.use { networkParameters.signWithCert(Volume.keyPair.private, Volume.networkMapCert).serialize().writeTo(it) }
LOG.info("wrote network params to local file: ${networkParamsFile.absolutePath}")
}

View File

@ -10,10 +10,10 @@ import net.corda.tools.shell.utlities.CRaSHANSIProgressRenderer
import org.apache.commons.lang3.SystemUtils
import org.assertj.core.api.Assertions.assertThat
import org.crsh.text.RenderPrintWriter
import org.junit.Test
import rx.Observable
import org.fusesource.jansi.Ansi
import org.junit.Before
import org.junit.Test
import rx.Observable
import rx.subjects.PublishSubject
class ANSIProgressRendererTest {