Merge pull request #182 from corda/colljos-os-hc02-merge-121217

OS -> Enterprise merge for HC02
This commit is contained in:
josecoll 2017-12-13 15:06:40 +00:00 committed by GitHub
commit 65ccd2318f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
298 changed files with 3604 additions and 1619 deletions

View File

@ -2756,6 +2756,10 @@ public static final class net.corda.core.serialization.SerializationContext$UseC
public static net.corda.core.serialization.SerializationContext$UseCase valueOf(String)
public static net.corda.core.serialization.SerializationContext$UseCase[] values()
##
public interface net.corda.core.serialization.SerializationCustomSerializer
public abstract Object fromProxy(Object)
public abstract Object toProxy(Object)
##
public final class net.corda.core.serialization.SerializationDefaults extends java.lang.Object
@org.jetbrains.annotations.NotNull public final net.corda.core.serialization.SerializationContext getCHECKPOINT_CONTEXT()
@org.jetbrains.annotations.NotNull public final net.corda.core.serialization.SerializationContext getP2P_CONTEXT()

View File

@ -6,6 +6,7 @@ import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.contracts.Amount
import net.corda.core.cordapp.CordappProvider
import net.corda.core.crypto.*
import net.corda.core.identity.CordaX500Name
import net.corda.core.node.ServiceHub
import net.corda.core.transactions.SignedTransaction
import net.corda.finance.USD
@ -20,9 +21,12 @@ import java.util.*
import kotlin.test.assertEquals
class JacksonSupportTest {
companion object {
private val SEED = BigInteger.valueOf(20170922L)
private companion object {
val SEED = BigInteger.valueOf(20170922L)!!
val mapper = JacksonSupport.createNonRpcMapper()
val ALICE_PUBKEY = TestIdentity(ALICE_NAME, 70).pubkey
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
val MINI_CORP = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")).party
}
@Rule

View File

@ -2,6 +2,7 @@ package net.corda.client.jfx
import net.corda.client.jfx.model.NodeMonitorModel
import net.corda.client.jfx.model.ProgressTrackingEvent
import net.corda.core.context.Origin
import net.corda.core.contracts.Amount
import net.corda.core.contracts.ContractState
import net.corda.core.crypto.isFulfilledBy
@ -10,7 +11,6 @@ import net.corda.core.flows.StateMachineRunId
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.internal.bufferUntilSubscribed
import net.corda.core.context.Origin
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.StateMachineTransactionMapping
import net.corda.core.messaging.StateMachineUpdate
@ -53,7 +53,7 @@ class NodeMonitorModelTest : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE, BOB, CHARLIE, DUMMY_NOTARY)
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE_NAME, BOB_NAME, CHARLIE_NAME, DUMMY_NOTARY_NAME)
.map { it.toDatabaseSchemaNames("","_10000","_10003") }.flatten().toTypedArray())
}

View File

