mirror of
https://github.com/corda/corda.git
synced 2025-06-18 23:28:21 +00:00
Re-factoring of OnLedgerAsset generateSpend code (moved to VaultService)
This commit is contained in:
@ -239,26 +239,27 @@ object TwoPartyTradeProtocol {
|
|||||||
|
|
||||||
private fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair<TransactionBuilder, List<PublicKey>> {
|
private fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair<TransactionBuilder, List<PublicKey>> {
|
||||||
val ptx = TransactionType.General.Builder(notary)
|
val ptx = TransactionType.General.Builder(notary)
|
||||||
// Add input and output states for the movement of cash, by using the Cash contract to generate the states.
|
|
||||||
val vault = serviceHub.vaultService.currentVault
|
// Add input and output states for the movement of cash, by using the Cash contract to generate the states
|
||||||
val cashStates = vault.statesOfType<Cash.State>()
|
val (tx, cashSigningPubKeys) = serviceHub.vaultService.generateSpend(ptx, tradeRequest.price, tradeRequest.sellerOwnerKey)
|
||||||
val cashSigningPubKeys = Cash().generateSpend(ptx, tradeRequest.price, tradeRequest.sellerOwnerKey, cashStates)
|
|
||||||
// Add inputs/outputs/a command for the movement of the asset.
|
// Add inputs/outputs/a command for the movement of the asset.
|
||||||
ptx.addInputState(tradeRequest.assetForSale)
|
tx.addInputState(tradeRequest.assetForSale)
|
||||||
|
|
||||||
// Just pick some new public key for now. This won't be linked with our identity in any way, which is what
|
// Just pick some new public key for now. This won't be linked with our identity in any way, which is what
|
||||||
// we want for privacy reasons: the key is here ONLY to manage and control ownership, it is not intended to
|
// we want for privacy reasons: the key is here ONLY to manage and control ownership, it is not intended to
|
||||||
// reveal who the owner actually is. The key management service is expected to derive a unique key from some
|
// reveal who the owner actually is. The key management service is expected to derive a unique key from some
|
||||||
// initial seed in order to provide privacy protection.
|
// initial seed in order to provide privacy protection.
|
||||||
val freshKey = serviceHub.keyManagementService.freshKey()
|
val freshKey = serviceHub.keyManagementService.freshKey()
|
||||||
val (command, state) = tradeRequest.assetForSale.state.data.withNewOwner(freshKey.public)
|
val (command, state) = tradeRequest.assetForSale.state.data.withNewOwner(freshKey.public)
|
||||||
ptx.addOutputState(state, tradeRequest.assetForSale.state.notary)
|
tx.addOutputState(state, tradeRequest.assetForSale.state.notary)
|
||||||
ptx.addCommand(command, tradeRequest.assetForSale.state.data.owner)
|
tx.addCommand(command, tradeRequest.assetForSale.state.data.owner)
|
||||||
|
|
||||||
// And add a request for timestamping: it may be that none of the contracts need this! But it can't hurt
|
// And add a request for timestamping: it may be that none of the contracts need this! But it can't hurt
|
||||||
// to have one.
|
// to have one.
|
||||||
val currentTime = serviceHub.clock.instant()
|
val currentTime = serviceHub.clock.instant()
|
||||||
ptx.setTime(currentTime, 30.seconds)
|
tx.setTime(currentTime, 30.seconds)
|
||||||
return Pair(ptx, cashSigningPubKeys)
|
return Pair(tx, cashSigningPubKeys)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import com.google.common.util.concurrent.ListenableFuture
|
|||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
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.transactions.TransactionBuilder
|
||||||
import com.r3corda.core.transactions.WireTransaction
|
import com.r3corda.core.transactions.WireTransaction
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
@ -154,6 +155,15 @@ interface VaultService {
|
|||||||
}
|
}
|
||||||
return future
|
return future
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fungible Asset operations
|
||||||
|
**/
|
||||||
|
@Throws(InsufficientBalanceException::class)
|
||||||
|
fun generateSpend(tx: TransactionBuilder,
|
||||||
|
amount: Amount<Currency>,
|
||||||
|
to: PublicKey,
|
||||||
|
onlyFromParties: Set<Party>? = null): Pair<TransactionBuilder, List<PublicKey>>
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : LinearState> VaultService.linearHeadsOfType() = linearHeadsOfType_(T::class.java)
|
inline fun <reified T : LinearState> VaultService.linearHeadsOfType() = linearHeadsOfType_(T::class.java)
|
||||||
|
@ -3,10 +3,12 @@ package com.r3corda.core.testing
|
|||||||
import com.r3corda.core.ThreadBox
|
import com.r3corda.core.ThreadBox
|
||||||
import com.r3corda.core.bufferUntilSubscribed
|
import com.r3corda.core.bufferUntilSubscribed
|
||||||
import com.r3corda.core.contracts.*
|
import com.r3corda.core.contracts.*
|
||||||
|
import com.r3corda.core.crypto.Party
|
||||||
import com.r3corda.core.node.ServiceHub
|
import com.r3corda.core.node.ServiceHub
|
||||||
import com.r3corda.core.node.services.Vault
|
import com.r3corda.core.node.services.Vault
|
||||||
import com.r3corda.core.node.services.VaultService
|
import com.r3corda.core.node.services.VaultService
|
||||||
import com.r3corda.core.serialization.SingletonSerializeAsToken
|
import com.r3corda.core.serialization.SingletonSerializeAsToken
|
||||||
|
import com.r3corda.core.transactions.TransactionBuilder
|
||||||
import com.r3corda.core.transactions.WireTransaction
|
import com.r3corda.core.transactions.WireTransaction
|
||||||
import com.r3corda.core.utilities.loggerFor
|
import com.r3corda.core.utilities.loggerFor
|
||||||
import com.r3corda.core.utilities.trace
|
import com.r3corda.core.utilities.trace
|
||||||
@ -104,6 +106,11 @@ open class InMemoryVaultService(protected val services: ServiceHub) : SingletonS
|
|||||||
return changedVault
|
return changedVault
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun generateSpend(tx: TransactionBuilder, amount: Amount<Currency>, to: PublicKey, onlyFromParties: Set<Party>?): Pair<TransactionBuilder, List<PublicKey>> {
|
||||||
|
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun isRelevant(state: ContractState, ourKeys: Set<PublicKey>): Boolean {
|
private fun isRelevant(state: ContractState, ourKeys: Set<PublicKey>): Boolean {
|
||||||
return if (state is OwnableState) {
|
return if (state is OwnableState) {
|
||||||
state.owner in ourKeys
|
state.owner in ourKeys
|
||||||
|
@ -73,21 +73,14 @@ class ServerRPCOps(
|
|||||||
val builder: TransactionBuilder = TransactionType.General.Builder(null)
|
val builder: TransactionBuilder = TransactionType.General.Builder(null)
|
||||||
// TODO: Have some way of restricting this to states the caller controls
|
// TODO: Have some way of restricting this to states the caller controls
|
||||||
try {
|
try {
|
||||||
val vaultCashStates = services.vaultService.currentVault.statesOfType<Cash.State>()
|
val (spendTX, keysForSigning) = services.vaultService.generateSpend(builder, req.amount.withoutIssuer(), req.recipient.owningKey)
|
||||||
// TODO: Move cash state filtering by issuer down to the contract itself
|
|
||||||
val cashStatesOfRightCurrency = vaultCashStates.filter { it.state.data.amount.token == req.amount.token }
|
|
||||||
val keysForSigning = Cash().generateSpend(
|
|
||||||
tx = builder,
|
|
||||||
amount = req.amount.withoutIssuer(),
|
|
||||||
to = req.recipient.owningKey,
|
|
||||||
assetsStates = cashStatesOfRightCurrency,
|
|
||||||
onlyFromParties = setOf(req.amount.token.issuer.party)
|
|
||||||
)
|
|
||||||
keysForSigning.forEach {
|
keysForSigning.forEach {
|
||||||
val key = services.keyManagementService.keys[it] ?: throw IllegalStateException("Could not find signing key for ${it.toStringShort()}")
|
val key = services.keyManagementService.keys[it] ?: throw IllegalStateException("Could not find signing key for ${it.toStringShort()}")
|
||||||
builder.signWith(KeyPair(it, key))
|
builder.signWith(KeyPair(it, key))
|
||||||
}
|
}
|
||||||
val tx = builder.toSignedTransaction(checkSufficientSignatures = false)
|
|
||||||
|
val tx = spendTX.toSignedTransaction(checkSufficientSignatures = false)
|
||||||
val protocol = FinalityProtocol(tx, setOf(req), setOf(req.recipient))
|
val protocol = FinalityProtocol(tx, setOf(req), setOf(req.recipient))
|
||||||
return TransactionBuildResult.ProtocolStarted(
|
return TransactionBuildResult.ProtocolStarted(
|
||||||
smm.add(protocol).id,
|
smm.add(protocol).id,
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package com.r3corda.node.services.vault
|
package com.r3corda.node.services.vault
|
||||||
|
|
||||||
import com.google.common.collect.Sets
|
import com.google.common.collect.Sets
|
||||||
|
import com.r3corda.contracts.asset.Cash
|
||||||
import com.r3corda.core.ThreadBox
|
import com.r3corda.core.ThreadBox
|
||||||
import com.r3corda.core.bufferUntilSubscribed
|
import com.r3corda.core.bufferUntilSubscribed
|
||||||
import com.r3corda.core.contracts.*
|
import com.r3corda.core.contracts.*
|
||||||
|
import com.r3corda.core.crypto.Party
|
||||||
import com.r3corda.core.node.ServiceHub
|
import com.r3corda.core.node.ServiceHub
|
||||||
import com.r3corda.core.node.services.Vault
|
import com.r3corda.core.node.services.Vault
|
||||||
import com.r3corda.core.node.services.VaultService
|
import com.r3corda.core.node.services.VaultService
|
||||||
import com.r3corda.core.serialization.SingletonSerializeAsToken
|
import com.r3corda.core.serialization.SingletonSerializeAsToken
|
||||||
|
import com.r3corda.core.transactions.TransactionBuilder
|
||||||
import com.r3corda.core.transactions.WireTransaction
|
import com.r3corda.core.transactions.WireTransaction
|
||||||
import com.r3corda.core.utilities.loggerFor
|
import com.r3corda.core.utilities.loggerFor
|
||||||
import com.r3corda.core.utilities.trace
|
import com.r3corda.core.utilities.trace
|
||||||
@ -117,6 +120,121 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
|
|||||||
return currentVault
|
return currentVault
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a transaction that moves an amount of currency to the given pubkey.
|
||||||
|
*
|
||||||
|
* @param onlyFromParties if non-null, the asset states will be filtered to only include those issued by the set
|
||||||
|
* of given parties. This can be useful if the party you're trying to pay has expectations
|
||||||
|
* about which type of asset claims they are willing to accept.
|
||||||
|
*/
|
||||||
|
override fun generateSpend(tx: TransactionBuilder,
|
||||||
|
amount: Amount<Currency>,
|
||||||
|
to: PublicKey,
|
||||||
|
onlyFromParties: Set<Party>?): Pair<TransactionBuilder, List<PublicKey>> {
|
||||||
|
// Discussion
|
||||||
|
//
|
||||||
|
// This code is analogous to the Wallet.send() set of methods in bitcoinj, and has the same general outline.
|
||||||
|
//
|
||||||
|
// First we must select a set of asset states (which for convenience we will call 'coins' here, as in bitcoinj).
|
||||||
|
// The input states can be considered our "vault", and may consist of different products, and with different
|
||||||
|
// issuers and deposits.
|
||||||
|
//
|
||||||
|
// Coin selection is a complex problem all by itself and many different approaches can be used. It is easily
|
||||||
|
// possible for different actors to use different algorithms and approaches that, for example, compete on
|
||||||
|
// privacy vs efficiency (number of states created). Some spends may be artificial just for the purposes of
|
||||||
|
// obfuscation and so on.
|
||||||
|
//
|
||||||
|
// Having selected input states of the correct asset, we must craft output states for the amount we're sending and
|
||||||
|
// the "change", which goes back to us. The change is required to make the amounts balance. We may need more
|
||||||
|
// than one change output in order to avoid merging assets from different deposits. The point of this design
|
||||||
|
// is to ensure that ledger entries are immutable and globally identifiable.
|
||||||
|
//
|
||||||
|
// Finally, we add the states to the provided partial transaction.
|
||||||
|
|
||||||
|
val assetsStates = currentVault.statesOfType<Cash.State>()
|
||||||
|
|
||||||
|
val currency = amount.token
|
||||||
|
var acceptableCoins = run {
|
||||||
|
val ofCurrency = assetsStates.filter { it.state.data.amount.token.product == currency }
|
||||||
|
if (onlyFromParties != null)
|
||||||
|
ofCurrency.filter { it.state.data.deposit.party in onlyFromParties }
|
||||||
|
else
|
||||||
|
ofCurrency
|
||||||
|
}
|
||||||
|
tx.notary = acceptableCoins.firstOrNull()?.state?.notary
|
||||||
|
// TODO: We should be prepared to produce multiple transactions spending inputs from
|
||||||
|
// different notaries, or at least group states by notary and take the set with the
|
||||||
|
// highest total value
|
||||||
|
acceptableCoins = acceptableCoins.filter { it.state.notary == tx.notary }
|
||||||
|
|
||||||
|
val (gathered, gatheredAmount) = gatherCoins(acceptableCoins, amount)
|
||||||
|
val takeChangeFrom = gathered.firstOrNull()
|
||||||
|
val change = if (takeChangeFrom != null && gatheredAmount > amount) {
|
||||||
|
Amount(gatheredAmount.quantity - amount.quantity, takeChangeFrom.state.data.issuanceDef)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
val keysUsed = gathered.map { it.state.data.owner }.toSet()
|
||||||
|
|
||||||
|
val states = gathered.groupBy { it.state.data.deposit }.map {
|
||||||
|
val coins = it.value
|
||||||
|
val totalAmount = coins.map { it.state.data.amount }.sumOrThrow()
|
||||||
|
deriveState(coins.first().state, totalAmount, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
val outputs = if (change != null) {
|
||||||
|
// Just copy a key across as the change key. In real life of course, this works but leaks private data.
|
||||||
|
// In bitcoinj we derive a fresh key here and then shuffle the outputs to ensure it's hard to follow
|
||||||
|
// value flows through the transaction graph.
|
||||||
|
val changeKey = gathered.first().state.data.owner
|
||||||
|
// Add a change output and adjust the last output downwards.
|
||||||
|
states.subList(0, states.lastIndex) +
|
||||||
|
states.last().let { deriveState(it, it.data.amount - change, it.data.owner) } +
|
||||||
|
deriveState(gathered.last().state, change, changeKey)
|
||||||
|
} else states
|
||||||
|
|
||||||
|
for (state in gathered) tx.addInputState(state)
|
||||||
|
for (state in outputs) tx.addOutputState(state)
|
||||||
|
|
||||||
|
// What if we already have a move command with the right keys? Filter it out here or in platform code?
|
||||||
|
val keysList = keysUsed.toList()
|
||||||
|
tx.addCommand(Cash().generateMoveCommand(), keysList)
|
||||||
|
|
||||||
|
// update Vault
|
||||||
|
// notify(tx.toWireTransaction())
|
||||||
|
// Vault update must be completed AFTER transaction is recorded to ledger storage!!!
|
||||||
|
// (this is accomplished within the recordTransaction function)
|
||||||
|
|
||||||
|
return Pair(tx, keysList)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deriveState(txState: TransactionState<Cash.State>, amount: Amount<Issued<Currency>>, owner: PublicKey)
|
||||||
|
= txState.copy(data = txState.data.copy(amount = amount, owner = owner))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather assets from the given list of states, sufficient to match or exceed the given amount.
|
||||||
|
*
|
||||||
|
* @param acceptableCoins list of states to use as inputs.
|
||||||
|
* @param amount the amount to gather states up to.
|
||||||
|
* @throws InsufficientBalanceException if there isn't enough value in the states to cover the requested amount.
|
||||||
|
*/
|
||||||
|
@Throws(InsufficientBalanceException::class)
|
||||||
|
private fun gatherCoins(acceptableCoins: Collection<StateAndRef<Cash.State>>,
|
||||||
|
amount: Amount<Currency>): Pair<ArrayList<StateAndRef<Cash.State>>, Amount<Currency>> {
|
||||||
|
val gathered = arrayListOf<StateAndRef<Cash.State>>()
|
||||||
|
var gatheredAmount = Amount(0, amount.token)
|
||||||
|
for (c in acceptableCoins) {
|
||||||
|
if (gatheredAmount >= amount) break
|
||||||
|
gathered.add(c)
|
||||||
|
gatheredAmount += Amount(c.state.data.amount.quantity, amount.token)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gatheredAmount < amount)
|
||||||
|
throw InsufficientBalanceException(amount - gatheredAmount)
|
||||||
|
|
||||||
|
return Pair(gathered, gatheredAmount)
|
||||||
|
}
|
||||||
|
|
||||||
private fun makeUpdate(tx: WireTransaction, netDelta: Vault.Update, ourKeys: Set<PublicKey>): Vault.Update {
|
private fun makeUpdate(tx: WireTransaction, netDelta: Vault.Update, ourKeys: Set<PublicKey>): Vault.Update {
|
||||||
val ourNewStates = tx.outputs.
|
val ourNewStates = tx.outputs.
|
||||||
filter { isRelevant(it.data, ourKeys) }.
|
filter { isRelevant(it.data, ourKeys) }.
|
||||||
@ -151,4 +269,5 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import com.r3corda.core.node.services.Vault
|
|||||||
import com.r3corda.core.protocols.StateMachineRunId
|
import com.r3corda.core.protocols.StateMachineRunId
|
||||||
import com.r3corda.core.serialization.OpaqueBytes
|
import com.r3corda.core.serialization.OpaqueBytes
|
||||||
import com.r3corda.core.transactions.SignedTransaction
|
import com.r3corda.core.transactions.SignedTransaction
|
||||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
|
||||||
import com.r3corda.node.internal.ServerRPCOps
|
import com.r3corda.node.internal.ServerRPCOps
|
||||||
import com.r3corda.node.services.messaging.StateMachineUpdate
|
import com.r3corda.node.services.messaging.StateMachineUpdate
|
||||||
import com.r3corda.node.services.network.NetworkMapService
|
import com.r3corda.node.services.network.NetworkMapService
|
||||||
|
@ -88,15 +88,19 @@ class VaultWithCashTest {
|
|||||||
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), freshKey.public, DUMMY_NOTARY)
|
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), freshKey.public, DUMMY_NOTARY)
|
||||||
signWith(MEGA_CORP_KEY)
|
signWith(MEGA_CORP_KEY)
|
||||||
}.toSignedTransaction()
|
}.toSignedTransaction()
|
||||||
val myOutput = usefulTX.toLedgerTransaction(services).outRef<Cash.State>(0)
|
|
||||||
|
assertNull(vault.cashBalances[USD])
|
||||||
|
services.recordTransactions(usefulTX)
|
||||||
|
|
||||||
// A tx that spends our money.
|
// A tx that spends our money.
|
||||||
val spendTX = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
val spendTX = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||||
Cash().generateSpend(this, 80.DOLLARS, BOB_PUBKEY, listOf(myOutput))
|
vault.generateSpend(this, 80.DOLLARS, BOB_PUBKEY)
|
||||||
signWith(freshKey)
|
signWith(freshKey)
|
||||||
signWith(DUMMY_NOTARY_KEY)
|
signWith(DUMMY_NOTARY_KEY)
|
||||||
}.toSignedTransaction()
|
}.toSignedTransaction()
|
||||||
|
|
||||||
|
assertEquals(100.DOLLARS, vault.cashBalances[USD])
|
||||||
|
|
||||||
// A tx that doesn't send us anything.
|
// A tx that doesn't send us anything.
|
||||||
val irrelevantTX = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
val irrelevantTX = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||||
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), BOB_KEY.public, DUMMY_NOTARY)
|
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), BOB_KEY.public, DUMMY_NOTARY)
|
||||||
@ -104,14 +108,11 @@ class VaultWithCashTest {
|
|||||||
signWith(DUMMY_NOTARY_KEY)
|
signWith(DUMMY_NOTARY_KEY)
|
||||||
}.toSignedTransaction()
|
}.toSignedTransaction()
|
||||||
|
|
||||||
assertNull(services.vaultService.cashBalances[USD])
|
|
||||||
services.recordTransactions(usefulTX)
|
|
||||||
assertEquals(100.DOLLARS, services.vaultService.cashBalances[USD])
|
|
||||||
services.recordTransactions(irrelevantTX)
|
services.recordTransactions(irrelevantTX)
|
||||||
assertEquals(100.DOLLARS, services.vaultService.cashBalances[USD])
|
assertEquals(100.DOLLARS, vault.cashBalances[USD])
|
||||||
services.recordTransactions(spendTX)
|
services.recordTransactions(spendTX)
|
||||||
|
|
||||||
assertEquals(20.DOLLARS, services.vaultService.cashBalances[USD])
|
assertEquals(20.DOLLARS, vault.cashBalances[USD])
|
||||||
|
|
||||||
// TODO: Flesh out these tests as needed.
|
// TODO: Flesh out these tests as needed.
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import com.r3corda.node.services.persistence.PerFileCheckpointStorage
|
|||||||
import com.r3corda.node.services.transactions.InMemoryUniquenessProvider
|
import com.r3corda.node.services.transactions.InMemoryUniquenessProvider
|
||||||
import com.r3corda.node.services.transactions.SimpleNotaryService
|
import com.r3corda.node.services.transactions.SimpleNotaryService
|
||||||
import com.r3corda.node.services.transactions.ValidatingNotaryService
|
import com.r3corda.node.services.transactions.ValidatingNotaryService
|
||||||
|
import com.r3corda.node.services.vault.NodeVaultService
|
||||||
import com.r3corda.node.utilities.AffinityExecutor
|
import com.r3corda.node.utilities.AffinityExecutor
|
||||||
import com.r3corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
import com.r3corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
||||||
import com.r3corda.node.utilities.databaseTransaction
|
import com.r3corda.node.utilities.databaseTransaction
|
||||||
@ -139,7 +140,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
|
|
||||||
override fun makeIdentityService() = MockIdentityService(mockNet.identities)
|
override fun makeIdentityService() = MockIdentityService(mockNet.identities)
|
||||||
|
|
||||||
override fun makeVaultService(): VaultService = InMemoryVaultService(services)
|
override fun makeVaultService(): VaultService = NodeVaultService(services)
|
||||||
|
|
||||||
override fun makeKeyManagementService(): KeyManagementService = E2ETestKeyManagementService(partyKeys)
|
override fun makeKeyManagementService(): KeyManagementService = E2ETestKeyManagementService(partyKeys)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user