diff --git a/core/src/main/java/com/google/bitcoin/jni/NativePaymentChannelServerConnectionEventHandler.java b/core/src/main/java/com/google/bitcoin/jni/NativePaymentChannelServerConnectionEventHandler.java index 9bbf321b..bb54634f 100644 --- a/core/src/main/java/com/google/bitcoin/jni/NativePaymentChannelServerConnectionEventHandler.java +++ b/core/src/main/java/com/google/bitcoin/jni/NativePaymentChannelServerConnectionEventHandler.java @@ -17,7 +17,7 @@ public class NativePaymentChannelServerConnectionEventHandler extends ServerConn public native void channelOpen(Sha256Hash channelId); @Override - public native void paymentIncrease(Coin by, Coin to, ByteString info); + public native ByteString paymentIncrease(Coin by, Coin to, ByteString info); @Override public native void channelClosed(PaymentChannelCloseException.CloseReason reason); diff --git a/core/src/main/java/com/google/bitcoin/protocols/channels/IPaymentChannelClient.java b/core/src/main/java/com/google/bitcoin/protocols/channels/IPaymentChannelClient.java index c648ad56..7932ca54 100644 --- a/core/src/main/java/com/google/bitcoin/protocols/channels/IPaymentChannelClient.java +++ b/core/src/main/java/com/google/bitcoin/protocols/channels/IPaymentChannelClient.java @@ -84,7 +84,7 @@ public interface IPaymentChannelClient { * (see {@link PaymentChannelClientConnection#getChannelOpenFuture()} for the second) * @return a future that completes when the server acknowledges receipt and acceptance of the payment. */ - ListenableFuture incrementPayment(Coin size, @Nullable ByteString info) throws ValueOutOfRangeException, IllegalStateException; + ListenableFuture incrementPayment(Coin size, @Nullable ByteString info) throws ValueOutOfRangeException, IllegalStateException; /** * Implements the connection between this client and the server, providing an interface which allows messages to be diff --git a/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelClient.java b/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelClient.java index cba2946e..83db22a8 100644 --- a/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelClient.java +++ b/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelClient.java @@ -90,7 +90,7 @@ public class PaymentChannelClient implements IPaymentChannelClient { @GuardedBy("lock") private long minPayment; - @GuardedBy("lock") SettableFuture increasePaymentFuture; + @GuardedBy("lock") SettableFuture increasePaymentFuture; @GuardedBy("lock") Coin lastPaymentActualAmount; /** @@ -290,7 +290,7 @@ public class PaymentChannelClient implements IPaymentChannelClient { receiveChannelOpen(); return; case PAYMENT_ACK: - receivePaymentAck(); + receivePaymentAck(msg.getPaymentAck()); return; case CLOSE: receiveClose(msg); @@ -462,13 +462,13 @@ public class PaymentChannelClient implements IPaymentChannelClient { * 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). + * @return 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 * ({@link PaymentChannelClientConnection#state()}.getTotalValue()) * @throws IllegalStateException If the channel has been closed or is not yet open * (see {@link PaymentChannelClientConnection#getChannelOpenFuture()} for the second) - * @return a future that completes when the server acknowledges receipt and acceptance of the payment. */ - public ListenableFuture incrementPayment(Coin size) throws ValueOutOfRangeException, IllegalStateException { + public ListenableFuture incrementPayment(Coin size) throws ValueOutOfRangeException, IllegalStateException { return incrementPayment(size, null); } @@ -481,14 +481,14 @@ public class PaymentChannelClient implements IPaymentChannelClient { * * @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. + * @return 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 * ({@link PaymentChannelClientConnection#state()}.getTotalValue()) * @throws IllegalStateException If the channel has been closed or is not yet open * (see {@link PaymentChannelClientConnection#getChannelOpenFuture()} for the second) - * @return a future that completes when the server acknowledges receipt and acceptance of the payment. */ @Override - public ListenableFuture incrementPayment(Coin size, @Nullable ByteString info) throws ValueOutOfRangeException, IllegalStateException { + public ListenableFuture incrementPayment(Coin size, @Nullable ByteString info) throws ValueOutOfRangeException, IllegalStateException { lock.lock(); try { if (state() == null || !connectionOpen || step != InitStep.CHANNEL_OPEN) @@ -523,8 +523,8 @@ public class PaymentChannelClient implements IPaymentChannelClient { } } - private void receivePaymentAck() { - SettableFuture future; + private void receivePaymentAck(Protos.PaymentAck paymentAck) { + SettableFuture future; Coin value; lock.lock(); @@ -539,6 +539,6 @@ public class PaymentChannelClient implements IPaymentChannelClient { } // Ensure the future runs without the client lock held. - future.set(value); + future.set(new PaymentIncrementAck(value, paymentAck.getInfo())); } } diff --git a/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelClientConnection.java b/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelClientConnection.java index 610b4da7..35df1b01 100644 --- a/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelClientConnection.java +++ b/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelClientConnection.java @@ -136,7 +136,7 @@ public class PaymentChannelClientConnection { * @throws IllegalStateException If the channel has been closed or is not yet open * (see {@link PaymentChannelClientConnection#getChannelOpenFuture()} for the second) */ - public ListenableFuture incrementPayment(Coin size) throws ValueOutOfRangeException, IllegalStateException { + public ListenableFuture incrementPayment(Coin size) throws ValueOutOfRangeException, IllegalStateException { return channelClient.incrementPayment(size, null); } /** @@ -149,7 +149,7 @@ public class PaymentChannelClientConnection { * @throws IllegalStateException If the channel has been closed or is not yet open * (see {@link PaymentChannelClientConnection#getChannelOpenFuture()} for the second) */ - public ListenableFuture incrementPayment(Coin size, ByteString info) throws ValueOutOfRangeException, IllegalStateException { + public ListenableFuture incrementPayment(Coin size, ByteString info) throws ValueOutOfRangeException, IllegalStateException { return channelClient.incrementPayment(size, info); } diff --git a/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelServer.java b/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelServer.java index 930329c9..11683d19 100644 --- a/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelServer.java +++ b/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelServer.java @@ -101,8 +101,10 @@ public class PaymentChannelServer { * @param by The increase in total payment * @param to The new total payment to us (not including fees which may be required to claim the payment) * @param info Information about this payment increase, used to extend this protocol. + * @return An ack message that will be included in the PaymentAck message to the client. Use null for no ack message. */ - public void paymentIncrease(Coin by, Coin to, @Nullable ByteString info); + @Nullable + public ByteString paymentIncrease(Coin by, Coin to, @Nullable ByteString info); } private final ServerConnection conn; @@ -315,14 +317,16 @@ public class PaymentChannelServer { boolean stillUsable = state.incrementPayment(refundSize, msg.getSignature().toByteArray()); Coin bestPaymentChange = state.getBestValueToMe().subtract(lastBestPayment); + ByteString ackInfo = null; if (bestPaymentChange.signum() > 0) { ByteString info = (msg.hasInfo()) ? msg.getInfo() : null; - conn.paymentIncrease(bestPaymentChange, state.getBestValueToMe(), info); + ackInfo = conn.paymentIncrease(bestPaymentChange, state.getBestValueToMe(), info); } if (sendAck) { Protos.TwoWayChannelMessage.Builder ack = Protos.TwoWayChannelMessage.newBuilder(); ack.setType(Protos.TwoWayChannelMessage.MessageType.PAYMENT_ACK); + if (ackInfo != null) ack.setPaymentAck(ack.getPaymentAckBuilder().setInfo(ackInfo)); conn.sendToClient(ack.build()); } diff --git a/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelServerListener.java b/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelServerListener.java index 7256273c..d2960783 100644 --- a/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelServerListener.java +++ b/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentChannelServerListener.java @@ -83,8 +83,8 @@ public class PaymentChannelServerListener { eventHandler.channelOpen(contractHash); } - @Override public void paymentIncrease(Coin by, Coin to, @Nullable ByteString info) { - eventHandler.paymentIncrease(by, to, info); + @Override public ByteString paymentIncrease(Coin by, Coin to, @Nullable ByteString info) { + return eventHandler.paymentIncrease(by, to, info); } }); diff --git a/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentIncrementAck.java b/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentIncrementAck.java new file mode 100644 index 00000000..171f93b4 --- /dev/null +++ b/core/src/main/java/com/google/bitcoin/protocols/channels/PaymentIncrementAck.java @@ -0,0 +1,28 @@ +package com.google.bitcoin.protocols.channels; + +import com.google.bitcoin.core.Coin; +import com.google.protobuf.ByteString; + +import javax.annotation.Nullable; + +/** + * An acknowledgement of a payment increase + */ +public class PaymentIncrementAck { + private final Coin value; + @Nullable private final ByteString info; + + public PaymentIncrementAck(Coin value, @Nullable ByteString info) { + this.value = value; + this.info = info; + } + + public Coin getValue() { + return value; + } + + @Nullable + public ByteString getInfo() { + return info; + } +} diff --git a/core/src/main/java/com/google/bitcoin/protocols/channels/ServerConnectionEventHandler.java b/core/src/main/java/com/google/bitcoin/protocols/channels/ServerConnectionEventHandler.java index 327457be..402920a0 100644 --- a/core/src/main/java/com/google/bitcoin/protocols/channels/ServerConnectionEventHandler.java +++ b/core/src/main/java/com/google/bitcoin/protocols/channels/ServerConnectionEventHandler.java @@ -71,8 +71,10 @@ public abstract class ServerConnectionEventHandler { * @param by The increase in total payment * @param to The new total payment to us (not including fees which may be required to claim the payment) * @param info Information about this payment increase, used to extend this protocol. + * @return acknowledgment information to be sent to the client. */ - public abstract void paymentIncrease(Coin by, Coin to, ByteString info); + @Nullable + public abstract ByteString paymentIncrease(Coin by, Coin to, ByteString info); /** *

Called when the channel was closed for some reason. May be called without a call to diff --git a/core/src/main/java/org/bitcoin/paymentchannel/Protos.java b/core/src/main/java/org/bitcoin/paymentchannel/Protos.java index 4b3cdbb1..22de5d72 100644 --- a/core/src/main/java/org/bitcoin/paymentchannel/Protos.java +++ b/core/src/main/java/org/bitcoin/paymentchannel/Protos.java @@ -143,6 +143,20 @@ public final class Protos { */ org.bitcoin.paymentchannel.Protos.UpdatePaymentOrBuilder getUpdatePaymentOrBuilder(); + // optional .paymentchannels.PaymentAck payment_ack = 11; + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + boolean hasPaymentAck(); + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + org.bitcoin.paymentchannel.Protos.PaymentAck getPaymentAck(); + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + org.bitcoin.paymentchannel.Protos.PaymentAckOrBuilder getPaymentAckOrBuilder(); + // optional .paymentchannels.Settlement settlement = 9; /** * optional .paymentchannels.Settlement settlement = 9; @@ -332,7 +346,7 @@ public final class Protos { } case 74: { org.bitcoin.paymentchannel.Protos.Settlement.Builder subBuilder = null; - if (((bitField0_ & 0x00000100) == 0x00000100)) { + if (((bitField0_ & 0x00000200) == 0x00000200)) { subBuilder = settlement_.toBuilder(); } settlement_ = input.readMessage(org.bitcoin.paymentchannel.Protos.Settlement.PARSER, extensionRegistry); @@ -340,12 +354,12 @@ public final class Protos { subBuilder.mergeFrom(settlement_); settlement_ = subBuilder.buildPartial(); } - bitField0_ |= 0x00000100; + bitField0_ |= 0x00000200; break; } case 82: { org.bitcoin.paymentchannel.Protos.Error.Builder subBuilder = null; - if (((bitField0_ & 0x00000200) == 0x00000200)) { + if (((bitField0_ & 0x00000400) == 0x00000400)) { subBuilder = error_.toBuilder(); } error_ = input.readMessage(org.bitcoin.paymentchannel.Protos.Error.PARSER, extensionRegistry); @@ -353,7 +367,20 @@ public final class Protos { subBuilder.mergeFrom(error_); error_ = subBuilder.buildPartial(); } - bitField0_ |= 0x00000200; + bitField0_ |= 0x00000400; + break; + } + case 90: { + org.bitcoin.paymentchannel.Protos.PaymentAck.Builder subBuilder = null; + if (((bitField0_ & 0x00000100) == 0x00000100)) { + subBuilder = paymentAck_.toBuilder(); + } + paymentAck_ = input.readMessage(org.bitcoin.paymentchannel.Protos.PaymentAck.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(paymentAck_); + paymentAck_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000100; break; } } @@ -825,6 +852,28 @@ public final class Protos { return updatePayment_; } + // optional .paymentchannels.PaymentAck payment_ack = 11; + public static final int PAYMENT_ACK_FIELD_NUMBER = 11; + private org.bitcoin.paymentchannel.Protos.PaymentAck paymentAck_; + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + public boolean hasPaymentAck() { + return ((bitField0_ & 0x00000100) == 0x00000100); + } + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + public org.bitcoin.paymentchannel.Protos.PaymentAck getPaymentAck() { + return paymentAck_; + } + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + public org.bitcoin.paymentchannel.Protos.PaymentAckOrBuilder getPaymentAckOrBuilder() { + return paymentAck_; + } + // optional .paymentchannels.Settlement settlement = 9; public static final int SETTLEMENT_FIELD_NUMBER = 9; private org.bitcoin.paymentchannel.Protos.Settlement settlement_; @@ -832,7 +881,7 @@ public final class Protos { * optional .paymentchannels.Settlement settlement = 9; */ public boolean hasSettlement() { - return ((bitField0_ & 0x00000100) == 0x00000100); + return ((bitField0_ & 0x00000200) == 0x00000200); } /** * optional .paymentchannels.Settlement settlement = 9; @@ -854,7 +903,7 @@ public final class Protos { * optional .paymentchannels.Error error = 10; */ public boolean hasError() { - return ((bitField0_ & 0x00000200) == 0x00000200); + return ((bitField0_ & 0x00000400) == 0x00000400); } /** * optional .paymentchannels.Error error = 10; @@ -878,6 +927,7 @@ public final class Protos { returnRefund_ = org.bitcoin.paymentchannel.Protos.ReturnRefund.getDefaultInstance(); provideContract_ = org.bitcoin.paymentchannel.Protos.ProvideContract.getDefaultInstance(); updatePayment_ = org.bitcoin.paymentchannel.Protos.UpdatePayment.getDefaultInstance(); + paymentAck_ = org.bitcoin.paymentchannel.Protos.PaymentAck.getDefaultInstance(); settlement_ = org.bitcoin.paymentchannel.Protos.Settlement.getDefaultInstance(); error_ = org.bitcoin.paymentchannel.Protos.Error.getDefaultInstance(); } @@ -969,12 +1019,15 @@ public final class Protos { if (((bitField0_ & 0x00000080) == 0x00000080)) { output.writeMessage(8, updatePayment_); } - if (((bitField0_ & 0x00000100) == 0x00000100)) { + if (((bitField0_ & 0x00000200) == 0x00000200)) { output.writeMessage(9, settlement_); } - if (((bitField0_ & 0x00000200) == 0x00000200)) { + if (((bitField0_ & 0x00000400) == 0x00000400)) { output.writeMessage(10, error_); } + if (((bitField0_ & 0x00000100) == 0x00000100)) { + output.writeMessage(11, paymentAck_); + } getUnknownFields().writeTo(output); } @@ -1016,14 +1069,18 @@ public final class Protos { size += com.google.protobuf.CodedOutputStream .computeMessageSize(8, updatePayment_); } - if (((bitField0_ & 0x00000100) == 0x00000100)) { + if (((bitField0_ & 0x00000200) == 0x00000200)) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(9, settlement_); } - if (((bitField0_ & 0x00000200) == 0x00000200)) { + if (((bitField0_ & 0x00000400) == 0x00000400)) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(10, error_); } + if (((bitField0_ & 0x00000100) == 0x00000100)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(11, paymentAck_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -1145,6 +1202,7 @@ public final class Protos { getReturnRefundFieldBuilder(); getProvideContractFieldBuilder(); getUpdatePaymentFieldBuilder(); + getPaymentAckFieldBuilder(); getSettlementFieldBuilder(); getErrorFieldBuilder(); } @@ -1199,18 +1257,24 @@ public final class Protos { updatePaymentBuilder_.clear(); } bitField0_ = (bitField0_ & ~0x00000080); + if (paymentAckBuilder_ == null) { + paymentAck_ = org.bitcoin.paymentchannel.Protos.PaymentAck.getDefaultInstance(); + } else { + paymentAckBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000100); if (settlementBuilder_ == null) { settlement_ = org.bitcoin.paymentchannel.Protos.Settlement.getDefaultInstance(); } else { settlementBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000100); + bitField0_ = (bitField0_ & ~0x00000200); if (errorBuilder_ == null) { error_ = org.bitcoin.paymentchannel.Protos.Error.getDefaultInstance(); } else { errorBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000200); + bitField0_ = (bitField0_ & ~0x00000400); return this; } @@ -1302,13 +1366,21 @@ public final class Protos { if (((from_bitField0_ & 0x00000100) == 0x00000100)) { to_bitField0_ |= 0x00000100; } + if (paymentAckBuilder_ == null) { + result.paymentAck_ = paymentAck_; + } else { + result.paymentAck_ = paymentAckBuilder_.build(); + } + if (((from_bitField0_ & 0x00000200) == 0x00000200)) { + to_bitField0_ |= 0x00000200; + } if (settlementBuilder_ == null) { result.settlement_ = settlement_; } else { result.settlement_ = settlementBuilder_.build(); } - if (((from_bitField0_ & 0x00000200) == 0x00000200)) { - to_bitField0_ |= 0x00000200; + if (((from_bitField0_ & 0x00000400) == 0x00000400)) { + to_bitField0_ |= 0x00000400; } if (errorBuilder_ == null) { result.error_ = error_; @@ -1355,6 +1427,9 @@ public final class Protos { if (other.hasUpdatePayment()) { mergeUpdatePayment(other.getUpdatePayment()); } + if (other.hasPaymentAck()) { + mergePaymentAck(other.getPaymentAck()); + } if (other.hasSettlement()) { mergeSettlement(other.getSettlement()); } @@ -2355,6 +2430,123 @@ public final class Protos { return updatePaymentBuilder_; } + // optional .paymentchannels.PaymentAck payment_ack = 11; + private org.bitcoin.paymentchannel.Protos.PaymentAck paymentAck_ = org.bitcoin.paymentchannel.Protos.PaymentAck.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + org.bitcoin.paymentchannel.Protos.PaymentAck, org.bitcoin.paymentchannel.Protos.PaymentAck.Builder, org.bitcoin.paymentchannel.Protos.PaymentAckOrBuilder> paymentAckBuilder_; + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + public boolean hasPaymentAck() { + return ((bitField0_ & 0x00000100) == 0x00000100); + } + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + public org.bitcoin.paymentchannel.Protos.PaymentAck getPaymentAck() { + if (paymentAckBuilder_ == null) { + return paymentAck_; + } else { + return paymentAckBuilder_.getMessage(); + } + } + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + public Builder setPaymentAck(org.bitcoin.paymentchannel.Protos.PaymentAck value) { + if (paymentAckBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + paymentAck_ = value; + onChanged(); + } else { + paymentAckBuilder_.setMessage(value); + } + bitField0_ |= 0x00000100; + return this; + } + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + public Builder setPaymentAck( + org.bitcoin.paymentchannel.Protos.PaymentAck.Builder builderForValue) { + if (paymentAckBuilder_ == null) { + paymentAck_ = builderForValue.build(); + onChanged(); + } else { + paymentAckBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000100; + return this; + } + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + public Builder mergePaymentAck(org.bitcoin.paymentchannel.Protos.PaymentAck value) { + if (paymentAckBuilder_ == null) { + if (((bitField0_ & 0x00000100) == 0x00000100) && + paymentAck_ != org.bitcoin.paymentchannel.Protos.PaymentAck.getDefaultInstance()) { + paymentAck_ = + org.bitcoin.paymentchannel.Protos.PaymentAck.newBuilder(paymentAck_).mergeFrom(value).buildPartial(); + } else { + paymentAck_ = value; + } + onChanged(); + } else { + paymentAckBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000100; + return this; + } + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + public Builder clearPaymentAck() { + if (paymentAckBuilder_ == null) { + paymentAck_ = org.bitcoin.paymentchannel.Protos.PaymentAck.getDefaultInstance(); + onChanged(); + } else { + paymentAckBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000100); + return this; + } + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + public org.bitcoin.paymentchannel.Protos.PaymentAck.Builder getPaymentAckBuilder() { + bitField0_ |= 0x00000100; + onChanged(); + return getPaymentAckFieldBuilder().getBuilder(); + } + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + public org.bitcoin.paymentchannel.Protos.PaymentAckOrBuilder getPaymentAckOrBuilder() { + if (paymentAckBuilder_ != null) { + return paymentAckBuilder_.getMessageOrBuilder(); + } else { + return paymentAck_; + } + } + /** + * optional .paymentchannels.PaymentAck payment_ack = 11; + */ + private com.google.protobuf.SingleFieldBuilder< + org.bitcoin.paymentchannel.Protos.PaymentAck, org.bitcoin.paymentchannel.Protos.PaymentAck.Builder, org.bitcoin.paymentchannel.Protos.PaymentAckOrBuilder> + getPaymentAckFieldBuilder() { + if (paymentAckBuilder_ == null) { + paymentAckBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.bitcoin.paymentchannel.Protos.PaymentAck, org.bitcoin.paymentchannel.Protos.PaymentAck.Builder, org.bitcoin.paymentchannel.Protos.PaymentAckOrBuilder>( + paymentAck_, + getParentForChildren(), + isClean()); + paymentAck_ = null; + } + return paymentAckBuilder_; + } + // optional .paymentchannels.Settlement settlement = 9; private org.bitcoin.paymentchannel.Protos.Settlement settlement_ = org.bitcoin.paymentchannel.Protos.Settlement.getDefaultInstance(); private com.google.protobuf.SingleFieldBuilder< @@ -2363,7 +2555,7 @@ public final class Protos { * optional .paymentchannels.Settlement settlement = 9; */ public boolean hasSettlement() { - return ((bitField0_ & 0x00000100) == 0x00000100); + return ((bitField0_ & 0x00000200) == 0x00000200); } /** * optional .paymentchannels.Settlement settlement = 9; @@ -2388,7 +2580,7 @@ public final class Protos { } else { settlementBuilder_.setMessage(value); } - bitField0_ |= 0x00000100; + bitField0_ |= 0x00000200; return this; } /** @@ -2402,7 +2594,7 @@ public final class Protos { } else { settlementBuilder_.setMessage(builderForValue.build()); } - bitField0_ |= 0x00000100; + bitField0_ |= 0x00000200; return this; } /** @@ -2410,7 +2602,7 @@ public final class Protos { */ public Builder mergeSettlement(org.bitcoin.paymentchannel.Protos.Settlement value) { if (settlementBuilder_ == null) { - if (((bitField0_ & 0x00000100) == 0x00000100) && + if (((bitField0_ & 0x00000200) == 0x00000200) && settlement_ != org.bitcoin.paymentchannel.Protos.Settlement.getDefaultInstance()) { settlement_ = org.bitcoin.paymentchannel.Protos.Settlement.newBuilder(settlement_).mergeFrom(value).buildPartial(); @@ -2421,7 +2613,7 @@ public final class Protos { } else { settlementBuilder_.mergeFrom(value); } - bitField0_ |= 0x00000100; + bitField0_ |= 0x00000200; return this; } /** @@ -2434,14 +2626,14 @@ public final class Protos { } else { settlementBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000100); + bitField0_ = (bitField0_ & ~0x00000200); return this; } /** * optional .paymentchannels.Settlement settlement = 9; */ public org.bitcoin.paymentchannel.Protos.Settlement.Builder getSettlementBuilder() { - bitField0_ |= 0x00000100; + bitField0_ |= 0x00000200; onChanged(); return getSettlementFieldBuilder().getBuilder(); } @@ -2480,7 +2672,7 @@ public final class Protos { * optional .paymentchannels.Error error = 10; */ public boolean hasError() { - return ((bitField0_ & 0x00000200) == 0x00000200); + return ((bitField0_ & 0x00000400) == 0x00000400); } /** * optional .paymentchannels.Error error = 10; @@ -2505,7 +2697,7 @@ public final class Protos { } else { errorBuilder_.setMessage(value); } - bitField0_ |= 0x00000200; + bitField0_ |= 0x00000400; return this; } /** @@ -2519,7 +2711,7 @@ public final class Protos { } else { errorBuilder_.setMessage(builderForValue.build()); } - bitField0_ |= 0x00000200; + bitField0_ |= 0x00000400; return this; } /** @@ -2527,7 +2719,7 @@ public final class Protos { */ public Builder mergeError(org.bitcoin.paymentchannel.Protos.Error value) { if (errorBuilder_ == null) { - if (((bitField0_ & 0x00000200) == 0x00000200) && + if (((bitField0_ & 0x00000400) == 0x00000400) && error_ != org.bitcoin.paymentchannel.Protos.Error.getDefaultInstance()) { error_ = org.bitcoin.paymentchannel.Protos.Error.newBuilder(error_).mergeFrom(value).buildPartial(); @@ -2538,7 +2730,7 @@ public final class Protos { } else { errorBuilder_.mergeFrom(value); } - bitField0_ |= 0x00000200; + bitField0_ |= 0x00000400; return this; } /** @@ -2551,14 +2743,14 @@ public final class Protos { } else { errorBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000200); + bitField0_ = (bitField0_ & ~0x00000400); return this; } /** * optional .paymentchannels.Error error = 10; */ public org.bitcoin.paymentchannel.Protos.Error.Builder getErrorBuilder() { - bitField0_ |= 0x00000200; + bitField0_ |= 0x00000400; onChanged(); return getErrorFieldBuilder().getBuilder(); } @@ -6588,7 +6780,7 @@ public final class Protos { * optional bytes info = 3; * *

-     * Information about the this update. Used to extend this protocol.
+     * Information about this update. Used to extend this protocol.
      * 
*/ boolean hasInfo(); @@ -6596,7 +6788,7 @@ public final class Protos { * optional bytes info = 3; * *
-     * Information about the this update. Used to extend this protocol.
+     * Information about this update. Used to extend this protocol.
      * 
*/ com.google.protobuf.ByteString getInfo(); @@ -6786,7 +6978,7 @@ public final class Protos { * optional bytes info = 3; * *
-     * Information about the this update. Used to extend this protocol.
+     * Information about this update. Used to extend this protocol.
      * 
*/ public boolean hasInfo() { @@ -6796,7 +6988,7 @@ public final class Protos { * optional bytes info = 3; * *
-     * Information about the this update. Used to extend this protocol.
+     * Information about this update. Used to extend this protocol.
      * 
*/ public com.google.protobuf.ByteString getInfo() { @@ -7219,7 +7411,7 @@ public final class Protos { * optional bytes info = 3; * *
-       * Information about the this update. Used to extend this protocol.
+       * Information about this update. Used to extend this protocol.
        * 
*/ public boolean hasInfo() { @@ -7229,7 +7421,7 @@ public final class Protos { * optional bytes info = 3; * *
-       * Information about the this update. Used to extend this protocol.
+       * Information about this update. Used to extend this protocol.
        * 
*/ public com.google.protobuf.ByteString getInfo() { @@ -7239,7 +7431,7 @@ public final class Protos { * optional bytes info = 3; * *
-       * Information about the this update. Used to extend this protocol.
+       * Information about this update. Used to extend this protocol.
        * 
*/ public Builder setInfo(com.google.protobuf.ByteString value) { @@ -7255,7 +7447,7 @@ public final class Protos { * optional bytes info = 3; * *
-       * Information about the this update. Used to extend this protocol.
+       * Information about this update. Used to extend this protocol.
        * 
*/ public Builder clearInfo() { @@ -7276,6 +7468,445 @@ public final class Protos { // @@protoc_insertion_point(class_scope:paymentchannels.UpdatePayment) } + public interface PaymentAckOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // optional bytes info = 1; + /** + * optional bytes info = 1; + * + *
+     * Information about this update. Used to extend this protocol
+     * 
+ */ + boolean hasInfo(); + /** + * optional bytes info = 1; + * + *
+     * Information about this update. Used to extend this protocol
+     * 
+ */ + com.google.protobuf.ByteString getInfo(); + } + /** + * Protobuf type {@code paymentchannels.PaymentAck} + * + *
+   * This message is sent as an acknowledgement of an UpdatePayment message
+   * 
+ */ + public static final class PaymentAck extends + com.google.protobuf.GeneratedMessage + implements PaymentAckOrBuilder { + // Use PaymentAck.newBuilder() to construct. + private PaymentAck(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private PaymentAck(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final PaymentAck defaultInstance; + public static PaymentAck getDefaultInstance() { + return defaultInstance; + } + + public PaymentAck getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private PaymentAck( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + bitField0_ |= 0x00000001; + info_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.bitcoin.paymentchannel.Protos.internal_static_paymentchannels_PaymentAck_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.bitcoin.paymentchannel.Protos.internal_static_paymentchannels_PaymentAck_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.bitcoin.paymentchannel.Protos.PaymentAck.class, org.bitcoin.paymentchannel.Protos.PaymentAck.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public PaymentAck parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new PaymentAck(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // optional bytes info = 1; + public static final int INFO_FIELD_NUMBER = 1; + private com.google.protobuf.ByteString info_; + /** + * optional bytes info = 1; + * + *
+     * Information about this update. Used to extend this protocol
+     * 
+ */ + public boolean hasInfo() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional bytes info = 1; + * + *
+     * Information about this update. Used to extend this protocol
+     * 
+ */ + public com.google.protobuf.ByteString getInfo() { + return info_; + } + + private void initFields() { + info_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, info_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, info_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static org.bitcoin.paymentchannel.Protos.PaymentAck parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.bitcoin.paymentchannel.Protos.PaymentAck parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.bitcoin.paymentchannel.Protos.PaymentAck parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.bitcoin.paymentchannel.Protos.PaymentAck parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.bitcoin.paymentchannel.Protos.PaymentAck parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.bitcoin.paymentchannel.Protos.PaymentAck parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.bitcoin.paymentchannel.Protos.PaymentAck parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.bitcoin.paymentchannel.Protos.PaymentAck parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.bitcoin.paymentchannel.Protos.PaymentAck parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.bitcoin.paymentchannel.Protos.PaymentAck parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.bitcoin.paymentchannel.Protos.PaymentAck prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code paymentchannels.PaymentAck} + * + *
+     * This message is sent as an acknowledgement of an UpdatePayment message
+     * 
+ */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements org.bitcoin.paymentchannel.Protos.PaymentAckOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.bitcoin.paymentchannel.Protos.internal_static_paymentchannels_PaymentAck_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.bitcoin.paymentchannel.Protos.internal_static_paymentchannels_PaymentAck_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.bitcoin.paymentchannel.Protos.PaymentAck.class, org.bitcoin.paymentchannel.Protos.PaymentAck.Builder.class); + } + + // Construct using org.bitcoin.paymentchannel.Protos.PaymentAck.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + info_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.bitcoin.paymentchannel.Protos.internal_static_paymentchannels_PaymentAck_descriptor; + } + + public org.bitcoin.paymentchannel.Protos.PaymentAck getDefaultInstanceForType() { + return org.bitcoin.paymentchannel.Protos.PaymentAck.getDefaultInstance(); + } + + public org.bitcoin.paymentchannel.Protos.PaymentAck build() { + org.bitcoin.paymentchannel.Protos.PaymentAck result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.bitcoin.paymentchannel.Protos.PaymentAck buildPartial() { + org.bitcoin.paymentchannel.Protos.PaymentAck result = new org.bitcoin.paymentchannel.Protos.PaymentAck(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.info_ = info_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.bitcoin.paymentchannel.Protos.PaymentAck) { + return mergeFrom((org.bitcoin.paymentchannel.Protos.PaymentAck)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.bitcoin.paymentchannel.Protos.PaymentAck other) { + if (other == org.bitcoin.paymentchannel.Protos.PaymentAck.getDefaultInstance()) return this; + if (other.hasInfo()) { + setInfo(other.getInfo()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.bitcoin.paymentchannel.Protos.PaymentAck parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.bitcoin.paymentchannel.Protos.PaymentAck) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // optional bytes info = 1; + private com.google.protobuf.ByteString info_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes info = 1; + * + *
+       * Information about this update. Used to extend this protocol
+       * 
+ */ + public boolean hasInfo() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional bytes info = 1; + * + *
+       * Information about this update. Used to extend this protocol
+       * 
+ */ + public com.google.protobuf.ByteString getInfo() { + return info_; + } + /** + * optional bytes info = 1; + * + *
+       * Information about this update. Used to extend this protocol
+       * 
+ */ + public Builder setInfo(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + info_ = value; + onChanged(); + return this; + } + /** + * optional bytes info = 1; + * + *
+       * Information about this update. Used to extend this protocol
+       * 
+ */ + public Builder clearInfo() { + bitField0_ = (bitField0_ & ~0x00000001); + info_ = getDefaultInstance().getInfo(); + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:paymentchannels.PaymentAck) + } + + static { + defaultInstance = new PaymentAck(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:paymentchannels.PaymentAck) + } + public interface SettlementOrBuilder extends com.google.protobuf.MessageOrBuilder { @@ -8691,6 +9322,11 @@ public final class Protos { private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_paymentchannels_UpdatePayment_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_paymentchannels_PaymentAck_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_paymentchannels_PaymentAck_fieldAccessorTable; private static com.google.protobuf.Descriptors.Descriptor internal_static_paymentchannels_Settlement_descriptor; private static @@ -8711,7 +9347,7 @@ public final class Protos { static { java.lang.String[] descriptorData = { "\n\024paymentchannel.proto\022\017paymentchannels\"" + - "\376\005\n\024TwoWayChannelMessage\022?\n\004type\030\001 \002(\01621" + + "\260\006\n\024TwoWayChannelMessage\022?\n\004type\030\001 \002(\01621" + ".paymentchannels.TwoWayChannelMessage.Me" + "ssageType\0226\n\016client_version\030\002 \001(\0132\036.paym" + "entchannels.ClientVersion\0226\n\016server_vers" + @@ -8722,36 +9358,38 @@ public final class Protos { "\006 \001(\0132\035.paymentchannels.ReturnRefund\022:\n\020", "provide_contract\030\007 \001(\0132 .paymentchannels" + ".ProvideContract\0226\n\016update_payment\030\010 \001(\013" + - "2\036.paymentchannels.UpdatePayment\022/\n\nsett" + - "lement\030\t \001(\0132\033.paymentchannels.Settlemen" + - "t\022%\n\005error\030\n \001(\0132\026.paymentchannels.Error" + - "\"\315\001\n\013MessageType\022\022\n\016CLIENT_VERSION\020\001\022\022\n\016" + - "SERVER_VERSION\020\002\022\014\n\010INITIATE\020\003\022\022\n\016PROVID" + - "E_REFUND\020\004\022\021\n\rRETURN_REFUND\020\005\022\024\n\020PROVIDE" + - "_CONTRACT\020\006\022\020\n\014CHANNEL_OPEN\020\007\022\022\n\016UPDATE_" + - "PAYMENT\020\010\022\017\n\013PAYMENT_ACK\020\013\022\t\n\005CLOSE\020\t\022\t\n", - "\005ERROR\020\n\"X\n\rClientVersion\022\r\n\005major\030\001 \002(\005" + - "\022\020\n\005minor\030\002 \001(\005:\0010\022&\n\036previous_channel_c" + - "ontract_hash\030\003 \001(\014\"0\n\rServerVersion\022\r\n\005m" + - "ajor\030\001 \002(\005\022\020\n\005minor\030\002 \001(\005:\0010\"r\n\010Initiate" + - "\022\024\n\014multisig_key\030\001 \002(\014\022!\n\031min_accepted_c" + - "hannel_size\030\002 \002(\004\022\030\n\020expire_time_secs\030\003 " + - "\002(\004\022\023\n\013min_payment\030\004 \002(\004\"1\n\rProvideRefun" + - "d\022\024\n\014multisig_key\030\001 \002(\014\022\n\n\002tx\030\002 \002(\014\"!\n\014R" + - "eturnRefund\022\021\n\tsignature\030\001 \002(\014\"V\n\017Provid" + - "eContract\022\n\n\002tx\030\001 \002(\014\0227\n\017initial_payment", - "\030\002 \002(\0132\036.paymentchannels.UpdatePayment\"M" + - "\n\rUpdatePayment\022\033\n\023client_change_value\030\001" + - " \002(\004\022\021\n\tsignature\030\002 \002(\014\022\014\n\004info\030\003 \001(\014\"\030\n" + - "\nSettlement\022\n\n\002tx\030\003 \002(\014\"\246\002\n\005Error\0225\n\004cod" + - "e\030\001 \001(\0162 .paymentchannels.Error.ErrorCod" + - "e:\005OTHER\022\023\n\013explanation\030\002 \001(\t\022\026\n\016expecte" + - "d_value\030\003 \001(\004\"\270\001\n\tErrorCode\022\013\n\007TIMEOUT\020\001" + - "\022\020\n\014SYNTAX_ERROR\020\002\022\031\n\025NO_ACCEPTABLE_VERS" + - "ION\020\003\022\023\n\017BAD_TRANSACTION\020\004\022\031\n\025TIME_WINDO" + - "W_TOO_LARGE\020\005\022\033\n\027CHANNEL_VALUE_TOO_LARGE", - "\020\006\022\031\n\025MIN_PAYMENT_TOO_LARGE\020\007\022\t\n\005OTHER\020\010" + - "B$\n\032org.bitcoin.paymentchannelB\006Protos" + "2\036.paymentchannels.UpdatePayment\0220\n\013paym" + + "ent_ack\030\013 \001(\0132\033.paymentchannels.PaymentA" + + "ck\022/\n\nsettlement\030\t \001(\0132\033.paymentchannels" + + ".Settlement\022%\n\005error\030\n \001(\0132\026.paymentchan" + + "nels.Error\"\315\001\n\013MessageType\022\022\n\016CLIENT_VER" + + "SION\020\001\022\022\n\016SERVER_VERSION\020\002\022\014\n\010INITIATE\020\003" + + "\022\022\n\016PROVIDE_REFUND\020\004\022\021\n\rRETURN_REFUND\020\005\022" + + "\024\n\020PROVIDE_CONTRACT\020\006\022\020\n\014CHANNEL_OPEN\020\007\022", + "\022\n\016UPDATE_PAYMENT\020\010\022\017\n\013PAYMENT_ACK\020\013\022\t\n\005" + + "CLOSE\020\t\022\t\n\005ERROR\020\n\"X\n\rClientVersion\022\r\n\005m" + + "ajor\030\001 \002(\005\022\020\n\005minor\030\002 \001(\005:\0010\022&\n\036previous" + + "_channel_contract_hash\030\003 \001(\014\"0\n\rServerVe" + + "rsion\022\r\n\005major\030\001 \002(\005\022\020\n\005minor\030\002 \001(\005:\0010\"r" + + "\n\010Initiate\022\024\n\014multisig_key\030\001 \002(\014\022!\n\031min_" + + "accepted_channel_size\030\002 \002(\004\022\030\n\020expire_ti" + + "me_secs\030\003 \002(\004\022\023\n\013min_payment\030\004 \002(\004\"1\n\rPr" + + "ovideRefund\022\024\n\014multisig_key\030\001 \002(\014\022\n\n\002tx\030" + + "\002 \002(\014\"!\n\014ReturnRefund\022\021\n\tsignature\030\001 \002(\014", + "\"V\n\017ProvideContract\022\n\n\002tx\030\001 \002(\014\0227\n\017initi" + + "al_payment\030\002 \002(\0132\036.paymentchannels.Updat" + + "ePayment\"M\n\rUpdatePayment\022\033\n\023client_chan" + + "ge_value\030\001 \002(\004\022\021\n\tsignature\030\002 \002(\014\022\014\n\004inf" + + "o\030\003 \001(\014\"\032\n\nPaymentAck\022\014\n\004info\030\001 \001(\014\"\030\n\nS" + + "ettlement\022\n\n\002tx\030\003 \002(\014\"\246\002\n\005Error\0225\n\004code\030" + + "\001 \001(\0162 .paymentchannels.Error.ErrorCode:" + + "\005OTHER\022\023\n\013explanation\030\002 \001(\t\022\026\n\016expected_" + + "value\030\003 \001(\004\"\270\001\n\tErrorCode\022\013\n\007TIMEOUT\020\001\022\020" + + "\n\014SYNTAX_ERROR\020\002\022\031\n\025NO_ACCEPTABLE_VERSIO", + "N\020\003\022\023\n\017BAD_TRANSACTION\020\004\022\031\n\025TIME_WINDOW_" + + "TOO_LARGE\020\005\022\033\n\027CHANNEL_VALUE_TOO_LARGE\020\006" + + "\022\031\n\025MIN_PAYMENT_TOO_LARGE\020\007\022\t\n\005OTHER\020\010B$" + + "\n\032org.bitcoin.paymentchannelB\006Protos" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -8763,7 +9401,7 @@ public final class Protos { internal_static_paymentchannels_TwoWayChannelMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_paymentchannels_TwoWayChannelMessage_descriptor, - new java.lang.String[] { "Type", "ClientVersion", "ServerVersion", "Initiate", "ProvideRefund", "ReturnRefund", "ProvideContract", "UpdatePayment", "Settlement", "Error", }); + new java.lang.String[] { "Type", "ClientVersion", "ServerVersion", "Initiate", "ProvideRefund", "ReturnRefund", "ProvideContract", "UpdatePayment", "PaymentAck", "Settlement", "Error", }); internal_static_paymentchannels_ClientVersion_descriptor = getDescriptor().getMessageTypes().get(1); internal_static_paymentchannels_ClientVersion_fieldAccessorTable = new @@ -8806,14 +9444,20 @@ public final class Protos { com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_paymentchannels_UpdatePayment_descriptor, new java.lang.String[] { "ClientChangeValue", "Signature", "Info", }); - internal_static_paymentchannels_Settlement_descriptor = + internal_static_paymentchannels_PaymentAck_descriptor = getDescriptor().getMessageTypes().get(8); + internal_static_paymentchannels_PaymentAck_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_paymentchannels_PaymentAck_descriptor, + new java.lang.String[] { "Info", }); + internal_static_paymentchannels_Settlement_descriptor = + getDescriptor().getMessageTypes().get(9); internal_static_paymentchannels_Settlement_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_paymentchannels_Settlement_descriptor, new java.lang.String[] { "Tx", }); internal_static_paymentchannels_Error_descriptor = - getDescriptor().getMessageTypes().get(9); + getDescriptor().getMessageTypes().get(10); internal_static_paymentchannels_Error_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_paymentchannels_Error_descriptor, diff --git a/core/src/paymentchannel.proto b/core/src/paymentchannel.proto index f8f1d316..58e55943 100644 --- a/core/src/paymentchannel.proto +++ b/core/src/paymentchannel.proto @@ -83,6 +83,7 @@ message TwoWayChannelMessage { optional ReturnRefund return_refund = 6; optional ProvideContract provide_contract = 7; optional UpdatePayment update_payment = 8; + optional PaymentAck payment_ack = 11; optional Settlement settlement = 9; optional Error error = 10; @@ -214,6 +215,12 @@ message UpdatePayment { } +// This message is sent as an acknowledgement of an UpdatePayment message +message PaymentAck { + // Information about this update. Used to extend this protocol + optional bytes info = 1; +} + message Settlement { // A copy of the fully signed final contract that settles the channel. The client can verify // the transaction is correct and then commit it to their wallet. diff --git a/core/src/test/java/com/google/bitcoin/protocols/channels/ChannelConnectionTest.java b/core/src/test/java/com/google/bitcoin/protocols/channels/ChannelConnectionTest.java index b24fb388..a4114883 100644 --- a/core/src/test/java/com/google/bitcoin/protocols/channels/ChannelConnectionTest.java +++ b/core/src/test/java/com/google/bitcoin/protocols/channels/ChannelConnectionTest.java @@ -130,8 +130,9 @@ public class ChannelConnectionTest extends TestWithWallet { } @Override - public void paymentIncrease(Coin by, Coin to, ByteString info) { + public ByteString paymentIncrease(Coin by, Coin to, ByteString info) { q.add(new ChannelTestUtils.UpdatePair(to, info)); + return null; } @Override @@ -682,20 +683,20 @@ public class ChannelConnectionTest extends TestWithWallet { pair.clientRecorder.checkInitiated(); assertNull(pair.serverRecorder.q.poll()); assertNull(pair.clientRecorder.q.poll()); - ListenableFuture future = client.incrementPayment(CENT); - server.receiveMessage(pair.clientRecorder.checkNextMsg(MessageType.UPDATE_PAYMENT)); - pair.serverRecorder.q.take(); - client.receiveMessage(pair.serverRecorder.checkNextMsg(MessageType.PAYMENT_ACK)); - assertTrue(future.isDone()); - client.incrementPayment(CENT); - server.receiveMessage(pair.clientRecorder.checkNextMsg(MessageType.UPDATE_PAYMENT)); - pair.serverRecorder.q.take(); - client.receiveMessage(pair.serverRecorder.checkNextMsg(MessageType.PAYMENT_ACK)); - - client.incrementPayment(CENT); - server.receiveMessage(pair.clientRecorder.checkNextMsg(MessageType.UPDATE_PAYMENT)); - pair.serverRecorder.q.take(); - client.receiveMessage(pair.serverRecorder.checkNextMsg(MessageType.PAYMENT_ACK)); + for (int i = 0; i < 3; i++) { + ListenableFuture future = client.incrementPayment(CENT); + server.receiveMessage(pair.clientRecorder.checkNextMsg(MessageType.UPDATE_PAYMENT)); + pair.serverRecorder.q.take(); + final Protos.TwoWayChannelMessage msg = pair.serverRecorder.checkNextMsg(MessageType.PAYMENT_ACK); + final Protos.PaymentAck paymentAck = msg.getPaymentAck(); + assertTrue("No PaymentAck.Info", paymentAck.hasInfo()); + assertEquals("Wrong PaymentAck info", ByteString.copyFromUtf8(CENT.toPlainString()), paymentAck.getInfo()); + client.receiveMessage(msg); + assertTrue(future.isDone()); + final PaymentIncrementAck paymentIncrementAck = future.get(); + assertEquals("Wrong value returned from increasePayment", CENT, paymentIncrementAck.getValue()); + assertEquals("Wrong info returned from increasePayment", ByteString.copyFromUtf8(CENT.toPlainString()), paymentIncrementAck.getInfo()); + } // Settle it and verify it's considered to be settled. broadcastTxPause.release(); diff --git a/core/src/test/java/com/google/bitcoin/protocols/channels/ChannelTestUtils.java b/core/src/test/java/com/google/bitcoin/protocols/channels/ChannelTestUtils.java index 5129fe20..898b91cf 100644 --- a/core/src/test/java/com/google/bitcoin/protocols/channels/ChannelTestUtils.java +++ b/core/src/test/java/com/google/bitcoin/protocols/channels/ChannelTestUtils.java @@ -37,8 +37,9 @@ public class ChannelTestUtils { } @Override - public void paymentIncrease(Coin by, Coin to, @Nullable ByteString info) { + public ByteString paymentIncrease(Coin by, Coin to, @Nullable ByteString info) { q.add(new UpdatePair(to, info)); + return ByteString.copyFromUtf8(by.toPlainString()); } public Protos.TwoWayChannelMessage getNextMsg() throws InterruptedException { diff --git a/examples/src/main/java/com/google/bitcoin/examples/ExamplePaymentChannelServer.java b/examples/src/main/java/com/google/bitcoin/examples/ExamplePaymentChannelServer.java index a70fb4dc..b8f38fb2 100644 --- a/examples/src/main/java/com/google/bitcoin/examples/ExamplePaymentChannelServer.java +++ b/examples/src/main/java/com/google/bitcoin/examples/ExamplePaymentChannelServer.java @@ -102,8 +102,9 @@ public class ExamplePaymentChannelServer implements PaymentChannelServerListener } @Override - public void paymentIncrease(Coin by, Coin to, ByteString info) { + public ByteString paymentIncrease(Coin by, Coin to, ByteString info) { log.info("Client {} paid increased payment by {} for a total of " + to.toString(), clientAddress, by); + return null; } @Override