mirror of
https://github.com/corda/corda.git
synced 2024-12-28 00:38:55 +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",
|
||||
updateDeadline = updateDeadline
|
||||
)
|
||||
)
|
||||
)
|
||||
))
|
||||
|
||||
updates.expectEvents(isStrict = true) {
|
||||
sequence(
|
||||
|
@ -40,6 +40,7 @@ interface NetworkMapStorage {
|
||||
/**
|
||||
* 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>
|
||||
|
||||
/**
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
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.node.NodeInfo
|
||||
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
||||
@ -33,11 +34,10 @@ interface NodeInfoStorage {
|
||||
fun getNodeInfo(nodeInfoHash: SecureHash): SignedNodeInfo?
|
||||
|
||||
/**
|
||||
* Retrieve latest accepted parameters hash for nodeInfo with given hash.
|
||||
* @return Hash of network parameters that the node has accepted or null if couldn't find node info with given hash or
|
||||
* Returns the 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
|
||||
*/
|
||||
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.
|
||||
|
@ -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.CertificateRevocationListEntity
|
||||
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.DatabaseTransaction
|
||||
import java.math.BigInteger
|
||||
@ -21,10 +20,7 @@ class PersistentCertificateRevocationListStorage(private val database: CordaPers
|
||||
}
|
||||
}
|
||||
// We just want the last signed entry
|
||||
val crlEntity = session.createQuery(query).setMaxResults(1).uniqueResult()
|
||||
crlEntity?.let {
|
||||
X509CertificateFactory().delegate.generateCRL(crlEntity.crlBytes.inputStream()) as X509CRL
|
||||
}
|
||||
session.createQuery(query).setMaxResults(1).uniqueResult()?.crl
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +30,7 @@ class PersistentCertificateRevocationListStorage(private val database: CordaPers
|
||||
revokeCertificate(it.serialNumber, revokedAt, this)
|
||||
}
|
||||
session.save(CertificateRevocationListEntity(
|
||||
crlBytes = crl.encoded,
|
||||
crl = crl,
|
||||
crlIssuer = crlIssuer,
|
||||
signedBy = signedBy,
|
||||
modifiedAt = Instant.now()
|
||||
|
@ -51,7 +51,7 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
|
||||
session.merge(certificateSigningRequest)
|
||||
val certificateDataEntity = CertificateDataEntity(
|
||||
certificateStatus = CertificateStatus.VALID,
|
||||
certificatePathBytes = certPath.encoded,
|
||||
certPath = certPath,
|
||||
certificateSigningRequest = certificateSigningRequest,
|
||||
certificateSerialNumber = certPath.x509Certificates.first().serialNumber)
|
||||
session.persist(certificateDataEntity)
|
||||
@ -71,7 +71,7 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
|
||||
requestId = requestId,
|
||||
legalName = legalNameOrRejectMessage as? CordaX500Name,
|
||||
publicKeyHash = toSupportedPublicKey(request.subjectPublicKeyInfo).hashString(),
|
||||
requestBytes = request.encoded,
|
||||
request = request,
|
||||
remark = legalNameOrRejectMessage as? String,
|
||||
modifiedBy = CertificateSigningRequestStorage.DOORMAN_SIGNATURE,
|
||||
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.node.NetworkParameters
|
||||
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.SignedNetworkParameters
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import java.time.Instant
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* Database implementation of the [NetworkMapStorage] interface
|
||||
@ -49,9 +48,9 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
||||
"Network parameters ${networkMap.networkParameterHash} are not signed"
|
||||
}
|
||||
session.save(NetworkMapEntity(
|
||||
networkMapBytes = signedNetworkMap.raw.bytes,
|
||||
networkMap = networkMap,
|
||||
signature = signedNetworkMap.sig.bytes,
|
||||
certificate = signedNetworkMap.sig.by.encoded,
|
||||
certificate = signedNetworkMap.sig.by,
|
||||
networkParameters = networkParametersEntity
|
||||
))
|
||||
}
|
||||
@ -85,21 +84,22 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
||||
}
|
||||
|
||||
override fun saveNetworkParameters(networkParameters: NetworkParameters, signature: DigitalSignatureWithCert?): SecureHash {
|
||||
val serialised = networkParameters.serialize()
|
||||
val hash = serialised.hash
|
||||
val serialized = networkParameters.serialize()
|
||||
signature?.verify(serialized)
|
||||
val hash = serialized.hash
|
||||
database.transaction {
|
||||
val entity = getNetworkParametersEntity(hash)
|
||||
val newNetworkParamsEntity = if (entity != null) {
|
||||
entity.copy(
|
||||
signature = signature?.bytes,
|
||||
certificate = signature?.by?.encoded
|
||||
certificate = signature?.by
|
||||
)
|
||||
} else {
|
||||
NetworkParametersEntity(
|
||||
parametersBytes = serialised.bytes,
|
||||
parametersHash = hash.toString(),
|
||||
networkParameters = networkParameters,
|
||||
hash = hash.toString(),
|
||||
signature = signature?.bytes,
|
||||
certificate = signature?.by?.encoded
|
||||
certificate = signature?.by
|
||||
)
|
||||
}
|
||||
session.merge(newNetworkParamsEntity)
|
||||
@ -139,7 +139,7 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
||||
|
||||
override fun getParametersUpdate(): ParametersUpdateEntity? {
|
||||
return database.transaction {
|
||||
val currentParametersHash = getActiveNetworkMap()?.toNetworkMap()?.networkParameterHash
|
||||
val currentParametersHash = getActiveNetworkMap()?.networkParameters?.hash
|
||||
val latestParameters = getLatestNetworkParameters()
|
||||
val criteria = session.criteriaBuilder.createQuery(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"
|
||||
}
|
||||
// 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"
|
||||
}
|
||||
parametersUpdate
|
||||
@ -160,16 +160,16 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
||||
override fun setFlagDay(parametersHash: SecureHash) {
|
||||
database.transaction {
|
||||
val parametersUpdateEntity = getParametersUpdate() ?: throw IllegalArgumentException("Setting flag day but no parameters update to switch to")
|
||||
if (parametersHash.toString() != parametersUpdateEntity.networkParameters.parametersHash) {
|
||||
throw IllegalArgumentException("Setting flag day for parameters: $parametersHash, but in database we have update for: ${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.hash}")
|
||||
}
|
||||
session.merge(parametersUpdateEntity.copy(flagDay = true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun DatabaseTransaction.getNetworkParametersEntity(hash: SecureHash): NetworkParametersEntity? {
|
||||
return uniqueEntityWhere { builder, path ->
|
||||
builder.equal(path.get<String>(NetworkParametersEntity::parametersHash.name), hash.toString())
|
||||
}
|
||||
internal fun DatabaseTransaction.getNetworkParametersEntity(hash: SecureHash): NetworkParametersEntity? {
|
||||
return uniqueEntityWhere { builder, path ->
|
||||
builder.equal(path.get<String>(NetworkParametersEntity::hash.name), hash.toString())
|
||||
}
|
||||
}
|
||||
|
@ -11,14 +11,13 @@
|
||||
package com.r3.corda.networkmanage.common.persistence
|
||||
|
||||
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.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.hashString
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.internal.CertRole
|
||||
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.SignedNodeInfo
|
||||
import net.corda.nodeapi.internal.crypto.x509Certificates
|
||||
@ -34,7 +33,7 @@ class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeIn
|
||||
val (nodeInfo, signedNodeInfo) = nodeInfoAndSigned
|
||||
val nodeCaCert = nodeInfo.legalIdentitiesAndCerts[0].certPath.x509Certificates.find { CertRole.extract(it) == NODE_CA }
|
||||
nodeCaCert ?: throw IllegalArgumentException("Missing Node CA")
|
||||
return database.transaction {
|
||||
database.transaction {
|
||||
// TODO Move these checks out of data access layer
|
||||
val request = requireNotNull(getSignedRequestByPublicHash(nodeCaCert.publicKey.encoded.sha256())) {
|
||||
"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" }
|
||||
}
|
||||
|
||||
// Update any [NodeInfoEntity] instance for this CSR as not current.
|
||||
entitiesWhere<NodeInfoEntity> { builder, path ->
|
||||
val requestEq = builder.equal(path.get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name), request)
|
||||
val isCurrent = builder.isTrue(path.get<Boolean>(NodeInfoEntity::isCurrent.name))
|
||||
builder.and(requestEq, isCurrent)
|
||||
}.resultStream.use { existingNodeInfos ->
|
||||
existingNodeInfos.forEach { session.merge(it.copy(isCurrent = false)) }
|
||||
}
|
||||
val existingNodeInfos = session.createQuery(
|
||||
"from ${NodeInfoEntity::class.java.name} n where n.certificateSigningRequest = :csr and n.isCurrent = true order by n.publishedAt desc",
|
||||
NodeInfoEntity::class.java)
|
||||
.setParameter("csr", request)
|
||||
.resultList
|
||||
|
||||
val hash = signedNodeInfo.raw.hash
|
||||
val hashedNodeInfo = NodeInfoEntity(
|
||||
nodeInfoHash = hash.toString(),
|
||||
identityPkHash = nodeInfo.legalIdentities.first().owningKey.hashString(),
|
||||
// Update any [NodeInfoEntity] instance for this CSR as not current.
|
||||
existingNodeInfos.forEach { session.merge(it.copy(isCurrent = false)) }
|
||||
|
||||
session.save(NodeInfoEntity(
|
||||
nodeInfoHash = signedNodeInfo.raw.hash.toString(),
|
||||
publicKeyHash = nodeInfo.legalIdentities[0].owningKey.hashString(),
|
||||
certificateSigningRequest = request,
|
||||
signedNodeInfoBytes = signedNodeInfo.serialize().bytes,
|
||||
isCurrent = true)
|
||||
session.save(hashedNodeInfo)
|
||||
hash
|
||||
signedNodeInfo = signedNodeInfo,
|
||||
isCurrent = true,
|
||||
acceptedNetworkParameters = existingNodeInfos.firstOrNull()?.acceptedNetworkParameters
|
||||
))
|
||||
}
|
||||
return signedNodeInfo.raw.hash
|
||||
}
|
||||
|
||||
override fun getNodeInfo(nodeInfoHash: SecureHash): SignedNodeInfo? {
|
||||
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 {
|
||||
val hashString = session.find(NodeInfoEntity::class.java, nodeInfoHash.toString())?.acceptedParametersHash
|
||||
if (hashString == null || hashString.isEmpty()) null else SecureHash.parse(hashString)
|
||||
session.find(NodeInfoEntity::class.java, nodeInfoHash.toString())?.acceptedNetworkParameters
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCertificatePath(publicKeyHash: SecureHash): CertPath? {
|
||||
return database.transaction {
|
||||
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 query = builder.createQuery(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 newInfo = nodeInfo.copy(acceptedParametersHash = acceptedParametersHash.toString())
|
||||
val nodeInfo = requireNotNull(session.createQuery(query).setMaxResults(1).uniqueResult()) {
|
||||
"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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
import com.r3.corda.networkmanage.common.persistence.CrlIssuer
|
||||
import java.security.cert.X509CRL
|
||||
import java.time.Instant
|
||||
import javax.persistence.*
|
||||
|
||||
@Entity
|
||||
@Table(name = "certificate_revocation_list")
|
||||
@Table(name = "cert_revocation_list")
|
||||
class CertificateRevocationListEntity(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||
val id: Long? = null,
|
||||
|
||||
@Column(name = "issuer")
|
||||
@Column(name = "issuer", length = 16, nullable = false, columnDefinition = "NVARCHAR(16)")
|
||||
@Enumerated(EnumType.STRING)
|
||||
val crlIssuer: CrlIssuer,
|
||||
|
||||
@Lob
|
||||
@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,
|
||||
|
||||
@Column(name = "modified_at", nullable = false)
|
||||
|
@ -9,73 +9,52 @@ import java.time.Instant
|
||||
import javax.persistence.*
|
||||
|
||||
@Entity
|
||||
@Table(name = "certificate_revocation_request")
|
||||
class CertificateRevocationRequestEntity(
|
||||
@Table(name = "cert_revocation_request")
|
||||
data class CertificateRevocationRequestEntity(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||
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,
|
||||
|
||||
@OneToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "certificate_data")
|
||||
@JoinColumn(name = "cert_data", nullable = false)
|
||||
val certificateData: CertificateDataEntity,
|
||||
|
||||
@Column(name = "certificate_serial_number", nullable = false)
|
||||
@Column(name = "cert_serial_number", nullable = false, columnDefinition = "NUMERIC(28)")
|
||||
val certificateSerialNumber: BigInteger,
|
||||
|
||||
@Column(name = "legal_name", length = 256, nullable = false)
|
||||
@Convert(converter = CordaX500NameAttributeConverter::class)
|
||||
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
|
||||
@Column(name = "status", nullable = false)
|
||||
@Column(name = "status", length = 16, nullable = false, columnDefinition = "NVARCHAR(16)")
|
||||
@Enumerated(EnumType.STRING)
|
||||
val status: RequestStatus = RequestStatus.NEW,
|
||||
|
||||
@Column(name = "reporter", nullable = false, length = 512)
|
||||
@Column(name = "reporter", nullable = false, length = 64)
|
||||
val reporter: String,
|
||||
|
||||
@Audited
|
||||
@Column(name = "modified_by", nullable = false, length = 512)
|
||||
@Column(name = "modified_by", nullable = false, length = 64)
|
||||
val modifiedBy: String,
|
||||
|
||||
@Audited
|
||||
@Column(name = "modified_at", nullable = false)
|
||||
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
|
||||
@Column(name = "revocation_reason", nullable = false)
|
||||
@Column(name = "revocation_reason", length = 32, nullable = false, columnDefinition = "NVARCHAR(32)")
|
||||
@Enumerated(EnumType.STRING)
|
||||
val revocationReason: CRLReason,
|
||||
|
||||
@Audited
|
||||
@Column(name = "remark", length = 256)
|
||||
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.CertificateStatus
|
||||
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.identity.CordaX500Name
|
||||
import net.corda.nodeapi.internal.crypto.x509Certificates
|
||||
@ -26,10 +25,10 @@ import java.time.Instant
|
||||
import javax.persistence.*
|
||||
|
||||
@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(
|
||||
@Id
|
||||
@Column(name = "request_id", length = 64)
|
||||
@Column(name = "request_id", length = 64, nullable = false)
|
||||
val requestId: String,
|
||||
|
||||
// TODO: Store X500Name with a proper schema.
|
||||
@ -37,19 +36,21 @@ data class CertificateSigningRequestEntity(
|
||||
@Convert(converter = CordaX500NameAttributeConverter::class)
|
||||
val legalName: CordaX500Name?,
|
||||
|
||||
@Column(name = "public_key_hash", length = 64)
|
||||
@Column(name = "public_key_hash", length = 64, nullable = false)
|
||||
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
|
||||
@Column(name = "status", nullable = false)
|
||||
@Column(name = "status", length = 16, nullable = false, columnDefinition = "NVARCHAR(16)")
|
||||
@Enumerated(EnumType.STRING)
|
||||
val status: RequestStatus = RequestStatus.NEW,
|
||||
|
||||
@Audited
|
||||
@Column(name = "modified_by", length = 512)
|
||||
@Column(name = "modified_by", length = 64, nullable = false)
|
||||
val modifiedBy: String,
|
||||
|
||||
@Audited
|
||||
// TODO: Use audit framework instead.
|
||||
@Column(name = "modified_at", nullable = false)
|
||||
val modifiedAt: Instant = Instant.now(),
|
||||
|
||||
@ -62,10 +63,11 @@ data class CertificateSigningRequestEntity(
|
||||
|
||||
@Lob
|
||||
@Column(name = "request_bytes", nullable = false)
|
||||
val requestBytes: ByteArray,
|
||||
@Convert(converter = PKCS10CertificationRequestConverter::class)
|
||||
val request: PKCS10CertificationRequest,
|
||||
|
||||
@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
|
||||
) {
|
||||
fun toCertificateSigningRequest(): CertificateSigningRequest {
|
||||
@ -74,70 +76,53 @@ data class CertificateSigningRequestEntity(
|
||||
legalName = legalName,
|
||||
publicKeyHash = SecureHash.parse(publicKeyHash),
|
||||
status = status,
|
||||
request = request(),
|
||||
request = request,
|
||||
remark = remark,
|
||||
modifiedBy = modifiedBy,
|
||||
certData = certificateData?.toCertificateData()
|
||||
)
|
||||
}
|
||||
|
||||
private fun request() = PKCS10CertificationRequest(requestBytes)
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "certificate_data")
|
||||
@Table(name = "cert_data")
|
||||
data class CertificateDataEntity(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||
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,
|
||||
|
||||
@Lob
|
||||
@Column(name = "certificate_path_bytes")
|
||||
val certificatePathBytes: ByteArray,
|
||||
@Column(name = "cert_path_bytes", nullable = false)
|
||||
@Convert(converter = CertPathConverter::class)
|
||||
val certPath: CertPath,
|
||||
|
||||
@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,
|
||||
|
||||
@Column(name = "certificate_serial_number", unique = true)
|
||||
@Column(name = "cert_serial_number", unique = true, nullable = false, columnDefinition = "NUMERIC(28)")
|
||||
val certificateSerialNumber: BigInteger
|
||||
) {
|
||||
fun toCertificateData(): CertificateData {
|
||||
return CertificateData(
|
||||
certStatus = certificateStatus,
|
||||
certPath = toCertificatePath()
|
||||
)
|
||||
}
|
||||
fun toCertificateData(): CertificateData = CertificateData(certificateStatus, certPath)
|
||||
|
||||
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
|
||||
@Table(name = "private_network")
|
||||
data class PrivateNetworkEntity(
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
@Column(name = "id", length = 64)
|
||||
val networkId: String,
|
||||
|
||||
@Column(name = "name")
|
||||
@Column(name = "name", length = 255, nullable = false)
|
||||
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
|
||||
|
||||
import net.corda.core.internal.DigitalSignatureWithCert
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.nodeapi.internal.network.NetworkMap
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||
import java.security.cert.X509Certificate
|
||||
import javax.persistence.*
|
||||
|
||||
@Entity
|
||||
@ -27,26 +26,23 @@ class NetworkMapEntity(
|
||||
|
||||
@Lob
|
||||
@Column(name = "serialized_network_map", nullable = false)
|
||||
val networkMapBytes: ByteArray,
|
||||
@Convert(converter = NetworkMapConverter::class)
|
||||
val networkMap: NetworkMap,
|
||||
|
||||
@Lob
|
||||
@Column(name = "signature", nullable = false)
|
||||
val signature: ByteArray,
|
||||
|
||||
@Lob
|
||||
@Column(name = "certificate", nullable = false)
|
||||
val certificate: ByteArray,
|
||||
@Column(name = "cert", nullable = false)
|
||||
@Convert(converter = X509CertificateConverter::class)
|
||||
val certificate: X509Certificate,
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "network_parameters")
|
||||
@JoinColumn(name = "network_parameters", nullable = false)
|
||||
val networkParameters: NetworkParametersEntity
|
||||
) {
|
||||
fun toNetworkMap(): NetworkMap = networkMapBytes.deserialize()
|
||||
|
||||
fun toSignedNetworkMap(): SignedNetworkMap {
|
||||
return SignedNetworkMap(
|
||||
SerializedBytes(networkMapBytes),
|
||||
DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), signature)
|
||||
)
|
||||
return SignedNetworkMap(networkMap.serialize(), DigitalSignatureWithCert(certificate, signature))
|
||||
}
|
||||
}
|
||||
|
@ -12,27 +12,26 @@ package com.r3.corda.networkmanage.common.persistence.entity
|
||||
|
||||
import net.corda.core.internal.DigitalSignatureWithCert
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
||||
import org.hibernate.annotations.CreationTimestamp
|
||||
import java.security.cert.X509Certificate
|
||||
import java.time.Instant
|
||||
import javax.persistence.*
|
||||
|
||||
@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(
|
||||
@Id
|
||||
@Column(name = "hash", length = 64, unique = true)
|
||||
val parametersHash: String,
|
||||
@Column(name = "hash", length = 64, nullable = false)
|
||||
val hash: String,
|
||||
|
||||
@CreationTimestamp
|
||||
@Column(nullable = false)
|
||||
val created: Instant = Instant.now(),
|
||||
|
||||
@Lob
|
||||
@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
|
||||
// inserted into database without signature. Then signing service will sign them.
|
||||
@ -41,31 +40,27 @@ class NetworkParametersEntity(
|
||||
val signature: ByteArray?,
|
||||
|
||||
@Lob
|
||||
@Column(name = "certificate")
|
||||
val certificate: ByteArray?
|
||||
@Column(name = "cert")
|
||||
@Convert(converter = X509CertificateConverter::class)
|
||||
val certificate: X509Certificate?
|
||||
) {
|
||||
val isSigned: Boolean get() = certificate != null && signature != null
|
||||
|
||||
fun toNetworkParameters(): NetworkParameters = parametersBytes.deserialize()
|
||||
|
||||
fun toSignedNetworkParameters(): SignedNetworkParameters {
|
||||
if (certificate == null || signature == null) throw IllegalStateException("Network parameters entity is not signed: $parametersHash")
|
||||
return SignedNetworkParameters(
|
||||
SerializedBytes(parametersBytes),
|
||||
DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), signature)
|
||||
)
|
||||
if (certificate == null || signature == null) throw IllegalStateException("Network parameters entity is not signed: $hash")
|
||||
return SignedNetworkParameters(networkParameters.serialize(), DigitalSignatureWithCert(certificate, signature))
|
||||
}
|
||||
|
||||
fun copy(parametersHash: String = this.parametersHash,
|
||||
fun copy(parametersHash: String = this.hash,
|
||||
created: Instant = this.created,
|
||||
parametersBytes: ByteArray = this.parametersBytes,
|
||||
networkParameters: NetworkParameters = this.networkParameters,
|
||||
signature: ByteArray? = this.signature,
|
||||
certificate: ByteArray? = this.certificate
|
||||
certificate: X509Certificate? = this.certificate
|
||||
): NetworkParametersEntity {
|
||||
return NetworkParametersEntity(
|
||||
parametersHash = parametersHash,
|
||||
hash = parametersHash,
|
||||
created = created,
|
||||
parametersBytes = parametersBytes,
|
||||
networkParameters = networkParameters,
|
||||
signature = signature,
|
||||
certificate = certificate
|
||||
)
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
package com.r3.corda.networkmanage.common.persistence.entity
|
||||
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||
import java.time.Instant
|
||||
import javax.persistence.*
|
||||
@ -21,47 +20,27 @@ data class NodeInfoEntity(
|
||||
// Hash of serialized [NodeInfo] without signatures.
|
||||
@Id
|
||||
@Column(name = "node_info_hash", length = 64)
|
||||
val nodeInfoHash: String = "",
|
||||
val nodeInfoHash: String,
|
||||
|
||||
@Column(name = "public_key_hash", length = 64)
|
||||
val identityPkHash: String = "",
|
||||
val publicKeyHash: String,
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "certificate_signing_request")
|
||||
@JoinColumn(name = "cert_signing_request", nullable = false)
|
||||
val certificateSigningRequest: CertificateSigningRequestEntity,
|
||||
|
||||
@Lob
|
||||
@Column(name = "signed_node_info_bytes")
|
||||
val signedNodeInfoBytes: ByteArray,
|
||||
@Column(name = "signed_node_info_bytes", nullable = false)
|
||||
@Convert(converter = SignedNodeInfoConverter::class)
|
||||
val signedNodeInfo: SignedNodeInfo,
|
||||
|
||||
@Column(name = "is_current")
|
||||
@Column(name = "is_current", nullable = false)
|
||||
val isCurrent: Boolean,
|
||||
|
||||
@Column(name = "published_at")
|
||||
@Column(name = "published_at", nullable = false)
|
||||
val publishedAt: Instant = Instant.now(),
|
||||
|
||||
@Column(name = "accepted_parameters_hash", length = 64)
|
||||
val acceptedParametersHash: String = ""
|
||||
) {
|
||||
/**
|
||||
* 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
|
||||
)
|
||||
}
|
||||
}
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "accepted_network_parameters")
|
||||
val acceptedNetworkParameters: NetworkParametersEntity?
|
||||
)
|
||||
|
@ -7,7 +7,7 @@ import javax.persistence.*
|
||||
|
||||
@Entity
|
||||
@Table(name = "parameters_update")
|
||||
class ParametersUpdateEntity(
|
||||
data class ParametersUpdateEntity(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||
val id: Long? = null,
|
||||
@ -17,31 +17,17 @@ class ParametersUpdateEntity(
|
||||
@JoinColumn(name = "network_parameters", foreignKey = ForeignKey(name = "FK__param_up__net_param"))
|
||||
val networkParameters: NetworkParametersEntity,
|
||||
|
||||
@Column(name = "description")
|
||||
@Column(name = "description", nullable = false)
|
||||
val description: String,
|
||||
|
||||
@Column(name = "update_deadline")
|
||||
@Column(name = "update_deadline", nullable = false)
|
||||
val updateDeadline: Instant,
|
||||
|
||||
// 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
|
||||
) {
|
||||
fun toParametersUpdate(): ParametersUpdate = ParametersUpdate(SecureHash.parse(networkParameters.parametersHash), 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
|
||||
)
|
||||
fun toParametersUpdate(): ParametersUpdate {
|
||||
return ParametersUpdate(SecureHash.parse(networkParameters.hash), description, updateDeadline)
|
||||
}
|
||||
}
|
@ -12,15 +12,12 @@ package com.r3.corda.networkmanage.common.signer
|
||||
|
||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.nodeapi.internal.network.NetworkMap
|
||||
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.debug
|
||||
import net.corda.nodeapi.internal.network.NetworkMap
|
||||
import net.corda.nodeapi.internal.network.NetworkMapAndSigned
|
||||
|
||||
|
||||
class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private val signer: Signer) {
|
||||
private companion object {
|
||||
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.
|
||||
*/
|
||||
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()
|
||||
if (latestNetworkParameters == null) {
|
||||
logger.debug("No network parameters present")
|
||||
return
|
||||
}
|
||||
logger.debug { "Retrieved latest network parameters: ${latestNetworkParameters.toNetworkParameters()}" }
|
||||
logger.debug { "Retrieved latest network parameters: ${latestNetworkParameters.networkParameters}" }
|
||||
|
||||
val parametersUpdate = networkMapStorage.getParametersUpdate()
|
||||
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) {
|
||||
signAndPersistNetworkParameters(latestNetworkParameters.toNetworkParameters())
|
||||
signAndPersistNetworkParameters(latestNetworkParameters.networkParameters)
|
||||
} else {
|
||||
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()
|
||||
latestNetworkParameters
|
||||
} else currentNetworkParameters
|
||||
val newNetworkMap = NetworkMap(nodeInfoHashes, SecureHash.parse(parametersToNetworkMap.parametersHash), parametersUpdate?.toNetMapUpdate())
|
||||
} else {
|
||||
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" }
|
||||
if (currentNetworkMap?.toNetworkMap() != newNetworkMap) {
|
||||
val netNetworkMapAndSigned = NetworkMapAndSigned(newNetworkMap) { signer.signBytes(it.bytes) }
|
||||
networkMapStorage.saveNewActiveNetworkMap(netNetworkMapAndSigned)
|
||||
|
||||
if (activeNetworkMap?.networkMap != newNetworkMap) {
|
||||
val newNetworkMapAndSigned = NetworkMapAndSigned(newNetworkMap) { signer.signBytes(it.bytes) }
|
||||
networkMapStorage.saveNewActiveNetworkMap(newNetworkMapAndSigned)
|
||||
logger.info("Signed new network map: $newNetworkMap")
|
||||
} else {
|
||||
logger.debug("Current network map is up-to-date")
|
||||
|
@ -22,7 +22,6 @@ import com.r3.corda.networkmanage.doorman.webservice.NetworkMapWebService
|
||||
import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
@ -60,7 +59,7 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
|
||||
|
||||
private fun getNetworkMapService(config: NetworkMapConfig, signer: LocalSigner?): NetworkMapWebService {
|
||||
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")
|
||||
logger.info("Starting network map service with network parameters: $latestParameters")
|
||||
localNetworkMapSigner?.signAndPersistNetworkParameters(latestParameters)
|
||||
@ -153,7 +152,7 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
|
||||
|
||||
private fun handleSetNetworkParameters(setNetParams: NetworkParametersCmd.Set) {
|
||||
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) {
|
||||
require(setNetParams.parametersUpdate == null) {
|
||||
"'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)
|
||||
} else {
|
||||
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)
|
||||
|
||||
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!"
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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)
|
||||
|
||||
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"
|
||||
}
|
||||
// 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) {
|
||||
"The latest network parameters is not the scheduled one:\n${latestNetParamsEntity.toNetworkParameters()}\n${parametersUpdate.toParametersUpdate()}"
|
||||
check(latestNetParamsEntity.hash == parametersUpdate.networkParameters.hash) {
|
||||
"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" +
|
||||
"Switching from: $activeNetParams\nTo: ${latestNetParamsEntity.toNetworkParameters()}")
|
||||
networkMapStorage.setFlagDay(SecureHash.parse(parametersUpdate.networkParameters.parametersHash))
|
||||
"Switching from: $activeNetParams\nTo: ${latestNetParamsEntity.networkParameters}")
|
||||
networkMapStorage.setFlagDay(SecureHash.parse(parametersUpdate.networkParameters.hash))
|
||||
}
|
||||
|
||||
private fun handleCancelUpdate() {
|
||||
|
@ -57,9 +57,9 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
||||
.build {
|
||||
networkMapStorage.getActiveNetworkMap()?.let {
|
||||
logger.info("Re-publishing network map")
|
||||
val networkMap = it.toNetworkMap()
|
||||
val networkMap = it.networkMap
|
||||
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}" }
|
||||
nodeInfoStorage.ackNodeInfoParametersUpdate(signedParametersHash.sig.by.encoded.sha256(), hash)
|
||||
ok()
|
||||
} catch (e: Exception) {
|
||||
when (e) {
|
||||
is SignatureException -> status(Response.Status.FORBIDDEN).entity(e.message)
|
||||
else -> status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
}
|
||||
} catch (e: SignatureException) {
|
||||
status(Response.Status.FORBIDDEN).entity(e.message)
|
||||
}.build()
|
||||
}
|
||||
|
||||
|
@ -15,30 +15,39 @@
|
||||
<changeSet author="R3.Corda" id="1513267683777-1" dbms="mssql">
|
||||
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
|
||||
</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">
|
||||
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1513267683777-1.3" dbms="postgres">
|
||||
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1513267683777-1.1" dbms="h2">
|
||||
<createSequence sequenceName="hibernate_sequence"/>
|
||||
<changeSet author="R3.Corda" id="1513267683777-1.4" dbms="oracle">
|
||||
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-2">
|
||||
<createTable tableName="certificate_data">
|
||||
<createTable tableName="cert_data">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="certificate_path_bytes" type="BLOB"/>
|
||||
<column name="certificate_status" type="INT"/>
|
||||
<column name="certificate_signing_request" type="NVARCHAR(64)">
|
||||
<column name="cert_path_bytes" type="BLOB">
|
||||
<constraints nullable="false"/>
|
||||
</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"/>
|
||||
</column>
|
||||
<column name="certificate_serial_number" type="NUMERIC(28)"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-3">
|
||||
<createTable tableName="certificate_signing_request">
|
||||
<createTable tableName="cert_signing_request">
|
||||
<column name="request_id" type="NVARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
@ -50,16 +59,20 @@
|
||||
<column name="request_bytes" type="BLOB">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="status" type="NVARCHAR(255)">
|
||||
<column name="status" type="NVARCHAR(16)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="public_key_hash" type="NVARCHAR(64)"/>
|
||||
<column name="modified_by" type="NVARCHAR(512)"/>
|
||||
<column name="private_network" type="NVARCHAR(255)"/>
|
||||
<column name="public_key_hash" type="NVARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="modified_by" type="NVARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="private_network" type="NVARCHAR(64)"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<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)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
@ -67,10 +80,9 @@
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="REVTYPE" type="TINYINT"/>
|
||||
<column name="modified_at" type="TIMESTAMP"/>
|
||||
<column name="remark" type="NVARCHAR(256)"/>
|
||||
<column name="status" type="NVARCHAR(255)"/>
|
||||
<column name="modified_by" type="NVARCHAR(512)"/>
|
||||
<column name="status" type="NVARCHAR(16)"/>
|
||||
<column name="modified_by" type="NVARCHAR(64)"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-5">
|
||||
@ -78,7 +90,7 @@
|
||||
<column name="version" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="certificate" type="BLOB">
|
||||
<column name="cert" type="BLOB">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="serialized_network_map" type="BLOB">
|
||||
@ -97,8 +109,10 @@
|
||||
<column name="hash" type="NVARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="created" type="TIMESTAMP"/>
|
||||
<column name="certificate" type="BLOB"/>
|
||||
<column name="cert" type="BLOB"/>
|
||||
<column name="created" type="TIMESTAMP">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="parameters_bytes" type="BLOB">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
@ -114,7 +128,7 @@
|
||||
<column name="signed_node_info_bytes" type="BLOB">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="certificate_signing_request" type="NVARCHAR(64)">
|
||||
<column name="cert_signing_request" type="NVARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="is_current" type="BOOLEAN">
|
||||
@ -123,62 +137,66 @@
|
||||
<column name="published_at" type="TIMESTAMP">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="accepted_parameters_hash" type="NVARCHAR(64)"/>
|
||||
<column name="accepted_network_parameters" type="NVARCHAR(64)"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-8">
|
||||
<createTable tableName="REVINFO">
|
||||
<column autoIncrement="true" name="REV" type="INT">
|
||||
<constraints primaryKey="true" primaryKeyName="PK_REVINFO_REV"/>
|
||||
<constraints primaryKey="true" primaryKeyName="PK__REVINFO__REV"/>
|
||||
</column>
|
||||
<column name="REVTSTMP" type="BIGINT"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<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 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 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 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 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 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 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 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"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
<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"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-21">
|
||||
<addForeignKeyConstraint baseColumnNames="REV" baseTableName="certificate_signing_request_AUD"
|
||||
constraintName="FK_CSRA_REV"
|
||||
<addForeignKeyConstraint baseColumnNames="REV" baseTableName="cert_signing_request_AUD"
|
||||
constraintName="FK__CSRA__REV"
|
||||
referencedColumnNames="REV" referencedTableName="REVINFO"/>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-22">
|
||||
<addForeignKeyConstraint baseColumnNames="certificate_signing_request" baseTableName="node_info"
|
||||
constraintName="FK_NI_CSR"
|
||||
referencedColumnNames="request_id" referencedTableName="certificate_signing_request"/>
|
||||
<addForeignKeyConstraint baseColumnNames="cert_signing_request" baseTableName="node_info"
|
||||
constraintName="FK__NI__CSR"
|
||||
referencedColumnNames="request_id" referencedTableName="cert_signing_request"/>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-23">
|
||||
<addForeignKeyConstraint baseColumnNames="certificate_signing_request" baseTableName="certificate_data"
|
||||
constraintName="FK_CD_CSR"
|
||||
referencedColumnNames="request_id" referencedTableName="certificate_signing_request"/>
|
||||
<addForeignKeyConstraint baseColumnNames="cert_signing_request" baseTableName="cert_data"
|
||||
constraintName="FK__CD__CSR"
|
||||
referencedColumnNames="request_id" referencedTableName="cert_signing_request"/>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-24">
|
||||
<createIndex indexName="IDX_NP_HASH" tableName="network_parameters">
|
||||
@ -186,42 +204,42 @@
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-25">
|
||||
<createTable tableName="certificate_revocation_request">
|
||||
<createTable tableName="cert_revocation_request">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="request_id" type="NVARCHAR(256)">
|
||||
<column name="request_id" type="NVARCHAR(64)">
|
||||
<constraints nullable="false" unique="true"/>
|
||||
</column>
|
||||
<column name="certificate_serial_number" type="NUMERIC(28)">
|
||||
<column name="cert_serial_number" type="NUMERIC(28)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="legal_name" type="NVARCHAR(256)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="status" type="NVARCHAR(256)">
|
||||
<column name="status" type="NVARCHAR(16)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="reporter" type="NVARCHAR(512)">
|
||||
<column name="reporter" type="NVARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="modified_by" type="NVARCHAR(512)">
|
||||
<column name="modified_by" type="NVARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="modified_at" type="TIMESTAMP">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="remark" type="NVARCHAR(256)"/>
|
||||
<column name="revocation_reason" type="NVARCHAR(256)">
|
||||
<column name="revocation_reason" type="NVARCHAR(32)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="certificate_data" type="BIGINT">
|
||||
<column name="cert_data" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-26">
|
||||
<createTable tableName="certificate_revocation_request_AUD">
|
||||
<createTable tableName="cert_revocation_request_AUD">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
@ -229,85 +247,73 @@
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<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_by" type="NVARCHAR(256)"/>
|
||||
<column name="modified_by" type="NVARCHAR(64)"/>
|
||||
<column name="remark" type="NVARCHAR(256)"/>
|
||||
<column name="status" type="NVARCHAR(256)"/>
|
||||
<column name="status" type="NVARCHAR(16)"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-27">
|
||||
<createTable tableName="certificate_revocation_list">
|
||||
<createTable tableName="cert_revocation_list">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</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"/>
|
||||
</column>
|
||||
<column name="crl_bytes" type="BLOB"/>
|
||||
<column name="modified_at" type="TIMESTAMP">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="signed_by" type="NVARCHAR(512)">
|
||||
<column name="signed_by" type="NVARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
</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">
|
||||
<addPrimaryKey columnNames="id" constraintName="certificate_revocation_request_pk" tableName="certificate_revocation_request"/>
|
||||
<addPrimaryKey columnNames="id" constraintName="PK__CRR" tableName="cert_revocation_request"/>
|
||||
</changeSet>
|
||||
<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 author="R3.Corda" id="1520338500424-31">
|
||||
<addPrimaryKey columnNames="id" constraintName="certificate_revocation_list_pk" tableName="certificate_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"/>
|
||||
<addPrimaryKey columnNames="id" constraintName="PK__CRL" tableName="cert_revocation_list"/>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-33">
|
||||
<addForeignKeyConstraint baseColumnNames="certificate_data"
|
||||
baseTableName="certificate_revocation_request"
|
||||
constraintName="cert_data__cert_rev_req_fk"
|
||||
<addForeignKeyConstraint baseColumnNames="cert_data"
|
||||
baseTableName="cert_revocation_request"
|
||||
constraintName="FK__CRR__CD"
|
||||
referencedColumnNames="id"
|
||||
referencedTableName="certificate_data"/>
|
||||
referencedTableName="cert_data"/>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-34">
|
||||
<addForeignKeyConstraint baseColumnNames="rev"
|
||||
baseTableName="certificate_revocation_request_AUD"
|
||||
constraintName="cert_rev_req__REVINFO_AUD_fk"
|
||||
baseTableName="cert_revocation_request_AUD"
|
||||
constraintName="FK__CRR_AUD__REVINFO"
|
||||
referencedColumnNames="rev"
|
||||
referencedTableName="REVINFO"/>
|
||||
</changeSet>
|
||||
<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"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-36">
|
||||
<createTable tableName="private_network">
|
||||
<column name="id" type="NVARCHAR(255)">
|
||||
<constraints primaryKey="true" primaryKeyName="PK_PRIV_NETWORK_ID"/>
|
||||
<column name="id" type="NVARCHAR(64)">
|
||||
<constraints primaryKey="true" primaryKeyName="PK__PRIV_NETWORK__ID" nullable="false"/>
|
||||
</column>
|
||||
<column name="name" type="NVARCHAR(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="name" type="NVARCHAR(255)"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-37">
|
||||
<addForeignKeyConstraint baseColumnNames="private_network" baseTableName="certificate_signing_request"
|
||||
constraintName="FK_CSR_PN"
|
||||
<addForeignKeyConstraint baseColumnNames="private_network" baseTableName="cert_signing_request"
|
||||
constraintName="FK__CSR__PN"
|
||||
referencedColumnNames="id" referencedTableName="private_network"/>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="1520338500424-38">
|
||||
@ -315,21 +321,32 @@
|
||||
constraintName="FK_NM_NP"
|
||||
referencedColumnNames="hash" referencedTableName="network_parameters"/>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="update-net-params">
|
||||
<changeSet author="R3.Corda" id="1520338500424-39">
|
||||
<createTable tableName="parameters_update">
|
||||
<column name="description" type="VARCHAR(255)"/>
|
||||
<column name="update_deadline" type="TIMESTAMP"/>
|
||||
<column name="description" type="VARCHAR(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="update_deadline" type="TIMESTAMP">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="network_parameters" type="NVARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="flag_day" type="BOOLEAN"/>
|
||||
<column name="flag_day" type="BOOLEAN">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<addPrimaryKey columnNames="id" constraintName="CONSTRAINT_PARAMUPKEY" tableName="parameters_update"/>
|
||||
<addForeignKeyConstraint baseTableName="parameters_update" baseColumnNames="network_parameters"
|
||||
constraintName="FK_PU_NP"
|
||||
referencedTableName="network_parameters" referencedColumnNames="hash"/>
|
||||
</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>
|
||||
|
@ -15,18 +15,17 @@ fun createNetworkParametersEntity(signingCertAndKeyPair: CertificateAndKeyPair =
|
||||
networkParameters: NetworkParameters = testNetworkParameters()): NetworkParametersEntity {
|
||||
val signedNetParams = signingCertAndKeyPair.sign(networkParameters)
|
||||
return NetworkParametersEntity(
|
||||
parametersHash = signedNetParams.raw.hash.toString(),
|
||||
parametersBytes = signedNetParams.raw.bytes,
|
||||
hash = signedNetParams.raw.hash.toString(),
|
||||
networkParameters = networkParameters,
|
||||
signature = signedNetParams.sig.bytes,
|
||||
certificate = signedNetParams.sig.by.encoded
|
||||
certificate = signedNetParams.sig.by
|
||||
)
|
||||
}
|
||||
|
||||
fun createNetworkParametersEntityUnsigned(networkParameters: NetworkParameters = testNetworkParameters()): NetworkParametersEntity {
|
||||
val serialised = networkParameters.serialize()
|
||||
return NetworkParametersEntity(
|
||||
parametersHash = serialised.hash.toString(),
|
||||
parametersBytes = serialised.bytes,
|
||||
hash = networkParameters.serialize().hash.toString(),
|
||||
networkParameters = networkParameters,
|
||||
signature = null,
|
||||
certificate = null
|
||||
)
|
||||
@ -36,11 +35,12 @@ fun createNetworkMapEntity(signingCertAndKeyPair: CertificateAndKeyPair = create
|
||||
netParamsEntity: NetworkParametersEntity,
|
||||
nodeInfoHashes: List<SecureHash> = emptyList(),
|
||||
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(
|
||||
networkMapBytes = signedNetMap.raw.bytes,
|
||||
signature = signedNetMap.sig.bytes,
|
||||
certificate = signedNetMap.sig.by.encoded,
|
||||
networkMap = networkMap,
|
||||
signature = signedNetworkMap.sig.bytes,
|
||||
certificate = signedNetworkMap.sig.by,
|
||||
networkParameters = netParamsEntity
|
||||
)
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
assertThat(activeSignedNetworkMap.sig).isEqualTo(networkMapAndSigned.signed.sig)
|
||||
assertThat(activeNetworkParameters).isEqualTo(networkParameters)
|
||||
assertThat(activeSignedNetworkParameters.sig).isEqualTo(networkParametersSig)
|
||||
assertThat(SecureHash.parse(activeNetworkParametersEntity.parametersHash))
|
||||
assertThat(SecureHash.parse(activeNetworkParametersEntity.hash))
|
||||
.isEqualTo(activeNetworkMap.networkParameterHash)
|
||||
.isEqualTo(networkParametersHash)
|
||||
}
|
||||
@ -100,7 +100,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
// We may have not signed them yet.
|
||||
networkMapStorage.saveNetworkParameters(params2, null)
|
||||
|
||||
assertThat(networkMapStorage.getLatestNetworkParameters()?.toNetworkParameters()).isEqualTo(params2)
|
||||
assertThat(networkMapStorage.getLatestNetworkParameters()?.networkParameters).isEqualTo(params2)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -14,15 +14,18 @@ import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.utils.hashString
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.CertRole
|
||||
import net.corda.core.serialization.serialize
|
||||
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.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
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.createDevIntermediateCaCertPath
|
||||
import net.corda.testing.internal.signWith
|
||||
@ -45,13 +48,15 @@ class PersistentNodeInfoStorageTest : TestBase() {
|
||||
private lateinit var networkMapStorage: PersistentNetworkMapStorage
|
||||
private lateinit var persistence: CordaPersistence
|
||||
private lateinit var rootCaCert: X509Certificate
|
||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||
private lateinit var doormanCertAndKeyPair: CertificateAndKeyPair
|
||||
private lateinit var networkMapCertAndKeyPair: CertificateAndKeyPair
|
||||
|
||||
@Before
|
||||
fun startDb() {
|
||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||
rootCaCert = rootCa.certificate
|
||||
this.intermediateCa = intermediateCa
|
||||
this.doormanCertAndKeyPair = intermediateCa
|
||||
networkMapCertAndKeyPair = createDevNetworkMapCa(rootCa)
|
||||
persistence = configureDatabase(MockServices.makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))
|
||||
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
|
||||
requestStorage = PersistentCertificateSigningRequestStorage(persistence)
|
||||
@ -70,8 +75,8 @@ class PersistentNodeInfoStorageTest : TestBase() {
|
||||
val name = CordaX500Name(organisation = "Test", locality = "London", country = "GB")
|
||||
val nodeCaCert = X509Utilities.createCertificate(
|
||||
CertificateType.NODE_CA,
|
||||
intermediateCa.certificate,
|
||||
intermediateCa.keyPair,
|
||||
doormanCertAndKeyPair.certificate,
|
||||
doormanCertAndKeyPair.keyPair,
|
||||
name.x500Principal,
|
||||
keyPair.public)
|
||||
|
||||
@ -85,7 +90,7 @@ class PersistentNodeInfoStorageTest : TestBase() {
|
||||
|
||||
requestStorage.putCertificatePath(
|
||||
requestId,
|
||||
X509Utilities.buildCertPath(nodeCaCert, intermediateCa.certificate, rootCaCert),
|
||||
X509Utilities.buildCertPath(nodeCaCert, doormanCertAndKeyPair.certificate, rootCaCert),
|
||||
CertificateSigningRequestStorage.DOORMAN_SIGNATURE)
|
||||
|
||||
val storedCertPath = nodeInfoStorage.getCertificatePath(SecureHash.parse(keyPair.public.hashString()))
|
||||
@ -150,16 +155,37 @@ class PersistentNodeInfoStorageTest : TestBase() {
|
||||
@Test
|
||||
fun `accept parameters updates node info correctly`() {
|
||||
// given
|
||||
val (nodeInfoWithSigned) = createValidSignedNodeInfo("Test", requestStorage)
|
||||
val (nodeInfoAndSigned) = createValidSignedNodeInfo("Test", requestStorage)
|
||||
|
||||
// when
|
||||
val paramsHash = SecureHash.randomSHA256()
|
||||
val nodeInfoHash = nodeInfoStorage.putNodeInfo(nodeInfoWithSigned)
|
||||
nodeInfoStorage.ackNodeInfoParametersUpdate(SecureHash.parse(nodeInfoWithSigned.nodeInfo.legalIdentities.first().owningKey.hashString()), paramsHash)
|
||||
val networkParameters = testNetworkParameters()
|
||||
val sigWithCert = networkMapCertAndKeyPair.sign(networkParameters).sig
|
||||
val netParamsHash = networkMapStorage.saveNetworkParameters(networkParameters, sigWithCert)
|
||||
val nodeInfoHash = nodeInfoStorage.putNodeInfo(nodeInfoAndSigned)
|
||||
nodeInfoStorage.ackNodeInfoParametersUpdate(nodeInfoAndSigned.nodeInfo.legalIdentities[0].owningKey.encoded.sha256(), netParamsHash)
|
||||
|
||||
// then
|
||||
val persistedParametersHash = nodeInfoStorage.getAcceptedParametersUpdateHash(nodeInfoHash)
|
||||
assertThat(persistedParametersHash).isEqualTo(paramsHash)
|
||||
val acceptedNetworkParameters = nodeInfoStorage.getAcceptedNetworkParameters(nodeInfoHash)
|
||||
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
|
||||
val currentNetworkParameters = createNetworkParametersEntity(signingCertAndKeyPair)
|
||||
val updateNetworkParameters = createNetworkParametersEntityUnsigned(testNetworkParameters(epoch = 2))
|
||||
val updateParametersHash = SecureHash.parse(updateNetworkParameters.parametersHash)
|
||||
val parametersUpdate = ParametersUpdateEntity(0, updateNetworkParameters,"Update time", Instant.ofEpochMilli(random63BitValue()))
|
||||
val netMapEntity = createNetworkMapEntity(signingCertAndKeyPair, currentNetworkParameters, emptyList(), null)
|
||||
whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(netMapEntity)
|
||||
@ -170,8 +169,8 @@ class NetworkMapSignerTest : TestBase() {
|
||||
val paramsCaptor = argumentCaptor<NetworkParameters>()
|
||||
val signatureCaptor = argumentCaptor<DigitalSignatureWithCert>()
|
||||
verify(networkMapStorage, times(1)).saveNetworkParameters(paramsCaptor.capture(), signatureCaptor.capture())
|
||||
assertEquals(paramsCaptor.firstValue, updateNetworkParameters.toNetworkParameters())
|
||||
assertThat(signatureCaptor.firstValue.verify(updateNetworkParameters.parametersBytes))
|
||||
assertEquals(paramsCaptor.firstValue, updateNetworkParameters.networkParameters)
|
||||
signatureCaptor.firstValue.verify(updateNetworkParameters.networkParameters.serialize())
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -206,7 +205,7 @@ class NetworkMapSignerTest : TestBase() {
|
||||
argumentCaptor<NetworkMapAndSigned>().apply {
|
||||
verify(networkMapStorage).saveNewActiveNetworkMap(capture())
|
||||
val netMap = firstValue.networkMap
|
||||
assertEquals(SecureHash.parse(updateNetworkParameters.parametersHash), netMap.networkParameterHash)
|
||||
assertEquals(SecureHash.parse(updateNetworkParameters.hash), netMap.networkParameterHash)
|
||||
assertEquals(emptyList(), netMap.nodeInfoHashes)
|
||||
assertEquals(null, netMap.parametersUpdate)
|
||||
}
|
||||
@ -231,7 +230,7 @@ class NetworkMapSignerTest : TestBase() {
|
||||
argumentCaptor<NetworkMapAndSigned>().apply {
|
||||
verify(networkMapStorage).saveNewActiveNetworkMap(capture())
|
||||
val netMap = firstValue.networkMap
|
||||
assertEquals(SecureHash.parse(activeNetworkParameters.parametersHash), netMap.networkParameterHash)
|
||||
assertEquals(SecureHash.parse(activeNetworkParameters.hash), netMap.networkParameterHash)
|
||||
assertEquals(emptyList(), netMap.nodeInfoHashes)
|
||||
assertEquals(null, netMap.parametersUpdate)
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ class NetworkMapWebServiceTest {
|
||||
it.start()
|
||||
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
||||
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 networkParameterHash: SecureHash,
|
||||
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.
|
||||
|
@ -48,8 +48,7 @@ class NetworkParametersReader(private val trustRoot: X509Certificate,
|
||||
// you get them from network map, but you have to run the approval step.
|
||||
if (signedParametersFromFile == null) { // Node joins for the first time.
|
||||
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)
|
||||
} else { // Update case.
|
||||
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.")
|
||||
}
|
||||
parametersUpdateFile.moveTo(networkParamsFile, StandardCopyOption.REPLACE_EXISTING)
|
||||
logger.info("Scheduled update to network parameters has occurred - node now updated to these new parameters.")
|
||||
return signedUpdatedParameters
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,9 @@ package net.corda.node.services.network
|
||||
|
||||
import net.corda.core.crypto.SecureHash
|
||||
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.serialization.deserialize
|
||||
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.node.utilities.registration.cacheControl
|
||||
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.net.URL
|
||||
import java.security.cert.X509Certificate
|
||||
@ -54,10 +59,7 @@ class NetworkMapClient(compatibilityZoneURL: URL, val trustedRoot: X509Certifica
|
||||
val signedNetworkMap = connection.responseAs<SignedNetworkMap>()
|
||||
val networkMap = signedNetworkMap.verifiedNetworkMapCert(trustedRoot)
|
||||
val timeout = connection.cacheControl().maxAgeSeconds().seconds
|
||||
logger.trace {
|
||||
"Fetched network map update from $networkMapUrl successfully, retrieved ${networkMap.nodeInfoHashes.size} " +
|
||||
"node info hashes. Node Info hashes:\n${networkMap.nodeInfoHashes.joinToString("\n")}"
|
||||
}
|
||||
logger.trace { "Fetched network map update from $networkMapUrl successfully: $networkMap" }
|
||||
return NetworkMapResponse(networkMap, timeout)
|
||||
}
|
||||
|
||||
|
@ -157,12 +157,13 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal,
|
||||
// This update was handled already.
|
||||
return
|
||||
}
|
||||
val newParameters = networkMapClient.getNetworkParameters(update.newParametersHash)
|
||||
logger.info("Downloaded new network parameters: $newParameters from the update: $update")
|
||||
newNetworkParameters = Pair(update, newParameters)
|
||||
val newSignedNetParams = networkMapClient.getNetworkParameters(update.newParametersHash)
|
||||
val newNetParams = newSignedNetParams.verifiedNetworkMapCert(networkMapClient.trustedRoot)
|
||||
logger.info("Downloaded new network parameters: $newNetParams from the update: $update")
|
||||
newNetworkParameters = Pair(update, newSignedNetParams)
|
||||
val updateInfo = ParametersUpdateInfo(
|
||||
update.newParametersHash,
|
||||
newParameters.verifiedNetworkMapCert(networkMapClient.trustedRoot),
|
||||
newNetParams,
|
||||
update.description,
|
||||
update.updateDeadline)
|
||||
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")
|
||||
// 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.
|
||||
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.
|
||||
val newParametersHash = newParams.verifiedNetworkMapCert(networkMapClient.trustedRoot).serialize().hash
|
||||
val newNetParams = signedNewNetParams.verifiedNetworkMapCert(networkMapClient.trustedRoot)
|
||||
val newParametersHash = newNetParams.serialize().hash
|
||||
if (parametersHash == newParametersHash) {
|
||||
// The latest parameters have priority.
|
||||
newParams.serialize()
|
||||
signedNewNetParams.serialize()
|
||||
.open()
|
||||
.copyTo(baseDirectory / NETWORK_PARAMS_UPDATE_FILE_NAME, StandardCopyOption.REPLACE_EXISTING)
|
||||
networkMapClient.ackNetworkParametersUpdate(sign(parametersHash))
|
||||
logger.info("Accepted network parameter update $update: $newNetParams")
|
||||
} else {
|
||||
throw IllegalArgumentException("Refused to accept parameters with hash $parametersHash because network map " +
|
||||
"advertises update with hash $newParametersHash. Please check newest version")
|
||||
|
Loading…
Reference in New Issue
Block a user