Uploaded image for project: 'Corda'
  1. CORDA-2633

Provide a better error message on an incompatible implicit contract upgrade

    Details

    • Type: Bug
    • Status: Done (View workflow)
    • Priority: Medium
    • Resolution: Done
    • Affects versions: Corda 4 RC05
    • Fix versions: Corda 4.1
    • Components: None
    • Labels:
      None

      Description

      When using signature constraints and implicit contract upgrades, if the upgraded version is incompatible with the older version (e.g. a new non-nullable field is added), a deserialization error occurs when trying to load an old state with the new version of the app.

      For example:

      Caused by: net.corda.core.node.services.VaultQueryException: An error occurred while attempting to query the vault: Failed to deserialise group OUTPUTS_GROUP at index 0 in transaction:           Cannot construct evolution serializer for remote type net.corda.finance.contracts.asset.Cash$State: net.corda.core.contracts.FungibleAsset<java.util.Currency>, net.corda.core.contracts.FungibleState<net.corda.core.contracts.Issued<java.util.Currency>>, net.corda.core.contracts.ContractState, net.corda.core.contracts.OwnableState, net.corda.core.schemas.QueryableState
      amount: net.corda.core.contracts.Amount<net.corda.core.contracts.Issued<java.util.Currency>>
        displayTokenSize: java.math.BigDecimal
        quantity: long
        token: net.corda.core.contracts.Issued<java.util.Currency>
          issuer: net.corda.core.contracts.PartyAndReference
            party: net.corda.core.identity.AbstractParty
              owningKey: java.security.PublicKey
            reference: net.corda.core.utilities.OpaqueBytes
              bytes: byte[]
          product: java.util.Currency
      exitKeys: java.util.Collection<java.security.PublicKey>
      owner: net.corda.core.identity.AbstractParty
        owningKey: java.security.PublicKey
      
                Mandatory property upgradedState of local type is not present in remote type - did someone remove a property from the schema without considering old clients?
      	at net.corda.node.services.vault.NodeVaultService._queryBy(NodeVaultService.kt:519) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.CordaRPCOpsImpl.vaultQueryBy(CordaRPCOpsImpl.kt:108) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.CordaRPCOpsImpl.vaultQuery(CordaRPCOpsImpl.kt:264) ~[corda-node-4.0-RC05.jar:?]
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_202]
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_202]
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_202]
      	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_202]
      	at net.corda.node.internal.InvocationHandlerTemplate$DefaultImpls.invoke(InvocationHandlerTemplate.kt:16) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy$PermissionsEnforcingInvocationHandler$invoke$1.invoke(AuthenticatedRpcOpsProxy.kt:42) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.guard(AuthenticatedRpcOpsProxy.kt:52) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.guard(AuthenticatedRpcOpsProxy.kt:46) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.access$guard(AuthenticatedRpcOpsProxy.kt:1) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy$PermissionsEnforcingInvocationHandler.invoke(AuthenticatedRpcOpsProxy.kt:42) ~[corda-node-4.0-RC05.jar:?]
      	... 42 more
      Caused by: net.corda.core.internal.TransactionDeserialisationException: Failed to deserialise group OUTPUTS_GROUP at index 0 in transaction:           Cannot construct evolution serializer for remote type net.corda.finance.contracts.asset.Cash$State: net.corda.core.contracts.FungibleAsset<java.util.Currency>, net.corda.core.contracts.FungibleState<net.corda.core.contracts.Issued<java.util.Currency>>, net.corda.core.contracts.ContractState, net.corda.core.contracts.OwnableState, net.corda.core.schemas.QueryableState
      amount: net.corda.core.contracts.Amount<net.corda.core.contracts.Issued<java.util.Currency>>
        displayTokenSize: java.math.BigDecimal
        quantity: long
        token: net.corda.core.contracts.Issued<java.util.Currency>
          issuer: net.corda.core.contracts.PartyAndReference
            party: net.corda.core.identity.AbstractParty
              owningKey: java.security.PublicKey
            reference: net.corda.core.utilities.OpaqueBytes
              bytes: byte[]
          product: java.util.Currency
      exitKeys: java.util.Collection<java.security.PublicKey>
      owner: net.corda.core.identity.AbstractParty
        owningKey: java.security.PublicKey
      
                Mandatory property upgradedState of local type is not present in remote type - did someone remove a property from the schema without considering old clients?
      	at net.corda.core.internal.TransactionUtilsKt$deserialiseComponentGroup$1.invoke(TransactionUtils.kt:82) ~[corda-core-4.0-RC05.jar:?]
      	at net.corda.core.internal.TransactionUtilsKt$deserialiseComponentGroup$1.invoke(TransactionUtils.kt) ~[corda-core-4.0-RC05.jar:?]
      	at net.corda.core.internal.LazyMappedList.get(InternalUtils.kt:533) ~[corda-core-4.0-RC05.jar:?]
      	at net.corda.node.internal.ServicesForResolutionImpl.loadStates(ServicesForResolutionImpl.kt:38) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.services.vault.NodeVaultService$_queryBy$2.invoke(NodeVaultService.kt:604) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.services.vault.NodeVaultService$_queryBy$2.invoke(NodeVaultService.kt:55) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.nodeapi.internal.persistence.CordaPersistence.inTopLevelTransaction(CordaPersistence.kt:236) ~[corda-node-api-4.0-RC05.jar:?]
      	at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:221) ~[corda-node-api-4.0-RC05.jar:?]
      	at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:199) ~[corda-node-api-4.0-RC05.jar:?]
      	at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:205) ~[corda-node-api-4.0-RC05.jar:?]
      	at net.corda.node.services.vault.NodeVaultService._queryBy(NodeVaultService.kt:526) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.services.vault.NodeVaultService._queryBy(NodeVaultService.kt:515) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.CordaRPCOpsImpl.vaultQueryBy(CordaRPCOpsImpl.kt:108) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.CordaRPCOpsImpl.vaultQuery(CordaRPCOpsImpl.kt:264) ~[corda-node-4.0-RC05.jar:?]
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_202]
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_202]
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_202]
      	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_202]
      	at net.corda.node.internal.InvocationHandlerTemplate$DefaultImpls.invoke(InvocationHandlerTemplate.kt:16) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy$PermissionsEnforcingInvocationHandler$invoke$1.invoke(AuthenticatedRpcOpsProxy.kt:42) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.guard(AuthenticatedRpcOpsProxy.kt:52) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.guard(AuthenticatedRpcOpsProxy.kt:46) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.access$guard(AuthenticatedRpcOpsProxy.kt:1) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy$PermissionsEnforcingInvocationHandler.invoke(AuthenticatedRpcOpsProxy.kt:42) ~[corda-node-4.0-RC05.jar:?]
      	... 42 more
      Caused by: net.corda.serialization.internal.amqp.EvolutionSerializationException:           Cannot construct evolution serializer for remote type net.corda.finance.contracts.asset.Cash$State: net.corda.core.contracts.FungibleAsset<java.util.Currency>, net.corda.core.contracts.FungibleState<net.corda.core.contracts.Issued<java.util.Currency>>, net.corda.core.contracts.ContractState, net.corda.core.contracts.OwnableState, net.corda.core.schemas.QueryableState
      amount: net.corda.core.contracts.Amount<net.corda.core.contracts.Issued<java.util.Currency>>
        displayTokenSize: java.math.BigDecimal
        quantity: long
        token: net.corda.core.contracts.Issued<java.util.Currency>
          issuer: net.corda.core.contracts.PartyAndReference
            party: net.corda.core.identity.AbstractParty
              owningKey: java.security.PublicKey
            reference: net.corda.core.utilities.OpaqueBytes
              bytes: byte[]
          product: java.util.Currency
      exitKeys: java.util.Collection<java.security.PublicKey>
      owner: net.corda.core.identity.AbstractParty
        owningKey: java.security.PublicKey
      
                Mandatory property upgradedState of local type is not present in remote type - did someone remove a property from the schema without considering old clients?
      	at net.corda.serialization.internal.amqp.DefaultEvolutionSerializerFactory.validateEvolvability(EvolutionSerializerFactory.kt:110) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DefaultEvolutionSerializerFactory.getEvolutionSerializer(EvolutionSerializerFactory.kt:65) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DefaultEvolutionSerializerFactory.getEvolutionSerializer(EvolutionSerializerFactory.kt:40) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory.getUncached(RemoteSerializerFactory.kt:99) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory.access$getUncached(RemoteSerializerFactory.kt:47) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory$get$1$$special$$inlined$mapValues$lambda$1.invoke(RemoteSerializerFactory.kt:73) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory$get$1$$special$$inlined$mapValues$lambda$1.invoke(RemoteSerializerFactory.kt:47) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DefaultDescriptorBasedSerializerRegistry.getOrBuild(DescriptorBasedSerializerRegistry.kt:28) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory$get$1.invoke(RemoteSerializerFactory.kt:72) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory$get$1.invoke(RemoteSerializerFactory.kt:47) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DefaultDescriptorBasedSerializerRegistry.getOrBuild(DescriptorBasedSerializerRegistry.kt:28) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory.get(RemoteSerializerFactory.kt:62) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.ComposedSerializerFactory.get(SerializerFactory.kt) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DeserializationInput.readObject$serialization(DeserializationInput.kt:172) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DeserializationInput.readObjectOrNull$serialization(DeserializationInput.kt:147) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DeserializationInput$deserialize$1.invoke(DeserializationInput.kt:124) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DeserializationInput.des(DeserializationInput.kt:99) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.DeserializationInput.deserialize(DeserializationInput.kt:119) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme.deserialize(AMQPSerializationScheme.kt:225) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.SerializationFactoryImpl$deserialize$1$1.invoke(SerializationScheme.kt:102) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.core.serialization.SerializationFactory.withCurrentContext(SerializationAPI.kt:72) ~[corda-core-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.SerializationFactoryImpl$deserialize$1.invoke(SerializationScheme.kt:102) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.SerializationFactoryImpl$deserialize$1.invoke(SerializationScheme.kt:70) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.core.serialization.SerializationFactory.asCurrent(SerializationAPI.kt:86) ~[corda-core-4.0-RC05.jar:?]
      	at net.corda.serialization.internal.SerializationFactoryImpl.deserialize(SerializationScheme.kt:102) ~[corda-serialization-4.0-RC05.jar:?]
      	at net.corda.core.internal.TransactionUtilsKt$deserialiseComponentGroup$1.invoke(TransactionUtils.kt:78) ~[corda-core-4.0-RC05.jar:?]
      	at net.corda.core.internal.TransactionUtilsKt$deserialiseComponentGroup$1.invoke(TransactionUtils.kt) ~[corda-core-4.0-RC05.jar:?]
      	at net.corda.core.internal.LazyMappedList.get(InternalUtils.kt:533) ~[corda-core-4.0-RC05.jar:?]
      	at net.corda.node.internal.ServicesForResolutionImpl.loadStates(ServicesForResolutionImpl.kt:38) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.services.vault.NodeVaultService$_queryBy$2.invoke(NodeVaultService.kt:604) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.services.vault.NodeVaultService$_queryBy$2.invoke(NodeVaultService.kt:55) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.nodeapi.internal.persistence.CordaPersistence.inTopLevelTransaction(CordaPersistence.kt:236) ~[corda-node-api-4.0-RC05.jar:?]
      	at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:221) ~[corda-node-api-4.0-RC05.jar:?]
      	at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:199) ~[corda-node-api-4.0-RC05.jar:?]
      	at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:205) ~[corda-node-api-4.0-RC05.jar:?]
      	at net.corda.node.services.vault.NodeVaultService._queryBy(NodeVaultService.kt:526) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.services.vault.NodeVaultService._queryBy(NodeVaultService.kt:515) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.CordaRPCOpsImpl.vaultQueryBy(CordaRPCOpsImpl.kt:108) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.CordaRPCOpsImpl.vaultQuery(CordaRPCOpsImpl.kt:264) ~[corda-node-4.0-RC05.jar:?]
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_202]
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_202]
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_202]
      	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_202]
      	at net.corda.node.internal.InvocationHandlerTemplate$DefaultImpls.invoke(InvocationHandlerTemplate.kt:16) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy$PermissionsEnforcingInvocationHandler$invoke$1.invoke(AuthenticatedRpcOpsProxy.kt:42) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.guard(AuthenticatedRpcOpsProxy.kt:52) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.guard(AuthenticatedRpcOpsProxy.kt:46) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.access$guard(AuthenticatedRpcOpsProxy.kt:1) ~[corda-node-4.0-RC05.jar:?]
      	at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy$PermissionsEnforcingInvocationHandler.invoke(AuthenticatedRpcOpsProxy.kt:42) ~[corda-node-4.0-RC05.jar:?]
      	... 42 more
      

      For user this exception message is very cryptic and does not explain what the root cause can be.

        Attachments

          Activity

            People

            • Assignee:
              james.higgs James Higgs
              Reporter:
              andrius.dagys Andrius Dagys
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: