Merge pull request #876 from corda/os-merge-3136e97

O/S merge from 3136e97
This commit is contained in:
Shams Asari 2018-05-24 16:53:03 +01:00 committed by GitHub
commit 77ef131c0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 395 additions and 238 deletions

4
.idea/compiler.xml generated
View File

@ -37,6 +37,8 @@
<module name="capsule-crr-submission_test" target="1.8" />
<module name="capsule-hsm-cert-generator_main" target="1.8" />
<module name="capsule-hsm-cert-generator_test" target="1.8" />
<module name="capsule-hsm-crl-generator_main" target="1.8" />
<module name="capsule-hsm-crl-generator_test" target="1.8" />
<module name="capsule-hsm_main" target="1.8" />
<module name="capsule-hsm_test" target="1.8" />
<module name="client_main" target="1.8" />
@ -96,6 +98,8 @@
<module name="experimental-behave_main" target="1.8" />
<module name="experimental-behave_smokeTest" target="1.8" />
<module name="experimental-behave_test" target="1.8" />
<module name="experimental-blobinspector_main" target="1.8" />
<module name="experimental-blobinspector_test" target="1.8" />
<module name="experimental-kryo-hook_main" target="1.8" />
<module name="experimental-kryo-hook_test" target="1.8" />
<module name="experimental_main" target="1.8" />

View File

@ -125,6 +125,7 @@ see changes to this list.
* Micheal Hinstridge (Thoughtworks)
* Michele Sollecito (R3)
* Mike Hearn (R3)
* Mike Ward (R3)
* Mike Reichelt (US Bank)
* Mustafa Ozturk (Natixis)
* Nick Skinner (Northern Trust)
@ -161,6 +162,7 @@ see changes to this list.
* Sasmit Sahu
* Scott James
* Shams Asari (R3)
* Siddhartha Sengupta (Tradewind Markets)
* Simon Taylor (Barclays)
* Sofus Mortensen (Digital Asset Holdings)
* stevenroose

View File

