Rename PartialTransaction -> TransactionBuilder. The term "partial transaction" should be reserved to mean a transaction that is lacking some signatures as it's in the process of being built up by multiple parties.

This commit is contained in:
Mike Hearn 2015-12-22 15:28:38 +00:00
parent 89b1a5648b
commit 049f0aa3b3
16 changed files with 58 additions and 58 deletions

View File

@ -353,7 +353,7 @@ OK, let's do the same for the buyer side:
// the state we are being offered! For now, just assume validity! // the state we are being offered! For now, just assume validity!
// Generate the shared transaction that both sides will sign, using the data we have. // Generate the shared transaction that both sides will sign, using the data we have.
val ptx = PartialTransaction() val ptx = TransactionBuilder()
// Add input and output states for the movement of cash, by using the Cash contract // Add input and output states for the movement of cash, by using the Cash contract
// to generate the states. // to generate the states.
val wallet = serviceHub.walletService.currentWallet val wallet = serviceHub.walletService.currentWallet

View File

@ -662,19 +662,19 @@ a method to wrap up the issuance process:
.. sourcecode:: kotlin .. sourcecode:: kotlin
fun craftIssue(issuance: InstitutionReference, faceValue: Amount, maturityDate: Instant): PartialTransaction { fun craftIssue(issuance: InstitutionReference, faceValue: Amount, maturityDate: Instant): TransactionBuilder {
val state = State(issuance, issuance.party.owningKey, faceValue, maturityDate) val state = State(issuance, issuance.party.owningKey, faceValue, maturityDate)
return PartialTransaction(state, WireCommand(Commands.Issue, issuance.party.owningKey)) return TransactionBuilder(state, WireCommand(Commands.Issue, issuance.party.owningKey))
} }
We take a reference that points to the issuing party (i.e. the caller) and which can contain any internal We take a reference that points to the issuing party (i.e. the caller) and which can contain any internal
bookkeeping/reference numbers that we may require. Then the face value of the paper, and the maturity date. It bookkeeping/reference numbers that we may require. Then the face value of the paper, and the maturity date. It
returns a ``PartialTransaction``. A ``PartialTransaction`` is one of the few mutable classes the platform provides. returns a ``TransactionBuilder``. A ``TransactionBuilder`` is one of the few mutable classes the platform provides.
It allows you to add inputs, outputs and commands to it and is designed to be passed around, potentially between It allows you to add inputs, outputs and commands to it and is designed to be passed around, potentially between
multiple contracts. multiple contracts.
.. note:: Crafting methods should ideally be written to compose with each other, that is, they should take a .. note:: Crafting methods should ideally be written to compose with each other, that is, they should take a
``PartialTransaction`` as an argument instead of returning one, unless you are sure it doesn't make sense to ``TransactionBuilder`` as an argument instead of returning one, unless you are sure it doesn't make sense to
combine this type of transaction with others. In this case, issuing CP at the same time as doing other things combine this type of transaction with others. In this case, issuing CP at the same time as doing other things
would just introduce complexity that isn't likely to be worth it, so we return a fresh object each time: instead, would just introduce complexity that isn't likely to be worth it, so we return a fresh object each time: instead,
an issuer should issue the CP (starting out owned by themselves), and then sell it in a separate transaction. an issuer should issue the CP (starting out owned by themselves), and then sell it in a separate transaction.
@ -687,7 +687,7 @@ The returned partial transaction has a ``WireCommand`` object as a parameter. Th
that implements the ``Command`` interface, along with a key that is expected to sign this transaction. In this case, that implements the ``Command`` interface, along with a key that is expected to sign this transaction. In this case,
issuance requires that the issuing party sign, so we put the key of the party there. issuance requires that the issuing party sign, so we put the key of the party there.
The ``PartialTransaction`` constructor we used above takes a variable argument list for convenience. You can pass in The ``TransactionBuilder`` constructor we used above takes a variable argument list for convenience. You can pass in
any ``ContractStateRef`` (input), ``ContractState`` (output) or ``Command`` objects and it'll build up the transaction any ``ContractStateRef`` (input), ``ContractState`` (output) or ``Command`` objects and it'll build up the transaction
for you. for you.
@ -697,13 +697,13 @@ What about moving the paper, i.e. reassigning ownership to someone else?
.. sourcecode:: kotlin .. sourcecode:: kotlin
fun craftMove(tx: PartialTransaction, paper: StateAndRef<State>, newOwner: PublicKey) { fun craftMove(tx: TransactionBuilder, paper: StateAndRef<State>, newOwner: PublicKey) {
tx.addInputState(paper.ref) tx.addInputState(paper.ref)
tx.addOutputState(paper.state.copy(owner = newOwner)) tx.addOutputState(paper.state.copy(owner = newOwner))
tx.addArg(WireCommand(Commands.Move, paper.state.owner)) tx.addArg(WireCommand(Commands.Move, paper.state.owner))
} }
Here, the method takes a pre-existing ``PartialTransaction`` and adds to it. This is correct because typically Here, the method takes a pre-existing ``TransactionBuilder`` and adds to it. This is correct because typically
you will want to combine a sale of CP atomically with the movement of some other asset, such as cash. So both you will want to combine a sale of CP atomically with the movement of some other asset, such as cash. So both
craft methods should operate on the same transaction. You can see an example of this being done in the unit tests craft methods should operate on the same transaction. You can see an example of this being done in the unit tests
for the commercial paper contract. for the commercial paper contract.
@ -719,7 +719,7 @@ Finally, we can do redemption.
.. sourcecode:: kotlin .. sourcecode:: kotlin
@Throws(InsufficientBalanceException::class) @Throws(InsufficientBalanceException::class)
fun craftRedeem(tx: PartialTransaction, paper: StateAndRef<State>, wallet: List<StateAndRef<Cash.State>>) { fun craftRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<Cash.State>>) {
// Add the cash movement using the states in our wallet. // Add the cash movement using the states in our wallet.
Cash().craftSpend(tx, paper.state.faceValue, paper.state.owner, wallet) Cash().craftSpend(tx, paper.state.faceValue, paper.state.owner, wallet)
tx.addInputState(paper.ref) tx.addInputState(paper.ref)
@ -740,10 +740,10 @@ an exception is thrown. And then we add the paper itself as an input, but, not a
from the ledger permanently). Finally, we add a Redeem command that should be signed by the owner of the commercial from the ledger permanently). Finally, we add a Redeem command that should be signed by the owner of the commercial
paper. paper.
A ``PartialTransaction`` is not by itself ready to be used anywhere, so first, we must convert it to something that A ``TransactionBuilder`` is not by itself ready to be used anywhere, so first, we must convert it to something that
is recognised by the network. The most important next step is for the participating entities to sign it using the is recognised by the network. The most important next step is for the participating entities to sign it using the
``signWith()`` method. This takes a keypair, serialises the transaction, signs the serialised form and then stores the ``signWith()`` method. This takes a keypair, serialises the transaction, signs the serialised form and then stores the
signature inside the ``PartialTransaction``. Once all parties have signed, you can call ``PartialTransaction.toSignedTransaction()`` signature inside the ``TransactionBuilder``. Once all parties have signed, you can call ``TransactionBuilder.toSignedTransaction()``
to get a ``SignedWireTransaction`` object. This is an immutable form of the transaction that's ready for *timestamping*. to get a ``SignedWireTransaction`` object. This is an immutable form of the transaction that's ready for *timestamping*.
.. note:: Timestamping and passing around of partial transactions for group signing is not yet fully implemented. .. note:: Timestamping and passing around of partial transactions for group signing is not yet fully implemented.

