2017-06-07 16:14:01 +01:00
|
|
|
|
Transaction tear-offs
|
|
|
|
|
=====================
|
|
|
|
|
|
|
|
|
|
Example of usage
|
|
|
|
|
----------------
|
|
|
|
|
Let’s focus on a code example. We want to construct a transaction with commands containing interest rate fix data as in:
|
|
|
|
|
:doc:`oracles`. After construction of a partial transaction, with included ``Fix`` commands in it, we want to send it
|
|
|
|
|
to the Oracle for checking and signing. To do so we need to specify which parts of the transaction are going to be
|
|
|
|
|
revealed. That can be done by constructing filtering function over fields of ``WireTransaction`` of type ``(Any) ->
|
|
|
|
|
Boolean``.
|
|
|
|
|
|
|
|
|
|
.. container:: codeset
|
|
|
|
|
|
|
|
|
|
.. sourcecode:: kotlin
|
|
|
|
|
|
|
|
|
|
val partialTx = ...
|
|
|
|
|
val oracle: Party = ...
|
|
|
|
|
fun filtering(elem: Any): Boolean {
|
|
|
|
|
return when (elem) {
|
|
|
|
|
is Command -> oracleParty.owningKey in elem.signers && elem.value is Fix
|
|
|
|
|
else -> false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Assuming that we already assembled partialTx with some commands and know the identity of Oracle service, we construct
|
|
|
|
|
filtering function over commands - ``filtering``. It performs type checking and filters only ``Fix`` commands as in
|
|
|
|
|
IRSDemo example. Then we can construct ``FilteredTransaction``:
|
|
|
|
|
|
|
|
|
|
.. container:: codeset
|
|
|
|
|
|
|
|
|
|
.. sourcecode:: kotlin
|
|
|
|
|
|
|
|
|
|
val wtx: WireTransaction = partialTx.toWireTransaction()
|
|
|
|
|
val ftx: FilteredTransaction = wtx.buildFilteredTransaction(filtering)
|
|
|
|
|
|
|
|
|
|
In the Oracle example this step takes place in ``RatesFixFlow`` by overriding ``filtering`` function, see:
|
|
|
|
|
:ref:`filtering_ref`.
|
|
|
|
|
|
2017-09-27 15:51:44 +01:00
|
|
|
|
Both ``WireTransaction`` and ``FilteredTransaction`` inherit from ``TraversableTransaction``, so access to the
|
|
|
|
|
transaction components is exactly the same. Note that unlike ``WireTransaction``,
|
|
|
|
|
``FilteredTransaction`` only holds data that we wanted to reveal (after filtering).
|
2017-06-07 16:14:01 +01:00
|
|
|
|
|
|
|
|
|
.. container:: codeset
|
|
|
|
|
|
|
|
|
|
.. sourcecode:: kotlin
|
|
|
|
|
|
2017-09-27 15:51:44 +01:00
|
|
|
|
// Direct access to included commands, inputs, outputs, attachments etc.
|
|
|
|
|
val cmds: List<Command> = ftx.commands
|
|
|
|
|
val ins: List<StateRef> = ftx.inputs
|
|
|
|
|
val timeWindow: TimeWindow? = ftx.timeWindow
|
2017-06-07 16:14:01 +01:00
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
.. literalinclude:: ../../samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt
|
|
|
|
|
:language: kotlin
|
|
|
|
|
:start-after: DOCSTART 1
|
|
|
|
|
:end-before: DOCEND 1
|
|
|
|
|
|
|
|
|
|
Above code snippet is taken from ``NodeInterestRates.kt`` file and implements a signing part of an Oracle. You can
|
2017-09-27 15:51:44 +01:00
|
|
|
|
check only leaves using ``ftx.checkWithFun { check(it) }`` and then verify obtained ``FilteredTransaction`` to see
|
|
|
|
|
if its data belongs to ``WireTransaction`` with provided ``id``. All you need is the root hash
|
2017-06-07 16:14:01 +01:00
|
|
|
|
of the full transaction:
|
|
|
|
|
|
|
|
|
|
.. container:: codeset
|
|
|
|
|
|
|
|
|
|
.. sourcecode:: kotlin
|
|
|
|
|
|
|
|
|
|
if (!ftx.verify(merkleRoot)){
|
|
|
|
|
throw MerkleTreeException("Rate Fix Oracle: Couldn't verify partial Merkle tree.")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Or combine the two steps together:
|
|
|
|
|
|
|
|
|
|
.. container:: codeset
|
|
|
|
|
|
|
|
|
|
.. sourcecode:: kotlin
|
|
|
|
|
|
|
|
|
|
ftx.verifyWithFunction(merkleRoot, ::check)
|
|
|
|
|
|
2017-09-27 15:51:44 +01:00
|
|
|
|
.. note:: The way the ``FilteredTransaction`` is constructed ensures that after signing of the root hash it's impossible
|
|
|
|
|
to add or remove components (leaves). However, it can happen that having transaction with multiple commands one party
|
|
|
|
|
reveals only subset of them to the Oracle. As signing is done now over the Merkle root hash, the service signs all
|
|
|
|
|
commands of given type, even though it didn't see all of them. In the case however where all of the commands should be
|
|
|
|
|
visible to an Oracle, one can type ``ftx.checkAllComponentsVisible(COMMANDS_GROUP)`` before invoking ``ftx.verify``.
|
|
|
|
|
``checkAllComponentsVisible`` is using a sophisticated underlying partial Merkle tree check to guarantee that all of
|
|
|
|
|
the components of a particular group that existed in the original ``WireTransaction`` are included in the received
|
|
|
|
|
``FilteredTransaction``.
|