com.google.bitcoin.protocols.channels
Class PaymentChannelClient

java.lang.Object
  extended by com.google.bitcoin.protocols.channels.PaymentChannelClient
All Implemented Interfaces:
IPaymentChannelClient

public class PaymentChannelClient
extends Object
implements IPaymentChannelClient

A class which handles most of the complexity of creating a payment channel connection by providing a simple in/out interface which is provided with protobufs from the server and which generates protobufs which should be sent to the server.

Does all required verification of server messages and properly stores state objects in the wallet-attached StoredPaymentChannelClientStates so that they are automatically closed when necessary and refund transactions are not lost if the application crashes before it unlocks.

Though this interface is largely designed with stateful protocols (eg simple TCP connections) in mind, it is also possible to use it with stateless protocols (eg sending protobufs when required over HTTP headers). In this case, the "connection" translates roughly into the server-client relationship. See the javadocs for specific functions for more details.


Nested Class Summary
 
Nested classes/interfaces inherited from interface com.google.bitcoin.protocols.channels.IPaymentChannelClient
IPaymentChannelClient.ClientConnection, IPaymentChannelClient.Factory
 
Field Summary
protected  ReentrantLock lock
           
 long MAX_TIME_WINDOW
          The maximum amount of time for which we will accept the server locking up our funds for the multisig contract.
 
Constructor Summary
PaymentChannelClient(Wallet wallet, ECKey myKey, BigInteger maxValue, Sha256Hash serverId, IPaymentChannelClient.ClientConnection conn)
          Constructs a new channel manager which waits for connectionOpen() before acting.
 
Method Summary
 void connectionClosed()
          Called when the connection terminates.
 void connectionOpen()
          Called to indicate the connection has been opened and messages can now be generated for the server.
 BigInteger getMissing()
          Returns the amount of satoshis missing when a server requests too much value.
 com.google.common.util.concurrent.ListenableFuture<BigInteger> incrementPayment(BigInteger size)
          Increments the total value which we pay the server.
 void receiveMessage(Protos.TwoWayChannelMessage msg)
          Called when a message is received from the server.
 void settle()
          Closes the connection, notifying the server it should settle the channel by broadcasting the most recent payment transaction.
 PaymentChannelClientState state()
          Gets the PaymentChannelClientState object which stores the current state of the connection with the server.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

lock

protected final ReentrantLock lock

MAX_TIME_WINDOW

public long MAX_TIME_WINDOW

The maximum amount of time for which we will accept the server locking up our funds for the multisig contract.

Note that though this is not final, it is in all caps because it should generally not be modified unless you have some guarantee that the server will not request at least this (channels will fail if this is too small).

24 hours is the default as it is expected that clients limit risk exposure by limiting channel size instead of limiting lock time when dealing with potentially malicious servers.

Constructor Detail

PaymentChannelClient

public PaymentChannelClient(Wallet wallet,
                            ECKey myKey,
                            BigInteger maxValue,
                            Sha256Hash serverId,
                            IPaymentChannelClient.ClientConnection conn)
Constructs a new channel manager which waits for connectionOpen() before acting.

Parameters:
wallet - The wallet which will be paid from, and where completed transactions will be committed. Must already have a StoredPaymentChannelClientStates object in its extensions set.
myKey - A freshly generated keypair used for the multisig contract and refund output.
maxValue - The maximum value the server is allowed to request that we lock into this channel until the refund transaction unlocks. Note that if there is a previously open channel, the refund transaction used in this channel may be larger than maxValue. Thus, maxValue is not a method for limiting the amount payable through this channel.
serverId - An arbitrary hash representing this channel. This must uniquely identify the server. If an existing stored channel exists in the wallet's StoredPaymentChannelClientStates, then an attempt will be made to resume that channel.
conn - A callback listener which represents the connection to the server (forwards messages we generate to the server)
Method Detail

getMissing

public BigInteger getMissing()

Returns the amount of satoshis missing when a server requests too much value.

When InsufficientMoneyException is thrown due to the server requesting too much value, an instance of PaymentChannelClient needs access to how many satoshis are missing.


receiveMessage

public void receiveMessage(Protos.TwoWayChannelMessage msg)
                    throws InsufficientMoneyException
Called when a message is received from the server. Processes the given message and generates events based on its content.

Specified by:
receiveMessage in interface IPaymentChannelClient
Throws:
InsufficientMoneyException

connectionClosed

public void connectionClosed()

Called when the connection terminates. Notifies the StoredClientChannel object that we can attempt to resume this channel in the future and stops generating messages for the server.

For stateless protocols, this translates to a client not using the channel for the immediate future, but intending to reopen the channel later. There is likely little reason to use this in a stateless protocol.

Note that this MUST still be called even after either ClientConnection#destroyConnection(com.google.bitcoin.protocols.channels.PaymentChannelCloseException.CloseReason) or settle() is called, to actually handle the connection close logic.

Specified by:
connectionClosed in interface IPaymentChannelClient

settle

public void settle()
            throws IllegalStateException

Closes the connection, notifying the server it should settle the channel by broadcasting the most recent payment transaction.

Note that this only generates a CLOSE message for the server and calls ClientConnection#destroyConnection(CloseReason) to settle the connection, it does not actually handle connection close logic, and connectionClosed() must still be called after the connection fully closes.

Specified by:
settle in interface IPaymentChannelClient
Throws:
IllegalStateException - If the connection is not currently open (ie the CLOSE message cannot be sent)

connectionOpen

public void connectionOpen()

Called to indicate the connection has been opened and messages can now be generated for the server.

Attempts to find a channel to resume and generates a CLIENT_VERSION message for the server based on the result.

Specified by:
connectionOpen in interface IPaymentChannelClient

state

public PaymentChannelClientState state()

Gets the PaymentChannelClientState object which stores the current state of the connection with the server.

Note that if you call any methods which update state directly the server will not be notified and channel initialization logic in the connection may fail unexpectedly.


incrementPayment

public com.google.common.util.concurrent.ListenableFuture<BigInteger> incrementPayment(BigInteger size)
                                                                                throws ValueOutOfRangeException,
                                                                                       IllegalStateException
Increments the total value which we pay the server. Note that the amount of money sent may not be the same as the amount of money actually requested. It can be larger if the amount left over in the channel would be too small to be accepted by the Bitcoin network. ValueOutOfRangeException will be thrown, however, if there's not enough money left in the channel to make the payment at all. Only one payment can be in-flight at once. You have to ensure you wait for the previous increase payment future to complete before incrementing the payment again.

Specified by:
incrementPayment in interface IPaymentChannelClient
Parameters:
size - How many satoshis to increment the payment by (note: not the new total).
Returns:
a future that completes when the server acknowledges receipt and acceptance of the payment.
Throws:
ValueOutOfRangeException - If the size is negative or would pay more than this channel's total value (PaymentChannelClientConnection.state().getTotalValue())
IllegalStateException - If the channel has been closed or is not yet open (see PaymentChannelClientConnection.getChannelOpenFuture() for the second)


Copyright © 2014. All rights reserved.