CORDA-961 Wire up and enforce max transaction size (#2465)

* wire up and enforce max transaction size

* fixup after rebase
moved network parameter from AbstractNode to NodeProperties

* removed TODO

* fix broken import

* address PR issues

* remove API breaking change
address PR issue

* added max transaction size to driver and mock network.
address PR issues

* fix failing test

* added TODO

* fix verifier test

* fix spring driver build error
This commit is contained in:
Patrick Kuo 2018-02-09 14:48:45 +00:00 committed by GitHub
parent 1902a4f11e
commit c8cf46c657
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 251 additions and 35 deletions

View File

@ -280,6 +280,7 @@ public static final class net.corda.core.contracts.AmountTransfer$Companion exte
@net.corda.core.serialization.CordaSerializable public interface net.corda.core.contracts.Attachment extends net.corda.core.contracts.NamedByHash
public abstract void extractFile(String, java.io.OutputStream)
@org.jetbrains.annotations.NotNull public abstract List getSigners()
public abstract int getSize()
@org.jetbrains.annotations.NotNull public abstract java.io.InputStream open()
@org.jetbrains.annotations.NotNull public abstract jar.JarInputStream openAsJAR()
##
@ -347,6 +348,7 @@ public final class net.corda.core.contracts.ComponentGroupEnum extends java.lang
@org.jetbrains.annotations.NotNull public final String getContract()
@org.jetbrains.annotations.NotNull public net.corda.core.crypto.SecureHash getId()
@org.jetbrains.annotations.NotNull public List getSigners()
public int getSize()
@org.jetbrains.annotations.NotNull public java.io.InputStream open()
@org.jetbrains.annotations.NotNull public jar.JarInputStream openAsJAR()
##
@ -3584,7 +3586,7 @@ public static final class net.corda.client.jackson.StringToMethodCallParser$Unpa
##
public final class net.corda.testing.driver.Driver extends java.lang.Object
public static final Object driver(net.corda.testing.driver.DriverParameters, kotlin.jvm.functions.Function1)
public static final Object driver(net.corda.testing.driver.DriverParameters, boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, Map, boolean, boolean, boolean, boolean, List, List, net.corda.testing.driver.JmxPolicy, kotlin.jvm.functions.Function1)
public static final Object driver(net.corda.testing.driver.DriverParameters, boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, Map, boolean, boolean, boolean, boolean, List, List, net.corda.testing.driver.JmxPolicy, int, kotlin.jvm.functions.Function1)
##
@net.corda.core.DoNotImplement public interface net.corda.testing.driver.DriverDSL
@org.jetbrains.annotations.NotNull public abstract java.nio.file.Path baseDirectory(net.corda.core.identity.CordaX500Name)
@ -3599,11 +3601,12 @@ public final class net.corda.testing.driver.Driver extends java.lang.Object
##
public final class net.corda.testing.driver.DriverParameters extends java.lang.Object
public <init>()
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, Map, boolean, boolean, boolean, boolean, List, List, net.corda.testing.driver.JmxPolicy)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, Map, boolean, boolean, boolean, boolean, List, List, net.corda.testing.driver.JmxPolicy, int)
public final boolean component1()
@org.jetbrains.annotations.NotNull public final List component10()
@org.jetbrains.annotations.NotNull public final List component11()
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.JmxPolicy component12()
public final int component13()
@org.jetbrains.annotations.NotNull public final java.nio.file.Path component2()
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.PortAllocation component3()
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.PortAllocation component4()
@ -3612,13 +3615,14 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
public final boolean component7()
public final boolean component8()
public final boolean component9()
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, Map, boolean, boolean, boolean, boolean, List, List, net.corda.testing.driver.JmxPolicy)
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, Map, boolean, boolean, boolean, boolean, List, List, net.corda.testing.driver.JmxPolicy, int)
public boolean equals(Object)
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.PortAllocation getDebugPortAllocation()
@org.jetbrains.annotations.NotNull public final java.nio.file.Path getDriverDirectory()
@org.jetbrains.annotations.NotNull public final List getExtraCordappPackagesToScan()
public final boolean getInitialiseSerialization()
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.JmxPolicy getJmxPolicy()
public final int getMaxTransactionSize()
@org.jetbrains.annotations.NotNull public final List getNotarySpecs()
@org.jetbrains.annotations.NotNull public final net.corda.testing.driver.PortAllocation getPortAllocation()
public final boolean getStartNodesInProcess()
@ -3892,7 +3896,7 @@ public final class net.corda.testing.node.MockKeyManagementService extends net.c
public class net.corda.testing.node.MockNetwork extends java.lang.Object
public <init>(List)
public <init>(List, net.corda.testing.node.MockNetworkParameters)
public <init>(List, net.corda.testing.node.MockNetworkParameters, boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, kotlin.jvm.functions.Function1, boolean, List)
public <init>(List, net.corda.testing.node.MockNetworkParameters, boolean, boolean, net.corda.testing.node.InMemoryMessagingNetwork$ServicePeerAllocationStrategy, kotlin.jvm.functions.Function1, boolean, List, int)
@org.jetbrains.annotations.NotNull public final net.corda.testing.node.MockNetwork$MockNode addressToNode(net.corda.core.messaging.MessageRecipients)
@org.jetbrains.annotations.NotNull public final java.nio.file.Path baseDirectory(int)
@org.jetbrains.annotations.NotNull public final net.corda.node.internal.StartedNode createNode(net.corda.testing.node.MockNodeParameters)

