Skip to content

Commit 4df64c2

Browse files
Merge pull request #9 from onix-labs/feature-pointers
feature-pointers
2 parents 9fa4903 + 7dc5d83 commit 4df64c2

File tree

29 files changed

+182
-267
lines changed

29 files changed

+182
-267
lines changed

onixlabs-corda-identity-framework-contract/src/main/kotlin/io/onixlabs/corda/identityframework/contract/Attestation.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,8 @@ open class Attestation<T : ContractState>(
9494
linearId = linearId.id,
9595
externalId = linearId.externalId,
9696
attestor = attestor,
97-
pointerStateRef = pointer.stateRef.toString(),
97+
pointer = pointer.statePointer.toString(),
9898
pointerStateType = pointer.stateType.canonicalName,
99-
pointerStateLinearId = pointer.getLinearId()?.id,
100-
pointerStateExternalId = pointer.getLinearId()?.externalId,
10199
pointerHash = pointer.hash.toString(),
102100
status = status,
103101
previousStateRef = previousStateRef?.toString(),

onixlabs-corda-identity-framework-contract/src/main/kotlin/io/onixlabs/corda/identityframework/contract/AttestationPointer.kt

Lines changed: 78 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -34,33 +34,61 @@ import java.util.*
3434
* Represents the base class for attestation pointer implementations.
3535
*
3636
* @param T The underlying [ContractState] type.
37-
* @property stateRef The [StateRef] of the witnessed state being attested.
3837
* @property stateType The [Class] of the witnessed state being attested.
39-
* @property hash The unique hash of the attestation pointer.
38+
* @property statePointer The pointer to the witnessed state being attested.
39+
* @property hash The hash of the attestation pointer.
40+
*
41+
* Note that attestation pointer hashes should be unique for static attestation pointers since they point to the
42+
* attested state's [StateRef], however attestation pointer hashes for linear attestation pointers will not be unique
43+
* since they point to the attested state's [UniqueIdentifier].
4044
*/
4145
@CordaSerializable
4246
sealed class AttestationPointer<T : ContractState> : SingularResolvable<T>, Hashable {
4347
abstract val stateType: Class<T>
44-
abstract val stateRef: StateRef
48+
abstract val statePointer: Any
49+
50+
final override val hash: SecureHash
51+
get() = SecureHash.sha256("$stateType$statePointer")
4552

4653
/**
47-
* Determines whether any immutable properties of this object have changed.
54+
* Determines whether the specified object is equal to the current object.
4855
*
49-
* @param other The pointer to compare to this one.
50-
* @return Returns true if the immutable properties remain unchanged; otherwise, false.
56+
* @param other The object to compare with the current object.
57+
* @return Returns true if the specified object is equal to the current object; otherwise, false.
5158
*/
52-
internal abstract fun immutableEquals(other: AttestationPointer<T>): Boolean
59+
final override fun equals(other: Any?): Boolean {
60+
return this === other || (other is AttestationPointer<*>
61+
&& other.javaClass == javaClass
62+
&& other.stateType == stateType
63+
&& other.statePointer == statePointer)
64+
}
5365

5466
/**
55-
* Determines whether this [SingularResolvable] is pointing to the specified [StateAndRef] instance.
67+
* Serves as the default hash function.
5668
*
57-
* @param stateAndRef The [StateAndRef] to determine being pointed to.
58-
* @return Returns true if this [SingularResolvable] is pointing to the specified [StateAndRef]; otherwise, false.
69+
* @return Returns a hash code for the current object.
5970
*/
60-
override fun isPointingTo(stateAndRef: StateAndRef<T>): Boolean {
61-
return stateAndRef.ref == stateRef
71+
final override fun hashCode(): Int {
72+
return Objects.hash(stateType, statePointer)
73+
}
74+
75+
/**
76+
* Serves as the default hash function.
77+
*
78+
* @return Returns a hash code for the current object.
79+
*/
80+
final override fun toString(): String {
81+
return toDataClassString()
6282
}
6383

84+
/**
85+
* Determines whether any immutable properties of this object have changed.
86+
*
87+
* @param other The pointer to compare to this one.
88+
* @return Returns true if the immutable properties remain unchanged; otherwise, false.
89+
*/
90+
internal abstract fun immutableEquals(other: AttestationPointer<T>): Boolean
91+
6492
/**
6593
* Checks the claim and value class types of the specified state to ensure they match the expected types.
6694
*
@@ -75,77 +103,46 @@ sealed class AttestationPointer<T : ContractState> : SingularResolvable<T>, Hash
75103
}
76104
}
77105
}
78-
79-
/**
80-
* Gets the state linearId if this [AttestationPointer] is a [LinearAttestationPointer]; otherwise, null.
81-
* @return Returns the state linearId if this [AttestationPointer] is a [LinearAttestationPointer]; otherwise, null.
82-
*/
83-
internal fun getLinearId(): UniqueIdentifier? {
84-
return if (this is LinearAttestationPointer<*>) stateLinearId else null
85-
}
86106
}
87107

88108
/**
89109
* Represents a linear attestation pointer to a [LinearState].
90110
*
91-
* @param T The underlying [LinearState] type.
111+
* The intention of a linear attestation pointer is to evolve with the linear state that they point to. In this case
112+
* the linear state being witnessed and attested is free to evolve without losing attestation, since the attestation
113+
* points to the state by it's linear ID. Whilst this behavior is deliberate, it might incur some security concerns;
114+
* for example, the state being witnessed and attested may evolve to contain erroneous data, however its attestation
115+
* will remain unchanged until the attestor amends it.
92116
*
117+
* To mitigate these security concerns, the intention is that developers will derive a custom attestation and decide
118+
* on the attestation's validity based on some other factor about the underlying state.
119+
*
120+
* @param T The underlying [LinearState] type.
93121
* @property stateType The [Class] of the witnessed state being attested.
94-
* @property stateRef The [StateRef] of the witnessed state being attested.
95-
* @property stateLinearId The [UniqueIdentifier] of the witnessed state being attested.
96-
* @property hash The unique hash of the attestation pointer.
122+
* @property statePointer The pointer to the witnessed state being attested.
123+
* @property hash The hash of the attestation pointer.
97124
*/
98125
class LinearAttestationPointer<T : LinearState> internal constructor(
99126
override val stateType: Class<T>,
100-
override val stateRef: StateRef,
101-
val stateLinearId: UniqueIdentifier
127+
override val statePointer: UniqueIdentifier
102128
) : AttestationPointer<T>() {
103129

104-
constructor(stateAndRef: StateAndRef<T>) : this(
105-
stateType = stateAndRef.state.data.javaClass,
106-
stateRef = stateAndRef.ref,
107-
stateLinearId = stateAndRef.state.data.linearId
108-
)
130+
constructor(stateAndRef: StateAndRef<T>) : this(stateAndRef.state.data.javaClass, stateAndRef.state.data.linearId)
109131

110132
private val criteria: QueryCriteria = vaultQuery(stateType) {
111-
stateStatus(Vault.StateStatus.ALL)
133+
stateStatus(Vault.StateStatus.UNCONSUMED)
112134
relevancyStatus(Vault.RelevancyStatus.ALL)
113-
stateRefs(stateRef)
114-
linearIds(stateLinearId)
115-
}
116-
117-
override val hash: SecureHash
118-
get() = SecureHash.sha256("$stateType$stateRef$stateLinearId")
119-
120-
/**
121-
* Determines whether the specified object is equal to the current object.
122-
*
123-
* @param other The object to compare with the current object.
124-
* @return Returns true if the specified object is equal to the current object; otherwise, false.
125-
*/
126-
override fun equals(other: Any?): Boolean {
127-
return this === other || (other is LinearAttestationPointer<*>
128-
&& other.stateType == stateType
129-
&& other.stateRef == stateRef
130-
&& other.stateLinearId == stateLinearId)
131-
}
132-
133-
/**
134-
* Serves as the default hash function.
135-
*
136-
* @return Returns a hash code for the current object.
137-
*/
138-
override fun hashCode(): Int {
139-
return Objects.hash(stateType, stateRef, stateLinearId)
135+
linearIds(statePointer)
140136
}
141137

142138
/**
143-
* Serves as the default hash function.
139+
* Determines whether this [SingularResolvable] is pointing to the specified [StateAndRef] instance.
144140
*
145-
* @return Returns a hash code for the current object.
141+
* @param stateAndRef The [StateAndRef] to determine being pointed to.
142+
* @return Returns true if this [SingularResolvable] is pointing to the specified [StateAndRef]; otherwise, false.
146143
*/
147-
override fun toString(): String {
148-
return toDataClassString()
144+
override fun isPointingTo(stateAndRef: StateAndRef<T>): Boolean {
145+
return statePointer == stateAndRef.state.data.linearId
149146
}
150147

151148
/**
@@ -194,66 +191,46 @@ class LinearAttestationPointer<T : LinearState> internal constructor(
194191
override fun immutableEquals(other: AttestationPointer<T>): Boolean {
195192
return other is LinearAttestationPointer<*>
196193
&& other.stateType == stateType
197-
&& other.stateLinearId == stateLinearId
194+
&& other.statePointer == statePointer
198195
}
199196
}
200197

201198
/**
202199
* Represents a static attestation pointer to a [ContractState].
203200
*
204-
* @param T The underlying [LinearState] type.
201+
* The intention of a static attestation pointer is to point specifically to a version of a state by its [StateRef].
202+
* Any evolution of the state being witnessed and attested therefore renders existing attestations useless since
203+
* they no longer point to a relevant state on the ledger, and must be amended to point to the latest state version.
204+
*
205+
* In most cases, static attestation pointers may be considered safer than linear attestation pointers, since they
206+
* do not permit state evolution.
205207
*
208+
* @param T The underlying [LinearState] type.
206209
* @property stateType The [Class] of the witnessed state being attested.
207-
* @property stateRef The [StateRef] of the witnessed state being attested.
208-
* @property hash The unique hash of the attestation pointer.
210+
* @property statePointer The pointer to the witnessed state being attested.
211+
* @property hash The hash of the attestation pointer.
209212
*/
210213
class StaticAttestationPointer<T : ContractState> internal constructor(
211214
override val stateType: Class<T>,
212-
override val stateRef: StateRef
215+
override val statePointer: StateRef
213216
) : AttestationPointer<T>() {
214217

215-
constructor(stateAndRef: StateAndRef<T>) : this(
216-
stateType = stateAndRef.state.data.javaClass,
217-
stateRef = stateAndRef.ref
218-
)
218+
constructor(stateAndRef: StateAndRef<T>) : this(stateAndRef.state.data.javaClass, stateAndRef.ref)
219219

220220
private val criteria: QueryCriteria = vaultQuery(stateType) {
221221
stateStatus(Vault.StateStatus.ALL)
222222
relevancyStatus(Vault.RelevancyStatus.ALL)
223-
stateRefs(stateRef)
224-
}
225-
226-
override val hash: SecureHash
227-
get() = SecureHash.sha256("$stateType$stateRef")
228-
229-
/**
230-
* Determines whether the specified object is equal to the current object.
231-
*
232-
* @param other The object to compare with the current object.
233-
* @return Returns true if the specified object is equal to the current object; otherwise, false.
234-
*/
235-
override fun equals(other: Any?): Boolean {
236-
return this === other || (other is StaticAttestationPointer<*>
237-
&& other.stateType == stateType
238-
&& other.stateRef == stateRef)
223+
stateRefs(statePointer)
239224
}
240225

241226
/**
242-
* Serves as the default hash function.
243-
*
244-
* @return Returns a hash code for the current object.
245-
*/
246-
override fun hashCode(): Int {
247-
return Objects.hash(stateType, stateRef)
248-
}
249-
250-
/**
251-
* Serves as the default hash function.
227+
* Determines whether this [SingularResolvable] is pointing to the specified [StateAndRef] instance.
252228
*
253-
* @return Returns a hash code for the current object.
229+
* @param stateAndRef The [StateAndRef] to determine being pointed to.
230+
* @return Returns true if this [SingularResolvable] is pointing to the specified [StateAndRef]; otherwise, false.
254231
*/
255-
override fun toString(): String {
256-
return toDataClassString()
232+
override fun isPointingTo(stateAndRef: StateAndRef<T>): Boolean {
233+
return statePointer == stateAndRef.ref
257234
}
258235

259236
/**

onixlabs-corda-identity-framework-contract/src/main/kotlin/io/onixlabs/corda/identityframework/contract/AttestationSchema.kt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,12 @@ object AttestationSchema {
4141
@Column(name = "attestor", nullable = false)
4242
val attestor: AbstractParty = NULL_PARTY,
4343

44-
@Column(name = "pointer_state_ref", nullable = false)
45-
val pointerStateRef: String = "",
44+
@Column(name = "pointer_state_pointer", nullable = false)
45+
val pointer: String = "",
4646

4747
@Column(name = "pointer_state_type", nullable = false)
4848
val pointerStateType: String = "",
4949

50-
@Column(name = "pointer_state_linear_id", nullable = true)
51-
val pointerStateLinearId: UUID? = null,
52-
53-
@Column(name = "pointer_state_external_id", nullable = true)
54-
val pointerStateExternalId: String? = null,
55-
5650
@Column(name = "pointer_hash", nullable = false)
5751
val pointerHash: String = "",
5852

onixlabs-corda-identity-framework-contract/src/main/kotlin/io/onixlabs/corda/identityframework/contract/Extensions.Attestation.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.amendA
4646
* @param metadata Additional information about the attestation.
4747
* @return Returns an amended attestation.
4848
*/
49-
inline fun <reified T : ContractState, reified U : Attestation<T>> StateAndRef<U>.amendContractStateAttestation(
49+
inline fun <reified T : ContractState, reified U : Attestation<T>> StateAndRef<U>.amendStaticAttestation(
5050
status: AttestationStatus,
5151
stateAndRef: StateAndRef<T>,
5252
metadata: Map<String, String> = emptyMap()
@@ -62,7 +62,7 @@ inline fun <reified T : ContractState, reified U : Attestation<T>> StateAndRef<U
6262
* @param metadata Additional information about the attestation.
6363
* @return Returns an amended attestation.
6464
*/
65-
inline fun <reified T : LinearState, reified U : Attestation<T>> StateAndRef<U>.amendLinearStateAttestation(
65+
inline fun <reified T : LinearState, reified U : Attestation<T>> StateAndRef<U>.amendLinearAttestation(
6666
status: AttestationStatus,
6767
stateAndRef: StateAndRef<T>,
6868
metadata: Map<String, String> = emptyMap()
@@ -77,7 +77,7 @@ inline fun <reified T : LinearState, reified U : Attestation<T>> StateAndRef<U>.
7777
* @param metadata Additional information about the attestation.
7878
* @return Returns an accepted attestation.
7979
*/
80-
inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.acceptState(
80+
inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.acceptAttestation(
8181
pointer: AttestationPointer<T> = this.state.data.pointer,
8282
metadata: Map<String, String> = emptyMap()
8383
): U = amendAttestation(AttestationStatus.ACCEPTED, pointer, metadata)
@@ -91,7 +91,7 @@ inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.accept
9191
* @param metadata Additional information about the attestation.
9292
* @return Returns an accepted attestation.
9393
*/
94-
inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.acceptContractState(
94+
inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.acceptStaticAttestation(
9595
stateAndRef: StateAndRef<T>,
9696
metadata: Map<String, String> = emptyMap()
9797
): U = amendAttestation(AttestationStatus.ACCEPTED, stateAndRef.toStaticAttestationPointer(), metadata)
@@ -105,7 +105,7 @@ inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.accept
105105
* @param metadata Additional information about the attestation.
106106
* @return Returns an accepted attestation.
107107
*/
108-
inline fun <T : LinearState, reified U : Attestation<T>> StateAndRef<U>.acceptLinearState(
108+
inline fun <T : LinearState, reified U : Attestation<T>> StateAndRef<U>.acceptLinearAttestation(
109109
stateAndRef: StateAndRef<T>,
110110
metadata: Map<String, String> = emptyMap()
111111
): U = amendAttestation(AttestationStatus.ACCEPTED, stateAndRef.toLinearAttestationPointer(), metadata)
@@ -119,7 +119,7 @@ inline fun <T : LinearState, reified U : Attestation<T>> StateAndRef<U>.acceptLi
119119
* @param metadata Additional information about the attestation.
120120
* @return Returns an rejected attestation.
121121
*/
122-
inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.rejectState(
122+
inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.rejectAttestation(
123123
pointer: AttestationPointer<T> = this.state.data.pointer,
124124
metadata: Map<String, String> = emptyMap()
125125
): U = amendAttestation(AttestationStatus.REJECTED, pointer, metadata)
@@ -133,7 +133,7 @@ inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.reject
133133
* @param metadata Additional information about the attestation.
134134
* @return Returns an rejected attestation.
135135
*/
136-
inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.rejectContractState(
136+
inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.rejectStaticAttestation(
137137
stateAndRef: StateAndRef<T>,
138138
metadata: Map<String, String> = emptyMap()
139139
): U = amendAttestation(AttestationStatus.REJECTED, stateAndRef.toStaticAttestationPointer(), metadata)
@@ -147,7 +147,7 @@ inline fun <T : ContractState, reified U : Attestation<T>> StateAndRef<U>.reject
147147
* @param metadata Additional information about the attestation.
148148
* @return Returns an rejected attestation.
149149
*/
150-
inline fun <T : LinearState, reified U : Attestation<T>> StateAndRef<U>.rejectLinearState(
150+
inline fun <T : LinearState, reified U : Attestation<T>> StateAndRef<U>.rejectLinearAttestation(
151151
stateAndRef: StateAndRef<T>,
152152
metadata: Map<String, String> = emptyMap()
153153
): U = amendAttestation(AttestationStatus.REJECTED, stateAndRef.toLinearAttestationPointer(), metadata)

onixlabs-corda-identity-framework-contract/src/main/kotlin/io/onixlabs/corda/identityframework/contract/Extensions.CordaClaim.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ import net.corda.core.contracts.StateAndRef
2525
* @param U The underlying [CordaClaim] type.
2626
* @param value The amended claim value.
2727
* @return Returns an amended claim.
28+
* @throws IllegalStateException if the amend function of the specified state type cannot be cast to [U].
29+
*
30+
* Note that this function tends to fail if you don't override the amend function of custom claim types.
2831
*/
2932
inline fun <T : Any, reified U : CordaClaim<T>> StateAndRef<U>.amend(value: T): U = try {
3033
U::class.java.cast(state.data.amend(ref, value))

0 commit comments

Comments
 (0)