mirror of
https://github.com/corda/corda.git
synced 2024-12-29 09:18:58 +00:00
ENT-1524 & ENT-1358: Cleaned up doorman db schema (#565)
* Renamed tables and constraints to have name < 30 characters * Using AttributeConverters were possible for custom types * NodeInfoEntity has relationship to accepted NetworkParametersEntity, not the hash * Improved logging in the node
This commit is contained in:
parent
34d5f72f51
commit
ff4bbaf63f
@ -107,8 +107,7 @@ class NetworkParametersUpdateTest {
|
|||||||
description = "Very Important Update",
|
description = "Very Important Update",
|
||||||
updateDeadline = updateDeadline
|
updateDeadline = updateDeadline
|
||||||
)
|
)
|
||||||
)
|
))
|
||||||
)
|
|
||||||
|
|
||||||
updates.expectEvents(isStrict = true) {
|
updates.expectEvents(isStrict = true) {
|
||||||
sequence(
|
sequence(
|
||||||
|
@ -40,6 +40,7 @@ interface NetworkMapStorage {
|
|||||||
/**
|
/**
|
||||||
* 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]
|
||||||
*/
|
*/
|
||||||
|
// TODO "Active" is the wrong word here
|
||||||
fun getActiveNodeInfoHashes(): List<SecureHash>
|
fun getActiveNodeInfoHashes(): List<SecureHash>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
package com.r3.corda.networkmanage.common.persistence
|
package com.r3.corda.networkmanage.common.persistence
|
||||||
|
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.entity.NetworkParametersEntity
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
||||||
@ -33,11 +34,10 @@ interface NodeInfoStorage {
|
|||||||
fun getNodeInfo(nodeInfoHash: SecureHash): SignedNodeInfo?
|
fun getNodeInfo(nodeInfoHash: SecureHash): SignedNodeInfo?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve latest accepted parameters hash for nodeInfo with given hash.
|
* Returns the network parameters that the node has accepted or null if couldn't find node info with given hash or
|
||||||
* @return Hash of network parameters that the node has accepted or null if couldn't find node info with given hash or
|
|
||||||
* there is no information on accepted parameters hash stored for this entity
|
* there is no information on accepted parameters hash stored for this entity
|
||||||
*/
|
*/
|
||||||
fun getAcceptedParametersUpdateHash(nodeInfoHash: SecureHash): SecureHash?
|
fun getAcceptedNetworkParameters(nodeInfoHash: SecureHash): NetworkParametersEntity?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [nodeInfoAndSigned] is keyed by the public key, old node info with the same public key will be replaced by the new node info.
|
* The [nodeInfoAndSigned] is keyed by the public key, old node info with the same public key will be replaced by the new node info.
|
||||||
|
@ -3,7 +3,6 @@ package com.r3.corda.networkmanage.common.persistence
|
|||||||
import com.r3.corda.networkmanage.common.persistence.entity.CertificateDataEntity
|
import com.r3.corda.networkmanage.common.persistence.entity.CertificateDataEntity
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.CertificateRevocationListEntity
|
import com.r3.corda.networkmanage.common.persistence.entity.CertificateRevocationListEntity
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.CertificateRevocationRequestEntity
|
import com.r3.corda.networkmanage.common.persistence.entity.CertificateRevocationRequestEntity
|
||||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
|
||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
|
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
@ -21,10 +20,7 @@ class PersistentCertificateRevocationListStorage(private val database: CordaPers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We just want the last signed entry
|
// We just want the last signed entry
|
||||||
val crlEntity = session.createQuery(query).setMaxResults(1).uniqueResult()
|
session.createQuery(query).setMaxResults(1).uniqueResult()?.crl
|
||||||
crlEntity?.let {
|
|
||||||
X509CertificateFactory().delegate.generateCRL(crlEntity.crlBytes.inputStream()) as X509CRL
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +30,7 @@ class PersistentCertificateRevocationListStorage(private val database: CordaPers
|
|||||||
revokeCertificate(it.serialNumber, revokedAt, this)
|
revokeCertificate(it.serialNumber, revokedAt, this)
|
||||||
}
|
}
|
||||||
session.save(CertificateRevocationListEntity(
|
session.save(CertificateRevocationListEntity(
|
||||||
crlBytes = crl.encoded,
|
crl = crl,
|
||||||
crlIssuer = crlIssuer,
|
crlIssuer = crlIssuer,
|
||||||
signedBy = signedBy,
|
signedBy = signedBy,
|
||||||
modifiedAt = Instant.now()
|
modifiedAt = Instant.now()
|
||||||
|
@ -51,7 +51,7 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
|
|||||||
session.merge(certificateSigningRequest)
|
session.merge(certificateSigningRequest)
|
||||||
val certificateDataEntity = CertificateDataEntity(
|
val certificateDataEntity = CertificateDataEntity(
|
||||||
certificateStatus = CertificateStatus.VALID,
|
certificateStatus = CertificateStatus.VALID,
|
||||||
certificatePathBytes = certPath.encoded,
|
certPath = certPath,
|
||||||
certificateSigningRequest = certificateSigningRequest,
|
certificateSigningRequest = certificateSigningRequest,
|
||||||
certificateSerialNumber = certPath.x509Certificates.first().serialNumber)
|
certificateSerialNumber = certPath.x509Certificates.first().serialNumber)
|
||||||
session.persist(certificateDataEntity)
|
session.persist(certificateDataEntity)
|
||||||
@ -71,7 +71,7 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
|
|||||||
requestId = requestId,
|
requestId = requestId,
|
||||||
legalName = legalNameOrRejectMessage as? CordaX500Name,
|
legalName = legalNameOrRejectMessage as? CordaX500Name,
|
||||||
publicKeyHash = toSupportedPublicKey(request.subjectPublicKeyInfo).hashString(),
|
publicKeyHash = toSupportedPublicKey(request.subjectPublicKeyInfo).hashString(),
|
||||||
requestBytes = request.encoded,
|
request = request,
|
||||||
remark = legalNameOrRejectMessage as? String,
|
remark = legalNameOrRejectMessage as? String,
|
||||||
modifiedBy = CertificateSigningRequestStorage.DOORMAN_SIGNATURE,
|
modifiedBy = CertificateSigningRequestStorage.DOORMAN_SIGNATURE,
|
||||||
status = if (legalNameOrRejectMessage is CordaX500Name) RequestStatus.NEW else RequestStatus.REJECTED
|
status = if (legalNameOrRejectMessage is CordaX500Name) RequestStatus.NEW else RequestStatus.REJECTED
|
||||||
|
@ -15,12 +15,11 @@ 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.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.nodeapi.internal.network.ParametersUpdate
|
|
||||||
import net.corda.nodeapi.internal.network.NetworkMapAndSigned
|
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 java.time.Instant
|
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
|
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database implementation of the [NetworkMapStorage] interface
|
* Database implementation of the [NetworkMapStorage] interface
|
||||||
@ -49,9 +48,9 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
"Network parameters ${networkMap.networkParameterHash} are not signed"
|
"Network parameters ${networkMap.networkParameterHash} are not signed"
|
||||||
}
|
}
|
||||||
session.save(NetworkMapEntity(
|
session.save(NetworkMapEntity(
|
||||||
networkMapBytes = signedNetworkMap.raw.bytes,
|
networkMap = networkMap,
|
||||||
signature = signedNetworkMap.sig.bytes,
|
signature = signedNetworkMap.sig.bytes,
|
||||||
certificate = signedNetworkMap.sig.by.encoded,
|
certificate = signedNetworkMap.sig.by,
|
||||||
networkParameters = networkParametersEntity
|
networkParameters = networkParametersEntity
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -85,21 +84,22 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun saveNetworkParameters(networkParameters: NetworkParameters, signature: DigitalSignatureWithCert?): SecureHash {
|
override fun saveNetworkParameters(networkParameters: NetworkParameters, signature: DigitalSignatureWithCert?): SecureHash {
|
||||||
val serialised = networkParameters.serialize()
|
val serialized = networkParameters.serialize()
|
||||||
val hash = serialised.hash
|
signature?.verify(serialized)
|
||||||
|
val hash = serialized.hash
|
||||||
database.transaction {
|
database.transaction {
|
||||||
val entity = getNetworkParametersEntity(hash)
|
val entity = getNetworkParametersEntity(hash)
|
||||||
val newNetworkParamsEntity = if (entity != null) {
|
val newNetworkParamsEntity = if (entity != null) {
|
||||||
entity.copy(
|
entity.copy(
|
||||||
signature = signature?.bytes,
|
signature = signature?.bytes,
|
||||||
certificate = signature?.by?.encoded
|
certificate = signature?.by
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
NetworkParametersEntity(
|
NetworkParametersEntity(
|
||||||
parametersBytes = serialised.bytes,
|
networkParameters = networkParameters,
|
||||||
parametersHash = hash.toString(),
|
hash = hash.toString(),
|
||||||
signature = signature?.bytes,
|
signature = signature?.bytes,
|
||||||
certificate = signature?.by?.encoded
|
certificate = signature?.by
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
session.merge(newNetworkParamsEntity)
|
session.merge(newNetworkParamsEntity)
|
||||||
@ -139,7 +139,7 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
|
|
||||||
override fun getParametersUpdate(): ParametersUpdateEntity? {
|
override fun getParametersUpdate(): ParametersUpdateEntity? {
|
||||||
return database.transaction {
|
return database.transaction {
|
||||||
val currentParametersHash = getActiveNetworkMap()?.toNetworkMap()?.networkParameterHash
|
val currentParametersHash = getActiveNetworkMap()?.networkParameters?.hash
|
||||||
val latestParameters = getLatestNetworkParameters()
|
val latestParameters = getLatestNetworkParameters()
|
||||||
val criteria = session.criteriaBuilder.createQuery(ParametersUpdateEntity::class.java)
|
val criteria = session.criteriaBuilder.createQuery(ParametersUpdateEntity::class.java)
|
||||||
val root = criteria.from(ParametersUpdateEntity::class.java)
|
val root = criteria.from(ParametersUpdateEntity::class.java)
|
||||||
@ -150,7 +150,7 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
"ParametersUpdate doesn't correspond to latest network parameters"
|
"ParametersUpdate doesn't correspond to latest network parameters"
|
||||||
}
|
}
|
||||||
// Highly unlikely, but...
|
// Highly unlikely, but...
|
||||||
check (parametersUpdate == null || latestParameters?.parametersHash != currentParametersHash?.toString()) {
|
check(parametersUpdate == null || latestParameters?.hash != currentParametersHash) {
|
||||||
"Having update for parameters that are already in network map"
|
"Having update for parameters that are already in network map"
|
||||||
}
|
}
|
||||||
parametersUpdate
|
parametersUpdate
|
||||||
@ -160,16 +160,16 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
override fun setFlagDay(parametersHash: SecureHash) {
|
override fun setFlagDay(parametersHash: SecureHash) {
|
||||||
database.transaction {
|
database.transaction {
|
||||||
val parametersUpdateEntity = getParametersUpdate() ?: throw IllegalArgumentException("Setting flag day but no parameters update to switch to")
|
val parametersUpdateEntity = getParametersUpdate() ?: throw IllegalArgumentException("Setting flag day but no parameters update to switch to")
|
||||||
if (parametersHash.toString() != parametersUpdateEntity.networkParameters.parametersHash) {
|
if (parametersHash.toString() != parametersUpdateEntity.networkParameters.hash) {
|
||||||
throw IllegalArgumentException("Setting flag day for parameters: $parametersHash, but in database we have update for: ${parametersUpdateEntity.networkParameters.parametersHash}")
|
throw IllegalArgumentException("Setting flag day for parameters: $parametersHash, but in database we have update for: ${parametersUpdateEntity.networkParameters.hash}")
|
||||||
}
|
}
|
||||||
session.merge(parametersUpdateEntity.copy(flagDay = true))
|
session.merge(parametersUpdateEntity.copy(flagDay = true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun DatabaseTransaction.getNetworkParametersEntity(hash: SecureHash): NetworkParametersEntity? {
|
internal fun DatabaseTransaction.getNetworkParametersEntity(hash: SecureHash): NetworkParametersEntity? {
|
||||||
return uniqueEntityWhere { builder, path ->
|
return uniqueEntityWhere { builder, path ->
|
||||||
builder.equal(path.get<String>(NetworkParametersEntity::parametersHash.name), hash.toString())
|
builder.equal(path.get<String>(NetworkParametersEntity::hash.name), hash.toString())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,14 +11,13 @@
|
|||||||
package com.r3.corda.networkmanage.common.persistence
|
package com.r3.corda.networkmanage.common.persistence
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.CertificateSigningRequestEntity
|
import com.r3.corda.networkmanage.common.persistence.entity.CertificateSigningRequestEntity
|
||||||
|
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 com.r3.corda.networkmanage.common.utils.buildCertPath
|
|
||||||
import com.r3.corda.networkmanage.common.utils.hashString
|
import com.r3.corda.networkmanage.common.utils.hashString
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.internal.CertRole
|
import net.corda.core.internal.CertRole
|
||||||
import net.corda.core.internal.CertRole.NODE_CA
|
import net.corda.core.internal.CertRole.NODE_CA
|
||||||
import net.corda.core.serialization.serialize
|
|
||||||
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.crypto.x509Certificates
|
import net.corda.nodeapi.internal.crypto.x509Certificates
|
||||||
@ -34,7 +33,7 @@ class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeIn
|
|||||||
val (nodeInfo, signedNodeInfo) = nodeInfoAndSigned
|
val (nodeInfo, signedNodeInfo) = nodeInfoAndSigned
|
||||||
val nodeCaCert = nodeInfo.legalIdentitiesAndCerts[0].certPath.x509Certificates.find { CertRole.extract(it) == NODE_CA }
|
val nodeCaCert = nodeInfo.legalIdentitiesAndCerts[0].certPath.x509Certificates.find { CertRole.extract(it) == NODE_CA }
|
||||||
nodeCaCert ?: throw IllegalArgumentException("Missing Node CA")
|
nodeCaCert ?: throw IllegalArgumentException("Missing Node CA")
|
||||||
return database.transaction {
|
database.transaction {
|
||||||
// TODO Move these checks out of data access layer
|
// TODO Move these checks out of data access layer
|
||||||
val request = requireNotNull(getSignedRequestByPublicHash(nodeCaCert.publicKey.encoded.sha256())) {
|
val request = requireNotNull(getSignedRequestByPublicHash(nodeCaCert.publicKey.encoded.sha256())) {
|
||||||
"Node-info not registered with us"
|
"Node-info not registered with us"
|
||||||
@ -43,44 +42,43 @@ class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeIn
|
|||||||
require(it == CertificateStatus.VALID) { "Certificate is no longer valid: $it" }
|
require(it == CertificateStatus.VALID) { "Certificate is no longer valid: $it" }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update any [NodeInfoEntity] instance for this CSR as not current.
|
val existingNodeInfos = session.createQuery(
|
||||||
entitiesWhere<NodeInfoEntity> { builder, path ->
|
"from ${NodeInfoEntity::class.java.name} n where n.certificateSigningRequest = :csr and n.isCurrent = true order by n.publishedAt desc",
|
||||||
val requestEq = builder.equal(path.get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name), request)
|
NodeInfoEntity::class.java)
|
||||||
val isCurrent = builder.isTrue(path.get<Boolean>(NodeInfoEntity::isCurrent.name))
|
.setParameter("csr", request)
|
||||||
builder.and(requestEq, isCurrent)
|
.resultList
|
||||||
}.resultStream.use { existingNodeInfos ->
|
|
||||||
existingNodeInfos.forEach { session.merge(it.copy(isCurrent = false)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val hash = signedNodeInfo.raw.hash
|
// Update any [NodeInfoEntity] instance for this CSR as not current.
|
||||||
val hashedNodeInfo = NodeInfoEntity(
|
existingNodeInfos.forEach { session.merge(it.copy(isCurrent = false)) }
|
||||||
nodeInfoHash = hash.toString(),
|
|
||||||
identityPkHash = nodeInfo.legalIdentities.first().owningKey.hashString(),
|
session.save(NodeInfoEntity(
|
||||||
|
nodeInfoHash = signedNodeInfo.raw.hash.toString(),
|
||||||
|
publicKeyHash = nodeInfo.legalIdentities[0].owningKey.hashString(),
|
||||||
certificateSigningRequest = request,
|
certificateSigningRequest = request,
|
||||||
signedNodeInfoBytes = signedNodeInfo.serialize().bytes,
|
signedNodeInfo = signedNodeInfo,
|
||||||
isCurrent = true)
|
isCurrent = true,
|
||||||
session.save(hashedNodeInfo)
|
acceptedNetworkParameters = existingNodeInfos.firstOrNull()?.acceptedNetworkParameters
|
||||||
hash
|
))
|
||||||
}
|
}
|
||||||
|
return signedNodeInfo.raw.hash
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNodeInfo(nodeInfoHash: SecureHash): SignedNodeInfo? {
|
override fun getNodeInfo(nodeInfoHash: SecureHash): SignedNodeInfo? {
|
||||||
return database.transaction {
|
return database.transaction {
|
||||||
session.find(NodeInfoEntity::class.java, nodeInfoHash.toString())?.toSignedNodeInfo()
|
session.find(NodeInfoEntity::class.java, nodeInfoHash.toString())?.signedNodeInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAcceptedParametersUpdateHash(nodeInfoHash: SecureHash): SecureHash? {
|
override fun getAcceptedNetworkParameters(nodeInfoHash: SecureHash): NetworkParametersEntity? {
|
||||||
return database.transaction {
|
return database.transaction {
|
||||||
val hashString = session.find(NodeInfoEntity::class.java, nodeInfoHash.toString())?.acceptedParametersHash
|
session.find(NodeInfoEntity::class.java, nodeInfoHash.toString())?.acceptedNetworkParameters
|
||||||
if (hashString == null || hashString.isEmpty()) null else SecureHash.parse(hashString)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCertificatePath(publicKeyHash: SecureHash): CertPath? {
|
override fun getCertificatePath(publicKeyHash: SecureHash): CertPath? {
|
||||||
return database.transaction {
|
return database.transaction {
|
||||||
val request = getSignedRequestByPublicHash(publicKeyHash)
|
val request = getSignedRequestByPublicHash(publicKeyHash)
|
||||||
request?.let { buildCertPath(it.certificateData!!.certificatePathBytes) }
|
request?.let { it.certificateData!!.certPath }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,11 +87,17 @@ class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeIn
|
|||||||
val builder = session.criteriaBuilder
|
val builder = session.criteriaBuilder
|
||||||
val query = builder.createQuery(NodeInfoEntity::class.java).run {
|
val query = builder.createQuery(NodeInfoEntity::class.java).run {
|
||||||
from(NodeInfoEntity::class.java).run {
|
from(NodeInfoEntity::class.java).run {
|
||||||
where(builder.equal(get<NodeInfoEntity>(NodeInfoEntity::identityPkHash.name), publicKeyHash.toString()))
|
where(builder.equal(get<NodeInfoEntity>(NodeInfoEntity::publicKeyHash.name), publicKeyHash.toString()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val nodeInfo = session.createQuery(query).setMaxResults(1).uniqueResult()
|
val nodeInfo = requireNotNull(session.createQuery(query).setMaxResults(1).uniqueResult()) {
|
||||||
val newInfo = nodeInfo.copy(acceptedParametersHash = acceptedParametersHash.toString())
|
"NodeInfo with public key hash $publicKeyHash doesn't exist"
|
||||||
|
}
|
||||||
|
val networkParameters = requireNotNull(getNetworkParametersEntity(acceptedParametersHash)) {
|
||||||
|
"Network parameters $acceptedParametersHash doesn't exist"
|
||||||
|
}
|
||||||
|
require(networkParameters.isSigned) { "Network parameters $acceptedParametersHash is not signed" }
|
||||||
|
val newInfo = nodeInfo.copy(acceptedNetworkParameters = networkParameters)
|
||||||
session.merge(newInfo)
|
session.merge(newInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
package com.r3.corda.networkmanage.common.persistence.entity
|
||||||
|
|
||||||
|
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||||
|
import net.corda.core.node.NetworkParameters
|
||||||
|
import net.corda.core.serialization.SerializationFactory
|
||||||
|
import net.corda.core.serialization.serialize
|
||||||
|
import net.corda.core.utilities.sequence
|
||||||
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||||
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
|
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||||
|
import java.security.cert.CertPath
|
||||||
|
import java.security.cert.X509CRL
|
||||||
|
import java.security.cert.X509Certificate
|
||||||
|
import javax.persistence.AttributeConverter
|
||||||
|
import net.corda.core.identity.CordaX500Name
|
||||||
|
|
||||||
|
class PKCS10CertificationRequestConverter : AttributeConverter<PKCS10CertificationRequest, ByteArray> {
|
||||||
|
override fun convertToEntityAttribute(dbData: ByteArray?): PKCS10CertificationRequest? = dbData?.let(::PKCS10CertificationRequest)
|
||||||
|
override fun convertToDatabaseColumn(attribute: PKCS10CertificationRequest?): ByteArray? = attribute?.encoded
|
||||||
|
}
|
||||||
|
|
||||||
|
class CertPathConverter : AttributeConverter<CertPath, ByteArray> {
|
||||||
|
override fun convertToEntityAttribute(dbData: ByteArray?): CertPath? = dbData?.let(::buildCertPath)
|
||||||
|
override fun convertToDatabaseColumn(attribute: CertPath?): ByteArray? = attribute?.encoded
|
||||||
|
}
|
||||||
|
|
||||||
|
class X509CertificateConverter : AttributeConverter<X509Certificate, ByteArray> {
|
||||||
|
override fun convertToEntityAttribute(dbData: ByteArray?): X509Certificate? {
|
||||||
|
return dbData?.let { X509CertificateFactory().generateCertificate(it.inputStream()) }
|
||||||
|
}
|
||||||
|
override fun convertToDatabaseColumn(attribute: X509Certificate?): ByteArray? = attribute?.encoded
|
||||||
|
}
|
||||||
|
|
||||||
|
class X509CRLConverter : AttributeConverter<X509CRL, ByteArray> {
|
||||||
|
override fun convertToEntityAttribute(dbData: ByteArray?): X509CRL? {
|
||||||
|
return dbData?.let { X509CertificateFactory().delegate.generateCRL(it.inputStream()) as X509CRL }
|
||||||
|
}
|
||||||
|
override fun convertToDatabaseColumn(attribute: X509CRL?): ByteArray? = attribute?.encoded
|
||||||
|
}
|
||||||
|
|
||||||
|
class NetworkParametersConverter : CordaSerializationConverter<NetworkParameters>(NetworkParameters::class.java)
|
||||||
|
|
||||||
|
class NetworkMapConverter : CordaSerializationConverter<NetworkMap>(NetworkMap::class.java)
|
||||||
|
|
||||||
|
class SignedNodeInfoConverter : CordaSerializationConverter<SignedNodeInfo>(SignedNodeInfo::class.java)
|
||||||
|
|
||||||
|
sealed class CordaSerializationConverter<T : Any>(private val clazz: Class<T>) : AttributeConverter<T, ByteArray> {
|
||||||
|
override fun convertToEntityAttribute(dbData: ByteArray?): T? {
|
||||||
|
return dbData?.let {
|
||||||
|
val serializationFactory = SerializationFactory.defaultFactory
|
||||||
|
serializationFactory.deserialize(it.sequence(), clazz, serializationFactory.defaultContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun convertToDatabaseColumn(attribute: T?): ByteArray? = attribute?.serialize()?.bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
class CordaX500NameAttributeConverter : AttributeConverter<CordaX500Name, String> {
|
||||||
|
override fun convertToDatabaseColumn(attribute: CordaX500Name?): String? = attribute?.toString()
|
||||||
|
override fun convertToEntityAttribute(dbData: String?): CordaX500Name? = dbData?.let { CordaX500Name.parse(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Use SecureHash in entities
|
||||||
|
//class SecureHashAttributeConverter : AttributeConverter<SecureHash, String> {
|
||||||
|
// override fun convertToDatabaseColumn(attribute: SecureHash?): String? = attribute?.toString()
|
||||||
|
// override fun convertToEntityAttribute(dbData: String?): SecureHash? = dbData?.let { SecureHash.parse(it) }
|
||||||
|
//}
|
||||||
|
|
@ -1,24 +1,27 @@
|
|||||||
package com.r3.corda.networkmanage.common.persistence.entity
|
package com.r3.corda.networkmanage.common.persistence.entity
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.common.persistence.CrlIssuer
|
import com.r3.corda.networkmanage.common.persistence.CrlIssuer
|
||||||
|
import java.security.cert.X509CRL
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import javax.persistence.*
|
import javax.persistence.*
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "certificate_revocation_list")
|
@Table(name = "cert_revocation_list")
|
||||||
class CertificateRevocationListEntity(
|
class CertificateRevocationListEntity(
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||||
val id: Long? = null,
|
val id: Long? = null,
|
||||||
|
|
||||||
@Column(name = "issuer")
|
@Column(name = "issuer", length = 16, nullable = false, columnDefinition = "NVARCHAR(16)")
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
val crlIssuer: CrlIssuer,
|
val crlIssuer: CrlIssuer,
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "crl_bytes", nullable = false)
|
@Column(name = "crl_bytes", nullable = false)
|
||||||
val crlBytes: ByteArray,
|
@Convert(converter = X509CRLConverter::class)
|
||||||
|
val crl: X509CRL,
|
||||||
|
|
||||||
@Column(name = "signed_by", length = 512)
|
@Column(name = "signed_by", length = 64, nullable = false)
|
||||||
val signedBy: String,
|
val signedBy: String,
|
||||||
|
|
||||||
@Column(name = "modified_at", nullable = false)
|
@Column(name = "modified_at", nullable = false)
|
||||||
|
@ -9,73 +9,52 @@ import java.time.Instant
|
|||||||
import javax.persistence.*
|
import javax.persistence.*
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "certificate_revocation_request")
|
@Table(name = "cert_revocation_request")
|
||||||
class CertificateRevocationRequestEntity(
|
data class CertificateRevocationRequestEntity(
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||||
val id: Long? = null,
|
val id: Long? = null,
|
||||||
|
|
||||||
@Column(name = "request_id", length = 256, nullable = false, unique = true)
|
@Column(name = "request_id", length = 64, nullable = false, unique = true)
|
||||||
val requestId: String,
|
val requestId: String,
|
||||||
|
|
||||||
@OneToOne(fetch = FetchType.EAGER)
|
@OneToOne(fetch = FetchType.EAGER)
|
||||||
@JoinColumn(name = "certificate_data")
|
@JoinColumn(name = "cert_data", nullable = false)
|
||||||
val certificateData: CertificateDataEntity,
|
val certificateData: CertificateDataEntity,
|
||||||
|
|
||||||
@Column(name = "certificate_serial_number", nullable = false)
|
@Column(name = "cert_serial_number", nullable = false, columnDefinition = "NUMERIC(28)")
|
||||||
val certificateSerialNumber: BigInteger,
|
val certificateSerialNumber: BigInteger,
|
||||||
|
|
||||||
@Column(name = "legal_name", length = 256, nullable = false)
|
@Column(name = "legal_name", length = 256, nullable = false)
|
||||||
@Convert(converter = CordaX500NameAttributeConverter::class)
|
@Convert(converter = CordaX500NameAttributeConverter::class)
|
||||||
val legalName: CordaX500Name,
|
val legalName: CordaX500Name,
|
||||||
|
|
||||||
|
// Setting [columnDefinition] is a work around for a hibernate problem when using SQL database.
|
||||||
|
// TODO: Remove this when we find out the cause of the problem.
|
||||||
@Audited
|
@Audited
|
||||||
@Column(name = "status", nullable = false)
|
@Column(name = "status", length = 16, nullable = false, columnDefinition = "NVARCHAR(16)")
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
val status: RequestStatus = RequestStatus.NEW,
|
val status: RequestStatus = RequestStatus.NEW,
|
||||||
|
|
||||||
@Column(name = "reporter", nullable = false, length = 512)
|
@Column(name = "reporter", nullable = false, length = 64)
|
||||||
val reporter: String,
|
val reporter: String,
|
||||||
|
|
||||||
@Audited
|
@Audited
|
||||||
@Column(name = "modified_by", nullable = false, length = 512)
|
@Column(name = "modified_by", nullable = false, length = 64)
|
||||||
val modifiedBy: String,
|
val modifiedBy: String,
|
||||||
|
|
||||||
@Audited
|
@Audited
|
||||||
@Column(name = "modified_at", nullable = false)
|
@Column(name = "modified_at", nullable = false)
|
||||||
val modifiedAt: Instant = Instant.now(),
|
val modifiedAt: Instant = Instant.now(),
|
||||||
|
|
||||||
|
// Setting [columnDefinition] is a work around for a hibernate problem when using SQL database.
|
||||||
|
// TODO: Remove this when we find out the cause of the problem.
|
||||||
@Audited
|
@Audited
|
||||||
@Column(name = "revocation_reason", nullable = false)
|
@Column(name = "revocation_reason", length = 32, nullable = false, columnDefinition = "NVARCHAR(32)")
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
val revocationReason: CRLReason,
|
val revocationReason: CRLReason,
|
||||||
|
|
||||||
@Audited
|
@Audited
|
||||||
@Column(name = "remark", length = 256)
|
@Column(name = "remark", length = 256)
|
||||||
val remark: String? = null
|
val remark: String? = null
|
||||||
) {
|
)
|
||||||
fun copy(requestId: String = this.requestId,
|
|
||||||
certificateData: CertificateDataEntity = this.certificateData,
|
|
||||||
certificateSerialNumber: BigInteger = this.certificateSerialNumber,
|
|
||||||
status: RequestStatus = this.status,
|
|
||||||
legalName: CordaX500Name = this.legalName,
|
|
||||||
reporter: String = this.reporter,
|
|
||||||
modifiedBy: String = this.modifiedBy,
|
|
||||||
modifiedAt: Instant = this.modifiedAt,
|
|
||||||
revocationReason: CRLReason = this.revocationReason,
|
|
||||||
remark: String? = this.remark): CertificateRevocationRequestEntity {
|
|
||||||
return CertificateRevocationRequestEntity(
|
|
||||||
id = this.id,
|
|
||||||
requestId = requestId,
|
|
||||||
certificateData = certificateData,
|
|
||||||
certificateSerialNumber = certificateSerialNumber,
|
|
||||||
status = status,
|
|
||||||
legalName = legalName,
|
|
||||||
reporter = reporter,
|
|
||||||
modifiedBy = modifiedBy,
|
|
||||||
modifiedAt = modifiedAt,
|
|
||||||
revocationReason = revocationReason,
|
|
||||||
remark = remark
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,7 +14,6 @@ import com.r3.corda.networkmanage.common.persistence.CertificateData
|
|||||||
import com.r3.corda.networkmanage.common.persistence.CertificateSigningRequest
|
import com.r3.corda.networkmanage.common.persistence.CertificateSigningRequest
|
||||||
import com.r3.corda.networkmanage.common.persistence.CertificateStatus
|
import com.r3.corda.networkmanage.common.persistence.CertificateStatus
|
||||||
import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
||||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.nodeapi.internal.crypto.x509Certificates
|
import net.corda.nodeapi.internal.crypto.x509Certificates
|
||||||
@ -26,10 +25,10 @@ import java.time.Instant
|
|||||||
import javax.persistence.*
|
import javax.persistence.*
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "certificate_signing_request", indexes = arrayOf(Index(name = "IDX_PUB_KEY_HASH", columnList = "public_key_hash")))
|
@Table(name = "cert_signing_request", indexes = arrayOf(Index(name = "IDX__CSR__PKH", columnList = "public_key_hash")))
|
||||||
data class CertificateSigningRequestEntity(
|
data class CertificateSigningRequestEntity(
|
||||||
@Id
|
@Id
|
||||||
@Column(name = "request_id", length = 64)
|
@Column(name = "request_id", length = 64, nullable = false)
|
||||||
val requestId: String,
|
val requestId: String,
|
||||||
|
|
||||||
// TODO: Store X500Name with a proper schema.
|
// TODO: Store X500Name with a proper schema.
|
||||||
@ -37,19 +36,21 @@ data class CertificateSigningRequestEntity(
|
|||||||
@Convert(converter = CordaX500NameAttributeConverter::class)
|
@Convert(converter = CordaX500NameAttributeConverter::class)
|
||||||
val legalName: CordaX500Name?,
|
val legalName: CordaX500Name?,
|
||||||
|
|
||||||
@Column(name = "public_key_hash", length = 64)
|
@Column(name = "public_key_hash", length = 64, nullable = false)
|
||||||
val publicKeyHash: String,
|
val publicKeyHash: String,
|
||||||
|
|
||||||
|
// Setting [columnDefinition] is a work around for a hibernate problem when using SQL database.
|
||||||
|
// TODO: Remove this when we find out the cause of the problem.
|
||||||
@Audited
|
@Audited
|
||||||
@Column(name = "status", nullable = false)
|
@Column(name = "status", length = 16, nullable = false, columnDefinition = "NVARCHAR(16)")
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
val status: RequestStatus = RequestStatus.NEW,
|
val status: RequestStatus = RequestStatus.NEW,
|
||||||
|
|
||||||
@Audited
|
@Audited
|
||||||
@Column(name = "modified_by", length = 512)
|
@Column(name = "modified_by", length = 64, nullable = false)
|
||||||
val modifiedBy: String,
|
val modifiedBy: String,
|
||||||
|
|
||||||
@Audited
|
// TODO: Use audit framework instead.
|
||||||
@Column(name = "modified_at", nullable = false)
|
@Column(name = "modified_at", nullable = false)
|
||||||
val modifiedAt: Instant = Instant.now(),
|
val modifiedAt: Instant = Instant.now(),
|
||||||
|
|
||||||
@ -62,10 +63,11 @@ data class CertificateSigningRequestEntity(
|
|||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "request_bytes", nullable = false)
|
@Column(name = "request_bytes", nullable = false)
|
||||||
val requestBytes: ByteArray,
|
@Convert(converter = PKCS10CertificationRequestConverter::class)
|
||||||
|
val request: PKCS10CertificationRequest,
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "private_network", foreignKey = ForeignKey(name = "FK_CSR_PN"))
|
@JoinColumn(name = "private_network", foreignKey = ForeignKey(name = "FK__CSR__PN"))
|
||||||
val privateNetwork: PrivateNetworkEntity? = null
|
val privateNetwork: PrivateNetworkEntity? = null
|
||||||
) {
|
) {
|
||||||
fun toCertificateSigningRequest(): CertificateSigningRequest {
|
fun toCertificateSigningRequest(): CertificateSigningRequest {
|
||||||
@ -74,70 +76,53 @@ data class CertificateSigningRequestEntity(
|
|||||||
legalName = legalName,
|
legalName = legalName,
|
||||||
publicKeyHash = SecureHash.parse(publicKeyHash),
|
publicKeyHash = SecureHash.parse(publicKeyHash),
|
||||||
status = status,
|
status = status,
|
||||||
request = request(),
|
request = request,
|
||||||
remark = remark,
|
remark = remark,
|
||||||
modifiedBy = modifiedBy,
|
modifiedBy = modifiedBy,
|
||||||
certData = certificateData?.toCertificateData()
|
certData = certificateData?.toCertificateData()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun request() = PKCS10CertificationRequest(requestBytes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "certificate_data")
|
@Table(name = "cert_data")
|
||||||
data class CertificateDataEntity(
|
data class CertificateDataEntity(
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||||
val id: Long? = null,
|
val id: Long? = null,
|
||||||
|
|
||||||
@Column(name = "certificate_status")
|
// Setting [columnDefinition] is a work around for a hibernate problem when using SQL database.
|
||||||
|
// TODO: Remove this when we find out the cause of the problem.
|
||||||
|
@Column(name = "cert_status", length = 16, nullable = false, columnDefinition = "NVARCHAR(16)")
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
val certificateStatus: CertificateStatus,
|
val certificateStatus: CertificateStatus,
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "certificate_path_bytes")
|
@Column(name = "cert_path_bytes", nullable = false)
|
||||||
val certificatePathBytes: ByteArray,
|
@Convert(converter = CertPathConverter::class)
|
||||||
|
val certPath: CertPath,
|
||||||
|
|
||||||
@OneToOne(fetch = FetchType.EAGER, optional = false)
|
@OneToOne(fetch = FetchType.EAGER, optional = false)
|
||||||
@JoinColumn(name = "certificate_signing_request", foreignKey = ForeignKey(name = "FK__cert_data__cert_sign_req"))
|
@JoinColumn(name = "cert_signing_request", foreignKey = ForeignKey(name = "FK__CD__CSR"), nullable = false)
|
||||||
val certificateSigningRequest: CertificateSigningRequestEntity,
|
val certificateSigningRequest: CertificateSigningRequestEntity,
|
||||||
|
|
||||||
@Column(name = "certificate_serial_number", unique = true)
|
@Column(name = "cert_serial_number", unique = true, nullable = false, columnDefinition = "NUMERIC(28)")
|
||||||
val certificateSerialNumber: BigInteger
|
val certificateSerialNumber: BigInteger
|
||||||
) {
|
) {
|
||||||
fun toCertificateData(): CertificateData {
|
fun toCertificateData(): CertificateData = CertificateData(certificateStatus, certPath)
|
||||||
return CertificateData(
|
|
||||||
certStatus = certificateStatus,
|
|
||||||
certPath = toCertificatePath()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val legalName: CordaX500Name get() {
|
val legalName: CordaX500Name get() {
|
||||||
return CordaX500Name.build(toCertificatePath().x509Certificates[0].subjectX500Principal)
|
return CordaX500Name.build(certPath.x509Certificates[0].subjectX500Principal)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copy(certificateStatus: CertificateStatus = this.certificateStatus,
|
|
||||||
certificatePathBytes: ByteArray = this.certificatePathBytes,
|
|
||||||
certificateSigningRequest: CertificateSigningRequestEntity = this.certificateSigningRequest,
|
|
||||||
certificateSerialNumber: BigInteger = this.certificateSerialNumber): CertificateDataEntity {
|
|
||||||
return CertificateDataEntity(
|
|
||||||
id = this.id,
|
|
||||||
certificateStatus = certificateStatus,
|
|
||||||
certificatePathBytes = certificatePathBytes,
|
|
||||||
certificateSigningRequest = certificateSigningRequest,
|
|
||||||
certificateSerialNumber = certificateSerialNumber)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toCertificatePath(): CertPath = buildCertPath(certificatePathBytes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "private_network")
|
@Table(name = "private_network")
|
||||||
data class PrivateNetworkEntity(
|
data class PrivateNetworkEntity(
|
||||||
@Id
|
@Id
|
||||||
@Column(name = "id")
|
@Column(name = "id", length = 64)
|
||||||
val networkId: String,
|
val networkId: String,
|
||||||
|
|
||||||
@Column(name = "name")
|
@Column(name = "name", length = 255, nullable = false)
|
||||||
val networkName: String
|
val networkName: String
|
||||||
)
|
)
|
@ -1,15 +0,0 @@
|
|||||||
package com.r3.corda.networkmanage.common.persistence.entity
|
|
||||||
|
|
||||||
import net.corda.core.identity.CordaX500Name
|
|
||||||
import javax.persistence.AttributeConverter
|
|
||||||
|
|
||||||
class CordaX500NameAttributeConverter : AttributeConverter<CordaX500Name, String> {
|
|
||||||
override fun convertToDatabaseColumn(attribute: CordaX500Name?): String? = attribute?.toString()
|
|
||||||
override fun convertToEntityAttribute(dbData: String?): CordaX500Name? = dbData?.let { CordaX500Name.parse(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO Use SecureHash in entities
|
|
||||||
//class SecureHashAttributeConverter : AttributeConverter<SecureHash, String> {
|
|
||||||
// override fun convertToDatabaseColumn(attribute: SecureHash?): String? = attribute?.toString()
|
|
||||||
// override fun convertToEntityAttribute(dbData: String?): SecureHash? = dbData?.let { SecureHash.parse(it) }
|
|
||||||
//}
|
|
@ -11,11 +11,10 @@
|
|||||||
package com.r3.corda.networkmanage.common.persistence.entity
|
package com.r3.corda.networkmanage.common.persistence.entity
|
||||||
|
|
||||||
import net.corda.core.internal.DigitalSignatureWithCert
|
import net.corda.core.internal.DigitalSignatureWithCert
|
||||||
import net.corda.core.serialization.SerializedBytes
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.serialization.deserialize
|
|
||||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
|
||||||
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 java.security.cert.X509Certificate
|
||||||
import javax.persistence.*
|
import javax.persistence.*
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -27,26 +26,23 @@ class NetworkMapEntity(
|
|||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "serialized_network_map", nullable = false)
|
@Column(name = "serialized_network_map", nullable = false)
|
||||||
val networkMapBytes: ByteArray,
|
@Convert(converter = NetworkMapConverter::class)
|
||||||
|
val networkMap: NetworkMap,
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "signature", nullable = false)
|
@Column(name = "signature", nullable = false)
|
||||||
val signature: ByteArray,
|
val signature: ByteArray,
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "certificate", nullable = false)
|
@Column(name = "cert", nullable = false)
|
||||||
val certificate: ByteArray,
|
@Convert(converter = X509CertificateConverter::class)
|
||||||
|
val certificate: X509Certificate,
|
||||||
|
|
||||||
@ManyToOne(optional = false, fetch = FetchType.EAGER)
|
@ManyToOne(optional = false, fetch = FetchType.EAGER)
|
||||||
@JoinColumn(name = "network_parameters")
|
@JoinColumn(name = "network_parameters", nullable = false)
|
||||||
val networkParameters: NetworkParametersEntity
|
val networkParameters: NetworkParametersEntity
|
||||||
) {
|
) {
|
||||||
fun toNetworkMap(): NetworkMap = networkMapBytes.deserialize()
|
|
||||||
|
|
||||||
fun toSignedNetworkMap(): SignedNetworkMap {
|
fun toSignedNetworkMap(): SignedNetworkMap {
|
||||||
return SignedNetworkMap(
|
return SignedNetworkMap(networkMap.serialize(), DigitalSignatureWithCert(certificate, signature))
|
||||||
SerializedBytes(networkMapBytes),
|
|
||||||
DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), signature)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,27 +12,26 @@ package com.r3.corda.networkmanage.common.persistence.entity
|
|||||||
|
|
||||||
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.SerializedBytes
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.serialization.deserialize
|
|
||||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
||||||
import org.hibernate.annotations.CreationTimestamp
|
import java.security.cert.X509Certificate
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import javax.persistence.*
|
import javax.persistence.*
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "network_parameters", indexes = arrayOf(Index(name = "IDX_NET_PARAMS_HASH", columnList = "hash")))
|
@Table(name = "network_parameters", indexes = arrayOf(Index(name = "IDX_NP_HASH", columnList = "hash")))
|
||||||
class NetworkParametersEntity(
|
class NetworkParametersEntity(
|
||||||
@Id
|
@Id
|
||||||
@Column(name = "hash", length = 64, unique = true)
|
@Column(name = "hash", length = 64, nullable = false)
|
||||||
val parametersHash: String,
|
val hash: String,
|
||||||
|
|
||||||
@CreationTimestamp
|
@Column(nullable = false)
|
||||||
val created: Instant = Instant.now(),
|
val created: Instant = Instant.now(),
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "parameters_bytes", nullable = false)
|
@Column(name = "parameters_bytes", nullable = false)
|
||||||
val parametersBytes: ByteArray,
|
@Convert(converter = NetworkParametersConverter::class)
|
||||||
|
val networkParameters: NetworkParameters,
|
||||||
|
|
||||||
// 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
|
||||||
// inserted into database without signature. Then signing service will sign them.
|
// inserted into database without signature. Then signing service will sign them.
|
||||||
@ -41,31 +40,27 @@ class NetworkParametersEntity(
|
|||||||
val signature: ByteArray?,
|
val signature: ByteArray?,
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "certificate")
|
@Column(name = "cert")
|
||||||
val certificate: ByteArray?
|
@Convert(converter = X509CertificateConverter::class)
|
||||||
|
val certificate: X509Certificate?
|
||||||
) {
|
) {
|
||||||
val isSigned: Boolean get() = certificate != null && signature != null
|
val isSigned: Boolean get() = certificate != null && signature != null
|
||||||
|
|
||||||
fun toNetworkParameters(): NetworkParameters = parametersBytes.deserialize()
|
|
||||||
|
|
||||||
fun toSignedNetworkParameters(): SignedNetworkParameters {
|
fun toSignedNetworkParameters(): SignedNetworkParameters {
|
||||||
if (certificate == null || signature == null) throw IllegalStateException("Network parameters entity is not signed: $parametersHash")
|
if (certificate == null || signature == null) throw IllegalStateException("Network parameters entity is not signed: $hash")
|
||||||
return SignedNetworkParameters(
|
return SignedNetworkParameters(networkParameters.serialize(), DigitalSignatureWithCert(certificate, signature))
|
||||||
SerializedBytes(parametersBytes),
|
|
||||||
DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), signature)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copy(parametersHash: String = this.parametersHash,
|
fun copy(parametersHash: String = this.hash,
|
||||||
created: Instant = this.created,
|
created: Instant = this.created,
|
||||||
parametersBytes: ByteArray = this.parametersBytes,
|
networkParameters: NetworkParameters = this.networkParameters,
|
||||||
signature: ByteArray? = this.signature,
|
signature: ByteArray? = this.signature,
|
||||||
certificate: ByteArray? = this.certificate
|
certificate: X509Certificate? = this.certificate
|
||||||
): NetworkParametersEntity {
|
): NetworkParametersEntity {
|
||||||
return NetworkParametersEntity(
|
return NetworkParametersEntity(
|
||||||
parametersHash = parametersHash,
|
hash = parametersHash,
|
||||||
created = created,
|
created = created,
|
||||||
parametersBytes = parametersBytes,
|
networkParameters = networkParameters,
|
||||||
signature = signature,
|
signature = signature,
|
||||||
certificate = certificate
|
certificate = certificate
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
package com.r3.corda.networkmanage.common.persistence.entity
|
package com.r3.corda.networkmanage.common.persistence.entity
|
||||||
|
|
||||||
import net.corda.core.serialization.deserialize
|
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import javax.persistence.*
|
import javax.persistence.*
|
||||||
@ -21,47 +20,27 @@ data class NodeInfoEntity(
|
|||||||
// Hash of serialized [NodeInfo] without signatures.
|
// Hash of serialized [NodeInfo] without signatures.
|
||||||
@Id
|
@Id
|
||||||
@Column(name = "node_info_hash", length = 64)
|
@Column(name = "node_info_hash", length = 64)
|
||||||
val nodeInfoHash: String = "",
|
val nodeInfoHash: String,
|
||||||
|
|
||||||
@Column(name = "public_key_hash", length = 64)
|
@Column(name = "public_key_hash", length = 64)
|
||||||
val identityPkHash: String = "",
|
val publicKeyHash: String,
|
||||||
|
|
||||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "certificate_signing_request")
|
@JoinColumn(name = "cert_signing_request", nullable = false)
|
||||||
val certificateSigningRequest: CertificateSigningRequestEntity,
|
val certificateSigningRequest: CertificateSigningRequestEntity,
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "signed_node_info_bytes")
|
@Column(name = "signed_node_info_bytes", nullable = false)
|
||||||
val signedNodeInfoBytes: ByteArray,
|
@Convert(converter = SignedNodeInfoConverter::class)
|
||||||
|
val signedNodeInfo: SignedNodeInfo,
|
||||||
|
|
||||||
@Column(name = "is_current")
|
@Column(name = "is_current", nullable = false)
|
||||||
val isCurrent: Boolean,
|
val isCurrent: Boolean,
|
||||||
|
|
||||||
@Column(name = "published_at")
|
@Column(name = "published_at", nullable = false)
|
||||||
val publishedAt: Instant = Instant.now(),
|
val publishedAt: Instant = Instant.now(),
|
||||||
|
|
||||||
@Column(name = "accepted_parameters_hash", length = 64)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
val acceptedParametersHash: String = ""
|
@JoinColumn(name = "accepted_network_parameters")
|
||||||
) {
|
val acceptedNetworkParameters: NetworkParametersEntity?
|
||||||
/**
|
)
|
||||||
* Deserialize NodeInfoEntity.signedNodeInfoBytes into the [SignedNodeInfo] instance
|
|
||||||
*/
|
|
||||||
fun toSignedNodeInfo() = signedNodeInfoBytes.deserialize<SignedNodeInfo>()
|
|
||||||
|
|
||||||
fun copy(nodeInfoHash: String = this.nodeInfoHash,
|
|
||||||
certificateSigningRequest: CertificateSigningRequestEntity = this.certificateSigningRequest,
|
|
||||||
signedNodeInfoBytes: ByteArray = this.signedNodeInfoBytes,
|
|
||||||
isCurrent: Boolean = this.isCurrent,
|
|
||||||
publishedAt: Instant = this.publishedAt,
|
|
||||||
acceptedParametersHash: String = this.acceptedParametersHash
|
|
||||||
): NodeInfoEntity {
|
|
||||||
return NodeInfoEntity(
|
|
||||||
nodeInfoHash = nodeInfoHash,
|
|
||||||
certificateSigningRequest = certificateSigningRequest,
|
|
||||||
signedNodeInfoBytes = signedNodeInfoBytes,
|
|
||||||
isCurrent = isCurrent,
|
|
||||||
publishedAt = publishedAt,
|
|
||||||
acceptedParametersHash = acceptedParametersHash
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -7,7 +7,7 @@ import javax.persistence.*
|
|||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "parameters_update")
|
@Table(name = "parameters_update")
|
||||||
class ParametersUpdateEntity(
|
data class ParametersUpdateEntity(
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||||
val id: Long? = null,
|
val id: Long? = null,
|
||||||
@ -17,31 +17,17 @@ class ParametersUpdateEntity(
|
|||||||
@JoinColumn(name = "network_parameters", foreignKey = ForeignKey(name = "FK__param_up__net_param"))
|
@JoinColumn(name = "network_parameters", foreignKey = ForeignKey(name = "FK__param_up__net_param"))
|
||||||
val networkParameters: NetworkParametersEntity,
|
val networkParameters: NetworkParametersEntity,
|
||||||
|
|
||||||
@Column(name = "description")
|
@Column(name = "description", nullable = false)
|
||||||
val description: String,
|
val description: String,
|
||||||
|
|
||||||
@Column(name = "update_deadline")
|
@Column(name = "update_deadline", nullable = false)
|
||||||
val updateDeadline: Instant,
|
val updateDeadline: Instant,
|
||||||
|
|
||||||
// This boolean flag is used when we want to explicitly point that it's time to switch parameters in network map.
|
// This boolean flag is used when we want to explicitly point that it's time to switch parameters in network map.
|
||||||
@Column(name = "flag_day")
|
@Column(name = "flag_day", nullable = false)
|
||||||
val flagDay: Boolean = false
|
val flagDay: Boolean = false
|
||||||
) {
|
) {
|
||||||
fun toParametersUpdate(): ParametersUpdate = ParametersUpdate(SecureHash.parse(networkParameters.parametersHash), description, updateDeadline)
|
fun toParametersUpdate(): ParametersUpdate {
|
||||||
|
return ParametersUpdate(SecureHash.parse(networkParameters.hash), description, updateDeadline)
|
||||||
fun toNetMapUpdate(): ParametersUpdate? = if (!flagDay) ParametersUpdate(SecureHash.parse(networkParameters.parametersHash), description, updateDeadline) else null
|
|
||||||
|
|
||||||
fun copy(id: Long? = this.id,
|
|
||||||
networkParameters: NetworkParametersEntity = this.networkParameters,
|
|
||||||
description: String = this.description,
|
|
||||||
updateDeadline: Instant = this.updateDeadline,
|
|
||||||
flagDay: Boolean = this.flagDay): ParametersUpdateEntity {
|
|
||||||
return ParametersUpdateEntity(
|
|
||||||
id = id,
|
|
||||||
networkParameters = networkParameters,
|
|
||||||
description = description,
|
|
||||||
updateDeadline = updateDeadline,
|
|
||||||
flagDay = flagDay
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,15 +12,12 @@ 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.crypto.SecureHash
|
||||||
import net.corda.nodeapi.internal.network.NetworkMap
|
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.serialization.SerializedBytes
|
|
||||||
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.core.utilities.debug
|
||||||
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
import net.corda.nodeapi.internal.network.NetworkMapAndSigned
|
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 {
|
||||||
val logger = contextLogger()
|
val logger = contextLogger()
|
||||||
@ -30,41 +27,56 @@ 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 signNetworkMap() {
|
||||||
logger.debug("Fetching current network map...")
|
|
||||||
val currentNetworkMap = networkMapStorage.getActiveNetworkMap()
|
|
||||||
if (currentNetworkMap == null) {
|
|
||||||
logger.info("There is currently no network map")
|
|
||||||
} else {
|
|
||||||
logger.debug { "Current network map: $currentNetworkMap" }
|
|
||||||
}
|
|
||||||
val currentNetworkParameters = currentNetworkMap?.networkParameters
|
|
||||||
logger.debug("Current network map parameters: ${currentNetworkParameters?.toNetworkParameters()}")
|
|
||||||
logger.debug("Fetching node info hashes with VALID certificates...")
|
|
||||||
val nodeInfoHashes = networkMapStorage.getActiveNodeInfoHashes()
|
|
||||||
logger.debug("Retrieved node info hashes: $nodeInfoHashes")
|
|
||||||
val latestNetworkParameters = networkMapStorage.getLatestNetworkParameters()
|
val latestNetworkParameters = networkMapStorage.getLatestNetworkParameters()
|
||||||
if (latestNetworkParameters == null) {
|
if (latestNetworkParameters == null) {
|
||||||
logger.debug("No network parameters present")
|
logger.debug("No network parameters present")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.debug { "Retrieved latest network parameters: ${latestNetworkParameters.toNetworkParameters()}" }
|
logger.debug { "Retrieved latest network parameters: ${latestNetworkParameters.networkParameters}" }
|
||||||
|
|
||||||
val parametersUpdate = networkMapStorage.getParametersUpdate()
|
val parametersUpdate = networkMapStorage.getParametersUpdate()
|
||||||
logger.debug { "Retrieved parameters update: $parametersUpdate" }
|
logger.debug { "Retrieved parameters update: $parametersUpdate" }
|
||||||
// We persist signed parameters only if they were not persisted before (they are not in currentSignedNetworkMap as normal parameters or as an update)
|
check(parametersUpdate == null || parametersUpdate.networkParameters.hash == latestNetworkParameters.hash) {
|
||||||
|
"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}" }
|
||||||
|
|
||||||
|
val nodeInfoHashes = networkMapStorage.getActiveNodeInfoHashes()
|
||||||
|
logger.debug { "Retrieved node info hashes:\n${nodeInfoHashes.joinToString("\n")}" }
|
||||||
|
|
||||||
|
// We persist signed parameters only if they were not persisted before (they are not in currentSignedNetworkMap as
|
||||||
|
// normal parameters or as an update)
|
||||||
if (!latestNetworkParameters.isSigned) {
|
if (!latestNetworkParameters.isSigned) {
|
||||||
signAndPersistNetworkParameters(latestNetworkParameters.toNetworkParameters())
|
signAndPersistNetworkParameters(latestNetworkParameters.networkParameters)
|
||||||
} else {
|
} else {
|
||||||
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?.flagDay == true || currentNetworkParameters == null) {
|
|
||||||
|
val parametersToNetworkMap = if (parametersUpdate?.flagDay == true || activeNetworkParameters == null) {
|
||||||
networkMapStorage.clearParametersUpdates()
|
networkMapStorage.clearParametersUpdates()
|
||||||
latestNetworkParameters
|
latestNetworkParameters
|
||||||
} else currentNetworkParameters
|
} else {
|
||||||
val newNetworkMap = NetworkMap(nodeInfoHashes, SecureHash.parse(parametersToNetworkMap.parametersHash), parametersUpdate?.toNetMapUpdate())
|
activeNetworkParameters
|
||||||
|
}
|
||||||
|
|
||||||
|
val newNetworkMap = NetworkMap(
|
||||||
|
nodeInfoHashes,
|
||||||
|
SecureHash.parse(parametersToNetworkMap.hash),
|
||||||
|
parametersUpdate?.let { if (!it.flagDay) it.toParametersUpdate() else null })
|
||||||
logger.debug { "Potential new network map: $newNetworkMap" }
|
logger.debug { "Potential new network map: $newNetworkMap" }
|
||||||
if (currentNetworkMap?.toNetworkMap() != newNetworkMap) {
|
|
||||||
val netNetworkMapAndSigned = NetworkMapAndSigned(newNetworkMap) { signer.signBytes(it.bytes) }
|
if (activeNetworkMap?.networkMap != newNetworkMap) {
|
||||||
networkMapStorage.saveNewActiveNetworkMap(netNetworkMapAndSigned)
|
val newNetworkMapAndSigned = NetworkMapAndSigned(newNetworkMap) { signer.signBytes(it.bytes) }
|
||||||
|
networkMapStorage.saveNewActiveNetworkMap(newNetworkMapAndSigned)
|
||||||
logger.info("Signed new network map: $newNetworkMap")
|
logger.info("Signed new network map: $newNetworkMap")
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Current network map is up-to-date")
|
logger.debug("Current network map is up-to-date")
|
||||||
|
@ -22,7 +22,6 @@ import com.r3.corda.networkmanage.doorman.webservice.NetworkMapWebService
|
|||||||
import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService
|
import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService
|
||||||
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.serialization.serialize
|
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||||
@ -60,7 +59,7 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
|
|||||||
|
|
||||||
private fun getNetworkMapService(config: NetworkMapConfig, signer: LocalSigner?): NetworkMapWebService {
|
private fun getNetworkMapService(config: NetworkMapConfig, signer: LocalSigner?): NetworkMapWebService {
|
||||||
val localNetworkMapSigner = signer?.let { NetworkMapSigner(networkMapStorage, it) }
|
val localNetworkMapSigner = signer?.let { NetworkMapSigner(networkMapStorage, it) }
|
||||||
val latestParameters = networkMapStorage.getLatestNetworkParameters()?.toNetworkParameters() ?:
|
val latestParameters = networkMapStorage.getLatestNetworkParameters()?.networkParameters ?:
|
||||||
throw IllegalStateException("No network parameters were found. Please upload new network parameters before starting network map service")
|
throw IllegalStateException("No network parameters were found. Please upload new network parameters before starting network map service")
|
||||||
logger.info("Starting network map service with network parameters: $latestParameters")
|
logger.info("Starting network map service with network parameters: $latestParameters")
|
||||||
localNetworkMapSigner?.signAndPersistNetworkParameters(latestParameters)
|
localNetworkMapSigner?.signAndPersistNetworkParameters(latestParameters)
|
||||||
@ -153,7 +152,7 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
|
|||||||
|
|
||||||
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?.toNetworkParameters()
|
val activeNetParams = networkMapStorage.getActiveNetworkMap()?.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"
|
||||||
@ -163,19 +162,19 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
|
|||||||
networkMapStorage.saveNetworkParameters(initialNetParams, null)
|
networkMapStorage.saveNetworkParameters(initialNetParams, null)
|
||||||
} else {
|
} else {
|
||||||
val parametersUpdate = requireNotNull(setNetParams.parametersUpdate) {
|
val parametersUpdate = requireNotNull(setNetParams.parametersUpdate) {
|
||||||
"'parametersUpdate' not specified in network parameters file but there is already an active set of network parameters."
|
"'parametersUpdate' not specified in network parameters file but there is already an active set of network parameters"
|
||||||
}
|
}
|
||||||
|
|
||||||
setNetParams.checkCompatibility(activeNetParams)
|
setNetParams.checkCompatibility(activeNetParams)
|
||||||
|
|
||||||
val latestNetParams = checkNotNull(networkMapStorage.getLatestNetworkParameters()?.toNetworkParameters()) {
|
val latestNetParams = checkNotNull(networkMapStorage.getLatestNetworkParameters()?.networkParameters) {
|
||||||
"Something has gone wrong! We have an active set of network parameters ($activeNetParams) but apparently no latest network parameters!"
|
"Something has gone wrong! We have an active set of network parameters ($activeNetParams) but apparently no latest network parameters!"
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's not necessary that latestNetParams is the current active network parameters. It can be the network
|
// It's not necessary that latestNetParams is the current active network parameters. It can be the network
|
||||||
// parameters from a previous update attempt which has't activated yet. We still take the epoch value for this
|
// parameters from a previous update attempt which has't activated yet. We still take the epoch value for this
|
||||||
// new set from latestNetParams to make sure the advertised update attempts have incrementing epochs.
|
// new set from latestNetParams to make sure the advertised update attempts have incrementing epochs.
|
||||||
// This has the implication that active network parameters may have gaps in their epochs.
|
// This has the implication that *active* network parameters may have gaps in their epochs.
|
||||||
val newNetParams = setNetParams.toNetworkParameters(modifiedTime = Instant.now(), epoch = latestNetParams.epoch + 1)
|
val newNetParams = setNetParams.toNetworkParameters(modifiedTime = Instant.now(), epoch = latestNetParams.epoch + 1)
|
||||||
|
|
||||||
logger.info("Enabling update to network parameters:\n$newNetParams\n$parametersUpdate")
|
logger.info("Enabling update to network parameters:\n$newNetParams\n$parametersUpdate")
|
||||||
@ -205,12 +204,12 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
|
|||||||
"Parameters we are trying to switch to haven't been signed yet"
|
"Parameters we are trying to switch to haven't been signed yet"
|
||||||
}
|
}
|
||||||
// TODO This check is stil not good enough as when it comes to signing, the NetworkMapSigner will just accept
|
// TODO This check is stil not good enough as when it comes to signing, the NetworkMapSigner will just accept
|
||||||
check(latestNetParamsEntity.parametersHash == parametersUpdate.networkParameters.parametersHash) {
|
check(latestNetParamsEntity.hash == parametersUpdate.networkParameters.hash) {
|
||||||
"The latest network parameters is not the scheduled one:\n${latestNetParamsEntity.toNetworkParameters()}\n${parametersUpdate.toParametersUpdate()}"
|
"The latest network parameters is not the scheduled one:\n${latestNetParamsEntity.networkParameters}\n${parametersUpdate.toParametersUpdate()}"
|
||||||
}
|
}
|
||||||
logger.info("Flag day has occurred, however the new network parameters won't be active until the new network map is signed.\n" +
|
logger.info("Flag day has occurred, however the new network parameters won't be active until the new network map is signed.\n" +
|
||||||
"Switching from: $activeNetParams\nTo: ${latestNetParamsEntity.toNetworkParameters()}")
|
"Switching from: $activeNetParams\nTo: ${latestNetParamsEntity.networkParameters}")
|
||||||
networkMapStorage.setFlagDay(SecureHash.parse(parametersUpdate.networkParameters.parametersHash))
|
networkMapStorage.setFlagDay(SecureHash.parse(parametersUpdate.networkParameters.hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleCancelUpdate() {
|
private fun handleCancelUpdate() {
|
||||||
|
@ -57,9 +57,9 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
.build {
|
.build {
|
||||||
networkMapStorage.getActiveNetworkMap()?.let {
|
networkMapStorage.getActiveNetworkMap()?.let {
|
||||||
logger.info("Re-publishing network map")
|
logger.info("Re-publishing network map")
|
||||||
val networkMap = it.toNetworkMap()
|
val networkMap = it.networkMap
|
||||||
val signedNetworkMap = it.toSignedNetworkMap()
|
val signedNetworkMap = it.toSignedNetworkMap()
|
||||||
CachedData(signedNetworkMap, networkMap.nodeInfoHashes.toSet(), it.networkParameters.toNetworkParameters())
|
CachedData(signedNetworkMap, networkMap.nodeInfoHashes.toSet(), it.networkParameters.networkParameters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,11 +109,8 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
logger.debug { "Received ack-parameters with $hash from ${signedParametersHash.sig.by}" }
|
logger.debug { "Received ack-parameters with $hash from ${signedParametersHash.sig.by}" }
|
||||||
nodeInfoStorage.ackNodeInfoParametersUpdate(signedParametersHash.sig.by.encoded.sha256(), hash)
|
nodeInfoStorage.ackNodeInfoParametersUpdate(signedParametersHash.sig.by.encoded.sha256(), hash)
|
||||||
ok()
|
ok()
|
||||||
} catch (e: Exception) {
|
} catch (e: SignatureException) {
|
||||||
when (e) {
|
status(Response.Status.FORBIDDEN).entity(e.message)
|
||||||
is SignatureException -> status(Response.Status.FORBIDDEN).entity(e.message)
|
|
||||||
else -> status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
||||||
}
|
|
||||||
}.build()
|
}.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,30 +15,39 @@
|
|||||||
<changeSet author="R3.Corda" id="1513267683777-1" dbms="mssql">
|
<changeSet author="R3.Corda" id="1513267683777-1" dbms="mssql">
|
||||||
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
|
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
|
<changeSet author="R3.Corda" id="1513267683777-1.1" dbms="h2">
|
||||||
|
<createSequence sequenceName="hibernate_sequence"/>
|
||||||
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1513267683777-1.2" dbms="azure">
|
<changeSet author="R3.Corda" id="1513267683777-1.2" dbms="azure">
|
||||||
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
|
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1513267683777-1.3" dbms="postgres">
|
<changeSet author="R3.Corda" id="1513267683777-1.3" dbms="postgres">
|
||||||
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
|
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1513267683777-1.1" dbms="h2">
|
<changeSet author="R3.Corda" id="1513267683777-1.4" dbms="oracle">
|
||||||
<createSequence sequenceName="hibernate_sequence"/>
|
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-2">
|
<changeSet author="R3.Corda" id="1520338500424-2">
|
||||||
<createTable tableName="certificate_data">
|
<createTable tableName="cert_data">
|
||||||
<column name="id" type="BIGINT">
|
<column name="id" type="BIGINT">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="certificate_path_bytes" type="BLOB"/>
|
<column name="cert_path_bytes" type="BLOB">
|
||||||
<column name="certificate_status" type="INT"/>
|
<constraints nullable="false"/>
|
||||||
<column name="certificate_signing_request" type="NVARCHAR(64)">
|
</column>
|
||||||
|
<column name="cert_status" type="NVARCHAR(16)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="cert_signing_request" type="NVARCHAR(64)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="cert_serial_number" type="NUMERIC(28)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="certificate_serial_number" type="NUMERIC(28)"/>
|
|
||||||
</createTable>
|
</createTable>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-3">
|
<changeSet author="R3.Corda" id="1520338500424-3">
|
||||||
<createTable tableName="certificate_signing_request">
|
<createTable tableName="cert_signing_request">
|
||||||
<column name="request_id" type="NVARCHAR(64)">
|
<column name="request_id" type="NVARCHAR(64)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
@ -50,16 +59,20 @@
|
|||||||
<column name="request_bytes" type="BLOB">
|
<column name="request_bytes" type="BLOB">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="status" type="NVARCHAR(255)">
|
<column name="status" type="NVARCHAR(16)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="public_key_hash" type="NVARCHAR(64)"/>
|
<column name="public_key_hash" type="NVARCHAR(64)">
|
||||||
<column name="modified_by" type="NVARCHAR(512)"/>
|
<constraints nullable="false"/>
|
||||||
<column name="private_network" type="NVARCHAR(255)"/>
|
</column>
|
||||||
|
<column name="modified_by" type="NVARCHAR(64)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="private_network" type="NVARCHAR(64)"/>
|
||||||
</createTable>
|
</createTable>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-4">
|
<changeSet author="R3.Corda" id="1520338500424-4">
|
||||||
<createTable tableName="certificate_signing_request_AUD">
|
<createTable tableName="cert_signing_request_AUD">
|
||||||
<column name="request_id" type="NVARCHAR(64)">
|
<column name="request_id" type="NVARCHAR(64)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
@ -67,10 +80,9 @@
|
|||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="REVTYPE" type="TINYINT"/>
|
<column name="REVTYPE" type="TINYINT"/>
|
||||||
<column name="modified_at" type="TIMESTAMP"/>
|
|
||||||
<column name="remark" type="NVARCHAR(256)"/>
|
<column name="remark" type="NVARCHAR(256)"/>
|
||||||
<column name="status" type="NVARCHAR(255)"/>
|
<column name="status" type="NVARCHAR(16)"/>
|
||||||
<column name="modified_by" type="NVARCHAR(512)"/>
|
<column name="modified_by" type="NVARCHAR(64)"/>
|
||||||
</createTable>
|
</createTable>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-5">
|
<changeSet author="R3.Corda" id="1520338500424-5">
|
||||||
@ -78,7 +90,7 @@
|
|||||||
<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="cert" type="BLOB">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="serialized_network_map" type="BLOB">
|
<column name="serialized_network_map" type="BLOB">
|
||||||
@ -97,8 +109,10 @@
|
|||||||
<column name="hash" type="NVARCHAR(64)">
|
<column name="hash" type="NVARCHAR(64)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="created" type="TIMESTAMP"/>
|
<column name="cert" type="BLOB"/>
|
||||||
<column name="certificate" type="BLOB"/>
|
<column name="created" type="TIMESTAMP">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
<column name="parameters_bytes" type="BLOB">
|
<column name="parameters_bytes" type="BLOB">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
@ -114,7 +128,7 @@
|
|||||||
<column name="signed_node_info_bytes" type="BLOB">
|
<column name="signed_node_info_bytes" type="BLOB">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="certificate_signing_request" type="NVARCHAR(64)">
|
<column name="cert_signing_request" type="NVARCHAR(64)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="is_current" type="BOOLEAN">
|
<column name="is_current" type="BOOLEAN">
|
||||||
@ -123,62 +137,66 @@
|
|||||||
<column name="published_at" type="TIMESTAMP">
|
<column name="published_at" type="TIMESTAMP">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="accepted_parameters_hash" type="NVARCHAR(64)"/>
|
<column name="accepted_network_parameters" type="NVARCHAR(64)"/>
|
||||||
</createTable>
|
</createTable>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-8">
|
<changeSet author="R3.Corda" id="1520338500424-8">
|
||||||
<createTable tableName="REVINFO">
|
<createTable tableName="REVINFO">
|
||||||
<column autoIncrement="true" name="REV" type="INT">
|
<column autoIncrement="true" name="REV" type="INT">
|
||||||
<constraints primaryKey="true" primaryKeyName="PK_REVINFO_REV"/>
|
<constraints primaryKey="true" primaryKeyName="PK__REVINFO__REV"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="REVTSTMP" type="BIGINT"/>
|
<column name="REVTSTMP" type="BIGINT"/>
|
||||||
</createTable>
|
</createTable>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-9">
|
<changeSet author="R3.Corda" id="1520338500424-9">
|
||||||
<addPrimaryKey columnNames="hash" constraintName="PK_NP_H" tableName="network_parameters"/>
|
<addPrimaryKey columnNames="hash" constraintName="PK__NP__H" tableName="network_parameters"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-10">
|
<changeSet author="R3.Corda" id="1520338500424-10">
|
||||||
<addPrimaryKey columnNames="id" constraintName="PK_CD_ID" tableName="certificate_data"/>
|
<addPrimaryKey columnNames="id" constraintName="PK__CD__ID" tableName="cert_data"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-11">
|
<changeSet author="R3.Corda" id="1520338500424-11">
|
||||||
<addPrimaryKey columnNames="request_id, rev" constraintName="PK_CSRA_RID" tableName="certificate_signing_request_AUD"/>
|
<addPrimaryKey columnNames="request_id, rev" constraintName="PK__CSRA__RID"
|
||||||
|
tableName="cert_signing_request_AUD"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-12">
|
<changeSet author="R3.Corda" id="1520338500424-12">
|
||||||
<addPrimaryKey columnNames="node_info_hash" constraintName="PK_NI_NIH" tableName="node_info"/>
|
<addPrimaryKey columnNames="node_info_hash" constraintName="PK__NI__NIH" tableName="node_info"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-13">
|
<changeSet author="R3.Corda" id="1520338500424-13">
|
||||||
<addPrimaryKey columnNames="version" constraintName="PK_NM_V" tableName="network_map"/>
|
<addPrimaryKey columnNames="version" constraintName="PK__NM__V" tableName="network_map"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-14">
|
<changeSet author="R3.Corda" id="1520338500424-14">
|
||||||
<addPrimaryKey columnNames="request_id" constraintName="PK_CSR_RID" tableName="certificate_signing_request"/>
|
<addPrimaryKey columnNames="request_id" constraintName="PK__CSR__RID" tableName="cert_signing_request"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-15">
|
<changeSet author="R3.Corda" id="1520338500424-15">
|
||||||
<addUniqueConstraint columnNames="certificate_signing_request" constraintName="UK_CD_CSR" tableName="certificate_data"/>
|
<addUniqueConstraint columnNames="cert_signing_request" constraintName="UK_CD_CSR" tableName="cert_data"/>
|
||||||
|
</changeSet>
|
||||||
|
<changeSet author="R3.Corda" id="1520338500424-16">
|
||||||
|
<addUniqueConstraint columnNames="cert_serial_number" constraintName="UK_CD_CSN" tableName="cert_data"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-19">
|
<changeSet author="R3.Corda" id="1520338500424-19">
|
||||||
<createIndex indexName="IDX_CSRA_REV" tableName="certificate_signing_request_AUD">
|
<createIndex indexName="IDX__CSRA__REV" tableName="cert_signing_request_AUD">
|
||||||
<column name="REV"/>
|
<column name="REV"/>
|
||||||
</createIndex>
|
</createIndex>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-20">
|
<changeSet author="R3.Corda" id="1520338500424-20">
|
||||||
<createIndex indexName="IDX_PUB_KEY_HASH" tableName="certificate_signing_request">
|
<createIndex indexName="IDX__CSR__PKH" tableName="cert_signing_request">
|
||||||
<column name="public_key_hash"/>
|
<column name="public_key_hash"/>
|
||||||
</createIndex>
|
</createIndex>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-21">
|
<changeSet author="R3.Corda" id="1520338500424-21">
|
||||||
<addForeignKeyConstraint baseColumnNames="REV" baseTableName="certificate_signing_request_AUD"
|
<addForeignKeyConstraint baseColumnNames="REV" baseTableName="cert_signing_request_AUD"
|
||||||
constraintName="FK_CSRA_REV"
|
constraintName="FK__CSRA__REV"
|
||||||
referencedColumnNames="REV" referencedTableName="REVINFO"/>
|
referencedColumnNames="REV" referencedTableName="REVINFO"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-22">
|
<changeSet author="R3.Corda" id="1520338500424-22">
|
||||||
<addForeignKeyConstraint baseColumnNames="certificate_signing_request" baseTableName="node_info"
|
<addForeignKeyConstraint baseColumnNames="cert_signing_request" baseTableName="node_info"
|
||||||
constraintName="FK_NI_CSR"
|
constraintName="FK__NI__CSR"
|
||||||
referencedColumnNames="request_id" referencedTableName="certificate_signing_request"/>
|
referencedColumnNames="request_id" referencedTableName="cert_signing_request"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-23">
|
<changeSet author="R3.Corda" id="1520338500424-23">
|
||||||
<addForeignKeyConstraint baseColumnNames="certificate_signing_request" baseTableName="certificate_data"
|
<addForeignKeyConstraint baseColumnNames="cert_signing_request" baseTableName="cert_data"
|
||||||
constraintName="FK_CD_CSR"
|
constraintName="FK__CD__CSR"
|
||||||
referencedColumnNames="request_id" referencedTableName="certificate_signing_request"/>
|
referencedColumnNames="request_id" referencedTableName="cert_signing_request"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-24">
|
<changeSet author="R3.Corda" id="1520338500424-24">
|
||||||
<createIndex indexName="IDX_NP_HASH" tableName="network_parameters">
|
<createIndex indexName="IDX_NP_HASH" tableName="network_parameters">
|
||||||
@ -186,42 +204,42 @@
|
|||||||
</createIndex>
|
</createIndex>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-25">
|
<changeSet author="R3.Corda" id="1520338500424-25">
|
||||||
<createTable tableName="certificate_revocation_request">
|
<createTable tableName="cert_revocation_request">
|
||||||
<column name="id" type="BIGINT">
|
<column name="id" type="BIGINT">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="request_id" type="NVARCHAR(256)">
|
<column name="request_id" type="NVARCHAR(64)">
|
||||||
<constraints nullable="false" unique="true"/>
|
<constraints nullable="false" unique="true"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="certificate_serial_number" type="NUMERIC(28)">
|
<column name="cert_serial_number" type="NUMERIC(28)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="legal_name" type="NVARCHAR(256)">
|
<column name="legal_name" type="NVARCHAR(256)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="status" type="NVARCHAR(256)">
|
<column name="status" type="NVARCHAR(16)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="reporter" type="NVARCHAR(512)">
|
<column name="reporter" type="NVARCHAR(64)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="modified_by" type="NVARCHAR(512)">
|
<column name="modified_by" type="NVARCHAR(64)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="modified_at" type="TIMESTAMP">
|
<column name="modified_at" type="TIMESTAMP">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="remark" type="NVARCHAR(256)"/>
|
<column name="remark" type="NVARCHAR(256)"/>
|
||||||
<column name="revocation_reason" type="NVARCHAR(256)">
|
<column name="revocation_reason" type="NVARCHAR(32)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="certificate_data" type="BIGINT">
|
<column name="cert_data" type="BIGINT">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
</createTable>
|
</createTable>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-26">
|
<changeSet author="R3.Corda" id="1520338500424-26">
|
||||||
<createTable tableName="certificate_revocation_request_AUD">
|
<createTable tableName="cert_revocation_request_AUD">
|
||||||
<column name="id" type="BIGINT">
|
<column name="id" type="BIGINT">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
@ -229,85 +247,73 @@
|
|||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="revtype" type="TINYINT"/>
|
<column name="revtype" type="TINYINT"/>
|
||||||
<column name="revocation_reason" type="NVARCHAR(256)"/>
|
<column name="revocation_reason" type="NVARCHAR(32)"/>
|
||||||
<column name="modified_at" type="TIMESTAMP"/>
|
<column name="modified_at" type="TIMESTAMP"/>
|
||||||
<column name="modified_by" type="NVARCHAR(256)"/>
|
<column name="modified_by" type="NVARCHAR(64)"/>
|
||||||
<column name="remark" type="NVARCHAR(256)"/>
|
<column name="remark" type="NVARCHAR(256)"/>
|
||||||
<column name="status" type="NVARCHAR(256)"/>
|
<column name="status" type="NVARCHAR(16)"/>
|
||||||
</createTable>
|
</createTable>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-27">
|
<changeSet author="R3.Corda" id="1520338500424-27">
|
||||||
<createTable tableName="certificate_revocation_list">
|
<createTable tableName="cert_revocation_list">
|
||||||
<column name="id" type="BIGINT">
|
<column name="id" type="BIGINT">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="issuer" type="NVARCHAR(256)">
|
<column name="issuer" type="NVARCHAR(16)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="crl_bytes" type="BLOB">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="crl_bytes" type="BLOB"/>
|
|
||||||
<column name="modified_at" type="TIMESTAMP">
|
<column name="modified_at" type="TIMESTAMP">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="signed_by" type="NVARCHAR(512)">
|
<column name="signed_by" type="NVARCHAR(64)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
</createTable>
|
</createTable>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-28">
|
|
||||||
<createTable tableName="certificate_revocation_list_AUD">
|
|
||||||
<column name="id" type="BIGINT">
|
|
||||||
<constraints nullable="false"/>
|
|
||||||
</column>
|
|
||||||
<column name="rev" type="INT">
|
|
||||||
<constraints nullable="false"/>
|
|
||||||
</column>
|
|
||||||
<column name="revtype" type="TINYINT"/>
|
|
||||||
<column name="modified_at" type="TIMESTAMP"/>
|
|
||||||
<column name="signed_by" type="NVARCHAR(512)"/>
|
|
||||||
</createTable>
|
|
||||||
</changeSet>
|
|
||||||
<changeSet author="R3.Corda" id="1520338500424-29">
|
<changeSet author="R3.Corda" id="1520338500424-29">
|
||||||
<addPrimaryKey columnNames="id" constraintName="certificate_revocation_request_pk" tableName="certificate_revocation_request"/>
|
<addPrimaryKey columnNames="id" constraintName="PK__CRR" tableName="cert_revocation_request"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-30">
|
<changeSet author="R3.Corda" id="1520338500424-30">
|
||||||
<addPrimaryKey columnNames="id, rev" constraintName="certificate_revocation_request_AUD_pk" tableName="certificate_revocation_request_AUD"/>
|
<addPrimaryKey columnNames="id, rev" constraintName="PK__CRR_AUD" tableName="cert_revocation_request_AUD"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-31">
|
<changeSet author="R3.Corda" id="1520338500424-31">
|
||||||
<addPrimaryKey columnNames="id" constraintName="certificate_revocation_list_pk" tableName="certificate_revocation_list"/>
|
<addPrimaryKey columnNames="id" constraintName="PK__CRL" tableName="cert_revocation_list"/>
|
||||||
</changeSet>
|
|
||||||
<changeSet author="R3.Corda" id="1520338500424-32">
|
|
||||||
<addPrimaryKey columnNames="id, rev" constraintName="certificate_revocation_list_AUD_pk" tableName="certificate_revocation_list_AUD"/>
|
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-33">
|
<changeSet author="R3.Corda" id="1520338500424-33">
|
||||||
<addForeignKeyConstraint baseColumnNames="certificate_data"
|
<addForeignKeyConstraint baseColumnNames="cert_data"
|
||||||
baseTableName="certificate_revocation_request"
|
baseTableName="cert_revocation_request"
|
||||||
constraintName="cert_data__cert_rev_req_fk"
|
constraintName="FK__CRR__CD"
|
||||||
referencedColumnNames="id"
|
referencedColumnNames="id"
|
||||||
referencedTableName="certificate_data"/>
|
referencedTableName="cert_data"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-34">
|
<changeSet author="R3.Corda" id="1520338500424-34">
|
||||||
<addForeignKeyConstraint baseColumnNames="rev"
|
<addForeignKeyConstraint baseColumnNames="rev"
|
||||||
baseTableName="certificate_revocation_request_AUD"
|
baseTableName="cert_revocation_request_AUD"
|
||||||
constraintName="cert_rev_req__REVINFO_AUD_fk"
|
constraintName="FK__CRR_AUD__REVINFO"
|
||||||
referencedColumnNames="rev"
|
referencedColumnNames="rev"
|
||||||
referencedTableName="REVINFO"/>
|
referencedTableName="REVINFO"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-35">
|
<changeSet author="R3.Corda" id="1520338500424-35">
|
||||||
<createIndex indexName="certificate_revocation_request_AUD_index" tableName="certificate_revocation_request_AUD">
|
<createIndex indexName="IDX__CRR_AUD" tableName="cert_revocation_request_AUD">
|
||||||
<column name="rev"/>
|
<column name="rev"/>
|
||||||
</createIndex>
|
</createIndex>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-36">
|
<changeSet author="R3.Corda" id="1520338500424-36">
|
||||||
<createTable tableName="private_network">
|
<createTable tableName="private_network">
|
||||||
<column name="id" type="NVARCHAR(255)">
|
<column name="id" type="NVARCHAR(64)">
|
||||||
<constraints primaryKey="true" primaryKeyName="PK_PRIV_NETWORK_ID"/>
|
<constraints primaryKey="true" primaryKeyName="PK__PRIV_NETWORK__ID" nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="name" type="NVARCHAR(255)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="name" type="NVARCHAR(255)"/>
|
|
||||||
</createTable>
|
</createTable>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="1520338500424-37">
|
<changeSet author="R3.Corda" id="1520338500424-37">
|
||||||
<addForeignKeyConstraint baseColumnNames="private_network" baseTableName="certificate_signing_request"
|
<addForeignKeyConstraint baseColumnNames="private_network" baseTableName="cert_signing_request"
|
||||||
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">
|
<changeSet author="R3.Corda" id="1520338500424-38">
|
||||||
@ -315,21 +321,32 @@
|
|||||||
constraintName="FK_NM_NP"
|
constraintName="FK_NM_NP"
|
||||||
referencedColumnNames="hash" referencedTableName="network_parameters"/>
|
referencedColumnNames="hash" referencedTableName="network_parameters"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="R3.Corda" id="update-net-params">
|
<changeSet author="R3.Corda" id="1520338500424-39">
|
||||||
<createTable tableName="parameters_update">
|
<createTable tableName="parameters_update">
|
||||||
<column name="description" type="VARCHAR(255)"/>
|
<column name="description" type="VARCHAR(255)">
|
||||||
<column name="update_deadline" type="TIMESTAMP"/>
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="update_deadline" type="TIMESTAMP">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
<column name="id" type="BIGINT">
|
<column name="id" type="BIGINT">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="network_parameters" type="NVARCHAR(64)">
|
<column name="network_parameters" type="NVARCHAR(64)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="flag_day" type="BOOLEAN"/>
|
<column name="flag_day" type="BOOLEAN">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
</createTable>
|
</createTable>
|
||||||
<addPrimaryKey columnNames="id" constraintName="CONSTRAINT_PARAMUPKEY" tableName="parameters_update"/>
|
<addPrimaryKey columnNames="id" constraintName="CONSTRAINT_PARAMUPKEY" tableName="parameters_update"/>
|
||||||
<addForeignKeyConstraint baseTableName="parameters_update" baseColumnNames="network_parameters"
|
<addForeignKeyConstraint baseTableName="parameters_update" baseColumnNames="network_parameters"
|
||||||
constraintName="FK_PU_NP"
|
constraintName="FK_PU_NP"
|
||||||
referencedTableName="network_parameters" referencedColumnNames="hash"/>
|
referencedTableName="network_parameters" referencedColumnNames="hash"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
|
<changeSet author="R3.Corda" id="1520338500424-40">
|
||||||
|
<addForeignKeyConstraint baseColumnNames="accepted_network_parameters" baseTableName="node_info"
|
||||||
|
constraintName="FK__NI__NP"
|
||||||
|
referencedColumnNames="hash" referencedTableName="network_parameters"/>
|
||||||
|
</changeSet>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
@ -15,18 +15,17 @@ fun createNetworkParametersEntity(signingCertAndKeyPair: CertificateAndKeyPair =
|
|||||||
networkParameters: NetworkParameters = testNetworkParameters()): NetworkParametersEntity {
|
networkParameters: NetworkParameters = testNetworkParameters()): NetworkParametersEntity {
|
||||||
val signedNetParams = signingCertAndKeyPair.sign(networkParameters)
|
val signedNetParams = signingCertAndKeyPair.sign(networkParameters)
|
||||||
return NetworkParametersEntity(
|
return NetworkParametersEntity(
|
||||||
parametersHash = signedNetParams.raw.hash.toString(),
|
hash = signedNetParams.raw.hash.toString(),
|
||||||
parametersBytes = signedNetParams.raw.bytes,
|
networkParameters = networkParameters,
|
||||||
signature = signedNetParams.sig.bytes,
|
signature = signedNetParams.sig.bytes,
|
||||||
certificate = signedNetParams.sig.by.encoded
|
certificate = signedNetParams.sig.by
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createNetworkParametersEntityUnsigned(networkParameters: NetworkParameters = testNetworkParameters()): NetworkParametersEntity {
|
fun createNetworkParametersEntityUnsigned(networkParameters: NetworkParameters = testNetworkParameters()): NetworkParametersEntity {
|
||||||
val serialised = networkParameters.serialize()
|
|
||||||
return NetworkParametersEntity(
|
return NetworkParametersEntity(
|
||||||
parametersHash = serialised.hash.toString(),
|
hash = networkParameters.serialize().hash.toString(),
|
||||||
parametersBytes = serialised.bytes,
|
networkParameters = networkParameters,
|
||||||
signature = null,
|
signature = null,
|
||||||
certificate = null
|
certificate = null
|
||||||
)
|
)
|
||||||
@ -36,11 +35,12 @@ fun createNetworkMapEntity(signingCertAndKeyPair: CertificateAndKeyPair = create
|
|||||||
netParamsEntity: NetworkParametersEntity,
|
netParamsEntity: NetworkParametersEntity,
|
||||||
nodeInfoHashes: List<SecureHash> = emptyList(),
|
nodeInfoHashes: List<SecureHash> = emptyList(),
|
||||||
parametersUpdate: ParametersUpdate? = null): NetworkMapEntity {
|
parametersUpdate: ParametersUpdate? = null): NetworkMapEntity {
|
||||||
val signedNetMap = signingCertAndKeyPair.sign(NetworkMap(nodeInfoHashes, SecureHash.parse(netParamsEntity.parametersHash), parametersUpdate))
|
val networkMap = NetworkMap(nodeInfoHashes, SecureHash.parse(netParamsEntity.hash), parametersUpdate)
|
||||||
|
val signedNetworkMap = signingCertAndKeyPair.sign(networkMap)
|
||||||
return NetworkMapEntity(
|
return NetworkMapEntity(
|
||||||
networkMapBytes = signedNetMap.raw.bytes,
|
networkMap = networkMap,
|
||||||
signature = signedNetMap.sig.bytes,
|
signature = signedNetworkMap.sig.bytes,
|
||||||
certificate = signedNetMap.sig.by.encoded,
|
certificate = signedNetworkMap.sig.by,
|
||||||
networkParameters = netParamsEntity
|
networkParameters = netParamsEntity
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
|||||||
assertThat(activeSignedNetworkMap.sig).isEqualTo(networkMapAndSigned.signed.sig)
|
assertThat(activeSignedNetworkMap.sig).isEqualTo(networkMapAndSigned.signed.sig)
|
||||||
assertThat(activeNetworkParameters).isEqualTo(networkParameters)
|
assertThat(activeNetworkParameters).isEqualTo(networkParameters)
|
||||||
assertThat(activeSignedNetworkParameters.sig).isEqualTo(networkParametersSig)
|
assertThat(activeSignedNetworkParameters.sig).isEqualTo(networkParametersSig)
|
||||||
assertThat(SecureHash.parse(activeNetworkParametersEntity.parametersHash))
|
assertThat(SecureHash.parse(activeNetworkParametersEntity.hash))
|
||||||
.isEqualTo(activeNetworkMap.networkParameterHash)
|
.isEqualTo(activeNetworkMap.networkParameterHash)
|
||||||
.isEqualTo(networkParametersHash)
|
.isEqualTo(networkParametersHash)
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
|||||||
// We may have not signed them yet.
|
// We may have not signed them yet.
|
||||||
networkMapStorage.saveNetworkParameters(params2, null)
|
networkMapStorage.saveNetworkParameters(params2, null)
|
||||||
|
|
||||||
assertThat(networkMapStorage.getLatestNetworkParameters()?.toNetworkParameters()).isEqualTo(params2)
|
assertThat(networkMapStorage.getLatestNetworkParameters()?.networkParameters).isEqualTo(params2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -14,15 +14,18 @@ import com.r3.corda.networkmanage.TestBase
|
|||||||
import com.r3.corda.networkmanage.common.utils.hashString
|
import com.r3.corda.networkmanage.common.utils.hashString
|
||||||
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.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.CertRole
|
import net.corda.core.internal.CertRole
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
||||||
|
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.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
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
|
||||||
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.internal.TestNodeInfoBuilder
|
import net.corda.testing.internal.TestNodeInfoBuilder
|
||||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||||
import net.corda.testing.internal.signWith
|
import net.corda.testing.internal.signWith
|
||||||
@ -45,13 +48,15 @@ class PersistentNodeInfoStorageTest : TestBase() {
|
|||||||
private lateinit var networkMapStorage: PersistentNetworkMapStorage
|
private lateinit var networkMapStorage: PersistentNetworkMapStorage
|
||||||
private lateinit var persistence: CordaPersistence
|
private lateinit var persistence: CordaPersistence
|
||||||
private lateinit var rootCaCert: X509Certificate
|
private lateinit var rootCaCert: X509Certificate
|
||||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
private lateinit var doormanCertAndKeyPair: CertificateAndKeyPair
|
||||||
|
private lateinit var networkMapCertAndKeyPair: CertificateAndKeyPair
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun startDb() {
|
fun startDb() {
|
||||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||||
rootCaCert = rootCa.certificate
|
rootCaCert = rootCa.certificate
|
||||||
this.intermediateCa = intermediateCa
|
this.doormanCertAndKeyPair = intermediateCa
|
||||||
|
networkMapCertAndKeyPair = createDevNetworkMapCa(rootCa)
|
||||||
persistence = configureDatabase(MockServices.makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))
|
persistence = configureDatabase(MockServices.makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))
|
||||||
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
|
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
|
||||||
requestStorage = PersistentCertificateSigningRequestStorage(persistence)
|
requestStorage = PersistentCertificateSigningRequestStorage(persistence)
|
||||||
@ -70,8 +75,8 @@ class PersistentNodeInfoStorageTest : TestBase() {
|
|||||||
val name = CordaX500Name(organisation = "Test", locality = "London", country = "GB")
|
val name = CordaX500Name(organisation = "Test", locality = "London", country = "GB")
|
||||||
val nodeCaCert = X509Utilities.createCertificate(
|
val nodeCaCert = X509Utilities.createCertificate(
|
||||||
CertificateType.NODE_CA,
|
CertificateType.NODE_CA,
|
||||||
intermediateCa.certificate,
|
doormanCertAndKeyPair.certificate,
|
||||||
intermediateCa.keyPair,
|
doormanCertAndKeyPair.keyPair,
|
||||||
name.x500Principal,
|
name.x500Principal,
|
||||||
keyPair.public)
|
keyPair.public)
|
||||||
|
|
||||||
@ -85,7 +90,7 @@ class PersistentNodeInfoStorageTest : TestBase() {
|
|||||||
|
|
||||||
requestStorage.putCertificatePath(
|
requestStorage.putCertificatePath(
|
||||||
requestId,
|
requestId,
|
||||||
X509Utilities.buildCertPath(nodeCaCert, intermediateCa.certificate, rootCaCert),
|
X509Utilities.buildCertPath(nodeCaCert, doormanCertAndKeyPair.certificate, rootCaCert),
|
||||||
CertificateSigningRequestStorage.DOORMAN_SIGNATURE)
|
CertificateSigningRequestStorage.DOORMAN_SIGNATURE)
|
||||||
|
|
||||||
val storedCertPath = nodeInfoStorage.getCertificatePath(SecureHash.parse(keyPair.public.hashString()))
|
val storedCertPath = nodeInfoStorage.getCertificatePath(SecureHash.parse(keyPair.public.hashString()))
|
||||||
@ -150,16 +155,37 @@ class PersistentNodeInfoStorageTest : TestBase() {
|
|||||||
@Test
|
@Test
|
||||||
fun `accept parameters updates node info correctly`() {
|
fun `accept parameters updates node info correctly`() {
|
||||||
// given
|
// given
|
||||||
val (nodeInfoWithSigned) = createValidSignedNodeInfo("Test", requestStorage)
|
val (nodeInfoAndSigned) = createValidSignedNodeInfo("Test", requestStorage)
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val paramsHash = SecureHash.randomSHA256()
|
val networkParameters = testNetworkParameters()
|
||||||
val nodeInfoHash = nodeInfoStorage.putNodeInfo(nodeInfoWithSigned)
|
val sigWithCert = networkMapCertAndKeyPair.sign(networkParameters).sig
|
||||||
nodeInfoStorage.ackNodeInfoParametersUpdate(SecureHash.parse(nodeInfoWithSigned.nodeInfo.legalIdentities.first().owningKey.hashString()), paramsHash)
|
val netParamsHash = networkMapStorage.saveNetworkParameters(networkParameters, sigWithCert)
|
||||||
|
val nodeInfoHash = nodeInfoStorage.putNodeInfo(nodeInfoAndSigned)
|
||||||
|
nodeInfoStorage.ackNodeInfoParametersUpdate(nodeInfoAndSigned.nodeInfo.legalIdentities[0].owningKey.encoded.sha256(), netParamsHash)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
val persistedParametersHash = nodeInfoStorage.getAcceptedParametersUpdateHash(nodeInfoHash)
|
val acceptedNetworkParameters = nodeInfoStorage.getAcceptedNetworkParameters(nodeInfoHash)
|
||||||
assertThat(persistedParametersHash).isEqualTo(paramsHash)
|
assertThat(acceptedNetworkParameters?.hash).isEqualTo(netParamsHash.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `updating node info after it's accepted network parameters`() {
|
||||||
|
val networkParameters = testNetworkParameters()
|
||||||
|
val sigWithCert = networkMapCertAndKeyPair.sign(networkParameters).sig
|
||||||
|
val netParamsHash = networkMapStorage.saveNetworkParameters(networkParameters, sigWithCert)
|
||||||
|
|
||||||
|
val (nodeInfoAndSigned, privateKey) = createValidSignedNodeInfo("Test", requestStorage)
|
||||||
|
nodeInfoStorage.putNodeInfo(nodeInfoAndSigned)
|
||||||
|
|
||||||
|
nodeInfoStorage.ackNodeInfoParametersUpdate(nodeInfoAndSigned.nodeInfo.legalIdentities[0].owningKey.encoded.sha256(), netParamsHash)
|
||||||
|
|
||||||
|
val nodeInfo2 = nodeInfoAndSigned.nodeInfo.copy(serial = 2)
|
||||||
|
val nodeInfoAndSigned2 = NodeInfoAndSigned(nodeInfo2.signWith(listOf(privateKey)))
|
||||||
|
val nodeInfoHash2 = nodeInfoStorage.putNodeInfo(nodeInfoAndSigned2)
|
||||||
|
|
||||||
|
val acceptedNetworkParameters = nodeInfoStorage.getAcceptedNetworkParameters(nodeInfoHash2)
|
||||||
|
assertThat(acceptedNetworkParameters?.hash).isEqualTo(netParamsHash.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,6 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
// given
|
// given
|
||||||
val currentNetworkParameters = createNetworkParametersEntity(signingCertAndKeyPair)
|
val currentNetworkParameters = createNetworkParametersEntity(signingCertAndKeyPair)
|
||||||
val updateNetworkParameters = createNetworkParametersEntityUnsigned(testNetworkParameters(epoch = 2))
|
val updateNetworkParameters = createNetworkParametersEntityUnsigned(testNetworkParameters(epoch = 2))
|
||||||
val updateParametersHash = SecureHash.parse(updateNetworkParameters.parametersHash)
|
|
||||||
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 = createNetworkMapEntity(signingCertAndKeyPair, currentNetworkParameters, emptyList(), null)
|
||||||
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(netMapEntity)
|
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(netMapEntity)
|
||||||
@ -170,8 +169,8 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
val paramsCaptor = argumentCaptor<NetworkParameters>()
|
val paramsCaptor = argumentCaptor<NetworkParameters>()
|
||||||
val signatureCaptor = argumentCaptor<DigitalSignatureWithCert>()
|
val signatureCaptor = argumentCaptor<DigitalSignatureWithCert>()
|
||||||
verify(networkMapStorage, times(1)).saveNetworkParameters(paramsCaptor.capture(), signatureCaptor.capture())
|
verify(networkMapStorage, times(1)).saveNetworkParameters(paramsCaptor.capture(), signatureCaptor.capture())
|
||||||
assertEquals(paramsCaptor.firstValue, updateNetworkParameters.toNetworkParameters())
|
assertEquals(paramsCaptor.firstValue, updateNetworkParameters.networkParameters)
|
||||||
assertThat(signatureCaptor.firstValue.verify(updateNetworkParameters.parametersBytes))
|
signatureCaptor.firstValue.verify(updateNetworkParameters.networkParameters.serialize())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -206,7 +205,7 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
argumentCaptor<NetworkMapAndSigned>().apply {
|
argumentCaptor<NetworkMapAndSigned>().apply {
|
||||||
verify(networkMapStorage).saveNewActiveNetworkMap(capture())
|
verify(networkMapStorage).saveNewActiveNetworkMap(capture())
|
||||||
val netMap = firstValue.networkMap
|
val netMap = firstValue.networkMap
|
||||||
assertEquals(SecureHash.parse(updateNetworkParameters.parametersHash), netMap.networkParameterHash)
|
assertEquals(SecureHash.parse(updateNetworkParameters.hash), netMap.networkParameterHash)
|
||||||
assertEquals(emptyList(), netMap.nodeInfoHashes)
|
assertEquals(emptyList(), netMap.nodeInfoHashes)
|
||||||
assertEquals(null, netMap.parametersUpdate)
|
assertEquals(null, netMap.parametersUpdate)
|
||||||
}
|
}
|
||||||
@ -231,7 +230,7 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
argumentCaptor<NetworkMapAndSigned>().apply {
|
argumentCaptor<NetworkMapAndSigned>().apply {
|
||||||
verify(networkMapStorage).saveNewActiveNetworkMap(capture())
|
verify(networkMapStorage).saveNewActiveNetworkMap(capture())
|
||||||
val netMap = firstValue.networkMap
|
val netMap = firstValue.networkMap
|
||||||
assertEquals(SecureHash.parse(activeNetworkParameters.parametersHash), netMap.networkParameterHash)
|
assertEquals(SecureHash.parse(activeNetworkParameters.hash), netMap.networkParameterHash)
|
||||||
assertEquals(emptyList(), netMap.nodeInfoHashes)
|
assertEquals(emptyList(), netMap.nodeInfoHashes)
|
||||||
assertEquals(null, netMap.parametersUpdate)
|
assertEquals(null, netMap.parametersUpdate)
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ class NetworkMapWebServiceTest {
|
|||||||
it.start()
|
it.start()
|
||||||
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
||||||
verify(networkMapStorage, times(1)).getActiveNetworkMap()
|
verify(networkMapStorage, times(1)).getActiveNetworkMap()
|
||||||
assertEquals(signedNetworkMapResponse.verifiedNetworkMapCert(rootCaCert), networkMapEntity.toNetworkMap())
|
assertEquals(signedNetworkMapResponse.verifiedNetworkMapCert(rootCaCert), networkMapEntity.networkMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,14 @@ data class NetworkMap(
|
|||||||
val nodeInfoHashes: List<SecureHash>,
|
val nodeInfoHashes: List<SecureHash>,
|
||||||
val networkParameterHash: SecureHash,
|
val networkParameterHash: SecureHash,
|
||||||
val parametersUpdate: ParametersUpdate?
|
val parametersUpdate: ParametersUpdate?
|
||||||
)
|
) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return """${NetworkMap::class.java.simpleName}(nodeInfoHashes=
|
||||||
|
${nodeInfoHashes.joinToString("\n")}
|
||||||
|
networkParameterHash=$networkParameterHash
|
||||||
|
parametersUpdate=$parametersUpdate)"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data class representing scheduled network parameters update.
|
* Data class representing scheduled network parameters update.
|
||||||
|
@ -48,8 +48,7 @@ class NetworkParametersReader(private val trustRoot: X509Certificate,
|
|||||||
// you get them from network map, but you have to run the approval step.
|
// you get them from network map, but you have to run the approval step.
|
||||||
if (signedParametersFromFile == null) { // Node joins for the first time.
|
if (signedParametersFromFile == null) { // Node joins for the first time.
|
||||||
downloadParameters(trustRoot, advertisedParametersHash)
|
downloadParameters(trustRoot, advertisedParametersHash)
|
||||||
}
|
} else if (signedParametersFromFile.raw.hash == advertisedParametersHash) { // Restarted with the same parameters.
|
||||||
else if (signedParametersFromFile.raw.hash == advertisedParametersHash) { // Restarted with the same parameters.
|
|
||||||
signedParametersFromFile.verifiedNetworkMapCert(trustRoot)
|
signedParametersFromFile.verifiedNetworkMapCert(trustRoot)
|
||||||
} else { // Update case.
|
} else { // Update case.
|
||||||
readParametersUpdate(advertisedParametersHash, signedParametersFromFile.raw.hash).verifiedNetworkMapCert(trustRoot)
|
readParametersUpdate(advertisedParametersHash, signedParametersFromFile.raw.hash).verifiedNetworkMapCert(trustRoot)
|
||||||
@ -74,6 +73,7 @@ class NetworkParametersReader(private val trustRoot: X509Certificate,
|
|||||||
"Please update node to use correct network parameters file.")
|
"Please update node to use correct network parameters file.")
|
||||||
}
|
}
|
||||||
parametersUpdateFile.moveTo(networkParamsFile, StandardCopyOption.REPLACE_EXISTING)
|
parametersUpdateFile.moveTo(networkParamsFile, StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
logger.info("Scheduled update to network parameters has occurred - node now updated to these new parameters.")
|
||||||
return signedUpdatedParameters
|
return signedUpdatedParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,9 @@ package net.corda.node.services.network
|
|||||||
|
|
||||||
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.internal.*
|
import net.corda.core.internal.openHttpConnection
|
||||||
|
import net.corda.core.internal.post
|
||||||
|
import net.corda.core.internal.responseAs
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
@ -21,7 +23,10 @@ import net.corda.core.utilities.seconds
|
|||||||
import net.corda.core.utilities.trace
|
import net.corda.core.utilities.trace
|
||||||
import net.corda.node.utilities.registration.cacheControl
|
import net.corda.node.utilities.registration.cacheControl
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.network.*
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
|
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||||
|
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
||||||
|
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
@ -54,10 +59,7 @@ class NetworkMapClient(compatibilityZoneURL: URL, val trustedRoot: X509Certifica
|
|||||||
val signedNetworkMap = connection.responseAs<SignedNetworkMap>()
|
val signedNetworkMap = connection.responseAs<SignedNetworkMap>()
|
||||||
val networkMap = signedNetworkMap.verifiedNetworkMapCert(trustedRoot)
|
val networkMap = signedNetworkMap.verifiedNetworkMapCert(trustedRoot)
|
||||||
val timeout = connection.cacheControl().maxAgeSeconds().seconds
|
val timeout = connection.cacheControl().maxAgeSeconds().seconds
|
||||||
logger.trace {
|
logger.trace { "Fetched network map update from $networkMapUrl successfully: $networkMap" }
|
||||||
"Fetched network map update from $networkMapUrl successfully, retrieved ${networkMap.nodeInfoHashes.size} " +
|
|
||||||
"node info hashes. Node Info hashes:\n${networkMap.nodeInfoHashes.joinToString("\n")}"
|
|
||||||
}
|
|
||||||
return NetworkMapResponse(networkMap, timeout)
|
return NetworkMapResponse(networkMap, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,12 +157,13 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal,
|
|||||||
// This update was handled already.
|
// This update was handled already.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val newParameters = networkMapClient.getNetworkParameters(update.newParametersHash)
|
val newSignedNetParams = networkMapClient.getNetworkParameters(update.newParametersHash)
|
||||||
logger.info("Downloaded new network parameters: $newParameters from the update: $update")
|
val newNetParams = newSignedNetParams.verifiedNetworkMapCert(networkMapClient.trustedRoot)
|
||||||
newNetworkParameters = Pair(update, newParameters)
|
logger.info("Downloaded new network parameters: $newNetParams from the update: $update")
|
||||||
|
newNetworkParameters = Pair(update, newSignedNetParams)
|
||||||
val updateInfo = ParametersUpdateInfo(
|
val updateInfo = ParametersUpdateInfo(
|
||||||
update.newParametersHash,
|
update.newParametersHash,
|
||||||
newParameters.verifiedNetworkMapCert(networkMapClient.trustedRoot),
|
newNetParams,
|
||||||
update.description,
|
update.description,
|
||||||
update.updateDeadline)
|
update.updateDeadline)
|
||||||
parametersUpdatesTrack.onNext(updateInfo)
|
parametersUpdatesTrack.onNext(updateInfo)
|
||||||
@ -172,15 +173,17 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal,
|
|||||||
networkMapClient ?: throw IllegalStateException("Network parameters updates are not support without compatibility zone configured")
|
networkMapClient ?: throw IllegalStateException("Network parameters updates are not support without compatibility zone configured")
|
||||||
// TODO This scenario will happen if node was restarted and didn't download parameters yet, but we accepted them.
|
// TODO This scenario will happen if node was restarted and didn't download parameters yet, but we accepted them.
|
||||||
// Add persisting of newest parameters from update.
|
// Add persisting of newest parameters from update.
|
||||||
val (_, newParams) = requireNotNull(newNetworkParameters) { "Couldn't find parameters update for the hash: $parametersHash" }
|
val (update, signedNewNetParams) = requireNotNull(newNetworkParameters) { "Couldn't find parameters update for the hash: $parametersHash" }
|
||||||
// We should check that we sign the right data structure hash.
|
// We should check that we sign the right data structure hash.
|
||||||
val newParametersHash = newParams.verifiedNetworkMapCert(networkMapClient.trustedRoot).serialize().hash
|
val newNetParams = signedNewNetParams.verifiedNetworkMapCert(networkMapClient.trustedRoot)
|
||||||
|
val newParametersHash = newNetParams.serialize().hash
|
||||||
if (parametersHash == newParametersHash) {
|
if (parametersHash == newParametersHash) {
|
||||||
// The latest parameters have priority.
|
// The latest parameters have priority.
|
||||||
newParams.serialize()
|
signedNewNetParams.serialize()
|
||||||
.open()
|
.open()
|
||||||
.copyTo(baseDirectory / NETWORK_PARAMS_UPDATE_FILE_NAME, StandardCopyOption.REPLACE_EXISTING)
|
.copyTo(baseDirectory / NETWORK_PARAMS_UPDATE_FILE_NAME, StandardCopyOption.REPLACE_EXISTING)
|
||||||
networkMapClient.ackNetworkParametersUpdate(sign(parametersHash))
|
networkMapClient.ackNetworkParametersUpdate(sign(parametersHash))
|
||||||
|
logger.info("Accepted network parameter update $update: $newNetParams")
|
||||||
} else {
|
} else {
|
||||||
throw IllegalArgumentException("Refused to accept parameters with hash $parametersHash because network map " +
|
throw IllegalArgumentException("Refused to accept parameters with hash $parametersHash because network map " +
|
||||||
"advertises update with hash $newParametersHash. Please check newest version")
|
"advertises update with hash $newParametersHash. Please check newest version")
|
||||||
|
Loading…
Reference in New Issue
Block a user