mirror of
https://github.com/corda/corda.git
synced 2025-02-22 18:12:53 +00:00
Merge remote-tracking branch 'open/master' into andrius/os-merge-06-27
This commit is contained in:
commit
4281061c47
14
build.gradle
14
build.gradle
@ -34,20 +34,6 @@ buildscript {
|
|||||||
ext.capsule_version = '1.0.1'
|
ext.capsule_version = '1.0.1'
|
||||||
|
|
||||||
ext.asm_version = '5.0.4'
|
ext.asm_version = '5.0.4'
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO Upgrade to version 2.4 for large message streaming support
|
|
||||||
*
|
|
||||||
* Due to a memory leak in the connection handling code in Artemis, we are
|
|
||||||
* temporarily downgrading to version 2.2.0.
|
|
||||||
*
|
|
||||||
* The memory leak essentially triggers an out-of-memory exception within
|
|
||||||
* less than 10 seconds and can take down a node if a non-TLS connection is
|
|
||||||
* attempted against the P2P port.
|
|
||||||
*
|
|
||||||
* The issue has been reported to upstream:
|
|
||||||
* https://issues.apache.org/jira/browse/ARTEMIS-1559
|
|
||||||
*/
|
|
||||||
ext.artemis_version = '2.5.0'
|
ext.artemis_version = '2.5.0'
|
||||||
ext.jackson_version = '2.9.5'
|
ext.jackson_version = '2.9.5'
|
||||||
ext.jetty_version = '9.4.7.v20170914'
|
ext.jetty_version = '9.4.7.v20170914'
|
||||||
|
@ -26,7 +26,7 @@ import net.corda.core.serialization.CordaSerializable
|
|||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
interface ContractState {
|
interface ContractState {
|
||||||
/**
|
/**
|
||||||
* A _participant_ is any party that is able to consume this state in a valid transaction.
|
* A _participant_ is any party that should be notified when the state is created or consumed.
|
||||||
*
|
*
|
||||||
* The list of participants is required for certain types of transactions. For example, when changing the notary
|
* The list of participants is required for certain types of transactions. For example, when changing the notary
|
||||||
* for this state, every participant has to be involved and approve the transaction
|
* for this state, every participant has to be involved and approve the transaction
|
||||||
|
@ -48,7 +48,7 @@ class CashIssueAndPaymentFlow(val amount: Amount<Currency>,
|
|||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call(): Result {
|
override fun call(): Result {
|
||||||
subFlow(CashIssueFlow(amount, issueRef, notary))
|
subFlow(CashIssueFlow(amount, issueRef, notary))
|
||||||
return subFlow(CashPaymentFlow(amount, recipient, anonymous))
|
return subFlow(CashPaymentFlow(amount, recipient, anonymous, notary))
|
||||||
}
|
}
|
||||||
|
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
@ -57,4 +57,4 @@ class CashIssueAndPaymentFlow(val amount: Amount<Currency>,
|
|||||||
val recipient: Party,
|
val recipient: Party,
|
||||||
val notary: Party,
|
val notary: Party,
|
||||||
val anonymous: Boolean) : AbstractRequest(amount)
|
val anonymous: Boolean) : AbstractRequest(amount)
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import java.util.*
|
|||||||
* @param recipient the party to pay the currency to.
|
* @param recipient the party to pay the currency to.
|
||||||
* @param issuerConstraint if specified, the payment will be made using only cash issued by the given parties.
|
* @param issuerConstraint if specified, the payment will be made using only cash issued by the given parties.
|
||||||
* @param anonymous whether to anonymous the recipient party. Should be true for normal usage, but may be false
|
* @param anonymous whether to anonymous the recipient party. Should be true for normal usage, but may be false
|
||||||
|
* @param notary if not specified, the first notary of the network map is selected
|
||||||
* for testing purposes.
|
* for testing purposes.
|
||||||
*/
|
*/
|
||||||
@StartableByRPC
|
@StartableByRPC
|
||||||
@ -42,14 +43,17 @@ open class CashPaymentFlow(
|
|||||||
val recipient: Party,
|
val recipient: Party,
|
||||||
val anonymous: Boolean,
|
val anonymous: Boolean,
|
||||||
progressTracker: ProgressTracker,
|
progressTracker: ProgressTracker,
|
||||||
val issuerConstraint: Set<Party> = emptySet()) : AbstractCashFlow<AbstractCashFlow.Result>(progressTracker) {
|
val issuerConstraint: Set<Party> = emptySet(),
|
||||||
|
val notary: Party? = null) : AbstractCashFlow<AbstractCashFlow.Result>(progressTracker) {
|
||||||
/** A straightforward constructor that constructs spends using cash states of any issuer. */
|
/** A straightforward constructor that constructs spends using cash states of any issuer. */
|
||||||
constructor(amount: Amount<Currency>, recipient: Party) : this(amount, recipient, true, tracker())
|
constructor(amount: Amount<Currency>, recipient: Party) : this(amount, recipient, true, tracker())
|
||||||
|
|
||||||
/** A straightforward constructor that constructs spends using cash states of any issuer. */
|
/** A straightforward constructor that constructs spends using cash states of any issuer. */
|
||||||
constructor(amount: Amount<Currency>, recipient: Party, anonymous: Boolean) : this(amount, recipient, anonymous, tracker())
|
constructor(amount: Amount<Currency>, recipient: Party, anonymous: Boolean) : this(amount, recipient, anonymous, tracker())
|
||||||
|
|
||||||
constructor(request: PaymentRequest) : this(request.amount, request.recipient, request.anonymous, tracker(), request.issuerConstraint)
|
constructor(amount: Amount<Currency>, recipient: Party, anonymous: Boolean, notary: Party) : this(amount, recipient, anonymous, tracker(), notary = notary)
|
||||||
|
|
||||||
|
constructor(request: PaymentRequest) : this(request.amount, request.recipient, request.anonymous, tracker(), request.issuerConstraint, request.notary)
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call(): AbstractCashFlow.Result {
|
override fun call(): AbstractCashFlow.Result {
|
||||||
@ -61,7 +65,7 @@ open class CashPaymentFlow(
|
|||||||
}
|
}
|
||||||
val anonymousRecipient = txIdentities[recipient] ?: recipient
|
val anonymousRecipient = txIdentities[recipient] ?: recipient
|
||||||
progressTracker.currentStep = GENERATING_TX
|
progressTracker.currentStep = GENERATING_TX
|
||||||
val builder = TransactionBuilder(notary = null)
|
val builder = TransactionBuilder(notary = notary ?: serviceHub.networkMapCache.notaryIdentities.first())
|
||||||
logger.info("Generating spend for: ${builder.lockId}")
|
logger.info("Generating spend for: ${builder.lockId}")
|
||||||
// TODO: Have some way of restricting this to states the caller controls
|
// TODO: Have some way of restricting this to states the caller controls
|
||||||
val (spendTX, keysForSigning) = try {
|
val (spendTX, keysForSigning) = try {
|
||||||
@ -90,5 +94,6 @@ open class CashPaymentFlow(
|
|||||||
class PaymentRequest(amount: Amount<Currency>,
|
class PaymentRequest(amount: Amount<Currency>,
|
||||||
val recipient: Party,
|
val recipient: Party,
|
||||||
val anonymous: Boolean,
|
val anonymous: Boolean,
|
||||||
val issuerConstraint: Set<Party> = emptySet()) : AbstractRequest(amount)
|
val issuerConstraint: Set<Party> = emptySet(),
|
||||||
|
val notary: Party? = null) : AbstractRequest(amount)
|
||||||
}
|
}
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
@ -21,6 +21,7 @@ import net.corda.core.identity.CordaX500Name
|
|||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FlowIORequest
|
import net.corda.core.internal.FlowIORequest
|
||||||
import net.corda.core.internal.ResolveTransactionsFlow
|
import net.corda.core.internal.ResolveTransactionsFlow
|
||||||
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.internal.notary.NotaryServiceFlow
|
import net.corda.core.internal.notary.NotaryServiceFlow
|
||||||
import net.corda.core.internal.notary.TrustedAuthorityNotaryService
|
import net.corda.core.internal.notary.TrustedAuthorityNotaryService
|
||||||
import net.corda.core.internal.notary.UniquenessProvider
|
import net.corda.core.internal.notary.UniquenessProvider
|
||||||
@ -55,8 +56,9 @@ import org.junit.rules.ExternalResource
|
|||||||
import org.junit.rules.RuleChain
|
import org.junit.rules.RuleChain
|
||||||
import org.slf4j.MDC
|
import org.slf4j.MDC
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
import java.util.concurrent.Future
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.test.assertNotEquals
|
import kotlin.test.assertNotEquals
|
||||||
|
|
||||||
class TimedFlowTestRule(val clusterSize: Int) : ExternalResource() {
|
class TimedFlowTestRule(val clusterSize: Int) : ExternalResource() {
|
||||||
@ -159,13 +161,11 @@ class TimedFlowTests {
|
|||||||
val flow = NotaryFlow.Client(issueTx)
|
val flow = NotaryFlow.Client(issueTx)
|
||||||
val progressTracker = flow.progressTracker
|
val progressTracker = flow.progressTracker
|
||||||
assertNotEquals(ProgressTracker.DONE, progressTracker.currentStep)
|
assertNotEquals(ProgressTracker.DONE, progressTracker.currentStep)
|
||||||
|
val progressTrackerDone = getDoneFuture(progressTracker)
|
||||||
|
|
||||||
val notarySignatures = services.startFlow(flow).resultFuture.get()
|
val notarySignatures = services.startFlow(flow).resultFuture.get()
|
||||||
(issueTx + notarySignatures).verifyRequiredSignatures()
|
(issueTx + notarySignatures).verifyRequiredSignatures()
|
||||||
assertEquals(
|
progressTrackerDone.get()
|
||||||
ProgressTracker.DONE,
|
|
||||||
progressTracker.currentStep,
|
|
||||||
"Ensure the same progress tracker object is re-used after flow restart"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,14 +178,12 @@ class TimedFlowTests {
|
|||||||
}
|
}
|
||||||
val flow = FinalityFlow(issueTx)
|
val flow = FinalityFlow(issueTx)
|
||||||
val progressTracker = flow.progressTracker
|
val progressTracker = flow.progressTracker
|
||||||
|
assertNotEquals(ProgressTracker.DONE, progressTracker.currentStep)
|
||||||
|
val progressTrackerDone = getDoneFuture(flow.progressTracker)
|
||||||
|
|
||||||
val stx = services.startFlow(flow).resultFuture.get()
|
val stx = services.startFlow(flow).resultFuture.get()
|
||||||
stx.verifyRequiredSignatures()
|
stx.verifyRequiredSignatures()
|
||||||
assertEquals(
|
progressTrackerDone.get()
|
||||||
ProgressTracker.DONE,
|
|
||||||
progressTracker.currentStep,
|
|
||||||
"Ensure the same progress tracker object is re-used after flow restart"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,6 +196,13 @@ class TimedFlowTests {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns a future that completes when the [progressTracker] reaches the [ProgressTracker.DONE] step. */
|
||||||
|
private fun getDoneFuture(progressTracker: ProgressTracker): Future<ProgressTracker.Change> {
|
||||||
|
return progressTracker.changes.takeFirst {
|
||||||
|
it.progressTracker.currentStep == ProgressTracker.DONE
|
||||||
|
}.bufferUntilSubscribed().toBlocking().toFuture()
|
||||||
|
}
|
||||||
|
|
||||||
@CordaService
|
@CordaService
|
||||||
private class TestNotaryService(override val services: AppServiceHub, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
|
private class TestNotaryService(override val services: AppServiceHub, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
|
||||||
override val uniquenessProvider = mock<UniquenessProvider>()
|
override val uniquenessProvider = mock<UniquenessProvider>()
|
||||||
@ -226,4 +231,4 @@ class TimedFlowTests {
|
|||||||
return TransactionParts(stx.id, stx.inputs, stx.tx.timeWindow, stx.notary)
|
return TransactionParts(stx.id, stx.inputs, stx.tx.timeWindow, stx.notary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,16 @@ public class CordaCaplet extends Capsule {
|
|||||||
|
|
||||||
private Config parseConfigFile(List<String> args) {
|
private Config parseConfigFile(List<String> args) {
|
||||||
String baseDirOption = getOption(args, "--base-directory");
|
String baseDirOption = getOption(args, "--base-directory");
|
||||||
|
// Ensure consistent behaviour with NodeArgsParser.kt, see CORDA-1598.
|
||||||
|
if (null == baseDirOption || baseDirOption.isEmpty()) {
|
||||||
|
baseDirOption = getOption(args, "-base-directory");
|
||||||
|
}
|
||||||
this.baseDir = Paths.get((baseDirOption == null) ? "." : baseDirOption).toAbsolutePath().normalize().toString();
|
this.baseDir = Paths.get((baseDirOption == null) ? "." : baseDirOption).toAbsolutePath().normalize().toString();
|
||||||
String config = getOption(args, "--config-file");
|
String config = getOption(args, "--config-file");
|
||||||
|
// Same as for baseDirOption.
|
||||||
|
if (null == config || config.isEmpty()) {
|
||||||
|
config = getOption(args, "-config-file");
|
||||||
|
}
|
||||||
File configFile = (config == null) ? new File(baseDir, "node.conf") : new File(config);
|
File configFile = (config == null) ? new File(baseDir, "node.conf") : new File(config);
|
||||||
try {
|
try {
|
||||||
ConfigParseOptions parseOptions = ConfigParseOptions.defaults().setAllowMissing(false);
|
ConfigParseOptions parseOptions = ConfigParseOptions.defaults().setAllowMissing(false);
|
||||||
|
@ -3,20 +3,73 @@ package net.corda.node.utilities
|
|||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
import net.corda.node.services.statemachine.StateMachineManagerInternal
|
import net.corda.node.services.statemachine.StateMachineManagerInternal
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The flow de-serialized from the checkpoint will contain a new instance of the progress tracker, which means that
|
* The flow de-serialized from the checkpoint will contain a new instance of the progress tracker, which means that
|
||||||
* any existing flow observers would be lost. We need to replace it with the old progress tracker to ensure progress
|
* any existing flow observers would be lost. We need to replace it with the old progress tracker to ensure progress
|
||||||
* updates are correctly sent out after the flow is retried.
|
* updates are correctly sent out after the flow is retried.
|
||||||
|
*
|
||||||
|
* If the new tracker contains any child trackers from sub-flows, we need to attach those to the old tracker as well.
|
||||||
*/
|
*/
|
||||||
fun StateMachineManagerInternal.injectOldProgressTracker(oldProgressTracker: ProgressTracker?, newFlowLogic: FlowLogic<*>) {
|
//TODO: instead of replacing the progress tracker after constructing the flow logic, we should inject it during fiber deserialization
|
||||||
if (oldProgressTracker != null) {
|
fun StateMachineManagerInternal.injectOldProgressTracker(oldTracker: ProgressTracker?, newFlowLogic: FlowLogic<*>) {
|
||||||
try {
|
if (oldTracker != null) {
|
||||||
val field = newFlowLogic::class.java.getDeclaredField("progressTracker")
|
val newTracker = newFlowLogic.progressTracker
|
||||||
field.isAccessible = true
|
if (newTracker != null) {
|
||||||
field.set(newFlowLogic, oldProgressTracker)
|
attachNewChildren(oldTracker, newTracker)
|
||||||
} catch (e: NoSuchFieldException) {
|
replaceTracker(newFlowLogic, oldTracker)
|
||||||
// The flow does not use a progress tracker.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun attachNewChildren(oldTracker: ProgressTracker, newTracker: ProgressTracker) {
|
||||||
|
oldTracker.currentStep = newTracker.currentStep
|
||||||
|
oldTracker.steps.forEachIndexed { index, step ->
|
||||||
|
val newStep = newTracker.steps[index]
|
||||||
|
val newChildTracker = newTracker.getChildProgressTracker(newStep)
|
||||||
|
newChildTracker?.let { child ->
|
||||||
|
oldTracker.setChildProgressTracker(step, child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resubscribeToChildren(oldTracker)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-subscribes to child tracker observables. When a nested progress tracker is deserialized from a checkpoint,
|
||||||
|
* it retains the child links, but does not automatically re-subscribe to the child changes.
|
||||||
|
*/
|
||||||
|
private fun resubscribeToChildren(tracker: ProgressTracker) {
|
||||||
|
tracker.steps.forEach {
|
||||||
|
val childTracker = tracker.getChildProgressTracker(it)
|
||||||
|
if (childTracker != null) {
|
||||||
|
tracker.setChildProgressTracker(it, childTracker)
|
||||||
|
resubscribeToChildren(childTracker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Replaces the deserialized [ProgressTracker] in the [newFlowLogic] with the old one to retain old subscribers. */
|
||||||
|
private fun replaceTracker(newFlowLogic: FlowLogic<*>, oldProgressTracker: ProgressTracker?) {
|
||||||
|
val field = getProgressTrackerField(newFlowLogic)
|
||||||
|
field?.apply {
|
||||||
|
isAccessible = true
|
||||||
|
set(newFlowLogic, oldProgressTracker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getProgressTrackerField(newFlowLogic: FlowLogic<*>): Field? {
|
||||||
|
var clazz: Class<*> = newFlowLogic::class.java
|
||||||
|
var field: Field? = null
|
||||||
|
// The progress tracker field may have been overridden in an abstract superclass, so we have to traverse up
|
||||||
|
// the hierarchy.
|
||||||
|
while (clazz != FlowLogic::class.java) {
|
||||||
|
field = clazz.declaredFields.firstOrNull { it.name == "progressTracker" }
|
||||||
|
if (field == null) {
|
||||||
|
clazz = clazz.superclass
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return field
|
||||||
}
|
}
|
@ -137,11 +137,6 @@ distributions {
|
|||||||
into 'cordapps'
|
into 'cordapps'
|
||||||
fileMode = 0444
|
fileMode = 0444
|
||||||
}
|
}
|
||||||
from(project(':samples:bank-of-corda-demo').jar) {
|
|
||||||
rename 'bank-of-corda-demo-(.*)', 'bank-of-corda.jar'
|
|
||||||
into 'cordapps'
|
|
||||||
fileMode = 0444
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ class CordappController : Controller() {
|
|||||||
|
|
||||||
private val jvm by inject<JVMConfig>()
|
private val jvm by inject<JVMConfig>()
|
||||||
private val cordappDir: Path = jvm.applicationDir.resolve(NodeConfig.cordappDirName)
|
private val cordappDir: Path = jvm.applicationDir.resolve(NodeConfig.cordappDirName)
|
||||||
private val bankOfCorda: Path = cordappDir.resolve("bank-of-corda.jar")
|
|
||||||
private val finance: Path = cordappDir.resolve("corda-finance.jar")
|
private val finance: Path = cordappDir.resolve("corda-finance.jar")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,11 +39,6 @@ class CordappController : Controller() {
|
|||||||
finance.copyToDirectory(config.cordappsDir, StandardCopyOption.REPLACE_EXISTING)
|
finance.copyToDirectory(config.cordappsDir, StandardCopyOption.REPLACE_EXISTING)
|
||||||
log.info("Installed 'Finance' cordapp")
|
log.info("Installed 'Finance' cordapp")
|
||||||
}
|
}
|
||||||
// Nodes cannot issue cash unless they contain the "Bank of Corda" cordapp.
|
|
||||||
if (config.nodeConfig.issuableCurrencies.isNotEmpty() && bankOfCorda.exists()) {
|
|
||||||
bankOfCorda.copyToDirectory(config.cordappsDir, StandardCopyOption.REPLACE_EXISTING)
|
|
||||||
log.info("Installed 'Bank of Corda' cordapp")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,14 +48,12 @@ class CordappController : Controller() {
|
|||||||
fun useCordappsFor(config: HasCordapps): List<Path> {
|
fun useCordappsFor(config: HasCordapps): List<Path> {
|
||||||
if (!config.cordappsDir.isDirectory()) return emptyList()
|
if (!config.cordappsDir.isDirectory()) return emptyList()
|
||||||
return config.cordappsDir.walk(1) { paths ->
|
return config.cordappsDir.walk(1) { paths ->
|
||||||
paths
|
paths.filter(Path::isCordapp)
|
||||||
.filter(Path::isCordapp)
|
.filter { !finance.endsWith(it.fileName) }
|
||||||
.filter { !bankOfCorda.endsWith(it.fileName) }
|
.toList()
|
||||||
.filter { !finance.endsWith(it.fileName) }
|
|
||||||
.toList()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Path.isCordapp(): Boolean = this.isReadable && this.fileName.toString().endsWith(".jar")
|
val Path.isCordapp: Boolean get() = this.isReadable && this.fileName.toString().endsWith(".jar")
|
||||||
fun Path.inCordappsDir(): Boolean = (this.parent != null) && this.parent.endsWith("cordapps/")
|
val Path.inCordappsDir: Boolean get() = (this.parent != null) && this.parent.endsWith("cordapps/")
|
||||||
|
@ -125,7 +125,7 @@ class ProfileController : Controller() {
|
|||||||
// Now extract all of the plugins from the ZIP file,
|
// Now extract all of the plugins from the ZIP file,
|
||||||
// and copy them to a temporary location.
|
// and copy them to a temporary location.
|
||||||
StreamSupport.stream(fs.rootDirectories.spliterator(), false)
|
StreamSupport.stream(fs.rootDirectories.spliterator(), false)
|
||||||
.flatMap { Files.find(it, 3, BiPredicate { p, attr -> p.inCordappsDir() && p.isCordapp() && attr.isRegularFile }) }
|
.flatMap { Files.find(it, 3, BiPredicate { p, attr -> p.inCordappsDir && p.isCordapp && attr.isRegularFile }) }
|
||||||
.forEach { cordapp ->
|
.forEach { cordapp ->
|
||||||
val config = nodeIndex[cordapp.getName(0).toString()] ?: return@forEach
|
val config = nodeIndex[cordapp.getName(0).toString()] ?: return@forEach
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ task buildExplorerJAR(type: FatCapsule, dependsOn: project(':tools:explorer').co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build.dependsOn buildExplorerJAR
|
assemble.dependsOn buildExplorerJAR
|
||||||
|
|
||||||
artifacts {
|
artifacts {
|
||||||
runtimeArtifacts buildExplorerJAR
|
runtimeArtifacts buildExplorerJAR
|
||||||
|
@ -153,6 +153,8 @@ class NewTransaction : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun selectNotary(): Party = notaries.first().value!!
|
||||||
|
|
||||||
private fun newTransactionDialog(window: Window) = Dialog<AbstractCashFlow.AbstractRequest>().apply {
|
private fun newTransactionDialog(window: Window) = Dialog<AbstractCashFlow.AbstractRequest>().apply {
|
||||||
dialogPane = root
|
dialogPane = root
|
||||||
initOwner(window)
|
initOwner(window)
|
||||||
@ -162,8 +164,8 @@ class NewTransaction : Fragment() {
|
|||||||
val issueRef = if (issueRef.value != null) OpaqueBytes.of(issueRef.value) else defaultRef
|
val issueRef = if (issueRef.value != null) OpaqueBytes.of(issueRef.value) else defaultRef
|
||||||
when (it) {
|
when (it) {
|
||||||
executeButton -> when (transactionTypeCB.value) {
|
executeButton -> when (transactionTypeCB.value) {
|
||||||
CashTransaction.Issue -> IssueAndPaymentRequest(Amount.fromDecimal(amount.value, currencyChoiceBox.value), issueRef, partyBChoiceBox.value.party, notaries.first().value!!, anonymous)
|
CashTransaction.Issue -> IssueAndPaymentRequest(Amount.fromDecimal(amount.value, currencyChoiceBox.value), issueRef, partyBChoiceBox.value.party, selectNotary(), anonymous)
|
||||||
CashTransaction.Pay -> PaymentRequest(Amount.fromDecimal(amount.value, currencyChoiceBox.value), partyBChoiceBox.value.party, anonymous = anonymous)
|
CashTransaction.Pay -> PaymentRequest(Amount.fromDecimal(amount.value, currencyChoiceBox.value), partyBChoiceBox.value.party, anonymous = anonymous, notary = selectNotary())
|
||||||
CashTransaction.Exit -> ExitRequest(Amount.fromDecimal(amount.value, currencyChoiceBox.value), issueRef)
|
CashTransaction.Exit -> ExitRequest(Amount.fromDecimal(amount.value, currencyChoiceBox.value), issueRef)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user