View File

@ -50,4 +50,9 @@ interface Attachment : NamedByHash {
* Can be empty, for example non-contract attachments won't be necessarily be signed.
*/
val signers: List<Party>
/**
* Attachment size in bytes.
*/
val size: Int
}

View File

@ -27,6 +27,10 @@ abstract class AbstractAttachment(dataLoader: () -> ByteArray) : Attachment {
}
protected val attachmentData: ByteArray by lazy(dataLoader)
// TODO: read file size information from metadata instead of loading the data.
override val size: Int get() = attachmentData.size
override fun open(): InputStream = attachmentData.inputStream()
override val signers by lazy {
// Can't start with empty set if we're doing intersections. Logically the null means "all possible signers":

View File

@ -0,0 +1,14 @@
package net.corda.core.internal
import net.corda.core.node.NetworkParameters
// TODO: This will cause problems when we run tests in parallel, make each node have its own properties.
object GlobalProperties {
private var _networkParameters: NetworkParameters? = null
var networkParameters: NetworkParameters
get() = checkNotNull(_networkParameters) { "Property 'networkParameters' has not been initialised." }
set(value) {
_networkParameters = value
}
}

View File

@ -17,7 +17,6 @@ import java.time.Instant
*/
// TODO Add eventHorizon - how many days a node can be offline before being automatically ejected from the network.
// It needs separate design.
// TODO Currently maxTransactionSize is not wired.
@CordaSerializable
data class NetworkParameters(
val minimumPlatformVersion: Int,

View File

@ -5,6 +5,7 @@ import net.corda.core.contracts.ComponentGroupEnum.*
import net.corda.core.crypto.*
import net.corda.core.identity.Party
import net.corda.core.internal.Emoji
import net.corda.core.internal.GlobalProperties
import net.corda.core.node.ServicesForResolution
import net.corda.core.node.services.AttachmentId
import net.corda.core.serialization.CordaSerializable
@ -118,7 +119,24 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
val contractAttachments = findAttachmentContracts(resolvedInputs, resolveContractAttachment, resolveAttachment)
// Order of attachments is important since contracts may refer to indexes so only append automatic attachments
val attachments = (attachments.map { resolveAttachment(it) ?: throw AttachmentResolutionException(it) } + contractAttachments).distinct()
return LedgerTransaction(resolvedInputs, outputs, authenticatedArgs, attachments, id, notary, timeWindow, privacySalt)
val ltx = LedgerTransaction(resolvedInputs, outputs, authenticatedArgs, attachments, id, notary, timeWindow, privacySalt)
checkTransactionSize(ltx)
return ltx
}
private fun checkTransactionSize(ltx: LedgerTransaction) {
var remainingTransactionSize = GlobalProperties.networkParameters.maxTransactionSize
fun minus(size: Int) {
require(remainingTransactionSize > size) { "Transaction exceeded network's maximum transaction size limit : ${GlobalProperties.networkParameters.maxTransactionSize} bytes." }
remainingTransactionSize -= size
}
// Check attachment size first as they are most likely to go over the limit.
ltx.attachments.forEach { minus(it.size) }
minus(ltx.inputs.serialize().size)
minus(ltx.commands.serialize().size)
minus(ltx.outputs.serialize().size)
}
/**

View File

@ -31,6 +31,7 @@ class AttachmentTest {
override val id get() = throw UnsupportedOperationException()
override fun open() = inputStream
override val signers get() = throw UnsupportedOperationException()
override val size: Int = 512
}
try {
attachment.openAsJAR()

View File

@ -114,6 +114,7 @@ class AttachmentSerializationTest {
private class CustomAttachment(override val id: SecureHash, internal val customContent: String) : Attachment {
override fun open() = throw UnsupportedOperationException("Not implemented.")
override val signers get() = throw UnsupportedOperationException()
override val size get() = throw UnsupportedOperationException()
}
private class CustomAttachmentLogic(serverIdentity: Party, private val attachmentId: SecureHash, private val customContent: String) : ClientLogic(serverIdentity) {

View File

@ -75,6 +75,9 @@ UNRELEASED
* Moved ``NodeInfoSchema`` to internal package as the node info's database schema is not part of the public API. This
was needed to allow changes to the schema.
* Introduced max transaction size limit on transactions. The max transaction size parameter is set by the compatibility zone
operator. The parameter is distributed to Corda nodes by network map service as part of the ``NetworkParameters``.
* Support for external user credentials data source and password encryption [CORDA-827].
* Exporting additional JMX metrics (artemis, hibernate statistics) and loading Jolokia agent at JVM startup when using

View File

@ -71,6 +71,7 @@ The current set of network parameters:
:maxMessageSize: Maximum allowed size in bytes of an individual message sent over the wire. Note that attachments are
a special case and may be fragmented for streaming transfer, however, an individual transaction or flow message
may not be larger than this value.
:maxTransactionSize: Maximum allowed size in bytes of a transaction. This is the size of the transaction object and its attachments.
:modifiedTime: The time when the network parameters were last modified by the compatibility zone operator.
:epoch: Version number of the network parameters. Starting from 1, this will always increment whenever any of the
parameters change.

View File

@ -13,13 +13,19 @@ import net.corda.core.flows.*
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.*
import net.corda.core.internal.FlowStateMachine
import net.corda.core.internal.GlobalProperties
import net.corda.core.internal.VisibleForTesting
import net.corda.core.internal.concurrent.map
import net.corda.core.internal.concurrent.openFuture
import net.corda.core.internal.uncheckedCast
import net.corda.core.messaging.*
import net.corda.core.node.*
import net.corda.core.node.services.*
import net.corda.core.serialization.*
import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.serialization.SerializeAsToken
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.serialization.serialize
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.debug
@ -118,7 +124,6 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
// low-performance prototyping period.
protected abstract val serverThread: AffinityExecutor
protected lateinit var networkParameters: NetworkParameters
private val cordappServices = MutableClassToInstanceMap.create<SerializeAsToken>()
private val flowFactories = ConcurrentHashMap<Class<out FlowLogic<*>>, InitiatedFlowFactory<*>>()
@ -166,7 +171,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
initCertificate()
val schemaService = NodeSchemaService(cordappLoader.cordappSchemas)
val (identity, identityKeyPair) = obtainIdentity(notaryConfig = null)
return initialiseDatabasePersistence(schemaService, makeIdentityService(identity.certificate)) { database ->
return initialiseDatabasePersistence(schemaService, makeIdentityService(identity.certificate)) { database ->
// TODO The fact that we need to specify an empty list of notaries just to generate our node info looks like
// a code smell.
val persistentNetworkMapCache = PersistentNetworkMapCache(database, notaries = emptyList())
@ -189,13 +194,13 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
val (identity, identityKeyPair) = obtainIdentity(notaryConfig = null)
val identityService = makeIdentityService(identity.certificate)
networkMapClient = configuration.compatibilityZoneURL?.let { NetworkMapClient(it, identityService.trustRoot) }
networkParameters = NetworkParametersReader(identityService.trustRoot, networkMapClient, configuration.baseDirectory).networkParameters
check(networkParameters.minimumPlatformVersion <= versionInfo.platformVersion) {
GlobalProperties.networkParameters = NetworkParametersReader(identityService.trustRoot, networkMapClient, configuration.baseDirectory).networkParameters
check(GlobalProperties.networkParameters.minimumPlatformVersion <= versionInfo.platformVersion) {
"Node's platform version is lower than network's required minimumPlatformVersion"
}
// Do all of this in a database transaction so anything that might need a connection has one.
val (startedImpl, schedulerService) = initialiseDatabasePersistence(schemaService, identityService) { database ->
val networkMapCache = NetworkMapCacheImpl(PersistentNetworkMapCache(database, networkParameters.notaries).start(), identityService)
val networkMapCache = NetworkMapCacheImpl(PersistentNetworkMapCache(database, GlobalProperties.networkParameters.notaries).start(), identityService)
val (keyPairs, info) = initNodeInfo(networkMapCache, identity, identityKeyPair)
identityService.loadIdentities(info.legalIdentitiesAndCerts)
val transactionStorage = makeTransactionStorage(database, configuration.transactionCacheSizeBytes)
@ -234,7 +239,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
networkMapUpdater = NetworkMapUpdater(services.networkMapCache,
NodeInfoWatcher(configuration.baseDirectory, getRxIoScheduler(), Duration.ofMillis(configuration.additionalNodeInfoPollingFrequencyMsec)),
networkMapClient,
networkParameters.serialize().hash,
GlobalProperties.networkParameters.serialize().hash,
configuration.baseDirectory)
runOnStop += networkMapUpdater::close
@ -520,7 +525,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
* Builds node internal, advertised, and plugin services.
* Returns a list of tokenizable services to be added to the serialisation context.
*/
private fun makeServices(keyPairs: Set<KeyPair>, schemaService: SchemaService, transactionStorage: WritableTransactionStorage, database: CordaPersistence, info: NodeInfo, identityService: IdentityServiceInternal, networkMapCache: NetworkMapCacheInternal): MutableList<Any> {
private fun makeServices(keyPairs: Set<KeyPair>, schemaService: SchemaService, transactionStorage: WritableTransactionStorage, database: CordaPersistence, info: NodeInfo, identityService: IdentityServiceInternal, networkMapCache: NetworkMapCacheInternal): MutableList<Any> {
checkpointStorage = DBCheckpointStorage()
val metrics = MetricRegistry()
attachments = NodeAttachmentService(metrics, configuration.attachmentContentCacheSizeBytes, configuration.attachmentCacheBound)

View File

@ -2,6 +2,7 @@ package net.corda.node.internal
import com.codahale.metrics.JmxReporter
import net.corda.core.concurrent.CordaFuture
import net.corda.core.internal.GlobalProperties.networkParameters
import net.corda.core.internal.concurrent.openFuture
import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.internal.div

View File

@ -0,0 +1,135 @@
package net.corda.node.services.transactions
import co.paralleluniverse.fibers.Suspendable
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.*
import net.corda.core.identity.Party
import net.corda.core.internal.InputStreamAndHash
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow
import net.corda.node.services.api.StartedNodeServices
import net.corda.testing.contracts.DummyContract
import net.corda.testing.contracts.DummyState
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.dummyCommand
import net.corda.testing.core.singleIdentity
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.startFlow
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class MaxTransactionSizeTests {
private lateinit var mockNet: MockNetwork
private lateinit var notaryServices: StartedNodeServices
private lateinit var aliceServices: StartedNodeServices
private lateinit var notary: Party
private lateinit var alice: Party
private lateinit var bob: Party
@Before
fun setup() {
mockNet = MockNetwork(listOf("net.corda.testing.contracts", "net.corda.node.services.transactions"), maxTransactionSize = 3_000_000)
val aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME))
val bobNode = mockNet.createNode(MockNodeParameters(legalName = BOB_NAME))
notaryServices = mockNet.defaultNotaryNode.services
aliceServices = aliceNode.services
notary = mockNet.defaultNotaryIdentity
alice = aliceNode.info.singleIdentity()
bob = bobNode.info.singleIdentity()
}
@After
fun cleanUp() {
mockNet.stopNodes()
}
@Test
fun `check transaction will fail when exceed max transaction size limit`() {
// These 4 attachments yield a transaction that's got ~ 4mb, which will exceed the 3mb max transaction size limit
val bigFile1 = InputStreamAndHash.createInMemoryTestZip(1024 * 1024, 0)
val bigFile2 = InputStreamAndHash.createInMemoryTestZip(1024 * 1024, 1)
val bigFile3 = InputStreamAndHash.createInMemoryTestZip(1024 * 1024, 2)
val bigFile4 = InputStreamAndHash.createInMemoryTestZip(1024 * 1024, 3)
val flow = aliceServices.database.transaction {
val hash1 = aliceServices.attachments.importAttachment(bigFile1.inputStream)
val hash2 = aliceServices.attachments.importAttachment(bigFile2.inputStream)
val hash3 = aliceServices.attachments.importAttachment(bigFile3.inputStream)
val hash4 = aliceServices.attachments.importAttachment(bigFile4.inputStream)
assertEquals(hash1, bigFile1.sha256)
SendLargeTransactionFlow(notary, bob, hash1, hash2, hash3, hash4)
}
val exception = assertFailsWith<IllegalArgumentException> {
val future = aliceServices.startFlow(flow)
mockNet.runNetwork()
future.getOrThrow()
}
assertThat(exception).hasMessageContaining("Transaction exceeded network's maximum transaction size limit")
}
@Test
fun `check transaction will be rejected by counterparty when exceed max transaction size limit`() {
// These 4 attachments yield a transaction that's got ~ 4mb, which will exceed the 3mb max transaction size limit
val bigFile1 = InputStreamAndHash.createInMemoryTestZip(1024 * 1024, 0)
val bigFile2 = InputStreamAndHash.createInMemoryTestZip(1024 * 1024, 1)
val bigFile3 = InputStreamAndHash.createInMemoryTestZip(1024 * 1024, 2)
val bigFile4 = InputStreamAndHash.createInMemoryTestZip(1024 * 1024, 3)
val flow = aliceServices.database.transaction {
val hash1 = aliceServices.attachments.importAttachment(bigFile1.inputStream)
val hash2 = aliceServices.attachments.importAttachment(bigFile2.inputStream)
val hash3 = aliceServices.attachments.importAttachment(bigFile3.inputStream)
val hash4 = aliceServices.attachments.importAttachment(bigFile4.inputStream)
assertEquals(hash1, bigFile1.sha256)
SendLargeTransactionFlow(notary, bob, hash1, hash2, hash3, hash4, verify = false)
}
val ex = assertFailsWith<UnexpectedFlowEndException> {
val future = aliceServices.startFlow(flow)
mockNet.runNetwork()
future.getOrThrow()
}
assertThat(ex).hasMessageContaining("Counterparty flow on O=Bob Plc, L=Rome, C=IT had an internal error and has terminated")
}
@StartableByRPC
@InitiatingFlow
class SendLargeTransactionFlow(private val notary: Party,
private val otherSide: Party,
private val hash1: SecureHash,
private val hash2: SecureHash,
private val hash3: SecureHash,
private val hash4: SecureHash,
private val verify: Boolean = true) : FlowLogic<Unit>() {
@Suspendable
override fun call() {
val tx = TransactionBuilder(notary = notary)
.addOutputState(DummyState(), DummyContract.PROGRAM_ID)
.addCommand(dummyCommand(ourIdentity.owningKey))
.addAttachment(hash1)
.addAttachment(hash2)
.addAttachment(hash3)
.addAttachment(hash4)
val stx = serviceHub.signInitialTransaction(tx, ourIdentity.owningKey)
if (verify) stx.verify(serviceHub, checkSufficientSignatures = false)
// Send to the other side and wait for it to trigger resolution from us.
val otherSideSession = initiateFlow(otherSide)
subFlow(SendTransactionFlow(otherSideSession, stx))
otherSideSession.receive<Unit>()
}
}
@InitiatedBy(SendLargeTransactionFlow::class)
@Suppress("UNUSED")
class ReceiveLargeTransactionFlow(private val otherSide: FlowSession) : FlowLogic<Unit>() {
@Suspendable
override fun call() {
subFlow(ReceiveTransactionFlow(otherSide))
// Unblock the other side by sending some dummy object (Unit is fine here as it's a singleton).
otherSide.send(Unit)
}
}
}

View File

@ -29,6 +29,7 @@ fun <A> springDriver(
startNodesInProcess: Boolean = defaultParameters.startNodesInProcess,
notarySpecs: List<NotarySpec> = defaultParameters.notarySpecs,
extraCordappPackagesToScan: List<String> = defaultParameters.extraCordappPackagesToScan,
maxTransactionSize: Int = defaultParameters.maxTransactionSize,
dsl: SpringBootDriverDSL.() -> A
): A {
return genericDriver(
@ -44,6 +45,7 @@ fun <A> springDriver(
extraCordappPackagesToScan = extraCordappPackagesToScan,
notarySpecs = notarySpecs,
driverDslWrapper = { driverDSL: DriverDSLImpl -> SpringBootDriverDSL(driverDSL) },
maxTransactionSize = maxTransactionSize,
coerce = { it }, dsl = dsl
)
}

View File

@ -147,7 +147,7 @@ data class NodeParameters(
data class JmxPolicy(val startJmxHttpServer: Boolean = false,
val jmxHttpServerPortAllocation: PortAllocation? =
if (startJmxHttpServer) PortAllocation.Incremental(7005) else null)
if (startJmxHttpServer) PortAllocation.Incremental(7005) else null)
/**
* [driver] allows one to start up nodes like this:
@ -174,7 +174,7 @@ data class JmxPolicy(val startJmxHttpServer: Boolean = false,
* @param useTestClock If true the test clock will be used in Node.
* @param startNodesInProcess Provides the default behaviour of whether new nodes should start inside this process or
* not. Note that this may be overridden in [DriverDSL.startNode].
* @param waitForAllNodesToFinish If true, the nodes will not shut down automatically after executing the code in the driver DSL block.
* @param waitForAllNodesToFinish If true, the nodes will not shut down automatically after executing the code in the driver DSL block.
* It will wait for them to be shut down externally instead.
* @param notarySpecs The notaries advertised for this network. These nodes will be started automatically and will be
* available from [DriverDSL.notaryHandles]. Defaults to a simple validating notary.
@ -198,6 +198,7 @@ fun <A> driver(
notarySpecs: List<NotarySpec> = defaultParameters.notarySpecs,
extraCordappPackagesToScan: List<String> = defaultParameters.extraCordappPackagesToScan,
jmxPolicy: JmxPolicy = defaultParameters.jmxPolicy,
maxTransactionSize: Int = defaultParameters.maxTransactionSize,
dsl: DriverDSL.() -> A
): A {
return genericDriver(
@ -213,7 +214,8 @@ fun <A> driver(
notarySpecs = notarySpecs,
extraCordappPackagesToScan = extraCordappPackagesToScan,
jmxPolicy = jmxPolicy,
compatibilityZone = null
compatibilityZone = null,
maxTransactionSize = maxTransactionSize
),
coerce = { it },
dsl = dsl,
@ -249,7 +251,8 @@ data class DriverParameters(
val waitForAllNodesToFinish: Boolean = false,
val notarySpecs: List<NotarySpec> = listOf(NotarySpec(DUMMY_NOTARY_NAME)),
val extraCordappPackagesToScan: List<String> = emptyList(),
val jmxPolicy: JmxPolicy = JmxPolicy()
val jmxPolicy: JmxPolicy = JmxPolicy(),
val maxTransactionSize: Int = Int.MAX_VALUE
) {
fun setIsDebug(isDebug: Boolean) = copy(isDebug = isDebug)
fun setDriverDirectory(driverDirectory: Path) = copy(driverDirectory = driverDirectory)

View File

@ -19,6 +19,7 @@ import net.corda.core.messaging.MessageRecipients
import net.corda.core.messaging.RPCOps
import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.NodeInfo
import net.corda.core.node.NotaryInfo
import net.corda.core.node.services.IdentityService
import net.corda.core.node.services.KeyManagementService
import net.corda.core.serialization.SerializationWhitelist
@ -42,16 +43,15 @@ import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
import net.corda.nodeapi.internal.DevIdentityGenerator
import net.corda.nodeapi.internal.config.User
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.core.node.NotaryInfo
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.core.setGlobalSerialization
import net.corda.testing.internal.rigorousMock
import net.corda.testing.internal.testThreadFactory
import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.core.setGlobalSerialization
import org.apache.activemq.artemis.utils.ReusableLatch
import org.apache.sshd.common.util.security.SecurityUtils
import rx.internal.schedulers.CachedThreadScheduler
@ -133,7 +133,8 @@ open class MockNetwork(private val cordappPackages: List<String>,
servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy = defaultParameters.servicePeerAllocationStrategy,
private val defaultFactory: (MockNodeArgs) -> MockNode = defaultParameters.defaultFactory,
initialiseSerialization: Boolean = defaultParameters.initialiseSerialization,
private val notarySpecs: List<NotarySpec> = defaultParameters.notarySpecs) {
private val notarySpecs: List<NotarySpec> = defaultParameters.notarySpecs,
maxTransactionSize: Int = Int.MAX_VALUE) {
/** Helper constructor for creating a [MockNetwork] with custom parameters from Java. */
@JvmOverloads
constructor(cordappPackages: List<String>, parameters: MockNetworkParameters = MockNetworkParameters()) : this(cordappPackages, defaultParameters = parameters)
@ -228,7 +229,7 @@ open class MockNetwork(private val cordappPackages: List<String>,
filesystem.getPath("/nodes").createDirectory()
val notaryInfos = generateNotaryIdentities()
// The network parameters must be serialised before starting any of the nodes
networkParameters = NetworkParametersCopier(testNetworkParameters(notaryInfos))
networkParameters = NetworkParametersCopier(testNetworkParameters(notaryInfos, maxTransactionSize = maxTransactionSize))
@Suppress("LeakingThis")
notaryNodes = createNotaries()
} catch (t: Throwable) {

View File

@ -6,6 +6,7 @@ import net.corda.core.crypto.*
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.GlobalProperties
import net.corda.core.messaging.DataFeed
import net.corda.core.messaging.FlowHandle
import net.corda.core.messaging.FlowProgressHandle
@ -31,6 +32,7 @@ import net.corda.node.services.vault.NodeVaultService
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.nodeapi.internal.persistence.HibernateConfiguration
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.DEV_ROOT_CA
import net.corda.testing.core.TestIdentity
import net.corda.testing.services.MockAttachmentStorage

View File

@ -9,11 +9,13 @@ import net.corda.core.context.InvocationContext
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.internal.GlobalProperties
import net.corda.core.node.ServiceHub
import net.corda.core.serialization.internal.effectiveSerializationEnv
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow
import net.corda.node.services.api.StartedNodeServices
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.core.TestIdentity
import net.corda.testing.core.chooseIdentity
@ -34,6 +36,7 @@ fun ServiceHub.ledger(
false
}
return LedgerDSL(TestLedgerDSLInterpreter(this), notary).apply {
GlobalProperties.networkParameters = testNetworkParameters(emptyList())
if (serializationExists) {
script()
} else {

View File

@ -14,6 +14,7 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.*
import net.corda.core.internal.concurrent.*
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.node.NotaryInfo
import net.corda.core.node.services.NetworkMapCache
import net.corda.core.serialization.deserialize
import net.corda.core.toFuture
@ -37,7 +38,6 @@ import net.corda.nodeapi.internal.crypto.X509KeyStore
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier
import net.corda.core.node.NotaryInfo
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME
@ -87,7 +87,8 @@ class DriverDSLImpl(
extraCordappPackagesToScan: List<String>,
val jmxPolicy: JmxPolicy,
val notarySpecs: List<NotarySpec>,
val compatibilityZone: CompatibilityZoneParams?
val compatibilityZone: CompatibilityZoneParams?,
val maxTransactionSize: Int
) : InternalDriverDSL {
private var _executorService: ScheduledExecutorService? = null
val executorService get() = _executorService!!
@ -699,7 +700,7 @@ class DriverDSLImpl(
* The local version of the network map, which is a bunch of classes that copy the relevant files to the node directories.
*/
private inner class LocalNetworkMap(notaryInfos: List<NotaryInfo>) {
val networkParametersCopier = NetworkParametersCopier(testNetworkParameters(notaryInfos))
val networkParametersCopier = NetworkParametersCopier(testNetworkParameters(notaryInfos, maxTransactionSize = maxTransactionSize))
// TODO: this object will copy NodeInfo files from started nodes to other nodes additional-node-infos/
// This uses the FileSystem and adds a delay (~5 seconds) given by the time we wait before polling the file system.
// Investigate whether we can avoid that.
@ -955,6 +956,7 @@ fun <DI : DriverDSL, D : InternalDriverDSL, A> genericDriver(
notarySpecs: List<NotarySpec>,
extraCordappPackagesToScan: List<String> = defaultParameters.extraCordappPackagesToScan,
jmxPolicy: JmxPolicy = JmxPolicy(),
maxTransactionSize: Int,
driverDslWrapper: (DriverDSLImpl) -> D,
coerce: (D) -> DI, dsl: DI.() -> A
): A {
@ -972,7 +974,8 @@ fun <DI : DriverDSL, D : InternalDriverDSL, A> genericDriver(
extraCordappPackagesToScan = extraCordappPackagesToScan,
jmxPolicy = jmxPolicy,
notarySpecs = notarySpecs,
compatibilityZone = null
compatibilityZone = null,
maxTransactionSize = maxTransactionSize
)
)
val shutdownHook = addShutdownHook(driverDsl::shutdown)
@ -1014,6 +1017,7 @@ fun <A> internalDriver(
notarySpecs: List<NotarySpec> = DriverParameters().notarySpecs,
extraCordappPackagesToScan: List<String> = DriverParameters().extraCordappPackagesToScan,
jmxPolicy: JmxPolicy = DriverParameters().jmxPolicy,
maxTransactionSize: Int = DriverParameters().maxTransactionSize,
compatibilityZone: CompatibilityZoneParams? = null,
dsl: DriverDSLImpl.() -> A
): A {
@ -1030,7 +1034,8 @@ fun <A> internalDriver(
notarySpecs = notarySpecs,
extraCordappPackagesToScan = extraCordappPackagesToScan,
jmxPolicy = jmxPolicy,
compatibilityZone = compatibilityZone
compatibilityZone = compatibilityZone,
maxTransactionSize = maxTransactionSize
),
coerce = { it },
dsl = dsl,

View File

@ -106,8 +106,9 @@ fun <A> rpcDriver(
notarySpecs: List<NotarySpec> = emptyList(),
externalTrace: Trace? = null,
jmxPolicy: JmxPolicy = JmxPolicy(),
maxTransactionSize: Int = Int.MAX_VALUE,
dsl: RPCDriverDSL.() -> A
) : A {
): A {
return genericDriver(
driverDsl = RPCDriverDSL(
DriverDSLImpl(
@ -122,7 +123,8 @@ fun <A> rpcDriver(
extraCordappPackagesToScan = extraCordappPackagesToScan,
notarySpecs = notarySpecs,
jmxPolicy = jmxPolicy,
compatibilityZone = null
compatibilityZone = null,
maxTransactionSize = maxTransactionSize
), externalTrace
),
coerce = { it },
@ -434,7 +436,7 @@ data class RPCDriverDSL(
minLargeMessageSize = MAX_MESSAGE_SIZE
isUseGlobalPools = false
}
val rpcSecurityManager = RPCSecurityManagerImpl.fromUserList(users = listOf(InternalUser(rpcUser.username, rpcUser.password, rpcUser.permissions)) , id = AuthServiceId("TEST_SECURITY_MANAGER"))
val rpcSecurityManager = RPCSecurityManagerImpl.fromUserList(users = listOf(InternalUser(rpcUser.username, rpcUser.password, rpcUser.permissions)), id = AuthServiceId("TEST_SECURITY_MANAGER"))
val rpcServer = RPCServer(
ops,
rpcUser.username,

View File

@ -9,7 +9,8 @@ fun testNetworkParameters(
minimumPlatformVersion: Int = 1,
modifiedTime: Instant = Instant.now(),
maxMessageSize: Int = 10485760,
maxTransactionSize: Int = 40000,
// TODO: Make this configurable and consistence across driver, bootstrapper, demobench and NetworkMapServer
maxTransactionSize: Int = Int.MAX_VALUE,
epoch: Int = 1
): NetworkParameters {
return NetworkParameters(

View File

@ -143,7 +143,7 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() {
notaries = listOf(NotaryInfo(identity, config.nodeConfig.notary!!.validating)),
modifiedTime = Instant.now(),
maxMessageSize = 10485760,
maxTransactionSize = 40000,
maxTransactionSize = Int.MAX_VALUE,
epoch = 1
))
notaryIdentity = identity

View File

@ -5,6 +5,7 @@ import com.typesafe.config.ConfigFactory
import net.corda.core.concurrent.CordaFuture
import net.corda.core.crypto.random63BitValue
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.GlobalProperties
import net.corda.core.internal.concurrent.OpenFuture
import net.corda.core.internal.concurrent.doneFuture
import net.corda.core.internal.concurrent.fork
@ -22,6 +23,7 @@ import net.corda.nodeapi.VerifierApi
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_USER
import net.corda.nodeapi.internal.config.NodeSSLConfiguration
import net.corda.nodeapi.internal.config.SSLConfiguration
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.driver.JmxPolicy
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.PortAllocation
@ -61,6 +63,7 @@ fun <A> verifierDriver(
extraCordappPackagesToScan: List<String> = emptyList(),
notarySpecs: List<NotarySpec> = emptyList(),
jmxPolicy: JmxPolicy = JmxPolicy(),
maxTransactionSize: Int = Int.MAX_VALUE,
dsl: VerifierDriverDSL.() -> A
) = genericDriver(
driverDsl = VerifierDriverDSL(
@ -76,7 +79,8 @@ fun <A> verifierDriver(
extraCordappPackagesToScan = extraCordappPackagesToScan,
notarySpecs = notarySpecs,
jmxPolicy = jmxPolicy,
compatibilityZone = null
compatibilityZone = null,
maxTransactionSize = maxTransactionSize
)
),
coerce = { it },
@ -162,6 +166,7 @@ data class VerifierDriverDSL(private val driverDSL: DriverDSLImpl) : InternalDri
/** Starts a lightweight verification requestor that implements the Node's Verifier API */
fun startVerificationRequestor(name: CordaX500Name): CordaFuture<VerificationRequestorHandle> {
val hostAndPort = driverDSL.portAllocation.nextHostAndPort()
GlobalProperties.networkParameters = testNetworkParameters(emptyList(), maxTransactionSize = driverDSL.maxTransactionSize)
return driverDSL.executorService.fork {
startVerificationRequestorInternal(name, hostAndPort)
}
@ -184,6 +189,7 @@ data class VerifierDriverDSL(private val driverDSL: DriverDSLImpl) : InternalDri
val securityManager = object : ActiveMQSecurityManager {
// We don't need auth, SSL is good enough
override fun validateUser(user: String?, password: String?) = true
override fun validateUserAndRole(user: String?, password: String?, roles: MutableSet<Role>?, checkType: CheckType?) = true
}