@ -14,7 +14,7 @@ import net.corda.nodeapi.internal.config.User;
import net.corda.testing.CoreTestUtils;
import net.corda.testing.IntegrationTestKt;
import net.corda.testing.IntegrationTestSchemas;
import net.corda.testing.internal.NodeBasedTest;
import net.corda.testing.node.internal.NodeBasedTest;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
@ -31,8 +31,8 @@ import static net.corda.finance.Currencies.DOLLARS;
import static net.corda.finance.contracts.GetBalances.getCashBalance;
import static net.corda.node.services.Permissions.invokeRpc;
import static net.corda.node.services.Permissions.startFlow;
import static net.corda.testing.TestConstants.getALICE;
import static net.corda.testing.TestConstants.getDUMMY_NOTARY;
import static net.corda.testing.TestConstants.getALICE_NAME;
import static net.corda.testing.TestConstants.getDUMMY_NOTARY_NAME;
public class CordaRPCJavaClientTest extends NodeBasedTest {
public CordaRPCJavaClientTest() {
@ -40,8 +40,8 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
}
@ClassRule
public static IntegrationTestSchemas databaseSchemas = new IntegrationTestSchemas(IntegrationTestKt.toDatabaseSchemaName(getALICE()),
IntegrationTestKt.toDatabaseSchemaName(getDUMMY_NOTARY()));
public static IntegrationTestSchemas databaseSchemas = new IntegrationTestSchemas(IntegrationTestKt.toDatabaseSchemaName(getALICE_NAME()),
IntegrationTestKt.toDatabaseSchemaName(getDUMMY_NOTARY_NAME()));
private List<String> perms = Arrays.asList(
startFlow(CashPaymentFlow.class),
@ -65,7 +65,7 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
@Before
public void setUp() throws Exception {
super.setUp();
node = startNode(getALICE().getName(), 1, singletonList(rpcUser));
node = startNode(getALICE_NAME(), 1, singletonList(rpcUser));
client = new CordaRPCClient(requireNonNull(node.getInternals().getConfiguration().getRpcAddress()));
}

View File

@ -18,7 +18,7 @@ class BlacklistKotlinClosureTest : IntegrationTest() {
const val EVIL: Long = 666
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(ALICE.toDatabaseSchemaName(), DUMMY_NOTARY.toDatabaseSchemaName())
val databaseSchemas = IntegrationTestSchemas(ALICE_NAME.toDatabaseSchemaName(), DUMMY_NOTARY_NAME.toDatabaseSchemaName())
}
@StartableByRPC
@ -33,7 +33,7 @@ class BlacklistKotlinClosureTest : IntegrationTest() {
@Test
fun `closure sent via RPC`() {
driver(startNodesInProcess = true) {
val rpc = startNode(providedName = ALICE.name).getOrThrow().rpc
val rpc = startNode(providedName = ALICE_NAME).getOrThrow().rpc
val packet = Packet { EVIL }
assertThatExceptionOfType(KryoException::class.java)
.isThrownBy { rpc.startFlow(::FlowC, packet) }

View File

@ -22,7 +22,7 @@ import net.corda.node.services.Permissions.Companion.invokeRpc
import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.nodeapi.internal.config.User
import net.corda.testing.*
import net.corda.testing.internal.NodeBasedTest
import net.corda.testing.node.internal.NodeBasedTest
import org.apache.activemq.artemis.api.core.ActiveMQSecurityException
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatExceptionOfType
@ -52,7 +52,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", C
}
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(ALICE.toDatabaseSchemaName())
val databaseSchemas = IntegrationTestSchemas(ALICE_NAME.toDatabaseSchemaName())
}
@Before
@ -141,7 +141,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", C
@Test
fun `flow initiator via RPC`() {
val externalTrace = Trace.newInstance()
val impersonatedActor = Actor(Actor.Id("Mark Dadada"), AuthServiceId("Test"), owningLegalIdentity = BOB.name)
val impersonatedActor = Actor(Actor.Id("Mark Dadada"), AuthServiceId("Test"), owningLegalIdentity = BOB_NAME)
login(rpcUser.username, rpcUser.password, externalTrace, impersonatedActor)
val proxy = connection!!.proxy

View File

@ -13,8 +13,8 @@ import net.corda.core.utilities.*
import net.corda.node.services.messaging.RPCServerConfiguration
import net.corda.nodeapi.RPCApi
import net.corda.testing.*
import net.corda.testing.internal.poll
import net.corda.testing.internal.*
import net.corda.testing.internal.testThreadFactory
import net.corda.testing.node.internal.*
import org.apache.activemq.artemis.api.core.SimpleString
import org.junit.After
import org.junit.Assert.assertEquals
@ -26,7 +26,10 @@ import rx.Observable
import rx.subjects.PublishSubject
import rx.subjects.UnicastSubject
import java.time.Duration
import java.util.concurrent.*
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
class RPCStabilityTests : IntegrationTest() {
@ -41,7 +44,7 @@ class RPCStabilityTests : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE, BOB, DUMMY_BANK_A)
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE_NAME, BOB_NAME, DUMMY_BANK_A_NAME)
.map { it.toDatabaseSchemaNames("","_10000","_10003","_10012") }.flatten().toTypedArray())
}

View File

@ -41,7 +41,7 @@ class KryoClientSerializationScheme : AbstractKryoSerializationScheme() {
return SerializationEnvironmentImpl(
SerializationFactoryImpl().apply {
registerScheme(KryoClientSerializationScheme())
registerScheme(AMQPClientSerializationScheme())
registerScheme(AMQPClientSerializationScheme(emptyList()))
},
KRYO_P2P_CONTEXT,
rpcClientContext = KRYO_RPC_CLIENT_CONTEXT)

View File

@ -48,8 +48,7 @@ public class StandaloneCordaRPCJavaClientTest {
port.getAndIncrement(),
port.getAndIncrement(),
true,
Collections.singletonList(rpcUser),
null
Collections.singletonList(rpcUser)
);
@Before

View File

@ -7,10 +7,10 @@ import net.corda.core.messaging.RPCOps
import net.corda.node.services.messaging.RPCServerConfiguration
import net.corda.nodeapi.internal.config.User
import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.internal.RPCDriverDSL
import net.corda.testing.internal.rpcTestUser
import net.corda.testing.internal.startInVmRpcClient
import net.corda.testing.internal.startRpcClient
import net.corda.testing.node.internal.RPCDriverDSL
import net.corda.testing.node.internal.rpcTestUser
import net.corda.testing.node.internal.startInVmRpcClient
import net.corda.testing.node.internal.startRpcClient
import org.apache.activemq.artemis.api.core.client.ClientSession
import org.junit.Rule
import org.junit.runners.Parameterized

View File

@ -7,9 +7,9 @@ import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.messaging.RPCOps
import net.corda.core.utilities.getOrThrow
import net.corda.node.services.messaging.rpcContext
import net.corda.testing.internal.RPCDriverDSL
import net.corda.testing.internal.rpcDriver
import net.corda.testing.internal.rpcTestUser
import net.corda.testing.node.internal.RPCDriverDSL
import net.corda.testing.node.internal.rpcDriver
import net.corda.testing.node.internal.rpcTestUser
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.junit.runner.RunWith

View File

@ -9,8 +9,8 @@ import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.millis
import net.corda.node.services.messaging.RPCServerConfiguration
import net.corda.testing.internal.RPCDriverDSL
import net.corda.testing.internal.rpcDriver
import net.corda.testing.node.internal.RPCDriverDSL
import net.corda.testing.node.internal.rpcDriver
import net.corda.testing.internal.testThreadFactory
import org.apache.activemq.artemis.utils.collections.ConcurrentHashSet
import org.junit.After

View File

@ -6,8 +6,8 @@ import net.corda.core.internal.concurrent.openFuture
import net.corda.core.messaging.*
import net.corda.core.utilities.getOrThrow
import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.internal.rpcDriver
import net.corda.testing.internal.startRpcClient
import net.corda.testing.node.internal.rpcDriver
import net.corda.testing.node.internal.startRpcClient
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Rule
import org.junit.Test

View File

@ -6,12 +6,12 @@ import net.corda.core.messaging.RPCOps
import net.corda.core.utilities.minutes
import net.corda.core.utilities.seconds
import net.corda.node.services.messaging.RPCServerConfiguration
import net.corda.testing.internal.RPCDriverDSL
import net.corda.testing.node.internal.RPCDriverDSL
import net.corda.testing.internal.performance.div
import net.corda.testing.internal.performance.startPublishingFixedRateInjector
import net.corda.testing.internal.performance.startReporter
import net.corda.testing.internal.performance.startTightLoopInjector
import net.corda.testing.internal.rpcDriver
import net.corda.testing.node.internal.performance.startPublishingFixedRateInjector
import net.corda.testing.node.internal.performance.startReporter
import net.corda.testing.node.internal.performance.startTightLoopInjector
import net.corda.testing.node.internal.rpcDriver
import net.corda.testing.measure
import org.junit.Ignore
import org.junit.Test

View File

@ -3,8 +3,8 @@ package net.corda.client.rpc
import net.corda.core.messaging.RPCOps
import net.corda.node.services.messaging.rpcContext
import net.corda.nodeapi.internal.config.User
import net.corda.testing.internal.RPCDriverDSL
import net.corda.testing.internal.rpcDriver
import net.corda.testing.node.internal.RPCDriverDSL
import net.corda.testing.node.internal.rpcDriver
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized

View File

@ -16,6 +16,7 @@ import net.corda.finance.flows.CashIssueAndPaymentFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.testing.*
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Test

View File

@ -1,14 +1,11 @@
package net.corda.confidential
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.identity.*
import net.corda.core.utilities.getOrThrow
import net.corda.testing.*
import net.corda.testing.node.MockNetwork
import org.junit.Before
import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.startFlow
import org.junit.Test
import kotlin.test.*
@ -24,8 +21,8 @@ class SwapIdentitiesFlowTests {
@Test
fun `issue key`() {
// Set up values we'll need
val aliceNode = mockNet.createPartyNode(ALICE.name)
val bobNode = mockNet.createPartyNode(BOB.name)
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
val bobNode = mockNet.createPartyNode(BOB_NAME)
val alice = aliceNode.info.singleIdentity()
val bob = bobNode.services.myInfo.singleIdentity()
@ -60,9 +57,9 @@ class SwapIdentitiesFlowTests {
@Test
fun `verifies identity name`() {
// Set up values we'll need
val aliceNode = mockNet.createPartyNode(ALICE.name)
val bobNode = mockNet.createPartyNode(BOB.name)
val charlieNode = mockNet.createPartyNode(CHARLIE.name)
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
val bobNode = mockNet.createPartyNode(BOB_NAME)
val charlieNode = mockNet.createPartyNode(CHARLIE_NAME)
val bob: Party = bobNode.services.myInfo.singleIdentity()
val notBob = charlieNode.database.transaction {
charlieNode.services.keyManagementService.freshKeyAndCert(charlieNode.services.myInfo.chooseIdentityAndCert(), false)
@ -83,8 +80,8 @@ class SwapIdentitiesFlowTests {
fun `verifies signature`() {
// Set up values we'll need
val notaryNode = mockNet.defaultNotaryNode
val aliceNode = mockNet.createPartyNode(ALICE.name)
val bobNode = mockNet.createPartyNode(BOB.name)
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
val bobNode = mockNet.createPartyNode(BOB_NAME)
val alice: PartyAndCertificate = aliceNode.info.singleIdentityAndCert()
val bob: PartyAndCertificate = bobNode.info.singleIdentityAndCert()
val notary: PartyAndCertificate = mockNet.defaultNotaryIdentityAndCert

View File

@ -4,8 +4,4 @@ trustStorePassword : "trustpass"
p2pAddress : "localhost:10002"
rpcAddress : "localhost:10003"
webAddress : "localhost:10004"
networkMapService : {
address : "localhost:10000"
legalName : "O=Network Map Service,OU=corda,L=London,C=GB"
}
useHTTPS : false

View File

@ -1,4 +1,4 @@
gradlePluginsVersion=3.0.0
gradlePluginsVersion=3.0.1
kotlinVersion=1.1.60
platformVersion=1
guavaVersion=21.0

View File

@ -3,6 +3,7 @@ package net.corda.core.cordapp
import net.corda.core.DoNotImplement
import net.corda.core.flows.FlowLogic
import net.corda.core.schemas.MappedSchema
import net.corda.core.serialization.SerializationCustomSerializer
import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.serialization.SerializeAsToken
import java.net.URL
@ -22,6 +23,7 @@ import java.net.URL
* @property schedulableFlows List of flows startable by the scheduler
* @property services List of RPC services
* @property serializationWhitelists List of Corda plugin registries
* @property serializationCustomSerializers List of serializers
* @property customSchemas List of custom schemas
* @property jarPath The path to the JAR for this CorDapp
*/
@ -35,6 +37,7 @@ interface Cordapp {
val schedulableFlows: List<Class<out FlowLogic<*>>>
val services: List<Class<out SerializeAsToken>>
val serializationWhitelists: List<SerializationWhitelist>
val serializationCustomSerializers: List<SerializationCustomSerializer<*, *>>
val customSchemas: Set<MappedSchema>
val jarPath: URL
val cordappClasses: List<String>

View File

@ -45,7 +45,7 @@ data class CordaX500Name(val commonName: String?,
init {
// Legal name checks.
LegalNameValidator.validateOrganization(organisation)
LegalNameValidator.validateOrganization(organisation, LegalNameValidator.Validation.MINIMAL)
// Attribute data width checks.
require(country.length == LENGTH_COUNTRY) { "Invalid country '$country' Country code must be $LENGTH_COUNTRY letters ISO code " }

View File

@ -1,18 +1,27 @@
package net.corda.core.internal
import java.lang.Character.UnicodeScript.*
import net.corda.core.internal.LegalNameValidator.normalize
import java.text.Normalizer
import java.util.regex.Pattern
import javax.security.auth.x500.X500Principal
object LegalNameValidator {
enum class Validation {
MINIMAL,
FULL
}
@Deprecated("Use validateOrganization instead", replaceWith = ReplaceWith("validateOrganization(normalizedLegalName)"))
fun validateLegalName(normalizedLegalName: String) = validateOrganization(normalizedLegalName)
fun validateLegalName(normalizedLegalName: String) = validateOrganization(normalizedLegalName, Validation.FULL)
/**
* The validation function validates a string for use as part of a legal name. It applies the following rules:
*
* - No blacklisted words like "node", "server".
* - Does not contain the null character
* - Must be normalized (as per the [normalize] function).
* - Length must be 255 characters or shorter.
*
* Full validation (typically this is only done for names the Doorman approves) adds:
*
* - Restrict names to Latin scripts for now to avoid right-to-left issues, debugging issues when we can't pronounce
* names over the phone, and character confusability attacks.
* - No commas or equals signs.
@ -20,25 +29,37 @@ object LegalNameValidator {
*
* @throws IllegalArgumentException if the name does not meet the required rules. The message indicates why not.
*/
fun validateNameAttribute(normalizedNameAttribute: String) {
Rule.baseNameRules.forEach { it.validate(normalizedNameAttribute) }
fun validateNameAttribute(normalizedNameAttribute: String, validation: Validation) {
when (validation) {
Validation.MINIMAL -> Rule.attributeRules.forEach { it.validate(normalizedNameAttribute) }
Validation.FULL -> Rule.attributeFullRules.forEach { it.validate(normalizedNameAttribute) }
}
}
/**
* The validation function validates a string for use as the organization attribute of a name, which includes additional
* constraints over basic name attribute checks. It applies the following rules:
* constraints over basic name attribute checks. It applies the following additional rules:
*
* - Must be normalized (as per the [normalize] function).
* - Length must be 255 characters or shorter.
* - No blacklisted words like "node", "server".
* - Must consist of at least three letters.
*
* Full validation (typically this is only done for names the Doorman approves) adds:
*
* - Restrict names to Latin scripts for now to avoid right-to-left issues, debugging issues when we can't pronounce
* names over the phone, and character confusability attacks.
* - Must consist of at least three letters and should start with a capital letter.
* - Must start with a capital letter.
* - No commas or equals signs.
* - No dollars or quote marks, we might need to relax the quote mark constraint in future to handle Irish company names.
*
* @throws IllegalArgumentException if the name does not meet the required rules. The message indicates why not.
*/
fun validateOrganization(normalizedOrganization: String) {
Rule.legalNameRules.forEach { it.validate(normalizedOrganization) }
fun validateOrganization(normalizedOrganization: String, validation: Validation) {
when (validation) {
Validation.MINIMAL -> Rule.legalNameRules.forEach { it.validate(normalizedOrganization) }
Validation.FULL -> Rule.legalNameFullRules.forEach { it.validate(normalizedOrganization) }
}
}
@Deprecated("Use normalize instead", replaceWith = ReplaceWith("normalize(legalName)"))
@ -57,18 +78,27 @@ object LegalNameValidator {
sealed class Rule<in T> {
companion object {
val baseNameRules: List<Rule<String>> = listOf(
val attributeRules: List<Rule<String>> = listOf(
UnicodeNormalizationRule(),
CharacterRule(',', '=', '$', '"', '\'', '\\'),
WordRule("node", "server"),
LengthRule(maxLength = 255),
MustHaveAtLeastTwoLettersRule(),
CharacterRule('\u0000') // Ban null
)
val attributeFullRules: List<Rule<String>> = attributeRules + listOf(
CharacterRule(',', '=', '$', '"', '\'', '\\'),
// TODO: Implement confusable character detection if we add more scripts.
UnicodeRangeRule(LATIN, COMMON, INHERITED),
UnicodeRangeRule(Character.UnicodeBlock.BASIC_LATIN),
CapitalLetterRule()
)
val legalNameRules: List<Rule<String>> = attributeRules + listOf(
WordRule("node", "server"),
X500NameRule()
)
val legalNameRules: List<Rule<String>> = baseNameRules + listOf(
CapitalLetterRule(),
MustHaveAtLeastTwoLettersRule()
val legalNameFullRules: List<Rule<String>> = legalNameRules + listOf(
CharacterRule(',', '=', '$', '"', '\'', '\\'),
// TODO: Implement confusable character detection if we add more scripts.
UnicodeRangeRule(Character.UnicodeBlock.BASIC_LATIN),
CapitalLetterRule()
)
}
@ -80,18 +110,13 @@ object LegalNameValidator {
}
}
private class UnicodeRangeRule(vararg supportScripts: Character.UnicodeScript) : Rule<String>() {
private val pattern = supportScripts.map { "\\p{Is$it}" }.joinToString(separator = "", prefix = "[", postfix = "]*").let { Pattern.compile(it) }
private class UnicodeRangeRule(vararg supportScripts: Character.UnicodeBlock) : Rule<String>() {
val supportScriptsSet = supportScripts.toSet()
override fun validate(legalName: String) {
require(pattern.matcher(legalName).matches()) {
val illegalChars = legalName.replace(pattern.toRegex(), "").toSet()
if (illegalChars.size > 1) {
"Forbidden characters $illegalChars in \"$legalName\"."
} else {
"Forbidden character $illegalChars in \"$legalName\"."
}
}
val illegalChars = legalName.toCharArray().filter { Character.UnicodeBlock.of(it) !in supportScriptsSet }.size
// We don't expose the characters or the legal name, for security reasons
require (illegalChars == 0) { "$illegalChars forbidden characters in legal name." }
}
}

View File

@ -3,6 +3,7 @@ package net.corda.core.internal.cordapp
import net.corda.core.cordapp.Cordapp
import net.corda.core.flows.FlowLogic
import net.corda.core.schemas.MappedSchema
import net.corda.core.serialization.SerializationCustomSerializer
import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.serialization.SerializeAsToken
import java.io.File
@ -16,6 +17,7 @@ data class CordappImpl(
override val schedulableFlows: List<Class<out FlowLogic<*>>>,
override val services: List<Class<out SerializeAsToken>>,
override val serializationWhitelists: List<SerializationWhitelist>,
override val serializationCustomSerializers: List<SerializationCustomSerializer<*, *>>,
override val customSchemas: Set<MappedSchema>,
override val jarPath: URL) : Cordapp {
override val name: String = File(jarPath.toURI()).name.removeSuffix(".jar")

View File

@ -53,7 +53,6 @@ interface NetworkMapCacheBase {
*
* Note that the identities are sorted based on legal name, and the ordering might change once new notaries are introduced.
*/
// TODO this list will be taken from NetworkParameters distributed by NetworkMap.
val notaryIdentities: List<Party>
// DOCEND 1
@ -117,7 +116,7 @@ interface NetworkMapCacheBase {
fun getNotary(name: CordaX500Name): Party? = notaryIdentities.firstOrNull { it.name == name }
// DOCEND 2
/** Checks whether a given party is an advertised notary identity. */
/** Returns true if and only if the given [Party] is a notary, which is defined by the network parameters. */
fun isNotary(party: Party): Boolean = party in notaryIdentities
/**

View File

@ -18,11 +18,11 @@ annotation class CordaSerializationTransformRenames(vararg val value: CordaSeria
// TODO When we have class renaming update the docs
/**
* This annotation is used to mark a class has having had a property element. It is used by the
* AMQP deserialiser to allow instances with different versions of the class on their Class Path
* to successfully deserialize the object
* AMQP deserializer to allow instances with different versions of the class on their Class Path
* to successfully deserialize the object.
*
* NOTE: Renaming of the class itself is not be done with this annotation. For class renaming
* see ???
* NOTE: Renaming of the class itself isn't done with this annotation or, at present, supported
* by Corda
*
* @property to [String] representation of the properties new name
* @property from [String] representation of the properties old new

View File

@ -2,10 +2,10 @@ package net.corda.core.serialization
/**
* This annotation is a marker to indicate which secondary constructors should be considered, and in which
* order, for evolving objects during their deserialisation.
* order, for evolving objects during their deserialization.
*
* Versions will be considered in descending order, currently duplicate versions will result in
* non deterministic behaviour when deserialising objects
* non deterministic behaviour when deserializing objects
*/
@Target(AnnotationTarget.CONSTRUCTOR)
@Retention(AnnotationRetention.RUNTIME)

View File

@ -3,6 +3,6 @@ package net.corda.core.serialization
import net.corda.core.CordaException
import net.corda.core.crypto.SecureHash
/** Thrown during deserialisation to indicate that an attachment needed to construct the [WireTransaction] is not found. */
/** Thrown during deserialization to indicate that an attachment needed to construct the [WireTransaction] is not found. */
@CordaSerializable
class MissingAttachmentsException(val ids: List<SecureHash>) : CordaException()

View File

@ -0,0 +1,24 @@
package net.corda.core.serialization
/**
* Allows CorDapps to provide custom serializers for third party libraries where those libraries cannot
* be recompiled with the -parameters flag rendering their classes natively serializable by Corda. In this case
* a proxy serializer can be written that extends this type whose purpose is to move between those an
* unserializable types and an intermediate representation.
*
* NOTE: The proxy object should be specified as a seperate class. However, this can be defined within the
* scope of the custom serializer.
*/
interface SerializationCustomSerializer<OBJ, PROXY> {
/**
* Should facilitate the conversion of the third party object into the serializable
* local class specified by [PROXY]
*/
fun toProxy(obj: OBJ) : PROXY
/**
* Should facilitate the conversion of the proxy object into a new instance of the
* unserializable type
*/
fun fromProxy(proxy: PROXY) : OBJ
}

View File

@ -6,7 +6,7 @@ import net.corda.core.serialization.SingletonSerializationToken.Companion.single
/**
* The interfaces and classes in this file allow large, singleton style classes to
* mark themselves as needing converting to some form of token representation in the serialised form
* and converting back again when deserialising.
* and converting back again when deserializing.
*
* Typically these classes would be used for node services and subsystems that might become reachable from
* Fibers and thus sucked into serialization when they are checkpointed.

View File

@ -50,7 +50,7 @@ data class SignedTransaction(val txBits: SerializedBytes<CoreTransaction>,
@Volatile
@Transient private var cachedTransaction: CoreTransaction? = null
/** Lazily calculated access to the deserialised/hashed transaction data. */
/** Lazily calculated access to the deserialized/hashed transaction data. */
private val transaction: CoreTransaction get() = cachedTransaction ?: txBits.deserialize().apply { cachedTransaction = this }
/** The id of the contained [WireTransaction]. */

View File

@ -14,7 +14,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import static net.corda.testing.CoreTestUtils.singleIdentity;
import static net.corda.testing.NodeTestUtils.startFlow;
import static net.corda.testing.node.NodeTestUtils.startFlow;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.Assert.fail;
@ -26,8 +26,8 @@ public class FlowsInJavaTest {
@Before
public void setUp() throws Exception {
aliceNode = mockNet.createPartyNode(TestConstants.getALICE().getName());
bobNode = mockNet.createPartyNode(TestConstants.getBOB().getName());
aliceNode = mockNet.createPartyNode(TestConstants.getALICE_NAME());
bobNode = mockNet.createPartyNode(TestConstants.getBOB_NAME());
bob = singleIdentity(bobNode.getInfo());
}

View File

@ -18,6 +18,11 @@ import kotlin.test.assertTrue
* Tests for the version 2 dummy contract, to cover ensuring upgrade transactions are built correctly.
*/
class DummyContractV2Tests {
private companion object {
val ALICE = TestIdentity(ALICE_NAME, 70).party
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
}
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()

View File

@ -1,7 +1,10 @@
package net.corda.core.crypto
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.contracts.*
import net.corda.core.crypto.SecureHash.Companion.zeroHash
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
@ -9,7 +12,10 @@ import net.corda.core.transactions.WireTransaction
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.finance.contracts.asset.Cash
import net.corda.node.services.api.IdentityServiceInternal
import net.corda.testing.*
import net.corda.testing.node.MockServices
import net.corda.testing.node.ledger
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@ -20,6 +26,16 @@ import kotlin.streams.toList
import kotlin.test.*
class PartialMerkleTreeTest {
private companion object {
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
val miniCorp = TestIdentity(CordaX500Name("MiniCorp", "London", "GB"))
val MEGA_CORP get() = megaCorp.party
val MEGA_CORP_PUBKEY get() = megaCorp.pubkey
val MINI_CORP get() = miniCorp.party
val MINI_CORP_PUBKEY get() = miniCorp.pubkey
}
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
@ -35,7 +51,9 @@ class PartialMerkleTreeTest {
hashed = nodes.map { it.serialize().sha256() }
expectedRoot = MerkleTree.getMerkleTree(hashed.toMutableList() + listOf(zeroHash, zeroHash)).hash
merkleTree = MerkleTree.getMerkleTree(hashed)
testLedger = ledger {
testLedger = MockServices(rigorousMock<IdentityServiceInternal>().also {
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
}, MEGA_CORP.name).ledger(DUMMY_NOTARY) {
unverifiedTransaction {
attachments(Cash.PROGRAM_ID)
output(Cash.PROGRAM_ID, "MEGA_CORP cash",

View File

@ -50,7 +50,7 @@ class X509NameConstraintsTest {
val nameConstraints = NameConstraints(acceptableNames, arrayOf())
val pathValidator = CertPathValidator.getInstance("PKIX")
val certFactory = X509CertificateFactory().delegate
val certFactory = X509CertificateFactory()
assertFailsWith(CertPathValidatorException::class) {
val (keystore, trustStore) = makeKeyStores(X500Name("CN=Bank B"), nameConstraints)

View File

@ -13,6 +13,7 @@ import net.corda.node.services.persistence.NodeAttachmentService
import net.corda.testing.*
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Test
@ -48,9 +49,8 @@ class AttachmentTests {
@Test
fun `download and store`() {
val aliceNode = mockNet.createPartyNode(ALICE.name)
val bobNode = mockNet.createPartyNode(BOB.name)
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
val bobNode = mockNet.createPartyNode(BOB_NAME)
val alice = aliceNode.info.singleIdentity()
aliceNode.registerInitiatedFlow(FetchAttachmentsResponse::class.java)
bobNode.registerInitiatedFlow(FetchAttachmentsResponse::class.java)
@ -81,8 +81,8 @@ class AttachmentTests {
@Test
fun `missing`() {
val aliceNode = mockNet.createPartyNode(ALICE.name)
val bobNode = mockNet.createPartyNode(BOB.name)
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
val bobNode = mockNet.createPartyNode(BOB_NAME)
aliceNode.registerInitiatedFlow(FetchAttachmentsResponse::class.java)
bobNode.registerInitiatedFlow(FetchAttachmentsResponse::class.java)
// Get node one to fetch a non-existent attachment.
@ -97,13 +97,13 @@ class AttachmentTests {
@Test
fun maliciousResponse() {
// Make a node that doesn't do sanity checking at load time.
val aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE.name), nodeFactory = { args ->
val aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME), nodeFactory = { args ->
object : MockNetwork.MockNode(args) {
override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = false }
}
})
val bobNode = mockNet.createNode(MockNodeParameters(legalName = BOB.name))
val alice = aliceNode.services.myInfo.identityFromX500Name(ALICE_NAME)
val bobNode = mockNet.createNode(MockNodeParameters(legalName = BOB_NAME))
val alice = aliceNode.info.singleIdentity()
aliceNode.registerInitiatedFlow(FetchAttachmentsResponse::class.java)
bobNode.registerInitiatedFlow(FetchAttachmentsResponse::class.java)
val attachment = fakeAttachment()

View File

@ -4,6 +4,7 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.core.contracts.Command
import net.corda.core.contracts.StateAndContract
import net.corda.core.contracts.requireThat
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.identity.excludeHostNode
import net.corda.core.identity.groupAbstractPartyByWellKnownParty
@ -15,6 +16,7 @@ import net.corda.testing.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockServices
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Test
@ -22,6 +24,10 @@ import kotlin.reflect.KClass
import kotlin.test.assertFailsWith
class CollectSignaturesFlowTests {
companion object {
private val miniCorp = TestIdentity(CordaX500Name("MiniCorp", "London", "GB"))
}
private lateinit var mockNet: MockNetwork
private lateinit var aliceNode: StartedNode<MockNetwork.MockNode>
private lateinit var bobNode: StartedNode<MockNetwork.MockNode>
@ -34,9 +40,9 @@ class CollectSignaturesFlowTests {
@Before
fun setup() {
mockNet = MockNetwork(cordappPackages = listOf("net.corda.testing.contracts"))
aliceNode = mockNet.createPartyNode(ALICE.name)
bobNode = mockNet.createPartyNode(BOB.name)
charlieNode = mockNet.createPartyNode(CHARLIE.name)
aliceNode = mockNet.createPartyNode(ALICE_NAME)
bobNode = mockNet.createPartyNode(BOB_NAME)
charlieNode = mockNet.createPartyNode(CHARLIE_NAME)
alice = aliceNode.info.singleIdentity()
bob = bobNode.info.singleIdentity()
charlie = charlieNode.info.singleIdentity()
@ -129,7 +135,7 @@ class CollectSignaturesFlowTests {
@Test
fun `fails when not signed by initiator`() {
val onePartyDummyContract = DummyContract.generateInitial(1337, notary, alice.ref(1))
val miniCorpServices = MockServices(listOf("net.corda.testing.contracts"), rigorousMock(), MINI_CORP.name, MINI_CORP_KEY)
val miniCorpServices = MockServices(listOf("net.corda.testing.contracts"), rigorousMock(), miniCorp)
val ptx = miniCorpServices.signInitialTransaction(onePartyDummyContract)
val flow = aliceNode.services.startFlow(CollectSignaturesFlow(ptx, emptySet()))
mockNet.runNetwork()

View File

@ -24,13 +24,13 @@ import net.corda.testing.ALICE_NAME
import net.corda.testing.BOB_NAME
import net.corda.testing.contracts.DummyContract
import net.corda.testing.contracts.DummyContractV2
import net.corda.testing.internal.RPCDriverDSL
import net.corda.testing.internal.rpcDriver
import net.corda.testing.internal.rpcTestUser
import net.corda.testing.internal.startRpcClient
import net.corda.testing.node.internal.RPCDriverDSL
import net.corda.testing.node.internal.rpcDriver
import net.corda.testing.node.internal.rpcTestUser
import net.corda.testing.node.internal.startRpcClient
import net.corda.testing.node.MockNetwork
import net.corda.testing.singleIdentity
import net.corda.testing.startFlow
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Test

View File

@ -9,6 +9,7 @@ import net.corda.finance.issuedBy
import net.corda.node.services.api.StartedNodeServices
import net.corda.testing.*
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Test
@ -16,6 +17,10 @@ import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class FinalityFlowTests {
companion object {
private val CHARLIE = TestIdentity(CHARLIE_NAME, 90).party
}
private lateinit var mockNet: MockNetwork
private lateinit var aliceServices: StartedNodeServices
private lateinit var bobServices: StartedNodeServices

View File

@ -7,7 +7,7 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap
import net.corda.testing.node.MockNetwork
import net.corda.testing.singleIdentity
import net.corda.testing.startFlow
import net.corda.testing.node.startFlow
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Test

View File

@ -1,7 +1,7 @@
package net.corda.core.identity
import net.corda.core.crypto.entropyToKeyPair
import net.corda.testing.ALICE
import net.corda.testing.ALICE_NAME
import org.junit.Test
import java.math.BigInteger
import kotlin.test.assertEquals
@ -13,7 +13,7 @@ class PartyTest {
val key = entropyToKeyPair(BigInteger.valueOf(20170207L)).public
val differentKey = entropyToKeyPair(BigInteger.valueOf(7201702L)).public
val anonymousParty = AnonymousParty(key)
val party = Party(ALICE.name, key)
val party = Party(ALICE_NAME, key)
assertEquals<AbstractParty>(party, anonymousParty)
assertEquals<AbstractParty>(anonymousParty, party)
assertNotEquals<AbstractParty>(AnonymousParty(differentKey), anonymousParty)

View File

@ -1,7 +1,7 @@
package net.corda.core.internal
import net.corda.testing.ALICE
import net.corda.testing.BOB
import net.corda.testing.ALICE_NAME
import net.corda.testing.BOB_NAME
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.After
import org.junit.AfterClass
@ -29,8 +29,8 @@ class AbstractAttachmentTest {
@BeforeClass
@JvmStatic
fun beforeClass() {
execute("keytool", "-genkey", "-keystore", "_teststore", "-storepass", "storepass", "-keyalg", "RSA", "-alias", "alice", "-keypass", "alicepass", "-dname", ALICE.toString())
execute("keytool", "-genkey", "-keystore", "_teststore", "-storepass", "storepass", "-keyalg", "RSA", "-alias", "bob", "-keypass", "bobpass", "-dname", BOB.toString())
execute("keytool", "-genkey", "-keystore", "_teststore", "-storepass", "storepass", "-keyalg", "RSA", "-alias", "alice", "-keypass", "alicepass", "-dname", ALICE_NAME.toString())
execute("keytool", "-genkey", "-keystore", "_teststore", "-storepass", "storepass", "-keyalg", "RSA", "-alias", "bob", "-keypass", "bobpass", "-dname", BOB_NAME.toString())
(dir / "_signable1").writeLines(listOf("signable1"))
(dir / "_signable2").writeLines(listOf("signable2"))
(dir / "_signable3").writeLines(listOf("signable3"))
@ -76,10 +76,10 @@ class AbstractAttachmentTest {
fun `one signer`() {
execute("jar", "cvf", "attachment.jar", "_signable1", "_signable2")
execute("jarsigner", "-keystore", "_teststore", "-storepass", "storepass", "-keypass", "alicepass", "attachment.jar", "alice")
assertEquals(listOf(ALICE.name), load("attachment.jar").signers.map { it.name }) // We only reused ALICE's distinguished name, so the keys will be different.
assertEquals(listOf(ALICE_NAME), load("attachment.jar").signers.map { it.name }) // We only reused ALICE's distinguished name, so the keys will be different.
(dir / "my-dir").createDirectory()
execute("jar", "uvf", "attachment.jar", "my-dir")
assertEquals(listOf(ALICE.name), load("attachment.jar").signers.map { it.name }) // Unsigned directory is irrelevant.
assertEquals(listOf(ALICE_NAME), load("attachment.jar").signers.map { it.name }) // Unsigned directory is irrelevant.
}
@Test
@ -87,17 +87,17 @@ class AbstractAttachmentTest {
execute("jar", "cvf", "attachment.jar", "_signable1", "_signable2")
execute("jarsigner", "-keystore", "_teststore", "-storepass", "storepass", "-keypass", "alicepass", "attachment.jar", "alice")
execute("jarsigner", "-keystore", "_teststore", "-storepass", "storepass", "-keypass", "bobpass", "attachment.jar", "bob")
assertEquals(listOf(ALICE.name, BOB.name), load("attachment.jar").signers.map { it.name })
assertEquals(listOf(ALICE_NAME, BOB_NAME), load("attachment.jar").signers.map { it.name })
}
@Test
fun `a party must sign all the files in the attachment to be a signer`() {
execute("jar", "cvf", "attachment.jar", "_signable1")
execute("jarsigner", "-keystore", "_teststore", "-storepass", "storepass", "-keypass", "alicepass", "attachment.jar", "alice")
assertEquals(listOf(ALICE.name), load("attachment.jar").signers.map { it.name })
assertEquals(listOf(ALICE_NAME), load("attachment.jar").signers.map { it.name })
execute("jar", "uvf", "attachment.jar", "_signable2")
execute("jarsigner", "-keystore", "_teststore", "-storepass", "storepass", "-keypass", "bobpass", "attachment.jar", "bob")
assertEquals(listOf(BOB.name), load("attachment.jar").signers.map { it.name }) // ALICE hasn't signed the new file.
assertEquals(listOf(BOB_NAME), load("attachment.jar").signers.map { it.name }) // ALICE hasn't signed the new file.
execute("jar", "uvf", "attachment.jar", "_signable3")
assertEquals(emptyList(), load("attachment.jar").signers) // Neither party has signed the new file.
}
@ -107,7 +107,7 @@ class AbstractAttachmentTest {
(dir / "volatile").writeLines(listOf("volatile"))
execute("jar", "cvf", "attachment.jar", "volatile")
execute("jarsigner", "-keystore", "_teststore", "-storepass", "storepass", "-keypass", "alicepass", "attachment.jar", "alice")
assertEquals(listOf(ALICE.name), load("attachment.jar").signers.map { it.name })
assertEquals(listOf(ALICE_NAME), load("attachment.jar").signers.map { it.name })
(dir / "volatile").writeLines(listOf("garbage"))
execute("jar", "uvf", "attachment.jar", "volatile", "_signable1") // ALICE's signature on volatile is now bad.
execute("jarsigner", "-keystore", "_teststore", "-storepass", "storepass", "-keypass", "bobpass", "attachment.jar", "bob")

View File

@ -8,55 +8,94 @@ class LegalNameValidatorTest {
@Test
fun `no double spaces`() {
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization("Test Legal Name")
LegalNameValidator.validateOrganization("Test Legal Name", LegalNameValidator.Validation.FULL)
}
LegalNameValidator.validateOrganization(LegalNameValidator.normalize("Test Legal Name"))
LegalNameValidator.validateOrganization(LegalNameValidator.normalize("Test Legal Name"), LegalNameValidator.Validation.FULL)
}
@Test
fun `no trailing white space`() {
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization("Test ")
LegalNameValidator.validateOrganization("Test ", LegalNameValidator.Validation.FULL)
}
}
@Test
fun `no prefixed white space`() {
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization(" Test")
LegalNameValidator.validateOrganization(" Test", LegalNameValidator.Validation.FULL)
}
}
@Test
fun `blacklisted words`() {
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization("Test Server")
LegalNameValidator.validateOrganization("Test Server", LegalNameValidator.Validation.FULL)
}
}
@Test
fun `blacklisted characters`() {
LegalNameValidator.validateOrganization("Test")
LegalNameValidator.validateOrganization("Test", LegalNameValidator.Validation.FULL)
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization("\$Test")
LegalNameValidator.validateOrganization("\$Test", LegalNameValidator.Validation.FULL)
}
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization("\"Test")
LegalNameValidator.validateOrganization("\"Test", LegalNameValidator.Validation.FULL)
}
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization("\'Test")
LegalNameValidator.validateOrganization("\'Test", LegalNameValidator.Validation.FULL)
}
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization("=Test")
LegalNameValidator.validateOrganization("=Test", LegalNameValidator.Validation.FULL)
}
}
@Test
fun `unicode range`() {
LegalNameValidator.validateOrganization("Test A")
fun `unicode range in organization`() {
LegalNameValidator.validateOrganization("The quick brown fox jumped over the lazy dog.1234567890", LegalNameValidator.Validation.FULL)
assertFailsWith(IllegalArgumentException::class) {
// Null
LegalNameValidator.validateOrganization("\u0000R3 Null", LegalNameValidator.Validation.FULL)
}
assertFailsWith(IllegalArgumentException::class) {
// Right to left direction override
LegalNameValidator.validateOrganization("\u202EdtL 3R", LegalNameValidator.Validation.FULL)
}
assertFailsWith(IllegalArgumentException::class) {
// Greek letter A.
LegalNameValidator.validateOrganization("Test Α")
LegalNameValidator.validateOrganization("Test \u0391", LegalNameValidator.Validation.FULL)
}
// Latin capital letter turned m
assertFailsWith<IllegalArgumentException> {
LegalNameValidator.validateOrganization( "Test\u019CLtd", LegalNameValidator.Validation.FULL)
}
// Latin small letter turned e
assertFailsWith<IllegalArgumentException> {
LegalNameValidator.validateOrganization("Test\u01ddLtd", LegalNameValidator.Validation.FULL)
}
}
@Test
fun `unicode range in general attributes`() {
LegalNameValidator.validateNameAttribute("The quick brown fox jumped over the lazy dog.1234567890", LegalNameValidator.Validation.FULL)
assertFailsWith(IllegalArgumentException::class) {
// Right to left direction override
LegalNameValidator.validateNameAttribute("\u202EdtL 3R", LegalNameValidator.Validation.FULL)
}
// Right to left direction override is okay with minimal validation though
LegalNameValidator.validateNameAttribute("\u202EdtL 3R", LegalNameValidator.Validation.MINIMAL)
assertFailsWith(IllegalArgumentException::class) {
// Greek letter A.
LegalNameValidator.validateNameAttribute("Test \u0391", LegalNameValidator.Validation.FULL)
}
// Latin capital letter turned m
assertFailsWith<IllegalArgumentException> {
LegalNameValidator.validateNameAttribute( "Test\u019CLtd", LegalNameValidator.Validation.FULL)
}
// Latin small letter turned e
assertFailsWith<IllegalArgumentException> {
LegalNameValidator.validateNameAttribute("Test\u01ddLtd", LegalNameValidator.Validation.FULL)
}
}
@ -66,21 +105,21 @@ class LegalNameValidatorTest {
while (longLegalName.length < 255) {
longLegalName.append("A")
}
LegalNameValidator.validateOrganization(longLegalName.toString())
LegalNameValidator.validateOrganization(longLegalName.toString(), LegalNameValidator.Validation.FULL)
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization(longLegalName.append("A").toString())
LegalNameValidator.validateOrganization(longLegalName.append("A").toString(), LegalNameValidator.Validation.FULL)
}
}
@Test
fun `legal name should be capitalized`() {
LegalNameValidator.validateOrganization("Good legal name")
LegalNameValidator.validateOrganization("Good legal name", LegalNameValidator.Validation.FULL)
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization("bad name")
LegalNameValidator.validateOrganization("bad name", LegalNameValidator.Validation.FULL)
}
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization("bad Name")
LegalNameValidator.validateOrganization("bad Name", LegalNameValidator.Validation.FULL)
}
}
@ -90,13 +129,13 @@ class LegalNameValidatorTest {
assertEquals("Legal Name With Unicode Whitespaces", LegalNameValidator.normalize("Legal Name\u2004With\u0009Unicode\u0020Whitespaces"))
assertEquals("Legal Name With Line Breaks", LegalNameValidator.normalize("Legal Name With\n\rLine\nBreaks"))
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization("Legal Name With\tTab")
LegalNameValidator.validateOrganization("Legal Name With\tTab", LegalNameValidator.Validation.FULL)
}
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization("Legal Name\u2004With\u0009Unicode\u0020Whitespaces")
LegalNameValidator.validateOrganization("Legal Name\u2004With\u0009Unicode\u0020Whitespaces", LegalNameValidator.Validation.FULL)
}
assertFailsWith(IllegalArgumentException::class) {
LegalNameValidator.validateOrganization("Legal Name With\n\rLine\nBreaks")
LegalNameValidator.validateOrganization("Legal Name With\n\rLine\nBreaks", LegalNameValidator.Validation.FULL)
}
}
}

View File

@ -3,17 +3,16 @@ package net.corda.core.internal
import co.paralleluniverse.fibers.Suspendable
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.*
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.sequence
import net.corda.node.internal.StartedNode
import net.corda.testing.MEGA_CORP
import net.corda.testing.MINI_CORP
import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockNetwork
import net.corda.testing.singleIdentity
import net.corda.testing.startFlow
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Test
@ -40,8 +39,8 @@ class ResolveTransactionsFlowTest {
fun setup() {
mockNet = MockNetwork(cordappPackages = listOf("net.corda.testing.contracts"))
notaryNode = mockNet.defaultNotaryNode
megaCorpNode = mockNet.createPartyNode(MEGA_CORP.name)
miniCorpNode = mockNet.createPartyNode(MINI_CORP.name)
megaCorpNode = mockNet.createPartyNode(CordaX500Name("MegaCorp", "London", "GB"))
miniCorpNode = mockNet.createPartyNode(CordaX500Name("MiniCorp", "London", "GB"))
megaCorpNode.registerInitiatedFlow(TestResponseFlow::class.java)
miniCorpNode.registerInitiatedFlow(TestResponseFlow::class.java)
notary = mockNet.defaultNotaryIdentity

View File

@ -5,14 +5,18 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.identity.AbstractParty
import net.corda.core.node.services.Vault
import net.corda.core.transactions.LedgerTransaction
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.DUMMY_NOTARY_NAME
import net.corda.testing.TestIdentity
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class VaultUpdateTests {
val DUMMY_PROGRAM_ID = "net.corda.core.node.VaultUpdateTests.DummyContract"
private companion object {
val DUMMY_PROGRAM_ID = "net.corda.core.node.VaultUpdateTests.DummyContract"
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
}
object DummyContract : Contract {

View File

@ -21,7 +21,7 @@ import net.corda.testing.BOB_NAME
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters
import net.corda.testing.singleIdentity
import net.corda.testing.startFlow
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Test

View File

@ -3,6 +3,7 @@ package net.corda.core.serialization
import net.corda.core.contracts.*
import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.seconds
@ -19,6 +20,16 @@ import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class TransactionSerializationTests {
private companion object {
val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20)
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
val MINI_CORP = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")).party
val DUMMY_NOTARY get() = dummyNotary.party
val DUMMY_NOTARY_KEY get() = dummyNotary.key
val MEGA_CORP get() = megaCorp.party
val MEGA_CORP_KEY get() = megaCorp.key
}
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()

View File

@ -18,6 +18,8 @@ class CompatibleTransactionTests {
private companion object {
val DUMMY_KEY_1 = generateKeyPair()
val DUMMY_KEY_2 = generateKeyPair()
val BOB = TestIdentity(BOB_NAME, 80).party
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
}
@Rule

View File

@ -5,6 +5,7 @@ import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.contracts.*
import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.node.services.api.IdentityServiceInternal
import net.corda.testing.*
@ -19,13 +20,17 @@ import kotlin.test.assertFailsWith
import kotlin.test.assertTrue
class LedgerTransactionQueryTests {
companion object {
private val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
}
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
private val keyPair = generateKeyPair()
private val services = MockServices(rigorousMock<IdentityServiceInternal>().also {
doReturn(null).whenever(it).partyFromKey(keyPair.public)
}, MEGA_CORP.name, keyPair)
}, CordaX500Name("MegaCorp", "London", "GB"), keyPair)
private val identity: Party = services.myInfo.singleIdentity()
@Before

View File

@ -1,16 +1,19 @@
package net.corda.core.transactions
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.contracts.Contract
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.requireThat
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.finance.contracts.asset.Cash
import net.corda.testing.MEGA_CORP
import net.corda.testing.MINI_CORP
import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.ledger
import net.corda.node.services.api.IdentityServiceInternal
import net.corda.testing.*
import net.corda.testing.node.MockServices
import net.corda.testing.node.ledger
import org.junit.Rule
import org.junit.Test
import java.time.Instant
@ -19,6 +22,14 @@ import java.time.temporal.ChronoUnit
val TEST_TIMELOCK_ID = "net.corda.core.transactions.TransactionEncumbranceTests\$DummyTimeLock"
class TransactionEncumbranceTests {
private companion object {
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
val MINI_CORP = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")).party
val MEGA_CORP get() = megaCorp.party
val MEGA_CORP_PUBKEY get() = megaCorp.pubkey
}
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
@ -50,9 +61,13 @@ class TransactionEncumbranceTests {
}
}
private val ledgerServices = MockServices(rigorousMock<IdentityServiceInternal>().also {
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
}, MEGA_CORP.name)
@Test
fun `state can be encumbered`() {
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
transaction {
attachments(Cash.PROGRAM_ID, TEST_TIMELOCK_ID)
input(Cash.PROGRAM_ID, state)
@ -66,7 +81,7 @@ class TransactionEncumbranceTests {
@Test
fun `state can transition if encumbrance rules are met`() {
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
unverifiedTransaction {
attachments(Cash.PROGRAM_ID, TEST_TIMELOCK_ID)
output(Cash.PROGRAM_ID, "state encumbered by 5pm time-lock", state)
@ -87,7 +102,7 @@ class TransactionEncumbranceTests {
@Test
fun `state cannot transition if the encumbrance contract fails to verify`() {
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
unverifiedTransaction {
attachments(Cash.PROGRAM_ID, TEST_TIMELOCK_ID)
output(Cash.PROGRAM_ID, "state encumbered by 5pm time-lock", state)
@ -108,7 +123,7 @@ class TransactionEncumbranceTests {
@Test
fun `state must be consumed along with its encumbrance`() {
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
unverifiedTransaction {
attachments(Cash.PROGRAM_ID, TEST_TIMELOCK_ID)
output(Cash.PROGRAM_ID, "state encumbered by 5pm time-lock", encumbrance = 1, contractState = state)
@ -127,7 +142,7 @@ class TransactionEncumbranceTests {
@Test
fun `state cannot be encumbered by itself`() {
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
transaction {
attachments(Cash.PROGRAM_ID)
input(Cash.PROGRAM_ID, state)
@ -140,7 +155,7 @@ class TransactionEncumbranceTests {
@Test
fun `encumbrance state index must be valid`() {
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
transaction {
attachments(Cash.PROGRAM_ID, TEST_TIMELOCK_ID)
input(Cash.PROGRAM_ID, state)
@ -154,7 +169,7 @@ class TransactionEncumbranceTests {
@Test
fun `correct encumbrance state must be provided`() {
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
unverifiedTransaction {
attachments(Cash.PROGRAM_ID, TEST_TIMELOCK_ID)
output(Cash.PROGRAM_ID, "state encumbered by some other state", encumbrance = 1, contractState = state)

View File

@ -4,12 +4,11 @@ import net.corda.core.contracts.*
import net.corda.core.crypto.*
import net.corda.core.crypto.CompositeKey
import net.corda.core.identity.Party
import net.corda.finance.contracts.asset.DUMMY_CASH_ISSUER_KEY
import net.corda.testing.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockAttachment
import org.junit.Rule
import org.junit.Test
import java.math.BigInteger
import java.security.KeyPair
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
@ -19,6 +18,12 @@ class TransactionTests {
private companion object {
val DUMMY_KEY_1 = generateKeyPair()
val DUMMY_KEY_2 = generateKeyPair()
val DUMMY_CASH_ISSUER_KEY = entropyToKeyPair(BigInteger.valueOf(10))
val ALICE = TestIdentity(ALICE_NAME, 70).party
val BOB = TestIdentity(BOB_NAME, 80).party
val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20)
val DUMMY_NOTARY get() = dummyNotary.party
val DUMMY_NOTARY_KEY get() = dummyNotary.key
}
@Rule
@ -106,7 +111,7 @@ class TransactionTests {
val inputs = emptyList<StateAndRef<*>>()
val outputs = listOf(baseOutState, baseOutState.copy(notary = ALICE), baseOutState.copy(notary = BOB))
val commands = emptyList<CommandWithParties<CommandData>>()
val attachments = listOf<Attachment>(ContractAttachment(MockAttachment(), DummyContract.PROGRAM_ID))
val attachments = listOf<Attachment>(ContractAttachment(rigorousMock(), DummyContract.PROGRAM_ID))
val id = SecureHash.randomSHA256()
val timeWindow: TimeWindow? = null
val privacySalt: PrivacySalt = PrivacySalt()

View File

@ -9,11 +9,11 @@ a developer environment.
IDE - IntelliJ
--------------
IntelliJ (R3's preferred IDE) integrates well with gradle (our chosen build, deployment and CLI tool). IntelliJ understands gradle
tasks and dependencies, automatically loading them in the background when a project is first opened or the gradle
project changes. Occasionally, however, you may need to refresh the gradle project manually - but this is hinted to you
by the IDE. It's a good idea to do this before carrying on with other work (and in fact you may find it is essential to pick
up new libraries, etc.).
IntelliJ (the preferred IDE for Corda) integrates well with gradle (Corda's default build, deployment and CLI tool).
IntelliJ understands gradle tasks and dependencies, automatically loading them in the background when a project is
first opened or the gradle project changes. Occasionally, however, you may need to refresh the gradle project manually
- but this is hinted to you by the IDE. It's a good idea to do this before carrying on with other work (and in fact you
may find it is essential to pick up new libraries, etc.).
There are some great resources about how to get started using IntelliJ. As opposed to trying to repeat them here, we advise
you to go to the `IntelliJ docs here <https://www.jetbrains.com/idea/documentation/>`_.

View File

@ -1,7 +1,7 @@
Code style guide
================
This document explains the coding style used in the R3 prototyping repository. You will be expected to follow these
This document explains the coding style used in the Corda repository. You will be expected to follow these
recommendations when submitting patches for review. Please take the time to read them and internalise them, to save
time during code review.

View File

@ -0,0 +1,73 @@
Pluggable Serializers for CorDapps
==================================
.. contents::
To be serializable by Corda Java classes must be compiled with the -parameters switch to enable matching of its properties
to constructor parameters. This is important because Corda's internal AMQP serialization scheme will only construct
objects using their constructors. However, when recompilation isn't possible, or classes are built in such a way that
they cannot be easily modified for simple serialization, CorDapps can provide custom proxy serializers that Corda
can use to move from types it cannot serialize to an interim representation that it can with the transformation to and
from this proxy object being handled by the supplied serializer.
Serializer Location
-------------------
Custom serializer classes should follow the rules for including classes found in :doc:`cordapp-build-systems`
Writing a Custom Serializer
---------------------------
Serializers must
* Inherit from net.corda.core.serialization.SerializationCustomSerializer
* Provide a proxy class to transform the object to and from
* Implement the ``toProxy`` and ``fromProxy`` methods
Serializers inheriting from SerializationCustomSerializer have to implement two methods and two types.
Example
-------
Consider this example class
.. sourcecode:: java
public final class Example {
private final Int a
private final Int b
private Example(Int a, Int b) {
this.a = a;
this.b = b;
}
public static Example of (int[] a) { return Example(a[0], a[1]); }
public int getA() { return a; }
public int getB() { return b; }
}
Without a custom serializer we cannot serialize this class as there is no public constructor that facilitates the
initialisation of all of its properties.
To be serializable by Corda this would require a custom serializer as follows:
.. sourcecode:: kotlin
class ExampleSerializer : SerializationCustomSerializer<Example, ExampleSerializer.Proxy> {
data class Proxy(val a: Int, val b: Int)
override fun toProxy(obj: Example) = Proxy(obj.a, obj.b)
override fun fromProxy(proxy: Proxy) : Example {
val constructorArg = IntArray(2);
constructorArg[0] = proxy.a
constructorArg[1] = proxy.b
return Example.create(constructorArg)
}
}
Whitelisting
------------
By writing a custom serializer for a class it has the effect of adding that class to the whitelist, meaning such
classes don't need explicitly adding to the CorDapp's whitelist.

View File

@ -48,10 +48,6 @@ handling, and ensures the Corda service is run at boot.
trustStorePassword : "trustpass"
useHTTPS : false
devMode : false
networkMapService {
address="networkmap.foo.bar.com:10002"
legalName="O=FooBar NetworkMap, L=Dublin, C=IE"
}
rpcUsers=[
{
user=corda
@ -223,10 +219,6 @@ at boot, and means the Corda service stays running with no users connected to th
extraAdvertisedServiceIds: [ "" ]
useHTTPS : false
devMode : false
networkMapService {
address="networkmap.foo.bar.com:10002"
legalName="O=FooBar NetworkMap, L=Dublin, C=IE"
}
rpcUsers=[
{
user=corda

View File

@ -23,7 +23,7 @@ import kotlin.test.assertEquals
class IntegrationTestingTutorial : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE, BOB, DUMMY_NOTARY).map { it.toDatabaseSchemaName() }.toTypedArray())
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE_NAME, BOB_NAME, DUMMY_NOTARY_NAME).map { it.toDatabaseSchemaName() }.toTypedArray())
}
@Test
@ -44,8 +44,8 @@ class IntegrationTestingTutorial : IntegrationTest() {
invokeRpc(CordaRPCOps::networkMapFeed)
))
val (alice, bob) = listOf(
startNode(providedName = ALICE.name, rpcUsers = listOf(aliceUser)),
startNode(providedName = BOB.name, rpcUsers = listOf(bobUser))
startNode(providedName = ALICE_NAME, rpcUsers = listOf(aliceUser)),
startNode(providedName = BOB_NAME, rpcUsers = listOf(bobUser))
).transpose().getOrThrow()
// END 1

View File

@ -33,7 +33,7 @@ import java.util.List;
import java.util.Set;
import static net.corda.core.contracts.ContractsDSL.requireThat;
import static net.corda.testing.TestConstants.getALICE_KEY;
import static net.corda.core.crypto.Crypto.generateKeyPair;
@SuppressWarnings("unused")
public class FlowCookbookJava {
@ -107,9 +107,7 @@ public class FlowCookbookJava {
@Override
public Void call() throws FlowException {
// We'll be using a dummy public key for demonstration purposes.
// These are built in to Corda, and are generally used for writing
// tests.
PublicKey dummyPubKey = getALICE_KEY().getPublic();
PublicKey dummyPubKey = generateKeyPair().getPublic();
/*---------------------------
* IDENTIFYING OTHER NODES *

View File

@ -2,35 +2,56 @@ package net.corda.docs.java.tutorial.testdsl;
import kotlin.Unit;
import net.corda.core.contracts.PartyAndReference;
import net.corda.core.utilities.OpaqueBytes;
import net.corda.core.identity.CordaX500Name;
import net.corda.core.identity.Party;
import net.corda.finance.contracts.ICommercialPaperState;
import net.corda.finance.contracts.JavaCommercialPaper;
import net.corda.finance.contracts.asset.Cash;
import net.corda.node.services.api.IdentityServiceInternal;
import net.corda.testing.SerializationEnvironmentRule;
import net.corda.testing.node.MockServices;
import net.corda.testing.TestIdentity;
import org.junit.Rule;
import org.junit.Test;
import java.security.PublicKey;
import java.time.temporal.ChronoUnit;
import static net.corda.core.crypto.Crypto.generateKeyPair;
import static net.corda.finance.Currencies.DOLLARS;
import static net.corda.finance.Currencies.issuedBy;
import static net.corda.finance.contracts.JavaCommercialPaper.JCP_PROGRAM_ID;
import static net.corda.testing.CoreTestUtils.*;
import static net.corda.testing.NodeTestUtils.ledger;
import static net.corda.testing.NodeTestUtils.transaction;
import static net.corda.testing.node.NodeTestUtils.ledger;
import static net.corda.testing.node.NodeTestUtils.transaction;
import static net.corda.testing.CoreTestUtils.rigorousMock;
import static net.corda.testing.TestConstants.*;
import static org.mockito.Mockito.doReturn;
public class CommercialPaperTest {
private static final TestIdentity ALICE = new TestIdentity(getALICE_NAME(), 70L);
private static final PublicKey BIG_CORP_PUBKEY = generateKeyPair().getPublic();
private static final TestIdentity BOB = new TestIdentity(getBOB_NAME(), 80L);
private static final TestIdentity MEGA_CORP = new TestIdentity(new CordaX500Name("MegaCorp", "London", "GB"));
private static final Party DUMMY_NOTARY = new TestIdentity(getDUMMY_NOTARY_NAME(), 20L).getParty();
@Rule
public final SerializationEnvironmentRule testSerialization = new SerializationEnvironmentRule();
private final OpaqueBytes defaultRef = new OpaqueBytes(new byte[]{123});
private final byte[] defaultRef = {123};
private final MockServices ledgerServices;
{
IdentityServiceInternal identityService = rigorousMock(IdentityServiceInternal.class);
doReturn(MEGA_CORP.getParty()).when(identityService).partyFromKey(MEGA_CORP.getPubkey());
doReturn(null).when(identityService).partyFromKey(BIG_CORP_PUBKEY);
doReturn(null).when(identityService).partyFromKey(ALICE.getPubkey());
ledgerServices = new MockServices(identityService, MEGA_CORP.getName());
}
// DOCSTART 1
private ICommercialPaperState getPaper() {
return new JavaCommercialPaper.State(
getMEGA_CORP().ref(defaultRef),
getMEGA_CORP(),
issuedBy(DOLLARS(1000), getMEGA_CORP().ref(defaultRef)),
MEGA_CORP.ref(defaultRef),
MEGA_CORP.getParty(),
issuedBy(DOLLARS(1000), MEGA_CORP.ref(defaultRef)),
getTEST_TX_TIME().plus(7, ChronoUnit.DAYS)
);
}
@ -40,7 +61,7 @@ public class CommercialPaperTest {
@Test
public void simpleCP() {
ICommercialPaperState inState = getPaper();
ledger(l -> {
ledger(ledgerServices, DUMMY_NOTARY, l -> {
l.transaction(tx -> {
tx.attachments(JCP_PROGRAM_ID);
tx.input(JCP_PROGRAM_ID, inState);
@ -55,10 +76,10 @@ public class CommercialPaperTest {
@Test
public void simpleCPMove() {
ICommercialPaperState inState = getPaper();
ledger(l -> {
ledger(ledgerServices, DUMMY_NOTARY, l -> {
l.transaction(tx -> {
tx.input(JCP_PROGRAM_ID, inState);
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Move());
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Move());
tx.attachments(JCP_PROGRAM_ID);
return tx.verifies();
});
@ -71,10 +92,10 @@ public class CommercialPaperTest {
@Test
public void simpleCPMoveFails() {
ICommercialPaperState inState = getPaper();
ledger(l -> {
ledger(ledgerServices, DUMMY_NOTARY, l -> {
l.transaction(tx -> {
tx.input(JCP_PROGRAM_ID, inState);
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Move());
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Move());
tx.attachments(JCP_PROGRAM_ID);
return tx.failsWith("the state is propagated");
});
@ -87,13 +108,13 @@ public class CommercialPaperTest {
@Test
public void simpleCPMoveSuccess() {
ICommercialPaperState inState = getPaper();
ledger(l -> {
ledger(ledgerServices, DUMMY_NOTARY, l -> {
l.transaction(tx -> {
tx.input(JCP_PROGRAM_ID, inState);
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Move());
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Move());
tx.attachments(JCP_PROGRAM_ID);
tx.failsWith("the state is propagated");
tx.output(JCP_PROGRAM_ID, "alice's paper", inState.withOwner(getALICE()));
tx.output(JCP_PROGRAM_ID, "alice's paper", inState.withOwner(ALICE.getParty()));
return tx.verifies();
});
return Unit.INSTANCE;
@ -104,16 +125,16 @@ public class CommercialPaperTest {
// DOCSTART 6
@Test
public void simpleIssuanceWithTweak() {
ledger(l -> {
ledger(ledgerServices, DUMMY_NOTARY, l -> {
l.transaction(tx -> {
tx.output(JCP_PROGRAM_ID, "paper", getPaper()); // Some CP is issued onto the ledger by MegaCorp.
tx.attachments(JCP_PROGRAM_ID);
tx.tweak(tw -> {
tw.command(getBIG_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Issue());
tw.command(BIG_CORP_PUBKEY, new JavaCommercialPaper.Commands.Issue());
tw.timeWindow(getTEST_TX_TIME());
return tw.failsWith("output states are issued by a command signer");
});
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Issue());
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Issue());
tx.timeWindow(getTEST_TX_TIME());
return tx.verifies();
});
@ -125,15 +146,15 @@ public class CommercialPaperTest {
// DOCSTART 7
@Test
public void simpleIssuanceWithTweakTopLevelTx() {
transaction(tx -> {
transaction(ledgerServices, DUMMY_NOTARY, tx -> {
tx.output(JCP_PROGRAM_ID, "paper", getPaper()); // Some CP is issued onto the ledger by MegaCorp.
tx.attachments(JCP_PROGRAM_ID);
tx.tweak(tw -> {
tw.command(getBIG_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Issue());
tw.command(BIG_CORP_PUBKEY, new JavaCommercialPaper.Commands.Issue());
tw.timeWindow(getTEST_TX_TIME());
return tw.failsWith("output states are issued by a command signer");
});
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Issue());
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Issue());
tx.timeWindow(getTEST_TX_TIME());
return tx.verifies();
});
@ -143,11 +164,11 @@ public class CommercialPaperTest {
// DOCSTART 8
@Test
public void chainCommercialPaper() {
PartyAndReference issuer = getMEGA_CORP().ref(defaultRef);
ledger(l -> {
PartyAndReference issuer = MEGA_CORP.ref(defaultRef);
ledger(ledgerServices, DUMMY_NOTARY, l -> {
l.unverifiedTransaction(tx -> {
tx.output(Cash.PROGRAM_ID, "alice's $900",
new Cash.State(issuedBy(DOLLARS(900), issuer), getALICE()));
new Cash.State(issuedBy(DOLLARS(900), issuer), ALICE.getParty()));
tx.attachments(Cash.PROGRAM_ID);
return Unit.INSTANCE;
});
@ -155,7 +176,7 @@ public class CommercialPaperTest {
// Some CP is issued onto the ledger by MegaCorp.
l.transaction("Issuance", tx -> {
tx.output(JCP_PROGRAM_ID, "paper", getPaper());
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Issue());
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Issue());
tx.attachments(JCP_PROGRAM_ID);
tx.timeWindow(getTEST_TX_TIME());
return tx.verifies();
@ -164,11 +185,11 @@ public class CommercialPaperTest {
l.transaction("Trade", tx -> {
tx.input("paper");
tx.input("alice's $900");
tx.output(Cash.PROGRAM_ID, "borrowed $900", new Cash.State(issuedBy(DOLLARS(900), issuer), getMEGA_CORP()));
tx.output(Cash.PROGRAM_ID, "borrowed $900", new Cash.State(issuedBy(DOLLARS(900), issuer), MEGA_CORP.getParty()));
JavaCommercialPaper.State inputPaper = l.retrieveOutput(JavaCommercialPaper.State.class, "paper");
tx.output(JCP_PROGRAM_ID, "alice's paper", inputPaper.withOwner(getALICE()));
tx.command(getALICE_PUBKEY(), new Cash.Commands.Move());
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Move());
tx.output(JCP_PROGRAM_ID, "alice's paper", inputPaper.withOwner(ALICE.getParty()));
tx.command(ALICE.getPubkey(), new Cash.Commands.Move());
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Move());
return tx.verifies();
});
return Unit.INSTANCE;
@ -179,11 +200,11 @@ public class CommercialPaperTest {
// DOCSTART 9
@Test
public void chainCommercialPaperDoubleSpend() {
PartyAndReference issuer = getMEGA_CORP().ref(defaultRef);
ledger(l -> {
PartyAndReference issuer = MEGA_CORP.ref(defaultRef);
ledger(ledgerServices, DUMMY_NOTARY, l -> {
l.unverifiedTransaction(tx -> {
tx.output(Cash.PROGRAM_ID, "alice's $900",
new Cash.State(issuedBy(DOLLARS(900), issuer), getALICE()));
new Cash.State(issuedBy(DOLLARS(900), issuer), ALICE.getParty()));
tx.attachments(Cash.PROGRAM_ID);
return Unit.INSTANCE;
});
@ -191,7 +212,7 @@ public class CommercialPaperTest {
// Some CP is issued onto the ledger by MegaCorp.
l.transaction("Issuance", tx -> {
tx.output(Cash.PROGRAM_ID, "paper", getPaper());
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Issue());
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Issue());
tx.attachments(JCP_PROGRAM_ID);
tx.timeWindow(getTEST_TX_TIME());
return tx.verifies();
@ -200,11 +221,11 @@ public class CommercialPaperTest {
l.transaction("Trade", tx -> {
tx.input("paper");
tx.input("alice's $900");
tx.output(Cash.PROGRAM_ID, "borrowed $900", new Cash.State(issuedBy(DOLLARS(900), issuer), getMEGA_CORP()));
tx.output(Cash.PROGRAM_ID, "borrowed $900", new Cash.State(issuedBy(DOLLARS(900), issuer), MEGA_CORP.getParty()));
JavaCommercialPaper.State inputPaper = l.retrieveOutput(JavaCommercialPaper.State.class, "paper");
tx.output(JCP_PROGRAM_ID, "alice's paper", inputPaper.withOwner(getALICE()));
tx.command(getALICE_PUBKEY(), new Cash.Commands.Move());
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Move());
tx.output(JCP_PROGRAM_ID, "alice's paper", inputPaper.withOwner(ALICE.getParty()));
tx.command(ALICE.getPubkey(), new Cash.Commands.Move());
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Move());
return tx.verifies();
});
@ -212,8 +233,8 @@ public class CommercialPaperTest {
tx.input("paper");
JavaCommercialPaper.State inputPaper = l.retrieveOutput(JavaCommercialPaper.State.class, "paper");
// We moved a paper to other pubkey.
tx.output(JCP_PROGRAM_ID, "bob's paper", inputPaper.withOwner(getBOB()));
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Move());
tx.output(JCP_PROGRAM_ID, "bob's paper", inputPaper.withOwner(BOB.getParty()));
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Move());
return tx.verifies();
});
l.fails();
@ -225,11 +246,11 @@ public class CommercialPaperTest {
// DOCSTART 10
@Test
public void chainCommercialPaperTweak() {
PartyAndReference issuer = getMEGA_CORP().ref(defaultRef);
ledger(l -> {
PartyAndReference issuer = MEGA_CORP.ref(defaultRef);
ledger(ledgerServices, DUMMY_NOTARY, l -> {
l.unverifiedTransaction(tx -> {
tx.output(Cash.PROGRAM_ID, "alice's $900",
new Cash.State(issuedBy(DOLLARS(900), issuer), getALICE()));
new Cash.State(issuedBy(DOLLARS(900), issuer), ALICE.getParty()));
tx.attachments(Cash.PROGRAM_ID);
return Unit.INSTANCE;
});
@ -237,7 +258,7 @@ public class CommercialPaperTest {
// Some CP is issued onto the ledger by MegaCorp.
l.transaction("Issuance", tx -> {
tx.output(Cash.PROGRAM_ID, "paper", getPaper());
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Issue());
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Issue());
tx.attachments(JCP_PROGRAM_ID);
tx.timeWindow(getTEST_TX_TIME());
return tx.verifies();
@ -246,11 +267,11 @@ public class CommercialPaperTest {
l.transaction("Trade", tx -> {
tx.input("paper");
tx.input("alice's $900");
tx.output(Cash.PROGRAM_ID, "borrowed $900", new Cash.State(issuedBy(DOLLARS(900), issuer), getMEGA_CORP()));
tx.output(Cash.PROGRAM_ID, "borrowed $900", new Cash.State(issuedBy(DOLLARS(900), issuer), MEGA_CORP.getParty()));
JavaCommercialPaper.State inputPaper = l.retrieveOutput(JavaCommercialPaper.State.class, "paper");
tx.output(JCP_PROGRAM_ID, "alice's paper", inputPaper.withOwner(getALICE()));
tx.command(getALICE_PUBKEY(), new Cash.Commands.Move());
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Move());
tx.output(JCP_PROGRAM_ID, "alice's paper", inputPaper.withOwner(ALICE.getParty()));
tx.command(ALICE.getPubkey(), new Cash.Commands.Move());
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Move());
return tx.verifies();
});
@ -259,8 +280,8 @@ public class CommercialPaperTest {
tx.input("paper");
JavaCommercialPaper.State inputPaper = l.retrieveOutput(JavaCommercialPaper.State.class, "paper");
// We moved a paper to another pubkey.
tx.output(JCP_PROGRAM_ID, "bob's paper", inputPaper.withOwner(getBOB()));
tx.command(getMEGA_CORP_PUBKEY(), new JavaCommercialPaper.Commands.Move());
tx.output(JCP_PROGRAM_ID, "bob's paper", inputPaper.withOwner(BOB.getParty()));
tx.command(MEGA_CORP.getPubkey(), new JavaCommercialPaper.Commands.Move());
return tx.verifies();
});
lw.fails();

View File

@ -18,7 +18,7 @@ import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.Permissions.Companion.invokeRpc
import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.nodeapi.internal.config.User
import net.corda.testing.ALICE
import net.corda.testing.ALICE_NAME
import net.corda.testing.driver.driver
import org.graphstream.graph.Edge
import org.graphstream.graph.Node
@ -49,7 +49,7 @@ fun main(args: Array<String>) {
invokeRpc(CordaRPCOps::nodeInfo)
))
driver(driverDirectory = baseDirectory, extraCordappPackagesToScan = listOf("net.corda.finance"), waitForAllNodesToFinish = true) {
val node = startNode(providedName = ALICE.name, rpcUsers = listOf(user)).get()
val node = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).get()
// END 1
// START 2

View File

@ -6,6 +6,7 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.core.contracts.*
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.TransactionSignature
import net.corda.core.crypto.generateKeyPair
import net.corda.core.flows.*
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
@ -23,7 +24,6 @@ import net.corda.core.utilities.UntrustworthyData
import net.corda.core.utilities.seconds
import net.corda.core.utilities.unwrap
import net.corda.finance.contracts.asset.Cash
import net.corda.testing.ALICE_PUBKEY
import net.corda.testing.contracts.DummyContract
import net.corda.testing.contracts.DummyState
import java.security.PublicKey
@ -87,9 +87,7 @@ class InitiatorFlow(val arg1: Boolean, val arg2: Int, private val counterparty:
@Suspendable
override fun call() {
// We'll be using a dummy public key for demonstration purposes.
// These are built in to Corda, and are generally used for writing
// tests.
val dummyPubKey: PublicKey = ALICE_PUBKEY
val dummyPubKey: PublicKey = generateKeyPair().public
/**--------------------------
* IDENTIFYING OTHER NODES *

View File

@ -21,7 +21,7 @@ import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MessagingServiceSpy
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.setMessagingServiceSpy
import net.corda.testing.startFlow
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Rule

View File

@ -4,16 +4,16 @@ import net.corda.core.contracts.Command
import net.corda.core.contracts.StateRef
import net.corda.core.contracts.TimeWindow
import net.corda.core.crypto.MerkleTreeException
import net.corda.core.identity.AbstractParty
import net.corda.core.transactions.FilteredTransaction
import net.corda.core.transactions.FilteredTransactionVerificationException
import net.corda.core.transactions.SignedTransaction
import net.corda.finance.contracts.Fix
import net.corda.testing.ALICE
import java.util.function.Predicate
fun main(args: Array<String>) {
// Typealias to make the example coherent.
val oracle = ALICE
val oracle = Any() as AbstractParty
val stx = Any() as SignedTransaction
// DOCSTART 1

View File

@ -1,5 +1,9 @@
package net.corda.docs.tutorial.testdsl
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.days
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
@ -8,14 +12,35 @@ import net.corda.finance.contracts.CommercialPaper
import net.corda.finance.contracts.ICommercialPaperState
import net.corda.finance.contracts.asset.CASH
import net.corda.finance.contracts.asset.Cash
import net.corda.node.services.api.IdentityServiceInternal
import net.corda.testing.*
import net.corda.testing.node.MockServices
import net.corda.testing.node.ledger
import net.corda.testing.node.transaction
import org.junit.Rule
import org.junit.Test
class CommercialPaperTest {
private companion object {
val alice = TestIdentity(ALICE_NAME, 70)
val BIG_CORP_PUBKEY = generateKeyPair().public
val BOB = TestIdentity(BOB_NAME, 80).party
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
val ALICE get() = alice.party
val ALICE_PUBKEY get() = alice.pubkey
val MEGA_CORP get() = megaCorp.party
val MEGA_CORP_PUBKEY get() = megaCorp.pubkey
}
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
private val ledgerServices = MockServices(rigorousMock<IdentityServiceInternal>().also {
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
doReturn(null).whenever(it).partyFromKey(BIG_CORP_PUBKEY)
doReturn(null).whenever(it).partyFromKey(ALICE_PUBKEY)
}, MEGA_CORP.name)
// DOCSTART 1
fun getPaper(): ICommercialPaperState = CommercialPaper.State(
@ -30,7 +55,7 @@ class CommercialPaperTest {
@Test
fun simpleCP() {
val inState = getPaper()
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
transaction {
attachments(CP_PROGRAM_ID)
input(CP_PROGRAM_ID, inState)
@ -44,7 +69,7 @@ class CommercialPaperTest {
@Test
fun simpleCPMove() {
val inState = getPaper()
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
transaction {
input(CP_PROGRAM_ID, inState)
command(MEGA_CORP_PUBKEY, CommercialPaper.Commands.Move())
@ -59,7 +84,7 @@ class CommercialPaperTest {
@Test
fun simpleCPMoveFails() {
val inState = getPaper()
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
transaction {
input(CP_PROGRAM_ID, inState)
command(MEGA_CORP_PUBKEY, CommercialPaper.Commands.Move())
@ -74,7 +99,7 @@ class CommercialPaperTest {
@Test
fun simpleCPMoveSuccess() {
val inState = getPaper()
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
transaction {
input(CP_PROGRAM_ID, inState)
command(MEGA_CORP_PUBKEY, CommercialPaper.Commands.Move())
@ -90,7 +115,7 @@ class CommercialPaperTest {
// DOCSTART 6
@Test
fun `simple issuance with tweak`() {
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
transaction {
output(CP_PROGRAM_ID, "paper", getPaper()) // Some CP is issued onto the ledger by MegaCorp.
attachments(CP_PROGRAM_ID)
@ -111,7 +136,7 @@ class CommercialPaperTest {
// DOCSTART 7
@Test
fun `simple issuance with tweak and top level transaction`() {
transaction {
ledgerServices.transaction(DUMMY_NOTARY) {
output(CP_PROGRAM_ID, "paper", getPaper()) // Some CP is issued onto the ledger by MegaCorp.
attachments(CP_PROGRAM_ID)
tweak {
@ -131,8 +156,7 @@ class CommercialPaperTest {
@Test
fun `chain commercial paper`() {
val issuer = MEGA_CORP.ref(123)
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
unverifiedTransaction {
attachments(Cash.PROGRAM_ID)
output(Cash.PROGRAM_ID, "alice's $900", 900.DOLLARS.CASH issuedBy issuer ownedBy ALICE)
@ -165,7 +189,7 @@ class CommercialPaperTest {
@Test
fun `chain commercial paper double spend`() {
val issuer = MEGA_CORP.ref(123)
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
unverifiedTransaction {
attachments(Cash.PROGRAM_ID)
output(Cash.PROGRAM_ID, "alice's $900", 900.DOLLARS.CASH issuedBy issuer ownedBy ALICE)
@ -207,7 +231,7 @@ class CommercialPaperTest {
@Test
fun `chain commercial tweak`() {
val issuer = MEGA_CORP.ref(123)
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
unverifiedTransaction {
attachments(Cash.PROGRAM_ID)
output(Cash.PROGRAM_ID, "alice's $900", 900.DOLLARS.CASH issuedBy issuer ownedBy ALICE)

View File

@ -10,14 +10,9 @@ dataSourceProperties : {
p2pAddress : "my-corda-node:10002"
rpcAddress : "my-corda-node:10003"
webAddress : "localhost:10004"
networkMapService : {
address : "my-network-map:10000"
legalName : "O=Network Map Service,OU=corda,L=London,C=GB"
}
useHTTPS : false
rpcUsers : [
{ username=user1, password=letmein, permissions=[ StartProtocol.net.corda.protocols.CashProtocol ] }
]
devMode : true
// Certificate signing service will be hosted by R3 in the near future.
//certificateSigningService : "https://testnet.certificate.corda.net"
// certificateSigningService : "https://testnet.certificate.corda.net"

View File

@ -10,7 +10,7 @@ import net.corda.finance.flows.CashIssueFlow
import net.corda.node.internal.StartedNode
import net.corda.testing.chooseIdentity
import net.corda.testing.node.MockNetwork
import net.corda.testing.startFlow
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Assert
import org.junit.Before

View File

@ -10,7 +10,7 @@ import net.corda.finance.flows.CashIssueFlow
import net.corda.node.internal.StartedNode
import net.corda.testing.chooseIdentity
import net.corda.testing.node.MockNetwork
import net.corda.testing.startFlow
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Test

View File

@ -12,6 +12,7 @@ import net.corda.core.utilities.getOrThrow
import net.corda.node.services.api.StartedNodeServices
import net.corda.testing.*
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Test

View File

@ -50,17 +50,21 @@ The name must also obey the following constraints:
* The country attribute is a valid ISO 3166-1 two letter code in upper-case
* The organisation field of the name obeys the following constraints:
* All attributes must obey the following constraints:
* Upper-case first letter
* Has at least two letters
* No leading or trailing whitespace
* No double-spacing
* Does not contain the words "node" or "server"
* Does not include the following characters: ``,`` , ``=`` , ``$`` , ``"`` , ``'`` , ``\``
* Is in NFKC normalization form
* Does not contain the null character
* Only the latin, common and inherited unicode scripts are supported
* The organisation field of the name also obeys the following constraints:
* No double-spacing
* Does not contain the words "node" or "server"
* This is to avoid right-to-left issues, debugging issues when we can't pronounce names over the phone, and
character confusability attacks

View File

@ -53,8 +53,6 @@ Protocol
The old name for a Corda "Flow"
Quasar
A library that provides performant lightweight threads that can be suspended and restored extremely quickly.
R3
The consortium behind Corda
SIMM
Standard Initial Margin Model. A way of determining a counterparty's margin payment to another counterparty based on a collection of trades such that, in the event of default, the receiving counterparty has limited exposure.
Serialization

View File

@ -12,6 +12,20 @@ Unreleased
That is the ability to alter an enum constant and, as long as certain rules are followed and the correct
annotations applied, have older and newer instances of that enumeration be understood.
* **AMQP Enabled**
AMQP Serialization is now enabled for both peer to peer communication and writing states to the vault. This change
brings a stable format Corda can support internally throughout it's lifetime that meets the needs of Corda and our
users.
* **Custom Serializers**
To allow interop with third party libraries that cannot be recompiled we add functionality that allows custom serializers
to be written for those classes. If needed, a proxy object can be created as an interim step that allows Corda's internal
serializers to operate on those types.
A good example of this is the SIMM valuation demo which has a number of such serializers defined in the plugin/customserializers package
Release 2.0
----------
Following quickly on the heels of the release of Corda 1.0, Corda version 2.0 consolidates

View File

@ -45,8 +45,6 @@ The most important fields regarding network configuration are:
resolvable name of a machine in a VPN.
* ``rpcAddress``: The address to which Artemis will bind for RPC calls.
* ``webAddress``: The address the webserver should bind. Note that the port must be distinct from that of ``p2pAddress`` and ``rpcAddress`` if they are on the same machine.
* ``networkMapService``: Details of the node running the network map service. If it's this node that's running the service
then this field must not be specified.
Starting the nodes
~~~~~~~~~~~~~~~~~~

View File

@ -1,18 +1,29 @@
package net.corda.finance.contracts.universal
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.identity.CordaX500Name
import net.corda.finance.contracts.BusinessCalendar
import net.corda.finance.contracts.FixOf
import net.corda.finance.contracts.Frequency
import net.corda.finance.contracts.Tenor
import net.corda.node.services.api.IdentityServiceInternal
import net.corda.testing.*
import net.corda.testing.node.MockServices
import net.corda.testing.node.transaction
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import java.time.Instant
import java.time.LocalDate
internal val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
fun transaction(script: TransactionDSL<TransactionDSLInterpreter>.() -> EnforceVerifyOrFail) = run {
net.corda.testing.transaction(cordappPackages = listOf("net.corda.finance.contracts.universal"), dsl = script)
MockServices(listOf("net.corda.finance.contracts.universal"), rigorousMock<IdentityServiceInternal>().also {
listOf(acmeCorp, highStreetBank, momAndPop).forEach { party ->
doReturn(null).whenever(it).partyFromKey(party.owningKey)
}
}, CordaX500Name("MegaCorp", "London", "GB")).transaction(DUMMY_NOTARY, script)
}
class Cap {

View File

@ -2,7 +2,6 @@ package net.corda.finance.contracts.universal
import net.corda.finance.contracts.FixOf
import net.corda.finance.contracts.Tenor
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.SerializationEnvironmentRule
import org.junit.Ignore
import org.junit.Rule

View File

@ -1,20 +1,17 @@
package net.corda.finance.contracts.universal
import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.Party
import net.corda.testing.ALICE
import net.corda.testing.MEGA_CORP
import net.corda.testing.MINI_CORP
import net.corda.core.identity.CordaX500Name
import net.corda.testing.TestIdentity
import org.junit.Test
import java.util.*
import kotlin.test.assertEquals
import kotlin.test.assertTrue
// Test parties
val acmeCorp = Party(ALICE.name, generateKeyPair().public)
val highStreetBank = Party(MEGA_CORP.name, generateKeyPair().public)
val momAndPop = Party(MINI_CORP.name, generateKeyPair().public)
val acmeCorp = TestIdentity(CordaX500Name("Alice Corp", "Madrid", "ES")).party
val highStreetBank = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")).party
val momAndPop = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")).party
val acmeCorporationHasDefaulted = TerminalEvent(acmeCorp, generateKeyPair().public)

View File

@ -1,6 +1,5 @@
package net.corda.finance.contracts.universal
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.SerializationEnvironmentRule
import org.junit.Ignore
import org.junit.Rule

View File

@ -1,6 +1,5 @@
package net.corda.finance.contracts.universal
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.SerializationEnvironmentRule
import org.junit.Ignore
import org.junit.Rule

View File

@ -3,7 +3,6 @@ package net.corda.finance.contracts.universal
import net.corda.finance.contracts.FixOf
import net.corda.finance.contracts.Frequency
import net.corda.finance.contracts.Tenor
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.SerializationEnvironmentRule
import org.junit.Ignore
import org.junit.Rule

View File

@ -1,7 +1,6 @@
package net.corda.finance.contracts.universal
import net.corda.finance.contracts.Frequency
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.SerializationEnvironmentRule
import org.junit.Rule
import org.junit.Test

View File

@ -2,7 +2,6 @@ package net.corda.finance.contracts.universal
import net.corda.finance.contracts.Frequency
import net.corda.finance.contracts.Tenor
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.SerializationEnvironmentRule
import org.junit.Ignore
import org.junit.Rule

View File

@ -1,6 +1,5 @@
package net.corda.finance.contracts.universal
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.SerializationEnvironmentRule
import org.junit.Rule
import org.junit.Test

View File

@ -13,7 +13,7 @@ import org.junit.Test
class CashConfigDataFlowTest : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE, BOB, DUMMY_BANK_A)
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE_NAME, BOB_NAME, DUMMY_BANK_A_NAME)
.map { it.toDatabaseSchemaNames("","_10000","_10003") }.flatten().toTypedArray())
}
@Test

View File

@ -7,10 +7,8 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.core.contracts.*
import net.corda.core.contracts.Amount.Companion.sumOrThrow
import net.corda.core.crypto.NullKeys.NULL_PARTY
import net.corda.core.crypto.entropyToKeyPair
import net.corda.core.crypto.toStringShort
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.Emoji
@ -25,7 +23,6 @@ import net.corda.finance.schemas.CashSchemaV1
import net.corda.finance.utils.sumCash
import net.corda.finance.utils.sumCashOrNull
import net.corda.finance.utils.sumCashOrZero
import java.math.BigInteger
import java.security.PublicKey
import java.util.*
@ -342,14 +339,7 @@ class Cash : OnLedgerAsset<Currency, Cash.Commands, Cash.State>() {
}
// Unit testing helpers. These could go in a separate file but it's hardly worth it for just a few functions.
/** A dummy, randomly generated issuer party by the name of "Snake Oil Issuer" */
val DUMMY_CASH_ISSUER_NAME = CordaX500Name(organisation = "Snake Oil Issuer", locality = "London", country = "GB")
/** A randomly generated key. */
val DUMMY_CASH_ISSUER_KEY by lazy { entropyToKeyPair(BigInteger.valueOf(10)) }
/** A dummy, randomly generated issuer party by the name of "Snake Oil Issuer" */
val DUMMY_CASH_ISSUER by lazy { Party(DUMMY_CASH_ISSUER_NAME, DUMMY_CASH_ISSUER_KEY.public).ref(1) }
/** 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)), NULL_PARTY)
val Amount<Currency>.CASH: Cash.State get() = Cash.State(Amount(quantity, Issued(NULL_PARTY.ref(1), token)), NULL_PARTY)
/** An extension property that lets you get a cash state from an issued token, under the [NULL_PARTY] */
val Amount<Issued<Currency>>.STATE: Cash.State get() = Cash.State(this, NULL_PARTY)

View File

@ -6,10 +6,8 @@ import net.corda.finance.contracts.NetType
import net.corda.finance.contracts.NettableState
import net.corda.finance.contracts.asset.Obligation.Lifecycle.NORMAL
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.entropyToKeyPair
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.internal.Emoji
import net.corda.core.internal.VisibleForTesting
@ -22,7 +20,6 @@ import net.corda.finance.utils.sumFungibleOrNull
import net.corda.finance.utils.sumObligations
import net.corda.finance.utils.sumObligationsOrNull
import net.corda.finance.utils.sumObligationsOrZero
import java.math.BigInteger
import java.security.PublicKey
import java.time.Duration
import java.time.Instant
@ -791,8 +788,3 @@ fun <T : Any> Obligation.State<T>.ownedBy(owner: AbstractParty) = copy(beneficia
@Suppress("unused")
fun <T : Any> Obligation.State<T>.issuedBy(party: AnonymousParty) = copy(obligor = party)
/** A randomly generated key. */
val DUMMY_OBLIGATION_ISSUER_KEY by lazy { entropyToKeyPair(BigInteger.valueOf(10)) }
/** A dummy, randomly generated issuer party by the name of "Snake Oil Issuer" */
val DUMMY_OBLIGATION_ISSUER by lazy { Party(CordaX500Name(organisation = "Snake Oil Issuer", locality = "London", country = "GB"), DUMMY_OBLIGATION_ISSUER_KEY.public) }

View File

@ -2,65 +2,76 @@ package net.corda.finance.contracts.asset;
import net.corda.core.contracts.PartyAndReference;
import net.corda.core.identity.AnonymousParty;
import net.corda.core.utilities.OpaqueBytes;
import net.corda.core.identity.CordaX500Name;
import net.corda.core.identity.Party;
import net.corda.node.services.api.IdentityServiceInternal;
import net.corda.testing.DummyCommandData;
import net.corda.testing.SerializationEnvironmentRule;
import net.corda.testing.TestIdentity;
import net.corda.testing.node.MockServices;
import org.junit.Rule;
import org.junit.Test;
import static net.corda.finance.Currencies.DOLLARS;
import static net.corda.finance.Currencies.issuedBy;
import static net.corda.testing.CoreTestUtils.*;
import static net.corda.testing.NodeTestUtils.transaction;
import static net.corda.testing.node.NodeTestUtils.transaction;
import static net.corda.testing.CoreTestUtils.rigorousMock;
import static net.corda.testing.TestConstants.getDUMMY_NOTARY_NAME;
import static org.mockito.Mockito.doReturn;
/**
* This is an incomplete Java replica of CashTests.kt to show how to use the Java test DSL
*/
public class CashTestsJava {
private final OpaqueBytes defaultRef = new OpaqueBytes(new byte[]{1});
private final PartyAndReference defaultIssuer = getMEGA_CORP().ref(defaultRef);
private final Cash.State inState = new Cash.State(issuedBy(DOLLARS(1000), defaultIssuer), new AnonymousParty(getMEGA_CORP_PUBKEY()));
private final Cash.State outState = new Cash.State(inState.getAmount(), new AnonymousParty(getMINI_CORP_PUBKEY()));
private static final Party DUMMY_NOTARY = new TestIdentity(getDUMMY_NOTARY_NAME(), 20L).getParty();
private static final TestIdentity MEGA_CORP = new TestIdentity(new CordaX500Name("MegaCorp", "London", "GB"));
private static final TestIdentity MINI_CORP = new TestIdentity(new CordaX500Name("MiniCorp", "London", "GB"));
private final PartyAndReference defaultIssuer = MEGA_CORP.ref((byte) 1);
private final Cash.State inState = new Cash.State(issuedBy(DOLLARS(1000), defaultIssuer), new AnonymousParty(MEGA_CORP.getPubkey()));
private final Cash.State outState = new Cash.State(inState.getAmount(), new AnonymousParty(MINI_CORP.getPubkey()));
@Rule
public final SerializationEnvironmentRule testSerialization = new SerializationEnvironmentRule();
@Test
public void trivial() {
transaction(tx -> {
IdentityServiceInternal identityService = rigorousMock(IdentityServiceInternal.class);
doReturn(MEGA_CORP.getParty()).when(identityService).partyFromKey(MEGA_CORP.getPubkey());
doReturn(MINI_CORP.getParty()).when(identityService).partyFromKey(MINI_CORP.getPubkey());
transaction(new MockServices(identityService, MEGA_CORP.getName()), DUMMY_NOTARY, tx -> {
tx.attachment(Cash.PROGRAM_ID);
tx.input(Cash.PROGRAM_ID, inState);
tx.tweak(tw -> {
tw.output(Cash.PROGRAM_ID, new Cash.State(issuedBy(DOLLARS(2000), defaultIssuer), new AnonymousParty(getMINI_CORP_PUBKEY())));
tw.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move());
tw.output(Cash.PROGRAM_ID, new Cash.State(issuedBy(DOLLARS(2000), defaultIssuer), new AnonymousParty(MINI_CORP.getPubkey())));
tw.command(MEGA_CORP.getPubkey(), new Cash.Commands.Move());
return tw.failsWith("the amounts balance");
});
tx.tweak(tw -> {
tw.output(Cash.PROGRAM_ID, outState);
tw.command(getMEGA_CORP_PUBKEY(), DummyCommandData.INSTANCE);
tw.command(MEGA_CORP.getPubkey(), DummyCommandData.INSTANCE);
// Invalid command
return tw.failsWith("required net.corda.finance.contracts.asset.Cash.Commands.Move command");
});
tx.tweak(tw -> {
tw.output(Cash.PROGRAM_ID, outState);
tw.command(getMINI_CORP_PUBKEY(), new Cash.Commands.Move());
tw.command(MINI_CORP.getPubkey(), new Cash.Commands.Move());
return tw.failsWith("the owning keys are a subset of the signing keys");
});
tx.tweak(tw -> {
tw.output(Cash.PROGRAM_ID, outState);
// issuedBy() can't be directly imported because it conflicts with other identically named functions
// with different overloads (for some reason).
tw.output(Cash.PROGRAM_ID, outState.issuedBy(getMINI_CORP()));
tw.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move());
tw.output(Cash.PROGRAM_ID, outState.issuedBy(MINI_CORP.getParty()));
tw.command(MEGA_CORP.getPubkey(), new Cash.Commands.Move());
return tw.failsWith("at least one cash input");
});
// Simple reallocation works.
return tx.tweak(tw -> {
tw.output(Cash.PROGRAM_ID, outState);
tw.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move());
tw.command(MEGA_CORP.getPubkey(), new Cash.Commands.Move());
return tw.verifies();
});
});

View File

@ -1,7 +1,11 @@
package net.corda.finance.contracts
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.contracts.*
import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.node.services.Vault
import net.corda.core.node.services.VaultService
@ -12,11 +16,14 @@ import net.corda.core.utilities.seconds
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.finance.contracts.asset.*
import net.corda.node.services.api.IdentityServiceInternal
import net.corda.testing.*
import net.corda.testing.contracts.VaultFiller
import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices
import net.corda.testing.node.ledger
import net.corda.testing.node.makeTestIdentityService
import net.corda.testing.node.transaction
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ -36,6 +43,11 @@ interface ICommercialPaperTestTemplate {
fun getContract(): ContractClassName
}
private val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
private val MEGA_CORP get() = megaCorp.party
private val MEGA_CORP_IDENTITY get() = megaCorp.identity
private val MEGA_CORP_PUBKEY get() = megaCorp.pubkey
class JavaCommercialPaperTest : ICommercialPaperTestTemplate {
override fun getPaper(): ICommercialPaperState = JavaCommercialPaper.State(
MEGA_CORP.ref(123),
@ -84,6 +96,22 @@ class CommercialPaperTestsGeneric {
@Parameterized.Parameters
@JvmStatic
fun data() = listOf(JavaCommercialPaperTest(), KotlinCommercialPaperTest(), KotlinCommercialPaperLegacyTest())
private val dummyCashIssuer = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10)
private val DUMMY_CASH_ISSUER_IDENTITY get() = dummyCashIssuer.identity
private val DUMMY_CASH_ISSUER = dummyCashIssuer.ref(1)
private val alice = TestIdentity(ALICE_NAME, 70)
private val BIG_CORP_KEY = generateKeyPair()
private val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20)
private val miniCorp = TestIdentity(CordaX500Name("MiniCorp", "London", "GB"))
private val ALICE get() = alice.party
private val ALICE_KEY get() = alice.key
private val ALICE_PUBKEY get() = alice.pubkey
private val DUMMY_NOTARY get() = dummyNotary.party
private val DUMMY_NOTARY_IDENTITY get() = dummyNotary.identity
private val MINI_CORP get() = miniCorp.party
private val MINI_CORP_IDENTITY get() = miniCorp.identity
private val MINI_CORP_PUBKEY get() = miniCorp.pubkey
}
@Parameterized.Parameter
@ -92,11 +120,16 @@ class CommercialPaperTestsGeneric {
@JvmField
val testSerialization = SerializationEnvironmentRule()
val issuer = MEGA_CORP.ref(123)
private val ledgerServices = MockServices(rigorousMock<IdentityServiceInternal>().also {
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
doReturn(MINI_CORP).whenever(it).partyFromKey(MINI_CORP_PUBKEY)
doReturn(null).whenever(it).partyFromKey(ALICE_PUBKEY)
}, MEGA_CORP.name)
@Test
fun `trade lifecycle test`() {
val someProfits = 1200.DOLLARS `issued by` issuer
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
unverifiedTransaction {
attachment(Cash.PROGRAM_ID)
output(Cash.PROGRAM_ID, "alice's $900", 900.DOLLARS.CASH issuedBy issuer ownedBy ALICE)
@ -162,6 +195,10 @@ class CommercialPaperTestsGeneric {
}
}
private fun transaction(script: TransactionDSL<TransactionDSLInterpreter>.() -> EnforceVerifyOrFail) = run {
ledgerServices.transaction(DUMMY_NOTARY, script)
}
@Test
fun `key mismatch at issue`() {
transaction {
@ -223,8 +260,8 @@ class CommercialPaperTestsGeneric {
private lateinit var aliceServices: MockServices
private lateinit var aliceVaultService: VaultService
private lateinit var alicesVault: Vault<ContractState>
private val notaryServices = MockServices(rigorousMock(), MEGA_CORP.name, DUMMY_NOTARY_KEY)
private val issuerServices = MockServices(listOf("net.corda.finance.contracts"), rigorousMock(), MEGA_CORP.name, DUMMY_CASH_ISSUER_KEY)
private val notaryServices = MockServices(rigorousMock(), MEGA_CORP.name, dummyNotary.key)
private val issuerServices = MockServices(listOf("net.corda.finance.contracts"), rigorousMock(), MEGA_CORP.name, dummyCashIssuer.key)
private lateinit var moveTX: SignedTransaction
@Test
fun `issue move and then redeem`() {
@ -238,7 +275,7 @@ class CommercialPaperTestsGeneric {
aliceVaultService = aliceServices.vaultService
databaseAlice.transaction {
alicesVault = VaultFiller(aliceServices, DUMMY_NOTARY, DUMMY_NOTARY_KEY, rngFactory = ::Random).fillWithSomeTestCash(9000.DOLLARS, issuerServices, 1, DUMMY_CASH_ISSUER)
alicesVault = VaultFiller(aliceServices, dummyNotary, rngFactory = ::Random).fillWithSomeTestCash(9000.DOLLARS, issuerServices, 1, DUMMY_CASH_ISSUER)
aliceVaultService = aliceServices.vaultService
}
val bigCorpDatabaseAndServices = makeTestDatabaseAndMockServices(
@ -251,7 +288,7 @@ class CommercialPaperTestsGeneric {
bigCorpVaultService = bigCorpServices.vaultService
databaseBigCorp.transaction {
bigCorpVault = VaultFiller(bigCorpServices, DUMMY_NOTARY, DUMMY_NOTARY_KEY, rngFactory = ::Random).fillWithSomeTestCash(13000.DOLLARS, issuerServices, 1, DUMMY_CASH_ISSUER)
bigCorpVault = VaultFiller(bigCorpServices, dummyNotary, rngFactory = ::Random).fillWithSomeTestCash(13000.DOLLARS, issuerServices, 1, DUMMY_CASH_ISSUER)
bigCorpVaultService = bigCorpServices.vaultService
}

View File

@ -4,10 +4,7 @@ import com.nhaarman.mockito_kotlin.*
import net.corda.core.contracts.*
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.identity.*
import net.corda.core.node.ServiceHub
import net.corda.core.node.services.VaultService
import net.corda.core.node.services.queryBy
@ -27,7 +24,9 @@ import net.corda.testing.contracts.DummyState
import net.corda.testing.contracts.VaultFiller
import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices
import net.corda.testing.node.ledger
import net.corda.testing.node.makeTestIdentityService
import net.corda.testing.node.transaction
import org.junit.After
import org.junit.Before
import org.junit.Rule
@ -36,10 +35,35 @@ import java.util.*
import kotlin.test.*
class CashTests {
private companion object {
val alice = TestIdentity(ALICE_NAME, 70)
val BOB_PUBKEY = TestIdentity(BOB_NAME, 80).pubkey
val charlie = TestIdentity(CHARLIE_NAME, 90)
val DUMMY_CASH_ISSUER_IDENTITY = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10).identity
val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20)
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
val miniCorp = TestIdentity(CordaX500Name("MiniCorp", "London", "GB"))
val ALICE get() = alice.party
val ALICE_PUBKEY get() = alice.pubkey
val CHARLIE get() = charlie.party
val CHARLIE_IDENTITY get() = charlie.identity
val DUMMY_NOTARY get() = dummyNotary.party
val DUMMY_NOTARY_IDENTITY get() = dummyNotary.identity
val DUMMY_NOTARY_KEY get() = dummyNotary.key
val MEGA_CORP get() = megaCorp.party
val MEGA_CORP_IDENTITY get() = megaCorp.identity
val MEGA_CORP_KEY get() = megaCorp.key
val MEGA_CORP_PUBKEY get() = megaCorp.pubkey
val MINI_CORP get() = miniCorp.party
val MINI_CORP_IDENTITY get() = miniCorp.identity
val MINI_CORP_KEY get() = miniCorp.key
val MINI_CORP_PUBKEY get() = miniCorp.pubkey
}
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
private val defaultRef = OpaqueBytes(ByteArray(1, { 1 }))
private val defaultRef = OpaqueBytes.of(1)
private val defaultIssuer = MEGA_CORP.ref(defaultRef)
private val inState = Cash.State(
amount = 1000.DOLLARS `issued by` defaultIssuer,
@ -86,12 +110,12 @@ class CashTests {
ourIdentity = ourServices.myInfo.singleIdentity()
miniCorpAnonymised = miniCorpServices.myInfo.singleIdentityAndCert().party.anonymise()
(miniCorpServices.myInfo.legalIdentitiesAndCerts + megaCorpServices.myInfo.legalIdentitiesAndCerts + notaryServices.myInfo.legalIdentitiesAndCerts).forEach { identity ->
ourServices.identityService.verifyAndRegisterIdentity(identity)
ourServices.identityService.verifyAndRegisterIdentity(identity) // TODO: Configure a mock identity service instead.
}
// Create some cash. Any attempt to spend >$500 will require multiple issuers to be involved.
database.transaction {
val vaultFiller = VaultFiller(ourServices, DUMMY_NOTARY, DUMMY_NOTARY_KEY, rngFactory = ::Random)
val vaultFiller = VaultFiller(ourServices, dummyNotary, rngFactory = ::Random)
vaultFiller.fillWithSomeTestCash(100.DOLLARS, megaCorpServices, 1, MEGA_CORP.ref(1), ourIdentity)
vaultFiller.fillWithSomeTestCash(400.DOLLARS, megaCorpServices, 1, MEGA_CORP.ref(1), ourIdentity)
vaultFiller.fillWithSomeTestCash(80.DOLLARS, miniCorpServices, 1, MINI_CORP.ref(1), ourIdentity)
@ -113,6 +137,15 @@ class CashTests {
database.close()
}
private fun transaction(script: TransactionDSL<TransactionDSLInterpreter>.() -> EnforceVerifyOrFail) = run {
MockServices(rigorousMock<IdentityServiceInternal>().also {
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
doReturn(MINI_CORP).whenever(it).partyFromKey(MINI_CORP_PUBKEY)
doReturn(null).whenever(it).partyFromKey(ALICE_PUBKEY)
doReturn(null).whenever(it).partyFromKey(BOB_PUBKEY)
}, MEGA_CORP.name).transaction(DUMMY_NOTARY, script)
}
@Test
fun trivial() {
transaction {
@ -779,7 +812,7 @@ class CashTests {
val mockService = MockServices(listOf("net.corda.finance.contracts.asset"), rigorousMock<IdentityServiceInternal>().also {
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
}, MEGA_CORP.name, MEGA_CORP_KEY)
ledger(mockService) {
mockService.ledger(DUMMY_NOTARY) {
unverifiedTransaction {
attachment(Cash.PROGRAM_ID)
output(Cash.PROGRAM_ID, "MEGA_CORP cash",

View File

@ -8,6 +8,7 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.sha256
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.NonEmptySet
import net.corda.core.utilities.OpaqueBytes
@ -22,6 +23,8 @@ import net.corda.testing.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.contracts.DummyState
import net.corda.testing.node.MockServices
import net.corda.testing.node.ledger
import net.corda.testing.node.transaction
import org.junit.Rule
import org.junit.Test
import java.time.Instant
@ -33,6 +36,25 @@ import kotlin.test.assertNotEquals
import kotlin.test.assertTrue
class ObligationTests {
private companion object {
val alice = TestIdentity(ALICE_NAME, 70)
val bob = TestIdentity(BOB_NAME, 80)
val CHARLIE = TestIdentity(CHARLIE_NAME, 90).party
val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20)
val DUMMY_OBLIGATION_ISSUER = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10).party
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
val miniCorp = TestIdentity(CordaX500Name("MiniCorp", "London", "GB"))
val ALICE get() = alice.party
val ALICE_PUBKEY get() = alice.pubkey
val BOB get() = bob.party
val BOB_PUBKEY get() = bob.pubkey
val DUMMY_NOTARY get() = dummyNotary.party
val MEGA_CORP get() = megaCorp.party
val MEGA_CORP_PUBKEY get() = megaCorp.pubkey
val MINI_CORP get() = miniCorp.party
val MINI_CORP_PUBKEY get() = miniCorp.pubkey
}
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
@ -54,14 +76,17 @@ class ObligationTests {
beneficiary = CHARLIE
)
private val outState = inState.copy(beneficiary = AnonymousParty(BOB_PUBKEY))
private val miniCorpServices = MockServices(listOf("net.corda.finance.contracts.asset"), rigorousMock(), MINI_CORP.name, MINI_CORP_KEY)
private val notaryServices = MockServices(rigorousMock(), MEGA_CORP.name, DUMMY_NOTARY_KEY)
private val mockService = MockServices(listOf("net.corda.finance.contracts.asset"), rigorousMock<IdentityServiceInternal>().also {
private val miniCorpServices = MockServices(listOf("net.corda.finance.contracts.asset"), rigorousMock(), miniCorp)
private val notaryServices = MockServices(rigorousMock(), MEGA_CORP.name, dummyNotary.key)
private val identityService = rigorousMock<IdentityServiceInternal>().also {
doReturn(null).whenever(it).partyFromKey(ALICE_PUBKEY)
doReturn(null).whenever(it).partyFromKey(BOB_PUBKEY)
doReturn(null).whenever(it).partyFromKey(CHARLIE.owningKey)
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
}, MEGA_CORP.name)
doReturn(MINI_CORP).whenever(it).partyFromKey(MINI_CORP_PUBKEY)
}
private val mockService = MockServices(listOf("net.corda.finance.contracts.asset"), identityService, MEGA_CORP.name)
private val ledgerServices get() = MockServices(identityService, MEGA_CORP.name)
private fun cashObligationTestRoots(
group: LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>
) = group.apply {
@ -74,6 +99,10 @@ class ObligationTests {
}
}
private fun transaction(script: TransactionDSL<TransactionDSLInterpreter>.() -> EnforceVerifyOrFail) = run {
ledgerServices.transaction(DUMMY_NOTARY, script)
}
@Test
fun trivial() {
transaction {
@ -347,7 +376,7 @@ class ObligationTests {
@Test
fun `close-out netting`() {
// Try netting out two obligations
ledger(mockService) {
mockService.ledger(DUMMY_NOTARY) {
cashObligationTestRoots(this)
transaction("Issuance") {
attachments(Obligation.PROGRAM_ID)
@ -363,7 +392,7 @@ class ObligationTests {
// Try netting out two obligations, with the third uninvolved obligation left
// as-is
ledger(mockService) {
mockService.ledger(DUMMY_NOTARY) {
cashObligationTestRoots(this)
transaction("Issuance") {
attachments(Obligation.PROGRAM_ID)
@ -379,7 +408,7 @@ class ObligationTests {
}
// Try having outputs mis-match the inputs
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
cashObligationTestRoots(this)
transaction("Issuance") {
attachments(Obligation.PROGRAM_ID)
@ -393,7 +422,7 @@ class ObligationTests {
}
// Have the wrong signature on the transaction
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
cashObligationTestRoots(this)
transaction("Issuance") {
attachments(Obligation.PROGRAM_ID)
@ -409,7 +438,7 @@ class ObligationTests {
@Test
fun `payment netting`() {
// Try netting out two obligations
ledger(mockService) {
mockService.ledger(DUMMY_NOTARY) {
cashObligationTestRoots(this)
transaction("Issuance") {
attachments(Obligation.PROGRAM_ID)
@ -424,7 +453,7 @@ class ObligationTests {
// Try netting out two obligations, but only provide one signature. Unlike close-out netting, we need both
// signatures for payment netting
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
cashObligationTestRoots(this)
transaction("Issuance") {
attachments(Obligation.PROGRAM_ID)
@ -437,7 +466,7 @@ class ObligationTests {
}
// Multilateral netting, A -> B -> C which can net down to A -> C
ledger(mockService) {
mockService.ledger(DUMMY_NOTARY) {
cashObligationTestRoots(this)
transaction("Issuance") {
attachments(Obligation.PROGRAM_ID)
@ -452,7 +481,7 @@ class ObligationTests {
}
// Multilateral netting without the key of the receiving party
ledger(mockService) {
mockService.ledger(DUMMY_NOTARY) {
cashObligationTestRoots(this)
transaction("Issuance") {
attachments(Obligation.PROGRAM_ID)
@ -469,7 +498,7 @@ class ObligationTests {
@Test
fun `cash settlement`() {
// Try settling an obligation
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
cashObligationTestRoots(this)
transaction("Settlement") {
attachments(Obligation.PROGRAM_ID)
@ -485,7 +514,7 @@ class ObligationTests {
// Try partial settling of an obligation
val halfAMillionDollars = 500000.DOLLARS `issued by` defaultIssuer
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
transaction("Settlement") {
attachments(Obligation.PROGRAM_ID, Cash.PROGRAM_ID)
input(Obligation.PROGRAM_ID, oneMillionDollars.OBLIGATION between Pair(ALICE, BOB))
@ -501,7 +530,7 @@ class ObligationTests {
// Make sure we can't settle an obligation that's defaulted
val defaultedObligation: Obligation.State<Currency> = (oneMillionDollars.OBLIGATION between Pair(ALICE, BOB)).copy(lifecycle = Lifecycle.DEFAULTED)
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
transaction("Settlement") {
attachments(Obligation.PROGRAM_ID, Cash.PROGRAM_ID)
input(Obligation.PROGRAM_ID, defaultedObligation) // Alice's defaulted $1,000,000 obligation to Bob
@ -514,7 +543,7 @@ class ObligationTests {
}
// Make sure settlement amount must match the amount leaving the ledger
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
cashObligationTestRoots(this)
transaction("Settlement") {
attachments(Obligation.PROGRAM_ID)
@ -538,7 +567,7 @@ class ObligationTests {
val oneUnitFcojObligation = Obligation.State(Obligation.Lifecycle.NORMAL, ALICE,
obligationDef, oneUnitFcoj.quantity, NULL_PARTY)
// Try settling a simple commodity obligation
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
unverifiedTransaction {
attachments(Obligation.PROGRAM_ID)
output(Obligation.PROGRAM_ID, "Alice's 1 FCOJ obligation to Bob", oneUnitFcojObligation between Pair(ALICE, BOB))
@ -560,7 +589,7 @@ class ObligationTests {
@Test
fun `payment default`() {
// Try defaulting an obligation without a time-window.
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
cashObligationTestRoots(this)
transaction("Settlement") {
attachments(Obligation.PROGRAM_ID)
@ -584,7 +613,7 @@ class ObligationTests {
}
// Try defaulting an obligation that is now in the past
ledger {
ledgerServices.ledger(DUMMY_NOTARY) {
transaction {
attachments(Obligation.PROGRAM_ID)
input(Obligation.PROGRAM_ID, oneMillionDollars.OBLIGATION between Pair(ALICE, BOB) `at` pastTestTime)

View File

@ -10,7 +10,7 @@ import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters
import net.corda.testing.startFlow
import net.corda.testing.node.startFlow
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.After
import org.junit.Test

View File

@ -11,7 +11,7 @@ import net.corda.testing.BOC_NAME
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetwork.MockNode
import net.corda.testing.startFlow
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Test

View File

@ -11,7 +11,7 @@ import net.corda.testing.BOC_NAME
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetwork.MockNode
import net.corda.testing.startFlow
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Test

View File

@ -14,6 +14,7 @@ import net.corda.testing.*
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetwork.MockNode
import net.corda.testing.node.startFlow
import org.junit.After
import org.junit.Before
import org.junit.Test

View File

@ -17,9 +17,6 @@ dependencies {
// TypeSafe Config: for simple and human friendly config files.
compile "com.typesafe:config:$typesafe_config_version"
// Bouncy Castle: for X.500 distinguished name manipulation
compile "org.bouncycastle:bcprov-jdk15on:$bouncycastle_version"
}
publish {

View File

@ -1,6 +1,5 @@
package net.corda.cordform;
import org.bouncycastle.asn1.x500.X500Name;
import java.nio.file.Path;
public interface CordformContext {

View File

@ -1,14 +1,16 @@
package net.corda.cordform;
import static java.util.Collections.emptyList;
import com.typesafe.config.*;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigValueFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static java.util.Collections.emptyList;
public class CordformNode implements NodeDefinition {
/**
* Path relative to the running node where the serialized NodeInfos are stored.

View File

@ -117,6 +117,16 @@ open class Cordform : DefaultTask() {
.newInstance()
}
/**
* The parametersGenerator needn't be compiled until just before our build method, so we load it manually via sourceSets.main.runtimeClasspath.
*/
private fun loadNetworkParamsGenClass(): Class<*> {
val plugin = project.convention.getPlugin(JavaPluginConvention::class.java)
val classpath = plugin.sourceSets.getByName(MAIN_SOURCE_SET_NAME).runtimeClasspath
val urls = classpath.files.map { it.toURI().toURL() }.toTypedArray()
return URLClassLoader(urls, javaClass.classLoader).loadClass("net.corda.nodeapi.internal.NetworkParametersGenerator")
}
/**
* This task action will create and install the nodes based on the node configurations added.
*/
@ -127,6 +137,7 @@ open class Cordform : DefaultTask() {
installRunScript()
nodes.forEach(Node::build)
generateAndInstallNodeInfos()
generateAndInstallNetworkParameters()
}
private fun initializeConfiguration() {
@ -153,6 +164,16 @@ open class Cordform : DefaultTask() {
}
}
private fun generateAndInstallNetworkParameters() {
project.logger.info("Generating and installing network parameters")
val networkParamsGenClass = loadNetworkParamsGenClass()
val nodeDirs = nodes.map(Node::fullPath)
val networkParamsGenObject = networkParamsGenClass.newInstance()
val runMethod = networkParamsGenClass.getMethod("run", List::class.java).apply { isAccessible = true }
// Call NetworkParametersGenerator.run
runMethod.invoke(networkParamsGenObject, nodeDirs)
}
private fun CordformDefinition.getMatchingCordapps(): List<File> {
val cordappJars = project.configuration("cordapp").files
return cordappPackages.map { `package` ->
@ -193,9 +214,10 @@ open class Cordform : DefaultTask() {
}
private fun buildNodeProcesses(): Map<Node, Process> {
return nodes
.map { buildNodeProcess(it) }
.toMap()
val command = generateNodeInfoCommand()
return nodes.map {
it.makeLogDirectory()
buildProcess(it, command, "generate-info.log") }.toMap()
}
private fun validateNodeProcessess(nodeProcesses: Map<Node, Process>) {
@ -210,14 +232,13 @@ open class Cordform : DefaultTask() {
}
}
private fun buildNodeProcess(node: Node): Pair<Node, Process> {
node.makeLogDirectory()
val process = ProcessBuilder(generateNodeInfoCommand())
private fun buildProcess(node: Node, command: List<String>, logFile: String): Pair<Node, Process> {
val process = ProcessBuilder(command)
.directory(node.fullPath().toFile())
.redirectErrorStream(true)
// InheritIO causes hangs on windows due the gradle buffer also not being flushed.
// Must redirect to output or logger (node log is still written, this is just startup banner)
.redirectOutput(node.logFile().toFile())
.redirectOutput(node.logFile(logFile).toFile())
.addEnvironment("CAPSULE_CACHE_DIR", Node.capsuleCacheDir)
.start()
return Pair(node, process)
@ -260,7 +281,6 @@ open class Cordform : DefaultTask() {
}
}
private fun Node.logFile(): Path = this.logDirectory().resolve("generate-info.log")
private fun Node.logFile(name: String): Path = this.logDirectory().resolve(name)
private fun ProcessBuilder.addEnvironment(key: String, value: String) = this.apply { environment().put(key, value) }
}

View File

@ -4,8 +4,6 @@ import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigRenderOptions
import com.typesafe.config.ConfigValueFactory
import net.corda.cordform.CordformNode
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x500.style.BCStyle
import org.gradle.api.Project
import java.io.File
import java.nio.charset.StandardCharsets
@ -62,21 +60,6 @@ class Node(private val project: Project) : CordformNode() {
config = config.withValue("useTestClock", ConfigValueFactory.fromAnyRef(useTestClock))
}
/**
* Set the network map address for this node.
*
* @warning This should not be directly set unless you know what you are doing. Use the networkMapName in the
* Cordform task instead.
* @param networkMapAddress Network map node address.
* @param networkMapLegalName Network map node legal name.
*/
fun networkMapAddress(networkMapAddress: String, networkMapLegalName: String) {
val networkMapService = mutableMapOf<String, String>()
networkMapService.put("address", networkMapAddress)
networkMapService.put("legalName", networkMapLegalName)
config = config.withValue("networkMapService", ConfigValueFactory.fromMap(networkMapService))
}
/**
* Enables SSH access on given port
*
@ -104,14 +87,10 @@ class Node(private val project: Project) : CordformNode() {
project.logger.error("Node has a null name - cannot create node")
throw IllegalStateException("Node has a null name - cannot create node")
}
val dirName = try {
val o = X500Name(name).getRDNs(BCStyle.O)
if (o.isNotEmpty()) o.first().first.value.toString() else name
} catch (_ : IllegalArgumentException) {
// Can't parse as an X500 name, use the full string
name
}
// Parsing O= part directly because importing BouncyCastle provider in Cordformation causes problems
// with loading our custom X509EdDSAEngine.
val organizationName = name.trim().split(",").firstOrNull { it.startsWith("O=") }?.substringAfter("=")
val dirName = organizationName ?: name
nodeDir = File(rootDir.toFile(), dirName.replace("\\s", ""))
}
@ -129,7 +108,7 @@ class Node(private val project: Project) : CordformNode() {
* Installs the corda fat JAR to the node directory.
*/
private fun installCordaJar() {
val cordaJar = verifyAndGetCordaJar()
val cordaJar = verifyAndGetRuntimeJar("corda")
project.copy {
it.apply {
from(cordaJar)
@ -144,7 +123,7 @@ class Node(private val project: Project) : CordformNode() {
* Installs the corda webserver JAR to the node directory
*/
private fun installWebserverJar() {
val webJar = verifyAndGetWebserverJar()
val webJar = verifyAndGetRuntimeJar("corda-webserver")
project.copy {
it.apply {
from(webJar)
@ -250,34 +229,17 @@ class Node(private val project: Project) : CordformNode() {
}
/**
* Find the corda JAR amongst the dependencies.
* Find the given JAR amongst the dependencies
* @param jarName JAR name without the version part, for example for corda-2.0-SNAPSHOT.jar provide only "corda" as jarName
*
* @return A file representing the Corda JAR.
* @return A file representing found JAR
*/
private fun verifyAndGetCordaJar(): File {
val maybeCordaJAR = project.configuration("runtime").filter {
it.toString().contains("corda-$releaseVersion.jar") || it.toString().contains("corda-enterprise-$releaseVersion.jar")
}
if (maybeCordaJAR.isEmpty) {
throw RuntimeException("No Corda Capsule JAR found. Have you deployed the Corda project to Maven? Looked for \"corda-$releaseVersion.jar\"")
} else {
val cordaJar = maybeCordaJAR.singleFile
assert(cordaJar.isFile)
return cordaJar
}
}
/**
* Find the corda JAR amongst the dependencies
*
* @return A file representing the Corda webserver JAR
*/
private fun verifyAndGetWebserverJar(): File {
private fun verifyAndGetRuntimeJar(jarName: String): File {
val maybeJar = project.configuration("runtime").filter {
it.toString().contains("corda-webserver-$releaseVersion.jar")
"$jarName-$releaseVersion.jar" in it.toString() || "$jarName-enterprise-$releaseVersion.jar" in it.toString()
}
if (maybeJar.isEmpty) {
throw RuntimeException("No Corda Webserver JAR found. Have you deployed the Corda project to Maven? Looked for \"corda-webserver-$releaseVersion.jar\"")
throw IllegalStateException("No $jarName JAR found. Have you deployed the Corda project to Maven? Looked for \"$jarName-$releaseVersion.jar\"")
} else {
val jar = maybeJar.singleFile
require(jar.isFile)

View File

@ -1,10 +1,3 @@
ext {
// We use Corda release artifact dependencies instead of project dependencies to make sure each doorman releases are
// aligned with the corresponding Corda release.
corda_dependency_version = '3.0-NETWORKMAP-20171204.134345-6'
}
version "$corda_dependency_version"
description 'Network management module encapsulating components such as Doorman, HSM Signing Service and Network Map'
@ -57,15 +50,11 @@ task integrationTest(type: Test) {
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
compile project(':node-api')
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "net.corda:corda-node-api:$corda_dependency_version"
// TODO remove this when AMQP P2P serialization context is supported.
compile "net.corda:corda-rpc:$corda_dependency_version"
testCompile "net.corda:corda-node-driver:$corda_dependency_version"
testCompile "net.corda:corda-test-common:$corda_dependency_version"
// Log4J: logging framework (with SLF4J bindings)
compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
compile "org.apache.logging.log4j:log4j-core:${log4j_version}"
@ -90,13 +79,16 @@ dependencies {
// Hibernate audit plugin
compile "org.hibernate:hibernate-envers:5.2.11.Final"
testCompile project(':test-utils')
testCompile project(':node-driver')
// Unit testing helpers.
testCompile 'junit:junit:4.12'
testCompile "org.assertj:assertj-core:${assertj_version}"
testCompile "com.nhaarman:mockito-kotlin:0.6.1"
testRuntime "net.corda:corda-rpc:$corda_dependency_version"
testRuntime "net.corda:corda-rpc:$corda_release_version"
testCompile "com.spotify:docker-client:8.9.1"
integrationTestRuntime "net.corda:corda-rpc:$corda_dependency_version"
integrationTestRuntime "net.corda:corda-rpc:$corda_release_version"
compile('com.atlassian.jira:jira-rest-java-client-core:4.0.0') {
// The jira client includes jersey-core 1.5 which breaks everything.

View File

@ -14,7 +14,7 @@ task buildHsmJAR(type: FatCapsule, dependsOn: 'jar') {
applicationClass 'com.r3.corda.networkmanage.hsm.MainKt'
archiveName "hsm-${version}.jar"
capsuleManifest {
applicationVersion = corda_dependency_version
applicationVersion = corda_release_version
systemProperties['visualvm.display.name'] = 'HSM Signing Service'
minJavaVersion = '1.8.0'
jvmArgs = ['-XX:+UseG1GC']

View File

@ -14,7 +14,7 @@ task buildDoormanJAR(type: FatCapsule, dependsOn: ':network-management:jar') {
applicationClass 'com.r3.corda.networkmanage.doorman.MainKt'
archiveName "doorman-${version}.jar"
capsuleManifest {
applicationVersion = corda_dependency_version
applicationVersion = corda_release_version
systemProperties['visualvm.display.name'] = 'Doorman'
minJavaVersion = '1.8.0'
jvmArgs = ['-XX:+UseG1GC']

View File

@ -12,7 +12,6 @@ import net.corda.core.crypto.sign
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.cert
import net.corda.core.internal.createDirectories
import net.corda.core.node.NodeInfo
import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort
@ -22,11 +21,12 @@ import net.corda.node.services.network.NetworkMapClient
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
import net.corda.node.utilities.registration.NetworkRegistrationHelper
import net.corda.nodeapi.internal.crypto.*
import net.corda.testing.ALICE
import net.corda.testing.ALICE_NAME
import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.testNodeConfiguration
import net.corda.testing.node.testNodeConfiguration
import org.bouncycastle.cert.X509CertificateHolder
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
@ -44,6 +44,8 @@ class DoormanIntegrationTest {
@JvmField
val testSerialization = SerializationEnvironmentRule(true)
// TODO: fix me (see commented out code in this test)
@Ignore
@Test
fun `initial registration`() {
val rootCertAndKey = createDoormanRootCertificateAndKeyPair()
@ -55,13 +57,13 @@ class DoormanIntegrationTest {
// Start Corda network registration.
val config = testNodeConfiguration(
baseDirectory = tempFolder.root.toPath(),
myLegalName = ALICE.name).also {
myLegalName = ALICE_NAME).also {
val doormanHostAndPort = doorman.hostAndPort
whenever(it.compatibilityZoneURL).thenReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}"))
whenever(it.emailAddress).thenReturn("iTest@R3.com")
}
config.rootCaCertFile.parent.createDirectories()
X509Utilities.saveCertificateAsPEMFile(rootCertAndKey.certificate, config.rootCaCertFile)
// config.rootCaCertFile.parent.createDirectories()
// X509Utilities.saveCertificateAsPEMFile(rootCertAndKey.certificate.toX509Certificate(), config.rootCaCertFile)
NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore()
@ -75,13 +77,13 @@ class DoormanIntegrationTest {
loadKeyStore(config.nodeKeystore, config.keyStorePassword).apply {
assert(containsAlias(X509Utilities.CORDA_CLIENT_CA))
assertEquals(ALICE.name.copy(commonName = X509Utilities.CORDA_CLIENT_CA_CN).x500Principal, getX509Certificate(X509Utilities.CORDA_CLIENT_CA).subjectX500Principal)
assertEquals(ALICE_NAME.copy(commonName = X509Utilities.CORDA_CLIENT_CA_CN).x500Principal, getX509Certificate(X509Utilities.CORDA_CLIENT_CA).subjectX500Principal)
assertEquals(listOf(intermediateCACert.cert, rootCACert.cert), getCertificateChain(X509Utilities.CORDA_CLIENT_CA).drop(1).toList())
}
loadKeyStore(config.sslKeystore, config.keyStorePassword).apply {
assert(containsAlias(X509Utilities.CORDA_CLIENT_TLS))
assertEquals(ALICE.name.x500Principal, getX509Certificate(X509Utilities.CORDA_CLIENT_TLS).subjectX500Principal)
assertEquals(ALICE_NAME.x500Principal, getX509Certificate(X509Utilities.CORDA_CLIENT_TLS).subjectX500Principal)
assertEquals(listOf(intermediateCACert.cert, rootCACert.cert), getCertificateChain(X509Utilities.CORDA_CLIENT_TLS).drop(2).toList())
}
@ -93,6 +95,8 @@ class DoormanIntegrationTest {
doorman.close()
}
// TODO: fix me (see commented out code in this test)
@Ignore
@Test
fun `nodeInfo is published to the network map`() {
// Given
@ -106,12 +110,12 @@ class DoormanIntegrationTest {
// Start Corda network registration.
val config = testNodeConfiguration(
baseDirectory = tempFolder.root.toPath(),
myLegalName = ALICE.name).also {
myLegalName = ALICE_NAME).also {
whenever(it.compatibilityZoneURL).thenReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}"))
whenever(it.emailAddress).thenReturn("iTest@R3.com")
}
config.rootCaCertFile.parent.createDirectories()
X509Utilities.saveCertificateAsPEMFile(rootCertAndKey.certificate, config.rootCaCertFile)
// config.rootCaCertFile.parent.createDirectories()
// X509Utilities.saveCertificateAsPEMFile(rootCertAndKey.certificate.toX509Certificate(), config.rootCaCertFile)
NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore()

View File

@ -15,7 +15,6 @@ import com.r3.corda.networkmanage.hsm.persistence.SignedCertificateRequestStorag
import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner
import net.corda.core.crypto.Crypto
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.createDirectories
import net.corda.core.internal.uncheckedCast
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.seconds
@ -24,7 +23,11 @@ import net.corda.node.utilities.registration.NetworkRegistrationHelper
import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.*
import net.corda.testing.ALICE_NAME
import net.corda.testing.BOB_NAME
import net.corda.testing.CHARLIE_NAME
import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.node.testNodeConfiguration
import org.bouncycastle.cert.X509CertificateHolder
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
import org.h2.tools.Server
@ -90,6 +93,8 @@ class SigningServiceIntegrationTest {
}
}
// TODO: fix me (see commented out code in this test)
@Ignore
@Test
fun `Signing service signs approved CSRs`() {
//Start doorman server
@ -100,7 +105,7 @@ class SigningServiceIntegrationTest {
// Start Corda network registration.
val config = testNodeConfiguration(
baseDirectory = tempFolder.root.toPath(),
myLegalName = ALICE.name).also {
myLegalName = ALICE_NAME).also {
val doormanHostAndPort = server.hostAndPort
whenever(it.compatibilityZoneURL).thenReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}"))
}
@ -127,8 +132,8 @@ class SigningServiceIntegrationTest {
// [org.hibernate.tool.schema.spi.SchemaManagementException] being thrown as the schema is missing.
}
}
config.rootCaCertFile.parent.createDirectories()
X509Utilities.saveCertificateAsPEMFile(rootCACert, config.rootCaCertFile)
// config.rootCaCertFile.parent.createDirectories()
// X509Utilities.saveCertificateAsPEMFile(rootCACert, config.rootCaCertFile)
NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore()
verify(hsmSigner).sign(any())
}
@ -161,9 +166,9 @@ class SigningServiceIntegrationTest {
val config = testNodeConfiguration(
baseDirectory = tempFolder.root.toPath(),
myLegalName = when (it) {
1 -> ALICE.name
2 -> BOB.name
3 -> CHARLIE.name
1 -> ALICE_NAME
2 -> BOB_NAME
3 -> CHARLIE_NAME
else -> throw IllegalArgumentException("Unrecognised option")
}).also {
whenever(it.compatibilityZoneURL).thenReturn(URL("http://$HOST:${server.hostAndPort.port}"))

Some files were not shown because too many files have changed in this diff Show More