Giter Club home page Giter Club logo

accounts's Introduction

Corda

Corda Accounts Library

Reminder

This project is open source under an Apache 2.0 licence. That means you can submit PRs to fix bugs and add new features if they are not currently available.

What is the accounts library?

In the context of Corda, the accounts library allows a Corda node to partition the vault—a collection of state objects—into a number of subsets, where each subset represents an account. In other words, the accounts library allows a Corda node operator to split the vault into multiple "logical" sub-vaults. This is advantageous for a couple of reasons:

  • Node operators can reduce costs by hosting multiple entities, as accounts, on one node
  • Node operators can partition the vault on a per entity basis

Accounts are created by host nodes, which are just regular Corda nodes. Hosts can create accounts for a range of purposes such as customer accounts, balance sheets or P&L accounts, employee accounts, etc.

The accounts library takes the form of a JAR which can be dropped into the CorDapps folder. Use of it is optional. This means that some nodes will support accounts but others will not. This is intentional by design as not all nodes will need to support accounts and the optional nature of accounts reduces the learning curve for new CorDapp developers.

How to use the library?

See the docs here for how to build CorDapps using accounts.

By far the easiest way to get started with the accounts SDK is to use the "tokens template" which is a branch on the kotlin version of the "CorDapp template". You can obtain it with the following commands:

git clone https://github.com/corda/cordapp-template-kotlin
cd cordapp-template-kotlin
git checkout token-template

Once you have cloned the repository, you should open it with IntelliJ. This will give you a template repo with tokens and accounts dependencies already included.

Example Account Projects

There are three projects demonstrating how to use accounts in the examples sub-directory:

Adding accounts dependencies to an existing CorDapp

First, add a variable for the accounts release group and the version you wish to use and set the corda version that should've been installed locally::

buildscript {
    ext {
        corda_release_version = '4.3-RC01'
        accounts_release_version = '1.0-RC04'
        accounts_release_group = 'com.r3.corda.lib.accounts'
        confidential_id_release_group = "com.r3.corda.lib.ci"
        confidential_id_release_version = "1.0-RC03"
    }
}

