diff --git a/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java b/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java index 497e5a1cda..b589d0ffb6 100644 --- a/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java +++ b/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java @@ -344,7 +344,7 @@ public class JavaCommercialPaper extends ClauseVerifier { } public void generateRedeem(TransactionBuilder tx, StateAndRef paper, List> wallet) throws InsufficientBalanceException { - new Cash().generateSpend(tx, paper.getState().getData().getFaceValue(), paper.getState().getData().getOwner(), wallet); + new Cash().generateSpend(tx, StructuresKt.withoutIssuer(paper.getState().getData().getFaceValue()), paper.getState().getData().getOwner(), wallet, null); tx.addInputState(paper); tx.addCommand(new Command(new Commands.Redeem(paper.getState().getNotary()), paper.getState().getData().getOwner())); } diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/asset/Cash.kt b/contracts/src/main/kotlin/com/r3corda/contracts/asset/Cash.kt index f2915f8ded..a34cd9f158 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/asset/Cash.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/asset/Cash.kt @@ -8,6 +8,7 @@ import com.r3corda.core.contracts.clauses.* import com.r3corda.core.crypto.* import com.r3corda.core.node.services.Wallet import com.r3corda.core.utilities.Emoji +import java.math.BigInteger import java.security.PublicKey import java.util.* @@ -211,16 +212,6 @@ class Cash : ClauseVerifier() { tx.addCommand(Cash.Commands.Issue(), at.party.owningKey) } - /** - * Generate a transaction that consumes one or more of the given input states to move money to the given pubkey. - * Note that the wallet list is not updated: it's up to you to do that. - */ - @Throws(InsufficientBalanceException::class) - fun generateSpend(tx: TransactionBuilder, amount: Amount>, to: PublicKey, - cashStates: List>): List = - generateSpend(tx, Amount(amount.quantity, amount.token.product), to, cashStates, - setOf(amount.token.issuer.party)) - /** * Generate a transaction that consumes one or more of the given input states to move money to the given pubkey. * Note that the wallet list is not updated: it's up to you to do that. @@ -301,21 +292,23 @@ class Cash : ClauseVerifier() { /** * Sums the cash states in the list belonging to a single owner, throwing an exception * if there are none, or if any of the cash states cannot be added together (i.e. are - * different currencies). + * different currencies or issuers). */ -fun Iterable.sumCashBy(owner: PublicKey) = filterIsInstance().filter { it.owner == owner }.map { it.amount }.sumOrThrow() +fun Iterable.sumCashBy(owner: PublicKey): Amount> = filterIsInstance().filter { it.owner == owner }.map { it.amount }.sumOrThrow() /** * Sums the cash states in the list, throwing an exception if there are none, or if any of the cash * states cannot be added together (i.e. are different currencies). */ -fun Iterable.sumCash() = filterIsInstance().map { it.amount }.sumOrThrow() +fun Iterable.sumCash(): Amount> = filterIsInstance().map { it.amount }.sumOrThrow() /** Sums the cash states in the list, returning null if there are none. */ -fun Iterable.sumCashOrNull() = filterIsInstance().map { it.amount }.sumOrNull() +fun Iterable.sumCashOrNull(): Amount>? = filterIsInstance().map { it.amount }.sumOrNull() -/** Sums the cash states in the list, returning zero of the given currency if there are none. */ -fun Iterable.sumCashOrZero(currency: Issued) = filterIsInstance().map { it.amount }.sumOrZero>(currency) +/** Sums the cash states in the list, returning zero of the given currency+issuer if there are none. */ +fun Iterable.sumCashOrZero(currency: Issued): Amount> { + return filterIsInstance().map { it.amount }.sumOrZero>(currency) +} /** * Returns a map of how much cash we have in each currency, ignoring details like issuer. Note: currencies for @@ -342,7 +335,7 @@ infix fun Cash.State.`with deposit`(deposit: PartyAndReference): Cash.State = wi // Unit testing helpers. These could go in a separate file but it's hardly worth it for just a few functions. /** A randomly generated key. */ -val DUMMY_CASH_ISSUER_KEY by lazy { generateKeyPair() } +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("Snake Oil Issuer", DUMMY_CASH_ISSUER_KEY.public).ref(1) } /** An extension property that lets you write 100.DOLLARS.CASH */ diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/asset/FungibleAsset.kt b/contracts/src/main/kotlin/com/r3corda/contracts/asset/FungibleAsset.kt index 67d7e7e910..5636ab50e1 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/asset/FungibleAsset.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/asset/FungibleAsset.kt @@ -4,7 +4,9 @@ import com.r3corda.core.contracts.* import java.security.PublicKey import java.util.* -class InsufficientBalanceException(val amountMissing: Amount<*>) : Exception() +class InsufficientBalanceException(val amountMissing: Amount<*>) : Exception() { + override fun toString() = "Insufficient balance, missing $amountMissing" +} /** * Interface for contract states representing assets which are fungible, countable and issued by a diff --git a/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt b/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt index a9a16df05d..fe06b16bd3 100644 --- a/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt +++ b/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt @@ -47,7 +47,7 @@ object TwoPartyTradeProtocol { val TOPIC = "platform.trade" - class UnacceptablePriceException(val givenPrice: Amount>) : Exception() + class UnacceptablePriceException(val givenPrice: Amount) : Exception() class AssetMismatchException(val expectedTypeName: String, val typeName: String) : Exception() { override fun toString() = "The submitted asset didn't match the expected type: $expectedTypeName vs $typeName" } @@ -55,7 +55,7 @@ object TwoPartyTradeProtocol { // This object is serialised to the network and is the first protocol message the seller sends to the buyer. class SellerTradeInfo( val assetForSale: StateAndRef, - val price: Amount>, + val price: Amount, val sellerOwnerKey: PublicKey, val sessionID: Long ) @@ -66,7 +66,7 @@ object TwoPartyTradeProtocol { open class Seller(val otherSide: Party, val notaryNode: NodeInfo, val assetToSell: StateAndRef, - val price: Amount>, + val price: Amount, val myKeyPair: KeyPair, val buyerSessionID: Long, override val progressTracker: ProgressTracker = Seller.tracker()) : ProtocolLogic() { @@ -133,7 +133,7 @@ object TwoPartyTradeProtocol { // This verifies that the transaction is contract-valid, even though it is missing signatures. serviceHub.verifyTransaction(wtx.toLedgerTransaction(serviceHub.identityService, serviceHub.storageService.attachments)) - if (wtx.outputs.map { it.data }.sumCashBy(myKeyPair.public) != price) + if (wtx.outputs.map { it.data }.sumCashBy(myKeyPair.public).withoutIssuer() != price) throw IllegalArgumentException("Transaction is not sending us the right amount of cash") // There are all sorts of funny games a malicious secondary might play here, we should fix them: @@ -178,7 +178,7 @@ object TwoPartyTradeProtocol { open class Buyer(val otherSide: Party, val notary: Party, - val acceptablePrice: Amount>, + val acceptablePrice: Amount, val typeToBuy: Class, val sessionID: Long) : ProtocolLogic() { diff --git a/core/src/main/kotlin/com/r3corda/core/Utils.kt b/core/src/main/kotlin/com/r3corda/core/Utils.kt index 68ebed813f..353700e060 100644 --- a/core/src/main/kotlin/com/r3corda/core/Utils.kt +++ b/core/src/main/kotlin/com/r3corda/core/Utils.kt @@ -31,6 +31,11 @@ val Long.bd: BigDecimal get() = BigDecimal(this) fun String.abbreviate(maxWidth: Int): String = if (length <= maxWidth) this else take(maxWidth - 1) + "…" +/** Like the + operator but throws an exception in case of integer overflow. */ +infix fun Int.checkedAdd(b: Int) = Math.addExact(this, b) +/** Like the + operator but throws an exception in case of integer overflow. */ +infix fun Long.checkedAdd(b: Long) = Math.addExact(this, b) + /** * Returns a random positive long generated using a secure RNG. This function sacrifies a bit of entropy in order to * avoid potential bugs where the value is used in a context where negative numbers are not expected. diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt b/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt index a437b10cdd..88553a1615 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt @@ -61,7 +61,7 @@ data class Amount(val quantity: Long, val token: T) : Comparable> { operator fun div(other: Int): Amount = Amount(quantity / other, token) operator fun times(other: Int): Amount = Amount(Math.multiplyExact(quantity, other.toLong()), token) - override fun toString(): String = (BigDecimal(quantity).divide(BigDecimal(100))).setScale(2).toPlainString() + override fun toString(): String = (BigDecimal(quantity).divide(BigDecimal(100))).setScale(2).toPlainString() + " " + token override fun compareTo(other: Amount): Int { checkCurrency(other) diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt b/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt index 313d57fc49..8bd276c240 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt @@ -146,10 +146,16 @@ interface IssuanceDefinition * * @param P the type of product underlying the definition, for example [Currency]. */ -data class Issued( - val issuer: PartyAndReference, - val product: P -) +data class Issued(val issuer: PartyAndReference, val product: P) { + override fun toString() = "$product issued by $issuer" +} + +/** + * Strips the issuer and returns an [Amount] of the raw token directly. This is useful when you are mixing code that + * cares about specific issuers with code that will accept any, or which is imposing issuer constraints via some + * other mechanism and the additional type safety is not wanted. + */ +fun Amount>.withoutIssuer(): Amount = Amount(quantity, token.product) /** * A contract state that can have a single owner. diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/TransactionBuilder.kt b/core/src/main/kotlin/com/r3corda/core/contracts/TransactionBuilder.kt index e032b2c6bb..59a76b1c9f 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/TransactionBuilder.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/TransactionBuilder.kt @@ -120,9 +120,9 @@ open class TransactionBuilder( fun toSignedTransaction(checkSufficientSignatures: Boolean = true): SignedTransaction { if (checkSufficientSignatures) { val gotKeys = currentSigs.map { it.by }.toSet() - val missing = signers - gotKeys + val missing: Set = signers - gotKeys if (missing.isNotEmpty()) - throw IllegalStateException("Missing signatures on the transaction for the public keys: ${missing.map { it.toStringShort() }}") + throw IllegalStateException("Missing signatures on the transaction for the public keys: ${missing.toStringsShort()}") } return SignedTransaction(toWireTransaction().serialize(), ArrayList(currentSigs)) } @@ -131,7 +131,6 @@ open class TransactionBuilder( fun addInputState(stateRef: StateRef, notary: Party) { check(currentSigs.isEmpty()) - signers.add(notary.owningKey) inputs.add(stateRef) } diff --git a/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt b/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt index 1bace21711..f7682c03e2 100644 --- a/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt +++ b/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt @@ -5,10 +5,14 @@ import com.r3corda.core.serialization.OpaqueBytes import com.r3corda.core.serialization.SerializedBytes import com.r3corda.core.serialization.deserialize import net.i2p.crypto.eddsa.EdDSAEngine +import net.i2p.crypto.eddsa.EdDSAPrivateKey import net.i2p.crypto.eddsa.EdDSAPublicKey +import net.i2p.crypto.eddsa.KeyPairGenerator +import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable +import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec +import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec import java.math.BigInteger import java.security.* -import net.i2p.crypto.eddsa.KeyPairGenerator as EddsaKeyPairGenerator fun newSecureRandom(): SecureRandom { if (System.getProperty("os.name") == "Linux") { @@ -115,6 +119,7 @@ object NullPublicKey : PublicKey, Comparable { override fun toString() = "NULL_KEY" } +// TODO: Clean up this duplication between Null and Dummy public key class DummyPublicKey(val s: String) : PublicKey, Comparable { override fun getAlgorithm() = "DUMMY" override fun getEncoded() = s.toByteArray() @@ -125,6 +130,9 @@ class DummyPublicKey(val s: String) : PublicKey, Comparable { override fun toString() = "PUBKEY[$s]" } +/** A signature with a key and value of zero. Useful when you want a signature object that you know won't ever be used. */ +object NullSignature : DigitalSignature.WithKey(NullPublicKey, ByteArray(32)) + /** Utility to simplify the act of signing a byte array */ fun PrivateKey.signWithECDSA(bits: ByteArray): DigitalSignature { val signer = EdDSAEngine() @@ -163,10 +171,24 @@ fun PublicKey.toStringShort(): String { } ?: toString() } +fun Iterable.toStringsShort(): String = map { it.toStringShort() }.toString() + // Allow Kotlin destructuring: val (private, public) = keypair operator fun KeyPair.component1() = this.private - operator fun KeyPair.component2() = this.public /** A simple wrapper that will make it easier to swap out the EC algorithm we use in future */ -fun generateKeyPair(): KeyPair = EddsaKeyPairGenerator().generateKeyPair() +fun generateKeyPair(): KeyPair = KeyPairGenerator().generateKeyPair() + +/** + * Returns a keypair derived from the given private key entropy. This is useful for unit tests and other cases where + * you want hard-coded private keys. + */ +fun entropyToKeyPair(entropy: BigInteger): KeyPair { + val params = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512) + val bits = entropy.toByteArray().copyOf(params.curve.field.getb() / 8) + val priv = EdDSAPrivateKeySpec(bits, params) + val pub = EdDSAPublicKeySpec(priv.a, params) + val key = KeyPair(EdDSAPublicKey(pub), EdDSAPrivateKey(priv)) + return key +} diff --git a/core/src/main/kotlin/com/r3corda/core/testing/CoreTestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/CoreTestUtils.kt index 704601cdec..1a80c1a024 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/CoreTestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/CoreTestUtils.kt @@ -7,14 +7,12 @@ import com.google.common.net.HostAndPort import com.r3corda.core.contracts.Attachment import com.r3corda.core.contracts.StateRef import com.r3corda.core.contracts.TransactionBuilder -import com.r3corda.core.crypto.DummyPublicKey -import com.r3corda.core.crypto.Party -import com.r3corda.core.crypto.SecureHash -import com.r3corda.core.crypto.generateKeyPair +import com.r3corda.core.crypto.* import com.r3corda.core.node.services.IdentityService import com.r3corda.core.node.services.StorageService import com.r3corda.core.node.services.testing.MockIdentityService import com.r3corda.core.node.services.testing.MockStorageService +import java.math.BigInteger import java.net.ServerSocket import java.security.KeyPair import java.security.PublicKey @@ -73,7 +71,7 @@ val CHARLIE: Party get() = Party("Charlie", CHARLIE_PUBKEY) val MEGA_CORP: Party get() = Party("MegaCorp", MEGA_CORP_PUBKEY) val MINI_CORP: Party get() = Party("MiniCorp", MINI_CORP_PUBKEY) -val DUMMY_NOTARY_KEY: KeyPair by lazy { generateKeyPair() } +val DUMMY_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(20)) } val DUMMY_NOTARY: Party get() = Party("Notary Service", DUMMY_NOTARY_KEY.public) val ALL_TEST_KEYS: List get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt index 44d74fcf7b..6d39d9c4fb 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt @@ -53,9 +53,7 @@ interface TransactionDSLInterpreter : Verifies, OutputStateLookup { fun tweak(dsl: TransactionDSL.() -> EnforceVerifyOrFail): EnforceVerifyOrFail } -class TransactionDSL (val interpreter: T) : - TransactionDSLInterpreter by interpreter { - +class TransactionDSL(val interpreter: T) : TransactionDSLInterpreter by interpreter { /** * Looks up the output label and adds the found state as an input. * @param stateLabel The label of the output state specified when calling [TransactionDSLInterpreter._output] and friends. diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt index 007a1f8d31..ad844dcc13 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt @@ -8,8 +8,6 @@ import com.r3corda.contracts.testing.fillWithSomeTestCash import com.r3corda.core.contracts.DOLLARS import com.r3corda.core.contracts.SignedTransaction import com.r3corda.core.contracts.`issued by` -import com.r3corda.core.crypto.Party -import com.r3corda.core.crypto.generateKeyPair import com.r3corda.core.days import com.r3corda.core.random63BitValue import com.r3corda.core.seconds @@ -43,8 +41,7 @@ class TradeSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwo } seller.services.recordTransactions(issuance) - val cashIssuerKey = generateKeyPair() - val amount = 1000.DOLLARS `issued by` Party("Big friendly bank", cashIssuerKey.public).ref(1) + val amount = 1000.DOLLARS val sessionID = random63BitValue() val buyerProtocol = TwoPartyTradeProtocol.Buyer( seller.info.identity, diff --git a/node/src/main/kotlin/com/r3corda/node/services/statemachine/StateMachineManager.kt b/node/src/main/kotlin/com/r3corda/node/services/statemachine/StateMachineManager.kt index 64c7f2c423..e6b247d4d9 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/statemachine/StateMachineManager.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/statemachine/StateMachineManager.kt @@ -270,8 +270,10 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService request.payload?.let { psm.logger.trace { "Sending message of type ${it.javaClass.name} using queue $queueID to ${request.destination} (${it.toString().abbreviate(50)})" } val node = serviceHub.networkMapCache.getNodeByLegalName(request.destination!!.name) - requireNotNull(node) { "Don't know about ${request.destination}" } - serviceHub.networkService.send(queueID, it, node!!.address) + if (node == null) { + throw IllegalArgumentException("Don't know about ${request.destination} but trying to send a message of type ${it.javaClass.name} on $queueID (${it.toString().abbreviate(50)})", request.stackTraceInCaseOfProblems) + } + serviceHub.networkService.send(queueID, it, node.address) } if (request is FiberRequest.NotExpectingResponse) { // We sent a message, but don't expect a response, so re-enter the continuation to let it keep going. diff --git a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt index 99a047ae52..aec019bb17 100644 --- a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt @@ -54,14 +54,14 @@ class TwoPartyTradeProtocolTests { lateinit var net: MockNetwork private fun runSeller(smm: StateMachineManager, notary: NodeInfo, - otherSide: Party, assetToSell: StateAndRef, price: Amount>, + otherSide: Party, assetToSell: StateAndRef, price: Amount, myKeyPair: KeyPair, buyerSessionID: Long): ListenableFuture { val seller = TwoPartyTradeProtocol.Seller(otherSide, notary, assetToSell, price, myKeyPair, buyerSessionID) return smm.add("${TwoPartyTradeProtocol.TOPIC}.seller", seller) } private fun runBuyer(smm: StateMachineManager, notaryNode: NodeInfo, - otherSide: Party, acceptablePrice: Amount>, typeToBuy: Class, + otherSide: Party, acceptablePrice: Amount, typeToBuy: Class, sessionID: Long): ListenableFuture { val buyer = TwoPartyTradeProtocol.Buyer(otherSide, notaryNode.identity, acceptablePrice, typeToBuy, sessionID) return smm.add("${TwoPartyTradeProtocol.TOPIC}.buyer", buyer) @@ -106,7 +106,7 @@ class TwoPartyTradeProtocolTests { bobNode.smm, notaryNode.info, aliceNode.info.identity, - 1000.DOLLARS `issued by` issuer, + 1000.DOLLARS, CommercialPaper.State::class.java, buyerSessionID ) @@ -115,7 +115,7 @@ class TwoPartyTradeProtocolTests { notaryNode.info, bobNode.info.identity, "alice's paper".outputStateAndRef(), - 1000.DOLLARS `issued by` issuer, + 1000.DOLLARS, ALICE_KEY, buyerSessionID ) @@ -158,7 +158,7 @@ class TwoPartyTradeProtocolTests { notaryNode.info, bobNode.info.identity, "alice's paper".outputStateAndRef(), - 1000.DOLLARS `issued by` issuer, + 1000.DOLLARS, ALICE_KEY, buyerSessionID ) @@ -166,7 +166,7 @@ class TwoPartyTradeProtocolTests { bobNode.smm, notaryNode.info, aliceNode.info.identity, - 1000.DOLLARS `issued by` issuer, + 1000.DOLLARS, CommercialPaper.State::class.java, buyerSessionID ) @@ -279,7 +279,7 @@ class TwoPartyTradeProtocolTests { notaryNode.info, bobNode.info.identity, "alice's paper".outputStateAndRef(), - 1000.DOLLARS `issued by` issuer, + 1000.DOLLARS, ALICE_KEY, buyerSessionID ) @@ -287,7 +287,7 @@ class TwoPartyTradeProtocolTests { bobNode.smm, notaryNode.info, aliceNode.info.identity, - 1000.DOLLARS `issued by` issuer, + 1000.DOLLARS, CommercialPaper.State::class.java, buyerSessionID ) @@ -390,7 +390,7 @@ class TwoPartyTradeProtocolTests { notaryNode.info, bobNode.info.identity, "alice's paper".outputStateAndRef(), - 1000.DOLLARS `issued by` issuer, + 1000.DOLLARS, ALICE_KEY, buyerSessionID ) @@ -398,7 +398,7 @@ class TwoPartyTradeProtocolTests { bobNode.smm, notaryNode.info, aliceNode.info.identity, - 1000.DOLLARS `issued by` issuer, + 1000.DOLLARS, CommercialPaper.State::class.java, buyerSessionID ) diff --git a/node/src/test/kotlin/com/r3corda/node/services/WalletWithCashTest.kt b/node/src/test/kotlin/com/r3corda/node/services/WalletWithCashTest.kt index 0270e7ffa9..8f8cd5ba3b 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/WalletWithCashTest.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/WalletWithCashTest.kt @@ -76,7 +76,7 @@ class WalletWithCashTest { // A tx that spends our money. val spendTX = TransactionType.General.Builder().apply { - Cash().generateSpend(this, 80.DOLLARS `issued by` MEGA_CORP.ref(1), BOB_PUBKEY, listOf(myOutput)) + Cash().generateSpend(this, 80.DOLLARS, BOB_PUBKEY, listOf(myOutput)) signWith(freshKey) signWith(DUMMY_NOTARY_KEY) }.toSignedTransaction() diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index ebdbde4689..c98449523b 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -164,7 +164,7 @@ fun runTraderDemo(args: Array): Int { // What happens next depends on the role. The buyer sits around waiting for a trade to start. The seller role // will contact the buyer and actually make something happen. - val amount = 1000.DOLLARS `issued by` cashIssuer.ref(0) // Note: "0" has to match the reference used in the wallet filler + val amount = 1000.DOLLARS if (role == Role.BUYER) { runBuyer(node, amount) } else { @@ -174,7 +174,7 @@ fun runTraderDemo(args: Array): Int { return 0 } -private fun runSeller(node: Node, amount: Amount>, otherSide: Party) { +private fun runSeller(node: Node, amount: Amount, otherSide: Party) { // The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash. // // The CP sale transaction comes with a prospectus PDF, which will tag along for the ride in an @@ -202,7 +202,7 @@ private fun runSeller(node: Node, amount: Amount>, otherSide: P node.stop() } -private fun runBuyer(node: Node, amount: Amount>) { +private fun runBuyer(node: Node, amount: Amount) { // Buyer will fetch the attachment from the seller automatically when it resolves the transaction. // For demo purposes just extract attachment jars when saved to disk, so the user can explore them. val attachmentsPath = (node.storage.attachments as NodeAttachmentService).let { @@ -236,7 +236,7 @@ val DEMO_TOPIC = "initiate.demo.trade" private class TraderDemoProtocolBuyer(val otherSide: Party, private val attachmentsPath: Path, - val amount: Amount>, + val amount: Amount, override val progressTracker: ProgressTracker = ProgressTracker(STARTING_BUY)) : ProtocolLogic() { object STARTING_BUY : ProgressTracker.Step("Seller connected, purchasing commercial paper asset") @@ -294,7 +294,7 @@ ${Emoji.renderIfSupported(cpIssuance)}""") } private class TraderDemoProtocolSeller(val otherSide: Party, - val amount: Amount>, + val amount: Amount, override val progressTracker: ProgressTracker = TraderDemoProtocolSeller.tracker()) : ProtocolLogic() { companion object { val PROSPECTUS_HASH = SecureHash.parse("decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9")