mirror of
https://github.com/corda/corda.git
synced 2025-06-20 16:10:26 +00:00
Merge remote-tracking branch 'remotes/open/master' into merges/27_11_2018_16_42
# Conflicts: # node/src/integration-test/kotlin/net/corda/node/AddressBindingFailureTests.kt # node/src/integration-test/kotlin/net/corda/node/amqp/AMQPBridgeTest.kt # node/src/integration-test/kotlin/net/corda/node/amqp/ProtonWrapperTests.kt # node/src/integration-test/kotlin/net/corda/node/modes/draining/FlowsDrainingModeContentionTest.kt # node/src/integration-test/kotlin/net/corda/node/modes/draining/P2PFlowsDrainingModeTest.kt # node/src/integration-test/kotlin/net/corda/node/modes/draining/RpcFlowsDrainingModeTest.kt # node/src/integration-test/kotlin/net/corda/node/persistence/H2SecurityTests.kt # node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt # node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapTest.kt # node/src/integration-test/kotlin/net/corda/services/messaging/AdditionP2PAddressModeTest.kt # node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt # samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt # testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt
This commit is contained in:
@ -6081,7 +6081,7 @@ public abstract class net.corda.testing.driver.PortAllocation extends java.lang.
|
||||
public abstract int nextPort()
|
||||
##
|
||||
@DoNotImplement
|
||||
public static final class net.corda.testing.driver.PortAllocation$Incremental extends net.corda.testing.driver.PortAllocation
|
||||
public static class net.corda.testing.driver.PortAllocation$Incremental extends net.corda.testing.driver.PortAllocation
|
||||
public <init>(int)
|
||||
@NotNull
|
||||
public final java.util.concurrent.atomic.AtomicInteger getPortCounter()
|
||||
|
1
.idea/codeStyles/codeStyleConfig.xml
generated
1
.idea/codeStyles/codeStyleConfig.xml
generated
@ -1,5 +1,6 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Michele" />
|
||||
</state>
|
||||
</component>
|
@ -189,7 +189,8 @@ private class WireTransactionSerializer : JsonSerializer<WireTransaction>() {
|
||||
value.timeWindow,
|
||||
value.attachments,
|
||||
value.references,
|
||||
value.privacySalt
|
||||
value.privacySalt,
|
||||
value.networkParametersHash
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -204,7 +205,8 @@ private class WireTransactionDeserializer : JsonDeserializer<WireTransaction>()
|
||||
wrapper.attachments,
|
||||
wrapper.notary,
|
||||
wrapper.timeWindow,
|
||||
wrapper.references
|
||||
wrapper.references,
|
||||
wrapper.networkParametersHash
|
||||
)
|
||||
return WireTransaction(componentGroups, wrapper.privacySalt)
|
||||
}
|
||||
@ -218,7 +220,8 @@ private class WireTransactionJson(val id: SecureHash,
|
||||
val timeWindow: TimeWindow?,
|
||||
val attachments: List<SecureHash>,
|
||||
val references: List<StateRef>,
|
||||
val privacySalt: PrivacySalt)
|
||||
val privacySalt: PrivacySalt,
|
||||
val networkParametersHash: SecureHash?)
|
||||
|
||||
private interface TransactionStateMixin {
|
||||
@get:JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
||||
|
@ -24,6 +24,7 @@ import net.corda.core.internal.DigitalSignatureWithCert
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.services.AttachmentStorage
|
||||
import net.corda.core.node.services.NetworkParametersStorage
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.serialization.serialize
|
||||
@ -92,8 +93,13 @@ class JacksonSupportTest(@Suppress("unused") private val name: String, factory:
|
||||
}
|
||||
services = rigorousMock()
|
||||
cordappProvider = rigorousMock()
|
||||
val networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
|
||||
val networkParametersStorage = rigorousMock<NetworkParametersStorage>().also {
|
||||
doReturn(networkParameters.serialize().hash).whenever(it).currentHash
|
||||
}
|
||||
doReturn(networkParametersStorage).whenever(services).networkParametersStorage
|
||||
doReturn(cordappProvider).whenever(services).cordappProvider
|
||||
doReturn(testNetworkParameters(minimumPlatformVersion = 4)).whenever(services).networkParameters
|
||||
doReturn(networkParameters).whenever(services).networkParameters
|
||||
doReturn(attachments).whenever(services).attachments
|
||||
}
|
||||
|
||||
@ -254,7 +260,7 @@ class JacksonSupportTest(@Suppress("unused") private val name: String, factory:
|
||||
println(mapper.writeValueAsString(json))
|
||||
val (wtxJson, signaturesJson) = json.assertHasOnlyFields("wire", "signatures")
|
||||
assertThat(signaturesJson.childrenAs<TransactionSignature>(mapper)).isEqualTo(stx.sigs)
|
||||
val wtxFields = wtxJson.assertHasOnlyFields("id", "notary", "inputs", "attachments", "outputs", "commands", "timeWindow", "references", "privacySalt")
|
||||
val wtxFields = wtxJson.assertHasOnlyFields("id", "notary", "inputs", "attachments", "outputs", "commands", "timeWindow", "references", "privacySalt", "networkParametersHash")
|
||||
assertThat(wtxFields[0].valueAs<SecureHash>(mapper)).isEqualTo(wtx.id)
|
||||
assertThat(wtxFields[1].valueAs<Party>(mapper)).isEqualTo(wtx.notary)
|
||||
assertThat(wtxFields[2].childrenAs<StateRef>(mapper)).isEqualTo(wtx.inputs)
|
||||
|
@ -13,7 +13,7 @@ import net.corda.node.services.messaging.RPCServerConfiguration
|
||||
import net.corda.nodeapi.RPCApi
|
||||
import net.corda.nodeapi.eventually
|
||||
import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.testThreadFactory
|
||||
import net.corda.testing.node.internal.*
|
||||
import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration
|
||||
@ -39,7 +39,7 @@ class RPCStabilityTests {
|
||||
val testSerialization = SerializationEnvironmentRule(true)
|
||||
|
||||
private val pool = Executors.newFixedThreadPool(10, testThreadFactory())
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
|
||||
@After
|
||||
fun shutdown() {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.corda.client.rpc.internal.serialization.amqp
|
||||
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.internal.toSynchronised
|
||||
import net.corda.core.serialization.ClassWhitelist
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.core.serialization.SerializationContext.UseCase
|
||||
@ -19,19 +20,19 @@ class AMQPClientSerializationScheme(
|
||||
cordappCustomSerializers: Set<SerializationCustomSerializer<*,*>>,
|
||||
serializerFactoriesForContexts: MutableMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>
|
||||
) : AbstractAMQPSerializationScheme(cordappCustomSerializers, serializerFactoriesForContexts) {
|
||||
constructor(cordapps: List<Cordapp>) : this(cordapps.customSerializers, AccessOrderLinkedHashMap { 128 })
|
||||
constructor(cordapps: List<Cordapp>) : this(cordapps.customSerializers, AccessOrderLinkedHashMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>(128).toSynchronised())
|
||||
constructor(cordapps: List<Cordapp>, serializerFactoriesForContexts: MutableMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>) : this(cordapps.customSerializers, serializerFactoriesForContexts)
|
||||
|
||||
@Suppress("UNUSED")
|
||||
constructor() : this(emptySet(), AccessOrderLinkedHashMap { 128 })
|
||||
constructor() : this(emptySet(), AccessOrderLinkedHashMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>(128).toSynchronised())
|
||||
|
||||
companion object {
|
||||
/** Call from main only. */
|
||||
fun initialiseSerialization(classLoader: ClassLoader? = null, serializerFactoriesForContexts: MutableMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory> = AccessOrderLinkedHashMap { 128 }) {
|
||||
fun initialiseSerialization(classLoader: ClassLoader? = null, serializerFactoriesForContexts: MutableMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory> = AccessOrderLinkedHashMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>(128).toSynchronised()) {
|
||||
nodeSerializationEnv = createSerializationEnv(classLoader, serializerFactoriesForContexts)
|
||||
}
|
||||
|
||||
fun createSerializationEnv(classLoader: ClassLoader? = null, serializerFactoriesForContexts: MutableMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory> = AccessOrderLinkedHashMap { 128 }): SerializationEnvironment {
|
||||
fun createSerializationEnv(classLoader: ClassLoader? = null, serializerFactoriesForContexts: MutableMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory> = AccessOrderLinkedHashMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>(128).toSynchronised()): SerializationEnvironment {
|
||||
return SerializationEnvironment.with(
|
||||
SerializationFactoryImpl().apply {
|
||||
registerScheme(AMQPClientSerializationScheme(emptyList(), serializerFactoriesForContexts))
|
||||
|
@ -71,7 +71,8 @@ object TransactionGenerator {
|
||||
TransactionVerificationRequest(
|
||||
wtx3.serialize(),
|
||||
arrayOf(wtx1.serialize(), wtx2.serialize()),
|
||||
arrayOf(contractAttachment.serialize().bytes))
|
||||
arrayOf(contractAttachment.serialize().bytes),
|
||||
ledgerServices.networkParameters.serialize())
|
||||
.serialize()
|
||||
.writeTo(output)
|
||||
}
|
||||
@ -104,7 +105,8 @@ object TransactionGenerator {
|
||||
TransactionVerificationRequest(
|
||||
wtx3.serialize(),
|
||||
arrayOf(wtx1.serialize(), wtx2.serialize()),
|
||||
arrayOf(contractAttachment.serialize().bytes))
|
||||
arrayOf(contractAttachment.serialize().bytes),
|
||||
ledgerServices.networkParameters.serialize())
|
||||
.serialize()
|
||||
.writeTo(output)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import net.corda.core.contracts.Attachment
|
||||
import net.corda.core.contracts.ContractAttachment
|
||||
import net.corda.core.contracts.ContractClassName
|
||||
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.serialization.deserialize
|
||||
@ -14,7 +15,8 @@ import net.corda.core.transactions.WireTransaction
|
||||
@CordaSerializable
|
||||
class TransactionVerificationRequest(val wtxToVerify: SerializedBytes<WireTransaction>,
|
||||
val dependencies: Array<SerializedBytes<WireTransaction>>,
|
||||
val attachments: Array<ByteArray>) {
|
||||
val attachments: Array<ByteArray>,
|
||||
val networkParameters: SerializedBytes<NetworkParameters>) {
|
||||
fun toLedgerTransaction(): LedgerTransaction {
|
||||
val deps = dependencies.map { it.deserialize() }.associateBy(WireTransaction::id)
|
||||
val attachments = attachments.map { it.deserialize<Attachment>() }
|
||||
@ -24,10 +26,11 @@ class TransactionVerificationRequest(val wtxToVerify: SerializedBytes<WireTransa
|
||||
val contractAttachmentMap = emptyMap<ContractClassName, ContractAttachment>()
|
||||
@Suppress("DEPRECATION")
|
||||
return wtxToVerify.deserialize().toLedgerTransaction(
|
||||
resolveIdentity = { null },
|
||||
resolveAttachment = { attachmentMap[it] },
|
||||
resolveStateRef = { deps[it.txhash]?.outputs?.get(it.index) },
|
||||
resolveContractAttachment = { contractAttachmentMap[it.contract]?.id }
|
||||
resolveIdentity = { null },
|
||||
resolveAttachment = { attachmentMap[it] },
|
||||
resolveStateRef = { deps[it.txhash]?.outputs?.get(it.index) },
|
||||
resolveContractAttachment = { contractAttachmentMap[it.contract]?.id },
|
||||
resolveParameters = { networkParameters.deserialize() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -12,5 +12,6 @@ enum class ComponentGroupEnum {
|
||||
NOTARY_GROUP, // ordinal = 4.
|
||||
TIMEWINDOW_GROUP, // ordinal = 5.
|
||||
SIGNERS_GROUP, // ordinal = 6.
|
||||
REFERENCES_GROUP // ordinal = 7.
|
||||
REFERENCES_GROUP, // ordinal = 7.
|
||||
PARAMETERS_GROUP // ordinal = 8.
|
||||
}
|
||||
|
@ -212,6 +212,11 @@ abstract class SignTransactionFlow @JvmOverloads constructor(val otherSideSessio
|
||||
progressTracker.currentStep = RECEIVING
|
||||
// Receive transaction and resolve dependencies, check sufficient signatures is disabled as we don't have all signatures.
|
||||
val stx = subFlow(ReceiveTransactionFlow(otherSideSession, checkSufficientSignatures = false))
|
||||
// TODO ENT-2666: Have time period for checking the parameters (because of the delay of propagation of new network data).
|
||||
check(stx.networkParametersHash == serviceHub.networkParametersStorage.currentHash) {
|
||||
"Received transaction for signing with invalid network parameters hash: ${stx.networkParametersHash}." +
|
||||
"Node's parameters hash: ${serviceHub.networkParametersStorage.currentHash}"
|
||||
}
|
||||
// Receive the signing key that the party requesting the signature expects us to sign with. Having this provided
|
||||
// means we only have to check we own that one key, rather than matching all keys in the transaction against all
|
||||
// keys we own.
|
||||
|
@ -33,7 +33,8 @@ class NotaryChangeFlow<out T : ContractState>(
|
||||
val tx = NotaryChangeTransactionBuilder(
|
||||
inputs.map { it.ref },
|
||||
originalState.state.notary,
|
||||
modification
|
||||
modification,
|
||||
serviceHub.networkParametersStorage.currentHash
|
||||
).build()
|
||||
|
||||
val participantKeys = inputs.flatMap { it.state.data.participants }.map { it.owningKey }.toSet()
|
||||
|
@ -2,6 +2,7 @@ package net.corda.core.flows
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.DoNotImplement
|
||||
import net.corda.core.contracts.ComponentGroupEnum
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.crypto.SecureHash
|
||||
@ -12,10 +13,7 @@ import net.corda.core.internal.FetchDataFlow
|
||||
import net.corda.core.internal.notary.generateSignature
|
||||
import net.corda.core.internal.notary.validateSignatures
|
||||
import net.corda.core.internal.pushToLoggingContext
|
||||
import net.corda.core.transactions.ContractUpgradeWireTransaction
|
||||
import net.corda.core.transactions.ReferenceStateRef
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.transactions.*
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.UntrustworthyData
|
||||
import net.corda.core.utilities.unwrap
|
||||
@ -30,7 +28,8 @@ class NotaryFlow {
|
||||
* signatures will be returned – one from each replica that accepted the input state commit.
|
||||
*
|
||||
* @throws NotaryException in case the any of the inputs to the transaction have been consumed
|
||||
* by another transaction or the time-window is invalid.
|
||||
* by another transaction or the time-window is invalid or
|
||||
* the parameters used for this transaction are no longer in force in the network.
|
||||
*/
|
||||
@DoNotImplement
|
||||
@InitiatingFlow
|
||||
@ -99,7 +98,9 @@ class NotaryFlow {
|
||||
val ctx = stx.coreTransaction
|
||||
val tx = when (ctx) {
|
||||
is ContractUpgradeWireTransaction -> ctx.buildFilteredTransaction()
|
||||
is WireTransaction -> ctx.buildFilteredTransaction(Predicate { it is StateRef || it is ReferenceStateRef || it is TimeWindow || it == notaryParty })
|
||||
is WireTransaction -> ctx.buildFilteredTransaction(Predicate {
|
||||
it is StateRef || it is ReferenceStateRef || it is TimeWindow || it == notaryParty || it is NetworkParametersHash
|
||||
})
|
||||
else -> ctx
|
||||
}
|
||||
session.send(NotarisationPayload(tx, signature))
|
||||
|
@ -21,6 +21,7 @@ object ContractUpgradeUtils {
|
||||
else -> getContractAttachmentId(stateAndRef.state.contract, services)
|
||||
}
|
||||
val upgradedContractAttachmentId = getContractAttachmentId(upgradedContractClass.name, services)
|
||||
val networkParametersHash = services.networkParametersStorage.currentHash
|
||||
|
||||
val inputs = listOf(stateAndRef.ref)
|
||||
return ContractUpgradeTransactionBuilder(
|
||||
@ -29,7 +30,8 @@ object ContractUpgradeUtils {
|
||||
legacyContractAttachmentId,
|
||||
upgradedContractClass.name,
|
||||
upgradedContractAttachmentId,
|
||||
privacySalt
|
||||
privacySalt,
|
||||
networkParametersHash
|
||||
).build()
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,7 @@ class FetchAttachmentsFlow(requests: Set<SecureHash>,
|
||||
* [FetchDataFlow.DownloadedVsRequestedDataMismatch] being thrown.
|
||||
* If the remote peer doesn't have an entry, it results in a [FetchDataFlow.HashNotFound] exception.
|
||||
* If the remote peer is not authorized to request this transaction, it results in a [FetchDataFlow.IllegalTransactionRequest] exception.
|
||||
* Authorisation is accorded only on valid ancestors of the root transation.
|
||||
* Authorisation is accorded only on valid ancestors of the root transaction.
|
||||
* Note that returned transactions are not inserted into the database, because it's up to the caller to actually verify the transactions are valid.
|
||||
*/
|
||||
class FetchTransactionsFlow(requests: Set<SecureHash>, otherSide: FlowSession) :
|
||||
|
@ -17,9 +17,10 @@ import kotlin.reflect.KClass
|
||||
/** Constructs a [NotaryChangeWireTransaction]. */
|
||||
class NotaryChangeTransactionBuilder(val inputs: List<StateRef>,
|
||||
val notary: Party,
|
||||
val newNotary: Party) {
|
||||
val newNotary: Party,
|
||||
val networkParametersHash: SecureHash) {
|
||||
fun build(): NotaryChangeWireTransaction {
|
||||
val components = listOf(inputs, notary, newNotary).map { it.serialize() }
|
||||
val components = listOf(inputs, notary, newNotary, networkParametersHash).map { it.serialize() }
|
||||
return NotaryChangeWireTransaction(components)
|
||||
}
|
||||
}
|
||||
@ -31,9 +32,10 @@ class ContractUpgradeTransactionBuilder(
|
||||
val legacyContractAttachmentId: SecureHash,
|
||||
val upgradedContractClassName: ContractClassName,
|
||||
val upgradedContractAttachmentId: SecureHash,
|
||||
val privacySalt: PrivacySalt = PrivacySalt()) {
|
||||
val privacySalt: PrivacySalt = PrivacySalt(),
|
||||
val networkParametersHash: SecureHash) {
|
||||
fun build(): ContractUpgradeWireTransaction {
|
||||
val components = listOf(inputs, notary, legacyContractAttachmentId, upgradedContractClassName, upgradedContractAttachmentId).map { it.serialize() }
|
||||
val components = listOf(inputs, notary, legacyContractAttachmentId, upgradedContractClassName, upgradedContractAttachmentId, networkParametersHash).map { it.serialize() }
|
||||
return ContractUpgradeWireTransaction(components, privacySalt)
|
||||
}
|
||||
}
|
||||
@ -128,7 +130,8 @@ fun createComponentGroups(inputs: List<StateRef>,
|
||||
attachments: List<SecureHash>,
|
||||
notary: Party?,
|
||||
timeWindow: TimeWindow?,
|
||||
references: List<StateRef>): List<ComponentGroup> {
|
||||
references: List<StateRef>,
|
||||
networkParametersHash: SecureHash?): List<ComponentGroup> {
|
||||
val serialize = { value: Any, _: Int -> value.serialize() }
|
||||
val componentGroupMap: MutableList<ComponentGroup> = mutableListOf()
|
||||
if (inputs.isNotEmpty()) componentGroupMap.add(ComponentGroup(ComponentGroupEnum.INPUTS_GROUP.ordinal, inputs.lazyMapped(serialize)))
|
||||
@ -142,6 +145,7 @@ fun createComponentGroups(inputs: List<StateRef>,
|
||||
// Adding signers to their own group. This is required for command visibility purposes: a party receiving
|
||||
// a FilteredTransaction can now verify it sees all the commands it should sign.
|
||||
if (commands.isNotEmpty()) componentGroupMap.add(ComponentGroup(ComponentGroupEnum.SIGNERS_GROUP.ordinal, commands.map { it.signers }.lazyMapped(serialize)))
|
||||
if (networkParametersHash != null) componentGroupMap.add(ComponentGroup(ComponentGroupEnum.PARAMETERS_GROUP.ordinal, listOf(networkParametersHash.serialize())))
|
||||
return componentGroupMap
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,6 @@ abstract class NotaryServiceFlow(val otherSideSession: FlowSession, val service:
|
||||
requestPayload.requestSignature,
|
||||
tx.timeWindow,
|
||||
tx.references)
|
||||
|
||||
} catch (e: NotaryInternalException) {
|
||||
logError(e.error)
|
||||
// Any exception that's not a NotaryInternalException is assumed to be an unexpected internal error
|
||||
@ -96,6 +95,7 @@ abstract class NotaryServiceFlow(val otherSideSession: FlowSession, val service:
|
||||
val transaction = extractParts(requestPayload)
|
||||
transactionId = transaction.id
|
||||
checkNotary(transaction.notary)
|
||||
checkParametersHash(transaction.networkParametersHash)
|
||||
checkInputs(transaction.inputs + transaction.references)
|
||||
return transaction
|
||||
} catch (e: Exception) {
|
||||
@ -123,6 +123,21 @@ abstract class NotaryServiceFlow(val otherSideSession: FlowSession, val service:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that network parameters hash on this transaction is the current hash for the network.
|
||||
*/
|
||||
// TODO ENT-2666 Implement network parameters fuzzy checking. By design in Corda network we have propagation time delay.
|
||||
// We will never end up in perfect synchronization with all the nodes. However, network parameters update process
|
||||
// lets us predict what is the reasonable time window for changing parameters on most of the nodes.
|
||||
@Suspendable
|
||||
protected fun checkParametersHash(networkParametersHash: SecureHash?) {
|
||||
if (networkParametersHash == null && serviceHub.networkParameters.minimumPlatformVersion < 4) return
|
||||
val notaryParametersHash = serviceHub.networkParametersStorage.currentHash
|
||||
require (notaryParametersHash == networkParametersHash) {
|
||||
"Transaction for notarisation was tagged with parameters with hash: $networkParametersHash, but current network parameters are: $notaryParametersHash"
|
||||
}
|
||||
}
|
||||
|
||||
/** Verifies that the correct notarisation request was signed by the counterparty. */
|
||||
private fun validateRequestSignature(request: NotarisationRequest, signature: NotarisationRequestSignature) {
|
||||
val requestingParty = otherSideSession.counterparty
|
||||
@ -151,7 +166,8 @@ abstract class NotaryServiceFlow(val otherSideSession: FlowSession, val service:
|
||||
val inputs: List<StateRef>,
|
||||
val timeWindow: TimeWindow?,
|
||||
val notary: Party?,
|
||||
val references: List<StateRef> = emptyList()
|
||||
val references: List<StateRef> = emptyList(),
|
||||
val networkParametersHash: SecureHash?
|
||||
)
|
||||
|
||||
private fun logError(error: NotaryError) {
|
||||
|
@ -5,10 +5,7 @@ import net.corda.core.DoNotImplement
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.cordapp.CordappContext
|
||||
import net.corda.core.cordapp.CordappProvider
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SignableData
|
||||
import net.corda.core.crypto.SignatureMetadata
|
||||
import net.corda.core.crypto.TransactionSignature
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.flows.ContractUpgradeFlow
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
@ -41,6 +38,9 @@ interface ServicesForResolution {
|
||||
/** Provides access to anything relating to cordapps including contract attachment resolution and app context */
|
||||
val cordappProvider: CordappProvider
|
||||
|
||||
/** Provides access to storage of historical network parameters that are used in transaction resolution */
|
||||
val networkParametersStorage: NetworkParametersStorage
|
||||
|
||||
/** Returns the network parameters the node is operating under. */
|
||||
val networkParameters: NetworkParameters
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
package net.corda.core.node.services
|
||||
|
||||
import net.corda.core.CordaInternal
|
||||
import net.corda.core.DoNotImplement
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.internal.SignedDataWithCert
|
||||
import net.corda.core.node.NetworkParameters
|
||||
|
||||
/**
|
||||
* Interface for handling network parameters storage used for resolving transactions according to parameters that were
|
||||
* historically in force in the network.
|
||||
*/
|
||||
@DoNotImplement
|
||||
interface NetworkParametersStorage {
|
||||
/**
|
||||
* Hash of the current parameters for the network.
|
||||
*/
|
||||
val currentHash: SecureHash
|
||||
|
||||
/**
|
||||
* For backwards compatibility, this parameters hash will be used for resolving historical transactions in the chain.
|
||||
*/
|
||||
val defaultHash: SecureHash
|
||||
|
||||
/**
|
||||
* Return network parameters for the given hash. Null if there are no parameters for this hash in the storage and we are unable to
|
||||
* get them from network map.
|
||||
*/
|
||||
fun lookup(hash: SecureHash): NetworkParameters?
|
||||
}
|
@ -3,6 +3,8 @@ package net.corda.core.transactions
|
||||
import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
|
||||
/**
|
||||
@ -16,13 +18,24 @@ abstract class CoreTransaction : BaseTransaction() {
|
||||
abstract override val inputs: List<StateRef>
|
||||
/** The reference inputs of this transaction, containing the state references only. **/
|
||||
abstract override val references: List<StateRef>
|
||||
/**
|
||||
* Hash of the network parameters that were in force when the transaction was notarised. Null means, that the transaction
|
||||
* was created on older version of Corda (before 4), resolution will default to initial parameters.
|
||||
*/
|
||||
abstract val networkParametersHash: SecureHash?
|
||||
}
|
||||
|
||||
/** A transaction with fully resolved components, such as input states. */
|
||||
abstract class FullTransaction : BaseTransaction() {
|
||||
abstract override val inputs: List<StateAndRef<ContractState>>
|
||||
abstract override val references: List<StateAndRef<ContractState>>
|
||||
|
||||
// TODO NetworkParameters field is nullable only because of the API stability and the fact that our ledger transactions exposed constructors
|
||||
// (they were data classes). This should be revisited.
|
||||
/**
|
||||
* Network parameters that were in force when this transaction was created. Resolved from the hash of network parameters on the corresponding
|
||||
* wire transaction.
|
||||
*/
|
||||
abstract val networkParameters: NetworkParameters?
|
||||
override fun checkBaseInvariants() {
|
||||
super.checkBaseInvariants()
|
||||
checkInputsAndReferencesHaveSameNotary()
|
||||
|
@ -69,6 +69,11 @@ data class ContractUpgradeWireTransaction(
|
||||
val legacyContractAttachmentId: SecureHash by lazy { serializedComponents[LEGACY_ATTACHMENT.ordinal].deserialize<SecureHash>() }
|
||||
val upgradedContractClassName: ContractClassName by lazy { serializedComponents[UPGRADED_CONTRACT.ordinal].deserialize<ContractClassName>() }
|
||||
val upgradedContractAttachmentId: SecureHash by lazy { serializedComponents[UPGRADED_ATTACHMENT.ordinal].deserialize<SecureHash>() }
|
||||
override val networkParametersHash: SecureHash? by lazy {
|
||||
if (serializedComponents.size >= PARAMETERS_HASH.ordinal + 1) {
|
||||
serializedComponents[PARAMETERS_HASH.ordinal].deserialize<SecureHash>()
|
||||
} else null
|
||||
}
|
||||
|
||||
init {
|
||||
check(inputs.isNotEmpty()) { "A contract upgrade transaction must have inputs" }
|
||||
@ -106,6 +111,8 @@ data class ContractUpgradeWireTransaction(
|
||||
?: throw AttachmentResolutionException(legacyContractAttachmentId)
|
||||
val upgradedContractAttachment = services.attachments.openAttachment(upgradedContractAttachmentId)
|
||||
?: throw AttachmentResolutionException(upgradedContractAttachmentId)
|
||||
val hashToResolve = networkParametersHash ?: services.networkParametersStorage.defaultHash
|
||||
val resolvedNetworkParameters = services.networkParametersStorage.lookup(hashToResolve) ?: throw TransactionResolutionException(id)
|
||||
return ContractUpgradeLedgerTransaction(
|
||||
resolvedInputs,
|
||||
notary,
|
||||
@ -115,7 +122,7 @@ data class ContractUpgradeWireTransaction(
|
||||
id,
|
||||
privacySalt,
|
||||
sigs,
|
||||
services.networkParameters
|
||||
resolvedNetworkParameters
|
||||
)
|
||||
}
|
||||
|
||||
@ -145,12 +152,13 @@ data class ContractUpgradeWireTransaction(
|
||||
}
|
||||
}
|
||||
|
||||
/** Constructs a filtered transaction: the inputs and the notary party are always visible, while the rest are hidden. */
|
||||
/** Constructs a filtered transaction: the inputs, the notary party and network parameters hash are always visible, while the rest are hidden. */
|
||||
fun buildFilteredTransaction(): ContractUpgradeFilteredTransaction {
|
||||
val totalComponents = (0 until serializedComponents.size).toSet()
|
||||
val visibleComponents = mapOf(
|
||||
INPUTS.ordinal to FilteredComponent(serializedComponents[INPUTS.ordinal], nonces[INPUTS.ordinal]),
|
||||
NOTARY.ordinal to FilteredComponent(serializedComponents[NOTARY.ordinal], nonces[NOTARY.ordinal])
|
||||
NOTARY.ordinal to FilteredComponent(serializedComponents[NOTARY.ordinal], nonces[NOTARY.ordinal]),
|
||||
PARAMETERS_HASH.ordinal to FilteredComponent(serializedComponents[PARAMETERS_HASH.ordinal], nonces[PARAMETERS_HASH.ordinal])
|
||||
)
|
||||
val hiddenComponents = (totalComponents - visibleComponents.keys).map { index ->
|
||||
val hash = componentHash(nonces[index], serializedComponents[index])
|
||||
@ -161,13 +169,13 @@ data class ContractUpgradeWireTransaction(
|
||||
}
|
||||
|
||||
enum class Component {
|
||||
INPUTS, NOTARY, LEGACY_ATTACHMENT, UPGRADED_CONTRACT, UPGRADED_ATTACHMENT
|
||||
INPUTS, NOTARY, LEGACY_ATTACHMENT, UPGRADED_CONTRACT, UPGRADED_ATTACHMENT, PARAMETERS_HASH
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A filtered version of the [ContractUpgradeWireTransaction]. In comparison with a regular [FilteredTransaction], there
|
||||
* is no flexibility on what parts of the transaction to reveal – the inputs and notary field are always visible and the
|
||||
* is no flexibility on what parts of the transaction to reveal – the inputs, notary and network parameters hash fields are always visible and the
|
||||
* rest of the transaction is always hidden. Its only purpose is to hide transaction data when using a non-validating notary.
|
||||
*/
|
||||
@KeepForDJVM
|
||||
@ -189,6 +197,9 @@ data class ContractUpgradeFilteredTransaction(
|
||||
visibleComponents[NOTARY.ordinal]?.component?.deserialize<Party>()
|
||||
?: throw IllegalArgumentException("Notary not specified")
|
||||
}
|
||||
override val networkParametersHash: SecureHash? by lazy {
|
||||
visibleComponents[PARAMETERS_HASH.ordinal]?.component?.deserialize<SecureHash>()
|
||||
}
|
||||
override val id: SecureHash by lazy {
|
||||
val totalComponents = visibleComponents.size + hiddenComponents.size
|
||||
val hashList = (0 until totalComponents).map { i ->
|
||||
@ -230,9 +241,9 @@ data class ContractUpgradeLedgerTransaction(
|
||||
override val id: SecureHash,
|
||||
val privacySalt: PrivacySalt,
|
||||
override val sigs: List<TransactionSignature>,
|
||||
private val networkParameters: NetworkParameters
|
||||
override val networkParameters: NetworkParameters
|
||||
) : FullTransaction(), TransactionWithSignatures {
|
||||
/** ContractUpgradeLEdgerTransactions do not contain reference input states. */
|
||||
/** ContractUpgradeLedgerTransactions do not contain reference input states. */
|
||||
override val references: List<StateAndRef<ContractState>> = emptyList()
|
||||
/** The legacy contract class name is determined by the first input state. */
|
||||
private val legacyContractClassName = inputs.first().state.contract
|
||||
|
@ -52,7 +52,10 @@ private constructor(
|
||||
override val notary: Party?,
|
||||
val timeWindow: TimeWindow?,
|
||||
val privacySalt: PrivacySalt,
|
||||
val networkParameters: NetworkParameters?,
|
||||
/** Network parameters that were in force when the transaction was notarised. */
|
||||
// TODO Network parameters should never be null on LedgerTransaction, this is left only because of deprecated constructors. We should decide to
|
||||
// get rid of them.
|
||||
override val networkParameters: NetworkParameters?,
|
||||
override val references: List<StateAndRef<ContractState>>
|
||||
//DOCEND 1
|
||||
) : FullTransaction() {
|
||||
@ -81,7 +84,7 @@ private constructor(
|
||||
notary: Party?,
|
||||
timeWindow: TimeWindow?,
|
||||
privacySalt: PrivacySalt,
|
||||
networkParameters: NetworkParameters?,
|
||||
networkParameters: NetworkParameters,
|
||||
references: List<StateAndRef<ContractState>>,
|
||||
componentGroups: List<ComponentGroup>? = null,
|
||||
serializedInputs: List<SerializedStateAndRef>? = null,
|
||||
@ -121,6 +124,11 @@ private constructor(
|
||||
*/
|
||||
@Throws(TransactionVerificationException::class)
|
||||
fun verify() {
|
||||
if (networkParameters == null) {
|
||||
// For backwards compatibility only.
|
||||
logger.warn("Network parameters on the LedgerTransaction with id: $id are null. Please don't use deprecated constructors of the LedgerTransaction. " +
|
||||
"Use WireTransaction.toLedgerTransaction instead. The result of the verify method might not be accurate.")
|
||||
}
|
||||
val contractAttachmentsByContract: Map<ContractClassName, ContractAttachment> = getUniqueContractAttachmentsByContract()
|
||||
|
||||
AttachmentsClassLoaderBuilder.withAttachmentsClassloaderContext(this.attachments) { transactionClassLoader ->
|
||||
@ -169,14 +177,14 @@ private constructor(
|
||||
/**
|
||||
* Verify that for each contract the network wide package owner is respected.
|
||||
*
|
||||
* TODO - revisit once transaction contains network parameters.
|
||||
* TODO - revisit once transaction contains network parameters. - UPDATE: It contains them, but because of the API stability and the fact that
|
||||
* LedgerTransaction was data class i.e. exposed constructors that shouldn't had been exposed, we still need to keep them nullable :/
|
||||
*/
|
||||
private fun validatePackageOwnership(contractAttachmentsByContract: Map<ContractClassName, ContractAttachment>) {
|
||||
// This should never happen once we have network parameters in the transaction.
|
||||
if (networkParameters == null) {
|
||||
return
|
||||
}
|
||||
|
||||
val contractsAndOwners = allStates.mapNotNull { transactionState ->
|
||||
val contractClassName = transactionState.contract
|
||||
networkParameters.getOwnerOf(contractClassName)?.let { contractClassName to it }
|
||||
@ -243,7 +251,6 @@ private constructor(
|
||||
|
||||
if (state.constraint is SignatureAttachmentConstraint)
|
||||
checkMinimumPlatformVersion(networkParameters?.minimumPlatformVersion ?: 1, 4, "Signature constraints")
|
||||
|
||||
if (!state.constraint.isSatisfiedBy(constraintAttachment)) {
|
||||
throw TransactionVerificationException.ContractConstraintRejection(id, state.contract)
|
||||
}
|
||||
@ -806,11 +813,8 @@ private constructor(
|
||||
|)""".trimMargin()
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Stuff that we can't remove and so is deprecated instead
|
||||
//
|
||||
|
||||
@Deprecated("LedgerTransaction should not be created directly, use WireTransaction.toLedgerTransaction instead.")
|
||||
constructor(
|
||||
inputs: List<StateAndRef<ContractState>>,
|
||||
@ -834,7 +838,7 @@ private constructor(
|
||||
notary: Party?,
|
||||
timeWindow: TimeWindow?,
|
||||
privacySalt: PrivacySalt,
|
||||
networkParameters: NetworkParameters?
|
||||
networkParameters: NetworkParameters
|
||||
) : this(inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, networkParameters, emptyList())
|
||||
|
||||
@Deprecated("LedgerTransactions should not be created directly, use WireTransaction.toLedgerTransaction instead.")
|
||||
|
@ -48,6 +48,12 @@ abstract class TraversableTransaction(open val componentGroups: List<ComponentGr
|
||||
timeWindows.firstOrNull()
|
||||
}
|
||||
|
||||
override val networkParametersHash: SecureHash? = let {
|
||||
val parametersHashes = deserialiseComponentGroup(componentGroups, SecureHash::class, PARAMETERS_GROUP)
|
||||
check(parametersHashes.size <= 1) { "Invalid Transaction. More than 1 network parameters hash detected." }
|
||||
parametersHashes.firstOrNull()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the component groups that are present in the transaction, excluding the privacySalt,
|
||||
* in the following order (which is the same with the order in [ComponentGroupEnum]:
|
||||
@ -58,12 +64,14 @@ abstract class TraversableTransaction(open val componentGroups: List<ComponentGr
|
||||
* - The notary [Party], if present (list with one element)
|
||||
* - The time-window of the transaction, if present (list with one element)
|
||||
* - list of each reference input that is present
|
||||
* - network parameters hash if present
|
||||
*/
|
||||
val availableComponentGroups: List<List<Any>>
|
||||
get() {
|
||||
val result = mutableListOf(inputs, outputs, commands, attachments, references)
|
||||
notary?.let { result += listOf(it) }
|
||||
timeWindow?.let { result += listOf(it) }
|
||||
networkParametersHash?.let { result += listOf(it) }
|
||||
return result
|
||||
}
|
||||
}
|
||||
@ -149,7 +157,9 @@ class FilteredTransaction internal constructor(
|
||||
if (wtx.timeWindow != null) filter(wtx.timeWindow, TIMEWINDOW_GROUP.ordinal, 0)
|
||||
// Note that because [inputs] and [references] share the same type [StateRef], we use a wrapper for references [ReferenceStateRef],
|
||||
// when filtering. Thus, to filter-in all [references] based on type, one should use the wrapper type [ReferenceStateRef] and not [StateRef].
|
||||
// Similar situation is for network parameters hash and attachments, one should use wrapper [NetworkParametersHash] and not [SecureHash].
|
||||
wtx.references.forEachIndexed { internalIndex, it -> filter(ReferenceStateRef(it), REFERENCES_GROUP.ordinal, internalIndex) }
|
||||
wtx.networkParametersHash?.let { filter(NetworkParametersHash(it), PARAMETERS_GROUP.ordinal, 0) }
|
||||
// It is highlighted that because there is no a signers property in TraversableTransaction,
|
||||
// one cannot specifically filter them in or out.
|
||||
// The above is very important to ensure someone won't filter out the signers component group if at least one
|
||||
@ -351,3 +361,8 @@ class FilteredTransactionVerificationException(val id: SecureHash, val reason: S
|
||||
@KeepForDJVM
|
||||
@CordaSerializable
|
||||
data class ReferenceStateRef(val stateRef: StateRef)
|
||||
|
||||
/** Wrapper over [SecureHash] to be used when filtering network parameters hash. */
|
||||
@KeepForDJVM
|
||||
@CordaSerializable
|
||||
data class NetworkParametersHash(val hash: SecureHash)
|
@ -8,6 +8,7 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.TransactionSignature
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.ServicesForResolution
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
@ -37,9 +38,16 @@ data class NotaryChangeWireTransaction(
|
||||
override val inputs: List<StateRef> = serializedComponents[INPUTS.ordinal].deserialize()
|
||||
override val references: List<StateRef> = emptyList()
|
||||
override val notary: Party = serializedComponents[NOTARY.ordinal].deserialize()
|
||||
|
||||
/** Identity of the notary service to reassign the states to.*/
|
||||
val newNotary: Party = serializedComponents[NEW_NOTARY.ordinal].deserialize()
|
||||
|
||||
override val networkParametersHash: SecureHash? by lazy {
|
||||
if (serializedComponents.size >= PARAMETERS_HASH.ordinal + 1) {
|
||||
serializedComponents[PARAMETERS_HASH.ordinal].deserialize<SecureHash>()
|
||||
} else null
|
||||
}
|
||||
|
||||
/**
|
||||
* This transaction does not contain any output states, outputs can be obtained by resolving a
|
||||
* [NotaryChangeLedgerTransaction] and applying the notary modification to inputs.
|
||||
@ -66,11 +74,14 @@ data class NotaryChangeWireTransaction(
|
||||
}
|
||||
}
|
||||
|
||||
/** Resolves input states and builds a [NotaryChangeLedgerTransaction]. */
|
||||
/** Resolves input states and network parameters and builds a [NotaryChangeLedgerTransaction]. */
|
||||
@DeleteForDJVM
|
||||
fun resolve(services: ServicesForResolution, sigs: List<TransactionSignature>): NotaryChangeLedgerTransaction {
|
||||
val resolvedInputs = services.loadStates(inputs.toSet()).toList()
|
||||
return NotaryChangeLedgerTransaction(resolvedInputs, notary, newNotary, id, sigs)
|
||||
val hashToResolve = networkParametersHash ?: services.networkParametersStorage.defaultHash
|
||||
val resolvedNetworkParameters = services.networkParametersStorage.lookup(hashToResolve)
|
||||
?: throw TransactionResolutionException(id)
|
||||
return NotaryChangeLedgerTransaction.create(resolvedInputs, notary, newNotary, id, sigs, resolvedNetworkParameters)
|
||||
}
|
||||
|
||||
/** Resolves input states and builds a [NotaryChangeLedgerTransaction]. */
|
||||
@ -92,7 +103,7 @@ data class NotaryChangeWireTransaction(
|
||||
}
|
||||
|
||||
enum class Component {
|
||||
INPUTS, NOTARY, NEW_NOTARY
|
||||
INPUTS, NOTARY, NEW_NOTARY, PARAMETERS_HASH
|
||||
}
|
||||
|
||||
@Deprecated("Required only for backwards compatibility purposes. This type of transaction should not be constructed outside Corda code.", ReplaceWith("NotaryChangeTransactionBuilder"), DeprecationLevel.WARNING)
|
||||
@ -105,13 +116,29 @@ data class NotaryChangeWireTransaction(
|
||||
* needed for signature verification.
|
||||
*/
|
||||
@KeepForDJVM
|
||||
data class NotaryChangeLedgerTransaction(
|
||||
class NotaryChangeLedgerTransaction
|
||||
private constructor(
|
||||
override val inputs: List<StateAndRef<ContractState>>,
|
||||
override val notary: Party,
|
||||
val newNotary: Party,
|
||||
override val id: SecureHash,
|
||||
override val sigs: List<TransactionSignature>
|
||||
override val sigs: List<TransactionSignature>,
|
||||
// TODO Network parameters should never be null on NotaryChangeLedgerTransaction, this is left only because of deprecated constructors. We should decide to
|
||||
// get rid of them.
|
||||
override val networkParameters: NetworkParameters?
|
||||
) : FullTransaction(), TransactionWithSignatures {
|
||||
companion object {
|
||||
@CordaInternal
|
||||
internal fun create(inputs: List<StateAndRef<ContractState>>,
|
||||
notary: Party,
|
||||
newNotary: Party,
|
||||
id: SecureHash,
|
||||
sigs: List<TransactionSignature>,
|
||||
networkParameters: NetworkParameters): NotaryChangeLedgerTransaction {
|
||||
return NotaryChangeLedgerTransaction(inputs, notary, newNotary, id, sigs, networkParameters)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
checkEncumbrances()
|
||||
}
|
||||
@ -157,4 +184,54 @@ data class NotaryChangeLedgerTransaction(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun component1(): List<StateAndRef<ContractState>> = inputs
|
||||
operator fun component2(): Party = notary
|
||||
operator fun component3(): Party = newNotary
|
||||
operator fun component4(): SecureHash = id
|
||||
operator fun component5(): List<TransactionSignature> = sigs
|
||||
operator fun component6(): NetworkParameters? = networkParameters
|
||||
|
||||
override fun equals(other: Any?): Boolean = this === other || other is NotaryChangeLedgerTransaction && this.id == other.id
|
||||
|
||||
override fun hashCode(): Int = id.hashCode()
|
||||
|
||||
override fun toString(): String {
|
||||
return """NotaryChangeLedgerTransaction(
|
||||
| id=$id
|
||||
| inputs=$inputs
|
||||
| notary=$notary
|
||||
| newNotary=$newNotary
|
||||
| sigs=$sigs
|
||||
| networkParameters=$networkParameters
|
||||
|)""".trimMargin()
|
||||
}
|
||||
|
||||
// Things that we can't remove after `data class` removal from this class, so it is deprecated instead.
|
||||
//
|
||||
@Deprecated("NotaryChangeLedgerTransaction should not be created directly, use NotaryChangeWireTransaction.resolve instead.")
|
||||
constructor(
|
||||
inputs: List<StateAndRef<ContractState>>,
|
||||
notary: Party,
|
||||
newNotary: Party,
|
||||
id: SecureHash,
|
||||
sigs: List<TransactionSignature>
|
||||
) : this(inputs, notary, newNotary, id, sigs, null)
|
||||
|
||||
@Deprecated("NotaryChangeLedgerTransaction should not be created directly, use NotaryChangeWireTransaction.resolve instead.")
|
||||
fun copy(inputs: List<StateAndRef<ContractState>> = this.inputs,
|
||||
notary: Party = this.notary,
|
||||
newNotary: Party = this.newNotary,
|
||||
id: SecureHash = this.id,
|
||||
sigs: List<TransactionSignature> = this.sigs
|
||||
): NotaryChangeLedgerTransaction {
|
||||
return NotaryChangeLedgerTransaction(
|
||||
inputs,
|
||||
notary,
|
||||
newNotary,
|
||||
id,
|
||||
sigs,
|
||||
this.networkParameters
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +76,8 @@ data class SignedTransaction(val txBits: SerializedBytes<CoreTransaction>,
|
||||
val references: List<StateRef> get() = coreTransaction.references
|
||||
/** Helper to access the notary of the contained transaction. */
|
||||
val notary: Party? get() = coreTransaction.notary
|
||||
/** Helper to access the network parameters hash for the contained transaction. */
|
||||
val networkParametersHash: SecureHash? get() = coreTransaction.networkParametersHash
|
||||
|
||||
override val requiredSigningKeys: Set<PublicKey> get() = tx.requiredSigningKeys
|
||||
|
||||
|
@ -167,8 +167,8 @@ open class TransactionBuilder @JvmOverloads constructor(
|
||||
(allContractAttachments + attachments).toSortedSet().toList(), // Sort the attachments to ensure transaction builds are stable.
|
||||
notary,
|
||||
window,
|
||||
referenceStates
|
||||
),
|
||||
referenceStates,
|
||||
services.networkParametersStorage.currentHash),
|
||||
privacySalt
|
||||
)
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
||||
notary: Party?,
|
||||
timeWindow: TimeWindow?,
|
||||
privacySalt: PrivacySalt = PrivacySalt()
|
||||
) : this(createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow, emptyList()), privacySalt)
|
||||
) : this(createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow, emptyList(), null), privacySalt)
|
||||
|
||||
init {
|
||||
check(componentGroups.all { it.components.isNotEmpty() }) { "Empty component groups are not allowed" }
|
||||
@ -106,7 +106,10 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
||||
resolveIdentity = { services.identityService.partyFromKey(it) },
|
||||
resolveAttachment = { services.attachments.openAttachment(it) },
|
||||
resolveStateRefAsSerialized = { resolveStateRefBinaryComponent(it, services) },
|
||||
networkParameters = services.networkParameters
|
||||
resolveParameters = {
|
||||
val hashToResolve = it ?: services.networkParametersStorage.defaultHash
|
||||
services.networkParametersStorage.lookup(hashToResolve)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -119,21 +122,24 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
||||
*/
|
||||
@Deprecated("Use toLedgerTransaction(ServicesForTransaction) instead")
|
||||
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class)
|
||||
@JvmOverloads
|
||||
fun toLedgerTransaction(
|
||||
resolveIdentity: (PublicKey) -> Party?,
|
||||
resolveAttachment: (SecureHash) -> Attachment?,
|
||||
resolveStateRef: (StateRef) -> TransactionState<*>?,
|
||||
@Suppress("UNUSED_PARAMETER") resolveContractAttachment: (TransactionState<ContractState>) -> AttachmentId?
|
||||
@Suppress("UNUSED_PARAMETER") resolveContractAttachment: (TransactionState<ContractState>) -> AttachmentId?,
|
||||
resolveParameters: (SecureHash?) -> NetworkParameters? = { null } // TODO This { null } is left here only because of API stability. It doesn't make much sense anymore as it will fail on transaction verification.
|
||||
): LedgerTransaction {
|
||||
// This reverts to serializing the resolved transaction state.
|
||||
return toLedgerTransactionInternal(resolveIdentity, resolveAttachment, { stateRef -> resolveStateRef(stateRef)?.serialize() }, null)
|
||||
return toLedgerTransactionInternal(resolveIdentity, resolveAttachment, { stateRef -> resolveStateRef(stateRef)?.serialize() }, resolveParameters)
|
||||
}
|
||||
|
||||
|
||||
private fun toLedgerTransactionInternal(
|
||||
resolveIdentity: (PublicKey) -> Party?,
|
||||
resolveAttachment: (SecureHash) -> Attachment?,
|
||||
resolveStateRefAsSerialized: (StateRef) -> SerializedBytes<TransactionState<ContractState>>?,
|
||||
networkParameters: NetworkParameters?
|
||||
resolveParameters: (SecureHash?) -> NetworkParameters?
|
||||
): LedgerTransaction {
|
||||
// Look up public keys to authenticated identities.
|
||||
val authenticatedCommands = commands.lazyMapped { cmd, _ ->
|
||||
@ -153,6 +159,8 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
||||
|
||||
val resolvedAttachments = attachments.lazyMapped { att, _ -> resolveAttachment(att) ?: throw AttachmentResolutionException(att) }
|
||||
|
||||
val resolvedNetworkParameters = resolveParameters(networkParametersHash) ?: throw TransactionResolutionException(id)
|
||||
|
||||
val ltx = LedgerTransaction.create(
|
||||
resolvedInputs,
|
||||
outputs,
|
||||
@ -162,14 +170,14 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
||||
notary,
|
||||
timeWindow,
|
||||
privacySalt,
|
||||
networkParameters,
|
||||
resolvedNetworkParameters,
|
||||
resolvedReferences,
|
||||
componentGroups,
|
||||
serializedResolvedInputs,
|
||||
serializedResolvedReferences
|
||||
)
|
||||
|
||||
checkTransactionSize(ltx, networkParameters?.maxTransactionSize ?: DEFAULT_MAX_TX_SIZE, serializedResolvedInputs, serializedResolvedReferences)
|
||||
checkTransactionSize(ltx, resolvedNetworkParameters.maxTransactionSize, serializedResolvedInputs, serializedResolvedReferences)
|
||||
|
||||
return ltx
|
||||
}
|
||||
@ -286,8 +294,6 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DEFAULT_MAX_TX_SIZE = 10485760
|
||||
|
||||
@CordaInternal
|
||||
@Deprecated("Do not use, this is internal API")
|
||||
fun createComponentGroups(inputs: List<StateRef>,
|
||||
@ -296,7 +302,7 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
||||
attachments: List<SecureHash>,
|
||||
notary: Party?,
|
||||
timeWindow: TimeWindow?): List<ComponentGroup> {
|
||||
return createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow, emptyList())
|
||||
return createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow, emptyList(), null)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -346,6 +352,9 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
||||
val emoji = Emoji.paperclip
|
||||
buf.appendln("${emoji}ATTACHMENT: $attachment")
|
||||
}
|
||||
if (networkParametersHash != null) {
|
||||
buf.appendln("PARAMETERS HASH: $networkParametersHash")
|
||||
}
|
||||
return buf.toString()
|
||||
}
|
||||
|
||||
|
@ -162,6 +162,7 @@ class PartialMerkleTreeTest {
|
||||
assertEquals(1, ftx.commands.size)
|
||||
assertNull(ftx.notary)
|
||||
assertNotNull(ftx.timeWindow)
|
||||
assertNull(ftx.networkParametersHash)
|
||||
ftx.verify()
|
||||
}
|
||||
|
||||
@ -186,6 +187,7 @@ class PartialMerkleTreeTest {
|
||||
assertTrue(ftxNothing.outputs.isEmpty())
|
||||
assertNull(ftxNothing.timeWindow)
|
||||
assertTrue(ftxNothing.availableComponentGroups.flatten().isEmpty())
|
||||
assertNull(ftxNothing.networkParametersHash)
|
||||
ftxNothing.verify() // We allow empty ftx transactions (eg from a timestamp authority that blindly signs).
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import net.corda.core.identity.Party
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.transactions.CoreTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.core.TestIdentity
|
||||
import org.junit.Rule
|
||||
@ -31,6 +32,7 @@ class TopologicalSortTest {
|
||||
override val outputs: List<TransactionState<ContractState>> = (1..numberOfOutputs).map {
|
||||
TransactionState(DummyState(), "", notary)
|
||||
}
|
||||
override val networkParametersHash: SecureHash? = testNetworkParameters().serialize().hash
|
||||
}
|
||||
|
||||
class DummyState : ContractState {
|
||||
|
@ -6,6 +6,7 @@ import net.corda.core.crypto.*
|
||||
import net.corda.core.internal.createComponentGroups
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.contracts.DummyContract
|
||||
import net.corda.testing.contracts.DummyState
|
||||
import net.corda.testing.core.*
|
||||
@ -38,6 +39,7 @@ class CompatibleTransactionTests {
|
||||
private val notary = DUMMY_NOTARY
|
||||
private val timeWindow = TimeWindow.fromOnly(Instant.now())
|
||||
private val privacySalt: PrivacySalt = PrivacySalt()
|
||||
private val paramsHash = SecureHash.randomSHA256()
|
||||
|
||||
private val inputGroup by lazy { ComponentGroup(INPUTS_GROUP.ordinal, inputs.map { it.serialize() }) }
|
||||
private val outputGroup by lazy { ComponentGroup(OUTPUTS_GROUP.ordinal, outputs.map { it.serialize() }) }
|
||||
@ -46,6 +48,7 @@ class CompatibleTransactionTests {
|
||||
private val notaryGroup by lazy { ComponentGroup(NOTARY_GROUP.ordinal, listOf(notary.serialize())) }
|
||||
private val timeWindowGroup by lazy { ComponentGroup(TIMEWINDOW_GROUP.ordinal, listOf(timeWindow.serialize())) }
|
||||
private val signersGroup by lazy { ComponentGroup(SIGNERS_GROUP.ordinal, commands.map { it.signers.serialize() }) }
|
||||
private val networkParamsGroup by lazy { ComponentGroup(PARAMETERS_GROUP.ordinal, listOf(paramsHash.serialize())) }
|
||||
|
||||
private val newUnknownComponentGroup = ComponentGroup(100, listOf(OpaqueBytes(secureRandomBytes(4)), OpaqueBytes(secureRandomBytes(8))))
|
||||
private val newUnknownComponentEmptyGroup = ComponentGroup(101, emptyList())
|
||||
@ -125,7 +128,7 @@ class CompatibleTransactionTests {
|
||||
|
||||
@Test
|
||||
fun `WireTransaction constructors and compatibility`() {
|
||||
val groups = createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow, emptyList())
|
||||
val groups = createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow, emptyList(), null)
|
||||
val wireTransactionOldConstructor = WireTransaction(groups, privacySalt)
|
||||
assertEquals(wireTransactionA, wireTransactionOldConstructor)
|
||||
|
||||
@ -211,6 +214,7 @@ class CompatibleTransactionTests {
|
||||
ftxAll.checkAllComponentsVisible(NOTARY_GROUP)
|
||||
ftxAll.checkAllComponentsVisible(TIMEWINDOW_GROUP)
|
||||
ftxAll.checkAllComponentsVisible(SIGNERS_GROUP)
|
||||
ftxAll.checkAllComponentsVisible(PARAMETERS_GROUP)
|
||||
|
||||
// Filter inputs only.
|
||||
fun filtering(elem: Any): Boolean {
|
||||
@ -261,6 +265,8 @@ class CompatibleTransactionTests {
|
||||
assertEquals(3, ftxCompatible.filteredComponentGroups.firstOrNull { it.groupIndex == INPUTS_GROUP.ordinal }!!.components.size)
|
||||
assertEquals(3, ftxCompatible.filteredComponentGroups.firstOrNull { it.groupIndex == INPUTS_GROUP.ordinal }!!.nonces.size)
|
||||
assertNotNull(ftxCompatible.filteredComponentGroups.firstOrNull { it.groupIndex == INPUTS_GROUP.ordinal }!!.partialMerkleTree)
|
||||
assertNull(wireTransactionCompatibleA.networkParametersHash)
|
||||
assertNull(ftxCompatible.networkParametersHash)
|
||||
|
||||
// Now, let's allow everything, including the new component type that we cannot process.
|
||||
val ftxCompatibleAll = wireTransactionCompatibleA.buildFilteredTransaction(Predicate { true }) // All filtered, including the unknown component.
|
||||
@ -547,5 +553,34 @@ class CompatibleTransactionTests {
|
||||
// Also, checkAllComponentsVisible() will not pass (top level Merkle tree cannot be verified against transaction's id).
|
||||
assertFailsWith<ComponentVisibilityException> { ftxAlterSignerB.checkCommandVisibility(DUMMY_KEY_1.public) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parameters hash visibility`() {
|
||||
fun paramsFilter(elem: Any): Boolean = elem is NetworkParametersHash && elem.hash == paramsHash
|
||||
fun attachmentFilter(elem: Any): Boolean = elem is SecureHash && elem == paramsHash
|
||||
val attachments = ComponentGroup(ATTACHMENTS_GROUP.ordinal, listOf(paramsHash.serialize())) // Same hash as network parameters
|
||||
val componentGroups = listOf(
|
||||
inputGroup,
|
||||
outputGroup,
|
||||
attachments,
|
||||
commandGroup,
|
||||
notaryGroup,
|
||||
timeWindowGroup,
|
||||
signersGroup,
|
||||
networkParamsGroup
|
||||
)
|
||||
val wtx = WireTransaction(componentGroups, privacySalt)
|
||||
val ftx1 = wtx.buildFilteredTransaction(Predicate(::paramsFilter)) // Filter only network parameters hash.
|
||||
ftx1.verify()
|
||||
assertEquals(wtx.id, ftx1.id)
|
||||
ftx1.checkAllComponentsVisible(PARAMETERS_GROUP)
|
||||
assertFailsWith<ComponentVisibilityException> { ftx1.checkAllComponentsVisible(ATTACHMENTS_GROUP) }
|
||||
// Filter only attachment.
|
||||
val ftx2 = wtx.buildFilteredTransaction(Predicate(::attachmentFilter))
|
||||
ftx2.verify()
|
||||
assertEquals(wtx.id, ftx2.id)
|
||||
ftx2.checkAllComponentsVisible(ATTACHMENTS_GROUP)
|
||||
assertFailsWith<ComponentVisibilityException> { ftx2.checkAllComponentsVisible(PARAMETERS_GROUP) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,8 @@ import net.corda.core.internal.PLATFORM_VERSION
|
||||
import net.corda.core.node.ServicesForResolution
|
||||
import net.corda.core.node.ZoneVersionTooLowException
|
||||
import net.corda.core.node.services.AttachmentStorage
|
||||
import net.corda.core.node.services.NetworkParametersStorage
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.contracts.DummyContract
|
||||
import net.corda.testing.contracts.DummyState
|
||||
@ -35,13 +37,17 @@ class TransactionBuilderTest {
|
||||
private val services = rigorousMock<ServicesForResolution>()
|
||||
private val contractAttachmentId = SecureHash.randomSHA256()
|
||||
private val attachments = rigorousMock<AttachmentStorage>()
|
||||
private val networkParametersStorage = rigorousMock<NetworkParametersStorage>()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
val cordappProvider = rigorousMock<CordappProvider>()
|
||||
val networkParameters = testNetworkParameters(minimumPlatformVersion = PLATFORM_VERSION)
|
||||
doReturn(networkParametersStorage).whenever(services).networkParametersStorage
|
||||
doReturn(networkParameters.serialize().hash).whenever(networkParametersStorage).currentHash
|
||||
doReturn(cordappProvider).whenever(services).cordappProvider
|
||||
doReturn(contractAttachmentId).whenever(cordappProvider).getContractAttachmentID(DummyContract.PROGRAM_ID)
|
||||
doReturn(testNetworkParameters(minimumPlatformVersion = PLATFORM_VERSION)).whenever(services).networkParameters
|
||||
doReturn(networkParameters).whenever(services).networkParameters
|
||||
|
||||
val attachmentStorage = rigorousMock<AttachmentStorage>()
|
||||
doReturn(attachmentStorage).whenever(services).attachments
|
||||
@ -67,6 +73,7 @@ class TransactionBuilderTest {
|
||||
val wtx = builder.toWireTransaction(services)
|
||||
assertThat(wtx.outputs).containsOnly(outputState)
|
||||
assertThat(wtx.commands).containsOnly(Command(DummyCommandData, notary.owningKey))
|
||||
assertThat(wtx.networkParametersHash).isEqualTo(networkParametersStorage.currentHash)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -176,7 +176,7 @@ class TransactionTests {
|
||||
notary,
|
||||
timeWindow,
|
||||
privacySalt,
|
||||
null,
|
||||
testNetworkParameters(),
|
||||
emptyList()
|
||||
)
|
||||
|
||||
|
@ -32,7 +32,7 @@ import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.internal.FINANCE_CORDAPP
|
||||
import net.corda.testing.node.internal.TestCordappDirectories
|
||||
@ -54,7 +54,7 @@ class FlowWorkerStartStopTest {
|
||||
@JvmField
|
||||
val serializationEnvironment = SerializationEnvironmentRule(true)
|
||||
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -31,7 +31,7 @@ import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.internal.FINANCE_CORDAPP
|
||||
import net.corda.testing.node.internal.TestCordappDirectories
|
||||
@ -53,7 +53,7 @@ class FlowWorkerTest {
|
||||
@JvmField
|
||||
val serializationEnvironment = SerializationEnvironmentRule(true)
|
||||
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
|
||||
companion object {
|
||||
private val networkParameters = NetworkParameters(
|
||||
|
@ -15,8 +15,12 @@ import net.corda.finance.flows.CashIssueFlow
|
||||
import net.corda.finance.flows.CashPaymentFlow
|
||||
import net.corda.node.services.Permissions.Companion.invokeRpc
|
||||
import net.corda.node.services.Permissions.Companion.startFlow
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.driver.*
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||
import net.corda.testing.core.singleIdentity
|
||||
import net.corda.testing.driver.NodeHandle
|
||||
import net.corda.testing.driver.OutOfProcess
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.IntegrationTestSchemas
|
||||
import net.corda.testing.internal.toDatabaseSchemaName
|
||||
@ -67,7 +71,7 @@ class InstrumentationTest : IntegrationTest() {
|
||||
}
|
||||
private fun setup(inMemoryDB: Boolean = true, testBlock: InternalDriverDSL.() -> Unit) {
|
||||
|
||||
val portAllocation = PortAllocation.Incremental(10000)
|
||||
val portAllocation = incrementalPortAllocation(10000)
|
||||
|
||||
internalDriver(
|
||||
cordappsForAllNodes = cordappsForPackages("net.corda.finance.contracts", "net.corda.finance.schemas"),
|
||||
|
@ -7,7 +7,9 @@ import net.corda.core.contracts.withoutIssuer
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.utilities.*
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.finance.POUNDS
|
||||
import net.corda.finance.contracts.asset.Cash
|
||||
import net.corda.finance.contracts.asset.OnLedgerAsset
|
||||
@ -20,7 +22,7 @@ import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.singleIdentity
|
||||
import net.corda.testing.driver.NodeHandle
|
||||
import net.corda.testing.driver.OutOfProcess
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.node.User
|
||||
import net.corda.testing.node.internal.InternalDriverDSL
|
||||
@ -101,7 +103,7 @@ class SystematicTerminationTest(private val terminationData: TerminationData) :
|
||||
|
||||
private fun setup(testBlock: InternalDriverDSL.() -> Unit) {
|
||||
|
||||
val portAllocation = PortAllocation.Incremental(10000)
|
||||
val portAllocation = incrementalPortAllocation(10000)
|
||||
|
||||
internalDriver(
|
||||
cordappsForAllNodes = cordappsForPackages("net.corda.finance.contracts", "net.corda.finance.schemas"),
|
||||
|
@ -20,7 +20,7 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.LogHelper
|
||||
import net.corda.testing.internal.TestingNamedCacheFactory
|
||||
import net.corda.testing.internal.configureDatabase
|
||||
@ -45,7 +45,7 @@ class RaftTransactionCommitLogTests {
|
||||
val testSerialization = SerializationEnvironmentRule(true)
|
||||
|
||||
private val databases: MutableList<CordaPersistence> = mutableListOf()
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
|
||||
private lateinit var cluster: List<Member>
|
||||
|
||||
|
@ -15,7 +15,7 @@ import java.nio.file.Path
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.util.Collections.singleton
|
||||
|
||||
// When scanning of the CorDapp Jar is performed without "corda-core.jar" being the in the classpath, there is no way to appreciate
|
||||
// When scanning of the CorDapp Jar is performed without "corda-core.jar" being in the classpath, there is no way to appreciate
|
||||
// relationships between those interfaces, therefore they have to be listed explicitly.
|
||||
val coreContractClasses = setOf(Contract::class, UpgradedContractWithLegacyConstraint::class, UpgradedContract::class)
|
||||
|
||||
|
@ -4,13 +4,12 @@ import com.nhaarman.mockito_kotlin.any
|
||||
import com.nhaarman.mockito_kotlin.doReturn
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.AbstractAttachment
|
||||
import net.corda.core.node.ServicesForResolution
|
||||
import net.corda.core.node.services.AttachmentStorage
|
||||
import net.corda.core.node.services.NetworkParametersStorage
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.transactions.LedgerTransaction
|
||||
@ -67,19 +66,18 @@ class AttachmentsClassLoaderStaticContractTests {
|
||||
}
|
||||
}
|
||||
|
||||
private val unsignedAttachment = object : AbstractAttachment({ byteArrayOf() }) {
|
||||
override val id: SecureHash get() = throw UnsupportedOperationException()
|
||||
private val networkParameters = testNetworkParameters()
|
||||
|
||||
private val networkParametersStorage get() = rigorousMock<NetworkParametersStorage>().also {
|
||||
doReturn(networkParameters.serialize().hash).whenever(it).currentHash
|
||||
}
|
||||
|
||||
private val attachments = rigorousMock<AttachmentStorage>().also {
|
||||
doReturn(unsignedAttachment).whenever(it).openAttachment(any())
|
||||
}
|
||||
|
||||
private val serviceHub = rigorousMock<ServicesForResolution>().also {
|
||||
private val serviceHub get() = rigorousMock<ServicesForResolution>().also {
|
||||
val cordappProviderImpl = CordappProviderImpl(cordappLoaderForPackages(listOf("net.corda.nodeapi.internal")), MockCordappConfigProvider(), MockAttachmentStorage())
|
||||
cordappProviderImpl.start(testNetworkParameters().whitelistedContractImplementations)
|
||||
doReturn(cordappProviderImpl).whenever(it).cordappProvider
|
||||
doReturn(testNetworkParameters()).whenever(it).networkParameters
|
||||
doReturn(networkParametersStorage).whenever(it).networkParametersStorage
|
||||
doReturn(networkParameters).whenever(it).networkParameters
|
||||
val attachmentStorage = rigorousMock<AttachmentStorage>()
|
||||
doReturn(attachmentStorage).whenever(it).attachments
|
||||
val attachment = rigorousMock<ContractAttachment>()
|
||||
|
@ -5,7 +5,6 @@ import io.netty.handler.ssl.ClientAuth
|
||||
import io.netty.handler.ssl.SslContextBuilder
|
||||
import io.netty.handler.ssl.SslProvider
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.crypto.Crypto.COMPOSITE_KEY
|
||||
import net.corda.core.crypto.Crypto.ECDSA_SECP256K1_SHA256
|
||||
import net.corda.core.crypto.Crypto.ECDSA_SECP256R1_SHA256
|
||||
@ -13,6 +12,8 @@ import net.corda.core.crypto.Crypto.EDDSA_ED25519_SHA512
|
||||
import net.corda.core.crypto.Crypto.RSA_SHA256
|
||||
import net.corda.core.crypto.Crypto.SPHINCS256_SHA256
|
||||
import net.corda.core.crypto.Crypto.generateKeyPair
|
||||
import net.corda.core.crypto.SignatureScheme
|
||||
import net.corda.core.crypto.newSecureRandom
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
@ -33,7 +34,7 @@ import net.corda.serialization.internal.amqp.amqpMagic
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.TestIdentity
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.NettyTestClient
|
||||
import net.corda.testing.internal.NettyTestHandler
|
||||
import net.corda.testing.internal.NettyTestServer
|
||||
@ -75,7 +76,7 @@ class X509UtilitiesTest {
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
)
|
||||
|
||||
val portAllocation = PortAllocation.Incremental(10000)
|
||||
val portAllocation = incrementalPortAllocation(10000)
|
||||
|
||||
// We ensure that all of the algorithms are both used (at least once) as first and second in the following [Pair]s.
|
||||
// We also add [DEFAULT_TLS_SIGNATURE_SCHEME] and [DEFAULT_IDENTITY_SIGNATURE_SCHEME] combinations for consistency.
|
||||
|
@ -8,8 +8,8 @@ import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.DUMMY_BANK_A_NAME
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.IntegrationTestSchemas
|
||||
import net.corda.testing.internal.toDatabaseSchemaName
|
||||
@ -29,7 +29,7 @@ class AddressBindingFailureTests: IntegrationTest() {
|
||||
@JvmField
|
||||
val databaseSchemas = IntegrationTestSchemas(ALICE_NAME.toDatabaseSchemaName(), BOB_NAME.toDatabaseSchemaName(), DUMMY_BANK_A_NAME.toDatabaseSchemaName())
|
||||
|
||||
private val portAllocation = PortAllocation.Incremental(20_000)
|
||||
private val portAllocation = incrementalPortAllocation(20_000)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -56,8 +56,8 @@ class AddressBindingFailureTests: IntegrationTest() {
|
||||
|
||||
assertThatThrownBy {
|
||||
driver(DriverParameters(startNodesInProcess = false,
|
||||
notarySpecs = listOf(NotarySpec(notaryName)),
|
||||
notaryCustomOverrides = mapOf("p2pAddress" to address.toString()),
|
||||
notarySpecs = listOf(NotarySpec(notaryName)),
|
||||
notaryCustomOverrides = mapOf("p2pAddress" to address.toString()),
|
||||
portAllocation = portAllocation)
|
||||
) {} }.isInstanceOfSatisfying(IllegalStateException::class.java) { error ->
|
||||
|
||||
|
@ -7,15 +7,18 @@ import net.corda.client.rpc.RPCException
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.node.services.config.*
|
||||
import net.corda.node.services.config.EnterpriseConfiguration
|
||||
import net.corda.node.services.config.MutualExclusionConfiguration
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.config.configureWithDevSSLCertificate
|
||||
import net.corda.node.services.messaging.ArtemisMessagingServer
|
||||
import net.corda.nodeapi.internal.config.MessagingServerConnectionConfiguration
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||
import net.corda.testing.core.MAX_MESSAGE_SIZE
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.IntegrationTestSchemas
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
@ -42,7 +45,7 @@ class ExternalBrokertests : IntegrationTest() {
|
||||
@JvmField
|
||||
val tempFolder = TemporaryFolder()
|
||||
|
||||
private val portAllocator = PortAllocation.Incremental(10000)
|
||||
private val portAllocator = incrementalPortAllocation(10000)
|
||||
|
||||
private abstract class AbstractNodeConfiguration : NodeConfiguration
|
||||
|
||||
|
@ -18,7 +18,7 @@ import net.corda.nodeapi.internal.bridging.BridgeManager
|
||||
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPConfiguration
|
||||
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPServer
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
import net.corda.testing.internal.stubs.CertificateStoreStubs
|
||||
import org.apache.activemq.artemis.api.core.Message.HDR_DUPLICATE_DETECTION_ID
|
||||
@ -81,7 +81,7 @@ class AMQPBridgeTest(private val useOpenSsl: Boolean, private val enableSNI: Boo
|
||||
|
||||
private val BOB = TestIdentity(BOB_NAME)
|
||||
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
private val artemisAddress = portAllocation.nextHostAndPort()
|
||||
private val amqpAddress = portAllocation.nextHostAndPort()
|
||||
|
||||
|
@ -24,7 +24,7 @@ import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.CHARLIE_NAME
|
||||
import net.corda.testing.core.MAX_MESSAGE_SIZE
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.DEV_INTERMEDIATE_CA
|
||||
import net.corda.testing.internal.DEV_ROOT_CA
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
@ -72,7 +72,7 @@ class CertificateRevocationListNodeTests {
|
||||
private val ROOT_CA = DEV_ROOT_CA
|
||||
private lateinit var INTERMEDIATE_CA: CertificateAndKeyPair
|
||||
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
private val serverPort = portAllocation.nextPort()
|
||||
|
||||
private lateinit var server: CrlServer
|
||||
|
@ -15,28 +15,30 @@ import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.CHARLIE_NAME
|
||||
import net.corda.testing.core.MAX_MESSAGE_SIZE
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
import net.corda.testing.internal.stubs.CertificateStoreStubs
|
||||
import org.junit.*
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import kotlin.test.assertEquals
|
||||
import org.eclipse.jetty.proxy.ProxyServlet
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler.SESSIONS
|
||||
import org.eclipse.jetty.proxy.ConnectHandler
|
||||
import org.eclipse.jetty.proxy.ProxyServlet
|
||||
import org.eclipse.jetty.server.Connector
|
||||
import org.eclipse.jetty.server.Server
|
||||
import org.eclipse.jetty.server.ServerConnector
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler.SESSIONS
|
||||
import org.eclipse.jetty.servlet.ServletHolder
|
||||
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class HttpTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val temporaryFolder = TemporaryFolder()
|
||||
|
||||
private val portAllocator = PortAllocation.Incremental(10000)
|
||||
private val portAllocator = incrementalPortAllocation(10000)
|
||||
private val httpProxyPort = portAllocator.nextPort()
|
||||
private val serverPort = portAllocator.nextPort()
|
||||
private val serverPort2 = portAllocator.nextPort()
|
||||
|
@ -19,7 +19,7 @@ import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.MAX_MESSAGE_SIZE
|
||||
import net.corda.testing.core.TestIdentity
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
import net.corda.testing.internal.stubs.CertificateStoreStubs
|
||||
import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration
|
||||
@ -48,7 +48,7 @@ class LoopbackBridgeTest(private val useOpenSsl: Boolean) {
|
||||
val temporaryFolder = TemporaryFolder()
|
||||
private val log = loggerFor<LoopbackBridgeTest>()
|
||||
private val BOB = TestIdentity(BOB_NAME)
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
private val artemisAddress = portAllocation.nextHostAndPort()
|
||||
private val amqpAddress = portAllocation.nextHostAndPort()
|
||||
|
||||
|
@ -28,7 +28,7 @@ import net.corda.nodeapi.internal.protonwrapper.netty.init
|
||||
import net.corda.nodeapi.internal.registerDevP2pCertificates
|
||||
import net.corda.nodeapi.internal.registerDevSigningCertificates
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
import net.corda.testing.internal.stubs.CertificateStoreStubs
|
||||
@ -68,7 +68,7 @@ class ProtonWrapperTests(val sslSetup: SslSetup) {
|
||||
@JvmField
|
||||
val temporaryFolder = TemporaryFolder()
|
||||
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
private val serverPort = portAllocation.nextPort()
|
||||
private val serverPort2 = portAllocation.nextPort()
|
||||
private val artemisPort = portAllocation.nextPort()
|
||||
|
@ -23,8 +23,11 @@ import net.corda.nodeapi.internal.ArtemisMessagingClient
|
||||
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.P2P_PREFIX
|
||||
import net.corda.nodeapi.internal.protonwrapper.messages.MessageStatus
|
||||
import net.corda.nodeapi.internal.protonwrapper.netty.*
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.CHARLIE_NAME
|
||||
import net.corda.testing.core.MAX_MESSAGE_SIZE
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
import net.corda.testing.internal.stubs.CertificateStoreStubs
|
||||
import org.apache.activemq.artemis.api.core.RoutingType
|
||||
@ -41,7 +44,7 @@ class SocksTests {
|
||||
@JvmField
|
||||
val temporaryFolder = TemporaryFolder()
|
||||
|
||||
private val portAllocator = PortAllocation.Incremental(10000)
|
||||
private val portAllocator = incrementalPortAllocation(10000)
|
||||
private val socksPort = portAllocator.nextPort()
|
||||
private val serverPort = portAllocator.nextPort()
|
||||
private val serverPort2 = portAllocator.nextPort()
|
||||
|
@ -23,8 +23,8 @@ import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||
import net.corda.testing.core.singleIdentity
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.IntegrationTestSchemas
|
||||
import net.corda.testing.internal.toDatabaseSchemaName
|
||||
@ -43,7 +43,7 @@ class FlowsDrainingModeContentionTest : IntegrationTest() {
|
||||
@JvmField
|
||||
val databaseSchemas = IntegrationTestSchemas(ALICE_NAME.toDatabaseSchemaName(), BOB_NAME.toDatabaseSchemaName(), DUMMY_NOTARY_NAME.toDatabaseSchemaName())
|
||||
}
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
private val user = User("mark", "dadada", setOf(all()))
|
||||
private val users = listOf(user)
|
||||
|
||||
|
@ -16,8 +16,8 @@ import net.corda.node.services.Permissions
|
||||
import net.corda.nodeapi.internal.hasCancelledDrainingShutdown
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.IntegrationTestSchemas
|
||||
import net.corda.testing.internal.toDatabaseSchemaName
|
||||
@ -45,7 +45,7 @@ class P2PFlowsDrainingModeTest : IntegrationTest() {
|
||||
private val logger = contextLogger()
|
||||
}
|
||||
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
private val user = User("mark", "dadada", setOf(Permissions.all()))
|
||||
private val users = listOf(user)
|
||||
|
||||
|
@ -9,8 +9,8 @@ import net.corda.node.services.Permissions
|
||||
import net.corda.nodeapi.exceptions.RejectedCommandException
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.IntegrationTestSchemas
|
||||
import net.corda.testing.internal.toDatabaseSchemaName
|
||||
@ -28,7 +28,7 @@ class RpcFlowsDrainingModeTest : IntegrationTest() {
|
||||
DUMMY_BANK_A_NAME.toDatabaseSchemaName(), DUMMY_NOTARY_NAME.toDatabaseSchemaName())
|
||||
}
|
||||
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
private val user = User("mark", "dadada", setOf(Permissions.all()))
|
||||
private val users = listOf(user)
|
||||
|
||||
|
@ -9,8 +9,8 @@ import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.node.services.Permissions
|
||||
import net.corda.nodeapi.internal.persistence.CouldNotCreateDataSourceException
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.node.User
|
||||
import org.junit.Assume.assumeTrue
|
||||
@ -23,7 +23,7 @@ import kotlin.test.assertTrue
|
||||
|
||||
class H2SecurityTests {
|
||||
companion object {
|
||||
private val port = PortAllocation.Incremental(21_000)
|
||||
private val port = incrementalPortAllocation(21_000)
|
||||
private fun getFreePort() = port.nextPort()
|
||||
private const val h2AddressKey = "h2Settings.address"
|
||||
private const val dbPasswordKey = "dataSourceProperties.dataSource.password"
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.node.services
|
||||
|
||||
import com.nhaarman.mockito_kotlin.any
|
||||
import com.nhaarman.mockito_kotlin.doReturn
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import net.corda.core.CordaRuntimeException
|
||||
@ -13,7 +14,9 @@ import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.node.ServicesForResolution
|
||||
import net.corda.core.node.services.AttachmentStorage
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.node.services.NetworkParametersStorage
|
||||
import net.corda.core.serialization.SerializationFactory
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.node.VersionInfo
|
||||
@ -69,6 +72,7 @@ class AttachmentLoadingTests : IntegrationTest() {
|
||||
}
|
||||
|
||||
private val services = object : ServicesForResolution {
|
||||
private val testNetworkParameters = testNetworkParameters()
|
||||
override fun loadState(stateRef: StateRef): TransactionState<*> = throw NotImplementedError()
|
||||
override fun loadStates(stateRefs: Set<StateRef>): Set<StateAndRef<ContractState>> = throw NotImplementedError()
|
||||
override val identityService = rigorousMock<IdentityService>().apply {
|
||||
@ -76,7 +80,11 @@ class AttachmentLoadingTests : IntegrationTest() {
|
||||
}
|
||||
override val attachments: AttachmentStorage get() = this@AttachmentLoadingTests.attachments
|
||||
override val cordappProvider: CordappProvider get() = this@AttachmentLoadingTests.provider
|
||||
override val networkParameters: NetworkParameters = testNetworkParameters()
|
||||
override val networkParameters: NetworkParameters = testNetworkParameters
|
||||
override val networkParametersStorage: NetworkParametersStorage get() = rigorousMock<NetworkParametersStorage>().apply {
|
||||
doReturn(testNetworkParameters.serialize().hash).whenever(this).currentHash
|
||||
doReturn(testNetworkParameters).whenever(this).lookup(any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -10,9 +10,9 @@ import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.cryptoservice.CryptoServiceException
|
||||
import net.corda.testing.core.DUMMY_BANK_A_NAME
|
||||
import net.corda.testing.core.getTestPartyAndCertificate
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import org.junit.Test
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import org.junit.ClassRule
|
||||
import org.junit.Test
|
||||
import java.io.IOException
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
@ -26,7 +26,7 @@ class UtimacoCryptoServiceIntegrationTest {
|
||||
companion object {
|
||||
@ClassRule
|
||||
@JvmField
|
||||
val hsmSimulator: HsmSimulator = HsmSimulator(PortAllocation.Incremental(12300))
|
||||
val hsmSimulator: HsmSimulator = HsmSimulator(incrementalPortAllocation(12300))
|
||||
}
|
||||
|
||||
private val config = testConfig(hsmSimulator.address.port)
|
||||
|
@ -14,7 +14,7 @@ import net.corda.node.utilities.registration.TestDoorman
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.core.singleIdentity
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.DEV_ROOT_CA
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.IntegrationTestSchemas
|
||||
@ -42,7 +42,7 @@ class UtimacoNodeRegistrationTest : IntegrationTest() {
|
||||
@JvmField
|
||||
val testSerialization = SerializationEnvironmentRule(true)
|
||||
|
||||
private val portAllocation = PortAllocation.Incremental(13400)
|
||||
private val portAllocation = incrementalPortAllocation(13400)
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
|
@ -17,7 +17,7 @@ import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.MAX_MESSAGE_SIZE
|
||||
import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.LogHelper
|
||||
import net.corda.testing.internal.TestingNamedCacheFactory
|
||||
import net.corda.testing.internal.configureDatabase
|
||||
@ -57,7 +57,7 @@ class ArtemisMessagingTest {
|
||||
@JvmField
|
||||
val temporaryFolder = TemporaryFolder()
|
||||
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
private val serverPort = portAllocation.nextPort()
|
||||
private val identity = generateKeyPair()
|
||||
|
||||
|
@ -16,8 +16,8 @@ import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.driver.NodeHandle
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.NodeHandleInternal
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.IntegrationTestSchemas
|
||||
import net.corda.testing.internal.toDatabaseSchemaName
|
||||
@ -41,7 +41,7 @@ class NetworkMapTest(var initFunc: (URL, NetworkMapServer) -> CompatibilityZoneP
|
||||
val testSerialization = SerializationEnvironmentRule(true)
|
||||
|
||||
private val cacheTimeout = 1.seconds
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
|
||||
private lateinit var networkMapServer: NetworkMapServer
|
||||
private lateinit var compatibilityZone: CompatibilityZoneParams
|
||||
@ -60,23 +60,23 @@ class NetworkMapTest(var initFunc: (URL, NetworkMapServer) -> CompatibilityZoneP
|
||||
{
|
||||
addr: URL,
|
||||
nms: NetworkMapServer -> SharedCompatibilityZoneParams(
|
||||
addr,
|
||||
pnm = null,
|
||||
publishNotaries = {
|
||||
nms.networkParameters = testNetworkParameters(it, modifiedTime = Instant.ofEpochMilli(random63BitValue()), epoch = 2)
|
||||
}
|
||||
)
|
||||
addr,
|
||||
pnm = null,
|
||||
publishNotaries = {
|
||||
nms.networkParameters = testNetworkParameters(it, modifiedTime = Instant.ofEpochMilli(random63BitValue()), epoch = 2)
|
||||
}
|
||||
)
|
||||
},
|
||||
{
|
||||
addr: URL,
|
||||
nms: NetworkMapServer -> SplitCompatibilityZoneParams (
|
||||
doormanURL = URL("http://I/Don't/Exist"),
|
||||
networkMapURL = addr,
|
||||
pnm = null,
|
||||
publishNotaries = {
|
||||
nms.networkParameters = testNetworkParameters(it, modifiedTime = Instant.ofEpochMilli(random63BitValue()), epoch = 2)
|
||||
}
|
||||
)
|
||||
doormanURL = URL("http://I/Don't/Exist"),
|
||||
networkMapURL = addr,
|
||||
pnm = null,
|
||||
publishNotaries = {
|
||||
nms.networkParameters = testNetworkParameters(it, modifiedTime = Instant.ofEpochMilli(random63BitValue()), epoch = 2)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
)
|
||||
|
@ -23,6 +23,7 @@ import net.corda.nodeapi.internal.config.MutualSslConfiguration
|
||||
import net.corda.nodeapi.internal.config.User
|
||||
import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.TestingNamedCacheFactory
|
||||
import net.corda.testing.internal.fromUserList
|
||||
import net.corda.testing.internal.p2pSslOptions
|
||||
@ -37,7 +38,7 @@ import java.nio.file.Path
|
||||
import javax.security.auth.x500.X500Principal
|
||||
|
||||
class ArtemisRpcTests {
|
||||
private val ports: PortAllocation = PortAllocation.Incremental(10000)
|
||||
private val ports: PortAllocation = incrementalPortAllocation(10000)
|
||||
|
||||
private val user = User("mark", "dadada", setOf(all()))
|
||||
private val users = listOf(user)
|
||||
|
@ -17,7 +17,7 @@ import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.core.singleIdentity
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.DEV_ROOT_CA
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.IntegrationTestSchemas
|
||||
@ -60,7 +60,7 @@ class NodeRegistrationTest : IntegrationTest() {
|
||||
@JvmField
|
||||
val testSerialization = SerializationEnvironmentRule(true)
|
||||
|
||||
private val portAllocation = PortAllocation.Incremental(13000)
|
||||
private val portAllocation = incrementalPortAllocation(13000)
|
||||
private val registrationHandler = RegistrationHandler(DEV_ROOT_CA)
|
||||
private lateinit var server: NetworkMapServer
|
||||
private lateinit var serverHostAndPort: NetworkHostAndPort
|
||||
|
@ -14,8 +14,8 @@ import net.corda.finance.flows.CashIssueAndPaymentFlow
|
||||
import net.corda.node.services.Permissions.Companion.all
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.IntegrationTestSchemas
|
||||
import net.corda.testing.internal.toDatabaseSchemaName
|
||||
@ -32,7 +32,7 @@ class AdditionP2PAddressModeTest : IntegrationTest() {
|
||||
DUMMY_NOTARY_NAME.toDatabaseSchemaName())
|
||||
}
|
||||
|
||||
private val portAllocation = PortAllocation.Incremental(27182)
|
||||
private val portAllocation = incrementalPortAllocation(27182)
|
||||
@Test
|
||||
fun `runs nodes with one configured to use additionalP2PAddresses`() {
|
||||
val testUser = User("test", "test", setOf(all()))
|
||||
|
@ -165,16 +165,18 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
val networkMapClient: NetworkMapClient? = configuration.networkServices?.let { NetworkMapClient(it.networkMapURL, versionInfo) }
|
||||
val attachments = NodeAttachmentService(metricRegistry, cacheFactory, database).tokenize()
|
||||
val cryptoService = configuration.makeCryptoService()
|
||||
val networkParametersStorage = DBNetworkParametersStorage(cacheFactory, database, networkMapClient).tokenize()
|
||||
val cordappProvider = CordappProviderImpl(cordappLoader, CordappConfigFileProvider(configuration.cordappDirectories), attachments).tokenize()
|
||||
@Suppress("LeakingThis")
|
||||
val keyManagementService = makeKeyManagementService(identityService).tokenize()
|
||||
val servicesForResolution = ServicesForResolutionImpl(identityService, attachments, cordappProvider, transactionStorage).also {
|
||||
val servicesForResolution = ServicesForResolutionImpl(identityService, attachments, cordappProvider, networkParametersStorage, transactionStorage).also {
|
||||
attachments.servicesForResolution = it
|
||||
}
|
||||
@Suppress("LeakingThis")
|
||||
val vaultService = makeVaultService(keyManagementService, servicesForResolution, database).tokenize()
|
||||
val nodeProperties = NodePropertiesPersistentStore(StubbedNodeUniqueIdProvider::value, database, cacheFactory)
|
||||
val flowLogicRefFactory = FlowLogicRefFactoryImpl(cordappLoader.appClassLoader)
|
||||
// TODO Cancelling parameters updates - if we do that, how we ensure that no one uses cancelled parameters in the transactions?
|
||||
val networkMapUpdater = NetworkMapUpdater(
|
||||
networkMapCache,
|
||||
NodeInfoWatcher(
|
||||
@ -185,7 +187,8 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
),
|
||||
networkMapClient,
|
||||
configuration.baseDirectory,
|
||||
configuration.extraNetworkMapKeys
|
||||
configuration.extraNetworkMapKeys,
|
||||
networkParametersStorage
|
||||
).closeOnStop()
|
||||
@Suppress("LeakingThis")
|
||||
val transactionVerifierService = InMemoryTransactionVerifierService(transactionVerifierWorkerCount).tokenize()
|
||||
@ -323,7 +326,6 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
check(netParams.minimumPlatformVersion <= versionInfo.platformVersion) {
|
||||
"Node's platform version is lower than network's required minimumPlatformVersion"
|
||||
}
|
||||
servicesForResolution.start(netParams)
|
||||
networkMapCache.start(netParams.notaries)
|
||||
|
||||
startDatabase()
|
||||
@ -366,6 +368,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
|
||||
// Do all of this in a database transaction so anything that might need a connection has one.
|
||||
return database.transaction {
|
||||
networkParametersStorage.start(signedNetParams, trustRoot)
|
||||
identityService.loadIdentities(nodeInfo.legalIdentitiesAndCerts)
|
||||
attachments.start()
|
||||
cordappProvider.start(netParams.whitelistedContractImplementations)
|
||||
@ -1019,6 +1022,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
override val configuration: NodeConfiguration get() = this@AbstractNode.configuration
|
||||
override val networkMapUpdater: NetworkMapUpdater get() = this@AbstractNode.networkMapUpdater
|
||||
override val cacheFactory: NamedCacheFactory get() = this@AbstractNode.cacheFactory
|
||||
override val networkParametersStorage: NetworkParametersStorage get() = this@AbstractNode.networkParametersStorage
|
||||
|
||||
private lateinit var _myInfo: NodeInfo
|
||||
override val myInfo: NodeInfo get() = _myInfo
|
||||
|
@ -0,0 +1,159 @@
|
||||
package net.corda.node.internal
|
||||
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.internal.DigitalSignatureWithCert
|
||||
import net.corda.core.internal.NamedCacheFactory
|
||||
import net.corda.core.internal.SignedDataWithCert
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.node.services.NetworkParametersStorage
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.utilities.MAX_HASH_HEX_SIZE
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.core.utilities.trace
|
||||
import net.corda.node.services.network.NetworkMapClient
|
||||
import net.corda.node.utilities.AppendOnlyPersistentMap
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
||||
import net.corda.nodeapi.internal.network.verifiedNetworkParametersCert
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
|
||||
import org.apache.commons.lang.ArrayUtils
|
||||
import java.security.cert.X509Certificate
|
||||
import javax.persistence.*
|
||||
|
||||
interface NetworkParametersStorageInternal : NetworkParametersStorage {
|
||||
/**
|
||||
* Return parameters epoch for the given parameters hash. Null if there are no parameters for this hash in the storage and we are unable to
|
||||
* get them from network map.
|
||||
*/
|
||||
fun getEpochFromHash(hash: SecureHash): Int?
|
||||
|
||||
/**
|
||||
* Save signed network parameters data. Internally network parameters bytes should be stored with the signature.
|
||||
* It's because of ability of older nodes to function in network where parameters were extended with new fields.
|
||||
* Hash should always be calculated over the serialized bytes.
|
||||
*/
|
||||
fun saveParameters(signedNetworkParameters: SignedDataWithCert<NetworkParameters>)
|
||||
}
|
||||
|
||||
class DBNetworkParametersStorage(
|
||||
cacheFactory: NamedCacheFactory,
|
||||
private val database: CordaPersistence,
|
||||
// TODO It's very inefficient solution (at least at the beginning when node joins without historical data)
|
||||
// We could have historic parameters endpoint or always add parameters as an attachment to the transaction.
|
||||
private val networkMapClient: NetworkMapClient?
|
||||
) : NetworkParametersStorageInternal, SingletonSerializeAsToken() {
|
||||
private lateinit var trustRoot: X509Certificate
|
||||
|
||||
companion object {
|
||||
private val log = contextLogger()
|
||||
|
||||
fun createParametersMap(cacheFactory: NamedCacheFactory): AppendOnlyPersistentMap<SecureHash, SignedDataWithCert<NetworkParameters>, PersistentNetworkParameters, String> {
|
||||
return AppendOnlyPersistentMap(
|
||||
cacheFactory = cacheFactory,
|
||||
name = "NodeParametersStorage_networkParametersByHash",
|
||||
toPersistentEntityKey = { it.toString() },
|
||||
fromPersistentEntity = {
|
||||
Pair(
|
||||
SecureHash.parse(it.hash),
|
||||
it.signedNetworkParameters
|
||||
)
|
||||
},
|
||||
toPersistentEntity = { key: SecureHash, value: SignedDataWithCert<NetworkParameters> ->
|
||||
PersistentNetworkParameters(key.toString(), value.verified().epoch, value.raw.bytes, value.sig.bytes, value.sig.by.encoded,
|
||||
X509Utilities.buildCertPath(value.sig.parentCertsChain).encoded)
|
||||
},
|
||||
persistentEntityClass = PersistentNetworkParameters::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun start(currentSignedParameters: SignedDataWithCert<NetworkParameters>, trustRoot: X509Certificate) {
|
||||
this.trustRoot = trustRoot
|
||||
saveParameters(currentSignedParameters)
|
||||
_currentHash = currentSignedParameters.raw.hash
|
||||
}
|
||||
|
||||
private lateinit var _currentHash: SecureHash
|
||||
override val currentHash: SecureHash get() = _currentHash
|
||||
// TODO Have network map serve special "starting" parameters as parameters for resolution for older transactions?
|
||||
override val defaultHash: SecureHash get() = currentHash
|
||||
|
||||
private val hashToParameters = createParametersMap(cacheFactory)
|
||||
|
||||
override fun lookup(hash: SecureHash): NetworkParameters? {
|
||||
return database.transaction { hashToParameters[hash]?.raw?.deserialize() } ?: tryDownloadUnknownParameters(hash)
|
||||
}
|
||||
|
||||
override fun getEpochFromHash(hash: SecureHash): Int? = lookup(hash)?.epoch
|
||||
|
||||
override fun saveParameters(signedNetworkParameters: SignedNetworkParameters) {
|
||||
log.trace { "Saving new network parameters to network parameters storage." }
|
||||
val networkParameters = signedNetworkParameters.verified()
|
||||
val hash = signedNetworkParameters.raw.hash
|
||||
log.trace { "Parameters to save $networkParameters with hash $hash" }
|
||||
database.transaction {
|
||||
hashToParameters.addWithDuplicatesAllowed(hash, signedNetworkParameters)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO For the future we could get them also as signed (by network operator) attachments on transactions.
|
||||
private fun tryDownloadUnknownParameters(parametersHash: SecureHash): NetworkParameters? {
|
||||
return if (networkMapClient != null) {
|
||||
try {
|
||||
val signedParams = networkMapClient.getNetworkParameters(parametersHash)
|
||||
val networkParameters = signedParams.verifiedNetworkParametersCert(trustRoot)
|
||||
saveParameters(signedParams)
|
||||
networkParameters
|
||||
} catch (e: Exception) {
|
||||
log.warn("Failed to download historical network parameters with hash $parametersHash", e)
|
||||
null
|
||||
}
|
||||
} else {
|
||||
log.warn("Tried to download historical network parameters with hash $parametersHash, but network map url isn't configured")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "${NODE_DATABASE_PREFIX}network_parameters")
|
||||
class PersistentNetworkParameters(
|
||||
@Id
|
||||
@Column(name = "hash", length = MAX_HASH_HEX_SIZE, nullable = false)
|
||||
val hash: String = "",
|
||||
|
||||
@Column(name = "epoch", nullable = false)
|
||||
val epoch: Int = 0,
|
||||
|
||||
// Stored as serialized bytes because network parameters structure evolves over time.
|
||||
@Lob
|
||||
@Column(name = "parameters_bytes", nullable = false)
|
||||
val networkParametersBytes: ByteArray = ArrayUtils.EMPTY_BYTE_ARRAY,
|
||||
|
||||
@Lob
|
||||
@Column(name = "signature_bytes", nullable = false)
|
||||
private val signature: ByteArray = ArrayUtils.EMPTY_BYTE_ARRAY,
|
||||
|
||||
// First certificate in the certificate chain.
|
||||
@Lob
|
||||
@Column(name = "cert", nullable = false)
|
||||
private val certificate: ByteArray = ArrayUtils.EMPTY_BYTE_ARRAY,
|
||||
|
||||
// Parent certificate path (the first one is stored separately), so node is agnostic to certificate hierarchy.
|
||||
@Lob
|
||||
@Column(name = "parent_cert_path", nullable = false)
|
||||
private val certPath: ByteArray = ArrayUtils.EMPTY_BYTE_ARRAY
|
||||
) {
|
||||
val networkParameters: NetworkParameters get() = networkParametersBytes.deserialize()
|
||||
val signedNetworkParameters: SignedDataWithCert<NetworkParameters>
|
||||
get() {
|
||||
val certChain = X509CertificateFactory().delegate.generateCertPath(certPath.inputStream())
|
||||
.certificates.map { it as X509Certificate }
|
||||
val signWithCert = DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), certChain, signature)
|
||||
return SignedDataWithCert(SerializedBytes(networkParametersBytes), signWithCert)
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,10 @@ import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.node.services.network.NetworkMapClient
|
||||
import net.corda.nodeapi.internal.network.*
|
||||
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME
|
||||
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_UPDATE_FILE_NAME
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
||||
import net.corda.nodeapi.internal.network.verifiedNetworkParametersCert
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.security.cert.X509Certificate
|
||||
@ -23,7 +26,7 @@ class NetworkParametersReader(private val trustRoot: X509Certificate,
|
||||
class NetworkMapNotConfigured : Error("Node hasn't been configured to connect to a network map from which to get the network parameters.")
|
||||
class OldParamsAndUpdate : Error(
|
||||
"Both network parameters and network parameters update files don't match" +
|
||||
"parameters advertised by network map. Please update node to use correct network parameters file."
|
||||
"parameters advertised by network map. Please update node to use correct network parameters file."
|
||||
)
|
||||
class OldParams(previousParametersHash: SecureHash, advertisedParametersHash: SecureHash) : Error(
|
||||
"Node uses parameters with hash: $previousParametersHash but network map is advertising: " +
|
||||
|
@ -5,6 +5,7 @@ import net.corda.core.cordapp.CordappProvider
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.node.ServicesForResolution
|
||||
import net.corda.core.node.services.AttachmentStorage
|
||||
import net.corda.core.node.services.NetworkParametersStorage
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.node.services.TransactionStorage
|
||||
|
||||
@ -12,14 +13,11 @@ data class ServicesForResolutionImpl(
|
||||
override val identityService: IdentityService,
|
||||
override val attachments: AttachmentStorage,
|
||||
override val cordappProvider: CordappProvider,
|
||||
override val networkParametersStorage: NetworkParametersStorage,
|
||||
private val validatedTransactions: TransactionStorage
|
||||
) : ServicesForResolution {
|
||||
private lateinit var _networkParameters: NetworkParameters
|
||||
override val networkParameters: NetworkParameters get() = _networkParameters
|
||||
|
||||
fun start(networkParameters: NetworkParameters) {
|
||||
_networkParameters = networkParameters
|
||||
}
|
||||
override val networkParameters: NetworkParameters get() = networkParametersStorage.lookup(networkParametersStorage.currentHash) ?:
|
||||
throw IllegalArgumentException("No current parameters in network parameters storage")
|
||||
|
||||
@Throws(TransactionResolutionException::class)
|
||||
override fun loadState(stateRef: StateRef): TransactionState<*> {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.corda.node.serialization.amqp
|
||||
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.internal.toSynchronised
|
||||
import net.corda.core.serialization.ClassWhitelist
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.core.serialization.SerializationCustomSerializer
|
||||
@ -19,10 +20,10 @@ class AMQPServerSerializationScheme(
|
||||
cordappCustomSerializers: Set<SerializationCustomSerializer<*, *>>,
|
||||
serializerFactoriesForContexts: MutableMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>
|
||||
) : AbstractAMQPSerializationScheme(cordappCustomSerializers, serializerFactoriesForContexts) {
|
||||
constructor(cordapps: List<Cordapp>) : this(cordapps.customSerializers, AccessOrderLinkedHashMap { 128 })
|
||||
constructor(cordapps: List<Cordapp>) : this(cordapps.customSerializers, AccessOrderLinkedHashMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>(128).toSynchronised())
|
||||
constructor(cordapps: List<Cordapp>, serializerFactoriesForContexts: MutableMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>) : this(cordapps.customSerializers, serializerFactoriesForContexts)
|
||||
|
||||
constructor() : this(emptySet(), AccessOrderLinkedHashMap { 128 })
|
||||
constructor() : this(emptySet(), AccessOrderLinkedHashMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>(128).toSynchronised() )
|
||||
|
||||
override fun rpcClientSerializerFactory(context: SerializationContext): SerializerFactory {
|
||||
throw UnsupportedOperationException()
|
||||
|
@ -12,6 +12,7 @@ import net.corda.core.node.services.KeyManagementService
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.core.utilities.minutes
|
||||
import net.corda.node.internal.NetworkParametersStorageInternal
|
||||
import net.corda.node.services.api.NetworkMapCacheInternal
|
||||
import net.corda.node.services.config.NetworkParameterAcceptanceSettings
|
||||
import net.corda.node.utilities.NamedThreadFactory
|
||||
@ -33,7 +34,8 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal,
|
||||
private val nodeInfoWatcher: NodeInfoWatcher,
|
||||
private val networkMapClient: NetworkMapClient?,
|
||||
private val baseDirectory: Path,
|
||||
private val extraNetworkMapKeys: List<UUID>
|
||||
private val extraNetworkMapKeys: List<UUID>,
|
||||
private val networkParametersStorage: NetworkParametersStorageInternal
|
||||
) : AutoCloseable {
|
||||
companion object {
|
||||
private val logger = contextLogger()
|
||||
@ -209,6 +211,7 @@ The node will shutdown now.""")
|
||||
}
|
||||
val newSignedNetParams = networkMapClient.getNetworkParameters(update.newParametersHash)
|
||||
val newNetParams = newSignedNetParams.verifiedNetworkParametersCert(trustRoot)
|
||||
networkParametersStorage.saveParameters(newSignedNetParams)
|
||||
logger.info("Downloaded new network parameters: $newNetParams from the update: $update")
|
||||
newNetworkParameters = Pair(update, newSignedNetParams)
|
||||
val updateInfo = ParametersUpdateInfo(
|
||||
|
@ -7,6 +7,7 @@ import net.corda.core.contracts.LinearState
|
||||
import net.corda.core.schemas.*
|
||||
import net.corda.core.schemas.MappedSchemaValidator.crossReferencesToOtherMappedSchema
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.node.internal.DBNetworkParametersStorage
|
||||
import net.corda.node.internal.schemas.NodeInfoSchemaV1
|
||||
import net.corda.node.services.api.SchemaService
|
||||
import net.corda.node.services.api.SchemaService.SchemaOptions
|
||||
@ -45,6 +46,7 @@ class NodeSchemaService(private val extraSchemas: Set<MappedSchema> = emptySet()
|
||||
PersistentIdentityService.PersistentIdentityNames::class.java,
|
||||
ContractUpgradeServiceImpl.DBContractUpgrade::class.java,
|
||||
RunOnceService.MutualExclusion::class.java,
|
||||
DBNetworkParametersStorage.PersistentNetworkParameters::class.java,
|
||||
PersistentKeyManagementService.PublicKeyHashToExternalId::class.java
|
||||
)) {
|
||||
override val migrationResource = "node-core.changelog-master"
|
||||
@ -53,9 +55,9 @@ class NodeSchemaService(private val extraSchemas: Set<MappedSchema> = emptySet()
|
||||
// Required schemas are those used by internal Corda services
|
||||
private val requiredSchemas: Map<MappedSchema, SchemaService.SchemaOptions> =
|
||||
mapOf(Pair(CommonSchemaV1, SchemaOptions()),
|
||||
Pair(VaultSchemaV1, SchemaOptions()),
|
||||
Pair(NodeInfoSchemaV1, SchemaOptions()),
|
||||
Pair(NodeCoreV1, SchemaOptions()))
|
||||
Pair(VaultSchemaV1, SchemaOptions()),
|
||||
Pair(NodeInfoSchemaV1, SchemaOptions()),
|
||||
Pair(NodeCoreV1, SchemaOptions()))
|
||||
|
||||
fun internalSchemas() = requiredSchemas.keys + extraSchemas.filter { schema -> // when mapped schemas from the finance module are present, they are considered as internal ones
|
||||
schema::class.qualifiedName == "net.corda.finance.schemas.CashSchemaV1" ||
|
||||
|
@ -28,11 +28,12 @@ class NonValidatingNotaryFlow(otherSideSession: FlowSession, service: SinglePart
|
||||
checkAllComponentsVisible(ComponentGroupEnum.INPUTS_GROUP)
|
||||
checkAllComponentsVisible(ComponentGroupEnum.TIMEWINDOW_GROUP)
|
||||
checkAllComponentsVisible(ComponentGroupEnum.REFERENCES_GROUP)
|
||||
if(serviceHub.networkParameters.minimumPlatformVersion >= 4) checkAllComponentsVisible(ComponentGroupEnum.PARAMETERS_GROUP)
|
||||
}
|
||||
TransactionParts(tx.id, tx.inputs, tx.timeWindow, tx.notary, tx.references)
|
||||
TransactionParts(tx.id, tx.inputs, tx.timeWindow, tx.notary, tx.references, networkParametersHash = tx.networkParametersHash)
|
||||
}
|
||||
is ContractUpgradeFilteredTransaction,
|
||||
is NotaryChangeWireTransaction -> TransactionParts(tx.id, tx.inputs, null, tx.notary)
|
||||
is NotaryChangeWireTransaction -> TransactionParts(tx.id, tx.inputs, null, tx.notary, networkParametersHash = tx.networkParametersHash)
|
||||
else -> {
|
||||
throw IllegalArgumentException("Received unexpected transaction type: ${tx::class.java.simpleName}," +
|
||||
"expected either ${FilteredTransaction::class.java.simpleName} or ${NotaryChangeWireTransaction::class.java.simpleName}")
|
||||
|
@ -24,7 +24,7 @@ open class ValidatingNotaryFlow(otherSideSession: FlowSession, service: SinglePa
|
||||
override fun extractParts(requestPayload: NotarisationPayload): TransactionParts {
|
||||
val stx = requestPayload.signedTransaction
|
||||
val timeWindow: TimeWindow? = if (stx.coreTransaction is WireTransaction) stx.tx.timeWindow else null
|
||||
return TransactionParts(stx.id, stx.inputs, timeWindow, stx.notary, stx.references)
|
||||
return TransactionParts(stx.id, stx.inputs, timeWindow, stx.notary, stx.references, stx.networkParametersHash)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,6 +57,7 @@ open class DefaultNamedCacheFactory protected constructor(private val metricRegi
|
||||
name == "BFTNonValidatingNotaryService_transactions" -> caffeine.maximumSize(defaultCacheSize)
|
||||
name == "RaftUniquenessProvider_transactions" -> caffeine.maximumSize(defaultCacheSize)
|
||||
name == "BasicHSMKeyManagementService_keys" -> caffeine.maximumSize(defaultCacheSize)
|
||||
name == "NodeParametersStorage_networkParametersByHash" -> caffeine.maximumSize(defaultCacheSize)
|
||||
else -> throw IllegalArgumentException("Unexpected cache name $name. Did you add a new cache?")
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import com.nhaarman.mockito_kotlin.mock
|
||||
import net.corda.client.rpc.internal.serialization.amqp.RpcClientObservableDeSerializer
|
||||
import net.corda.core.context.Trace
|
||||
import net.corda.core.internal.ThreadBox
|
||||
import net.corda.core.internal.toSynchronised
|
||||
import net.corda.core.serialization.ClassWhitelist
|
||||
import net.corda.node.internal.serialization.testutils.AMQPRoundTripRPCSerializationScheme
|
||||
import net.corda.node.internal.serialization.testutils.serializationContext
|
||||
import net.corda.node.serialization.amqp.RpcServerObservableSerializer
|
||||
@ -16,6 +18,7 @@ import net.corda.nodeapi.RPCApi
|
||||
import net.corda.serialization.internal.amqp.AccessOrderLinkedHashMap
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import org.apache.activemq.artemis.api.core.SimpleString
|
||||
import org.junit.Test
|
||||
import rx.Notification
|
||||
@ -60,7 +63,7 @@ class RoundTripObservableSerializerTests {
|
||||
@Test
|
||||
fun roundTripTest1() {
|
||||
val serializationScheme = AMQPRoundTripRPCSerializationScheme(
|
||||
serializationContext, emptySet(), AccessOrderLinkedHashMap { 128 })
|
||||
serializationContext, emptySet(), AccessOrderLinkedHashMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>(128).toSynchronised())
|
||||
|
||||
// Fake up a message ID, needs to be used on both "sides". The server setting it in the subscriptionMap,
|
||||
// the client as a property of the deserializer which, in the actual RPC client, is pulled off of
|
||||
|
@ -24,7 +24,7 @@ import net.corda.client.rpc.internal.ObservableContext as ClientObservableContex
|
||||
class AMQPRoundTripRPCSerializationScheme(
|
||||
private val serializationContext: SerializationContext,
|
||||
cordappCustomSerializers: Set<SerializationCustomSerializer<*, *>>,
|
||||
serializerFactoriesForContexts: AccessOrderLinkedHashMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>)
|
||||
serializerFactoriesForContexts: MutableMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>)
|
||||
: AbstractAMQPSerializationScheme(
|
||||
cordappCustomSerializers, serializerFactoriesForContexts
|
||||
) {
|
||||
|
@ -1,8 +1,6 @@
|
||||
package net.corda.node.messaging
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.nhaarman.mockito_kotlin.doReturn
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.*
|
||||
@ -34,7 +32,6 @@ import net.corda.finance.contracts.asset.CASH
|
||||
import net.corda.finance.contracts.asset.Cash
|
||||
import net.corda.finance.flows.TwoPartyTradeFlow.Buyer
|
||||
import net.corda.finance.flows.TwoPartyTradeFlow.Seller
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.node.services.api.WritableTransactionStorage
|
||||
import net.corda.node.services.persistence.DBTransactionStorage
|
||||
import net.corda.node.services.persistence.checkpoints
|
||||
@ -45,9 +42,7 @@ import net.corda.testing.dsl.TestLedgerDSLInterpreter
|
||||
import net.corda.testing.dsl.TestTransactionDSLInterpreter
|
||||
import net.corda.testing.internal.LogHelper
|
||||
import net.corda.testing.internal.TEST_TX_TIME
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
import net.corda.testing.internal.vault.VaultFiller
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.internal.*
|
||||
import net.corda.testing.node.ledger
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
@ -71,6 +66,7 @@ import kotlin.test.assertTrue
|
||||
*
|
||||
* We assume that Alice and Bob already found each other via some market, and have agreed the details already.
|
||||
*/
|
||||
// TODO These tests need serious cleanup.
|
||||
@RunWith(Parameterized::class)
|
||||
class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
companion object {
|
||||
@ -80,7 +76,6 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
fun data(): Collection<Boolean> = listOf(true, false)
|
||||
|
||||
private val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20)
|
||||
private val MEGA_CORP = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")).party
|
||||
private val DUMMY_NOTARY get() = dummyNotary.party
|
||||
}
|
||||
|
||||
@ -105,17 +100,15 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
// we run in the unit test thread exclusively to speed things up, ensure deterministic results and
|
||||
// allow interruption half way through.
|
||||
mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages(cordappPackages), threadPerNode = true)
|
||||
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
|
||||
MockServices(cordappPackages, MEGA_CORP.name, ledgerIdentityService).ledger(DUMMY_NOTARY) {
|
||||
val notaryNode = mockNet.defaultNotaryNode
|
||||
val notaryNode = mockNet.defaultNotaryNode
|
||||
val notary = mockNet.defaultNotaryIdentity
|
||||
notaryNode.services.ledger(notary) {
|
||||
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
|
||||
val bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
val bankNode = mockNet.createPartyNode(BOC_NAME)
|
||||
val alice = aliceNode.info.singleIdentity()
|
||||
val bank = bankNode.info.singleIdentity()
|
||||
doReturn(null).whenever(ledgerIdentityService).partyFromKey(bank.owningKey)
|
||||
val bob = bobNode.info.singleIdentity()
|
||||
val notary = mockNet.defaultNotaryIdentity
|
||||
val cashIssuer = bank.ref(1)
|
||||
val cpIssuer = bank.ref(1, 2, 3)
|
||||
|
||||
@ -157,15 +150,13 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
@Test(expected = InsufficientBalanceException::class)
|
||||
fun `trade cash for commercial paper fails using soft locking`() {
|
||||
mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages(cordappPackages), threadPerNode = true)
|
||||
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
|
||||
MockServices(cordappPackages, MEGA_CORP.name, ledgerIdentityService).ledger(DUMMY_NOTARY) {
|
||||
val notaryNode = mockNet.defaultNotaryNode
|
||||
val notaryNode = mockNet.defaultNotaryNode
|
||||
notaryNode.services.ledger(notaryNode.info.singleIdentity()) {
|
||||
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
|
||||
val bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
val bankNode = mockNet.createPartyNode(BOC_NAME)
|
||||
val alice = aliceNode.info.singleIdentity()
|
||||
val bank = bankNode.info.singleIdentity()
|
||||
doReturn(null).whenever(ledgerIdentityService).partyFromKey(bank.owningKey)
|
||||
val bob = bobNode.info.singleIdentity()
|
||||
val issuer = bank.ref(1)
|
||||
val notary = mockNet.defaultNotaryIdentity
|
||||
@ -215,9 +206,9 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
@Test
|
||||
fun `shutdown and restore`() {
|
||||
mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages(cordappPackages))
|
||||
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
|
||||
MockServices(cordappPackages, MEGA_CORP.name, ledgerIdentityService).ledger(DUMMY_NOTARY) {
|
||||
val notaryNode = mockNet.defaultNotaryNode
|
||||
val notaryNode = mockNet.defaultNotaryNode
|
||||
val notary = mockNet.defaultNotaryIdentity
|
||||
notaryNode.services.ledger(notary) {
|
||||
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
|
||||
var bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
val bankNode = mockNet.createPartyNode(BOC_NAME)
|
||||
@ -227,10 +218,8 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
val bobAddr = bobNode.network.myAddress
|
||||
mockNet.runNetwork() // Clear network map registration messages
|
||||
|
||||
val notary = mockNet.defaultNotaryIdentity
|
||||
val alice = aliceNode.info.singleIdentity()
|
||||
val bank = bankNode.info.singleIdentity()
|
||||
doReturn(null).whenever(ledgerIdentityService).partyFromKey(bank.owningKey)
|
||||
val bob = bobNode.info.singleIdentity()
|
||||
val issuer = bank.ref(1, 2, 3)
|
||||
|
||||
@ -336,7 +325,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
val bob = bobNode.info.singleIdentity()
|
||||
val bank = bankNode.info.singleIdentity()
|
||||
val issuer = bank.ref(1, 2, 3)
|
||||
aliceNode.services.ledger(DUMMY_NOTARY) {
|
||||
aliceNode.services.ledger(notary) {
|
||||
// Insert a prospectus type attachment into the commercial paper transaction.
|
||||
val stream = ByteArrayOutputStream()
|
||||
JarOutputStream(stream).use {
|
||||
@ -440,7 +429,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
val bank: Party = bankNode.info.singleIdentity()
|
||||
val bob = bobNode.info.singleIdentity()
|
||||
val issuer = bank.ref(1, 2, 3)
|
||||
aliceNode.services.ledger(DUMMY_NOTARY) {
|
||||
aliceNode.services.ledger(notary) {
|
||||
// Insert a prospectus type attachment into the commercial paper transaction.
|
||||
val stream = ByteArrayOutputStream()
|
||||
JarOutputStream(stream).use {
|
||||
@ -508,18 +497,16 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
@Test
|
||||
fun `dependency with error on buyer side`() {
|
||||
mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages(cordappPackages))
|
||||
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
|
||||
MockServices(cordappPackages, MEGA_CORP.name, ledgerIdentityService).ledger(DUMMY_NOTARY) {
|
||||
runWithError(ledgerIdentityService, true, false, "at least one cash input")
|
||||
mockNet.defaultNotaryNode.services.ledger(DUMMY_NOTARY) {
|
||||
runWithError(true, false, "at least one cash input")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `dependency with error on seller side`() {
|
||||
mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages(cordappPackages))
|
||||
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
|
||||
MockServices(cordappPackages, MEGA_CORP.name, ledgerIdentityService).ledger(DUMMY_NOTARY) {
|
||||
runWithError(ledgerIdentityService, false, true, "Issuances have a time-window")
|
||||
mockNet.defaultNotaryNode.services.ledger(DUMMY_NOTARY) {
|
||||
runWithError(false, true, "Issuances have a time-window")
|
||||
}
|
||||
}
|
||||
|
||||
@ -581,7 +568,6 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
data class TestTx(val notaryIdentity: Party, val price: Amount<Currency>, val anonymous: Boolean)
|
||||
|
||||
private fun LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.runWithError(
|
||||
ledgerIdentityService: IdentityServiceInternal,
|
||||
bobError: Boolean,
|
||||
aliceError: Boolean,
|
||||
expectedMessageSubstring: String
|
||||
@ -595,7 +581,6 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
val alice = aliceNode.info.singleIdentity()
|
||||
val bob = bobNode.info.singleIdentity()
|
||||
val bank = bankNode.info.singleIdentity()
|
||||
doReturn(null).whenever(ledgerIdentityService).partyFromKey(bank.owningKey)
|
||||
val issuer = bank.ref(1, 2, 3)
|
||||
|
||||
val bobsBadCash = bobNode.database.transaction {
|
||||
@ -624,7 +609,6 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun insertFakeTransactions(
|
||||
wtxToSign: List<WireTransaction>,
|
||||
node: TestStartedNode,
|
||||
@ -719,7 +703,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
notary: Party): Pair<Vault<ContractState>, List<WireTransaction>> {
|
||||
val ap = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
|
||||
output(CommercialPaper.CP_PROGRAM_ID, "alice's paper", notary = notary,
|
||||
contractState = CommercialPaper.State(issuer, owner, amount, TEST_TX_TIME + 7.days))
|
||||
contractState = CommercialPaper.State(issuer, owner, amount, TEST_TX_TIME + 7.days))
|
||||
command(issuer.party.owningKey, CommercialPaper.Commands.Issue())
|
||||
if (!withError)
|
||||
timeWindow(time = TEST_TX_TIME)
|
||||
@ -736,7 +720,6 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
return Pair(vault, listOf(ap))
|
||||
}
|
||||
|
||||
|
||||
class RecordingTransactionStorage(
|
||||
private val database: CordaPersistence,
|
||||
private val delegate: WritableTransactionStorage
|
||||
@ -777,5 +760,4 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
data class Add(val transaction: SignedTransaction) : TxRecord
|
||||
data class Get(val id: SecureHash) : TxRecord
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,132 @@
|
||||
package net.corda.node.services.network
|
||||
|
||||
import com.nhaarman.mockito_kotlin.any
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import com.nhaarman.mockito_kotlin.times
|
||||
import com.nhaarman.mockito_kotlin.verify
|
||||
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.internal.SignedDataWithCert
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.node.services.NetworkParametersStorage
|
||||
import net.corda.node.internal.DBNetworkParametersStorage
|
||||
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
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.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.internal.DEV_INTERMEDIATE_CA
|
||||
import net.corda.testing.internal.DEV_ROOT_CA
|
||||
import net.corda.testing.internal.TestingNamedCacheFactory
|
||||
import net.corda.testing.internal.configureDatabase
|
||||
import net.corda.testing.node.MockServices
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.io.PrintStream
|
||||
import kotlin.streams.toList
|
||||
|
||||
class DBNetworkParametersStorageTest {
|
||||
@Rule
|
||||
@JvmField
|
||||
val testSerialization = SerializationEnvironmentRule(true)
|
||||
|
||||
private lateinit var networkMapClient: NetworkMapClient
|
||||
private lateinit var nodeParametersStorage: NetworkParametersStorage
|
||||
private lateinit var database: CordaPersistence
|
||||
|
||||
private val certKeyPair: CertificateAndKeyPair = createDevNetworkMapCa()
|
||||
private lateinit var netParams1: SignedDataWithCert<NetworkParameters>
|
||||
private lateinit var netParams2: SignedDataWithCert<NetworkParameters>
|
||||
private lateinit var incorrectParams: SignedDataWithCert<NetworkParameters>
|
||||
private lateinit var hash1: SecureHash
|
||||
private lateinit var hash2: SecureHash
|
||||
private lateinit var hash3: SecureHash
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
netParams1 = certKeyPair.sign(testNetworkParameters(minimumPlatformVersion = 1))
|
||||
netParams2 = certKeyPair.sign(testNetworkParameters(minimumPlatformVersion = 2))
|
||||
incorrectParams = createDevNetworkMapCa(DEV_INTERMEDIATE_CA).sign(testNetworkParameters(minimumPlatformVersion = 3))
|
||||
hash1 = netParams1.raw.hash
|
||||
hash2 = netParams2.raw.hash
|
||||
hash3 = incorrectParams.raw.hash
|
||||
database = configureDatabase(
|
||||
MockServices.makeTestDataSourceProperties(),
|
||||
DatabaseConfig(),
|
||||
{ null },
|
||||
{ null }
|
||||
)
|
||||
networkMapClient = createMockNetworkMapClient()
|
||||
nodeParametersStorage = DBNetworkParametersStorage(TestingNamedCacheFactory(), database, networkMapClient).apply {
|
||||
database.transaction {
|
||||
start(netParams1, DEV_ROOT_CA.certificate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
database.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `set current parameters`() {
|
||||
assertThat(nodeParametersStorage.currentHash).isEqualTo(hash1)
|
||||
assertThat(nodeParametersStorage.lookup(hash1)).isEqualTo(netParams1.verified())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get default parameters`() {
|
||||
// TODO After implementing default endpoint on network map check it is correct, for now we set it to current.
|
||||
assertThat(nodeParametersStorage.defaultHash).isEqualTo(hash1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `download parameters from network map server`() {
|
||||
database.transaction {
|
||||
val netParams = nodeParametersStorage.lookup(hash2)
|
||||
assertThat(nodeParametersStorage.lookup(hash2)).isEqualTo(netParams)
|
||||
verify(networkMapClient, times(1)).getNetworkParameters(hash2)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `try save parameters with incorrect signature`() {
|
||||
database.transaction {
|
||||
val consoleOutput = interceptConsoleOutput {
|
||||
nodeParametersStorage.lookup(hash3)
|
||||
}
|
||||
assertThat(consoleOutput).anySatisfy {
|
||||
it.contains("Caused by: java.security.cert.CertPathValidatorException: subject/issuer name chaining check failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun interceptConsoleOutput(block: () -> Unit): List<String> {
|
||||
val oldOut = System.out
|
||||
val out = ByteOutputStream()
|
||||
System.setOut(PrintStream(out))
|
||||
block()
|
||||
System.setOut(oldOut)
|
||||
return out.bytes.inputStream().bufferedReader().lines().toList()
|
||||
}
|
||||
|
||||
private fun createMockNetworkMapClient(): NetworkMapClient {
|
||||
return mock {
|
||||
on { getNetworkParameters(any()) }.then {
|
||||
val hash = it.getArguments()[0]
|
||||
when (hash) {
|
||||
hash1 -> netParams1
|
||||
hash2 -> netParams2
|
||||
hash3 -> incorrectParams
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ import net.corda.node.VersionInfo
|
||||
import net.corda.node.services.api.NetworkMapCacheInternal
|
||||
import net.corda.node.services.config.NetworkParameterAcceptanceSettings
|
||||
import net.corda.core.internal.NODE_INFO_DIRECTORY
|
||||
import net.corda.node.internal.NetworkParametersStorageInternal
|
||||
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
@ -64,6 +65,7 @@ class NetworkMapUpdaterTest {
|
||||
private val networkMapCache = createMockNetworkMapCache()
|
||||
private lateinit var ourKeyPair: KeyPair
|
||||
private lateinit var ourNodeInfo: SignedNodeInfo
|
||||
private val networkParametersStorage: NetworkParametersStorageInternal = mock()
|
||||
private lateinit var server: NetworkMapServer
|
||||
private lateinit var networkMapClient: NetworkMapClient
|
||||
private lateinit var updater: NetworkMapUpdater
|
||||
@ -86,7 +88,7 @@ class NetworkMapUpdaterTest {
|
||||
}
|
||||
|
||||
private fun setUpdater(extraNetworkMapKeys: List<UUID> = emptyList(), netMapClient: NetworkMapClient? = networkMapClient) {
|
||||
updater = NetworkMapUpdater(networkMapCache, fileWatcher, netMapClient, baseDir, extraNetworkMapKeys)
|
||||
updater = NetworkMapUpdater(networkMapCache, fileWatcher, netMapClient, baseDir, extraNetworkMapKeys, networkParametersStorage)
|
||||
}
|
||||
|
||||
private fun startUpdater(ourNodeInfo: SignedNodeInfo = this.ourNodeInfo,
|
||||
@ -236,6 +238,7 @@ class NetworkMapUpdaterTest {
|
||||
val updateFile = baseDir / NETWORK_PARAMS_UPDATE_FILE_NAME
|
||||
assert(!updateFile.exists()) { "network parameters should not be auto accepted" }
|
||||
updater.acceptNewNetworkParameters(newHash) { it.serialize().sign(ourKeyPair) }
|
||||
verify(networkParametersStorage, times(1)).saveParameters(any())
|
||||
val signedNetworkParams = updateFile.readObject<SignedNetworkParameters>()
|
||||
val paramsFromFile = signedNetworkParams.verifiedNetworkParametersCert(DEV_ROOT_CA.certificate)
|
||||
assertEquals(newParameters, paramsFromFile)
|
||||
|
@ -4,21 +4,18 @@ import co.paralleluniverse.fibers.Suspendable
|
||||
import com.esotericsoftware.kryo.KryoException
|
||||
import net.corda.core.contracts.UniqueIdentifier
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.FlowLogic.Companion.sleep
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.TestIdentity
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.makeTestIdentityService
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.ClassRule
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.io.Serializable
|
||||
import java.time.Duration
|
||||
import javax.persistence.Column
|
||||
import javax.persistence.Entity
|
||||
import javax.persistence.Id
|
||||
@ -26,7 +23,6 @@ import javax.persistence.Table
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
|
||||
class ExposeJpaToFlowsTests {
|
||||
|
||||
object FooSchema
|
||||
@ -39,15 +35,28 @@ class ExposeJpaToFlowsTests {
|
||||
|
||||
val myself = TestIdentity(CordaX500Name("Me", "London", "GB"))
|
||||
val cordapps = listOf("net.corda.node.services.persistence")
|
||||
val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(
|
||||
cordappPackages = cordapps,
|
||||
identityService = makeTestIdentityService(myself.identity),
|
||||
initialIdentity = myself,
|
||||
networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
|
||||
)
|
||||
lateinit var mockNet: MockNetwork
|
||||
lateinit var services: MockServices
|
||||
lateinit var database: CordaPersistence
|
||||
|
||||
val services: MockServices = databaseAndServices.second
|
||||
val database: CordaPersistence = databaseAndServices.first
|
||||
@Before
|
||||
fun setUp() {
|
||||
mockNet = MockNetwork(cordapps)
|
||||
val (db, mockServices) = MockServices.makeTestDatabaseAndMockServices(
|
||||
cordappPackages = cordapps,
|
||||
identityService = makeTestIdentityService(myself.identity),
|
||||
initialIdentity = myself,
|
||||
networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
|
||||
)
|
||||
|
||||
services = mockServices
|
||||
database = db
|
||||
}
|
||||
|
||||
@After
|
||||
fun cleanUp() {
|
||||
mockNet.stopNodes()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `can persist and query custom entities`() {
|
||||
@ -71,7 +80,6 @@ class ExposeJpaToFlowsTests {
|
||||
|
||||
@Test
|
||||
fun `can't perform suspendable operations inside withEntityManager`() {
|
||||
val mockNet = MockNetwork(cordapps)
|
||||
val mockNode = mockNet.createNode()
|
||||
assertFailsWith(KryoException::class) {
|
||||
mockNode.startFlow(object : FlowLogic<Unit>() {
|
||||
@ -84,6 +92,5 @@ class ExposeJpaToFlowsTests {
|
||||
}
|
||||
})
|
||||
}
|
||||
mockNet.stopNodes()
|
||||
}
|
||||
}
|
@ -4,8 +4,6 @@ import co.paralleluniverse.fibers.Suspendable
|
||||
import com.codahale.metrics.MetricRegistry
|
||||
import com.google.common.jimfs.Configuration
|
||||
import com.google.common.jimfs.Jimfs
|
||||
import com.nhaarman.mockito_kotlin.doReturn
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import net.corda.core.contracts.ContractAttachment
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
@ -20,7 +18,6 @@ import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.node.services.transactions.PersistentUniquenessProvider
|
||||
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.core.ALICE_NAME
|
||||
import net.corda.testing.core.JarSignatureTestUtils.createJar
|
||||
import net.corda.testing.core.JarSignatureTestUtils.generateKey
|
||||
@ -33,7 +30,10 @@ import net.corda.testing.node.MockServices.Companion.makeTestDataSourcePropertie
|
||||
import net.corda.testing.node.internal.InternalMockNetwork
|
||||
import net.corda.testing.node.internal.startFlow
|
||||
import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
import org.junit.*
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.Closeable
|
||||
import java.io.OutputStream
|
||||
@ -52,7 +52,6 @@ import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertNotEquals
|
||||
import kotlin.test.assertNull
|
||||
|
||||
|
||||
class NodeAttachmentServiceTest {
|
||||
|
||||
// Use an in memory file system for testing attachment storage.
|
||||
@ -69,8 +68,6 @@ class NodeAttachmentServiceTest {
|
||||
database = configureDatabase(dataSourceProperties, DatabaseConfig(runMigration = true), { null }, { null })
|
||||
fs = Jimfs.newFileSystem(Configuration.unix())
|
||||
|
||||
doReturn(testNetworkParameters()).whenever(services).networkParameters
|
||||
|
||||
storage = NodeAttachmentService(MetricRegistry(), TestingNamedCacheFactory(), database).also {
|
||||
database.transaction {
|
||||
it.start()
|
||||
@ -427,5 +424,4 @@ class NodeAttachmentServiceTest {
|
||||
return Paths.get(fileManager.list(StandardLocation.CLASS_OUTPUT, "", setOf(JavaFileObject.Kind.CLASS), true).single().name)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ class MaxTransactionSizeTests {
|
||||
mockNet = MockNetwork(listOf("net.corda.testing.contracts"), networkParameters = testNetworkParameters(maxTransactionSize = 3_000_000))
|
||||
aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME))
|
||||
bobNode = mockNet.createNode(MockNodeParameters(legalName = BOB_NAME))
|
||||
bobNode.registerInitiatedFlow(ReceiveLargeTransactionFlow::class.java)
|
||||
notaryNode = mockNet.defaultNotaryNode
|
||||
notary = mockNet.defaultNotaryIdentity
|
||||
alice = aliceNode.info.singleIdentity()
|
||||
|
@ -3,18 +3,23 @@ package net.corda.node.services.transactions
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.flows.NotaryError
|
||||
import net.corda.core.flows.NotaryException
|
||||
import net.corda.core.flows.NotaryFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.NotaryChangeTransactionBuilder
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.transactions.NotaryChangeWireTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||
import net.corda.testing.core.singleIdentity
|
||||
import net.corda.testing.node.MockNetworkNotarySpec
|
||||
import net.corda.testing.node.internal.*
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@ -31,7 +36,8 @@ class NotaryServiceTests {
|
||||
fun setup() {
|
||||
mockNet = InternalMockNetwork(
|
||||
cordappsForAllNodes = cordappsForPackages("net.corda.testing.contracts"),
|
||||
notarySpecs = listOf(MockNetworkNotarySpec(DUMMY_NOTARY_NAME, validating = false))
|
||||
notarySpecs = listOf(MockNetworkNotarySpec(DUMMY_NOTARY_NAME, validating = false)),
|
||||
networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
|
||||
)
|
||||
aliceNode = mockNet.createNode(InternalMockNodeParameters(legalName = ALICE_NAME))
|
||||
notaryServices = mockNet.defaultNotaryNode.services //TODO get rid of that
|
||||
@ -49,6 +55,28 @@ class NotaryServiceTests {
|
||||
notariseWithTooManyInputs(aliceNode, alice, notary, mockNet)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should reject when network parameters component is not visible`() {
|
||||
val stx = generateTransaction(aliceNode, alice, notary, null, 13)
|
||||
val future = aliceNode.services.startFlow(DummyClientFlow(stx, notary)).resultFuture
|
||||
mockNet.runNetwork()
|
||||
val ex = assertFailsWith<NotaryException> { future.getOrThrow() }
|
||||
val notaryError = ex.error as NotaryError.TransactionInvalid
|
||||
assertThat(notaryError.cause).hasMessageContaining("Transaction for notarisation was tagged with parameters with hash: null")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should reject when parameters not current`() {
|
||||
val hash = SecureHash.randomSHA256()
|
||||
val stx = generateTransaction(aliceNode, alice, notary, hash, 13)
|
||||
val future = aliceNode.services.startFlow(DummyClientFlow(stx, notary)).resultFuture
|
||||
mockNet.runNetwork()
|
||||
val ex = assertFailsWith<NotaryException> { future.getOrThrow() }
|
||||
val notaryError = ex.error as NotaryError.TransactionInvalid
|
||||
assertThat(notaryError.cause).hasMessageContaining("Transaction for notarisation was tagged with parameters with hash: $hash, " +
|
||||
"but current network parameters are: ${notaryServices.networkParametersStorage.currentHash}")
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
/** This is used by both [NotaryServiceTests] and [ValidatingNotaryServiceTests]. */
|
||||
fun notariseWithTooManyInputs(node: TestStartedNode, party: Party, notary: Party, network: InternalMockNetwork) {
|
||||
@ -59,10 +87,17 @@ class NotaryServiceTests {
|
||||
assertFailsWith<NotaryException> { future.getOrThrow() }
|
||||
}
|
||||
|
||||
private fun generateTransaction(node: TestStartedNode, party: Party, notary: Party): SignedTransaction {
|
||||
private fun generateTransaction(node: TestStartedNode,
|
||||
party: Party, notary: Party,
|
||||
paramsHash: SecureHash? = node.services.networkParametersStorage.currentHash,
|
||||
numberOfInputs: Int = 10_005): SignedTransaction {
|
||||
val txHash = SecureHash.randomSHA256()
|
||||
val inputs = (1..10_005).map { StateRef(txHash, it) }
|
||||
val tx = NotaryChangeTransactionBuilder(inputs, notary, party).build()
|
||||
val inputs = (1..numberOfInputs).map { StateRef(txHash, it) }
|
||||
val tx = if (paramsHash != null) {
|
||||
NotaryChangeTransactionBuilder(inputs, notary, party, paramsHash).build()
|
||||
} else {
|
||||
NotaryChangeWireTransaction(listOf(inputs, notary, party).map { it.serialize() })
|
||||
}
|
||||
|
||||
return node.services.run {
|
||||
val myKey = myInfo.legalIdentities.first().owningKey
|
||||
|
@ -11,6 +11,7 @@ import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.core.TestIdentity
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.makeTestIdentityService
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
@ -25,14 +26,7 @@ class ResolveStatePointersTest {
|
||||
private val myself = TestIdentity(CordaX500Name("Me", "London", "GB"))
|
||||
private val notary = TestIdentity(DUMMY_NOTARY_NAME, 20)
|
||||
private val cordapps = listOf("net.corda.testing.contracts")
|
||||
private val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(
|
||||
cordappPackages = cordapps,
|
||||
identityService = makeTestIdentityService(notary.identity, myself.identity),
|
||||
initialIdentity = myself,
|
||||
networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
|
||||
)
|
||||
|
||||
private val services = databaseAndServices.second
|
||||
private lateinit var services: MockServices
|
||||
|
||||
private data class Bar(
|
||||
override val participants: List<AbstractParty> = listOf(),
|
||||
@ -58,6 +52,17 @@ class ResolveStatePointersTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(
|
||||
cordappPackages = cordapps,
|
||||
identityService = makeTestIdentityService(notary.identity, myself.identity),
|
||||
initialIdentity = myself,
|
||||
networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
|
||||
)
|
||||
services = databaseAndServices.second
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `resolve state pointers and check reference state is added to transaction`() {
|
||||
val stateAndRef = createPointedToState(barOne)
|
||||
@ -154,5 +159,4 @@ class ResolveStatePointersTest {
|
||||
val foo = ltx.outputs.single().data as Foo<Bar>
|
||||
assertEquals(stateAndRef, foo.baz.resolve(ltx))
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,7 @@ package net.corda.node.services.transactions
|
||||
|
||||
import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.core.contracts.Command
|
||||
import net.corda.core.contracts.PrivacySalt
|
||||
import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.*
|
||||
@ -14,16 +15,19 @@ import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.core.utilities.seconds
|
||||
import net.corda.node.services.issueInvalidState
|
||||
import net.corda.node.services.messaging.Message
|
||||
import net.corda.node.services.statemachine.InitialSessionMessage
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.contracts.DummyContract
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.dummyCommand
|
||||
import net.corda.testing.core.singleIdentity
|
||||
import net.corda.testing.internal.createWireTransaction
|
||||
import net.corda.testing.node.TestClock
|
||||
import net.corda.testing.node.internal.*
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
@ -46,7 +50,8 @@ class ValidatingNotaryServiceTests {
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages("net.corda.testing.contracts"))
|
||||
mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages("net.corda.testing.contracts"),
|
||||
networkParameters = testNetworkParameters(minimumPlatformVersion = 4))
|
||||
aliceNode = mockNet.createNode(InternalMockNodeParameters(legalName = ALICE_NAME))
|
||||
notaryNode = mockNet.defaultNotaryNode
|
||||
notary = mockNet.defaultNotaryIdentity
|
||||
@ -96,6 +101,27 @@ class ValidatingNotaryServiceTests {
|
||||
assertEquals(setOf(expectedMissingKey), missingKeys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should reject transaction without network parameters`() {
|
||||
val inputState = issueState(aliceNode.services, alice).ref
|
||||
val wtx = createWireTransaction(inputs = listOf(inputState),
|
||||
attachments = emptyList(),
|
||||
outputs = emptyList(),
|
||||
commands = listOf(dummyCommand(alice.owningKey)),
|
||||
notary = notary,
|
||||
timeWindow = null)
|
||||
assertThat(wtx.networkParametersHash).isNull()
|
||||
val sig = aliceNode.services.keyManagementService.sign(
|
||||
SignableData(wtx.id, SignatureMetadata(1, Crypto.findSignatureScheme(alice.owningKey).schemeNumberID)), alice.owningKey
|
||||
)
|
||||
val stx = SignedTransaction(wtx, listOf(sig))
|
||||
assertThat(stx.networkParametersHash).isNull()
|
||||
val future = runNotaryClient(stx)
|
||||
val ex = assertFailsWith(NotaryException::class) { future.getOrThrow() }
|
||||
val notaryError = ex.error as NotaryError.TransactionInvalid
|
||||
assertThat(notaryError.cause).hasMessageContaining("Transaction for notarisation was tagged with parameters with hash: null")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should sign a unique transaction with a valid time-window`() {
|
||||
val stx = run {
|
||||
@ -173,7 +199,7 @@ class ValidatingNotaryServiceTests {
|
||||
fun `notarise issue tx with time-window`() {
|
||||
val stx = run {
|
||||
val tx = DummyContract.generateInitial(Random().nextInt(), notary, alice.ref(0))
|
||||
.setTimeWindow(Instant.now(), 30.seconds)
|
||||
.setTimeWindow(Instant.now(), 30.seconds)
|
||||
aliceNode.services.signInitialTransaction(tx)
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.core.TestIdentity
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
import net.corda.testing.node.MockServices
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.util.*
|
||||
@ -37,19 +38,25 @@ class ExternalIdMappingTest {
|
||||
|
||||
private val myself = TestIdentity(CordaX500Name("Me", "London", "GB"))
|
||||
private val notary = TestIdentity(CordaX500Name("NotaryService", "London", "GB"), 1337L)
|
||||
private val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(
|
||||
cordappPackages = cordapps,
|
||||
identityService = rigorousMock<IdentityServiceInternal>().also {
|
||||
doReturn(notary.party).whenever(it).partyFromKey(notary.publicKey)
|
||||
doReturn(notary.party).whenever(it).wellKnownPartyFromAnonymous(notary.party)
|
||||
doReturn(notary.party).whenever(it).wellKnownPartyFromX500Name(notary.name)
|
||||
},
|
||||
initialIdentity = myself,
|
||||
networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
|
||||
)
|
||||
|
||||
private val services: MockServices = databaseAndServices.second
|
||||
private val database: CordaPersistence = databaseAndServices.first
|
||||
lateinit var services: MockServices
|
||||
lateinit var database: CordaPersistence
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
val (db, mockServices) = MockServices.makeTestDatabaseAndMockServices(
|
||||
cordappPackages = cordapps,
|
||||
identityService = rigorousMock<IdentityServiceInternal>().also {
|
||||
doReturn(notary.party).whenever(it).partyFromKey(notary.publicKey)
|
||||
doReturn(notary.party).whenever(it).wellKnownPartyFromAnonymous(notary.party)
|
||||
doReturn(notary.party).whenever(it).wellKnownPartyFromX500Name(notary.name)
|
||||
},
|
||||
initialIdentity = myself,
|
||||
networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
|
||||
)
|
||||
services = mockServices
|
||||
database = db
|
||||
}
|
||||
|
||||
private fun freshKeyForExternalId(externalId: UUID): AnonymousParty {
|
||||
val anonymousParty = freshKey()
|
||||
|
@ -29,6 +29,7 @@ import net.corda.finance.utils.sumCash
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.node.services.api.WritableTransactionStorage
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.contracts.DummyContract
|
||||
import net.corda.testing.contracts.DummyState
|
||||
import net.corda.testing.core.*
|
||||
@ -90,17 +91,19 @@ class NodeVaultServiceTest {
|
||||
@Before
|
||||
fun setUp() {
|
||||
LogHelper.setLevel(NodeVaultService::class)
|
||||
val parameters = testNetworkParameters()
|
||||
val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(
|
||||
cordappPackages,
|
||||
makeTestIdentityService(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY),
|
||||
megaCorp)
|
||||
megaCorp,
|
||||
parameters)
|
||||
database = databaseAndServices.first
|
||||
services = databaseAndServices.second
|
||||
vaultFiller = VaultFiller(services, dummyNotary)
|
||||
// This is safe because MockServices only ever have a single identity
|
||||
identity = services.myInfo.singleIdentityAndCert()
|
||||
issuerServices = MockServices(cordappPackages, dummyCashIssuer, rigorousMock<IdentityService>())
|
||||
bocServices = MockServices(cordappPackages, bankOfCorda, rigorousMock<IdentityService>())
|
||||
issuerServices = MockServices(cordappPackages, dummyCashIssuer, rigorousMock<IdentityService>(), parameters)
|
||||
bocServices = MockServices(cordappPackages, bankOfCorda, rigorousMock<IdentityService>(), parameters)
|
||||
services.identityService.verifyAndRegisterIdentity(DUMMY_CASH_ISSUER_IDENTITY)
|
||||
services.identityService.verifyAndRegisterIdentity(BOC_IDENTITY)
|
||||
}
|
||||
@ -571,7 +574,6 @@ class NodeVaultServiceTest {
|
||||
}
|
||||
|
||||
// TODO: Unit test linear state relevancy checks
|
||||
|
||||
@Test
|
||||
fun `correct updates are generated for general transactions`() {
|
||||
val notary = identity.party
|
||||
@ -647,7 +649,7 @@ class NodeVaultServiceTest {
|
||||
// Change notary
|
||||
services.identityService.verifyAndRegisterIdentity(DUMMY_NOTARY_IDENTITY)
|
||||
val newNotary = DUMMY_NOTARY
|
||||
val changeNotaryTx = NotaryChangeTransactionBuilder(listOf(initialCashState.ref), issueStx.notary!!, newNotary).build()
|
||||
val changeNotaryTx = NotaryChangeTransactionBuilder(listOf(initialCashState.ref), issueStx.notary!!, newNotary, services.networkParametersStorage.currentHash).build()
|
||||
val cashStateWithNewNotary = StateAndRef(initialCashState.state.copy(notary = newNotary), StateRef(changeNotaryTx.id, 0))
|
||||
|
||||
database.transaction {
|
||||
|
@ -16,6 +16,10 @@ import org.junit.rules.ExpectedException
|
||||
class VaultQueryExceptionsTests : VaultQueryParties by rule {
|
||||
|
||||
companion object {
|
||||
@ClassRule
|
||||
@JvmField
|
||||
val testSerialization = SerializationEnvironmentRule()
|
||||
|
||||
@ClassRule
|
||||
@JvmField
|
||||
val rule = object : VaultQueryTestRule() {
|
||||
@ -26,10 +30,6 @@ class VaultQueryExceptionsTests : VaultQueryParties by rule {
|
||||
}
|
||||
}
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val testSerialization = SerializationEnvironmentRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val expectedEx: ExpectedException = ExpectedException.none()
|
||||
|
@ -99,7 +99,6 @@ interface VaultQueryParties {
|
||||
}
|
||||
|
||||
open class VaultQueryTestRule : ExternalResource(), VaultQueryParties {
|
||||
|
||||
override val alice = TestIdentity(ALICE_NAME, 70)
|
||||
override val bankOfCorda = TestIdentity(BOC_NAME)
|
||||
override val bigCorp = TestIdentity(CordaX500Name("BigCorporation", "New York", "US"))
|
||||
|
@ -9,7 +9,7 @@ import net.corda.core.crypto.SignatureScheme
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.nodeapi.internal.crypto.*
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.NettyTestClient
|
||||
import net.corda.testing.internal.NettyTestHandler
|
||||
import net.corda.testing.internal.NettyTestServer
|
||||
@ -52,7 +52,7 @@ class NettyEngineBasedTlsAuthenticationTests(val sslSetup: SslSetup) {
|
||||
private fun tempFile(name: String): Path = tempFolder.root.toPath() / name
|
||||
|
||||
companion object {
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
|
||||
data class SslSetup(val clientNative: Boolean, val serverNative: Boolean) {
|
||||
override fun toString(): String = "Client: ${if (clientNative) "openSsl" else "javaSsl"} Server: ${if (serverNative) "openSsl" else "javaSsl"} "
|
||||
|
@ -15,8 +15,8 @@ import net.corda.node.services.Permissions.Companion.startFlow
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.InProcess
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.driver.internal.internalServices
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.IntegrationTestSchemas
|
||||
@ -127,7 +127,7 @@ class NodePerformanceTests : IntegrationTest() {
|
||||
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, rpcUsers = listOf(user))),
|
||||
startNodesInProcess = true,
|
||||
extraCordappPackagesToScan = listOf("net.corda.finance", "com.r3.corda.enterprise.perftestcordapp"),
|
||||
portAllocation = PortAllocation.Incremental(20000)
|
||||
portAllocation = incrementalPortAllocation(20000)
|
||||
)) {
|
||||
val notary = defaultNotaryNode.getOrThrow() as InProcess
|
||||
val metricRegistry = startReporter((this as InternalDriverDSL).shutdownManager, notary.internalServices.monitoringService.metrics)
|
||||
@ -151,7 +151,7 @@ class NodePerformanceTests : IntegrationTest() {
|
||||
driver(DriverParameters(
|
||||
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME)),
|
||||
startNodesInProcess = true,
|
||||
portAllocation = PortAllocation.Incremental(20000)
|
||||
portAllocation = incrementalPortAllocation(20000)
|
||||
)) {
|
||||
val aliceFuture = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user), startInSameProcess = true)
|
||||
val alice = aliceFuture.getOrThrow() as InProcess
|
||||
@ -176,7 +176,7 @@ class NodePerformanceTests : IntegrationTest() {
|
||||
driver(DriverParameters(
|
||||
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME)),
|
||||
startNodesInProcess = true,
|
||||
portAllocation = PortAllocation.Incremental(20000)
|
||||
portAllocation = incrementalPortAllocation(20000)
|
||||
)) {
|
||||
val aliceFuture = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user))
|
||||
val bobFuture = startNode(providedName = BOB_NAME, rpcUsers = listOf(user))
|
||||
|
@ -9,7 +9,7 @@ import net.corda.finance.DOLLARS
|
||||
import net.corda.node.services.Permissions
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.NodeHandle
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.setGlobalSerialization
|
||||
import net.corda.testing.node.User
|
||||
import net.corda.testing.node.internal.DriverDSLImpl
|
||||
@ -31,7 +31,7 @@ class CheckAllTheTestFlows {
|
||||
val driverParameters = DriverParameters(
|
||||
startNodesInProcess = true,
|
||||
extraCordappPackagesToScan = listOf("com.r3.corda.enterprise.perftestcordapp"),
|
||||
portAllocation = PortAllocation.Incremental(20000)
|
||||
portAllocation = incrementalPortAllocation(20000)
|
||||
)
|
||||
val driver = DriverDSLImpl(
|
||||
portAllocation = driverParameters.portAllocation,
|
||||
|
@ -7,8 +7,8 @@ import net.corda.testing.core.DUMMY_BANK_A_NAME
|
||||
import net.corda.testing.core.DUMMY_BANK_B_NAME
|
||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.IntegrationTestSchemas
|
||||
import net.corda.testing.internal.toDatabaseSchemaName
|
||||
@ -28,7 +28,7 @@ class AttachmentDemoTest : IntegrationTest() {
|
||||
@Test
|
||||
fun `attachment demo using a 10MB zip file`() {
|
||||
val numOfExpectedBytes = 10_000_000
|
||||
driver(DriverParameters(portAllocation = PortAllocation.Incremental(20000), startNodesInProcess = true)) {
|
||||
driver(DriverParameters(portAllocation = incrementalPortAllocation(20000), startNodesInProcess = true)) {
|
||||
val demoUser = listOf(User("demo", "demo", setOf(all())))
|
||||
val (nodeA, nodeB) = listOf(
|
||||
startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = demoUser, maximumHeapSize = "1g"),
|
||||
|
@ -9,6 +9,7 @@ import net.corda.core.StubOutForDJVM
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.internal.isAbstractClass
|
||||
import net.corda.core.internal.objectOrNewInstance
|
||||
import net.corda.core.internal.toSynchronised
|
||||
import net.corda.core.internal.uncheckedCast
|
||||
import net.corda.core.serialization.*
|
||||
import net.corda.core.utilities.ByteSequence
|
||||
@ -44,7 +45,7 @@ abstract class AbstractAMQPSerializationScheme(
|
||||
val sff: SerializerFactoryFactory = createSerializerFactoryFactory()
|
||||
) : SerializationScheme {
|
||||
@DeleteForDJVM
|
||||
constructor(cordapps: List<Cordapp>) : this(cordapps.customSerializers, AccessOrderLinkedHashMap(128))
|
||||
constructor(cordapps: List<Cordapp>) : this(cordapps.customSerializers, AccessOrderLinkedHashMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>(128).toSynchronised())
|
||||
|
||||
// This is a bit gross but a broader check for ConcurrentMap is not allowed inside DJVM.
|
||||
private val serializerFactoriesForContexts: MutableMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory> = if (maybeNotConcurrentSerializerFactoriesForContexts is AccessOrderLinkedHashMap<*, *>) {
|
||||
@ -189,20 +190,24 @@ abstract class AbstractAMQPSerializationScheme(
|
||||
}
|
||||
|
||||
override fun <T : Any> deserialize(byteSequence: ByteSequence, clazz: Class<T>, context: SerializationContext): T {
|
||||
var contextToUse = context
|
||||
if (context.useCase == SerializationContext.UseCase.RPCClient) {
|
||||
contextToUse = context.withClassLoader(getContextClassLoader())
|
||||
}
|
||||
val serializerFactory = getSerializerFactory(contextToUse)
|
||||
// This is a hack introduced in version 3 to fix a spring boot issue - CORDA-1747.
|
||||
// It breaks the shell because it overwrites the CordappClassloader with the system classloader that doesn't know about any CorDapps.
|
||||
// In case a spring boot serialization issue with generics is found, a better solution needs to be found to address it.
|
||||
// var contextToUse = context
|
||||
// if (context.useCase == SerializationContext.UseCase.RPCClient) {
|
||||
// contextToUse = context.withClassLoader(getContextClassLoader())
|
||||
// }
|
||||
val serializerFactory = getSerializerFactory(context)
|
||||
return DeserializationInput(serializerFactory).deserialize(byteSequence, clazz, context)
|
||||
}
|
||||
|
||||
override fun <T : Any> serialize(obj: T, context: SerializationContext): SerializedBytes<T> {
|
||||
var contextToUse = context
|
||||
if (context.useCase == SerializationContext.UseCase.RPCClient) {
|
||||
contextToUse = context.withClassLoader(getContextClassLoader())
|
||||
}
|
||||
val serializerFactory = getSerializerFactory(contextToUse)
|
||||
// See the above comment.
|
||||
// var contextToUse = context
|
||||
// if (context.useCase == SerializationContext.UseCase.RPCClient) {
|
||||
// contextToUse = context.withClassLoader(getContextClassLoader())
|
||||
// }
|
||||
val serializerFactory = getSerializerFactory(context)
|
||||
return SerializationOutput(serializerFactory).serialize(obj, context)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.serialization.internal.amqp
|
||||
|
||||
import net.corda.core.internal.toSynchronised
|
||||
import net.corda.core.serialization.ClassWhitelist
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.core.serialization.deserialize
|
||||
@ -39,7 +40,7 @@ class AbstractAMQPSerializationSchemeTest {
|
||||
|
||||
val factory = SerializerFactoryBuilder.build(TESTING_CONTEXT.whitelist, TESTING_CONTEXT.deserializationClassLoader)
|
||||
val maxFactories = 512
|
||||
val backingMap = AccessOrderLinkedHashMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>({ maxFactories })
|
||||
val backingMap = AccessOrderLinkedHashMap<Pair<ClassWhitelist, ClassLoader>, SerializerFactory>({ maxFactories }).toSynchronised()
|
||||
val scheme = object : AbstractAMQPSerializationScheme(emptySet(), backingMap, createSerializerFactoryFactory()) {
|
||||
override fun rpcClientSerializerFactory(context: SerializationContext): SerializerFactory {
|
||||
return factory
|
||||
|
@ -16,7 +16,7 @@ import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.node.internal.Node
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||
import net.corda.testing.driver.PortAllocation.Incremental
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.driver.internal.internalServices
|
||||
import net.corda.testing.node.NotarySpec
|
||||
import net.corda.testing.node.TestCordapp
|
||||
@ -114,7 +114,7 @@ abstract class PortAllocation {
|
||||
/**
|
||||
* An implementation of [PortAllocation] which allocates ports sequentially
|
||||
*/
|
||||
class Incremental(startingPort: Int) : PortAllocation() {
|
||||
open class Incremental(startingPort: Int) : PortAllocation() {
|
||||
/** The backing [AtomicInteger] used to keep track of the currently allocated port */
|
||||
val portCounter = AtomicInteger(startingPort)
|
||||
|
||||
@ -307,7 +307,7 @@ data class NodeParameters(
|
||||
*/
|
||||
data class JmxPolicy(val startJmxHttpServer: Boolean = false,
|
||||
val jmxHttpServerPortAllocation: PortAllocation? =
|
||||
if (startJmxHttpServer) PortAllocation.Incremental(7005) else null)
|
||||
if (startJmxHttpServer) incrementalPortAllocation(7005) else null)
|
||||
|
||||
/**
|
||||
* [driver] allows one to start up nodes like this:
|
||||
@ -389,8 +389,8 @@ fun <A> driver(defaultParameters: DriverParameters = DriverParameters(), dsl: Dr
|
||||
data class DriverParameters(
|
||||
val isDebug: Boolean = false,
|
||||
val driverDirectory: Path = Paths.get("build", getTimestampAsDirectoryName()),
|
||||
val portAllocation: PortAllocation = PortAllocation.Incremental(10000),
|
||||
val debugPortAllocation: PortAllocation = PortAllocation.Incremental(5005),
|
||||
val portAllocation: PortAllocation = incrementalPortAllocation(10000),
|
||||
val debugPortAllocation: PortAllocation = incrementalPortAllocation(5005),
|
||||
val systemProperties: Map<String, String> = emptyMap(),
|
||||
val useTestClock: Boolean = false,
|
||||
val startNodesInProcess: Boolean = false,
|
||||
@ -408,8 +408,8 @@ data class DriverParameters(
|
||||
constructor(
|
||||
isDebug: Boolean = false,
|
||||
driverDirectory: Path = Paths.get("build", getTimestampAsDirectoryName()),
|
||||
portAllocation: PortAllocation = PortAllocation.Incremental(10000),
|
||||
debugPortAllocation: PortAllocation = PortAllocation.Incremental(5005),
|
||||
portAllocation: PortAllocation = incrementalPortAllocation(10000),
|
||||
debugPortAllocation: PortAllocation = incrementalPortAllocation(5005),
|
||||
systemProperties: Map<String, String> = emptyMap(),
|
||||
useTestClock: Boolean = false,
|
||||
startNodesInProcess: Boolean = false,
|
||||
|
@ -0,0 +1,20 @@
|
||||
package net.corda.testing.driver.internal
|
||||
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
|
||||
fun incrementalPortAllocation(startingPortIfNoEnv: Int): PortAllocation {
|
||||
|
||||
return when {
|
||||
System.getenv(GlobalTestPortAllocation.enablingEnvVar)?.toBoolean() == true -> GlobalTestPortAllocation
|
||||
else -> PortAllocation.Incremental(startingPortIfNoEnv)
|
||||
}
|
||||
}
|
||||
|
||||
private object GlobalTestPortAllocation : PortAllocation.Incremental(startingPort = startingPort) {
|
||||
|
||||
const val enablingEnvVar = "CORDA_TEST_GLOBAL_PORT_ALLOCATION_ENABLED"
|
||||
const val startingPortEnvVariable = "CORDA_TEST_GLOBAL_PORT_ALLOCATION_STARTING_PORT"
|
||||
const val startingPortDefaultValue = 5000
|
||||
}
|
||||
|
||||
private val startingPort: Int = System.getenv(GlobalTestPortAllocation.startingPortEnvVariable)?.toIntOrNull() ?: GlobalTestPortAllocation.startingPortDefaultValue
|
@ -9,6 +9,7 @@ import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.SignedDataWithCert
|
||||
import net.corda.core.messaging.DataFeed
|
||||
import net.corda.core.messaging.FlowHandle
|
||||
import net.corda.core.messaging.FlowProgressHandle
|
||||
@ -16,10 +17,12 @@ import net.corda.core.messaging.StateMachineTransactionMapping
|
||||
import net.corda.core.node.*
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.node.VersionInfo
|
||||
import net.corda.node.cordapp.CordappLoader
|
||||
import net.corda.node.internal.NetworkParametersStorageInternal
|
||||
import net.corda.node.internal.ServicesForResolutionImpl
|
||||
import net.corda.node.internal.cordapp.JarScanningCordappLoader
|
||||
import net.corda.node.services.api.*
|
||||
@ -40,9 +43,11 @@ import net.corda.testing.services.MockAttachmentStorage
|
||||
import java.security.KeyPair
|
||||
import java.sql.Connection
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import java.util.function.Consumer
|
||||
import javax.persistence.EntityManager
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
/**
|
||||
* Returns a simple [InMemoryIdentityService] containing the supplied [identities].
|
||||
@ -101,7 +106,7 @@ open class MockServices private constructor(
|
||||
fun makeTestDatabaseAndMockServices(cordappPackages: List<String>,
|
||||
identityService: IdentityService,
|
||||
initialIdentity: TestIdentity,
|
||||
networkParameters: NetworkParameters = testNetworkParameters(),
|
||||
networkParameters: NetworkParameters = testNetworkParameters(modifiedTime = Instant.MIN),
|
||||
vararg moreKeys: KeyPair): Pair<CordaPersistence, MockServices> {
|
||||
|
||||
val cordappLoader = cordappLoaderForPackages(cordappPackages)
|
||||
@ -111,7 +116,7 @@ open class MockServices private constructor(
|
||||
val mockService = database.transaction {
|
||||
object : MockServices(cordappLoader, identityService, networkParameters, initialIdentity, moreKeys) {
|
||||
override val vaultService: VaultService = makeVaultService(schemaService, database)
|
||||
|
||||
override val networkParametersStorage: NetworkParametersStorage get() = MockNetworkParametersStorage(networkParameters)
|
||||
override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable<SignedTransaction>) {
|
||||
ServiceHubInternal.recordTransactions(statesToRecord, txs,
|
||||
validatedTransactions as WritableTransactionStorage,
|
||||
@ -161,7 +166,7 @@ open class MockServices private constructor(
|
||||
initialIdentity: TestIdentity,
|
||||
identityService: IdentityService = makeTestIdentityService(),
|
||||
vararg moreKeys: KeyPair) :
|
||||
this(cordappLoaderForPackages(cordappPackages), identityService, testNetworkParameters(), initialIdentity, moreKeys)
|
||||
this(cordappLoaderForPackages(cordappPackages), identityService, testNetworkParameters(modifiedTime = Instant.MIN), initialIdentity, moreKeys)
|
||||
|
||||
constructor(cordappPackages: Iterable<String>,
|
||||
initialIdentity: TestIdentity,
|
||||
@ -249,15 +254,14 @@ open class MockServices private constructor(
|
||||
}
|
||||
override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(2)
|
||||
private val mockCordappProvider: MockCordappProvider = MockCordappProvider(cordappLoader, attachments).also {
|
||||
it.start( networkParameters.whitelistedContractImplementations)
|
||||
it.start(networkParameters.whitelistedContractImplementations)
|
||||
}
|
||||
override val cordappProvider: CordappProvider get() = mockCordappProvider
|
||||
override val networkParametersStorage: NetworkParametersStorage get() = MockNetworkParametersStorage(networkParameters)
|
||||
|
||||
protected val servicesForResolution: ServicesForResolution
|
||||
get() {
|
||||
return ServicesForResolutionImpl(identityService, attachments, cordappProvider, validatedTransactions).also {
|
||||
it.start(networkParameters)
|
||||
}
|
||||
return ServicesForResolutionImpl(identityService, attachments, cordappProvider, networkParametersStorage, validatedTransactions)
|
||||
}
|
||||
|
||||
internal fun makeVaultService(schemaService: SchemaService, database: CordaPersistence): VaultServiceInternal {
|
||||
@ -315,4 +319,4 @@ fun <T : SerializeAsToken> createMockCordaService(serviceHub: MockServices, serv
|
||||
}
|
||||
}
|
||||
return MockAppServiceHubImpl(serviceHub, serviceConstructor).serviceInstance
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
package net.corda.testing.node.internal
|
||||
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.internal.SignedDataWithCert
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.node.internal.NetworkParametersStorageInternal
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import java.time.Instant
|
||||
|
||||
class MockNetworkParametersStorage(val currentParameters: NetworkParameters = testNetworkParameters(modifiedTime = Instant.MIN)) : NetworkParametersStorageInternal {
|
||||
private val hashToParametersMap: HashMap<SecureHash, NetworkParameters> = HashMap()
|
||||
|
||||
init {
|
||||
hashToParametersMap[currentHash] = currentParameters
|
||||
}
|
||||
|
||||
override val currentHash: SecureHash get() = currentParameters.serialize().hash
|
||||
override val defaultHash: SecureHash get() = currentHash
|
||||
override fun getEpochFromHash(hash: SecureHash): Int? = lookup(hash)?.epoch
|
||||
override fun lookup(hash: SecureHash): NetworkParameters? = hashToParametersMap[hash]
|
||||
override fun saveParameters(signedNetworkParameters: SignedDataWithCert<NetworkParameters>) {
|
||||
val networkParameters = signedNetworkParameters.verified()
|
||||
val hash = signedNetworkParameters.raw.hash
|
||||
hashToParametersMap[hash] = networkParameters
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ import net.corda.nodeapi.internal.config.toConfig
|
||||
import net.corda.nodeapi.internal.network.NetworkParametersCopier
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.IntegrationTest
|
||||
import net.corda.testing.internal.testThreadFactory
|
||||
import net.corda.testing.node.User
|
||||
@ -54,7 +54,7 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
|
||||
|
||||
private val nodes = mutableListOf<NodeWithInfo>()
|
||||
private val nodeInfos = mutableListOf<NodeInfo>()
|
||||
private val portAllocation = PortAllocation.Incremental(10000)
|
||||
private val portAllocation = incrementalPortAllocation(10000)
|
||||
|
||||
init {
|
||||
System.setProperty("consoleLogLevel", Level.DEBUG.name().toLowerCase())
|
||||
|
@ -28,6 +28,7 @@ import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.MAX_MESSAGE_SIZE
|
||||
import net.corda.testing.driver.JmxPolicy
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.TestingNamedCacheFactory
|
||||
import net.corda.testing.internal.fromUserList
|
||||
import net.corda.testing.node.NotarySpec
|
||||
@ -102,8 +103,8 @@ val rpcTestUser = User("user1", "test", permissions = emptySet())
|
||||
val fakeNodeLegalName = CordaX500Name(organisation = "Not:a:real:name", locality = "Nowhere", country = "GB")
|
||||
|
||||
// Use a global pool so that we can run RPC tests in parallel
|
||||
private val globalPortAllocation = PortAllocation.Incremental(10000)
|
||||
private val globalDebugPortAllocation = PortAllocation.Incremental(5005)
|
||||
private val globalPortAllocation = incrementalPortAllocation(10000)
|
||||
private val globalDebugPortAllocation = incrementalPortAllocation(5005)
|
||||
|
||||
fun <A> rpcDriver(
|
||||
isDebug: Boolean = false,
|
||||
|
@ -155,7 +155,7 @@ fun createWireTransaction(inputs: List<StateRef>,
|
||||
notary: Party?,
|
||||
timeWindow: TimeWindow?,
|
||||
privacySalt: PrivacySalt = PrivacySalt()): WireTransaction {
|
||||
val componentGroups = createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow, emptyList())
|
||||
val componentGroups = createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow, emptyList(), null)
|
||||
return WireTransaction(componentGroups, privacySalt)
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ import net.corda.sample.businessnetwork.membership.flow.ObtainMembershipListCont
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.driver.*
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.node.User
|
||||
import net.corda.testing.node.internal.FINANCE_CORDAPP
|
||||
import net.corda.testing.node.internal.BUSINESS_NETWORK_CORDAPP
|
||||
@ -77,7 +78,7 @@ class ExplorerSimulation(private val options: OptionSet) {
|
||||
}
|
||||
|
||||
private fun startDemoNodes() {
|
||||
val portAllocation = PortAllocation.Incremental(20000)
|
||||
val portAllocation = incrementalPortAllocation(20000)
|
||||
driver(DriverParameters(
|
||||
portAllocation = portAllocation,
|
||||
cordappsForAllNodes = listOf(FINANCE_CORDAPP, BUSINESS_NETWORK_CORDAPP),
|
||||
|
@ -4,7 +4,7 @@ import com.google.common.util.concurrent.RateLimiter
|
||||
import net.corda.client.mock.Generator
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.core.utilities.toBase58String
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import java.util.*
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@ -170,7 +170,7 @@ fun runLoadTests(configuration: LoadTestConfiguration, tests: List<Pair<LoadTest
|
||||
}
|
||||
}
|
||||
|
||||
connectToNodes(remoteNodes, PortAllocation.Incremental(configuration.localTunnelStartingPort)) { connections ->
|
||||
connectToNodes(remoteNodes, incrementalPortAllocation(configuration.localTunnelStartingPort)) { connections ->
|
||||
log.info("Connected to all nodes!")
|
||||
val hostNodeMap = ConcurrentHashMap<String, NodeConnection>()
|
||||
connections.parallelStream().forEach { connection ->
|
||||
|
Reference in New Issue
Block a user