Second, you must add the accounts artifactory repository to the list of repositories for your project (if it hasn't already been added):

repositories {
    maven { url 'https://software.r3.com/artifactory/corda-lib-dev' }
    maven { url 'https://software.r3.com/artifactory/corda-lib' }
}

Now, you can add the accounts dependencies to the dependencies block in each module of your CorDapp. For contract modules add:

cordaCompile "$accounts_release_group:accounts-contracts:$accounts_release_version"

In your workflow build.gradle add:

cordaCompile "$confidential_id_release_group:ci-workflows:$confidential_id_release_version"
cordaCompile "$accounts_release_group:accounts-workflows:$accounts_release_version"

If you want to use the deployNodes task, you will need to add the following dependencies to your root build.gradle file:

cordapp "$confidential_id_release_group:ci-workflows:$confidential_id_release_version"
cordapp "$accounts_release_group:accounts-contracts:$accounts_release_version"
cordapp "$accounts_release_group:accounts-workflows:$accounts_release_version"

These should also be added to the deployNodes task with the following syntax:

nodeDefaults {
    projectCordapp {
        deploy = false
    }
    cordapp("$confidential_id_release_group:ci-workflows:$confidential_id_release_version")
    cordapp("$accounts_release_group:accounts-contracts:$accounts_release_version")
    cordapp("$accounts_release_group:accounts-workflows:$accounts_release_version")
}

Modifying An Existing CorDapp to Use Accounts

States should use AnonymousParty instead of Party as a Party refers to a node and the PublicKey can refer to an account.

In order to create your state you need to request the PublicKey with a flow. e.g.

val lenderKey = subFlow(RequestKeyForAccount(lenderAccountInfo.state.data)).owningKey

Once you have keys you need to have logic to determine who signs.

If your accounts are on the same node that you are running the flow on then they can all be on the signInitialTransaction, however, if one is on another node you need to use a CollectSignatureFlow

When calling the FinalityFlow you will need different sessions depending on if all the accounts are on one node or on different nodes.

If accounts are on different nodes you need to shareAccountInfoWithParty before you can transact between accounts otherwise the nodes running the flows wont be aware of the accounts on the other nodes.

Currently, if accounts are on different nodes you also need to run shareStateAndSyncAccounts after the flow to make sure that you can use all methods to look up accountInfo.

Installing the accounts library

If you wish to build the accounts library from source then do the following to publish binaries to your local maven repository:

git clone https://github.com/corda/accounts
cd accounts
./gradlew clean install

Other useful links

Contributing

accounts's People

Contributors

etaroid avatar kasiastreich avatar knguyen-r3 avatar opticyclic avatar rajvjn avatar roastario avatar ronanbrowne avatar willhr3 avatar wzur-r3 avatar zkiss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

accounts's Issues

Incorrect result with Token intergration using Accounts

Hi,

I have executed ConfidentialIntegrationTest provided in the examples folder. I have added another account on both nodes A and B. Hence following is my configuration
Node A -> Account A1 and Account A2
Node B -> Account B1 and Account B2

Process 1:
Step 1: Issue 100 tokens to A1 and A2 :
Expected Balances: A1 - 100, A2 -100 ,B1 -0 ,B2 - 0
Actual Balances : A1 - 100, A2 -100 ,B1 -0 ,B2 - 0

Step 2: Move 25 units from A1 - B1
Expected Balances: A1 - 75, A2 -100 ,B1 -25 ,B2 - 0
Actual Balances : A1 - 75, A2 -100 ,B1 -25 ,B2 - 0

Step 3: Move 30 units from A2 - B2
Expected Balances: A1 - 75, A2 -70 ,B1 -25 ,B2 - 30
Actual Balances : A1 - 75, A2 -70 ,B1 -25 ,B2 - 30

Step 4: Move 25 units from A1 - B1
Expected Balances: A1 - 50, A2 -70 ,B1 -25,25 (50) ,B2 - 30
Actual Balances : A1 - 50, A2 -70 ,B1 -25,25 (50) ,B2 - 30

Process 2:
Restart the whole process

Step 1: Issue 100 tokens to A1 and A2 :
Expected Balances: A1 - 100, A2 -100 ,B1 -0 ,B2 - 0
Actual Balances : A1 - 100, A2 -100 ,B1 -0 ,B2 - 0

Step 2: Move 25 units from A1 - B1
Expected Balances: A1 - 75, A2 -100 ,B1 -25 ,B2 - 0
Actual Balances : A1 - 75, A2 -100 ,B1 -25 ,B2 - 0

Step 3: Move 25 units from A1 - B1
Expected Balances: A1 - 50, A2 -70 ,B1 -25,25 (50) ,B2 - 30
Actual Balances : A1 - 75, A2 -75 ,B1 -25,25 (50) ,B2 - 0

Step 4: Move 30 units from A2 - B2
Expected Balances: A1 - 75, A2 -70 ,B1 -25 ,B2 - 30
Actual Balances : A1 - 75, A2 -45 ,B1 -25 ,B2 - 30

As you can see transfer happens in an alternate fashion from the accounts in Node A.
I have also executed the same test by explicitly by specifying public key of the Account instead of using the Node's Legal identity. I have found it to behave in the same manner.

Can somebody please explain what is going on in the above scenario? Is there anyway to mitigate this error and ensure that the tokens are indeed deducted from the expected accounts.

Thanks in advance

Advice on implementing equivalent to FlowLogic.ourIdentity

It's typical for developers to rely on Flow.ourIdentity or (FlowStateMachine.ourIdentity if you like) for a consistent result in regards to the initiating identity. This may seem trivial but in practice provides an implicit identity context to a flow and all subflows or other components used during execution of it's FlowLogic.call.

My question is, how could an app-specific implementation/initialization in FlowLogic reliably "store" an AccountInfo (or PublicKey, or AnonymousParty) object to provide a similar context and API for all code within a FlowLogic.call stack?

Create A Flow And Service To Share/Synchronise All Accounts

There is a service called shareAccountInfoWithParty that the gold-trading example uses for trading using accounts instead of nodes.

It would be useful if there was a function that shared all accounts with another Party/node.

The next logical step would be to have the other node share all their accounts back.

The final step would be to have a function that iterated over all the nodes on the network and shared/synchronised all the accounts between all nodes so that every account would be able to deal with any other account in the same way that every node is automatically able to deal with any other node.

Improvement Suggestion

As we can see that under one node many accounts are produced to make it more sensible add the feature like private key or password. So, user can be authorized by the account library only. I know it can be handled on application-level also but adding features like this can make more secure to access cordapp.
Can generate a private key from name or UUID at the time of the creation of account. And add one more function to verify the account. So, we can verify by library function only(function which returns boolean value by verifying the keys).

There is one more question
If we can have a private key feature then how it can be handled with different node and registered accounts with them?
More suggestions are admired

SendKeyForAccountFlow to return AnonymousParty

It would be beneficial, here that:

class SendKeyForAccountFlow(val otherSide: FlowSession) : FlowLogic<Unit>() {

Be instead:

class SendKeyForAccountFlow(val otherSide: FlowSession) : FlowLogic<AnonymousParty>() {

My use case is an atomic sale, 1 NFT in exchange for a bunch of fungible tokens:

  • The seller initiates, it has the account's id of the buyer.
  • The seller asks the buyer's host what anonymous party to use as the new holder for the NFT, via RequestKeyForAccountFlow.
  • The buyer sends a new anonymous party, and keeps a copy for itself in the session, via the "new" SendKeyForAccountFlow.
  • The seller creates the transaction, signs it and asks for signature from the buyer.
  • The buyer receives the transaction, and confirms that the NFT holder is exactly the anonymous party that was previously sent.

For the reason of "the buyer verifies that the transaction is correct", the buyer session needs to know what was sent earlier.

You will notice that this way of doing is already done in confidential identities here for ProvideKeyFlow.

How to extend AccountInfo ContractState

I have a use case where each account would have some extra details like First Name, Last Name, Email etc.
I noticed that your library creates AccountInfo State which is accessible by all accounts on the same node. So, can we extend AccountInfo such it can store custom fields along with name, host and identifier?
Also, is it wise to create another State to store user information and share it with all the other accounts on the same node?

Could not resolve net.corda:corda-core:4.3-RC01

The build fails to resolve the corda jars:


* What went wrong:
Execution failed for task ':contracts:compileKotlin'.
> Could not resolve all files for configuration ':contracts:compileClasspath'.
   > Could not resolve net.corda:corda-core:4.3-RC01.
     Required by:
         project :contracts
      > Could not resolve net.corda:corda-core:4.3-RC01.
         > Could not get resource 'https://jitpack.io/net/corda/corda-core/4.3-RC01/corda-core-4.3-RC01.pom'.
            > Could not GET 'https://jitpack.io/net/corda/corda-core/4.3-RC01/corda-core-4.3-RC01.pom'. Received status code 522 from server: Origin Connection Time-out

See the logs in this CI run:
https://dev.azure.com/opticyclic/corda-accounts-ci/_build/results?buildId=5

This is probably due to the ordering of the repositories.

It is further compounded by the fact that mavenLocal() is included which will hide the issue from developers that are also working on the main corda repo and have the dependency there.

Incorrect result while transferring token from Node containing account

Hi,

I have deployed a cordapp with 2 nodes A and B and a Notary.

I have created an account on node A .

Hence following is my configuration
Node A -> Account A1

Process :
Step 1: Issue 100.00 USD to Node A to Node B :
Expected Balances: Node A - 0, Account A1 -0 , Node B -100
Actual Balances : Node A - 0, Account A1 -0 , Node B -100

Step 2: Issue 70.00 USD to Node A to Account A1 :
Expected Balances: Node A - 0, Account A1 -70 , Node B -100
Actual Balances : Node A - 0, Account A1 -70 , Node B -100

Step 3: Transfer 5 USD from Node B to Node A.
Expected Balances: Node A - 5, Account A1 -70 , Node B -95
Actual Balances : Node A - 5, Account A1 -70 , Node B -95

Step 4: Transfer 2 USD from Node A to Account A1 :
Expected Balances: Node A - 3, Account A1 -70, 2 , Node B -95
Actual Balances : Node A - 3, Account A1 -70, 2 , Node B -95

Step 5: Transfer 9 USD from Node A to Account A1 :
Expected Balances: Error as Node A doesn't have expected tokens
Actual Balances : Node A - 5, 68, Account A1 - 2 , Node B -95

I want to transfer tokens from the node A and not the account A.

I have tried writing criteria expression as follows :

Field checkForHostField = PersistentFungibleToken.class.getDeclaredField("holder"); CriteriaExpression hostIndex = Builder.equal( checkForHostField, getOurIdentity(), true); QueryCriteria hostCriteria = new QueryCriteria.VaultCustomQueryCriteria(hostIndex); QueryCriteria criteria = unconsumedStatesCriteria.and(hostCriteria);

This query criteria however fetches fungible token states where both account and Node is the token holder after step 3.

When I tried to query heldTokenAmountCriteria(token, nodeAIdentity)) I got the same result as mentioned above, but I want to retrieve tokens held by NodeA and not an account in NodeA.

Can somebody please explain what is going on in the above scenario? Is there anyway to mitigate this error and ensure that the tokens are indeed deducted from the expected accounts.

Thanks in advance

Which Versions Of Corda Are Supported?

Its not clear which versions of Corda are supported
The README says:

buildscript {
    ext {
        corda_release_version = '4.3-RC01'
        accounts_release_version = '1.0-RC04'
        accounts_release_group = 'com.r3.corda.lib.accounts'
        confidential_id_release_group = "com.r3.corda.lib.ci"
        confidential_id_release_version = "1.0-RC03"
    }
}

and there doesn't appear to have been a release for about a year:
https://ci-artifactory.corda.r3cev.com/artifactory/corda-lib/com/r3/corda/lib/accounts/accounts-contracts/

The README also links to the tokens template:
https://github.com/corda/cordapp-template-kotlin/blob/token-template/build.gradle

This has a slightly different buildscript section

buildscript {
    ext {
        corda_release_group = 'net.corda'
        corda_release_version = '4.3'
        tokens_release_group = 'com.r3.corda.lib.tokens'
        tokens_release_version = '1.2'
        accounts_release_group = 'com.r3.corda.lib.accounts'
        accounts_release_version = '1.0'

However, still corda 4.3 and accounts 1.0.

Does this mean that we can only use Corda 4.3?

If newer versions are supported, please update the README to list all the supported versions and update the samples to include newer versions as well.

Cannot resolve symbol 'r3'

Hello, I'm trying to build a corda account for my project. I've installed the libraries inside of my build.gradle file. But, it seems have problem when I import the com.r3.corda.lib.accounts.contracts and com.r3.corda.lib.accounts.workflows inside of the file. Can I know how to solve the issues? (The issue is Cannot resolve symbol 'r3' and so on"

Make Accounts Easier To Use

Discussion before adding a pull request:

In my test code I have a few extension functions to make using the accounts SDK easier.
e.g. this:

val StateAndRef<AccountInfo>.uuid: UUID get() = state.data.linearId.id

fun VaultService.accountStates(accountId:UUID): List<StateAndRef<ContractState>> {
    return this.queryBy<ContractState>(QueryCriteria.VaultQueryCriteria(externalIds = listOf(accountId))).states
}

allows me to do this:

banks.services.vaultService.accountStates(bank1.uuid)

Instead of this:

banks.services.vaultService.queryBy<ContractState>(QueryCriteria.VaultQueryCriteria(externalIds = listOf(bank1.state.data.linearId.id))).states

However, calling kotlin extension functions from Java is tricky.

Would this and other similar helper functions be better in AccountService/KeyManagementBackedAccountService?

See also #37

Empty account_to_state_refs table

Corda Open Source 4.3
Tokens 1.1-RC01
Accounts 1.0
Confidential Identities 1.0

I assume that when you assign (e.g. issue, transfer) a state (e.g. FungibleToken) to an account; a new entry should appear in the account_to_state_refs table.
I noticed that this table is empty in my case, I assign FungibleTokens to accounts; I tested it with H2 and Postgres, locally and on GCP. In all cases, the table was empty.
Roger Willis mentioned that they tested this table and they didn't have any problems with it.
I create a repo (for a different issue), but I was able to recreate the issue in it; so please have a look: https://github.com/adelRestom/tokens-sdk-issue-172
Follow these steps to reproduce:

  • Deploy the nodes: ./gradlew deployNodes
  • Browse to the nodes (Notary, Mint, and Wallet): cd build/nodes/
  • Start all nodes (Notary, Mint, and Wallet): java -jar corda.jar
  • Inside Mint terminal Mint tokens: start MintFixedToken. This will mint 800.867681.
  • Inside Mint terminal Issue tokens: start IssueFixedToken. This will issue 0.867681 to an Account123 on Wallet node.
  • Open the H2 database: cd /bin/h2/bin, sh h2.sh, the DB port for Wallet node is 10091

You will see that the account is created inside accounts table, and the token is inside fungible_token table, but the account_to_state_refs table is empty.

The logs didn't show any errors.

IDEA Compile Directories Are Not Ignored

The .gitignore only ignores the IDEA compile directory (out) in the root and not in all the sub-projects which creates lots of "Unversioned files" when debugging in IDEA

Unable to build Accounts since today

Summary
When trying to build the accounts library, the build process returns an error when attempting to access the quasar-core library.

Going to the software.r3.com website, the JFrog platform, to manually search for the repo refuses to let me see any library with an error You are not authorized to view this page. It wants me to login, however there is no way to register or create an account on the JFrog platform.

Error logs
Here is the error logs when trying to run gradlew.bat clean install

> Task :contracts:compileKotlin FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':contracts:compileKotlin'.
> Could not resolve all files for configuration ':contracts:compileClasspath'.
   > Could not resolve co.paralleluniverse:quasar-core:0.7.12_r3.
     Required by:
         project :contracts
      > Could not resolve co.paralleluniverse:quasar-core:0.7.12_r3.
         > Could not get resource 'https://software.r3.com/artifactory/corda-dev/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'.
            > Could not GET 'https://software.r3.com/artifactory/corda-dev/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'. Received status code 401 from server:
      > Could not resolve co.paralleluniverse:quasar-core:0.7.12_r3.
         > Could not get resource 'https://software.r3.com/artifactory/corda-releases/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'.
            > Could not GET 'https://software.r3.com/artifactory/corda-releases/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'. Received status code 401 from server:
      > Could not resolve co.paralleluniverse:quasar-core:0.7.12_r3.
         > Could not get resource 'https://software.r3.com/artifactory/corda-dependencies/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'.
            > Could not GET 'https://software.r3.com/artifactory/corda-dependencies/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'. Received status code 401 from server:
      > Could not resolve co.paralleluniverse:quasar-core:0.7.12_r3.
         > Could not get resource 'https://software.r3.com/artifactory/corda-lib/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'.
            > Could not GET 'https://software.r3.com/artifactory/corda-lib/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'. Received status code 401 from server:
      > Could not resolve co.paralleluniverse:quasar-core:0.7.12_r3.
         > Could not get resource 'https://software.r3.com/artifactory/corda-lib-dev/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'.
            > Could not GET 'https://software.r3.com/artifactory/corda-lib-dev/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'. Received status code 409 from server:
   > Could not resolve co.paralleluniverse:quasar-core:0.7.12_r3.
     Required by:
         project :contracts > net.corda:corda-core:4.4
      > Could not resolve co.paralleluniverse:quasar-core:0.7.12_r3.
         > Could not get resource 'https://software.r3.com/artifactory/corda-dev/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'.
            > Could not GET 'https://software.r3.com/artifactory/corda-dev/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'. Received status code 401 from server:
      > Could not resolve co.paralleluniverse:quasar-core:0.7.12_r3.
         > Could not get resource 'https://software.r3.com/artifactory/corda-releases/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'.
            > Could not GET 'https://software.r3.com/artifactory/corda-releases/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'. Received status code 401 from server:
      > Could not resolve co.paralleluniverse:quasar-core:0.7.12_r3.
         > Could not get resource 'https://software.r3.com/artifactory/corda-dependencies/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'.
            > Could not GET 'https://software.r3.com/artifactory/corda-dependencies/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'. Received status code 401 from server:
      > Could not resolve co.paralleluniverse:quasar-core:0.7.12_r3.
         > Could not get resource 'https://software.r3.com/artifactory/corda-lib/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'.
            > Could not GET 'https://software.r3.com/artifactory/corda-lib/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'. Received status code 401 from server:
      > Could not resolve co.paralleluniverse:quasar-core:0.7.12_r3.
         > Could not get resource 'https://software.r3.com/artifactory/corda-lib-dev/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'.
            > Could not GET 'https://software.r3.com/artifactory/corda-lib-dev/co/paralleluniverse/quasar-core/0.7.12_r3/quasar-core-0.7.12_r3.pom'. Received status code 409 from server:

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.6/userguide/command_line_interface.html#sec:command_line_warnings

BUILD FAILED in 5s
16 actionable tasks: 3 executed, 13 up-to-date

Expected
Successful compilation of the library

Additional information

A similar error (different url for another library but identical error) occures when attemting to compile a cordapp that uses the Accounts library

DDL Error On Startup "EXTERNAL_ID_IDX" already exists

When running a test either using the MockNetwork or the DriverDSL the following error appears in the logs:

[INFO] 10:42:53,127 [main] connections.access. - HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@28383eeb] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
[WARN] 10:42:53,155 [main] internal.ExceptionHandlerLoggedImpl. - GenerationTarget encountered exception accepting command : Error executing DDL "create index external_id_idx on public_key_to_account_id (external_id)" via JDBC Statement [errorCode=r6jypp, moreInformationAt=https://errors.corda.net/OS/4.3-SNAPSHOT/r6jypp]
 org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "create index external_id_idx on public_key_to_account_id (external_id)" via JDBC Statement
	at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-5.4.3.Final.jar:5.4.3.Final]
	at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlString(AbstractSchemaMigrator.java:559) ~[hibernate-core-5.4.3.Final.jar:5.4.3.Final]
	at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlStrings(AbstractSchemaMigrator.java:504) ~[hibernate-core-5.4.3.Final.jar:5.4.3.Final]
	at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applyIndexes(AbstractSchemaMigrator.java:331) ~[hibernate-core-5.4.3.Final.jar:5.4.3.Final]
	at org.hibernate.tool.schema.internal.GroupedSchemaMigratorImpl.performTablesMigration(GroupedSchemaMigratorImpl.java:84) ~[hibernate-core-5.4.3.Final.jar:5.4.3.Final]
	at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.performMigration(AbstractSchemaMigrator.java:207) ~[hibernate-core-5.4.3.Final.jar:5.4.3.Final]
	at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:114) ~[hibernate-core-5.4.3.Final.jar:5.4.3.Final]
	at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:184) ~[hibernate-core-5.4.3.Final.jar:5.4.3.Final]
	at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:73) ~[hibernate-core-5.4.3.Final.jar:5.4.3.Final]
	at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:309) ~[hibernate-core-5.4.3.Final.jar:5.4.3.Final]
	at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:462) ~[hibernate-core-5.4.3.Final.jar:5.4.3.Final]
	at net.corda.nodeapi.internal.persistence.HibernateConfiguration.buildSessionFactory(HibernateConfiguration.kt:143) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.HibernateConfiguration.makeSessionFactoryForSchemas(HibernateConfiguration.kt:100) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.HibernateConfiguration.access$makeSessionFactoryForSchemas(HibernateConfiguration.kt:29) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.HibernateConfiguration$sessionFactoryForSchemas$1.invoke(HibernateConfiguration.kt:70) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.HibernateConfiguration$sessionFactoryForSchemas$1.invoke(HibernateConfiguration.kt:29) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.HibernateConfiguration$sam$java_util_function_Function$0.apply(HibernateConfiguration.kt) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at com.github.benmanes.caffeine.cache.BoundedLocalCache.lambda$doComputeIfAbsent$14(BoundedLocalCache.java:2337) ~[caffeine-2.7.0.jar:?]
	at java.util.concurrent.ConcurrentHashMap.compute(ConcurrentHashMap.java:1853) ~[?:1.8.0_202]
	at com.github.benmanes.caffeine.cache.BoundedLocalCache.doComputeIfAbsent(BoundedLocalCache.java:2335) ~[caffeine-2.7.0.jar:?]
	at com.github.benmanes.caffeine.cache.BoundedLocalCache.computeIfAbsent(BoundedLocalCache.java:2318) ~[caffeine-2.7.0.jar:?]
	at com.github.benmanes.caffeine.cache.LocalCache.computeIfAbsent(LocalCache.java:111) ~[caffeine-2.7.0.jar:?]
	at com.github.benmanes.caffeine.cache.LocalManualCache.get(LocalManualCache.java:54) ~[caffeine-2.7.0.jar:?]
	at net.corda.nodeapi.internal.persistence.HibernateConfiguration.sessionFactoryForSchemas(HibernateConfiguration.kt:70) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.HibernateConfiguration.<init>(HibernateConfiguration.kt:66) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.CordaPersistence$hibernateConfig$2$1.invoke(CordaPersistence.kt:111) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.CordaPersistence$hibernateConfig$2$1.invoke(CordaPersistence.kt:94) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:224) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:204) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:210) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.CordaPersistence$hibernateConfig$2.invoke(CordaPersistence.kt:109) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.CordaPersistence$hibernateConfig$2.invoke(CordaPersistence.kt:94) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
	at net.corda.nodeapi.internal.persistence.CordaPersistence.getHibernateConfig(CordaPersistence.kt) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.CordaPersistence.getEntityManagerFactory(CordaPersistence.kt:121) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.DatabaseTransaction$sessionDelegate$1.invoke(DatabaseTransaction.kt:39) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.DatabaseTransaction$sessionDelegate$1.invoke(DatabaseTransaction.kt:21) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
	at net.corda.nodeapi.internal.persistence.DatabaseTransaction.getSession(DatabaseTransaction.kt) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.DatabaseTransactionKt.currentDBSession(DatabaseTransaction.kt:12) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.node.utilities.AppendOnlyPersistentMapBase.loadValue(AppendOnlyPersistentMap.kt:193) ~[corda-node-4.3-SNAPSHOT.jar:?]
	at net.corda.node.utilities.AppendOnlyPersistentMapBase.access$loadValue(AppendOnlyPersistentMap.kt:22) ~[corda-node-4.3-SNAPSHOT.jar:?]
	at net.corda.node.utilities.AppendOnlyPersistentMapBase$transactionalLoadValue$3.invoke(AppendOnlyPersistentMap.kt:213) ~[corda-node-4.3-SNAPSHOT.jar:?]
	at net.corda.node.utilities.AppendOnlyPersistentMapBase$Transactional$Unknown$valueWithoutIsolationDelegate$1.invoke(AppendOnlyPersistentMap.kt:304) ~[corda-node-4.3-SNAPSHOT.jar:?]
	at kotlin.SafePublicationLazyImpl.getValue(LazyJVM.kt:107) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
	at net.corda.node.utilities.AppendOnlyPersistentMapBase$Transactional$Unknown.isPresent(AppendOnlyPersistentMap.kt:302) ~[corda-node-4.3-SNAPSHOT.jar:?]
	at net.corda.node.utilities.AppendOnlyPersistentMapBase$Transactional.orElse(AppendOnlyPersistentMap.kt:275) ~[corda-node-4.3-SNAPSHOT.jar:?]
	at net.corda.node.utilities.AppendOnlyPersistentMapBase.get(AppendOnlyPersistentMap.kt:39) ~[corda-node-4.3-SNAPSHOT.jar:?]
	at net.corda.node.utilities.AppendOnlyPersistentMapBase.contains(AppendOnlyPersistentMap.kt:217) ~[corda-node-4.3-SNAPSHOT.jar:?]
	at net.corda.node.internal.AbstractNode$obtainIdentity$1.invoke(AbstractNode.kt:883) ~[corda-node-4.3-SNAPSHOT.jar:?]
	at net.corda.node.internal.AbstractNode$obtainIdentity$1.invoke(AbstractNode.kt:121) ~[corda-node-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.CordaPersistence.inTopLevelTransaction(CordaPersistence.kt:250) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:226) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:204) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:210) ~[corda-node-api-4.3-SNAPSHOT.jar:?]
	at net.corda.node.internal.AbstractNode.obtainIdentity(AbstractNode.kt:881) ~[corda-node-4.3-SNAPSHOT.jar:?]
	at net.corda.node.internal.AbstractNode.start(AbstractNode.kt:358) ~[corda-node-4.3-SNAPSHOT.jar:?]
	at net.corda.testing.node.internal.InternalMockNetwork$MockNode.start(InternalMockNetwork.kt:346) ~[corda-node-driver-4.3-SNAPSHOT.jar:?]
	at net.corda.testing.node.internal.InternalMockNetwork.createNodeImpl(InternalMockNetwork.kt:471) ~[corda-node-driver-4.3-SNAPSHOT.jar:?]
	at net.corda.testing.node.internal.InternalMockNetwork.createNode(InternalMockNetwork.kt:449) ~[corda-node-driver-4.3-SNAPSHOT.jar:?]
	at net.corda.testing.node.internal.InternalMockNetwork.createNode(InternalMockNetwork.kt:444) ~[corda-node-driver-4.3-SNAPSHOT.jar:?]
	at net.corda.testing.node.internal.InternalMockNetwork.createPartyNode(InternalMockNetwork.kt:545) ~[corda-node-driver-4.3-SNAPSHOT.jar:?]
	at net.corda.testing.node.MockNetwork.createPartyNode(MockNetwork.kt:337) ~[corda-node-driver-4.3-SNAPSHOT.jar:?]
	at com.demo.case.flows.FlowTests.setup(FlowTests.kt:48) ~[classes/:?]
	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 org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124) ~[testng-6.14.3.jar:?]
	at org.testng.internal.MethodInvocationHelper.invokeMethodConsideringTimeout(MethodInvocationHelper.java:59) ~[testng-6.14.3.jar:?]
	at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:458) ~[testng-6.14.3.jar:?]
	at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:222) ~[testng-6.14.3.jar:?]
	at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:142) ~[testng-6.14.3.jar:?]
	at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:168) ~[testng-6.14.3.jar:?]
	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:105) ~[testng-6.14.3.jar:?]
	at org.testng.TestRunner.privateRun(TestRunner.java:648) ~[testng-6.14.3.jar:?]
	at org.testng.TestRunner.run(TestRunner.java:505) ~[testng-6.14.3.jar:?]
	at org.testng.SuiteRunner.runTest(SuiteRunner.java:455) ~[testng-6.14.3.jar:?]
	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450) ~[testng-6.14.3.jar:?]
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415) ~[testng-6.14.3.jar:?]
	at org.testng.SuiteRunner.run(SuiteRunner.java:364) ~[testng-6.14.3.jar:?]
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) ~[testng-6.14.3.jar:?]
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84) ~[testng-6.14.3.jar:?]
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208) ~[testng-6.14.3.jar:?]
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1137) ~[testng-6.14.3.jar:?]
	at org.testng.TestNG.runSuites(TestNG.java:1049) ~[testng-6.14.3.jar:?]
	at org.testng.TestNG.run(TestNG.java:1017) ~[testng-6.14.3.jar:?]
	at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:73) ~[testng-plugin.jar:?]
	at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123) ~[testng-plugin.jar:?]
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Index "EXTERNAL_ID_IDX" already exists; SQL statement:
create index external_id_idx on public_key_to_account_id (external_id) [42111-199]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:451) ~[h2-1.4.199.jar:1.4.199]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) ~[h2-1.4.199.jar:1.4.199]
	at org.h2.message.DbException.get(DbException.java:205) ~[h2-1.4.199.jar:1.4.199]
	at org.h2.message.DbException.get(DbException.java:181) ~[h2-1.4.199.jar:1.4.199]
	at org.h2.command.ddl.CreateIndex.update(CreateIndex.java:76) ~[h2-1.4.199.jar:1.4.199]
	at org.h2.command.CommandContainer.update(CommandContainer.java:133) ~[h2-1.4.199.jar:1.4.199]
	at org.h2.command.Command.executeUpdate(Command.java:267) ~[h2-1.4.199.jar:1.4.199]
	at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:233) ~[h2-1.4.199.jar:1.4.199]
	at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:205) ~[h2-1.4.199.jar:1.4.199]
	at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:95) ~[HikariCP-3.3.1.jar:?]
	at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) ~[HikariCP-3.3.1.jar:?]
	at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:54) ~[hibernate-core-5.4.3.Final.jar:5.4.3.Final]
	... 88 more

