mirror of
https://github.com/corda/corda.git
synced 2025-06-16 06:08:13 +00:00
Change references to 'wallet' with 'vault'
This commit is contained in:
@ -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)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user