mirror of
https://github.com/corda/corda.git
synced 2025-01-22 20:38:05 +00:00
Clean up of ServiceHubInternal, including how it's created in AbstractNode
This commit is contained in:
parent
56402c744a
commit
46e23b7716
@ -1,7 +1,7 @@
|
|||||||
package net.corda.core.contracts
|
package net.corda.core.contracts
|
||||||
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.node.services.ReadOnlyTransactionStorage
|
import net.corda.core.node.services.TransactionStorage
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -18,7 +18,7 @@ import java.util.concurrent.Callable
|
|||||||
* @param transactions map of transaction id to [SignedTransaction].
|
* @param transactions map of transaction id to [SignedTransaction].
|
||||||
* @param startPoints transactions to use as starting points for the search.
|
* @param startPoints transactions to use as starting points for the search.
|
||||||
*/
|
*/
|
||||||
class TransactionGraphSearch(val transactions: ReadOnlyTransactionStorage,
|
class TransactionGraphSearch(val transactions: TransactionStorage,
|
||||||
val startPoints: List<WireTransaction>) : Callable<List<WireTransaction>> {
|
val startPoints: List<WireTransaction>) : Callable<List<WireTransaction>> {
|
||||||
class Query(
|
class Query(
|
||||||
val withCommandOfType: Class<out CommandData>? = null,
|
val withCommandOfType: Class<out CommandData>? = null,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.core.node
|
package net.corda.core.node
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.DigitalSignature
|
import net.corda.core.crypto.DigitalSignature
|
||||||
import net.corda.core.node.services.*
|
import net.corda.core.node.services.*
|
||||||
@ -17,8 +18,10 @@ import java.time.Clock
|
|||||||
*/
|
*/
|
||||||
interface ServicesForResolution {
|
interface ServicesForResolution {
|
||||||
val identityService: IdentityService
|
val identityService: IdentityService
|
||||||
|
|
||||||
/** Provides access to storage of arbitrary JAR files (which may contain only data, no code). */
|
/** Provides access to storage of arbitrary JAR files (which may contain only data, no code). */
|
||||||
val attachments: AttachmentStorage
|
val attachments: AttachmentStorage
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a [StateRef] loads the referenced transaction and looks up the specified output [ContractState].
|
* Given a [StateRef] loads the referenced transaction and looks up the specified output [ContractState].
|
||||||
*
|
*
|
||||||
@ -40,12 +43,13 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
val vaultService: VaultService
|
val vaultService: VaultService
|
||||||
val vaultQueryService: VaultQueryService
|
val vaultQueryService: VaultQueryService
|
||||||
val keyManagementService: KeyManagementService
|
val keyManagementService: KeyManagementService
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of hash->tx where tx has been signature/contract validated and the states are known to be correct.
|
* A map of hash->tx where tx has been signature/contract validated and the states are known to be correct.
|
||||||
* The signatures aren't technically needed after that point, but we keep them around so that we can relay
|
* The signatures aren't technically needed after that point, but we keep them around so that we can relay
|
||||||
* the transaction data to other nodes that need it.
|
* the transaction data to other nodes that need it.
|
||||||
*/
|
*/
|
||||||
val validatedTransactions: ReadOnlyTransactionStorage
|
val validatedTransactions: TransactionStorage
|
||||||
|
|
||||||
val networkMapCache: NetworkMapCache
|
val networkMapCache: NetworkMapCache
|
||||||
val transactionVerifierService: TransactionVerifierService
|
val transactionVerifierService: TransactionVerifierService
|
||||||
@ -60,41 +64,41 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
fun <T : SerializeAsToken> cordaService(type: Class<T>): T
|
fun <T : SerializeAsToken> cordaService(type: Class<T>): T
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a [SignedTransaction], writes it to the local storage for validated transactions and then
|
* Stores the given [SignedTransaction]s in the local transaction storage and then sends them to the vault for
|
||||||
* sends them to the vault for further processing. Expects to be run within a database transaction.
|
* further processing. This is expected to be run within a database transaction.
|
||||||
*
|
*
|
||||||
* @param txs The transactions to record.
|
* @param txs The transactions to record.
|
||||||
*/
|
*/
|
||||||
// TODO: Make this take a single tx.
|
|
||||||
fun recordTransactions(txs: Iterable<SignedTransaction>)
|
fun recordTransactions(txs: Iterable<SignedTransaction>)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given some [SignedTransaction]s, writes them to the local storage for validated transactions and then
|
* Stores the given [SignedTransaction]s in the local transaction storage and then sends them to the vault for
|
||||||
* sends them to the vault for further processing.
|
* further processing. This is expected to be run within a database transaction.
|
||||||
*
|
|
||||||
* @param txs The transactions to record.
|
|
||||||
*/
|
*/
|
||||||
fun recordTransactions(vararg txs: SignedTransaction) = recordTransactions(txs.toList())
|
fun recordTransactions(first: SignedTransaction, vararg remaining: SignedTransaction) {
|
||||||
|
recordTransactions(Lists.asList(first, remaining))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a [StateRef] loads the referenced transaction and looks up the specified output [ContractState].
|
* Given a [StateRef] loads the referenced transaction and looks up the specified output [ContractState].
|
||||||
*
|
*
|
||||||
* @throws TransactionResolutionException if the [StateRef] points to a non-existent transaction.
|
* @throws TransactionResolutionException if [stateRef] points to a non-existent transaction.
|
||||||
*/
|
*/
|
||||||
@Throws(TransactionResolutionException::class)
|
@Throws(TransactionResolutionException::class)
|
||||||
override fun loadState(stateRef: StateRef): TransactionState<*> {
|
override fun loadState(stateRef: StateRef): TransactionState<*> {
|
||||||
val definingTx = validatedTransactions.getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash)
|
val stx = validatedTransactions.getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash)
|
||||||
return definingTx.tx.outputs[stateRef.index]
|
return stx.tx.outputs[stateRef.index]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will check [logicType] and [args] against a whitelist and if acceptable then construct and initiate the protocol.
|
* Converts the given [StateRef] into a [StateAndRef] object.
|
||||||
*
|
*
|
||||||
* @throws IllegalProtocolLogicException or IllegalArgumentException if there are problems with the [logicType] or [args].
|
* @throws TransactionResolutionException if [stateRef] points to a non-existent transaction.
|
||||||
*/
|
*/
|
||||||
fun <T : ContractState> toStateAndRef(ref: StateRef): StateAndRef<T> {
|
@Throws(TransactionResolutionException::class)
|
||||||
val definingTx = validatedTransactions.getTransaction(ref.txhash) ?: throw TransactionResolutionException(ref.txhash)
|
fun <T : ContractState> toStateAndRef(stateRef: StateRef): StateAndRef<T> {
|
||||||
return definingTx.tx.outRef<T>(ref.index)
|
val stx = validatedTransactions.getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash)
|
||||||
|
return stx.tx.outRef<T>(stateRef.index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,7 +106,7 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
* Node's primary signing identity.
|
* Node's primary signing identity.
|
||||||
* Typical use is during signing in flows and for unit test signing.
|
* Typical use is during signing in flows and for unit test signing.
|
||||||
* When this [PublicKey] is passed into the signing methods below, or on the KeyManagementService
|
* When this [PublicKey] is passed into the signing methods below, or on the KeyManagementService
|
||||||
* the matching [PrivateKey] will be looked up internally and used to sign.
|
* the matching [java.security.PrivateKey] will be looked up internally and used to sign.
|
||||||
* If the key is actually a CompositeKey, the first leaf key hosted on this node
|
* If the key is actually a CompositeKey, the first leaf key hosted on this node
|
||||||
* will be used to create the signature.
|
* will be used to create the signature.
|
||||||
*/
|
*/
|
||||||
@ -114,8 +118,8 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
* otherwise an IllegalArgumentException will be thrown.
|
* otherwise an IllegalArgumentException will be thrown.
|
||||||
* Typical use is during signing in flows and for unit test signing.
|
* Typical use is during signing in flows and for unit test signing.
|
||||||
* When this [PublicKey] is passed into the signing methods below, or on the KeyManagementService
|
* When this [PublicKey] is passed into the signing methods below, or on the KeyManagementService
|
||||||
* the matching [PrivateKey] will be looked up internally and used to sign.
|
* the matching [java.security.PrivateKey] will be looked up internally and used to sign.
|
||||||
* If the key is actually a [CompositeKey], the first leaf key hosted on this node
|
* If the key is actually a [net.corda.core.crypto.CompositeKey], the first leaf key hosted on this node
|
||||||
* will be used to create the signature.
|
* will be used to create the signature.
|
||||||
*/
|
*/
|
||||||
val notaryIdentityKey: PublicKey get() = this.myInfo.notaryIdentity.owningKey
|
val notaryIdentityKey: PublicKey get() = this.myInfo.notaryIdentity.owningKey
|
||||||
@ -125,7 +129,7 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
* using keys stored inside the node.
|
* using keys stored inside the node.
|
||||||
* @param builder The [TransactionBuilder] to seal with the node's signature.
|
* @param builder The [TransactionBuilder] to seal with the node's signature.
|
||||||
* Any existing signatures on the builder will be preserved.
|
* Any existing signatures on the builder will be preserved.
|
||||||
* @param publicKey The [PublicKey] matched to the internal [PrivateKey] to use in signing this transaction.
|
* @param publicKey The [PublicKey] matched to the internal [java.security.PrivateKey] to use in signing this transaction.
|
||||||
* If the passed in key is actually a CompositeKey the code searches for the first child key hosted within this node
|
* If the passed in key is actually a CompositeKey the code searches for the first child key hosted within this node
|
||||||
* to sign with.
|
* to sign with.
|
||||||
* @return Returns a SignedTransaction with the new node signature attached.
|
* @return Returns a SignedTransaction with the new node signature attached.
|
||||||
@ -150,30 +154,30 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
* using a set of keys all held in this node.
|
* using a set of keys all held in this node.
|
||||||
* @param builder The [TransactionBuilder] to seal with the node's signature.
|
* @param builder The [TransactionBuilder] to seal with the node's signature.
|
||||||
* Any existing signatures on the builder will be preserved.
|
* Any existing signatures on the builder will be preserved.
|
||||||
* @param signingPubKeys A list of [PublicKeys] used to lookup the matching [PrivateKey] and sign.
|
* @param signingPubKeys A list of [PublicKey]s used to lookup the matching [java.security.PrivateKey] and sign.
|
||||||
* @throws IllegalArgumentException is thrown if any keys are unavailable locally.
|
* @throws IllegalArgumentException is thrown if any keys are unavailable locally.
|
||||||
* @return Returns a [SignedTransaction] with the new node signature attached.
|
* @return Returns a [SignedTransaction] with the new node signature attached.
|
||||||
*/
|
*/
|
||||||
fun signInitialTransaction(builder: TransactionBuilder, signingPubKeys: Iterable<PublicKey>): SignedTransaction {
|
fun signInitialTransaction(builder: TransactionBuilder, signingPubKeys: Iterable<PublicKey>): SignedTransaction {
|
||||||
var stx: SignedTransaction? = null
|
val it = signingPubKeys.iterator()
|
||||||
for (pubKey in signingPubKeys) {
|
var stx = signInitialTransaction(builder, it.next())
|
||||||
stx = if (stx == null) {
|
while (it.hasNext()) {
|
||||||
signInitialTransaction(builder, pubKey)
|
stx = addSignature(stx, it.next())
|
||||||
} else {
|
|
||||||
addSignature(stx, pubKey)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return stx!!
|
return stx
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to create an additional signature for an existing (partially) [SignedTransaction].
|
* Helper method to create an additional signature for an existing (partially) [SignedTransaction].
|
||||||
* @param signedTransaction The [SignedTransaction] to which the signature will apply.
|
* @param signedTransaction The [SignedTransaction] to which the signature will apply.
|
||||||
* @param publicKey The [PublicKey] matching to a signing [PrivateKey] hosted in the node.
|
* @param publicKey The [PublicKey] matching to a signing [java.security.PrivateKey] hosted in the node.
|
||||||
* If the [PublicKey] is actually a [CompositeKey] the first leaf key found locally will be used for signing.
|
* If the [PublicKey] is actually a [net.corda.core.crypto.CompositeKey] the first leaf key found locally will be used
|
||||||
* @return The [DigitalSignature.WithKey] generated by signing with the internally held [PrivateKey].
|
* for signing.
|
||||||
|
* @return The [DigitalSignature.WithKey] generated by signing with the internally held [java.security.PrivateKey].
|
||||||
*/
|
*/
|
||||||
fun createSignature(signedTransaction: SignedTransaction, publicKey: PublicKey): DigitalSignature.WithKey = keyManagementService.sign(signedTransaction.id.bytes, publicKey)
|
fun createSignature(signedTransaction: SignedTransaction, publicKey: PublicKey): DigitalSignature.WithKey {
|
||||||
|
return keyManagementService.sign(signedTransaction.id.bytes, publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to create an additional signature for an existing (partially) SignedTransaction
|
* Helper method to create an additional signature for an existing (partially) SignedTransaction
|
||||||
@ -181,16 +185,21 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
* @param signedTransaction The SignedTransaction to which the signature will apply.
|
* @param signedTransaction The SignedTransaction to which the signature will apply.
|
||||||
* @return The DigitalSignature.WithKey generated by signing with the internally held identity PrivateKey.
|
* @return The DigitalSignature.WithKey generated by signing with the internally held identity PrivateKey.
|
||||||
*/
|
*/
|
||||||
fun createSignature(signedTransaction: SignedTransaction): DigitalSignature.WithKey = createSignature(signedTransaction, legalIdentityKey)
|
fun createSignature(signedTransaction: SignedTransaction): DigitalSignature.WithKey {
|
||||||
|
return createSignature(signedTransaction, legalIdentityKey)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to append an additional signature to an existing (partially) [SignedTransaction].
|
* Helper method to append an additional signature to an existing (partially) [SignedTransaction].
|
||||||
* @param signedTransaction The [SignedTransaction] to which the signature will be added.
|
* @param signedTransaction The [SignedTransaction] to which the signature will be added.
|
||||||
* @param publicKey The [PublicKey] matching to a signing [PrivateKey] hosted in the node.
|
* @param publicKey The [PublicKey] matching to a signing [java.security.PrivateKey] hosted in the node.
|
||||||
* If the [PublicKey] is actually a [CompositeKey] the first leaf key found locally will be used for signing.
|
* If the [PublicKey] is actually a [net.corda.core.crypto.CompositeKey] the first leaf key found locally will be used
|
||||||
|
* for signing.
|
||||||
* @return A new [SignedTransaction] with the addition of the new signature.
|
* @return A new [SignedTransaction] with the addition of the new signature.
|
||||||
*/
|
*/
|
||||||
fun addSignature(signedTransaction: SignedTransaction, publicKey: PublicKey): SignedTransaction = signedTransaction + createSignature(signedTransaction, publicKey)
|
fun addSignature(signedTransaction: SignedTransaction, publicKey: PublicKey): SignedTransaction {
|
||||||
|
return signedTransaction + createSignature(signedTransaction, publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to ap-pend an additional signature for an existing (partially) [SignedTransaction]
|
* Helper method to ap-pend an additional signature for an existing (partially) [SignedTransaction]
|
||||||
|
@ -2,21 +2,14 @@ package net.corda.core.node.services
|
|||||||
|
|
||||||
import net.corda.core.contracts.Attachment
|
import net.corda.core.contracts.Attachment
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.nio.file.Path
|
import java.nio.file.FileAlreadyExistsException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An attachment store records potentially large binary objects, identified by their hash.
|
* An attachment store records potentially large binary objects, identified by their hash.
|
||||||
*/
|
*/
|
||||||
interface AttachmentStorage {
|
interface AttachmentStorage {
|
||||||
/**
|
|
||||||
* If true, newly inserted attachments will be unzipped to a subdirectory of the [storePath]. This is intended for
|
|
||||||
* human browsing convenience: the attachment itself will still be the file (that is, edits to the extracted directory
|
|
||||||
* will not have any effect).
|
|
||||||
*/
|
|
||||||
var automaticallyExtractAttachments: Boolean
|
|
||||||
var storePath: Path
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a handle to a locally stored attachment, or null if it's not known. The handle can be used to open
|
* Returns a handle to a locally stored attachment, or null if it's not known. The handle can be used to open
|
||||||
* a stream for the data, which will be a zip/jar file.
|
* a stream for the data, which will be a zip/jar file.
|
||||||
@ -27,13 +20,14 @@ interface AttachmentStorage {
|
|||||||
* Inserts the given attachment into the store, does *not* close the input stream. This can be an intensive
|
* Inserts the given attachment into the store, does *not* close the input stream. This can be an intensive
|
||||||
* operation due to the need to copy the bytes to disk and hash them along the way.
|
* operation due to the need to copy the bytes to disk and hash them along the way.
|
||||||
*
|
*
|
||||||
* Note that you should not pass a [JarInputStream] into this method and it will throw if you do, because access
|
* Note that you should not pass a [java.util.jar.JarInputStream] into this method and it will throw if you do, because
|
||||||
* to the raw byte stream is required.
|
* access to the raw byte stream is required.
|
||||||
*
|
*
|
||||||
* @throws FileAlreadyExistsException if the given byte stream has already been inserted.
|
* @throws FileAlreadyExistsException if the given byte stream has already been inserted.
|
||||||
* @throws IllegalArgumentException if the given byte stream is empty or a [JarInputStream].
|
* @throws IllegalArgumentException if the given byte stream is empty or a [java.util.jar.JarInputStream].
|
||||||
* @throws IOException if something went wrong.
|
* @throws IOException if something went wrong.
|
||||||
*/
|
*/
|
||||||
|
@Throws(FileAlreadyExistsException::class, IOException::class)
|
||||||
fun importAttachment(jar: InputStream): SecureHash
|
fun importAttachment(jar: InputStream): SecureHash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import rx.Observable
|
|||||||
/**
|
/**
|
||||||
* Thread-safe storage of transactions.
|
* Thread-safe storage of transactions.
|
||||||
*/
|
*/
|
||||||
interface ReadOnlyTransactionStorage {
|
interface TransactionStorage {
|
||||||
/**
|
/**
|
||||||
* Return the transaction with the given [id], or null if no such transaction exists.
|
* Return the transaction with the given [id], or null if no such transaction exists.
|
||||||
*/
|
*/
|
||||||
@ -24,18 +24,4 @@ interface ReadOnlyTransactionStorage {
|
|||||||
* Returns all currently stored transactions and further fresh ones.
|
* Returns all currently stored transactions and further fresh ones.
|
||||||
*/
|
*/
|
||||||
fun track(): DataFeed<List<SignedTransaction>, SignedTransaction>
|
fun track(): DataFeed<List<SignedTransaction>, SignedTransaction>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Thread-safe storage of transactions.
|
|
||||||
*/
|
|
||||||
interface TransactionStorage : ReadOnlyTransactionStorage {
|
|
||||||
/**
|
|
||||||
* Add a new transaction to the store. If the store already has a transaction with the same id it will be
|
|
||||||
* overwritten.
|
|
||||||
* @param transaction The transaction to be recorded.
|
|
||||||
* @return true if the transaction was recorded successfully, false if it was already recorded.
|
|
||||||
*/
|
|
||||||
// TODO: Throw an exception if trying to add a transaction with fewer signatures than an existing entry.
|
|
||||||
fun addTransaction(transaction: SignedTransaction): Boolean
|
|
||||||
}
|
|
@ -74,16 +74,15 @@ class FinalityFlow(val transactions: Iterable<SignedTransaction>,
|
|||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
private fun notariseAndRecord(stxnsAndParties: List<Pair<SignedTransaction, Set<Party>>>): List<Pair<SignedTransaction, Set<Party>>> {
|
private fun notariseAndRecord(stxnsAndParties: List<Pair<SignedTransaction, Set<Party>>>): List<Pair<SignedTransaction, Set<Party>>> {
|
||||||
return stxnsAndParties.map { pair ->
|
return stxnsAndParties.map { (stx, parties) ->
|
||||||
val stx = pair.first
|
|
||||||
val notarised = if (needsNotarySignature(stx)) {
|
val notarised = if (needsNotarySignature(stx)) {
|
||||||
val notarySignatures = subFlow(NotaryFlow.Client(stx))
|
val notarySignatures = subFlow(NotaryFlow.Client(stx))
|
||||||
stx + notarySignatures
|
stx + notarySignatures
|
||||||
} else {
|
} else {
|
||||||
stx
|
stx
|
||||||
}
|
}
|
||||||
serviceHub.recordTransactions(listOf(notarised))
|
serviceHub.recordTransactions(notarised)
|
||||||
Pair(notarised, pair.second)
|
Pair(notarised, parties)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,8 +100,7 @@ class FinalityFlow(val transactions: Iterable<SignedTransaction>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun lookupParties(ltxns: List<Pair<SignedTransaction, LedgerTransaction>>): List<Pair<SignedTransaction, Set<Party>>> {
|
private fun lookupParties(ltxns: List<Pair<SignedTransaction, LedgerTransaction>>): List<Pair<SignedTransaction, Set<Party>>> {
|
||||||
return ltxns.map { pair ->
|
return ltxns.map { (stx, ltx) ->
|
||||||
val (stx, ltx) = pair
|
|
||||||
// Calculate who is meant to see the results based on the participants involved.
|
// Calculate who is meant to see the results based on the participants involved.
|
||||||
val keys = ltx.outputs.flatMap { it.data.participants } + ltx.inputs.flatMap { it.state.data.participants }
|
val keys = ltx.outputs.flatMap { it.data.participants } + ltx.inputs.flatMap { it.state.data.participants }
|
||||||
// TODO: Is it safe to drop participants we don't know how to contact? Does not knowing how to contact them count as a reason to fail?
|
// TODO: Is it safe to drop participants we don't know how to contact? Does not knowing how to contact them count as a reason to fail?
|
||||||
|
@ -178,14 +178,14 @@ class ContractUpgradeFlowTest {
|
|||||||
mockNet.runNetwork()
|
mockNet.runNetwork()
|
||||||
val stx = result.getOrThrow().stx
|
val stx = result.getOrThrow().stx
|
||||||
val stateAndRef = stx.tx.outRef<Cash.State>(0)
|
val stateAndRef = stx.tx.outRef<Cash.State>(0)
|
||||||
val baseState = a.database.transaction { a.vault.unconsumedStates<ContractState>().single() }
|
val baseState = a.database.transaction { a.services.vaultService.unconsumedStates<ContractState>().single() }
|
||||||
assertTrue(baseState.state.data is Cash.State, "Contract state is old version.")
|
assertTrue(baseState.state.data is Cash.State, "Contract state is old version.")
|
||||||
// Starts contract upgrade flow.
|
// Starts contract upgrade flow.
|
||||||
val upgradeResult = a.services.startFlow(ContractUpgradeFlow(stateAndRef, CashV2::class.java)).resultFuture
|
val upgradeResult = a.services.startFlow(ContractUpgradeFlow(stateAndRef, CashV2::class.java)).resultFuture
|
||||||
mockNet.runNetwork()
|
mockNet.runNetwork()
|
||||||
upgradeResult.getOrThrow()
|
upgradeResult.getOrThrow()
|
||||||
// Get contract state from the vault.
|
// Get contract state from the vault.
|
||||||
val firstState = a.database.transaction { a.vault.unconsumedStates<ContractState>().single() }
|
val firstState = a.database.transaction { a.services.vaultService.unconsumedStates<ContractState>().single() }
|
||||||
assertTrue(firstState.state.data is CashV2.State, "Contract state is upgraded to the new version.")
|
assertTrue(firstState.state.data is CashV2.State, "Contract state is upgraded to the new version.")
|
||||||
assertEquals(Amount(1000000, USD).`issued by`(a.info.legalIdentity.ref(1)), (firstState.state.data as CashV2.State).amount, "Upgraded cash contain the correct amount.")
|
assertEquals(Amount(1000000, USD).`issued by`(a.info.legalIdentity.ref(1)), (firstState.state.data as CashV2.State).amount, "Upgraded cash contain the correct amount.")
|
||||||
assertEquals<Collection<AbstractParty>>(listOf(a.info.legalIdentity), (firstState.state.data as CashV2.State).owners, "Upgraded cash belongs to the right owner.")
|
assertEquals<Collection<AbstractParty>>(listOf(a.info.legalIdentity), (firstState.state.data as CashV2.State).owners, "Upgraded cash belongs to the right owner.")
|
||||||
|
@ -33,8 +33,8 @@ class CashPaymentFlowTests {
|
|||||||
bankOfCorda = bankOfCordaNode.info.legalIdentity
|
bankOfCorda = bankOfCordaNode.info.legalIdentity
|
||||||
|
|
||||||
notaryNode.registerInitiatedFlow(TxKeyFlow.Provider::class.java)
|
notaryNode.registerInitiatedFlow(TxKeyFlow.Provider::class.java)
|
||||||
notaryNode.identity.registerIdentity(bankOfCordaNode.info.legalIdentityAndCert)
|
notaryNode.services.identityService.registerIdentity(bankOfCordaNode.info.legalIdentityAndCert)
|
||||||
bankOfCordaNode.identity.registerIdentity(notaryNode.info.legalIdentityAndCert)
|
bankOfCordaNode.services.identityService.registerIdentity(notaryNode.info.legalIdentityAndCert)
|
||||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(initialBalance, ref,
|
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(initialBalance, ref,
|
||||||
bankOfCorda,
|
bankOfCorda,
|
||||||
notary)).resultFuture
|
notary)).resultFuture
|
||||||
|
@ -5,8 +5,8 @@ import net.corda.core.contracts.DummyContract
|
|||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.contracts.TransactionType
|
import net.corda.core.contracts.TransactionType
|
||||||
import net.corda.core.identity.Party
|
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.map
|
import net.corda.core.map
|
||||||
import net.corda.core.utilities.DUMMY_BANK_A
|
import net.corda.core.utilities.DUMMY_BANK_A
|
||||||
import net.corda.flows.NotaryError
|
import net.corda.flows.NotaryError
|
||||||
@ -26,28 +26,28 @@ class RaftNotaryServiceTests : NodeBasedTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `detect double spend`() {
|
fun `detect double spend`() {
|
||||||
val (masterNode, alice) = Futures.allAsList(
|
val (bankA) = Futures.allAsList(
|
||||||
startNotaryCluster(notaryName, 3).map { it.first() },
|
startNode(DUMMY_BANK_A.name),
|
||||||
startNode(DUMMY_BANK_A.name)
|
startNotaryCluster(notaryName, 3).map { it.first() }
|
||||||
).getOrThrow()
|
).getOrThrow()
|
||||||
|
|
||||||
val notaryParty = alice.netMapCache.getNotary(notaryName)!!
|
val notaryParty = bankA.services.networkMapCache.getNotary(notaryName)!!
|
||||||
|
|
||||||
val inputState = issueState(alice, notaryParty)
|
val inputState = issueState(bankA, notaryParty)
|
||||||
|
|
||||||
val firstTxBuilder = TransactionType.General.Builder(notaryParty).withItems(inputState)
|
val firstTxBuilder = TransactionType.General.Builder(notaryParty).withItems(inputState)
|
||||||
val firstSpendTx = alice.services.signInitialTransaction(firstTxBuilder)
|
val firstSpendTx = bankA.services.signInitialTransaction(firstTxBuilder)
|
||||||
|
|
||||||
val firstSpend = alice.services.startFlow(NotaryFlow.Client(firstSpendTx))
|
val firstSpend = bankA.services.startFlow(NotaryFlow.Client(firstSpendTx))
|
||||||
firstSpend.resultFuture.getOrThrow()
|
firstSpend.resultFuture.getOrThrow()
|
||||||
|
|
||||||
val secondSpendBuilder = TransactionType.General.Builder(notaryParty).withItems(inputState).run {
|
val secondSpendBuilder = TransactionType.General.Builder(notaryParty).withItems(inputState).run {
|
||||||
val dummyState = DummyContract.SingleOwnerState(0, alice.info.legalIdentity)
|
val dummyState = DummyContract.SingleOwnerState(0, bankA.info.legalIdentity)
|
||||||
addOutputState(dummyState)
|
addOutputState(dummyState)
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
val secondSpendTx = alice.services.signInitialTransaction(secondSpendBuilder)
|
val secondSpendTx = bankA.services.signInitialTransaction(secondSpendBuilder)
|
||||||
val secondSpend = alice.services.startFlow(NotaryFlow.Client(secondSpendTx))
|
val secondSpend = bankA.services.startFlow(NotaryFlow.Client(secondSpendTx))
|
||||||
|
|
||||||
val ex = assertFailsWith(NotaryException::class) { secondSpend.resultFuture.getOrThrow() }
|
val ex = assertFailsWith(NotaryException::class) { secondSpend.resultFuture.getOrThrow() }
|
||||||
val error = ex.error as NotaryError.Conflict
|
val error = ex.error as NotaryError.Conflict
|
||||||
@ -58,7 +58,7 @@ class RaftNotaryServiceTests : NodeBasedTest() {
|
|||||||
return node.database.transaction {
|
return node.database.transaction {
|
||||||
val builder = DummyContract.generateInitial(Random().nextInt(), notary, node.info.legalIdentity.ref(0))
|
val builder = DummyContract.generateInitial(Random().nextInt(), notary, node.info.legalIdentity.ref(0))
|
||||||
val stx = node.services.signInitialTransaction(builder)
|
val stx = node.services.signInitialTransaction(builder)
|
||||||
node.services.recordTransactions(listOf(stx))
|
node.services.recordTransactions(stx)
|
||||||
StateAndRef(builder.outputStates().first(), StateRef(stx.id, 0))
|
StateAndRef(builder.outputStates().first(), StateRef(stx.id, 0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ import net.corda.core.messaging.SingleMessageRecipient
|
|||||||
import net.corda.core.node.*
|
import net.corda.core.node.*
|
||||||
import net.corda.core.node.services.*
|
import net.corda.core.node.services.*
|
||||||
import net.corda.core.node.services.NetworkMapCache.MapChange
|
import net.corda.core.node.services.NetworkMapCache.MapChange
|
||||||
import net.corda.core.node.services.NotaryService
|
|
||||||
import net.corda.core.serialization.SerializeAsToken
|
import net.corda.core.serialization.SerializeAsToken
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
@ -42,6 +41,7 @@ import net.corda.node.services.messaging.MessagingService
|
|||||||
import net.corda.node.services.messaging.sendRequest
|
import net.corda.node.services.messaging.sendRequest
|
||||||
import net.corda.node.services.network.InMemoryNetworkMapCache
|
import net.corda.node.services.network.InMemoryNetworkMapCache
|
||||||
import net.corda.node.services.network.NetworkMapService
|
import net.corda.node.services.network.NetworkMapService
|
||||||
|
import net.corda.node.services.network.NetworkMapService.RegistrationRequest
|
||||||
import net.corda.node.services.network.NetworkMapService.RegistrationResponse
|
import net.corda.node.services.network.NetworkMapService.RegistrationResponse
|
||||||
import net.corda.node.services.network.NodeRegistration
|
import net.corda.node.services.network.NodeRegistration
|
||||||
import net.corda.node.services.network.PersistentNetworkMapService
|
import net.corda.node.services.network.PersistentNetworkMapService
|
||||||
@ -122,78 +122,18 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
private val flowFactories = ConcurrentHashMap<Class<out FlowLogic<*>>, InitiatedFlowFactory<*>>()
|
private val flowFactories = ConcurrentHashMap<Class<out FlowLogic<*>>, InitiatedFlowFactory<*>>()
|
||||||
protected val partyKeys = mutableSetOf<KeyPair>()
|
protected val partyKeys = mutableSetOf<KeyPair>()
|
||||||
|
|
||||||
val services = object : ServiceHubInternal {
|
val services: ServiceHubInternal get() = _services
|
||||||
override val attachments: AttachmentStorage get() = this@AbstractNode.attachments
|
|
||||||
override val uploaders: List<FileUploader> get() = this@AbstractNode.uploaders
|
|
||||||
override val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage
|
|
||||||
get() = this@AbstractNode.transactionMappings
|
|
||||||
override val validatedTransactions: TransactionStorage get() = this@AbstractNode.transactions
|
|
||||||
override val networkService: MessagingService get() = network
|
|
||||||
override val networkMapCache: NetworkMapCacheInternal get() = netMapCache
|
|
||||||
override val vaultService: VaultService get() = vault
|
|
||||||
override val vaultQueryService: VaultQueryService get() = vaultQuery
|
|
||||||
override val keyManagementService: KeyManagementService get() = keyManagement
|
|
||||||
override val identityService: IdentityService get() = identity
|
|
||||||
override val schedulerService: SchedulerService get() = scheduler
|
|
||||||
override val clock: Clock get() = platformClock
|
|
||||||
override val myInfo: NodeInfo get() = info
|
|
||||||
override val schemaService: SchemaService get() = schemas
|
|
||||||
override val transactionVerifierService: TransactionVerifierService get() = txVerifierService
|
|
||||||
override val auditService: AuditService get() = this@AbstractNode.auditService
|
|
||||||
override val database: Database get() = this@AbstractNode.database
|
|
||||||
override val configuration: NodeConfiguration get() = this@AbstractNode.configuration
|
|
||||||
|
|
||||||
override fun <T : SerializeAsToken> cordaService(type: Class<T>): T {
|
|
||||||
require(type.isAnnotationPresent(CordaService::class.java)) { "${type.name} is not a Corda service" }
|
|
||||||
return cordappServices.getInstance(type) ?: throw IllegalArgumentException("Corda service ${type.name} does not exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
override val rpcFlows: List<Class<out FlowLogic<*>>> get() = this@AbstractNode.rpcFlows
|
|
||||||
|
|
||||||
// Internal only
|
|
||||||
override val monitoringService: MonitoringService = MonitoringService(MetricRegistry())
|
|
||||||
|
|
||||||
override fun <T> startFlow(logic: FlowLogic<T>, flowInitiator: FlowInitiator): FlowStateMachineImpl<T> {
|
|
||||||
return serverThread.fetchFrom { smm.add(logic, flowInitiator) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>): InitiatedFlowFactory<*>? {
|
|
||||||
return flowFactories[initiatingFlowClass]
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
|
||||||
database.transaction {
|
|
||||||
super.recordTransactions(txs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun findMyLocation(): WorldMapLocation? {
|
|
||||||
return configuration.myLegalName.locationOrNull?.let { CityDatabase[it] }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private lateinit var _services: ServiceHubInternalImpl
|
||||||
lateinit var info: NodeInfo
|
lateinit var info: NodeInfo
|
||||||
lateinit var checkpointStorage: CheckpointStorage
|
lateinit var checkpointStorage: CheckpointStorage
|
||||||
lateinit var smm: StateMachineManager
|
lateinit var smm: StateMachineManager
|
||||||
lateinit var attachments: NodeAttachmentService
|
lateinit var attachments: NodeAttachmentService
|
||||||
lateinit var transactions: TransactionStorage
|
|
||||||
lateinit var transactionMappings: StateMachineRecordedTransactionMappingStorage
|
|
||||||
lateinit var uploaders: List<FileUploader>
|
|
||||||
lateinit var vault: VaultService
|
|
||||||
lateinit var vaultQuery: VaultQueryService
|
|
||||||
lateinit var keyManagement: KeyManagementService
|
|
||||||
var inNodeNetworkMapService: NetworkMapService? = null
|
var inNodeNetworkMapService: NetworkMapService? = null
|
||||||
lateinit var txVerifierService: TransactionVerifierService
|
|
||||||
lateinit var identity: IdentityService
|
|
||||||
lateinit var network: MessagingService
|
lateinit var network: MessagingService
|
||||||
lateinit var netMapCache: NetworkMapCacheInternal
|
|
||||||
lateinit var scheduler: NodeSchedulerService
|
|
||||||
lateinit var schemas: SchemaService
|
|
||||||
lateinit var auditService: AuditService
|
|
||||||
protected val runOnStop = ArrayList<() -> Any?>()
|
protected val runOnStop = ArrayList<() -> Any?>()
|
||||||
lateinit var database: Database
|
lateinit var database: Database
|
||||||
protected var dbCloser: (() -> Any?)? = null
|
protected var dbCloser: (() -> Any?)? = null
|
||||||
private lateinit var rpcFlows: List<Class<out FlowLogic<*>>>
|
|
||||||
|
|
||||||
var isPreviousCheckpointsPresent = false
|
var isPreviousCheckpointsPresent = false
|
||||||
private set
|
private set
|
||||||
@ -215,6 +155,10 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
/** The implementation of the [CordaRPCOps] interface used by this node. */
|
/** The implementation of the [CordaRPCOps] interface used by this node. */
|
||||||
open val rpcOps: CordaRPCOps by lazy { CordaRPCOpsImpl(services, smm, database) } // Lazy to avoid init ordering issue with the SMM.
|
open val rpcOps: CordaRPCOps by lazy { CordaRPCOpsImpl(services, smm, database) } // Lazy to avoid init ordering issue with the SMM.
|
||||||
|
|
||||||
|
open fun findMyLocation(): WorldMapLocation? {
|
||||||
|
return configuration.myLegalName.locationOrNull?.let { CityDatabase[it] }
|
||||||
|
}
|
||||||
|
|
||||||
open fun start(): AbstractNode {
|
open fun start(): AbstractNode {
|
||||||
require(!started) { "Node has already been started" }
|
require(!started) { "Node has already been started" }
|
||||||
|
|
||||||
@ -233,8 +177,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
|
|
||||||
// Do all of this in a database transaction so anything that might need a connection has one.
|
// Do all of this in a database transaction so anything that might need a connection has one.
|
||||||
initialiseDatabasePersistence {
|
initialiseDatabasePersistence {
|
||||||
val keyStoreWrapper = KeyStoreWrapper(configuration.trustStoreFile, configuration.trustStorePassword)
|
val tokenizableServices = makeServices()
|
||||||
val tokenizableServices = makeServices(keyStoreWrapper)
|
|
||||||
|
|
||||||
smm = StateMachineManager(services,
|
smm = StateMachineManager(services,
|
||||||
checkpointStorage,
|
checkpointStorage,
|
||||||
@ -266,9 +209,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
if (scanResult != null) {
|
if (scanResult != null) {
|
||||||
installCordaServices(scanResult)
|
installCordaServices(scanResult)
|
||||||
registerInitiatedFlows(scanResult)
|
registerInitiatedFlows(scanResult)
|
||||||
rpcFlows = findRPCFlows(scanResult)
|
findRPCFlows(scanResult)
|
||||||
} else {
|
|
||||||
rpcFlows = emptyList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Investigate having class path scanning find this flow
|
// TODO: Investigate having class path scanning find this flow
|
||||||
@ -283,7 +224,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
smm.start()
|
smm.start()
|
||||||
// Shut down the SMM so no Fibers are scheduled.
|
// Shut down the SMM so no Fibers are scheduled.
|
||||||
runOnStop += { smm.stop(acceptableLiveFiberCountOnStop()) }
|
runOnStop += { smm.stop(acceptableLiveFiberCountOnStop()) }
|
||||||
scheduler.start()
|
_services.schedulerService.start()
|
||||||
}
|
}
|
||||||
started = true
|
started = true
|
||||||
return this
|
return this
|
||||||
@ -301,7 +242,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return scanResult.getClassesWithAnnotation(SerializeAsToken::class, CordaService::class)
|
scanResult.getClassesWithAnnotation(SerializeAsToken::class, CordaService::class)
|
||||||
.filter {
|
.filter {
|
||||||
val serviceType = getServiceType(it)
|
val serviceType = getServiceType(it)
|
||||||
if (serviceType != null && info.serviceIdentities(serviceType).isEmpty()) {
|
if (serviceType != null && info.serviceIdentities(serviceType).isEmpty()) {
|
||||||
@ -434,19 +375,21 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
return observable
|
return observable
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findRPCFlows(scanResult: ScanResult): List<Class<out FlowLogic<*>>> {
|
private fun findRPCFlows(scanResult: ScanResult) {
|
||||||
fun Class<out FlowLogic<*>>.isUserInvokable(): Boolean {
|
fun Class<out FlowLogic<*>>.isUserInvokable(): Boolean {
|
||||||
return isPublic(modifiers) && !isLocalClass && !isAnonymousClass && (!isMemberClass || isStatic(modifiers))
|
return isPublic(modifiers) && !isLocalClass && !isAnonymousClass && (!isMemberClass || isStatic(modifiers))
|
||||||
}
|
}
|
||||||
|
|
||||||
return scanResult.getClassesWithAnnotation(FlowLogic::class, StartableByRPC::class).filter { it.isUserInvokable() } +
|
_services.rpcFlows += scanResult
|
||||||
// Add any core flows here
|
.getClassesWithAnnotation(FlowLogic::class, StartableByRPC::class)
|
||||||
listOf(
|
.filter { it.isUserInvokable() } +
|
||||||
ContractUpgradeFlow::class.java,
|
// Add any core flows here
|
||||||
// TODO Remove all Cash flows from default list once they are split into separate CorDapp.
|
listOf(
|
||||||
CashIssueFlow::class.java,
|
ContractUpgradeFlow::class.java,
|
||||||
CashExitFlow::class.java,
|
// TODO Remove all Cash flows from default list once they are split into separate CorDapp.
|
||||||
CashPaymentFlow::class.java)
|
CashIssueFlow::class.java,
|
||||||
|
CashExitFlow::class.java,
|
||||||
|
CashPaymentFlow::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -476,36 +419,20 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
* Builds node internal, advertised, and plugin services.
|
* Builds node internal, advertised, and plugin services.
|
||||||
* Returns a list of tokenizable services to be added to the serialisation context.
|
* Returns a list of tokenizable services to be added to the serialisation context.
|
||||||
*/
|
*/
|
||||||
private fun makeServices(keyStoreWrapper: KeyStoreWrapper): MutableList<Any> {
|
private fun makeServices(): MutableList<Any> {
|
||||||
val keyStore = keyStoreWrapper.keyStore
|
|
||||||
attachments = createAttachmentStorage()
|
|
||||||
transactions = createTransactionStorage()
|
|
||||||
transactionMappings = DBTransactionMappingStorage()
|
|
||||||
checkpointStorage = DBCheckpointStorage()
|
checkpointStorage = DBCheckpointStorage()
|
||||||
netMapCache = InMemoryNetworkMapCache(services)
|
_services = ServiceHubInternalImpl()
|
||||||
|
attachments = createAttachmentStorage()
|
||||||
network = makeMessagingService()
|
network = makeMessagingService()
|
||||||
schemas = makeSchemaService()
|
|
||||||
vault = makeVaultService(configuration.dataSourceProperties)
|
|
||||||
vaultQuery = makeVaultQueryService(schemas)
|
|
||||||
txVerifierService = makeTransactionVerifierService()
|
|
||||||
auditService = DummyAuditService()
|
|
||||||
|
|
||||||
info = makeInfo()
|
info = makeInfo()
|
||||||
identity = makeIdentityService(keyStore.getCertificate(X509Utilities.CORDA_ROOT_CA)!! as X509Certificate,
|
|
||||||
keyStoreWrapper.certificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA),
|
|
||||||
info.legalIdentityAndCert)
|
|
||||||
// Place the long term identity key in the KMS. Eventually, this is likely going to be separated again because
|
|
||||||
// the KMS is meant for derived temporary keys used in transactions, and we're not supposed to sign things with
|
|
||||||
// the identity key. But the infrastructure to make that easy isn't here yet.
|
|
||||||
keyManagement = makeKeyManagementService(identity)
|
|
||||||
scheduler = NodeSchedulerService(services, database, unfinishedSchedules = busyNodeLatch)
|
|
||||||
|
|
||||||
val tokenizableServices = mutableListOf(attachments, network, vault, vaultQuery, keyManagement, identity, platformClock, scheduler)
|
val tokenizableServices = mutableListOf(attachments, network, services.vaultService, services.vaultQueryService,
|
||||||
|
services.keyManagementService, services.identityService, platformClock, services.schedulerService)
|
||||||
makeAdvertisedServices(tokenizableServices)
|
makeAdvertisedServices(tokenizableServices)
|
||||||
return tokenizableServices
|
return tokenizableServices
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun createTransactionStorage(): TransactionStorage = DBTransactionStorage()
|
protected open fun makeTransactionStorage(): WritableTransactionStorage = DBTransactionStorage()
|
||||||
|
|
||||||
private fun scanCordapps(): ScanResult? {
|
private fun scanCordapps(): ScanResult? {
|
||||||
val scanPackage = System.getProperty("net.corda.node.cordapp.scan.package")
|
val scanPackage = System.getProperty("net.corda.node.cordapp.scan.package")
|
||||||
@ -560,14 +487,15 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initUploaders() {
|
private fun initUploaders() {
|
||||||
uploaders = listOf(attachments) + cordappServices.values.filterIsInstance(AcceptsFileUpload::class.java)
|
_services.uploaders += attachments
|
||||||
|
cordappServices.values.filterIsInstanceTo(_services.uploaders, AcceptsFileUpload::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeVaultObservers() {
|
private fun makeVaultObservers() {
|
||||||
VaultSoftLockManager(vault, smm)
|
VaultSoftLockManager(services.vaultService, smm)
|
||||||
CashBalanceAsMetricsObserver(services, database)
|
CashBalanceAsMetricsObserver(services, database)
|
||||||
ScheduledActivityObserver(services)
|
ScheduledActivityObserver(services)
|
||||||
HibernateObserver(vault.rawUpdates, HibernateConfiguration(schemas))
|
HibernateObserver(services.vaultService.rawUpdates, HibernateConfiguration(services.schemaService))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeInfo(): NodeInfo {
|
private fun makeInfo(): NodeInfo {
|
||||||
@ -684,7 +612,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
val expires = instant + NetworkMapService.DEFAULT_EXPIRATION_PERIOD
|
val expires = instant + NetworkMapService.DEFAULT_EXPIRATION_PERIOD
|
||||||
val reg = NodeRegistration(info, instant.toEpochMilli(), ADD, expires)
|
val reg = NodeRegistration(info, instant.toEpochMilli(), ADD, expires)
|
||||||
val legalIdentityKey = obtainLegalIdentityKey()
|
val legalIdentityKey = obtainLegalIdentityKey()
|
||||||
val request = NetworkMapService.RegistrationRequest(reg.toWire(keyManagement, legalIdentityKey.public), network.myAddress)
|
val request = RegistrationRequest(reg.toWire(services.keyManagementService, legalIdentityKey.public), network.myAddress)
|
||||||
return network.sendRequest(NetworkMapService.REGISTER_TOPIC, request, networkMapAddress)
|
return network.sendRequest(NetworkMapService.REGISTER_TOPIC, request, networkMapAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -735,7 +663,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
.toTypedArray()
|
.toTypedArray()
|
||||||
val service = InMemoryIdentityService(setOf(info.legalIdentityAndCert), trustRoot = trustRoot, caCertificates = *caCertificates)
|
val service = InMemoryIdentityService(setOf(info.legalIdentityAndCert), trustRoot = trustRoot, caCertificates = *caCertificates)
|
||||||
services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.legalIdentityAndCert) }
|
services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.legalIdentityAndCert) }
|
||||||
netMapCache.changed.subscribe { mapChange ->
|
services.networkMapCache.changed.subscribe { mapChange ->
|
||||||
// TODO how should we handle network map removal
|
// TODO how should we handle network map removal
|
||||||
if (mapChange is MapChange.Added) {
|
if (mapChange is MapChange.Added) {
|
||||||
service.registerIdentity(mapChange.node.legalIdentityAndCert)
|
service.registerIdentity(mapChange.node.legalIdentityAndCert)
|
||||||
@ -744,13 +672,6 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
return service
|
return service
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: sort out ordering of open & protected modifiers of functions in this class.
|
|
||||||
protected open fun makeVaultService(dataSourceProperties: Properties): VaultService = NodeVaultService(services, dataSourceProperties)
|
|
||||||
|
|
||||||
protected open fun makeVaultQueryService(schemas: SchemaService): VaultQueryService = HibernateVaultQueryImpl(HibernateConfiguration(schemas), vault.updatesPublisher)
|
|
||||||
|
|
||||||
protected open fun makeSchemaService(): SchemaService = NodeSchemaService(pluginRegistries.flatMap { it.requiredSchemas }.toSet())
|
|
||||||
|
|
||||||
protected abstract fun makeTransactionVerifierService(): TransactionVerifierService
|
protected abstract fun makeTransactionVerifierService(): TransactionVerifierService
|
||||||
|
|
||||||
open fun stop() {
|
open fun stop() {
|
||||||
@ -844,6 +765,60 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
val attachmentsDir = (configuration.baseDirectory / "attachments").createDirectories()
|
val attachmentsDir = (configuration.baseDirectory / "attachments").createDirectories()
|
||||||
return NodeAttachmentService(attachmentsDir, configuration.dataSourceProperties, services.monitoringService.metrics)
|
return NodeAttachmentService(attachmentsDir, configuration.dataSourceProperties, services.monitoringService.metrics)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inner class ServiceHubInternalImpl : ServiceHubInternal, SingletonSerializeAsToken() {
|
||||||
|
override val rpcFlows = ArrayList<Class<out FlowLogic<*>>>()
|
||||||
|
override val uploaders = ArrayList<FileUploader>()
|
||||||
|
override val stateMachineRecordedTransactionMapping = DBTransactionMappingStorage()
|
||||||
|
override val auditService = DummyAuditService()
|
||||||
|
override val monitoringService = MonitoringService(MetricRegistry())
|
||||||
|
override val validatedTransactions = makeTransactionStorage()
|
||||||
|
override val transactionVerifierService by lazy { makeTransactionVerifierService() }
|
||||||
|
override val networkMapCache by lazy { InMemoryNetworkMapCache(this) }
|
||||||
|
override val vaultService by lazy { NodeVaultService(this, configuration.dataSourceProperties) }
|
||||||
|
override val vaultQueryService by lazy {
|
||||||
|
HibernateVaultQueryImpl(HibernateConfiguration(schemaService), vaultService.updatesPublisher)
|
||||||
|
}
|
||||||
|
// Place the long term identity key in the KMS. Eventually, this is likely going to be separated again because
|
||||||
|
// the KMS is meant for derived temporary keys used in transactions, and we're not supposed to sign things with
|
||||||
|
// the identity key. But the infrastructure to make that easy isn't here yet.
|
||||||
|
override val keyManagementService by lazy { makeKeyManagementService(identityService) }
|
||||||
|
override val schedulerService by lazy { NodeSchedulerService(this, unfinishedSchedules = busyNodeLatch) }
|
||||||
|
override val identityService by lazy {
|
||||||
|
val keyStoreWrapper = KeyStoreWrapper(configuration.trustStoreFile, configuration.trustStorePassword)
|
||||||
|
makeIdentityService(
|
||||||
|
keyStoreWrapper.keyStore.getCertificate(X509Utilities.CORDA_ROOT_CA)!! as X509Certificate,
|
||||||
|
keyStoreWrapper.certificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA),
|
||||||
|
info.legalIdentityAndCert)
|
||||||
|
}
|
||||||
|
override val attachments: AttachmentStorage get() = this@AbstractNode.attachments
|
||||||
|
override val networkService: MessagingService get() = network
|
||||||
|
override val clock: Clock get() = platformClock
|
||||||
|
override val myInfo: NodeInfo get() = info
|
||||||
|
override val schemaService by lazy { NodeSchemaService(pluginRegistries.flatMap { it.requiredSchemas }.toSet()) }
|
||||||
|
override val database: Database get() = this@AbstractNode.database
|
||||||
|
override val configuration: NodeConfiguration get() = this@AbstractNode.configuration
|
||||||
|
|
||||||
|
override fun <T : SerializeAsToken> cordaService(type: Class<T>): T {
|
||||||
|
require(type.isAnnotationPresent(CordaService::class.java)) { "${type.name} is not a Corda service" }
|
||||||
|
return cordappServices.getInstance(type) ?: throw IllegalArgumentException("Corda service ${type.name} does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T> startFlow(logic: FlowLogic<T>, flowInitiator: FlowInitiator): FlowStateMachineImpl<T> {
|
||||||
|
return serverThread.fetchFrom { smm.add(logic, flowInitiator) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>): InitiatedFlowFactory<*>? {
|
||||||
|
return flowFactories[initiatingFlowClass]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
||||||
|
database.transaction {
|
||||||
|
super.recordTransactions(txs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class KeyStoreWrapper(val keyStore: KeyStore, val storePath: Path, private val storePassword: String) {
|
private class KeyStoreWrapper(val keyStore: KeyStore, val storePath: Path, private val storePassword: String) {
|
||||||
|
@ -72,7 +72,7 @@ interface ServiceHubInternal : PluginServiceHub {
|
|||||||
* The signatures aren't technically needed after that point, but we keep them around so that we can relay
|
* The signatures aren't technically needed after that point, but we keep them around so that we can relay
|
||||||
* the transaction data to other nodes that need it.
|
* the transaction data to other nodes that need it.
|
||||||
*/
|
*/
|
||||||
override val validatedTransactions: TransactionStorage
|
override val validatedTransactions: WritableTransactionStorage
|
||||||
val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage
|
val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage
|
||||||
val monitoringService: MonitoringService
|
val monitoringService: MonitoringService
|
||||||
val schemaService: SchemaService
|
val schemaService: SchemaService
|
||||||
@ -89,8 +89,9 @@ interface ServiceHubInternal : PluginServiceHub {
|
|||||||
val uploaders: List<FileUploader>
|
val uploaders: List<FileUploader>
|
||||||
|
|
||||||
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
||||||
val stateMachineRunId = FlowStateMachineImpl.currentStateMachine()?.id
|
|
||||||
val recordedTransactions = txs.filter { validatedTransactions.addTransaction(it) }
|
val recordedTransactions = txs.filter { validatedTransactions.addTransaction(it) }
|
||||||
|
require(recordedTransactions.isNotEmpty()) { "No transactions passed in for recording" }
|
||||||
|
val stateMachineRunId = FlowStateMachineImpl.currentStateMachine()?.id
|
||||||
if (stateMachineRunId != null) {
|
if (stateMachineRunId != null) {
|
||||||
recordedTransactions.forEach {
|
recordedTransactions.forEach {
|
||||||
stateMachineRecordedTransactionMapping.addMapping(stateMachineRunId, it.id)
|
stateMachineRecordedTransactionMapping.addMapping(stateMachineRunId, it.id)
|
||||||
@ -135,6 +136,20 @@ interface ServiceHubInternal : PluginServiceHub {
|
|||||||
fun getFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>): InitiatedFlowFactory<*>?
|
fun getFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>): InitiatedFlowFactory<*>?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread-safe storage of transactions.
|
||||||
|
*/
|
||||||
|
interface WritableTransactionStorage : TransactionStorage {
|
||||||
|
/**
|
||||||
|
* Add a new transaction to the store. If the store already has a transaction with the same id it will be
|
||||||
|
* overwritten.
|
||||||
|
* @param transaction The transaction to be recorded.
|
||||||
|
* @return true if the transaction was recorded successfully, false if it was already recorded.
|
||||||
|
*/
|
||||||
|
// TODO: Throw an exception if trying to add a transaction with fewer signatures than an existing entry.
|
||||||
|
fun addTransaction(transaction: SignedTransaction): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the interface to storage storing state machine -> recorded tx mappings. Any time a transaction is recorded
|
* This is the interface to storage storing state machine -> recorded tx mappings. Any time a transaction is recorded
|
||||||
* during a flow run [addMapping] should be called.
|
* during a flow run [addMapping] should be called.
|
||||||
|
@ -17,7 +17,6 @@ import net.corda.node.services.api.ServiceHubInternal
|
|||||||
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
|
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
|
||||||
import net.corda.node.utilities.*
|
import net.corda.node.utilities.*
|
||||||
import org.apache.activemq.artemis.utils.ReusableLatch
|
import org.apache.activemq.artemis.utils.ReusableLatch
|
||||||
import org.jetbrains.exposed.sql.Database
|
|
||||||
import org.jetbrains.exposed.sql.ResultRow
|
import org.jetbrains.exposed.sql.ResultRow
|
||||||
import org.jetbrains.exposed.sql.statements.InsertStatement
|
import org.jetbrains.exposed.sql.statements.InsertStatement
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@ -43,7 +42,6 @@ import javax.annotation.concurrent.ThreadSafe
|
|||||||
*/
|
*/
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
class NodeSchedulerService(private val services: ServiceHubInternal,
|
class NodeSchedulerService(private val services: ServiceHubInternal,
|
||||||
private val database: Database,
|
|
||||||
private val schedulerTimerExecutor: Executor = Executors.newSingleThreadExecutor(),
|
private val schedulerTimerExecutor: Executor = Executors.newSingleThreadExecutor(),
|
||||||
private val unfinishedSchedules: ReusableLatch = ReusableLatch())
|
private val unfinishedSchedules: ReusableLatch = ReusableLatch())
|
||||||
: SchedulerService, SingletonSerializeAsToken() {
|
: SchedulerService, SingletonSerializeAsToken() {
|
||||||
@ -159,7 +157,7 @@ class NodeSchedulerService(private val services: ServiceHubInternal,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onTimeReached(scheduledState: ScheduledStateRef) {
|
private fun onTimeReached(scheduledState: ScheduledStateRef) {
|
||||||
database.transaction {
|
services.database.transaction {
|
||||||
val scheduledFlow = getScheduledFlow(scheduledState)
|
val scheduledFlow = getScheduledFlow(scheduledState)
|
||||||
if (scheduledFlow != null) {
|
if (scheduledFlow != null) {
|
||||||
// TODO Because the flow is executed asynchronously, there is a small window between this tx we're in
|
// TODO Because the flow is executed asynchronously, there is a small window between this tx we're in
|
||||||
|
@ -4,9 +4,9 @@ import com.google.common.annotations.VisibleForTesting
|
|||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.bufferUntilSubscribed
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.messaging.DataFeed
|
import net.corda.core.messaging.DataFeed
|
||||||
import net.corda.core.node.services.TransactionStorage
|
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.node.services.api.WritableTransactionStorage
|
||||||
import net.corda.node.utilities.*
|
import net.corda.node.utilities.*
|
||||||
import org.jetbrains.exposed.sql.ResultRow
|
import org.jetbrains.exposed.sql.ResultRow
|
||||||
import org.jetbrains.exposed.sql.exposedLogger
|
import org.jetbrains.exposed.sql.exposedLogger
|
||||||
@ -15,7 +15,7 @@ import rx.Observable
|
|||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
import java.util.Collections.synchronizedMap
|
import java.util.Collections.synchronizedMap
|
||||||
|
|
||||||
class DBTransactionStorage : TransactionStorage, SingletonSerializeAsToken() {
|
class DBTransactionStorage : WritableTransactionStorage, SingletonSerializeAsToken() {
|
||||||
private object Table : JDBCHashedTable("${NODE_DATABASE_PREFIX}transactions") {
|
private object Table : JDBCHashedTable("${NODE_DATABASE_PREFIX}transactions") {
|
||||||
val txId = secureHash("tx_id")
|
val txId = secureHash("tx_id")
|
||||||
val transaction = blob("transaction")
|
val transaction = blob("transaction")
|
||||||
|
@ -8,10 +8,7 @@ import com.google.common.hash.HashingInputStream
|
|||||||
import com.google.common.io.CountingInputStream
|
import com.google.common.io.CountingInputStream
|
||||||
import net.corda.core.contracts.AbstractAttachment
|
import net.corda.core.contracts.AbstractAttachment
|
||||||
import net.corda.core.contracts.Attachment
|
import net.corda.core.contracts.Attachment
|
||||||
import net.corda.core.createDirectory
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.div
|
|
||||||
import net.corda.core.extractZipFile
|
|
||||||
import net.corda.core.isDirectory
|
import net.corda.core.isDirectory
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
import net.corda.core.node.services.AttachmentStorage
|
||||||
import net.corda.core.serialization.*
|
import net.corda.core.serialization.*
|
||||||
@ -35,7 +32,7 @@ import javax.annotation.concurrent.ThreadSafe
|
|||||||
* Stores attachments in H2 database.
|
* Stores attachments in H2 database.
|
||||||
*/
|
*/
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
class NodeAttachmentService(override var storePath: Path, dataSourceProperties: Properties, metrics: MetricRegistry)
|
class NodeAttachmentService(val storePath: Path, dataSourceProperties: Properties, metrics: MetricRegistry)
|
||||||
: AttachmentStorage, AcceptsFileUpload, SingletonSerializeAsToken() {
|
: AttachmentStorage, AcceptsFileUpload, SingletonSerializeAsToken() {
|
||||||
companion object {
|
companion object {
|
||||||
private val log = loggerFor<NodeAttachmentService>()
|
private val log = loggerFor<NodeAttachmentService>()
|
||||||
@ -48,7 +45,6 @@ class NodeAttachmentService(override var storePath: Path, dataSourceProperties:
|
|||||||
var checkAttachmentsOnLoad = true
|
var checkAttachmentsOnLoad = true
|
||||||
|
|
||||||
private val attachmentCount = metrics.counter("Attachments")
|
private val attachmentCount = metrics.counter("Attachments")
|
||||||
@Volatile override var automaticallyExtractAttachments = false
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(storePath.isDirectory()) { "$storePath must be a directory" }
|
require(storePath.isDirectory()) { "$storePath must be a directory" }
|
||||||
@ -183,19 +179,6 @@ class NodeAttachmentService(override var storePath: Path, dataSourceProperties:
|
|||||||
|
|
||||||
log.info("Stored new attachment $id")
|
log.info("Stored new attachment $id")
|
||||||
|
|
||||||
if (automaticallyExtractAttachments) {
|
|
||||||
val extractTo = storePath / "$id.jar"
|
|
||||||
try {
|
|
||||||
extractTo.createDirectory()
|
|
||||||
extractZipFile(ByteArrayInputStream(bytes), extractTo)
|
|
||||||
} catch(e: FileAlreadyExistsException) {
|
|
||||||
log.trace("Did not extract attachment jar to directory because it already exists")
|
|
||||||
} catch(e: Exception) {
|
|
||||||
log.error("Failed to extract attachment jar $id, ", e)
|
|
||||||
// TODO: Delete the extractTo directory here.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ import net.corda.core.messaging.SingleMessageRecipient
|
|||||||
import net.corda.core.messaging.StateMachineTransactionMapping
|
import net.corda.core.messaging.StateMachineTransactionMapping
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.TransactionStorage
|
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
@ -32,6 +31,7 @@ import net.corda.core.utilities.*
|
|||||||
import net.corda.flows.TwoPartyTradeFlow.Buyer
|
import net.corda.flows.TwoPartyTradeFlow.Buyer
|
||||||
import net.corda.flows.TwoPartyTradeFlow.Seller
|
import net.corda.flows.TwoPartyTradeFlow.Seller
|
||||||
import net.corda.node.internal.AbstractNode
|
import net.corda.node.internal.AbstractNode
|
||||||
|
import net.corda.node.services.api.WritableTransactionStorage
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.services.persistence.DBTransactionStorage
|
import net.corda.node.services.persistence.DBTransactionStorage
|
||||||
import net.corda.node.services.persistence.checkpoints
|
import net.corda.node.services.persistence.checkpoints
|
||||||
@ -153,7 +153,7 @@ class TwoPartyTradeFlowTests {
|
|||||||
val cashLockId = UUID.randomUUID()
|
val cashLockId = UUID.randomUUID()
|
||||||
bobNode.database.transaction {
|
bobNode.database.transaction {
|
||||||
// lock the cash states with an arbitrary lockId (to prevent the Buyer flow from claiming the states)
|
// lock the cash states with an arbitrary lockId (to prevent the Buyer flow from claiming the states)
|
||||||
bobNode.vault.softLockReserve(cashLockId, cashStates.states.map { it.ref }.toSet())
|
bobNode.services.vaultService.softLockReserve(cashLockId, cashStates.states.map { it.ref }.toSet())
|
||||||
}
|
}
|
||||||
|
|
||||||
val (bobStateMachine, aliceResult) = runBuyerAndSeller(notaryNode, aliceNode, bobNode,
|
val (bobStateMachine, aliceResult) = runBuyerAndSeller(notaryNode, aliceNode, bobNode,
|
||||||
@ -284,8 +284,8 @@ class TwoPartyTradeFlowTests {
|
|||||||
entropyRoot: BigInteger): MockNetwork.MockNode {
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
||||||
// That constructs a recording tx storage
|
// That constructs a recording tx storage
|
||||||
override fun createTransactionStorage(): TransactionStorage {
|
override fun makeTransactionStorage(): WritableTransactionStorage {
|
||||||
return RecordingTransactionStorage(database, super.createTransactionStorage())
|
return RecordingTransactionStorage(database, super.makeTransactionStorage())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,7 +311,7 @@ class TwoPartyTradeFlowTests {
|
|||||||
attachment(ByteArrayInputStream(stream.toByteArray()))
|
attachment(ByteArrayInputStream(stream.toByteArray()))
|
||||||
}
|
}
|
||||||
|
|
||||||
val extraKey = bobNode.keyManagement.keys.single()
|
val extraKey = bobNode.services.keyManagementService.keys.single()
|
||||||
val bobsFakeCash = fillUpForBuyer(false, AnonymousParty(extraKey),
|
val bobsFakeCash = fillUpForBuyer(false, AnonymousParty(extraKey),
|
||||||
DUMMY_CASH_ISSUER.party,
|
DUMMY_CASH_ISSUER.party,
|
||||||
notaryNode.info.notaryIdentity).second
|
notaryNode.info.notaryIdentity).second
|
||||||
@ -410,7 +410,7 @@ class TwoPartyTradeFlowTests {
|
|||||||
attachment(ByteArrayInputStream(stream.toByteArray()))
|
attachment(ByteArrayInputStream(stream.toByteArray()))
|
||||||
}
|
}
|
||||||
|
|
||||||
val bobsKey = bobNode.keyManagement.keys.single()
|
val bobsKey = bobNode.services.keyManagementService.keys.single()
|
||||||
val bobsFakeCash = fillUpForBuyer(false, AnonymousParty(bobsKey),
|
val bobsFakeCash = fillUpForBuyer(false, AnonymousParty(bobsKey),
|
||||||
DUMMY_CASH_ISSUER.party,
|
DUMMY_CASH_ISSUER.party,
|
||||||
notaryNode.info.notaryIdentity).second
|
notaryNode.info.notaryIdentity).second
|
||||||
@ -675,7 +675,7 @@ class TwoPartyTradeFlowTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class RecordingTransactionStorage(val database: Database, val delegate: TransactionStorage) : TransactionStorage {
|
class RecordingTransactionStorage(val database: Database, val delegate: WritableTransactionStorage) : WritableTransactionStorage {
|
||||||
override fun track(): DataFeed<List<SignedTransaction>, SignedTransaction> {
|
override fun track(): DataFeed<List<SignedTransaction>, SignedTransaction> {
|
||||||
return database.transaction {
|
return database.transaction {
|
||||||
delegate.track()
|
delegate.track()
|
||||||
|
@ -18,19 +18,20 @@ import net.corda.node.services.transactions.InMemoryTransactionVerifierService
|
|||||||
import net.corda.testing.MOCK_IDENTITY_SERVICE
|
import net.corda.testing.MOCK_IDENTITY_SERVICE
|
||||||
import net.corda.testing.node.MockAttachmentStorage
|
import net.corda.testing.node.MockAttachmentStorage
|
||||||
import net.corda.testing.node.MockNetworkMapCache
|
import net.corda.testing.node.MockNetworkMapCache
|
||||||
import org.jetbrains.exposed.sql.Database
|
|
||||||
import net.corda.testing.node.MockStateMachineRecordedTransactionMappingStorage
|
import net.corda.testing.node.MockStateMachineRecordedTransactionMappingStorage
|
||||||
import net.corda.testing.node.MockTransactionStorage
|
import net.corda.testing.node.MockTransactionStorage
|
||||||
|
import org.jetbrains.exposed.sql.Database
|
||||||
import java.time.Clock
|
import java.time.Clock
|
||||||
|
|
||||||
open class MockServiceHubInternal(
|
open class MockServiceHubInternal(
|
||||||
|
override val database: Database,
|
||||||
val customVault: VaultService? = null,
|
val customVault: VaultService? = null,
|
||||||
val customVaultQuery: VaultQueryService? = null,
|
val customVaultQuery: VaultQueryService? = null,
|
||||||
val keyManagement: KeyManagementService? = null,
|
val keyManagement: KeyManagementService? = null,
|
||||||
val network: MessagingService? = null,
|
val network: MessagingService? = null,
|
||||||
val identity: IdentityService? = MOCK_IDENTITY_SERVICE,
|
val identity: IdentityService? = MOCK_IDENTITY_SERVICE,
|
||||||
override val attachments: AttachmentStorage = MockAttachmentStorage(),
|
override val attachments: AttachmentStorage = MockAttachmentStorage(),
|
||||||
override val validatedTransactions: TransactionStorage = MockTransactionStorage(),
|
override val validatedTransactions: WritableTransactionStorage = MockTransactionStorage(),
|
||||||
override val uploaders: List<FileUploader> = listOf<FileUploader>(),
|
override val uploaders: List<FileUploader> = listOf<FileUploader>(),
|
||||||
override val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage = MockStateMachineRecordedTransactionMappingStorage(),
|
override val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage = MockStateMachineRecordedTransactionMappingStorage(),
|
||||||
val mapCache: NetworkMapCacheInternal? = null,
|
val mapCache: NetworkMapCacheInternal? = null,
|
||||||
@ -59,8 +60,6 @@ open class MockServiceHubInternal(
|
|||||||
get() = overrideClock ?: throw UnsupportedOperationException()
|
get() = overrideClock ?: throw UnsupportedOperationException()
|
||||||
override val myInfo: NodeInfo
|
override val myInfo: NodeInfo
|
||||||
get() = throw UnsupportedOperationException()
|
get() = throw UnsupportedOperationException()
|
||||||
override val database: Database
|
|
||||||
get() = throw UnsupportedOperationException()
|
|
||||||
override val configuration: NodeConfiguration
|
override val configuration: NodeConfiguration
|
||||||
get() = throw UnsupportedOperationException()
|
get() = throw UnsupportedOperationException()
|
||||||
override val monitoringService: MonitoringService = MonitoringService(MetricRegistry())
|
override val monitoringService: MonitoringService = MonitoringService(MetricRegistry())
|
||||||
|
@ -135,7 +135,7 @@ class NotaryChangeTests {
|
|||||||
addOutputState(stateB, notary, encumbrance = 1) // Encumbered by stateC
|
addOutputState(stateB, notary, encumbrance = 1) // Encumbered by stateC
|
||||||
}
|
}
|
||||||
val stx = node.services.signInitialTransaction(tx)
|
val stx = node.services.signInitialTransaction(tx)
|
||||||
node.services.recordTransactions(listOf(stx))
|
node.services.recordTransactions(stx)
|
||||||
return tx.toWireTransaction()
|
return tx.toWireTransaction()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ fun issueState(node: AbstractNode, notaryNode: AbstractNode): StateAndRef<*> {
|
|||||||
val tx = DummyContract.generateInitial(Random().nextInt(), notaryNode.info.notaryIdentity, node.info.legalIdentity.ref(0))
|
val tx = DummyContract.generateInitial(Random().nextInt(), notaryNode.info.notaryIdentity, node.info.legalIdentity.ref(0))
|
||||||
val signedByNode = node.services.signInitialTransaction(tx)
|
val signedByNode = node.services.signInitialTransaction(tx)
|
||||||
val stx = notaryNode.services.addSignature(signedByNode, notaryNode.services.notaryIdentityKey)
|
val stx = notaryNode.services.addSignature(signedByNode, notaryNode.services.notaryIdentityKey)
|
||||||
node.services.recordTransactions(listOf(stx))
|
node.services.recordTransactions(stx)
|
||||||
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,8 +163,8 @@ fun issueMultiPartyState(nodeA: AbstractNode, nodeB: AbstractNode, notaryNode: A
|
|||||||
val signedByA = nodeA.services.signInitialTransaction(tx)
|
val signedByA = nodeA.services.signInitialTransaction(tx)
|
||||||
val signedByAB = nodeB.services.addSignature(signedByA)
|
val signedByAB = nodeB.services.addSignature(signedByA)
|
||||||
val stx = notaryNode.services.addSignature(signedByAB, notaryNode.services.notaryIdentityKey)
|
val stx = notaryNode.services.addSignature(signedByAB, notaryNode.services.notaryIdentityKey)
|
||||||
nodeA.services.recordTransactions(listOf(stx))
|
nodeA.services.recordTransactions(stx)
|
||||||
nodeB.services.recordTransactions(listOf(stx))
|
nodeB.services.recordTransactions(stx)
|
||||||
val stateAndRef = StateAndRef(state, StateRef(stx.id, 0))
|
val stateAndRef = StateAndRef(state, StateRef(stx.id, 0))
|
||||||
return stateAndRef
|
return stateAndRef
|
||||||
}
|
}
|
||||||
@ -173,6 +173,6 @@ fun issueInvalidState(node: AbstractNode, notary: Party): StateAndRef<*> {
|
|||||||
val tx = DummyContract.generateInitial(Random().nextInt(), notary, node.info.legalIdentity.ref(0))
|
val tx = DummyContract.generateInitial(Random().nextInt(), notary, node.info.legalIdentity.ref(0))
|
||||||
tx.addTimeWindow(Instant.now(), 30.seconds)
|
tx.addTimeWindow(Instant.now(), 30.seconds)
|
||||||
val stx = node.services.signInitialTransaction(tx)
|
val stx = node.services.signInitialTransaction(tx)
|
||||||
node.services.recordTransactions(listOf(stx))
|
node.services.recordTransactions(stx)
|
||||||
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
||||||
}
|
}
|
||||||
|
@ -87,11 +87,11 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
|||||||
InMemoryMessagingNetwork.PeerHandle(0, nullIdentity),
|
InMemoryMessagingNetwork.PeerHandle(0, nullIdentity),
|
||||||
AffinityExecutor.ServiceAffinityExecutor("test", 1),
|
AffinityExecutor.ServiceAffinityExecutor("test", 1),
|
||||||
database)
|
database)
|
||||||
services = object : MockServiceHubInternal(overrideClock = testClock, keyManagement = kms, network = mockMessagingService), TestReference {
|
services = object : MockServiceHubInternal(database, overrideClock = testClock, keyManagement = kms, network = mockMessagingService), TestReference {
|
||||||
override val vaultService: VaultService = NodeVaultService(this, dataSourceProps)
|
override val vaultService: VaultService = NodeVaultService(this, dataSourceProps)
|
||||||
override val testReference = this@NodeSchedulerServiceTest
|
override val testReference = this@NodeSchedulerServiceTest
|
||||||
}
|
}
|
||||||
scheduler = NodeSchedulerService(services, database, schedulerGatedExecutor)
|
scheduler = NodeSchedulerService(services, schedulerGatedExecutor)
|
||||||
smmExecutor = AffinityExecutor.ServiceAffinityExecutor("test", 1)
|
smmExecutor = AffinityExecutor.ServiceAffinityExecutor("test", 1)
|
||||||
val mockSMM = StateMachineManager(services, DBCheckpointStorage(), smmExecutor, database)
|
val mockSMM = StateMachineManager(services, DBCheckpointStorage(), smmExecutor, database)
|
||||||
mockSMM.changes.subscribe { change ->
|
mockSMM.changes.subscribe { change ->
|
||||||
|
@ -38,13 +38,13 @@ class InMemoryNetworkMapCacheTest {
|
|||||||
mockNet.runNetwork()
|
mockNet.runNetwork()
|
||||||
|
|
||||||
// Node A currently knows only about itself, so this returns node A
|
// Node A currently knows only about itself, so this returns node A
|
||||||
assertEquals(nodeA.netMapCache.getNodeByLegalIdentityKey(nodeA.info.legalIdentity.owningKey), nodeA.info)
|
assertEquals(nodeA.services.networkMapCache.getNodeByLegalIdentityKey(nodeA.info.legalIdentity.owningKey), nodeA.info)
|
||||||
|
|
||||||
nodeA.database.transaction {
|
nodeA.database.transaction {
|
||||||
nodeA.netMapCache.addNode(nodeB.info)
|
nodeA.services.networkMapCache.addNode(nodeB.info)
|
||||||
}
|
}
|
||||||
// The details of node B write over those for node A
|
// The details of node B write over those for node A
|
||||||
assertEquals(nodeA.netMapCache.getNodeByLegalIdentityKey(nodeA.info.legalIdentity.owningKey), nodeB.info)
|
assertEquals(nodeA.services.networkMapCache.getNodeByLegalIdentityKey(nodeA.info.legalIdentity.owningKey), nodeB.info)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -131,7 +131,7 @@ class NotaryServiceTests {
|
|||||||
val tx = DummyContract.generateInitial(Random().nextInt(), notaryNode.info.notaryIdentity, node.info.legalIdentity.ref(0))
|
val tx = DummyContract.generateInitial(Random().nextInt(), notaryNode.info.notaryIdentity, node.info.legalIdentity.ref(0))
|
||||||
val signedByNode = node.services.signInitialTransaction(tx)
|
val signedByNode = node.services.signInitialTransaction(tx)
|
||||||
val stx = notaryNode.services.addSignature(signedByNode, notaryNode.services.notaryIdentityKey)
|
val stx = notaryNode.services.addSignature(signedByNode, notaryNode.services.notaryIdentityKey)
|
||||||
node.services.recordTransactions(listOf(stx))
|
node.services.recordTransactions(stx)
|
||||||
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ class ValidatingNotaryServiceTests {
|
|||||||
val tx = DummyContract.generateInitial(Random().nextInt(), notaryNode.info.notaryIdentity, node.info.legalIdentity.ref(0))
|
val tx = DummyContract.generateInitial(Random().nextInt(), notaryNode.info.notaryIdentity, node.info.legalIdentity.ref(0))
|
||||||
val signedByNode = node.services.signInitialTransaction(tx)
|
val signedByNode = node.services.signInitialTransaction(tx)
|
||||||
val stx = notaryNode.services.addSignature(signedByNode, notaryNode.services.notaryIdentityKey)
|
val stx = notaryNode.services.addSignature(signedByNode, notaryNode.services.notaryIdentityKey)
|
||||||
node.services.recordTransactions(listOf(stx))
|
node.services.recordTransactions(stx)
|
||||||
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,7 +405,7 @@ class NodeVaultServiceTest {
|
|||||||
}
|
}
|
||||||
val usefulTX = megaCorpServices.signInitialTransaction(usefulBuilder)
|
val usefulTX = megaCorpServices.signInitialTransaction(usefulBuilder)
|
||||||
|
|
||||||
services.recordTransactions(listOf(usefulTX))
|
services.recordTransactions(usefulTX)
|
||||||
|
|
||||||
vaultSvc.addNoteToTransaction(usefulTX.id, "USD Sample Note 1")
|
vaultSvc.addNoteToTransaction(usefulTX.id, "USD Sample Note 1")
|
||||||
vaultSvc.addNoteToTransaction(usefulTX.id, "USD Sample Note 2")
|
vaultSvc.addNoteToTransaction(usefulTX.id, "USD Sample Note 2")
|
||||||
@ -418,7 +418,7 @@ class NodeVaultServiceTest {
|
|||||||
}
|
}
|
||||||
val anotherTX = megaCorpServices.signInitialTransaction(anotherBuilder)
|
val anotherTX = megaCorpServices.signInitialTransaction(anotherBuilder)
|
||||||
|
|
||||||
services.recordTransactions(listOf(anotherTX))
|
services.recordTransactions(anotherTX)
|
||||||
|
|
||||||
vaultSvc.addNoteToTransaction(anotherTX.id, "GPB Sample Note 1")
|
vaultSvc.addNoteToTransaction(anotherTX.id, "GPB Sample Note 1")
|
||||||
assertEquals(1, vaultSvc.getTransactionNotes(anotherTX.id).count())
|
assertEquals(1, vaultSvc.getTransactionNotes(anotherTX.id).count())
|
||||||
|
@ -167,7 +167,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
val serviceProviders: List<SimulatedNode> = listOf(notary, ratesOracle, networkMap)
|
val serviceProviders: List<SimulatedNode> = listOf(notary, ratesOracle, networkMap)
|
||||||
val banks: List<SimulatedNode> = bankFactory.createAll()
|
val banks: List<SimulatedNode> = bankFactory.createAll()
|
||||||
|
|
||||||
val clocks = (serviceProviders + regulators + banks).map { it.services.clock as TestClock }
|
val clocks = (serviceProviders + regulators + banks).map { it.platformClock as TestClock }
|
||||||
|
|
||||||
// These are used from the network visualiser tool.
|
// These are used from the network visualiser tool.
|
||||||
private val _allFlowSteps = PublishSubject.create<Pair<SimulatedNode, ProgressTracker.Change>>()
|
private val _allFlowSteps = PublishSubject.create<Pair<SimulatedNode, ProgressTracker.Change>>()
|
||||||
|
@ -4,7 +4,6 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import net.corda.contracts.CommercialPaper
|
import net.corda.contracts.CommercialPaper
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.TransactionGraphSearch
|
import net.corda.core.contracts.TransactionGraphSearch
|
||||||
import net.corda.core.div
|
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.InitiatedBy
|
import net.corda.core.flows.InitiatedBy
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
@ -39,7 +38,7 @@ class BuyerFlow(val otherParty: Party) : FlowLogic<Unit>() {
|
|||||||
// This invokes the trading flow and out pops our finished transaction.
|
// This invokes the trading flow and out pops our finished transaction.
|
||||||
val tradeTX: SignedTransaction = subFlow(buyer)
|
val tradeTX: SignedTransaction = subFlow(buyer)
|
||||||
// TODO: This should be moved into the flow itself.
|
// TODO: This should be moved into the flow itself.
|
||||||
serviceHub.recordTransactions(listOf(tradeTX))
|
serviceHub.recordTransactions(tradeTX)
|
||||||
|
|
||||||
println("Purchase complete - we are a happy customer! Final transaction is: " +
|
println("Purchase complete - we are a happy customer! Final transaction is: " +
|
||||||
"\n\n${Emoji.renderIfSupported(tradeTX.tx)}")
|
"\n\n${Emoji.renderIfSupported(tradeTX.tx)}")
|
||||||
@ -61,18 +60,11 @@ class BuyerFlow(val otherParty: Party) : FlowLogic<Unit>() {
|
|||||||
val cpIssuance = search.call().single()
|
val cpIssuance = search.call().single()
|
||||||
|
|
||||||
// Buyer will fetch the attachment from the seller automatically when it resolves the transaction.
|
// Buyer will fetch the attachment from the seller automatically when it resolves the transaction.
|
||||||
// For demo purposes just extract attachment jars when saved to disk, so the user can explore them.
|
|
||||||
val attachmentsPath = (serviceHub.attachments).let {
|
|
||||||
it.automaticallyExtractAttachments = true
|
|
||||||
it.storePath
|
|
||||||
}
|
|
||||||
|
|
||||||
cpIssuance.attachments.first().let {
|
cpIssuance.attachments.first().let {
|
||||||
val p = attachmentsPath / "$it.jar"
|
|
||||||
println("""
|
println("""
|
||||||
|
|
||||||
The issuance of the commercial paper came with an attachment. You can find it expanded in this directory:
|
The issuance of the commercial paper came with an attachment. You can find it in the attachments directory: $it.jar
|
||||||
$p
|
|
||||||
|
|
||||||
${Emoji.renderIfSupported(cpIssuance)}""")
|
${Emoji.renderIfSupported(cpIssuance)}""")
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,11 @@ import net.corda.core.messaging.MessageRecipients
|
|||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.core.node.CordaPluginRegistry
|
import net.corda.core.node.CordaPluginRegistry
|
||||||
import net.corda.core.node.WorldMapLocation
|
|
||||||
import net.corda.core.node.ServiceEntry
|
import net.corda.core.node.ServiceEntry
|
||||||
import net.corda.core.node.services.*
|
import net.corda.core.node.WorldMapLocation
|
||||||
|
import net.corda.core.node.services.IdentityService
|
||||||
|
import net.corda.core.node.services.KeyManagementService
|
||||||
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
||||||
import net.corda.core.utilities.getTestPartyAndCertificate
|
import net.corda.core.utilities.getTestPartyAndCertificate
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
@ -32,7 +34,6 @@ import net.corda.node.services.network.NetworkMapService
|
|||||||
import net.corda.node.services.transactions.InMemoryTransactionVerifierService
|
import net.corda.node.services.transactions.InMemoryTransactionVerifierService
|
||||||
import net.corda.node.services.transactions.SimpleNotaryService
|
import net.corda.node.services.transactions.SimpleNotaryService
|
||||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||||
import net.corda.node.services.vault.NodeVaultService
|
|
||||||
import net.corda.node.utilities.AffinityExecutor
|
import net.corda.node.utilities.AffinityExecutor
|
||||||
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
||||||
import net.corda.testing.MOCK_VERSION_INFO
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
@ -181,8 +182,6 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
trustRoot = trustRoot, caCertificates = *caCertificates)
|
trustRoot = trustRoot, caCertificates = *caCertificates)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun makeVaultService(dataSourceProperties: Properties): VaultService = NodeVaultService(services, dataSourceProperties)
|
|
||||||
|
|
||||||
override fun makeKeyManagementService(identityService: IdentityService): KeyManagementService {
|
override fun makeKeyManagementService(identityService: IdentityService): KeyManagementService {
|
||||||
return E2ETestKeyManagementService(identityService, partyKeys + (overrideServices?.values ?: emptySet()))
|
return E2ETestKeyManagementService(identityService, partyKeys + (overrideServices?.values ?: emptySet()))
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import net.corda.core.utilities.DUMMY_CA
|
|||||||
import net.corda.core.utilities.getTestPartyAndCertificate
|
import net.corda.core.utilities.getTestPartyAndCertificate
|
||||||
import net.corda.flows.AnonymisedIdentity
|
import net.corda.flows.AnonymisedIdentity
|
||||||
import net.corda.node.services.api.StateMachineRecordedTransactionMappingStorage
|
import net.corda.node.services.api.StateMachineRecordedTransactionMappingStorage
|
||||||
|
import net.corda.node.services.api.WritableTransactionStorage
|
||||||
import net.corda.node.services.database.HibernateConfiguration
|
import net.corda.node.services.database.HibernateConfiguration
|
||||||
import net.corda.node.services.identity.InMemoryIdentityService
|
import net.corda.node.services.identity.InMemoryIdentityService
|
||||||
import net.corda.node.services.keys.freshCertificate
|
import net.corda.node.services.keys.freshCertificate
|
||||||
@ -35,8 +36,6 @@ import java.io.ByteArrayInputStream
|
|||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.nio.file.Path
|
|
||||||
import java.nio.file.Paths
|
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.PrivateKey
|
import java.security.PrivateKey
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
@ -66,7 +65,7 @@ open class MockServices(vararg val keys: KeyPair) : ServiceHub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val attachments: AttachmentStorage = MockAttachmentStorage()
|
override val attachments: AttachmentStorage = MockAttachmentStorage()
|
||||||
override val validatedTransactions: TransactionStorage = MockTransactionStorage()
|
override val validatedTransactions: WritableTransactionStorage = MockTransactionStorage()
|
||||||
val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage = MockStateMachineRecordedTransactionMappingStorage()
|
val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage = MockStateMachineRecordedTransactionMappingStorage()
|
||||||
override final val identityService: IdentityService = InMemoryIdentityService(MOCK_IDENTITIES, trustRoot = DUMMY_CA.certificate)
|
override final val identityService: IdentityService = InMemoryIdentityService(MOCK_IDENTITIES, trustRoot = DUMMY_CA.certificate)
|
||||||
override val keyManagementService: KeyManagementService = MockKeyManagementService(identityService, *keys)
|
override val keyManagementService: KeyManagementService = MockKeyManagementService(identityService, *keys)
|
||||||
@ -124,10 +123,8 @@ class MockKeyManagementService(val identityService: IdentityService,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockAttachmentStorage : AttachmentStorage {
|
class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() {
|
||||||
val files = HashMap<SecureHash, ByteArray>()
|
val files = HashMap<SecureHash, ByteArray>()
|
||||||
override var automaticallyExtractAttachments = false
|
|
||||||
override var storePath: Path = Paths.get("")
|
|
||||||
|
|
||||||
override fun openAttachment(id: SecureHash): Attachment? {
|
override fun openAttachment(id: SecureHash): Attachment? {
|
||||||
val f = files[id] ?: return null
|
val f = files[id] ?: return null
|
||||||
@ -159,7 +156,7 @@ class MockStateMachineRecordedTransactionMappingStorage(
|
|||||||
val storage: StateMachineRecordedTransactionMappingStorage = InMemoryStateMachineRecordedTransactionMappingStorage()
|
val storage: StateMachineRecordedTransactionMappingStorage = InMemoryStateMachineRecordedTransactionMappingStorage()
|
||||||
) : StateMachineRecordedTransactionMappingStorage by storage
|
) : StateMachineRecordedTransactionMappingStorage by storage
|
||||||
|
|
||||||
open class MockTransactionStorage : TransactionStorage {
|
open class MockTransactionStorage : WritableTransactionStorage, SingletonSerializeAsToken() {
|
||||||
override fun track(): DataFeed<List<SignedTransaction>, SignedTransaction> {
|
override fun track(): DataFeed<List<SignedTransaction>, SignedTransaction> {
|
||||||
return DataFeed(txns.values.toList(), _updatesPublisher)
|
return DataFeed(txns.values.toList(), _updatesPublisher)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user