The KeyManagementBackedAccountService implementation fails to retrieve the accounts when the number of accounts exceeds DEFAULT_PAGE_SIZE

The

net.corda.core.node.services.VaultQueryException: 
There are <n> results, which exceeds the limit of 200 for queries that do not specify paging. In order to retrieve these results, provide a `PageSpecification(pageNumber, pageSize)` to the method invoked.

exception is thrown by the following functions implemented in the KeyManagementBackedAccountService:

  • accountsForHost(host: Party) - when the number of accounts for host is greater than the vault DEFAULT_PAGE_SIZE
  • ourAccounts() - when the number of accounts for hosted by the node is greater than the vault DEFAULT_PAGE_SIZE
  • allAccounts() - when the total number of accounts in the node is greater than the vault DEFAULT_PAGE_SIZE

PublicKeys Are Not Tied To AccountInfo

My state defines the participants via PublicKey.

data class MyState(
    val id: String,
    val partyA: PublicKey,
    val partyB: PublicKey,
    val status: Status,
    override val linearId: UniqueIdentifier = UniqueIdentifier()
) : LinearState {

    override val participants: List<AbstractParty> get() = listOf(partyA, partyB).map { AnonymousParty(it) }

The contract checks that they aren't the same identity:

    val outputState = tx.outputsOfType<MyState>().single()
    "PartyA and PartyB cannot be the same identity." using (outputState.partyA != outputState.partyB)

I get the key during the flow with:

    val partyAKey = subFlow(RequestKeyForAccount(partyAAccountInfo.state.data)).owningKey
    val partyBKey = subFlow(RequestKeyForAccount(partyBAccountInfo.state.data)).owningKey

If I pass the same account info to the flow for PartyA and PartyB you would expect that partyAKey would be the same as partyBKey and the contract would pick up the issue.

However, what happens is that a fresh key is generated every single time meaning that different keys are created for the same account and the contract can't tell if they are the same.

The RequestKeyForAccount flow does:

    // The account is hosted on the initiating node. So we can generate a key and register it with the identity
    // service locally.
    return if (hostSession.counterparty == ourIdentity) {
        createKeyForAccount(accountInfo, serviceHub)

Which then goes to the confidential identity utils which generates the fresh key every single time:

@CordaInternal
fun createKeyForAccount(accountInfo: AccountInfo, serviceHub: ServiceHub) : AnonymousParty {
    val newKey = serviceHub.keyManagementService.freshKey(accountInfo.identifier.id)
    registerKeyToParty(newKey, serviceHub.ourIdentity, serviceHub)
    return AnonymousParty(newKey)
}

The key should be cached and tied to the account.

Share data between accounts on same node

I have created four accounts, two on each node. I sent a message from one account say account1 on node 1 to account2 on node 2 and I also have an account - account3, present on node 2. Is there any method through which I can view the data shared to account2 from account3?

Move Test Helper Functions Higher Up

There are some useful functions in the test code that allow you to write more readable code

e.g. val signedTx = banks.startFlow(flow).runAndGet(network)

https://github.com/corda/accounts/blob/master/workflows/src/test/kotlin/com/r3/corda/lib/accounts/workflows/test/TestUtils.kt

And others like

fun StartedMockNode.accountService(): AccountService {
    return this.services.cordaService(KeyManagementBackedAccountService::class.java)
}

So you can do:

banks = network.createPartyNode(legalName = CordaX500Name("Banks Node", "London", "GB"))
val banksAccountService = banks.accountService()

These would be useful if moved outside of the test code of this module and higher up into Corda Core to make all Corda code easier to read.

Schema-validation: wrong column type encountered in column [external_id] in table [XX.account_to_state_refs]

Cordapp with accounts enable cannot connect to sql server. I tried with version 2017, 2019 and Azure SQL. Almost in all versions I get the same error:
The runMigration flag is already set to true in build config. I am getting this error while starting the nodes.

Since the error points to the account_to_state_refs table and that is created internally by corda, I am not sure to fix it in the cordapp side.

[ERROR] 2020-03-19T14:18:41,156Z [main] internal.NodeStartupLogging. - Exception during node startup: Incompatible schema change detected.
Please run the node with database.initialiseSchema=true. Reason: Schema-validation: wrong column type encountered in column [external_id] in table
[partya_schema.account_to_state_refs]; found [uniqueidentifier (Types#CHAR)], but expecting [binary(255) (Types#BINARY)] [errorCode=bdopq4, moreInformationAt=https://errors.corda.net/ENT/4.3/bdopq4] {}
net.corda.nodeapi.internal.persistence.HibernateSchemaChangeException: Incompatible schema change detected. Please run the node with database.initialiseSchema=true. Reason: Schema-validation: wrong column type encountered in column [external_id] in table [partya_schema.account_to_state_refs]; found [uniqueidentifier (Types#CHAR)], but expecting [binary(255) (Types#BINARY)]
at net.corda.nodeapi.internal.persistence.CordaPersistence$hibernateConfig$2$1.invoke(CordaPersistence.kt:121) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence$hibernateConfig$2$1.invoke(CordaPersistence.kt:101) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:248) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:227) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:233) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence$hibernateConfig$2.invoke(CordaPersistence.kt:116) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence$hibernateConfig$2.invoke(CordaPersistence.kt:101) ~[corda-node-api-4.3.jar:?]
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
at net.corda.nodeapi.internal.persistence.CordaPersistence.getHibernateConfig(CordaPersistence.kt) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.getEntityManagerFactory(CordaPersistence.kt:128) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.DatabaseTransaction$sessionDelegate$1.invoke(DatabaseTransaction.kt:41) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.DatabaseTransaction$sessionDelegate$1.invoke(DatabaseTransaction.kt:21) ~[corda-node-api-4.3.jar:?]
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
at net.corda.nodeapi.internal.persistence.DatabaseTransaction.getSession(DatabaseTransaction.kt) ~[corda-node-api-4.3.jar:?]
at net.corda.node.services.network.PersistentNetworkMapCache$getNodesByLegalName$1.invoke(PersistentNetworkMapCache.kt:125) ~[corda-node-4.3.jar:?]
at net.corda.node.services.network.PersistentNetworkMapCache$getNodesByLegalName$1.invoke(PersistentNetworkMapCache.kt:41) ~[corda-node-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:248) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:227) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:233) ~[corda-node-api-4.3.jar:?]
at net.corda.node.services.network.PersistentNetworkMapCache.getNodesByLegalName(PersistentNetworkMapCache.kt:125) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.AbstractNode.getPreviousNodeInfoIfPresent(AbstractNode.kt:638) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.AbstractNode.updateNodeInfo(AbstractNode.kt:606) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.AbstractNode.access$updateNodeInfo(AbstractNode.kt:208) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.AbstractNode$start$6.invoke(AbstractNode.kt:468) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.AbstractNode$start$6.invoke(AbstractNode.kt:208) ~[corda-node-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.inTopLevelTransaction(CordaPersistence.kt:281) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:250) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:227) ~[corda-node-api-4.3.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:233) ~[corda-node-api-4.3.jar:?]
at net.corda.node.internal.AbstractNode.start(AbstractNode.kt:467) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.Node.start(Node.kt:552) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.EnterpriseNode.start(EnterpriseNode.kt:210) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.NodeStartup.startNode(NodeStartup.kt:211) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.NodeStartupCli$runProgram$2.run(NodeStartup.kt:132) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.NodeStartup$initialiseAndRun$5.invoke(NodeStartup.kt:188) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.NodeStartup$initialiseAndRun$5.invoke(NodeStartup.kt:139) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.NodeStartupLogging$DefaultImpls.attempt(NodeStartup.kt:538) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.NodeStartup.attempt(NodeStartup.kt:139) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.NodeStartup.initialiseAndRun(NodeStartup.kt:187) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.NodeStartupCli.runProgram(NodeStartup.kt:130) ~[corda-node-4.3.jar:?]
at net.corda.cliutils.CordaCliWrapper.call(CordaCliWrapper.kt:190) ~[corda-tools-cliutils-4.3.jar:?]
at net.corda.node.internal.NodeStartupCli.call(NodeStartup.kt:85) ~[corda-node-4.3.jar:?]
at net.corda.node.internal.NodeStartupCli.call(NodeStartup.kt:66) ~[corda-node-4.3.jar:?]
at picocli.CommandLine.execute(CommandLine.java:1173) ~[picocli-3.9.6.jar:3.9.6]
at picocli.CommandLine.access$800(CommandLine.java:141) ~[picocli-3.9.6.jar:3.9.6]
at picocli.CommandLine$RunLast.handle(CommandLine.java:1367) ~[picocli-3.9.6.jar:3.9.6]
at picocli.CommandLine$RunLast.handle(CommandLine.java:1335) ~[picocli-3.9.6.jar:3.9.6]
at picocli.CommandLine$AbstractParseResultHandler.handleParseResult(CommandLine.java:1243) ~[picocli-3.9.6.jar:3.9.6]
at picocli.CommandLine.parseWithHandlers(CommandLine.java:1526) ~[picocli-3.9.6.jar:3.9.6]
at net.corda.cliutils.CordaCliWrapperKt.start(CordaCliWrapper.kt:73) ~[corda-tools-cliutils-4.3.jar:?]
at net.corda.node.Corda.main(Corda.kt:13) ~[corda-node-4.3.jar:?]

