Removed is relevant from LinearState (#1294)

This commit is contained in:
Patrick Kuo 2017-08-30 16:26:34 +01:00 committed by GitHub
parent cdea1665cf
commit 9bd4342039
13 changed files with 24 additions and 57 deletions

View File

@ -219,11 +219,6 @@ interface LinearState : ContractState {
* except at issuance/termination. * except at issuance/termination.
*/ */
val linearId: UniqueIdentifier val linearId: UniqueIdentifier
/**
* True if this should be tracked by our vault(s).
*/
fun isRelevant(ourKeys: Set<PublicKey>): Boolean
} }
// DOCEND 2 // DOCEND 2

View File

@ -34,7 +34,6 @@ UNRELEASED
must use ``SendTransactionFlow`` at the correct place. There is also ``ReceiveStateAndRefFlow`` and ``SendStateAndRefFlow`` for must use ``SendTransactionFlow`` at the correct place. There is also ``ReceiveStateAndRefFlow`` and ``SendStateAndRefFlow`` for
dealing with ``StateAndRef``s. dealing with ``StateAndRef``s.
* Vault query soft locking enhancements and deprecations * Vault query soft locking enhancements and deprecations
* removed original ``VaultService`` ``softLockedStates` query mechanism. * removed original ``VaultService`` ``softLockedStates` query mechanism.
* introduced improved ``SoftLockingCondition`` filterable attribute in ``VaultQueryCriteria`` to enable specification * introduced improved ``SoftLockingCondition`` filterable attribute in ``VaultQueryCriteria`` to enable specification
@ -68,6 +67,9 @@ UNRELEASED
* Moved ``:finance`` gradle project files into a ``net.corda.finance`` package namespace. * Moved ``:finance`` gradle project files into a ``net.corda.finance`` package namespace.
This may require adjusting imports of Cash flow references and also of ``StartFlow`` permission in ``gradle.build`` files. This may require adjusting imports of Cash flow references and also of ``StartFlow`` permission in ``gradle.build`` files.
* Removed the concept of relevancy from ``LinearState``. The ``ContractState``'s relevancy to the vault can be determined
by the flow context, the vault will process any transaction from a flow which is not derived from transaction resolution verification.
Milestone 14 Milestone 14
------------ ------------

View File

