From 73cbab0084014e208e78fa4a93d0602db7f615c4 Mon Sep 17 00:00:00 2001 From: "rick.parker" Date: Fri, 10 Jun 2016 09:45:43 +0100 Subject: [PATCH] Pull out Wallet observable into it's own branch Review feedback Review feedback Apply feedback from previous PR Apply feedback from previous PR Apply feedback from previous PR PR feedback PR feedback PR feedback --- .../r3corda/core/node/services/Services.kt | 38 +++++- .../r3corda/core/node/WalletUpdateTests.kt | 83 +++++++++++++ .../com/r3corda/node/internal/AbstractNode.kt | 3 + .../node/internal/testing/TradeSimulation.kt | 3 +- .../node/internal/testing/WalletFiller.kt | 62 ++++++++++ .../wallet/CashBalanceAsMetricsObserver.kt | 42 +++++++ .../node/services/wallet/NodeWalletService.kt | 112 ++++-------------- .../messaging/TwoPartyTradeProtocolTests.kt | 6 +- .../node/services/NodeWalletServiceTest.kt | 3 +- .../kotlin/com/r3corda/demos/TraderDemo.kt | 5 +- 10 files changed, 262 insertions(+), 95 deletions(-) create mode 100644 core/src/test/kotlin/com/r3corda/core/node/WalletUpdateTests.kt create mode 100644 node/src/main/kotlin/com/r3corda/node/internal/testing/WalletFiller.kt create mode 100644 node/src/main/kotlin/com/r3corda/node/services/wallet/CashBalanceAsMetricsObserver.kt diff --git a/core/src/main/kotlin/com/r3corda/core/node/services/Services.kt b/core/src/main/kotlin/com/r3corda/core/node/services/Services.kt index 34a379b565..5d2c106311 100644 --- a/core/src/main/kotlin/com/r3corda/core/node/services/Services.kt +++ b/core/src/main/kotlin/com/r3corda/core/node/services/Services.kt @@ -3,7 +3,6 @@ package com.r3corda.core.node.services import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash -import com.r3corda.core.node.services.TransactionStorage import java.security.KeyPair import java.security.PrivateKey import java.security.PublicKey @@ -38,6 +37,37 @@ abstract class Wallet { * which we have no cash evaluate to null (not present in map), not 0. */ abstract val cashBalances: Map> + + /** + * Represents an update observed by the Wallet that will be notified to observers. Include the [StateRef]s of + * transaction outputs that were consumed (inputs) and the [ContractState]s produced (outputs) to/by the transaction + * or transactions observed and the Wallet. + * + * If the Wallet observes multiple transactions simultaneously, where some transactions consume the outputs of some of the + * other transactions observed, then the changes are observed "net" of those. + */ + data class Update(val consumed: Set, val produced: Set>) { + + /** + * Combine two updates into a single update with the combined inputs and outputs of the two updates but net + * any outputs of the left-hand-side (this) that are consumed by the inputs of the right-hand-side (rhs). + * + * i.e. the net effect in terms of state live-ness of receiving the combined update is the same as receiving this followed by rhs. + */ + operator fun plus(rhs: Update): Update { + val previouslyProduced = produced.map { it.ref } + val previouslyConsumed = consumed + val combined = Wallet.Update( + previouslyConsumed + (rhs.consumed - previouslyProduced), + rhs.produced + produced.filter { it.ref !in rhs.consumed }) + return combined + } + } + + companion object { + val NoUpdate = Update(emptySet(), emptySet()) + } + } /** @@ -89,6 +119,12 @@ interface WalletService { /** Same as notifyAll but with a single transaction. */ fun notify(tx: WireTransaction): Wallet = notifyAll(listOf(tx)) + + /** + * Get a synchronous Observable of updates. When observations are pushed to the Observer, the Wallet will already incorporate + * the update. + */ + val updates: rx.Observable } inline fun WalletService.linearHeadsOfType() = linearHeadsOfType_(T::class.java) diff --git a/core/src/test/kotlin/com/r3corda/core/node/WalletUpdateTests.kt b/core/src/test/kotlin/com/r3corda/core/node/WalletUpdateTests.kt new file mode 100644 index 0000000000..437f8ecf73 --- /dev/null +++ b/core/src/test/kotlin/com/r3corda/core/node/WalletUpdateTests.kt @@ -0,0 +1,83 @@ +package com.r3corda.core.node + +import com.r3corda.core.contracts.* +import com.r3corda.core.crypto.SecureHash +import com.r3corda.core.node.services.Wallet +import com.r3corda.core.testing.DUMMY_NOTARY +import org.junit.Test +import kotlin.test.assertEquals + + +class WalletUpdateTests { + + object DummyContract : Contract { + + override fun verify(tx: TransactionForVerification) { + } + + override val legalContractReference: SecureHash = SecureHash.sha256("") + } + + private class DummyState : ContractState { + override val notary = DUMMY_NOTARY + override val contract = WalletUpdateTests.DummyContract + } + + private val stateRef0 = StateRef(SecureHash.randomSHA256(), 0) + private val stateRef1 = StateRef(SecureHash.randomSHA256(), 1) + private val stateRef2 = StateRef(SecureHash.randomSHA256(), 2) + private val stateRef3 = StateRef(SecureHash.randomSHA256(), 3) + private val stateRef4 = StateRef(SecureHash.randomSHA256(), 4) + + private val stateAndRef0 = StateAndRef(DummyState(), stateRef0) + private val stateAndRef1 = StateAndRef(DummyState(), stateRef1) + private val stateAndRef2 = StateAndRef(DummyState(), stateRef2) + private val stateAndRef3 = StateAndRef(DummyState(), stateRef3) + private val stateAndRef4 = StateAndRef(DummyState(), stateRef4) + + @Test + fun `nothing plus nothing is nothing`() { + val before = Wallet.NoUpdate + val after = before + Wallet.NoUpdate + assertEquals(before, after) + } + + @Test + fun `something plus nothing is something`() { + val before = Wallet.Update(setOf(stateRef0, stateRef1), setOf(stateAndRef2, stateAndRef3)) + val after = before + Wallet.NoUpdate + assertEquals(before, after) + } + + @Test + fun `nothing plus something is something`() { + val before = Wallet.NoUpdate + val after = before + Wallet.Update(setOf(stateRef0, stateRef1), setOf(stateAndRef2, stateAndRef3)) + val expected = Wallet.Update(setOf(stateRef0, stateRef1), setOf(stateAndRef2, stateAndRef3)) + assertEquals(expected, after) + } + + @Test + fun `something plus consume state 0 is something without state 0 output`() { + val before = Wallet.Update(setOf(stateRef2, stateRef3), setOf(stateAndRef0, stateAndRef1)) + val after = before + Wallet.Update(setOf(stateRef0), setOf()) + val expected = Wallet.Update(setOf(stateRef2, stateRef3), setOf(stateAndRef1)) + assertEquals(expected, after) + } + + @Test + fun `something plus produce state 4 is something with additional state 4 output`() { + val before = Wallet.Update(setOf(stateRef2, stateRef3), setOf(stateAndRef0, stateAndRef1)) + val after = before + Wallet.Update(setOf(), setOf(stateAndRef4)) + val expected = Wallet.Update(setOf(stateRef2, stateRef3), setOf(stateAndRef0, stateAndRef1, stateAndRef4)) + assertEquals(expected, after) + } + + @Test + fun `something plus consume states 0 and 1, and produce state 4, is something without state 0 and 1 outputs and only state 4 output`() { + val before = Wallet.Update(setOf(stateRef2, stateRef3), setOf(stateAndRef0, stateAndRef1)) + val after = before + Wallet.Update(setOf(stateRef0, stateRef1), setOf(stateAndRef4)) + val expected = Wallet.Update(setOf(stateRef2, stateRef3), setOf(stateAndRef4)) + assertEquals(expected, after) + } +} \ No newline at end of file diff --git a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt index 383f80c565..3bb2c963c1 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt @@ -34,6 +34,7 @@ import com.r3corda.node.services.transactions.InMemoryUniquenessProvider import com.r3corda.node.services.transactions.NotaryService import com.r3corda.node.services.transactions.SimpleNotaryService import com.r3corda.node.services.transactions.ValidatingNotaryService +import com.r3corda.node.services.wallet.CashBalanceAsMetricsObserver import com.r3corda.node.services.wallet.NodeWalletService import com.r3corda.node.utilities.ANSIProgressObserver import com.r3corda.node.utilities.AddOrRemove @@ -140,6 +141,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, // TODO: this model might change but for now it provides some de-coupling // Add SMM observers ANSIProgressObserver(smm) + // Add wallet observers + CashBalanceAsMetricsObserver(services) startMessagingService() networkMapRegistrationFuture = registerWithNetworkMap() diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt index 6c5a8c6403..11e864b9f4 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt @@ -9,7 +9,6 @@ import com.r3corda.core.days import com.r3corda.core.random63BitValue import com.r3corda.core.seconds import com.r3corda.node.services.network.InMemoryMessagingNetwork -import com.r3corda.node.services.wallet.NodeWalletService import com.r3corda.protocols.TwoPartyTradeProtocol import java.time.Instant @@ -27,7 +26,7 @@ class TradeSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwo val buyer = banks[buyerBankIndex] val seller = banks[sellerBankIndex] - (buyer.services.walletService as NodeWalletService).fillWithSomeTestCash(notary.info.identity, 1500.DOLLARS) + WalletFiller.fillWithSomeTestCash(buyer.services, notary.info.identity, 1500.DOLLARS) val issuance = run { val tx = CommercialPaper().generateIssue(seller.info.identity.ref(1, 2, 3), 1100.DOLLARS, Instant.now() + 10.days, notary.info.identity) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/WalletFiller.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/WalletFiller.kt new file mode 100644 index 0000000000..ca9dc37058 --- /dev/null +++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/WalletFiller.kt @@ -0,0 +1,62 @@ +package com.r3corda.node.internal.testing + +import com.r3corda.contracts.cash.Cash +import com.r3corda.core.contracts.Amount +import com.r3corda.core.contracts.TransactionBuilder +import com.r3corda.core.crypto.Party +import com.r3corda.core.node.ServiceHub +import java.util.* + +object WalletFiller { + + /** + * Creates a random set of between (by default) 3 and 10 cash states that add up to the given amount and adds them + * to the wallet. + * + * The cash is self issued with the current nodes identity, as fetched from the storage service. Thus it + * would not be trusted by any sensible market participant and is effectively an IOU. If it had been issued by + * the central bank, well ... that'd be a different story altogether. + */ + fun fillWithSomeTestCash(services: ServiceHub, notary: Party, howMuch: Amount, atLeastThisManyStates: Int = 3, + atMostThisManyStates: Int = 10, rng: Random = Random()) { + val amounts = calculateRandomlySizedAmounts(howMuch, atLeastThisManyStates, atMostThisManyStates, rng) + + val myIdentity = services.storageService.myLegalIdentity + val myKey = services.storageService.myLegalIdentityKey + + // We will allocate one state to one transaction, for simplicities sake. + val cash = Cash() + val transactions = amounts.map { pennies -> + // This line is what makes the cash self issued. We just use zero as our deposit reference: we don't need + // this field as there's no other database or source of truth we need to sync with. + val depositRef = myIdentity.ref(0) + + val issuance = TransactionBuilder() + val freshKey = services.keyManagementService.freshKey() + cash.generateIssue(issuance, Amount(pennies, howMuch.token), depositRef, freshKey.public, notary) + issuance.signWith(myKey) + + return@map issuance.toSignedTransaction(true) + } + + services.recordTransactions(transactions) + } + + private fun calculateRandomlySizedAmounts(howMuch: Amount, min: Int, max: Int, rng: Random): LongArray { + val numStates = min + Math.floor(rng.nextDouble() * (max - min)).toInt() + val amounts = LongArray(numStates) + val baseSize = howMuch.quantity / numStates + var filledSoFar = 0L + for (i in 0..numStates - 1) { + if (i < numStates - 1) { + // Adjust the amount a bit up or down, to give more realistic amounts (not all identical). + amounts[i] = baseSize + (baseSize / 2 * (rng.nextDouble() - 0.5)).toLong() + filledSoFar += baseSize + } else { + // Handle inexact rounding. + amounts[i] = howMuch.quantity - filledSoFar + } + } + return amounts + } +} \ No newline at end of file diff --git a/node/src/main/kotlin/com/r3corda/node/services/wallet/CashBalanceAsMetricsObserver.kt b/node/src/main/kotlin/com/r3corda/node/services/wallet/CashBalanceAsMetricsObserver.kt new file mode 100644 index 0000000000..fbdda94b94 --- /dev/null +++ b/node/src/main/kotlin/com/r3corda/node/services/wallet/CashBalanceAsMetricsObserver.kt @@ -0,0 +1,42 @@ +package com.r3corda.node.services.wallet + +import com.codahale.metrics.Gauge +import com.r3corda.core.node.services.Wallet +import com.r3corda.node.services.api.ServiceHubInternal +import java.util.* + +/** + * This class observes the wallet and reflect current cash balances as exposed metrics in the monitoring service. + */ +class CashBalanceAsMetricsObserver(val serviceHubInternal: ServiceHubInternal) { + + init { + // TODO: Need to consider failure scenarios. This needs to run if the TX is successfully recorded + serviceHubInternal.walletService.updates.subscribe { update -> + exportCashBalancesViaMetrics(serviceHubInternal.walletService.currentWallet) + } + } + + private class BalanceMetric : Gauge { + @Volatile var pennies = 0L + override fun getValue(): Long? = pennies + } + + private val balanceMetrics = HashMap() + + private fun exportCashBalancesViaMetrics(wallet: Wallet) { + // This is just for demo purposes. We probably shouldn't expose balances via JMX in a real node as that might + // be commercially sensitive info that the sysadmins aren't even meant to know. + // + // Note: exported as pennies. + val m = serviceHubInternal.monitoringService.metrics + for (balance in wallet.cashBalances) { + val metric = balanceMetrics.getOrPut(balance.key) { + val newMetric = BalanceMetric() + m.register("WalletBalances.${balance.key}Pennies", newMetric) + newMetric + } + metric.pennies = balance.value.quantity + } + } +} \ No newline at end of file diff --git a/node/src/main/kotlin/com/r3corda/node/services/wallet/NodeWalletService.kt b/node/src/main/kotlin/com/r3corda/node/services/wallet/NodeWalletService.kt index 9e1e55e519..b51d8a0f3f 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/wallet/NodeWalletService.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/wallet/NodeWalletService.kt @@ -1,10 +1,7 @@ package com.r3corda.node.services.wallet -import com.codahale.metrics.Gauge -import com.r3corda.contracts.cash.Cash import com.r3corda.core.ThreadBox import com.r3corda.core.contracts.* -import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash import com.r3corda.core.node.services.Wallet import com.r3corda.core.node.services.WalletService @@ -12,6 +9,8 @@ import com.r3corda.core.serialization.SingletonSerializeAsToken import com.r3corda.core.utilities.loggerFor import com.r3corda.core.utilities.trace import com.r3corda.node.services.api.ServiceHubInternal +import rx.Observable +import rx.subjects.PublishSubject import java.security.PublicKey import java.util.* import javax.annotation.concurrent.ThreadSafe @@ -36,6 +35,11 @@ class NodeWalletService(private val services: ServiceHubInternal) : SingletonSer override val currentWallet: Wallet get() = mutex.locked { wallet } + private val _updatesPublisher = PublishSubject.create() + + override val updates: Observable + get() = _updatesPublisher + /** * Returns a snapshot of how much cash we have in each currency, ignoring details like issuer. Note: currencies for * which we have no cash evaluate to null, not 0. @@ -66,14 +70,24 @@ class NodeWalletService(private val services: ServiceHubInternal) : SingletonSer // // ... and many other things .... (Wallet.java in bitcoinj is several thousand lines long) - mutex.locked { + var netDelta = Wallet.NoUpdate + val changedWallet = mutex.locked { // Starting from the current wallet, keep applying the transaction updates, calculating a new Wallet each // time, until we get to the result (this is perhaps a bit inefficient, but it's functional and easily // unit tested). - wallet = txns.fold(currentWallet) { current, tx -> current.update(tx, ourKeys) } - exportCashBalancesViaMetrics(wallet) - return wallet + val walletAndNetDelta = txns.fold(Pair(currentWallet, Wallet.NoUpdate)) { walletAndDelta, tx -> + val (wallet, delta) = walletAndDelta.first.update(tx, ourKeys) + val combinedDelta = delta + walletAndDelta.second + Pair(wallet, combinedDelta) + } + wallet = walletAndNetDelta.first + netDelta = walletAndNetDelta.second + return@locked wallet } + if (netDelta != Wallet.NoUpdate) { + _updatesPublisher.onNext(netDelta) + } + return changedWallet } private fun isRelevant(state: ContractState, ourKeys: Set): Boolean { @@ -87,7 +101,7 @@ class NodeWalletService(private val services: ServiceHubInternal) : SingletonSer } } - private fun Wallet.update(tx: WireTransaction, ourKeys: Set): Wallet { + private fun Wallet.update(tx: WireTransaction, ourKeys: Set): Pair { val ourNewStates = tx.outputs. filter { isRelevant(it, ourKeys) }. map { tx.outRef(it) } @@ -98,9 +112,11 @@ class NodeWalletService(private val services: ServiceHubInternal) : SingletonSer // Is transaction irrelevant? if (consumed.isEmpty() && ourNewStates.isEmpty()) { log.trace { "tx ${tx.id} was irrelevant to this wallet, ignoring" } - return this + return Pair(this, Wallet.NoUpdate) } + val change = Wallet.Update(consumed, HashSet(ourNewStates)) + // And calculate the new wallet. val newStates = states.filter { it.ref !in consumed } + ourNewStates @@ -108,82 +124,6 @@ class NodeWalletService(private val services: ServiceHubInternal) : SingletonSer "Applied tx ${tx.id.prefixChars()} to the wallet: consumed ${consumed.size} states and added ${newStates.size}" } - return WalletImpl(newStates) - } - - private class BalanceMetric : Gauge { - @Volatile var pennies = 0L - override fun getValue(): Long? = pennies - } - - private val balanceMetrics = HashMap() - - private fun exportCashBalancesViaMetrics(wallet: Wallet) { - // This is just for demo purposes. We probably shouldn't expose balances via JMX in a real node as that might - // be commercially sensitive info that the sysadmins aren't even meant to know. - // - // Note: exported as pennies. - val m = services.monitoringService.metrics - for (balance in wallet.cashBalances) { - val metric = balanceMetrics.getOrPut(balance.key) { - val newMetric = BalanceMetric() - m.register("WalletBalances.${balance.key}Pennies", newMetric) - newMetric - } - metric.pennies = balance.value.quantity - } - } - - /** - * Creates a random set of between (by default) 3 and 10 cash states that add up to the given amount and adds them - * to the wallet. - * - * The cash is self issued with the current nodes identity, as fetched from the storage service. Thus it - * would not be trusted by any sensible market participant and is effectively an IOU. If it had been issued by - * the central bank, well ... that'd be a different story altogether. - * - * TODO: Move this out of NodeWalletService - */ - fun fillWithSomeTestCash(notary: Party, howMuch: Amount, atLeastThisManyStates: Int = 3, - atMostThisManyStates: Int = 10, rng: Random = Random()) { - val amounts = calculateRandomlySizedAmounts(howMuch, atLeastThisManyStates, atMostThisManyStates, rng) - - val myIdentity = services.storageService.myLegalIdentity - val myKey = services.storageService.myLegalIdentityKey - - // We will allocate one state to one transaction, for simplicities sake. - val cash = Cash() - val transactions = amounts.map { pennies -> - // This line is what makes the cash self issued. We just use zero as our deposit reference: we don't need - // this field as there's no other database or source of truth we need to sync with. - val depositRef = myIdentity.ref(0) - - val issuance = TransactionBuilder() - val freshKey = services.keyManagementService.freshKey() - cash.generateIssue(issuance, Amount(pennies, howMuch.token), depositRef, freshKey.public, notary) - issuance.signWith(myKey) - - return@map issuance.toSignedTransaction(true) - } - - services.recordTransactions(transactions) - } - - private fun calculateRandomlySizedAmounts(howMuch: Amount, min: Int, max: Int, rng: Random): LongArray { - val numStates = min + Math.floor(rng.nextDouble() * (max - min)).toInt() - val amounts = LongArray(numStates) - val baseSize = howMuch.quantity / numStates - var filledSoFar = 0L - for (i in 0..numStates - 1) { - if (i < numStates - 1) { - // Adjust the amount a bit up or down, to give more realistic amounts (not all identical). - amounts[i] = baseSize + (baseSize / 2 * (rng.nextDouble() - 0.5)).toLong() - filledSoFar += baseSize - } else { - // Handle inexact rounding. - amounts[i] = howMuch.quantity - filledSoFar - } - } - return amounts + return Pair(WalletImpl(newStates), change) } } diff --git a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt index 3a45fbe148..8324f71c05 100644 --- a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt @@ -21,13 +21,13 @@ import com.r3corda.core.seconds import com.r3corda.core.testing.* import com.r3corda.core.utilities.BriefLogFormatter import com.r3corda.node.internal.testing.MockNetwork +import com.r3corda.node.internal.testing.WalletFiller import com.r3corda.node.services.config.NodeConfiguration import com.r3corda.node.services.network.InMemoryMessagingNetwork import com.r3corda.node.services.persistence.NodeAttachmentService import com.r3corda.node.services.persistence.PerFileTransactionStorage import com.r3corda.node.services.persistence.StorageServiceImpl import com.r3corda.node.services.statemachine.StateMachineManager -import com.r3corda.node.services.wallet.NodeWalletService import com.r3corda.node.services.wallet.WalletImpl import com.r3corda.protocols.TwoPartyTradeProtocol import org.assertj.core.api.Assertions.assertThat @@ -93,7 +93,7 @@ class TwoPartyTradeProtocolTests { val aliceNode = net.createPartyNode(notaryNode.info, ALICE.name, ALICE_KEY) val bobNode = net.createPartyNode(notaryNode.info, BOB.name, BOB_KEY) - (bobNode.wallet as NodeWalletService).fillWithSomeTestCash(DUMMY_NOTARY, 2000.DOLLARS) + WalletFiller.fillWithSomeTestCash(bobNode.services, DUMMY_NOTARY, 2000.DOLLARS) val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey, notaryNode.info.identity, null).second @@ -144,7 +144,7 @@ class TwoPartyTradeProtocolTests { net.runNetwork() // Clear network map registration messages - (bobNode.wallet as NodeWalletService).fillWithSomeTestCash(DUMMY_NOTARY, 2000.DOLLARS) + WalletFiller.fillWithSomeTestCash(bobNode.services, DUMMY_NOTARY, 2000.DOLLARS) val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey, notaryNode.info.identity, null).second insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey) diff --git a/node/src/test/kotlin/com/r3corda/node/services/NodeWalletServiceTest.kt b/node/src/test/kotlin/com/r3corda/node/services/NodeWalletServiceTest.kt index c5dc65b40a..ff228c6bd8 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/NodeWalletServiceTest.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/NodeWalletServiceTest.kt @@ -10,6 +10,7 @@ import com.r3corda.core.node.services.testing.MockKeyManagementService import com.r3corda.core.node.services.testing.MockStorageService import com.r3corda.core.testing.* import com.r3corda.core.utilities.BriefLogFormatter +import com.r3corda.node.internal.testing.WalletFiller import com.r3corda.node.services.wallet.NodeWalletService import org.junit.After import org.junit.Before @@ -42,7 +43,7 @@ class NodeWalletServiceTest { kms.nextKeys += Array(3) { ALICE_KEY } // Fix the PRNG so that we get the same splits every time. - wallet.fillWithSomeTestCash(DUMMY_NOTARY, 100.DOLLARS, 3, 3, Random(0L)) + WalletFiller.fillWithSomeTestCash(services, DUMMY_NOTARY, 100.DOLLARS, 3, 3, Random(0L)) val w = wallet.currentWallet assertEquals(3, w.states.size) diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index 707386a722..63aec87b2f 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -20,12 +20,13 @@ import com.r3corda.core.utilities.BriefLogFormatter import com.r3corda.core.utilities.Emoji import com.r3corda.core.utilities.ProgressTracker import com.r3corda.node.internal.Node +import com.r3corda.node.internal.testing.WalletFiller import com.r3corda.node.services.config.NodeConfigurationFromConfig import com.r3corda.node.services.messaging.ArtemisMessagingService import com.r3corda.node.services.network.NetworkMapService import com.r3corda.node.services.persistence.NodeAttachmentService import com.r3corda.node.services.transactions.SimpleNotaryService -import com.r3corda.node.services.wallet.NodeWalletService +import com.r3corda.node.utilities.ANSIProgressRenderer import com.r3corda.protocols.NotaryProtocol import com.r3corda.protocols.TwoPartyTradeProtocol import com.typesafe.config.ConfigFactory @@ -221,7 +222,7 @@ class TraderDemoProtocolBuyer(private val attachmentsPath: Path, val notary: Par // Self issue some cash. // // TODO: At some point this demo should be extended to have a central bank node. - (serviceHub.walletService as NodeWalletService).fillWithSomeTestCash(notary, 3000.DOLLARS) + WalletFiller.fillWithSomeTestCash(serviceHub, notary, 3000.DOLLARS) while (true) { // Wait around until a node asks to start a trade with us. In a real system, this part would happen out of band