com.google.bitcoin.protocols.channels
Class PaymentChannelServerState

java.lang.Object
  extended by com.google.bitcoin.protocols.channels.PaymentChannelServerState

public class PaymentChannelServerState
extends Object

A payment channel is a method of sending money to someone such that the amount of money you send can be adjusted after the fact, in an efficient manner that does not require broadcasting to the network. This can be used to implement micropayments or other payment schemes in which immediate settlement is not required, but zero trust negotiation is. Note that this class only allows the amount of money received to be incremented, not decremented.

This class implements the core state machine for the server side of the protocol. The client side is implemented by PaymentChannelClientState and PaymentChannelServerListener implements the server-side network protocol listening for TCP/IP connections and moving this class through each state. We say that the party who is sending funds is the client or initiating party. The party that is receiving the funds is the server or receiving party. Although the underlying Bitcoin protocol is capable of more complex relationships than that, this class implements only the simplest case.

To protect clients from malicious servers, a channel has an expiry parameter. When this expiration is reached, the client will broadcast the created refund transaction and take back all the money in this channel. Because this is specified in terms of block timestamps, it is fairly fuzzy and it is possible to spend the refund transaction up to a few hours before the actual timestamp. Thus, it is very important that the channel be closed with plenty of time left to get the highest value payment transaction confirmed before the expire time (minimum 3-4 hours is suggested if the payment transaction has enough fee to be confirmed in the next block or two).

To begin, we must provide the client with a pubkey which we wish to use for the multi-sig contract which locks in the channel. The client will then provide us with an incomplete refund transaction and the pubkey which they used in the multi-sig contract. We use this pubkey to recreate the multi-sig output and then sign that to the refund transaction. We provide that signature to the client and they then have the ability to spend the refund transaction at the specified expire time. The client then provides us with the full, signed multi-sig contract which we verify and broadcast, locking in their funds until we spend a payment transaction or the expire time is reached. The client can then begin paying by providing us with signatures for the multi-sig contract which pay some amount back to the client, and the rest is ours to do with as we wish.


Nested Class Summary
static class PaymentChannelServerState.State
          The different logical states the channel can be in.
 
Constructor Summary
PaymentChannelServerState(TransactionBroadcaster broadcaster, Wallet wallet, ECKey serverKey, long minExpireTime)
          Creates a new state object to track the server side of a payment channel.
 
Method Summary
 com.google.common.util.concurrent.ListenableFuture<Transaction> close()
          Closes this channel and broadcasts the highest value payment transaction on the network.
 BigInteger getBestValueToMe()
          Gets the highest payment to ourselves (which we will receive on settle(), not including fees)
 BigInteger getFeePaid()
          Gets the fee paid in the final payment transaction (only available if settle() did not throw an exception)
 Transaction getMultisigContract()
          Gets the multisig contract which was used to initialize this channel
 long getRefundTransactionUnlockTime()
          Gets the client's refund transaction which they can spend to get the entire channel value back if it reaches its lock time.
 PaymentChannelServerState.State getState()
          This object implements a state machine, and this accessor returns which state it's currently in.
 boolean incrementPayment(BigInteger refundSize, byte[] signatureBytes)
          Called when the client provides us with a new signature and wishes to increment total payment by size.
 com.google.common.util.concurrent.ListenableFuture<PaymentChannelServerState> provideMultiSigContract(Transaction multisigContract)
          Called when the client provides the multi-sig contract.
 byte[] provideRefundTransaction(Transaction refundTx, byte[] clientMultiSigPubKey)
          Called when the client provides the refund transaction.
 void storeChannelInWallet(PaymentChannelServer connectedHandler)
          Stores this channel's state in the wallet as a part of a StoredPaymentChannelServerStates wallet extension and keeps it up-to-date each time payment is incremented.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

PaymentChannelServerState

public PaymentChannelServerState(TransactionBroadcaster broadcaster,
                                 Wallet wallet,
                                 ECKey serverKey,
                                 long minExpireTime)
Creates a new state object to track the server side of a payment channel.

Parameters:
broadcaster - The peer group which we will broadcast transactions to, this should have multiple peers
wallet - The wallet which will be used to complete transactions
serverKey - The private key which we use for our part of the multi-sig contract (this MUST be fresh and CANNOT be used elsewhere)
minExpireTime - The earliest time at which the client can claim the refund transaction (UNIX timestamp of block)
Method Detail

getState

