Merge remote-tracking branch 'open/master' into anthony-os-merge-20180406

# Conflicts:
#	testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt
This commit is contained in:
Anthony Keenan 2018-04-06 11:43:34 +01:00
commit f798c58c36
3 changed files with 89 additions and 51 deletions

View File

@ -58,28 +58,12 @@ interface NetworkMapCacheBaseInternal : NetworkMapCacheBase {
interface ServiceHubInternal : ServiceHub { interface ServiceHubInternal : ServiceHub {
companion object { companion object {
private val log = contextLogger() private val log = contextLogger()
}
override val vaultService: VaultServiceInternal fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable<SignedTransaction>,
/** validatedTransactions: WritableTransactionStorage,
* A map of hash->tx where tx has been signature/contract validated and the states are known to be correct. stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage,
* The signatures aren't technically needed after that point, but we keep them around so that we can relay vaultService: VaultServiceInternal) {
* the transaction data to other nodes that need it.
*/
override val validatedTransactions: WritableTransactionStorage
val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage
val monitoringService: MonitoringService
val schemaService: SchemaService
override val networkMapCache: NetworkMapCacheInternal
val auditService: AuditService
val rpcFlows: List<Class<out FlowLogic<*>>>
val networkService: MessagingService
val database: CordaPersistence
val configuration: NodeConfiguration
val nodeProperties: NodePropertiesStore
val networkMapUpdater: NetworkMapUpdater
override val cordappProvider: CordappProviderInternal
override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable<SignedTransaction>) {
require(txs.any()) { "No transactions passed in for recording" } require(txs.any()) { "No transactions passed in for recording" }
val recordedTransactions = txs.filter { validatedTransactions.addTransaction(it) } val recordedTransactions = txs.filter { validatedTransactions.addTransaction(it) }
val stateMachineRunId = FlowStateMachineImpl.currentStateMachine()?.id val stateMachineRunId = FlowStateMachineImpl.currentStateMachine()?.id
@ -126,9 +110,33 @@ interface ServiceHubInternal : ServiceHub {
// //
// Because the primary use case for recording irrelevant states is observer/regulator nodes, who are unlikely // Because the primary use case for recording irrelevant states is observer/regulator nodes, who are unlikely
// to make writes to the ledger very often or at all, we choose to punt this issue for the time being. // to make writes to the ledger very often or at all, we choose to punt this issue for the time being.
vaultService.notifyAll(statesToRecord, txs.map { it.coreTransaction }) vaultService.notifyAll(statesToRecord, recordedTransactions.map { it.coreTransaction })
} }
} }
}
override val vaultService: VaultServiceInternal
/**
* 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 transaction data to other nodes that need it.
*/
override val validatedTransactions: WritableTransactionStorage
val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage
val monitoringService: MonitoringService
val schemaService: SchemaService
override val networkMapCache: NetworkMapCacheInternal
val auditService: AuditService
val rpcFlows: List<Class<out FlowLogic<*>>>
val networkService: MessagingService
val database: CordaPersistence
val configuration: NodeConfiguration
val nodeProperties: NodePropertiesStore
val networkMapUpdater: NetworkMapUpdater
override val cordappProvider: CordappProviderInternal
override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable<SignedTransaction>) {
recordTransactions(statesToRecord, txs, validatedTransactions, stateMachineRecordedTransactionMapping, vaultService)
}
fun getFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>): InitiatedFlowFactory<*>? fun getFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>): InitiatedFlowFactory<*>?
} }

View File

@ -140,6 +140,18 @@ class NodeVaultServiceTest {
return tryLockFungibleStatesForSpending(lockId, baseCriteria, amount, Cash.State::class.java) return tryLockFungibleStatesForSpending(lockId, baseCriteria, amount, Cash.State::class.java)
} }
@Test
fun `duplicate insert of transaction does not fail`() {
database.transaction {
val cash = Cash()
val howMuch = 100.DOLLARS
val issuance = TransactionBuilder(null as Party?)
cash.generateIssue(issuance, Amount(howMuch.quantity, Issued(DUMMY_CASH_ISSUER, howMuch.token)), services.myInfo.singleIdentity(), dummyNotary.party)
val transaction = issuerServices.signInitialTransaction(issuance, DUMMY_CASH_ISSUER.party.owningKey)
services.recordTransactions(transaction)
services.recordTransactions(transaction)
}
}
@Test @Test
fun `states not local to instance`() { fun `states not local to instance`() {

View File

@ -19,10 +19,13 @@ import net.corda.core.contracts.StateRef
import net.corda.core.cordapp.CordappProvider import net.corda.core.cordapp.CordappProvider
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StateMachineRunId
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate import net.corda.core.identity.PartyAndCertificate
import net.corda.core.messaging.DataFeed
import net.corda.core.messaging.FlowHandle import net.corda.core.messaging.FlowHandle
import net.corda.core.messaging.FlowProgressHandle import net.corda.core.messaging.FlowProgressHandle
import net.corda.core.messaging.StateMachineTransactionMapping
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.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsToken
@ -37,6 +40,7 @@ import net.corda.node.services.api.WritableTransactionStorage
import net.corda.node.services.config.ConfigHelper import net.corda.node.services.config.ConfigHelper
import net.corda.node.services.config.configOf import net.corda.node.services.config.configOf
import net.corda.node.services.config.parseToDbSchemaFriendlyName import net.corda.node.services.config.parseToDbSchemaFriendlyName
import net.corda.node.services.api.*
import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.identity.InMemoryIdentityService
import net.corda.node.services.schema.HibernateObserver import net.corda.node.services.schema.HibernateObserver
import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.schema.NodeSchemaService
@ -148,9 +152,10 @@ open class MockServices private constructor(
override val vaultService: VaultService = makeVaultService(database.hibernateConfig, schemaService) override val vaultService: VaultService = makeVaultService(database.hibernateConfig, schemaService)
override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable<SignedTransaction>) { override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable<SignedTransaction>) {
super.recordTransactions(statesToRecord, txs) ServiceHubInternal.recordTransactions(statesToRecord, txs,
// Refactored to use notifyAll() as we have no other unit test for that method with multiple transactions. validatedTransactions as WritableTransactionStorage,
(vaultService as VaultServiceInternal).notifyAll(statesToRecord, txs.map { it.coreTransaction }) mockStateMachineRecordedTransactionMappingStorage,
vaultService as VaultServiceInternal)
} }
override fun jdbcSession(): Connection = database.createSession() override fun jdbcSession(): Connection = database.createSession()
@ -166,6 +171,19 @@ open class MockServices private constructor(
// compiler and then the c'tor itself. // compiler and then the c'tor itself.
return Throwable().stackTrace[3].className.split('.').dropLast(1).joinToString(".") return Throwable().stackTrace[3].className.split('.').dropLast(1).joinToString(".")
} }
// Because Kotlin is dumb and makes not publicly visible objects public, thus changing the public API.
private val mockStateMachineRecordedTransactionMappingStorage = MockStateMachineRecordedTransactionMappingStorage()
}
private class MockStateMachineRecordedTransactionMappingStorage : StateMachineRecordedTransactionMappingStorage {
override fun addMapping(stateMachineRunId: StateMachineRunId, transactionId: SecureHash) {
throw UnsupportedOperationException()
}
override fun track(): DataFeed<List<StateMachineTransactionMapping>, StateMachineTransactionMapping> {
throw UnsupportedOperationException()
}
} }
private constructor(cordappLoader: CordappLoader, identityService: IdentityService, networkParameters: NetworkParameters, private constructor(cordappLoader: CordappLoader, identityService: IdentityService, networkParameters: NetworkParameters,