mirror of
https://github.com/corda/corda.git
synced 2025-06-06 01:11:45 +00:00
Merged in mike-ledgertx-refactoring-part-2 (pull request #260)
More simplifications to unit testing, introduce UnitTestServices
This commit is contained in:
commit
918de94a22
@ -2,6 +2,8 @@
|
|||||||
package com.r3corda.contracts.testing
|
package com.r3corda.contracts.testing
|
||||||
|
|
||||||
import com.r3corda.contracts.asset.Cash
|
import com.r3corda.contracts.asset.Cash
|
||||||
|
import com.r3corda.contracts.asset.DUMMY_CASH_ISSUER
|
||||||
|
import com.r3corda.contracts.asset.DUMMY_CASH_ISSUER_KEY
|
||||||
import com.r3corda.core.contracts.Amount
|
import com.r3corda.core.contracts.Amount
|
||||||
import com.r3corda.core.contracts.Issued
|
import com.r3corda.core.contracts.Issued
|
||||||
import com.r3corda.core.contracts.SignedTransaction
|
import com.r3corda.core.contracts.SignedTransaction
|
||||||
@ -11,16 +13,14 @@ import com.r3corda.core.node.ServiceHub
|
|||||||
import com.r3corda.core.node.services.Wallet
|
import com.r3corda.core.node.services.Wallet
|
||||||
import com.r3corda.core.serialization.OpaqueBytes
|
import com.r3corda.core.serialization.OpaqueBytes
|
||||||
import com.r3corda.core.testing.DUMMY_NOTARY
|
import com.r3corda.core.testing.DUMMY_NOTARY
|
||||||
|
import java.security.PublicKey
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a random set of between (by default) 3 and 10 cash states that add up to the given amount and adds them
|
* 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 wallet. This is intended for unit tests.
|
* to the wallet. This is intended for unit tests. The cash is issued by [DUMMY_CASH_ISSUER] and owned by the legal
|
||||||
*
|
* identity key from the storage service.
|
||||||
* The cash is self issued with the current nodes identity, as fetched from the storage service. Thus it
|
|
||||||
* would not be trusted by any sensible market participant and is effectively an IOU. If it had been issued by
|
|
||||||
* the central bank, well ... that'd be a different story altogether.
|
|
||||||
*
|
*
|
||||||
* The service hub needs to provide at least a key management service and a storage service.
|
* The service hub needs to provide at least a key management service and a storage service.
|
||||||
*
|
*
|
||||||
@ -31,23 +31,18 @@ fun ServiceHub.fillWithSomeTestCash(howMuch: Amount<Currency>,
|
|||||||
atLeastThisManyStates: Int = 3,
|
atLeastThisManyStates: Int = 3,
|
||||||
atMostThisManyStates: Int = 10,
|
atMostThisManyStates: Int = 10,
|
||||||
rng: Random = Random(),
|
rng: Random = Random(),
|
||||||
ref: OpaqueBytes = OpaqueBytes(ByteArray(1, { 0 }))): Wallet {
|
ref: OpaqueBytes = OpaqueBytes(ByteArray(1, { 1 })),
|
||||||
|
ownedBy: PublicKey? = null): Wallet {
|
||||||
val amounts = calculateRandomlySizedAmounts(howMuch, atLeastThisManyStates, atMostThisManyStates, rng)
|
val amounts = calculateRandomlySizedAmounts(howMuch, atLeastThisManyStates, atMostThisManyStates, rng)
|
||||||
|
|
||||||
val myIdentity = storageService.myLegalIdentity
|
val myKey: PublicKey = ownedBy ?: storageService.myLegalIdentityKey.public
|
||||||
val myKey = storageService.myLegalIdentityKey
|
|
||||||
|
|
||||||
// We will allocate one state to one transaction, for simplicities sake.
|
// We will allocate one state to one transaction, for simplicities sake.
|
||||||
val cash = Cash()
|
val cash = Cash()
|
||||||
val transactions: List<SignedTransaction> = amounts.map { pennies ->
|
val transactions: List<SignedTransaction> = amounts.map { pennies ->
|
||||||
// This line is what makes the cash self issued. We just use zero as our deposit reference: we don't need
|
|
||||||
// this field as there's no other database or source of truth we need to sync with.
|
|
||||||
val depositRef = myIdentity.ref(ref)
|
|
||||||
|
|
||||||
val issuance = TransactionType.General.Builder()
|
val issuance = TransactionType.General.Builder()
|
||||||
val freshKey = keyManagementService.freshKey()
|
cash.generateIssue(issuance, Amount(pennies, Issued(DUMMY_CASH_ISSUER.copy(reference = ref), howMuch.token)), myKey, notary)
|
||||||
cash.generateIssue(issuance, Amount(pennies, Issued(depositRef, howMuch.token)), freshKey.public, notary)
|
issuance.signWith(DUMMY_CASH_ISSUER_KEY)
|
||||||
issuance.signWith(myKey)
|
|
||||||
|
|
||||||
return@map issuance.toSignedTransaction(true)
|
return@map issuance.toSignedTransaction(true)
|
||||||
}
|
}
|
||||||
@ -77,7 +72,7 @@ private fun calculateRandomlySizedAmounts(howMuch: Amount<Currency>, min: Int, m
|
|||||||
// Handle inexact rounding.
|
// Handle inexact rounding.
|
||||||
amounts[i] = howMuch.quantity - filledSoFar
|
amounts[i] = howMuch.quantity - filledSoFar
|
||||||
}
|
}
|
||||||
check(amounts[i] >= 0) { amounts[i] }
|
check(amounts[i] >= 0) { "${amounts[i]} : $filledSoFar : $howMuch" }
|
||||||
}
|
}
|
||||||
check(amounts.sum() == howMuch.quantity)
|
check(amounts.sum() == howMuch.quantity)
|
||||||
return amounts
|
return amounts
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
package com.r3corda.core.node.services.testing
|
package com.r3corda.core.node.services.testing
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.r3corda.core.contracts.Attachment
|
import com.r3corda.core.contracts.Attachment
|
||||||
import com.r3corda.core.contracts.SignedTransaction
|
import com.r3corda.core.contracts.SignedTransaction
|
||||||
import com.r3corda.core.crypto.Party
|
import com.r3corda.core.crypto.Party
|
||||||
import com.r3corda.core.crypto.SecureHash
|
import com.r3corda.core.crypto.SecureHash
|
||||||
import com.r3corda.core.crypto.generateKeyPair
|
import com.r3corda.core.crypto.generateKeyPair
|
||||||
import com.r3corda.core.crypto.sha256
|
import com.r3corda.core.crypto.sha256
|
||||||
|
import com.r3corda.core.messaging.MessagingService
|
||||||
|
import com.r3corda.core.node.ServiceHub
|
||||||
import com.r3corda.core.node.services.*
|
import com.r3corda.core.node.services.*
|
||||||
|
import com.r3corda.core.protocols.ProtocolLogic
|
||||||
import com.r3corda.core.serialization.SingletonSerializeAsToken
|
import com.r3corda.core.serialization.SingletonSerializeAsToken
|
||||||
|
import com.r3corda.core.testing.DUMMY_NOTARY
|
||||||
|
import com.r3corda.core.testing.MEGA_CORP
|
||||||
|
import com.r3corda.core.testing.MINI_CORP
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -15,10 +22,40 @@ import java.io.InputStream
|
|||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.PrivateKey
|
import java.security.PrivateKey
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
import java.time.Clock
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.jar.JarInputStream
|
import java.util.jar.JarInputStream
|
||||||
import javax.annotation.concurrent.ThreadSafe
|
import javax.annotation.concurrent.ThreadSafe
|
||||||
|
|
||||||
|
// TODO: We need a single, rationalised unit testing environment that is usable for everything. Fix this!
|
||||||
|
// That means it probably shouldn't be in the 'core' module, which lacks enough code to create a realistic test env.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A singleton utility that only provides a mock identity, key and storage service. However, this is sufficient for
|
||||||
|
* building chains of transactions and verifying them. It isn't sufficient for testing protocols however.
|
||||||
|
*/
|
||||||
|
open class MockServices(val key: KeyPair = generateKeyPair()) : ServiceHub {
|
||||||
|
override fun <T : Any> invokeProtocolAsync(logicType: Class<out ProtocolLogic<T>>, vararg args: Any?): ListenableFuture<T> {
|
||||||
|
throw UnsupportedOperationException("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
||||||
|
for (stx in txs) {
|
||||||
|
storageService.validatedTransactions.addTransaction(stx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val storageService: TxWritableStorageService = MockStorageService(myLegalIdentityKey = key)
|
||||||
|
override val identityService: MockIdentityService = MockIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY))
|
||||||
|
override val keyManagementService: MockKeyManagementService = MockKeyManagementService(key)
|
||||||
|
|
||||||
|
override val walletService: WalletService get() = throw UnsupportedOperationException()
|
||||||
|
override val networkService: MessagingService get() = throw UnsupportedOperationException()
|
||||||
|
override val networkMapCache: NetworkMapCache get() = throw UnsupportedOperationException()
|
||||||
|
override val clock: Clock get() = throw UnsupportedOperationException()
|
||||||
|
override val schedulerService: SchedulerService get() = throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
class MockIdentityService(val identities: List<Party>) : IdentityService, SingletonSerializeAsToken() {
|
class MockIdentityService(val identities: List<Party>) : IdentityService, SingletonSerializeAsToken() {
|
||||||
private val keyToParties: Map<PublicKey, Party>
|
private val keyToParties: Map<PublicKey, Party>
|
||||||
|
@ -4,14 +4,12 @@ package com.r3corda.core.testing
|
|||||||
|
|
||||||
import com.google.common.base.Throwables
|
import com.google.common.base.Throwables
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import com.r3corda.core.contracts.Attachment
|
|
||||||
import com.r3corda.core.contracts.StateRef
|
import com.r3corda.core.contracts.StateRef
|
||||||
import com.r3corda.core.contracts.TransactionBuilder
|
import com.r3corda.core.contracts.TransactionBuilder
|
||||||
import com.r3corda.core.crypto.*
|
import com.r3corda.core.crypto.*
|
||||||
import com.r3corda.core.node.services.IdentityService
|
import com.r3corda.core.node.ServiceHub
|
||||||
import com.r3corda.core.node.services.StorageService
|
|
||||||
import com.r3corda.core.node.services.testing.MockIdentityService
|
import com.r3corda.core.node.services.testing.MockIdentityService
|
||||||
import com.r3corda.core.node.services.testing.MockStorageService
|
import com.r3corda.core.node.services.testing.MockServices
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.net.ServerSocket
|
import java.net.ServerSocket
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
@ -95,17 +93,14 @@ fun freeLocalHostAndPort(): HostAndPort {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and tests a ledger built by the passed in dsl.
|
* Creates and tests a ledger built by the passed in dsl. The provided services can be customised, otherwise a default
|
||||||
* @param identityService: The [IdentityService] to be used while building the ledger.
|
* of a freshly built [MockServices] is used.
|
||||||
* @param storageService: The [StorageService] to be used for storing e.g. [Attachment]s.
|
|
||||||
* @param dsl: The dsl building the ledger.
|
|
||||||
*/
|
*/
|
||||||
@JvmOverloads fun ledger(
|
@JvmOverloads fun ledger(
|
||||||
identityService: IdentityService = MOCK_IDENTITY_SERVICE,
|
services: ServiceHub = MockServices(),
|
||||||
storageService: StorageService = MockStorageService(),
|
|
||||||
dsl: LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.() -> Unit
|
dsl: LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.() -> Unit
|
||||||
): LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter> {
|
): LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter> {
|
||||||
val ledgerDsl = LedgerDSL(TestLedgerDSLInterpreter(identityService, storageService))
|
val ledgerDsl = LedgerDSL(TestLedgerDSLInterpreter(services))
|
||||||
dsl(ledgerDsl)
|
dsl(ledgerDsl)
|
||||||
return ledgerDsl
|
return ledgerDsl
|
||||||
}
|
}
|
||||||
|
@ -40,11 +40,13 @@ interface Verifies {
|
|||||||
val exceptionMessage = exception.message
|
val exceptionMessage = exception.message
|
||||||
if (exceptionMessage == null) {
|
if (exceptionMessage == null) {
|
||||||
throw AssertionError(
|
throw AssertionError(
|
||||||
"Expected exception containing '$expectedMessage' but raised exception had no message"
|
"Expected exception containing '$expectedMessage' but raised exception had no message",
|
||||||
|
exception
|
||||||
)
|
)
|
||||||
} else if (!exceptionMessage.toLowerCase().contains(expectedMessage.toLowerCase())) {
|
} else if (!exceptionMessage.toLowerCase().contains(expectedMessage.toLowerCase())) {
|
||||||
throw AssertionError(
|
throw AssertionError(
|
||||||
"Expected exception containing '$expectedMessage' but raised exception was '$exception'"
|
"Expected exception containing '$expectedMessage' but raised exception was '$exception'",
|
||||||
|
exception
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,7 @@ import com.r3corda.core.crypto.DigitalSignature
|
|||||||
import com.r3corda.core.crypto.Party
|
import com.r3corda.core.crypto.Party
|
||||||
import com.r3corda.core.crypto.SecureHash
|
import com.r3corda.core.crypto.SecureHash
|
||||||
import com.r3corda.core.crypto.signWithECDSA
|
import com.r3corda.core.crypto.signWithECDSA
|
||||||
import com.r3corda.core.node.services.IdentityService
|
import com.r3corda.core.node.ServiceHub
|
||||||
import com.r3corda.core.node.services.StorageService
|
|
||||||
import com.r3corda.core.serialization.serialize
|
import com.r3corda.core.serialization.serialize
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
@ -95,6 +94,10 @@ data class TestTransactionDSLInterpreter private constructor(
|
|||||||
transactionBuilder: TransactionBuilder
|
transactionBuilder: TransactionBuilder
|
||||||
) : this(ledgerInterpreter, transactionBuilder, HashMap())
|
) : this(ledgerInterpreter, transactionBuilder, HashMap())
|
||||||
|
|
||||||
|
val services = object : ServiceHub by ledgerInterpreter.services {
|
||||||
|
override fun loadState(stateRef: StateRef) = ledgerInterpreter.resolveStateRef<ContractState>(stateRef)
|
||||||
|
}
|
||||||
|
|
||||||
private fun copy(): TestTransactionDSLInterpreter =
|
private fun copy(): TestTransactionDSLInterpreter =
|
||||||
TestTransactionDSLInterpreter(
|
TestTransactionDSLInterpreter(
|
||||||
ledgerInterpreter = ledgerInterpreter,
|
ledgerInterpreter = ledgerInterpreter,
|
||||||
@ -141,18 +144,15 @@ data class TestTransactionDSLInterpreter private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class TestLedgerDSLInterpreter private constructor (
|
data class TestLedgerDSLInterpreter private constructor (
|
||||||
private val identityService: IdentityService,
|
val services: ServiceHub,
|
||||||
private val storageService: StorageService,
|
|
||||||
internal val labelToOutputStateAndRefs: HashMap<String, StateAndRef<ContractState>> = HashMap(),
|
internal val labelToOutputStateAndRefs: HashMap<String, StateAndRef<ContractState>> = HashMap(),
|
||||||
private val transactionWithLocations: HashMap<SecureHash, WireTransactionWithLocation> = HashMap(),
|
private val transactionWithLocations: HashMap<SecureHash, WireTransactionWithLocation> = LinkedHashMap(),
|
||||||
private val nonVerifiedTransactionWithLocations: HashMap<SecureHash, WireTransactionWithLocation> = HashMap()
|
private val nonVerifiedTransactionWithLocations: HashMap<SecureHash, WireTransactionWithLocation> = HashMap()
|
||||||
) : LedgerDSLInterpreter<TestTransactionDSLInterpreter> {
|
) : LedgerDSLInterpreter<TestTransactionDSLInterpreter> {
|
||||||
val wireTransactions: List<WireTransaction> get() = transactionWithLocations.values.map { it.transaction }
|
val wireTransactions: List<WireTransaction> get() = transactionWithLocations.values.map { it.transaction }
|
||||||
|
|
||||||
// We specify [labelToOutputStateAndRefs] just so that Kotlin picks the primary constructor instead of cycling
|
// We specify [labelToOutputStateAndRefs] just so that Kotlin picks the primary constructor instead of cycling
|
||||||
constructor(identityService: IdentityService, storageService: StorageService) : this(
|
constructor(services: ServiceHub) : this(services, labelToOutputStateAndRefs = HashMap())
|
||||||
identityService, storageService, labelToOutputStateAndRefs = HashMap()
|
|
||||||
)
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun getCallerLocation(): String? {
|
private fun getCallerLocation(): String? {
|
||||||
@ -179,8 +179,7 @@ data class TestLedgerDSLInterpreter private constructor (
|
|||||||
|
|
||||||
internal fun copy(): TestLedgerDSLInterpreter =
|
internal fun copy(): TestLedgerDSLInterpreter =
|
||||||
TestLedgerDSLInterpreter(
|
TestLedgerDSLInterpreter(
|
||||||
identityService,
|
services,
|
||||||
storageService,
|
|
||||||
labelToOutputStateAndRefs = HashMap(labelToOutputStateAndRefs),
|
labelToOutputStateAndRefs = HashMap(labelToOutputStateAndRefs),
|
||||||
transactionWithLocations = HashMap(transactionWithLocations),
|
transactionWithLocations = HashMap(transactionWithLocations),
|
||||||
nonVerifiedTransactionWithLocations = HashMap(nonVerifiedTransactionWithLocations)
|
nonVerifiedTransactionWithLocations = HashMap(nonVerifiedTransactionWithLocations)
|
||||||
@ -189,7 +188,7 @@ data class TestLedgerDSLInterpreter private constructor (
|
|||||||
internal fun resolveWireTransaction(wireTransaction: WireTransaction): TransactionForVerification {
|
internal fun resolveWireTransaction(wireTransaction: WireTransaction): TransactionForVerification {
|
||||||
return wireTransaction.run {
|
return wireTransaction.run {
|
||||||
val authenticatedCommands = commands.map {
|
val authenticatedCommands = commands.map {
|
||||||
AuthenticatedObject(it.signers, it.signers.mapNotNull { identityService.partyFromKey(it) }, it.value)
|
AuthenticatedObject(it.signers, it.signers.mapNotNull { services.identityService.partyFromKey(it) }, it.value)
|
||||||
}
|
}
|
||||||
val resolvedInputStates = inputs.map { resolveStateRef<ContractState>(it) }
|
val resolvedInputStates = inputs.map { resolveStateRef<ContractState>(it) }
|
||||||
val resolvedAttachments = attachments.map { resolveAttachment(it) }
|
val resolvedAttachments = attachments.map { resolveAttachment(it) }
|
||||||
@ -220,7 +219,7 @@ data class TestLedgerDSLInterpreter private constructor (
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun resolveAttachment(attachmentId: SecureHash): Attachment =
|
internal fun resolveAttachment(attachmentId: SecureHash): Attachment =
|
||||||
storageService.attachments.openAttachment(attachmentId) ?: throw AttachmentResolutionException(attachmentId)
|
services.storageService.attachments.openAttachment(attachmentId) ?: throw AttachmentResolutionException(attachmentId)
|
||||||
|
|
||||||
private fun <R> interpretTransactionDsl(
|
private fun <R> interpretTransactionDsl(
|
||||||
transactionBuilder: TransactionBuilder,
|
transactionBuilder: TransactionBuilder,
|
||||||
@ -233,10 +232,10 @@ data class TestLedgerDSLInterpreter private constructor (
|
|||||||
|
|
||||||
fun toTransactionGroup(): TransactionGroup {
|
fun toTransactionGroup(): TransactionGroup {
|
||||||
val ledgerTransactions = transactionWithLocations.map {
|
val ledgerTransactions = transactionWithLocations.map {
|
||||||
it.value.transaction.toLedgerTransaction(identityService, storageService.attachments)
|
it.value.transaction.toLedgerTransaction(services.identityService, services.storageService.attachments)
|
||||||
}
|
}
|
||||||
val nonVerifiedLedgerTransactions = nonVerifiedTransactionWithLocations.map {
|
val nonVerifiedLedgerTransactions = nonVerifiedTransactionWithLocations.map {
|
||||||
it.value.transaction.toLedgerTransaction(identityService, storageService.attachments)
|
it.value.transaction.toLedgerTransaction(services.identityService, services.storageService.attachments)
|
||||||
}
|
}
|
||||||
return TransactionGroup(ledgerTransactions.toSet(), nonVerifiedLedgerTransactions.toSet())
|
return TransactionGroup(ledgerTransactions.toSet(), nonVerifiedLedgerTransactions.toSet())
|
||||||
}
|
}
|
||||||
@ -295,7 +294,7 @@ data class TestLedgerDSLInterpreter private constructor (
|
|||||||
dsl(LedgerDSL(copy()))
|
dsl(LedgerDSL(copy()))
|
||||||
|
|
||||||
override fun attachment(attachment: InputStream): SecureHash {
|
override fun attachment(attachment: InputStream): SecureHash {
|
||||||
return storageService.attachments.importAttachment(attachment)
|
return services.storageService.attachments.importAttachment(attachment)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun verifies(): EnforceVerifyOrFail {
|
override fun verifies(): EnforceVerifyOrFail {
|
||||||
@ -322,6 +321,9 @@ data class TestLedgerDSLInterpreter private constructor (
|
|||||||
return stateAndRef as StateAndRef<S>
|
return stateAndRef as StateAndRef<S>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val transactionsToVerify: List<WireTransaction> get() = transactionWithLocations.values.map { it.transaction }
|
||||||
|
val transactionsUnverified: List<WireTransaction> get() = nonVerifiedTransactionWithLocations.values.map { it.transaction }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -330,7 +332,7 @@ data class TestLedgerDSLInterpreter private constructor (
|
|||||||
* @param extraKeys extra keys to sign transactions with.
|
* @param extraKeys extra keys to sign transactions with.
|
||||||
* @return List of [SignedTransaction]s.
|
* @return List of [SignedTransaction]s.
|
||||||
*/
|
*/
|
||||||
fun signAll(transactionsToSign: List<WireTransaction>, extraKeys: Array<out KeyPair>) = transactionsToSign.map { wtx ->
|
fun signAll(transactionsToSign: List<WireTransaction>, extraKeys: List<KeyPair>) = transactionsToSign.map { wtx ->
|
||||||
val allPubKeys = wtx.signers.toMutableSet()
|
val allPubKeys = wtx.signers.toMutableSet()
|
||||||
val bits = wtx.serialize()
|
val bits = wtx.serialize()
|
||||||
require(bits == wtx.serialized)
|
require(bits == wtx.serialized)
|
||||||
@ -350,4 +352,4 @@ fun signAll(transactionsToSign: List<WireTransaction>, extraKeys: Array<out KeyP
|
|||||||
* @return List of [SignedTransaction]s.
|
* @return List of [SignedTransaction]s.
|
||||||
*/
|
*/
|
||||||
fun LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.signAll(
|
fun LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.signAll(
|
||||||
vararg extraKeys: KeyPair) = signAll(this.interpreter.wireTransactions, extraKeys)
|
vararg extraKeys: KeyPair) = signAll(this.interpreter.wireTransactions, extraKeys.toList())
|
||||||
|
@ -3,7 +3,9 @@ package com.r3corda.contracts
|
|||||||
import com.r3corda.core.contracts.*
|
import com.r3corda.core.contracts.*
|
||||||
import com.r3corda.core.crypto.Party
|
import com.r3corda.core.crypto.Party
|
||||||
import com.r3corda.core.crypto.SecureHash
|
import com.r3corda.core.crypto.SecureHash
|
||||||
|
import com.r3corda.core.days
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
import java.time.Instant
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -109,9 +111,11 @@ class BillOfLadingAgreement : Contract {
|
|||||||
/**
|
/**
|
||||||
* Returns a transaction that issues a Bill of Lading Agreement
|
* Returns a transaction that issues a Bill of Lading Agreement
|
||||||
*/
|
*/
|
||||||
fun generateIssue(owner: PublicKey, beneficiary: Party, props: BillOfLadingProperties, notary: Party? = null): TransactionBuilder {
|
fun generateIssue(owner: PublicKey, beneficiary: Party, props: BillOfLadingProperties, notary: Party): TransactionBuilder {
|
||||||
val state = State(owner, beneficiary, props)
|
val state = State(owner, beneficiary, props)
|
||||||
return TransactionType.General.Builder(notary = notary).withItems(state, Command(Commands.IssueBL(), props.carrierOwner.owningKey))
|
val builder = TransactionType.General.Builder(notary = notary)
|
||||||
|
builder.setTime(Instant.now(), notary, 1.days)
|
||||||
|
return builder.withItems(state, Command(Commands.IssueBL(), props.carrierOwner.owningKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,7 +4,10 @@ import com.r3corda.contracts.asset.sumCashBy
|
|||||||
import com.r3corda.core.contracts.*
|
import com.r3corda.core.contracts.*
|
||||||
import com.r3corda.core.crypto.Party
|
import com.r3corda.core.crypto.Party
|
||||||
import com.r3corda.core.crypto.SecureHash
|
import com.r3corda.core.crypto.SecureHash
|
||||||
|
import com.r3corda.core.days
|
||||||
|
import com.r3corda.core.testing.DUMMY_NOTARY
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
import java.time.Instant
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.Period
|
import java.time.Period
|
||||||
import java.time.ZoneOffset
|
import java.time.ZoneOffset
|
||||||
@ -142,7 +145,9 @@ class LOC : Contract {
|
|||||||
|
|
||||||
fun generateIssue(beneficiaryPaid: Boolean, issued: Boolean, terminated: Boolean, props: LOCProperties, notary: Party): TransactionBuilder {
|
fun generateIssue(beneficiaryPaid: Boolean, issued: Boolean, terminated: Boolean, props: LOCProperties, notary: Party): TransactionBuilder {
|
||||||
val state = State(beneficiaryPaid, issued, terminated, props)
|
val state = State(beneficiaryPaid, issued, terminated, props)
|
||||||
return TransactionType.General.Builder(notary = notary).withItems(state, Command(Commands.Issuance(), props.issuingbank.owningKey))
|
val builder = TransactionType.General.Builder(notary = notary)
|
||||||
|
builder.setTime(Instant.now(), notary, 1.days)
|
||||||
|
return builder.withItems(state, Command(Commands.Issuance(), props.issuingbank.owningKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,8 +48,9 @@ class BillOfLadingAgreementTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun issueGenerationMethod() {
|
fun issueGenerationMethod() {
|
||||||
val ptx = BillOfLadingAgreement().generateIssue(Bill.owner, Bill.beneficiary,Bill.props, notary = DUMMY_NOTARY).apply {
|
val ptx = BillOfLadingAgreement().generateIssue(Bill.owner, Bill.beneficiary, Bill.props, DUMMY_NOTARY).apply {
|
||||||
signWith(ALICE_KEY)
|
signWith(ALICE_KEY)
|
||||||
|
signWith(DUMMY_NOTARY_KEY)
|
||||||
}
|
}
|
||||||
val stx = ptx.toSignedTransaction()
|
val stx = ptx.toSignedTransaction()
|
||||||
stx.verifyToLedgerTransaction(MOCK_IDENTITY_SERVICE,attachments)
|
stx.verifyToLedgerTransaction(MOCK_IDENTITY_SERVICE,attachments)
|
||||||
@ -57,14 +58,14 @@ class BillOfLadingAgreementTests {
|
|||||||
|
|
||||||
@Test(expected = IllegalStateException::class)
|
@Test(expected = IllegalStateException::class)
|
||||||
fun issueGenerationMethod_Unsigned() {
|
fun issueGenerationMethod_Unsigned() {
|
||||||
val ptx = BillOfLadingAgreement().generateIssue(Bill.owner, Bill.beneficiary, Bill.props)
|
val ptx = BillOfLadingAgreement().generateIssue(Bill.owner, Bill.beneficiary, Bill.props, DUMMY_NOTARY)
|
||||||
val stx = ptx.toSignedTransaction()
|
val stx = ptx.toSignedTransaction()
|
||||||
stx.verifyToLedgerTransaction(MOCK_IDENTITY_SERVICE,attachments)
|
stx.verifyToLedgerTransaction(MOCK_IDENTITY_SERVICE,attachments)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalStateException::class)
|
@Test(expected = IllegalStateException::class)
|
||||||
fun issueGenerationMethod_KeyMismatch() {
|
fun issueGenerationMethod_KeyMismatch() {
|
||||||
val ptx = BillOfLadingAgreement().generateIssue(Bill.owner, Bill.beneficiary, Bill.props).apply {
|
val ptx = BillOfLadingAgreement().generateIssue(Bill.owner, Bill.beneficiary, Bill.props, DUMMY_NOTARY).apply {
|
||||||
signWith(BOB_KEY)
|
signWith(BOB_KEY)
|
||||||
}
|
}
|
||||||
val stx = ptx.toSignedTransaction()
|
val stx = ptx.toSignedTransaction()
|
||||||
|
@ -120,6 +120,7 @@ class LOCTests {
|
|||||||
fun issueSignedByBank() {
|
fun issueSignedByBank() {
|
||||||
val ptx = LOC().generateIssue(LOCstate.beneficiaryPaid, LOCstate.issued, LOCstate.terminated, LOCstate.props, DUMMY_NOTARY).apply {
|
val ptx = LOC().generateIssue(LOCstate.beneficiaryPaid, LOCstate.issued, LOCstate.terminated, LOCstate.props, DUMMY_NOTARY).apply {
|
||||||
signWith(MEGA_CORP_KEY)
|
signWith(MEGA_CORP_KEY)
|
||||||
|
signWith(DUMMY_NOTARY_KEY)
|
||||||
}
|
}
|
||||||
val stx = ptx.toSignedTransaction()
|
val stx = ptx.toSignedTransaction()
|
||||||
stx.verify()
|
stx.verify()
|
||||||
|
@ -2,10 +2,7 @@ package com.r3corda.node.messaging
|
|||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.r3corda.contracts.CommercialPaper
|
import com.r3corda.contracts.CommercialPaper
|
||||||
import com.r3corda.contracts.asset.CASH
|
import com.r3corda.contracts.asset.*
|
||||||
import com.r3corda.contracts.asset.Cash
|
|
||||||
import com.r3corda.contracts.asset.`issued by`
|
|
||||||
import com.r3corda.contracts.asset.`owned by`
|
|
||||||
import com.r3corda.contracts.testing.fillWithSomeTestCash
|
import com.r3corda.contracts.testing.fillWithSomeTestCash
|
||||||
import com.r3corda.core.contracts.*
|
import com.r3corda.core.contracts.*
|
||||||
import com.r3corda.core.crypto.Party
|
import com.r3corda.core.crypto.Party
|
||||||
@ -93,9 +90,8 @@ class TwoPartyTradeProtocolTests {
|
|||||||
val bobNode = net.createPartyNode(notaryNode.info, BOB.name, BOB_KEY)
|
val bobNode = net.createPartyNode(notaryNode.info, BOB.name, BOB_KEY)
|
||||||
|
|
||||||
bobNode.services.fillWithSomeTestCash(2000.DOLLARS)
|
bobNode.services.fillWithSomeTestCash(2000.DOLLARS)
|
||||||
val issuer = bobNode.services.storageService.myLegalIdentity.ref(0)
|
|
||||||
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
|
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
|
||||||
1200.DOLLARS `issued by` issuer, notaryNode.info.identity, null).second
|
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, notaryNode.info.identity, null).second
|
||||||
|
|
||||||
insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey, notaryNode.storage.myLegalIdentityKey)
|
insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey, notaryNode.storage.myLegalIdentityKey)
|
||||||
|
|
||||||
@ -134,7 +130,6 @@ class TwoPartyTradeProtocolTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `shutdown and restore`() {
|
fun `shutdown and restore`() {
|
||||||
|
|
||||||
ledger {
|
ledger {
|
||||||
val notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
val notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
||||||
val aliceNode = net.createPartyNode(notaryNode.info, ALICE.name, ALICE_KEY)
|
val aliceNode = net.createPartyNode(notaryNode.info, ALICE.name, ALICE_KEY)
|
||||||
@ -142,13 +137,12 @@ class TwoPartyTradeProtocolTests {
|
|||||||
|
|
||||||
val bobAddr = bobNode.net.myAddress as InMemoryMessagingNetwork.Handle
|
val bobAddr = bobNode.net.myAddress as InMemoryMessagingNetwork.Handle
|
||||||
val networkMapAddr = notaryNode.info
|
val networkMapAddr = notaryNode.info
|
||||||
val issuer = bobNode.services.storageService.myLegalIdentity.ref(0)
|
|
||||||
|
|
||||||
net.runNetwork() // Clear network map registration messages
|
net.runNetwork() // Clear network map registration messages
|
||||||
|
|
||||||
bobNode.services.fillWithSomeTestCash(2000.DOLLARS)
|
bobNode.services.fillWithSomeTestCash(2000.DOLLARS)
|
||||||
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
|
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
|
||||||
1200.DOLLARS `issued by` issuer, notaryNode.info.identity, null).second
|
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, notaryNode.info.identity, null).second
|
||||||
insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey)
|
insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey)
|
||||||
|
|
||||||
val buyerSessionID = random63BitValue()
|
val buyerSessionID = random63BitValue()
|
||||||
@ -252,7 +246,7 @@ class TwoPartyTradeProtocolTests {
|
|||||||
val aliceNode = makeNodeWithTracking(notaryNode.info, ALICE.name, ALICE_KEY)
|
val aliceNode = makeNodeWithTracking(notaryNode.info, ALICE.name, ALICE_KEY)
|
||||||
val bobNode = makeNodeWithTracking(notaryNode.info, BOB.name, BOB_KEY)
|
val bobNode = makeNodeWithTracking(notaryNode.info, BOB.name, BOB_KEY)
|
||||||
|
|
||||||
ledger(storageService = aliceNode.storage) {
|
ledger(aliceNode.services) {
|
||||||
|
|
||||||
// Insert a prospectus type attachment into the commercial paper transaction.
|
// Insert a prospectus type attachment into the commercial paper transaction.
|
||||||
val stream = ByteArrayOutputStream()
|
val stream = ByteArrayOutputStream()
|
||||||
@ -419,7 +413,7 @@ class TwoPartyTradeProtocolTests {
|
|||||||
wtxToSign: List<WireTransaction>,
|
wtxToSign: List<WireTransaction>,
|
||||||
services: ServiceHub,
|
services: ServiceHub,
|
||||||
vararg extraKeys: KeyPair): Map<SecureHash, SignedTransaction> {
|
vararg extraKeys: KeyPair): Map<SecureHash, SignedTransaction> {
|
||||||
val signed: List<SignedTransaction> = signAll(wtxToSign, extraKeys)
|
val signed: List<SignedTransaction> = signAll(wtxToSign, extraKeys.toList())
|
||||||
services.recordTransactions(signed)
|
services.recordTransactions(signed)
|
||||||
val validatedTransactions = services.storageService.validatedTransactions
|
val validatedTransactions = services.storageService.validatedTransactions
|
||||||
if (validatedTransactions is RecordingTransactionStorage) {
|
if (validatedTransactions is RecordingTransactionStorage) {
|
||||||
|
@ -19,7 +19,7 @@ import com.r3corda.node.services.statemachine.StateMachineManager
|
|||||||
import com.r3corda.node.services.wallet.NodeWalletService
|
import com.r3corda.node.services.wallet.NodeWalletService
|
||||||
import java.time.Clock
|
import java.time.Clock
|
||||||
|
|
||||||
open class MockServices(
|
open class MockServiceHubInternal(
|
||||||
customWallet: WalletService? = null,
|
customWallet: WalletService? = null,
|
||||||
val keyManagement: KeyManagementService? = null,
|
val keyManagement: KeyManagementService? = null,
|
||||||
val net: MessagingServiceInternal? = null,
|
val net: MessagingServiceInternal? = null,
|
@ -60,7 +60,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
|||||||
init {
|
init {
|
||||||
val kms = MockKeyManagementService(ALICE_KEY)
|
val kms = MockKeyManagementService(ALICE_KEY)
|
||||||
val mockMessagingService = InMemoryMessagingNetwork(false).InMemoryMessaging(false, InMemoryMessagingNetwork.Handle(0, "None"))
|
val mockMessagingService = InMemoryMessagingNetwork(false).InMemoryMessaging(false, InMemoryMessagingNetwork.Handle(0, "None"))
|
||||||
val mockServices = object : MockServices(overrideClock = testClock, keyManagement = kms, net = mockMessagingService), TestReference {
|
val mockServices = object : MockServiceHubInternal(overrideClock = testClock, keyManagement = kms, net = mockMessagingService), TestReference {
|
||||||
override val testReference = this@NodeSchedulerServiceTest
|
override val testReference = this@NodeSchedulerServiceTest
|
||||||
}
|
}
|
||||||
services = mockServices
|
services = mockServices
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package com.r3corda.node.services
|
package com.r3corda.node.services
|
||||||
|
|
||||||
import com.r3corda.contracts.asset.Cash
|
import com.r3corda.contracts.asset.Cash
|
||||||
|
import com.r3corda.contracts.asset.DUMMY_CASH_ISSUER
|
||||||
import com.r3corda.contracts.asset.cashBalances
|
import com.r3corda.contracts.asset.cashBalances
|
||||||
import com.r3corda.contracts.testing.fillWithSomeTestCash
|
import com.r3corda.contracts.testing.fillWithSomeTestCash
|
||||||
import com.r3corda.core.contracts.*
|
import com.r3corda.core.contracts.*
|
||||||
import com.r3corda.core.crypto.SecureHash
|
import com.r3corda.core.crypto.SecureHash
|
||||||
import com.r3corda.core.node.ServiceHub
|
import com.r3corda.core.node.services.WalletService
|
||||||
import com.r3corda.core.node.services.testing.MockKeyManagementService
|
|
||||||
import com.r3corda.core.node.services.testing.MockStorageService
|
import com.r3corda.core.node.services.testing.MockStorageService
|
||||||
import com.r3corda.core.serialization.OpaqueBytes
|
import com.r3corda.core.node.services.testing.MockServices
|
||||||
import com.r3corda.core.testing.*
|
import com.r3corda.core.testing.*
|
||||||
import com.r3corda.core.utilities.BriefLogFormatter
|
import com.r3corda.core.utilities.BriefLogFormatter
|
||||||
import com.r3corda.node.services.wallet.NodeWalletService
|
import com.r3corda.node.services.wallet.NodeWalletService
|
||||||
@ -23,11 +23,22 @@ import kotlin.test.assertNull
|
|||||||
// TODO: Move this to the cash contract tests once mock services are further split up.
|
// TODO: Move this to the cash contract tests once mock services are further split up.
|
||||||
|
|
||||||
class WalletWithCashTest {
|
class WalletWithCashTest {
|
||||||
val kms = MockKeyManagementService(ALICE_KEY)
|
lateinit var services: MockServices
|
||||||
|
val wallet: WalletService get() = services.walletService
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
BriefLogFormatter.loggingOn(NodeWalletService::class)
|
BriefLogFormatter.loggingOn(NodeWalletService::class)
|
||||||
|
services = object : MockServices() {
|
||||||
|
override val walletService: WalletService = NodeWalletService(this)
|
||||||
|
|
||||||
|
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
||||||
|
for (stx in txs) {
|
||||||
|
storageService.validatedTransactions.addTransaction(stx)
|
||||||
|
walletService.notify(stx.tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@ -35,37 +46,24 @@ class WalletWithCashTest {
|
|||||||
BriefLogFormatter.loggingOff(NodeWalletService::class)
|
BriefLogFormatter.loggingOff(NodeWalletService::class)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun make(): Pair<NodeWalletService, ServiceHub> {
|
|
||||||
val services = MockServices(keyManagement = kms)
|
|
||||||
return Pair(services.walletService as NodeWalletService, services)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun splits() {
|
fun splits() {
|
||||||
val (wallet, services) = make()
|
|
||||||
val ref = OpaqueBytes(ByteArray(1, {0}))
|
|
||||||
|
|
||||||
kms.nextKeys += Array(3) { ALICE_KEY }
|
|
||||||
// Fix the PRNG so that we get the same splits every time.
|
// Fix the PRNG so that we get the same splits every time.
|
||||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L), ref)
|
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L))
|
||||||
|
|
||||||
val w = wallet.currentWallet
|
val w = wallet.currentWallet
|
||||||
assertEquals(3, w.states.size)
|
assertEquals(3, w.states.size)
|
||||||
|
|
||||||
val state = w.states[0].state.data as Cash.State
|
val state = w.states[0].state.data as Cash.State
|
||||||
val myIdentity = services.storageService.myLegalIdentity
|
assertEquals(29.01.DOLLARS `issued by` DUMMY_CASH_ISSUER, state.amount)
|
||||||
val myPartyRef = myIdentity.ref(ref)
|
assertEquals(services.key.public, state.owner)
|
||||||
assertEquals(29.01.DOLLARS `issued by` myPartyRef, state.amount)
|
|
||||||
assertEquals(ALICE_PUBKEY, state.owner)
|
|
||||||
|
|
||||||
assertEquals(35.38.DOLLARS `issued by` myPartyRef, (w.states[2].state.data as Cash.State).amount)
|
assertEquals(35.38.DOLLARS `issued by` DUMMY_CASH_ISSUER, (w.states[2].state.data as Cash.State).amount)
|
||||||
assertEquals(35.61.DOLLARS `issued by` myPartyRef, (w.states[1].state.data as Cash.State).amount)
|
assertEquals(35.61.DOLLARS `issued by` DUMMY_CASH_ISSUER, (w.states[1].state.data as Cash.State).amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun basics() {
|
fun basics() {
|
||||||
val (wallet, services) = make()
|
|
||||||
|
|
||||||
// A tx that sends us money.
|
// A tx that sends us money.
|
||||||
val freshKey = services.keyManagementService.freshKey()
|
val freshKey = services.keyManagementService.freshKey()
|
||||||
val usefulTX = TransactionType.General.Builder().apply {
|
val usefulTX = TransactionType.General.Builder().apply {
|
||||||
@ -102,10 +100,7 @@ class WalletWithCashTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun branchingLinearStatesFails() {
|
fun branchingLinearStatesFails() {
|
||||||
val (wallet, services) = make()
|
|
||||||
|
|
||||||
val freshKey = services.keyManagementService.freshKey()
|
val freshKey = services.keyManagementService.freshKey()
|
||||||
|
|
||||||
val thread = SecureHash.sha256("thread")
|
val thread = SecureHash.sha256("thread")
|
||||||
|
|
||||||
// Issue a linear state
|
// Issue a linear state
|
||||||
@ -131,8 +126,6 @@ class WalletWithCashTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun sequencingLinearStatesWorks() {
|
fun sequencingLinearStatesWorks() {
|
||||||
val (wallet, services) = make()
|
|
||||||
|
|
||||||
val freshKey = services.keyManagementService.freshKey()
|
val freshKey = services.keyManagementService.freshKey()
|
||||||
|
|
||||||
val thread = SecureHash.sha256("thread")
|
val thread = SecureHash.sha256("thread")
|
||||||
|
@ -4,7 +4,7 @@ import co.paralleluniverse.fibers.Fiber
|
|||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.r3corda.core.messaging.MessagingService
|
import com.r3corda.core.messaging.MessagingService
|
||||||
import com.r3corda.core.protocols.ProtocolLogic
|
import com.r3corda.core.protocols.ProtocolLogic
|
||||||
import com.r3corda.node.services.MockServices
|
import com.r3corda.node.services.MockServiceHubInternal
|
||||||
import com.r3corda.node.services.api.Checkpoint
|
import com.r3corda.node.services.api.Checkpoint
|
||||||
import com.r3corda.node.services.api.CheckpointStorage
|
import com.r3corda.node.services.api.CheckpointStorage
|
||||||
import com.r3corda.node.services.api.MessagingServiceInternal
|
import com.r3corda.node.services.api.MessagingServiceInternal
|
||||||
@ -45,7 +45,7 @@ class StateMachineManagerTests {
|
|||||||
assertThat(protocol.lazyTime).isNotNull()
|
assertThat(protocol.lazyTime).isNotNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createManager() = StateMachineManager(object : MockServices() {
|
private fun createManager() = StateMachineManager(object : MockServiceHubInternal() {
|
||||||
override val networkService: MessagingServiceInternal get() = network
|
override val networkService: MessagingServiceInternal get() = network
|
||||||
}, emptyList(), checkpointStorage, AffinityExecutor.SAME_THREAD)
|
}, emptyList(), checkpointStorage, AffinityExecutor.SAME_THREAD)
|
||||||
|
|
||||||
|
@ -17,13 +17,13 @@ class GraphVisualiser(val dsl: LedgerDSL<TestTransactionDSLInterpreter, TestLedg
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun convert(): SingleGraph {
|
fun convert(): SingleGraph {
|
||||||
val tg = dsl.interpreter.toTransactionGroup()
|
val testLedger: TestLedgerDSLInterpreter = dsl.interpreter
|
||||||
val graph = createGraph("Transaction group", css)
|
val graph = createGraph("Transaction group", css)
|
||||||
|
|
||||||
// Map all the transactions, including the bogus non-verified ones (with no inputs) to graph nodes.
|
// Map all the transactions, including the bogus non-verified ones (with no inputs) to graph nodes.
|
||||||
for ((txIndex, tx) in (tg.transactions + tg.nonVerifiedRoots).withIndex()) {
|
for ((txIndex, tx) in (testLedger.transactionsToVerify + testLedger.transactionsUnverified).withIndex()) {
|
||||||
val txNode = graph.addNode<Node>("tx$txIndex")
|
val txNode = graph.addNode<Node>("tx$txIndex")
|
||||||
if (tx !in tg.nonVerifiedRoots)
|
if (tx !in testLedger.transactionsUnverified)
|
||||||
txNode.label = dsl.interpreter.transactionName(tx.id).let { it ?: "TX[${tx.id.prefixChars()}]" }
|
txNode.label = dsl.interpreter.transactionName(tx.id).let { it ?: "TX[${tx.id.prefixChars()}]" }
|
||||||
txNode.styleClass = "tx"
|
txNode.styleClass = "tx"
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ class GraphVisualiser(val dsl: LedgerDSL<TestTransactionDSLInterpreter, TestLedg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// And now all states and transactions were mapped to graph nodes, hook up the input edges.
|
// And now all states and transactions were mapped to graph nodes, hook up the input edges.
|
||||||
for ((txIndex, tx) in tg.transactions.withIndex()) {
|
for ((txIndex, tx) in testLedger.transactionsToVerify.withIndex()) {
|
||||||
for ((inputIndex, ref) in tx.inputs.withIndex()) {
|
for ((inputIndex, ref) in tx.inputs.withIndex()) {
|
||||||
val edge = graph.addEdge<Edge>("tx$txIndex-in$inputIndex", ref.toString(), "tx$txIndex", true)
|
val edge = graph.addEdge<Edge>("tx$txIndex-in$inputIndex", ref.toString(), "tx$txIndex", true)
|
||||||
edge.weight = 1.2
|
edge.weight = 1.2
|
||||||
|
@ -6,9 +6,6 @@ import com.r3corda.core.testing.utilities.TestTimestamp
|
|||||||
import com.r3corda.core.testing.utilities.assertExitOrKill
|
import com.r3corda.core.testing.utilities.assertExitOrKill
|
||||||
import com.r3corda.core.testing.utilities.spawn
|
import com.r3corda.core.testing.utilities.spawn
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.nio.file.Paths
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class TraderDemoTest {
|
class TraderDemoTest {
|
||||||
|
@ -136,7 +136,6 @@ fun runTraderDemo(args: Array<String>): Int {
|
|||||||
// One of the two servers needs to run the network map and notary services. In such a trivial two-node network
|
// One of the two servers needs to run the network map and notary services. In such a trivial two-node network
|
||||||
// the map is not very helpful, but we need one anyway. So just make the buyer side run the network map as it's
|
// the map is not very helpful, but we need one anyway. So just make the buyer side run the network map as it's
|
||||||
// the side that sticks around waiting for the seller.
|
// the side that sticks around waiting for the seller.
|
||||||
var cashIssuer: Party? = null
|
|
||||||
val networkMapId = if (role == Role.BUYER) {
|
val networkMapId = if (role == Role.BUYER) {
|
||||||
advertisedServices = setOf(NetworkMapService.Type, SimpleNotaryService.Type)
|
advertisedServices = setOf(NetworkMapService.Type, SimpleNotaryService.Type)
|
||||||
null
|
null
|
||||||
@ -148,7 +147,6 @@ fun runTraderDemo(args: Array<String>): Int {
|
|||||||
val path = Paths.get(baseDirectory, Role.BUYER.name.toLowerCase(), "identity-public")
|
val path = Paths.get(baseDirectory, Role.BUYER.name.toLowerCase(), "identity-public")
|
||||||
val party = Files.readAllBytes(path).deserialize<Party>()
|
val party = Files.readAllBytes(path).deserialize<Party>()
|
||||||
advertisedServices = emptySet()
|
advertisedServices = emptySet()
|
||||||
cashIssuer = party
|
|
||||||
NodeInfo(ArtemisMessagingService.makeRecipient(theirNetAddr), party, setOf(NetworkMapService.Type))
|
NodeInfo(ArtemisMessagingService.makeRecipient(theirNetAddr), party, setOf(NetworkMapService.Type))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,18 +155,15 @@ fun runTraderDemo(args: Array<String>): Int {
|
|||||||
Node(directory, myNetAddr, apiNetAddr, config, networkMapId, advertisedServices).setup().start()
|
Node(directory, myNetAddr, apiNetAddr, config, networkMapId, advertisedServices).setup().start()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace with a separate trusted cash issuer
|
|
||||||
if (cashIssuer == null) {
|
|
||||||
cashIssuer = node.services.storageService.myLegalIdentity
|
|
||||||
}
|
|
||||||
|
|
||||||
// What happens next depends on the role. The buyer sits around waiting for a trade to start. The seller role
|
// 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.
|
// will contact the buyer and actually make something happen.
|
||||||
val amount = 1000.DOLLARS
|
val amount = 1000.DOLLARS
|
||||||
if (role == Role.BUYER) {
|
if (role == Role.BUYER) {
|
||||||
runBuyer(node, amount)
|
runBuyer(node, amount)
|
||||||
} else {
|
} else {
|
||||||
runSeller(node, amount, cashIssuer)
|
node.networkMapRegistrationFuture.get()
|
||||||
|
val party = node.netMapCache.getNodeByLegalName("Bank A")?.identity ?: throw IllegalStateException("Cannot find other node?!")
|
||||||
|
runSeller(node, amount, party)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
@ -213,7 +208,9 @@ private fun runBuyer(node: Node, amount: Amount<Currency>) {
|
|||||||
// Self issue some cash.
|
// Self issue some cash.
|
||||||
//
|
//
|
||||||
// TODO: At some point this demo should be extended to have a central bank node.
|
// TODO: At some point this demo should be extended to have a central bank node.
|
||||||
node.services.fillWithSomeTestCash(3000.DOLLARS, node.info.identity)
|
node.services.fillWithSomeTestCash(3000.DOLLARS,
|
||||||
|
notary = node.info.identity, // In this demo, the buyer and notary are the same.
|
||||||
|
ownedBy = node.services.keyManagementService.freshKey().public)
|
||||||
|
|
||||||
// Wait around until a node asks to start a trade with us. In a real system, this part would happen out of band
|
// Wait around until a node asks to start a trade with us. In a real system, this part would happen out of band
|
||||||
// via some other system like an exchange or maybe even a manual messaging system like Bloomberg. But for the
|
// via some other system like an exchange or maybe even a manual messaging system like Bloomberg. But for the
|
||||||
@ -250,7 +247,7 @@ private class TraderDemoProtocolBuyer(val otherSide: Party,
|
|||||||
progressTracker.currentStep = STARTING_BUY
|
progressTracker.currentStep = STARTING_BUY
|
||||||
send(otherSide, 0, sessionID)
|
send(otherSide, 0, sessionID)
|
||||||
|
|
||||||
val notary = serviceHub.networkMapCache.notaryNodes[0]
|
val notary: NodeInfo = serviceHub.networkMapCache.notaryNodes[0]
|
||||||
val buyer = TwoPartyTradeProtocol.Buyer(
|
val buyer = TwoPartyTradeProtocol.Buyer(
|
||||||
otherSide,
|
otherSide,
|
||||||
notary.identity,
|
notary.identity,
|
||||||
@ -323,7 +320,7 @@ private class TraderDemoProtocolSeller(val otherSide: Party,
|
|||||||
|
|
||||||
progressTracker.currentStep = SELF_ISSUING
|
progressTracker.currentStep = SELF_ISSUING
|
||||||
|
|
||||||
val notary = serviceHub.networkMapCache.notaryNodes[0]
|
val notary: NodeInfo = serviceHub.networkMapCache.notaryNodes[0]
|
||||||
val cpOwnerKey = serviceHub.keyManagementService.freshKey()
|
val cpOwnerKey = serviceHub.keyManagementService.freshKey()
|
||||||
val commercialPaper = selfIssueSomeCommercialPaper(cpOwnerKey.public, notary)
|
val commercialPaper = selfIssueSomeCommercialPaper(cpOwnerKey.public, notary)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user