View File

@ -466,7 +466,7 @@ forms.</p>
// the state we are being offered! For now, just assume validity! // the state we are being offered! For now, just assume validity!
// Generate the shared transaction that both sides will sign, using the data we have. // Generate the shared transaction that both sides will sign, using the data we have.
val ptx = PartialTransaction() val ptx = TransactionBuilder()
// Add input and output states for the movement of cash, by using the Cash contract // Add input and output states for the movement of cash, by using the Cash contract
// to generate the states. // to generate the states.
val wallet = serviceHub.walletService.currentWallet val wallet = serviceHub.walletService.currentWallet

File diff suppressed because one or more lines are too long

View File

@ -741,22 +741,22 @@ like a module), the basic concept is the same: preparation of a transaction usin
<p>For our commercial paper contract however, the things that can be done with it are quite simple. Let&#8217;s start with <p>For our commercial paper contract however, the things that can be done with it are quite simple. Let&#8217;s start with
a method to wrap up the issuance process:</p> a method to wrap up the issuance process:</p>
<div class="codeset container"> <div class="codeset container">
<div class="highlight-kotlin"><div class="highlight"><pre><span class="k">fun</span> <span class="nf">craftIssue</span><span class="p">(</span><span class="n">issuance</span><span class="p">:</span> <span class="n">InstitutionReference</span><span class="p">,</span> <span class="n">faceValue</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span> <span class="n">maturityDate</span><span class="p">:</span> <span class="n">Instant</span><span class="p">):</span> <span class="n">PartialTransaction</span> <span class="p">{</span> <div class="highlight-kotlin"><div class="highlight"><pre><span class="k">fun</span> <span class="nf">craftIssue</span><span class="p">(</span><span class="n">issuance</span><span class="p">:</span> <span class="n">InstitutionReference</span><span class="p">,</span> <span class="n">faceValue</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span> <span class="n">maturityDate</span><span class="p">:</span> <span class="n">Instant</span><span class="p">):</span> <span class="n">TransactionBuilder</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">state</span> <span class="p">=</span> <span class="n">State</span><span class="p">(</span><span class="n">issuance</span><span class="p">,</span> <span class="n">issuance</span><span class="p">.</span><span class="n">party</span><span class="p">.</span><span class="n">owningKey</span><span class="p">,</span> <span class="n">faceValue</span><span class="p">,</span> <span class="n">maturityDate</span><span class="p">)</span> <span class="k">val</span> <span class="py">state</span> <span class="p">=</span> <span class="n">State</span><span class="p">(</span><span class="n">issuance</span><span class="p">,</span> <span class="n">issuance</span><span class="p">.</span><span class="n">party</span><span class="p">.</span><span class="n">owningKey</span><span class="p">,</span> <span class="n">faceValue</span><span class="p">,</span> <span class="n">maturityDate</span><span class="p">)</span>
<span class="k">return</span> <span class="n">PartialTransaction</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">WireCommand</span><span class="p">(</span><span class="n">Commands</span><span class="p">.</span><span class="n">Issue</span><span class="p">,</span> <span class="n">issuance</span><span class="p">.</span><span class="n">party</span><span class="p">.</span><span class="n">owningKey</span><span class="p">))</span> <span class="k">return</span> <span class="n">TransactionBuilder</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">WireCommand</span><span class="p">(</span><span class="n">Commands</span><span class="p">.</span><span class="n">Issue</span><span class="p">,</span> <span class="n">issuance</span><span class="p">.</span><span class="n">party</span><span class="p">.</span><span class="n">owningKey</span><span class="p">))</span>
<span class="p">}</span> <span class="p">}</span>
</pre></div> </pre></div>
</div> </div>
</div> </div>
<p>We take a reference that points to the issuing party (i.e. the caller) and which can contain any internal <p>We take a reference that points to the issuing party (i.e. the caller) and which can contain any internal
bookkeeping/reference numbers that we may require. Then the face value of the paper, and the maturity date. It bookkeeping/reference numbers that we may require. Then the face value of the paper, and the maturity date. It
returns a <code class="docutils literal"><span class="pre">PartialTransaction</span></code>. A <code class="docutils literal"><span class="pre">PartialTransaction</span></code> is one of the few mutable classes the platform provides. returns a <code class="docutils literal"><span class="pre">TransactionBuilder</span></code>. A <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> is one of the few mutable classes the platform provides.
It allows you to add inputs, outputs and commands to it and is designed to be passed around, potentially between It allows you to add inputs, outputs and commands to it and is designed to be passed around, potentially between
multiple contracts.</p> multiple contracts.</p>
<div class="admonition note"> <div class="admonition note">
<p class="first admonition-title">Note</p> <p class="first admonition-title">Note</p>
<p class="last">Crafting methods should ideally be written to compose with each other, that is, they should take a <p class="last">Crafting methods should ideally be written to compose with each other, that is, they should take a
<code class="docutils literal"><span class="pre">PartialTransaction</span></code> as an argument instead of returning one, unless you are sure it doesn&#8217;t make sense to <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> as an argument instead of returning one, unless you are sure it doesn&#8217;t make sense to
combine this type of transaction with others. In this case, issuing CP at the same time as doing other things combine this type of transaction with others. In this case, issuing CP at the same time as doing other things
would just introduce complexity that isn&#8217;t likely to be worth it, so we return a fresh object each time: instead, would just introduce complexity that isn&#8217;t likely to be worth it, so we return a fresh object each time: instead,
an issuer should issue the CP (starting out owned by themselves), and then sell it in a separate transaction.</p> an issuer should issue the CP (starting out owned by themselves), and then sell it in a separate transaction.</p>
@ -767,12 +767,12 @@ to issue CP onto the ledger that&#8217;s immediately owned by someone else, they
<p>The returned partial transaction has a <code class="docutils literal"><span class="pre">WireCommand</span></code> object as a parameter. This is a container for any object <p>The returned partial transaction has a <code class="docutils literal"><span class="pre">WireCommand</span></code> object as a parameter. This is a container for any object
that implements the <code class="docutils literal"><span class="pre">Command</span></code> interface, along with a key that is expected to sign this transaction. In this case, that implements the <code class="docutils literal"><span class="pre">Command</span></code> interface, along with a key that is expected to sign this transaction. In this case,
issuance requires that the issuing party sign, so we put the key of the party there.</p> issuance requires that the issuing party sign, so we put the key of the party there.</p>
<p>The <code class="docutils literal"><span class="pre">PartialTransaction</span></code> constructor we used above takes a variable argument list for convenience. You can pass in <p>The <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> constructor we used above takes a variable argument list for convenience. You can pass in
any <code class="docutils literal"><span class="pre">ContractStateRef</span></code> (input), <code class="docutils literal"><span class="pre">ContractState</span></code> (output) or <code class="docutils literal"><span class="pre">Command</span></code> objects and it&#8217;ll build up the transaction any <code class="docutils literal"><span class="pre">ContractStateRef</span></code> (input), <code class="docutils literal"><span class="pre">ContractState</span></code> (output) or <code class="docutils literal"><span class="pre">Command</span></code> objects and it&#8217;ll build up the transaction
for you.</p> for you.</p>
<p>What about moving the paper, i.e. reassigning ownership to someone else?</p> <p>What about moving the paper, i.e. reassigning ownership to someone else?</p>
<div class="codeset container"> <div class="codeset container">
<div class="highlight-kotlin"><div class="highlight"><pre><span class="k">fun</span> <span class="nf">craftMove</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">PartialTransaction</span><span class="p">,</span> <span class="n">paper</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">State</span><span class="p">&gt;,</span> <span class="n">newOwner</span><span class="p">:</span> <span class="n">PublicKey</span><span class="p">)</span> <span class="p">{</span> <div class="highlight-kotlin"><div class="highlight"><pre><span class="k">fun</span> <span class="nf">craftMove</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">TransactionBuilder</span><span class="p">,</span> <span class="n">paper</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">State</span><span class="p">&gt;,</span> <span class="n">newOwner</span><span class="p">:</span> <span class="n">PublicKey</span><span class="p">)</span> <span class="p">{</span>
<span class="n">tx</span><span class="p">.</span><span class="n">addInputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">ref</span><span class="p">)</span> <span class="n">tx</span><span class="p">.</span><span class="n">addInputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">ref</span><span class="p">)</span>
<span class="n">tx</span><span class="p">.</span><span class="n">addOutputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">copy</span><span class="p">(</span><span class="n">owner</span> <span class="p">=</span> <span class="n">newOwner</span><span class="p">))</span> <span class="n">tx</span><span class="p">.</span><span class="n">addOutputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">copy</span><span class="p">(</span><span class="n">owner</span> <span class="p">=</span> <span class="n">newOwner</span><span class="p">))</span>
<span class="n">tx</span><span class="p">.</span><span class="n">addArg</span><span class="p">(</span><span class="n">WireCommand</span><span class="p">(</span><span class="n">Commands</span><span class="p">.</span><span class="n">Move</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">))</span> <span class="n">tx</span><span class="p">.</span><span class="n">addArg</span><span class="p">(</span><span class="n">WireCommand</span><span class="p">(</span><span class="n">Commands</span><span class="p">.</span><span class="n">Move</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">))</span>
@ -780,7 +780,7 @@ for you.</p>
</pre></div> </pre></div>
</div> </div>
</div> </div>
<p>Here, the method takes a pre-existing <code class="docutils literal"><span class="pre">PartialTransaction</span></code> and adds to it. This is correct because typically <p>Here, the method takes a pre-existing <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> and adds to it. This is correct because typically
you will want to combine a sale of CP atomically with the movement of some other asset, such as cash. So both you will want to combine a sale of CP atomically with the movement of some other asset, such as cash. So both
craft methods should operate on the same transaction. You can see an example of this being done in the unit tests craft methods should operate on the same transaction. You can see an example of this being done in the unit tests
for the commercial paper contract.</p> for the commercial paper contract.</p>
@ -790,7 +790,7 @@ state on the ledger.</p>
<p>Finally, we can do redemption.</p> <p>Finally, we can do redemption.</p>
<div class="codeset container"> <div class="codeset container">
<div class="highlight-kotlin"><div class="highlight"><pre><span class="n">@Throws</span><span class="p">(</span><span class="n">InsufficientBalanceException</span><span class="o">::</span><span class="k">class</span><span class="p">)</span> <div class="highlight-kotlin"><div class="highlight"><pre><span class="n">@Throws</span><span class="p">(</span><span class="n">InsufficientBalanceException</span><span class="o">::</span><span class="k">class</span><span class="p">)</span>
<span class="k">fun</span> <span class="nf">craftRedeem</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">PartialTransaction</span><span class="p">,</span> <span class="n">paper</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">State</span><span class="p">&gt;,</span> <span class="n">wallet</span><span class="p">:</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">Cash</span><span class="p">.</span><span class="n">State</span><span class="p">&gt;&gt;)</span> <span class="p">{</span> <span class="k">fun</span> <span class="nf">craftRedeem</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">TransactionBuilder</span><span class="p">,</span> <span class="n">paper</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">State</span><span class="p">&gt;,</span> <span class="n">wallet</span><span class="p">:</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">Cash</span><span class="p">.</span><span class="n">State</span><span class="p">&gt;&gt;)</span> <span class="p">{</span>
<span class="c1">// Add the cash movement using the states in our wallet.</span> <span class="c1">// Add the cash movement using the states in our wallet.</span>
<span class="n">Cash</span><span class="p">().</span><span class="n">craftSpend</span><span class="p">(</span><span class="n">tx</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">faceValue</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">,</span> <span class="n">wallet</span><span class="p">)</span> <span class="n">Cash</span><span class="p">().</span><span class="n">craftSpend</span><span class="p">(</span><span class="n">tx</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">faceValue</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">,</span> <span class="n">wallet</span><span class="p">)</span>
<span class="n">tx</span><span class="p">.</span><span class="n">addInputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">ref</span><span class="p">)</span> <span class="n">tx</span><span class="p">.</span><span class="n">addInputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">ref</span><span class="p">)</span>
@ -813,10 +813,10 @@ from the issuer of the commercial paper to the current owner. If we don&#8217;t
an exception is thrown. And then we add the paper itself as an input, but, not an output (as we wish to delete it an exception is thrown. And then we add the paper itself as an input, but, not an output (as we wish to delete it
from the ledger permanently). Finally, we add a Redeem command that should be signed by the owner of the commercial from the ledger permanently). Finally, we add a Redeem command that should be signed by the owner of the commercial
paper.</p> paper.</p>
<p>A <code class="docutils literal"><span class="pre">PartialTransaction</span></code> is not by itself ready to be used anywhere, so first, we must convert it to something that <p>A <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> is not by itself ready to be used anywhere, so first, we must convert it to something that
is recognised by the network. The most important next step is for the participating entities to sign it using the is recognised by the network. The most important next step is for the participating entities to sign it using the
<code class="docutils literal"><span class="pre">signWith()</span></code> method. This takes a keypair, serialises the transaction, signs the serialised form and then stores the <code class="docutils literal"><span class="pre">signWith()</span></code> method. This takes a keypair, serialises the transaction, signs the serialised form and then stores the
signature inside the <code class="docutils literal"><span class="pre">PartialTransaction</span></code>. Once all parties have signed, you can call <code class="docutils literal"><span class="pre">PartialTransaction.toSignedTransaction()</span></code> signature inside the <code class="docutils literal"><span class="pre">TransactionBuilder</span></code>. Once all parties have signed, you can call <code class="docutils literal"><span class="pre">TransactionBuilder.toSignedTransaction()</span></code>
to get a <code class="docutils literal"><span class="pre">SignedWireTransaction</span></code> object. This is an immutable form of the transaction that&#8217;s ready for <em>timestamping</em>.</p> to get a <code class="docutils literal"><span class="pre">SignedWireTransaction</span></code> object. This is an immutable form of the transaction that&#8217;s ready for <em>timestamping</em>.</p>
<div class="admonition note"> <div class="admonition note">
<p class="first admonition-title">Note</p> <p class="first admonition-title">Note</p>

