Merge remote-tracking branch 'open/master' into colljos-merge-171117

This commit is contained in:
josecoll 2017-11-18 11:03:36 +00:00
commit ea1cd0035a
18 changed files with 283 additions and 167 deletions

View File

@ -13,6 +13,9 @@ UNRELEASED
* ``CordaRPCOps`` implementation now checks permissions for any function invocation, rather than just when starting flows.
* ``wellKnownPartyFromAnonymous()`` now always resolve the key to a ``Party``, then the party to the well known party.
Previously if it was passed a ``Party`` it would use its name as-is without verifying the key matched that name.
* ``OpaqueBytes.bytes`` now returns a clone of its underlying ``ByteArray``, and has been redeclared as ``final``.
This is a minor change to the public API, but is required to ensure that classes like ``SecureHash`` are immutable.

View File

@ -13,7 +13,6 @@ import java.sql.ResultSet
import java.util.*
class CashSelectionH2Impl : AbstractCashSelection() {
companion object {
const val JDBC_DRIVER_NAME = "H2 JDBC Driver"
val log = loggerFor<CashSelectionH2Impl>()
@ -25,7 +24,6 @@ class CashSelectionH2Impl : AbstractCashSelection() {
override fun toString() = "${this::class.java} for $JDBC_DRIVER_NAME"
// We are using an H2 specific means of selecting a minimum set of rows that match a request amount of coins:
// 1) There is no standard SQL mechanism of calculating a cumulative total on a field and restricting row selection on the
// running total of such an accumulator
@ -34,7 +32,7 @@ class CashSelectionH2Impl : AbstractCashSelection() {
// 3) H2 does not support JOIN's in FOR UPDATE (hence we are forced to execute 2 queries)
override fun executeQuery(connection: Connection, amount: Amount<Currency>, lockId: UUID, notary: Party?,
onlyFromIssuerParties: Set<AbstractParty>, withIssuerRefs: Set<OpaqueBytes>) : ResultSet {
connection.createStatement().execute("CALL SET(@t, 0);")
connection.createStatement().execute("CALL SET(@t, CAST(0 AS BIGINT));")
val selectJoin = """
SELECT vs.transaction_id, vs.output_index, ccs.pennies, SET(@t, ifnull(@t,0)+ccs.pennies) total_pennies, vs.lock_id

View File

@ -54,8 +54,7 @@ class CashTests {
lateinit var database: CordaPersistence
private lateinit var vaultStatesUnconsumed: List<StateAndRef<Cash.State>>
private lateinit var OUR_IDENTITY_1: AbstractParty
private lateinit var OUR_IDENTITY_AND_CERT: PartyAndCertificate
private lateinit var ourIdentity: AbstractParty
private lateinit var miniCorpAnonymised: AnonymousParty
private val CHARLIE_ANONYMISED = CHARLIE_IDENTITY.party.anonymise()
@ -65,28 +64,33 @@ class CashTests {
fun setUp() {
LogHelper.setLevel(NodeVaultService::class)
megaCorpServices = MockServices(listOf("net.corda.finance.contracts.asset"), MEGA_CORP.name, MEGA_CORP_KEY)
miniCorpServices = MockServices(listOf("net.corda.finance.contracts.asset"), MINI_CORP.name, MINI_CORP_KEY)
val notaryServices = MockServices(listOf("net.corda.finance.contracts.asset"), DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
val databaseAndServices = makeTestDatabaseAndMockServices(
cordappPackages = listOf("net.corda.finance.contracts.asset"),
initialIdentityName = CordaX500Name(organisation = "Me", locality = "London", country = "GB"),
keys = listOf(generateKeyPair()))
database = databaseAndServices.first
miniCorpServices = MockServices(listOf("net.corda.finance.contracts.asset"), MINI_CORP.name, MINI_CORP_KEY)
ourServices = databaseAndServices.second
OUR_IDENTITY_AND_CERT = ourServices.myInfo.singleIdentityAndCert()
OUR_IDENTITY_1 = ourServices.myInfo.singleIdentity()
// Set up and register identities
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)
}
// Create some cash. Any attempt to spend >$500 will require multiple issuers to be involved.
database.transaction {
database.transaction {
ourServices.fillWithSomeTestCash(howMuch = 100.DOLLARS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
ownedBy = OUR_IDENTITY_1, issuedBy = MEGA_CORP.ref(1), issuerServices = megaCorpServices)
owner = ourIdentity, issuedBy = MEGA_CORP.ref(1), issuerServices = megaCorpServices)
ourServices.fillWithSomeTestCash(howMuch = 400.DOLLARS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
ownedBy = OUR_IDENTITY_1, issuedBy = MEGA_CORP.ref(1), issuerServices = megaCorpServices)
owner = ourIdentity, issuedBy = MEGA_CORP.ref(1), issuerServices = megaCorpServices)
ourServices.fillWithSomeTestCash(howMuch = 80.DOLLARS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
ownedBy = OUR_IDENTITY_1, issuedBy = MINI_CORP.ref(1), issuerServices = miniCorpServices)
owner = ourIdentity, issuedBy = MINI_CORP.ref(1), issuerServices = miniCorpServices)
ourServices.fillWithSomeTestCash(howMuch = 80.SWISS_FRANCS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
ownedBy = OUR_IDENTITY_1, issuedBy = MINI_CORP.ref(1), issuerServices = miniCorpServices)
owner = ourIdentity, issuedBy = MINI_CORP.ref(1), issuerServices = miniCorpServices)
}
miniCorpAnonymised = miniCorpServices.myInfo.singleIdentityAndCert().party.anonymise()
database.transaction {
vaultStatesUnconsumed = ourServices.vaultService.queryBy<Cash.State>().states
}
@ -495,7 +499,7 @@ class CashTests {
private fun makeCash(amount: Amount<Currency>, issuer: AbstractParty, depositRef: Byte = 1) =
StateAndRef(
TransactionState(Cash.State(amount `issued by` issuer.ref(depositRef), OUR_IDENTITY_1), Cash.PROGRAM_ID, DUMMY_NOTARY),
TransactionState(Cash.State(amount `issued by` issuer.ref(depositRef), ourIdentity), Cash.PROGRAM_ID, DUMMY_NOTARY),
StateRef(SecureHash.randomSHA256(), Random().nextInt(32))
)
@ -509,12 +513,14 @@ class CashTests {
return tx.toWireTransaction(serviceHub)
}
private fun makeSpend(amount: Amount<Currency>, dest: AbstractParty): WireTransaction {
private fun makeSpend(services: ServiceHub, amount: Amount<Currency>, dest: AbstractParty): WireTransaction {
val ourIdentity = services.myInfo.singleIdentityAndCert()
val changeIdentity = services.keyManagementService.freshKeyAndCert(ourIdentity, false)
val tx = TransactionBuilder(DUMMY_NOTARY)
database.transaction {
Cash.generateSpend(ourServices, tx, amount, OUR_IDENTITY_AND_CERT, dest)
Cash.generateSpend(services, tx, amount, changeIdentity, dest)
}
return tx.toWireTransaction(miniCorpServices)
return tx.toWireTransaction(services)
}
/**
@ -588,7 +594,7 @@ class CashTests {
fun generateExitWithEmptyVault() {
assertFailsWith<IllegalArgumentException> {
val tx = TransactionBuilder(DUMMY_NOTARY)
Cash().generateExit(tx, Amount(100, Issued(CHARLIE.ref(1), GBP)), emptyList(), OUR_IDENTITY_1)
Cash().generateExit(tx, Amount(100, Issued(CHARLIE.ref(1), GBP)), emptyList(), ourIdentity)
}
}
@ -596,22 +602,23 @@ class CashTests {
fun generateSimpleDirectSpend() {
val wtx =
database.transaction {
makeSpend(100.DOLLARS, miniCorpAnonymised)
makeSpend(ourServices, 100.DOLLARS, miniCorpAnonymised)
}
database.transaction {
val vaultState = vaultStatesUnconsumed.elementAt(0)
assertEquals(vaultState.ref, wtx.inputs[0])
assertEquals(vaultState.state.data.copy(owner = miniCorpAnonymised), wtx.getOutput(0))
assertEquals(OUR_IDENTITY_1.owningKey, wtx.commands.single { it.value is Cash.Commands.Move }.signers[0])
assertEquals(ourIdentity.owningKey, wtx.commands.single { it.value is Cash.Commands.Move }.signers[0])
}
}
@Test
fun generateSimpleSpendWithParties() {
val changeIdentity = ourServices.keyManagementService.freshKeyAndCert(ourServices.myInfo.singleIdentityAndCert(), false)
database.transaction {
val tx = TransactionBuilder(DUMMY_NOTARY)
Cash.generateSpend(ourServices, tx, 80.DOLLARS, OUR_IDENTITY_AND_CERT, ALICE, setOf(MINI_CORP))
Cash.generateSpend(ourServices, tx, 80.DOLLARS, changeIdentity, ALICE, setOf(MINI_CORP))
assertEquals(vaultStatesUnconsumed.elementAt(2).ref, tx.inputStates()[0])
}
@ -621,7 +628,7 @@ class CashTests {
fun generateSimpleSpendWithChange() {
val wtx =
database.transaction {
makeSpend(10.DOLLARS, miniCorpAnonymised)
makeSpend(ourServices, 10.DOLLARS, miniCorpAnonymised)
}
database.transaction {
val vaultState = vaultStatesUnconsumed.elementAt(0)
@ -638,7 +645,7 @@ class CashTests {
assertEquals(vaultState.ref, wtx.inputs[0])
assertEquals(vaultState.state.data.copy(owner = miniCorpAnonymised, amount = 10.DOLLARS `issued by` defaultIssuer), wtx.outputs[0].data)
assertEquals(vaultState.state.data.copy(amount = changeAmount, owner = changeOwner), wtx.outputs[1].data)
assertEquals(OUR_IDENTITY_1.owningKey, wtx.commands.single { it.value is Cash.Commands.Move }.signers[0])
assertEquals(ourIdentity.owningKey, wtx.commands.single { it.value is Cash.Commands.Move }.signers[0])
}
}
@ -646,7 +653,7 @@ class CashTests {
fun generateSpendWithTwoInputs() {
val wtx =
database.transaction {
makeSpend(500.DOLLARS, miniCorpAnonymised)
makeSpend(ourServices, 500.DOLLARS, miniCorpAnonymised)
}
database.transaction {
val vaultState0 = vaultStatesUnconsumed.elementAt(0)
@ -654,7 +661,7 @@ class CashTests {
assertEquals(vaultState0.ref, wtx.inputs[0])
assertEquals(vaultState1.ref, wtx.inputs[1])
assertEquals(vaultState0.state.data.copy(owner = miniCorpAnonymised, amount = 500.DOLLARS `issued by` defaultIssuer), wtx.getOutput(0))
assertEquals(OUR_IDENTITY_1.owningKey, wtx.commands.single { it.value is Cash.Commands.Move }.signers[0])
assertEquals(ourIdentity.owningKey, wtx.commands.single { it.value is Cash.Commands.Move }.signers[0])
}
}
@ -662,7 +669,7 @@ class CashTests {
fun generateSpendMixedDeposits() {
val wtx =
database.transaction {
val wtx = makeSpend(580.DOLLARS, miniCorpAnonymised)
val wtx = makeSpend(ourServices, 580.DOLLARS, miniCorpAnonymised)
assertEquals(3, wtx.inputs.size)
wtx
}
@ -675,7 +682,7 @@ class CashTests {
assertEquals(vaultState2.ref, wtx.inputs[2])
assertEquals(vaultState0.state.data.copy(owner = miniCorpAnonymised, amount = 500.DOLLARS `issued by` defaultIssuer), wtx.outputs[1].data)
assertEquals(vaultState2.state.data.copy(owner = miniCorpAnonymised), wtx.outputs[0].data)
assertEquals(OUR_IDENTITY_1.owningKey, wtx.commands.single { it.value is Cash.Commands.Move }.signers[0])
assertEquals(ourIdentity.owningKey, wtx.commands.single { it.value is Cash.Commands.Move }.signers[0])
}
}
@ -684,12 +691,12 @@ class CashTests {
database.transaction {
val e: InsufficientBalanceException = assertFailsWith("balance") {
makeSpend(1000.DOLLARS, miniCorpAnonymised)
makeSpend(ourServices, 1000.DOLLARS, miniCorpAnonymised)
}
assertEquals((1000 - 580).DOLLARS, e.amountMissing)
assertFailsWith(InsufficientBalanceException::class) {
makeSpend(81.SWISS_FRANCS, miniCorpAnonymised)
makeSpend(ourServices, 81.SWISS_FRANCS, miniCorpAnonymised)
}
}
}
@ -821,7 +828,7 @@ class CashTests {
fun multiSpend() {
val tx = TransactionBuilder(DUMMY_NOTARY)
database.transaction {
val changeIdentity = ourServices.keyManagementService.freshKeyAndCert(OUR_IDENTITY_AND_CERT, false)
val changeIdentity = ourServices.keyManagementService.freshKeyAndCert(ourServices.myInfo.singleIdentityAndCert(), false)
val payments = listOf(
PartyAndAmount(miniCorpAnonymised, 400.DOLLARS),
PartyAndAmount(CHARLIE_ANONYMISED, 150.DOLLARS)

View File

@ -1,8 +1,12 @@
package net.corda.finance.contracts.asset
package net.corda.finance.contracts.asset.cash.selection
import net.corda.core.internal.concurrent.transpose
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.finance.DOLLARS
import net.corda.finance.POUNDS
import net.corda.finance.flows.CashException
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters
@ -10,8 +14,9 @@ import net.corda.testing.startFlow
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.After
import org.junit.Test
import java.util.Collections.nCopies
class CashSelectionH2Test {
class CashSelectionH2ImplTest {
private val mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance"))
@After
@ -19,6 +24,19 @@ class CashSelectionH2Test {
mockNet.stopNodes()
}
@Test
fun `selecting pennies amount larger than max int, which is split across multiple cash states`() {
val node = mockNet.createNode()
// The amount has to split across at least two states, probably to trigger the H2 accumulator variable during the
// spend operation below.
// Issuing Integer.MAX_VALUE will not cause an exception since PersistentCashState.pennies is a long
nCopies(2, Integer.MAX_VALUE).map { issueAmount ->
node.services.startFlow(CashIssueFlow(issueAmount.POUNDS, OpaqueBytes.of(1), mockNet.defaultNotaryIdentity)).resultFuture
}.transpose().getOrThrow()
// The spend must be more than the size of a single cash state to force the accumulator onto the second state.
node.services.startFlow(CashPaymentFlow((Integer.MAX_VALUE + 1L).POUNDS, node.info.legalIdentities[0])).resultFuture.getOrThrow()
}
@Test
fun `check does not hold connection over retries`() {
val bankA = mockNet.createNode(MockNodeParameters(configOverrides = {

View File

@ -41,26 +41,30 @@ class NodeStatePersistenceTests : IntegrationTest() {
val user = User("mark", "dadada", setOf(startFlow<SendMessageFlow>(), invokeRpc("vaultQuery")))
val message = Message("Hello world!")
driver(isDebug = true, startNodesInProcess = isQuasarAgentSpecified()) {
val stateAndRef: StateAndRef<MessageState>? = driver(isDebug = true, startNodesInProcess = isQuasarAgentSpecified()) {
val nodeName = {
val nodeHandle = startNode(rpcUsers = listOf(user)).getOrThrow()
val nodeName = nodeHandle.nodeInfo.chooseIdentity().name
// Ensure the notary node has finished starting up, before starting a flow that needs a notary
defaultNotaryNode.getOrThrow()
nodeHandle.rpcClientToNode().start(user.username, user.password).use {
it.proxy.startFlow(::SendMessageFlow, message).returnValue.getOrThrow()
it.proxy.startFlow(::SendMessageFlow, message, defaultNotaryIdentity).returnValue.getOrThrow()
}
nodeHandle.stop()
nodeName
}()
val nodeHandle = startNode(providedName = nodeName, rpcUsers = listOf(user)).getOrThrow()
nodeHandle.rpcClientToNode().start(user.username, user.password).use {
val result = nodeHandle.rpcClientToNode().start(user.username, user.password).use {
val page = it.proxy.vaultQuery(MessageState::class.java)
val stateAndRef = page.states.singleOrNull()
assertNotNull(stateAndRef)
val retrievedMessage = stateAndRef!!.state.data.message
assertEquals(message, retrievedMessage)
page.states.singleOrNull()
}
nodeHandle.stop()
result
}
assertNotNull(stateAndRef)
val retrievedMessage = stateAndRef!!.state.data.message
assertEquals(message, retrievedMessage)
}
}
@ -127,7 +131,7 @@ open class MessageContract : Contract {
}
@StartableByRPC
class SendMessageFlow(private val message: Message) : FlowLogic<SignedTransaction>() {
class SendMessageFlow(private val message: Message, private val notary: Party) : FlowLogic<SignedTransaction>() {
companion object {
object GENERATING_TRANSACTION : ProgressTracker.Step("Generating transaction based on the message.")
object VERIFYING_TRANSACTION : ProgressTracker.Step("Verifying contract constraints.")
@ -143,8 +147,6 @@ class SendMessageFlow(private val message: Message) : FlowLogic<SignedTransactio
@Suspendable
override fun call(): SignedTransaction {
val notary = serviceHub.networkMapCache.notaryIdentities.first()
progressTracker.currentStep = GENERATING_TRANSACTION
val messageState = MessageState(message = message, by = ourIdentity)

View File

@ -99,14 +99,14 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptyS
override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]?.party
override fun wellKnownPartyFromX500Name(name: CordaX500Name): Party? = principalToParties[name]?.party
override fun wellKnownPartyFromAnonymous(party: AbstractParty): Party? {
// Expand the anonymous party to a full party (i.e. has a name) if possible
val candidate = party as? Party ?: keyToParties[party.owningKey]?.party
// The original version of this would return the party as-is if it was a Party (rather than AnonymousParty),
// however that means that we don't verify that we know who owns the key. As such as now enforce turning the key
// into a party, and from there figure out the well known party.
val candidate = partyFromKey(party.owningKey)
// TODO: This should be done via the network map cache, which is the authoritative source of well known identities
// Look up the well known identity for that name
return if (candidate != null) {
// If we have a well known identity by that name, use it in preference to the candidate. Otherwise default
// back to the candidate.
principalToParties[candidate.name]?.party ?: candidate
require(party.nameOrNull() == null || party.nameOrNull() == candidate.name) { "Candidate party ${candidate} does not match expected ${party}" }
wellKnownPartyFromX500Name(candidate.name)
} else {
null
}

View File

@ -164,15 +164,13 @@ class PersistentIdentityService(identities: Iterable<PartyAndCertificate> = empt
override fun partyFromKey(key: PublicKey): Party? = certificateFromKey(key)?.party
override fun wellKnownPartyFromX500Name(name: CordaX500Name): Party? = certificateFromCordaX500Name(name)?.party
override fun wellKnownPartyFromAnonymous(party: AbstractParty): Party? {
// Expand the anonymous party to a full party (i.e. has a name) if possible
val candidate = party as? Party ?: partyFromKey(party.owningKey)
// The original version of this would return the party as-is if it was a Party (rather than AnonymousParty),
// however that means that we don't verify that we know who owns the key. As such as now enforce turning the key
// into a party, and from there figure out the well known party.
val candidate = partyFromKey(party.owningKey)
// TODO: This should be done via the network map cache, which is the authoritative source of well known identities
// Look up the well known identity for that name
return if (candidate != null) {
// If we have a well known identity by that name, use it in preference to the candidate. Otherwise default
// back to the candidate.
val res = wellKnownPartyFromX500Name(candidate.name) ?: candidate
res
wellKnownPartyFromX500Name(candidate.name)
} else {
null
}

View File

@ -23,7 +23,7 @@ class AbstractPartyToX500NameAsStringConverter(identitySvc: () -> IdentityServic
if (party != null) {
val partyName = identityService.wellKnownPartyFromAnonymous(party)?.toString()
if (partyName != null) return partyName
log.warn("Identity service unable to resolve AbstractParty: $party")
log.warn("Identity service unable to resolve AbstractParty: $party")
}
return null // non resolvable anonymous parties
}

View File

@ -1,37 +1,57 @@
package net.corda.node.services.vault;
import com.google.common.collect.*;
import kotlin.*;
import com.google.common.collect.ImmutableSet;
import kotlin.Pair;
import kotlin.Triple;
import net.corda.core.contracts.*;
import net.corda.core.identity.*;
import net.corda.core.messaging.*;
import net.corda.core.node.services.*;
import net.corda.core.identity.AbstractParty;
import net.corda.core.messaging.DataFeed;
import net.corda.core.node.services.IdentityService;
import net.corda.core.node.services.Vault;
import net.corda.core.node.services.VaultQueryException;
import net.corda.core.node.services.VaultService;
import net.corda.core.node.services.vault.*;
import net.corda.core.node.services.vault.QueryCriteria.*;
import net.corda.core.utilities.*;
import net.corda.finance.contracts.*;
import net.corda.finance.contracts.asset.*;
import net.corda.finance.schemas.*;
import net.corda.node.utilities.*;
import net.corda.testing.*;
import net.corda.testing.contracts.*;
import net.corda.testing.node.*;
import org.junit.*;
import net.corda.core.node.services.vault.QueryCriteria.LinearStateQueryCriteria;
import net.corda.core.node.services.vault.QueryCriteria.VaultCustomQueryCriteria;
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria;
import net.corda.core.utilities.EncodingUtils;
import net.corda.core.utilities.OpaqueBytes;
import net.corda.finance.contracts.DealState;
import net.corda.finance.contracts.asset.Cash;
import net.corda.finance.contracts.asset.CashUtilities;
import net.corda.finance.schemas.CashSchemaV1;
import net.corda.node.utilities.CordaPersistence;
import net.corda.node.utilities.DatabaseTransaction;
import net.corda.testing.SerializationEnvironmentRule;
import net.corda.testing.TestConstants;
import net.corda.testing.contracts.DummyLinearContract;
import net.corda.testing.contracts.VaultFiller;
import net.corda.testing.node.MockServices;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import rx.Observable;
import java.io.*;
import java.lang.reflect.*;
import java.security.*;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.cert.CertificateException;
import java.util.*;
import java.util.stream.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static net.corda.core.node.services.vault.QueryCriteriaUtils.*;
import static net.corda.core.utilities.ByteArrays.*;
import static net.corda.core.node.services.vault.QueryCriteriaUtils.DEFAULT_PAGE_NUM;
import static net.corda.core.node.services.vault.QueryCriteriaUtils.MAX_PAGE_SIZE;
import static net.corda.core.utilities.ByteArrays.toHexString;
import static net.corda.finance.contracts.asset.CashUtilities.*;
import static net.corda.testing.CoreTestUtils.*;
import static net.corda.testing.TestConstants.*;
import static net.corda.testing.node.MockServices.*;
import static org.assertj.core.api.Assertions.*;
import static net.corda.testing.node.MockServices.makeTestDatabaseAndMockServices;
import static net.corda.testing.node.MockServices.makeTestIdentityService;
import static org.assertj.core.api.Assertions.assertThat;
public class VaultQueryJavaTests {
@Rule
@ -42,7 +62,7 @@ public class VaultQueryJavaTests {
private CordaPersistence database;
@Before
public void setUp() {
public void setUp() throws CertificateException, InvalidAlgorithmParameterException {
List<String> cordappPackages = Arrays.asList("net.corda.testing.contracts", "net.corda.finance.contracts.asset", CashSchemaV1.class.getPackage().getName());
ArrayList<KeyPair> keys = new ArrayList<>();
keys.add(getMEGA_CORP_KEY());
@ -54,6 +74,8 @@ public class VaultQueryJavaTests {
database = databaseAndServices.getFirst();
services = databaseAndServices.getSecond();
vaultService = services.getVaultService();
services.getIdentityService().verifyAndRegisterIdentity(getDUMMY_CASH_ISSUER_IDENTITY());
services.getIdentityService().verifyAndRegisterIdentity(getDUMMY_NOTARY_IDENTITY());
}
@After

View File

@ -169,9 +169,23 @@ class InMemoryIdentityServiceTests {
* Ensure if we feed in a full identity, we get the same identity back.
*/
@Test
fun `deanonymising a well known identity`() {
fun `deanonymising a well known identity should return the identity`() {
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
val expected = ALICE
val actual = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT).wellKnownPartyFromAnonymous(expected)
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
val actual = service.wellKnownPartyFromAnonymous(expected)
assertEquals(expected, actual)
}
/**
* Ensure we don't blindly trust what an anonymous identity claims to be.
*/
@Test
fun `deanonymising a false well known identity should return null`() {
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
val notAlice = Party(ALICE.name, generateKeyPair().public)
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
val actual = service.wellKnownPartyFromAnonymous(notAlice)
assertNull(actual)
}
}

View File

@ -269,11 +269,23 @@ class PersistentIdentityServiceTests {
* Ensure if we feed in a full identity, we get the same identity back.
*/
@Test
fun `deanonymising a well known identity`() {
fun `deanonymising a well known identity should return the identity`() {
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
val expected = ALICE
val actual = database.transaction {
identityService.wellKnownPartyFromAnonymous(expected)
}
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
val actual = service.wellKnownPartyFromAnonymous(expected)
assertEquals(expected, actual)
}
/**
* Ensure we don't blindly trust what an anonymous identity claims to be.
*/
@Test
fun `deanonymising a false well known identity should return null`() {
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
val notAlice = Party(ALICE.name, generateKeyPair().public)
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
val actual = service.wellKnownPartyFromAnonymous(notAlice)
assertNull(actual)
}
}

View File

@ -1,24 +1,26 @@
package net.corda.node.services.persistence
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.StateRef
import net.corda.core.contracts.TransactionState
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.Party
import net.corda.core.node.StatesToRecord
import net.corda.core.utilities.toBase58String
import net.corda.core.node.services.Vault
import net.corda.core.node.services.VaultService
import net.corda.core.schemas.CommonSchemaV1
import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentStateRef
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.SerializationDefaults
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.toBase58String
import net.corda.finance.DOLLARS
import net.corda.finance.POUNDS
import net.corda.finance.SWISS_FRANCS
import net.corda.finance.contracts.asset.*
import net.corda.finance.contracts.asset.Cash
import net.corda.finance.contracts.asset.DUMMY_CASH_ISSUER_KEY
import net.corda.finance.contracts.asset.DUMMY_CASH_ISSUER_NAME
import net.corda.finance.contracts.asset.DummyFungibleContract
import net.corda.finance.schemas.CashSchemaV1
import net.corda.finance.schemas.SampleCashSchemaV2
import net.corda.finance.schemas.SampleCashSchemaV3
@ -54,7 +56,9 @@ class HibernateConfigurationTest {
@JvmField
val testSerialization = SerializationEnvironmentRule()
lateinit var services: MockServices
lateinit var bankServices: MockServices
lateinit var issuerServices: MockServices
lateinit var notaryServices: MockServices
lateinit var database: CordaPersistence
val vault: VaultService get() = services.vaultService
@ -65,19 +69,27 @@ class HibernateConfigurationTest {
lateinit var entityManager: EntityManager
lateinit var criteriaBuilder: CriteriaBuilder
// Identities used
private lateinit var identity: Party
private lateinit var issuer: Party
private lateinit var notary: Party
// test States
lateinit var cashStates: List<StateAndRef<Cash.State>>
@Before
fun setUp() {
val cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts.asset")
issuerServices = MockServices(cordappPackages, DUMMY_CASH_ISSUER_NAME, DUMMY_CASH_ISSUER_KEY, BOB_KEY, BOC_KEY)
bankServices = MockServices(cordappPackages, BOC.name, BOC_KEY)
issuerServices = MockServices(cordappPackages, DUMMY_CASH_ISSUER_NAME, DUMMY_CASH_ISSUER_KEY)
notaryServices = MockServices(cordappPackages, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
val dataSourceProps = makeTestDataSourceProperties()
val defaultDatabaseProperties = makeTestDatabaseProperties()
database = configureDatabase(dataSourceProps, defaultDatabaseProperties, ::makeTestIdentityService)
database.transaction {
hibernateConfig = database.hibernateConfig
services = object : MockServices(cordappPackages, BOB_NAME, BOB_KEY, BOC_KEY, DUMMY_NOTARY_KEY) {
// `consumeCash` expects we can self-notarise transactions
services = object : MockServices(cordappPackages, BOB_NAME, generateKeyPair(), DUMMY_NOTARY_KEY) {
override val vaultService = makeVaultService(database.hibernateConfig)
override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable<SignedTransaction>) {
for (stx in txs) {
@ -91,7 +103,17 @@ class HibernateConfigurationTest {
}
hibernatePersister = services.hibernatePersister
}
setUpDb()
identity = services.myInfo.singleIdentity()
issuer = issuerServices.myInfo.singleIdentity()
notary = notaryServices.myInfo.singleIdentity()
database.transaction {
val numStates = 10
cashStates = services.fillWithSomeTestCash(100.DOLLARS, issuerServices, notary, numStates, numStates, Random(0L), issuedBy = issuer.ref(1))
.states.toList()
}
sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, CashSchemaV1, SampleCashSchemaV2, SampleCashSchemaV3)
entityManager = sessionFactory.createEntityManager()
criteriaBuilder = sessionFactory.criteriaBuilder
@ -104,12 +126,6 @@ class HibernateConfigurationTest {
database.close()
}
private fun setUpDb() {
database.transaction {
cashStates = services.fillWithSomeTestCash(100.DOLLARS, issuerServices, DUMMY_NOTARY, 10, 10, Random(0L)).states.toList()
}
}
@Test
fun `count rows`() {
// structure query
@ -125,7 +141,7 @@ class HibernateConfigurationTest {
@Test
fun `consumed states`() {
database.transaction {
services.consumeCash(50.DOLLARS, notary = DUMMY_NOTARY)
services.consumeCash(50.DOLLARS, notary = notary)
}
// structure query
@ -206,11 +222,11 @@ class HibernateConfigurationTest {
fun `with sorting by state ref desc and asc`() {
// generate additional state ref indexes
database.transaction {
services.consumeCash(1.DOLLARS, notary = DUMMY_NOTARY)
services.consumeCash(2.DOLLARS, notary = DUMMY_NOTARY)
services.consumeCash(3.DOLLARS, notary = DUMMY_NOTARY)
services.consumeCash(4.DOLLARS, notary = DUMMY_NOTARY)
services.consumeCash(5.DOLLARS, notary = DUMMY_NOTARY)
services.consumeCash(1.DOLLARS, notary = notary)
services.consumeCash(2.DOLLARS, notary = notary)
services.consumeCash(3.DOLLARS, notary = notary)
services.consumeCash(4.DOLLARS, notary = notary)
services.consumeCash(5.DOLLARS, notary = notary)
}
// structure query
@ -236,11 +252,11 @@ class HibernateConfigurationTest {
fun `with sorting by state ref index and txId desc and asc`() {
// generate additional state ref indexes
database.transaction {
services.consumeCash(1.DOLLARS, notary = DUMMY_NOTARY)
services.consumeCash(2.DOLLARS, notary = DUMMY_NOTARY)
services.consumeCash(3.DOLLARS, notary = DUMMY_NOTARY)
services.consumeCash(4.DOLLARS, notary = DUMMY_NOTARY)
services.consumeCash(5.DOLLARS, notary = DUMMY_NOTARY)
services.consumeCash(1.DOLLARS, notary = notary)
services.consumeCash(2.DOLLARS, notary = notary)
services.consumeCash(3.DOLLARS, notary = notary)
services.consumeCash(4.DOLLARS, notary = notary)
services.consumeCash(5.DOLLARS, notary = notary)
}
// structure query
@ -267,7 +283,7 @@ class HibernateConfigurationTest {
fun `with pagination`() {
// add 100 additional cash entries
database.transaction {
services.fillWithSomeTestCash(1000.POUNDS, issuerServices, DUMMY_NOTARY, 100, 100, Random(0L), issuedBy = DUMMY_CASH_ISSUER)
services.fillWithSomeTestCash(1000.POUNDS, issuerServices, notary, 100, 100, Random(0L), issuedBy = issuer.ref(1))
}
// structure query
@ -369,11 +385,11 @@ class HibernateConfigurationTest {
fun `calculate cash balances`() {
database.transaction {
services.fillWithSomeTestCash(100.DOLLARS, issuerServices, DUMMY_NOTARY, 10, 10, Random(0L)) // +$100 = $200
services.fillWithSomeTestCash(50.POUNDS, issuerServices, DUMMY_NOTARY, 5, 5, Random(0L)) // £50 = £50
services.fillWithSomeTestCash(25.POUNDS, issuerServices, DUMMY_NOTARY, 5, 5, Random(0L)) // +£25 = £175
services.fillWithSomeTestCash(500.SWISS_FRANCS, issuerServices, DUMMY_NOTARY, 10, 10, Random(0L)) // CHF500 = CHF500
services.fillWithSomeTestCash(250.SWISS_FRANCS, issuerServices, DUMMY_NOTARY, 5, 5, Random(0L)) // +CHF250 = CHF750
services.fillWithSomeTestCash(100.DOLLARS, issuerServices, notary, 10, issuer.ref(1)) // +$100 = $200
services.fillWithSomeTestCash(50.POUNDS, issuerServices, notary, 5, issuer.ref(1)) // £50 = £50
services.fillWithSomeTestCash(25.POUNDS, issuerServices, notary, 5, issuer.ref(1)) // +£25 = £175
services.fillWithSomeTestCash(500.SWISS_FRANCS, issuerServices, notary, 10, issuer.ref(1)) // CHF500 = CHF500
services.fillWithSomeTestCash(250.SWISS_FRANCS, issuerServices, notary, 5, issuer.ref(1)) // +CHF250 = CHF750
}
// structure query
@ -402,8 +418,8 @@ class HibernateConfigurationTest {
@Test
fun `calculate cash balance for single currency`() {
database.transaction {
services.fillWithSomeTestCash(50.POUNDS, issuerServices, DUMMY_NOTARY, 5, 5, Random(0L)) // £50 = £50
services.fillWithSomeTestCash(25.POUNDS, issuerServices, DUMMY_NOTARY, 5, 5, Random(0L)) // +£25 = £175
services.fillWithSomeTestCash(50.POUNDS, issuerServices, notary, 5, issuer.ref(1)) // £50 = £50
services.fillWithSomeTestCash(25.POUNDS, issuerServices, notary, 5, issuer.ref(1)) // +£25 = £175
}
// structure query
@ -432,10 +448,10 @@ class HibernateConfigurationTest {
@Test
fun `calculate and order by cash balance for owner and currency`() {
database.transaction {
services.fillWithSomeTestCash(200.DOLLARS, issuerServices, DUMMY_NOTARY, 2, 2, Random(0L), issuedBy = BOC.ref(1))
services.fillWithSomeTestCash(300.POUNDS, issuerServices, DUMMY_NOTARY, 3, 3, Random(0L), issuedBy = DUMMY_CASH_ISSUER)
services.fillWithSomeTestCash(400.POUNDS, issuerServices, DUMMY_NOTARY, 4, 4, Random(0L), issuedBy = BOC.ref(2))
val bank = bankServices.myInfo.legalIdentities.single()
services.fillWithSomeTestCash(200.DOLLARS, bankServices, notary, 2, bank.ref(1))
services.fillWithSomeTestCash(300.POUNDS, issuerServices, notary, 3, issuer.ref(1))
services.fillWithSomeTestCash(400.POUNDS, bankServices, notary, 4, bank.ref(2))
}
// structure query
@ -622,9 +638,9 @@ class HibernateConfigurationTest {
hibernatePersister.persistStateWithSchema(dummyFungibleState, it.ref, SampleCashSchemaV3)
}
services.fillWithSomeTestCash(100.DOLLARS, issuerServices, DUMMY_NOTARY, 2, 2, Random(0L), ownedBy = ALICE)
val cashStates = services.fillWithSomeTestCash(100.DOLLARS, issuerServices, DUMMY_NOTARY, 2, 2, Random(0L),
issuedBy = BOB.ref(0), ownedBy = (BOB)).states
services.fillWithSomeTestCash(100.DOLLARS, issuerServices, notary, 2, 2, Random(0L),
issuedBy = issuer.ref(1), owner = ALICE)
val cashStates = services.fillWithSomeTestCash(100.DOLLARS, services, notary, 2, identity.ref(0)).states
// persist additional cash states explicitly with V3 schema
cashStates.forEach {
val cashState = it.state.data
@ -646,7 +662,7 @@ class HibernateConfigurationTest {
// search predicate
val cashStatesSchema = criteriaQuery.from(SampleCashSchemaV3.PersistentCashState::class.java)
val queryOwner = BOB.name.toString()
val queryOwner = identity.name.toString()
criteriaQuery.where(criteriaBuilder.equal(cashStatesSchema.get<String>("owner"), queryOwner))
val joinVaultStatesToCash = criteriaBuilder.equal(vaultStates.get<PersistentStateRef>("stateRef"), cashStatesSchema.get<PersistentStateRef>("stateRef"))
@ -701,8 +717,8 @@ class HibernateConfigurationTest {
hibernatePersister.persistStateWithSchema(dummyFungibleState, it.ref, SampleCashSchemaV3)
}
val moreCash = services.fillWithSomeTestCash(100.DOLLARS, issuerServices, DUMMY_NOTARY, 2, 2, Random(0L),
issuedBy = BOB.ref(0), ownedBy = BOB).states
val moreCash = services.fillWithSomeTestCash(100.DOLLARS, services, notary, 2, 2, Random(0L),
issuedBy = identity.ref(0), owner = identity).states
// persist additional cash states explicitly with V3 schema
moreCash.forEach {
val cashState = it.state.data
@ -710,7 +726,7 @@ class HibernateConfigurationTest {
hibernatePersister.persistStateWithSchema(dummyFungibleState, it.ref, SampleCashSchemaV3)
}
val cashStates = services.fillWithSomeTestCash(100.DOLLARS, issuerServices, DUMMY_NOTARY, 2, 2, Random(0L), ownedBy = (ALICE)).states
val cashStates = services.fillWithSomeTestCash(100.DOLLARS, issuerServices, notary, 2, 2, Random(0L), owner = ALICE, issuedBy = issuer.ref(1)).states
// persist additional cash states explicitly with V3 schema
cashStates.forEach {
val cashState = it.state.data

View File

@ -5,7 +5,8 @@ import net.corda.core.contracts.Amount
import net.corda.core.contracts.Issued
import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.StateRef
import net.corda.core.crypto.*
import net.corda.core.crypto.NullKeys
import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party
@ -77,7 +78,9 @@ class NodeVaultServiceTest {
identity = services.myInfo.singleIdentityAndCert()
issuerServices = MockServices(cordappPackages, DUMMY_CASH_ISSUER_NAME, DUMMY_CASH_ISSUER_KEY)
bocServices = MockServices(cordappPackages, BOC_NAME, BOC_KEY)
services.identityService.verifyAndRegisterIdentity(DUMMY_CASH_ISSUER_IDENTITY)
services.identityService.verifyAndRegisterIdentity(BOC_IDENTITY)
}
@After
@ -511,10 +514,9 @@ class NodeVaultServiceTest {
@Test
fun `correct updates are generated for general transactions`() {
val service = vaultService
val notary = identity.party
val vaultSubscriber = TestSubscriber<Vault.Update<*>>().apply {
service.updates.subscribe(this)
vaultService.updates.subscribe(this)
}
val identity = services.myInfo.singleIdentityAndCert()
@ -533,15 +535,16 @@ class NodeVaultServiceTest {
val signedIssuedTx = services.signInitialTransaction(issueBuilder)
services.validatedTransactions.addTransaction(signedIssuedTx)
database.transaction { service.notify(StatesToRecord.ONLY_RELEVANT, issueTx) }
database.transaction { vaultService.notify(StatesToRecord.ONLY_RELEVANT, issueTx) }
val expectedIssueUpdate = Vault.Update(emptySet(), setOf(cashState), null)
database.transaction {
val moveBuilder = TransactionBuilder(notary).apply {
Cash.generateSpend(services, this, Amount(1000, GBP), thirdPartyIdentity)
val changeIdentity = services.keyManagementService.freshKeyAndCert(identity, false)
Cash.generateSpend(services, this, Amount(1000, GBP), changeIdentity, thirdPartyIdentity)
}
val moveTx = moveBuilder.toWireTransaction(services)
service.notify(StatesToRecord.ONLY_RELEVANT, moveTx)
vaultService.notify(StatesToRecord.ONLY_RELEVANT, moveTx)
}
val expectedMoveUpdate = Vault.Update(setOf(cashState), emptySet(), null)
@ -580,6 +583,7 @@ class NodeVaultServiceTest {
val initialCashState = StateAndRef(issueStx.tx.outputs.single(), StateRef(issueStx.id, 0))
// Change notary
services.identityService.verifyAndRegisterIdentity(DUMMY_NOTARY_IDENTITY)
val newNotary = DUMMY_NOTARY
val changeNotaryTx = NotaryChangeWireTransaction(listOf(initialCashState.ref), issueStx.notary!!, newNotary)
val cashStateWithNewNotary = StateAndRef(initialCashState.state.copy(notary = newNotary), StateRef(changeNotaryTx.id, 0))

View File

@ -12,7 +12,10 @@ import net.corda.core.internal.packageName
import net.corda.core.node.services.*
import net.corda.core.node.services.vault.*
import net.corda.core.node.services.vault.QueryCriteria.*
import net.corda.core.utilities.*
import net.corda.core.utilities.NonEmptySet
import net.corda.core.utilities.days
import net.corda.core.utilities.seconds
import net.corda.core.utilities.toHexString
import net.corda.finance.*
import net.corda.finance.contracts.CommercialPaper
import net.corda.finance.contracts.Commodity
@ -31,7 +34,6 @@ import net.corda.testing.contracts.*
import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import net.corda.testing.node.MockServices.Companion.makeTestIdentityService
import net.corda.testing.schemas.DummyLinearStateSchemaV1
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
@ -57,7 +59,7 @@ class VaultQueryTests {
private lateinit var services: MockServices
private lateinit var notaryServices: MockServices
private val vaultService: VaultService get() = services.vaultService
private val identitySvc: IdentityService = makeTestIdentityService()
private lateinit var identitySvc: IdentityService
private lateinit var database: CordaPersistence
// test cash notary
@ -68,14 +70,16 @@ class VaultQueryTests {
@Before
fun setUp() {
// register additional identities
identitySvc.verifyAndRegisterIdentity(CASH_NOTARY_IDENTITY)
identitySvc.verifyAndRegisterIdentity(BOC_IDENTITY)
val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(MEGA_CORP_KEY, DUMMY_NOTARY_KEY),
createIdentityService = { identitySvc },
cordappPackages = cordappPackages)
database = databaseAndServices.first
services = databaseAndServices.second
notaryServices = MockServices(cordappPackages, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY, DUMMY_CASH_ISSUER_KEY, BOC_KEY, MEGA_CORP_KEY)
identitySvc = services.identityService
// Register all of the identities we're going to use
(notaryServices.myInfo.legalIdentitiesAndCerts + BOC_IDENTITY + CASH_NOTARY_IDENTITY + MINI_CORP_IDENTITY + MEGA_CORP_IDENTITY).forEach { identity ->
services.identityService.verifyAndRegisterIdentity(identity)
}
}
@After
@ -1388,20 +1392,24 @@ class VaultQueryTests {
// GBP issuer
val gbpCashIssuerName = CordaX500Name(organisation = "British Pounds Cash Issuer", locality = "London", country = "GB")
val gbpCashIssuerServices = MockServices(cordappPackages, gbpCashIssuerName, generateKeyPair())
val gbpCashIssuer = gbpCashIssuerServices.myInfo.singleIdentity().ref(1)
val gbpCashIssuer = gbpCashIssuerServices.myInfo.singleIdentityAndCert()
// USD issuer
val usdCashIssuerName = CordaX500Name(organisation = "US Dollars Cash Issuer", locality = "New York", country = "US")
val usdCashIssuerServices = MockServices(cordappPackages, usdCashIssuerName, generateKeyPair())
val usdCashIssuer = usdCashIssuerServices.myInfo.singleIdentity().ref(1)
val usdCashIssuer = usdCashIssuerServices.myInfo.singleIdentityAndCert()
// CHF issuer
val chfCashIssuerName = CordaX500Name(organisation = "Swiss Francs Cash Issuer", locality = "Zurich", country = "CH")
val chfCashIssuerServices = MockServices(cordappPackages, chfCashIssuerName, generateKeyPair())
val chfCashIssuer = chfCashIssuerServices.myInfo.singleIdentity().ref(1)
val chfCashIssuer = chfCashIssuerServices.myInfo.singleIdentityAndCert()
listOf(gbpCashIssuer, usdCashIssuer, chfCashIssuer).forEach { identity ->
services.identityService.verifyAndRegisterIdentity(identity)
}
database.transaction {
services.fillWithSomeTestCash(100.POUNDS, gbpCashIssuerServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = gbpCashIssuer.party.ref(1))
services.fillWithSomeTestCash(100.DOLLARS, usdCashIssuerServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = usdCashIssuer.party.ref(1))
services.fillWithSomeTestCash(100.SWISS_FRANCS, chfCashIssuerServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = chfCashIssuer.party.ref(1))
}
database.transaction {
services.fillWithSomeTestCash(100.POUNDS, gbpCashIssuerServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = gbpCashIssuer)
services.fillWithSomeTestCash(100.DOLLARS, usdCashIssuerServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = usdCashIssuer)
services.fillWithSomeTestCash(100.SWISS_FRANCS, chfCashIssuerServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = chfCashIssuer)
val criteria = FungibleAssetQueryCriteria(issuer = listOf(gbpCashIssuer.party, usdCashIssuer.party))
val results = vaultService.queryBy<FungibleAsset<*>>(criteria)
assertThat(results.states).hasSize(2)
@ -1413,8 +1421,9 @@ class VaultQueryTests {
database.transaction {
services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = BOC.ref(1))
services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L),
issuedBy = MEGA_CORP.ref(0), ownedBy = (MINI_CORP))
issuedBy = MEGA_CORP.ref(0), owner = (MINI_CORP))
}
database.transaction {
val criteria = FungibleAssetQueryCriteria(owner = listOf(MEGA_CORP))
val results = vaultService.queryBy<FungibleAsset<*>>(criteria)
assertThat(results.states).hasSize(1) // can only be 1 owner of a node (MEGA_CORP in this MockServices setup)
@ -1426,10 +1435,11 @@ class VaultQueryTests {
database.transaction {
services.fillWithSomeTestCash(100.DOLLARS, notaryServices, CASH_NOTARY, 1, 1, Random(0L))
services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L),
issuedBy = MEGA_CORP.ref(0), ownedBy = (MEGA_CORP))
issuedBy = MEGA_CORP.ref(0), owner = (MEGA_CORP))
services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L),
issuedBy = BOC.ref(0), ownedBy = (MINI_CORP)) // irrelevant to this vault
issuedBy = BOC.ref(0), owner = MINI_CORP) // irrelevant to this vault
}
database.transaction {
// DOCSTART VaultQueryExample5.2
val criteria = FungibleAssetQueryCriteria(owner = listOf(MEGA_CORP, BOC))
val results = vaultService.queryBy<ContractState>(criteria)

View File

@ -148,7 +148,7 @@ class VaultWithCashTest {
database.transaction {
// A tx that sends us money.
services.fillWithSomeTestCash(100.DOLLARS, issuerServices, DUMMY_NOTARY, 10, 10, Random(0L), ownedBy = AnonymousParty(freshKey),
services.fillWithSomeTestCash(100.DOLLARS, issuerServices, DUMMY_NOTARY, 10, 10, Random(0L), owner = AnonymousParty(freshKey),
issuedBy = MEGA_CORP.ref(1))
println("Cash balance: ${services.getCashBalance(USD)}")
}
@ -298,7 +298,7 @@ class VaultWithCashTest {
val freshKey = services.keyManagementService.freshKey()
database.transaction {
services.fillWithSomeTestCash(100.DOLLARS, issuerServices, DUMMY_NOTARY, 3, 3, Random(0L), ownedBy = AnonymousParty(freshKey))
services.fillWithSomeTestCash(100.DOLLARS, issuerServices, DUMMY_NOTARY, 3, 3, Random(0L), owner = AnonymousParty(freshKey))
services.fillWithSomeTestCash(100.SWISS_FRANCS, issuerServices, DUMMY_NOTARY, 2, 2, Random(0L))
services.fillWithSomeTestCash(100.POUNDS, issuerServices, DUMMY_NOTARY, 1, 1, Random(0L))
}

View File

@ -60,6 +60,7 @@ open class MockServices(
vararg val keys: KeyPair
) : ServiceHub, StateLoader by stateLoader {
companion object {
private val MOCK_IDENTITIES = listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)
@JvmStatic
val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Vendor")
@ -126,7 +127,7 @@ open class MockServices(
/**
* Makes database and mock services appropriate for unit tests.
* @param keys a list of [KeyPair] instances to be used by [MockServices]. Defaults to [MEGA_CORP_KEY]
* @param createIdentityService a lambda function returning an instance of [IdentityService]. Defauts to [InMemoryIdentityService].
* @param createIdentityService a lambda function returning an instance of [IdentityService]. Defaults to [InMemoryIdentityService].
*
* @return a pair where the first element is the instance of [CordaPersistence] and the second is [MockServices].
*/

View File

@ -87,9 +87,6 @@ val ALL_TEST_KEYS: List<KeyPair> get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, AL
val DUMMY_CASH_ISSUER_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(DUMMY_CASH_ISSUER.party as Party)
val MOCK_IDENTITIES = listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)
val MOCK_IDENTITY_SERVICE: IdentityService get() = InMemoryIdentityService(MOCK_IDENTITIES, emptySet(), DEV_CA.certificate.cert)
val MOCK_HOST_AND_PORT = NetworkHostAndPort("mockHost", 30000)
fun generateStateRef() = StateRef(SecureHash.randomSHA256(), 0)

View File

@ -96,9 +96,26 @@ fun ServiceHub.fillWithSomeTestLinearStates(numberToCreate: Int,
return Vault(states)
}
/**
* Creates a random set of cash states that add up to the given amount and adds them to the vault. This is intended for
* unit tests. The cash is owned by the legal identity key from the storage service.
*
* The service hub needs to provide at least a key management service and a storage service.
*
* @param issuerServices service hub of the issuer node, which will be used to sign the transaction.
* @param outputNotary the notary to use for output states. The transaction is NOT signed by this notary.
* @return a vault object that represents the generated states (it will NOT be the full vault from the service hub!).
*/
fun ServiceHub.fillWithSomeTestCash(howMuch: Amount<Currency>,
issuerServices: ServiceHub,
outputNotary: Party,
states: Int,
issuedBy: PartyAndReference): Vault<Cash.State>
= fillWithSomeTestCash(howMuch, issuerServices, outputNotary, states, states, issuedBy = issuedBy)
/**
* Creates a random set of between (by default) 3 and 10 cash states that add up to the given amount and adds them
* to the vault. This is intended for unit tests. The cash is issued by [DUMMY_CASH_ISSUER] and owned by the legal
* to the vault. This is intended for unit tests. By default the cash is issued by [DUMMY_CASH_ISSUER] and owned by the legal
* identity key from the storage service.
*
* The service hub needs to provide at least a key management service and a storage service.
@ -113,18 +130,15 @@ fun ServiceHub.fillWithSomeTestCash(howMuch: Amount<Currency>,
atLeastThisManyStates: Int = 3,
atMostThisManyStates: Int = 10,
rng: Random = Random(),
ownedBy: AbstractParty? = null,
owner: AbstractParty? = null,
issuedBy: PartyAndReference = DUMMY_CASH_ISSUER): Vault<Cash.State> {
val amounts = calculateRandomlySizedAmounts(howMuch, atLeastThisManyStates, atMostThisManyStates, rng)
val myKey = ownedBy?.owningKey ?: myInfo.chooseIdentity().owningKey
val anonParty = AnonymousParty(myKey)
// We will allocate one state to one transaction, for simplicities sake.
val cash = Cash()
val transactions: List<SignedTransaction> = amounts.map { pennies ->
val issuance = TransactionBuilder(null as Party?)
cash.generateIssue(issuance, Amount(pennies, Issued(issuedBy, howMuch.token)), anonParty, outputNotary)
cash.generateIssue(issuance, Amount(pennies, Issued(issuedBy, howMuch.token)),owner ?: myInfo.singleIdentity(), outputNotary)
return@map issuerServices.signInitialTransaction(issuance, issuedBy.party.owningKey)
}