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:
Michele Sollecito
2018-11-27 16:55:40 +00:00
100 changed files with 1031 additions and 328 deletions

View File

@ -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()

View File

@ -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>

View File

@ -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)

View File

@ -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)

View File

@ -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() {

View File

@ -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))

View File

@ -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)
}

View File

@ -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>() }
@ -27,7 +29,8 @@ class TransactionVerificationRequest(val wtxToVerify: SerializedBytes<WireTransa
resolveIdentity = { null },
resolveAttachment = { attachmentMap[it] },
resolveStateRef = { deps[it.txhash]?.outputs?.get(it.index) },
resolveContractAttachment = { contractAttachmentMap[it.contract]?.id }
resolveContractAttachment = { contractAttachmentMap[it.contract]?.id },
resolveParameters = { networkParameters.deserialize() }
)
}
}

View File

@ -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.
}

View File

@ -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.

View File

@ -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()

View File

@ -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))

View File

@ -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()
}

View File

@ -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) :

View File

@ -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
}

View File

@ -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) {

View File

@ -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

View File

@ -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?
}

View File

@ -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()

View File

@ -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

View File

@ -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.")

View File

@ -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)

View File

@ -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
)
}
}

View File

@ -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

View File

@ -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
)
}

View File

@ -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()
}

View File

@ -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).
}

View File

@ -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 {

View File

@ -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) }
}
}

View File

@ -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

View File

@ -176,7 +176,7 @@ class TransactionTests {
notary,
timeWindow,
privacySalt,
null,
testNetworkParameters(),
emptyList()
)

View File

@ -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 {

View File

@ -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(

View File

@ -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"),

View File

@ -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"),

View File

@ -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>

View File

@ -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)

View File

@ -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>()

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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"

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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()))

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -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

View File

@ -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<*> {

View File

@ -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()

View File

@ -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(

View File

@ -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"

View File

@ -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}")

View File

@ -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)
}
/**

View File

@ -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?")
}
}

View File

@ -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

View File

@ -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
) {

View File

@ -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 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
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 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,
@ -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
}
}

View File

@ -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
}
}
}
}
}

View File

@ -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)

View File

@ -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(
lateinit var mockNet: MockNetwork
lateinit var services: MockServices
lateinit var database: CordaPersistence
@Before
fun setUp() {
mockNet = MockNetwork(cordapps)
val (db, mockServices) = MockServices.makeTestDatabaseAndMockServices(
cordappPackages = cordapps,
identityService = makeTestIdentityService(myself.identity),
initialIdentity = myself,
networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
)
val services: MockServices = databaseAndServices.second
val database: CordaPersistence = databaseAndServices.first
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()
}
}

View File

@ -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)
}
}
}

View File

@ -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()

View File

@ -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

View File

@ -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))
}
}

View File

@ -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 {

View File

@ -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,7 +38,13 @@ class ExternalIdMappingTest {
private val myself = TestIdentity(CordaX500Name("Me", "London", "GB"))
private val notary = TestIdentity(CordaX500Name("NotaryService", "London", "GB"), 1337L)
private val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(
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)
@ -47,9 +54,9 @@ class ExternalIdMappingTest {
initialIdentity = myself,
networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
)
private val services: MockServices = databaseAndServices.second
private val database: CordaPersistence = databaseAndServices.first
services = mockServices
database = db
}
private fun freshKeyForExternalId(externalId: UUID): AnonymousParty {
val anonymousParty = freshKey()

View File

@ -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 {

View File

@ -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()

View File

@ -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"))

View File

@ -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"} "

View File

@ -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))

View File

@ -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,

View File

@ -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"),

View File

@ -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)
}

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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())

View File

@ -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,

View File

@ -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)
}

View File

@ -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),

View File

@ -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 ->