@ -70,10 +70,6 @@ dependencies {
compile "org.bouncycastle:bcpkix-jdk15on:${bouncycastle_version}"
// Seems to be needed?
compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version"
// Pulled in by whitelist
compile ("com.esotericsoftware:kryo:4.0.0") {
transitive = false
}
// Log4J: logging framework (with SLF4J bindings)
compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"

View File

@ -7,11 +7,11 @@ import net.corda.core.serialization.SerializationCustomSerializer
import net.corda.core.serialization.internal.SerializationEnvironment
import net.corda.core.serialization.internal.SerializationEnvironmentImpl
import net.corda.core.serialization.internal.nodeSerializationEnv
import net.corda.nodeapi.internal.serialization.amqp.custom.RxNotificationSerializer
import net.corda.serialization.internal.*
import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme
import net.corda.serialization.internal.amqp.SerializerFactory
import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.amqp.custom.RxNotificationSerializer
import java.util.concurrent.ConcurrentHashMap
/**

View File

@ -23,7 +23,7 @@
<Appenders>
<Console name="Console-Appender" target="SYSTEM_OUT">
<PatternLayout pattern="%highlight{%level{length=1} %date{HH:mm:ssZ} [%t] %c{2}.%method - %msg %X%n}{INFO=white,WARN=red,FATAL=bright red}" />
<PatternLayout pattern="%highlight{%level{length=1} %date{HH:mm:ssZ} [%t] %c{2}.%method - %msg %equals{%X}{{}}{}%n}{INFO=white,WARN=red,FATAL=bright red}" />
</Console>
<!-- Required for printBasicInfo -->

View File

@ -13,9 +13,9 @@ package net.corda.core.utilities
import com.esotericsoftware.kryo.KryoException
import net.corda.core.crypto.random63BitValue
import net.corda.core.serialization.*
import net.corda.serialization.internal.KRYO_CHECKPOINT_CONTEXT
import net.corda.node.serialization.kryo.KRYO_CHECKPOINT_CONTEXT
import net.corda.node.serialization.kryo.kryoMagic
import net.corda.serialization.internal.SerializationContextImpl
import net.corda.serialization.internal.kryo.kryoMagic
import net.corda.testing.core.SerializationEnvironmentRule
import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule

View File

@ -8,6 +8,10 @@ Unreleased
==========
* Introduced a hierarchy of ``DatabaseMigrationException``s, allowing ``NodeStartup`` to gracefully inform users of problems related to database migrations before exiting with a non-zero code.
* ``NodeStartup`` will now only print node's configuration if ``devMode`` is ``true``, avoiding the risk of printing passwords in a production setup.
* SLF4J's MDC will now only be printed to the console if not empty. No more log lines ending with "{}".
* ``WireTransaction.Companion.createComponentGroups`` has been marked as ``@CordaInternal``. It was never intended to be
public and was already internal for Kotlin code.

View File

@ -11,20 +11,16 @@ Identifying an area to contribute
---------------------------------
There are several ways to identify an area where you can contribute to Corda:
* Browse issues labelled as ``good first issue`` in the
`Corda GitHub Issues <https://github.com/corda/corda/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22>`_
* Any issue with a ``good first issue`` label is considered ideal for open-source contributions
* If there is a feature you would like to add and there isn't a corresponding issue labelled as ``good first issue``,
that doesn't mean your contribution isn't welcome. Please reach out on the ``#design`` channel to clarify (see
below)
* Ask in the ``#design`` channel of the `Corda Slack <http://slack.corda.net/>`_
* Browse the `Corda GitHub issues <https://github.com/corda/corda/issues>`_
* It's always worth checking in the ``#design`` channel whether a given issue is a good target for your
contribution. Someone else may already be working on it, or it may be blocked by an on-going piece of work
* Browse issues labelled as ``HelpWanted`` on the
`Corda JIRA board <https://r3-cev.atlassian.net/issues/?jql=labels%20%3D%20HelpWanted>`_
* Any issue with a ``HelpWanted`` label is considered ideal for open-source contributions
* If there is a feature you would like to add and there isn't a corresponding issue labelled as ``HelpWanted``, that
doesn't mean your contribution isn't welcome. Please reach out on the ``#design`` channel to clarify
Making the required changes
---------------------------
@ -32,44 +28,117 @@ Making the required changes
2. Clone the fork to your local machine
3. Make the changes, in accordance with the :doc:`code style guide </codestyle>`
Things to check
^^^^^^^^^^^^^^^
Is your error handling up to scratch?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Errors should not leak to the UI. When writing tools intended for end users, like the node or command line tools,
remember to add ``try``/``catch`` blocks. Throw meaningful errors. For example, instead of throwing an
``OutOfMemoryError``, use the error message to indicate that a file is missing, a network socket was unreachable, etc.
Tools should not dump stack traces to the end user.
Look for API breaks
~~~~~~~~~~~~~~~~~~~
We have an automated checker tool that runs as part of our continuous integration pipeline and helps a lot, but it
can't catch semantic changes where the behavior of an API changes in ways that might violate app developer expectations.
Suppress inevitable compiler warnings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compiler warnings should have a ``@Suppress`` annotation on them if they're expected and can't be avoided.
Remove deprecated functionality
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When deprecating functionality, make sure you remove the deprecated uses in the codebase.
Avoid making formatting changes as you work
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In Kotlin 1.2.20, new style guide rules were implemented. The new Kotlin style guide is significantly more detailed
than before and IntelliJ knows how to implement those rules. Re-formatting the codebase creates a lot of diffs that
make merging more complicated.
Things to consider when writing CLI apps
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Set exit codes using ``exitProcess``. Zero means success. Other numbers mean errors. Setting a unique error code
(starting from 1) for each thing that can conceivably break makes your tool shell-scripting friendly
* Do a bit of work to figure out reasonable defaults. Nobody likes having to set a dozen flags before the tool will
cooperate
* Your ``--help`` text or other docs should ideally include examples. Writing examples is also a good way to find out
that your program requires a dozen flags to do anything
* Flags should have sensible defaults
* Dont print logging output to the console unless the user requested it via a ``verbose`` flag (conventionally
shortened to ``-v``) or a ``log-to-console`` flag. Logs should be either suppressed or saved to a text file during
normal usage, except for errors, which are always OK to print
Testing the changes
-------------------
Adding tests
^^^^^^^^^^^^
Unit tests and integration tests for external API changes must cover Java and Kotlin. For internal API changes these
tests can be scaled back to kotlin only.
Running the tests
^^^^^^^^^^^^^^^^^
Your changes must pass the tests described :doc:`here </testing>`.
Manual testing
^^^^^^^^^^^^^^
Before sending that code for review, spend time poking and prodding the tool and thinking, “Would the experience of
using this feature make my mum proud of me?”. Automated tests are not a substitute for dogfooding.
Building against the master branch
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can test your changes against CorDapps defined in other repos by following the instructions :doc:`here </building-against-master>`.
You can test your changes against CorDapps defined in other repos by following the instructions
:doc:`here </building-against-master>`.
Updating the docs
-----------------
Any changes to Corda's public API must be documented as follows:
1. Update the relevant `.rst file(s) <https://github.com/corda/corda/tree/master/docs/source>`_
2. Include the change in the :doc:`changelog </changelog>` and :doc:`release notes </release-notes>` where applicable
3. :doc:`Build the docs locally </building-the-docs>`
4. Open the built .html files for the modified pages to ensure they render correctly
1. Add comments and javadocs/kdocs. API functions must have javadoc/kdoc comments and sentences must be terminated
with a full stop. We also start comments with capital letters, even for inline comments. Where Java APIs have
synonyms (e.g. ``%d`` and ``%date``), we prefer the longer form for legibility reasons. You can configure your IDE
to highlight these in bright yellow
2. Update the relevant `.rst file(s) <https://github.com/corda/corda/tree/master/docs/source>`_
3. Include the change in the :doc:`changelog </changelog>` if the change is external and therefore visible to CorDapp
developers and/or node operators
4. :doc:`Build the docs locally </building-the-docs>`
5. Check the built .html files (under ``docs/build/html``) for the modified pages to ensure they render correctly
6. If relevant, add a sample. Samples are one of the key ways in which users learn about what the platform can do.
If you add a new API or feature and don't update the samples, your work will be much less impactful
Merging the changes back into Corda
-----------------------------------
1. Create a pull request from your fork to the master branch of the Corda repo
2. Complete the pull-request checklist in the comments box:
1. Create a pull request from your fork to the ``master`` branch of the Corda repo
* State that you have run the tests
* State that you have included JavaDocs for any new public APIs
* State that you have included the change in the :doc:`changelog </changelog>` and
:doc:`release notes </release-notes>` where applicable
* State that you are in agreement with the terms of
`CONTRIBUTING.md <https://github.com/corda/corda/blob/master/CONTRIBUTING.md>`_
2. In the PR comments box, complete the pull-request checklist:
3. Request a review from a member of the Corda platform team via the `#design channel <http://slack.corda.net/>`_
4. Wait for your PR to pass all four types of continuous integration tests (integration, API stability, build and unit)
* [ ] Have you run the unit, integration and smoke tests as described here? https://docs.corda.net/head/testing.html
* [ ] If you added/changed public APIs, did you write/update the JavaDocs?
* [ ] If the changes are of interest to application developers, have you added them to the changelog, and potentially
release notes?
* [ ] If you are contributing for the first time, please read the agreement in CONTRIBUTING.md now and add to this
Pull Request that you agree to it.
* Currently, external contributors cannot see the output of these tests. If your PR fails a test that passed
locally, ask the reviewer for further details
3. In the PR comments box, also add a clear description of the purpose for the PR
5. Once a reviewer has approved the PR and the tests have passed, squash-and-merge the PR as a single commit
4. Request a review from a member of the Corda platform team via the `#design channel <http://slack.corda.net/>`_
5. The reviewer will either:
* Accept and merge your PR
* Request that you make further changes. Do this by committing and pushing the changes onto the branch you are PRing
into Corda. The PR will be updated automatically

View File

@ -66,6 +66,34 @@ created the "denial of state" transaction, allowing the attack to be resolved of
In the case of the validating model, the use of anonymous, freshly-generated public keys instead of legal identities to
identify parties in a transaction limit the information the notary cluster sees.
Data visibility
^^^^^^^^^^^^^^^
Below is a summary of what specific transaction components have to be revealed to each type of notary:
+-----------------------------------+---------------+-----------------------+
| Transaction components | Validating | Non-validating |
+===================================+===============+=======================+
| Input states | Fully visible | References only [1]_ |
+-----------------------------------+---------------+-----------------------+
| Output states | Fully visible | Hidden |
+-----------------------------------+---------------+-----------------------+
| Commands (with signer identities) | Fully visible | Hidden |
+-----------------------------------+---------------+-----------------------+
| Attachments | Fully visible | Hidden |
+-----------------------------------+---------------+-----------------------+
| Time window | Fully visible | Fully visible |
+-----------------------------------+---------------+-----------------------+
| Notary identity | Fully visible | Fully visible |
+-----------------------------------+---------------+-----------------------+
| Signatures | Fully visible | Hidden |
+-----------------------------------+---------------+-----------------------+
Both types of notaries record the calling party's identity: the public key and the X.500 Distinguished Name.
.. [1] A state reference is composed of the issuing transaction's id and the state's position in the outputs. It does not
reveal what kind of state it is or its contents.
Multiple notaries
-----------------
Each Corda network can have multiple notary clusters, each potentially running a different consensus algorithm. This

View File

@ -6,7 +6,7 @@ Default in-memory database
By default, nodes store their data in an H2 database. You can connect directly to a running node's database to see its
stored states, transactions and attachments as follows:
* Download the `h2 platform-independent zip <http://www.h2database.com/html/download.html>`_, unzip the zip, and
* Download the **last stable** `h2 platform-independent zip <http://www.h2database.com/html/download.html>`_, unzip the zip, and
navigate in a terminal window to the unzipped folder
* Change directories to the bin folder: ``cd h2/bin``

View File

@ -7,7 +7,7 @@ Attachments are ZIP/JAR files referenced from transaction by hash, but not inclu
itself. These files are automatically requested from the node sending the transaction when needed and cached
locally so they are not re-requested if encountered again. Attachments typically contain:
* Contract executable code
* Contract code
* Metadata about a transaction, such as PDF version of an invoice being settled
* Shared information to be permanently recorded on the ledger

View File

@ -5,7 +5,11 @@ import net.corda.core.serialization.EncodingWhitelist
import net.corda.core.serialization.SerializationEncoding
import net.corda.core.utilities.ByteSequence
import net.corda.serialization.internal.SerializationFactoryImpl
import net.corda.serialization.internal.amqp.*
import net.corda.serialization.internal.amqp.CompositeType
import net.corda.serialization.internal.amqp.DeserializationInput
import net.corda.serialization.internal.amqp.RestrictedType
import net.corda.serialization.internal.amqp.TypeNotation
import net.corda.serialization.internal.amqp.amqpMagic
import org.apache.qpid.proton.amqp.Binary
import org.apache.qpid.proton.amqp.DescribedType
import org.apache.qpid.proton.amqp.Symbol

View File

@ -37,19 +37,16 @@ import net.corda.serialization.internal.CordaSerializationMagic
import net.corda.serialization.internal.SerializationFactoryImpl
import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme
import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.kryo.AbstractKryoSerializationScheme
import net.corda.serialization.internal.kryo.kryoMagic
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.StandardCopyOption.REPLACE_EXISTING
import java.time.Instant
import java.util.concurrent.Executors
import java.util.concurrent.TimeoutException
import kotlin.streams.toList
import kotlin.collections.HashSet
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.set
import kotlin.streams.toList
/**
* Class to bootstrap a local network of Corda nodes on the same filesystem.
@ -348,22 +345,12 @@ class NetworkBootstrapper {
private fun initialiseSerialization() {
_contextSerializationEnv.set(SerializationEnvironmentImpl(
SerializationFactoryImpl().apply {
registerScheme(KryoParametersSerializationScheme)
registerScheme(AMQPParametersSerializationScheme)
},
AMQP_P2P_CONTEXT)
)
}
private object KryoParametersSerializationScheme : AbstractKryoSerializationScheme() {
override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean {
return magic == kryoMagic && target == SerializationContext.UseCase.P2P
}
override fun rpcClientKryoPool(context: SerializationContext) = throw UnsupportedOperationException()
override fun rpcServerKryoPool(context: SerializationContext) = throw UnsupportedOperationException()
}
private object AMQPParametersSerializationScheme : AbstractAMQPSerializationScheme(emptyList()) {
override fun rpcClientSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException()
override fun rpcServerSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException()

View File

@ -21,10 +21,10 @@ import net.corda.core.serialization.serialize
import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
import net.corda.nodeapi.internal.config.SSLConfiguration
import net.corda.nodeapi.internal.createDevKeyStores
import net.corda.serialization.internal.AllWhitelist
import net.corda.serialization.internal.SerializationContextImpl
import net.corda.serialization.internal.SerializationFactoryImpl
import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.AllWhitelist
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.TestIdentity
@ -362,13 +362,15 @@ class X509UtilitiesTest {
@Test
fun `serialize - deserialize X509CertPath`() {
val factory = SerializationFactoryImpl().apply { registerScheme(AMQPServerSerializationScheme()) }
val context = SerializationContextImpl(amqpMagic,
val context = SerializationContextImpl(
amqpMagic,
javaClass.classLoader,
AllWhitelist,
emptyMap(),
true,
SerializationContext.UseCase.P2P,
null)
null
)
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val rootCACert = X509Utilities.createSelfSignedCACertificate(ALICE_NAME.x500Principal, rootCAKey)
val certificate = X509Utilities.createCertificate(CertificateType.TLS, rootCACert, rootCAKey, BOB_NAME.x500Principal, BOB.publicKey)

View File

@ -84,6 +84,10 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
// Kryo: object graph serialization.
compile "com.esotericsoftware:kryo:4.0.0"
compile "de.javakaffee:kryo-serializers:0.41"
compile "com.google.guava:guava:$guava_version"
// For caches rather than guava

View File

@ -10,12 +10,14 @@
package net.corda.node
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import joptsimple.OptionSet
import joptsimple.util.EnumConverter
import joptsimple.util.PathConverter
import net.corda.core.internal.div
import net.corda.core.internal.exists
import net.corda.core.utilities.Try
import net.corda.node.services.config.ConfigHelper
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.parseAsNodeConfiguration
@ -125,19 +127,22 @@ data class CmdLineOptions(val baseDirectory: Path,
val bootstrapRaftCluster: Boolean,
val unknownConfigKeysPolicy: UnknownConfigKeysPolicy,
val devMode: Boolean) {
fun loadConfig(): NodeConfiguration {
val config = ConfigHelper.loadConfig(
fun loadConfig(): Pair<Config, Try<NodeConfiguration>> {
val rawConfig = ConfigHelper.loadConfig(
baseDirectory,
configFile,
configOverrides = ConfigFactory.parseMap(mapOf("noLocalShell" to this.noLocalShell) +
if (devMode) mapOf("devMode" to this.devMode) else emptyMap<String, Any>())
).parseAsNodeConfiguration(unknownConfigKeysPolicy::handle)
if (nodeRegistrationOption != null) {
require(!config.devMode) { "registration cannot occur in devMode" }
requireNotNull(config.compatibilityZoneURL) {
"compatibilityZoneURL must be present in node configuration file in registration mode."
)
return rawConfig to Try.on {
rawConfig.parseAsNodeConfiguration(unknownConfigKeysPolicy::handle).also {
if (nodeRegistrationOption != null) {
require(!it.devMode) { "registration cannot occur in devMode" }
requireNotNull(it.compatibilityZoneURL) {
"compatibilityZoneURL must be present in node configuration file in registration mode."
}
}
}
}
return config
}
}

View File

@ -382,6 +382,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
NodeInfoWatcher(configuration.baseDirectory, getRxIoScheduler(), Duration.ofMillis(configuration.additionalNodeInfoPollingFrequencyMsec)),
networkMapClient,
networkParameters.serialize().hash,
services.myInfo.serialize().hash,
configuration.baseDirectory,
configuration.extraNetworkMapKeys)
runOnStop += networkMapUpdater::close
@ -862,7 +863,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
private fun makeIdentityService(identityCert: X509Certificate): PersistentIdentityService {
val trustRoot = configuration.loadTrustStore().getCertificate(X509Utilities.CORDA_ROOT_CA)
val nodeCa = configuration.loadNodeKeyStore().getCertificate(X509Utilities.CORDA_CLIENT_CA)
return PersistentIdentityService(trustRoot, identityCert, nodeCa)
return PersistentIdentityService(trustRoot, listOf(identityCert, nodeCa))
}
protected abstract fun makeTransactionVerifierService(): TransactionVerifierService

View File

@ -38,6 +38,7 @@ import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.internal.security.RPCSecurityManagerImpl
import net.corda.node.internal.security.RPCSecurityManagerWithAdditionalUser
import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
import net.corda.node.serialization.kryo.KRYO_CHECKPOINT_CONTEXT
import net.corda.node.serialization.kryo.KryoServerSerializationScheme
import net.corda.node.services.Permissions
import net.corda.node.services.api.NodePropertiesStore

View File

@ -11,6 +11,8 @@
package net.corda.node.internal
import com.jcabi.manifests.Manifests
import com.typesafe.config.Config
import com.typesafe.config.ConfigRenderOptions
import io.netty.channel.unix.Errors
import net.corda.core.cordapp.Cordapp
import net.corda.core.crypto.Crypto
@ -19,6 +21,7 @@ import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.core.internal.randomOrNull
import net.corda.core.utilities.Try
import net.corda.core.utilities.loggerFor
import net.corda.node.CmdLineOptions
import net.corda.node.NodeArgsParser
@ -92,7 +95,11 @@ open class NodeStartup(val args: Array<String>) {
drawBanner(versionInfo)
Node.printBasicNodeInfo(LOGS_CAN_BE_FOUND_IN_STRING, System.getProperty("log-path"))
val conf = try {
val conf0 = loadConfigFile(cmdlineOptions)
val (rawConfig, conf0Result) = loadConfigFile(cmdlineOptions)
if (cmdlineOptions.devMode) {
println("Config:\n${rawConfig.root().render(ConfigRenderOptions.defaults())}")
}
val conf0 = conf0Result.getOrThrow()
if (cmdlineOptions.bootstrapRaftCluster) {
if (conf0 is NodeConfigurationImpl) {
println("Bootstrapping raft cluster (starting up as seed node).")
@ -227,7 +234,7 @@ open class NodeStartup(val args: Array<String>) {
NodeRegistrationHelper(conf, HTTPNetworkRegistrationService(compatibilityZoneURL), nodeRegistrationConfig).buildKeystore()
}
protected open fun loadConfigFile(cmdlineOptions: CmdLineOptions): NodeConfiguration = cmdlineOptions.loadConfig()
protected open fun loadConfigFile(cmdlineOptions: CmdLineOptions): Pair<Config, Try<NodeConfiguration>> = cmdlineOptions.loadConfig()
protected open fun banJavaSerialisation(conf: NodeConfiguration) {
val isOracleDbDriver = conf.dataSourceProperties.getProperty("dataSource.url", "").startsWith("jdbc:oracle:")

View File

@ -4,10 +4,10 @@ import net.corda.core.cordapp.Cordapp
import net.corda.core.serialization.ClassWhitelist
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationCustomSerializer
import net.corda.nodeapi.internal.serialization.amqp.custom.RxNotificationSerializer
import net.corda.serialization.internal.CordaSerializationMagic
import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme
import net.corda.serialization.internal.amqp.SerializerFactory
import net.corda.serialization.internal.amqp.custom.RxNotificationSerializer
import java.util.concurrent.ConcurrentHashMap
/**

View File

@ -8,7 +8,7 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
package net.corda.serialization.internal.kryo
package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.*
import com.esotericsoftware.kryo.io.Input
@ -23,6 +23,7 @@ import net.corda.core.serialization.SerializationContext
import net.corda.core.utilities.contextLogger
import net.corda.serialization.internal.AttachmentsClassLoader
import net.corda.serialization.internal.MutableClassWhitelist
import net.corda.serialization.internal.TransientClassWhiteList
import net.corda.serialization.internal.amqp.hasAnnotationInHierarchy
import java.io.PrintWriter
import java.lang.reflect.Modifier
@ -156,43 +157,6 @@ class CordaClassResolver(serializationContext: SerializationContext) : DefaultCl
}
}
class BuiltInExceptionsWhitelist : ClassWhitelist {
companion object {
private val packageName = "^(?:java|kotlin)(?:[.]|$)".toRegex()
}
override fun hasListed(type: Class<*>) = Throwable::class.java.isAssignableFrom(type) && packageName.containsMatchIn(type.`package`.name)
}
sealed class AbstractMutableClassWhitelist(private val whitelist: MutableSet<String>, private val delegate: ClassWhitelist) : MutableClassWhitelist {
override fun hasListed(type: Class<*>): Boolean {
/**
* There are certain delegates like [net.corda.serialization.internal.AllButBlacklisted]
* which may throw when asked whether the type is listed.
* In such situations - it may be a good idea to ask [delegate] first before making a check against own [whitelist].
*/
return delegate.hasListed(type) || (type.name in whitelist)
}
override fun add(entry: Class<*>) {
whitelist += entry.name
}
}
// TODO: Need some concept of from which class loader
class GlobalTransientClassWhiteList(delegate: ClassWhitelist) : AbstractMutableClassWhitelist(whitelist, delegate) {
companion object {
private val whitelist: MutableSet<String> = Collections.synchronizedSet(mutableSetOf())
}
}
/**
* A whitelist that can be customised via the [net.corda.core.serialization.SerializationWhitelist],
* since it implements [MutableClassWhitelist].
*/
class TransientClassWhiteList(delegate: ClassWhitelist) : AbstractMutableClassWhitelist(Collections.synchronizedSet(mutableSetOf()), delegate)
/**
* This class is not currently used, but can be installed to log a large number of missing entries from the whitelist
* and was used to track down the initial set.

View File

@ -8,7 +8,7 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
package net.corda.serialization.internal.kryo
package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.io.Output

View File

@ -8,7 +8,7 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
package net.corda.serialization.internal.kryo
package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.Serializer

View File

@ -8,7 +8,7 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
package net.corda.serialization.internal.kryo
package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.*
import com.esotericsoftware.kryo.factories.ReflectionSerializerFactory

View File

@ -8,7 +8,7 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
package net.corda.serialization.internal.kryo
package net.corda.node.serialization.kryo
import co.paralleluniverse.fibers.Fiber
import co.paralleluniverse.io.serialization.kryo.KryoSerializer
@ -22,10 +22,11 @@ import com.esotericsoftware.kryo.serializers.ClosureSerializer
import net.corda.core.internal.uncheckedCast
import net.corda.core.serialization.ClassWhitelist
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationDefaults
import net.corda.core.serialization.SerializedBytes
import net.corda.core.utilities.ByteSequence
import net.corda.serialization.internal.*
import net.corda.serialization.internal.SectionId
import net.corda.serialization.internal.CordaSerializationEncoding.SNAPPY
import java.security.PublicKey
import java.util.concurrent.ConcurrentHashMap
@ -140,3 +141,14 @@ abstract class AbstractKryoSerializationScheme : SerializationScheme {
}
}
}
val KRYO_CHECKPOINT_CONTEXT = SerializationContextImpl(
kryoMagic,
SerializationDefaults.javaClass.classLoader,
QuasarWhitelist,
emptyMap(),
true,
SerializationContext.UseCase.Checkpoint,
SNAPPY,
AlwaysAcceptEncodingWhitelist
)

View File

@ -13,8 +13,6 @@ package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.pool.KryoPool
import net.corda.core.serialization.SerializationContext
import net.corda.serialization.internal.CordaSerializationMagic
import net.corda.serialization.internal.kryo.AbstractKryoSerializationScheme
import net.corda.serialization.internal.kryo.kryoMagic
class KryoServerSerializationScheme : AbstractKryoSerializationScheme() {
override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean {
@ -22,7 +20,5 @@ class KryoServerSerializationScheme : AbstractKryoSerializationScheme() {
}
override fun rpcClientKryoPool(context: SerializationContext): KryoPool = throw UnsupportedOperationException()
override fun rpcServerKryoPool(context: SerializationContext): KryoPool = throw UnsupportedOperationException()
}
}

View File

@ -10,7 +10,7 @@
@file:JvmName("KryoStreams")
package net.corda.serialization.internal.kryo
package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output

View File

@ -8,7 +8,7 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
package net.corda.serialization.internal.kryo
package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.KryoException

View File

@ -15,7 +15,6 @@ import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigFactory.systemEnvironment
import com.typesafe.config.ConfigFactory.systemProperties
import com.typesafe.config.ConfigParseOptions
import com.typesafe.config.ConfigRenderOptions
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
@ -64,8 +63,6 @@ object ConfigHelper {
.withFallback(defaultConfig)
.resolve()
log.info("Config:\n${finalConfig.root().render(ConfigRenderOptions.defaults())}")
val entrySet = finalConfig.entrySet().filter { entry -> entry.key.contains("\"") }
for ((key) in entrySet) {
log.error("Config files should not contain \" in property names. Please fix: $key")

View File

@ -34,7 +34,7 @@ import javax.annotation.concurrent.ThreadSafe
*/
// TODO There is duplicated logic between this and PersistentIdentityService
@ThreadSafe
class InMemoryIdentityService(identities: Array<out PartyAndCertificate>,
class InMemoryIdentityService(identities: List<out PartyAndCertificate> = emptyList(),
override val trustRoot: X509Certificate) : SingletonSerializeAsToken(), IdentityService {
companion object {
private val log = contextLogger()

View File

@ -38,10 +38,17 @@ import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Lob
/**
* An identity service that stores parties and their identities to a key value tables in the database. The entries are
* cached for efficient lookup.
*
* @param trustRoot certificate from the zone operator for identity on the network.
* @param caCertificates list of additional certificates.
*/
// TODO There is duplicated logic between this and InMemoryIdentityService
@ThreadSafe
class PersistentIdentityService(override val trustRoot: X509Certificate,
vararg caCertificates: X509Certificate) : SingletonSerializeAsToken(), IdentityServiceInternal {
caCertificates: List<X509Certificate> = emptyList()) : SingletonSerializeAsToken(), IdentityServiceInternal {
companion object {
private val log = contextLogger()

View File

@ -45,6 +45,7 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal,
private val fileWatcher: NodeInfoWatcher,
private val networkMapClient: NetworkMapClient?,
private val currentParametersHash: SecureHash,
private val ourNodeInfoHash: SecureHash?,
private val baseDirectory: Path,
private val extraNetworkMapKeys: List<UUID>
) : AutoCloseable {
@ -79,8 +80,10 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal,
networkMapCache.addNode(it.nodeInfo)
}
is NodeInfoUpdate.Remove -> {
val nodeInfo = networkMapCache.getNodeByHash(it.hash)
nodeInfo?.let { networkMapCache.removeNode(it) }
if (it.hash != ourNodeInfoHash) {
val nodeInfo = networkMapCache.getNodeByHash(it.hash)
nodeInfo?.let { networkMapCache.removeNode(it) }
}
}
}
}
@ -137,8 +140,11 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal,
// Remove node info from network map.
(currentNodeHashes - allHashesFromNetworkMap - fileWatcher.processedNodeInfoHashes)
.mapNotNull(networkMapCache::getNodeByHash)
.forEach(networkMapCache::removeNode)
.mapNotNull {
if (it != ourNodeInfoHash) {
networkMapCache.getNodeByHash(it)
} else null
}.forEach(networkMapCache::removeNode)
return cacheTimeout
}

View File

@ -1,9 +1,9 @@
package net.corda.node.internal.serialization.testutils
import net.corda.core.serialization.SerializationContext
import net.corda.serialization.internal.AllWhitelist
import net.corda.serialization.internal.SerializationContextImpl
import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.AllWhitelist
val serializationProperties: MutableMap<Any, Any> = mutableMapOf()
@ -14,4 +14,5 @@ val serializationContext = SerializationContextImpl(
properties = serializationProperties,
objectReferencesEnabled = false,
useCase = SerializationContext.UseCase.Testing,
encoding = null)
encoding = null
)

