CORDA-1266 - When a cash output is identical only the fist output is saved. (#3244) (#3311)

(cherry picked from commit 0a4d981)
This commit is contained in:
szymonsztuka 2018-06-06 16:02:50 +01:00 committed by Katelyn Baker
parent 51bb6a8dfc
commit cdce596acd
2 changed files with 50 additions and 7 deletions

View File

@ -131,9 +131,9 @@ class NodeVaultService(
val myKeys = keyManagementService.filterMyKeys(tx.outputs.flatMap { it.data.participants.map { it.owningKey } })
val ourNewStates = when (statesToRecord) {
StatesToRecord.NONE -> throw AssertionError("Should not reach here")
StatesToRecord.ONLY_RELEVANT -> tx.outputs.filter { isRelevant(it.data, myKeys.toSet()) }
StatesToRecord.ALL_VISIBLE -> tx.outputs
}.map { tx.outRef<ContractState>(it.data) }
StatesToRecord.ONLY_RELEVANT -> tx.outputs.withIndex().filter { isRelevant(it.value.data, myKeys.toSet()) }
StatesToRecord.ALL_VISIBLE -> tx.outputs.withIndex()
}.map { tx.outRef<ContractState>(it.index) }
// Retrieve all unconsumed states for this transaction's inputs
val consumedStates = loadStates(tx.inputs)

View File

@ -4,10 +4,7 @@ import co.paralleluniverse.fibers.Suspendable
import com.nhaarman.mockito_kotlin.argThat
import com.nhaarman.mockito_kotlin.doNothing
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.contracts.Amount
import net.corda.core.contracts.Issued
import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.StateRef
import net.corda.core.contracts.*
import net.corda.core.crypto.NullKeys
import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.*
@ -675,4 +672,50 @@ class NodeVaultServiceTest {
}
assertEquals(currentCashStates + 1, countCash())
}
@Test
fun `insert equal cash states issued by single transaction`() {
val nodeIdentity = MEGA_CORP
val coins = listOf(1.DOLLARS, 1.DOLLARS).map { it.issuedBy(nodeIdentity.ref(1)) }
//create single transaction with 2 'identical' cash outputs
val txb = TransactionBuilder(DUMMY_NOTARY)
coins.map { txb.addOutputState(TransactionState(Cash.State(it, nodeIdentity), Cash.PROGRAM_ID, DUMMY_NOTARY)) }
txb.addCommand(Cash.Commands.Issue(), nodeIdentity.owningKey)
val issueTx = txb.toWireTransaction(services)
// ensure transaction contract state is persisted in DBStorage
val signedIssuedTx = services.signInitialTransaction(txb)
(services.validatedTransactions as WritableTransactionStorage).addTransaction(signedIssuedTx)
database.transaction { vaultService.notify(StatesToRecord.ONLY_RELEVANT, issueTx) }
val recordedStates = database.transaction {
vaultService.queryBy<Cash.State>().states.size
}
assertThat(recordedStates).isEqualTo(coins.size)
}
@Test
fun `insert different cash states issued by single transaction`() {
val nodeIdentity = MEGA_CORP
val coins = listOf(2.DOLLARS, 1.DOLLARS).map { it.issuedBy(nodeIdentity.ref(1)) }
//create single transaction with 2 'identical' cash outputs
val txb = TransactionBuilder(DUMMY_NOTARY)
coins.map { txb.addOutputState(TransactionState(Cash.State(it, nodeIdentity), Cash.PROGRAM_ID, DUMMY_NOTARY)) }
txb.addCommand(Cash.Commands.Issue(), nodeIdentity.owningKey)
val issueTx = txb.toWireTransaction(services)
// ensure transaction contract state is persisted in DBStorage
val signedIssuedTx = services.signInitialTransaction(txb)
(services.validatedTransactions as WritableTransactionStorage).addTransaction(signedIssuedTx)
database.transaction { vaultService.notify(StatesToRecord.ONLY_RELEVANT, issueTx) }
val recordedStates = database.transaction {
vaultService.queryBy<Cash.State>().states.size
}
assertThat(recordedStates).isEqualTo(coins.size)
}
}