org.bitcoinj.protocols.channels.IPaymentChannelClient Maven / Gradle / Ivy
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.protocols.channels;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.InsufficientMoneyException;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.protobuf.ByteString;
import org.bitcoin.paymentchannel.Protos;
import org.bitcoinj.wallet.SendRequest;
import org.spongycastle.crypto.params.KeyParameter;
import javax.annotation.Nullable;
/**
* A class implementing this interface supports the basic operations of a payment channel. An implementation is provided
* in {@link PaymentChannelClient}, but alternative implementations are possible. For example, an implementor might
* send RPCs to a separate (locally installed or even remote) wallet app rather than implementing the algorithm locally.
*/
public interface IPaymentChannelClient {
/**
* Called when a message is received from the server. Processes the given message and generates events based on its
* content.
*/
void receiveMessage(Protos.TwoWayChannelMessage msg) throws InsufficientMoneyException;
/**
* Called when the connection to the server terminates.
*
* 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
* {@link org.bitcoinj.protocols.channels.IPaymentChannelClient.ClientConnection#destroyConnection(org.bitcoinj.protocols.channels.PaymentChannelCloseException.CloseReason)} or
* {@link IPaymentChannelClient#settle()} is called, to actually handle the connection close logic.
*/
void connectionClosed();
/**
* Settles the channel, notifying the server it can broadcast the most recent payment transaction.
*
* Note that this only generates a CLOSE message for the server and calls
* {@link org.bitcoinj.protocols.channels.IPaymentChannelClient.ClientConnection#destroyConnection(org.bitcoinj.protocols.channels.PaymentChannelCloseException.CloseReason)}
* to settle the connection, it does not actually handle connection close logic, and
* {@link PaymentChannelClient#connectionClosed()} must still be called after the connection fully settles.
*
* @throws IllegalStateException If the connection is not currently open (ie the CLOSE message cannot be sent)
*/
void settle() throws IllegalStateException;
/**
* 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.
*/
void connectionOpen();
/**
* 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.
*
* @param size How many satoshis to increment the payment by (note: not the new total).
* @param info Information about this update, used to extend this protocol.
* @throws ValueOutOfRangeException If the size is negative or would pay more than this channel's total value
* ({@link PaymentChannelClientConnection#state()}.getTotalValue())
* @throws IllegalStateException If the channel has been closed or is not yet open
* (see {@link PaymentChannelClientConnection#getChannelOpenFuture()} for the second)
* @throws ECKey.KeyIsEncryptedException If the keys are encrypted and no AES key has been provided,
* @return a future that completes when the server acknowledges receipt and acceptance of the payment.
*/
ListenableFuture incrementPayment(Coin size, @Nullable ByteString info,
@Nullable KeyParameter userKey)
throws ValueOutOfRangeException, IllegalStateException, ECKey.KeyIsEncryptedException;
/**
* Implements the connection between this client and the server, providing an interface which allows messages to be
* sent to the server, requests for the connection to the server to be closed, and a callback which occurs when the
* channel is fully open.
*/
interface ClientConnection {
/**
* Requests that the given message be sent to the server. There are no blocking requirements for this method,
* however the order of messages must be preserved.
*
* If the send fails, no exception should be thrown, however
* {@link org.bitcoinj.protocols.channels.PaymentChannelClient#connectionClosed()} should be called immediately. In the case of messages which
* are a part of initialization, initialization will simply fail and the refund transaction will be broadcasted
* when it unlocks (if necessary). In the case of a payment message, the payment will be lost however if the
* channel is resumed it will begin again from the channel value after the failed payment.
*
* Called while holding a lock on the {@link org.bitcoinj.protocols.channels.PaymentChannelClient} object - be careful about reentrancy
*/
void sendToServer(Protos.TwoWayChannelMessage msg);
/**
* Requests that the connection to the server be closed. For stateless protocols, note that after this call,
* no more messages should be received from the server and this object is no longer usable. A
* {@link org.bitcoinj.protocols.channels.PaymentChannelClient#connectionClosed()} event should be generated immediately after this call.
*
* Called while holding a lock on the {@link org.bitcoinj.protocols.channels.PaymentChannelClient} object - be careful about reentrancy
*
* @param reason The reason for the closure, see the individual values for more details.
* It is usually safe to ignore this and treat any value below
* {@link org.bitcoinj.protocols.channels.PaymentChannelCloseException.CloseReason#CLIENT_REQUESTED_CLOSE} as "unrecoverable error" and all others as
* "try again once and see if it works then"
*/
void destroyConnection(PaymentChannelCloseException.CloseReason reason);
/**
* Queries if the expire time proposed by server is acceptable. If false
is return the channel
* will be closed with a {@link org.bitcoinj.protocols.channels.PaymentChannelCloseException.CloseReason#TIME_WINDOW_UNACCEPTABLE}.
* @param expireTime The time, in seconds, when this channel will be closed by the server. Note this is in absolute time, i.e. seconds since 1970-01-01T00:00:00.
* @return true
if the proposed time is acceptable false
otherwise.
*/
boolean acceptExpireTime(long expireTime);
/**
* Indicates the channel has been successfully opened and
* {@link org.bitcoinj.protocols.channels.PaymentChannelClient#incrementPayment(Coin)}
* may be called at will.
*
* Called while holding a lock on the {@link org.bitcoinj.protocols.channels.PaymentChannelClient}
* object - be careful about reentrancy
*
* @param wasInitiated If true, the channel is newly opened. If false, it was resumed.
*/
void channelOpen(boolean wasInitiated);
}
/**
* Set Client payment channel properties.
*/
interface ClientChannelProperties {
/**
* Modify the sendRequest used for the contract.
* @param sendRequest the current sendRequest.
* @return the modified sendRequest.
*/
SendRequest modifyContractSendRequest(SendRequest sendRequest);
/**
* The maximum acceptable min payment. If the server suggests a higher amount
* the channel creation will be aborted.
*/
Coin acceptableMinPayment();
/**
* The time in seconds, relative to now, on how long this channel should be kept open. Note that is is
* a proposal to the server. The server may in turn propose something different.
* See {@link org.bitcoinj.protocols.channels.IPaymentChannelClient.ClientConnection#acceptExpireTime(long)}
*
*/
long timeWindow();
/**
* An enum indicating which versions to support:
* VERSION_1: use only version 1 of the protocol
* VERSION_2_ALLOW_1: suggest version 2 but allow downgrade to version 1
* VERSION_2: suggest version 2 and enforce use of version 2
*
*/
PaymentChannelClient.VersionSelector versionSelector();
}
/**
* An implementor of this interface creates payment channel clients that "talk back" with the given connection.
* The client might be a PaymentChannelClient, or an RPC interface, or something else entirely.
*/
interface Factory {
IPaymentChannelClient create(String serverPaymentIdentity, ClientConnection connection);
}
}