View File

@ -8,7 +8,7 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
package net.corda.serialization.internal.kryo
package net.corda.node.serialization.kryo
import net.corda.core.internal.declaredField
import net.corda.serialization.internal.ByteBufferOutputStream
@ -38,7 +38,7 @@ class KryoStreamsTest {
fun `substitute output works`() {
assertArrayEquals(byteArrayOf(100, -101), kryoOutput {
write(100)
substitute(::NegOutputStream)
substitute(KryoStreamsTest::NegOutputStream)
write(101)
})
}
@ -47,7 +47,7 @@ class KryoStreamsTest {
fun `substitute input works`() {
kryoInput(byteArrayOf(100, 101).inputStream()) {
assertEquals(100, read())
substitute(::NegInputStream)
substitute(KryoStreamsTest::NegInputStream)
assertEquals(-101, read().toByte())
assertEquals(-1, read())
}

View File

@ -8,7 +8,7 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
package net.corda.serialization.internal.kryo
package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.KryoException
@ -43,6 +43,7 @@ import org.slf4j.LoggerFactory
import java.io.InputStream
import java.time.Instant
import java.util.*
import kotlin.collections.ArrayList
import kotlin.test.*
class TestScheme : AbstractKryoSerializationScheme() {
@ -103,7 +104,7 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
fun `serialised form is stable when the same object instance is added to the deserialised object graph`() {
val noReferencesContext = context.withoutReferences()
val obj : ByteSequence = Ints.toByteArray(0x01234567).sequence()
val originalList : ArrayList<ByteSequence> = arrayListOf(obj)
val originalList : ArrayList<ByteSequence> = ArrayList<ByteSequence>().apply { this += obj }
val deserialisedList = originalList.serialize(factory, noReferencesContext).deserialize(factory, noReferencesContext)
originalList += obj
deserialisedList += obj
@ -116,8 +117,14 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
val instant = Instant.ofEpochMilli(123)
val instantCopy = Instant.ofEpochMilli(123)
assertThat(instant).isNotSameAs(instantCopy)
val listWithCopies = arrayListOf(instant, instantCopy)
val listWithSameInstances = arrayListOf(instant, instant)
val listWithCopies = ArrayList<Instant>().apply {
this += instant
this += instantCopy
}
val listWithSameInstances = ArrayList<Instant>().apply {
this += instant
this += instant
}
assertThat(listWithSameInstances.serialize(factory, noReferencesContext)).isEqualTo(listWithCopies.serialize(factory, noReferencesContext))
}

View File

@ -42,7 +42,7 @@ class InMemoryIdentityServiceTests {
val BOB get() = bob.party
val BOB_IDENTITY get() = bob.identity
val BOB_PUBKEY get() = bob.publicKey
fun createService(vararg identities: PartyAndCertificate) = InMemoryIdentityService(identities, DEV_ROOT_CA.certificate)
fun createService(vararg identities: PartyAndCertificate) = InMemoryIdentityService(identities.toList(), DEV_ROOT_CA.certificate)
}
@Rule

View File

@ -15,6 +15,7 @@ import com.google.common.jimfs.Jimfs
import com.nhaarman.mockito_kotlin.*
import net.corda.cordform.CordformNode.NODE_INFO_DIRECTORY
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.sign
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
@ -71,7 +72,6 @@ class NetworkMapUpdaterTest {
server = NetworkMapServer(cacheExpiryMs.millis, PortAllocation.Incremental(10000).nextHostAndPort())
val hostAndPort = server.start()
networkMapClient = NetworkMapClient(URL("http://${hostAndPort.host}:${hostAndPort.port}"), DEV_ROOT_CA.certificate)
updater = NetworkMapUpdater(networkMapCache, fileWatcher, networkMapClient, server.networkParameters.serialize().hash, baseDir, listOf(privateNetUUID))
}
@After
@ -81,8 +81,13 @@ class NetworkMapUpdaterTest {
server.close()
}
private fun setUpdater(ourNodeHash: SecureHash? = null, extraNetworkMapKeys: List<UUID> = emptyList()) {
updater = NetworkMapUpdater(networkMapCache, fileWatcher, networkMapClient, server.networkParameters.serialize().hash, ourNodeHash, baseDir, extraNetworkMapKeys)
}
@Test
fun `process add node updates from network map, with additional node infos from dir`() {
setUpdater()
val (nodeInfo1, signedNodeInfo1) = createNodeInfoAndSigned("Info 1")
val (nodeInfo2, signedNodeInfo2) = createNodeInfoAndSigned("Info 2")
val (nodeInfo3, signedNodeInfo3) = createNodeInfoAndSigned("Info 3")
@ -118,6 +123,7 @@ class NetworkMapUpdaterTest {
@Test
fun `process remove node updates from network map, with additional node infos from dir`() {
setUpdater()
val (nodeInfo1, signedNodeInfo1) = createNodeInfoAndSigned("Info 1")
val (nodeInfo2, signedNodeInfo2) = createNodeInfoAndSigned("Info 2")
val (nodeInfo3, signedNodeInfo3) = createNodeInfoAndSigned("Info 3")
@ -158,6 +164,7 @@ class NetworkMapUpdaterTest {
@Test
fun `receive node infos from directory, without a network map`() {
setUpdater()
val fileNodeInfoAndSigned = createNodeInfoAndSigned("Info from file")
// Not subscribed yet.
@ -176,6 +183,7 @@ class NetworkMapUpdaterTest {
@Test
fun `emit new parameters update info on parameters update from network map`() {
setUpdater()
val paramsFeed = updater.trackParametersUpdate()
val snapshot = paramsFeed.snapshot
val updates = paramsFeed.updates.bufferUntilSubscribed()
@ -198,6 +206,7 @@ class NetworkMapUpdaterTest {
@Test
fun `ack network parameters update`() {
setUpdater()
val newParameters = testNetworkParameters(epoch = 314)
server.scheduleParametersUpdate(newParameters, "Test update", Instant.MIN)
updater.subscribeToNetworkMap()
@ -214,6 +223,7 @@ class NetworkMapUpdaterTest {
@Test
fun `fetch nodes from private network`() {
setUpdater(extraNetworkMapKeys = listOf(privateNetUUID))
server.addNodesToPrivateNetwork(privateNetUUID, listOf(ALICE_NAME))
Assertions.assertThatThrownBy { networkMapClient.getNetworkMap(privateNetUUID).payload.nodeInfoHashes }
.isInstanceOf(IOException::class.java)
@ -230,6 +240,7 @@ class NetworkMapUpdaterTest {
@Test
fun `remove node from filesystem deletes it from network map cache`() {
setUpdater()
val fileNodeInfoAndSigned1 = createNodeInfoAndSigned("Info from file 1")
val fileNodeInfoAndSigned2 = createNodeInfoAndSigned("Info from file 2")
updater.subscribeToNetworkMap()
@ -252,6 +263,7 @@ class NetworkMapUpdaterTest {
@Test
fun `remove node info file, but node in network map server`() {
setUpdater()
val nodeInfoBuilder = TestNodeInfoBuilder()
val (_, key) = nodeInfoBuilder.addLegalIdentity(CordaX500Name("Info", "London", "GB"))
val (serverNodeInfo, serverSignedNodeInfo) = nodeInfoBuilder.buildWithSigned(1, 1)
@ -280,6 +292,23 @@ class NetworkMapUpdaterTest {
assertThat(networkMapCache.allNodeHashes).containsOnly(serverSignedNodeInfo.raw.hash)
}
// Test fix for ENT-1882
// This scenario can happen when signing of network map server is performed much longer after the node joined the network.
// Network map will advertise hashes without that node.
@Test
fun `not remove own node info when it is not in network map yet`() {
val (myInfo, signedMyInfo) = createNodeInfoAndSigned("My node info")
val (_, signedOtherInfo) = createNodeInfoAndSigned("Other info")
setUpdater(ourNodeHash = signedMyInfo.raw.hash)
networkMapCache.addNode(myInfo) // Simulate behaviour on node startup when our node info is added to cache
networkMapClient.publish(signedOtherInfo)
updater.subscribeToNetworkMap()
Thread.sleep(2L * cacheExpiryMs)
verify(networkMapCache, never()).removeNode(myInfo)
assertThat(server.networkMapHashes()).containsOnly(signedOtherInfo.raw.hash)
assertThat(networkMapCache.allNodeHashes).containsExactlyInAnyOrder(signedMyInfo.raw.hash, signedOtherInfo.raw.hash)
}
private fun createMockNetworkMapCache(): NetworkMapCacheInternal {
return mock {
val data = ConcurrentHashMap<Party, NodeInfo>()

View File

@ -12,9 +12,6 @@ dependencies {
compile "org.apache.activemq:artemis-commons:${artemis_version}"
// Kryo: object graph serialization.
compile "com.esotericsoftware:kryo:4.0.0"
compile "de.javakaffee:kryo-serializers:0.41"
compile "org.ow2.asm:asm:$asm_version"
// For AMQP serialisation.

View File

@ -15,7 +15,7 @@ internal val serializeOutputStreamPool = LazyPool(
shouldReturnToPool = { it.size() < 256 * 1024 }, // Discard if it grew too large
newInstance = { ByteBufferOutputStream(64 * 1024) })
internal fun <T> byteArrayOutput(task: (ByteBufferOutputStream) -> T): ByteArray {
fun <T> byteArrayOutput(task: (ByteBufferOutputStream) -> T): ByteArray {
return serializeOutputStreamPool.run { underlying ->
task(underlying)
underlying.toByteArray() // Must happen after close, to allow ZIP footer to be written for example.

View File

@ -1,6 +1,7 @@
package net.corda.serialization.internal
import net.corda.core.serialization.ClassWhitelist
import java.util.*
interface MutableClassWhitelist : ClassWhitelist {
fun add(entry: Class<*>)
@ -9,3 +10,41 @@ interface MutableClassWhitelist : ClassWhitelist {
object AllWhitelist : ClassWhitelist {
override fun hasListed(type: Class<*>): Boolean = true
}
class BuiltInExceptionsWhitelist : ClassWhitelist {
companion object {
private val packageName = "^(?:java|kotlin)(?:[.]|$)".toRegex()
}
override fun hasListed(type: Class<*>): Boolean {
return Throwable::class.java.isAssignableFrom(type) && packageName.containsMatchIn(type.`package`.name)
}
}
sealed class AbstractMutableClassWhitelist(private val whitelist: MutableSet<String>, private val delegate: ClassWhitelist) : MutableClassWhitelist {
override fun hasListed(type: Class<*>): Boolean {
/**
* There are certain delegates like [net.corda.serialization.internal.AllButBlacklisted]
* which may throw when asked whether the type is listed.
* In such situations - it may be a good idea to ask [delegate] first before making a check against own [whitelist].
*/
return delegate.hasListed(type) || (type.name in whitelist)
}
override fun add(entry: Class<*>) {
whitelist += entry.name
}
}
/**
* A whitelist that can be customised via the [net.corda.core.serialization.SerializationWhitelist],
* since it implements [MutableClassWhitelist].
*/
class TransientClassWhiteList(delegate: ClassWhitelist) : AbstractMutableClassWhitelist(Collections.synchronizedSet(mutableSetOf()), delegate)
// TODO: Need some concept of from which class loader
class GlobalTransientClassWhiteList(delegate: ClassWhitelist) : AbstractMutableClassWhitelist(whitelist, delegate) {
companion object {
private val whitelist: MutableSet<String> = Collections.synchronizedSet(mutableSetOf())
}
}

View File

@ -15,9 +15,6 @@ package net.corda.serialization.internal
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationDefaults
import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.kryo.BuiltInExceptionsWhitelist
import net.corda.serialization.internal.kryo.GlobalTransientClassWhiteList
import net.corda.serialization.internal.kryo.kryoMagic
/*
* Serialisation contexts for the client.
@ -26,10 +23,12 @@ import net.corda.serialization.internal.kryo.kryoMagic
*/
val AMQP_RPC_CLIENT_CONTEXT = SerializationContextImpl(amqpMagic,
val AMQP_RPC_CLIENT_CONTEXT = SerializationContextImpl(
amqpMagic,
SerializationDefaults.javaClass.classLoader,
GlobalTransientClassWhiteList(BuiltInExceptionsWhitelist()),
emptyMap(),
true,
SerializationContext.UseCase.RPCClient,
null)
null
)

View File

@ -10,7 +10,6 @@
package net.corda.serialization.internal
import com.esotericsoftware.kryo.KryoException
import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.utilities.NetworkHostAndPort
import org.apache.activemq.artemis.api.core.SimpleString
@ -40,7 +39,6 @@ object DefaultWhitelist : SerializationWhitelist {
mapOf(Unit to Unit).javaClass, // SingletonMap
NetworkHostAndPort::class.java,
SimpleString::class.java,
KryoException::class.java, // TODO: Will be removed when we migrate away from Kryo
StringBuffer::class.java,
Unit::class.java,
java.io.ByteArrayInputStream::class.java,

View File

@ -10,7 +10,6 @@
package net.corda.serialization.internal
import net.corda.core.internal.VisibleForTesting
import net.corda.core.serialization.SerializationEncoding
import net.corda.core.utilities.ByteSequence
import net.corda.core.utilities.OpaqueBytes
@ -64,5 +63,4 @@ enum class CordaSerializationEncoding : SerializationEncoding, OrdinalWriter {
abstract fun wrap(stream: InputStream): InputStream
}
@VisibleForTesting
internal val encodingNotPermittedFormat = "Encoding not permitted: %s"
const val encodingNotPermittedFormat = "Encoding not permitted: %s"

View File

@ -18,7 +18,6 @@ import net.corda.core.internal.copyBytes
import net.corda.core.serialization.*
import net.corda.core.utilities.ByteSequence
import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.kryo.kryoMagic
import org.slf4j.LoggerFactory
import java.io.NotSerializableException
import java.util.*
@ -108,7 +107,7 @@ open class SerializationFactoryImpl(
constructor() : this(ConcurrentHashMap())
companion object {
val magicSize = sequenceOf(kryoMagic, amqpMagic).map { it.size }.distinct().single()
val magicSize = amqpMagic.size
}
private val creator: List<StackTraceElement> = Exception().stackTrace.asList()
@ -124,7 +123,7 @@ open class SerializationFactoryImpl(
return schemes.computeIfAbsent(lookupKey) {
registeredSchemes.filter { it.canDeserializeVersion(magic, target) }.forEach { return@computeIfAbsent it } // XXX: Not single?
logger.warn("Cannot find serialization scheme for: [$lookupKey, " +
"${if (magic == amqpMagic) "AMQP" else if (magic == kryoMagic) "Kryo" else "UNKNOWN MAGIC"}] registeredSchemes are: $registeredSchemes")
"${if (magic == amqpMagic) "AMQP" else "UNKNOWN MAGIC"}] registeredSchemes are: $registeredSchemes")
throw UnsupportedOperationException("Serialization scheme $lookupKey not supported.")
} to magic
}
@ -154,15 +153,12 @@ open class SerializationFactoryImpl(
registeredSchemes += scheme
}
val alreadyRegisteredSchemes: Collection<SerializationScheme> get() = Collections.unmodifiableCollection(registeredSchemes)
override fun toString(): String {
return "${this.javaClass.name} registeredSchemes=$registeredSchemes ${creator.joinToString("\n")}"
}
override fun equals(other: Any?): Boolean {
return other is SerializationFactoryImpl &&
other.registeredSchemes == this.registeredSchemes
return other is SerializationFactoryImpl && other.registeredSchemes == this.registeredSchemes
}
override fun hashCode(): Int = registeredSchemes.hashCode()

View File

@ -15,9 +15,6 @@ package net.corda.serialization.internal
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationDefaults
import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.kryo.BuiltInExceptionsWhitelist
import net.corda.serialization.internal.kryo.GlobalTransientClassWhiteList
import net.corda.serialization.internal.kryo.kryoMagic
/*
* Serialisation contexts for the server.
@ -30,19 +27,23 @@ import net.corda.serialization.internal.kryo.kryoMagic
*/
val AMQP_STORAGE_CONTEXT = SerializationContextImpl(amqpMagic,
val AMQP_STORAGE_CONTEXT = SerializationContextImpl(
amqpMagic,
SerializationDefaults.javaClass.classLoader,
AllButBlacklisted,
emptyMap(),
true,
SerializationContext.UseCase.Storage,
null,
AlwaysAcceptEncodingWhitelist)
AlwaysAcceptEncodingWhitelist
)
val AMQP_RPC_SERVER_CONTEXT = SerializationContextImpl(amqpMagic,
val AMQP_RPC_SERVER_CONTEXT = SerializationContextImpl(
amqpMagic,
SerializationDefaults.javaClass.classLoader,
GlobalTransientClassWhiteList(BuiltInExceptionsWhitelist()),
emptyMap(),
true,
SerializationContext.UseCase.RPCServer,
null)
null
)

View File

@ -15,35 +15,18 @@ package net.corda.serialization.internal
import net.corda.core.serialization.*
import net.corda.serialization.internal.CordaSerializationEncoding.SNAPPY
import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.kryo.BuiltInExceptionsWhitelist
import net.corda.serialization.internal.kryo.GlobalTransientClassWhiteList
import net.corda.serialization.internal.kryo.kryoMagic
/*
* Serialisation contexts shared by the server and client.
*
* NOTE: The [KRYO_STORAGE_CONTEXT] and [AMQP_STORAGE_CONTEXT]
* CANNOT always be instantiated outside of the server and so
* MUST be kept separate from these ones!
*/
val KRYO_CHECKPOINT_CONTEXT = SerializationContextImpl(kryoMagic,
SerializationDefaults.javaClass.classLoader,
QuasarWhitelist,
emptyMap(),
true,
SerializationContext.UseCase.Checkpoint,
SNAPPY,
AlwaysAcceptEncodingWhitelist)
val AMQP_P2P_CONTEXT = SerializationContextImpl(amqpMagic,
val AMQP_P2P_CONTEXT = SerializationContextImpl(
amqpMagic,
SerializationDefaults.javaClass.classLoader,
GlobalTransientClassWhiteList(BuiltInExceptionsWhitelist()),
emptyMap(),
true,
SerializationContext.UseCase.P2P,
null)
null
)
internal object AlwaysAcceptEncodingWhitelist : EncodingWhitelist {
object AlwaysAcceptEncodingWhitelist : EncodingWhitelist {
override fun acceptEncoding(encoding: SerializationEncoding) = true
}

View File

@ -14,10 +14,10 @@ import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationFactory
import java.util.*
internal fun checkUseCase(allowedUseCases: EnumSet<SerializationContext.UseCase>) {
fun checkUseCase(allowedUseCases: EnumSet<SerializationContext.UseCase>) {
val currentContext: SerializationContext = SerializationFactory.currentFactory?.currentContext
?: throw IllegalStateException("Current context is not set")
if (!allowedUseCases.contains(currentContext.useCase)) {
throw IllegalStateException("UseCase '${currentContext.useCase}' is not within '$allowedUseCases'")
}
}
}

View File

@ -18,10 +18,7 @@ import net.corda.core.internal.objectOrNewInstance
import net.corda.core.internal.uncheckedCast
import net.corda.core.serialization.*
import net.corda.core.utilities.ByteSequence
import net.corda.serialization.internal.CordaSerializationMagic
import net.corda.serialization.internal.DefaultWhitelist
import net.corda.serialization.internal.MutableClassWhitelist
import net.corda.serialization.internal.SerializationScheme
import net.corda.serialization.internal.*
import java.lang.reflect.Modifier
import java.util.*
import java.util.concurrent.ConcurrentHashMap

View File

@ -124,14 +124,33 @@ class MapSerializer(private val declaredType: ParameterizedType, factory: Serial
}
internal fun Class<*>.checkSupportedMapType() {
checkHashMap()
checkWeakHashMap()
checkDictionary()
}
private fun Class<*>.checkHashMap() {
if (HashMap::class.java.isAssignableFrom(this) && !LinkedHashMap::class.java.isAssignableFrom(this)) {
throw IllegalArgumentException(
"Map type $this is unstable under iteration. Suggested fix: use java.util.LinkedHashMap instead.")
} else if (WeakHashMap::class.java.isAssignableFrom(this)) {
}
}
/**
* The [WeakHashMap] class does not exist within the DJVM, and so we need
* to isolate this reference.
*/
private fun Class<*>.checkWeakHashMap() {
if (WeakHashMap::class.java.isAssignableFrom(this)) {
throw IllegalArgumentException("Weak references with map types not supported. Suggested fix: "
+ "use java.util.LinkedHashMap instead.")
} else if (Dictionary::class.java.isAssignableFrom(this)) {
}
}
private fun Class<*>.checkDictionary() {
if (Dictionary::class.java.isAssignableFrom(this)) {
throw IllegalArgumentException(
"Unable to serialise deprecated type $this. Suggested fix: prefer java.util.map implementations")
}
}
}

View File

@ -1,4 +1,4 @@
package net.corda.nodeapi.internal.serialization.amqp.custom
package net.corda.serialization.internal.amqp.custom
import net.corda.serialization.internal.amqp.CustomSerializer
import net.corda.serialization.internal.amqp.SerializerFactory

View File

@ -10,18 +10,18 @@
package net.corda.serialization.internal;
import com.google.common.collect.Maps;
import net.corda.core.serialization.SerializationContext;
import net.corda.core.serialization.SerializationFactory;
import net.corda.core.serialization.SerializedBytes;
import net.corda.node.serialization.kryo.CordaClosureSerializer;
import net.corda.node.serialization.kryo.KryoSerializationSchemeKt;
import net.corda.testing.core.SerializationEnvironmentRule;
import net.corda.serialization.internal.kryo.CordaClosureSerializer;
import net.corda.serialization.internal.kryo.KryoSerializationSchemeKt;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import java.io.Serializable;
import java.util.Collections;
import java.util.concurrent.Callable;
import static org.assertj.core.api.Assertions.assertThat;
@ -36,7 +36,15 @@ public final class LambdaCheckpointSerializationTest {
@Before
public void setup() {
factory = testSerialization.getSerializationFactory();
context = new SerializationContextImpl(KryoSerializationSchemeKt.getKryoMagic(), this.getClass().getClassLoader(), AllWhitelist.INSTANCE, Maps.newHashMap(), true, SerializationContext.UseCase.Checkpoint, null);
context = new SerializationContextImpl(
KryoSerializationSchemeKt.getKryoMagic(),
getClass().getClassLoader(),
AllWhitelist.INSTANCE,
Collections.emptyMap(),
true,
SerializationContext.UseCase.Checkpoint,
null
);
}
@Test

View File

@ -24,9 +24,9 @@ import net.corda.core.node.services.AttachmentStorage
import net.corda.core.serialization.ClassWhitelist
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializationContext
import net.corda.serialization.internal.kryo.CordaClassResolver
import net.corda.serialization.internal.kryo.CordaKryo
import net.corda.serialization.internal.kryo.kryoMagic
import net.corda.node.serialization.kryo.CordaClassResolver
import net.corda.node.serialization.kryo.CordaKryo
import net.corda.node.serialization.kryo.kryoMagic
import net.corda.testing.internal.rigorousMock
import net.corda.testing.services.MockAttachmentStorage
import org.junit.Rule

View File

@ -13,11 +13,11 @@ package net.corda.serialization.internal
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.util.DefaultClassResolver
import net.corda.core.serialization.*
import net.corda.node.serialization.kryo.kryoMagic
import net.corda.node.services.statemachine.DataSessionMessage
import net.corda.serialization.internal.amqp.DeserializationInput
import net.corda.serialization.internal.amqp.Envelope
import net.corda.serialization.internal.amqp.SerializerFactory
import net.corda.serialization.internal.kryo.kryoMagic
import net.corda.testing.internal.amqpSpecific
import net.corda.testing.internal.kryoSpecific
import net.corda.testing.core.SerializationEnvironmentRule

View File

@ -16,8 +16,8 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
import net.corda.node.serialization.kryo.kryoMagic
import net.corda.node.services.statemachine.DataSessionMessage
import net.corda.serialization.internal.kryo.kryoMagic
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.internal.amqpSpecific
import net.corda.testing.internal.kryoSpecific

View File

@ -15,10 +15,10 @@ import com.esotericsoftware.kryo.KryoException
import com.esotericsoftware.kryo.io.Output
import net.corda.core.serialization.*
import net.corda.core.utilities.OpaqueBytes
import net.corda.serialization.internal.kryo.CordaClassResolver
import net.corda.serialization.internal.kryo.CordaKryo
import net.corda.serialization.internal.kryo.DefaultKryoCustomizer
import net.corda.serialization.internal.kryo.kryoMagic
import net.corda.node.serialization.kryo.CordaClassResolver
import net.corda.node.serialization.kryo.CordaKryo
import net.corda.node.serialization.kryo.DefaultKryoCustomizer
import net.corda.node.serialization.kryo.kryoMagic
import net.corda.testing.internal.rigorousMock
import net.corda.testing.core.SerializationEnvironmentRule
import org.assertj.core.api.Assertions.assertThat

View File

@ -14,8 +14,8 @@ import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.util.DefaultClassResolver
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
import net.corda.node.serialization.kryo.kryoMagic
import net.corda.node.services.statemachine.DataSessionMessage
import net.corda.serialization.internal.kryo.kryoMagic
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.internal.kryoSpecific
import org.junit.Assert.assertArrayEquals

View File

@ -3,8 +3,8 @@ package net.corda.serialization.internal.amqp
import net.corda.core.serialization.*
import net.corda.core.utilities.ByteSequence
import net.corda.serialization.internal.*
import net.corda.serialization.internal.kryo.BuiltInExceptionsWhitelist
import net.corda.serialization.internal.kryo.GlobalTransientClassWhiteList
import net.corda.serialization.internal.BuiltInExceptionsWhitelist
import net.corda.serialization.internal.GlobalTransientClassWhiteList
import org.junit.Test
import java.util.concurrent.ConcurrentHashMap
import kotlin.test.assertEquals

View File

@ -59,7 +59,7 @@ import java.util.*
/**
* Returns a simple [InMemoryIdentityService] containing the supplied [identities].
*/
fun makeTestIdentityService(vararg identities: PartyAndCertificate) = InMemoryIdentityService(identities, DEV_ROOT_CA.certificate)
fun makeTestIdentityService(vararg identities: PartyAndCertificate) = InMemoryIdentityService(identities.toList(), DEV_ROOT_CA.certificate)
/**
* An implementation of [ServiceHub] that is designed for in-memory unit tests of contract validation logic. It has

View File

@ -15,11 +15,11 @@
</Properties>
<Appenders>
<Console name="Console-Appender" target="SYSTEM_OUT">
<PatternLayout pattern="[%-5level] %date{HH:mm:ss,SSS} [%t] (%F:%L) %c{2}.%method - %msg %X%n" />
<PatternLayout pattern="[%-5level] %date{HH:mm:ss,SSS} [%t] (%F:%L) %c{2}.%method - %msg %equals{%X}{{}}{}%n"/>
</Console>
<!-- Required for printBasicInfo -->
<Console name="Console-Appender-Println" target="SYSTEM_OUT">
<PatternLayout pattern="%msg%n" />
<PatternLayout pattern="%msg%n"/>
</Console>
</Appenders>
<Loggers>
@ -32,8 +32,8 @@
<Logger name="BasicInfo" additivity="false">
<AppenderRef ref="Console-Appender-Println"/>
</Logger>
<Logger name="org.hibernate.SQL" level="info" additivity="false">
<AppenderRef ref="Console-Appender"/>
<Logger name="org.hibernate.SQL" level="info" additivity="false">
<AppenderRef ref="Console-Appender"/>
</Logger>
<Logger name="org.jolokia" additivity="true" level="warn">
<AppenderRef ref="Console-Appender-Println"/>

View File

@ -16,6 +16,7 @@ import net.corda.client.rpc.internal.serialization.amqp.AMQPClientSerializationS
import net.corda.core.DoNotImplement
import net.corda.core.serialization.internal.*
import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
import net.corda.node.serialization.kryo.KRYO_CHECKPOINT_CONTEXT
import net.corda.node.serialization.kryo.KryoServerSerializationScheme
import net.corda.serialization.internal.*
import net.corda.testing.core.SerializationEnvironmentRule

View File

@ -18,7 +18,7 @@
<Appenders>
<Console name="Console-Appender" target="SYSTEM_OUT">
<PatternLayout pattern="[%-5level] %date{HH:mm:ss,SSS} [%t] (%F:%L) %c{2}.%method - %msg %X%n" />
<PatternLayout pattern="[%-5level] %date{HH:mm:ss,SSS} [%t] (%F:%L) %c{2}.%method - %msg %equals{%X}{{}}{}%n" />
</Console>
</Appenders>

View File

@ -46,7 +46,7 @@ class InteractiveShellTest {
override fun call() = a
}
private val ids = InMemoryIdentityService(arrayOf(megaCorp.identity), DEV_ROOT_CA.certificate)
private val ids = InMemoryIdentityService(listOf(megaCorp.identity), DEV_ROOT_CA.certificate)
@Suppress("DEPRECATION")
private val om = JacksonSupport.createInMemoryMapper(ids, YAMLFactory())

View File

@ -12,9 +12,10 @@
package com.r3.enclaves.txverify
import com.esotericsoftware.minlog.Log
import net.corda.core.contracts.Attachment
import net.corda.core.serialization.*
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializedBytes
import net.corda.core.serialization.deserialize
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.WireTransaction
import java.io.File
@ -82,7 +83,6 @@ private fun deserialise(reqBytes: ByteArray): LedgerTransaction {
// Note: This is only here for debugging purposes
fun main(args: Array<String>) {
Log.TRACE()
Class.forName("com.r3.enclaves.txverify.EnclaveletSerializationScheme")
val reqBytes = File(args[0]).readBytes()
verifyInEnclave(reqBytes)

View File

@ -21,8 +21,6 @@ import net.corda.serialization.internal.SerializationFactoryImpl
import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme
import net.corda.serialization.internal.amqp.SerializerFactory
import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.kryo.AbstractKryoSerializationScheme
import net.corda.serialization.internal.kryo.kryoMagic
@Suppress("UNUSED")
private class EnclaveletSerializationScheme {
@ -33,7 +31,6 @@ private class EnclaveletSerializationScheme {
init {
nodeSerializationEnv = SerializationEnvironmentImpl(
SerializationFactoryImpl(HashMap()).apply {
registerScheme(KryoVerifierSerializationScheme)
registerScheme(AMQPVerifierSerializationScheme)
},
/**
@ -50,15 +47,6 @@ private class EnclaveletSerializationScheme {
}
}
private object KryoVerifierSerializationScheme : AbstractKryoSerializationScheme() {
override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean {
return magic == kryoMagic && target == SerializationContext.UseCase.P2P
}
override fun rpcClientKryoPool(context: SerializationContext) = throw UnsupportedOperationException()
override fun rpcServerKryoPool(context: SerializationContext) = throw UnsupportedOperationException()
}
private object AMQPVerifierSerializationScheme : AbstractAMQPSerializationScheme(emptySet(), HashMap()) {
override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean {
return magic == amqpMagic && target == SerializationContext.UseCase.P2P