0
votes

I'm struggling to understand the cause of the issue that I'm facing.

I have a module with Contracts and module with Validators. Some of the Validators are being used in Contracts' module. For example:

override fun verify(tx: LedgerTransaction){
   validator.validate(tx.outputs)
}

I start my flow and during Contract verification, I see: ClassNotFoundException so the Class from Validators module cannot be found in the classloader. Obviously, CorDapp with Validators exists in the node.

While debugging Corda Framework, I can see that attachments will be uploaded into AttachmentStorageInternal during the start-up, but only those jar which includes Contracts.

private fun loadContractsIntoAttachmentStore(): Map<SecureHash, URL> =
        cordapps.filter { !it.contractClassNames.isEmpty() }.map {
            it.jarPath.openStream().use { stream -> //some code}

Moreover, I can see that during a Verification stage, when ClassNotFoundException or ClassNotDefFoundException occurs, then Corda will try to load missing class, but it will try to find it only from Contract Attachments that were uploaded on the start-up of the Node.

fun AttachmentStorage.internalFindTrustedAttachmentForClass(className: String): Attachment? {
    val allTrusted = queryAttachments(
            AttachmentQueryCriteria.AttachmentsQueryCriteria().withUploader(Builder.`in`(TRUSTED_UPLOADERS)),
            AttachmentSort(listOf(AttachmentSort.AttachmentSortColumn(AttachmentSort.AttachmentSortAttribute.VERSION, Sort.Direction.DESC))))

    for (attId in allTrusted) {
  1. Can someone point me out, how Corda will load helper classes that Contract's verify() method might need in my implementation?
  2. Is it possible to use classes from other modules in Contacts' CorDapp?
2
did you fat jar your contract jar? In that, all the dependencies it needs are built into the jar itself? This will make it larger but not require any other external jars. Funnily enough I was actually talking about this with my colleague the other day who proposed a different solution. I need to manually test the solution before I can confirm that it works.Dan Newton
no, I try to avoid having a fat jar for contracts and my contract module consists only of State and Contract... I guess I'll leave that as a last option, but I totally agree that that would work as far as Contract would have Validators inside its jar.edward_wong
@DanNewton I guess the most dirtiest workaround would be to have a Dummy Contract in that Shared library ? :Dedward_wong
This might help. But it is not a solution that I have tried myself. “Whenever your contract code depends on some external library, the flow must explicitly attach that dependency to the transaction, and there must be a check in the contract code that ensures that a malicious party didn’t attach an invalid dependency JAR that could compromise the verification logic.”Dan Newton

2 Answers

1
votes

Are you using Corda v4.0? I remember v4.1 made some changes to revert back to the class loader if you do not manually add the cordapp as an attachment. Can you try adding the Cordapp with your dependencies as an attachment and see if it works? https://docs.corda.net/head/cordapp-advanced-concepts.html?advanced-cordapp-concepts#code-samples-for-dependent-libraries-and-cordapps

1
votes

There are several options:

  1. The possible workaround is to add a DummyContract into the dependent helper module. Adding something like:

    class DummyContract : Contract {
        override fun verify(tx: LedgerTransaction)
    }
    

Will force Corda to upload Attachment on Corda Node's startup and during Verification stage, Corda will add missing attachments into the transactionClassLoader

  1. There is always a possibility to create a fat - jar. The Contracts module may (and even should) have all the dependencies inside of it. If your Contract has any external dependencies, they are an inevitable part of the contract itself. Theoretically, if you release a new version of a dependent module, you would be required to initiate Contract upgrade flow.

  2. Probably one of the options is to avoid having the dependency at all if it is possible. One of the suggestions from R3 team was to not rely on: addMissingAttachments and avoid it, if it is possible.

  3. R3 Team will enhance the work with the dependencies in future versions of Corda. Probably in Corda 5.

Kudos to Dan N, Stefano and Roger W.