From 1963b53543afa8a5d81ce15fac1e0596d625eace Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 11 Feb 2020 09:49:10 +0000 Subject: [PATCH 1/6] proposed doc updates for LTS --- docs/InMemoryTokenSelection.md | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/docs/InMemoryTokenSelection.md b/docs/InMemoryTokenSelection.md index 5d76d191..d5543f06 100644 --- a/docs/InMemoryTokenSelection.md +++ b/docs/InMemoryTokenSelection.md @@ -2,10 +2,10 @@ ## Overview -To remove potential performance bottleneck and remove the requirement for database specific SQL to be provided for each backend, -in memory implementation of token selection was introduced as an experimental feature of `token-sdk`. -To use it, you need to have `VaultWatcherService` installed as a `CordaService` on node startup. Indexing -strategy could be specified, by PublicKey, by ExternalId (if using accounts feature) or just by token type and identifier. +To remove potential performance bottlenecks and remove the requirement for database specific SQL to be provided for each backend, +a threadsafe, in memory implementation of token selection was introduced as an experimental feature of `token-sdk`. +To use it, you need to have `VaultWatcherService` installed as a `CordaService` on node startup. An Indexing +strategy can be specified, by PublicKey or by ExternalId (if using accounts feature) or just by token type and identifier. ## How to switch between database based selection and in memory cache? @@ -16,9 +16,10 @@ In your [CorDapp config](https://docs.corda.net/cordapp-build-systems.html#corda ```text stateSelection { - in_memory { - indexingStrategy: ["external_id"|"public_key"|"token_only"] - cacheSize: Int + inMemory { + enabled: true + indexingStrategy: ["EXTERNAL_ID"|"PUBLIC_KEY"|"TOKEN_ONLY"] + cacheSize: 2048 } } ``` @@ -36,8 +37,9 @@ nodeDefaults { config ''' stateSelection { inMemory { - indexingStrategy: "token_only" - cacheSize: 1024 + enabled: true + indexingStrategy: ["EXTERNAL_ID"] + cacheSize: 1024 } } ''' @@ -148,4 +150,15 @@ val (inputs, outputs) = localTokenSelector.generateMove( changeHolder = this.ourIdentity, // Get tokens issued by issuerParty and notarised by notaryParty queryBy = TokenQueryBy(issuer = issuerParty, predicate = { it.state.notary == notaryParty })) -``` \ No newline at end of file +``` + +### Configuring the LocalTokenSelector in Driver based tests + +To avoid warnings in your Driver based tests, when creating the list of test cordapps you can do something similar to: + +```kotlin +private val tokenSelectionConfig = mapOf("stateSelection" to + mapOf("inMemory" to + mapOf("enabled" to true, "cacheSize" to 1024, "indexingStrategies" to listOf("EXTERNAL_ID")))) +val TokenSelectionCordapps: Set = setOf(TestCordapp.findCordapp("com.r3.corda.lib.tokens.selection")).map{ it.withConfig(tokenSelectionConfig) }.toSet() +``` From 57e2683794fa177e717ce2e95ed995676d0236c7 Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 11 Feb 2020 09:50:56 +0000 Subject: [PATCH 2/6] added notes on token release --- docs/InMemoryTokenSelection.md | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/InMemoryTokenSelection.md b/docs/InMemoryTokenSelection.md index d5543f06..64f5901b 100644 --- a/docs/InMemoryTokenSelection.md +++ b/docs/InMemoryTokenSelection.md @@ -162,3 +162,43 @@ private val tokenSelectionConfig = mapOf("stateSelection" to mapOf("enabled" to true, "cacheSize" to 1024, "indexingStrategies" to listOf("EXTERNAL_ID")))) val TokenSelectionCordapps: Set = setOf(TestCordapp.findCordapp("com.r3.corda.lib.tokens.selection")).map{ it.withConfig(tokenSelectionConfig) }.toSet() ``` + +### Unlocking Tokens + +The db token selector has a feature than when you fall off the end of a flow, any still locked tokens are auto-unlocked. While this makes +it easy to get started using the Token SDK, it hides a lot of complexity. E.g. if a node is down in a Flow, then the tokens will be locked +until that node comes back up again - that could be a while. + +We believe it's better to explicitly reason about your locking behaviour in the context of your CorDapp. + +We have built in a time based auto unlock, that you can configure with a business appropriate timeout. + +In the future we will add hooks into the StateMachine lifecycle that allow you to respond to events. For the moment if you want to +mimic the existing behaviour of the db token selection you can do something like: + +```kotlin +package io.mycompany.common.workflows.flows + +import co.paralleluniverse.fibers.Suspendable +import com.r3.corda.lib.tokens.selection.memory.selector.LocalTokenSelector +import net.corda.core.flows.FlowLogic + +abstract class SdxTokenReleaseFlow : FlowLogic() { + + lateinit var localTokenSelector: LocalTokenSelector + + @Suspendable + override fun call(): T { + localTokenSelector = LocalTokenSelector(serviceHub) + return try { + callThenReleaseTokens() + } finally { + localTokenSelector.rollback() + } + } + + @Suspendable + abstract fun callThenReleaseTokens(): T + +} +``` From 1024ba97fcbb22514e1f4939e5e49c804cecd114 Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 11 Feb 2020 10:31:21 +0000 Subject: [PATCH 3/6] added info re new exception --- docs/InMemoryTokenSelection.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/InMemoryTokenSelection.md b/docs/InMemoryTokenSelection.md index 64f5901b..887e994a 100644 --- a/docs/InMemoryTokenSelection.md +++ b/docs/InMemoryTokenSelection.md @@ -202,3 +202,9 @@ abstract class SdxTokenReleaseFlow : FlowLogic() { } ``` + +### Exception Handling + +There is a new exception in LTS. Previously if there were not enough tokens we used to throw an `IllegalStateException`, and indeed we still +do throw this in certain circumstances. But if you do not have enough tokens we now throw an `InsufficientBalanceException` so that you can +pick this out explicitly. NB you may need to catch both `IllegalStateException` and `InsufficientBalanceException` now. \ No newline at end of file From 5c01c6c8d12cbad673fd08c11c9d47bb967c60ce Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 11 Feb 2020 17:44:48 +0000 Subject: [PATCH 4/6] de-clientification (thanks for spotting) --- docs/InMemoryTokenSelection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/InMemoryTokenSelection.md b/docs/InMemoryTokenSelection.md index 887e994a..ed33d3f7 100644 --- a/docs/InMemoryTokenSelection.md +++ b/docs/InMemoryTokenSelection.md @@ -183,7 +183,7 @@ import co.paralleluniverse.fibers.Suspendable import com.r3.corda.lib.tokens.selection.memory.selector.LocalTokenSelector import net.corda.core.flows.FlowLogic -abstract class SdxTokenReleaseFlow : FlowLogic() { +abstract class TokenReleaseFlow : FlowLogic() { lateinit var localTokenSelector: LocalTokenSelector From 75caf0541165dd42493e69d5b9fec0f6da05a70d Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 12 Feb 2020 15:50:16 +0000 Subject: [PATCH 5/6] believe this needs to be indexingStrategies based on issue we are seeing --- docs/InMemoryTokenSelection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/InMemoryTokenSelection.md b/docs/InMemoryTokenSelection.md index ed33d3f7..165cc01f 100644 --- a/docs/InMemoryTokenSelection.md +++ b/docs/InMemoryTokenSelection.md @@ -18,7 +18,7 @@ In your [CorDapp config](https://docs.corda.net/cordapp-build-systems.html#corda stateSelection { inMemory { enabled: true - indexingStrategy: ["EXTERNAL_ID"|"PUBLIC_KEY"|"TOKEN_ONLY"] + indexingStrategies: ["EXTERNAL_ID"|"PUBLIC_KEY"|"TOKEN_ONLY"] cacheSize: 2048 } } @@ -38,7 +38,7 @@ nodeDefaults { stateSelection { inMemory { enabled: true - indexingStrategy: ["EXTERNAL_ID"] + indexingStrategies: ["EXTERNAL_ID"] cacheSize: 1024 } } From 26c3e54a74d4a303a4626169d1924336f4892e6e Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 12 Feb 2020 18:13:22 +0000 Subject: [PATCH 6/6] note re reuse --- docs/InMemoryTokenSelection.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/InMemoryTokenSelection.md b/docs/InMemoryTokenSelection.md index 165cc01f..7eef8f3a 100644 --- a/docs/InMemoryTokenSelection.md +++ b/docs/InMemoryTokenSelection.md @@ -207,4 +207,9 @@ abstract class TokenReleaseFlow : FlowLogic() { There is a new exception in LTS. Previously if there were not enough tokens we used to throw an `IllegalStateException`, and indeed we still do throw this in certain circumstances. But if you do not have enough tokens we now throw an `InsufficientBalanceException` so that you can -pick this out explicitly. NB you may need to catch both `IllegalStateException` and `InsufficientBalanceException` now. \ No newline at end of file +pick this out explicitly. NB you may need to catch both `IllegalStateException` and `InsufficientBalanceException` now. + +### Note about re-using LTS + +It is worth noting that you should use a new LTS for each query - this is because it is an app concern regarding what rollback means if you make two +different queries with the same LTS.