public PaymentChannelServerState.State getState()
This object implements a state machine, and this accessor returns which state it's currently in.


provideRefundTransaction

public byte[] provideRefundTransaction(Transaction refundTx,
                                       byte[] clientMultiSigPubKey)
                                throws VerificationException
Called when the client provides the refund transaction. The refund transaction must have one input from the multisig contract (that we don't have yet) and one output that the client creates to themselves. This object will later be modified when we start getting paid.

Parameters:
refundTx - The refund transaction, this object will be mutated when payment is incremented.
clientMultiSigPubKey - The client's pubkey which is required for the multisig output
Returns:
Our signature that makes the refund transaction valid
Throws:
VerificationException - If the transaction isnt valid or did not meet the requirements of a refund transaction.

provideMultiSigContract

public com.google.common.util.concurrent.ListenableFuture<PaymentChannelServerState> provideMultiSigContract(Transaction multisigContract)
                                                                                                      throws VerificationException
Called when the client provides the multi-sig contract. Checks that the previously-provided refund transaction spends this transaction (because we will use it as a base to create payment transactions) as well as output value and form (ie it is a 2-of-2 multisig to the correct keys).

Parameters:
multisigContract - The provided multisig contract. Do not mutate this object after this call.
Returns:
A future which completes when the provided multisig contract successfully broadcasts, or throws if the broadcast fails for some reason Note that if the network simply rejects the transaction, this future will never complete, a timeout should be used.
Throws:
VerificationException - If the provided multisig contract is not well-formed or does not meet previously-specified parameters

incrementPayment

public boolean incrementPayment(BigInteger refundSize,
                                byte[] signatureBytes)
                         throws VerificationException,
                                ValueOutOfRangeException,
                                InsufficientMoneyException
Called when the client provides us with a new signature and wishes to increment total payment by size. Verifies the provided signature and only updates values if everything checks out. If the new refundSize is not the lowest we have seen, it is simply ignored.

Parameters:
refundSize - How many satoshis of the original contract are refunded to the client (the rest are ours)
signatureBytes - The new signature spending the multi-sig contract to a new payment transaction
Returns:
true if there is more value left on the channel, false if it is now fully used up.
Throws:
VerificationException - If the signature does not verify or size is out of range (incl being rejected by the network as dust).
ValueOutOfRangeException
InsufficientMoneyException

close

public com.google.common.util.concurrent.ListenableFuture<Transaction> close()
                                                                      throws InsufficientMoneyException

Closes this channel and broadcasts the highest value payment transaction on the network.

This will set the state to PaymentChannelServerState.State.CLOSED if the transaction is successfully broadcast on the network. If we fail to broadcast for some reason, the state is set to PaymentChannelServerState.State.ERROR.

If the current state is before PaymentChannelServerState.State.READY (ie we have not finished initializing the channel), we simply set the state to PaymentChannelServerState.State.CLOSED and let the client handle getting its refund transaction confirmed.

Returns:
a future which completes when the provided multisig contract successfully broadcasts, or throws if the broadcast fails for some reason. Note that if the network simply rejects the transaction, this future will never complete, a timeout should be used.
Throws:
InsufficientMoneyException - If the payment tx would have cost more in fees to spend than it is worth.

getBestValueToMe

public BigInteger getBestValueToMe()
Gets the highest payment to ourselves (which we will receive on settle(), not including fees)


getFeePaid

public BigInteger getFeePaid()
Gets the fee paid in the final payment transaction (only available if settle() did not throw an exception)


getMultisigContract

public Transaction getMultisigContract()
Gets the multisig contract which was used to initialize this channel


getRefundTransactionUnlockTime

public long getRefundTransactionUnlockTime()
Gets the client's refund transaction which they can spend to get the entire channel value back if it reaches its lock time.


storeChannelInWallet

public void storeChannelInWallet(@Nullable
                                 PaymentChannelServer connectedHandler)
Stores this channel's state in the wallet as a part of a StoredPaymentChannelServerStates wallet extension and keeps it up-to-date each time payment is incremented. This will be automatically removed when a call to close() completes successfully. A channel may only be stored after it has fully opened (ie state == State.READY).

Parameters:
connectedHandler - Optional PaymentChannelServer object that manages this object. This will set the appropriate pointer in the newly created StoredServerChannel before it is committed to wallet. If set, closing the state object will propagate the close to the handler which can then do a TCP disconnect.


Copyright © 2014. All rights reserved.