Don't Use Project References In Examples

The examples use project references in the build.gradle

cordapp project(":contracts")
cordapp project(":workflows")

This is contradictory to what the README says:

cordapp "$accounts_release_group:accounts-contracts:$accounts_release_version"
cordapp "$accounts_release_group:accounts-workflows:$accounts_release_version"

When you add the dependencies in the same way as the README you get the error from #45

The examples should be updated to not use project references.

CreateAccount flow error: Flow sessions were not provided for the following transaction participants

Corda OS: 4.1
Accounts: 1.0-RC03

Steps to reproduce:

  1. Start node using java -jar corda.jar
  2. Run flow start CreateAccount name: test
  3. Error doesn't happen in a mock network (i.e. using flow tests), it only happens when running flow from inside the node console.

I attached my Intellij debugger to the node and it happens here:

  1. CreateAccount class:
val finalisedTransaction = subFlow(FinalityFlow(signedTransaction, emptyList()))
  1. Which is caused by this check inside FinalityFlow class:
require(missingRecipients.isEmpty()) {
                "Flow sessions were not provided for the following transaction participants: $missingRecipients"
            }

Log A Warning When Getting AccountInfo By Name

If I create accounts with the same name on different nodes then share one of them to another node I can mistakenly get the wrong account when getting AccountInfo by Name.

