Transaction Construction Algorithm (voting pools)

From Open Transactions
Revision as of 15:23, 22 September 2014 by Justusranvier (talk | contribs) (Finalize Transaction: add description of this step.)
Jump to navigation Jump to search

Introduction

In order to avoid an expensive and error-prone consensus process, it is mandatory for wallets to be able to construct withdrawal transactions in a deterministic manner, assuming they are given the withdrawal requests in a deterministic order. Once this is accomplished, then it only becomes necessary for wallets to share signatures among themselves because they know they all signed the exact same bitcoin transaction.

Procedure

Overview

Transaction Construction Algorithm - Overview.png

Initial Conditions

The startwithdrawal API call has been received by the wallet, and all the arguments have been checked for errors.

Sequence

The basic flow of the procedure is:

  1. Gather accounting information from the API call arguments
  2. Validate and sort the output list
  3. Start a new transactions
  4. Add outputs to the transaction until either all outputs are added or all inputs are used.
  5. Make sure all generated transactions are ready for signing.
  6. Create a list of all signatures which the wallet is capable of generating.
  7. Create a status list containing the deposition of every output the caller specified.
  8. Return the status list and signature list to the caller.

Each step in this chart is more fully described below.


Preparation

Transaction Construction Algorithm - Preparation.png

Initial Conditions

The startwithdrawal API call has been received by the wallet, and all the arguments have been checked for errors.

Sequence

  1. The algorithm must keep track of the next change address to be used. The initial value is supplied as the changestart argument. Any time a change output is allocated, the index value of the address identifier is incremented, and if a change output is remove from a transaction the index value is decremented. The final value will be returned to the caller as the nextchangestart value in the withdrawal status list.
  2. Prepare an empty list for holding transactions as they are constructed and before they are signed.
  3. Prepare an empty array to hold the transaction signatures which will be returned to the caller as the signatures value.
  4. Prepare an withdrawal status object.
    1. roundID: copied from roundID argument
    2. nextinputstart: nil
    3. nextchangestart: nil
    4. fees: 0
    5. outputs: should contain an entry for every output passed:
      1. outBailmentID: copied from outBailmentID entry in outputs argument
      2. status: empty string
      3. transactions: nil

Output List Initialization

Transaction Construction Algorithm - Output List Initialization.png

Initial Conditions

The startwithdrawal API call has been received by the wallet, and all the arguments have been checked for errors.

Sequence

  1. Pass the inputstart, inputstop, and dustthreshold parameters to the input selection algorithm to obtain an ordered list of eligible inputs.
  2. Perform a first pass check to determine if the requested outputs exceed the size of the eligible inputs. Note that this check is only definitive in the case where the output sum is greater than the input sum. At this stage of the algorithm, the input sum exceeding the output sum does not prove that all outputs will be successfully created.
    1. Take the sum of both lists.
    2. If the sum of the outputs exceeds the sum of the inputs, remove outputs in descending size order until this is no longer true. Note this may result in the output list being an empty set.
  3. If the output list is non-empty, sort it by outBailmentID
  4. Move both the input lists and outputs lists into separate stacks by pushing them in reverse list order. The first input and first output should be on the top of their respective stacks.

Initialize New Transaction

Transaction Construction Algorithm - Initialize New Transaction.png

Initial Conditions

There are no pending transactions to in the process of being constructed, either because this is the first transaction of the algorithm or because a previous pending transaction has been moved to the finished transaction list.

The input stack contains at least one input.

The output stack contains at least one output.

Sequence

  1. Create a minimal transaction skeleton with a header and one change output.
    1. The change output will be the last output of the transaction, but the number of other outputs in this transaction is not yet known.
    2. The change output must be included in the skeleton for transaction size calculations.
    3. The position index for the change output is nil.
    4. The first non-change output for the transaction will be placed at position index 0.

After creating the transaction skeleton, and after any action which alters it, the new transaction size (bytes) and minimum required transaction fee must be recalculated.


Add Next Output

Transaction Construction Algorithm - Add Next Output.png

Initial Conditions

The output stack contains at least one output.

There is a transaction in progress which is ready to accept new outputs. This transaction is either empty or it contains 1 or more outputs.

If the transaction already contains outputs, then it also contains sufficient inputs to cover those outputs and any required transaction fees without exceeding size limits. This is because it must have already successfully passed through this procedure before.

Sequence

  1. Locate the entry for this output in the withdrawal status object by finding the corresponding outBailmentID.
  2. Validate the output address.
    1. If it is invalid, update status entry for this output to "invalid" and exit from this procedure.
    2. If it is valid, add it to the transaction.
      1. Add a new entry to the transaction array for this output:
        • nxid: nil
        • index: next unused
        • amount: copied from outputs list.
  3. Check that the transaction does not exceed size limits. If it does, follow the Oversize Transaction procedure.
  4. Compare the sum of the inputs to the sum of the inputs and required transaction fee to determine if more inputs are required.
    1. If no more inputs are required, then update the status for this output to "success".
  5. If more inputs are required, then check to see if any more are available.
    1. According to the initial conditions, the input stack can not be empty on the first run through this loop.
    2. If the input stack is empty at this point, then the output has added at least one input beyond what was needed to satisfy the prior output (if there was a prior output)
    3. If the input stack is empty, then the output can only be partially fulfilled. Follow the Split Output procedure.
  6. Add the next input from the stack, and continue the loop at step 2.

The loop will continue until either:

  • The transaction contains sufficient input value to satisfy the output plus transaction fees
  • The transaction exceeds size limits
  • There is not enough input value, but no more inputs are available

Finalize Transaction

Transaction Construction Algorithm - Finalize Transaction.png

Initial Conditions

  • An unfinished transaction is ready for processing.
    • The transaction may or may not have have a useful (non-change) output
    • The transaction is valid
      • Not too big
      • Inputs are sufficient to cover outputs and required fees
    • A change output may exist in the transaction
      • If a change output exists, it is located in position 0 and has a nil value.

Sequence

  1. If the transaction only contains a change output and no inputs, then it may be discarded.
  2. The change amount is calculated by: Σ(txin) - ( Σ(txout) + fees )
    1. If the change amount is greater than zero:
      1. Set the value of the output
      2. Set the position of the output to the next unused value after the last non-change output.
    2. If the change amount is zero, then the change output is removed from the transaction.
  3. Calculate an ntxid for the transaction for tracking purposes.
  4. Loop through every (non-change) output in the transaction and update the withdrawal status object for the corresponding output.
    1. The withdrawal status object contain an entry for every output in the transaction, where each entry has an transactions object containing a nil ntxid, an index matching the output position index, and a matching amount.
    2. Update the nxid value from nil to the ntxid for the transaction.
  5. Add the fees from this transaction to the fees property of the withdrawal status object.
  6. Move the transaction to the finished transaction list.

Update Signatures

Transaction Construction Algorithm - Update Signatures.png

Update Status

Transaction Construction Algorithm - Update Status.png

Oversize Transaction

Transaction Construction Algorithm - Oversize Transaction.png

Rollback Last Output

Transaction Construction Algorithm - Rollback Last Output.png

Split Output

Transaction Construction Algorithm - Split Output.png

Insufficient Inputs

Transaction Construction Algorithm - Insufficient Inputs.png