Add state query methods to LedgerTransaction.

Update to use LedgerTransaction api

Push query output logic onto BaseTransaction and update usages where possible

Migrate a few more uses

Address some PR comments

Address some PR comments

Fixup after rebase
This commit is contained in:
Matthew Nesbit 2017-07-18 12:02:56 +01:00
parent fe9db6f1f7
commit 9a02a27619
29 changed files with 650 additions and 84 deletions

View File

@ -123,7 +123,7 @@ sealed class TransactionType {
*/
private fun verifyContracts(tx: LedgerTransaction) {
// TODO: This will all be replaced in future once the sandbox and contract constraints work is done.
val contracts = (tx.inputs.map { it.state.data.contract } + tx.outputs.map { it.data.contract }).toSet()
val contracts = (tx.inputStates.map { it.contract } + tx.outputStates.map { it.contract }).toSet()
for (contract in contracts) {
try {
contract.verify(tx)
@ -171,6 +171,6 @@ sealed class TransactionType {
}
}
override fun getRequiredSigners(tx: LedgerTransaction) = tx.inputs.flatMap { it.state.data.participants }.map { it.owningKey }.toSet()
override fun getRequiredSigners(tx: LedgerTransaction) = tx.inputStates.flatMap { it.participants }.map { it.owningKey }.toSet()
}
}

View File

@ -23,7 +23,7 @@ fun <C : CommandData> verifyClause(tx: LedgerTransaction,
Clause.log.trace("Tx ${tx.id} clause: $clause")
}
}
val matchedCommands = clause.verify(tx, tx.inputs.map { it.state.data }, tx.outputs.map { it.data }, commands, null)
val matchedCommands = clause.verify(tx, tx.inputStates, tx.outputStates, commands, null)
check(matchedCommands.containsAll(commands.map { it.value })) { "The following commands were not matched at the end of execution: " + (commands - matchedCommands) }
}

View File

@ -24,7 +24,7 @@ class ContractUpgradeFlow<OldState : ContractState, out NewState : ContractState
@JvmStatic
fun verify(tx: LedgerTransaction) {
// Contract Upgrade transaction should have 1 input, 1 output and 1 command.
verify(tx.inputs.single().state.data, tx.outputs.single().data, tx.commands.map { Command(it.value, it.signers) }.single())
verify(tx.inputStates.single(), tx.outputStates.single(), tx.commands.map { Command(it.value, it.signers) }.single())
}
@JvmStatic

View File

@ -133,7 +133,7 @@ open class FinalityFlow(val transactions: Iterable<SignedTransaction>,
* overriding functions.
*/
protected fun extractParticipants(ltx: LedgerTransaction): List<AbstractParty> {
return ltx.outputs.flatMap { it.data.participants } + ltx.inputs.flatMap { it.state.data.participants }
return ltx.outputStates.flatMap { it.participants } + ltx.inputStates.flatMap { it.participants }
}
/**

View File

@ -2,8 +2,10 @@ package net.corda.core.transactions
import net.corda.core.contracts.*
import net.corda.core.identity.Party
import net.corda.core.indexOfOrThrow
import java.security.PublicKey
import java.util.*
import java.util.function.Predicate
/**
* An abstract class defining fields shared by all transaction types in the system.
@ -56,4 +58,123 @@ abstract class BaseTransaction(
override fun hashCode() = Objects.hash(notary, mustSign, type, timeWindow)
override fun toString(): String = "${javaClass.simpleName}(id=$id)"
/**
* Returns a [StateAndRef] for the given output index.
*/
@Suppress("UNCHECKED_CAST")
fun <T : ContractState> outRef(index: Int): StateAndRef<T> = StateAndRef(outputs[index] as TransactionState<T>, StateRef(id, index))
/**
* Returns a [StateAndRef] for the requested output state, or throws [IllegalArgumentException] if not found.
*/
fun <T : ContractState> outRef(state: ContractState): StateAndRef<T> = outRef(outputStates.indexOfOrThrow(state))
/**
* Helper property to return a list of [ContractState] objects, rather than the often less convenient [TransactionState]
*/
val outputStates: List<ContractState> get() = outputs.map { it.data }
/**
* Helper to simplify getting an indexed output.
* @param index the position of the item in the output.
* @return The ContractState at the requested index
*/
fun getOutput(index: Int): ContractState = outputs[index].data
/**
* Helper to simplify getting all output states of a particular class, interface, or base class.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* Clazz must be an extension of [ContractState].
* @return the possibly empty list of output states matching the clazz restriction.
*/
fun <T : ContractState> outputsOfType(clazz: Class<T>): List<T> {
@Suppress("UNCHECKED_CAST")
return outputs.filter { clazz.isInstance(it.data) }.map { it.data as T }
}
/**
* Helper to simplify filtering outputs according to a [Predicate].
* @param predicate A filtering function taking a state of type T and returning true if it should be included in the list.
* The class filtering is applied before the predicate.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* Clazz must be an extension of [ContractState].
* @return the possibly empty list of output states matching the predicate and clazz restrictions.
*/
fun <T : ContractState> filterOutputs(predicate: Predicate<T>, clazz: Class<T>): List<T> {
return outputsOfType(clazz).filter { predicate.test(it) }
}
/**
* Helper to simplify finding a single output matching a [Predicate].
* @param predicate A filtering function taking a state of type T and returning true if this is the desired item.
* The class filtering is applied before the predicate.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* Clazz must be an extension of [ContractState].
* @return the single item matching the predicate.
* @throws IllegalArgumentException if no item, or multiple items are found matching the requirements.
*/
fun <T : ContractState> findOutput(predicate: Predicate<T>, clazz: Class<T>): T {
return filterOutputs(predicate, clazz).single()
}
/**
* Helper to simplify getting all output [StateAndRef] items of a particular state class, interface, or base class.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* Clazz must be an extension of [ContractState].
* @return the possibly empty list of output [StateAndRef<T>] states matching the clazz restriction.
*/
fun <T : ContractState> outRefsOfType(clazz: Class<T>): List<StateAndRef<T>> {
@Suppress("UNCHECKED_CAST")
return outputs.mapIndexed { index, state -> StateAndRef(state, StateRef(id, index)) }
.filter { clazz.isInstance(it.state.data) }
.map { it as StateAndRef<T> }
}
/**
* Helper to simplify filtering output [StateAndRef] items according to a [Predicate].
* @param predicate A filtering function taking a state of type T and returning true if it should be included in the list.
* The class filtering is applied before the predicate.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* Clazz must be an extension of [ContractState].
* @return the possibly empty list of output [StateAndRef] states matching the predicate and clazz restrictions.
*/
fun <T : ContractState> filterOutRefs(predicate: Predicate<T>, clazz: Class<T>): List<StateAndRef<T>> {
return outRefsOfType(clazz).filter { predicate.test(it.state.data) }
}
/**
* Helper to simplify finding a single output [StateAndRef] matching a [Predicate].
* @param predicate A filtering function taking a state of type T and returning true if this is the desired item.
* The class filtering is applied before the predicate.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* Clazz must be an extension of [ContractState].
* @return the single [StateAndRef] item matching the predicate.
* @throws IllegalArgumentException if no item, or multiple items are found matching the requirements.
*/
fun <T : ContractState> findOutRef(predicate: Predicate<T>, clazz: Class<T>): StateAndRef<T> {
return filterOutRefs(predicate, clazz).single()
}
//Kotlin extension methods to take advantage of Kotlin's smart type inference when querying the LedgerTransaction
inline fun <reified T : ContractState> outputsOfType(): List<T> = this.outputsOfType(T::class.java)
inline fun <reified T : ContractState> filterOutputs(crossinline predicate: (T) -> Boolean): List<T> {
return filterOutputs(Predicate { predicate(it) }, T::class.java)
}
inline fun <reified T : ContractState> findOutput(crossinline predicate: (T) -> Boolean): T {
return findOutput(Predicate { predicate(it) }, T::class.java)
}
inline fun <reified T : ContractState> outRefsOfType(): List<StateAndRef<T>> = this.outRefsOfType(T::class.java)
inline fun <reified T : ContractState> filterOutRefs(crossinline predicate: (T) -> Boolean): List<StateAndRef<T>> {
return filterOutRefs(Predicate { predicate(it) }, T::class.java)
}
inline fun <reified T : ContractState> findOutRef(crossinline predicate: (T) -> Boolean): StateAndRef<T> {
return findOutRef(Predicate { predicate(it) }, T::class.java)
}
}