@ -3,7 +3,6 @@ package net.corda.docs
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.core.contracts.* import net.corda.core.contracts.*
import net.corda.core.crypto.TransactionSignature import net.corda.core.crypto.TransactionSignature
import net.corda.core.crypto.containsAny
import net.corda.core.flows.FinalityFlow import net.corda.core.flows.FinalityFlow
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatedBy
@ -18,7 +17,6 @@ import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
import java.security.PublicKey
// Minimal state model of a manual approval process // Minimal state model of a manual approval process
@CordaSerializable @CordaSerializable
@ -51,10 +49,6 @@ data class TradeApprovalContract(private val blank: Void? = null) : Contract {
val parties: List<Party> get() = listOf(source, counterparty) val parties: List<Party> get() = listOf(source, counterparty)
override val participants: List<AbstractParty> get() = parties override val participants: List<AbstractParty> get() = parties
override fun isRelevant(ourKeys: Set<PublicKey>): Boolean {
return participants.any { it.owningKey.containsAny(ourKeys) }
}
} }
/** /**

View File

@ -4,7 +4,6 @@ import co.paralleluniverse.fibers.Suspendable
import co.paralleluniverse.strands.Strand import co.paralleluniverse.strands.Strand
import net.corda.core.contracts.* import net.corda.core.contracts.*
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.containsAny
import net.corda.core.internal.ThreadBox import net.corda.core.internal.ThreadBox
import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.VisibleForTesting
import net.corda.core.internal.tee import net.corda.core.internal.tee
@ -144,10 +143,10 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
} }
private fun notifyRegular(txns: Iterable<WireTransaction>) { private fun notifyRegular(txns: Iterable<WireTransaction>) {
val ourKeys = services.keyManagementService.keys
fun makeUpdate(tx: WireTransaction): Vault.Update<ContractState> { fun makeUpdate(tx: WireTransaction): Vault.Update<ContractState> {
val myKeys = services.keyManagementService.filterMyKeys(tx.outputs.flatMap { it.data.participants.map { it.owningKey } })
val ourNewStates = tx.outputs. val ourNewStates = tx.outputs.
filter { isRelevant(it.data, ourKeys) }. filter { isRelevant(it.data, myKeys.toSet()) }.
map { tx.outRef<ContractState>(it.data) } map { tx.outRef<ContractState>(it.data) }
// Retrieve all unconsumed states for this transaction's inputs // Retrieve all unconsumed states for this transaction's inputs
@ -173,13 +172,10 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
// We also can't do filtering beforehand, since output encumbrance pointers get recalculated based on // We also can't do filtering beforehand, since output encumbrance pointers get recalculated based on
// input positions // input positions
val ltx = tx.resolve(services, emptyList()) val ltx = tx.resolve(services, emptyList())
val myKeys = services.keyManagementService.filterMyKeys(ltx.outputs.flatMap { it.data.participants.map { it.owningKey } })
val (consumedStateAndRefs, producedStates) = ltx.inputs. val (consumedStateAndRefs, producedStates) = ltx.inputs.
zip(ltx.outputs). zip(ltx.outputs).
filter { filter { (_, output) -> isRelevant(output.data, myKeys.toSet()) }.
(_, output) ->
isRelevant(output.data, ourKeys)
}.
unzip() unzip()
val producedStateAndRefs = producedStates.map { ltx.outRef<ContractState>(it.data) } val producedStateAndRefs = producedStates.map { ltx.outRef<ContractState>(it.data) }
@ -391,9 +387,11 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
} }
@VisibleForTesting @VisibleForTesting
internal fun isRelevant(state: ContractState, ourKeys: Set<PublicKey>) = when (state) { internal fun isRelevant(state: ContractState, myKeys: Set<PublicKey>): Boolean {
is OwnableState -> state.owner.owningKey.containsAny(ourKeys) val keysToCheck = when (state) {
is LinearState -> state.isRelevant(ourKeys) is OwnableState -> listOf(state.owner.owningKey)
else -> ourKeys.intersect(state.participants.map { it.owningKey }).isNotEmpty() else -> state.participants.map { it.owningKey }
}
return keysToCheck.any { it in myKeys }
} }
} }

View File

@ -5,6 +5,7 @@ import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowLogicRef import net.corda.core.flows.FlowLogicRef
import net.corda.core.flows.FlowLogicRefFactory import net.corda.core.flows.FlowLogicRefFactory
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party
import net.corda.core.node.ServiceHub import net.corda.core.node.ServiceHub
import net.corda.core.node.services.VaultService import net.corda.core.node.services.VaultService
import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken
@ -120,14 +121,12 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
resetTestSerialization() resetTestSerialization()
} }
class TestState(val flowLogicRef: FlowLogicRef, val instant: Instant) : LinearState, SchedulableState { class TestState(val flowLogicRef: FlowLogicRef, val instant: Instant, private val myIdentity: Party) : LinearState, SchedulableState {
override val participants: List<AbstractParty> override val participants: List<AbstractParty>
get() = throw UnsupportedOperationException() get() = listOf(myIdentity)
override val linearId = UniqueIdentifier() override val linearId = UniqueIdentifier()
override fun isRelevant(ourKeys: Set<PublicKey>): Boolean = true
override fun nextScheduledActivity(thisStateRef: StateRef, flowLogicRefFactory: FlowLogicRefFactory): ScheduledActivity? { override fun nextScheduledActivity(thisStateRef: StateRef, flowLogicRefFactory: FlowLogicRefFactory): ScheduledActivity? {
return ScheduledActivity(flowLogicRef, instant) return ScheduledActivity(flowLogicRef, instant)
} }
@ -279,7 +278,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
database.transaction { database.transaction {
apply { apply {
val freshKey = services.keyManagementService.freshKey() val freshKey = services.keyManagementService.freshKey()
val state = TestState(FlowLogicRefFactoryImpl.createForRPC(TestFlowLogic::class.java, increment), instant) val state = TestState(FlowLogicRefFactoryImpl.createForRPC(TestFlowLogic::class.java, increment), instant, services.myInfo.legalIdentity)
val builder = TransactionBuilder(null).apply { val builder = TransactionBuilder(null).apply {
addOutputState(state, DUMMY_NOTARY) addOutputState(state, DUMMY_NOTARY)
addCommand(Command(), freshKey) addCommand(Command(), freshKey)

View File

@ -58,10 +58,6 @@ class ScheduledFlowTests {
} }
override val participants: List<AbstractParty> = listOf(source, destination) override val participants: List<AbstractParty> = listOf(source, destination)
override fun isRelevant(ourKeys: Set<PublicKey>): Boolean {
return participants.any { it.owningKey.containsAny(ourKeys) }
}
} }
class InsertInitialStateFlow(val destination: Party) : FlowLogic<Unit>() { class InsertInitialStateFlow(val destination: Party) : FlowLogic<Unit>() {

View File

@ -476,15 +476,18 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
val service = (services.vaultService as NodeVaultService) val service = (services.vaultService as NodeVaultService)
val amount = Amount(1000, Issued(BOC.ref(1), GBP)) val amount = Amount(1000, Issued(BOC.ref(1), GBP))
val wellKnownCash = Cash.State(amount, services.myInfo.legalIdentity) val wellKnownCash = Cash.State(amount, services.myInfo.legalIdentity)
assertTrue { service.isRelevant(wellKnownCash, services.keyManagementService.keys) } val myKeys = services.keyManagementService.filterMyKeys(listOf(wellKnownCash.owner.owningKey))
assertTrue { service.isRelevant(wellKnownCash, myKeys.toSet()) }
val anonymousIdentity = services.keyManagementService.freshKeyAndCert(services.myInfo.legalIdentityAndCert, false) val anonymousIdentity = services.keyManagementService.freshKeyAndCert(services.myInfo.legalIdentityAndCert, false)
val anonymousCash = Cash.State(amount, anonymousIdentity.party) val anonymousCash = Cash.State(amount, anonymousIdentity.party)
assertTrue { service.isRelevant(anonymousCash, services.keyManagementService.keys) } val anonymousKeys = services.keyManagementService.filterMyKeys(listOf(anonymousCash.owner.owningKey))
assertTrue { service.isRelevant(anonymousCash, anonymousKeys.toSet()) }
val thirdPartyIdentity = AnonymousParty(generateKeyPair().public) val thirdPartyIdentity = AnonymousParty(generateKeyPair().public)
val thirdPartyCash = Cash.State(amount, thirdPartyIdentity) val thirdPartyCash = Cash.State(amount, thirdPartyIdentity)
assertFalse { service.isRelevant(thirdPartyCash, services.keyManagementService.keys) } val thirdPartyKeys = services.keyManagementService.filterMyKeys(listOf(thirdPartyCash.owner.owningKey))
assertFalse { service.isRelevant(thirdPartyCash, thirdPartyKeys.toSet()) }
} }
// TODO: Unit test linear state relevancy checks // TODO: Unit test linear state relevancy checks

View File

@ -618,10 +618,6 @@ class InterestRateSwap : Contract {
override val participants: List<AbstractParty> override val participants: List<AbstractParty>
get() = listOf(fixedLeg.fixedRatePayer, floatingLeg.floatingRatePayer) get() = listOf(fixedLeg.fixedRatePayer, floatingLeg.floatingRatePayer)
override fun isRelevant(ourKeys: Set<PublicKey>): Boolean {
return fixedLeg.fixedRatePayer.owningKey.containsAny(ourKeys) || floatingLeg.floatingRatePayer.owningKey.containsAny(ourKeys)
}
override fun nextScheduledActivity(thisStateRef: StateRef, flowLogicRefFactory: FlowLogicRefFactory): ScheduledActivity? { override fun nextScheduledActivity(thisStateRef: StateRef, flowLogicRefFactory: FlowLogicRefFactory): ScheduledActivity? {
val nextFixingOf = nextFixingOf() ?: return null val nextFixingOf = nextFixingOf() ?: return null

View File

@ -22,10 +22,6 @@ data class IRSState(val swap: SwapData,
val ref: String get() = linearId.externalId!! // Same as the constructor for UniqueIdentified val ref: String get() = linearId.externalId!! // Same as the constructor for UniqueIdentified
override val participants: List<AbstractParty> get() = listOf(buyer, seller) override val participants: List<AbstractParty> get() = listOf(buyer, seller)
override fun isRelevant(ourKeys: Set<PublicKey>): Boolean {
return participants.flatMap { it.owningKey.keys }.intersect(ourKeys).isNotEmpty()
}
override fun generateAgreement(notary: Party): TransactionBuilder { override fun generateAgreement(notary: Party): TransactionBuilder {
val state = IRSState(swap, buyer, seller, OGTrade()) val state = IRSState(swap, buyer, seller, OGTrade())
return TransactionBuilder(notary).withItems(state, Command(OGTrade.Commands.Agree(), participants.map { it.owningKey })) return TransactionBuilder(notary).withItems(state, Command(OGTrade.Commands.Agree(), participants.map { it.owningKey }))

View File

@ -37,10 +37,6 @@ data class PortfolioState(val portfolio: List<StateRef>,
return ScheduledActivity(flow, LocalDate.now().plus(1, ChronoUnit.DAYS).atStartOfDay().toInstant(ZoneOffset.UTC)) return ScheduledActivity(flow, LocalDate.now().plus(1, ChronoUnit.DAYS).atStartOfDay().toInstant(ZoneOffset.UTC))
} }
override fun isRelevant(ourKeys: Set<PublicKey>): Boolean {
return participants.flatMap { it.owningKey.keys }.intersect(ourKeys).isNotEmpty()
}
override fun generateAgreement(notary: Party): TransactionBuilder { override fun generateAgreement(notary: Party): TransactionBuilder {
return TransactionBuilder(notary).withItems(copy(), Command(PortfolioSwap.Commands.Agree(), participants.map { it.owningKey })) return TransactionBuilder(notary).withItems(copy(), Command(PortfolioSwap.Commands.Agree(), participants.map { it.owningKey }))
} }

View File

@ -26,10 +26,6 @@ class DummyDealContract : Contract {
participants: List<AbstractParty> = listOf(), participants: List<AbstractParty> = listOf(),
ref: String) : this(contract, participants, UniqueIdentifier(ref)) ref: String) : this(contract, participants, UniqueIdentifier(ref))
override fun isRelevant(ourKeys: Set<PublicKey>): Boolean {
return participants.any { it.owningKey.containsAny(ourKeys) }
}
override fun generateAgreement(notary: Party): TransactionBuilder { override fun generateAgreement(notary: Party): TransactionBuilder {
throw UnsupportedOperationException("not implemented") throw UnsupportedOperationException("not implemented")
} }

View File

@ -39,10 +39,6 @@ class DummyLinearContract : Contract {
val linearBoolean: Boolean = true, val linearBoolean: Boolean = true,
val nonce: SecureHash = SecureHash.randomSHA256()) : LinearState, QueryableState { val nonce: SecureHash = SecureHash.randomSHA256()) : LinearState, QueryableState {
override fun isRelevant(ourKeys: Set<java.security.PublicKey>): Boolean {
return participants.any { it.owningKey.containsAny(ourKeys) }
}
override fun supportedSchemas(): Iterable<MappedSchema> = listOf(DummyLinearStateSchemaV1, DummyLinearStateSchemaV2) override fun supportedSchemas(): Iterable<MappedSchema> = listOf(DummyLinearStateSchemaV1, DummyLinearStateSchemaV2)
override fun generateMappedObject(schema: MappedSchema): PersistentState { override fun generateMappedObject(schema: MappedSchema): PersistentState {