mirror of
https://github.com/corda/corda.git
synced 2025-01-24 05:18:24 +00:00
Adds helper methods to grab a LedgerTx or verify a SignedTx. Deprecates builder signing methods.
This commit is contained in:
parent
562b186a65
commit
7df8c50167
@ -136,7 +136,6 @@ interface ServiceHub : ServicesForResolution {
|
||||
return builder.toSignedTransaction(false)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper method to construct an initial partially signed transaction from a TransactionBuilder
|
||||
* using the default identity key contained in the node.
|
||||
@ -146,7 +145,6 @@ interface ServiceHub : ServicesForResolution {
|
||||
*/
|
||||
fun signInitialTransaction(builder: TransactionBuilder): SignedTransaction = signInitialTransaction(builder, legalIdentityKey)
|
||||
|
||||
|
||||
/**
|
||||
* Helper method to construct an initial partially signed transaction from a [TransactionBuilder]
|
||||
* using a set of keys all held in this node.
|
||||
|
@ -3,9 +3,11 @@ package net.corda.core.transactions
|
||||
import net.corda.core.contracts.AttachmentResolutionException
|
||||
import net.corda.core.contracts.NamedByHash
|
||||
import net.corda.core.contracts.TransactionResolutionException
|
||||
import net.corda.core.contracts.TransactionVerificationException
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
@ -136,17 +138,46 @@ data class SignedTransaction(val txBits: SerializedBytes<WireTransaction>,
|
||||
operator fun plus(sigList: Collection<DigitalSignature.WithKey>) = withAdditionalSignatures(sigList)
|
||||
|
||||
/**
|
||||
* Calls [verifySignatures] to check all required signatures are present, and then calls
|
||||
* [WireTransaction.toLedgerTransaction] with the passed in [ServiceHub] to resolve the dependencies,
|
||||
* returning an unverified LedgerTransaction.
|
||||
* Checks the transaction's signatures are valid, optionally calls [verifySignatures] to check
|
||||
* all required signatures are present, and then calls [WireTransaction.toLedgerTransaction]
|
||||
* with the passed in [ServiceHub] to resolve the dependencies, returning an unverified
|
||||
* LedgerTransaction.
|
||||
*
|
||||
* This allows us to perform validation over the entirety of the transaction's contents.
|
||||
* WireTransaction only contains StateRef for the inputs and hashes for the attachments,
|
||||
* rather than ContractState instances for the inputs and Attachment instances for the attachments.
|
||||
*
|
||||
* @throws AttachmentResolutionException if a required attachment was not found in storage.
|
||||
* @throws TransactionResolutionException if an input points to a transaction not found in storage.
|
||||
* @throws SignatureException if any signatures were invalid or unrecognised
|
||||
* @throws SignaturesMissingException if any signatures that should have been present are missing.
|
||||
*/
|
||||
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class, SignatureException::class)
|
||||
fun toLedgerTransaction(services: ServiceHub) = verifySignatures().toLedgerTransaction(services)
|
||||
@JvmOverloads
|
||||
@Throws(SignatureException::class, AttachmentResolutionException::class, TransactionResolutionException::class)
|
||||
fun toLedgerTransaction(services: ServiceHub, checkSufficientSignatures: Boolean = true): LedgerTransaction {
|
||||
checkSignaturesAreValid()
|
||||
if (checkSufficientSignatures) verifySignatures()
|
||||
return tx.toLedgerTransaction(services)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the transaction's signatures are valid, optionally calls [verifySignatures] to check
|
||||
* all required signatures are present, calls [WireTransaction.toLedgerTransaction] with the
|
||||
* passed in [ServiceHub] to resolve the dependencies and return an unverified
|
||||
* LedgerTransaction, then verifies the LedgerTransaction.
|
||||
*
|
||||
* @throws AttachmentResolutionException if a required attachment was not found in storage.
|
||||
* @throws TransactionResolutionException if an input points to a transaction not found in storage.
|
||||
* @throws SignatureException if any signatures were invalid or unrecognised
|
||||
* @throws SignaturesMissingException if any signatures that should have been present are missing.
|
||||
*/
|
||||
@JvmOverloads
|
||||
@Throws(SignatureException::class, AttachmentResolutionException::class, TransactionResolutionException::class, TransactionVerificationException::class)
|
||||
fun verify(services: ServiceHub, checkSufficientSignatures: Boolean = true) {
|
||||
checkSignaturesAreValid()
|
||||
if (checkSufficientSignatures) verifySignatures()
|
||||
tx.toLedgerTransaction(services).verify()
|
||||
}
|
||||
|
||||
override fun toString(): String = "${javaClass.simpleName}(id=$id)"
|
||||
}
|
||||
|
@ -1,13 +1,16 @@
|
||||
package net.corda.core.transactions
|
||||
|
||||
import co.paralleluniverse.strands.Strand
|
||||
import com.google.common.annotations.VisibleForTesting
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.internal.FlowStateMachine
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.serialize
|
||||
import java.security.KeyPair
|
||||
import java.security.PublicKey
|
||||
import java.security.SignatureException
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
@ -40,8 +43,6 @@ open class TransactionBuilder(
|
||||
protected var timeWindow: TimeWindow? = null) {
|
||||
constructor(type: TransactionType, notary: Party) : this(type, notary, (Strand.currentStrand() as? FlowStateMachine<*>)?.id?.uuid ?: UUID.randomUUID())
|
||||
|
||||
val time: TimeWindow? get() = timeWindow // TODO: rename using a more descriptive name (i.e. timeWindowGetter) or remove if unused.
|
||||
|
||||
/**
|
||||
* Creates a copy of the builder.
|
||||
*/
|
||||
@ -57,27 +58,6 @@ open class TransactionBuilder(
|
||||
timeWindow = timeWindow
|
||||
)
|
||||
|
||||
/**
|
||||
* Places a [TimeWindow] in this transaction, removing any existing command if there is one.
|
||||
* The command requires a signature from the Notary service, which acts as a Timestamp Authority.
|
||||
* The signature can be obtained using [NotaryFlow].
|
||||
*
|
||||
* The window of time in which the final time-window may lie is defined as [time] +/- [timeTolerance].
|
||||
* If you want a non-symmetrical time window you must add the command via [addCommand] yourself. The tolerance
|
||||
* should be chosen such that your code can finish building the transaction and sending it to the TSA within that
|
||||
* window of time, taking into account factors such as network latency. Transactions being built by a group of
|
||||
* collaborating parties may therefore require a higher time tolerance than a transaction being built by a single
|
||||
* node.
|
||||
*/
|
||||
fun addTimeWindow(time: Instant, timeTolerance: Duration) = addTimeWindow(TimeWindow.withTolerance(time, timeTolerance))
|
||||
|
||||
fun addTimeWindow(timeWindow: TimeWindow) {
|
||||
check(notary != null) { "Only notarised transactions can have a time-window" }
|
||||
signers.add(notary!!.owningKey)
|
||||
check(currentSigs.isEmpty()) { "Cannot change time-window after signing" }
|
||||
this.timeWindow = timeWindow
|
||||
}
|
||||
|
||||
// DOCSTART 1
|
||||
/** A more convenient way to add items to this transaction that calls the add* methods for you based on type */
|
||||
fun withItems(vararg items: Any): TransactionBuilder {
|
||||
@ -95,62 +75,18 @@ open class TransactionBuilder(
|
||||
}
|
||||
// DOCEND 1
|
||||
|
||||
/** The signatures that have been collected so far - might be incomplete! */
|
||||
protected val currentSigs = arrayListOf<DigitalSignature.WithKey>()
|
||||
|
||||
@Deprecated("Use ServiceHub.signInitialTransaction() instead.")
|
||||
fun signWith(key: KeyPair): TransactionBuilder {
|
||||
check(currentSigs.none { it.by == key.public }) { "This partial transaction was already signed by ${key.public}" }
|
||||
val data = toWireTransaction().id
|
||||
addSignatureUnchecked(key.sign(data.bytes))
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the given signature matches one of the commands and that it is a correct signature over the tx, then
|
||||
* adds it.
|
||||
*
|
||||
* @throws SignatureException if the signature didn't match the transaction contents.
|
||||
* @throws IllegalArgumentException if the signature key doesn't appear in any command.
|
||||
*/
|
||||
fun checkAndAddSignature(sig: DigitalSignature.WithKey) {
|
||||
checkSignature(sig)
|
||||
addSignatureUnchecked(sig)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the given signature matches one of the commands and that it is a correct signature over the tx.
|
||||
*
|
||||
* @throws SignatureException if the signature didn't match the transaction contents.
|
||||
* @throws IllegalArgumentException if the signature key doesn't appear in any command.
|
||||
*/
|
||||
fun checkSignature(sig: DigitalSignature.WithKey) {
|
||||
require(commands.any { it.signers.any { sig.by in it.keys } }) { "Signature key doesn't match any command" }
|
||||
sig.verify(toWireTransaction().id)
|
||||
}
|
||||
|
||||
/** Adds the signature directly to the transaction, without checking it for validity. */
|
||||
fun addSignatureUnchecked(sig: DigitalSignature.WithKey): TransactionBuilder {
|
||||
currentSigs.add(sig)
|
||||
return this
|
||||
}
|
||||
|
||||
fun toWireTransaction() = WireTransaction(ArrayList(inputs), ArrayList(attachments),
|
||||
ArrayList(outputs), ArrayList(commands), notary, signers.toList(), type, timeWindow)
|
||||
|
||||
fun toSignedTransaction(checkSufficientSignatures: Boolean = true): SignedTransaction {
|
||||
if (checkSufficientSignatures) {
|
||||
val gotKeys = currentSigs.map { it.by }.toSet()
|
||||
val missing: Set<PublicKey> = signers.filter { !it.isFulfilledBy(gotKeys) }.toSet()
|
||||
if (missing.isNotEmpty())
|
||||
throw IllegalStateException("Missing signatures on the transaction for the public keys: ${missing.joinToString()}")
|
||||
}
|
||||
val wtx = toWireTransaction()
|
||||
return SignedTransaction(wtx.serialize(), ArrayList(currentSigs))
|
||||
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class)
|
||||
fun toLedgerTransaction(services: ServiceHub) = toWireTransaction().toLedgerTransaction(services)
|
||||
|
||||
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class, TransactionVerificationException::class)
|
||||
fun verify(services: ServiceHub) {
|
||||
toLedgerTransaction(services).verify()
|
||||
}
|
||||
|
||||
open fun addInputState(stateAndRef: StateAndRef<*>) {
|
||||
check(currentSigs.isEmpty())
|
||||
val notary = stateAndRef.state.notary
|
||||
require(notary == this.notary) { "Input state requires notary \"$notary\" which does not match the transaction notary \"${this.notary}\"." }
|
||||
signers.add(notary.owningKey)
|
||||
@ -158,12 +94,10 @@ open class TransactionBuilder(
|
||||
}
|
||||
|
||||
fun addAttachment(attachmentId: SecureHash) {
|
||||
check(currentSigs.isEmpty())
|
||||
attachments.add(attachmentId)
|
||||
}
|
||||
|
||||
fun addOutputState(state: TransactionState<*>): Int {
|
||||
check(currentSigs.isEmpty())
|
||||
outputs.add(state)
|
||||
return outputs.size - 1
|
||||
}
|
||||
@ -178,7 +112,6 @@ open class TransactionBuilder(
|
||||
}
|
||||
|
||||
fun addCommand(arg: Command) {
|
||||
check(currentSigs.isEmpty())
|
||||
// TODO: replace pubkeys in commands with 'pointers' to keys in signers
|
||||
signers.addAll(arg.signers)
|
||||
commands.add(arg)
|
||||
@ -187,10 +120,84 @@ open class TransactionBuilder(
|
||||
fun addCommand(data: CommandData, vararg keys: PublicKey) = addCommand(Command(data, listOf(*keys)))
|
||||
fun addCommand(data: CommandData, keys: List<PublicKey>) = addCommand(Command(data, keys))
|
||||
|
||||
/**
|
||||
* Places a [TimeWindow] in this transaction, removing any existing command if there is one.
|
||||
* The command requires a signature from the Notary service, which acts as a Timestamp Authority.
|
||||
* The signature can be obtained using [NotaryFlow].
|
||||
*
|
||||
* The window of time in which the final time-window may lie is defined as [time] +/- [timeTolerance].
|
||||
* If you want a non-symmetrical time window you must add the command via [addCommand] yourself. The tolerance
|
||||
* should be chosen such that your code can finish building the transaction and sending it to the TSA within that
|
||||
* window of time, taking into account factors such as network latency. Transactions being built by a group of
|
||||
* collaborating parties may therefore require a higher time tolerance than a transaction being built by a single
|
||||
* node.
|
||||
*/
|
||||
fun addTimeWindow(time: Instant, timeTolerance: Duration) = addTimeWindow(TimeWindow.withTolerance(time, timeTolerance))
|
||||
|
||||
fun addTimeWindow(timeWindow: TimeWindow) {
|
||||
check(notary != null) { "Only notarised transactions can have a time-window" }
|
||||
signers.add(notary!!.owningKey)
|
||||
this.timeWindow = timeWindow
|
||||
}
|
||||
|
||||
// Accessors that yield immutable snapshots.
|
||||
fun inputStates(): List<StateRef> = ArrayList(inputs)
|
||||
|
||||
fun attachments(): List<SecureHash> = ArrayList(attachments)
|
||||
fun outputStates(): List<TransactionState<*>> = ArrayList(outputs)
|
||||
fun commands(): List<Command> = ArrayList(commands)
|
||||
fun attachments(): List<SecureHash> = ArrayList(attachments)
|
||||
|
||||
/** The signatures that have been collected so far - might be incomplete! */
|
||||
@Deprecated("Signatures should be gathered on a SignedTransaction instead.")
|
||||
protected val currentSigs = arrayListOf<DigitalSignature.WithKey>()
|
||||
|
||||
@Deprecated("Use ServiceHub.signInitialTransaction() instead.")
|
||||
fun signWith(key: KeyPair): TransactionBuilder {
|
||||
val data = toWireTransaction().id
|
||||
addSignatureUnchecked(key.sign(data.bytes))
|
||||
return this
|
||||
}
|
||||
|
||||
/** Adds the signature directly to the transaction, without checking it for validity. */
|
||||
@Deprecated("Use ServiceHub.signInitialTransaction() instead.")
|
||||
fun addSignatureUnchecked(sig: DigitalSignature.WithKey): TransactionBuilder {
|
||||
currentSigs.add(sig)
|
||||
return this
|
||||
}
|
||||
|
||||
@Deprecated("Use ServiceHub.signInitialTransaction() instead.")
|
||||
fun toSignedTransaction(checkSufficientSignatures: Boolean = true): SignedTransaction {
|
||||
if (checkSufficientSignatures) {
|
||||
val gotKeys = currentSigs.map { it.by }.toSet()
|
||||
val missing: Set<PublicKey> = signers.filter { !it.isFulfilledBy(gotKeys) }.toSet()
|
||||
if (missing.isNotEmpty())
|
||||
throw IllegalStateException("Missing signatures on the transaction for the public keys: ${missing.joinToString()}")
|
||||
}
|
||||
val wtx = toWireTransaction()
|
||||
return SignedTransaction(wtx.serialize(), ArrayList(currentSigs))
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the given signature matches one of the commands and that it is a correct signature over the tx, then
|
||||
* adds it.
|
||||
*
|
||||
* @throws SignatureException if the signature didn't match the transaction contents.
|
||||
* @throws IllegalArgumentException if the signature key doesn't appear in any command.
|
||||
*/
|
||||
@Deprecated("Use WireTransaction.checkSignature() instead.")
|
||||
fun checkAndAddSignature(sig: DigitalSignature.WithKey) {
|
||||
checkSignature(sig)
|
||||
addSignatureUnchecked(sig)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the given signature matches one of the commands and that it is a correct signature over the tx.
|
||||
*
|
||||
* @throws SignatureException if the signature didn't match the transaction contents.
|
||||
* @throws IllegalArgumentException if the signature key doesn't appear in any command.
|
||||
*/
|
||||
@Deprecated("Use WireTransaction.checkSignature() instead.")
|
||||
fun checkSignature(sig: DigitalSignature.WithKey) {
|
||||
require(commands.any { it.signers.any { sig.by in it.keys } }) { "Signature key doesn't match any command" }
|
||||
sig.verify(toWireTransaction().id)
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,10 @@ package net.corda.core.transactions
|
||||
|
||||
import com.esotericsoftware.kryo.pool.KryoPool
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.MerkleTree
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.indexOfOrThrow
|
||||
import net.corda.core.node.ServicesForResolution
|
||||
@ -13,6 +15,7 @@ import net.corda.core.serialization.p2PKryo
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.Emoji
|
||||
import java.security.PublicKey
|
||||
import java.security.SignatureException
|
||||
import java.util.function.Predicate
|
||||
|
||||
/**
|
||||
@ -135,6 +138,17 @@ class WireTransaction(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the given signature matches one of the commands and that it is a correct signature over the tx.
|
||||
*
|
||||
* @throws SignatureException if the signature didn't match the transaction contents.
|
||||
* @throws IllegalArgumentException if the signature key doesn't appear in any command.
|
||||
*/
|
||||
fun checkSignature(sig: DigitalSignature.WithKey) {
|
||||
require(commands.any { it.signers.any { sig.by in it.keys } }) { "Signature key doesn't match any command" }
|
||||
sig.verify(id)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val buf = StringBuilder()
|
||||
buf.appendln("Transaction:")
|
||||
|
@ -6,6 +6,8 @@ import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import net.corda.testing.MEGA_CORP_KEY
|
||||
import net.corda.testing.MEGA_CORP_PUBKEY
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.MockTransactionStorage
|
||||
import org.junit.Test
|
||||
import java.security.KeyPair
|
||||
@ -28,24 +30,29 @@ class TransactionGraphSearchTests {
|
||||
* @param command the command to add to the origin transaction.
|
||||
* @param signer signer for the two transactions and their commands.
|
||||
*/
|
||||
fun buildTransactions(command: CommandData, signer: KeyPair): GraphTransactionStorage {
|
||||
val originTx = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
addOutputState(DummyState(random31BitValue()))
|
||||
addCommand(command, signer.public)
|
||||
signWith(signer)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction(false)
|
||||
val inputTx = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
addInputState(originTx.tx.outRef<DummyState>(0))
|
||||
signWith(signer)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction(false)
|
||||
fun buildTransactions(command: CommandData): GraphTransactionStorage {
|
||||
val megaCorpServices = MockServices(MEGA_CORP_KEY)
|
||||
val notaryServices = MockServices(DUMMY_NOTARY_KEY)
|
||||
|
||||
val originBuilder = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
originBuilder.addOutputState(DummyState(random31BitValue()))
|
||||
originBuilder.addCommand(command, MEGA_CORP_PUBKEY)
|
||||
|
||||
val originPtx = megaCorpServices.signInitialTransaction(originBuilder)
|
||||
val originTx = notaryServices.addSignature(originPtx)
|
||||
|
||||
val inputBuilder = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
inputBuilder.addInputState(originTx.tx.outRef<DummyState>(0))
|
||||
|
||||
val inputPtx = megaCorpServices.signInitialTransaction(inputBuilder)
|
||||
val inputTx = megaCorpServices.addSignature(inputPtx)
|
||||
|
||||
return GraphTransactionStorage(originTx, inputTx)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `return empty from empty`() {
|
||||
val storage = buildTransactions(DummyContract.Commands.Create(), MEGA_CORP_KEY)
|
||||
val storage = buildTransactions(DummyContract.Commands.Create())
|
||||
val search = TransactionGraphSearch(storage, emptyList())
|
||||
search.query = TransactionGraphSearch.Query()
|
||||
val expected = emptyList<WireTransaction>()
|
||||
@ -56,7 +63,7 @@ class TransactionGraphSearchTests {
|
||||
|
||||
@Test
|
||||
fun `return empty from no match`() {
|
||||
val storage = buildTransactions(DummyContract.Commands.Create(), MEGA_CORP_KEY)
|
||||
val storage = buildTransactions(DummyContract.Commands.Create())
|
||||
val search = TransactionGraphSearch(storage, listOf(storage.inputTx.tx))
|
||||
search.query = TransactionGraphSearch.Query()
|
||||
val expected = emptyList<WireTransaction>()
|
||||
@ -67,7 +74,7 @@ class TransactionGraphSearchTests {
|
||||
|
||||
@Test
|
||||
fun `return origin on match`() {
|
||||
val storage = buildTransactions(DummyContract.Commands.Create(), MEGA_CORP_KEY)
|
||||
val storage = buildTransactions(DummyContract.Commands.Create())
|
||||
val search = TransactionGraphSearch(storage, listOf(storage.inputTx.tx))
|
||||
search.query = TransactionGraphSearch.Query(DummyContract.Commands.Create::class.java)
|
||||
val expected = listOf(storage.originTx.tx)
|
||||
|
@ -13,7 +13,9 @@ import net.corda.flows.CollectSignaturesFlow
|
||||
import net.corda.flows.FinalityFlow
|
||||
import net.corda.flows.SignTransactionFlow
|
||||
import net.corda.testing.MINI_CORP_KEY
|
||||
import net.corda.testing.MINI_CORP_PUBKEY
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockServices
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@ -26,6 +28,7 @@ class CollectSignaturesFlowTests {
|
||||
lateinit var b: MockNetwork.MockNode
|
||||
lateinit var c: MockNetwork.MockNode
|
||||
lateinit var notary: Party
|
||||
val services = MockServices()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
@ -162,7 +165,8 @@ class CollectSignaturesFlowTests {
|
||||
@Test
|
||||
fun `fails when not signed by initiator`() {
|
||||
val onePartyDummyContract = DummyContract.generateInitial(1337, notary, a.info.legalIdentity.ref(1))
|
||||
val ptx = onePartyDummyContract.signWith(MINI_CORP_KEY).toSignedTransaction(false)
|
||||
val miniCorpServices = MockServices(MINI_CORP_KEY)
|
||||
val ptx = miniCorpServices.signInitialTransaction(onePartyDummyContract)
|
||||
val flow = a.services.startFlow(CollectSignaturesFlow(ptx))
|
||||
mockNet.runNetwork()
|
||||
assertFailsWith<IllegalArgumentException>("The Initiator of CollectSignaturesFlow must have signed the transaction.") {
|
||||
|
@ -14,6 +14,7 @@ import net.corda.testing.MEGA_CORP
|
||||
import net.corda.testing.MEGA_CORP_KEY
|
||||
import net.corda.testing.MINI_CORP
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockServices
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@ -32,6 +33,8 @@ class ResolveTransactionsFlowTest {
|
||||
lateinit var a: MockNetwork.MockNode
|
||||
lateinit var b: MockNetwork.MockNode
|
||||
lateinit var notary: Party
|
||||
val megaCorpServices = MockServices(MEGA_CORP_KEY)
|
||||
val notaryServices = MockServices(DUMMY_NOTARY_KEY)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
@ -94,9 +97,8 @@ class ResolveTransactionsFlowTest {
|
||||
val count = 50
|
||||
var cursor = stx2
|
||||
repeat(count) {
|
||||
val stx = DummyContract.move(cursor.tx.outRef(0), MINI_CORP)
|
||||
.addSignatureUnchecked(NullSignature)
|
||||
.toSignedTransaction(false)
|
||||
val builder = DummyContract.move(cursor.tx.outRef(0), MINI_CORP)
|
||||
val stx = megaCorpServices.signInitialTransaction(builder)
|
||||
a.database.transaction {
|
||||
a.services.recordTransactions(stx)
|
||||
}
|
||||
@ -114,15 +116,13 @@ class ResolveTransactionsFlowTest {
|
||||
val stx1 = makeTransactions().first
|
||||
|
||||
val stx2 = DummyContract.move(stx1.tx.outRef(0), MINI_CORP).run {
|
||||
signWith(MEGA_CORP_KEY)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
toSignedTransaction()
|
||||
val ptx = megaCorpServices.signInitialTransaction(this)
|
||||
notaryServices.addSignature(ptx)
|
||||
}
|
||||
|
||||
val stx3 = DummyContract.move(listOf(stx1.tx.outRef(0), stx2.tx.outRef(0)), MINI_CORP).run {
|
||||
signWith(MEGA_CORP_KEY)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
toSignedTransaction()
|
||||
val ptx = megaCorpServices.signInitialTransaction(this)
|
||||
notaryServices.addSignature(ptx)
|
||||
}
|
||||
|
||||
a.database.transaction {
|
||||
@ -168,15 +168,19 @@ class ResolveTransactionsFlowTest {
|
||||
val dummy1: SignedTransaction = DummyContract.generateInitial(0, notary, MEGA_CORP.ref(1)).let {
|
||||
if (withAttachment != null)
|
||||
it.addAttachment(withAttachment)
|
||||
if (signFirstTX)
|
||||
it.signWith(MEGA_CORP_KEY)
|
||||
it.signWith(DUMMY_NOTARY_KEY)
|
||||
it.toSignedTransaction(false)
|
||||
when (signFirstTX) {
|
||||
true -> {
|
||||
val ptx = megaCorpServices.signInitialTransaction(it)
|
||||
notaryServices.addSignature(ptx)
|
||||
}
|
||||
false -> {
|
||||
notaryServices.signInitialTransaction(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
val dummy2: SignedTransaction = DummyContract.move(dummy1.tx.outRef(0), MINI_CORP).let {
|
||||
it.signWith(MEGA_CORP_KEY)
|
||||
it.signWith(DUMMY_NOTARY_KEY)
|
||||
it.toSignedTransaction()
|
||||
val ptx = megaCorpServices.signInitialTransaction(it)
|
||||
notaryServices.addSignature(ptx)
|
||||
}
|
||||
a.database.transaction {
|
||||
a.services.recordTransactions(dummy1, dummy2)
|
||||
|
@ -5,14 +5,9 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.seconds
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.DUMMY_KEY_2
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import net.corda.core.utilities.TEST_TX_TIME
|
||||
import net.corda.testing.MEGA_CORP
|
||||
import net.corda.testing.MEGA_CORP_KEY
|
||||
import net.corda.testing.MINI_CORP
|
||||
import net.corda.testing.generateStateRef
|
||||
import net.corda.core.utilities.*
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.node.MockServices
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.security.SignatureException
|
||||
@ -53,7 +48,8 @@ class TransactionSerializationTests {
|
||||
val outputState = TransactionState(TestCash.State(depositRef, 600.POUNDS, MEGA_CORP), DUMMY_NOTARY)
|
||||
val changeState = TransactionState(TestCash.State(depositRef, 400.POUNDS, MEGA_CORP), DUMMY_NOTARY)
|
||||
|
||||
|
||||
val megaCorpServices = MockServices(MEGA_CORP_KEY)
|
||||
val notaryServices = MockServices(DUMMY_NOTARY_KEY)
|
||||
lateinit var tx: TransactionBuilder
|
||||
|
||||
@Before
|
||||
@ -65,53 +61,47 @@ class TransactionSerializationTests {
|
||||
|
||||
@Test
|
||||
fun signWireTX() {
|
||||
tx.signWith(DUMMY_NOTARY_KEY)
|
||||
tx.signWith(MEGA_CORP_KEY)
|
||||
val signedTX = tx.toSignedTransaction()
|
||||
val ptx = megaCorpServices.signInitialTransaction(tx)
|
||||
val stx = notaryServices.addSignature(ptx)
|
||||
|
||||
// Now check that the signature we just made verifies.
|
||||
signedTX.verifySignatures()
|
||||
stx.verifySignatures()
|
||||
|
||||
// Corrupt the data and ensure the signature catches the problem.
|
||||
signedTX.id.bytes[5] = signedTX.id.bytes[5].inc()
|
||||
stx.id.bytes[5] = stx.id.bytes[5].inc()
|
||||
assertFailsWith(SignatureException::class) {
|
||||
signedTX.verifySignatures()
|
||||
stx.verifySignatures()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wrongKeys() {
|
||||
// Can't convert if we don't have signatures for all commands
|
||||
assertFailsWith(IllegalStateException::class) {
|
||||
tx.toSignedTransaction()
|
||||
}
|
||||
|
||||
tx.signWith(MEGA_CORP_KEY)
|
||||
tx.signWith(DUMMY_NOTARY_KEY)
|
||||
val signedTX = tx.toSignedTransaction()
|
||||
val ptx = megaCorpServices.signInitialTransaction(tx)
|
||||
val stx = notaryServices.addSignature(ptx)
|
||||
|
||||
// Cannot construct with an empty sigs list.
|
||||
assertFailsWith(IllegalArgumentException::class) {
|
||||
signedTX.copy(sigs = emptyList())
|
||||
stx.copy(sigs = emptyList())
|
||||
}
|
||||
|
||||
// If the signature was replaced in transit, we don't like it.
|
||||
assertFailsWith(SignatureException::class) {
|
||||
val tx2 = TransactionType.General.Builder(DUMMY_NOTARY).withItems(inputState, outputState, changeState,
|
||||
Command(TestCash.Commands.Move(), DUMMY_KEY_2.public))
|
||||
tx2.signWith(DUMMY_NOTARY_KEY)
|
||||
tx2.signWith(DUMMY_KEY_2)
|
||||
|
||||
signedTX.copy(sigs = tx2.toSignedTransaction().sigs).verifySignatures()
|
||||
val ptx2 = notaryServices.signInitialTransaction(tx2)
|
||||
val dummyServices = MockServices(DUMMY_KEY_2)
|
||||
val stx2 = dummyServices.addSignature(ptx2)
|
||||
|
||||
stx.copy(sigs = stx2.sigs).verifySignatures()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun timeWindow() {
|
||||
tx.addTimeWindow(TEST_TX_TIME, 30.seconds)
|
||||
tx.signWith(MEGA_CORP_KEY)
|
||||
tx.signWith(DUMMY_NOTARY_KEY)
|
||||
val stx = tx.toSignedTransaction()
|
||||
val ptx = megaCorpServices.signInitialTransaction(tx)
|
||||
val stx = notaryServices.addSignature(ptx)
|
||||
assertEquals(TEST_TX_TIME, stx.tx.timeWindow?.midpoint)
|
||||
}
|
||||
}
|
||||
|
@ -205,6 +205,8 @@ class CommercialPaperTestsGeneric {
|
||||
private lateinit var aliceVaultService: VaultService
|
||||
private lateinit var alicesVault: Vault<ContractState>
|
||||
|
||||
private val notaryServices = MockServices(DUMMY_NOTARY_KEY)
|
||||
|
||||
private lateinit var moveTX: SignedTransaction
|
||||
|
||||
@Test
|
||||
@ -215,7 +217,7 @@ class CommercialPaperTestsGeneric {
|
||||
val databaseAlice = dataSourceAndDatabaseAlice.second
|
||||
databaseAlice.transaction {
|
||||
|
||||
aliceServices = object : MockServices() {
|
||||
aliceServices = object : MockServices(ALICE_KEY) {
|
||||
override val vaultService: VaultService = makeVaultService(dataSourcePropsAlice)
|
||||
|
||||
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
||||
@ -235,7 +237,7 @@ class CommercialPaperTestsGeneric {
|
||||
val databaseBigCorp = dataSourceAndDatabaseBigCorp.second
|
||||
databaseBigCorp.transaction {
|
||||
|
||||
bigCorpServices = object : MockServices() {
|
||||
bigCorpServices = object : MockServices(BIG_CORP_KEY) {
|
||||
override val vaultService: VaultService = makeVaultService(dataSourcePropsBigCorp)
|
||||
|
||||
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
||||
@ -257,29 +259,27 @@ class CommercialPaperTestsGeneric {
|
||||
// BigCorp™ issues $10,000 of commercial paper, to mature in 30 days, owned initially by itself.
|
||||
val faceValue = 10000.DOLLARS `issued by` DUMMY_CASH_ISSUER
|
||||
val issuance = bigCorpServices.myInfo.legalIdentity.ref(1)
|
||||
val issueTX: SignedTransaction =
|
||||
CommercialPaper().generateIssue(issuance, faceValue, TEST_TX_TIME + 30.days, DUMMY_NOTARY).apply {
|
||||
addTimeWindow(TEST_TX_TIME, 30.seconds)
|
||||
signWith(bigCorpServices.key)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
val issueBuilder = CommercialPaper().generateIssue(issuance, faceValue, TEST_TX_TIME + 30.days, DUMMY_NOTARY)
|
||||
issueBuilder.addTimeWindow(TEST_TX_TIME, 30.seconds)
|
||||
val issuePtx = bigCorpServices.signInitialTransaction(issueBuilder)
|
||||
val issueTx = notaryServices.addSignature(issuePtx)
|
||||
|
||||
databaseAlice.transaction {
|
||||
// Alice pays $9000 to BigCorp to own some of their debt.
|
||||
moveTX = run {
|
||||
val ptx = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
aliceVaultService.generateSpend(ptx, 9000.DOLLARS, AnonymousParty(bigCorpServices.key.public))
|
||||
CommercialPaper().generateMove(ptx, issueTX.tx.outRef(0), AnonymousParty(aliceServices.key.public))
|
||||
ptx.signWith(bigCorpServices.key)
|
||||
ptx.signWith(aliceServices.key)
|
||||
ptx.signWith(DUMMY_NOTARY_KEY)
|
||||
ptx.toSignedTransaction()
|
||||
val builder = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
aliceVaultService.generateSpend(builder, 9000.DOLLARS, AnonymousParty(bigCorpServices.key.public))
|
||||
CommercialPaper().generateMove(builder, issueTx.tx.outRef(0), AnonymousParty(aliceServices.key.public))
|
||||
val ptx = aliceServices.signInitialTransaction(builder)
|
||||
val ptx2 = bigCorpServices.addSignature(ptx)
|
||||
val stx = notaryServices.addSignature(ptx2)
|
||||
stx
|
||||
}
|
||||
}
|
||||
|
||||
databaseBigCorp.transaction {
|
||||
// Verify the txns are valid and insert into both sides.
|
||||
listOf(issueTX, moveTX).forEach {
|
||||
listOf(issueTx, moveTX).forEach {
|
||||
it.toLedgerTransaction(aliceServices).verify()
|
||||
aliceServices.recordTransactions(it)
|
||||
bigCorpServices.recordTransactions(it)
|
||||
@ -288,13 +288,13 @@ class CommercialPaperTestsGeneric {
|
||||
|
||||
databaseBigCorp.transaction {
|
||||
fun makeRedeemTX(time: Instant): Pair<SignedTransaction, UUID> {
|
||||
val ptx = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
ptx.addTimeWindow(time, 30.seconds)
|
||||
CommercialPaper().generateRedeem(ptx, moveTX.tx.outRef(1), bigCorpVaultService)
|
||||
ptx.signWith(aliceServices.key)
|
||||
ptx.signWith(bigCorpServices.key)
|
||||
ptx.signWith(DUMMY_NOTARY_KEY)
|
||||
return Pair(ptx.toSignedTransaction(), ptx.lockId)
|
||||
val builder = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
builder.addTimeWindow(time, 30.seconds)
|
||||
CommercialPaper().generateRedeem(builder, moveTX.tx.outRef(1), bigCorpVaultService)
|
||||
val ptx = aliceServices.signInitialTransaction(builder)
|
||||
val ptx2 = bigCorpServices.addSignature(ptx)
|
||||
val stx = notaryServices.addSignature(ptx2)
|
||||
return Pair(stx, builder.lockId)
|
||||
}
|
||||
|
||||
val redeemTX = makeRedeemTX(TEST_TX_TIME + 10.days)
|
||||
|
@ -43,8 +43,8 @@ class CashTests {
|
||||
amount = Amount(amount.quantity, token = amount.token.copy(amount.token.issuer.copy(reference = OpaqueBytes.of(ref))))
|
||||
)
|
||||
|
||||
lateinit var services: MockServices
|
||||
val vault: VaultService get() = services.vaultService
|
||||
lateinit var miniCorpServices: MockServices
|
||||
val vault: VaultService get() = miniCorpServices.vaultService
|
||||
lateinit var dataSource: Closeable
|
||||
lateinit var database: Database
|
||||
lateinit var vaultStatesUnconsumed: List<StateAndRef<Cash.State>>
|
||||
@ -57,7 +57,7 @@ class CashTests {
|
||||
dataSource = dataSourceAndDatabase.first
|
||||
database = dataSourceAndDatabase.second
|
||||
database.transaction {
|
||||
services = object : MockServices() {
|
||||
miniCorpServices = object : MockServices(MINI_CORP_KEY) {
|
||||
override val keyManagementService: MockKeyManagementService = MockKeyManagementService(identityService, MINI_CORP_KEY, MEGA_CORP_KEY, OUR_KEY)
|
||||
override val vaultService: VaultService = makeVaultService(dataSourceProps)
|
||||
|
||||
@ -70,16 +70,16 @@ class CashTests {
|
||||
}
|
||||
}
|
||||
|
||||
services.fillWithSomeTestCash(howMuch = 100.DOLLARS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
|
||||
miniCorpServices.fillWithSomeTestCash(howMuch = 100.DOLLARS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
|
||||
issuedBy = MEGA_CORP.ref(1), issuerKey = MEGA_CORP_KEY, ownedBy = OUR_IDENTITY_1)
|
||||
services.fillWithSomeTestCash(howMuch = 400.DOLLARS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
|
||||
miniCorpServices.fillWithSomeTestCash(howMuch = 400.DOLLARS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
|
||||
issuedBy = MEGA_CORP.ref(1), issuerKey = MEGA_CORP_KEY, ownedBy = OUR_IDENTITY_1)
|
||||
services.fillWithSomeTestCash(howMuch = 80.DOLLARS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
|
||||
miniCorpServices.fillWithSomeTestCash(howMuch = 80.DOLLARS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
|
||||
issuedBy = MINI_CORP.ref(1), issuerKey = MINI_CORP_KEY, ownedBy = OUR_IDENTITY_1)
|
||||
services.fillWithSomeTestCash(howMuch = 80.SWISS_FRANCS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
|
||||
miniCorpServices.fillWithSomeTestCash(howMuch = 80.SWISS_FRANCS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
|
||||
issuedBy = MINI_CORP.ref(1), issuerKey = MINI_CORP_KEY, ownedBy = OUR_IDENTITY_1)
|
||||
|
||||
vaultStatesUnconsumed = services.vaultService.unconsumedStates<Cash.State>().toList()
|
||||
vaultStatesUnconsumed = miniCorpServices.vaultService.unconsumedStates<Cash.State>().toList()
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,8 +160,7 @@ class CashTests {
|
||||
// Test generation works.
|
||||
val tx: WireTransaction = TransactionType.General.Builder(notary = null).apply {
|
||||
Cash().generateIssue(this, 100.DOLLARS `issued by` MINI_CORP.ref(12, 34), owner = AnonymousParty(DUMMY_PUBKEY_1), notary = DUMMY_NOTARY)
|
||||
signWith(MINI_CORP_KEY)
|
||||
}.toSignedTransaction().tx
|
||||
}.toWireTransaction()
|
||||
assertTrue(tx.inputs.isEmpty())
|
||||
val s = tx.outputs[0].data as Cash.State
|
||||
assertEquals(100.DOLLARS `issued by` MINI_CORP.ref(12, 34), s.amount)
|
||||
@ -177,8 +176,7 @@ class CashTests {
|
||||
val amount = 100.DOLLARS `issued by` MINI_CORP.ref(12, 34)
|
||||
val tx: WireTransaction = TransactionType.General.Builder(notary = null).apply {
|
||||
Cash().generateIssue(this, amount, owner = AnonymousParty(DUMMY_PUBKEY_1), notary = DUMMY_NOTARY)
|
||||
signWith(MINI_CORP_KEY)
|
||||
}.toSignedTransaction().tx
|
||||
}.toWireTransaction()
|
||||
assertTrue(tx.inputs.isEmpty())
|
||||
assertEquals(tx.outputs[0], tx.outputs[0])
|
||||
}
|
||||
@ -250,8 +248,7 @@ class CashTests {
|
||||
var ptx = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
|
||||
Cash().generateIssue(ptx, 100.DOLLARS `issued by` MINI_CORP.ref(12, 34), owner = MINI_CORP, notary = DUMMY_NOTARY)
|
||||
ptx.signWith(MINI_CORP_KEY)
|
||||
val tx = ptx.toSignedTransaction()
|
||||
val tx = miniCorpServices.signInitialTransaction(ptx)
|
||||
|
||||
// Include the previously issued cash in a new issuance command
|
||||
ptx = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
|
@ -11,6 +11,7 @@ import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
import net.corda.core.utilities.*
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.node.MockServices
|
||||
import org.junit.Test
|
||||
import java.time.Duration
|
||||
import java.time.temporal.ChronoUnit
|
||||
@ -39,6 +40,8 @@ class ObligationTests {
|
||||
beneficiary = CHARLIE
|
||||
)
|
||||
val outState = inState.copy(beneficiary = AnonymousParty(DUMMY_PUBKEY_2))
|
||||
val miniCorpServices = MockServices(MINI_CORP_KEY)
|
||||
val notaryServices = MockServices(DUMMY_NOTARY_KEY)
|
||||
|
||||
private fun cashObligationTestRoots(
|
||||
group: LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>
|
||||
@ -125,8 +128,7 @@ class ObligationTests {
|
||||
val tx = TransactionType.General.Builder(notary = null).apply {
|
||||
Obligation<Currency>().generateIssue(this, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity,
|
||||
beneficiary = CHARLIE, notary = DUMMY_NOTARY)
|
||||
signWith(MINI_CORP_KEY)
|
||||
}.toSignedTransaction().tx
|
||||
}.toWireTransaction()
|
||||
assertTrue(tx.inputs.isEmpty())
|
||||
val expected = Obligation.State(
|
||||
obligor = MINI_CORP,
|
||||
@ -203,12 +205,12 @@ class ObligationTests {
|
||||
val tx = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
Obligation<Currency>().generateIssue(this, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity,
|
||||
beneficiary = MINI_CORP, notary = DUMMY_NOTARY)
|
||||
signWith(MINI_CORP_KEY)
|
||||
}.toSignedTransaction()
|
||||
}.toWireTransaction()
|
||||
|
||||
|
||||
// Include the previously issued obligation in a new issuance command
|
||||
val ptx = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
ptx.addInputState(tx.tx.outRef<Obligation.State<Currency>>(0))
|
||||
ptx.addInputState(tx.outRef<Obligation.State<Currency>>(0))
|
||||
Obligation<Currency>().generateIssue(ptx, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity,
|
||||
beneficiary = MINI_CORP, notary = DUMMY_NOTARY)
|
||||
}
|
||||
@ -220,9 +222,7 @@ class ObligationTests {
|
||||
val obligationBobToAlice = oneMillionDollars.OBLIGATION between Pair(BOB, ALICE)
|
||||
val tx = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
Obligation<Currency>().generateCloseOutNetting(this, ALICE, obligationAliceToBob, obligationBobToAlice)
|
||||
signWith(ALICE_KEY)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction().tx
|
||||
}.toWireTransaction()
|
||||
assertEquals(0, tx.outputs.size)
|
||||
}
|
||||
|
||||
@ -233,9 +233,7 @@ class ObligationTests {
|
||||
val obligationBobToAlice = oneMillionDollars.OBLIGATION between Pair(BOB, ALICE)
|
||||
val tx = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
Obligation<Currency>().generateCloseOutNetting(this, ALICE, obligationAliceToBob, obligationBobToAlice)
|
||||
signWith(ALICE_KEY)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction().tx
|
||||
}.toWireTransaction()
|
||||
assertEquals(1, tx.outputs.size)
|
||||
|
||||
val actual = tx.outputs[0].data
|
||||
@ -249,10 +247,7 @@ class ObligationTests {
|
||||
val obligationBobToAlice = oneMillionDollars.OBLIGATION between Pair(BOB, ALICE)
|
||||
val tx = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
Obligation<Currency>().generatePaymentNetting(this, obligationAliceToBob.amount.token, DUMMY_NOTARY, obligationAliceToBob, obligationBobToAlice)
|
||||
signWith(ALICE_KEY)
|
||||
signWith(BOB_KEY)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction().tx
|
||||
}.toWireTransaction()
|
||||
assertEquals(0, tx.outputs.size)
|
||||
}
|
||||
|
||||
@ -263,9 +258,7 @@ class ObligationTests {
|
||||
val obligationBobToAlice = (2000000.DOLLARS `issued by` defaultIssuer).OBLIGATION between Pair(BOB, ALICE)
|
||||
val tx = TransactionType.General.Builder(null).apply {
|
||||
Obligation<Currency>().generatePaymentNetting(this, obligationAliceToBob.amount.token, DUMMY_NOTARY, obligationAliceToBob, obligationBobToAlice)
|
||||
signWith(ALICE_KEY)
|
||||
signWith(BOB_KEY)
|
||||
}.toSignedTransaction().tx
|
||||
}.toWireTransaction()
|
||||
assertEquals(1, tx.outputs.size)
|
||||
val expected = obligationBobToAlice.copy(quantity = obligationBobToAlice.quantity - obligationAliceToBob.quantity)
|
||||
val actual = tx.outputs[0].data
|
||||
@ -282,30 +275,31 @@ class ObligationTests {
|
||||
var tx = TransactionType.General.Builder(null).apply {
|
||||
Obligation<Currency>().generateIssue(this, MINI_CORP, megaCorpDollarSettlement.copy(dueBefore = dueBefore), 100.DOLLARS.quantity,
|
||||
beneficiary = MINI_CORP, notary = DUMMY_NOTARY)
|
||||
signWith(MINI_CORP_KEY)
|
||||
}.toSignedTransaction()
|
||||
var stateAndRef = tx.tx.outRef<Obligation.State<Currency>>(0)
|
||||
}
|
||||
var stx = miniCorpServices.signInitialTransaction(tx)
|
||||
var stateAndRef = stx.tx.outRef<Obligation.State<Currency>>(0)
|
||||
|
||||
// Now generate a transaction marking the obligation as having defaulted
|
||||
tx = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
Obligation<Currency>().generateSetLifecycle(this, listOf(stateAndRef), Lifecycle.DEFAULTED, DUMMY_NOTARY)
|
||||
signWith(MINI_CORP_KEY)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
assertEquals(1, tx.tx.outputs.size)
|
||||
assertEquals(stateAndRef.state.data.copy(lifecycle = Lifecycle.DEFAULTED), tx.tx.outputs[0].data)
|
||||
tx.verifySignatures()
|
||||
}
|
||||
var ptx = miniCorpServices.signInitialTransaction(tx, MINI_CORP_PUBKEY)
|
||||
stx = notaryServices.addSignature(ptx)
|
||||
|
||||
assertEquals(1, stx.tx.outputs.size)
|
||||
assertEquals(stateAndRef.state.data.copy(lifecycle = Lifecycle.DEFAULTED), stx.tx.outputs[0].data)
|
||||
stx.verifySignatures()
|
||||
|
||||
// And set it back
|
||||
stateAndRef = tx.tx.outRef<Obligation.State<Currency>>(0)
|
||||
stateAndRef = stx.tx.outRef<Obligation.State<Currency>>(0)
|
||||
tx = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
Obligation<Currency>().generateSetLifecycle(this, listOf(stateAndRef), Lifecycle.NORMAL, DUMMY_NOTARY)
|
||||
signWith(MINI_CORP_KEY)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
assertEquals(1, tx.tx.outputs.size)
|
||||
assertEquals(stateAndRef.state.data.copy(lifecycle = Lifecycle.NORMAL), tx.tx.outputs[0].data)
|
||||
tx.verifySignatures()
|
||||
}
|
||||
ptx = miniCorpServices.signInitialTransaction(tx)
|
||||
stx = notaryServices.addSignature(ptx)
|
||||
assertEquals(1, stx.tx.outputs.size)
|
||||
assertEquals(stateAndRef.state.data.copy(lifecycle = Lifecycle.NORMAL), stx.tx.outputs[0].data)
|
||||
stx.verifySignatures()
|
||||
}
|
||||
|
||||
/** Test generating a transaction to settle an obligation. */
|
||||
@ -313,22 +307,18 @@ class ObligationTests {
|
||||
fun `generate settlement transaction`() {
|
||||
val cashTx = TransactionType.General.Builder(null).apply {
|
||||
Cash().generateIssue(this, 100.DOLLARS `issued by` defaultIssuer, MINI_CORP, DUMMY_NOTARY)
|
||||
signWith(MEGA_CORP_KEY)
|
||||
}.toSignedTransaction().tx
|
||||
}.toWireTransaction()
|
||||
|
||||
// Generate a transaction issuing the obligation
|
||||
val obligationTx = TransactionType.General.Builder(null).apply {
|
||||
Obligation<Currency>().generateIssue(this, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity,
|
||||
beneficiary = MINI_CORP, notary = DUMMY_NOTARY)
|
||||
signWith(MINI_CORP_KEY)
|
||||
}.toSignedTransaction().tx
|
||||
}.toWireTransaction()
|
||||
|
||||
// Now generate a transaction settling the obligation
|
||||
val settleTx = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
Obligation<Currency>().generateSettle(this, listOf(obligationTx.outRef(0)), listOf(cashTx.outRef(0)), Cash.Commands.Move(), DUMMY_NOTARY)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
signWith(MINI_CORP_KEY)
|
||||
}.toSignedTransaction().tx
|
||||
}.toWireTransaction()
|
||||
assertEquals(2, settleTx.inputs.size)
|
||||
assertEquals(1, settleTx.outputs.size)
|
||||
}
|
||||
@ -864,7 +854,7 @@ class ObligationTests {
|
||||
@Test
|
||||
fun `summing balances due between parties`() {
|
||||
val simple: Map<Pair<AbstractParty, AbstractParty>, Amount<Currency>> = mapOf(Pair(Pair(ALICE, BOB), Amount(100000000, GBP)))
|
||||
val expected: Map<AbstractParty, Long> = mapOf(Pair(ALICE, -100000000L), Pair(BOB, 100000000L))
|
||||
val expected: Map<AbstractParty, Long> = mapOf(Pair(ALICE, -100000000L), Pair(BOB, 100000000L))
|
||||
val actual = sumAmountsDue(simple)
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
@ -394,15 +394,16 @@ class NodeVaultServiceTest {
|
||||
|
||||
@Test
|
||||
fun addNoteToTransaction() {
|
||||
database.transaction {
|
||||
val megaCorpServices = MockServices(MEGA_CORP_KEY)
|
||||
|
||||
database.transaction {
|
||||
val freshKey = services.legalIdentityKey
|
||||
|
||||
// Issue a txn to Send us some Money
|
||||
val usefulTX = TransactionType.General.Builder(null).apply {
|
||||
val usefulBuilder = TransactionType.General.Builder(null).apply {
|
||||
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), AnonymousParty(freshKey), DUMMY_NOTARY)
|
||||
signWith(MEGA_CORP_KEY)
|
||||
}.toSignedTransaction()
|
||||
}
|
||||
val usefulTX = megaCorpServices.signInitialTransaction(usefulBuilder)
|
||||
|
||||
services.recordTransactions(listOf(usefulTX))
|
||||
|
||||
@ -412,10 +413,10 @@ class NodeVaultServiceTest {
|
||||
assertEquals(3, vaultSvc.getTransactionNotes(usefulTX.id).count())
|
||||
|
||||
// Issue more Money (GBP)
|
||||
val anotherTX = TransactionType.General.Builder(null).apply {
|
||||
val anotherBuilder = TransactionType.General.Builder(null).apply {
|
||||
Cash().generateIssue(this, 200.POUNDS `issued by` MEGA_CORP.ref(1), AnonymousParty(freshKey), DUMMY_NOTARY)
|
||||
signWith(MEGA_CORP_KEY)
|
||||
}.toSignedTransaction()
|
||||
}
|
||||
val anotherTX = megaCorpServices.signInitialTransaction(anotherBuilder)
|
||||
|
||||
services.recordTransactions(listOf(anotherTX))
|
||||
|
||||
|
@ -22,8 +22,7 @@ import net.corda.testing.MEGA_CORP
|
||||
import net.corda.testing.MEGA_CORP_KEY
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.makeTestDataSourceProperties
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.assertj.core.api.Assertions.*
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
@ -42,6 +41,7 @@ class VaultWithCashTest {
|
||||
val vault: VaultService get() = services.vaultService
|
||||
lateinit var dataSource: Closeable
|
||||
lateinit var database: Database
|
||||
val notaryServices = MockServices(DUMMY_NOTARY_KEY)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
@ -91,32 +91,32 @@ class VaultWithCashTest {
|
||||
|
||||
@Test
|
||||
fun `issue and spend total correctly and irrelevant ignored`() {
|
||||
val megaCorpServices = MockServices(MEGA_CORP_KEY)
|
||||
|
||||
database.transaction {
|
||||
// A tx that sends us money.
|
||||
val freshKey = services.keyManagementService.freshKey()
|
||||
val usefulTX = TransactionType.General.Builder(null).apply {
|
||||
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), AnonymousParty(freshKey), DUMMY_NOTARY)
|
||||
signWith(MEGA_CORP_KEY)
|
||||
}.toSignedTransaction()
|
||||
val usefulBuilder = TransactionType.General.Builder(null)
|
||||
Cash().generateIssue(usefulBuilder, 100.DOLLARS `issued by` MEGA_CORP.ref(1), AnonymousParty(freshKey), DUMMY_NOTARY)
|
||||
val usefulTX = megaCorpServices.signInitialTransaction(usefulBuilder)
|
||||
|
||||
assertNull(vault.cashBalances[USD])
|
||||
services.recordTransactions(usefulTX)
|
||||
|
||||
// A tx that spends our money.
|
||||
val spendTXBuilder = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
vault.generateSpend(this, 80.DOLLARS, BOB)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}
|
||||
val spendTX = services.signInitialTransaction(spendTXBuilder, freshKey)
|
||||
val spendTXBuilder = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
vault.generateSpend(spendTXBuilder, 80.DOLLARS, BOB)
|
||||
val spendPTX = services.signInitialTransaction(spendTXBuilder, freshKey)
|
||||
val spendTX = notaryServices.addSignature(spendPTX)
|
||||
|
||||
assertEquals(100.DOLLARS, vault.cashBalances[USD])
|
||||
|
||||
// A tx that doesn't send us anything.
|
||||
val irrelevantTX = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), BOB, DUMMY_NOTARY)
|
||||
signWith(MEGA_CORP_KEY)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
val irrelevantBuilder = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
Cash().generateIssue(irrelevantBuilder, 100.DOLLARS `issued by` MEGA_CORP.ref(1), BOB, DUMMY_NOTARY)
|
||||
|
||||
val irrelevantPTX = megaCorpServices.signInitialTransaction(irrelevantBuilder)
|
||||
val irrelevantTX = notaryServices.addSignature(irrelevantPTX)
|
||||
|
||||
services.recordTransactions(irrelevantTX)
|
||||
assertEquals(100.DOLLARS, vault.cashBalances[USD])
|
||||
@ -150,12 +150,10 @@ class VaultWithCashTest {
|
||||
backgroundExecutor.submit {
|
||||
database.transaction {
|
||||
try {
|
||||
val txn1Builder =
|
||||
TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
vault.generateSpend(this, 60.DOLLARS, BOB)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}
|
||||
val txn1 = services.signInitialTransaction(txn1Builder, freshKey)
|
||||
val txn1Builder = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
vault.generateSpend(txn1Builder, 60.DOLLARS, BOB)
|
||||
val ptxn1 = notaryServices.signInitialTransaction(txn1Builder)
|
||||
val txn1 = services.addSignature(ptxn1, freshKey)
|
||||
println("txn1: ${txn1.id} spent ${((txn1.tx.outputs[0].data) as Cash.State).amount}")
|
||||
println("""txn1 states:
|
||||
UNCONSUMED: ${vault.unconsumedStates<Cash.State>().count()} : ${vault.unconsumedStates<Cash.State>()},
|
||||
@ -182,12 +180,10 @@ class VaultWithCashTest {
|
||||
backgroundExecutor.submit {
|
||||
database.transaction {
|
||||
try {
|
||||
val txn2Builder =
|
||||
TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
vault.generateSpend(this, 80.DOLLARS, BOB)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}
|
||||
val txn2 = services.signInitialTransaction(txn2Builder, freshKey)
|
||||
val txn2Builder = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
vault.generateSpend(txn2Builder, 80.DOLLARS, BOB)
|
||||
val ptxn2 = notaryServices.signInitialTransaction(txn2Builder)
|
||||
val txn2 = services.addSignature(ptxn2, freshKey)
|
||||
println("txn2: ${txn2.id} spent ${((txn2.tx.outputs[0].data) as Cash.State).amount}")
|
||||
println("""txn2 states:
|
||||
UNCONSUMED: ${vault.unconsumedStates<Cash.State>().count()} : ${vault.unconsumedStates<Cash.State>()},
|
||||
@ -229,9 +225,8 @@ class VaultWithCashTest {
|
||||
val dummyIssueBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)))
|
||||
addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)))
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}
|
||||
val dummyIssue = services.signInitialTransaction(dummyIssueBuilder)
|
||||
val dummyIssue = notaryServices.signInitialTransaction(dummyIssueBuilder)
|
||||
|
||||
assertThatThrownBy {
|
||||
dummyIssue.toLedgerTransaction(services).verify()
|
||||
@ -248,11 +243,10 @@ class VaultWithCashTest {
|
||||
val linearId = UniqueIdentifier()
|
||||
|
||||
// Issue a linear state
|
||||
val dummyIssueBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)))
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}
|
||||
val dummyIssue = services.signInitialTransaction(dummyIssueBuilder, services.legalIdentityKey)
|
||||
val dummyIssueBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY)
|
||||
dummyIssueBuilder.addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)))
|
||||
val dummyIssuePtx = notaryServices.signInitialTransaction(dummyIssueBuilder)
|
||||
val dummyIssue = services.addSignature(dummyIssuePtx)
|
||||
|
||||
dummyIssue.toLedgerTransaction(services).verify()
|
||||
|
||||
@ -260,11 +254,12 @@ class VaultWithCashTest {
|
||||
assertThat(vault.unconsumedStates<DummyLinearContract.State>()).hasSize(1)
|
||||
|
||||
// Move the same state
|
||||
val dummyMove = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
val dummyMoveBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)))
|
||||
addInputState(dummyIssue.tx.outRef<LinearState>(0))
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
}
|
||||
|
||||
val dummyMove = notaryServices.signInitialTransaction(dummyMoveBuilder)
|
||||
|
||||
dummyIssue.toLedgerTransaction(services).verify()
|
||||
|
||||
@ -291,11 +286,10 @@ class VaultWithCashTest {
|
||||
|
||||
database.transaction {
|
||||
// A tx that spends our money.
|
||||
val spendTXBuilder = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
vault.generateSpend(this, 80.DOLLARS, BOB)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}
|
||||
val spendTX = services.signInitialTransaction(spendTXBuilder, freshKey)
|
||||
val spendTXBuilder = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
vault.generateSpend(spendTXBuilder, 80.DOLLARS, BOB)
|
||||
val spendPTX = notaryServices.signInitialTransaction(spendTXBuilder)
|
||||
val spendTX = services.addSignature(spendPTX, freshKey)
|
||||
services.recordTransactions(spendTX)
|
||||
|
||||
val consumedStates = vault.consumedStates<ContractState>()
|
||||
@ -322,13 +316,14 @@ class VaultWithCashTest {
|
||||
linearStates.forEach { println(it.state.data.linearId) }
|
||||
|
||||
// Create a txn consuming different contract types
|
||||
val dummyMove = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
val dummyMoveBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
addOutputState(DummyLinearContract.State(participants = listOf(freshIdentity)))
|
||||
addOutputState(DummyDealContract.State(ref = "999", participants = listOf(freshIdentity)))
|
||||
addInputState(linearStates.first())
|
||||
addInputState(deals.first())
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
}
|
||||
|
||||
val dummyMove = notaryServices.signInitialTransaction(dummyMoveBuilder)
|
||||
|
||||
dummyMove.toLedgerTransaction(services).verify()
|
||||
services.recordTransactions(dummyMove)
|
||||
|
@ -108,11 +108,9 @@ class AttachmentDemoFlow(val otherSide: Party, val hash: SecureHash.SHA256) : Fl
|
||||
ptx.addAttachment(hash)
|
||||
|
||||
progressTracker.currentStep = SIGNING
|
||||
// Sign with the notary key
|
||||
ptx.signWith(DUMMY_NOTARY_KEY)
|
||||
|
||||
// Send the transaction to the other recipient
|
||||
val stx = ptx.toSignedTransaction()
|
||||
val stx = serviceHub.signInitialTransaction(ptx)
|
||||
|
||||
return subFlow(FinalityFlow(stx, setOf(otherSide))).single()
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ open class RatesFixFlow(protected val tx: TransactionBuilder,
|
||||
val resp = sendAndReceive<DigitalSignature.LegallyIdentifiable>(oracle, SignRequest(partialMerkleTx))
|
||||
return resp.unwrap { sig ->
|
||||
check(sig.signer == oracle)
|
||||
tx.checkSignature(sig)
|
||||
tx.toWireTransaction().checkSignature(sig)
|
||||
sig
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ class NodeInterestRatesTest {
|
||||
val wtx = tx.toWireTransaction()
|
||||
val ftx = wtx.buildFilteredTransaction(Predicate { x -> fixCmdFilter(x) })
|
||||
val signature = oracle.sign(ftx)
|
||||
tx.checkAndAddSignature(signature)
|
||||
wtx.checkSignature(signature)
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,8 +228,8 @@ class NodeInterestRatesTest {
|
||||
val future = n1.services.startFlow(flow).resultFuture
|
||||
mockNet.runNetwork()
|
||||
future.getOrThrow()
|
||||
// We should now have a valid signature over our tx from the oracle.
|
||||
val fix = tx.toSignedTransaction(true).tx.commands.map { it.value as Fix }.first()
|
||||
// We should now have a valid fix of our tx from the oracle.
|
||||
val fix = tx.toWireTransaction().commands.map { it.value as Fix }.first()
|
||||
assertEquals(fixOf, fix.of)
|
||||
assertEquals("0.678".bd, fix.value)
|
||||
}
|
||||
|
@ -201,6 +201,10 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
|
||||
}
|
||||
|
||||
class IRSTests {
|
||||
val megaCorpServices = MockServices(MEGA_CORP_KEY)
|
||||
val miniCorpServices = MockServices(MINI_CORP_KEY)
|
||||
val notaryServices = MockServices(DUMMY_NOTARY_KEY)
|
||||
|
||||
@Test
|
||||
fun ok() {
|
||||
trade().verifies()
|
||||
@ -224,11 +228,10 @@ class IRSTests {
|
||||
common = dummyIRS.common,
|
||||
notary = DUMMY_NOTARY).apply {
|
||||
addTimeWindow(TEST_TX_TIME, 30.seconds)
|
||||
signWith(MEGA_CORP_KEY)
|
||||
signWith(MINI_CORP_KEY)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}
|
||||
gtx.toSignedTransaction()
|
||||
val ptx1 = megaCorpServices.signInitialTransaction(gtx)
|
||||
val ptx2 = miniCorpServices.addSignature(ptx1)
|
||||
notaryServices.addSignature(ptx2)
|
||||
}
|
||||
return genTX
|
||||
}
|
||||
@ -308,13 +311,10 @@ class IRSTests {
|
||||
val tx = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
val fixing = Fix(nextFix, "0.052".percent.value)
|
||||
InterestRateSwap().generateFix(tx, previousTXN.tx.outRef(0), fixing)
|
||||
with(tx) {
|
||||
addTimeWindow(TEST_TX_TIME, 30.seconds)
|
||||
signWith(MEGA_CORP_KEY)
|
||||
signWith(MINI_CORP_KEY)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}
|
||||
tx.toSignedTransaction()
|
||||
tx.addTimeWindow(TEST_TX_TIME, 30.seconds)
|
||||
val ptx1 = megaCorpServices.signInitialTransaction(tx)
|
||||
val ptx2 = miniCorpServices.addSignature(ptx1)
|
||||
notaryServices.addSignature(ptx2)
|
||||
}
|
||||
fixTX.toLedgerTransaction(services).verify()
|
||||
services.recordTransactions(fixTX)
|
||||
|
@ -16,6 +16,7 @@ import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.seconds
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.flows.FinalityFlow
|
||||
import net.corda.flows.NotaryFlow
|
||||
import net.corda.flows.TwoPartyTradeFlow
|
||||
import net.corda.testing.BOC
|
||||
@ -69,8 +70,7 @@ class SellerFlow(val otherParty: Party,
|
||||
@Suspendable
|
||||
fun selfIssueSomeCommercialPaper(ownedBy: AbstractParty, notaryNode: NodeInfo): StateAndRef<CommercialPaper.State> {
|
||||
// Make a fake company that's issued its own paper.
|
||||
val keyPair = generateKeyPair()
|
||||
val party = Party(BOC.name, keyPair.public)
|
||||
val party = Party(BOC.name, serviceHub.legalIdentityKey)
|
||||
|
||||
val issuance: SignedTransaction = run {
|
||||
val tx = CommercialPaper().generateIssue(party.ref(1, 2, 3), 1100.DOLLARS `issued by` DUMMY_CASH_ISSUER,
|
||||
@ -85,29 +85,17 @@ class SellerFlow(val otherParty: Party,
|
||||
tx.addTimeWindow(Instant.now(), 30.seconds)
|
||||
|
||||
// Sign it as ourselves.
|
||||
tx.signWith(keyPair)
|
||||
val stx = serviceHub.signInitialTransaction(tx)
|
||||
|
||||
// Get the notary to sign the time-window.
|
||||
val notarySigs = subFlow(NotaryFlow.Client(tx.toSignedTransaction(false)))
|
||||
notarySigs.forEach { tx.addSignatureUnchecked(it) }
|
||||
|
||||
// Commit it to local storage.
|
||||
val stx = tx.toSignedTransaction(true)
|
||||
serviceHub.recordTransactions(listOf(stx))
|
||||
|
||||
stx
|
||||
subFlow(FinalityFlow(stx)).single()
|
||||
}
|
||||
|
||||
// Now make a dummy transaction that moves it to a new key, just to show that resolving dependencies works.
|
||||
val move: SignedTransaction = run {
|
||||
val builder = TransactionType.General.Builder(notaryNode.notaryIdentity)
|
||||
CommercialPaper().generateMove(builder, issuance.tx.outRef(0), ownedBy)
|
||||
builder.signWith(keyPair)
|
||||
val notarySignature = subFlow(NotaryFlow.Client(builder.toSignedTransaction(false)))
|
||||
notarySignature.forEach { builder.addSignatureUnchecked(it) }
|
||||
val tx = builder.toSignedTransaction(true)
|
||||
serviceHub.recordTransactions(listOf(tx))
|
||||
tx
|
||||
val stx = serviceHub.signInitialTransaction(builder)
|
||||
subFlow(FinalityFlow(stx)).single()
|
||||
}
|
||||
|
||||
return move.tx.outRef(0)
|
||||
|
@ -53,6 +53,8 @@ import java.util.concurrent.atomic.AtomicInteger
|
||||
* - The Int.DOLLARS syntax doesn't work from Java. Use the DOLLARS(int) function instead.
|
||||
*/
|
||||
|
||||
// TODO: Refactor these dummies to work with the new identities framework.
|
||||
|
||||
// A few dummy values for testing.
|
||||
val MEGA_CORP_KEY: KeyPair by lazy { generateKeyPair() }
|
||||
val MEGA_CORP_PUBKEY: PublicKey get() = MEGA_CORP_KEY.public
|
||||
|
@ -139,7 +139,6 @@ data class TestTransactionDSLInterpreter private constructor(
|
||||
// Verify on a copy of the transaction builder, so if it's then further modified it doesn't error due to
|
||||
// the existing signature
|
||||
transactionBuilder.copy().apply {
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
toWireTransaction().toLedgerTransaction(services).verify()
|
||||
}
|
||||
return EnforceVerifyOrFail.Token
|
||||
|
@ -14,6 +14,7 @@ import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.flows.FinalityFlow
|
||||
import net.corda.loadtest.LoadTest
|
||||
import net.corda.loadtest.NodeConnection
|
||||
import net.corda.testing.node.MockServices
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
private val log = LoggerFactory.getLogger("NotaryTest")
|
||||
@ -23,16 +24,15 @@ data class NotariseCommand(val issueTx: SignedTransaction, val moveTx: SignedTra
|
||||
val dummyNotarisationTest = LoadTest<NotariseCommand, Unit>(
|
||||
"Notarising dummy transactions",
|
||||
generate = { _, _ ->
|
||||
val issuerServices = MockServices(DUMMY_CASH_ISSUER_KEY)
|
||||
val generateTx = Generator.pickOne(simpleNodes).bind { node ->
|
||||
Generator.int().map {
|
||||
val issueTx = DummyContract.generateInitial(it, notary.info.notaryIdentity, DUMMY_CASH_ISSUER).apply {
|
||||
signWith(DUMMY_CASH_ISSUER_KEY)
|
||||
}
|
||||
val asset = issueTx.toWireTransaction().outRef<DummyContract.SingleOwnerState>(0)
|
||||
val moveTx = DummyContract.move(asset, DUMMY_CASH_ISSUER.party).apply {
|
||||
signWith(DUMMY_CASH_ISSUER_KEY)
|
||||
}
|
||||
NotariseCommand(issueTx.toSignedTransaction(false), moveTx.toSignedTransaction(false), node)
|
||||
val issueBuilder = DummyContract.generateInitial(it, notary.info.notaryIdentity, DUMMY_CASH_ISSUER)
|
||||
val issueTx = issuerServices.signInitialTransaction(issueBuilder)
|
||||
val asset = issueTx.tx.outRef<DummyContract.SingleOwnerState>(0)
|
||||
val moveBuilder = DummyContract.move(asset, DUMMY_CASH_ISSUER.party)
|
||||
val moveTx = issuerServices.signInitialTransaction(moveBuilder)
|
||||
NotariseCommand(issueTx, moveTx, node)
|
||||
}
|
||||
}
|
||||
Generator.replicate(10, generateTx)
|
||||
|
Loading…
Reference in New Issue
Block a user