mirror of
https://github.com/corda/corda.git
synced 2024-12-21 05:53:23 +00:00
Removed is relevant from LinearState (#1294)
This commit is contained in:
parent
cdea1665cf
commit
9bd4342039
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -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) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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>() {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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 }))
|
||||||
|
@ -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 }))
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user