mirror of
https://github.com/corda/corda.git
synced 2025-02-06 02:59:15 +00:00
Introduce full legal names for test parties
Use full names for test parties, ahead of complete X.500 name support.
This commit is contained in:
parent
2de5c0b218
commit
684d1089f0
@ -188,16 +188,16 @@ tasks.withType(Test) {
|
|||||||
|
|
||||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||||
directory "./build/nodes"
|
directory "./build/nodes"
|
||||||
networkMap "Controller"
|
networkMap "CN=Controller,O=R3,OU=corda,L=London,C=UK"
|
||||||
node {
|
node {
|
||||||
name "Controller"
|
name "CN=Controller,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = ["corda.notary.validating"]
|
advertisedServices = ["corda.notary.validating"]
|
||||||
p2pPort 10002
|
p2pPort 10002
|
||||||
cordapps = []
|
cordapps = []
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Bank A"
|
name "CN=Bank A,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10012
|
p2pPort 10012
|
||||||
@ -206,7 +206,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
cordapps = []
|
cordapps = []
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Bank B"
|
name "CN=Bank B,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "New York"
|
nearestCity "New York"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10007
|
p2pPort 10007
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.client.rpc
|
|||||||
|
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.serialization.SerializedBytes
|
import net.corda.core.serialization.SerializedBytes
|
||||||
|
import net.corda.core.utilities.ALICE
|
||||||
import net.corda.core.utilities.LogHelper
|
import net.corda.core.utilities.LogHelper
|
||||||
import net.corda.node.services.RPCUserService
|
import net.corda.node.services.RPCUserService
|
||||||
import net.corda.node.services.messaging.RPCDispatcher
|
import net.corda.node.services.messaging.RPCDispatcher
|
||||||
@ -73,7 +74,7 @@ abstract class AbstractClientRPCTest {
|
|||||||
override val users: List<User> get() = listOf(rpcUser)
|
override val users: List<User> get() = listOf(rpcUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
val dispatcher = object : RPCDispatcher(rpcImpl, userService, "SomeName") {
|
val dispatcher = object : RPCDispatcher(rpcImpl, userService, ALICE.name) {
|
||||||
override fun send(data: SerializedBytes<*>, toAddress: String) {
|
override fun send(data: SerializedBytes<*>, toAddress: String) {
|
||||||
val msg = serverSession.createMessage(false).apply {
|
val msg = serverSession.createMessage(false).apply {
|
||||||
writeBodyBufferBytes(data.bytes)
|
writeBodyBufferBytes(data.bytes)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
myLegalName : "Bank A"
|
myLegalName : "CN=Bank A,O=Bank A,L=London,C=UK"
|
||||||
nearestCity : "London"
|
nearestCity : "London"
|
||||||
keyStorePassword : "cordacadevpass"
|
keyStorePassword : "cordacadevpass"
|
||||||
trustStorePassword : "trustpass"
|
trustStorePassword : "trustpass"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
myLegalName : "Notary Service"
|
myLegalName : "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity : "London"
|
nearestCity : "London"
|
||||||
keyStorePassword : "cordacadevpass"
|
keyStorePassword : "cordacadevpass"
|
||||||
trustStorePassword : "trustpass"
|
trustStorePassword : "trustpass"
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
package net.corda.core.utilities
|
package net.corda.core.utilities
|
||||||
|
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
@ -19,34 +20,34 @@ val DUMMY_KEY_2: KeyPair by lazy { generateKeyPair() }
|
|||||||
|
|
||||||
val DUMMY_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(20)) }
|
val DUMMY_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(20)) }
|
||||||
/** Dummy notary identity for tests and simulations */
|
/** Dummy notary identity for tests and simulations */
|
||||||
val DUMMY_NOTARY: Party get() = Party("Notary Service", DUMMY_NOTARY_KEY.public)
|
val DUMMY_NOTARY: Party get() = Party("CN=Notary Service,O=R3,OU=corda,L=London,C=UK", DUMMY_NOTARY_KEY.public)
|
||||||
|
|
||||||
val DUMMY_MAP_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(30)) }
|
val DUMMY_MAP_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(30)) }
|
||||||
/** Dummy network map service identity for tests and simulations */
|
/** Dummy network map service identity for tests and simulations */
|
||||||
val DUMMY_MAP: Party get() = Party("Network Map Service", DUMMY_MAP_KEY.public)
|
val DUMMY_MAP: Party get() = Party("CN=Network Map Service,O=R3,OU=corda,L=London,C=UK", DUMMY_MAP_KEY.public)
|
||||||
|
|
||||||
val DUMMY_BANK_A_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(40)) }
|
val DUMMY_BANK_A_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(40)) }
|
||||||
/** Dummy bank identity for tests and simulations */
|
/** Dummy bank identity for tests and simulations */
|
||||||
val DUMMY_BANK_A: Party get() = Party("Bank A", DUMMY_BANK_A_KEY.public)
|
val DUMMY_BANK_A: Party get() = Party("CN=Bank A,O=Bank A,L=London,C=UK", DUMMY_BANK_A_KEY.public)
|
||||||
|
|
||||||
val DUMMY_BANK_B_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(50)) }
|
val DUMMY_BANK_B_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(50)) }
|
||||||
/** Dummy bank identity for tests and simulations */
|
/** Dummy bank identity for tests and simulations */
|
||||||
val DUMMY_BANK_B: Party get() = Party("Bank B", DUMMY_BANK_B_KEY.public)
|
val DUMMY_BANK_B: Party get() = Party("CN=Bank B,O=Bank B,L=New York,C=USA", DUMMY_BANK_B_KEY.public)
|
||||||
|
|
||||||
val DUMMY_BANK_C_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(60)) }
|
val DUMMY_BANK_C_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(60)) }
|
||||||
/** Dummy bank identity for tests and simulations */
|
/** Dummy bank identity for tests and simulations */
|
||||||
val DUMMY_BANK_C: Party get() = Party("Bank C", DUMMY_BANK_C_KEY.public)
|
val DUMMY_BANK_C: Party get() = Party("CN=Bank C,O=Bank C,L=Tokyo,C=Japan", DUMMY_BANK_C_KEY.public)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val ALICE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(70)) }
|
val ALICE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(70)) }
|
||||||
/** Dummy individual identity for tests and simulations */
|
/** Dummy individual identity for tests and simulations */
|
||||||
val ALICE: Party get() = Party("Alice", ALICE_KEY.public)
|
val ALICE: Party get() = Party("CN=Alice Corp,O=Alice Corp,L=London,C=UK", ALICE_KEY.public)
|
||||||
|
|
||||||
val BOB_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(80)) }
|
val BOB_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(80)) }
|
||||||
/** Dummy individual identity for tests and simulations */
|
/** Dummy individual identity for tests and simulations */
|
||||||
val BOB: Party get() = Party("Bob", BOB_KEY.public)
|
val BOB: Party get() = Party("CN=Bob Plc,O=Bob Plc,L=London,C=UK", BOB_KEY.public)
|
||||||
|
|
||||||
val CHARLIE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(90)) }
|
val CHARLIE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(90)) }
|
||||||
/** Dummy individual identity for tests and simulations */
|
/** Dummy individual identity for tests and simulations */
|
||||||
val CHARLIE: Party get() = Party("Charlie", CHARLIE_KEY.public)
|
val CHARLIE: Party get() = Party("CN=Charlie Ltd,O=Charlie Ltd,L=London,C=UK", CHARLIE_KEY.public)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.core.crypto
|
package net.corda.core.crypto
|
||||||
|
|
||||||
|
import net.corda.core.utilities.ALICE
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -11,7 +12,7 @@ class PartyTest {
|
|||||||
val key = entropyToKeyPair(BigInteger.valueOf(20170207L)).public
|
val key = entropyToKeyPair(BigInteger.valueOf(20170207L)).public
|
||||||
val differentKey = entropyToKeyPair(BigInteger.valueOf(7201702L)).public
|
val differentKey = entropyToKeyPair(BigInteger.valueOf(7201702L)).public
|
||||||
val anonymousParty = AnonymousParty(key)
|
val anonymousParty = AnonymousParty(key)
|
||||||
val party = Party("test key", key)
|
val party = Party(ALICE.name, key)
|
||||||
assertEquals<AbstractParty>(party, anonymousParty)
|
assertEquals<AbstractParty>(party, anonymousParty)
|
||||||
assertEquals<AbstractParty>(anonymousParty, party)
|
assertEquals<AbstractParty>(anonymousParty, party)
|
||||||
assertNotEquals<AbstractParty>(AnonymousParty(differentKey), anonymousParty)
|
assertNotEquals<AbstractParty>(AnonymousParty(differentKey), anonymousParty)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.core.node
|
package net.corda.core.node
|
||||||
|
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.ServiceType
|
import net.corda.core.node.services.ServiceType
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -8,7 +9,7 @@ import kotlin.test.assertFailsWith
|
|||||||
|
|
||||||
class ServiceInfoTests {
|
class ServiceInfoTests {
|
||||||
val serviceType = ServiceType.getServiceType("test", "service").getSubType("subservice")
|
val serviceType = ServiceType.getServiceType("test", "service").getSubType("subservice")
|
||||||
val name = "service.name"
|
val name = "CN=service.name,O=R3,OU=corda,L=London,C=UK"
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `type and name encodes correctly`() {
|
fun `type and name encodes correctly`() {
|
||||||
|
@ -34,7 +34,7 @@ NetworkMapService plus Simple Notary configuration file.
|
|||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
myLegalName : "Notary Service"
|
myLegalName : "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity : "London"
|
nearestCity : "London"
|
||||||
keyStorePassword : "cordacadevpass"
|
keyStorePassword : "cordacadevpass"
|
||||||
trustStorePassword : "trustpass"
|
trustStorePassword : "trustpass"
|
||||||
|
@ -194,9 +194,9 @@ is a three node example;
|
|||||||
|
|
||||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||||
directory "./build/nodes" // The output directory
|
directory "./build/nodes" // The output directory
|
||||||
networkMap "Controller" // The artemis address of the node named here will be used as the networkMapService.address on all other nodes.
|
networkMap "CN=Controller,O=R3,OU=corda,L=London,C=UK" // The distinguished name of the node named here will be used as the networkMapService.address on all other nodes.
|
||||||
node {
|
node {
|
||||||
name "Controller"
|
name "CN=Controller,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = [ "corda.notary.validating" ]
|
advertisedServices = [ "corda.notary.validating" ]
|
||||||
p2pPort 10002
|
p2pPort 10002
|
||||||
@ -206,7 +206,7 @@ is a three node example;
|
|||||||
cordapps []
|
cordapps []
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "NodeA"
|
name "CN=NodeA,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10005
|
p2pPort 10005
|
||||||
@ -216,7 +216,7 @@ is a three node example;
|
|||||||
cordapps []
|
cordapps []
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "NodeB"
|
name "CN=NodeB,O=R3,OU=corda,L=New York,C=USA"
|
||||||
nearestCity "New York"
|
nearestCity "New York"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10008
|
p2pPort 10008
|
||||||
|
@ -76,9 +76,9 @@ task integrationTest(type: Test) {
|
|||||||
|
|
||||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||||
directory "./build/nodes"
|
directory "./build/nodes"
|
||||||
networkMap "Notary"
|
networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
node {
|
node {
|
||||||
name "Notary"
|
name "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = ["corda.notary.validating"]
|
advertisedServices = ["corda.notary.validating"]
|
||||||
p2pPort 10002
|
p2pPort 10002
|
||||||
@ -87,7 +87,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
cordapps = []
|
cordapps = []
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Alice"
|
name "CN=Alice Corp,O=Alice Corp,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10005
|
p2pPort 10005
|
||||||
|
@ -3,6 +3,7 @@ package net.corda.docs
|
|||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.USD
|
import net.corda.core.contracts.USD
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.node.CordaPluginRegistry
|
import net.corda.core.node.CordaPluginRegistry
|
||||||
@ -11,6 +12,8 @@ import net.corda.core.serialization.CordaSerializable
|
|||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
import net.corda.core.serialization.SerializationCustomization
|
import net.corda.core.serialization.SerializationCustomization
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.utilities.ALICE
|
||||||
|
import net.corda.core.utilities.DUMMY_NOTARY
|
||||||
import net.corda.flows.CashExitFlow
|
import net.corda.flows.CashExitFlow
|
||||||
import net.corda.flows.CashIssueFlow
|
import net.corda.flows.CashIssueFlow
|
||||||
import net.corda.flows.CashPaymentFlow
|
import net.corda.flows.CashPaymentFlow
|
||||||
@ -46,8 +49,8 @@ fun main(args: Array<String>) {
|
|||||||
startFlowPermission<CashExitFlow>()))
|
startFlowPermission<CashExitFlow>()))
|
||||||
|
|
||||||
driver(driverDirectory = baseDirectory) {
|
driver(driverDirectory = baseDirectory) {
|
||||||
startNode("Notary", advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type)))
|
startNode(DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type)))
|
||||||
val node = startNode("Alice", rpcUsers = listOf(user)).get()
|
val node = startNode(ALICE.name, rpcUsers = listOf(user)).get()
|
||||||
// END 1
|
// END 1
|
||||||
|
|
||||||
// START 2
|
// START 2
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
myLegalName : "Notary Service"
|
myLegalName : "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity : "London"
|
nearestCity : "London"
|
||||||
keyStorePassword : "cordacadevpass"
|
keyStorePassword : "cordacadevpass"
|
||||||
trustStorePassword : "trustpass"
|
trustStorePassword : "trustpass"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
myLegalName : "Bank A"
|
myLegalName : "CN=Bank A,O=Bank A,L=London,C=UK"
|
||||||
nearestCity : "London"
|
nearestCity : "London"
|
||||||
keyStorePassword : "cordacadevpass"
|
keyStorePassword : "cordacadevpass"
|
||||||
trustStorePassword : "trustpass"
|
trustStorePassword : "trustpass"
|
||||||
@ -14,7 +14,7 @@ webAddress : "localhost:10004"
|
|||||||
extraAdvertisedServiceIds : [ "corda.interest_rates" ]
|
extraAdvertisedServiceIds : [ "corda.interest_rates" ]
|
||||||
networkMapService : {
|
networkMapService : {
|
||||||
address : "my-network-map:10000"
|
address : "my-network-map:10000"
|
||||||
legalName : "Network Map Service"
|
legalName : "CN=Network Map Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
}
|
}
|
||||||
useHTTPS : false
|
useHTTPS : false
|
||||||
rpcUsers : [
|
rpcUsers : [
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
myLegalName : "Bank A"
|
myLegalName : "CN=Bank A,O=Bank A,L=London,C=UK"
|
||||||
nearestCity : "London"
|
nearestCity : "London"
|
||||||
p2pAddress : "my-corda-node:10002"
|
p2pAddress : "my-corda-node:10002"
|
||||||
webAddress : "localhost:10003"
|
webAddress : "localhost:10003"
|
||||||
networkMapService : {
|
networkMapService : {
|
||||||
address : "my-network-map:10000"
|
address : "my-network-map:10000"
|
||||||
legalName : "Network Map Service"
|
legalName : "CN=Network Map Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
}
|
}
|
||||||
verifierType: "OutOfProcess"
|
verifierType: "OutOfProcess"
|
||||||
|
@ -12,6 +12,16 @@ composite key signatures. This will form the underlying basis of future work to
|
|||||||
formats to enable interoperability with other systems, as well as enabling the use of composite signatures on X.509
|
formats to enable interoperability with other systems, as well as enabling the use of composite signatures on X.509
|
||||||
certificates to prove association between transaction keys and identity keys.
|
certificates to prove association between transaction keys and identity keys.
|
||||||
|
|
||||||
|
The identity work is likely to require changes to existing code and configurations, to replace party names with full
|
||||||
|
X.500 distinguished names (see RFC 1779 for details on the construction of distinguished names). Generally:
|
||||||
|
|
||||||
|
* "myLegalName" in node configurations will need to be replaced, for example "Bank A" is replaced with
|
||||||
|
"CN=Bank A,O=Bank A,L=London,C=UK". Obviously organisation, location and country ("O", "L" and "C" respectively)
|
||||||
|
must be given values which are appropriate to the node, do not just use these example values.
|
||||||
|
* If you are constructing ``Party`` objects, be aware that the name must now be a distinguished name.
|
||||||
|
* If you are using mock parties for testing, try to standardise on the ``DUMMY_NOTARY``, ``DUMMY_BANK_A``, etc. provided
|
||||||
|
in order to ensure consistency.
|
||||||
|
|
||||||
We have updated DemoBench so that it is installed as "Corda DemoBench" for both Windows and MacOSX. The original version was installed as just "DemoBench", and so will not be overwritten automatically by the new version.
|
We have updated DemoBench so that it is installed as "Corda DemoBench" for both Windows and MacOSX. The original version was installed as just "DemoBench", and so will not be overwritten automatically by the new version.
|
||||||
|
|
||||||
Milestone 10
|
Milestone 10
|
||||||
|
@ -67,7 +67,7 @@ Yaml (yet another markup language) is a simple JSON-like way to describe object
|
|||||||
that make it helpful for our use case, like a lightweight syntax and support for "bare words" which mean you can
|
that make it helpful for our use case, like a lightweight syntax and support for "bare words" which mean you can
|
||||||
often skip the quotes around strings. Here is an example of how this syntax is used:
|
often skip the quotes around strings. Here is an example of how this syntax is used:
|
||||||
|
|
||||||
``flow start CashIssue amount: $1000, issueRef: 1234, recipient: Bank A, notary: Notary Service``
|
``flow start CashIssue amount: $1000, issueRef: 1234, recipient: "CN=Bank A,O=Bank A,L=London,C=UK", notary: "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"``
|
||||||
|
|
||||||
This invokes a constructor of a flow with the following prototype in the code:
|
This invokes a constructor of a flow with the following prototype in the code:
|
||||||
|
|
||||||
@ -140,4 +140,4 @@ The shell will be enhanced over time. The currently known limitations include:
|
|||||||
.. _Yaml: http://www.yaml.org/spec/1.2/spec.html
|
.. _Yaml: http://www.yaml.org/spec/1.2/spec.html
|
||||||
.. _the defined parsers: api/kotlin/corda/net.corda.jackson/-jackson-support/index.html
|
.. _the defined parsers: api/kotlin/corda/net.corda.jackson/-jackson-support/index.html
|
||||||
.. _Groovy: http://groovy-lang.org/
|
.. _Groovy: http://groovy-lang.org/
|
||||||
.. _CRaSH: http://www.crashub.org/
|
.. _CRaSH: http://www.crashub.org/
|
||||||
|
@ -116,7 +116,7 @@ In the instructions above the server node permissions are configured programmati
|
|||||||
|
|
||||||
driver(driverDirectory = baseDirectory) {
|
driver(driverDirectory = baseDirectory) {
|
||||||
val user = User("user", "password", permissions = setOf(startFlowPermission<CashFlow>()))
|
val user = User("user", "password", permissions = setOf(startFlowPermission<CashFlow>()))
|
||||||
val node = startNode("Alice", rpcUsers = listOf(user)).get()
|
val node = startNode("CN=Alice Corp,O=Alice Corp,L=London,C=UK", rpcUsers = listOf(user)).get()
|
||||||
|
|
||||||
When starting a standalone node using a configuration file we must supply the RPC credentials as follows:
|
When starting a standalone node using a configuration file we must supply the RPC credentials as follows:
|
||||||
|
|
||||||
|
@ -774,9 +774,9 @@ like to deploy for testing. See further details below:
|
|||||||
|
|
||||||
task deployNodes(type: com.r3corda.plugins.Cordform, dependsOn: ['jar']) {
|
task deployNodes(type: com.r3corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||||
directory "./kotlin-source/build/nodes" // The output directory.
|
directory "./kotlin-source/build/nodes" // The output directory.
|
||||||
networkMap "Controller" // The artemis address of the node to be used as the network map.
|
networkMap "CN=Controller,O=R3,OU=corda,L=London,C=UK" // The distinguished name of the node to be used as the network map.
|
||||||
node {
|
node {
|
||||||
name "Controller" // Artemis name of node to be deployed.
|
name "CN=Controller,O=R3,OU=corda,L=London,C=UK" // Distinguished name of node to be deployed.
|
||||||
nearestCity "London" // For use with the network visualiser.
|
nearestCity "London" // For use with the network visualiser.
|
||||||
advertisedServices = ["corda.notary.validating"] // A list of services you wish the node to offer.
|
advertisedServices = ["corda.notary.validating"] // A list of services you wish the node to offer.
|
||||||
p2pPort 10002
|
p2pPort 10002
|
||||||
@ -785,7 +785,7 @@ like to deploy for testing. See further details below:
|
|||||||
cordapps = [] // Add package names of CordaApps.
|
cordapps = [] // Add package names of CordaApps.
|
||||||
}
|
}
|
||||||
node { // Create an additional node.
|
node { // Create an additional node.
|
||||||
name "NodeA"
|
name "CN=NodeA,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10005
|
p2pPort 10005
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
package net.corda.contracts.universal
|
package net.corda.contracts.universal
|
||||||
|
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
|
import net.corda.core.utilities.ALICE
|
||||||
|
import net.corda.testing.MEGA_CORP
|
||||||
|
import net.corda.testing.MINI_CORP
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
// Test parties
|
// Test parties
|
||||||
val acmeCorp = Party("ACME Corporation", generateKeyPair().public)
|
val acmeCorp = Party(ALICE.name, generateKeyPair().public)
|
||||||
val highStreetBank = Party("High Street Bank", generateKeyPair().public)
|
val highStreetBank = Party(MEGA_CORP.name, generateKeyPair().public)
|
||||||
val momAndPop = Party("Mom and Pop", generateKeyPair().public)
|
val momAndPop = Party(MINI_CORP.name, generateKeyPair().public)
|
||||||
|
|
||||||
val acmeCorporationHasDefaulted = TerminalEvent(acmeCorp, generateKeyPair().public)
|
val acmeCorporationHasDefaulted = TerminalEvent(acmeCorp, generateKeyPair().public)
|
||||||
|
|
||||||
|
@ -203,7 +203,7 @@ infix fun Cash.State.`with deposit`(deposit: PartyAndReference): Cash.State = wi
|
|||||||
/** A randomly generated key. */
|
/** A randomly generated key. */
|
||||||
val DUMMY_CASH_ISSUER_KEY by lazy { entropyToKeyPair(BigInteger.valueOf(10)) }
|
val DUMMY_CASH_ISSUER_KEY by lazy { entropyToKeyPair(BigInteger.valueOf(10)) }
|
||||||
/** A dummy, randomly generated issuer party by the name of "Snake Oil Issuer" */
|
/** A dummy, randomly generated issuer party by the name of "Snake Oil Issuer" */
|
||||||
val DUMMY_CASH_ISSUER by lazy { Party("Snake Oil Issuer", DUMMY_CASH_ISSUER_KEY.public).ref(1) }
|
val DUMMY_CASH_ISSUER by lazy { Party("CN=Snake Oil Issuer,O=R3,OU=corda,L=London,C=UK", DUMMY_CASH_ISSUER_KEY.public).ref(1) }
|
||||||
/** An extension property that lets you write 100.DOLLARS.CASH */
|
/** An extension property that lets you write 100.DOLLARS.CASH */
|
||||||
val Amount<Currency>.CASH: Cash.State get() = Cash.State(Amount(quantity, Issued(DUMMY_CASH_ISSUER, token)), NullPublicKey)
|
val Amount<Currency>.CASH: Cash.State get() = Cash.State(Amount(quantity, Issued(DUMMY_CASH_ISSUER, token)), NullPublicKey)
|
||||||
/** An extension property that lets you get a cash state from an issued token, under the [NullPublicKey] */
|
/** An extension property that lets you get a cash state from an issued token, under the [NullPublicKey] */
|
||||||
|
@ -719,7 +719,7 @@ infix fun <T : Any> Obligation.State<T>.`issued by`(party: AbstractParty) = copy
|
|||||||
/** A randomly generated key. */
|
/** A randomly generated key. */
|
||||||
val DUMMY_OBLIGATION_ISSUER_KEY by lazy { entropyToKeyPair(BigInteger.valueOf(10)) }
|
val DUMMY_OBLIGATION_ISSUER_KEY by lazy { entropyToKeyPair(BigInteger.valueOf(10)) }
|
||||||
/** A dummy, randomly generated issuer party by the name of "Snake Oil Issuer" */
|
/** A dummy, randomly generated issuer party by the name of "Snake Oil Issuer" */
|
||||||
val DUMMY_OBLIGATION_ISSUER by lazy { Party("Snake Oil Issuer", DUMMY_OBLIGATION_ISSUER_KEY.public) }
|
val DUMMY_OBLIGATION_ISSUER by lazy { Party("CN=Snake Oil Issuer,O=R3,OU=corda,L=London,C=UK", DUMMY_OBLIGATION_ISSUER_KEY.public) }
|
||||||
|
|
||||||
val Issued<Currency>.OBLIGATION_DEF: Obligation.Terms<Currency>
|
val Issued<Currency>.OBLIGATION_DEF: Obligation.Terms<Currency>
|
||||||
get() = Obligation.Terms(nonEmptySetOf(Cash().legalContractReference), nonEmptySetOf(this), TEST_TX_TIME)
|
get() = Obligation.Terms(nonEmptySetOf(Cash().legalContractReference), nonEmptySetOf(this), TEST_TX_TIME)
|
||||||
|
@ -42,7 +42,7 @@ class DriverTests {
|
|||||||
fun `simple node startup and shutdown`() {
|
fun `simple node startup and shutdown`() {
|
||||||
val handles = driver {
|
val handles = driver {
|
||||||
val notary = startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type)))
|
val notary = startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type)))
|
||||||
val regulator = startNode("Regulator", setOf(ServiceInfo(RegulatorService.type)))
|
val regulator = startNode("CN=Regulator,O=R3,OU=corda,L=London,C=UK", setOf(ServiceInfo(RegulatorService.type)))
|
||||||
listOf(nodeMustBeUp(notary), nodeMustBeUp(regulator))
|
listOf(nodeMustBeUp(notary), nodeMustBeUp(regulator))
|
||||||
}
|
}
|
||||||
handles.map { nodeMustBeDown(it) }
|
handles.map { nodeMustBeDown(it) }
|
||||||
|
@ -98,4 +98,4 @@ class BFTNotaryServiceTests : NodeBasedTest() {
|
|||||||
|
|
||||||
return remainingNodes + masterNode
|
return remainingNodes + masterNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import kotlin.test.assertEquals
|
|||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
class RaftNotaryServiceTests : NodeBasedTest() {
|
class RaftNotaryServiceTests : NodeBasedTest() {
|
||||||
private val notaryName = "RAFT Notary Service"
|
private val notaryName = "CN=RAFT Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `detect double spend`() {
|
fun `detect double spend`() {
|
||||||
|
@ -42,9 +42,9 @@ class P2PSecurityTest : NodeBasedTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `register with the network map service using a legal name different from the TLS CN`() {
|
fun `register with the network map service using a legal name different from the TLS CN`() {
|
||||||
startSimpleNode("Attacker").use {
|
startSimpleNode("CN=Attacker,O=R3,OU=corda,L=London,C=UK").use {
|
||||||
// Register with the network map using a different legal name
|
// Register with the network map using a different legal name
|
||||||
val response = it.registerWithNetworkMap("Legit Business")
|
val response = it.registerWithNetworkMap("CN=Legit Business,O=R3,OU=corda,L=London,C=UK")
|
||||||
// We don't expect a response because the network map's host verification will prevent a connection back
|
// We don't expect a response because the network map's host verification will prevent a connection back
|
||||||
// to the attacker as the TLS CN will not match the legal name it has just provided
|
// to the attacker as the TLS CN will not match the legal name it has just provided
|
||||||
assertThatExceptionOfType(TimeoutException::class.java).isThrownBy {
|
assertThatExceptionOfType(TimeoutException::class.java).isThrownBy {
|
||||||
|
@ -51,6 +51,7 @@ import net.corda.node.utilities.AffinityExecutor
|
|||||||
import net.corda.node.utilities.configureDatabase
|
import net.corda.node.utilities.configureDatabase
|
||||||
import net.corda.node.utilities.transaction
|
import net.corda.node.utilities.transaction
|
||||||
import org.apache.activemq.artemis.utils.ReusableLatch
|
import org.apache.activemq.artemis.utils.ReusableLatch
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.jetbrains.exposed.sql.Database
|
import org.jetbrains.exposed.sql.Database
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
@ -305,7 +306,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
protected open fun makeServiceEntries(): List<ServiceEntry> {
|
protected open fun makeServiceEntries(): List<ServiceEntry> {
|
||||||
return advertisedServices.map {
|
return advertisedServices.map {
|
||||||
val serviceId = it.type.id
|
val serviceId = it.type.id
|
||||||
val serviceName = it.name ?: "$serviceId|${configuration.myLegalName}"
|
val serviceName = it.name ?: "ou=$serviceId,${configuration.myLegalName}"
|
||||||
val identity = obtainKeyPair(configuration.baseDirectory, serviceId + "-private-key", serviceId + "-public", serviceName).first
|
val identity = obtainKeyPair(configuration.baseDirectory, serviceId + "-private-key", serviceId + "-public", serviceName).first
|
||||||
ServiceEntry(it, identity)
|
ServiceEntry(it, identity)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import com.google.common.util.concurrent.ListenableFuture
|
|||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.FlowStateMachine
|
import net.corda.core.flows.FlowStateMachine
|
||||||
import net.corda.core.flows.StateMachineRunId
|
import net.corda.core.flows.StateMachineRunId
|
||||||
@ -16,6 +17,7 @@ import net.corda.core.utilities.UntrustworthyData
|
|||||||
import net.corda.jackson.JacksonSupport
|
import net.corda.jackson.JacksonSupport
|
||||||
import net.corda.node.services.identity.InMemoryIdentityService
|
import net.corda.node.services.identity.InMemoryIdentityService
|
||||||
import net.corda.node.shell.InteractiveShell
|
import net.corda.node.shell.InteractiveShell
|
||||||
|
import net.corda.testing.MEGA_CORP
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -28,12 +30,12 @@ class InteractiveShellTest {
|
|||||||
constructor(b: Int, c: String) : this(b.toString() + c)
|
constructor(b: Int, c: String) : this(b.toString() + c)
|
||||||
constructor(amount: Amount<Currency>) : this(amount.toString())
|
constructor(amount: Amount<Currency>) : this(amount.toString())
|
||||||
constructor(pair: Pair<Amount<Currency>, SecureHash.SHA256>) : this(pair.toString())
|
constructor(pair: Pair<Amount<Currency>, SecureHash.SHA256>) : this(pair.toString())
|
||||||
constructor(party: Party) : this(party.name)
|
constructor(party: Party) : this(party.name.toString())
|
||||||
|
|
||||||
override fun call() = a
|
override fun call() = a
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ids = InMemoryIdentityService().apply { registerIdentity(Party("SomeCorp", DUMMY_PUBKEY_1)) }
|
private val someCorpLegalName = MEGA_CORP.name
|
||||||
|
private val ids = InMemoryIdentityService().apply { registerIdentity(Party(MEGA_CORP.name, DUMMY_PUBKEY_1)) }
|
||||||
private val om = JacksonSupport.createInMemoryMapper(ids, YAMLFactory())
|
private val om = JacksonSupport.createInMemoryMapper(ids, YAMLFactory())
|
||||||
|
|
||||||
private fun check(input: String, expected: String) {
|
private fun check(input: String, expected: String) {
|
||||||
@ -66,7 +68,7 @@ class InteractiveShellTest {
|
|||||||
fun flowTooManyParams() = check("b: 12, c: Yo, d: Bar", "")
|
fun flowTooManyParams() = check("b: 12, c: Yo, d: Bar", "")
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun party() = check("party: SomeCorp", "SomeCorp")
|
fun party() = check("party: \"${someCorpLegalName}\"", someCorpLegalName)
|
||||||
|
|
||||||
class DummyFSM(val logic: FlowA) : FlowStateMachine<Any?> {
|
class DummyFSM(val logic: FlowA) : FlowStateMachine<Any?> {
|
||||||
override fun <T : Any> sendAndReceive(receiveType: Class<T>, otherParty: Party, payload: Any, sessionFlow: FlowLogic<*>): UntrustworthyData<T> {
|
override fun <T : Any> sendAndReceive(receiveType: Class<T>, otherParty: Party, payload: Any, sessionFlow: FlowLogic<*>): UntrustworthyData<T> {
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.node.services
|
|||||||
|
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
@ -74,7 +75,7 @@ class NotaryChangeTests {
|
|||||||
@Test
|
@Test
|
||||||
fun `should throw when a participant refuses to change Notary`() {
|
fun `should throw when a participant refuses to change Notary`() {
|
||||||
val state = issueMultiPartyState(clientNodeA, clientNodeB, oldNotaryNode)
|
val state = issueMultiPartyState(clientNodeA, clientNodeB, oldNotaryNode)
|
||||||
val newEvilNotary = Party("Evil Notary", generateKeyPair().public)
|
val newEvilNotary = Party("CN=Evil Notary,O=Evil R3,OU=corda,L=London,C=UK", generateKeyPair().public)
|
||||||
val flow = Instigator(state, newEvilNotary)
|
val flow = Instigator(state, newEvilNotary)
|
||||||
val future = clientNodeA.services.startFlow(flow)
|
val future = clientNodeA.services.startFlow(flow)
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.node.services.config
|
package net.corda.node.services.config
|
||||||
|
|
||||||
|
import net.corda.core.utilities.ALICE
|
||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
import net.corda.testing.testConfiguration
|
import net.corda.testing.testConfiguration
|
||||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||||
@ -10,7 +11,7 @@ class FullNodeConfigurationTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `Artemis special characters not permitted in RPC usernames`() {
|
fun `Artemis special characters not permitted in RPC usernames`() {
|
||||||
fun configWithRPCUsername(username: String): FullNodeConfiguration {
|
fun configWithRPCUsername(username: String): FullNodeConfiguration {
|
||||||
return testConfiguration(Paths.get("."), "NodeA", 0).copy(
|
return testConfiguration(Paths.get("."), ALICE.name, 0).copy(
|
||||||
rpcUsers = listOf(User(username, "pass", emptySet())))
|
rpcUsers = listOf(User(username, "pass", emptySet())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,13 @@ import com.google.common.util.concurrent.Futures
|
|||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import com.typesafe.config.ConfigFactory.empty
|
import com.typesafe.config.ConfigFactory.empty
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.messaging.Message
|
import net.corda.core.messaging.Message
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.messaging.createMessage
|
import net.corda.core.messaging.createMessage
|
||||||
import net.corda.core.node.services.DEFAULT_SESSION_ID
|
import net.corda.core.node.services.DEFAULT_SESSION_ID
|
||||||
|
import net.corda.core.utilities.ALICE
|
||||||
import net.corda.core.utilities.LogHelper
|
import net.corda.core.utilities.LogHelper
|
||||||
import net.corda.node.services.RPCUserService
|
import net.corda.node.services.RPCUserService
|
||||||
import net.corda.node.services.RPCUserServiceImpl
|
import net.corda.node.services.RPCUserServiceImpl
|
||||||
@ -73,7 +75,7 @@ class ArtemisMessagingTests {
|
|||||||
userService = RPCUserServiceImpl(emptyList())
|
userService = RPCUserServiceImpl(emptyList())
|
||||||
config = TestNodeConfiguration(
|
config = TestNodeConfiguration(
|
||||||
baseDirectory = baseDirectory,
|
baseDirectory = baseDirectory,
|
||||||
myLegalName = "me",
|
myLegalName = ALICE.name,
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
||||||
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties())
|
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties())
|
||||||
|
@ -10,6 +10,7 @@ import net.corda.core.node.services.ServiceInfo
|
|||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.utilities.ALICE
|
import net.corda.core.utilities.ALICE
|
||||||
import net.corda.core.utilities.BOB
|
import net.corda.core.utilities.BOB
|
||||||
|
import net.corda.core.utilities.CHARLIE
|
||||||
import net.corda.flows.sendRequest
|
import net.corda.flows.sendRequest
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.services.network.AbstractNetworkMapServiceTest.Changed.Added
|
import net.corda.node.services.network.AbstractNetworkMapServiceTest.Changed.Added
|
||||||
@ -141,7 +142,7 @@ abstract class AbstractNetworkMapServiceTest<out S : AbstractNetworkMapService>
|
|||||||
val updates = alice.subscribe()
|
val updates = alice.subscribe()
|
||||||
val bob = addNewNodeToNetworkMap(BOB.name)
|
val bob = addNewNodeToNetworkMap(BOB.name)
|
||||||
alice.unsubscribe()
|
alice.unsubscribe()
|
||||||
addNewNodeToNetworkMap("Charlie")
|
addNewNodeToNetworkMap(CHARLIE.name)
|
||||||
swizzle()
|
swizzle()
|
||||||
assertThat(updates.map { it.wireReg.verified().toChanged() }).containsOnly(Added(bob.info))
|
assertThat(updates.map { it.wireReg.verified().toChanged() }).containsOnly(Added(bob.info))
|
||||||
}
|
}
|
||||||
@ -274,4 +275,4 @@ abstract class AbstractNetworkMapServiceTest<out S : AbstractNetworkMapService>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.corda.node.services.network
|
package net.corda.node.services.network
|
||||||
|
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.node.services.identity.InMemoryIdentityService
|
import net.corda.node.services.identity.InMemoryIdentityService
|
||||||
import net.corda.core.utilities.ALICE
|
import net.corda.core.utilities.ALICE
|
||||||
@ -50,9 +51,10 @@ class InMemoryIdentityServiceTests {
|
|||||||
@Test
|
@Test
|
||||||
fun `get identity by name`() {
|
fun `get identity by name`() {
|
||||||
val service = InMemoryIdentityService()
|
val service = InMemoryIdentityService()
|
||||||
val identities = listOf("Node A", "Node B", "Node C").map { Party(it, generateKeyPair().public) }
|
val identities = listOf("Node A", "Node B", "Node C")
|
||||||
|
.map { Party("CN=$it,O=R3,OU=corda,L=London,C=UK", generateKeyPair().public) }
|
||||||
assertNull(service.partyFromName(identities.first().name))
|
assertNull(service.partyFromName(identities.first().name))
|
||||||
identities.forEach { service.registerIdentity(it) }
|
identities.forEach { service.registerIdentity(it) }
|
||||||
identities.forEach { assertEquals(it, service.partyFromName(it.name)) }
|
identities.forEach { assertEquals(it, service.partyFromName(it.name)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package net.corda.node.services.network
|
|||||||
|
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
|
import net.corda.core.utilities.ALICE
|
||||||
|
import net.corda.core.utilities.BOB
|
||||||
import net.corda.node.utilities.transaction
|
import net.corda.node.utilities.transaction
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -22,8 +24,8 @@ class InMemoryNetworkMapCacheTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `key collision`() {
|
fun `key collision`() {
|
||||||
val entropy = BigInteger.valueOf(24012017L)
|
val entropy = BigInteger.valueOf(24012017L)
|
||||||
val nodeA = network.createNode(null, -1, MockNetwork.DefaultFactory, true, "Node A", null, entropy, ServiceInfo(NetworkMapService.type))
|
val nodeA = network.createNode(null, -1, MockNetwork.DefaultFactory, true, ALICE.name, null, entropy, ServiceInfo(NetworkMapService.type))
|
||||||
val nodeB = network.createNode(null, -1, MockNetwork.DefaultFactory, true, "Node B", null, entropy, ServiceInfo(NetworkMapService.type))
|
val nodeB = network.createNode(null, -1, MockNetwork.DefaultFactory, true, BOB.name, null, entropy, ServiceInfo(NetworkMapService.type))
|
||||||
assertEquals(nodeA.info.legalIdentity, nodeB.info.legalIdentity)
|
assertEquals(nodeA.info.legalIdentity, nodeB.info.legalIdentity)
|
||||||
|
|
||||||
// Node A currently knows only about itself, so this returns node A
|
// Node A currently knows only about itself, so this returns node A
|
||||||
|
@ -8,6 +8,7 @@ import net.corda.core.*
|
|||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.contracts.DummyState
|
import net.corda.core.contracts.DummyState
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
@ -73,12 +74,12 @@ class StateMachineManagerTests {
|
|||||||
node1 = nodes.first
|
node1 = nodes.first
|
||||||
node2 = nodes.second
|
node2 = nodes.second
|
||||||
val notaryKeyPair = generateKeyPair()
|
val notaryKeyPair = generateKeyPair()
|
||||||
val notaryService = ServiceInfo(ValidatingNotaryService.type, "notary-service-2000")
|
val notaryService = ServiceInfo(ValidatingNotaryService.type, "CN=notary-service-2000,O=R3,OU=corda,L=London,C=UK")
|
||||||
val overrideServices = mapOf(Pair(notaryService, notaryKeyPair))
|
val overrideServices = mapOf(Pair(notaryService, notaryKeyPair))
|
||||||
// Note that these notaries don't operate correctly as they don't share their state. They are only used for testing
|
// Note that these notaries don't operate correctly as they don't share their state. They are only used for testing
|
||||||
// service addressing.
|
// service addressing.
|
||||||
notary1 = net.createNotaryNode(networkMapAddr = node1.services.myInfo.address, overrideServices = overrideServices, serviceName = "notary-service-2000")
|
notary1 = net.createNotaryNode(networkMapAddr = node1.services.myInfo.address, overrideServices = overrideServices, serviceName = notaryService.name)
|
||||||
notary2 = net.createNotaryNode(networkMapAddr = node1.services.myInfo.address, overrideServices = overrideServices, serviceName = "notary-service-2000")
|
notary2 = net.createNotaryNode(networkMapAddr = node1.services.myInfo.address, overrideServices = overrideServices, serviceName = notaryService.name)
|
||||||
|
|
||||||
net.messagingNetwork.receivedMessages.toSessionTransfers().forEach { sessionTransfers += it }
|
net.messagingNetwork.receivedMessages.toSessionTransfers().forEach { sessionTransfers += it }
|
||||||
net.runNetwork()
|
net.runNetwork()
|
||||||
|
@ -6,6 +6,7 @@ import com.nhaarman.mockito_kotlin.mock
|
|||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.X509Utilities
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.exists
|
import net.corda.core.exists
|
||||||
|
import net.corda.core.utilities.ALICE
|
||||||
import net.corda.testing.TestNodeConfiguration
|
import net.corda.testing.TestNodeConfiguration
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -34,7 +35,7 @@ class NetworkRegistrationHelperTest {
|
|||||||
|
|
||||||
val config = TestNodeConfiguration(
|
val config = TestNodeConfiguration(
|
||||||
baseDirectory = tempFolder.root.toPath(),
|
baseDirectory = tempFolder.root.toPath(),
|
||||||
myLegalName = "me",
|
myLegalName = ALICE.name,
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
|
|
||||||
assertFalse(config.keyStoreFile.exists())
|
assertFalse(config.keyStoreFile.exists())
|
||||||
|
@ -55,9 +55,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
ext.rpcUsers = [['username': "demo", 'password': "demo", 'permissions': ["StartFlow.net.corda.flows.FinalityFlow"]]]
|
ext.rpcUsers = [['username': "demo", 'password': "demo", 'permissions': ["StartFlow.net.corda.flows.FinalityFlow"]]]
|
||||||
|
|
||||||
directory "./build/nodes"
|
directory "./build/nodes"
|
||||||
networkMap "Controller"
|
networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
node {
|
node {
|
||||||
name "Controller"
|
name "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices["corda.notary.validating"]
|
advertisedServices["corda.notary.validating"]
|
||||||
p2pPort 10002
|
p2pPort 10002
|
||||||
@ -66,7 +66,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
rpcUsers = ext.rpcUsers
|
rpcUsers = ext.rpcUsers
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Bank A"
|
name "CN=Bank A,O=Bank A,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10005
|
p2pPort 10005
|
||||||
@ -75,7 +75,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
rpcUsers = ext.rpcUsers
|
rpcUsers = ext.rpcUsers
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Bank B"
|
name "CN=Bank B,O=Bank B,L=New York,C=USA"
|
||||||
nearestCity "New York"
|
nearestCity "New York"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10008
|
p2pPort 10008
|
||||||
|
@ -13,6 +13,7 @@ import net.corda.core.getOrThrow
|
|||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.startTrackedFlow
|
import net.corda.core.messaging.startTrackedFlow
|
||||||
import net.corda.core.sizedInputStreamAndHash
|
import net.corda.core.sizedInputStreamAndHash
|
||||||
|
import net.corda.core.utilities.DUMMY_BANK_B
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY
|
import net.corda.core.utilities.DUMMY_NOTARY
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
||||||
import net.corda.core.utilities.Emoji
|
import net.corda.core.utilities.Emoji
|
||||||
@ -66,7 +67,7 @@ fun sender(rpc: CordaRPCOps, numOfClearBytes: Int = 1024) { // default size 1K.
|
|||||||
|
|
||||||
fun sender(rpc: CordaRPCOps, inputStream: InputStream, hash: SecureHash.SHA256) {
|
fun sender(rpc: CordaRPCOps, inputStream: InputStream, hash: SecureHash.SHA256) {
|
||||||
// Get the identity key of the other side (the recipient).
|
// Get the identity key of the other side (the recipient).
|
||||||
val otherSide: Party = rpc.partyFromName("Bank B")!!
|
val otherSide: Party = rpc.partyFromName(DUMMY_BANK_B.name) ?: throw IllegalStateException("Could not find counterparty \"${DUMMY_BANK_B.name}\"")
|
||||||
|
|
||||||
// Make sure we have the file in storage
|
// Make sure we have the file in storage
|
||||||
if (!rpc.attachmentExists(hash)) {
|
if (!rpc.attachmentExists(hash)) {
|
||||||
@ -133,4 +134,4 @@ class AttachmentContract : Contract {
|
|||||||
override val contract: Contract = AttachmentContract()
|
override val contract: Contract = AttachmentContract()
|
||||||
override val participants: List<PublicKey> = emptyList()
|
override val participants: List<PublicKey> = emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ The RPC API requires a client to pass in user credentials:
|
|||||||
client.start("bankUser","test")
|
client.start("bankUser","test")
|
||||||
which are validated on the Bank of Corda node against those configured at node startup:
|
which are validated on the Bank of Corda node against those configured at node startup:
|
||||||
User("bankUser", "test", permissions = setOf(startFlowPermission<IssuerFlow.IssuanceRequester>()))
|
User("bankUser", "test", permissions = setOf(startFlowPermission<IssuerFlow.IssuanceRequester>()))
|
||||||
startNode("BankOfCorda", rpcUsers = listOf(user))
|
startNode(BOC.name, rpcUsers = listOf(user))
|
||||||
|
|
||||||
Notary
|
Notary
|
||||||
We are using a [SimpleNotaryService] in this example, but could easily switch to a [ValidatingNotaryService]
|
We are using a [SimpleNotaryService] in this example, but could easily switch to a [ValidatingNotaryService]
|
||||||
|
@ -52,9 +52,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
directory "./build/nodes"
|
directory "./build/nodes"
|
||||||
// This name "Notary" is hard-coded into BankOfCordaClientApi so if you change it here, change it there too.
|
// This name "Notary" is hard-coded into BankOfCordaClientApi so if you change it here, change it there too.
|
||||||
// In this demo the node that runs a standalone notary also acts as the network map server.
|
// In this demo the node that runs a standalone notary also acts as the network map server.
|
||||||
networkMap "Notary"
|
networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
node {
|
node {
|
||||||
name "Notary"
|
name "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = ["corda.notary.validating"]
|
advertisedServices = ["corda.notary.validating"]
|
||||||
p2pPort 10002
|
p2pPort 10002
|
||||||
@ -62,8 +62,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
cordapps = []
|
cordapps = []
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "BankOfCorda"
|
name "CN=BankOfCorda,O=R3,OU=corda,L=New York,C=USA"
|
||||||
nearestCity "London"
|
nearestCity "New York"
|
||||||
advertisedServices = ["corda.issuer.USD"]
|
advertisedServices = ["corda.issuer.USD"]
|
||||||
p2pPort 10005
|
p2pPort 10005
|
||||||
rpcPort 10006
|
rpcPort 10006
|
||||||
@ -77,7 +77,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "BigCorporation"
|
name "CN=BigCorporation,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "New York"
|
nearestCity "New York"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10008
|
p2pPort 10008
|
||||||
|
@ -16,10 +16,10 @@ class BankOfCordaHttpAPITest {
|
|||||||
driver(dsl = {
|
driver(dsl = {
|
||||||
val (nodeBankOfCorda) = Futures.allAsList(
|
val (nodeBankOfCorda) = Futures.allAsList(
|
||||||
startNode(BOC.name, setOf(ServiceInfo(SimpleNotaryService.type))),
|
startNode(BOC.name, setOf(ServiceInfo(SimpleNotaryService.type))),
|
||||||
startNode("BigCorporation")
|
startNode(BIGCORP_LEGAL_NAME)
|
||||||
).getOrThrow()
|
).getOrThrow()
|
||||||
val nodeBankOfCordaApiAddr = startWebserver(nodeBankOfCorda).getOrThrow().listenAddress
|
val nodeBankOfCordaApiAddr = startWebserver(nodeBankOfCorda).getOrThrow().listenAddress
|
||||||
assert(BankOfCordaClientApi(nodeBankOfCordaApiAddr).requestWebIssue(IssueRequestParams(1000, "USD", "BigCorporation", "1", BOC.name)))
|
assert(BankOfCordaClientApi(nodeBankOfCordaApiAddr).requestWebIssue(IssueRequestParams(1000, "USD", BIGCORP_LEGAL_NAME, "1", BOC.name)))
|
||||||
}, isDebug = true)
|
}, isDebug = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ class BankOfCordaRPCClientTest {
|
|||||||
val bigCorpCFO = User("bigCorpCFO", "password2", permissions = emptySet())
|
val bigCorpCFO = User("bigCorpCFO", "password2", permissions = emptySet())
|
||||||
val (nodeBankOfCorda, nodeBigCorporation) = Futures.allAsList(
|
val (nodeBankOfCorda, nodeBigCorporation) = Futures.allAsList(
|
||||||
startNode(BOC.name, setOf(ServiceInfo(SimpleNotaryService.type)), listOf(bocManager)),
|
startNode(BOC.name, setOf(ServiceInfo(SimpleNotaryService.type)), listOf(bocManager)),
|
||||||
startNode("BigCorporation", rpcUsers = listOf(bigCorpCFO))
|
startNode(BIGCORP_LEGAL_NAME, rpcUsers = listOf(bigCorpCFO))
|
||||||
).getOrThrow()
|
).getOrThrow()
|
||||||
|
|
||||||
// Bank of Corda RPC Client
|
// Bank of Corda RPC Client
|
||||||
|
@ -4,6 +4,7 @@ import com.google.common.net.HostAndPort
|
|||||||
import joptsimple.OptionParser
|
import joptsimple.OptionParser
|
||||||
import net.corda.bank.api.BankOfCordaClientApi
|
import net.corda.bank.api.BankOfCordaClientApi
|
||||||
import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
|
import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.ServiceType
|
import net.corda.core.node.services.ServiceType
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
@ -27,6 +28,8 @@ fun main(args: Array<String>) {
|
|||||||
val BANK_USERNAME = "bankUser"
|
val BANK_USERNAME = "bankUser"
|
||||||
val BIGCORP_USERNAME = "bigCorpUser"
|
val BIGCORP_USERNAME = "bigCorpUser"
|
||||||
|
|
||||||
|
val BIGCORP_LEGAL_NAME = "CN=BigCorporation,O=R3,OU=corda,L=London,C=UK"
|
||||||
|
|
||||||
private class BankOfCordaDriver {
|
private class BankOfCordaDriver {
|
||||||
enum class Role {
|
enum class Role {
|
||||||
ISSUE_CASH_RPC,
|
ISSUE_CASH_RPC,
|
||||||
@ -57,13 +60,13 @@ private class BankOfCordaDriver {
|
|||||||
val bigCorpUser = User(BIGCORP_USERNAME, "test", permissions = setOf(startFlowPermission<CashPaymentFlow>()))
|
val bigCorpUser = User(BIGCORP_USERNAME, "test", permissions = setOf(startFlowPermission<CashPaymentFlow>()))
|
||||||
startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type)))
|
startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type)))
|
||||||
val bankOfCorda = startNode(BOC.name, rpcUsers = listOf(bankUser), advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("issuer.USD"))))
|
val bankOfCorda = startNode(BOC.name, rpcUsers = listOf(bankUser), advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("issuer.USD"))))
|
||||||
startNode("BigCorporation", rpcUsers = listOf(bigCorpUser))
|
startNode(BIGCORP_LEGAL_NAME, rpcUsers = listOf(bigCorpUser))
|
||||||
startWebserver(bankOfCorda.get())
|
startWebserver(bankOfCorda.get())
|
||||||
waitForAllNodesToFinish()
|
waitForAllNodesToFinish()
|
||||||
}, isDebug = true)
|
}, isDebug = true)
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
val requestParams = IssueRequestParams(options.valueOf(quantity), options.valueOf(currency), "BigCorporation", "1", "BankOfCorda")
|
val requestParams = IssueRequestParams(options.valueOf(quantity), options.valueOf(currency), BIGCORP_LEGAL_NAME, "1", BOC.name)
|
||||||
when (role) {
|
when (role) {
|
||||||
Role.ISSUE_CASH_RPC -> {
|
Role.ISSUE_CASH_RPC -> {
|
||||||
println("Requesting Cash via RPC ...")
|
println("Requesting Cash via RPC ...")
|
||||||
|
@ -57,9 +57,9 @@ dependencies {
|
|||||||
|
|
||||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||||
directory "./build/nodes"
|
directory "./build/nodes"
|
||||||
networkMap "Notary"
|
networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
node {
|
node {
|
||||||
name "Notary"
|
name "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = ["corda.notary.validating", "corda.interest_rates"]
|
advertisedServices = ["corda.notary.validating", "corda.interest_rates"]
|
||||||
p2pPort 10002
|
p2pPort 10002
|
||||||
@ -69,7 +69,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
useTestClock true
|
useTestClock true
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Bank A"
|
name "CN=Bank A,O=Bank A,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10005
|
p2pPort 10005
|
||||||
@ -79,7 +79,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
useTestClock true
|
useTestClock true
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Bank B"
|
name "CN=Bank B,O=Bank B,L=New York,C=USA"
|
||||||
nearestCity "New York"
|
nearestCity "New York"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10008
|
p2pPort 10008
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.simulation
|
|||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
import com.google.common.util.concurrent.Futures
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.flatMap
|
import net.corda.core.flatMap
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
@ -70,7 +71,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
// TODO: Set this back to "Bank of $city" after video day.
|
// TODO: Set this back to "Bank of $city" after video day.
|
||||||
myLegalName = "Bank $letter",
|
myLegalName = "CN=Bank $letter,O=Bank $letter,L=city",
|
||||||
nearestCity = city,
|
nearestCity = city,
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
||||||
@ -121,7 +122,8 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
require(advertisedServices.containsType(NodeInterestRates.type))
|
require(advertisedServices.containsType(NodeInterestRates.type))
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = "Rates Service Provider",
|
// TODO: Make a more realistic legal name
|
||||||
|
myLegalName = "CN=Rates Service Provider,O=R3,OU=corda,L=London,C=UK",
|
||||||
nearestCity = "Madrid",
|
nearestCity = "Madrid",
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
||||||
@ -144,7 +146,8 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
entropyRoot: BigInteger): MockNetwork.MockNode {
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = "Regulator A",
|
// TODO: Make a more realistic legal name
|
||||||
|
myLegalName = "Regulator A,O=R3,OU=corda,L=London,C=UK",
|
||||||
nearestCity = "Paris",
|
nearestCity = "Paris",
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"fixedLeg": {
|
"fixedLeg": {
|
||||||
"fixedRatePayer": "Bank A",
|
"fixedRatePayer": "CN=Bank A,O=Bank A,L=London,C=UK",
|
||||||
"notional": "€25000000",
|
"notional": "€25000000",
|
||||||
"paymentFrequency": "SemiAnnual",
|
"paymentFrequency": "SemiAnnual",
|
||||||
"effectiveDate": "2016-03-11",
|
"effectiveDate": "2016-03-11",
|
||||||
@ -22,7 +22,7 @@
|
|||||||
"interestPeriodAdjustment": "Adjusted"
|
"interestPeriodAdjustment": "Adjusted"
|
||||||
},
|
},
|
||||||
"floatingLeg": {
|
"floatingLeg": {
|
||||||
"floatingRatePayer": "Bank B",
|
"floatingRatePayer": "CN=Bank B,O=Bank B,L=New York,C=USA",
|
||||||
"notional": "€25000000",
|
"notional": "€25000000",
|
||||||
"paymentFrequency": "Quarterly",
|
"paymentFrequency": "Quarterly",
|
||||||
"effectiveDate": "2016-03-11",
|
"effectiveDate": "2016-03-11",
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
define(['utils/dayCountBasisLookup'], (dayCountBasisLookup) => {
|
define(['utils/dayCountBasisLookup'], (dayCountBasisLookup) => {
|
||||||
return {
|
return {
|
||||||
fixedRatePayer: "Bank A",
|
fixedRatePayer: "CN=Bank A,O=Bank A,L=London,C=UK",
|
||||||
notional: {
|
notional: {
|
||||||
quantity: 2500000000
|
quantity: 2500000000
|
||||||
},
|
},
|
||||||
@ -17,4 +17,4 @@ define(['utils/dayCountBasisLookup'], (dayCountBasisLookup) => {
|
|||||||
paymentDelay: "0",
|
paymentDelay: "0",
|
||||||
interestPeriodAdjustment: "Adjusted"
|
interestPeriodAdjustment: "Adjusted"
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
define(['utils/dayCountBasisLookup'], (dayCountBasisLookup) => {
|
define(['utils/dayCountBasisLookup'], (dayCountBasisLookup) => {
|
||||||
return {
|
return {
|
||||||
floatingRatePayer: "Bank B",
|
floatingRatePayer: "CN=Bank B,O=Bank B,L=New York,C=USA",
|
||||||
notional: {
|
notional: {
|
||||||
quantity: 2500000000
|
quantity: 2500000000
|
||||||
},
|
},
|
||||||
@ -25,4 +25,4 @@ define(['utils/dayCountBasisLookup'], (dayCountBasisLookup) => {
|
|||||||
name: "3M"
|
name: "3M"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -8,6 +8,7 @@ import net.corda.core.bd
|
|||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.MerkleTreeException
|
import net.corda.core.crypto.MerkleTreeException
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
@ -47,7 +48,7 @@ class NodeInterestRatesTest {
|
|||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
|
|
||||||
val DUMMY_CASH_ISSUER_KEY = generateKeyPair()
|
val DUMMY_CASH_ISSUER_KEY = generateKeyPair()
|
||||||
val DUMMY_CASH_ISSUER = Party("Cash issuer", DUMMY_CASH_ISSUER_KEY.public)
|
val DUMMY_CASH_ISSUER = Party("CN=Cash issuer,O=R3,OU=corda,L=London,C=UK", DUMMY_CASH_ISSUER_KEY.public)
|
||||||
|
|
||||||
val clock = Clock.systemUTC()
|
val clock = Clock.systemUTC()
|
||||||
lateinit var oracle: NodeInterestRates.Oracle
|
lateinit var oracle: NodeInterestRates.Oracle
|
||||||
|
@ -75,9 +75,9 @@ task generateNotaryIdentity(type: JavaExec) {
|
|||||||
|
|
||||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', 'generateNotaryIdentity']) {
|
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', 'generateNotaryIdentity']) {
|
||||||
directory deployTo
|
directory deployTo
|
||||||
networkMap "Notary 1"
|
networkMap "CN=Notary 1,O=R3,OU=corda,L=London,C=UK"
|
||||||
node {
|
node {
|
||||||
name "Party"
|
name "CN=Party,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10002
|
p2pPort 10002
|
||||||
@ -89,7 +89,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', 'generateN
|
|||||||
]]]
|
]]]
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Counterparty"
|
name "CN=Counterparty,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "New York"
|
nearestCity "New York"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10005
|
p2pPort 10005
|
||||||
@ -97,7 +97,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', 'generateN
|
|||||||
cordapps = []
|
cordapps = []
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Notary 1"
|
name "CN=Notary 1,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = [advertisedNotary]
|
advertisedServices = [advertisedNotary]
|
||||||
p2pPort 10008
|
p2pPort 10008
|
||||||
@ -106,7 +106,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', 'generateN
|
|||||||
notaryNodePort 11002
|
notaryNodePort 11002
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Notary 2"
|
name "CN=Notary 2,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = [advertisedNotary]
|
advertisedServices = [advertisedNotary]
|
||||||
p2pPort 10011
|
p2pPort 10011
|
||||||
@ -116,7 +116,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', 'generateN
|
|||||||
notaryClusterAddresses = ["localhost:11002"]
|
notaryClusterAddresses = ["localhost:11002"]
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Notary 3"
|
name "CN=Notary 3,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = [advertisedNotary]
|
advertisedServices = [advertisedNotary]
|
||||||
p2pPort 10014
|
p2pPort 10014
|
||||||
|
@ -68,16 +68,16 @@ dependencies {
|
|||||||
|
|
||||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||||
directory "./build/nodes"
|
directory "./build/nodes"
|
||||||
networkMap "Controller"
|
networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
node {
|
node {
|
||||||
name "Controller"
|
name "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = ["corda.notary.validating"]
|
advertisedServices = ["corda.notary.validating"]
|
||||||
p2pPort 10002
|
p2pPort 10002
|
||||||
cordapps = []
|
cordapps = []
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Bank A"
|
name "CN=Bank A,O=Bank A,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10004
|
p2pPort 10004
|
||||||
@ -85,7 +85,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
cordapps = []
|
cordapps = []
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Bank B"
|
name "CN=Bank B,O=Bank B,L=New York,C=USA"
|
||||||
nearestCity "New York"
|
nearestCity "New York"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10006
|
p2pPort 10006
|
||||||
@ -93,8 +93,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
cordapps = []
|
cordapps = []
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Bank C"
|
name "CN=Bank C,O=Bank C,L=Tokyo,C=Japan"
|
||||||
nearestCity "tokyo"
|
nearestCity "Tokyo"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10008
|
p2pPort 10008
|
||||||
webPort 10009
|
webPort 10009
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
var FixedLegViewModel = (function () {
|
var FixedLegViewModel = (function () {
|
||||||
function FixedLegViewModel() {
|
function FixedLegViewModel() {
|
||||||
this.fixedRatePayer = "Bank A";
|
this.fixedRatePayer = "CN=Bank A,O=Bank A,L=London,C=UK";
|
||||||
this.notional = {
|
this.notional = {
|
||||||
quantity: 2500000000
|
quantity: 2500000000
|
||||||
};
|
};
|
||||||
@ -17,4 +17,4 @@ var FixedLegViewModel = (function () {
|
|||||||
return FixedLegViewModel;
|
return FixedLegViewModel;
|
||||||
}());
|
}());
|
||||||
exports.FixedLegViewModel = FixedLegViewModel;
|
exports.FixedLegViewModel = FixedLegViewModel;
|
||||||
//# sourceMappingURL=FixedLegViewModel.js.map
|
//# sourceMappingURL=FixedLegViewModel.js.map
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
var FloatingLegViewModel = (function () {
|
var FloatingLegViewModel = (function () {
|
||||||
function FloatingLegViewModel() {
|
function FloatingLegViewModel() {
|
||||||
this.floatingRatePayer = "Bank B";
|
this.floatingRatePayer = "CN=Bank B,O=Bank B,L=New York,C=USA";
|
||||||
this.notional = {
|
this.notional = {
|
||||||
quantity: 2500000000
|
quantity: 2500000000
|
||||||
};
|
};
|
||||||
@ -25,4 +25,4 @@ var FloatingLegViewModel = (function () {
|
|||||||
return FloatingLegViewModel;
|
return FloatingLegViewModel;
|
||||||
}());
|
}());
|
||||||
exports.FloatingLegViewModel = FloatingLegViewModel;
|
exports.FloatingLegViewModel = FloatingLegViewModel;
|
||||||
//# sourceMappingURL=FloatingLegViewModel.js.map
|
//# sourceMappingURL=FloatingLegViewModel.js.map
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
export class FloatingLegViewModel {
|
export class FloatingLegViewModel {
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
floatingRatePayer = "Bank B";
|
floatingRatePayer = "CN=Bank B,O=Bank B,L=New York,C=USA";
|
||||||
notional: Object = {
|
notional: Object = {
|
||||||
quantity: 2500000000
|
quantity: 2500000000
|
||||||
};
|
};
|
||||||
|
@ -68,16 +68,16 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
directory "./build/nodes"
|
directory "./build/nodes"
|
||||||
// This name "Notary" is hard-coded into TraderDemoClientApi so if you change it here, change it there too.
|
// This name "Notary" is hard-coded into TraderDemoClientApi so if you change it here, change it there too.
|
||||||
// In this demo the node that runs a standalone notary also acts as the network map server.
|
// In this demo the node that runs a standalone notary also acts as the network map server.
|
||||||
networkMap "Notary"
|
networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
node {
|
node {
|
||||||
name "Notary"
|
name "CN=Notary Service,O=R3,OU=corda,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = ["corda.notary.validating"]
|
advertisedServices = ["corda.notary.validating"]
|
||||||
p2pPort 10002
|
p2pPort 10002
|
||||||
cordapps = []
|
cordapps = []
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Bank A"
|
name "CN=Bank A,O=Bank A,L=London,C=UK"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10005
|
p2pPort 10005
|
||||||
@ -86,7 +86,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
rpcUsers = ext.rpcUsers
|
rpcUsers = ext.rpcUsers
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "Bank B"
|
name "CN=Bank B,O=Bank B,L=New York,C=USA"
|
||||||
nearestCity "New York"
|
nearestCity "New York"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10008
|
p2pPort 10008
|
||||||
@ -95,7 +95,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
rpcUsers = ext.rpcUsers
|
rpcUsers = ext.rpcUsers
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "BankOfCorda"
|
name "CN=BankOfCorda,O=R3,OU=corda,L=New York,C=USA"
|
||||||
nearestCity "London"
|
nearestCity "London"
|
||||||
advertisedServices = []
|
advertisedServices = []
|
||||||
p2pPort 10011
|
p2pPort 10011
|
||||||
|
@ -48,7 +48,7 @@ private class TraderDemo {
|
|||||||
} else {
|
} else {
|
||||||
val host = HostAndPort.fromString("localhost:10009")
|
val host = HostAndPort.fromString("localhost:10009")
|
||||||
CordaRPCClient(host).use("demo", "demo") {
|
CordaRPCClient(host).use("demo", "demo") {
|
||||||
TraderDemoClientApi(this).runSeller(1000.DOLLARS, "Bank A")
|
TraderDemoClientApi(this).runSeller(1000.DOLLARS, "CN=Bank A,O=Bank A,L=London,C=UK")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,15 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import net.corda.contracts.CommercialPaper
|
import net.corda.contracts.CommercialPaper
|
||||||
import net.corda.contracts.asset.DUMMY_CASH_ISSUER
|
import net.corda.contracts.asset.DUMMY_CASH_ISSUER
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.days
|
import net.corda.core.days
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.seconds
|
import net.corda.core.seconds
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.utilities.DUMMY_BANK_C
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
import net.corda.flows.NotaryFlow
|
import net.corda.flows.NotaryFlow
|
||||||
import net.corda.flows.TwoPartyTradeFlow
|
import net.corda.flows.TwoPartyTradeFlow
|
||||||
@ -63,7 +66,7 @@ class SellerFlow(val otherParty: Party,
|
|||||||
fun selfIssueSomeCommercialPaper(ownedBy: PublicKey, notaryNode: NodeInfo): StateAndRef<CommercialPaper.State> {
|
fun selfIssueSomeCommercialPaper(ownedBy: PublicKey, notaryNode: NodeInfo): StateAndRef<CommercialPaper.State> {
|
||||||
// Make a fake company that's issued its own paper.
|
// Make a fake company that's issued its own paper.
|
||||||
val keyPair = generateKeyPair()
|
val keyPair = generateKeyPair()
|
||||||
val party = Party("Bank of London", keyPair.public)
|
val party = Party(DUMMY_BANK_C.name, keyPair.public)
|
||||||
|
|
||||||
val issuance: SignedTransaction = run {
|
val issuance: SignedTransaction = run {
|
||||||
val tx = CommercialPaper().generateIssue(party.ref(1, 2, 3), 1100.DOLLARS `issued by` DUMMY_CASH_ISSUER,
|
val tx = CommercialPaper().generateIssue(party.ref(1, 2, 3), 1100.DOLLARS `issued by` DUMMY_CASH_ISSUER,
|
||||||
|
@ -71,7 +71,7 @@ val MINI_CORP: Party get() = Party("MiniCorp", MINI_CORP_PUBKEY)
|
|||||||
|
|
||||||
val BOC_KEY: KeyPair by lazy { generateKeyPair() }
|
val BOC_KEY: KeyPair by lazy { generateKeyPair() }
|
||||||
val BOC_PUBKEY: PublicKey get() = BOC_KEY.public
|
val BOC_PUBKEY: PublicKey get() = BOC_KEY.public
|
||||||
val BOC: Party get() = Party("BankOfCorda", BOC_PUBKEY)
|
val BOC: Party get() = Party("CN=BankOfCorda,O=R3,OU=corda,L=New York,C=USA", BOC_PUBKEY)
|
||||||
val BOC_PARTY_REF = BOC.ref(OpaqueBytes.of(1)).reference
|
val BOC_PARTY_REF = BOC.ref(OpaqueBytes.of(1)).reference
|
||||||
|
|
||||||
val BIG_CORP_KEY: KeyPair by lazy { generateKeyPair() }
|
val BIG_CORP_KEY: KeyPair by lazy { generateKeyPair() }
|
||||||
|
@ -160,7 +160,7 @@ class NodeConfigTest {
|
|||||||
+ "\"h2port\":30001,"
|
+ "\"h2port\":30001,"
|
||||||
+ "\"myLegalName\":\"MyName\","
|
+ "\"myLegalName\":\"MyName\","
|
||||||
+ "\"nearestCity\":\"Stockholm\","
|
+ "\"nearestCity\":\"Stockholm\","
|
||||||
+ "\"networkMapService\":{\"address\":\"localhost:12345\",\"legalName\":\"NotaryService\"},"
|
+ "\"networkMapService\":{\"address\":\"localhost:12345\",\"legalName\":\"CN=NotaryService,O=R3,OU=corda,L=London,C=UK\"},"
|
||||||
+ "\"p2pAddress\":\"localhost:10001\","
|
+ "\"p2pAddress\":\"localhost:10001\","
|
||||||
+ "\"rpcAddress\":\"localhost:40002\","
|
+ "\"rpcAddress\":\"localhost:40002\","
|
||||||
+ "\"rpcUsers\":["
|
+ "\"rpcUsers\":["
|
||||||
|
Loading…
x
Reference in New Issue
Block a user