mirror of
https://github.com/corda/corda.git
synced 2025-01-30 16:14:39 +00:00
ENT-1586 Update entire service stack to support private network maps (#691)
* private network map
This commit is contained in:
parent
05ec885afd
commit
7f8c36faa0
@ -164,10 +164,10 @@ class HsmSigningServiceTest : HsmBaseTest() {
|
|||||||
// when
|
// when
|
||||||
initialiseSerialization()
|
initialiseSerialization()
|
||||||
networkMapStorage.saveNetworkParameters(networkMapParameters, hsmDataSigner.signBytes(networkMapParameters.serialize().bytes))
|
networkMapStorage.saveNetworkParameters(networkMapParameters, hsmDataSigner.signBytes(networkMapParameters.serialize().bytes))
|
||||||
networkMapSigner.signNetworkMap()
|
networkMapSigner.signNetworkMaps()
|
||||||
|
|
||||||
// then
|
// then
|
||||||
val persistedNetworkMap = networkMapStorage.getActiveNetworkMap()!!.toSignedNetworkMap().verified()
|
val persistedNetworkMap = networkMapStorage.getNetworkMaps().publicNetworkMap!!.toSignedNetworkMap().verified()
|
||||||
assertEquals(networkMapParameters.serialize().hash, persistedNetworkMap.networkParameterHash)
|
assertEquals(networkMapParameters.serialize().hash, persistedNetworkMap.networkParameterHash)
|
||||||
assertThat(persistedNetworkMap.nodeInfoHashes).isEmpty()
|
assertThat(persistedNetworkMap.nodeInfoHashes).isEmpty()
|
||||||
}
|
}
|
||||||
|
@ -22,24 +22,25 @@ import java.time.Instant
|
|||||||
* Data access object interface for NetworkMap persistence layer
|
* Data access object interface for NetworkMap persistence layer
|
||||||
*/
|
*/
|
||||||
// TODO This storage abstraction needs some thought. Some of the methods clearly don't make sense e.g. setParametersUpdateStatus.
|
// TODO This storage abstraction needs some thought. Some of the methods clearly don't make sense e.g. setParametersUpdateStatus.
|
||||||
|
// TODO: We should avoid exposing entity objects.
|
||||||
// The NetworkMapSignerTest uses a mock of this which means we need to provide methods for every trivial db operation.
|
// The NetworkMapSignerTest uses a mock of this which means we need to provide methods for every trivial db operation.
|
||||||
interface NetworkMapStorage {
|
interface NetworkMapStorage {
|
||||||
/**
|
/**
|
||||||
* Returns the active network map, or null
|
* Returns the network maps containing public network map and private network maps.
|
||||||
*/
|
*/
|
||||||
fun getActiveNetworkMap(): NetworkMapEntity?
|
fun getNetworkMaps(): NetworkMaps
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Persist the new active network map, replacing any existing network map.
|
* Persist the new network map for provided network ID, replacing any existing network map.
|
||||||
|
* The map will be stored as public network map if [networkId] = null.
|
||||||
*/
|
*/
|
||||||
fun saveNewActiveNetworkMap(networkMapAndSigned: NetworkMapAndSigned)
|
fun saveNewNetworkMap(networkId: String? = null, networkMapAndSigned: NetworkMapAndSigned)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves node info hashes where [NodeInfoEntity.isCurrent] is true and the certificate status is [CertificateStatus.VALID]
|
* Retrieves node info hashes for both public and private networks where [NodeInfoEntity.isCurrent] is true and the certificate status is [CertificateStatus.VALID]
|
||||||
* Nodes should have declared that they are using correct set of parameters.
|
* Nodes should have declared that they are using correct set of parameters.
|
||||||
*/
|
*/
|
||||||
// TODO "Active" is the wrong word here
|
fun getNodeInfoHashes(): NodeInfoHashes
|
||||||
fun getActiveNodeInfoHashes(): List<SecureHash>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the signed with certificate network parameters by their hash. The hash is that of the underlying
|
* Retrieve the signed with certificate network parameters by their hash. The hash is that of the underlying
|
||||||
@ -79,3 +80,9 @@ interface NetworkMapStorage {
|
|||||||
*/
|
*/
|
||||||
fun switchFlagDay(update: ParametersUpdateEntity)
|
fun switchFlagDay(update: ParametersUpdateEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class NetworkMaps(val publicNetworkMap: NetworkMapEntity?, val privateNetworkMap: Map<String, NetworkMapEntity>) {
|
||||||
|
val allNodeInfoHashes: Set<SecureHash> = privateNetworkMap.flatMap { it.value.networkMap.nodeInfoHashes }.toSet() + (publicNetworkMap?.networkMap?.nodeInfoHashes ?: emptySet())
|
||||||
|
}
|
||||||
|
|
||||||
|
data class NodeInfoHashes(val publicNodeInfoHashes: List<SecureHash>, val privateNodeInfoHashes: Map<String, List<SecureHash>>)
|
@ -26,20 +26,21 @@ import java.time.Instant
|
|||||||
* Database implementation of the [NetworkMapStorage] interface
|
* Database implementation of the [NetworkMapStorage] interface
|
||||||
*/
|
*/
|
||||||
class PersistentNetworkMapStorage(private val database: CordaPersistence) : NetworkMapStorage {
|
class PersistentNetworkMapStorage(private val database: CordaPersistence) : NetworkMapStorage {
|
||||||
override fun getActiveNetworkMap(): NetworkMapEntity? {
|
companion object {
|
||||||
|
// Used internally to identify global network map in database table.
|
||||||
|
private const val PUBLIC_NETWORK_ID = "PUBLIC_NETWORK"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNetworkMaps(): NetworkMaps {
|
||||||
return database.transaction {
|
return database.transaction {
|
||||||
val builder = session.criteriaBuilder
|
val networkMapEntities = session.createQuery("from ${NetworkMapEntity::class.java.name}", NetworkMapEntity::class.java)
|
||||||
val query = builder.createQuery(NetworkMapEntity::class.java).run {
|
.resultList
|
||||||
from(NetworkMapEntity::class.java).run {
|
.associateBy { it.id }
|
||||||
orderBy(builder.desc(get<Long>(NetworkMapEntity::version.name)))
|
NetworkMaps(networkMapEntities[PUBLIC_NETWORK_ID], networkMapEntities.filterKeys { it != PUBLIC_NETWORK_ID })
|
||||||
}
|
|
||||||
}
|
|
||||||
// We want the latest signed entry
|
|
||||||
session.createQuery(query).setMaxResults(1).uniqueResult()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveNewActiveNetworkMap(networkMapAndSigned: NetworkMapAndSigned) {
|
override fun saveNewNetworkMap(networkId: String?, networkMapAndSigned: NetworkMapAndSigned) {
|
||||||
val (networkMap, signedNetworkMap) = networkMapAndSigned
|
val (networkMap, signedNetworkMap) = networkMapAndSigned
|
||||||
database.transaction {
|
database.transaction {
|
||||||
val networkParametersEntity = checkNotNull(getNetworkParametersEntity(networkMap.networkParameterHash)) {
|
val networkParametersEntity = checkNotNull(getNetworkParametersEntity(networkMap.networkParameterHash)) {
|
||||||
@ -48,7 +49,8 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
check(networkParametersEntity.isSigned) {
|
check(networkParametersEntity.isSigned) {
|
||||||
"Network parameters ${networkMap.networkParameterHash} are not signed"
|
"Network parameters ${networkMap.networkParameterHash} are not signed"
|
||||||
}
|
}
|
||||||
session.save(NetworkMapEntity(
|
session.merge(NetworkMapEntity(
|
||||||
|
id = networkId ?: PUBLIC_NETWORK_ID,
|
||||||
networkMap = networkMap,
|
networkMap = networkMap,
|
||||||
signature = signedNetworkMap.sig.bytes,
|
signature = signedNetworkMap.sig.bytes,
|
||||||
certificate = signedNetworkMap.sig.by,
|
certificate = signedNetworkMap.sig.by,
|
||||||
@ -65,10 +67,10 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getActiveNodeInfoHashes(): List<SecureHash> {
|
override fun getNodeInfoHashes(): NodeInfoHashes {
|
||||||
return database.transaction {
|
return database.transaction {
|
||||||
val builder = session.criteriaBuilder
|
val builder = session.criteriaBuilder
|
||||||
val query = builder.createQuery(String::class.java).run {
|
val query = builder.createTupleQuery().run {
|
||||||
from(NodeInfoEntity::class.java).run {
|
from(NodeInfoEntity::class.java).run {
|
||||||
val certStatusExpression = get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name)
|
val certStatusExpression = get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name)
|
||||||
.get<CertificateDataEntity>(CertificateSigningRequestEntity::certificateData.name)
|
.get<CertificateDataEntity>(CertificateSigningRequestEntity::certificateData.name)
|
||||||
@ -77,10 +79,16 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
// isn't needed.
|
// isn't needed.
|
||||||
val certStatusEq = builder.equal(certStatusExpression, CertificateStatus.VALID)
|
val certStatusEq = builder.equal(certStatusExpression, CertificateStatus.VALID)
|
||||||
val isCurrentNodeInfo = builder.isTrue(get<Boolean>(NodeInfoEntity::isCurrent.name))
|
val isCurrentNodeInfo = builder.isTrue(get<Boolean>(NodeInfoEntity::isCurrent.name))
|
||||||
select(get<String>(NodeInfoEntity::nodeInfoHash.name)).where(builder.and(certStatusEq, isCurrentNodeInfo))
|
|
||||||
|
val networkIdSelector = get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name)
|
||||||
|
.get<PrivateNetworkEntity>(CertificateSigningRequestEntity::privateNetwork.name)
|
||||||
|
.get<String>(PrivateNetworkEntity::networkId.name)
|
||||||
|
|
||||||
|
multiselect(networkIdSelector, get<String>(NodeInfoEntity::nodeInfoHash.name)).where(builder.and(certStatusEq, isCurrentNodeInfo))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
session.createQuery(query).resultList.map { SecureHash.parse(it) }
|
val allNodeInfos = session.createQuery(query).resultList.groupBy { it[0]?.toString() ?: PUBLIC_NETWORK_ID }.mapValues { it.value.map { SecureHash.parse(it.get(1, String::class.java)) } }
|
||||||
|
NodeInfoHashes(allNodeInfos[PUBLIC_NETWORK_ID] ?: emptyList(), allNodeInfos.filterKeys { it != PUBLIC_NETWORK_ID })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,19 +98,15 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
val hash = serialized.hash
|
val hash = serialized.hash
|
||||||
return database.transaction {
|
return database.transaction {
|
||||||
val entity = getNetworkParametersEntity(hash)
|
val entity = getNetworkParametersEntity(hash)
|
||||||
val newNetworkParamsEntity = if (entity != null) {
|
val newNetworkParamsEntity = entity?.copy(
|
||||||
entity.copy(
|
|
||||||
signature = signature?.bytes,
|
signature = signature?.bytes,
|
||||||
certificate = signature?.by
|
certificate = signature?.by
|
||||||
)
|
) ?: NetworkParametersEntity(
|
||||||
} else {
|
|
||||||
NetworkParametersEntity(
|
|
||||||
networkParameters = networkParameters,
|
networkParameters = networkParameters,
|
||||||
hash = hash.toString(),
|
hash = hash.toString(),
|
||||||
signature = signature?.bytes,
|
signature = signature?.bytes,
|
||||||
certificate = signature?.by
|
certificate = signature?.by
|
||||||
)
|
)
|
||||||
}
|
|
||||||
session.merge(newNetworkParamsEntity) as NetworkParametersEntity
|
session.merge(newNetworkParamsEntity) as NetworkParametersEntity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,16 +14,20 @@ import net.corda.core.internal.DigitalSignatureWithCert
|
|||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.nodeapi.internal.network.NetworkMap
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||||
|
import org.hibernate.envers.Audited
|
||||||
|
import org.hibernate.envers.RelationTargetAuditMode
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
|
import java.time.Instant
|
||||||
import javax.persistence.*
|
import javax.persistence.*
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
|
@Audited
|
||||||
@Table(name = "network_map")
|
@Table(name = "network_map")
|
||||||
class NetworkMapEntity(
|
class NetworkMapEntity(
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
@Column(name = "id")
|
||||||
val version: Long? = null,
|
val id: String,
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "serialized_network_map", nullable = false)
|
@Column(name = "serialized_network_map", nullable = false)
|
||||||
@ -41,7 +45,11 @@ class NetworkMapEntity(
|
|||||||
|
|
||||||
@ManyToOne(optional = false, fetch = FetchType.EAGER)
|
@ManyToOne(optional = false, fetch = FetchType.EAGER)
|
||||||
@JoinColumn(name = "network_parameters", nullable = false)
|
@JoinColumn(name = "network_parameters", nullable = false)
|
||||||
val networkParameters: NetworkParametersEntity
|
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
|
||||||
|
val networkParameters: NetworkParametersEntity,
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
val timestamp: Instant = Instant.now()
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
fun toSignedNetworkMap(): SignedNetworkMap {
|
fun toSignedNetworkMap(): SignedNetworkMap {
|
||||||
return SignedNetworkMap(networkMap.serialize(), DigitalSignatureWithCert(certificate, signature))
|
return SignedNetworkMap(networkMap.serialize(), DigitalSignatureWithCert(certificate, signature))
|
||||||
|
@ -11,13 +11,17 @@
|
|||||||
package com.r3.corda.networkmanage.common.signer
|
package com.r3.corda.networkmanage.common.signer
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.UpdateStatus.*
|
import com.r3.corda.networkmanage.common.persistence.entity.NetworkMapEntity
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.entity.UpdateStatus.FLAG_DAY
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.entity.UpdateStatus.NEW
|
||||||
|
import com.r3.corda.networkmanage.common.utils.join
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.core.utilities.debug
|
import net.corda.core.utilities.debug
|
||||||
import net.corda.nodeapi.internal.network.NetworkMap
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
import net.corda.nodeapi.internal.network.NetworkMapAndSigned
|
import net.corda.nodeapi.internal.network.NetworkMapAndSigned
|
||||||
|
import net.corda.nodeapi.internal.network.ParametersUpdate
|
||||||
|
|
||||||
class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private val signer: Signer) {
|
class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private val signer: Signer) {
|
||||||
private companion object {
|
private companion object {
|
||||||
@ -27,12 +31,46 @@ class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private
|
|||||||
/**
|
/**
|
||||||
* Signs the network map and latest network parameters if they haven't been signed yet.
|
* Signs the network map and latest network parameters if they haven't been signed yet.
|
||||||
*/
|
*/
|
||||||
fun signNetworkMap() {
|
fun signNetworkMaps() {
|
||||||
val latestNetworkParameters = networkMapStorage.getLatestNetworkParameters()
|
val (publicNetworkMap, privateNetworkMaps) = networkMapStorage.getNetworkMaps()
|
||||||
if (latestNetworkParameters == null) {
|
val (publicNodeInfoHashes, privateNodeInfoHashes) = networkMapStorage.getNodeInfoHashes()
|
||||||
logger.debug("No network parameters present")
|
|
||||||
return
|
val (networkParameterHash, parametersUpdate) = maybeUpdateNetworkParameters(publicNetworkMap?.networkMap?.networkParameterHash)
|
||||||
|
logger.debug { "Current network parameters: $networkParameterHash" }
|
||||||
|
|
||||||
|
// Process public network map.
|
||||||
|
maybeSignNetworkMap(publicNetworkMap, publicNodeInfoHashes, parametersUpdate, networkParameterHash)
|
||||||
|
|
||||||
|
// Process each private network map.
|
||||||
|
privateNetworkMaps.join(privateNodeInfoHashes).forEach { networkId, (currentNetworkMap, nodeInfoHashes) ->
|
||||||
|
maybeSignNetworkMap(currentNetworkMap, nodeInfoHashes, parametersUpdate, networkParameterHash, networkId)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maybeSignNetworkMap(currentNetworkMap: NetworkMapEntity?, nodeInfoHashes: List<SecureHash>?, parametersUpdate: ParametersUpdate?, networkParameterHash: SecureHash, networkId: String? = null) {
|
||||||
|
val printableNetworkId = networkId ?: "Public Network"
|
||||||
|
if (currentNetworkMap == null) {
|
||||||
|
logger.info("There is currently no network map for network '$printableNetworkId'")
|
||||||
|
} else {
|
||||||
|
logger.debug { "Current network map for network '$printableNetworkId': ${currentNetworkMap.networkMap}" }
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug { "Retrieved node info hashes for network '$printableNetworkId' :\n${nodeInfoHashes?.joinToString("\n")}" }
|
||||||
|
|
||||||
|
val newNetworkMap = NetworkMap(nodeInfoHashes ?: emptyList(), networkParameterHash, parametersUpdate)
|
||||||
|
logger.debug { "Potential new network map for network '$printableNetworkId': $newNetworkMap" }
|
||||||
|
|
||||||
|
if (currentNetworkMap?.networkMap != newNetworkMap) {
|
||||||
|
val newNetworkMapAndSigned = NetworkMapAndSigned(newNetworkMap) { signer.signBytes(it.bytes) }
|
||||||
|
networkMapStorage.saveNewNetworkMap(networkId, newNetworkMapAndSigned)
|
||||||
|
logger.info("Signed new network map for network '$printableNetworkId' : $newNetworkMap")
|
||||||
|
} else {
|
||||||
|
logger.debug("Current network map for network '$printableNetworkId' is up-to-date")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maybeUpdateNetworkParameters(currentNetworkParametersHash: SecureHash?): Pair<SecureHash, ParametersUpdate?> {
|
||||||
|
val latestNetworkParameters = requireNotNull(networkMapStorage.getLatestNetworkParameters()) { "No network parameters present" }
|
||||||
logger.debug { "Retrieved latest network parameters: ${latestNetworkParameters.networkParameters}" }
|
logger.debug { "Retrieved latest network parameters: ${latestNetworkParameters.networkParameters}" }
|
||||||
|
|
||||||
val parametersUpdate = networkMapStorage.getCurrentParametersUpdate()
|
val parametersUpdate = networkMapStorage.getCurrentParametersUpdate()
|
||||||
@ -41,16 +79,6 @@ class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private
|
|||||||
"The latest network parameters are not the scheduled updated ones"
|
"The latest network parameters are not the scheduled updated ones"
|
||||||
}
|
}
|
||||||
|
|
||||||
val activeNetworkMap = networkMapStorage.getActiveNetworkMap()
|
|
||||||
if (activeNetworkMap == null) {
|
|
||||||
logger.info("There is currently no network map")
|
|
||||||
} else {
|
|
||||||
logger.debug { "Current network map: ${activeNetworkMap.networkMap}" }
|
|
||||||
}
|
|
||||||
|
|
||||||
val activeNetworkParameters = activeNetworkMap?.networkParameters
|
|
||||||
logger.debug { "Current network map parameters: ${activeNetworkParameters?.networkParameters}" }
|
|
||||||
|
|
||||||
// We persist signed parameters only if they were not persisted before (they are not in currentSignedNetworkMap as
|
// We persist signed parameters only if they were not persisted before (they are not in currentSignedNetworkMap as
|
||||||
// normal parameters or as an update)
|
// normal parameters or as an update)
|
||||||
if (!latestNetworkParameters.isSigned) {
|
if (!latestNetworkParameters.isSigned) {
|
||||||
@ -59,29 +87,14 @@ class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private
|
|||||||
logger.debug { "No need to sign any network parameters as they're up-to-date" }
|
logger.debug { "No need to sign any network parameters as they're up-to-date" }
|
||||||
}
|
}
|
||||||
|
|
||||||
val parametersToNetworkMap = if (parametersUpdate?.status == FLAG_DAY || activeNetworkParameters == null) {
|
val parametersToNetworkMap = if (parametersUpdate?.status == FLAG_DAY || currentNetworkParametersHash == null) {
|
||||||
parametersUpdate?.let { networkMapStorage.switchFlagDay(it) }
|
parametersUpdate?.let { networkMapStorage.switchFlagDay(it) }
|
||||||
latestNetworkParameters
|
SecureHash.parse(latestNetworkParameters.hash)
|
||||||
} else {
|
} else {
|
||||||
activeNetworkParameters
|
currentNetworkParametersHash
|
||||||
}
|
}
|
||||||
|
|
||||||
val nodeInfoHashes = networkMapStorage.getActiveNodeInfoHashes()
|
return Pair(parametersToNetworkMap, parametersUpdate?.let { if (it.status == NEW) it.toParametersUpdate() else null })
|
||||||
logger.debug { "Retrieved node info hashes:\n${nodeInfoHashes.joinToString("\n")}" }
|
|
||||||
|
|
||||||
val newNetworkMap = NetworkMap(
|
|
||||||
nodeInfoHashes,
|
|
||||||
SecureHash.parse(parametersToNetworkMap.hash),
|
|
||||||
parametersUpdate?.let { if (it.status == NEW) it.toParametersUpdate() else null })
|
|
||||||
logger.debug { "Potential new network map: $newNetworkMap" }
|
|
||||||
|
|
||||||
if (activeNetworkMap?.networkMap != newNetworkMap) {
|
|
||||||
val newNetworkMapAndSigned = NetworkMapAndSigned(newNetworkMap) { signer.signBytes(it.bytes) }
|
|
||||||
networkMapStorage.saveNewActiveNetworkMap(newNetworkMapAndSigned)
|
|
||||||
logger.info("Signed new network map: $newNetworkMap")
|
|
||||||
} else {
|
|
||||||
logger.debug("Current network map is up-to-date")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun signAndPersistNetworkParameters(networkParameters: NetworkParameters) {
|
fun signAndPersistNetworkParameters(networkParameters: NetworkParameters) {
|
||||||
|
@ -86,3 +86,5 @@ fun PKCS10CertificationRequest.getCertRole(): CertRole {
|
|||||||
* Helper method to extract email from certificate signing request.
|
* Helper method to extract email from certificate signing request.
|
||||||
*/
|
*/
|
||||||
fun PKCS10CertificationRequest.getEmail(): String = firstAttributeValue(BCStyle.E).toString()
|
fun PKCS10CertificationRequest.getEmail(): String = firstAttributeValue(BCStyle.E).toString()
|
||||||
|
|
||||||
|
fun <K, V, U> Map<K, V>.join(otherMap: Map<K, U>): Map<K, Pair<V?, U?>> = (keys + otherMap.keys).map { it to Pair(get(it), otherMap[it]) }.toMap()
|
||||||
|
@ -84,7 +84,7 @@ class NetworkManagementServer(dataSourceProperties: Properties,
|
|||||||
val scheduledExecutor = Executors.newScheduledThreadPool(1)
|
val scheduledExecutor = Executors.newScheduledThreadPool(1)
|
||||||
scheduledExecutor.scheduleAtFixedRate({
|
scheduledExecutor.scheduleAtFixedRate({
|
||||||
try {
|
try {
|
||||||
localNetworkMapSigner.signNetworkMap()
|
localNetworkMapSigner.signNetworkMaps()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// Log the error and carry on.
|
// Log the error and carry on.
|
||||||
logger.error("Unable to sign network map", e)
|
logger.error("Unable to sign network map", e)
|
||||||
@ -201,7 +201,7 @@ class NetworkManagementServer(dataSourceProperties: Properties,
|
|||||||
|
|
||||||
private fun handleSetNetworkParameters(setNetParams: NetworkParametersCmd.Set) {
|
private fun handleSetNetworkParameters(setNetParams: NetworkParametersCmd.Set) {
|
||||||
logger.info("maxMessageSize is not currently wired in the nodes")
|
logger.info("maxMessageSize is not currently wired in the nodes")
|
||||||
val activeNetParams = networkMapStorage.getActiveNetworkMap()?.networkParameters?.networkParameters
|
val activeNetParams = networkMapStorage.getNetworkMaps().publicNetworkMap?.networkParameters?.networkParameters
|
||||||
if (activeNetParams == null) {
|
if (activeNetParams == null) {
|
||||||
require(setNetParams.parametersUpdate == null) {
|
require(setNetParams.parametersUpdate == null) {
|
||||||
"'parametersUpdate' specified in network parameters file but there are no network parameters to update"
|
"'parametersUpdate' specified in network parameters file but there are no network parameters to update"
|
||||||
@ -253,7 +253,7 @@ class NetworkManagementServer(dataSourceProperties: Properties,
|
|||||||
check(parametersUpdate.networkParameters.hash == networkMapStorage.getLatestNetworkParameters()?.hash) {
|
check(parametersUpdate.networkParameters.hash == networkMapStorage.getLatestNetworkParameters()?.hash) {
|
||||||
"The latest network parameters is not the scheduled one:\n${latestNetParamsEntity?.networkParameters}\n${parametersUpdate.toParametersUpdate()}"
|
"The latest network parameters is not the scheduled one:\n${latestNetParamsEntity?.networkParameters}\n${parametersUpdate.toParametersUpdate()}"
|
||||||
}
|
}
|
||||||
val activeNetParams = networkMapStorage.getActiveNetworkMap()?.networkParameters
|
val activeNetParams = networkMapStorage.getNetworkMaps().publicNetworkMap?.networkParameters
|
||||||
check(parametersUpdate.networkParameters.isSigned) {
|
check(parametersUpdate.networkParameters.isSigned) {
|
||||||
"Parameters we are trying to switch to haven't been signed yet"
|
"Parameters we are trying to switch to haven't been signed yet"
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,14 @@ import com.github.benmanes.caffeine.cache.Caffeine
|
|||||||
import com.github.benmanes.caffeine.cache.LoadingCache
|
import com.github.benmanes.caffeine.cache.LoadingCache
|
||||||
import com.r3.corda.networkmanage.common.persistence.CertificateSigningRequestStorage
|
import com.r3.corda.networkmanage.common.persistence.CertificateSigningRequestStorage
|
||||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.NetworkMaps
|
||||||
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.entity.NetworkMapEntity
|
||||||
import com.r3.corda.networkmanage.doorman.NetworkMapConfig
|
import com.r3.corda.networkmanage.doorman.NetworkMapConfig
|
||||||
import com.r3.corda.networkmanage.doorman.webservice.NetworkMapWebService.Companion.NETWORK_MAP_PATH
|
import com.r3.corda.networkmanage.doorman.webservice.NetworkMapWebService.Companion.NETWORK_MAP_PATH
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.CompositeKey
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.SignedData
|
import net.corda.core.crypto.SignedData
|
||||||
import net.corda.core.crypto.sha256
|
|
||||||
import net.corda.core.internal.CertRole
|
import net.corda.core.internal.CertRole
|
||||||
import net.corda.core.internal.readObject
|
import net.corda.core.internal.readObject
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
@ -34,12 +35,14 @@ import net.corda.nodeapi.internal.SignedNodeInfo
|
|||||||
import net.corda.nodeapi.internal.crypto.X509Utilities.validateCertPath
|
import net.corda.nodeapi.internal.crypto.X509Utilities.validateCertPath
|
||||||
import net.corda.nodeapi.internal.crypto.x509
|
import net.corda.nodeapi.internal.crypto.x509
|
||||||
import net.corda.nodeapi.internal.crypto.x509Certificates
|
import net.corda.nodeapi.internal.crypto.x509Certificates
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.InvalidKeyException
|
import java.security.InvalidKeyException
|
||||||
import java.security.SignatureException
|
import java.security.SignatureException
|
||||||
import java.security.cert.CertPathValidatorException
|
import java.security.cert.CertPathValidatorException
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.servlet.http.HttpServletRequest
|
import javax.servlet.http.HttpServletRequest
|
||||||
import javax.ws.rs.*
|
import javax.ws.rs.*
|
||||||
@ -60,15 +63,11 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
const val NETWORK_MAP_PATH = "network-map"
|
const val NETWORK_MAP_PATH = "network-map"
|
||||||
}
|
}
|
||||||
|
|
||||||
private val networkMapCache: LoadingCache<Boolean, CachedData> = Caffeine.newBuilder()
|
private val networkMapCache: LoadingCache<Boolean, NetworkMaps> = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(config.cacheTimeout, TimeUnit.MILLISECONDS)
|
.expireAfterWrite(config.cacheTimeout, TimeUnit.MILLISECONDS)
|
||||||
.build {
|
.build {
|
||||||
networkMapStorage.getActiveNetworkMap()?.let {
|
|
||||||
logger.info("Re-publishing network map")
|
logger.info("Re-publishing network map")
|
||||||
val networkMap = it.networkMap
|
networkMapStorage.getNetworkMaps()
|
||||||
val signedNetworkMap = it.toSignedNetworkMap()
|
|
||||||
CachedData(signedNetworkMap, networkMap.nodeInfoHashes.toSet(), it.networkParameters.networkParameters)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val nodeInfoCache: LoadingCache<SecureHash, SignedNodeInfo> = Caffeine.newBuilder()
|
private val nodeInfoCache: LoadingCache<SecureHash, SignedNodeInfo> = Caffeine.newBuilder()
|
||||||
@ -76,9 +75,9 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
.softValues()
|
.softValues()
|
||||||
.build(nodeInfoStorage::getNodeInfo)
|
.build(nodeInfoStorage::getNodeInfo)
|
||||||
|
|
||||||
private val currentSignedNetworkMap: SignedNetworkMap? get() = networkMapCache.get(true)?.signedNetworkMap
|
private val networkMaps: NetworkMaps? get() = networkMapCache[true]
|
||||||
private val currentNodeInfoHashes: Set<SecureHash> get() = networkMapCache.get(true)?.nodeInfoHashes ?: emptySet()
|
private val currentNodeInfoHashes: Set<SecureHash> get() = networkMaps?.allNodeInfoHashes ?: emptySet()
|
||||||
private val currentNetworkParameters: NetworkParameters? get() = networkMapCache.get(true)?.networkParameters
|
private val currentNetworkParameters: NetworkParameters? get() = networkMaps?.publicNetworkMap?.networkParameters?.networkParameters
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path("publish")
|
@Path("publish")
|
||||||
@ -124,7 +123,14 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
fun getNetworkMap(): Response = createResponse(currentSignedNetworkMap, addCacheTimeout = true)
|
fun getNetworkMap(): Response = createNetworkMapResponse(networkMaps?.publicNetworkMap)
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("{id}")
|
||||||
|
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
fun getNetworkMap(@PathParam("id") privateNetworkID: String?): Response = createNetworkMapResponse(networkMaps?.privateNetworkMap?.get(privateNetworkID))
|
||||||
|
|
||||||
|
private fun createNetworkMapResponse(networkMap: NetworkMapEntity?) = createResponse(networkMap?.toSignedNetworkMap(), addCacheTimeout = true, timestamp = networkMap?.timestamp)
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("node-info/{nodeInfoHash}")
|
@Path("node-info/{nodeInfoHash}")
|
||||||
@ -182,12 +188,15 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createResponse(payload: Any?, addCacheTimeout: Boolean = false): Response {
|
private fun createResponse(payload: Any?, addCacheTimeout: Boolean = false, timestamp: Instant? = null): Response {
|
||||||
return if (payload != null) {
|
return if (payload != null) {
|
||||||
val ok = Response.ok(payload.serialize().bytes)
|
val ok = Response.ok(payload.serialize().bytes)
|
||||||
if (addCacheTimeout) {
|
if (addCacheTimeout) {
|
||||||
ok.header("Cache-Control", "max-age=${Duration.ofMillis(config.cacheTimeout).seconds}")
|
ok.header("Cache-Control", "max-age=${Duration.ofMillis(config.cacheTimeout).seconds}")
|
||||||
}
|
}
|
||||||
|
timestamp?.let {
|
||||||
|
ok.header("Last-Modified", DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneId.of("GMT")).format(it))
|
||||||
|
}
|
||||||
ok
|
ok
|
||||||
} else {
|
} else {
|
||||||
status(Response.Status.NOT_FOUND)
|
status(Response.Status.NOT_FOUND)
|
||||||
@ -211,8 +220,4 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
|
|
||||||
class NetworkMapNotInitialisedException(message: String?) : Exception(message)
|
class NetworkMapNotInitialisedException(message: String?) : Exception(message)
|
||||||
class RequestException(message: String) : Exception(message)
|
class RequestException(message: String) : Exception(message)
|
||||||
|
|
||||||
private data class CachedData(val signedNetworkMap: SignedNetworkMap,
|
|
||||||
val nodeInfoHashes: Set<SecureHash>,
|
|
||||||
val networkParameters: NetworkParameters)
|
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ class NetworkMapProcessor(private val config: NetworkMapCertificateConfig,
|
|||||||
val networkMapSigner = NetworkMapSigner(networkMapStorage, signer)
|
val networkMapSigner = NetworkMapSigner(networkMapStorage, signer)
|
||||||
try {
|
try {
|
||||||
logger.info("Executing network map signing...")
|
logger.info("Executing network map signing...")
|
||||||
networkMapSigner.signNetworkMap()
|
networkMapSigner.signNetworkMaps()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger.error("Exception thrown while signing network map", e)
|
logger.error("Exception thrown while signing network map", e)
|
||||||
}
|
}
|
||||||
|
@ -13,4 +13,5 @@
|
|||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
|
||||||
<include file="migration/network-manager.changelog-init.xml"/>
|
<include file="migration/network-manager.changelog-init.xml"/>
|
||||||
|
<include file="migration/network-manager.changelog-network-map-table-change.xml"/>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!--
|
||||||
|
~ R3 Proprietary and Confidential
|
||||||
|
~
|
||||||
|
~ Copyright (c) 2018 R3 Limited. All rights reserved.
|
||||||
|
~
|
||||||
|
~ The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
|
||||||
|
~
|
||||||
|
~ Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
|
||||||
|
|
||||||
|
<changeSet author="R3.Corda" id="1522853587063-1">
|
||||||
|
<dropTable tableName="network_map"/>
|
||||||
|
<createTable tableName="network_map">
|
||||||
|
<column name="id" type="NVARCHAR(64)">
|
||||||
|
<constraints nullable="false" primaryKey="true" primaryKeyName="PK__NM_ID"/>
|
||||||
|
</column>
|
||||||
|
<column name="cert" type="BLOB">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="serialized_network_map" type="BLOB">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="signature" type="BLOB">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="network_parameters" type="NVARCHAR(64)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="timestamp" type="TIMESTAMP">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
|
<addForeignKeyConstraint baseColumnNames="network_parameters" baseTableName="network_map"
|
||||||
|
constraintName="FK__NM__NP"
|
||||||
|
referencedColumnNames="hash" referencedTableName="network_parameters"/>
|
||||||
|
|
||||||
|
<createTable tableName="network_map_AUD">
|
||||||
|
<column name="id" type="NVARCHAR(64)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="REV" type="INT">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="REVTYPE" type="TINYINT"/>
|
||||||
|
<column name="cert" type="BLOB"/>
|
||||||
|
<column name="serialized_network_map" type="BLOB"/>
|
||||||
|
<column name="signature" type="BLOB"/>
|
||||||
|
<column name="network_parameters" type="NVARCHAR(64)"/>
|
||||||
|
<column name="timestamp" type="TIMESTAMP"/>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
|
<addPrimaryKey columnNames="id, rev" constraintName="PK__NMA__RID"
|
||||||
|
tableName="network_map_AUD"/>
|
||||||
|
|
||||||
|
<createIndex indexName="IDX__NMA__REV" tableName="network_map_AUD">
|
||||||
|
<column name="REV"/>
|
||||||
|
</createIndex>
|
||||||
|
|
||||||
|
<addForeignKeyConstraint baseColumnNames="REV" baseTableName="network_map_AUD"
|
||||||
|
constraintName="FK__NMA__REV"
|
||||||
|
referencedColumnNames="REV" referencedTableName="REVINFO"/>
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
@ -1,5 +1,6 @@
|
|||||||
package com.r3.corda.networkmanage
|
package com.r3.corda.networkmanage
|
||||||
|
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.NetworkMaps
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.NetworkMapEntity
|
import com.r3.corda.networkmanage.common.persistence.entity.NetworkMapEntity
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.NetworkParametersEntity
|
import com.r3.corda.networkmanage.common.persistence.entity.NetworkParametersEntity
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
@ -10,6 +11,7 @@ import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
|||||||
import net.corda.nodeapi.internal.network.NetworkMap
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
import net.corda.nodeapi.internal.network.ParametersUpdate
|
import net.corda.nodeapi.internal.network.ParametersUpdate
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
fun createNetworkParametersEntity(signingCertAndKeyPair: CertificateAndKeyPair = createDevNetworkMapCa(),
|
fun createNetworkParametersEntity(signingCertAndKeyPair: CertificateAndKeyPair = createDevNetworkMapCa(),
|
||||||
networkParameters: NetworkParameters = testNetworkParameters()): NetworkParametersEntity {
|
networkParameters: NetworkParameters = testNetworkParameters()): NetworkParametersEntity {
|
||||||
@ -31,23 +33,41 @@ fun createNetworkParametersEntityUnsigned(networkParameters: NetworkParameters =
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createNetworkMapEntity(signingCertAndKeyPair: CertificateAndKeyPair = createDevNetworkMapCa(),
|
fun createNetworkMaps(signingCertAndKeyPair: CertificateAndKeyPair = createDevNetworkMapCa(),
|
||||||
netParamsEntity: NetworkParametersEntity,
|
netParamsEntity: NetworkParametersEntity,
|
||||||
nodeInfoHashes: List<SecureHash> = emptyList(),
|
nodeInfoHashes: List<SecureHash> = emptyList(),
|
||||||
parametersUpdate: ParametersUpdate? = null): NetworkMapEntity {
|
privateNodeInfoHashes: Map<String, List<SecureHash>> = emptyMap(),
|
||||||
|
parametersUpdate: ParametersUpdate? = null,
|
||||||
|
timestamp: Instant = Instant.now()): NetworkMaps {
|
||||||
|
val publicMapEntity = createNetworkMapEntity("PUBLIC_NETWORK", nodeInfoHashes, netParamsEntity, parametersUpdate, signingCertAndKeyPair, timestamp)
|
||||||
|
val privateNetworkMaps = privateNodeInfoHashes.mapValues {
|
||||||
|
createNetworkMapEntity(it.key, it.value, netParamsEntity, parametersUpdate, signingCertAndKeyPair, timestamp)
|
||||||
|
}
|
||||||
|
return NetworkMaps(publicMapEntity, privateNetworkMaps)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createNetworkMapEntity(id: String,
|
||||||
|
nodeInfoHashes: List<SecureHash>,
|
||||||
|
netParamsEntity: NetworkParametersEntity,
|
||||||
|
parametersUpdate: ParametersUpdate?,
|
||||||
|
signingCertAndKeyPair: CertificateAndKeyPair,
|
||||||
|
timestamp: Instant): NetworkMapEntity {
|
||||||
val networkMap = NetworkMap(nodeInfoHashes, SecureHash.parse(netParamsEntity.hash), parametersUpdate)
|
val networkMap = NetworkMap(nodeInfoHashes, SecureHash.parse(netParamsEntity.hash), parametersUpdate)
|
||||||
val signedNetworkMap = signingCertAndKeyPair.sign(networkMap)
|
val signedNetworkMap = signingCertAndKeyPair.sign(networkMap)
|
||||||
return NetworkMapEntity(
|
return NetworkMapEntity(
|
||||||
|
id = id,
|
||||||
networkMap = networkMap,
|
networkMap = networkMap,
|
||||||
signature = signedNetworkMap.sig.bytes,
|
signature = signedNetworkMap.sig.bytes,
|
||||||
certificate = signedNetworkMap.sig.by,
|
certificate = signedNetworkMap.sig.by,
|
||||||
networkParameters = netParamsEntity
|
networkParameters = netParamsEntity,
|
||||||
)
|
timestamp = timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createNetworkMapEntity(signingCertAndKeyPair: CertificateAndKeyPair = createDevNetworkMapCa(),
|
fun createNetworkMaps(signingCertAndKeyPair: CertificateAndKeyPair = createDevNetworkMapCa(),
|
||||||
networkParameters: NetworkParameters = testNetworkParameters(),
|
networkParameters: NetworkParameters = testNetworkParameters(),
|
||||||
nodeInfoHashes: List<SecureHash> = emptyList()): NetworkMapEntity {
|
nodeInfoHashes: List<SecureHash> = emptyList(),
|
||||||
|
privateNodeInfoHashes: Map<String, List<SecureHash>> = emptyMap(),
|
||||||
|
timestamp: Instant = Instant.now()): NetworkMaps {
|
||||||
val netParamsEntity = createNetworkParametersEntity(signingCertAndKeyPair, networkParameters)
|
val netParamsEntity = createNetworkParametersEntity(signingCertAndKeyPair, networkParameters)
|
||||||
return createNetworkMapEntity(signingCertAndKeyPair, netParamsEntity, nodeInfoHashes)
|
return createNetworkMaps(signingCertAndKeyPair, netParamsEntity, nodeInfoHashes, privateNodeInfoHashes, timestamp = timestamp)
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ package com.r3.corda.networkmanage.common.persistence
|
|||||||
import com.r3.corda.networkmanage.TestBase
|
import com.r3.corda.networkmanage.TestBase
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.NodeInfoEntity
|
import com.r3.corda.networkmanage.common.persistence.entity.NodeInfoEntity
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.ParametersUpdateEntity
|
import com.r3.corda.networkmanage.common.persistence.entity.ParametersUpdateEntity
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.entity.PrivateNetworkEntity
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.UpdateStatus
|
import com.r3.corda.networkmanage.common.persistence.entity.UpdateStatus
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
@ -33,6 +34,7 @@ import org.junit.Before
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class PersistentNetworkMapStorageTest : TestBase() {
|
class PersistentNetworkMapStorageTest : TestBase() {
|
||||||
private lateinit var persistence: CordaPersistence
|
private lateinit var persistence: CordaPersistence
|
||||||
@ -74,23 +76,15 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
|||||||
val networkMapAndSigned = NetworkMapAndSigned(networkMap) { networkMapCertAndKeyPair.sign(networkMap).sig }
|
val networkMapAndSigned = NetworkMapAndSigned(networkMap) { networkMapCertAndKeyPair.sign(networkMap).sig }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
networkMapStorage.saveNewActiveNetworkMap(networkMapAndSigned)
|
networkMapStorage.saveNewNetworkMap(networkMapAndSigned = networkMapAndSigned)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
val activeNetworkMapEntity = networkMapStorage.getActiveNetworkMap()!!
|
val networkMaps = networkMapStorage.getNetworkMaps()
|
||||||
val activeSignedNetworkMap = activeNetworkMapEntity.toSignedNetworkMap()
|
val activeSignedNetworkMap = networkMaps.publicNetworkMap!!.toSignedNetworkMap()
|
||||||
val activeNetworkMap = activeSignedNetworkMap.verifiedNetworkMapCert(rootCaCert)
|
val activeNetworkMap = activeSignedNetworkMap.verifiedNetworkMapCert(rootCaCert)
|
||||||
val activeNetworkParametersEntity = activeNetworkMapEntity.networkParameters
|
|
||||||
val activeSignedNetworkParameters = activeNetworkParametersEntity.toSignedNetworkParameters()
|
|
||||||
val activeNetworkParameters = activeSignedNetworkParameters.verifiedNetworkMapCert(rootCaCert)
|
|
||||||
|
|
||||||
assertThat(activeNetworkMap).isEqualTo(networkMap)
|
assertThat(activeNetworkMap).isEqualTo(networkMap)
|
||||||
assertThat(activeSignedNetworkMap.sig).isEqualTo(networkMapAndSigned.signed.sig)
|
assertThat(activeSignedNetworkMap.sig).isEqualTo(networkMapAndSigned.signed.sig)
|
||||||
assertThat(activeNetworkParameters).isEqualTo(networkParameters)
|
|
||||||
assertThat(activeSignedNetworkParameters.sig).isEqualTo(networkParametersSig)
|
|
||||||
assertThat(activeNetworkParametersEntity.hash)
|
|
||||||
.isEqualTo(activeNetworkMap.networkParameterHash.toString())
|
|
||||||
.isEqualTo(networkParametersHash)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -105,26 +99,40 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getValidNodeInfoHashes returns only for current node-infos`() {
|
fun `getValidNodeInfoHashes returns node-infos for public and private networks`() {
|
||||||
// given
|
// given
|
||||||
// Create node infos.
|
// Create node infos.
|
||||||
val (signedNodeInfoA) = createValidSignedNodeInfo("TestA", requestStorage)
|
|
||||||
val (signedNodeInfoB) = createValidSignedNodeInfo("TestB", requestStorage)
|
val nodes = listOf("TestA", "TestB", "TestC", "TestD", "TestE")
|
||||||
|
|
||||||
|
val nodeInfos = nodes.map { it to createValidSignedNodeInfo(it, requestStorage) }.toMap()
|
||||||
|
|
||||||
// Put signed node info data
|
// Put signed node info data
|
||||||
val nodeInfoHashA = nodeInfoStorage.putNodeInfo(signedNodeInfoA)
|
|
||||||
val nodeInfoHashB = nodeInfoStorage.putNodeInfo(signedNodeInfoB)
|
|
||||||
|
|
||||||
persistence.transaction {
|
val storedNodeInfos = nodeInfos.mapValues { nodeInfoStorage.putNodeInfo(it.value.first) }
|
||||||
val entity = session.find(NodeInfoEntity::class.java, nodeInfoHashA.toString())
|
|
||||||
session.merge(entity.copy(isCurrent = false))
|
val (testNet1, testNet2) = persistence.transaction {
|
||||||
|
val testNet1 = PrivateNetworkEntity(UUID.randomUUID().toString(), "TestNet1").apply { session.save(this) }
|
||||||
|
val testNet2 = PrivateNetworkEntity(UUID.randomUUID().toString(), "TestNet2").apply { session.save(this) }
|
||||||
|
|
||||||
|
// set different private network for node info
|
||||||
|
session.find(NodeInfoEntity::class.java, storedNodeInfos["TestA"].toString()).apply {
|
||||||
|
session.merge(certificateSigningRequest.copy(privateNetwork = testNet1))
|
||||||
|
}
|
||||||
|
session.find(NodeInfoEntity::class.java, storedNodeInfos["TestC"].toString()).apply {
|
||||||
|
session.merge(certificateSigningRequest.copy(privateNetwork = testNet2))
|
||||||
|
}
|
||||||
|
Pair(testNet1, testNet2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val validNodeInfoHashes = networkMapStorage.getActiveNodeInfoHashes()
|
val nodeInfoHashes = networkMapStorage.getNodeInfoHashes()
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(validNodeInfoHashes).containsOnly(nodeInfoHashB)
|
assertThat(nodeInfoHashes.publicNodeInfoHashes).containsOnlyElementsOf(storedNodeInfos.filterKeys { it !in setOf("TestA", "TestC") }.values)
|
||||||
|
assertThat(nodeInfoHashes.privateNodeInfoHashes.keys).containsOnlyElementsOf(listOf(testNet1.networkId, testNet2.networkId))
|
||||||
|
assertThat(nodeInfoHashes.privateNodeInfoHashes[testNet1.networkId]).containsOnlyElementsOf(listOf(storedNodeInfos["TestA"]))
|
||||||
|
assertThat(nodeInfoHashes.privateNodeInfoHashes[testNet2.networkId]).containsOnlyElementsOf(listOf(storedNodeInfos["TestC"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -169,7 +177,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
|||||||
val parameterUpdate = networkMapStorage.getCurrentParametersUpdate()!!
|
val parameterUpdate = networkMapStorage.getCurrentParametersUpdate()!!
|
||||||
networkMapStorage.switchFlagDay(parameterUpdate)
|
networkMapStorage.switchFlagDay(parameterUpdate)
|
||||||
// when
|
// when
|
||||||
val validNodeInfoHashes = networkMapStorage.getActiveNodeInfoHashes()
|
val validNodeInfoHashes = networkMapStorage.getNodeInfoHashes().publicNodeInfoHashes
|
||||||
// then
|
// then
|
||||||
assertThat(validNodeInfoHashes).containsOnly(nodeInfoHashB)
|
assertThat(validNodeInfoHashes).containsOnly(nodeInfoHashB)
|
||||||
}
|
}
|
||||||
@ -196,7 +204,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
|||||||
val parameterUpdate = networkMapStorage.getCurrentParametersUpdate()!!
|
val parameterUpdate = networkMapStorage.getCurrentParametersUpdate()!!
|
||||||
networkMapStorage.switchFlagDay(parameterUpdate)
|
networkMapStorage.switchFlagDay(parameterUpdate)
|
||||||
// when
|
// when
|
||||||
val validNodeInfoHashes = networkMapStorage.getActiveNodeInfoHashes()
|
val validNodeInfoHashes = networkMapStorage.getNodeInfoHashes().publicNodeInfoHashes
|
||||||
// then
|
// then
|
||||||
assertThat(validNodeInfoHashes).containsOnly(nodeInfoHashB)
|
assertThat(validNodeInfoHashes).containsOnly(nodeInfoHashB)
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
package com.r3.corda.networkmanage.common.persistence
|
package com.r3.corda.networkmanage.common.persistence
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.TestBase
|
import com.r3.corda.networkmanage.TestBase
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.entity.NetworkMapEntity
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.NodeInfoEntity
|
import com.r3.corda.networkmanage.common.persistence.entity.NodeInfoEntity
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
@ -127,14 +128,14 @@ class PersistentNodeInfoStorageTest : TestBase() {
|
|||||||
|
|
||||||
val nodeInfo1Hash = nodeInfoStorage.putNodeInfo(node1)
|
val nodeInfo1Hash = nodeInfoStorage.putNodeInfo(node1)
|
||||||
assertEquals(node1.nodeInfo, nodeInfoStorage.getNodeInfo(nodeInfo1Hash)?.verified())
|
assertEquals(node1.nodeInfo, nodeInfoStorage.getNodeInfo(nodeInfo1Hash)?.verified())
|
||||||
assertTrue(networkMapStorage.getActiveNodeInfoHashes().contains(nodeInfo1Hash))
|
assertTrue(networkMapStorage.getNodeInfoHashes().publicNodeInfoHashes.contains(nodeInfo1Hash))
|
||||||
|
|
||||||
// This should replace the node info.
|
// This should replace the node info.
|
||||||
val nodeInfo2Hash = nodeInfoStorage.putNodeInfo(node2)
|
val nodeInfo2Hash = nodeInfoStorage.putNodeInfo(node2)
|
||||||
|
|
||||||
// Old node info should be removed from list of current node info hashes, but still accessible if required.
|
// Old node info should be removed from list of current node info hashes, but still accessible if required.
|
||||||
assertThat(networkMapStorage.getActiveNodeInfoHashes()).doesNotContain(nodeInfo1Hash)
|
assertThat(networkMapStorage.getNodeInfoHashes().publicNodeInfoHashes).doesNotContain(nodeInfo1Hash)
|
||||||
assertThat(networkMapStorage.getActiveNodeInfoHashes()).contains(nodeInfo2Hash)
|
assertThat(networkMapStorage.getNodeInfoHashes().publicNodeInfoHashes).contains(nodeInfo2Hash)
|
||||||
assertNotNull(nodeInfoStorage.getNodeInfo(nodeInfo1Hash))
|
assertNotNull(nodeInfoStorage.getNodeInfo(nodeInfo1Hash))
|
||||||
assertEquals(nodeInfo2, nodeInfoStorage.getNodeInfo(nodeInfo2.serialize().hash)?.verified())
|
assertEquals(nodeInfo2, nodeInfoStorage.getNodeInfo(nodeInfo2.serialize().hash)?.verified())
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,11 @@ package com.r3.corda.networkmanage.common.signer
|
|||||||
import com.nhaarman.mockito_kotlin.*
|
import com.nhaarman.mockito_kotlin.*
|
||||||
import com.r3.corda.networkmanage.TestBase
|
import com.r3.corda.networkmanage.TestBase
|
||||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.NetworkMaps
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.NodeInfoHashes
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.ParametersUpdateEntity
|
import com.r3.corda.networkmanage.common.persistence.entity.ParametersUpdateEntity
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.UpdateStatus
|
import com.r3.corda.networkmanage.common.persistence.entity.UpdateStatus
|
||||||
import com.r3.corda.networkmanage.createNetworkMapEntity
|
import com.r3.corda.networkmanage.createNetworkMaps
|
||||||
import com.r3.corda.networkmanage.createNetworkParametersEntity
|
import com.r3.corda.networkmanage.createNetworkParametersEntity
|
||||||
import com.r3.corda.networkmanage.createNetworkParametersEntityUnsigned
|
import com.r3.corda.networkmanage.createNetworkParametersEntityUnsigned
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
@ -67,29 +69,29 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
@Test
|
@Test
|
||||||
fun `signNetworkMap builds and signs network map and network parameters`() {
|
fun `signNetworkMap builds and signs network map and network parameters`() {
|
||||||
// given
|
// given
|
||||||
val nodeInfoHashes = listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256())
|
val nodeInfoHashes = NodeInfoHashes(listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256()), emptyMap())
|
||||||
val latestNetParams = testNetworkParameters(epoch = 3)
|
val latestNetParams = testNetworkParameters(epoch = 3)
|
||||||
val latestNetParamsEntity = createNetworkParametersEntityUnsigned(latestNetParams)
|
val latestNetParamsEntity = createNetworkParametersEntityUnsigned(latestNetParams)
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(latestNetParamsEntity)
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(latestNetParamsEntity)
|
||||||
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(nodeInfoHashes)
|
whenever(networkMapStorage.getNodeInfoHashes()).thenReturn(nodeInfoHashes)
|
||||||
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(null)
|
whenever(networkMapStorage.getNetworkMaps()).thenReturn(NetworkMaps(null, emptyMap()))
|
||||||
whenever(networkMapStorage.getCurrentParametersUpdate()).thenReturn(null)
|
whenever(networkMapStorage.getCurrentParametersUpdate()).thenReturn(null)
|
||||||
|
|
||||||
// when
|
// when
|
||||||
networkMapSigner.signNetworkMap()
|
networkMapSigner.signNetworkMaps()
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// Verify networkMapStorage calls
|
// Verify networkMapStorage calls
|
||||||
verify(networkMapStorage).getActiveNodeInfoHashes()
|
verify(networkMapStorage).getNodeInfoHashes()
|
||||||
verify(networkMapStorage).getActiveNetworkMap()
|
verify(networkMapStorage).getNetworkMaps()
|
||||||
verify(networkMapStorage).getCurrentParametersUpdate()
|
verify(networkMapStorage).getCurrentParametersUpdate()
|
||||||
verify(networkMapStorage).getLatestNetworkParameters()
|
verify(networkMapStorage).getLatestNetworkParameters()
|
||||||
argumentCaptor<NetworkMapAndSigned>().apply {
|
argumentCaptor<NetworkMapAndSigned>().apply {
|
||||||
verify(networkMapStorage).saveNewActiveNetworkMap(capture())
|
verify(networkMapStorage).saveNewNetworkMap(anyOrNull(), capture())
|
||||||
val capturedNetworkMap = firstValue.networkMap
|
val capturedNetworkMap = firstValue.networkMap
|
||||||
// Parameters in network map got swapped for latest ones.
|
// Parameters in network map got swapped for latest ones.
|
||||||
assertEquals(latestNetParams.serialize().hash, capturedNetworkMap.networkParameterHash)
|
assertEquals(latestNetParams.serialize().hash, capturedNetworkMap.networkParameterHash)
|
||||||
assertThat(capturedNetworkMap.nodeInfoHashes).isEqualTo(nodeInfoHashes)
|
assertThat(capturedNetworkMap.nodeInfoHashes).isEqualTo(nodeInfoHashes.publicNodeInfoHashes)
|
||||||
}
|
}
|
||||||
val paramsCaptor = argumentCaptor<NetworkParameters>()
|
val paramsCaptor = argumentCaptor<NetworkParameters>()
|
||||||
val signatureCaptor = argumentCaptor<DigitalSignatureWithCert>()
|
val signatureCaptor = argumentCaptor<DigitalSignatureWithCert>()
|
||||||
@ -102,17 +104,17 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
fun `signNetworkMap does NOT create a new network map if there are no changes`() {
|
fun `signNetworkMap does NOT create a new network map if there are no changes`() {
|
||||||
// given
|
// given
|
||||||
val netParamsEntity = createNetworkParametersEntity(signingCertAndKeyPair)
|
val netParamsEntity = createNetworkParametersEntity(signingCertAndKeyPair)
|
||||||
val netMapEntity = createNetworkMapEntity(signingCertAndKeyPair, netParamsEntity, emptyList())
|
val netMapEntity = createNetworkMaps(signingCertAndKeyPair, netParamsEntity, emptyList())
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(netParamsEntity)
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(netParamsEntity)
|
||||||
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList())
|
whenever(networkMapStorage.getNodeInfoHashes()).thenReturn(NodeInfoHashes(emptyList(), emptyMap()))
|
||||||
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(netMapEntity)
|
whenever(networkMapStorage.getNetworkMaps()).thenReturn(netMapEntity)
|
||||||
|
|
||||||
// when
|
// when
|
||||||
networkMapSigner.signNetworkMap()
|
networkMapSigner.signNetworkMaps()
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// Verify networkMapStorage is not called
|
// Verify networkMapStorage is not called
|
||||||
verify(networkMapStorage, never()).saveNewActiveNetworkMap(any())
|
verify(networkMapStorage, never()).saveNewNetworkMap(any(), any())
|
||||||
verify(networkMapStorage, never()).saveNetworkParameters(any(), any())
|
verify(networkMapStorage, never()).saveNetworkParameters(any(), any())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,21 +123,21 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
// given
|
// given
|
||||||
val netParams = testNetworkParameters()
|
val netParams = testNetworkParameters()
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(createNetworkParametersEntityUnsigned(netParams))
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(createNetworkParametersEntityUnsigned(netParams))
|
||||||
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList())
|
whenever(networkMapStorage.getNodeInfoHashes()).thenReturn(NodeInfoHashes(emptyList(), emptyMap()))
|
||||||
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(null)
|
whenever(networkMapStorage.getNetworkMaps()).thenReturn(NetworkMaps(null, emptyMap()))
|
||||||
whenever(networkMapStorage.getCurrentParametersUpdate()).thenReturn(null)
|
whenever(networkMapStorage.getCurrentParametersUpdate()).thenReturn(null)
|
||||||
|
|
||||||
// when
|
// when
|
||||||
networkMapSigner.signNetworkMap()
|
networkMapSigner.signNetworkMaps()
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// Verify networkMapStorage calls
|
// Verify networkMapStorage calls
|
||||||
verify(networkMapStorage).getActiveNodeInfoHashes()
|
verify(networkMapStorage).getNodeInfoHashes()
|
||||||
verify(networkMapStorage).getActiveNetworkMap()
|
verify(networkMapStorage).getNetworkMaps()
|
||||||
verify(networkMapStorage).getLatestNetworkParameters()
|
verify(networkMapStorage).getLatestNetworkParameters()
|
||||||
verify(networkMapStorage).getCurrentParametersUpdate()
|
verify(networkMapStorage).getCurrentParametersUpdate()
|
||||||
argumentCaptor<NetworkMapAndSigned>().apply {
|
argumentCaptor<NetworkMapAndSigned>().apply {
|
||||||
verify(networkMapStorage).saveNewActiveNetworkMap(capture())
|
verify(networkMapStorage).saveNewNetworkMap(anyOrNull(), capture())
|
||||||
assertEquals(netParams.serialize().hash, firstValue.networkMap.networkParameterHash)
|
assertEquals(netParams.serialize().hash, firstValue.networkMap.networkParameterHash)
|
||||||
}
|
}
|
||||||
val paramsCaptor = argumentCaptor<NetworkParameters>()
|
val paramsCaptor = argumentCaptor<NetworkParameters>()
|
||||||
@ -151,19 +153,19 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
val currentNetworkParameters = createNetworkParametersEntity(signingCertAndKeyPair)
|
val currentNetworkParameters = createNetworkParametersEntity(signingCertAndKeyPair)
|
||||||
val updateNetworkParameters = createNetworkParametersEntityUnsigned(testNetworkParameters(epoch = 2))
|
val updateNetworkParameters = createNetworkParametersEntityUnsigned(testNetworkParameters(epoch = 2))
|
||||||
val parametersUpdate = ParametersUpdateEntity(0, updateNetworkParameters, "Update time", Instant.ofEpochMilli(random63BitValue()))
|
val parametersUpdate = ParametersUpdateEntity(0, updateNetworkParameters, "Update time", Instant.ofEpochMilli(random63BitValue()))
|
||||||
val netMapEntity = createNetworkMapEntity(signingCertAndKeyPair, currentNetworkParameters, emptyList(), null)
|
val netMapEntity = createNetworkMaps(signingCertAndKeyPair, currentNetworkParameters)
|
||||||
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(netMapEntity)
|
whenever(networkMapStorage.getNetworkMaps()).thenReturn(netMapEntity)
|
||||||
whenever(networkMapStorage.getCurrentParametersUpdate()).thenReturn(parametersUpdate)
|
whenever(networkMapStorage.getCurrentParametersUpdate()).thenReturn(parametersUpdate)
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(updateNetworkParameters)
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(updateNetworkParameters)
|
||||||
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList())
|
whenever(networkMapStorage.getNodeInfoHashes()).thenReturn(NodeInfoHashes(emptyList(), emptyMap()))
|
||||||
|
|
||||||
// when
|
// when
|
||||||
networkMapSigner.signNetworkMap()
|
networkMapSigner.signNetworkMaps()
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// Verify networkMapStorage calls
|
// Verify networkMapStorage calls
|
||||||
verify(networkMapStorage).getActiveNetworkMap()
|
verify(networkMapStorage).getNetworkMaps()
|
||||||
verify(networkMapStorage).getActiveNodeInfoHashes()
|
verify(networkMapStorage).getNodeInfoHashes()
|
||||||
verify(networkMapStorage).getLatestNetworkParameters()
|
verify(networkMapStorage).getLatestNetworkParameters()
|
||||||
verify(networkMapStorage).getCurrentParametersUpdate()
|
verify(networkMapStorage).getCurrentParametersUpdate()
|
||||||
|
|
||||||
@ -178,13 +180,13 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
fun `signNetworkMap fails if there is parameter update without relevant parameters stored`() {
|
fun `signNetworkMap fails if there is parameter update without relevant parameters stored`() {
|
||||||
val updateNetworkParameters = createNetworkParametersEntityUnsigned(testNetworkParameters(epoch = 2))
|
val updateNetworkParameters = createNetworkParametersEntityUnsigned(testNetworkParameters(epoch = 2))
|
||||||
val parametersUpdate = ParametersUpdateEntity(0, updateNetworkParameters, "Update time", Instant.ofEpochMilli(random63BitValue()))
|
val parametersUpdate = ParametersUpdateEntity(0, updateNetworkParameters, "Update time", Instant.ofEpochMilli(random63BitValue()))
|
||||||
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(null)
|
whenever(networkMapStorage.getNetworkMaps()).thenReturn(NetworkMaps(null, emptyMap()))
|
||||||
whenever(networkMapStorage.getCurrentParametersUpdate()).thenReturn(parametersUpdate)
|
whenever(networkMapStorage.getCurrentParametersUpdate()).thenReturn(parametersUpdate)
|
||||||
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList())
|
whenever(networkMapStorage.getNodeInfoHashes()).thenReturn(NodeInfoHashes(emptyList(), emptyMap()))
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(createNetworkParametersEntity())
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(createNetworkParametersEntity())
|
||||||
|
|
||||||
verify(networkMapStorage, never()).saveNetworkParameters(any(), any())
|
verify(networkMapStorage, never()).saveNetworkParameters(any(), any())
|
||||||
verify(networkMapStorage, never()).saveNewActiveNetworkMap(any())
|
verify(networkMapStorage, never()).saveNewNetworkMap(any(), any())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -192,19 +194,19 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
val activeNetworkParameters = createNetworkParametersEntity(signingCertAndKeyPair, testNetworkParameters(epoch = 1))
|
val activeNetworkParameters = createNetworkParametersEntity(signingCertAndKeyPair, testNetworkParameters(epoch = 1))
|
||||||
val updateNetworkParameters = createNetworkParametersEntity(signingCertAndKeyPair, testNetworkParameters(epoch = 2))
|
val updateNetworkParameters = createNetworkParametersEntity(signingCertAndKeyPair, testNetworkParameters(epoch = 2))
|
||||||
val parametersUpdate = ParametersUpdateEntity(0, updateNetworkParameters, "Update time", Instant.ofEpochMilli(random63BitValue()))
|
val parametersUpdate = ParametersUpdateEntity(0, updateNetworkParameters, "Update time", Instant.ofEpochMilli(random63BitValue()))
|
||||||
val activeNetworkMap = createNetworkMapEntity(signingCertAndKeyPair, activeNetworkParameters, emptyList(), parametersUpdate.toParametersUpdate())
|
val activeNetworkMaps = createNetworkMaps(signingCertAndKeyPair, activeNetworkParameters, parametersUpdate = parametersUpdate.toParametersUpdate())
|
||||||
|
|
||||||
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(activeNetworkMap)
|
whenever(networkMapStorage.getNetworkMaps()).thenReturn(activeNetworkMaps)
|
||||||
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList())
|
whenever(networkMapStorage.getNodeInfoHashes()).thenReturn(NodeInfoHashes(emptyList(), emptyMap()))
|
||||||
whenever(networkMapStorage.getCurrentParametersUpdate()).thenReturn(parametersUpdate.copy(status = UpdateStatus.FLAG_DAY))
|
whenever(networkMapStorage.getCurrentParametersUpdate()).thenReturn(parametersUpdate.copy(status = UpdateStatus.FLAG_DAY))
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(updateNetworkParameters)
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(updateNetworkParameters)
|
||||||
|
|
||||||
// when
|
// when
|
||||||
networkMapSigner.signNetworkMap()
|
networkMapSigner.signNetworkMaps()
|
||||||
|
|
||||||
//then
|
//then
|
||||||
argumentCaptor<NetworkMapAndSigned>().apply {
|
argumentCaptor<NetworkMapAndSigned>().apply {
|
||||||
verify(networkMapStorage).saveNewActiveNetworkMap(capture())
|
verify(networkMapStorage).saveNewNetworkMap(anyOrNull(), capture())
|
||||||
val netMap = firstValue.networkMap
|
val netMap = firstValue.networkMap
|
||||||
assertEquals(SecureHash.parse(updateNetworkParameters.hash), netMap.networkParameterHash)
|
assertEquals(SecureHash.parse(updateNetworkParameters.hash), netMap.networkParameterHash)
|
||||||
assertEquals(emptyList(), netMap.nodeInfoHashes)
|
assertEquals(emptyList(), netMap.nodeInfoHashes)
|
||||||
@ -217,19 +219,19 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
val activeNetworkParameters = createNetworkParametersEntity(signingCertAndKeyPair, testNetworkParameters(epoch = 1))
|
val activeNetworkParameters = createNetworkParametersEntity(signingCertAndKeyPair, testNetworkParameters(epoch = 1))
|
||||||
val updateNetworkParameters = createNetworkParametersEntityUnsigned(testNetworkParameters(epoch = 2))
|
val updateNetworkParameters = createNetworkParametersEntityUnsigned(testNetworkParameters(epoch = 2))
|
||||||
val parametersUpdate = ParametersUpdateEntity(0, updateNetworkParameters, "Update time", Instant.ofEpochMilli(random63BitValue()))
|
val parametersUpdate = ParametersUpdateEntity(0, updateNetworkParameters, "Update time", Instant.ofEpochMilli(random63BitValue()))
|
||||||
val activeNetworkMap = createNetworkMapEntity(signingCertAndKeyPair, activeNetworkParameters, emptyList(), parametersUpdate.toParametersUpdate())
|
val activeNetworkMaps = createNetworkMaps(signingCertAndKeyPair, activeNetworkParameters, parametersUpdate = parametersUpdate.toParametersUpdate())
|
||||||
|
|
||||||
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(activeNetworkMap)
|
whenever(networkMapStorage.getNetworkMaps()).thenReturn(activeNetworkMaps)
|
||||||
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList())
|
whenever(networkMapStorage.getNodeInfoHashes()).thenReturn(NodeInfoHashes(emptyList(), emptyMap()))
|
||||||
whenever(networkMapStorage.getCurrentParametersUpdate()).thenReturn(null)
|
whenever(networkMapStorage.getCurrentParametersUpdate()).thenReturn(null)
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(createNetworkParametersEntity())
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(createNetworkParametersEntity())
|
||||||
|
|
||||||
// when
|
// when
|
||||||
networkMapSigner.signNetworkMap()
|
networkMapSigner.signNetworkMaps()
|
||||||
|
|
||||||
//then
|
//then
|
||||||
argumentCaptor<NetworkMapAndSigned>().apply {
|
argumentCaptor<NetworkMapAndSigned>().apply {
|
||||||
verify(networkMapStorage).saveNewActiveNetworkMap(capture())
|
verify(networkMapStorage).saveNewNetworkMap(anyOrNull(), capture())
|
||||||
val netMap = firstValue.networkMap
|
val netMap = firstValue.networkMap
|
||||||
assertEquals(SecureHash.parse(activeNetworkParameters.hash), netMap.networkParameterHash)
|
assertEquals(SecureHash.parse(activeNetworkParameters.hash), netMap.networkParameterHash)
|
||||||
assertEquals(emptyList(), netMap.nodeInfoHashes)
|
assertEquals(emptyList(), netMap.nodeInfoHashes)
|
||||||
|
@ -14,13 +14,19 @@ import com.nhaarman.mockito_kotlin.*
|
|||||||
import com.r3.corda.networkmanage.common.persistence.CertificateSigningRequestStorage
|
import com.r3.corda.networkmanage.common.persistence.CertificateSigningRequestStorage
|
||||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||||
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
||||||
import com.r3.corda.networkmanage.createNetworkMapEntity
|
import com.r3.corda.networkmanage.createNetworkMaps
|
||||||
import com.r3.corda.networkmanage.doorman.NetworkManagementWebServer
|
import com.r3.corda.networkmanage.doorman.NetworkManagementWebServer
|
||||||
import com.r3.corda.networkmanage.doorman.NetworkMapConfig
|
import com.r3.corda.networkmanage.doorman.NetworkMapConfig
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.Crypto
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.SecureHash.Companion.randomSHA256
|
import net.corda.core.crypto.SecureHash.Companion.randomSHA256
|
||||||
|
import net.corda.core.crypto.SignedData
|
||||||
|
import net.corda.core.crypto.sign
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.openHttpConnection
|
||||||
|
import net.corda.core.internal.post
|
||||||
|
import net.corda.core.internal.responseAs
|
||||||
|
import net.corda.core.internal.sign
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
@ -42,6 +48,16 @@ import org.junit.Test
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
|
import java.time.Duration
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
import kotlin.collections.component1
|
||||||
|
import kotlin.collections.component2
|
||||||
|
import kotlin.collections.first
|
||||||
|
import kotlin.collections.forEach
|
||||||
|
import kotlin.collections.listOf
|
||||||
|
import kotlin.collections.mapOf
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
@ -67,7 +83,7 @@ class NetworkMapWebServiceTest {
|
|||||||
// Create node info.
|
// Create node info.
|
||||||
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity())
|
on { getNetworkMaps() }.thenReturn(createNetworkMaps())
|
||||||
}
|
}
|
||||||
val csrStorage: CertificateSigningRequestStorage = mock {
|
val csrStorage: CertificateSigningRequestStorage = mock {
|
||||||
on { getValidCertificatePath(any()) }.thenReturn(signedNodeInfo.verified().legalIdentitiesAndCerts.first().certPath)
|
on { getValidCertificatePath(any()) }.thenReturn(signedNodeInfo.verified().legalIdentitiesAndCerts.first().certPath)
|
||||||
@ -85,7 +101,7 @@ class NetworkMapWebServiceTest {
|
|||||||
// Create node info.
|
// Create node info.
|
||||||
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity())
|
on { getNetworkMaps() }.thenReturn(createNetworkMaps())
|
||||||
}
|
}
|
||||||
val csrStorage: CertificateSigningRequestStorage = mock {
|
val csrStorage: CertificateSigningRequestStorage = mock {
|
||||||
on { getValidCertificatePath(any()) }.thenReturn(null)
|
on { getValidCertificatePath(any()) }.thenReturn(null)
|
||||||
@ -105,7 +121,7 @@ class NetworkMapWebServiceTest {
|
|||||||
// Create node info.
|
// Create node info.
|
||||||
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity(networkParameters = testNetworkParameters(minimumPlatformVersion = 2)))
|
on { getNetworkMaps() }.thenReturn(createNetworkMaps(networkParameters = testNetworkParameters(minimumPlatformVersion = 2)))
|
||||||
}
|
}
|
||||||
val csrStorage: CertificateSigningRequestStorage = mock {
|
val csrStorage: CertificateSigningRequestStorage = mock {
|
||||||
on { getValidCertificatePath(any()) }.thenReturn(signedNodeInfo.verified().legalIdentitiesAndCerts.first().certPath)
|
on { getValidCertificatePath(any()) }.thenReturn(signedNodeInfo.verified().legalIdentitiesAndCerts.first().certPath)
|
||||||
@ -123,7 +139,7 @@ class NetworkMapWebServiceTest {
|
|||||||
// Create node info.
|
// Create node info.
|
||||||
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getActiveNetworkMap() }.thenReturn(null)
|
on { getNetworkMaps() }.thenReturn(null)
|
||||||
}
|
}
|
||||||
val csrStorage: CertificateSigningRequestStorage = mock {
|
val csrStorage: CertificateSigningRequestStorage = mock {
|
||||||
on { getValidCertificatePath(any()) }.thenReturn(signedNodeInfo.verified().legalIdentitiesAndCerts.first().certPath)
|
on { getValidCertificatePath(any()) }.thenReturn(signedNodeInfo.verified().legalIdentitiesAndCerts.first().certPath)
|
||||||
@ -138,19 +154,69 @@ class NetworkMapWebServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get network map`() {
|
fun `get network map`() {
|
||||||
val networkMapEntity = createNetworkMapEntity(
|
val networkMaps = createNetworkMaps(
|
||||||
signingCertAndKeyPair = signingCertAndKeyPair,
|
signingCertAndKeyPair = signingCertAndKeyPair,
|
||||||
nodeInfoHashes = listOf(randomSHA256(), randomSHA256()))
|
nodeInfoHashes = listOf(randomSHA256(), randomSHA256()))
|
||||||
|
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getActiveNetworkMap() }.thenReturn(networkMapEntity)
|
on { getNetworkMaps() }.thenReturn(networkMaps)
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, mock(), testNetworkMapConfig)).use {
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, mock(), testNetworkMapConfig)).use {
|
||||||
it.start()
|
it.start()
|
||||||
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
||||||
verify(networkMapStorage, times(1)).getActiveNetworkMap()
|
verify(networkMapStorage, times(1)).getNetworkMaps()
|
||||||
assertEquals(signedNetworkMapResponse.verifiedNetworkMapCert(rootCaCert), networkMapEntity.networkMap)
|
assertEquals(signedNetworkMapResponse.verifiedNetworkMapCert(rootCaCert), networkMaps.publicNetworkMap!!.networkMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network map response contains correct http header parameter`() {
|
||||||
|
val timestamp = Instant.now()
|
||||||
|
val networkMaps = createNetworkMaps(
|
||||||
|
signingCertAndKeyPair = signingCertAndKeyPair,
|
||||||
|
nodeInfoHashes = listOf(randomSHA256(), randomSHA256()),
|
||||||
|
timestamp = timestamp)
|
||||||
|
|
||||||
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
|
on { getNetworkMaps() }.thenReturn(networkMaps)
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, mock(), testNetworkMapConfig)).use {
|
||||||
|
it.start()
|
||||||
|
val headers = URL("http://${it.hostAndPort}/network-map/").openHttpConnection().headerFields
|
||||||
|
assertEquals("max-age=${Duration.ofMillis(testNetworkMapConfig.cacheTimeout).seconds}", headers["Cache-Control"]?.first())
|
||||||
|
assertEquals(DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneId.of("GMT")).format(timestamp), headers["Last-Modified"]?.first())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `get private network map`() {
|
||||||
|
val publicNodeInfoHashes = listOf(randomSHA256(), randomSHA256())
|
||||||
|
val privateNodeInfoHashes = mapOf("PrivateNet1" to listOf(randomSHA256(), randomSHA256()), "PrivateNet2" to listOf(randomSHA256(), randomSHA256()))
|
||||||
|
|
||||||
|
val networkMaps = createNetworkMaps(
|
||||||
|
signingCertAndKeyPair = signingCertAndKeyPair,
|
||||||
|
nodeInfoHashes = publicNodeInfoHashes,
|
||||||
|
privateNodeInfoHashes = privateNodeInfoHashes
|
||||||
|
)
|
||||||
|
|
||||||
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
|
on { getNetworkMaps() }.thenReturn(networkMaps)
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, mock(), testNetworkMapConfig)).use {
|
||||||
|
it.start()
|
||||||
|
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
||||||
|
verify(networkMapStorage, times(1)).getNetworkMaps()
|
||||||
|
assertEquals(signedNetworkMapResponse.verifiedNetworkMapCert(rootCaCert), networkMaps.publicNetworkMap!!.networkMap)
|
||||||
|
|
||||||
|
networkMaps.privateNetworkMap.forEach { (key, privateNetworkMapEntity) ->
|
||||||
|
val response = it.doGet<SignedNetworkMap>(key)
|
||||||
|
// Result cached.
|
||||||
|
verify(networkMapStorage, times(1)).getNetworkMaps()
|
||||||
|
assertEquals(response.verifiedNetworkMapCert(rootCaCert), privateNetworkMapEntity.networkMap)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +231,7 @@ class NetworkMapWebServiceTest {
|
|||||||
|
|
||||||
// Mock network map storage
|
// Mock network map storage
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity(nodeInfoHashes = listOf(nodeInfoHash)))
|
on { getNetworkMaps() }.thenReturn(createNetworkMaps(nodeInfoHashes = listOf(nodeInfoHash)))
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(nodeInfoStorage, networkMapStorage, mock(), testNetworkMapConfig)).use {
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(nodeInfoStorage, networkMapStorage, mock(), testNetworkMapConfig)).use {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user