This is essentially the scenario in the javadocs:
https://github.com/corda/accounts/blob/master/workflows/src/main/kotlin/com/r3/corda/lib/accounts/workflows/services/AccountService.kt#L82-L90

For that reason a Warning should probably be logged when calling that method:

https://github.com/corda/accounts/blob/master/workflows/src/main/kotlin/com/r3/corda/lib/accounts/workflows/services/KeyManagementBackedAccountsService.kt#L53-L57

RequestAccountInfoFlow not receiving expecting Boolean value from counter-party

In the RequestAccountInfoFlow, there is a party where the current node is asking the counter-party whether a specific account exist on the counter-party's node by:
val hasAccount = host.sendAndReceive<Boolean>(id).unwrap { it }
Here it is waiting for a Boolean value as response.

However, in the RequestAccountInfoHandlerFlow, if the specified account does exist (i.e. response != null), the counter-party does not response with a Boolean value. Instead, it will response with the transaction the contains the specified account info.

This will cause an error when requesting an account that exist on the counter-party.

Can't Update States As Can't Find Accounts

I can create a state using accounts but I can't subsequently update that state in a different flow.
The account cannot be found in the second flow even though it was found in the first flow.

  • Create 2 nodes
  • Create an account on each node
  • Share accounts across nodes
  • Create an IOU between accounts
  • Verify that you can find both accounts on both nodes by UUID
  • Try to update the IOU
  • Fails because you can't find the account