View File

@ -353,7 +353,7 @@ OK, let's do the same for the buyer side:
// the state we are being offered! For now, just assume validity! // the state we are being offered! For now, just assume validity!
// Generate the shared transaction that both sides will sign, using the data we have. // Generate the shared transaction that both sides will sign, using the data we have.
val ptx = PartialTransaction() val ptx = TransactionBuilder()
// Add input and output states for the movement of cash, by using the Cash contract // Add input and output states for the movement of cash, by using the Cash contract
// to generate the states. // to generate the states.
val wallet = serviceHub.walletService.currentWallet val wallet = serviceHub.walletService.currentWallet

View File

@ -662,19 +662,19 @@ a method to wrap up the issuance process:
.. sourcecode:: kotlin .. sourcecode:: kotlin
fun craftIssue(issuance: InstitutionReference, faceValue: Amount, maturityDate: Instant): PartialTransaction { fun craftIssue(issuance: InstitutionReference, faceValue: Amount, maturityDate: Instant): TransactionBuilder {
val state = State(issuance, issuance.party.owningKey, faceValue, maturityDate) val state = State(issuance, issuance.party.owningKey, faceValue, maturityDate)
return PartialTransaction(state, WireCommand(Commands.Issue, issuance.party.owningKey)) return TransactionBuilder(state, WireCommand(Commands.Issue, issuance.party.owningKey))
} }
We take a reference that points to the issuing party (i.e. the caller) and which can contain any internal We take a reference that points to the issuing party (i.e. the caller) and which can contain any internal
bookkeeping/reference numbers that we may require. Then the face value of the paper, and the maturity date. It bookkeeping/reference numbers that we may require. Then the face value of the paper, and the maturity date. It
returns a ``PartialTransaction``. A ``PartialTransaction`` is one of the few mutable classes the platform provides. returns a ``TransactionBuilder``. A ``TransactionBuilder`` is one of the few mutable classes the platform provides.
It allows you to add inputs, outputs and commands to it and is designed to be passed around, potentially between It allows you to add inputs, outputs and commands to it and is designed to be passed around, potentially between
multiple contracts. multiple contracts.
.. note:: Crafting methods should ideally be written to compose with each other, that is, they should take a .. note:: Crafting methods should ideally be written to compose with each other, that is, they should take a
``PartialTransaction`` as an argument instead of returning one, unless you are sure it doesn't make sense to ``TransactionBuilder`` as an argument instead of returning one, unless you are sure it doesn't make sense to
combine this type of transaction with others. In this case, issuing CP at the same time as doing other things combine this type of transaction with others. In this case, issuing CP at the same time as doing other things
would just introduce complexity that isn't likely to be worth it, so we return a fresh object each time: instead, would just introduce complexity that isn't likely to be worth it, so we return a fresh object each time: instead,
an issuer should issue the CP (starting out owned by themselves), and then sell it in a separate transaction. an issuer should issue the CP (starting out owned by themselves), and then sell it in a separate transaction.
@ -687,7 +687,7 @@ The returned partial transaction has a ``WireCommand`` object as a parameter. Th
that implements the ``Command`` interface, along with a key that is expected to sign this transaction. In this case, that implements the ``Command`` interface, along with a key that is expected to sign this transaction. In this case,
issuance requires that the issuing party sign, so we put the key of the party there. issuance requires that the issuing party sign, so we put the key of the party there.
The ``PartialTransaction`` constructor we used above takes a variable argument list for convenience. You can pass in The ``TransactionBuilder`` constructor we used above takes a variable argument list for convenience. You can pass in
any ``ContractStateRef`` (input), ``ContractState`` (output) or ``Command`` objects and it'll build up the transaction any ``ContractStateRef`` (input), ``ContractState`` (output) or ``Command`` objects and it'll build up the transaction
for you. for you.
@ -697,13 +697,13 @@ What about moving the paper, i.e. reassigning ownership to someone else?
.. sourcecode:: kotlin .. sourcecode:: kotlin
fun craftMove(tx: PartialTransaction, paper: StateAndRef<State>, newOwner: PublicKey) { fun craftMove(tx: TransactionBuilder, paper: StateAndRef<State>, newOwner: PublicKey) {
tx.addInputState(paper.ref) tx.addInputState(paper.ref)
tx.addOutputState(paper.state.copy(owner = newOwner)) tx.addOutputState(paper.state.copy(owner = newOwner))
tx.addArg(WireCommand(Commands.Move, paper.state.owner)) tx.addArg(WireCommand(Commands.Move, paper.state.owner))
} }
Here, the method takes a pre-existing ``PartialTransaction`` and adds to it. This is correct because typically Here, the method takes a pre-existing ``TransactionBuilder`` and adds to it. This is correct because typically
you will want to combine a sale of CP atomically with the movement of some other asset, such as cash. So both you will want to combine a sale of CP atomically with the movement of some other asset, such as cash. So both
craft methods should operate on the same transaction. You can see an example of this being done in the unit tests craft methods should operate on the same transaction. You can see an example of this being done in the unit tests
for the commercial paper contract. for the commercial paper contract.
@ -719,7 +719,7 @@ Finally, we can do redemption.
.. sourcecode:: kotlin .. sourcecode:: kotlin
@Throws(InsufficientBalanceException::class) @Throws(InsufficientBalanceException::class)
fun craftRedeem(tx: PartialTransaction, paper: StateAndRef<State>, wallet: List<StateAndRef<Cash.State>>) { fun craftRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<Cash.State>>) {
// Add the cash movement using the states in our wallet. // Add the cash movement using the states in our wallet.
Cash().craftSpend(tx, paper.state.faceValue, paper.state.owner, wallet) Cash().craftSpend(tx, paper.state.faceValue, paper.state.owner, wallet)
tx.addInputState(paper.ref) tx.addInputState(paper.ref)
@ -740,10 +740,10 @@ an exception is thrown. And then we add the paper itself as an input, but, not a
from the ledger permanently). Finally, we add a Redeem command that should be signed by the owner of the commercial from the ledger permanently). Finally, we add a Redeem command that should be signed by the owner of the commercial
paper. paper.
A ``PartialTransaction`` is not by itself ready to be used anywhere, so first, we must convert it to something that A ``TransactionBuilder`` is not by itself ready to be used anywhere, so first, we must convert it to something that
is recognised by the network. The most important next step is for the participating entities to sign it using the is recognised by the network. The most important next step is for the participating entities to sign it using the
``signWith()`` method. This takes a keypair, serialises the transaction, signs the serialised form and then stores the ``signWith()`` method. This takes a keypair, serialises the transaction, signs the serialised form and then stores the
signature inside the ``PartialTransaction``. Once all parties have signed, you can call ``PartialTransaction.toSignedTransaction()`` signature inside the ``TransactionBuilder``. Once all parties have signed, you can call ``TransactionBuilder.toSignedTransaction()``
to get a ``SignedWireTransaction`` object. This is an immutable form of the transaction that's ready for *timestamping*. to get a ``SignedWireTransaction`` object. This is an immutable form of the transaction that's ready for *timestamping*.
.. note:: Timestamping and passing around of partial transactions for group signing is not yet fully implemented. .. note:: Timestamping and passing around of partial transactions for group signing is not yet fully implemented.

