mirror of
https://github.com/corda/corda.git
synced 2025-01-21 03:55:00 +00:00
Change references to 'wallet' with 'vault'
This commit is contained in:
parent
ae4513c8eb
commit
ebda724f14
@ -17,7 +17,7 @@ class EventGenerator(
|
||||
val notary: Party
|
||||
) {
|
||||
|
||||
private var wallet = listOf<StateAndRef<Cash.State>>()
|
||||
private var vault = listOf<StateAndRef<Cash.State>>()
|
||||
|
||||
val issuerGenerator =
|
||||
Generator.pickOne(parties).combine(Generator.intRange(0, 1)) { party, ref -> party.ref(ref.toByte()) }
|
||||
@ -42,19 +42,19 @@ class EventGenerator(
|
||||
|
||||
val consumedGenerator: Generator<Set<StateRef>> = Generator.frequency(
|
||||
0.7 to Generator.pure(setOf()),
|
||||
0.3 to Generator.impure { wallet }.bind { states ->
|
||||
0.3 to Generator.impure { vault }.bind { states ->
|
||||
Generator.sampleBernoulli(states, 0.2).map { someStates ->
|
||||
val consumedSet = someStates.map { it.ref }.toSet()
|
||||
wallet = wallet.filter { it.ref !in consumedSet }
|
||||
vault = vault.filter { it.ref !in consumedSet }
|
||||
consumedSet
|
||||
}
|
||||
}
|
||||
)
|
||||
val producedGenerator: Generator<Set<StateAndRef<ContractState>>> = Generator.frequency(
|
||||
// 0.1 to Generator.pure(setOf())
|
||||
0.9 to Generator.impure { wallet }.bind { states ->
|
||||
0.9 to Generator.impure { vault }.bind { states ->
|
||||
Generator.replicate(2, cashStateGenerator).map {
|
||||
wallet = states + it
|
||||
vault = states + it
|
||||
it.toSet()
|
||||
}
|
||||
}
|
||||
|
@ -304,8 +304,8 @@ public class JavaCommercialPaper implements Contract {
|
||||
return new TransactionType.General.Builder(notary).withItems(output, new Command(new Commands.Issue(), issuance.getParty().getOwningKey()));
|
||||
}
|
||||
|
||||
public void generateRedeem(TransactionBuilder tx, StateAndRef<State> paper, List<StateAndRef<Cash.State>> wallet) throws InsufficientBalanceException {
|
||||
new Cash().generateSpend(tx, StructuresKt.withoutIssuer(paper.getState().getData().getFaceValue()), paper.getState().getData().getOwner(), wallet, null);
|
||||
public void generateRedeem(TransactionBuilder tx, StateAndRef<State> paper, List<StateAndRef<Cash.State>> vault) throws InsufficientBalanceException {
|
||||
new Cash().generateSpend(tx, StructuresKt.withoutIssuer(paper.getState().getData().getFaceValue()), paper.getState().getData().getOwner(), vault, null);
|
||||
tx.addInputState(paper);
|
||||
tx.addCommand(new Command(new Commands.Redeem(), paper.getState().getData().getOwner()));
|
||||
}
|
||||
|
@ -187,13 +187,13 @@ class CommercialPaper : Contract {
|
||||
* to redeem the paper. We must therefore send enough money to the key that owns the paper to satisfy the face
|
||||
* value, and then ensure the paper is removed from the ledger.
|
||||
*
|
||||
* @throws InsufficientBalanceException if the wallet doesn't contain enough money to pay the redeemer.
|
||||
* @throws InsufficientBalanceException if the vault doesn't contain enough money to pay the redeemer.
|
||||
*/
|
||||
@Throws(InsufficientBalanceException::class)
|
||||
fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<Cash.State>>) {
|
||||
// Add the cash movement using the states in our wallet.
|
||||
fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, vault: List<StateAndRef<Cash.State>>) {
|
||||
// Add the cash movement using the states in our vault.
|
||||
val amount = paper.state.data.faceValue.let { amount -> Amount(amount.quantity, amount.token.product) }
|
||||
Cash().generateSpend(tx, amount, paper.state.data.owner, wallet)
|
||||
Cash().generateSpend(tx, amount, paper.state.data.owner, vault)
|
||||
tx.addInputState(paper)
|
||||
tx.addCommand(CommercialPaper.Commands.Redeem(), paper.state.data.owner)
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import com.r3corda.core.crypto.NullPublicKey
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.crypto.toStringShort
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.node.services.Vault
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.utilities.Emoji
|
||||
import java.security.PublicKey
|
||||
@ -125,10 +125,10 @@ class CommercialPaperLegacy : Contract {
|
||||
}
|
||||
|
||||
@Throws(InsufficientBalanceException::class)
|
||||
fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: Wallet) {
|
||||
// Add the cash movement using the states in our wallet.
|
||||
fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, vault: Vault) {
|
||||
// Add the cash movement using the states in our vault.
|
||||
Cash().generateSpend(tx, paper.state.data.faceValue.withoutIssuer(),
|
||||
paper.state.data.owner, wallet.statesOfType<Cash.State>())
|
||||
paper.state.data.owner, vault.statesOfType<Cash.State>())
|
||||
tx.addInputState(paper)
|
||||
tx.addCommand(Command(Commands.Redeem(), paper.state.data.owner))
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import com.r3corda.contracts.clause.NoZeroSizedOutputs
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.contracts.clauses.*
|
||||
import com.r3corda.core.crypto.*
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.node.services.Vault
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.utilities.Emoji
|
||||
import java.math.BigInteger
|
||||
@ -175,7 +175,7 @@ fun Iterable<ContractState>.sumCashOrZero(currency: Issued<Currency>): Amount<Is
|
||||
* Returns a map 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 present in map), not 0.
|
||||
*/
|
||||
val Wallet.cashBalances: Map<Currency, Amount<Currency>> get() = states.
|
||||
val Vault.cashBalances: Map<Currency, Amount<Currency>> get() = states.
|
||||
// Select the states we own which are cash, ignore the rest, take the amounts.
|
||||
mapNotNull { (it.state.data as? Cash.State)?.amount }.
|
||||
// Turn into a Map<Currency, List<Amount>> like { GBP -> (£100, £500, etc), USD -> ($2000, $50) }
|
||||
|
@ -50,9 +50,9 @@ abstract class OnLedgerAsset<T : Any, C: CommandData, S : FungibleAsset<T>> : Co
|
||||
|
||||
/**
|
||||
* Generate a transaction that consumes one or more of the given input states to move assets to the given pubkey.
|
||||
* Note that the wallet list is not updated: it's up to you to do that.
|
||||
* Note that the vault is not updated: it's up to you to do that.
|
||||
*
|
||||
* @param onlyFromParties if non-null, the wallet will be filtered to only include asset states issued by the set
|
||||
* @param onlyFromParties if non-null, the asset states will be filtered to only include those issued by the set
|
||||
* of given parties. This can be useful if the party you're trying to pay has expectations
|
||||
* about which type of asset claims they are willing to accept.
|
||||
*/
|
||||
|
@ -87,9 +87,9 @@ abstract class AbstractConserveAmount<S : FungibleAsset<T>, C : CommandData, T :
|
||||
|
||||
/**
|
||||
* Generate a transaction that consumes one or more of the given input states to move assets to the given pubkey.
|
||||
* Note that the wallet list is not updated: it's up to you to do that.
|
||||
* Note that the vault is not updated: it's up to you to do that.
|
||||
*
|
||||
* @param onlyFromParties if non-null, the wallet will be filtered to only include asset states issued by the set
|
||||
* @param onlyFromParties if non-null, the asset states will be filtered to only include those issued by the set
|
||||
* of given parties. This can be useful if the party you're trying to pay has expectations
|
||||
* about which type of asset claims they are willing to accept.
|
||||
*/
|
||||
@ -106,7 +106,7 @@ abstract class AbstractConserveAmount<S : FungibleAsset<T>, C : CommandData, T :
|
||||
// This code is analogous to the Wallet.send() set of methods in bitcoinj, and has the same general outline.
|
||||
//
|
||||
// First we must select a set of asset states (which for convenience we will call 'coins' here, as in bitcoinj).
|
||||
// The input states can be considered our "wallet", and may consist of different products, and with different
|
||||
// The input states can be considered our "vault", and may consist of different products, and with different
|
||||
// issuers and deposits.
|
||||
//
|
||||
// Coin selection is a complex problem all by itself and many different approaches can be used. It is easily
|
||||
|
@ -1,4 +1,4 @@
|
||||
@file:JvmName("WalletFiller")
|
||||
@file:JvmName("VaultFiller")
|
||||
package com.r3corda.contracts.testing
|
||||
|
||||
import com.r3corda.contracts.asset.Cash
|
||||
@ -10,7 +10,7 @@ import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.contracts.TransactionType
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.node.services.Vault
|
||||
import com.r3corda.core.serialization.OpaqueBytes
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import java.security.PublicKey
|
||||
@ -19,13 +19,13 @@ import java.util.*
|
||||
|
||||
/**
|
||||
* 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. This is intended for unit tests. The cash is issued by [DUMMY_CASH_ISSUER] and owned by the legal
|
||||
* to the vault. This is intended for unit tests. The cash is issued by [DUMMY_CASH_ISSUER] and owned by the legal
|
||||
* identity key from the storage service.
|
||||
*
|
||||
* The service hub needs to provide at least a key management service and a storage service.
|
||||
*
|
||||
* @param outputNotary the notary to use for output states. The transaction is NOT signed by this notary.
|
||||
* @return a wallet object that represents the generated states (it will NOT be the full wallet from the service hub!).
|
||||
* @return a vault object that represents the generated states (it will NOT be the full vault from the service hub!).
|
||||
*/
|
||||
fun ServiceHub.fillWithSomeTestCash(howMuch: Amount<Currency>,
|
||||
outputNotary: Party = DUMMY_NOTARY,
|
||||
@ -33,7 +33,7 @@ fun ServiceHub.fillWithSomeTestCash(howMuch: Amount<Currency>,
|
||||
atMostThisManyStates: Int = 10,
|
||||
rng: Random = Random(),
|
||||
ref: OpaqueBytes = OpaqueBytes(ByteArray(1, { 1 })),
|
||||
ownedBy: PublicKey? = null): Wallet {
|
||||
ownedBy: PublicKey? = null): Vault {
|
||||
val amounts = calculateRandomlySizedAmounts(howMuch, atLeastThisManyStates, atMostThisManyStates, rng)
|
||||
|
||||
val myKey: PublicKey = ownedBy ?: storageService.myLegalIdentityKey.public
|
||||
@ -55,7 +55,7 @@ fun ServiceHub.fillWithSomeTestCash(howMuch: Amount<Currency>,
|
||||
stx.tx.outputs.indices.map { i -> stx.tx.outRef<Cash.State>(i) }
|
||||
}
|
||||
|
||||
return Wallet(states)
|
||||
return Vault(states)
|
||||
}
|
||||
|
||||
private fun calculateRandomlySizedAmounts(howMuch: Amount<Currency>, min: Int, max: Int, rng: Random): LongArray {
|
@ -243,7 +243,7 @@ object TwoPartyTradeProtocol {
|
||||
private fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair<TransactionBuilder, List<PublicKey>> {
|
||||
val ptx = TransactionType.General.Builder(notary)
|
||||
// Add input and output states for the movement of cash, by using the Cash contract to generate the states.
|
||||
val wallet = serviceHub.walletService.currentWallet
|
||||
val wallet = serviceHub.vaultService.currentVault
|
||||
val cashStates = wallet.statesOfType<Cash.State>()
|
||||
val cashSigningPubKeys = Cash().generateSpend(ptx, tradeRequest.price, tradeRequest.sellerOwnerKey, cashStates)
|
||||
// Add inputs/outputs/a command for the movement of the asset.
|
||||
|
@ -191,7 +191,7 @@ class CommercialPaperTestsGeneric {
|
||||
}
|
||||
}
|
||||
|
||||
fun cashOutputsToWallet(vararg outputs: TransactionState<Cash.State>): Pair<LedgerTransaction, List<StateAndRef<Cash.State>>> {
|
||||
fun cashOutputsToVault(vararg outputs: TransactionState<Cash.State>): Pair<LedgerTransaction, List<StateAndRef<Cash.State>>> {
|
||||
val ltx = LedgerTransaction(emptyList(), listOf(*outputs), emptyList(), emptyList(), SecureHash.randomSHA256(), null, emptyList(), null, TransactionType.General())
|
||||
return Pair(ltx, outputs.mapIndexed { index, state -> StateAndRef(state, StateRef(ltx.id, index)) })
|
||||
}
|
||||
@ -199,14 +199,14 @@ class CommercialPaperTestsGeneric {
|
||||
@Test
|
||||
fun `issue move and then redeem`() {
|
||||
val aliceServices = MockServices()
|
||||
val alicesWallet = aliceServices.fillWithSomeTestCash(9000.DOLLARS)
|
||||
val alicesVault = aliceServices.fillWithSomeTestCash(9000.DOLLARS)
|
||||
|
||||
val bigCorpServices = MockServices()
|
||||
val bigCorpWallet = bigCorpServices.fillWithSomeTestCash(13000.DOLLARS)
|
||||
val bigCorpVault = bigCorpServices.fillWithSomeTestCash(13000.DOLLARS)
|
||||
|
||||
// Propagate the cash transactions to each side.
|
||||
aliceServices.recordTransactions(bigCorpWallet.states.map { bigCorpServices.storageService.validatedTransactions.getTransaction(it.ref.txhash)!! })
|
||||
bigCorpServices.recordTransactions(alicesWallet.states.map { aliceServices.storageService.validatedTransactions.getTransaction(it.ref.txhash)!! })
|
||||
aliceServices.recordTransactions(bigCorpVault.states.map { bigCorpServices.storageService.validatedTransactions.getTransaction(it.ref.txhash)!! })
|
||||
bigCorpServices.recordTransactions(alicesVault.states.map { aliceServices.storageService.validatedTransactions.getTransaction(it.ref.txhash)!! })
|
||||
|
||||
// BigCorp™ issues $10,000 of commercial paper, to mature in 30 days, owned initially by itself.
|
||||
val faceValue = 10000.DOLLARS `issued by` DUMMY_CASH_ISSUER
|
||||
@ -221,7 +221,7 @@ class CommercialPaperTestsGeneric {
|
||||
// Alice pays $9000 to BigCorp to own some of their debt.
|
||||
val moveTX: SignedTransaction = run {
|
||||
val ptx = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
Cash().generateSpend(ptx, 9000.DOLLARS, bigCorpServices.key.public, alicesWallet.statesOfType<Cash.State>())
|
||||
Cash().generateSpend(ptx, 9000.DOLLARS, bigCorpServices.key.public, alicesVault.statesOfType<Cash.State>())
|
||||
CommercialPaper().generateMove(ptx, issueTX.tx.outRef(0), aliceServices.key.public)
|
||||
ptx.signWith(bigCorpServices.key)
|
||||
ptx.signWith(aliceServices.key)
|
||||
@ -232,7 +232,7 @@ class CommercialPaperTestsGeneric {
|
||||
fun makeRedeemTX(time: Instant): SignedTransaction {
|
||||
val ptx = TransactionType.General.Builder(DUMMY_NOTARY)
|
||||
ptx.setTime(time, 30.seconds)
|
||||
CommercialPaper().generateRedeem(ptx, moveTX.tx.outRef(1), bigCorpWallet.statesOfType<Cash.State>())
|
||||
CommercialPaper().generateRedeem(ptx, moveTX.tx.outRef(1), bigCorpVault.statesOfType<Cash.State>())
|
||||
ptx.signWith(aliceServices.key)
|
||||
ptx.signWith(bigCorpServices.key)
|
||||
ptx.signWith(DUMMY_NOTARY_KEY)
|
||||
|
@ -220,18 +220,18 @@ data class ScheduledActivity(val logicRef: ProtocolLogicRef, override val schedu
|
||||
/**
|
||||
* A state that evolves by superseding itself, all of which share the common "linearId".
|
||||
*
|
||||
* This simplifies the job of tracking the current version of certain types of state in e.g. a wallet.
|
||||
* This simplifies the job of tracking the current version of certain types of state in e.g. a vault.
|
||||
*/
|
||||
interface LinearState: ContractState {
|
||||
/**
|
||||
* Unique id shared by all LinearState states throughout history within the wallets of all parties.
|
||||
* Unique id shared by all LinearState states throughout history within the vaults of all parties.
|
||||
* Verify methods should check that one input and one output share the id in a transaction,
|
||||
* except at issuance/termination.
|
||||
*/
|
||||
val linearId: UniqueIdentifier
|
||||
|
||||
/**
|
||||
* True if this should be tracked by our wallet(s).
|
||||
* True if this should be tracked by our vault(s).
|
||||
* */
|
||||
fun isRelevant(ourKeys: Set<PublicKey>): Boolean
|
||||
|
||||
@ -328,7 +328,7 @@ data class StateRef(val txhash: SecureHash, val index: Int) {
|
||||
override fun toString() = "$txhash($index)"
|
||||
}
|
||||
|
||||
/** A StateAndRef is simply a (state, ref) pair. For instance, a wallet (which holds available assets) contains these. */
|
||||
/** A StateAndRef is simply a (state, ref) pair. For instance, a vault (which holds available assets) contains these. */
|
||||
data class StateAndRef<out T : ContractState>(val state: TransactionState<T>, val ref: StateRef)
|
||||
|
||||
/** Filters a list of [StateAndRef] objects according to the type of the states */
|
||||
|
@ -31,7 +31,7 @@ data class TransactionForContract(val inputs: List<ContractState>,
|
||||
* The purpose of this function is to simplify the writing of verification logic for transactions that may contain
|
||||
* similar but unrelated state evolutions which need to be checked independently. Consider a transaction that
|
||||
* simultaneously moves both dollars and euros (e.g. is an atomic FX trade). There may be multiple dollar inputs and
|
||||
* multiple dollar outputs, depending on things like how fragmented the owners wallet is and whether various privacy
|
||||
* multiple dollar outputs, depending on things like how fragmented the owner's vault is and whether various privacy
|
||||
* techniques are in use. The quantity of dollars on the output side must sum to the same as on the input side, to
|
||||
* ensure no money is being lost track of. This summation and checking must be repeated independently for each
|
||||
* currency. To solve this, you would use groupStates with a type of Cash.State and a selector that returns the
|
||||
|
@ -19,7 +19,7 @@ import java.time.Clock
|
||||
* state from being serialized in checkpoints.
|
||||
*/
|
||||
interface ServiceHub {
|
||||
val walletService: WalletService
|
||||
val vaultService: VaultService
|
||||
val keyManagementService: KeyManagementService
|
||||
val identityService: IdentityService
|
||||
val storageService: StorageService
|
||||
@ -30,7 +30,7 @@ interface ServiceHub {
|
||||
|
||||
/**
|
||||
* Given a list of [SignedTransaction]s, writes them to the local storage for validated transactions and then
|
||||
* sends them to the wallet for further processing.
|
||||
* sends them to the vault for further processing.
|
||||
*
|
||||
* @param txs The transactions to record.
|
||||
*/
|
||||
@ -38,7 +38,7 @@ interface ServiceHub {
|
||||
|
||||
/**
|
||||
* Given some [SignedTransaction]s, writes them to the local storage for validated transactions and then
|
||||
* sends them to the wallet for further processing.
|
||||
* sends them to the vault for further processing.
|
||||
*
|
||||
* @param txs The transactions to record.
|
||||
*/
|
||||
|
@ -21,9 +21,9 @@ val DEFAULT_SESSION_ID = 0L
|
||||
*/
|
||||
|
||||
/**
|
||||
* A wallet (name may be temporary) wraps a set of states that are useful for us to keep track of, for instance,
|
||||
* because we own them. This class represents an immutable, stable state of a wallet: it is guaranteed not to
|
||||
* change out from underneath you, even though the canonical currently-best-known wallet may change as we learn
|
||||
* A vault (name may be temporary) wraps a set of states that are useful for us to keep track of, for instance,
|
||||
* because we own them. This class represents an immutable, stable state of a vault: it is guaranteed not to
|
||||
* change out from underneath you, even though the canonical currently-best-known vault may change as we learn
|
||||
* about new transactions from our peers and generate new transactions that consume states ourselves.
|
||||
*
|
||||
* This abstract class has no references to Cash contracts.
|
||||
@ -32,16 +32,16 @@ val DEFAULT_SESSION_ID = 0L
|
||||
* Active means they haven't been consumed yet (or we don't know about it).
|
||||
* Relevant means they contain at least one of our pubkeys.
|
||||
*/
|
||||
class Wallet(val states: Iterable<StateAndRef<ContractState>>) {
|
||||
class Vault(val states: Iterable<StateAndRef<ContractState>>) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T : ContractState> statesOfType() = states.filter { it.state.data is T } as List<StateAndRef<T>>
|
||||
|
||||
/**
|
||||
* Represents an update observed by the Wallet that will be notified to observers. Include the [StateRef]s of
|
||||
* Represents an update observed by the vault 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.
|
||||
* or transactions observed and the vault.
|
||||
*
|
||||
* If the Wallet observes multiple transactions simultaneously, where some transactions consume the outputs of some of the
|
||||
* If the vault 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<StateRef>, val produced: Set<StateAndRef<ContractState>>) {
|
||||
@ -54,7 +54,7 @@ class Wallet(val states: Iterable<StateAndRef<ContractState>>) {
|
||||
operator fun plus(rhs: Update): Update {
|
||||
val previouslyProduced = produced.map { it.ref }
|
||||
val previouslyConsumed = consumed
|
||||
val combined = Wallet.Update(
|
||||
val combined = Vault.Update(
|
||||
previouslyConsumed + (rhs.consumed - previouslyProduced),
|
||||
// The ordering below matters to preserve ordering of consumed/produced Sets when they are insertion order dependent implementations.
|
||||
produced.filter { it.ref !in rhs.consumed }.toSet() + rhs.produced)
|
||||
@ -79,19 +79,19 @@ class Wallet(val states: Iterable<StateAndRef<ContractState>>) {
|
||||
}
|
||||
|
||||
/**
|
||||
* A [WalletService] is responsible for securely and safely persisting the current state of a wallet to storage. The
|
||||
* wallet service vends immutable snapshots of the current wallet for working with: if you build a transaction based
|
||||
* on a wallet that isn't current, be aware that it may end up being invalid if the states that were used have been
|
||||
* A [VaultService] is responsible for securely and safely persisting the current state of a vault to storage. The
|
||||
* vault service vends immutable snapshots of the current vault for working with: if you build a transaction based
|
||||
* on a vault that isn't current, be aware that it may end up being invalid if the states that were used have been
|
||||
* consumed by someone else first!
|
||||
*
|
||||
* Note that transactions we've seen are held by the storage service, not the wallet.
|
||||
* Note that transactions we've seen are held by the storage service, not the vault.
|
||||
*/
|
||||
interface WalletService {
|
||||
interface VaultService {
|
||||
/**
|
||||
* Returns a read-only snapshot of the wallet at the time the call is made. Note that if you consume states or
|
||||
* keys in this wallet, you must inform the wallet service so it can update its internal state.
|
||||
* Returns a read-only snapshot of the vault at the time the call is made. Note that if you consume states or
|
||||
* keys in this vault, you must inform the vault service so it can update its internal state.
|
||||
*/
|
||||
val currentWallet: Wallet
|
||||
val currentVault: Vault
|
||||
|
||||
/**
|
||||
* Returns a snapshot of the heads of LinearStates.
|
||||
@ -107,34 +107,34 @@ interface WalletService {
|
||||
}
|
||||
|
||||
fun statesForRefs(refs: List<StateRef>): Map<StateRef, TransactionState<*>?> {
|
||||
val refsToStates = currentWallet.states.associateBy { it.ref }
|
||||
val refsToStates = currentVault.states.associateBy { it.ref }
|
||||
return refs.associateBy({ it }, { refsToStates[it]?.state })
|
||||
}
|
||||
|
||||
/**
|
||||
* Possibly update the wallet by marking as spent states that these transactions consume, and adding any relevant
|
||||
* Possibly update the vault by marking as spent states that these transactions consume, and adding any relevant
|
||||
* new states that they create. You should only insert transactions that have been successfully verified here!
|
||||
*
|
||||
* Returns the new wallet that resulted from applying the transactions (note: it may quickly become out of date).
|
||||
* Returns the new vault that resulted from applying the transactions (note: it may quickly become out of date).
|
||||
*
|
||||
* TODO: Consider if there's a good way to enforce the must-be-verified requirement in the type system.
|
||||
*/
|
||||
fun notifyAll(txns: Iterable<WireTransaction>): Wallet
|
||||
fun notifyAll(txns: Iterable<WireTransaction>): Vault
|
||||
|
||||
/** Same as notifyAll but with a single transaction. */
|
||||
fun notify(tx: WireTransaction): Wallet = notifyAll(listOf(tx))
|
||||
fun notify(tx: WireTransaction): Vault = notifyAll(listOf(tx))
|
||||
|
||||
/**
|
||||
* Get a synchronous Observable of updates. When observations are pushed to the Observer, the Wallet will already incorporate
|
||||
* the update.
|
||||
* Get a synchronous Observable of updates. When observations are pushed to the Observer, the vault will already
|
||||
* incorporate the update.
|
||||
*/
|
||||
val updates: rx.Observable<Wallet.Update>
|
||||
val updates: rx.Observable<Vault.Update>
|
||||
|
||||
/**
|
||||
* Provide a [Future] for when a [StateRef] is consumed, which can be very useful in building tests.
|
||||
*/
|
||||
fun whenConsumed(ref: StateRef): ListenableFuture<Wallet.Update> {
|
||||
val future = SettableFuture.create<Wallet.Update>()
|
||||
fun whenConsumed(ref: StateRef): ListenableFuture<Vault.Update> {
|
||||
val future = SettableFuture.create<Vault.Update>()
|
||||
updates.filter { ref in it.consumed }.first().subscribe {
|
||||
future.set(it)
|
||||
}
|
||||
@ -142,7 +142,7 @@ interface WalletService {
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : LinearState> WalletService.linearHeadsOfType() = linearHeadsOfType_(T::class.java)
|
||||
inline fun <reified T : LinearState> VaultService.linearHeadsOfType() = linearHeadsOfType_(T::class.java)
|
||||
|
||||
/**
|
||||
* The KMS is responsible for storing and using private keys to sign things. An implementation of this may, for example,
|
||||
@ -206,7 +206,7 @@ interface TxWritableStorageService : StorageService {
|
||||
*
|
||||
* If the point in time is in the past, the expectation is that the activity will happen shortly after it is scheduled.
|
||||
*
|
||||
* The main consumer initially is an observer of the wallet to schedule activities based on transactions as they are
|
||||
* The main consumer initially is an observer of the vault to schedule activities based on transactions as they are
|
||||
* recorded.
|
||||
*/
|
||||
interface SchedulerService {
|
||||
|
@ -13,8 +13,8 @@ interface ReadOnlyTransactionStorage {
|
||||
fun getTransaction(id: SecureHash): SignedTransaction?
|
||||
|
||||
/**
|
||||
* Get a synchronous Observable of updates. When observations are pushed to the Observer, the Wallet will already incorporate
|
||||
* the update.
|
||||
* Get a synchronous Observable of updates. When observations are pushed to the Observer, the vault will already
|
||||
* incorporate the update.
|
||||
*/
|
||||
val updates: rx.Observable<SignedTransaction>
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ import com.r3corda.core.ThreadBox
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.node.services.WalletService
|
||||
import com.r3corda.core.node.services.Vault
|
||||
import com.r3corda.core.node.services.VaultService
|
||||
import com.r3corda.core.serialization.SingletonSerializeAsToken
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.loggerFor
|
||||
@ -17,88 +17,88 @@ import java.util.*
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
|
||||
/**
|
||||
* This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience
|
||||
* method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist
|
||||
* states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.
|
||||
* This class implements a simple, in memory vault that tracks states that are owned by us, and also has a convenience
|
||||
* method to auto-generate some self-issued cash states that can be used for test trading. A real vault would persist
|
||||
* states relevant to us into a database and once such a vault is implemented, this scaffolding can be removed.
|
||||
*/
|
||||
@ThreadSafe
|
||||
open class InMemoryWalletService(protected val services: ServiceHub) : SingletonSerializeAsToken(), WalletService {
|
||||
open protected val log = loggerFor<InMemoryWalletService>()
|
||||
open class InMemoryVaultService(protected val services: ServiceHub) : SingletonSerializeAsToken(), VaultService {
|
||||
open protected val log = loggerFor<InMemoryVaultService>()
|
||||
|
||||
// Variables inside InnerState are protected with a lock by the ThreadBox and aren't in scope unless you're
|
||||
// inside mutex.locked {} code block. So we can't forget to take the lock unless we accidentally leak a reference
|
||||
// to wallet somewhere.
|
||||
// to vault somewhere.
|
||||
protected class InnerState {
|
||||
var wallet = Wallet(emptyList<StateAndRef<ContractState>>())
|
||||
var vault = Vault(emptyList<StateAndRef<ContractState>>())
|
||||
}
|
||||
|
||||
protected val mutex = ThreadBox(InnerState())
|
||||
|
||||
override val currentWallet: Wallet get() = mutex.locked { wallet }
|
||||
override val currentVault: Vault get() = mutex.locked { vault }
|
||||
|
||||
private val _updatesPublisher = PublishSubject.create<Wallet.Update>()
|
||||
private val _updatesPublisher = PublishSubject.create<Vault.Update>()
|
||||
|
||||
override val updates: Observable<Wallet.Update>
|
||||
override val updates: Observable<Vault.Update>
|
||||
get() = _updatesPublisher
|
||||
|
||||
/**
|
||||
* Returns a snapshot of the heads of LinearStates.
|
||||
*/
|
||||
override val linearHeads: Map<UniqueIdentifier, StateAndRef<LinearState>>
|
||||
get() = currentWallet.let { wallet ->
|
||||
wallet.states.filterStatesOfType<LinearState>().associateBy { it.state.data.linearId }.mapValues { it.value }
|
||||
get() = currentVault.let { vault ->
|
||||
vault.states.filterStatesOfType<LinearState>().associateBy { it.state.data.linearId }.mapValues { it.value }
|
||||
}
|
||||
|
||||
override fun notifyAll(txns: Iterable<WireTransaction>): Wallet {
|
||||
override fun notifyAll(txns: Iterable<WireTransaction>): Vault {
|
||||
val ourKeys = services.keyManagementService.keys.keys
|
||||
|
||||
// Note how terribly incomplete this all is!
|
||||
//
|
||||
// - We don't notify anyone of anything, there are no event listeners.
|
||||
// - We don't handle or even notice invalidations due to double spends of things in our wallet.
|
||||
// - We don't handle or even notice invalidations due to double spends of things in our vault.
|
||||
// - We have no concept of confidence (for txns where there is no definite finality).
|
||||
// - No notification that keys are used, for the case where we observe a spend of our own states.
|
||||
// - No ability to create complex spends.
|
||||
// - No logging or tracking of how the wallet got into this state.
|
||||
// - No logging or tracking of how the vault got into this state.
|
||||
// - No persistence.
|
||||
// - Does tx relevancy calculation and key management need to be interlocked? Probably yes.
|
||||
//
|
||||
// ... and many other things .... (Wallet.java in bitcoinj is several thousand lines long)
|
||||
|
||||
var netDelta = Wallet.NoUpdate
|
||||
val changedWallet = mutex.locked {
|
||||
// Starting from the current wallet, keep applying the transaction updates, calculating a new Wallet each
|
||||
var netDelta = Vault.NoUpdate
|
||||
val changedVault = mutex.locked {
|
||||
// Starting from the current vault, keep applying the transaction updates, calculating a new vault each
|
||||
// time, until we get to the result (this is perhaps a bit inefficient, but it's functional and easily
|
||||
// unit tested).
|
||||
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)
|
||||
val vaultAndNetDelta = txns.fold(Pair(currentVault, Vault.NoUpdate)) { vaultAndDelta, tx ->
|
||||
val (vault, delta) = vaultAndDelta.first.update(tx, ourKeys)
|
||||
val combinedDelta = delta + vaultAndDelta.second
|
||||
Pair(vault, combinedDelta)
|
||||
}
|
||||
|
||||
wallet = walletAndNetDelta.first
|
||||
netDelta = walletAndNetDelta.second
|
||||
return@locked wallet
|
||||
vault = vaultAndNetDelta.first
|
||||
netDelta = vaultAndNetDelta.second
|
||||
return@locked vault
|
||||
}
|
||||
|
||||
if (netDelta != Wallet.NoUpdate) {
|
||||
if (netDelta != Vault.NoUpdate) {
|
||||
_updatesPublisher.onNext(netDelta)
|
||||
}
|
||||
return changedWallet
|
||||
return changedVault
|
||||
}
|
||||
|
||||
private fun isRelevant(state: ContractState, ourKeys: Set<PublicKey>): Boolean {
|
||||
return if (state is OwnableState) {
|
||||
state.owner in ourKeys
|
||||
} else if (state is LinearState) {
|
||||
// It's potentially of interest to the wallet
|
||||
// It's potentially of interest to the vault
|
||||
state.isRelevant(ourKeys)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun Wallet.update(tx: WireTransaction, ourKeys: Set<PublicKey>): Pair<Wallet, Wallet.Update> {
|
||||
private fun Vault.update(tx: WireTransaction, ourKeys: Set<PublicKey>): Pair<Vault, Vault.Update> {
|
||||
val ourNewStates = tx.outputs.
|
||||
filter { isRelevant(it.data, ourKeys) }.
|
||||
map { tx.outRef<ContractState>(it.data) }
|
||||
@ -108,19 +108,19 @@ open class InMemoryWalletService(protected val services: ServiceHub) : Singleton
|
||||
|
||||
// Is transaction irrelevant?
|
||||
if (consumed.isEmpty() && ourNewStates.isEmpty()) {
|
||||
log.trace { "tx ${tx.id} was irrelevant to this wallet, ignoring" }
|
||||
return Pair(this, Wallet.NoUpdate)
|
||||
log.trace { "tx ${tx.id} was irrelevant to this vault, ignoring" }
|
||||
return Pair(this, Vault.NoUpdate)
|
||||
}
|
||||
|
||||
val change = Wallet.Update(consumed, HashSet(ourNewStates))
|
||||
val change = Vault.Update(consumed, HashSet(ourNewStates))
|
||||
|
||||
// And calculate the new wallet.
|
||||
// And calculate the new vault.
|
||||
val newStates = states.filter { it.ref !in consumed } + ourNewStates
|
||||
|
||||
log.trace {
|
||||
"Applied tx ${tx.id.prefixChars()} to the wallet: consumed ${consumed.size} states and added ${newStates.size}"
|
||||
"Applied tx ${tx.id.prefixChars()} to the vault: consumed ${consumed.size} states and added ${newStates.size}"
|
||||
}
|
||||
|
||||
return Pair(Wallet(newStates), change)
|
||||
return Pair(Vault(newStates), change)
|
||||
}
|
||||
}
|
@ -2,14 +2,14 @@ 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.node.services.Vault
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import org.junit.Test
|
||||
import java.security.PublicKey
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
||||
class WalletUpdateTests {
|
||||
class VaultUpdateTests {
|
||||
|
||||
object DummyContract : Contract {
|
||||
|
||||
@ -22,7 +22,7 @@ class WalletUpdateTests {
|
||||
private class DummyState : ContractState {
|
||||
override val participants: List<PublicKey>
|
||||
get() = emptyList()
|
||||
override val contract = WalletUpdateTests.DummyContract
|
||||
override val contract = VaultUpdateTests.DummyContract
|
||||
}
|
||||
|
||||
private val stateRef0 = StateRef(SecureHash.randomSHA256(), 0)
|
||||
@ -39,47 +39,47 @@ class WalletUpdateTests {
|
||||
|
||||
@Test
|
||||
fun `nothing plus nothing is nothing`() {
|
||||
val before = Wallet.NoUpdate
|
||||
val after = before + Wallet.NoUpdate
|
||||
val before = Vault.NoUpdate
|
||||
val after = before + Vault.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
|
||||
val before = Vault.Update(setOf(stateRef0, stateRef1), setOf(stateAndRef2, stateAndRef3))
|
||||
val after = before + Vault.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))
|
||||
val before = Vault.NoUpdate
|
||||
val after = before + Vault.Update(setOf(stateRef0, stateRef1), setOf(stateAndRef2, stateAndRef3))
|
||||
val expected = Vault.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))
|
||||
val before = Vault.Update(setOf(stateRef2, stateRef3), setOf(stateAndRef0, stateAndRef1))
|
||||
val after = before + Vault.Update(setOf(stateRef0), setOf())
|
||||
val expected = Vault.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))
|
||||
val before = Vault.Update(setOf(stateRef2, stateRef3), setOf(stateAndRef0, stateAndRef1))
|
||||
val after = before + Vault.Update(setOf(), setOf(stateAndRef4))
|
||||
val expected = Vault.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))
|
||||
val before = Vault.Update(setOf(stateRef2, stateRef3), setOf(stateAndRef0, stateAndRef1))
|
||||
val after = before + Vault.Update(setOf(stateRef0, stateRef1), setOf(stateAndRef4))
|
||||
val expected = Vault.Update(setOf(stateRef2, stateRef3), setOf(stateAndRef4))
|
||||
assertEquals(expected, after)
|
||||
}
|
||||
}
|
@ -13,6 +13,8 @@ API changes:
|
||||
location.
|
||||
* ``AbstractStateReplacementProtocol.verifyProposal`` has changed its prototype in a minor way.
|
||||
* The ``UntrustworthyData<T>.validate`` method has been renamed to ``unwrap`` - the old name is now deprecated.
|
||||
* The wallet, wallet service, etc. are now vault, vault service, etc. These better reflect the intent that they
|
||||
are a generic secure data store, rather than something which holds cash.
|
||||
|
||||
Milestone 3
|
||||
-----------
|
||||
|
@ -30,10 +30,10 @@ class APIServerImpl(val node: AbstractNode) : APIServer {
|
||||
// something we can't later implement against a persistent store (i.e. need to pick / build a query engine)
|
||||
if (query is StatesQuery.Selection) {
|
||||
if (query.criteria is StatesQuery.Criteria.AllDeals) {
|
||||
val states = node.services.walletService.linearHeads
|
||||
val states = node.services.vaultService.linearHeads
|
||||
return states.values.map { it.ref }
|
||||
} else if (query.criteria is StatesQuery.Criteria.Deal) {
|
||||
val states = node.services.walletService.linearHeadsOfType<DealState>().filterValues {
|
||||
val states = node.services.vaultService.linearHeadsOfType<DealState>().filterValues {
|
||||
it.state.data.ref == query.criteria.ref
|
||||
}
|
||||
return states.values.map { it.ref }
|
||||
@ -43,7 +43,7 @@ class APIServerImpl(val node: AbstractNode) : APIServer {
|
||||
}
|
||||
|
||||
override fun fetchStates(states: List<StateRef>): Map<StateRef, TransactionState<ContractState>?> {
|
||||
return node.services.walletService.statesForRefs(states)
|
||||
return node.services.vaultService.statesForRefs(states)
|
||||
}
|
||||
|
||||
override fun fetchTransactions(txs: List<SecureHash>): Map<SecureHash, SignedTransaction?> {
|
||||
|
@ -43,8 +43,8 @@ import com.r3corda.node.services.statemachine.StateMachineManager
|
||||
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.services.vault.CashBalanceAsMetricsObserver
|
||||
import com.r3corda.node.services.vault.NodeVaultService
|
||||
import com.r3corda.node.utilities.*
|
||||
import org.slf4j.Logger
|
||||
import java.nio.file.FileAlreadyExistsException
|
||||
@ -94,7 +94,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
||||
override val networkService: MessagingServiceInternal get() = net
|
||||
override val networkMapCache: NetworkMapCache get() = netMapCache
|
||||
override val storageService: TxWritableStorageService get() = storage
|
||||
override val walletService: WalletService get() = wallet
|
||||
override val vaultService: VaultService get() = vault
|
||||
override val keyManagementService: KeyManagementService get() = keyManagement
|
||||
override val identityService: IdentityService get() = identity
|
||||
override val schedulerService: SchedulerService get() = scheduler
|
||||
@ -121,7 +121,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
||||
lateinit var storage: TxWritableStorageService
|
||||
lateinit var checkpointStorage: CheckpointStorage
|
||||
lateinit var smm: StateMachineManager
|
||||
lateinit var wallet: WalletService
|
||||
lateinit var vault: VaultService
|
||||
lateinit var keyManagement: KeyManagementService
|
||||
var inNodeNetworkMapService: NetworkMapService? = null
|
||||
var inNodeWalletMonitorService: WalletMonitorService? = null
|
||||
@ -167,7 +167,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
||||
checkpointStorage = storageServices.second
|
||||
netMapCache = InMemoryNetworkMapCache()
|
||||
net = makeMessagingService()
|
||||
wallet = makeWalletService()
|
||||
vault = makeVaultService()
|
||||
|
||||
identity = makeIdentityService()
|
||||
|
||||
@ -180,7 +180,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
||||
|
||||
protocolLogicFactory = initialiseProtocolLogicFactory()
|
||||
|
||||
val tokenizableServices = mutableListOf(storage, net, wallet, keyManagement, identity, platformClock, scheduler)
|
||||
val tokenizableServices = mutableListOf(storage, net, vault, keyManagement, identity, platformClock, scheduler)
|
||||
|
||||
customServices.clear()
|
||||
customServices.addAll(buildPluginServices(tokenizableServices))
|
||||
@ -211,7 +211,7 @@ 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
|
||||
// Add vault observers
|
||||
CashBalanceAsMetricsObserver(services)
|
||||
ScheduledActivityObserver(services)
|
||||
}
|
||||
@ -372,7 +372,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
||||
}
|
||||
|
||||
// TODO: sort out ordering of open & protected modifiers of functions in this class.
|
||||
protected open fun makeWalletService(): WalletService = NodeWalletService(services)
|
||||
protected open fun makeVaultService(): VaultService = NodeVaultService(services)
|
||||
|
||||
protected open fun makeWalletMonitorService(): WalletMonitorService = WalletMonitorService(services, smm)
|
||||
|
||||
|
@ -39,14 +39,14 @@ abstract class ServiceHubInternal : ServiceHub {
|
||||
|
||||
/**
|
||||
* Given a list of [SignedTransaction]s, writes them to the given storage for validated transactions and then
|
||||
* sends them to the wallet for further processing. This is intended for implementations to call from
|
||||
* sends them to the vault for further processing. This is intended for implementations to call from
|
||||
* [recordTransactions].
|
||||
*
|
||||
* @param txs The transactions to record.
|
||||
*/
|
||||
internal fun recordTransactionsInternal(writableStorageService: TxWritableStorageService, txs: Iterable<SignedTransaction>) {
|
||||
txs.forEach { writableStorageService.validatedTransactions.addTransaction(it) }
|
||||
walletService.notifyAll(txs.map { it.tx })
|
||||
vaultService.notifyAll(txs.map { it.tx })
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,7 @@ import javax.annotation.concurrent.ThreadSafe
|
||||
|
||||
/**
|
||||
* A first pass of a simple [SchedulerService] that works with [MutableClock]s for testing, demonstrations and simulations
|
||||
* that also encompasses the [Wallet] observer for processing transactions.
|
||||
* that also encompasses the [Vault] observer for processing transactions.
|
||||
*
|
||||
* This will observe transactions as they are stored and schedule and unschedule activities based on the States consumed
|
||||
* or produced.
|
||||
@ -50,7 +50,7 @@ class NodeSchedulerService(private val services: ServiceHubInternal,
|
||||
// to somewhere.
|
||||
private class InnerState {
|
||||
// TODO: This has no persistence, and we don't consider initialising from non-empty map if we add persistence.
|
||||
// If we were to rebuild the wallet at start up by replaying transactions and re-calculating, then
|
||||
// If we were to rebuild the vault at start up by replaying transactions and re-calculating, then
|
||||
// persistence here would be unnecessary.
|
||||
var scheduledStates = HashMap<StateRef, ScheduledStateRef>()
|
||||
var earliestState: ScheduledStateRef? = null
|
||||
|
@ -8,21 +8,21 @@ import com.r3corda.core.protocols.ProtocolLogicRefFactory
|
||||
import com.r3corda.node.services.api.ServiceHubInternal
|
||||
|
||||
/**
|
||||
* This observes the wallet and schedules and unschedules activities appropriately based on state production and
|
||||
* This observes the vault and schedules and unschedules activities appropriately based on state production and
|
||||
* consumption.
|
||||
*/
|
||||
class ScheduledActivityObserver(val services: ServiceHubInternal) {
|
||||
init {
|
||||
// TODO: Need to consider failure scenarios. This needs to run if the TX is successfully recorded
|
||||
services.walletService.updates.subscribe { update ->
|
||||
services.vaultService.updates.subscribe { update ->
|
||||
update.consumed.forEach { services.schedulerService.unscheduleStateActivity(it) }
|
||||
update.produced.forEach { scheduleStateActivity(it, services.protocolLogicRefFactory) }
|
||||
}
|
||||
|
||||
// In the short term, to get restart-able IRS demo, re-initialise from wallet state
|
||||
// In the short term, to get restart-able IRS demo, re-initialise from vault state
|
||||
// TODO: there's a race condition here. We need to move persistence into the scheduler but that is a bigger
|
||||
// change so I want to revisit as a distinct branch/PR.
|
||||
for (state in services.walletService.currentWallet.statesOfType<SchedulableState>()) {
|
||||
for (state in services.vaultService.currentVault.statesOfType<SchedulableState>()) {
|
||||
scheduleStateActivity(state, services.protocolLogicRefFactory)
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.toStringShort
|
||||
import com.r3corda.core.messaging.MessageRecipients
|
||||
import com.r3corda.core.node.services.DEFAULT_SESSION_ID
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.node.services.Vault
|
||||
import com.r3corda.core.protocols.ProtocolLogic
|
||||
import com.r3corda.core.serialization.serialize
|
||||
import com.r3corda.core.transactions.LedgerTransaction
|
||||
@ -60,7 +60,7 @@ class WalletMonitorService(services: ServiceHubInternal, val smm: StateMachineMa
|
||||
|
||||
// Notify listeners on state changes
|
||||
services.storageService.validatedTransactions.updates.subscribe { tx -> notifyTransaction(tx.tx.toLedgerTransaction(services)) }
|
||||
services.walletService.updates.subscribe { update -> notifyWalletUpdate(update) }
|
||||
services.vaultService.updates.subscribe { update -> notifyVaultUpdate(update) }
|
||||
smm.changes.subscribe { change ->
|
||||
val fiberId: Long = change.third
|
||||
val logic: ProtocolLogic<*> = change.first
|
||||
@ -81,7 +81,7 @@ class WalletMonitorService(services: ServiceHubInternal, val smm: StateMachineMa
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal fun notifyWalletUpdate(update: Wallet.Update)
|
||||
internal fun notifyVaultUpdate(update: Vault.Update)
|
||||
= notifyEvent(ServiceToClientEvent.OutputState(Instant.now(), update.consumed, update.produced))
|
||||
|
||||
@VisibleForTesting
|
||||
@ -135,7 +135,7 @@ class WalletMonitorService(services: ServiceHubInternal, val smm: StateMachineMa
|
||||
fun processRegisterRequest(req: RegisterRequest) {
|
||||
try {
|
||||
listeners.add(RegisteredListener(req.replyToRecipient, req.sessionID))
|
||||
val stateMessage = StateSnapshotMessage(services.walletService.currentWallet.states.toList(),
|
||||
val stateMessage = StateSnapshotMessage(services.vaultService.currentVault.states.toList(),
|
||||
smm.allStateMachines.map { it.javaClass.name })
|
||||
net.send(net.createMessage(STATE_TOPIC, DEFAULT_SESSION_ID, stateMessage.serialize().bits), req.replyToRecipient)
|
||||
|
||||
@ -158,7 +158,7 @@ class WalletMonitorService(services: ServiceHubInternal, val smm: StateMachineMa
|
||||
try {
|
||||
Cash().generateSpend(builder, req.amount.withoutIssuer(), req.recipient.owningKey,
|
||||
// TODO: Move cash state filtering by issuer down to the contract itself
|
||||
services.walletService.currentWallet.statesOfType<Cash.State>().filter { it.state.data.amount.token == req.amount.token },
|
||||
services.vaultService.currentVault.statesOfType<Cash.State>().filter { it.state.data.amount.token == req.amount.token },
|
||||
setOf(req.amount.token.issuer.party))
|
||||
.forEach {
|
||||
val key = services.keyManagementService.keys[it] ?: throw IllegalStateException("Could not find signing key for ${it.toStringShort()}")
|
||||
@ -182,11 +182,11 @@ class WalletMonitorService(services: ServiceHubInternal, val smm: StateMachineMa
|
||||
try {
|
||||
val issuer = PartyAndReference(services.storageService.myLegalIdentity, req.issueRef)
|
||||
Cash().generateExit(builder, req.amount.issuedBy(issuer),
|
||||
services.walletService.currentWallet.statesOfType<Cash.State>().filter { it.state.data.owner == issuer.party.owningKey })
|
||||
services.vaultService.currentVault.statesOfType<Cash.State>().filter { it.state.data.owner == issuer.party.owningKey })
|
||||
builder.signWith(services.storageService.myLegalIdentityKey)
|
||||
|
||||
// Work out who the owners of the burnt states were
|
||||
val inputStatesNullable = services.walletService.statesForRefs(builder.inputStates())
|
||||
val inputStatesNullable = services.vaultService.statesForRefs(builder.inputStates())
|
||||
val inputStates = inputStatesNullable.values.filterNotNull().map { it.data }
|
||||
if (inputStatesNullable.size != inputStates.size) {
|
||||
val unresolvedStateRefs = inputStatesNullable.filter { it.value == null }.map { it.key }
|
||||
|
@ -1,19 +1,19 @@
|
||||
package com.r3corda.node.services.wallet
|
||||
package com.r3corda.node.services.vault
|
||||
|
||||
import com.codahale.metrics.Gauge
|
||||
import com.r3corda.contracts.asset.cashBalances
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.node.services.Vault
|
||||
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.
|
||||
* This class observes the vault 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)
|
||||
serviceHubInternal.vaultService.updates.subscribe { update ->
|
||||
exportCashBalancesViaMetrics(serviceHubInternal.vaultService.currentVault)
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,16 +24,16 @@ class CashBalanceAsMetricsObserver(val serviceHubInternal: ServiceHubInternal) {
|
||||
|
||||
private val balanceMetrics = HashMap<Currency, BalanceMetric>()
|
||||
|
||||
private fun exportCashBalancesViaMetrics(wallet: Wallet) {
|
||||
private fun exportCashBalancesViaMetrics(vault: Vault) {
|
||||
// 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 ((key, value) in wallet.cashBalances) {
|
||||
for ((key, value) in vault.cashBalances) {
|
||||
val metric = balanceMetrics.getOrPut(key) {
|
||||
val newMetric = BalanceMetric()
|
||||
m.register("WalletBalances.${key}Pennies", newMetric)
|
||||
m.register("VaultBalances.${key}Pennies", newMetric)
|
||||
newMetric
|
||||
}
|
||||
metric.pennies = value.quantity
|
@ -1,11 +1,11 @@
|
||||
package com.r3corda.node.services.wallet
|
||||
package com.r3corda.node.services.vault
|
||||
|
||||
import com.google.common.collect.Sets
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.node.services.WalletService
|
||||
import com.r3corda.core.node.services.Vault
|
||||
import com.r3corda.core.node.services.VaultService
|
||||
import com.r3corda.core.serialization.SingletonSerializeAsToken
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.loggerFor
|
||||
@ -21,8 +21,8 @@ import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
/**
|
||||
* Currently, the node wallet service is a very simple RDBMS backed implementation. It will change significantly when
|
||||
* we add further functionality as the design for the wallet and wallet service matures.
|
||||
* Currently, the node vault service is a very simple RDBMS backed implementation. It will change significantly when
|
||||
* we add further functionality as the design for the vault and vault service matures.
|
||||
*
|
||||
* This class needs database transactions to be in-flight during method calls and init, and will throw exceptions if
|
||||
* this is not the case.
|
||||
@ -31,10 +31,10 @@ import kotlin.concurrent.withLock
|
||||
* TODO: keep an audit trail with time stamps of previously unconsumed states "as of" a particular point in time.
|
||||
* TODO: have transaction storage do some caching.
|
||||
*/
|
||||
class NodeWalletService(private val services: ServiceHub) : SingletonSerializeAsToken(), WalletService {
|
||||
class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsToken(), VaultService {
|
||||
|
||||
private companion object {
|
||||
val log = loggerFor<NodeWalletService>()
|
||||
val log = loggerFor<NodeVaultService>()
|
||||
}
|
||||
|
||||
private object StatesSetTable : JDBCHashedTable("vault_unconsumed_states") {
|
||||
@ -53,11 +53,11 @@ class NodeWalletService(private val services: ServiceHub) : SingletonSerializeAs
|
||||
|
||||
protected val mutex = ReentrantLock()
|
||||
|
||||
override val currentWallet: Wallet get() = mutex.withLock { Wallet(allUnconsumedStates()) }
|
||||
override val currentVault: Vault get() = mutex.withLock { Vault(allUnconsumedStates()) }
|
||||
|
||||
private val _updatesPublisher = PublishSubject.create<Wallet.Update>()
|
||||
private val _updatesPublisher = PublishSubject.create<Vault.Update>()
|
||||
|
||||
override val updates: Observable<Wallet.Update>
|
||||
override val updates: Observable<Vault.Update>
|
||||
get() = _updatesPublisher
|
||||
|
||||
/**
|
||||
@ -66,21 +66,21 @@ class NodeWalletService(private val services: ServiceHub) : SingletonSerializeAs
|
||||
* TODO: Represent this using an actual JDBCHashMap or look at vault design further.
|
||||
*/
|
||||
override val linearHeads: Map<UniqueIdentifier, StateAndRef<LinearState>>
|
||||
get() = currentWallet.states.filterStatesOfType<LinearState>().associateBy { it.state.data.linearId }.mapValues { it.value }
|
||||
get() = currentVault.states.filterStatesOfType<LinearState>().associateBy { it.state.data.linearId }.mapValues { it.value }
|
||||
|
||||
override fun notifyAll(txns: Iterable<WireTransaction>): Wallet {
|
||||
override fun notifyAll(txns: Iterable<WireTransaction>): Vault {
|
||||
val ourKeys = services.keyManagementService.keys.keys
|
||||
val netDelta = txns.fold(Wallet.NoUpdate) { netDelta, txn -> netDelta + makeUpdate(txn, netDelta, ourKeys) }
|
||||
if (netDelta != Wallet.NoUpdate) {
|
||||
val netDelta = txns.fold(Vault.NoUpdate) { netDelta, txn -> netDelta + makeUpdate(txn, netDelta, ourKeys) }
|
||||
if (netDelta != Vault.NoUpdate) {
|
||||
mutex.withLock {
|
||||
recordUpdate(netDelta)
|
||||
}
|
||||
_updatesPublisher.onNext(netDelta)
|
||||
}
|
||||
return currentWallet
|
||||
return currentVault
|
||||
}
|
||||
|
||||
private fun makeUpdate(tx: WireTransaction, netDelta: Wallet.Update, ourKeys: Set<PublicKey>): Wallet.Update {
|
||||
private fun makeUpdate(tx: WireTransaction, netDelta: Vault.Update, ourKeys: Set<PublicKey>): Vault.Update {
|
||||
val ourNewStates = tx.outputs.
|
||||
filter { isRelevant(it.data, ourKeys) }.
|
||||
map { tx.outRef<ContractState>(it.data) }
|
||||
@ -95,26 +95,26 @@ class NodeWalletService(private val services: ServiceHub) : SingletonSerializeAs
|
||||
|
||||
// Is transaction irrelevant?
|
||||
if (consumed.isEmpty() && ourNewStates.isEmpty()) {
|
||||
log.trace { "tx ${tx.id} was irrelevant to this wallet, ignoring" }
|
||||
return Wallet.NoUpdate
|
||||
log.trace { "tx ${tx.id} was irrelevant to this vault, ignoring" }
|
||||
return Vault.NoUpdate
|
||||
}
|
||||
|
||||
return Wallet.Update(consumed, ourNewStates.toHashSet())
|
||||
return Vault.Update(consumed, ourNewStates.toHashSet())
|
||||
}
|
||||
|
||||
private fun isRelevant(state: ContractState, ourKeys: Set<PublicKey>): Boolean {
|
||||
return if (state is OwnableState) {
|
||||
state.owner in ourKeys
|
||||
} else if (state is LinearState) {
|
||||
// It's potentially of interest to the wallet
|
||||
// It's potentially of interest to the vault
|
||||
state.isRelevant(ourKeys)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun recordUpdate(update: Wallet.Update): Wallet.Update {
|
||||
if (update != Wallet.NoUpdate) {
|
||||
private fun recordUpdate(update: Vault.Update): Vault.Update {
|
||||
if (update != Vault.NoUpdate) {
|
||||
val producedStateRefs = update.produced.map { it.ref }
|
||||
val consumedStateRefs = update.consumed
|
||||
log.trace { "Removing $consumedStateRefs consumed contract states and adding $producedStateRefs produced contract states to the database." }
|
@ -11,7 +11,7 @@ import com.r3corda.core.messaging.SingleMessageRecipient
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.core.node.services.ServiceType
|
||||
import com.r3corda.core.node.services.TransactionStorage
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.node.services.Vault
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
@ -370,7 +370,7 @@ class TwoPartyTradeProtocolTests {
|
||||
|
||||
private fun LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.fillUpForBuyer(
|
||||
withError: Boolean,
|
||||
owner: PublicKey = BOB_PUBKEY): Pair<Wallet, List<WireTransaction>> {
|
||||
owner: PublicKey = BOB_PUBKEY): Pair<Vault, List<WireTransaction>> {
|
||||
val issuer = DUMMY_CASH_ISSUER
|
||||
// Bob (Buyer) has some cash he got from the Bank of Elbonia, Alice (Seller) has some commercial paper she
|
||||
// wants to sell to Bob.
|
||||
@ -407,15 +407,15 @@ class TwoPartyTradeProtocolTests {
|
||||
this.verifies()
|
||||
}
|
||||
|
||||
val wallet = Wallet(listOf("bob cash 1".outputStateAndRef(), "bob cash 2".outputStateAndRef()))
|
||||
return Pair(wallet, listOf(eb1, bc1, bc2))
|
||||
val vault = Vault(listOf("bob cash 1".outputStateAndRef(), "bob cash 2".outputStateAndRef()))
|
||||
return Pair(vault, listOf(eb1, bc1, bc2))
|
||||
}
|
||||
|
||||
private fun LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.fillUpForSeller(
|
||||
withError: Boolean,
|
||||
owner: PublicKey,
|
||||
amount: Amount<Issued<Currency>>,
|
||||
attachmentID: SecureHash?): Pair<Wallet, List<WireTransaction>> {
|
||||
attachmentID: SecureHash?): Pair<Vault, List<WireTransaction>> {
|
||||
val ap = transaction {
|
||||
output("alice's paper") {
|
||||
CommercialPaper.State(MEGA_CORP.ref(1, 2, 3), owner, amount, TEST_TX_TIME + 7.days)
|
||||
@ -432,8 +432,8 @@ class TwoPartyTradeProtocolTests {
|
||||
}
|
||||
}
|
||||
|
||||
val wallet = Wallet(listOf("alice's paper".outputStateAndRef()))
|
||||
return Pair(wallet, listOf(ap))
|
||||
val vault = Vault(listOf("alice's paper".outputStateAndRef()))
|
||||
return Pair(vault, listOf(ap))
|
||||
}
|
||||
|
||||
class RecordingTransactionStorage(val delegate: TransactionStorage) : TransactionStorage {
|
||||
|
@ -14,14 +14,14 @@ import com.r3corda.testing.node.MockNetworkMapCache
|
||||
import com.r3corda.node.services.network.NetworkMapService
|
||||
import com.r3corda.node.services.persistence.DataVending
|
||||
import com.r3corda.node.services.statemachine.StateMachineManager
|
||||
import com.r3corda.core.testing.InMemoryWalletService
|
||||
import com.r3corda.core.testing.InMemoryVaultService
|
||||
import com.r3corda.testing.node.MockStorageService
|
||||
import com.r3corda.testing.MOCK_IDENTITY_SERVICE
|
||||
import java.time.Clock
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
open class MockServiceHubInternal(
|
||||
customWallet: WalletService? = null,
|
||||
customVault: VaultService? = null,
|
||||
val keyManagement: KeyManagementService? = null,
|
||||
val net: MessagingServiceInternal? = null,
|
||||
val identity: IdentityService? = MOCK_IDENTITY_SERVICE,
|
||||
@ -32,7 +32,7 @@ open class MockServiceHubInternal(
|
||||
val overrideClock: Clock? = NodeClock(),
|
||||
val protocolFactory: ProtocolLogicRefFactory? = ProtocolLogicRefFactory()
|
||||
) : ServiceHubInternal() {
|
||||
override val walletService: WalletService = customWallet ?: InMemoryWalletService(this)
|
||||
override val vaultService: VaultService = customVault ?: InMemoryVaultService(this)
|
||||
override val keyManagementService: KeyManagementService
|
||||
get() = keyManagement ?: throw UnsupportedOperationException()
|
||||
override val identityService: IdentityService
|
||||
|
@ -17,7 +17,7 @@ import com.r3corda.node.services.events.NodeSchedulerService
|
||||
import com.r3corda.testing.node.InMemoryMessagingNetwork
|
||||
import com.r3corda.node.services.persistence.PerFileCheckpointStorage
|
||||
import com.r3corda.node.services.statemachine.StateMachineManager
|
||||
import com.r3corda.node.services.wallet.NodeWalletService
|
||||
import com.r3corda.node.services.vault.NodeVaultService
|
||||
import com.r3corda.node.utilities.AddOrRemove
|
||||
import com.r3corda.node.utilities.AffinityExecutor
|
||||
import com.r3corda.node.utilities.configureDatabase
|
||||
|
@ -3,11 +3,11 @@ package com.r3corda.node.services
|
||||
import com.r3corda.contracts.testing.fillWithSomeTestCash
|
||||
import com.r3corda.core.contracts.DOLLARS
|
||||
import com.r3corda.core.node.services.TxWritableStorageService
|
||||
import com.r3corda.core.node.services.WalletService
|
||||
import com.r3corda.core.node.services.VaultService
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import com.r3corda.core.utilities.LogHelper
|
||||
import com.r3corda.node.services.wallet.NodeWalletService
|
||||
import com.r3corda.node.services.vault.NodeVaultService
|
||||
import com.r3corda.node.utilities.configureDatabase
|
||||
import com.r3corda.node.utilities.databaseTransaction
|
||||
import com.r3corda.testing.node.MockServices
|
||||
@ -19,42 +19,42 @@ import org.junit.Test
|
||||
import java.io.Closeable
|
||||
import java.util.*
|
||||
|
||||
class NodeWalletServiceTest {
|
||||
class NodeVaultServiceTest {
|
||||
lateinit var dataSource: Closeable
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
LogHelper.setLevel(NodeWalletService::class)
|
||||
LogHelper.setLevel(NodeVaultService::class)
|
||||
dataSource = configureDatabase(makeTestDataSourceProperties()).first
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
dataSource.close()
|
||||
LogHelper.reset(NodeWalletService::class)
|
||||
LogHelper.reset(NodeVaultService::class)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `states not local to instance`() {
|
||||
databaseTransaction {
|
||||
val services1 = object : MockServices() {
|
||||
override val walletService: WalletService = NodeWalletService(this)
|
||||
override val vaultService: VaultService = NodeVaultService(this)
|
||||
|
||||
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
||||
for (stx in txs) {
|
||||
storageService.validatedTransactions.addTransaction(stx)
|
||||
walletService.notify(stx.tx)
|
||||
vaultService.notify(stx.tx)
|
||||
}
|
||||
}
|
||||
}
|
||||
services1.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L))
|
||||
|
||||
val w1 = services1.walletService.currentWallet
|
||||
val w1 = services1.vaultService.currentVault
|
||||
assertThat(w1.states).hasSize(3)
|
||||
|
||||
val originalStorage = services1.storageService
|
||||
val services2 = object : MockServices() {
|
||||
override val walletService: WalletService = NodeWalletService(this)
|
||||
override val vaultService: VaultService = NodeVaultService(this)
|
||||
|
||||
// We need to be able to find the same transactions as before, too.
|
||||
override val storageService: TxWritableStorageService get() = originalStorage
|
||||
@ -62,12 +62,12 @@ class NodeWalletServiceTest {
|
||||
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
||||
for (stx in txs) {
|
||||
storageService.validatedTransactions.addTransaction(stx)
|
||||
walletService.notify(stx.tx)
|
||||
vaultService.notify(stx.tx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val w2 = services2.walletService.currentWallet
|
||||
val w2 = services2.vaultService.currentVault
|
||||
assertThat(w2.states).hasSize(3)
|
||||
}
|
||||
}
|
@ -5,12 +5,12 @@ import com.r3corda.contracts.asset.DUMMY_CASH_ISSUER
|
||||
import com.r3corda.contracts.asset.cashBalances
|
||||
import com.r3corda.contracts.testing.fillWithSomeTestCash
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.node.services.WalletService
|
||||
import com.r3corda.core.node.services.VaultService
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import com.r3corda.core.utilities.LogHelper
|
||||
import com.r3corda.node.services.wallet.NodeWalletService
|
||||
import com.r3corda.node.services.vault.NodeVaultService
|
||||
import com.r3corda.node.utilities.configureDatabase
|
||||
import com.r3corda.node.utilities.databaseTransaction
|
||||
import com.r3corda.testing.*
|
||||
@ -27,25 +27,25 @@ import kotlin.test.assertNull
|
||||
|
||||
// TODO: Move this to the cash contract tests once mock services are further split up.
|
||||
|
||||
class WalletWithCashTest {
|
||||
class VaultWithCashTest {
|
||||
lateinit var services: MockServices
|
||||
val wallet: WalletService get() = services.walletService
|
||||
val vault: VaultService get() = services.vaultService
|
||||
lateinit var dataSource: Closeable
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
LogHelper.setLevel(NodeWalletService::class)
|
||||
LogHelper.setLevel(NodeVaultService::class)
|
||||
dataSource = configureDatabase(makeTestDataSourceProperties()).first
|
||||
databaseTransaction {
|
||||
services = object : MockServices() {
|
||||
override val walletService: WalletService = NodeWalletService(this)
|
||||
override val vaultService: VaultService = NodeVaultService(this)
|
||||
|
||||
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
||||
for (stx in txs) {
|
||||
storageService.validatedTransactions.addTransaction(stx)
|
||||
}
|
||||
// Refactored to use notifyAll() as we have no other unit test for that method with multiple transactions.
|
||||
walletService.notifyAll(txs.map { it.tx })
|
||||
vaultService.notifyAll(txs.map { it.tx })
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -53,7 +53,7 @@ class WalletWithCashTest {
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
LogHelper.reset(NodeWalletService::class)
|
||||
LogHelper.reset(NodeVaultService::class)
|
||||
dataSource.close()
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ class WalletWithCashTest {
|
||||
// Fix the PRNG so that we get the same splits every time.
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L))
|
||||
|
||||
val w = wallet.currentWallet
|
||||
val w = vault.currentVault
|
||||
assertEquals(3, w.states.toList().size)
|
||||
|
||||
val state = w.states.toList()[0].state.data as Cash.State
|
||||
@ -100,14 +100,14 @@ class WalletWithCashTest {
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
|
||||
assertNull(wallet.currentWallet.cashBalances[USD])
|
||||
assertNull(vault.currentVault.cashBalances[USD])
|
||||
services.recordTransactions(usefulTX)
|
||||
assertEquals(100.DOLLARS, wallet.currentWallet.cashBalances[USD])
|
||||
assertEquals(100.DOLLARS, vault.currentVault.cashBalances[USD])
|
||||
services.recordTransactions(irrelevantTX)
|
||||
assertEquals(100.DOLLARS, wallet.currentWallet.cashBalances[USD])
|
||||
assertEquals(100.DOLLARS, vault.currentVault.cashBalances[USD])
|
||||
services.recordTransactions(spendTX)
|
||||
|
||||
assertEquals(20.DOLLARS, wallet.currentWallet.cashBalances[USD])
|
||||
assertEquals(20.DOLLARS, vault.currentVault.cashBalances[USD])
|
||||
|
||||
// TODO: Flesh out these tests as needed.
|
||||
}
|
||||
@ -151,7 +151,7 @@ class WalletWithCashTest {
|
||||
dummyIssue.toLedgerTransaction(services).verify()
|
||||
|
||||
services.recordTransactions(dummyIssue)
|
||||
assertEquals(1, wallet.currentWallet.states.toList().size)
|
||||
assertEquals(1, vault.currentVault.states.toList().size)
|
||||
|
||||
// Move the same state
|
||||
val dummyMove = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
@ -163,7 +163,7 @@ class WalletWithCashTest {
|
||||
dummyIssue.toLedgerTransaction(services).verify()
|
||||
|
||||
services.recordTransactions(dummyMove)
|
||||
assertEquals(1, wallet.currentWallet.states.toList().size)
|
||||
assertEquals(1, vault.currentVault.states.toList().size)
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.crypto.newSecureRandom
|
||||
import com.r3corda.core.node.services.DEFAULT_SESSION_ID
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.node.services.Vault
|
||||
import com.r3corda.core.random63BitValue
|
||||
import com.r3corda.core.serialization.OpaqueBytes
|
||||
import com.r3corda.core.serialization.deserialize
|
||||
@ -77,8 +77,8 @@ class WalletMonitorServiceTests {
|
||||
val (monitorServiceNode, registerNode) = network.createTwoNodes()
|
||||
val sessionID = authenticate(monitorServiceNode, registerNode)
|
||||
var receivePsm = receiveWalletUpdate(registerNode, sessionID)
|
||||
var expected = Wallet.Update(emptySet(), emptySet())
|
||||
monitorServiceNode.inNodeWalletMonitorService!!.notifyWalletUpdate(expected)
|
||||
var expected = Vault.Update(emptySet(), emptySet())
|
||||
monitorServiceNode.inNodeWalletMonitorService!!.notifyVaultUpdate(expected)
|
||||
network.runNetwork()
|
||||
var actual = receivePsm.get(1, TimeUnit.SECONDS)
|
||||
assertEquals(expected.consumed, actual.consumed)
|
||||
@ -89,8 +89,8 @@ class WalletMonitorServiceTests {
|
||||
val consumed = setOf(StateRef(SecureHash.randomSHA256(), 0))
|
||||
val producedState = TransactionState(DummyContract.SingleOwnerState(newSecureRandom().nextInt(), DUMMY_PUBKEY_1), DUMMY_NOTARY)
|
||||
val produced = setOf(StateAndRef(producedState, StateRef(SecureHash.randomSHA256(), 0)))
|
||||
expected = Wallet.Update(consumed, produced)
|
||||
monitorServiceNode.inNodeWalletMonitorService!!.notifyWalletUpdate(expected)
|
||||
expected = Vault.Update(consumed, produced)
|
||||
monitorServiceNode.inNodeWalletMonitorService!!.notifyVaultUpdate(expected)
|
||||
network.runNetwork()
|
||||
actual = receivePsm.get(1, TimeUnit.SECONDS)
|
||||
assertEquals(expected.produced, actual.produced)
|
||||
@ -110,7 +110,7 @@ class WalletMonitorServiceTests {
|
||||
}
|
||||
|
||||
// Check the monitoring service wallet is empty
|
||||
assertFalse(monitorServiceNode.services.walletService.currentWallet.states.iterator().hasNext())
|
||||
assertFalse(monitorServiceNode.services.vaultService.currentVault.states.iterator().hasNext())
|
||||
|
||||
// Tell the monitoring service node to issue some cash
|
||||
val recipient = monitorServiceNode.services.storageService.myLegalIdentity
|
||||
|
@ -25,8 +25,8 @@ class DataVendingServiceTests {
|
||||
|
||||
@Test
|
||||
fun `notify of transaction`() {
|
||||
val (walletServiceNode, registerNode) = network.createTwoNodes()
|
||||
val beneficiary = walletServiceNode.services.storageService.myLegalIdentityKey.public
|
||||
val (vaultServiceNode, registerNode) = network.createTwoNodes()
|
||||
val beneficiary = vaultServiceNode.services.storageService.myLegalIdentityKey.public
|
||||
val deposit = registerNode.services.storageService.myLegalIdentity.ref(1)
|
||||
network.runNetwork()
|
||||
|
||||
@ -37,13 +37,13 @@ class DataVendingServiceTests {
|
||||
// Complete the cash transaction, and then manually relay it
|
||||
ptx.signWith(registerNode.services.storageService.myLegalIdentityKey)
|
||||
val tx = ptx.toSignedTransaction()
|
||||
assertEquals(0, walletServiceNode.services.walletService.currentWallet.states.toList().size)
|
||||
assertEquals(0, vaultServiceNode.services.vaultService.currentVault.states.toList().size)
|
||||
DataVending.Service.notify(registerNode.net, registerNode.services.storageService.myLegalIdentity,
|
||||
walletServiceNode.info, tx)
|
||||
vaultServiceNode.info, tx)
|
||||
network.runNetwork()
|
||||
|
||||
// Check the transaction is in the receiving node
|
||||
val actual = walletServiceNode.services.walletService.currentWallet.states.singleOrNull()
|
||||
val actual = vaultServiceNode.services.vaultService.currentVault.states.singleOrNull()
|
||||
val expected = tx.tx.outRef<Cash.State>(0)
|
||||
|
||||
assertEquals(expected, actual)
|
||||
@ -54,8 +54,8 @@ class DataVendingServiceTests {
|
||||
*/
|
||||
@Test
|
||||
fun `notify failure`() {
|
||||
val (walletServiceNode, registerNode) = network.createTwoNodes()
|
||||
val beneficiary = walletServiceNode.services.storageService.myLegalIdentityKey.public
|
||||
val (vaultServiceNode, registerNode) = network.createTwoNodes()
|
||||
val beneficiary = vaultServiceNode.services.storageService.myLegalIdentityKey.public
|
||||
val deposit = MEGA_CORP.ref(1)
|
||||
network.runNetwork()
|
||||
|
||||
@ -66,12 +66,12 @@ class DataVendingServiceTests {
|
||||
// The transaction tries issuing MEGA_CORP cash, but we aren't the issuer, so it's invalid
|
||||
ptx.signWith(registerNode.services.storageService.myLegalIdentityKey)
|
||||
val tx = ptx.toSignedTransaction(false)
|
||||
assertEquals(0, walletServiceNode.services.walletService.currentWallet.states.toList().size)
|
||||
assertEquals(0, vaultServiceNode.services.vaultService.currentVault.states.toList().size)
|
||||
DataVending.Service.notify(registerNode.net, registerNode.services.storageService.myLegalIdentity,
|
||||
walletServiceNode.info, tx)
|
||||
vaultServiceNode.info, tx)
|
||||
network.runNetwork()
|
||||
|
||||
// Check the transaction is not in the receiving node
|
||||
assertEquals(0, walletServiceNode.services.walletService.currentWallet.states.toList().size)
|
||||
assertEquals(0, vaultServiceNode.services.vaultService.currentVault.states.toList().size)
|
||||
}
|
||||
}
|
@ -260,7 +260,7 @@ private class TraderDemoProtocolBuyer(val otherSide: Party,
|
||||
}
|
||||
|
||||
private fun logBalance() {
|
||||
val balances = serviceHub.walletService.currentWallet.cashBalances.entries.map { "${it.key.currencyCode} ${it.value}" }
|
||||
val balances = serviceHub.vaultService.currentVault.cashBalances.entries.map { "${it.key.currencyCode} ${it.value}" }
|
||||
logger.info("Remaining balance: ${balances.joinToString()}")
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ class InterestRateSwapAPI(val services: ServiceHub) {
|
||||
private fun generateDealLink(deal: InterestRateSwap.State) = "/api/irs/deals/" + deal.common.tradeID
|
||||
|
||||
private fun getDealByRef(ref: String): InterestRateSwap.State? {
|
||||
val states = services.walletService.linearHeadsOfType<InterestRateSwap.State>().filterValues { it.state.data.ref == ref }
|
||||
val states = services.vaultService.linearHeadsOfType<InterestRateSwap.State>().filterValues { it.state.data.ref == ref }
|
||||
return if (states.isEmpty()) null else {
|
||||
val deals = states.values.map { it.state.data }
|
||||
return if (deals.isEmpty()) null else deals[0]
|
||||
@ -56,7 +56,7 @@ class InterestRateSwapAPI(val services: ServiceHub) {
|
||||
}
|
||||
|
||||
private fun getAllDeals(): Array<InterestRateSwap.State> {
|
||||
val states = services.walletService.linearHeadsOfType<InterestRateSwap.State>()
|
||||
val states = services.vaultService.linearHeadsOfType<InterestRateSwap.State>()
|
||||
val swaps = states.values.map { it.state.data }.toTypedArray()
|
||||
return swaps
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
|
||||
val node1: SimulatedNode = banks[i]
|
||||
val node2: SimulatedNode = banks[j]
|
||||
|
||||
val swaps: Map<UniqueIdentifier, StateAndRef<InterestRateSwap.State>> = node1.services.walletService.linearHeadsOfType<com.r3corda.contracts.InterestRateSwap.State>()
|
||||
val swaps: Map<UniqueIdentifier, StateAndRef<InterestRateSwap.State>> = node1.services.vaultService.linearHeadsOfType<com.r3corda.contracts.InterestRateSwap.State>()
|
||||
val theDealRef: StateAndRef<InterestRateSwap.State> = swaps.values.single()
|
||||
|
||||
// Do we have any more days left in this deal's lifetime? If not, return.
|
||||
@ -89,8 +89,8 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
|
||||
|
||||
val retFuture = SettableFuture.create<Unit>()
|
||||
// Complete the future when the state has been consumed on both nodes
|
||||
val futA = node1.services.walletService.whenConsumed(theDealRef.ref)
|
||||
val futB = node2.services.walletService.whenConsumed(theDealRef.ref)
|
||||
val futA = node1.services.vaultService.whenConsumed(theDealRef.ref)
|
||||
val futB = node2.services.vaultService.whenConsumed(theDealRef.ref)
|
||||
Futures.allAsList(futA, futB) success {
|
||||
retFuture.set(null)
|
||||
} failure { throwable ->
|
||||
|
@ -13,9 +13,9 @@ import com.r3corda.core.messaging.send
|
||||
import com.r3corda.core.node.PhysicalLocation
|
||||
import com.r3corda.core.node.services.KeyManagementService
|
||||
import com.r3corda.core.node.services.ServiceType
|
||||
import com.r3corda.core.node.services.WalletService
|
||||
import com.r3corda.core.node.services.VaultService
|
||||
import com.r3corda.core.serialization.deserialize
|
||||
import com.r3corda.core.testing.InMemoryWalletService
|
||||
import com.r3corda.core.testing.InMemoryVaultService
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import com.r3corda.core.utilities.loggerFor
|
||||
import com.r3corda.node.services.config.NodeConfiguration
|
||||
@ -91,7 +91,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
||||
|
||||
override fun makeIdentityService() = MockIdentityService(mockNet.identities)
|
||||
|
||||
override fun makeWalletService(): WalletService = InMemoryWalletService(services)
|
||||
override fun makeVaultService(): VaultService = InMemoryVaultService(services)
|
||||
|
||||
override fun makeKeyManagementService(): KeyManagementService = E2ETestKeyManagementService(setOf(storage.myLegalIdentityKey))
|
||||
|
||||
|
@ -51,7 +51,7 @@ open class MockServices(val key: KeyPair = generateKeyPair()) : ServiceHub {
|
||||
override val identityService: MockIdentityService = MockIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY))
|
||||
override val keyManagementService: MockKeyManagementService = MockKeyManagementService(key)
|
||||
|
||||
override val walletService: WalletService get() = throw UnsupportedOperationException()
|
||||
override val vaultService: VaultService get() = throw UnsupportedOperationException()
|
||||
override val networkService: MessagingService get() = throw UnsupportedOperationException()
|
||||
override val networkMapCache: NetworkMapCache get() = throw UnsupportedOperationException()
|
||||
override val clock: Clock get() = throw UnsupportedOperationException()
|
||||
|
Loading…
Reference in New Issue
Block a user