mirror of
https://github.com/corda/corda.git
synced 2025-02-20 17:33:15 +00:00
Use identity service to resolve anonymised identities in explorer
This commit is contained in:
parent
bc5aceddbf
commit
3b9c1ec0ff
@ -1,13 +1,14 @@
|
||||
package net.corda.client.jfx.model
|
||||
|
||||
import com.google.common.cache.CacheBuilder
|
||||
import com.google.common.cache.CacheLoader
|
||||
import javafx.beans.value.ObservableValue
|
||||
import javafx.collections.FXCollections
|
||||
import javafx.collections.ObservableList
|
||||
import net.corda.client.jfx.utils.firstOrDefault
|
||||
import net.corda.client.jfx.utils.firstOrNullObservable
|
||||
import net.corda.client.jfx.utils.fold
|
||||
import net.corda.client.jfx.utils.map
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.NetworkMapCache.MapChange
|
||||
import java.security.PublicKey
|
||||
@ -29,6 +30,12 @@ class NetworkIdentityModel {
|
||||
|
||||
private val rpcProxy by observableValue(NodeMonitorModel::proxyObservable)
|
||||
|
||||
private val identityCache = CacheBuilder.newBuilder()
|
||||
.build<PublicKey, ObservableValue<NodeInfo?>>(CacheLoader.from {
|
||||
publicKey ->
|
||||
publicKey?.let { rpcProxy.map { it?.nodeIdentityFromParty(AnonymousParty(publicKey)) } }
|
||||
})
|
||||
|
||||
val parties: ObservableList<NodeInfo> = networkIdentities.filtered { !it.isCordaService() }
|
||||
val notaries: ObservableList<NodeInfo> = networkIdentities.filtered { it.advertisedServices.any { it.info.type.isNotary() } }
|
||||
val myIdentity = rpcProxy.map { it?.nodeIdentity() }
|
||||
@ -38,8 +45,5 @@ class NetworkIdentityModel {
|
||||
return advertisedServices.any { it.info.type.isNetworkMap() || it.info.type.isNotary() }
|
||||
}
|
||||
|
||||
// TODO: Use Identity Service in service hub instead?
|
||||
fun lookup(publicKey: PublicKey): ObservableValue<NodeInfo?> = parties.firstOrDefault(notaries.firstOrNullObservable { it.notaryIdentity.owningKey.keys.any { it == publicKey } }) {
|
||||
it.legalIdentity.owningKey.keys.any { it == publicKey }
|
||||
}
|
||||
fun partyFromPublicKey(publicKey: PublicKey): ObservableValue<NodeInfo?> = identityCache[publicKey]
|
||||
}
|
||||
|
@ -14,10 +14,10 @@ import net.corda.client.jfx.model.Models
|
||||
import net.corda.client.jfx.model.NetworkIdentityModel
|
||||
import net.corda.client.jfx.utils.map
|
||||
import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.finance.contracts.asset.Cash
|
||||
import tornadofx.*
|
||||
import java.security.PublicKey
|
||||
|
||||
/**
|
||||
* Helper method to reduce boiler plate code
|
||||
@ -89,6 +89,6 @@ inline fun <reified M : Any> UIComponent.getModel(): M = Models.get(M::class, th
|
||||
fun <A, B> Collection<A>.cross(other: Collection<B>) = this.flatMap { a -> other.map { b -> a to b } }
|
||||
|
||||
// TODO: This is a temporary fix for the UI to show the correct issuer identity, this will break when we start randomizing keys. More work is needed here when the identity work is done.
|
||||
fun StateAndRef<Cash.State>.resolveIssuer(): ObservableValue<Party?> = state.data.amount.token.issuer.party.resolveIssuer()
|
||||
fun StateAndRef<Cash.State>.resolveIssuer(): ObservableValue<Party?> = state.data.amount.token.issuer.party.owningKey.toKnownParty()
|
||||
|
||||
fun AbstractParty.resolveIssuer(): ObservableValue<Party?> = Models.get(NetworkIdentityModel::class, javaClass.kotlin).lookup(owningKey).map { it?.legalIdentity }
|
||||
fun PublicKey.toKnownParty() = Models.get(NetworkIdentityModel::class, javaClass.kotlin).partyFromPublicKey(this).map { it?.legalIdentity }
|
||||
|
@ -79,7 +79,7 @@ class Network : CordaView() {
|
||||
.filterNotNull()
|
||||
.map { it.stateAndRef.state.data }.getParties()
|
||||
val outputParties = it.transaction.tx.outputStates.observable().getParties()
|
||||
val signingParties = it.transaction.sigs.map { getModel<NetworkIdentityModel>().lookup(it.by) }
|
||||
val signingParties = it.transaction.sigs.map { it.by.toKnownParty() }
|
||||
// Input parties fire a bullets to all output parties, and to the signing parties. !! This is a rough guess of how the message moves in the network.
|
||||
// TODO : Expose artemis queue to get real message information.
|
||||
inputParties.cross(outputParties) + inputParties.cross(signingParties)
|
||||
@ -170,10 +170,10 @@ class Network : CordaView() {
|
||||
zoomOutButton.setOnAction { zoom(0.8) }
|
||||
|
||||
lastTransactions.addListener { _, _, new ->
|
||||
new?.forEach {
|
||||
it.first.value?.let { a ->
|
||||
it.second.value?.let { b ->
|
||||
fireBulletBetweenNodes(a.legalIdentity, b.legalIdentity, "bank", "bank")
|
||||
new?.forEach { (partyA, partyB) ->
|
||||
partyA.value?.let { a ->
|
||||
partyB.value?.let { b ->
|
||||
fireBulletBetweenNodes(a, b, "bank", "bank")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -209,7 +209,7 @@ class Network : CordaView() {
|
||||
return Point2D(x, y)
|
||||
}
|
||||
|
||||
private fun List<ContractState>.getParties() = map { it.participants.map { getModel<NetworkIdentityModel>().lookup(it.owningKey) } }.flatten()
|
||||
private fun List<ContractState>.getParties() = map { it.participants.map { it.owningKey.toKnownParty() } }.flatten()
|
||||
|
||||
private fun fireBulletBetweenNodes(senderNode: Party, destNode: Party, startType: String, endType: String) {
|
||||
val senderNodeComp = allComponentMap[senderNode] ?: return
|
||||
|
@ -26,6 +26,7 @@ import net.corda.core.crypto.commonName
|
||||
import net.corda.core.crypto.toBase58String
|
||||
import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.explorer.AmountDiff
|
||||
import net.corda.explorer.formatters.AmountFormatter
|
||||
@ -70,8 +71,8 @@ class TransactionViewer : CordaView("Transactions") {
|
||||
val id: SecureHash,
|
||||
val inputs: Inputs,
|
||||
val outputs: ObservableList<StateAndRef<ContractState>>,
|
||||
val inputParties: ObservableList<List<ObservableValue<NodeInfo?>>>,
|
||||
val outputParties: ObservableList<List<ObservableValue<NodeInfo?>>>,
|
||||
val inputParties: ObservableList<List<ObservableValue<Party?>>>,
|
||||
val outputParties: ObservableList<List<ObservableValue<Party?>>>,
|
||||
val commandTypes: List<Class<CommandData>>,
|
||||
val totalValueEquiv: ObservableValue<AmountDiff<Currency>>
|
||||
)
|
||||
@ -135,8 +136,8 @@ class TransactionViewer : CordaView("Transactions") {
|
||||
"Transaction ID" to { tx, s -> "${tx.id}".contains(s, true) },
|
||||
"Input" to { tx, s -> tx.inputs.resolved.any { it.state.data.contract.javaClass.simpleName.contains(s, true) } },
|
||||
"Output" to { tx, s -> tx.outputs.any { it.state.data.contract.javaClass.simpleName.contains(s, true) } },
|
||||
"Input Party" to { tx, s -> tx.inputParties.any { it.any { it.value?.legalIdentity?.name?.commonName?.contains(s, true) ?: false } } },
|
||||
"Output Party" to { tx, s -> tx.outputParties.any { it.any { it.value?.legalIdentity?.name?.commonName?.contains(s, true) ?: false } } },
|
||||
"Input Party" to { tx, s -> tx.inputParties.any { it.any { it.value?.name?.commonName?.contains(s, true) ?: false } } },
|
||||
"Output Party" to { tx, s -> tx.outputParties.any { it.any { it.value?.name?.commonName?.contains(s, true) ?: false } } },
|
||||
"Command Type" to { tx, s -> tx.commandTypes.any { it.simpleName.contains(s, true) } }
|
||||
)
|
||||
root.top = searchField.root
|
||||
@ -199,13 +200,13 @@ class TransactionViewer : CordaView("Transactions") {
|
||||
})
|
||||
}
|
||||
|
||||
private fun ObservableList<List<ObservableValue<NodeInfo?>>>.formatJoinPartyNames(separator: String = "", formatter: Formatter<X500Name>): String {
|
||||
private fun ObservableList<List<ObservableValue<Party?>>>.formatJoinPartyNames(separator: String = ",", formatter: Formatter<X500Name>): String {
|
||||
return flatten().map {
|
||||
it.value?.legalIdentity?.let { formatter.format(it.name) }
|
||||
it.value?.let { formatter.format(it.name) }
|
||||
}.filterNotNull().toSet().joinToString(separator)
|
||||
}
|
||||
|
||||
private fun ObservableList<StateAndRef<ContractState>>.getParties() = map { it.state.data.participants.map { getModel<NetworkIdentityModel>().lookup(it.owningKey) } }
|
||||
private fun ObservableList<StateAndRef<ContractState>>.getParties() = map { it.state.data.participants.map { it.owningKey.toKnownParty() } }
|
||||
private fun ObservableList<StateAndRef<ContractState>>.toText() = map { it.contract().javaClass.simpleName }.groupBy { it }.map { "${it.key} (${it.value.size})" }.joinToString()
|
||||
|
||||
private class TransactionWidget : BorderPane() {
|
||||
@ -248,8 +249,8 @@ class TransactionViewer : CordaView("Transactions") {
|
||||
outputs.items = transaction.outputs.observable()
|
||||
|
||||
signatures.children.addAll(signatureData.map { signature ->
|
||||
val nodeInfo = getModel<NetworkIdentityModel>().lookup(signature)
|
||||
copyableLabel(nodeInfo.map { "${signature.toStringShort()} (${it?.legalIdentity?.let { PartyNameFormatter.short.format(it.name)} ?: "???"})" })
|
||||
val party = signature.toKnownParty()
|
||||
copyableLabel(party.map { "${signature.toStringShort()} (${it?.let { PartyNameFormatter.short.format(it.name) } ?: "Anonymous"})" })
|
||||
})
|
||||
}
|
||||
|
||||
@ -276,7 +277,7 @@ class TransactionViewer : CordaView("Transactions") {
|
||||
row {
|
||||
label("Issuer :") { gridpaneConstraints { hAlignment = HPos.RIGHT } }
|
||||
val anonymousIssuer: AbstractParty = data.amount.token.issuer.party
|
||||
val issuer: AbstractParty = anonymousIssuer.resolveIssuer().value ?: anonymousIssuer
|
||||
val issuer: AbstractParty = anonymousIssuer.owningKey.toKnownParty().value ?: anonymousIssuer
|
||||
// TODO: Anonymous should probably be italicised or similar
|
||||
label(issuer.nameOrNull()?.let { PartyNameFormatter.short.format(it) } ?: "Anonymous") {
|
||||
tooltip(anonymousIssuer.owningKey.toBase58String())
|
||||
@ -284,9 +285,8 @@ class TransactionViewer : CordaView("Transactions") {
|
||||
}
|
||||
row {
|
||||
label("Owner :") { gridpaneConstraints { hAlignment = HPos.RIGHT } }
|
||||
val owner = data.owner
|
||||
val nodeInfo = getModel<NetworkIdentityModel>().lookup(owner.owningKey)
|
||||
label(nodeInfo.map { it?.legalIdentity?.let { PartyNameFormatter.short.format(it.name) } ?: "???" }) {
|
||||
val owner = data.owner.owningKey.toKnownParty()
|
||||
label(owner.map { it?.let { PartyNameFormatter.short.format(it.name) } ?: "Anonymous" }) {
|
||||
tooltip(data.owner.owningKey.toBase58String())
|
||||
}
|
||||
}
|
||||
@ -300,27 +300,28 @@ class TransactionViewer : CordaView("Transactions") {
|
||||
}
|
||||
|
||||
private fun StateAndRef<ContractState>.contract() = this.state.data.contract
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* We calculate the total value by subtracting relevant input states and adding relevant output states, as long as they're cash
|
||||
*/
|
||||
private fun calculateTotalEquiv(identity: NodeInfo?,
|
||||
private fun calculateTotalEquiv(myIdentity: NodeInfo?,
|
||||
reportingCurrencyExchange: Pair<Currency, (Amount<Currency>) -> Amount<Currency>>,
|
||||
inputs: List<ContractState>,
|
||||
outputs: List<ContractState>): AmountDiff<Currency> {
|
||||
val (reportingCurrency, exchange) = reportingCurrencyExchange
|
||||
val legalIdentity = identity?.legalIdentity
|
||||
val myLegalIdentity = myIdentity?.legalIdentity
|
||||
fun List<ContractState>.sum() = this.map { it as? Cash.State }
|
||||
.filterNotNull()
|
||||
.filter { legalIdentity == it.owner }
|
||||
.filter { it.owner.owningKey.toKnownParty().value == myLegalIdentity }
|
||||
.map { exchange(it.amount.withoutIssuer()).quantity }
|
||||
.sum()
|
||||
|
||||
// For issuing cash, if I am the issuer and not the owner (e.g. issuing cash to other party), count it as negative.
|
||||
val issuedAmount = if (inputs.isEmpty()) outputs.map { it as? Cash.State }
|
||||
.filterNotNull()
|
||||
.filter { legalIdentity == it.amount.token.issuer.party && legalIdentity != it.owner }
|
||||
.filter { it.amount.token.issuer.party.owningKey.toKnownParty().value == myLegalIdentity && it.owner.owningKey.toKnownParty().value != myLegalIdentity }
|
||||
.map { exchange(it.amount.withoutIssuer()).quantity }
|
||||
.sum() else 0
|
||||
|
||||
|
@ -205,7 +205,7 @@ class CashViewer : CordaView("Cash") {
|
||||
/**
|
||||
* Assemble the Issuer node.
|
||||
*/
|
||||
val treeItem = TreeItem(ViewerNode.IssuerNode(issuer.resolveIssuer().value ?: issuer, equivSumAmount, memberStates))
|
||||
val treeItem = TreeItem(ViewerNode.IssuerNode(issuer.owningKey.toKnownParty().value ?: issuer, equivSumAmount, memberStates))
|
||||
|
||||
/**
|
||||
* Bind the children in the TreeTable structure.
|
||||
|
Loading…
x
Reference in New Issue
Block a user