'Corda - Checking equality of AbstractParty, Party and AnonymousParty

In Corda we have the following type hierarchy for providing ledger identities:

abstract class AbstractParty(val owningKey: PublicKey): Destination {

    /** Anonymised parties do not include any detail apart from owning key, 
        so equality is dependent solely on the key */

    override fun equals(other: Any?): Boolean {
        return other === this 
            || other is AbstractParty 
            && other.owningKey == owningKey
    }

    ...
}

// Shortened for brevity
class Party(...) : AbstractParty(...) { ... }
class AnonymousParty(...) : AbstractParty(...) { ... }

Note the comment:

Anonymised parties do not include any detail apart from owning key, so equality is dependent solely on the key

What I want to know is, why is equality defined at the root of the hierarchy, but nowhere else?

For example:

val wellKnownAlice = Party(aliceKey, aliceX500name)
val anonymousAlice = AnonymousParty(aliceKey)

wellKnownAlice == anonymousAlice
// true

Whilst I hold an opinionated view, I don't feel like these should be equal when they are fundamentally different things. I feel like this would have been better implemented like so:

abstract class AbstractParty(val owningKey: PublicKey): Destination {

    override fun equals(other: Any?): Boolean {
        return other === this 
            || other is AbstractParty 
            && other.javaClass == javaClass
            && equalsByKey(other)
    }

    fun equalsByKey(other: AbstractParty): Boolean {
        return other === this || other.owningKey == owningKey
    } 

    ...
}

class Party(...) : AbstractParty(...) {

    override fun equals(other: Any?): Boolean {
        return other === this 
            || other is Party
            && other.name == name
            && equalsByKey(other)
    }

    ...
}

class AnonymousParty(...) : AbstractParty(...) { ... }

Thoughts on this much appreciated.



Solution 1:[1]

I agree it is a bit of an inconsistency. I know you are a more experienced CorDapp developer than I am (because your previous questions have helped me learn Corda) but I will share my own experience.

When I first started working with Corda I thought (and coded) in terms of Party. However the more I introduced Confidential Identities into my CorDapps the more I began to think in terms of PublicKey (AnonymousParty).

So I actually find this “inconsistency” somewhat handy.

I wonder if the developers at R3 knew that CorDapps should generally always use AnonymousParty so wanted to make comparing AnonymousParty and Party as easy as possible. Just a guess.

Solution 2:[2]

Consider the case where you have name: CordaX500Name and key: PublicKey. Then define

val p1 = AnonymousParty(key)
val p2 = Party(name, key)

With your proposed implementation you would have p1 == p2 but not p2 == p1, so the relation is not symmetric and hence not a valid equivalence relation.

The well-known name is supposed to be unique for any given key, so I think that the current implementation is reasonable. Otherwise we would distinguish otherwise equal identities based on whether they were resolved to a name or not.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tywin Lannister
Solution 2 Ulrik Rasmussen