View File

@ -151,7 +151,7 @@ class Cash : Contract {
/** /**
* Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey. * Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey.
*/ */
fun craftIssue(tx: PartialTransaction, amount: Amount, at: PartyReference, owner: PublicKey) { fun craftIssue(tx: TransactionBuilder, amount: Amount, at: PartyReference, owner: PublicKey) {
check(tx.inputStates().isEmpty()) check(tx.inputStates().isEmpty())
check(tx.outputStates().sumCashOrNull() == null) check(tx.outputStates().sumCashOrNull() == null)
tx.addOutputState(Cash.State(at, amount, owner)) tx.addOutputState(Cash.State(at, amount, owner))
@ -167,7 +167,7 @@ class Cash : Contract {
* about which type of cash claims they are willing to accept. * about which type of cash claims they are willing to accept.
*/ */
@Throws(InsufficientBalanceException::class) @Throws(InsufficientBalanceException::class)
fun craftSpend(tx: PartialTransaction, amount: Amount, to: PublicKey, fun craftSpend(tx: TransactionBuilder, amount: Amount, to: PublicKey,
cashStates: List<StateAndRef<Cash.State>>, onlyFromParties: Set<Party>? = null): List<PublicKey> { cashStates: List<StateAndRef<Cash.State>>, onlyFromParties: Set<Party>? = null): List<PublicKey> {
// Discussion // Discussion
// //

View File

@ -117,15 +117,15 @@ class CommercialPaper : Contract {
* an existing transaction because you aren't able to issue multiple pieces of CP in a single transaction * an existing transaction because you aren't able to issue multiple pieces of CP in a single transaction
* at the moment: this restriction is not fundamental and may be lifted later. * at the moment: this restriction is not fundamental and may be lifted later.
*/ */
fun craftIssue(issuance: PartyReference, faceValue: Amount, maturityDate: Instant): PartialTransaction { fun craftIssue(issuance: PartyReference, faceValue: Amount, maturityDate: Instant): TransactionBuilder {
val state = State(issuance, issuance.party.owningKey, faceValue, maturityDate) val state = State(issuance, issuance.party.owningKey, faceValue, maturityDate)
return PartialTransaction().withItems(state, Command(Commands.Issue(), issuance.party.owningKey)) return TransactionBuilder().withItems(state, Command(Commands.Issue(), issuance.party.owningKey))
} }
/** /**
* Updates the given partial transaction with an input/output/command to reassign ownership of the paper. * Updates the given partial transaction with an input/output/command to reassign ownership of the paper.
*/ */
fun craftMove(tx: PartialTransaction, paper: StateAndRef<State>, newOwner: PublicKey) { fun craftMove(tx: TransactionBuilder, paper: StateAndRef<State>, newOwner: PublicKey) {
tx.addInputState(paper.ref) tx.addInputState(paper.ref)
tx.addOutputState(paper.state.copy(owner = newOwner)) tx.addOutputState(paper.state.copy(owner = newOwner))
tx.addCommand(Commands.Move(), paper.state.owner) tx.addCommand(Commands.Move(), paper.state.owner)
@ -139,7 +139,7 @@ class CommercialPaper : Contract {
* @throws InsufficientBalanceException if the wallet doesn't contain enough money to pay the redeemer * @throws InsufficientBalanceException if the wallet doesn't contain enough money to pay the redeemer
*/ */
@Throws(InsufficientBalanceException::class) @Throws(InsufficientBalanceException::class)
fun craftRedeem(tx: PartialTransaction, paper: StateAndRef<State>, wallet: List<StateAndRef<Cash.State>>) { fun craftRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<Cash.State>>) {
// Add the cash movement using the states in our wallet. // Add the cash movement using the states in our wallet.
Cash().craftSpend(tx, paper.state.faceValue, paper.state.owner, wallet) Cash().craftSpend(tx, paper.state.faceValue, paper.state.owner, wallet)
tx.addInputState(paper.ref) tx.addInputState(paper.ref)

View File

@ -142,16 +142,16 @@ class CrowdFund : Contract {
* Returns a transaction that registers a crowd-funding campaing, owned by the issuing institution's key. Does not update * Returns a transaction that registers a crowd-funding campaing, owned by the issuing institution's key. Does not update
* an existing transaction because it's not possible to register multiple campaigns in a single transaction * an existing transaction because it's not possible to register multiple campaigns in a single transaction
*/ */
fun craftRegister(owner: PartyReference, fundingTarget: Amount, fundingName: String, closingTime: Instant): PartialTransaction { fun craftRegister(owner: PartyReference, fundingTarget: Amount, fundingName: String, closingTime: Instant): TransactionBuilder {
val campaign = Campaign(owner = owner.party.owningKey, name = fundingName, target = fundingTarget, closingTime = closingTime) val campaign = Campaign(owner = owner.party.owningKey, name = fundingName, target = fundingTarget, closingTime = closingTime)
val state = State(campaign) val state = State(campaign)
return PartialTransaction().withItems(state, Command(Commands.Register(), owner.party.owningKey)) return TransactionBuilder().withItems(state, Command(Commands.Register(), owner.party.owningKey))
} }
/** /**
* Updates the given partial transaction with an input/output/command to fund the opportunity. * Updates the given partial transaction with an input/output/command to fund the opportunity.
*/ */
fun craftPledge(tx: PartialTransaction, campaign: StateAndRef<State>, subscriber: PublicKey) { fun craftPledge(tx: TransactionBuilder, campaign: StateAndRef<State>, subscriber: PublicKey) {
tx.addInputState(campaign.ref) tx.addInputState(campaign.ref)
tx.addOutputState(campaign.state.copy( tx.addOutputState(campaign.state.copy(
pledges = campaign.state.pledges + CrowdFund.Pledge(subscriber, 1000.DOLLARS) pledges = campaign.state.pledges + CrowdFund.Pledge(subscriber, 1000.DOLLARS)
@ -159,7 +159,7 @@ class CrowdFund : Contract {
tx.addCommand(Commands.Pledge(), subscriber) tx.addCommand(Commands.Pledge(), subscriber)
} }
fun craftClose(tx: PartialTransaction, campaign: StateAndRef<State>, wallet: List<StateAndRef<Cash.State>>) { fun craftClose(tx: TransactionBuilder, campaign: StateAndRef<State>, wallet: List<StateAndRef<Cash.State>>) {
tx.addInputState(campaign.ref) tx.addInputState(campaign.ref)
tx.addOutputState(campaign.state.copy(closed = true)) tx.addOutputState(campaign.state.copy(closed = true))
tx.addCommand(Commands.Close(), campaign.state.campaign.owner) tx.addCommand(Commands.Close(), campaign.state.campaign.owner)

View File

@ -155,7 +155,7 @@ private class TwoPartyTradeProtocolImpl(private val smm: StateMachineManager) :
// For now, just assume validity! // For now, just assume validity!
// Generate the shared transaction that both sides will sign, using the data we have. // Generate the shared transaction that both sides will sign, using the data we have.
val ptx = PartialTransaction() val ptx = TransactionBuilder()
// Add input and output states for the movement of cash, by using the Cash contract to generate the states. // 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.walletService.currentWallet
val cashStates = wallet.statesOfType<Cash.State>() val cashStates = wallet.statesOfType<Cash.State>()

View File

@ -31,7 +31,7 @@ import java.util.*
* keypairs. Note that a sighash is not the same thing as a *transaction id*, which is the hash of a SignedWireTransaction * keypairs. Note that a sighash is not the same thing as a *transaction id*, which is the hash of a SignedWireTransaction
* i.e. the outermost serialised form with everything included. * i.e. the outermost serialised form with everything included.
* *
* A PartialTransaction is a transaction class that's mutable (unlike the others which are all immutable). It is * A TransactionBuilder is a transaction class that's mutable (unlike the others which are all immutable). It is
* intended to be passed around contracts that may edit it by adding new states/commands or modifying the existing set. * intended to be passed around contracts that may edit it by adding new states/commands or modifying the existing set.
* Then once the states and commands are right, this class can be used as a holding bucket to gather signatures from * Then once the states and commands are right, this class can be used as a holding bucket to gather signatures from
* multiple parties. * multiple parties.
@ -67,7 +67,7 @@ data class WireTransaction(val inputStates: List<ContractStateRef>,
class NotOnTimeException : Exception() class NotOnTimeException : Exception()
/** A mutable transaction that's in the process of being built, before all signatures are present. */ /** A mutable transaction that's in the process of being built, before all signatures are present. */
class PartialTransaction(private val inputStates: MutableList<ContractStateRef> = arrayListOf(), class TransactionBuilder(private val inputStates: MutableList<ContractStateRef> = arrayListOf(),
private val outputStates: MutableList<ContractState> = arrayListOf(), private val outputStates: MutableList<ContractState> = arrayListOf(),
private val commands: MutableList<Command> = arrayListOf()) { private val commands: MutableList<Command> = arrayListOf()) {
@ -92,7 +92,7 @@ class PartialTransaction(private val inputStates: MutableList<ContractStateRef>
} }
/** A more convenient way to add items to this transaction that calls the add* methods for you based on type */ /** A more convenient way to add items to this transaction that calls the add* methods for you based on type */
public fun withItems(vararg items: Any): PartialTransaction { public fun withItems(vararg items: Any): TransactionBuilder {
for (t in items) { for (t in items) {
when (t) { when (t) {
is ContractStateRef -> inputStates.add(t) is ContractStateRef -> inputStates.add(t)

View File

@ -103,7 +103,7 @@ class CashTests {
this.accepts() this.accepts()
} }
val ptx = PartialTransaction() val ptx = TransactionBuilder()
Cash().craftIssue(ptx, 100.DOLLARS, MINI_CORP.ref(12,34), owner = DUMMY_PUBKEY_1) Cash().craftIssue(ptx, 100.DOLLARS, MINI_CORP.ref(12,34), owner = DUMMY_PUBKEY_1)
assertTrue(ptx.inputStates().isEmpty()) assertTrue(ptx.inputStates().isEmpty())
val s = ptx.outputStates()[0] as Cash.State val s = ptx.outputStates()[0] as Cash.State
@ -312,7 +312,7 @@ class CashTests {
) )
fun makeSpend(amount: Amount, dest: PublicKey): WireTransaction { fun makeSpend(amount: Amount, dest: PublicKey): WireTransaction {
val tx = PartialTransaction() val tx = TransactionBuilder()
Cash().craftSpend(tx, amount, dest, WALLET) Cash().craftSpend(tx, amount, dest, WALLET)
return tx.toWireTransaction() return tx.toWireTransaction()
} }
@ -327,7 +327,7 @@ class CashTests {
@Test @Test
fun craftSimpleSpendWithParties() { fun craftSimpleSpendWithParties() {
val tx = PartialTransaction() val tx = TransactionBuilder()
Cash().craftSpend(tx, 80.DOLLARS, ALICE, WALLET, setOf(MINI_CORP)) Cash().craftSpend(tx, 80.DOLLARS, ALICE, WALLET, setOf(MINI_CORP))
assertEquals(WALLET[2].ref, tx.inputStates()[0]) assertEquals(WALLET[2].ref, tx.inputStates()[0])
} }

View File

@ -149,7 +149,7 @@ class CommercialPaperTests {
// Alice pays $9000 to MiniCorp to own some of their debt. // Alice pays $9000 to MiniCorp to own some of their debt.
val moveTX: LedgerTransaction = run { val moveTX: LedgerTransaction = run {
val ptx = PartialTransaction() val ptx = TransactionBuilder()
Cash().craftSpend(ptx, 9000.DOLLARS, MINI_CORP_PUBKEY, alicesWallet) Cash().craftSpend(ptx, 9000.DOLLARS, MINI_CORP_PUBKEY, alicesWallet)
CommercialPaper().craftMove(ptx, issueTX.outRef(0), ALICE) CommercialPaper().craftMove(ptx, issueTX.outRef(0), ALICE)
ptx.signWith(MINI_CORP_KEY) ptx.signWith(MINI_CORP_KEY)
@ -165,7 +165,7 @@ class CommercialPaperTests {
) )
fun makeRedeemTX(time: Instant): LedgerTransaction { fun makeRedeemTX(time: Instant): LedgerTransaction {
val ptx = PartialTransaction() val ptx = TransactionBuilder()
ptx.setTime(time, DummyTimestampingAuthority.identity, 30.seconds) ptx.setTime(time, DummyTimestampingAuthority.identity, 30.seconds)
CommercialPaper().craftRedeem(ptx, moveTX.outRef(1), corpWallet) CommercialPaper().craftRedeem(ptx, moveTX.outRef(1), corpWallet)
ptx.signWith(ALICE_KEY) ptx.signWith(ALICE_KEY)

View File

@ -125,7 +125,7 @@ class CrowdFundTests {
// Alice pays $1000 to MiniCorp to fund their campaign. // Alice pays $1000 to MiniCorp to fund their campaign.
val pledgeTX: LedgerTransaction = run { val pledgeTX: LedgerTransaction = run {
val ptx = PartialTransaction() val ptx = TransactionBuilder()
CrowdFund().craftPledge(ptx, registerTX.outRef(0), ALICE) CrowdFund().craftPledge(ptx, registerTX.outRef(0), ALICE)
Cash().craftSpend(ptx, 1000.DOLLARS, MINI_CORP_PUBKEY, aliceWallet) Cash().craftSpend(ptx, 1000.DOLLARS, MINI_CORP_PUBKEY, aliceWallet)
ptx.setTime(TEST_TX_TIME, DummyTimestampingAuthority.identity, 30.seconds) ptx.setTime(TEST_TX_TIME, DummyTimestampingAuthority.identity, 30.seconds)
@ -143,7 +143,7 @@ class CrowdFundTests {
) )
// MiniCorp closes their campaign. // MiniCorp closes their campaign.
fun makeFundedTX(time: Instant): LedgerTransaction { fun makeFundedTX(time: Instant): LedgerTransaction {
val ptx = PartialTransaction() val ptx = TransactionBuilder()
ptx.setTime(time, DUMMY_TIMESTAMPER.identity, 30.seconds) ptx.setTime(time, DUMMY_TIMESTAMPER.identity, 30.seconds)
CrowdFund().craftClose(ptx, pledgeTX.outRef(0), miniCorpWallet) CrowdFund().craftClose(ptx, pledgeTX.outRef(0), miniCorpWallet)
ptx.signWith(MINI_CORP_KEY) ptx.signWith(MINI_CORP_KEY)

View File

@ -25,11 +25,11 @@ class TransactionSerializationTests {
val changeState = Cash.State(depositRef, 400.POUNDS, TestUtils.keypair.public) val changeState = Cash.State(depositRef, 400.POUNDS, TestUtils.keypair.public)
val fakeStateRef = ContractStateRef(SecureHash.sha256("fake tx id"), 0) val fakeStateRef = ContractStateRef(SecureHash.sha256("fake tx id"), 0)
lateinit var tx: PartialTransaction lateinit var tx: TransactionBuilder
@Before @Before
fun setup() { fun setup() {
tx = PartialTransaction().withItems( tx = TransactionBuilder().withItems(
fakeStateRef, outputState, changeState, Command(Cash.Commands.Move(), arrayListOf(TestUtils.keypair.public)) fakeStateRef, outputState, changeState, Command(Cash.Commands.Move(), arrayListOf(TestUtils.keypair.public))
) )
} }
@ -75,7 +75,7 @@ class TransactionSerializationTests {
// If the signature was replaced in transit, we don't like it. // If the signature was replaced in transit, we don't like it.
assertFailsWith(SignatureException::class) { assertFailsWith(SignatureException::class) {
val tx2 = PartialTransaction().withItems(fakeStateRef, outputState, changeState, val tx2 = TransactionBuilder().withItems(fakeStateRef, outputState, changeState,
Command(Cash.Commands.Move(), TestUtils.keypair2.public)) Command(Cash.Commands.Move(), TestUtils.keypair2.public))
tx2.signWith(TestUtils.keypair2) tx2.signWith(TestUtils.keypair2)