diff --git a/.idea/runConfigurations/Quasar_exclude_pattern_extraction_from_node_tests__need_not_pass__check_output_at_the_bottom_of_console_.xml b/.idea/runConfigurations/Quasar_exclude_pattern_extraction_from_node_tests__need_not_pass__check_output_at_the_bottom_of_console_.xml
deleted file mode 100644
index 8c8a89624b..0000000000
--- a/.idea/runConfigurations/Quasar_exclude_pattern_extraction_from_node_tests__need_not_pass__check_output_at_the_bottom_of_console_.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt
index fb882eb4ad..def8fb0424 100644
--- a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt
+++ b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt
@@ -46,6 +46,7 @@ interface ServiceHub : ServicesForResolution {
val vaultService: VaultService
val vaultQueryService: VaultQueryService
val keyManagementService: KeyManagementService
+ val contractUpgradeService: ContractUpgradeService
/**
* A map of hash->tx where tx has been signature/contract validated and the states are known to be correct.
diff --git a/core/src/main/kotlin/net/corda/core/node/services/ContractUpgradeService.kt b/core/src/main/kotlin/net/corda/core/node/services/ContractUpgradeService.kt
new file mode 100644
index 0000000000..c29702077c
--- /dev/null
+++ b/core/src/main/kotlin/net/corda/core/node/services/ContractUpgradeService.kt
@@ -0,0 +1,30 @@
+package net.corda.core.node.services
+
+import net.corda.core.contracts.StateAndRef
+import net.corda.core.contracts.StateRef
+import net.corda.core.contracts.UpgradedContract
+
+/**
+ * The [ContractUpgradeService] is responsible for securely upgrading contract state objects according to
+ * a specified and mutually agreed (amongst participants) contract version.
+ * See also [ContractUpgradeFlow] to understand the workflow associated with contract upgrades.
+ */
+interface ContractUpgradeService {
+
+ /** Get contracts we would be willing to upgrade the suggested contract to. */
+ fun getAuthorisedContractUpgrade(ref: StateRef): Class>?
+
+ /**
+ * Authorise a contract state upgrade.
+ * This will store the upgrade authorisation in the vault, and will be queried by [ContractUpgradeFlow.Acceptor] during contract upgrade process.
+ * Invoking this method indicate the node is willing to upgrade the [state] using the [upgradedContractClass].
+ * This method will NOT initiate the upgrade process. To start the upgrade process, see [ContractUpgradeFlow.Instigator].
+ */
+ fun authoriseContractUpgrade(stateAndRef: StateAndRef<*>, upgradedContractClass: Class>)
+
+ /**
+ * Authorise a contract state upgrade.
+ * This will remove the upgrade authorisation from the vault.
+ */
+ fun deauthoriseContractUpgrade(stateAndRef: StateAndRef<*>)
+}
diff --git a/core/src/main/kotlin/net/corda/core/node/services/VaultService.kt b/core/src/main/kotlin/net/corda/core/node/services/VaultService.kt
index ebd70ae93d..0b7aeb862f 100644
--- a/core/src/main/kotlin/net/corda/core/node/services/VaultService.kt
+++ b/core/src/main/kotlin/net/corda/core/node/services/VaultService.kt
@@ -173,17 +173,6 @@ interface VaultService {
*/
val updatesPublisher: PublishSubject>
- /**
- * Possibly update the vault by marking as spent states that these transactions consume, and adding any relevant
- * new states that they create. You should only insert transactions that have been successfully verified here!
- *
- * TODO: Consider if there's a good way to enforce the must-be-verified requirement in the type system.
- */
- fun notifyAll(txns: Iterable)
-
- /** Same as notifyAll but with a single transaction. */
- fun notify(tx: CoreTransaction) = notifyAll(listOf(tx))
-
/**
* Provide a [CordaFuture] for when a [StateRef] is consumed, which can be very useful in building tests.
*/
@@ -191,24 +180,6 @@ interface VaultService {
return updates.filter { it.consumed.any { it.ref == ref } }.toFuture()
}
- /** Get contracts we would be willing to upgrade the suggested contract to. */
- // TODO: We need a better place to put business logic functions
- fun getAuthorisedContractUpgrade(ref: StateRef): Class>?
-
- /**
- * Authorise a contract state upgrade.
- * This will store the upgrade authorisation in the vault, and will be queried by [ContractUpgradeFlow.Acceptor] during contract upgrade process.
- * Invoking this method indicate the node is willing to upgrade the [state] using the [upgradedContractClass].
- * This method will NOT initiate the upgrade process. To start the upgrade process, see [ContractUpgradeFlow.Instigator].
- */
- fun authoriseContractUpgrade(stateAndRef: StateAndRef<*>, upgradedContractClass: Class>)
-
- /**
- * Authorise a contract state upgrade.
- * This will remove the upgrade authorisation from the vault.
- */
- fun deauthoriseContractUpgrade(stateAndRef: StateAndRef<*>)
-
/**
* Add a note to an existing [LedgerTransaction] given by its unique [SecureHash] id
* Multiple notes may be attached to the same [LedgerTransaction].
diff --git a/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt b/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt
index 951f28b9e3..a8e93ea575 100644
--- a/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt
+++ b/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt
@@ -79,7 +79,7 @@ class ContractUpgradeFlowTest {
assertFailsWith(UnexpectedFlowEndException::class) { rejectedFuture.getOrThrow() }
// Party B authorise the contract state upgrade.
- b.services.vaultService.authoriseContractUpgrade(btx!!.tx.outRef(0), DummyContractV2::class.java)
+ b.services.contractUpgradeService.authoriseContractUpgrade(btx!!.tx.outRef(0), DummyContractV2::class.java)
// Party A initiates contract upgrade flow, expected to succeed this time.
val resultFuture = a.services.startFlow(ContractUpgradeFlow(atx.tx.outRef(0), DummyContractV2::class.java)).resultFuture
diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt
index c21f7bd800..ec864c606c 100644
--- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt
+++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt
@@ -56,6 +56,7 @@ import net.corda.node.services.statemachine.FlowStateMachineImpl
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.statemachine.flowVersionAndInitiatingClass
import net.corda.node.services.transactions.*
+import net.corda.node.services.upgrade.ContractUpgradeServiceImpl
import net.corda.node.services.vault.HibernateVaultQueryImpl
import net.corda.node.services.vault.NodeVaultService
import net.corda.node.services.vault.VaultSoftLockManager
@@ -770,6 +771,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
override val schemaService by lazy { NodeSchemaService(pluginRegistries.flatMap { it.requiredSchemas }.toSet()) }
override val networkMapCache by lazy { PersistentNetworkMapCache(this) }
override val vaultService by lazy { NodeVaultService(this) }
+ override val contractUpgradeService by lazy { ContractUpgradeServiceImpl() }
override val vaultQueryService by lazy {
HibernateVaultQueryImpl(database.hibernateConfig, vaultService)
}
diff --git a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt
index e87359f0a6..d4f51ee21f 100644
--- a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt
+++ b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt
@@ -170,8 +170,8 @@ class CordaRPCOpsImpl(
}
}
- override fun authoriseContractUpgrade(state: StateAndRef<*>, upgradedContractClass: Class>) = services.vaultService.authoriseContractUpgrade(state, upgradedContractClass)
- override fun deauthoriseContractUpgrade(state: StateAndRef<*>) = services.vaultService.deauthoriseContractUpgrade(state)
+ override fun authoriseContractUpgrade(state: StateAndRef<*>, upgradedContractClass: Class>) = services.contractUpgradeService.authoriseContractUpgrade(state, upgradedContractClass)
+ override fun deauthoriseContractUpgrade(state: StateAndRef<*>) = services.contractUpgradeService.deauthoriseContractUpgrade(state)
override fun currentNodeTime(): Instant = Instant.now(services.clock)
override fun waitUntilNetworkReady() = services.networkMapCache.nodeReady
override fun partyFromAnonymous(party: AbstractParty): Party? = services.identityService.partyFromAnonymous(party)
diff --git a/node/src/main/kotlin/net/corda/node/services/CoreFlowHandlers.kt b/node/src/main/kotlin/net/corda/node/services/CoreFlowHandlers.kt
index bbded81fa8..d311ea4fd2 100644
--- a/node/src/main/kotlin/net/corda/node/services/CoreFlowHandlers.kt
+++ b/node/src/main/kotlin/net/corda/node/services/CoreFlowHandlers.kt
@@ -58,7 +58,7 @@ class ContractUpgradeHandler(otherSide: Party) : AbstractStateReplacementFlow.Ac
val ourSTX = serviceHub.validatedTransactions.getTransaction(proposal.stateRef.txhash)
requireNotNull(ourSTX) { "We don't have a copy of the referenced state" }
val oldStateAndRef = ourSTX!!.tx.outRef(proposal.stateRef.index)
- val authorisedUpgrade = serviceHub.vaultService.getAuthorisedContractUpgrade(oldStateAndRef.ref) ?:
+ val authorisedUpgrade = serviceHub.contractUpgradeService.getAuthorisedContractUpgrade(oldStateAndRef.ref) ?:
throw IllegalStateException("Contract state upgrade is unauthorised. State hash : ${oldStateAndRef.ref}")
val proposedTx = stx.tx
val expectedTx = ContractUpgradeFlow.assembleBareTx(oldStateAndRef, proposal.modification, proposedTx.privacySalt).toWireTransaction()
diff --git a/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt b/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt
index 4d2bbfccbf..260e930ce8 100644
--- a/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt
+++ b/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt
@@ -22,6 +22,7 @@ import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.messaging.MessagingService
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
import net.corda.node.services.statemachine.FlowStateMachineImpl
+import net.corda.node.services.vault.NodeVaultService
import net.corda.node.utilities.CordaPersistence
interface NetworkMapCacheInternal : NetworkMapCache {
@@ -100,7 +101,7 @@ interface ServiceHubInternal : PluginServiceHub {
if (notifyVault) {
val toNotify = recordedTransactions.map { if (it.isNotaryChangeTransaction()) it.notaryChangeTx else it.tx }
- vaultService.notifyAll(toNotify)
+ (vaultService as NodeVaultService).notifyAll(toNotify)
}
}
diff --git a/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt b/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt
new file mode 100644
index 0000000000..c93a8d55da
--- /dev/null
+++ b/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt
@@ -0,0 +1,26 @@
+package net.corda.node.services.upgrade
+
+import net.corda.core.contracts.StateAndRef
+import net.corda.core.contracts.StateRef
+import net.corda.core.contracts.UpgradedContract
+import net.corda.core.node.services.ContractUpgradeService
+
+class ContractUpgradeServiceImpl : ContractUpgradeService {
+
+ // TODO : Persist this in DB.
+ private val authorisedUpgrade = mutableMapOf>>()
+
+ override fun getAuthorisedContractUpgrade(ref: StateRef) = authorisedUpgrade[ref]
+
+ override fun authoriseContractUpgrade(stateAndRef: StateAndRef<*>, upgradedContractClass: Class>) {
+ val upgrade = upgradedContractClass.newInstance()
+ if (upgrade.legacyContract != stateAndRef.state.data.contract.javaClass) {
+ throw IllegalArgumentException("The contract state cannot be upgraded using provided UpgradedContract.")
+ }
+ authorisedUpgrade.put(stateAndRef.ref, upgradedContractClass)
+ }
+
+ override fun deauthoriseContractUpgrade(stateAndRef: StateAndRef<*>) {
+ authorisedUpgrade.remove(stateAndRef.ref)
+ }
+}
\ No newline at end of file
diff --git a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt
index 023e87a1f7..9bb3249da8 100644
--- a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt
+++ b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt
@@ -114,7 +114,7 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
* indicate whether an update consists entirely of regular or notary change transactions, which may require
* different processing logic.
*/
- override fun notifyAll(txns: Iterable) {
+ fun notifyAll(txns: Iterable) {
// It'd be easier to just group by type, but then we'd lose ordering.
val regularTxns = mutableListOf()
val notaryChangeTxns = mutableListOf()
@@ -142,6 +142,9 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
if (notaryChangeTxns.isNotEmpty()) notifyNotaryChange(notaryChangeTxns.toList())
}
+ /** Same as notifyAll but with a single transaction. */
+ fun notify(tx: CoreTransaction) = notifyAll(listOf(tx))
+
private fun notifyRegular(txns: Iterable) {
fun makeUpdate(tx: WireTransaction): Vault.Update {
val myKeys = services.keyManagementService.filterMyKeys(tx.outputs.flatMap { it.data.participants.map { it.owningKey } })
@@ -369,22 +372,7 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
return claimedStates
}
- // TODO : Persists this in DB.
- private val authorisedUpgrade = mutableMapOf>>()
- override fun getAuthorisedContractUpgrade(ref: StateRef) = authorisedUpgrade[ref]
-
- override fun authoriseContractUpgrade(stateAndRef: StateAndRef<*>, upgradedContractClass: Class>) {
- val upgrade = upgradedContractClass.newInstance()
- if (upgrade.legacyContract != stateAndRef.state.data.contract.javaClass) {
- throw IllegalArgumentException("The contract state cannot be upgraded using provided UpgradedContract.")
- }
- authorisedUpgrade.put(stateAndRef.ref, upgradedContractClass)
- }
-
- override fun deauthoriseContractUpgrade(stateAndRef: StateAndRef<*>) {
- authorisedUpgrade.remove(stateAndRef.ref)
- }
@VisibleForTesting
internal fun isRelevant(state: ContractState, myKeys: Set): Boolean {
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt
index fa40b2dc05..6fbbf5e534 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt
@@ -64,7 +64,7 @@ class DBTransactionStorageTests : TestDependencyInjectionBase() {
validatedTransactions.addTransaction(stx)
}
// Refactored to use notifyAll() as we have no other unit test for that method with multiple transactions.
- vaultService.notifyAll(txs.map { it.tx })
+ (vaultService as NodeVaultService).notifyAll(txs.map { it.tx })
}
}
}
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt
index fcf843e776..f1fd90b136 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt
@@ -25,6 +25,7 @@ import net.corda.finance.schemas.SampleCashSchemaV3
import net.corda.finance.utils.sumCash
import net.corda.node.services.schema.HibernateObserver
import net.corda.node.services.schema.NodeSchemaService
+import net.corda.node.services.vault.NodeVaultService
import net.corda.node.services.vault.VaultSchemaV1
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase
@@ -88,7 +89,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
validatedTransactions.addTransaction(stx)
}
// Refactored to use notifyAll() as we have no other unit test for that method with multiple transactions.
- vaultService.notifyAll(txs.map { it.tx })
+ (vaultService as NodeVaultService).notifyAll(txs.map { it.tx })
}
override fun jdbcSession() = database.createSession()
}
diff --git a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt
index cc839addf4..cdf6d06fc5 100644
--- a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt
@@ -96,7 +96,7 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
val originalVault = vaultSvc
val originalVaultQuery = vaultQuery
val services2 = object : MockServices() {
- override val vaultService: VaultService get() = originalVault
+ override val vaultService: NodeVaultService get() = originalVault as NodeVaultService
override fun recordTransactions(notifyVault: Boolean, txs: Iterable) {
for (stx in txs) {
validatedTransactions.addTransaction(stx)
diff --git a/test-utils/src/main/kotlin/net/corda/node/testing/MockServiceHubInternal.kt b/test-utils/src/main/kotlin/net/corda/node/testing/MockServiceHubInternal.kt
index ff70a21606..d8ce9c23f7 100644
--- a/test-utils/src/main/kotlin/net/corda/node/testing/MockServiceHubInternal.kt
+++ b/test-utils/src/main/kotlin/net/corda/node/testing/MockServiceHubInternal.kt
@@ -42,6 +42,7 @@ open class MockServiceHubInternal(
val scheduler: SchedulerService? = null,
val overrideClock: Clock? = NodeClock(),
val schemas: SchemaService? = NodeSchemaService(),
+ val customContractUpgradeService: ContractUpgradeService? = null,
val customTransactionVerifierService: TransactionVerifierService? = InMemoryTransactionVerifierService(2)
) : ServiceHubInternal {
override val vaultQueryService: VaultQueryService
@@ -50,6 +51,8 @@ open class MockServiceHubInternal(
get() = customTransactionVerifierService ?: throw UnsupportedOperationException()
override val vaultService: VaultService
get() = customVault ?: throw UnsupportedOperationException()
+ override val contractUpgradeService: ContractUpgradeService
+ get() = customContractUpgradeService ?: throw UnsupportedOperationException()
override val keyManagementService: KeyManagementService
get() = keyManagement ?: throw UnsupportedOperationException()
override val identityService: IdentityService
diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt
index ab496c749a..3f0bdc17f5 100644
--- a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt
+++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt
@@ -26,6 +26,7 @@ import net.corda.node.services.persistence.InMemoryStateMachineRecordedTransacti
import net.corda.node.services.schema.HibernateObserver
import net.corda.node.services.schema.NodeSchemaService
import net.corda.node.services.transactions.InMemoryTransactionVerifierService
+import net.corda.node.services.upgrade.ContractUpgradeServiceImpl
import net.corda.node.services.vault.HibernateVaultQueryImpl
import net.corda.node.services.vault.NodeVaultService
import net.corda.node.utilities.CordaPersistence
@@ -123,7 +124,7 @@ open class MockServices(vararg val keys: KeyPair) : ServiceHub {
validatedTransactions.addTransaction(stx)
}
// Refactored to use notifyAll() as we have no other unit test for that method with multiple transactions.
- vaultService.notifyAll(txs.map { it.tx })
+ (vaultService as NodeVaultService).notifyAll(txs.map { it.tx })
}
override val vaultQueryService: VaultQueryService = HibernateVaultQueryImpl(database.hibernateConfig, vaultService)
@@ -155,6 +156,7 @@ open class MockServices(vararg val keys: KeyPair) : ServiceHub {
override val keyManagementService: KeyManagementService = MockKeyManagementService(identityService, *keys)
override val vaultService: VaultService get() = throw UnsupportedOperationException()
+ override val contractUpgradeService: ContractUpgradeService = ContractUpgradeServiceImpl()
override val vaultQueryService: VaultQueryService get() = throw UnsupportedOperationException()
override val networkMapCache: NetworkMapCache get() = throw UnsupportedOperationException()
override val clock: Clock get() = Clock.systemUTC()