mirror of
https://github.com/corda/corda.git
synced 2024-12-28 16:58:55 +00:00
network_map table references the network_parameters table (ENT-1524). (#567)
This commit is contained in:
parent
2a898658c2
commit
78b2bc7549
@ -388,10 +388,16 @@ val CordaX500Name.x500Name: X500Name
|
|||||||
val CordaX500Name.Companion.unspecifiedCountry
|
val CordaX500Name.Companion.unspecifiedCountry
|
||||||
get() = "ZZ"
|
get() = "ZZ"
|
||||||
|
|
||||||
fun <T : Any> T.signWithCert(privateKey: PrivateKey, certificate: X509Certificate): SignedDataWithCert<T> {
|
inline fun <T : Any> T.signWithCert(signer: (SerializedBytes<T>) -> DigitalSignatureWithCert): SignedDataWithCert<T> {
|
||||||
val serialised = serialize()
|
val serialised = serialize()
|
||||||
val signature = Crypto.doSign(privateKey, serialised.bytes)
|
return SignedDataWithCert(serialised, signer(serialised))
|
||||||
return SignedDataWithCert(serialised, DigitalSignatureWithCert(certificate, signature))
|
}
|
||||||
|
|
||||||
|
fun <T : Any> T.signWithCert(privateKey: PrivateKey, certificate: X509Certificate): SignedDataWithCert<T> {
|
||||||
|
return signWithCert {
|
||||||
|
val signature = Crypto.doSign(privateKey, it.bytes)
|
||||||
|
DigitalSignatureWithCert(certificate, signature)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T : Any> SerializedBytes<T>.sign(signer: (SerializedBytes<T>) -> DigitalSignature.WithKey): SignedData<T> {
|
inline fun <T : Any> SerializedBytes<T>.sign(signer: (SerializedBytes<T>) -> DigitalSignature.WithKey): SignedData<T> {
|
||||||
|
@ -165,9 +165,7 @@ class HsmSigningServiceTest : HsmBaseTest() {
|
|||||||
networkMapSigner.signNetworkMap()
|
networkMapSigner.signNetworkMap()
|
||||||
|
|
||||||
// then
|
// then
|
||||||
val signedNetworkMap = networkMapStorage.getCurrentNetworkMap()
|
val persistedNetworkMap = networkMapStorage.getActiveNetworkMap()!!.toSignedNetworkMap().verified()
|
||||||
assertNotNull(signedNetworkMap)
|
|
||||||
val persistedNetworkMap = signedNetworkMap!!.verified()
|
|
||||||
assertEquals(networkMapParameters.serialize().hash, persistedNetworkMap.networkParameterHash)
|
assertEquals(networkMapParameters.serialize().hash, persistedNetworkMap.networkParameterHash)
|
||||||
assertThat(persistedNetworkMap.nodeInfoHashes).isEmpty()
|
assertThat(persistedNetworkMap.nodeInfoHashes).isEmpty()
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,13 @@
|
|||||||
|
|
||||||
package com.r3.corda.networkmanage.common.persistence
|
package com.r3.corda.networkmanage.common.persistence
|
||||||
|
|
||||||
|
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.NodeInfoEntity
|
import com.r3.corda.networkmanage.common.persistence.entity.NodeInfoEntity
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.internal.DigitalSignatureWithCert
|
import net.corda.core.internal.DigitalSignatureWithCert
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
import net.corda.nodeapi.internal.network.NetworkMapAndSigned
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,47 +24,37 @@ import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
|||||||
*/
|
*/
|
||||||
interface NetworkMapStorage {
|
interface NetworkMapStorage {
|
||||||
/**
|
/**
|
||||||
* Retrieves current network map. Current in this context means the one that has been most recently signed.
|
* Returns the active network map, or null
|
||||||
* @return current network map
|
|
||||||
*/
|
*/
|
||||||
fun getCurrentNetworkMap(): SignedNetworkMap?
|
fun getActiveNetworkMap(): NetworkMapEntity?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persist the new active network map, replacing any existing network map.
|
||||||
|
*/
|
||||||
|
fun saveNewActiveNetworkMap(networkMapAndSigned: NetworkMapAndSigned)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves node info hashes where [NodeInfoEntity.isCurrent] is true and the certificate status is [CertificateStatus.VALID]
|
* Retrieves node info hashes where [NodeInfoEntity.isCurrent] is true and the certificate status is [CertificateStatus.VALID]
|
||||||
*
|
|
||||||
* @return list of current and valid node info hashes.
|
|
||||||
*/
|
*/
|
||||||
fun getActiveNodeInfoHashes(): List<SecureHash>
|
fun getActiveNodeInfoHashes(): List<SecureHash>
|
||||||
|
|
||||||
/**
|
|
||||||
* Persists a new instance of the signed network map.
|
|
||||||
* @param signedNetworkMap encapsulates all the information needed for persisting current network map state.
|
|
||||||
*/
|
|
||||||
fun saveNetworkMap(signedNetworkMap: SignedNetworkMap)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
* [NetworkParameters] object and not the `SignedWithCert<NetworkParameters>` object that's returned.
|
* [NetworkParameters] object and not the [SignedNetworkParameters] object that's returned.
|
||||||
* @return signed network parameters corresponding to the given hash or null if it does not exist (parameters don't exist or they haven't been signed yet)
|
* @return signed network parameters corresponding to the given hash or null if it does not exist (parameters don't exist or they haven't been signed yet)
|
||||||
*/
|
*/
|
||||||
fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters?
|
fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters?
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the network parameters of the current network map, or null if there's no network map.
|
|
||||||
*/
|
|
||||||
// TODO: Remove this method. We should get the "current" network parameter by using the the hash in the network map and use the [getSignedNetworkParameters] method.
|
|
||||||
fun getNetworkParametersOfNetworkMap(): SignedNetworkParameters?
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Persists given network parameters with signature if provided.
|
* Persists given network parameters with signature if provided.
|
||||||
* @return hash corresponding to newly created network parameters entry
|
* @return hash corresponding to newly created network parameters entry
|
||||||
*/
|
*/
|
||||||
fun saveNetworkParameters(networkParameters: NetworkParameters, sig: DigitalSignatureWithCert?): SecureHash
|
fun saveNetworkParameters(networkParameters: NetworkParameters, signature: DigitalSignatureWithCert?): SecureHash
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the latest (i.e. most recently inserted) network parameters
|
* Retrieves the latest (i.e. most recently inserted) network parameters
|
||||||
* Note that they may not have been signed up yet.
|
* Note that they may not have been signed up yet.
|
||||||
* @return latest network parameters
|
* @return latest network parameters
|
||||||
*/
|
*/
|
||||||
fun getLatestNetworkParameters(): NetworkParameters?
|
fun getLatestNetworkParameters(): NetworkParametersEntity?
|
||||||
}
|
}
|
||||||
|
@ -18,23 +18,24 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence
|
|||||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
|
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
|
||||||
import net.corda.nodeapi.internal.persistence.SchemaMigration
|
import net.corda.nodeapi.internal.persistence.SchemaMigration
|
||||||
|
import org.hibernate.query.Query
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.persistence.LockModeType
|
import javax.persistence.LockModeType
|
||||||
import javax.persistence.criteria.CriteriaBuilder
|
import javax.persistence.criteria.CriteriaBuilder
|
||||||
import javax.persistence.criteria.Path
|
import javax.persistence.criteria.Path
|
||||||
import javax.persistence.criteria.Predicate
|
import javax.persistence.criteria.Predicate
|
||||||
|
|
||||||
inline fun <reified T> DatabaseTransaction.singleEntityWhere(predicate: (CriteriaBuilder, Path<T>) -> Predicate): T? {
|
inline fun <reified T> DatabaseTransaction.uniqueEntityWhere(predicate: (CriteriaBuilder, Path<T>) -> Predicate): T? {
|
||||||
return getEntitiesWhere(predicate).firstOrNull()
|
return entitiesWhere(predicate).setMaxResults(1).uniqueResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T> DatabaseTransaction.getEntitiesWhere(predicate: (CriteriaBuilder, Path<T>) -> Predicate): List<T> {
|
inline fun <reified T> DatabaseTransaction.entitiesWhere(predicate: (CriteriaBuilder, Path<T>) -> Predicate): Query<T> {
|
||||||
val builder = session.criteriaBuilder
|
val builder = session.criteriaBuilder
|
||||||
val criteriaQuery = builder.createQuery(T::class.java)
|
val criteriaQuery = builder.createQuery(T::class.java)
|
||||||
val query = criteriaQuery.from(T::class.java).run {
|
val query = criteriaQuery.from(T::class.java).run {
|
||||||
criteriaQuery.where(predicate(builder, this))
|
criteriaQuery.where(predicate(builder, this))
|
||||||
}
|
}
|
||||||
return session.createQuery(query).setLockMode(LockModeType.PESSIMISTIC_WRITE).resultList
|
return session.createQuery(query).setLockMode(LockModeType.PESSIMISTIC_WRITE)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T> DatabaseTransaction.deleteEntity(predicate: (CriteriaBuilder, Path<T>) -> Predicate): Int {
|
inline fun <reified T> DatabaseTransaction.deleteEntity(predicate: (CriteriaBuilder, Path<T>) -> Predicate): Int {
|
||||||
|
@ -40,7 +40,7 @@ class PersistentCertificateRevocationListStorage(private val database: CordaPers
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun revokeCertificate(certificateSerialNumber: BigInteger, time: Instant, transaction: DatabaseTransaction) {
|
private fun revokeCertificate(certificateSerialNumber: BigInteger, time: Instant, transaction: DatabaseTransaction) {
|
||||||
val revocation = transaction.singleEntityWhere<CertificateRevocationRequestEntity> { builder, path ->
|
val revocation = transaction.uniqueEntityWhere<CertificateRevocationRequestEntity> { builder, path ->
|
||||||
builder.equal(path.get<BigInteger>(CertificateRevocationRequestEntity::certificateSerialNumber.name), certificateSerialNumber)
|
builder.equal(path.get<BigInteger>(CertificateRevocationRequestEntity::certificateSerialNumber.name), certificateSerialNumber)
|
||||||
}
|
}
|
||||||
revocation ?: throw IllegalStateException("The certificate revocation request for $certificateSerialNumber does not exist")
|
revocation ?: throw IllegalStateException("The certificate revocation request for $certificateSerialNumber does not exist")
|
||||||
|
@ -13,7 +13,7 @@ class PersistentCertificateRevocationRequestStorage(private val database: CordaP
|
|||||||
override fun saveRevocationRequest(certificateSerialNumber: BigInteger, reason: CRLReason, reporter: String): String {
|
override fun saveRevocationRequest(certificateSerialNumber: BigInteger, reason: CRLReason, reporter: String): String {
|
||||||
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
||||||
// Check if there is an entry for the given certificate serial number
|
// Check if there is an entry for the given certificate serial number
|
||||||
val revocation = singleEntityWhere<CertificateRevocationRequestEntity> { builder, path ->
|
val revocation = uniqueEntityWhere<CertificateRevocationRequestEntity> { builder, path ->
|
||||||
val serialNumberEqual = builder.equal(path.get<BigInteger>(CertificateRevocationRequestEntity::certificateSerialNumber.name), certificateSerialNumber)
|
val serialNumberEqual = builder.equal(path.get<BigInteger>(CertificateRevocationRequestEntity::certificateSerialNumber.name), certificateSerialNumber)
|
||||||
val statusNotEqualRejected = builder.notEqual(path.get<RequestStatus>(CertificateRevocationRequestEntity::status.name), RequestStatus.REJECTED)
|
val statusNotEqualRejected = builder.notEqual(path.get<RequestStatus>(CertificateRevocationRequestEntity::status.name), RequestStatus.REJECTED)
|
||||||
builder.and(serialNumberEqual, statusNotEqualRejected)
|
builder.and(serialNumberEqual, statusNotEqualRejected)
|
||||||
@ -21,7 +21,7 @@ class PersistentCertificateRevocationRequestStorage(private val database: CordaP
|
|||||||
if (revocation != null) {
|
if (revocation != null) {
|
||||||
revocation.requestId
|
revocation.requestId
|
||||||
} else {
|
} else {
|
||||||
val certificateData = singleEntityWhere<CertificateDataEntity> { builder, path ->
|
val certificateData = uniqueEntityWhere<CertificateDataEntity> { builder, path ->
|
||||||
val serialNumberEqual = builder.equal(path.get<BigInteger>(CertificateDataEntity::certificateSerialNumber.name), certificateSerialNumber)
|
val serialNumberEqual = builder.equal(path.get<BigInteger>(CertificateDataEntity::certificateSerialNumber.name), certificateSerialNumber)
|
||||||
val statusEqualValid = builder.equal(path.get<CertificateStatus>(CertificateDataEntity::certificateStatus.name), CertificateStatus.VALID)
|
val statusEqualValid = builder.equal(path.get<CertificateStatus>(CertificateDataEntity::certificateStatus.name), CertificateStatus.VALID)
|
||||||
builder.and(serialNumberEqual, statusEqualValid)
|
builder.and(serialNumberEqual, statusEqualValid)
|
||||||
@ -90,7 +90,7 @@ class PersistentCertificateRevocationRequestStorage(private val database: CordaP
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getRevocationRequestEntity(requestId: String): CertificateRevocationRequestEntity? = database.transaction {
|
private fun getRevocationRequestEntity(requestId: String): CertificateRevocationRequestEntity? = database.transaction {
|
||||||
singleEntityWhere { builder, path ->
|
uniqueEntityWhere { builder, path ->
|
||||||
builder.equal(path.get<String>(CertificateRevocationRequestEntity::requestId.name), requestId)
|
builder.equal(path.get<String>(CertificateRevocationRequestEntity::requestId.name), requestId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
|
|||||||
|
|
||||||
override fun putCertificatePath(requestId: String, certPath: CertPath, signedBy: String) {
|
override fun putCertificatePath(requestId: String, certPath: CertPath, signedBy: String) {
|
||||||
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
||||||
val request = singleEntityWhere<CertificateSigningRequestEntity> { builder, path ->
|
val request = uniqueEntityWhere<CertificateSigningRequestEntity> { builder, path ->
|
||||||
val requestIdEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::requestId.name), requestId)
|
val requestIdEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::requestId.name), requestId)
|
||||||
val statusEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::status.name), RequestStatus.APPROVED)
|
val statusEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::status.name), RequestStatus.APPROVED)
|
||||||
builder.and(requestIdEq, statusEq)
|
builder.and(requestIdEq, statusEq)
|
||||||
@ -89,7 +89,7 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
|
|||||||
|
|
||||||
private fun DatabaseTransaction.findRequest(requestId: String,
|
private fun DatabaseTransaction.findRequest(requestId: String,
|
||||||
requestStatus: RequestStatus? = null): CertificateSigningRequestEntity? {
|
requestStatus: RequestStatus? = null): CertificateSigningRequestEntity? {
|
||||||
return singleEntityWhere { builder, path ->
|
return uniqueEntityWhere { builder, path ->
|
||||||
val idClause = builder.equal(path.get<String>(CertificateSigningRequestEntity::requestId.name), requestId)
|
val idClause = builder.equal(path.get<String>(CertificateSigningRequestEntity::requestId.name), requestId)
|
||||||
if (requestStatus == null) {
|
if (requestStatus == null) {
|
||||||
idClause
|
idClause
|
||||||
|
@ -12,48 +12,54 @@ package com.r3.corda.networkmanage.common.persistence
|
|||||||
|
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.*
|
import com.r3.corda.networkmanage.common.persistence.entity.*
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.sha256
|
|
||||||
import net.corda.core.internal.DigitalSignatureWithCert
|
import net.corda.core.internal.DigitalSignatureWithCert
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
import net.corda.nodeapi.internal.network.NetworkMapAndSigned
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||||
|
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 getCurrentNetworkMap(): SignedNetworkMap? {
|
override fun getActiveNetworkMap(): NetworkMapEntity? {
|
||||||
return database.transaction {
|
return database.transaction {
|
||||||
getCurrentNetworkMapEntity()?.toSignedNetworkMap()
|
val builder = session.criteriaBuilder
|
||||||
}
|
val query = builder.createQuery(NetworkMapEntity::class.java).run {
|
||||||
}
|
from(NetworkMapEntity::class.java).run {
|
||||||
|
orderBy(builder.desc(get<Long>(NetworkMapEntity::version.name)))
|
||||||
override fun getNetworkParametersOfNetworkMap(): SignedNetworkParameters? {
|
}
|
||||||
return database.transaction {
|
|
||||||
getCurrentNetworkMapEntity()?.let {
|
|
||||||
val netParamsHash = it.toNetworkMap().networkParameterHash
|
|
||||||
getSignedNetworkParameters(netParamsHash) ?:
|
|
||||||
throw IllegalStateException("Current network map is pointing to network parameters that do not exist: $netParamsHash")
|
|
||||||
}
|
}
|
||||||
|
// We want the latest signed entry
|
||||||
|
session.createQuery(query).setMaxResults(1).uniqueResult()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveNetworkMap(signedNetworkMap: SignedNetworkMap) {
|
override fun saveNewActiveNetworkMap(networkMapAndSigned: NetworkMapAndSigned) {
|
||||||
|
val (networkMap, signedNetworkMap) = networkMapAndSigned
|
||||||
database.transaction {
|
database.transaction {
|
||||||
val networkMapEntity = NetworkMapEntity(
|
val networkParametersEntity = checkNotNull(getNetworkParametersEntity(networkMap.networkParameterHash)) {
|
||||||
networkMap = signedNetworkMap.raw.bytes,
|
"Network parameters ${networkMap.networkParameterHash} must be first persisted"
|
||||||
|
}
|
||||||
|
check(networkParametersEntity.isSigned) {
|
||||||
|
"Network parameters ${networkMap.networkParameterHash} are not signed"
|
||||||
|
}
|
||||||
|
session.save(NetworkMapEntity(
|
||||||
|
networkMapBytes = signedNetworkMap.raw.bytes,
|
||||||
signature = signedNetworkMap.sig.bytes,
|
signature = signedNetworkMap.sig.bytes,
|
||||||
certificate = signedNetworkMap.sig.by.encoded
|
certificate = signedNetworkMap.sig.by.encoded,
|
||||||
)
|
networkParameters = networkParametersEntity
|
||||||
session.save(networkMapEntity)
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters? {
|
override fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters? {
|
||||||
return getNetworkParametersEntity(hash.toString())?.let {
|
return database.transaction {
|
||||||
if (it.isSigned) it.toSignedNetworkParameters() else null
|
getNetworkParametersEntity(hash)?.let {
|
||||||
|
if (it.isSigned) it.toSignedNetworkParameters() else null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +71,8 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
val certStatusExpression = get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name)
|
val certStatusExpression = get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name)
|
||||||
.get<CertificateDataEntity>(CertificateSigningRequestEntity::certificateData.name)
|
.get<CertificateDataEntity>(CertificateSigningRequestEntity::certificateData.name)
|
||||||
.get<CertificateStatus>(CertificateDataEntity::certificateStatus.name)
|
.get<CertificateStatus>(CertificateDataEntity::certificateStatus.name)
|
||||||
|
// TODO When revoking certs, all node-infos that point to it must be made non-current. Then this check
|
||||||
|
// 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))
|
select(get<String>(NodeInfoEntity::nodeInfoHash.name)).where(builder.and(certStatusEq, isCurrentNodeInfo))
|
||||||
@ -74,21 +82,21 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveNetworkParameters(networkParameters: NetworkParameters, sig: DigitalSignatureWithCert?): SecureHash {
|
override fun saveNetworkParameters(networkParameters: NetworkParameters, signature: DigitalSignatureWithCert?): SecureHash {
|
||||||
return database.transaction {
|
val serialised = networkParameters.serialize()
|
||||||
val bytes = networkParameters.serialize().bytes
|
val hash = serialised.hash
|
||||||
val hash = bytes.sha256()
|
database.transaction {
|
||||||
session.saveOrUpdate(NetworkParametersEntity(
|
session.saveOrUpdate(NetworkParametersEntity(
|
||||||
parametersBytes = bytes,
|
parametersBytes = serialised.bytes,
|
||||||
parametersHash = hash.toString(),
|
parametersHash = hash.toString(),
|
||||||
signature = sig?.bytes,
|
signature = signature?.bytes,
|
||||||
certificate = sig?.by?.encoded
|
certificate = signature?.by?.encoded
|
||||||
))
|
))
|
||||||
hash
|
|
||||||
}
|
}
|
||||||
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLatestNetworkParameters(): NetworkParameters? {
|
override fun getLatestNetworkParameters(): NetworkParametersEntity? {
|
||||||
return database.transaction {
|
return database.transaction {
|
||||||
val query = session.criteriaBuilder.run {
|
val query = session.criteriaBuilder.run {
|
||||||
createQuery(NetworkParametersEntity::class.java).run {
|
createQuery(NetworkParametersEntity::class.java).run {
|
||||||
@ -98,30 +106,13 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We just want the last entry
|
// We just want the last entry
|
||||||
session.createQuery(query).setMaxResults(1).uniqueResult()?.toNetworkParameters()
|
session.createQuery(query).setMaxResults(1).uniqueResult()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCurrentNetworkMapEntity(): NetworkMapEntity? {
|
private fun DatabaseTransaction.getNetworkParametersEntity(hash: SecureHash): NetworkParametersEntity? {
|
||||||
return database.transaction {
|
return uniqueEntityWhere { builder, path ->
|
||||||
val builder = session.criteriaBuilder
|
builder.equal(path.get<String>(NetworkParametersEntity::parametersHash.name), hash.toString())
|
||||||
val query = builder.createQuery(NetworkMapEntity::class.java).run {
|
|
||||||
from(NetworkMapEntity::class.java).run {
|
|
||||||
// TODO a limit of 1 since we only need the first result
|
|
||||||
where(builder.isNotNull(get<ByteArray?>(NetworkMapEntity::signature.name)))
|
|
||||||
orderBy(builder.desc(get<String>(NetworkMapEntity::version.name)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// We just want the last signed entry
|
|
||||||
session.createQuery(query).resultList.firstOrNull()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getNetworkParametersEntity(parameterHash: String): NetworkParametersEntity? {
|
|
||||||
return database.transaction {
|
|
||||||
singleEntityWhere { builder, path ->
|
|
||||||
builder.equal(path.get<String>(NetworkParametersEntity::parametersHash.name), parameterHash)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,12 +43,13 @@ class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update any [NodeInfoEntity] instance for this CSR as not current.
|
// Update any [NodeInfoEntity] instance for this CSR as not current.
|
||||||
val existingNodeInfo = getEntitiesWhere<NodeInfoEntity> { builder, path ->
|
entitiesWhere<NodeInfoEntity> { builder, path ->
|
||||||
val requestEq = builder.equal(path.get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name), request)
|
val requestEq = builder.equal(path.get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name), request)
|
||||||
val isCurrent = builder.isTrue(path.get<Boolean>(NodeInfoEntity::isCurrent.name))
|
val isCurrent = builder.isTrue(path.get<Boolean>(NodeInfoEntity::isCurrent.name))
|
||||||
builder.and(requestEq, isCurrent)
|
builder.and(requestEq, isCurrent)
|
||||||
|
}.resultStream.use { existingNodeInfos ->
|
||||||
|
existingNodeInfos.forEach { session.merge(it.copy(isCurrent = false)) }
|
||||||
}
|
}
|
||||||
existingNodeInfo.forEach { session.merge(it.copy(isCurrent = false)) }
|
|
||||||
|
|
||||||
val hash = signedNodeInfo.raw.hash
|
val hash = signedNodeInfo.raw.hash
|
||||||
val hashedNodeInfo = NodeInfoEntity(
|
val hashedNodeInfo = NodeInfoEntity(
|
||||||
@ -75,7 +76,7 @@ class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun DatabaseTransaction.getSignedRequestByPublicHash(publicKeyHash: SecureHash): CertificateSigningRequestEntity? {
|
private fun DatabaseTransaction.getSignedRequestByPublicHash(publicKeyHash: SecureHash): CertificateSigningRequestEntity? {
|
||||||
return singleEntityWhere { builder, path ->
|
return uniqueEntityWhere { builder, path ->
|
||||||
val publicKeyEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::publicKeyHash.name), publicKeyHash.toString())
|
val publicKeyEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::publicKeyHash.name), publicKeyHash.toString())
|
||||||
val statusEq = builder.equal(path.get<RequestStatus>(CertificateSigningRequestEntity::status.name), RequestStatus.DONE)
|
val statusEq = builder.equal(path.get<RequestStatus>(CertificateSigningRequestEntity::status.name), RequestStatus.DONE)
|
||||||
builder.and(publicKeyEq, statusEq)
|
builder.and(publicKeyEq, statusEq)
|
||||||
|
@ -26,22 +26,26 @@ class NetworkMapEntity(
|
|||||||
val version: Long? = null,
|
val version: Long? = null,
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "serialized_network_map")
|
@Column(name = "serialized_network_map", nullable = false)
|
||||||
val networkMap: ByteArray,
|
val networkMapBytes: ByteArray,
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "signature")
|
@Column(name = "signature", nullable = false)
|
||||||
val signature: ByteArray,
|
val signature: ByteArray,
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "certificate")
|
@Column(name = "certificate", nullable = false)
|
||||||
val certificate: ByteArray
|
val certificate: ByteArray,
|
||||||
|
|
||||||
|
@ManyToOne(optional = false, fetch = FetchType.EAGER)
|
||||||
|
@JoinColumn(name = "network_parameters")
|
||||||
|
val networkParameters: NetworkParametersEntity
|
||||||
) {
|
) {
|
||||||
fun toNetworkMap(): NetworkMap = networkMap.deserialize()
|
fun toNetworkMap(): NetworkMap = networkMapBytes.deserialize()
|
||||||
|
|
||||||
fun toSignedNetworkMap(): SignedNetworkMap {
|
fun toSignedNetworkMap(): SignedNetworkMap {
|
||||||
return SignedNetworkMap(
|
return SignedNetworkMap(
|
||||||
SerializedBytes(networkMap),
|
SerializedBytes(networkMapBytes),
|
||||||
DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), signature)
|
DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), signature)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ class NetworkParametersEntity(
|
|||||||
val created: Instant = Instant.now(),
|
val created: Instant = Instant.now(),
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "parameters_bytes")
|
@Column(name = "parameters_bytes", nullable = false)
|
||||||
val parametersBytes: ByteArray,
|
val parametersBytes: ByteArray,
|
||||||
|
|
||||||
// Both of the fields below are nullable, because of the way we sign network map data. NetworkParameters can be
|
// Both of the fields below are nullable, because of the way we sign network map data. NetworkParameters can be
|
||||||
|
@ -11,11 +11,12 @@
|
|||||||
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 net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.serialization.serialize
|
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
|
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.SignedNetworkMap
|
import net.corda.nodeapi.internal.network.NetworkMapAndSigned
|
||||||
|
|
||||||
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 {
|
||||||
@ -28,41 +29,45 @@ class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private
|
|||||||
fun signNetworkMap() {
|
fun signNetworkMap() {
|
||||||
// TODO There is no network parameters update process in place yet. We assume that latest parameters are to be used
|
// TODO There is no network parameters update process in place yet. We assume that latest parameters are to be used
|
||||||
// in current network map.
|
// in current network map.
|
||||||
val latestNetworkParameters = networkMapStorage.getLatestNetworkParameters()
|
val latestNetParamsEntity = networkMapStorage.getLatestNetworkParameters()
|
||||||
if (latestNetworkParameters == null) {
|
if (latestNetParamsEntity == null) {
|
||||||
logger.debug("No network parameters present")
|
logger.warn("No network parameters present")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.debug("Fetching current network map parameters...")
|
|
||||||
val currentNetworkParameters = networkMapStorage.getNetworkParametersOfNetworkMap()
|
val latestNetParams = latestNetParamsEntity.toNetworkParameters()
|
||||||
logger.debug("Retrieved network map parameters: $currentNetworkParameters")
|
logger.debug { "Latest network parameters: $latestNetParams" }
|
||||||
if (currentNetworkParameters?.verified() != latestNetworkParameters) {
|
|
||||||
persistSignedNetworkParameters(latestNetworkParameters)
|
if (!latestNetParamsEntity.isSigned) {
|
||||||
|
signAndPersistNetworkParameters(latestNetParams)
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Network map parameters up-to-date. Skipping signing.")
|
logger.debug("Network parameters are already signed")
|
||||||
}
|
}
|
||||||
logger.debug("Fetching current network map...")
|
|
||||||
val currentSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
|
|
||||||
logger.debug("Fetching node info hashes with VALID certificates...")
|
|
||||||
val nodeInfoHashes = networkMapStorage.getActiveNodeInfoHashes()
|
val nodeInfoHashes = networkMapStorage.getActiveNodeInfoHashes()
|
||||||
logger.debug("Retrieved node info hashes: $nodeInfoHashes")
|
logger.debug { "Active node-info hashes:\n${nodeInfoHashes.joinToString("\n")}" }
|
||||||
val newNetworkMap = NetworkMap(nodeInfoHashes, latestNetworkParameters.serialize().hash, null)
|
|
||||||
val serialisedNetworkMap = newNetworkMap.serialize()
|
val currentNetworkMap = networkMapStorage.getActiveNetworkMap()?.toNetworkMap()
|
||||||
if (serialisedNetworkMap != currentSignedNetworkMap?.raw) {
|
if (currentNetworkMap != null) {
|
||||||
logger.info("Signing a new network map: $newNetworkMap")
|
logger.debug { "Current network map: $currentNetworkMap" }
|
||||||
logger.debug("Creating a new signed network map: ${serialisedNetworkMap.hash}")
|
|
||||||
val newSignedNetworkMap = SignedNetworkMap(serialisedNetworkMap, signer.signBytes(serialisedNetworkMap.bytes))
|
|
||||||
networkMapStorage.saveNetworkMap(newSignedNetworkMap)
|
|
||||||
logger.debug("Signed network map saved")
|
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Current network map is up-to-date. Skipping signing.")
|
logger.info("There is currently no network map")
|
||||||
|
}
|
||||||
|
|
||||||
|
val newNetworkMap = NetworkMap(nodeInfoHashes, SecureHash.parse(latestNetParamsEntity.parametersHash), null)
|
||||||
|
logger.debug { "Potential new network map: $newNetworkMap" }
|
||||||
|
|
||||||
|
if (currentNetworkMap != newNetworkMap) {
|
||||||
|
val netNetworkMapAndSigned = NetworkMapAndSigned(newNetworkMap) { signer.signBytes(it.bytes) }
|
||||||
|
networkMapStorage.saveNewActiveNetworkMap(netNetworkMapAndSigned)
|
||||||
|
logger.info("Signed new network map: $newNetworkMap")
|
||||||
|
} else {
|
||||||
|
logger.debug("Current network map is up-to-date")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun persistSignedNetworkParameters(networkParameters: NetworkParameters) {
|
fun signAndPersistNetworkParameters(networkParameters: NetworkParameters) {
|
||||||
logger.info("Signing and persisting network parameters: $networkParameters")
|
networkMapStorage.saveNetworkParameters(networkParameters, signer.signObject(networkParameters).sig)
|
||||||
val digitalSignature = signer.signObject(networkParameters).sig
|
logger.info("Signed network parameters: $networkParameters")
|
||||||
networkMapStorage.saveNetworkParameters(networkParameters, digitalSignature)
|
|
||||||
logger.info("Signed network map parameters saved.")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,9 +59,9 @@ class NetworkManagementServer : Closeable {
|
|||||||
val localNetworkMapSigner = signer?.let { NetworkMapSigner(networkMapStorage, it) }
|
val localNetworkMapSigner = signer?.let { NetworkMapSigner(networkMapStorage, it) }
|
||||||
|
|
||||||
newNetworkParameters?.let {
|
newNetworkParameters?.let {
|
||||||
val netParamsOfNetworkMap = networkMapStorage.getNetworkParametersOfNetworkMap()
|
val netParamsOfNetworkMap = networkMapStorage.getActiveNetworkMap()?.networkParameters
|
||||||
if (netParamsOfNetworkMap == null) {
|
if (netParamsOfNetworkMap == null) {
|
||||||
localNetworkMapSigner?.persistSignedNetworkParameters(it) ?: networkMapStorage.saveNetworkParameters(it, null)
|
localNetworkMapSigner?.signAndPersistNetworkParameters(it) ?: networkMapStorage.saveNetworkParameters(it, null)
|
||||||
} else {
|
} else {
|
||||||
throw UnsupportedOperationException("Network parameters already exist. Updating them is not supported yet.")
|
throw UnsupportedOperationException("Network parameters already exist. Updating them is not supported yet.")
|
||||||
}
|
}
|
||||||
|
@ -52,11 +52,12 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
|
|
||||||
private val networkMapCache: LoadingCache<Boolean, CachedData> = Caffeine.newBuilder()
|
private val networkMapCache: LoadingCache<Boolean, CachedData> = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(config.cacheTimeout, TimeUnit.MILLISECONDS)
|
.expireAfterWrite(config.cacheTimeout, TimeUnit.MILLISECONDS)
|
||||||
.build { _ ->
|
.build {
|
||||||
networkMapStorage.getCurrentNetworkMap()?.let {
|
networkMapStorage.getActiveNetworkMap()?.let {
|
||||||
val networkMap = it.verified()
|
logger.info("Re-publishing network map")
|
||||||
val networkParameters = networkMapStorage.getSignedNetworkParameters(networkMap.networkParameterHash)?.verified()
|
val networkMap = it.toNetworkMap()
|
||||||
CachedData(it, networkMap.nodeInfoHashes.toSet(), networkParameters)
|
val signedNetworkMap = it.toSignedNetworkMap()
|
||||||
|
CachedData(signedNetworkMap, networkMap.nodeInfoHashes.toSet(), it.networkParameters.toNetworkParameters())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +68,7 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
|
|
||||||
private val currentSignedNetworkMap: SignedNetworkMap? get() = networkMapCache.get(true)?.signedNetworkMap
|
private val currentSignedNetworkMap: SignedNetworkMap? get() = networkMapCache.get(true)?.signedNetworkMap
|
||||||
private val currentNodeInfoHashes: Set<SecureHash> get() = networkMapCache.get(true)?.nodeInfoHashes ?: emptySet()
|
private val currentNodeInfoHashes: Set<SecureHash> get() = networkMapCache.get(true)?.nodeInfoHashes ?: emptySet()
|
||||||
private val currentNetworkParameters: NetworkParameters? get() = networkMapCache.get(true)?.currentNetworkParameter
|
private val currentNetworkParameters: NetworkParameters? get() = networkMapCache.get(true)?.networkParameters
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path("publish")
|
@Path("publish")
|
||||||
@ -153,6 +154,7 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
class NetworkMapNotInitialisedException(message: String?) : Exception(message)
|
class NetworkMapNotInitialisedException(message: String?) : Exception(message)
|
||||||
class InvalidPlatformVersionException(message: String?) : Exception(message)
|
class InvalidPlatformVersionException(message: String?) : Exception(message)
|
||||||
|
|
||||||
private data class CachedData(val signedNetworkMap: SignedNetworkMap, val nodeInfoHashes: Set<SecureHash>, val currentNetworkParameter: NetworkParameters?)
|
private data class CachedData(val signedNetworkMap: SignedNetworkMap,
|
||||||
|
val nodeInfoHashes: Set<SecureHash>,
|
||||||
|
val networkParameters: NetworkParameters)
|
||||||
}
|
}
|
||||||
|
@ -80,9 +80,18 @@
|
|||||||
<column name="version" type="BIGINT">
|
<column name="version" type="BIGINT">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="certificate" type="BLOB"/>
|
<column name="certificate" type="BLOB">
|
||||||
<column name="serialized_network_map" type="BLOB"/>
|
<constraints nullable="false"/>
|
||||||
<column name="signature" type="BLOB"/>
|
</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>
|
||||||
</createTable>
|
</createTable>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-6">
|
<changeSet author="R3.Corda" id="1520338500424-6">
|
||||||
@ -92,7 +101,9 @@
|
|||||||
</column>
|
</column>
|
||||||
<column name="certificate" type="BLOB"/>
|
<column name="certificate" type="BLOB"/>
|
||||||
<column name="created" type="TIMESTAMP"/>
|
<column name="created" type="TIMESTAMP"/>
|
||||||
<column name="parameters_bytes" type="BLOB"/>
|
<column name="parameters_bytes" type="BLOB">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
<column name="signature" type="BLOB"/>
|
<column name="signature" type="BLOB"/>
|
||||||
</createTable>
|
</createTable>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
@ -299,4 +310,9 @@
|
|||||||
constraintName="FK_CSR_PN"
|
constraintName="FK_CSR_PN"
|
||||||
referencedColumnNames="id" referencedTableName="private_network"/>
|
referencedColumnNames="id" referencedTableName="private_network"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
|
<changeSet author="R3.Corda" id="1520338500424-38">
|
||||||
|
<addForeignKeyConstraint baseColumnNames="network_parameters" baseTableName="network_map"
|
||||||
|
constraintName="FK_NM_NP"
|
||||||
|
referencedColumnNames="hash" referencedTableName="network_parameters"/>
|
||||||
|
</changeSet>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.r3.corda.networkmanage
|
||||||
|
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.entity.NetworkMapEntity
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.entity.NetworkParametersEntity
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.node.NetworkParameters
|
||||||
|
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
||||||
|
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||||
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
|
|
||||||
|
fun createNetworkParametersEntity(signingCertAndKeyPair: CertificateAndKeyPair = createDevNetworkMapCa(),
|
||||||
|
networkParameters: NetworkParameters = testNetworkParameters()): NetworkParametersEntity {
|
||||||
|
val signedNetParams = signingCertAndKeyPair.sign(networkParameters)
|
||||||
|
return NetworkParametersEntity(
|
||||||
|
parametersHash = signedNetParams.raw.hash.toString(),
|
||||||
|
parametersBytes = signedNetParams.raw.bytes,
|
||||||
|
signature = signedNetParams.sig.bytes,
|
||||||
|
certificate = signedNetParams.sig.by.encoded
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createNetworkMapEntity(signingCertAndKeyPair: CertificateAndKeyPair = createDevNetworkMapCa(),
|
||||||
|
netParamsEntity: NetworkParametersEntity,
|
||||||
|
nodeInfoHashes: List<SecureHash> = emptyList()): NetworkMapEntity {
|
||||||
|
val signedNetMap = signingCertAndKeyPair.sign(NetworkMap(nodeInfoHashes, SecureHash.parse(netParamsEntity.parametersHash), null))
|
||||||
|
return NetworkMapEntity(
|
||||||
|
networkMapBytes = signedNetMap.raw.bytes,
|
||||||
|
signature = signedNetMap.sig.bytes,
|
||||||
|
certificate = signedNetMap.sig.by.encoded,
|
||||||
|
networkParameters = netParamsEntity
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createNetworkMapEntity(signingCertAndKeyPair: CertificateAndKeyPair = createDevNetworkMapCa(),
|
||||||
|
networkParameters: NetworkParameters = testNetworkParameters(),
|
||||||
|
nodeInfoHashes: List<SecureHash> = emptyList()): NetworkMapEntity {
|
||||||
|
val netParamsEntity = createNetworkParametersEntity(signingCertAndKeyPair, networkParameters)
|
||||||
|
return createNetworkMapEntity(signingCertAndKeyPair, netParamsEntity, nodeInfoHashes)
|
||||||
|
}
|
@ -11,10 +11,12 @@
|
|||||||
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 net.corda.core.internal.signWithCert
|
import com.r3.corda.networkmanage.common.persistence.entity.NodeInfoEntity
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
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.NetworkMapAndSigned
|
||||||
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
|
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
|
||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||||
@ -26,7 +28,6 @@ import org.junit.After
|
|||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import kotlin.test.assertEquals
|
|
||||||
|
|
||||||
class PersistentNetworkMapStorageTest : TestBase() {
|
class PersistentNetworkMapStorageTest : TestBase() {
|
||||||
private lateinit var persistence: CordaPersistence
|
private lateinit var persistence: CordaPersistence
|
||||||
@ -35,13 +36,13 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
|||||||
private lateinit var requestStorage: PersistentCertificateSigningRequestStorage
|
private lateinit var requestStorage: PersistentCertificateSigningRequestStorage
|
||||||
|
|
||||||
private lateinit var rootCaCert: X509Certificate
|
private lateinit var rootCaCert: X509Certificate
|
||||||
private lateinit var networkMapCa: CertificateAndKeyPair
|
private lateinit var networkMapCertAndKeyPair: CertificateAndKeyPair
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun startDb() {
|
fun startDb() {
|
||||||
val (rootCa) = createDevIntermediateCaCertPath()
|
val (rootCa) = createDevIntermediateCaCertPath()
|
||||||
rootCaCert = rootCa.certificate
|
rootCaCert = rootCa.certificate
|
||||||
networkMapCa = createDevNetworkMapCa(rootCa)
|
networkMapCertAndKeyPair = createDevNetworkMapCa(rootCa)
|
||||||
persistence = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))
|
persistence = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))
|
||||||
networkMapStorage = PersistentNetworkMapStorage(persistence)
|
networkMapStorage = PersistentNetworkMapStorage(persistence)
|
||||||
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
|
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
|
||||||
@ -54,74 +55,52 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `saveNetworkMap and saveNetworkParameters create current network map and parameters`() {
|
fun `saveNetworkParameters and then saveNewActiveNetworkMap creates the active network map`() {
|
||||||
// given
|
// given
|
||||||
// Create node info.
|
// Create node info.
|
||||||
val (signedNodeInfo) = createValidSignedNodeInfo("Test", requestStorage)
|
val (signedNodeInfo) = createValidSignedNodeInfo("Test", requestStorage)
|
||||||
val nodeInfoHash = nodeInfoStorage.putNodeInfo(signedNodeInfo)
|
val nodeInfoHash = nodeInfoStorage.putNodeInfo(signedNodeInfo)
|
||||||
|
|
||||||
val networkParameters = testNetworkParameters(emptyList())
|
|
||||||
val parametersSignature = networkParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig
|
|
||||||
// Create network parameters
|
// Create network parameters
|
||||||
val networkParametersHash = networkMapStorage.saveNetworkParameters(networkParameters, parametersSignature)
|
val networkParameters = testNetworkParameters(maxTransactionSize = 1234567)
|
||||||
|
val networkParametersSig = networkMapCertAndKeyPair.sign(networkParameters).sig
|
||||||
|
val networkParametersHash = networkMapStorage.saveNetworkParameters(networkParameters, networkParametersSig)
|
||||||
val networkMap = NetworkMap(listOf(nodeInfoHash), networkParametersHash, null)
|
val networkMap = NetworkMap(listOf(nodeInfoHash), networkParametersHash, null)
|
||||||
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
val networkMapAndSigned = NetworkMapAndSigned(networkMap) { networkMapCertAndKeyPair.sign(networkMap).sig }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
networkMapStorage.saveNetworkMap(signedNetworkMap)
|
networkMapStorage.saveNewActiveNetworkMap(networkMapAndSigned)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
|
val activeNetworkMapEntity = networkMapStorage.getActiveNetworkMap()!!
|
||||||
val persistedSignedParameters = networkMapStorage.getNetworkParametersOfNetworkMap()
|
val activeSignedNetworkMap = activeNetworkMapEntity.toSignedNetworkMap()
|
||||||
|
val activeNetworkMap = activeSignedNetworkMap.verifiedNetworkMapCert(rootCaCert)
|
||||||
|
val activeNetworkParametersEntity = activeNetworkMapEntity.networkParameters
|
||||||
|
val activeSignedNetworkParameters = activeNetworkParametersEntity.toSignedNetworkParameters()
|
||||||
|
val activeNetworkParameters = activeSignedNetworkParameters.verifiedNetworkMapCert(rootCaCert)
|
||||||
|
|
||||||
assertEquals(networkParameters, persistedSignedParameters?.verifiedNetworkMapCert(rootCaCert))
|
assertThat(activeNetworkMap).isEqualTo(networkMap)
|
||||||
assertEquals(parametersSignature, persistedSignedParameters?.sig)
|
assertThat(activeSignedNetworkMap.sig).isEqualTo(networkMapAndSigned.signed.sig)
|
||||||
assertEquals(signedNetworkMap.sig, persistedSignedNetworkMap?.sig)
|
assertThat(activeNetworkParameters).isEqualTo(networkParameters)
|
||||||
assertEquals(signedNetworkMap.verifiedNetworkMapCert(rootCaCert), persistedSignedNetworkMap?.verifiedNetworkMapCert(rootCaCert))
|
assertThat(activeSignedNetworkParameters.sig).isEqualTo(networkParametersSig)
|
||||||
assertEquals(signedNetworkMap.verifiedNetworkMapCert(rootCaCert).networkParameterHash, persistedSignedParameters?.raw?.hash)
|
assertThat(SecureHash.parse(activeNetworkParametersEntity.parametersHash))
|
||||||
|
.isEqualTo(activeNetworkMap.networkParameterHash)
|
||||||
|
.isEqualTo(networkParametersHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getLatestNetworkParameters returns last inserted`() {
|
fun `getLatestNetworkParameters returns last inserted`() {
|
||||||
val params1 = testNetworkParameters(emptyList(), minimumPlatformVersion = 1)
|
val params1 = testNetworkParameters(minimumPlatformVersion = 1)
|
||||||
val params2 = testNetworkParameters(emptyList(), minimumPlatformVersion = 2)
|
val params2 = testNetworkParameters(minimumPlatformVersion = 2)
|
||||||
// given
|
networkMapStorage.saveNetworkParameters(params1, networkMapCertAndKeyPair.sign(params1).sig)
|
||||||
networkMapStorage.saveNetworkParameters(params1, params1.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig)
|
|
||||||
// We may have not signed them yet.
|
// We may have not signed them yet.
|
||||||
networkMapStorage.saveNetworkParameters(params2, null)
|
networkMapStorage.saveNetworkParameters(params2, null)
|
||||||
|
|
||||||
// when
|
assertThat(networkMapStorage.getLatestNetworkParameters()?.toNetworkParameters()).isEqualTo(params2)
|
||||||
val latest = networkMapStorage.getLatestNetworkParameters()?.minimumPlatformVersion
|
|
||||||
// then
|
|
||||||
assertEquals(2, latest)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getNetworkParametersOfNetworkMap returns current network map parameters`() {
|
fun `getValidNodeInfoHashes returns only for current node-infos`() {
|
||||||
// given
|
|
||||||
// Create network parameters
|
|
||||||
val testParameters1 = testNetworkParameters(emptyList())
|
|
||||||
val networkParametersHash = networkMapStorage.saveNetworkParameters(testParameters1, testParameters1.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig)
|
|
||||||
// Create empty network map
|
|
||||||
|
|
||||||
// Sign network map making it current network map
|
|
||||||
val networkMap = NetworkMap(emptyList(), networkParametersHash, null)
|
|
||||||
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
|
||||||
networkMapStorage.saveNetworkMap(signedNetworkMap)
|
|
||||||
|
|
||||||
// Create new network parameters
|
|
||||||
val testParameters2 = testNetworkParameters(emptyList(), minimumPlatformVersion = 2)
|
|
||||||
networkMapStorage.saveNetworkParameters(testParameters2, testParameters2.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig)
|
|
||||||
|
|
||||||
// when
|
|
||||||
val result = networkMapStorage.getNetworkParametersOfNetworkMap()?.verifiedNetworkMapCert(rootCaCert)
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertEquals(1, result?.minimumPlatformVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `getValidNodeInfoHashes returns only valid and signed node info hashes`() {
|
|
||||||
// given
|
// given
|
||||||
// Create node infos.
|
// Create node infos.
|
||||||
val (signedNodeInfoA) = createValidSignedNodeInfo("TestA", requestStorage)
|
val (signedNodeInfoA) = createValidSignedNodeInfo("TestA", requestStorage)
|
||||||
@ -131,19 +110,15 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
|||||||
val nodeInfoHashA = nodeInfoStorage.putNodeInfo(signedNodeInfoA)
|
val nodeInfoHashA = nodeInfoStorage.putNodeInfo(signedNodeInfoA)
|
||||||
val nodeInfoHashB = nodeInfoStorage.putNodeInfo(signedNodeInfoB)
|
val nodeInfoHashB = nodeInfoStorage.putNodeInfo(signedNodeInfoB)
|
||||||
|
|
||||||
// Create network parameters
|
persistence.transaction {
|
||||||
val testParameters = testNetworkParameters(emptyList())
|
val entity = session.find(NodeInfoEntity::class.java, nodeInfoHashA.toString())
|
||||||
val networkParametersHash = networkMapStorage.saveNetworkParameters(testParameters, testParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig)
|
session.merge(entity.copy(isCurrent = false))
|
||||||
val networkMap = NetworkMap(listOf(nodeInfoHashA), networkParametersHash, null)
|
}
|
||||||
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
|
||||||
|
|
||||||
// Sign network map
|
|
||||||
networkMapStorage.saveNetworkMap(signedNetworkMap)
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val validNodeInfoHash = networkMapStorage.getActiveNodeInfoHashes()
|
val validNodeInfoHashes = networkMapStorage.getActiveNodeInfoHashes()
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(validNodeInfoHash).containsOnly(nodeInfoHashA, nodeInfoHashB)
|
assertThat(validNodeInfoHashes).containsOnly(nodeInfoHashB)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,18 +13,16 @@ 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.createNetworkMapEntity
|
||||||
|
import com.r3.corda.networkmanage.createNetworkParametersEntity
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.sha256
|
|
||||||
import net.corda.core.internal.DigitalSignatureWithCert
|
import net.corda.core.internal.DigitalSignatureWithCert
|
||||||
import net.corda.core.internal.signWithCert
|
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||||
import net.corda.nodeapi.internal.network.NetworkMap
|
import net.corda.nodeapi.internal.network.NetworkMapAndSigned
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
||||||
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
|
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
@ -39,13 +37,13 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
private lateinit var networkMapSigner: NetworkMapSigner
|
private lateinit var networkMapSigner: NetworkMapSigner
|
||||||
|
|
||||||
private lateinit var rootCaCert: X509Certificate
|
private lateinit var rootCaCert: X509Certificate
|
||||||
private lateinit var networkMapCa: CertificateAndKeyPair
|
private lateinit var signingCertAndKeyPair: CertificateAndKeyPair
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
val (rootCa) = createDevIntermediateCaCertPath()
|
val (rootCa) = createDevIntermediateCaCertPath()
|
||||||
rootCaCert = rootCa.certificate
|
rootCaCert = rootCa.certificate
|
||||||
networkMapCa = createDevNetworkMapCa(rootCa)
|
signingCertAndKeyPair = createDevNetworkMapCa(rootCa)
|
||||||
signer = mock()
|
signer = mock()
|
||||||
networkMapStorage = mock()
|
networkMapStorage = mock()
|
||||||
networkMapSigner = NetworkMapSigner(networkMapStorage, signer)
|
networkMapSigner = NetworkMapSigner(networkMapStorage, signer)
|
||||||
@ -54,20 +52,20 @@ 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 signedNodeInfoHashes = listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256())
|
val nodeInfoHashes = listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256())
|
||||||
val currentParameters = testNetworkParameters(emptyList(), minimumPlatformVersion = 1)
|
val activeNetParams = testNetworkParameters(minimumPlatformVersion = 1)
|
||||||
val latestNetworkParameters = testNetworkParameters(emptyList(), minimumPlatformVersion = 2)
|
val latestNetParams = testNetworkParameters(minimumPlatformVersion = 2)
|
||||||
val networkMap = NetworkMap(signedNodeInfoHashes, currentParameters.serialize().hash, null)
|
val activeNetParamsEntity = createNetworkParametersEntity(signingCertAndKeyPair, activeNetParams)
|
||||||
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
val latestNetParamsEntity = createNetworkParametersEntity(signingCertAndKeyPair, latestNetParams)
|
||||||
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(signedNetworkMap)
|
val netMapEntity = createNetworkMapEntity(signingCertAndKeyPair, activeNetParamsEntity, nodeInfoHashes)
|
||||||
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(signedNodeInfoHashes)
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(latestNetParamsEntity)
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(latestNetworkParameters)
|
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(nodeInfoHashes)
|
||||||
whenever(networkMapStorage.getNetworkParametersOfNetworkMap()).thenReturn(currentParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate))
|
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(netMapEntity)
|
||||||
whenever(signer.signBytes(any())).then {
|
whenever(signer.signBytes(any())).then {
|
||||||
DigitalSignatureWithCert(networkMapCa.certificate, Crypto.doSign(networkMapCa.keyPair.private, it.arguments[0] as ByteArray))
|
DigitalSignatureWithCert(signingCertAndKeyPair.certificate, Crypto.doSign(signingCertAndKeyPair.keyPair.private, it.arguments[0] as ByteArray))
|
||||||
}
|
}
|
||||||
whenever(signer.signObject(latestNetworkParameters)).then {
|
whenever(signer.signObject(latestNetParams)).then {
|
||||||
val serialised = latestNetworkParameters.serialize()
|
val serialised = latestNetParams.serialize()
|
||||||
SignedNetworkParameters(serialised, signer.signBytes(serialised.bytes))
|
SignedNetworkParameters(serialised, signer.signBytes(serialised.bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,48 +76,43 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
// Verify networkMapStorage calls
|
// Verify networkMapStorage calls
|
||||||
verify(networkMapStorage).getActiveNodeInfoHashes()
|
verify(networkMapStorage).getActiveNodeInfoHashes()
|
||||||
verify(networkMapStorage).getLatestNetworkParameters()
|
verify(networkMapStorage).getLatestNetworkParameters()
|
||||||
verify(networkMapStorage).getNetworkParametersOfNetworkMap()
|
argumentCaptor<NetworkMapAndSigned>().apply {
|
||||||
argumentCaptor<SignedNetworkMap>().apply {
|
verify(networkMapStorage).saveNewActiveNetworkMap(capture())
|
||||||
verify(networkMapStorage).saveNetworkMap(capture())
|
val capturedNetworkMap = firstValue.networkMap
|
||||||
val capturedNetworkMap = firstValue.verifiedNetworkMapCert(rootCaCert)
|
assertEquals(latestNetParams.serialize().hash, capturedNetworkMap.networkParameterHash)
|
||||||
assertEquals(latestNetworkParameters.serialize().hash, capturedNetworkMap.networkParameterHash)
|
assertThat(capturedNetworkMap.nodeInfoHashes).isEqualTo(nodeInfoHashes)
|
||||||
assertEquals(signedNodeInfoHashes.size, capturedNetworkMap.nodeInfoHashes.size)
|
|
||||||
assertThat(capturedNetworkMap.nodeInfoHashes).containsAll(signedNodeInfoHashes)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
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 networkParameters = testNetworkParameters(emptyList())
|
val netParamsEntity = createNetworkParametersEntity(signingCertAndKeyPair)
|
||||||
val networkMapParametersHash = networkParameters.serialize().bytes.sha256()
|
val netMapEntity = createNetworkMapEntity(signingCertAndKeyPair, netParamsEntity, emptyList())
|
||||||
val networkMap = NetworkMap(emptyList(), networkMapParametersHash, null)
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(netParamsEntity)
|
||||||
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
|
||||||
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(signedNetworkMap)
|
|
||||||
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList())
|
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList())
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
|
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(netMapEntity)
|
||||||
whenever(networkMapStorage.getNetworkParametersOfNetworkMap()).thenReturn(networkParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate))
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
networkMapSigner.signNetworkMap()
|
networkMapSigner.signNetworkMap()
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// Verify networkMapStorage is not called
|
// Verify networkMapStorage is not called
|
||||||
verify(networkMapStorage, never()).saveNetworkMap(any())
|
verify(networkMapStorage, never()).saveNewActiveNetworkMap(any())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `signNetworkMap creates a new network map if there is no current network map`() {
|
fun `signNetworkMap creates a new network map if there is no current network map`() {
|
||||||
// given
|
// given
|
||||||
val networkParameters = testNetworkParameters(emptyList())
|
val netParams = testNetworkParameters()
|
||||||
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(null)
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(createNetworkParametersEntity(signingCertAndKeyPair, netParams))
|
||||||
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList())
|
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList())
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
|
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(null)
|
||||||
whenever(signer.signBytes(any())).then {
|
whenever(signer.signBytes(any())).then {
|
||||||
DigitalSignatureWithCert(networkMapCa.certificate, Crypto.doSign(networkMapCa.keyPair.private, it.arguments[0] as ByteArray))
|
DigitalSignatureWithCert(signingCertAndKeyPair.certificate, Crypto.doSign(signingCertAndKeyPair.keyPair.private, it.arguments[0] as ByteArray))
|
||||||
}
|
}
|
||||||
whenever(signer.signObject(networkParameters)).then {
|
whenever(signer.signObject(netParams)).then {
|
||||||
val serialised = networkParameters.serialize()
|
val serialised = netParams.serialize()
|
||||||
SignedNetworkParameters(serialised, signer.signBytes(serialised.bytes))
|
SignedNetworkParameters(serialised, signer.signBytes(serialised.bytes))
|
||||||
}
|
}
|
||||||
// when
|
// when
|
||||||
@ -129,10 +122,9 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
// Verify networkMapStorage calls
|
// Verify networkMapStorage calls
|
||||||
verify(networkMapStorage).getActiveNodeInfoHashes()
|
verify(networkMapStorage).getActiveNodeInfoHashes()
|
||||||
verify(networkMapStorage).getLatestNetworkParameters()
|
verify(networkMapStorage).getLatestNetworkParameters()
|
||||||
argumentCaptor<SignedNetworkMap>().apply {
|
argumentCaptor<NetworkMapAndSigned>().apply {
|
||||||
verify(networkMapStorage).saveNetworkMap(capture())
|
verify(networkMapStorage).saveNewActiveNetworkMap(capture())
|
||||||
val networkMap = firstValue.verifiedNetworkMapCert(rootCaCert)
|
assertEquals(netParams.serialize().hash, firstValue.networkMap.networkParameterHash)
|
||||||
assertEquals(networkParameters.serialize().hash, networkMap.networkParameterHash)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,12 @@
|
|||||||
|
|
||||||
package com.r3.corda.networkmanage.doorman.webservice
|
package com.r3.corda.networkmanage.doorman.webservice
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.any
|
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
import com.nhaarman.mockito_kotlin.mock
|
||||||
import com.nhaarman.mockito_kotlin.times
|
import com.nhaarman.mockito_kotlin.times
|
||||||
import com.nhaarman.mockito_kotlin.verify
|
import com.nhaarman.mockito_kotlin.verify
|
||||||
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.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.SecureHash.Companion.randomSHA256
|
import net.corda.core.crypto.SecureHash.Companion.randomSHA256
|
||||||
@ -23,14 +23,12 @@ import net.corda.core.identity.CordaX500Name
|
|||||||
import net.corda.core.internal.checkOkResponse
|
import net.corda.core.internal.checkOkResponse
|
||||||
import net.corda.core.internal.openHttpConnection
|
import net.corda.core.internal.openHttpConnection
|
||||||
import net.corda.core.internal.responseAs
|
import net.corda.core.internal.responseAs
|
||||||
import net.corda.core.internal.signWithCert
|
|
||||||
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.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||||
import net.corda.nodeapi.internal.network.NetworkMap
|
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
||||||
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
|
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
|
||||||
@ -54,7 +52,7 @@ class NetworkMapWebServiceTest {
|
|||||||
val testSerialization = SerializationEnvironmentRule(true)
|
val testSerialization = SerializationEnvironmentRule(true)
|
||||||
|
|
||||||
private lateinit var rootCaCert: X509Certificate
|
private lateinit var rootCaCert: X509Certificate
|
||||||
private lateinit var networkMapCa: CertificateAndKeyPair
|
private lateinit var signingCertAndKeyPair: CertificateAndKeyPair
|
||||||
|
|
||||||
private val testNetworkMapConfig = NetworkMapConfig(10.seconds.toMillis(), 10.seconds.toMillis())
|
private val testNetworkMapConfig = NetworkMapConfig(10.seconds.toMillis(), 10.seconds.toMillis())
|
||||||
|
|
||||||
@ -62,16 +60,15 @@ class NetworkMapWebServiceTest {
|
|||||||
fun init() {
|
fun init() {
|
||||||
val (rootCa) = createDevIntermediateCaCertPath()
|
val (rootCa) = createDevIntermediateCaCertPath()
|
||||||
rootCaCert = rootCa.certificate
|
rootCaCert = rootCa.certificate
|
||||||
networkMapCa = createDevNetworkMapCa(rootCa)
|
signingCertAndKeyPair = createDevNetworkMapCa(rootCa)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `submit nodeInfo`() {
|
fun `submit nodeInfo`() {
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
val networkParameter = testNetworkParameters(emptyList()).signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity())
|
||||||
on { getSignedNetworkParameters(any()) }.thenReturn(networkParameter)
|
|
||||||
on { getCurrentNetworkMap() }.thenReturn(NetworkMap(emptyList(), networkParameter.raw.hash, null).signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create node info.
|
// Create node info.
|
||||||
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
|
||||||
|
|
||||||
@ -86,9 +83,7 @@ class NetworkMapWebServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `submit old nodeInfo`() {
|
fun `submit old nodeInfo`() {
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
val networkParameter = testNetworkParameters(emptyList(), minimumPlatformVersion = 2).signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity(networkParameters = testNetworkParameters(minimumPlatformVersion = 2)))
|
||||||
on { getSignedNetworkParameters(any()) }.thenReturn(networkParameter)
|
|
||||||
on { getCurrentNetworkMap() }.thenReturn(NetworkMap(emptyList(), networkParameter.raw.hash, null).signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate))
|
|
||||||
}
|
}
|
||||||
// Create node info.
|
// Create node info.
|
||||||
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
||||||
@ -102,9 +97,9 @@ class NetworkMapWebServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `submit nodeInfo when no network parameters`() {
|
fun `submit nodeInfo when no network map`() {
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getNetworkParametersOfNetworkMap() }.thenReturn(null)
|
on { getActiveNetworkMap() }.thenReturn(null)
|
||||||
}
|
}
|
||||||
// Create node info.
|
// Create node info.
|
||||||
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
||||||
@ -119,18 +114,19 @@ class NetworkMapWebServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get network map`() {
|
fun `get network map`() {
|
||||||
val networkMap = NetworkMap(listOf(randomSHA256(), randomSHA256()), randomSHA256(), null)
|
val networkMapEntity = createNetworkMapEntity(
|
||||||
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
signingCertAndKeyPair = signingCertAndKeyPair,
|
||||||
|
nodeInfoHashes = listOf(randomSHA256(), randomSHA256()))
|
||||||
|
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getCurrentNetworkMap() }.thenReturn(signedNetworkMap)
|
on { getActiveNetworkMap() }.thenReturn(networkMapEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
|
||||||
it.start()
|
it.start()
|
||||||
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
||||||
verify(networkMapStorage, times(1)).getCurrentNetworkMap()
|
verify(networkMapStorage, times(1)).getActiveNetworkMap()
|
||||||
assertEquals(signedNetworkMapResponse.verifiedNetworkMapCert(rootCaCert), networkMap)
|
assertEquals(signedNetworkMapResponse.verifiedNetworkMapCert(rootCaCert), networkMapEntity.toNetworkMap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,10 +140,8 @@ class NetworkMapWebServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mock network map storage
|
// Mock network map storage
|
||||||
val networkMap = NetworkMap(listOf(nodeInfoHash), randomSHA256(), null)
|
|
||||||
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getCurrentNetworkMap() }.thenReturn(signedNetworkMap)
|
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity(nodeInfoHashes = listOf(nodeInfoHash)))
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(nodeInfoStorage, networkMapStorage, testNetworkMapConfig)).use {
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(nodeInfoStorage, networkMapStorage, testNetworkMapConfig)).use {
|
||||||
@ -165,7 +159,7 @@ class NetworkMapWebServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `get network parameters`() {
|
fun `get network parameters`() {
|
||||||
val networkParameters = testNetworkParameters(emptyList())
|
val networkParameters = testNetworkParameters(emptyList())
|
||||||
val signedNetworkParameters = networkParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
val signedNetworkParameters = signingCertAndKeyPair.sign(networkParameters)
|
||||||
val networkParametersHash = signedNetworkParameters.raw.hash
|
val networkParametersHash = signedNetworkParameters.raw.hash
|
||||||
|
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
@ -177,7 +171,7 @@ class NetworkMapWebServiceTest {
|
|||||||
val netParamsResponse = it.doGet<SignedNetworkParameters>("network-parameters/$networkParametersHash")
|
val netParamsResponse = it.doGet<SignedNetworkParameters>("network-parameters/$networkParametersHash")
|
||||||
verify(networkMapStorage, times(1)).getSignedNetworkParameters(networkParametersHash)
|
verify(networkMapStorage, times(1)).getSignedNetworkParameters(networkParametersHash)
|
||||||
assertThat(netParamsResponse.verified()).isEqualTo(networkParameters)
|
assertThat(netParamsResponse.verified()).isEqualTo(networkParameters)
|
||||||
assertThat(netParamsResponse.sig.by).isEqualTo(networkMapCa.certificate)
|
assertThat(netParamsResponse.sig.by).isEqualTo(signingCertAndKeyPair.certificate)
|
||||||
assertThatExceptionOfType(IOException::class.java)
|
assertThatExceptionOfType(IOException::class.java)
|
||||||
.isThrownBy { it.doGet<SignedNetworkParameters>("network-parameters/${randomSHA256()}") }
|
.isThrownBy { it.doGet<SignedNetworkParameters>("network-parameters/${randomSHA256()}") }
|
||||||
.withMessageContaining("404")
|
.withMessageContaining("404")
|
||||||
@ -198,4 +192,4 @@ class NetworkMapWebServiceTest {
|
|||||||
private inline fun <reified T : Any> NetworkManagementWebServer.doGet(path: String): T {
|
private inline fun <reified T : Any> NetworkManagementWebServer.doGet(path: String): T {
|
||||||
return URL("http://$hostAndPort/network-map/$path").openHttpConnection().responseAs()
|
return URL("http://$hostAndPort/network-map/$path").openHttpConnection().responseAs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,7 @@ import net.corda.core.CordaOID
|
|||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.crypto.SignatureScheme
|
import net.corda.core.crypto.SignatureScheme
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.internal.CertRole
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.internal.reader
|
|
||||||
import net.corda.core.internal.uncheckedCast
|
|
||||||
import net.corda.core.internal.writer
|
|
||||||
import net.corda.core.utilities.days
|
import net.corda.core.utilities.days
|
||||||
import net.corda.core.utilities.millis
|
import net.corda.core.utilities.millis
|
||||||
import org.bouncycastle.asn1.*
|
import org.bouncycastle.asn1.*
|
||||||
@ -425,4 +422,6 @@ enum class CertificateType(val keyUsage: KeyUsage, vararg val purposes: KeyPurpo
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class CertificateAndKeyPair(val certificate: X509Certificate, val keyPair: KeyPair)
|
data class CertificateAndKeyPair(val certificate: X509Certificate, val keyPair: KeyPair) {
|
||||||
|
fun <T : Any> sign(obj: T): SignedDataWithCert<T> = obj.signWithCert(keyPair.private, certificate)
|
||||||
|
}
|
||||||
|
@ -12,10 +12,13 @@ package net.corda.nodeapi.internal.network
|
|||||||
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.internal.CertRole
|
import net.corda.core.internal.CertRole
|
||||||
|
import net.corda.core.internal.DigitalSignatureWithCert
|
||||||
import net.corda.core.internal.SignedDataWithCert
|
import net.corda.core.internal.SignedDataWithCert
|
||||||
|
import net.corda.core.internal.signWithCert
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
|
import net.corda.core.serialization.SerializedBytes
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@ -63,3 +66,10 @@ fun <T : Any> SignedDataWithCert<T>.verifiedNetworkMapCert(rootCert: X509Certifi
|
|||||||
X509Utilities.validateCertificateChain(rootCert, sig.by, rootCert)
|
X509Utilities.validateCertificateChain(rootCert, sig.by, rootCert)
|
||||||
return verified()
|
return verified()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NetworkMapAndSigned private constructor(val networkMap: NetworkMap, val signed: SignedNetworkMap) {
|
||||||
|
constructor(networkMap: NetworkMap, signer: (SerializedBytes<NetworkMap>) -> DigitalSignatureWithCert) : this(networkMap, networkMap.signWithCert(signer))
|
||||||
|
constructor(signed: SignedNetworkMap) : this(signed.verified(), signed)
|
||||||
|
operator fun component1(): NetworkMap = networkMap
|
||||||
|
operator fun component2(): SignedNetworkMap = signed
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user