See this repo for code demonstrating the issue.

Incorrect Information In gradle.properties

The contents of gradle.properties is currently

name = Test
group = com.example
version = 0.1
kotlin.incremental=false

The name should be accounts and the group should be net.corda or com.r3.corda or something similar and the version should match the released version.

ConfidentialIdentity Dependencies Aren't Propagated

When running tests in a CorDapp that uses accounts you get the error:

com/r3/corda/lib/ci/SignedKeyUtilitiesKt
java.lang.NoClassDefFoundError: com/r3/corda/lib/ci/SignedKeyUtilitiesKt
  at com.r3.corda.lib.accounts.workflows.internal.flows.ConfidentialIdentityUtilsKt.createKeyForAccount(ConfidentialIdentityUtils.kt:20)
  at com.r3.corda.lib.accounts.workflows.flows.RequestKeyForAccountFlow.call(RequestKeyForAccountFlows.kt:37)

It seems like the dependencies are not propagated properly.

Add Some Wrapper Flows To Facilitate Shell Access

I can create an account from the shell like this:

flow start CreateAccount name: TestAccount

However, it seems impossible to share that account with another node from the shell due to the complex objects in the constructor:

flow start ShareAccountInfo
No matching constructor found:
- [accountInfo: StateAndRef<com.r3.corda.lib.accounts.contracts.states.AccountInfo>, recipients: List<Party>]: missing parameter accountInfo

It would be useful to add extra flows that wrapped the normal flows so they can be called from the command line.

e.g. in this case it would be easier to pass the UUID as a String and a single Party in the same way that the Service works

fun shareAccountInfoWithParty(accountId: UUID, party: Party): CordaFuture<Unit>

Add Flows To Get Accounts From RPC

When you have access to the account service you can look up an account like this:

accountService.accountInfo(accountId)

And this can be done by UUID, name or PublicKey.

However, this can't be done via RPC.

There are already flows to get AllAccounts or OurAccounts which you could use to get this info by iterating.

However, it would be more useful if there were other flows to get the account directly in the same way that the service does.

Corda 5 compatibility

Hi team,

Do you have plans to upgrade this for compatibility with Corda 5?

Thanks

Add More Tests To Core Modules

#53 is blocked because the examples projects are apparently being used as tests:

I'm not sure this is a good idea for all of the samples.

They test important functionality. I think we should do this only after we've added more tests to the core modules.

Originally posted by @roastario in #53 (comment)

@roastario please list the functionality that needs moving to tests and whether it needs to be unit or integration (using the DriverDSL for instance) so we can unblock it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.