View File

@ -6,6 +6,7 @@ import net.corda.core.identity.Party
import net.corda.core.serialization.CordaSerializable
import java.security.PublicKey
import java.util.*
import java.util.function.Predicate
/**
* A LedgerTransaction is derived from a [WireTransaction]. It is the result of doing the following operations:
@ -42,8 +43,15 @@ class LedgerTransaction(
checkInvariants()
}
val inputStates: List<ContractState> get() = inputs.map { it.state.data }
/**
* Returns the typed input StateAndRef at the specified index
* @param index The index into the inputs.
* @return The [StateAndRef]
*/
@Suppress("UNCHECKED_CAST")
fun <T : ContractState> outRef(index: Int) = StateAndRef(outputs[index] as TransactionState<T>, StateRef(id, index))
fun <T : ContractState> inRef(index: Int) = inputs[index] as StateAndRef<T>
/**
* Verifies this transaction and throws an exception if not valid, depending on the type. For general transactions:
@ -100,8 +108,8 @@ class LedgerTransaction(
*/
// DOCSTART 2
fun <T : ContractState, K : Any> groupStates(ofType: Class<T>, selector: (T) -> K): List<InOutGroup<T, K>> {
val inputs = inputs.map { it.state.data }.filterIsInstance(ofType)
val outputs = outputs.map { it.data }.filterIsInstance(ofType)
val inputs = inputsOfType(ofType)
val outputs = outputsOfType(ofType)
val inGroups: Map<K, List<T>> = inputs.groupBy(selector)
val outGroups: Map<K, List<T>> = outputs.groupBy(selector)
@ -136,4 +144,166 @@ class LedgerTransaction(
// DOCSTART 3
data class InOutGroup<out T : ContractState, out K : Any>(val inputs: List<T>, val outputs: List<T>, val groupingKey: K)
// DOCEND 3
/**
* Helper to simplify getting an indexed input [ContractState].
* @param index the position of the item in the inputs.
* @return The [StateAndRef] at the requested index
*/
fun getInput(index: Int): ContractState = inputs[index].state.data
/**
* Helper to simplify getting all inputs states of a particular class, interface, or base class.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* [clazz] must be an extension of [ContractState].
* @return the possibly empty list of inputs matching the clazz restriction.
*/
fun <T : ContractState> inputsOfType(clazz: Class<T>): List<T> {
@Suppress("UNCHECKED_CAST")
return inputs.map { it.state.data }.filterIsInstance(clazz)
}
/**
* Helper to simplify getting all inputs states of a particular class, interface, or base class.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* [clazz] must be an extension of [ContractState].
* @return the possibly empty list of inputs [StateAndRef] matching the clazz restriction.
*/
fun <T : ContractState> inRefsOfType(clazz: Class<T>): List<StateAndRef<T>> {
@Suppress("UNCHECKED_CAST")
return inputs.filter { clazz.isInstance(it.state.data) }.map { it as StateAndRef<T> }
}
/**
* Helper to simplify filtering inputs according to a [Predicate].
* @param predicate A filtering function taking a state of type T and returning true if it should be included in the list.
* The class filtering is applied before the predicate.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* [clazz] must be an extension of [ContractState].
* @return the possibly empty list of input states matching the predicate and clazz restrictions.
*/
fun <T : ContractState> filterInputs(predicate: Predicate<T>, clazz: Class<T>): List<T> = inputsOfType(clazz).filter { predicate.test(it) }
/**
* Helper to simplify filtering inputs according to a [Predicate].
* @param predicate A filtering function taking a state of type T and returning true if it should be included in the list.
* The class filtering is applied before the predicate.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* [clazz] must be an extension of [ContractState].
* @return the possibly empty list of inputs [StateAndRef] matching the predicate and clazz restrictions.
*/
fun <T : ContractState> filterInRefs(predicate: Predicate<T>, clazz: Class<T>): List<StateAndRef<T>> = inRefsOfType(clazz).filter { predicate.test(it.state.data) }
/**
* Helper to simplify finding a single input [ContractState] matching a [Predicate].
* @param predicate A filtering function taking a state of type T and returning true if this is the desired item.
* The class filtering is applied before the predicate.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* [clazz] must be an extension of ContractState.
* @return the single item matching the predicate.
* @throws IllegalArgumentException if no item, or multiple items are found matching the requirements.
*/
fun <T : ContractState> findInput(predicate: Predicate<T>, clazz: Class<T>): T = filterInputs(predicate, clazz).single()
/**
* Helper to simplify finding a single input matching a [Predicate].
* @param predicate A filtering function taking a state of type T and returning true if this is the desired item.
* The class filtering is applied before the predicate.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* [clazz] must be an extension of ContractState.
* @return the single item matching the predicate.
* @throws IllegalArgumentException if no item, or multiple items are found matching the requirements.
*/
fun <T : ContractState> findInRef(predicate: Predicate<T>, clazz: Class<T>): StateAndRef<T> = filterInRefs(predicate, clazz).single()
/**
* Helper to simplify getting an indexed command.
* @param index the position of the item in the commands.
* @return The Command at the requested index
*/
fun getCommand(index: Int): Command = Command(commands[index].value, commands[index].signers)
/**
* Helper to simplify getting all [Command] items with a [CommandData] of a particular class, interface, or base class.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* [clazz] must be an extension of [CommandData].
* @return the possibly empty list of commands with [CommandData] values matching the clazz restriction.
*/
fun <T : CommandData> commandsOfType(clazz: Class<T>): List<Command> {
return commands.filter { clazz.isInstance(it.value) }.map { Command(it.value, it.signers) }
}
/**
* Helper to simplify filtering [Command] items according to a [Predicate].
* @param predicate A filtering function taking a [CommandData] item of type T and returning true if it should be included in the list.
* The class filtering is applied before the predicate.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* [clazz] must be an extension of [CommandData].
* @return the possibly empty list of [Command] items with [CommandData] values matching the predicate and clazz restrictions.
*/
fun <T : CommandData> filterCommands(predicate: Predicate<T>, clazz: Class<T>): List<Command> {
@Suppress("UNCHECKED_CAST")
return commandsOfType(clazz).filter { predicate.test(it.value as T) }
}
/**
* Helper to simplify finding a single [Command] items according to a [Predicate].
* @param predicate A filtering function taking a [CommandData] item of type T and returning true if it should be included in the list.
* The class filtering is applied before the predicate.
* @param clazz The class type used for filtering via an [Class.isInstance] check.
* [clazz] must be an extension of [CommandData].
* @return the [Command] item with [CommandData] values matching the predicate and clazz restrictions.
* @throws IllegalArgumentException if no items, or multiple items matched the requirements.
*/
fun <T : CommandData> findCommand(predicate: Predicate<T>, clazz: Class<T>): Command {
return filterCommands(predicate, clazz).single()
}
/**
* Helper to simplify getting an indexed attachment.
* @param index the position of the item in the attachments.
* @return The Attachment at the requested index.
*/
fun getAttachment(index: Int): Attachment = attachments[index]
/**
* Helper to simplify getting an indexed attachment.
* @param id the SecureHash of the desired attachment.
* @return The Attachment with the matching id.
* @throws IllegalArgumentException if no item matches the id.
*/
fun getAttachment(id: SecureHash): Attachment = attachments.single { it.id == id }
//Kotlin extension methods to take advantage of Kotlin's smart type inference when querying the LedgerTransaction
inline fun <reified T : ContractState> inputsOfType(): List<T> = this.inputsOfType(T::class.java)
inline fun <reified T : ContractState> inRefsOfType(): List<StateAndRef<T>> = this.inRefsOfType(T::class.java)
inline fun <reified T : ContractState> filterInputs(crossinline predicate: (T) -> Boolean): List<T> {
return filterInputs(Predicate { predicate(it) }, T::class.java)
}
inline fun <reified T : ContractState> filterInRefs(crossinline predicate: (T) -> Boolean): List<StateAndRef<T>> {
return filterInRefs(Predicate { predicate(it) }, T::class.java)
}
inline fun <reified T : ContractState> findInRef(crossinline predicate: (T) -> Boolean): StateAndRef<T> {
return findInRef(Predicate { predicate(it) }, T::class.java)
}
inline fun <reified T : ContractState> findInput(crossinline predicate: (T) -> Boolean): T {
return findInput(Predicate { predicate(it) }, T::class.java)
}
inline fun <reified T : CommandData> commandsOfType(): List<Command> = this.commandsOfType(T::class.java)
inline fun <reified T : CommandData> filterCommands(crossinline predicate: (T) -> Boolean): List<Command> {
return filterCommands(Predicate { predicate(it) }, T::class.java)
}
inline fun <reified T : CommandData> findCommand(crossinline predicate: (T) -> Boolean): Command {
return findCommand(Predicate { predicate(it) }, T::class.java)
}
}

View File

@ -6,12 +6,11 @@ import net.corda.core.crypto.MerkleTree
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.keys
import net.corda.core.identity.Party
import net.corda.core.indexOfOrThrow
import net.corda.core.internal.Emoji
import net.corda.core.node.ServicesForResolution
import net.corda.core.serialization.*
import net.corda.core.serialization.SerializationDefaults.P2P_CONTEXT
import net.corda.core.serialization.SerializationDefaults.SERIALIZATION_FACTORY
import net.corda.core.internal.Emoji
import java.security.PublicKey
import java.security.SignatureException
import java.util.function.Predicate
@ -53,16 +52,6 @@ class WireTransaction(
}
}
/** Returns a [StateAndRef] for the given output index. */
@Suppress("UNCHECKED_CAST")
fun <T : ContractState> outRef(index: Int): StateAndRef<T> {
require(index >= 0 && index < outputs.size)
return StateAndRef(outputs[index] as TransactionState<T>, StateRef(id, index))
}
/** Returns a [StateAndRef] for the requested output state, or throws [IllegalArgumentException] if not found. */
fun <T : ContractState> outRef(state: ContractState): StateAndRef<T> = outRef(outputs.map { it.data }.indexOfOrThrow(state))
/**
* Looks up identities and attachments from storage to generate a [LedgerTransaction]. A transaction is expected to
* have been fully resolved using the resolution flow by this point.

View File

@ -0,0 +1,289 @@
package net.corda.core.contracts
import net.corda.core.identity.AbstractParty
import net.corda.core.node.ServiceHub
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.TestDependencyInjectionBase
import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockServices
import org.junit.Before
import org.junit.Test
import java.util.function.Predicate
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertTrue
class LedgerTransactionQueryTests : TestDependencyInjectionBase() {
private lateinit var services: ServiceHub
@Before
fun setup() {
services = MockServices()
}
interface Commands {
data class Cmd1(val id: Int) : CommandData, Commands
data class Cmd2(val id: Int) : CommandData, Commands
}
private class StringTypeDummyState(val data: String) : ContractState {
override val contract: Contract = DummyContract()
override val participants: List<AbstractParty> = emptyList()
}
private class IntTypeDummyState(val data: Int) : ContractState {
override val contract: Contract = DummyContract()
override val participants: List<AbstractParty> = emptyList()
}
private fun makeDummyState(data: Any): ContractState {
return when (data) {
is String -> StringTypeDummyState(data)
is Int -> IntTypeDummyState(data)
else -> throw IllegalArgumentException()
}
}
private fun makeDummyStateAndRef(data: Any): StateAndRef<*> {
val dummyState = makeDummyState(data)
val fakeIssueTx = services.signInitialTransaction(TransactionBuilder(notary = DUMMY_NOTARY).addOutputState(dummyState))
services.recordTransactions(fakeIssueTx)
val dummyStateRef = StateRef(fakeIssueTx.id, 0)
return StateAndRef(TransactionState(dummyState, DUMMY_NOTARY, null), dummyStateRef)
}
private fun makeDummyTransaction(): LedgerTransaction {
val tx = TransactionBuilder(notary = DUMMY_NOTARY)
for (i in 0..4) {
tx.addInputState(makeDummyStateAndRef(i))
tx.addInputState(makeDummyStateAndRef(i.toString()))
tx.addOutputState(makeDummyState(i))
tx.addOutputState(makeDummyState(i.toString()))
tx.addCommand(Commands.Cmd1(i), listOf(services.myInfo.legalIdentity.owningKey))
tx.addCommand(Commands.Cmd2(i), listOf(services.myInfo.legalIdentity.owningKey))
}
return tx.toLedgerTransaction(services)
}
@Test
fun `Simple InRef Indexer tests`() {
val ltx = makeDummyTransaction()
assertEquals(0, ltx.inRef<IntTypeDummyState>(0).state.data.data)
assertEquals("0", ltx.inRef<StringTypeDummyState>(1).state.data.data)
assertEquals(3, ltx.inRef<IntTypeDummyState>(6).state.data.data)
assertEquals("3", ltx.inRef<StringTypeDummyState>(7).state.data.data)
assertFailsWith<IndexOutOfBoundsException> { ltx.inRef<IntTypeDummyState>(10) }
}
@Test
fun `Simple OutRef Indexer tests`() {
val ltx = makeDummyTransaction()
assertEquals(0, ltx.outRef<IntTypeDummyState>(0).state.data.data)
assertEquals("0", ltx.outRef<StringTypeDummyState>(1).state.data.data)
assertEquals(3, ltx.outRef<IntTypeDummyState>(6).state.data.data)
assertEquals("3", ltx.outRef<StringTypeDummyState>(7).state.data.data)
assertFailsWith<IndexOutOfBoundsException> { ltx.outRef<IntTypeDummyState>(10) }
}
@Test
fun `Simple Input Indexer tests`() {
val ltx = makeDummyTransaction()
assertEquals(0, (ltx.getInput(0) as IntTypeDummyState).data)
assertEquals("0", (ltx.getInput(1) as StringTypeDummyState).data)
assertEquals(3, (ltx.getInput(6) as IntTypeDummyState).data)
assertEquals("3", (ltx.getInput(7) as StringTypeDummyState).data)
assertFailsWith<IndexOutOfBoundsException> { ltx.getInput(10) }
}
@Test
fun `Simple Output Indexer tests`() {
val ltx = makeDummyTransaction()
assertEquals(0, (ltx.getOutput(0) as IntTypeDummyState).data)
assertEquals("0", (ltx.getOutput(1) as StringTypeDummyState).data)
assertEquals(3, (ltx.getOutput(6) as IntTypeDummyState).data)
assertEquals("3", (ltx.getOutput(7) as StringTypeDummyState).data)
assertFailsWith<IndexOutOfBoundsException> { ltx.getOutput(10) }
}
@Test
fun `Simple Command Indexer tests`() {
val ltx = makeDummyTransaction()
assertEquals(0, (ltx.getCommand(0).value as Commands.Cmd1).id)
assertEquals(0, (ltx.getCommand(1).value as Commands.Cmd2).id)
assertEquals(3, (ltx.getCommand(6).value as Commands.Cmd1).id)
assertEquals(3, (ltx.getCommand(7).value as Commands.Cmd2).id)
assertFailsWith<IndexOutOfBoundsException> { ltx.getOutput(10) }
}
@Test
fun `Simple Inputs of type tests`() {
val ltx = makeDummyTransaction()
val intStates = ltx.inputsOfType(IntTypeDummyState::class.java)
assertEquals(5, intStates.size)
assertEquals(listOf(0, 1, 2, 3, 4), intStates.map { it.data })
val stringStates = ltx.inputsOfType<StringTypeDummyState>()
assertEquals(5, stringStates.size)
assertEquals(listOf("0", "1", "2", "3", "4"), stringStates.map { it.data })
val notPresentQuery = ltx.inputsOfType(FungibleAsset::class.java)
assertEquals(emptyList(), notPresentQuery)
}
@Test
fun `Simple InputsRefs of type tests`() {
val ltx = makeDummyTransaction()
val intStates = ltx.inRefsOfType(IntTypeDummyState::class.java)
assertEquals(5, intStates.size)
assertEquals(listOf(0, 1, 2, 3, 4), intStates.map { it.state.data.data })
assertEquals(listOf(ltx.inputs[0], ltx.inputs[2], ltx.inputs[4], ltx.inputs[6], ltx.inputs[8]), intStates)
val stringStates = ltx.inRefsOfType<StringTypeDummyState>()
assertEquals(5, stringStates.size)
assertEquals(listOf("0", "1", "2", "3", "4"), stringStates.map { it.state.data.data })
assertEquals(listOf(ltx.inputs[1], ltx.inputs[3], ltx.inputs[5], ltx.inputs[7], ltx.inputs[9]), stringStates)
}
@Test
fun `Simple Outputs of type tests`() {
val ltx = makeDummyTransaction()
val intStates = ltx.outputsOfType(IntTypeDummyState::class.java)
assertEquals(5, intStates.size)
assertEquals(listOf(0, 1, 2, 3, 4), intStates.map { it.data })
val stringStates = ltx.outputsOfType<StringTypeDummyState>()
assertEquals(5, stringStates.size)
assertEquals(listOf("0", "1", "2", "3", "4"), stringStates.map { it.data })
val notPresentQuery = ltx.outputsOfType(FungibleAsset::class.java)
assertEquals(emptyList(), notPresentQuery)
}
@Test
fun `Simple OutputsRefs of type tests`() {
val ltx = makeDummyTransaction()
val intStates = ltx.outRefsOfType(IntTypeDummyState::class.java)
assertEquals(5, intStates.size)
assertEquals(listOf(0, 1, 2, 3, 4), intStates.map { it.state.data.data })
assertEquals(listOf(0, 2, 4, 6, 8), intStates.map { it.ref.index })
assertTrue(intStates.all { it.ref.txhash == ltx.id })
val stringStates = ltx.outRefsOfType<StringTypeDummyState>()
assertEquals(5, stringStates.size)
assertEquals(listOf("0", "1", "2", "3", "4"), stringStates.map { it.state.data.data })
assertEquals(listOf(1, 3, 5, 7, 9), stringStates.map { it.ref.index })
assertTrue(stringStates.all { it.ref.txhash == ltx.id })
}
@Test
fun `Simple Commands of type tests`() {
val ltx = makeDummyTransaction()
val intCmd1 = ltx.commandsOfType(Commands.Cmd1::class.java)
assertEquals(5, intCmd1.size)
assertEquals(listOf(0, 1, 2, 3, 4), intCmd1.map { (it.value as Commands.Cmd1).id })
val intCmd2 = ltx.commandsOfType<Commands.Cmd2>()
assertEquals(5, intCmd2.size)
assertEquals(listOf(0, 1, 2, 3, 4), intCmd2.map { (it.value as Commands.Cmd2).id })
val notPresentQuery = ltx.commandsOfType(FungibleAsset.Commands.Exit::class.java)
assertEquals(emptyList(), notPresentQuery)
}
@Test
fun `Filtered Input Tests`() {
val ltx = makeDummyTransaction()
val intStates = ltx.filterInputs(Predicate { it.data.rem(2) == 0 }, IntTypeDummyState::class.java)
assertEquals(3, intStates.size)
assertEquals(listOf(0, 2, 4), intStates.map { it.data })
val stringStates: List<StringTypeDummyState> = ltx.filterInputs { it.data == "3" }
assertEquals("3", stringStates.single().data)
}
@Test
fun `Filtered InRef Tests`() {
val ltx = makeDummyTransaction()
val intStates = ltx.filterInRefs(Predicate { it.data.rem(2) == 0 }, IntTypeDummyState::class.java)
assertEquals(3, intStates.size)
assertEquals(listOf(0, 2, 4), intStates.map { it.state.data.data })
assertEquals(listOf(ltx.inputs[0], ltx.inputs[4], ltx.inputs[8]), intStates)
val stringStates: List<StateAndRef<StringTypeDummyState>> = ltx.filterInRefs { it.data == "3" }
assertEquals("3", stringStates.single().state.data.data)
assertEquals(ltx.inputs[7], stringStates.single())
}
@Test
fun `Filtered Output Tests`() {
val ltx = makeDummyTransaction()
val intStates = ltx.filterOutputs(Predicate { it.data.rem(2) == 0 }, IntTypeDummyState::class.java)
assertEquals(3, intStates.size)
assertEquals(listOf(0, 2, 4), intStates.map { it.data })
val stringStates: List<StringTypeDummyState> = ltx.filterOutputs { it.data == "3" }
assertEquals("3", stringStates.single().data)
}
@Test
fun `Filtered OutRef Tests`() {
val ltx = makeDummyTransaction()
val intStates = ltx.filterOutRefs(Predicate { it.data.rem(2) == 0 }, IntTypeDummyState::class.java)
assertEquals(3, intStates.size)
assertEquals(listOf(0, 2, 4), intStates.map { it.state.data.data })
assertEquals(listOf(0, 4, 8), intStates.map { it.ref.index })
assertTrue(intStates.all { it.ref.txhash == ltx.id })
val stringStates: List<StateAndRef<StringTypeDummyState>> = ltx.filterOutRefs { it.data == "3" }
assertEquals("3", stringStates.single().state.data.data)
assertEquals(7, stringStates.single().ref.index)
assertEquals(ltx.id, stringStates.single().ref.txhash)
}
@Test
fun `Filtered Commands Tests`() {
val ltx = makeDummyTransaction()
val intCmds1 = ltx.filterCommands(Predicate { it.id.rem(2) == 0 }, Commands.Cmd1::class.java)
assertEquals(3, intCmds1.size)
assertEquals(listOf(0, 2, 4), intCmds1.map { (it.value as Commands.Cmd1).id })
val intCmds2 = ltx.filterCommands<Commands.Cmd2> { it.id == 3 }
assertEquals(3, (intCmds2.single().value as Commands.Cmd2).id)
}
@Test
fun `Find Input Tests`() {
val ltx = makeDummyTransaction()
val intState = ltx.findInput(Predicate { it.data == 4 }, IntTypeDummyState::class.java)
assertEquals(ltx.getInput(8), intState)
val stringState: StringTypeDummyState = ltx.findInput { it.data == "3" }
assertEquals(ltx.getInput(7), stringState)
}
@Test
fun `Find InRef Tests`() {
val ltx = makeDummyTransaction()
val intState = ltx.findInRef(Predicate { it.data == 4 }, IntTypeDummyState::class.java)
assertEquals(ltx.inRef(8), intState)
val stringState: StateAndRef<StringTypeDummyState> = ltx.findInRef { it.data == "3" }
assertEquals(ltx.inRef(7), stringState)
}
@Test
fun `Find Output Tests`() {
val ltx = makeDummyTransaction()
val intState = ltx.findOutput(Predicate { it.data == 4 }, IntTypeDummyState::class.java)
assertEquals(ltx.getOutput(8), intState)
val stringState: StringTypeDummyState = ltx.findOutput { it.data == "3" }
assertEquals(ltx.getOutput(7), stringState)
}
@Test
fun `Find OutRef Tests`() {
val ltx = makeDummyTransaction()
val intState = ltx.findOutRef(Predicate { it.data == 4 }, IntTypeDummyState::class.java)
assertEquals(ltx.outRef(8), intState)
val stringState: StateAndRef<StringTypeDummyState> = ltx.findOutRef { it.data == "3" }
assertEquals(ltx.outRef(7), stringState)
}
@Test
fun `Find Commands Tests`() {
val ltx = makeDummyTransaction()
val intCmd1 = ltx.findCommand(Predicate { it.id == 2 }, Commands.Cmd1::class.java)
assertEquals(ltx.getCommand(4), intCmd1)
val intCmd2 = ltx.findCommand<Commands.Cmd2> { it.id == 3 }
assertEquals(ltx.getCommand(7), intCmd2)
}
}

View File

@ -29,7 +29,7 @@ class TransactionEncumbranceTests {
class DummyTimeLock : Contract {
override val legalContractReference = SecureHash.sha256("DummyTimeLock")
override fun verify(tx: LedgerTransaction) {
val timeLockInput = tx.inputs.map { it.state.data }.filterIsInstance<State>().singleOrNull() ?: return
val timeLockInput = tx.inputsOfType<State>().singleOrNull() ?: return
val time = tx.timeWindow?.untilTime ?: throw IllegalArgumentException("Transactions containing time-locks must have a time-window")
requireThat {
"the time specified in the time-lock has passed" using (time >= timeLockInput.validFrom)

View File

@ -61,9 +61,10 @@ class CollectSignaturesFlowTests {
val flow = object : SignTransactionFlow(otherParty) {
@Suspendable override fun checkTransaction(stx: SignedTransaction) = requireThat {
val tx = stx.tx
val ltx = tx.toLedgerTransaction(serviceHub)
"There should only be one output state" using (tx.outputs.size == 1)
"There should only be one output state" using (tx.inputs.isEmpty())
val magicNumberState = tx.outputs.single().data as DummyContract.MultiOwnerState
val magicNumberState = ltx.outputsOfType<DummyContract.MultiOwnerState>().single()
"Must be 1337 or greater" using (magicNumberState.magicNumber >= 1337)
}
}
@ -118,9 +119,10 @@ class CollectSignaturesFlowTests {
val flow = object : SignTransactionFlow(otherParty) {
@Suspendable override fun checkTransaction(stx: SignedTransaction) = requireThat {
val tx = stx.tx
val ltx = tx.toLedgerTransaction(serviceHub)
"There should only be one output state" using (tx.outputs.size == 1)
"There should only be one output state" using (tx.inputs.isEmpty())
val magicNumberState = tx.outputs.single().data as DummyContract.MultiOwnerState
val magicNumberState = ltx.outputsOfType<DummyContract.MultiOwnerState>().single()
"Must be 1337 or greater" using (magicNumberState.magicNumber >= 1337)
}
}

View File

@ -295,7 +295,7 @@ class AttachmentClassLoaderTests : TestDependencyInjectionBase() {
}
val copiedWireTransaction = bytes.deserialize(context = context)
assertEquals(1, copiedWireTransaction.outputs.size)
val contract2 = copiedWireTransaction.outputs[0].data.contract as DummyContractBackdoor
val contract2 = copiedWireTransaction.getOutput(0).contract as DummyContractBackdoor
assertEquals(42, contract2.inspectState(copiedWireTransaction.outputs[0].data))
}

View File

@ -12,10 +12,7 @@ import net.corda.core.node.services.ServiceType
import net.corda.core.node.services.Vault.Page
import net.corda.core.node.services.queryBy
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.transactions.WireTransaction
import net.corda.core.transactions.*
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.ProgressTracker.Step
import net.corda.core.utilities.UntrustworthyData
@ -416,7 +413,7 @@ object FlowCookbook {
// sign it! We need to make sure the transaction represents an
// agreement we actually want to enter into.
// DOCSTART 34
val outputState: DummyState = wireTx.outputs.single().data as DummyState
val outputState: DummyState = wireTx.outputsOfType<DummyState>().single()
if (outputState.magicNumber == 777) {
// ``FlowException`` is a special exception type. It will be
// propagated back to any counterparty flows waiting for a
@ -548,7 +545,7 @@ object FlowCookbook {
val signTransactionFlow: SignTransactionFlow = object : SignTransactionFlow(counterparty) {
override fun checkTransaction(stx: SignedTransaction) = requireThat {
// Any additional checking we see fit...
val outputState = stx.tx.outputs.single().data as DummyState
val outputState = stx.tx.outputsOfType<DummyState>().single()
assert(outputState.magicNumber == 777)
}
}

View File

@ -79,7 +79,7 @@ data class TradeApprovalContract(override val legalContractReference: SecureHash
"Issue of new WorkflowContract must not include any inputs" using (tx.inputs.isEmpty())
"Issue of new WorkflowContract must be in a unique transaction" using (tx.outputs.size == 1)
}
val issued = tx.outputs[0].data as TradeApprovalContract.State
val issued = tx.outputsOfType<TradeApprovalContract.State>().single()
requireThat {
"Issue requires the source Party as signer" using (command.signers.contains(issued.source.owningKey))
"Initial Issue state must be NEW" using (issued.state == WorkflowState.NEW)

View File

@ -192,7 +192,7 @@ class UniversalContract : Contract {
when (value) {
is Commands.Action -> {
val inState = tx.inputs.single().state.data as State
val inState = tx.inputsOfType<State>().single()
val arr = when (inState.details) {
is Actions -> inState.details
is RollOut -> reduceRollOut(inState.details)
@ -222,7 +222,7 @@ class UniversalContract : Contract {
when (tx.outputs.size) {
1 -> {
val outState = tx.outputs.single().data as State
val outState = tx.outputsOfType<State>().single()
requireThat {
"output state must match action result state" using (arrangement.equals(outState.details))
"output state must match action result state" using (rest == zero)
@ -230,7 +230,7 @@ class UniversalContract : Contract {
}
0 -> throw IllegalArgumentException("must have at least one out state")
else -> {
val allContracts = And(tx.outputs.map { (it.data as State).details }.toSet())
val allContracts = And(tx.outputsOfType<State>().map { it.details }.toSet())
requireThat {
"output states must match action result state" using (arrangement.equals(allContracts))
@ -240,15 +240,15 @@ class UniversalContract : Contract {
}
}
is Commands.Issue -> {
val outState = tx.outputs.single().data as State
val outState = tx.outputsOfType<State>().single()
requireThat {
"the transaction is signed by all liable parties" using (liableParties(outState.details).all { it in cmd.signers })
"the transaction has no input states" using tx.inputs.isEmpty()
}
}
is Commands.Move -> {
val inState = tx.inputs.single().state.data as State
val outState = tx.outputs.single().data as State
val inState = tx.inputsOfType<State>().single()
val outState = tx.outputsOfType<State>().single()
requireThat {
"the transaction is signed by all liable parties" using
(liableParties(outState.details).all { it in cmd.signers })
@ -257,13 +257,13 @@ class UniversalContract : Contract {
}
}
is Commands.Fix -> {
val inState = tx.inputs.single().state.data as State
val inState = tx.inputsOfType<State>().single()
val arr = when (inState.details) {
is Actions -> inState.details
is RollOut -> reduceRollOut(inState.details)
else -> throw IllegalArgumentException("Unexpected arrangement, " + tx.inputs.single())
}
val outState = tx.outputs.single().data as State
val outState = tx.outputsOfType<State>().single()
val unusedFixes = value.fixes.map { it.of }.toMutableSet()
val expectedArr = replaceFixing(tx, arr,

View File

@ -13,13 +13,13 @@ import net.corda.core.crypto.random63BitValue
import net.corda.core.crypto.toBase58String
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party
import net.corda.core.internal.Emoji
import net.corda.core.node.services.VaultService
import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentState
import net.corda.core.schemas.QueryableState
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.internal.Emoji
import net.corda.schemas.CommercialPaperSchemaV1
import java.time.Instant
import java.util.*
@ -172,7 +172,7 @@ class CommercialPaper : Contract {
val timeWindow = tx.timeWindow
val input = inputs.single()
val received = tx.outputs.map { it.data }.sumCashBy(input.owner)
val received = tx.outputStates.sumCashBy(input.owner)
val time = timeWindow?.fromTime ?: throw IllegalArgumentException("Redemptions must have a time-window")
requireThat {
"the paper must have matured" using (time >= input.maturityDate)

View File

@ -7,10 +7,10 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.testing.NULL_PARTY
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party
import net.corda.core.internal.Emoji
import net.corda.core.node.services.VaultService
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.internal.Emoji
import java.time.Instant
import java.util.*
@ -81,7 +81,7 @@ class CommercialPaperLegacy : Contract {
is Commands.Redeem -> {
// Redemption of the paper requires movement of on-ledger cash.
val input = inputs.single()
val received = tx.outputs.map { it.data }.sumCashBy(input.owner)
val received = tx.outputStates.sumCashBy(input.owner)
val time = timeWindow?.fromTime ?: throw IllegalArgumentException("Redemptions must have a time-window")
requireThat {
"the paper must have matured" using (time >= input.maturityDate)

View File

@ -14,10 +14,10 @@ import net.corda.core.crypto.random63BitValue
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party
import net.corda.core.internal.Emoji
import net.corda.core.serialization.CordaSerializable
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.internal.Emoji
import net.corda.core.utilities.NonEmptySet
import net.corda.core.utilities.seconds
import org.bouncycastle.asn1.x500.X500Name
@ -159,7 +159,7 @@ class Obligation<P : Any> : Contract {
// Move (signed by B)
//
// That would pass this check. Ensuring they do not is best addressed in the transaction generation stage.
val assetStates = tx.outputs.map { it.data }.filterIsInstance<FungibleAsset<*>>()
val assetStates = tx.outputsOfType<FungibleAsset<*>>()
val acceptableAssetStates = assetStates
// TODO: This filter is nonsense, because it just checks there is an asset contract loaded, we need to
// verify the asset contract is the asset contract we expect.

View File

@ -6,8 +6,8 @@ import net.corda.core.contracts.*
import net.corda.core.flows.*
import net.corda.core.identity.Party
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap
import java.util.*
@ -49,10 +49,7 @@ object IssuerFlow {
return sendAndReceive<AbstractCashFlow.Result>(issuerBankParty, issueRequest).unwrap { res ->
val tx = res.stx.tx
val expectedAmount = Amount(amount.quantity, Issued(issuerBankParty.ref(issueToPartyRef), amount.token))
val cashOutputs = tx.outputs
.map { it.data}
.filterIsInstance<Cash.State>()
.filter { state -> state.owner == res.recipient }
val cashOutputs = tx.filterOutputs<Cash.State> { state -> state.owner == res.recipient }
require(cashOutputs.size == 1) { "Require a single cash output paying ${res.recipient}, found ${tx.outputs}" }
require(cashOutputs.single().amount == expectedAmount) { "Require payment of $expectedAmount"}
res

View File

@ -8,11 +8,11 @@ import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party
import net.corda.core.node.NodeInfo
import net.corda.core.utilities.seconds
import net.corda.core.serialization.CordaSerializable
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.seconds
import net.corda.core.utilities.unwrap
import java.security.PublicKey
import java.util.*
@ -85,7 +85,7 @@ object TwoPartyTradeFlow {
// DOCSTART 5
val signTransactionFlow = object : SignTransactionFlow(otherParty, VERIFYING_AND_SIGNING.childProgressTracker()) {
override fun checkTransaction(stx: SignedTransaction) {
if (stx.tx.outputs.map { it.data }.sumCashBy(me).withoutIssuer() != price)
if (stx.tx.outputStates.sumCashBy(me).withoutIssuer() != price)
throw FlowException("Transaction is not sending us the right amount of cash")
}
}

View File

@ -159,7 +159,7 @@ class CashTests : TestDependencyInjectionBase() {
Cash().generateIssue(this, 100.DOLLARS `issued by` MINI_CORP.ref(12, 34), owner = AnonymousParty(DUMMY_PUBKEY_1), notary = DUMMY_NOTARY)
}.toWireTransaction()
assertTrue(tx.inputs.isEmpty())
val s = tx.outputs[0].data as Cash.State
val s = tx.outputsOfType<Cash.State>().single()
assertEquals(100.DOLLARS `issued by` MINI_CORP.ref(12, 34), s.amount)
assertEquals(MINI_CORP as AbstractParty, s.amount.token.issuer.party)
assertEquals(AnonymousParty(DUMMY_PUBKEY_1), s.owner)
@ -514,7 +514,7 @@ class CashTests : TestDependencyInjectionBase() {
val wtx = makeExit(50.DOLLARS, MEGA_CORP, 1)
assertEquals(WALLET[0].ref, wtx.inputs[0])
assertEquals(1, wtx.outputs.size)
assertEquals(WALLET[0].state.data.copy(amount = WALLET[0].state.data.amount.splitEvenly(2).first()), wtx.outputs[0].data)
assertEquals(WALLET[0].state.data.copy(amount = WALLET[0].state.data.amount.splitEvenly(2).first()), wtx.getOutput(0))
}
/**
@ -574,7 +574,7 @@ class CashTests : TestDependencyInjectionBase() {
@Suppress("UNCHECKED_CAST")
val vaultState = vaultStatesUnconsumed.elementAt(0)
assertEquals(vaultState.ref, wtx.inputs[0])
assertEquals(vaultState.state.data.copy(owner = THEIR_IDENTITY_1), wtx.outputs[0].data)
assertEquals(vaultState.state.data.copy(owner = THEIR_IDENTITY_1), wtx.getOutput(0))
assertEquals(OUR_IDENTITY_1.owningKey, wtx.commands.single { it.value is Cash.Commands.Move }.signers[0])
}
}
@ -618,7 +618,7 @@ class CashTests : TestDependencyInjectionBase() {
val vaultState1 = vaultStatesUnconsumed.elementAt(1)
assertEquals(vaultState0.ref, wtx.inputs[0])
assertEquals(vaultState1.ref, wtx.inputs[1])
assertEquals(vaultState0.state.data.copy(owner = THEIR_IDENTITY_1, amount = 500.DOLLARS `issued by` defaultIssuer), wtx.outputs[0].data)
assertEquals(vaultState0.state.data.copy(owner = THEIR_IDENTITY_1, amount = 500.DOLLARS `issued by` defaultIssuer), wtx.getOutput(0))
assertEquals(OUR_IDENTITY_1.owningKey, wtx.commands.single { it.value is Cash.Commands.Move }.signers[0])
}
}
@ -639,7 +639,7 @@ class CashTests : TestDependencyInjectionBase() {
assertEquals(vaultState1.ref, wtx.inputs[1])
assertEquals(vaultState2.ref, wtx.inputs[2])
assertEquals(vaultState0.state.data.copy(owner = THEIR_IDENTITY_1, amount = 500.DOLLARS `issued by` defaultIssuer), wtx.outputs[1].data)
assertEquals(vaultState2.state.data.copy(owner = THEIR_IDENTITY_1), wtx.outputs[0].data)
assertEquals(vaultState2.state.data.copy(owner = THEIR_IDENTITY_1), wtx.getOutput(0))
assertEquals(OUR_IDENTITY_1.owningKey, wtx.commands.single { it.value is Cash.Commands.Move }.signers[0])
}
}

View File

@ -146,7 +146,7 @@ class ObligationTests {
beneficiary = CHARLIE,
template = megaCorpDollarSettlement
)
assertEquals(tx.outputs[0].data, expected)
assertEquals(tx.getOutput(0), expected)
assertTrue(tx.commands[0].value is Obligation.Commands.Issue)
assertEquals(MINI_CORP_PUBKEY, tx.commands[0].signers[0])
resetTestSerialization()
@ -250,7 +250,7 @@ class ObligationTests {
}.toWireTransaction()
assertEquals(1, tx.outputs.size)
val actual = tx.outputs[0].data
val actual = tx.getOutput(0)
assertEquals((1000000.DOLLARS `issued by` defaultIssuer).OBLIGATION between Pair(ALICE, BOB), actual)
}
@ -277,7 +277,7 @@ class ObligationTests {
}.toWireTransaction()
assertEquals(1, tx.outputs.size)
val expected = obligationBobToAlice.copy(quantity = obligationBobToAlice.quantity - obligationAliceToBob.quantity)
val actual = tx.outputs[0].data
val actual = tx.getOutput(0)
assertEquals(expected, actual)
}
@ -305,7 +305,7 @@ class ObligationTests {
stx = notaryServices.addSignature(ptx)
assertEquals(1, stx.tx.outputs.size)
assertEquals(stateAndRef.state.data.copy(lifecycle = Lifecycle.DEFAULTED), stx.tx.outputs[0].data)
assertEquals(stateAndRef.state.data.copy(lifecycle = Lifecycle.DEFAULTED), stx.tx.getOutput(0))
stx.verifyRequiredSignatures()
// And set it back
@ -316,7 +316,7 @@ class ObligationTests {
ptx = miniCorpServices.signInitialTransaction(tx)
stx = notaryServices.addSignature(ptx)
assertEquals(1, stx.tx.outputs.size)
assertEquals(stateAndRef.state.data.copy(lifecycle = Lifecycle.NORMAL), stx.tx.outputs[0].data)
assertEquals(stateAndRef.state.data.copy(lifecycle = Lifecycle.NORMAL), stx.tx.getOutput(0))
stx.verifyRequiredSignatures()
}

View File

@ -55,7 +55,7 @@ class CashExitFlowTests {
val expected = (initialBalance - exitAmount).`issued by`(bankOfCorda.ref(ref))
assertEquals(1, exitTx.inputs.size)
assertEquals(1, exitTx.outputs.size)
val output = exitTx.outputs.map { it.data }.filterIsInstance<Cash.State>().single()
val output = exitTx.outputsOfType<Cash.State>().single()
assertEquals(expected, output.amount)
}

View File

@ -47,7 +47,7 @@ class CashIssueFlowTests {
notary)).resultFuture
mockNet.runNetwork()
val issueTx = future.getOrThrow().stx
val output = issueTx.tx.outputs.single().data as Cash.State
val output = issueTx.tx.outputsOfType<Cash.State>().single()
assertEquals(expected.`issued by`(bankOfCorda.ref(ref)), output.amount)
}

View File

@ -457,7 +457,7 @@ class NodeVaultService(private val services: ServiceHub, dataSourceProperties: P
// Retrieve unspent and unlocked cash states that meet our spending criteria.
val acceptableCoins = unconsumedStatesForSpending<Cash.State>(amount, onlyFromParties, tx.notary, tx.lockId)
return OnLedgerAsset.generateSpend(tx, amount, to, acceptableCoins,
{ state, amount, owner -> deriveState(state, amount, owner) },
{ state, quantity, owner -> deriveState(state, quantity, owner) },
{ Cash().generateMoveCommand() })
}
@ -466,9 +466,7 @@ class NodeVaultService(private val services: ServiceHub, dataSourceProperties: P
@VisibleForTesting
internal fun makeUpdate(tx: WireTransaction, ourKeys: Set<PublicKey>): Vault.Update {
val ourNewStates = tx.outputs.
filter { isRelevant(it.data, ourKeys) }.
map { tx.outRef<ContractState>(it.data) }
val ourNewStates = tx.filterOutRefs<ContractState> { isRelevant(it, ourKeys) }
// Retrieve all unconsumed states for this transaction's inputs
val consumedStates = HashSet<StateAndRef<ContractState>>()

View File

@ -1,19 +1,19 @@
package net.corda.node.services
import net.corda.core.contracts.*
import net.corda.testing.contracts.DummyContract
import net.corda.core.crypto.generateKeyPair
import net.corda.core.flows.NotaryChangeFlow
import net.corda.core.flows.StateReplacementException
import net.corda.core.getOrThrow
import net.corda.core.identity.Party
import net.corda.core.node.services.ServiceInfo
import net.corda.core.utilities.seconds
import net.corda.core.transactions.WireTransaction
import net.corda.core.flows.NotaryChangeFlow
import net.corda.core.flows.StateReplacementException
import net.corda.core.utilities.seconds
import net.corda.node.internal.AbstractNode
import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.contracts.DummyContract
import net.corda.testing.getTestPartyAndCertificate
import net.corda.testing.node.MockNetwork
import org.assertj.core.api.Assertions.assertThatExceptionOfType
@ -109,8 +109,8 @@ class NotaryChangeTests {
val notaryChangeTx = clientNodeA.services.validatedTransactions.getTransaction(newState.ref.txhash)!!.tx
// Check that all encumbrances have been propagated to the outputs
val originalOutputs = issueTx.outputs.map { it.data }
val newOutputs = notaryChangeTx.outputs.map { it.data }
val originalOutputs = issueTx.outputStates
val newOutputs = notaryChangeTx.outputStates
assertTrue(originalOutputs.minus(newOutputs).isEmpty())
// Check that encumbrance links aren't broken after notary change

View File

@ -125,7 +125,7 @@ fun recipient(rpc: CordaRPCOps) {
val wtx = stx.tx
if (wtx.attachments.isNotEmpty()) {
if (wtx.outputs.isNotEmpty()) {
val state = wtx.outputs.map { it.data }.filterIsInstance<AttachmentContract.State>().single()
val state = wtx.outputsOfType<AttachmentContract.State>().single()
require(rpc.attachmentExists(state.hash))
// Download the attachment via the Web endpoint.
@ -173,7 +173,7 @@ class AttachmentContract : Contract {
get() = SecureHash.zeroHash // TODO not implemented
override fun verify(tx: LedgerTransaction) {
val state = tx.outputs.map { it.data }.filterIsInstance<AttachmentContract.State>().single()
val state = tx.outputsOfType<AttachmentContract.State>().single()
val attachment = tx.attachments.single()
require(state.hash == attachment.id)
}

View File

@ -2,8 +2,8 @@ package net.corda.irs.contract
import net.corda.contracts.*
import net.corda.core.contracts.*
import net.corda.core.utilities.seconds
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.seconds
import net.corda.testing.*
import net.corda.testing.node.MockServices
import org.junit.Test
@ -246,7 +246,7 @@ class IRSTests : TestDependencyInjectionBase() {
* Utility so I don't have to keep typing this.
*/
fun singleIRS(irsSelector: Int = 1): InterestRateSwap.State {
return generateIRSTxn(irsSelector).tx.outputs.map { it.data }.filterIsInstance<InterestRateSwap.State>().single()
return generateIRSTxn(irsSelector).tx.outputsOfType<InterestRateSwap.State>().single()
}
/**
@ -300,7 +300,7 @@ class IRSTests : TestDependencyInjectionBase() {
var previousTXN = generateIRSTxn(1)
previousTXN.toLedgerTransaction(services).verify()
services.recordTransactions(previousTXN)
fun currentIRS() = previousTXN.tx.outputs.map { it.data }.filterIsInstance<InterestRateSwap.State>().single()
fun currentIRS() = previousTXN.tx.outputsOfType<InterestRateSwap.State>().single()
while (true) {
val nextFix: FixOf = currentIRS().nextFixingOf() ?: break

View File

@ -27,8 +27,8 @@ import javafx.util.Duration
import net.corda.client.jfx.model.*
import net.corda.client.jfx.utils.*
import net.corda.core.contracts.ContractState
import net.corda.core.identity.Party
import net.corda.core.crypto.toBase58String
import net.corda.core.identity.Party
import net.corda.core.node.NodeInfo
import net.corda.explorer.formatters.PartyNameFormatter
import net.corda.explorer.model.CordaView
@ -77,7 +77,7 @@ class Network : CordaView() {
.map { it as? PartiallyResolvedTransaction.InputResolution.Resolved }
.filterNotNull()
.map { it.stateAndRef.state.data }.getParties()
val outputParties = it.transaction.tx.outputs.map { it.data }.observable().getParties()
val outputParties = it.transaction.tx.outputStates.observable().getParties()
val signingParties = it.transaction.sigs.map { getModel<NetworkIdentityModel>().lookup(it.by) }
// Input parties fire a bullets to all output parties, and to the signing parties. !! This is a rough guess of how the message moves in the network.
// TODO : Expose artemis queue to get real message information.

View File

@ -22,7 +22,10 @@ import net.corda.client.jfx.utils.map
import net.corda.client.jfx.utils.sequence
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.*
import net.corda.core.crypto.*
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.commonName
import net.corda.core.crypto.toBase58String
import net.corda.core.crypto.toStringShort
import net.corda.core.identity.AbstractParty
import net.corda.core.node.NodeInfo
import net.corda.explorer.AmountDiff
@ -124,7 +127,7 @@ class TransactionViewer : CordaView("Transactions") {
totalValueEquiv = ::calculateTotalEquiv.lift(myIdentity,
reportingExchange,
resolved.map { it.state.data }.lift(),
it.transaction.tx.outputs.map { it.data }.lift())
it.transaction.tx.outputStates.lift())
)
}