public class PaymentChannelClient extends java.lang.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.
Modifier and Type | Class and Description |
---|---|
static class |
PaymentChannelClient.DefaultClientChannelProperties |
static class |
PaymentChannelClient.VersionSelector |
IPaymentChannelClient.ClientChannelProperties, IPaymentChannelClient.ClientConnection, IPaymentChannelClient.Factory
Modifier and Type | Field and Description |
---|---|
protected IPaymentChannelClient.ClientChannelProperties |
clientChannelProperties |
static long |
DEFAULT_TIME_WINDOW
The default maximum amount of time for which we will accept the server locking up our funds for the multisig
contract.
|
static PaymentChannelClient.DefaultClientChannelProperties |
defaultChannelProperties |
protected java.util.concurrent.locks.ReentrantLock |
lock |
Constructor and Description |
---|
PaymentChannelClient(Wallet wallet,
ECKey myKey,
Coin maxValue,
Sha256Hash serverId,
IPaymentChannelClient.ClientConnection conn)
Constructs a new channel manager which waits for
connectionOpen() before acting. |
PaymentChannelClient(Wallet wallet,
ECKey myKey,
Coin maxValue,
Sha256Hash serverId,
org.bouncycastle.crypto.params.KeyParameter userKeySetup,
IPaymentChannelClient.ClientChannelProperties clientChannelProperties,
IPaymentChannelClient.ClientConnection conn)
Constructs a new channel manager which waits for
connectionOpen() before acting. |
PaymentChannelClient(Wallet wallet,
ECKey myKey,
Coin maxValue,
Sha256Hash serverId,
org.bouncycastle.crypto.params.KeyParameter userKeySetup,
IPaymentChannelClient.ClientConnection conn)
Constructs a new channel manager which waits for
connectionOpen() before acting. |
Modifier and Type | Method and Description |
---|---|
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.
|
Coin |
getMissing()
Returns the amount of satoshis missing when a server requests too much value.
|
com.google.common.util.concurrent.ListenableFuture<PaymentIncrementAck> |
incrementPayment(Coin size)
Increments the total value which we pay the server.
|
com.google.common.util.concurrent.ListenableFuture<PaymentIncrementAck> |
incrementPayment(Coin size,
com.google.protobuf.ByteString info,
org.bouncycastle.crypto.params.KeyParameter userKey)
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. |
protected final java.util.concurrent.locks.ReentrantLock lock
protected final IPaymentChannelClient.ClientChannelProperties clientChannelProperties
public static final long DEFAULT_TIME_WINDOW
The default maximum amount of time for which we will accept the server locking up our funds for the multisig contract.
24 hours less a minute 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.
public static PaymentChannelClient.DefaultClientChannelProperties defaultChannelProperties
public PaymentChannelClient(Wallet wallet, ECKey myKey, Coin maxValue, Sha256Hash serverId, IPaymentChannelClient.ClientConnection conn)
connectionOpen()
before acting.
A default time window of DEFAULT_TIME_WINDOW
will be used.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)public PaymentChannelClient(Wallet wallet, ECKey myKey, Coin maxValue, Sha256Hash serverId, @Nullable org.bouncycastle.crypto.params.KeyParameter userKeySetup, IPaymentChannelClient.ClientConnection conn)
connectionOpen()
before acting.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.userKeySetup
- Key derived from a user password, used to decrypt myKey, if it is encrypted, during setup.conn
- A callback listener which represents the connection to the server (forwards messages we generate to
the server)public PaymentChannelClient(Wallet wallet, ECKey myKey, Coin maxValue, Sha256Hash serverId, @Nullable org.bouncycastle.crypto.params.KeyParameter userKeySetup, @Nullable IPaymentChannelClient.ClientChannelProperties clientChannelProperties, IPaymentChannelClient.ClientConnection conn)
connectionOpen()
before acting.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.userKeySetup
- Key derived from a user password, used to decrypt myKey, if it is encrypted, during setup.clientChannelProperties
- Modify the channel's properties. You may extend PaymentChannelClient.DefaultClientChannelProperties
conn
- A callback listener which represents the connection to the server (forwards messages we generate to
the server)public Coin 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.
public void receiveMessage(Protos.TwoWayChannelMessage msg) throws InsufficientMoneyException
IPaymentChannelClient
receiveMessage
in interface IPaymentChannelClient
InsufficientMoneyException
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
IPaymentChannelClient.ClientConnection.destroyConnection(PaymentChannelCloseException.CloseReason)
or
settle()
is called, to actually handle the connection close logic.
connectionClosed
in interface IPaymentChannelClient
public void settle() throws java.lang.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
IPaymentChannelClient.ClientConnection.destroyConnection(PaymentChannelCloseException.CloseReason)
to settle the connection, it does not
actually handle connection close logic, and connectionClosed()
must still be called
after the connection fully closes.
settle
in interface IPaymentChannelClient
java.lang.IllegalStateException
- If the connection is not currently open (ie the CLOSE message cannot be sent)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.
connectionOpen
in interface IPaymentChannelClient
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.
public com.google.common.util.concurrent.ListenableFuture<PaymentIncrementAck> incrementPayment(Coin size) throws ValueOutOfRangeException, java.lang.IllegalStateException
size
- How many satoshis to increment the payment by (note: not the new total).ValueOutOfRangeException
- If the size is negative or would pay more than this channel's total value
(PaymentChannelClientConnection.state()
.getTotalValue())java.lang.IllegalStateException
- If the channel has been closed or is not yet open
(see PaymentChannelClientConnection.getChannelOpenFuture()
for the second)public com.google.common.util.concurrent.ListenableFuture<PaymentIncrementAck> incrementPayment(Coin size, @Nullable com.google.protobuf.ByteString info, @Nullable org.bouncycastle.crypto.params.KeyParameter userKey) throws ValueOutOfRangeException, java.lang.IllegalStateException, ECKey.KeyIsEncryptedException
incrementPayment
in interface IPaymentChannelClient
size
- How many satoshis to increment the payment by (note: not the new total).info
- Information about this update, used to extend this protocol.userKey
- Key derived from a user password, needed for any signing when the wallet is encrypted.
The wallet KeyCrypter is assumed.ValueOutOfRangeException
- If the size is negative or would pay more than this channel's total value
(PaymentChannelClientConnection.state()
.getTotalValue())java.lang.IllegalStateException
- If the channel has been closed or is not yet open
(see PaymentChannelClientConnection.getChannelOpenFuture()
for the second)ECKey.KeyIsEncryptedException
- If the keys are encrypted and no AES key has been provided,