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 a76a53f2..382aec78 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 @@ -1,9 +1,7 @@ package com.google.bitcoin.protocols.channels; -import java.math.BigInteger; -import java.util.concurrent.locks.ReentrantLock; - import com.google.bitcoin.core.*; +import com.google.bitcoin.protocols.channels.PaymentChannelCloseException.CloseReason; import com.google.bitcoin.utils.Threading; import com.google.common.annotations.VisibleForTesting; import com.google.protobuf.ByteString; @@ -11,7 +9,9 @@ import net.jcip.annotations.GuardedBy; import org.bitcoin.paymentchannel.Protos; import org.slf4j.LoggerFactory; -import com.google.bitcoin.protocols.channels.PaymentChannelCloseException.CloseReason; +import java.math.BigInteger; +import java.util.concurrent.locks.ReentrantLock; + import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; @@ -138,13 +138,12 @@ public class PaymentChannelClient { } @GuardedBy("lock") - private void receiveInitiate(Protos.Initiate initiate, BigInteger minChannelSize) throws VerificationException, ValueOutOfRangeException { + private void receiveInitiate(Protos.Initiate initiate, BigInteger contractValue) throws VerificationException, ValueOutOfRangeException { log.info("Got INITIATE message, providing refund transaction"); state = new PaymentChannelClientState(wallet, myKey, new ECKey(null, initiate.getMultisigKey().toByteArray()), - minChannelSize, - initiate.getExpireTimeSecs()); + contractValue, initiate.getExpireTimeSecs()); state.initiate(); step = InitStep.WAITING_FOR_REFUND_RETURN; @@ -232,14 +231,14 @@ public class PaymentChannelClient { } BigInteger minChannelSize = BigInteger.valueOf(initiate.getMinAcceptedChannelSize()); - if (minChannelSize.compareTo(maxValue) > 0) { + if (maxValue.compareTo(minChannelSize) < 0) { errorBuilder = Protos.Error.newBuilder() .setCode(Protos.Error.ErrorCode.CHANNEL_VALUE_TOO_LARGE); closeReason = CloseReason.SERVER_REQUESTED_TOO_MUCH_VALUE; break; } - receiveInitiate(initiate, minChannelSize); + receiveInitiate(initiate, maxValue); return; case RETURN_REFUND: receiveRefund(msg); 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 471e287c..ec3beaa6 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 @@ -473,7 +473,7 @@ public class ChannelConnectionTest extends TestWithWallet { } @Test - public void testClientValueTooLarge() throws Exception { + public void testValuesAreRespected() throws Exception { ChannelTestUtils.RecordingPair pair = ChannelTestUtils.makeRecorders(serverWallet, mockBroadcaster); PaymentChannelServer server = pair.server; PaymentChannelClient client = new PaymentChannelClient(wallet, myKey, Utils.COIN, Sha256Hash.ZERO_HASH, pair.clientRecorder); @@ -493,6 +493,27 @@ public class ChannelConnectionTest extends TestWithWallet { client.incrementPayment(BigInteger.ONE); fail(); } catch (IllegalStateException e) { } + + // Now check that if the server has a lower min size than what we are willing to spend, we do actually open + // a channel of that size. + sendMoneyToWallet(Utils.COIN.multiply(BigInteger.TEN), AbstractBlockChain.NewBlockType.BEST_CHAIN); + + pair = ChannelTestUtils.makeRecorders(serverWallet, mockBroadcaster); + server = pair.server; + final BigInteger myValue = Utils.COIN.multiply(BigInteger.TEN); + client = new PaymentChannelClient(wallet, myKey, myValue, Sha256Hash.ZERO_HASH, pair.clientRecorder); + client.connectionOpen(); + server.connectionOpen(); + server.receiveMessage(pair.clientRecorder.checkNextMsg(MessageType.CLIENT_VERSION)); + client.receiveMessage(pair.serverRecorder.checkNextMsg(MessageType.SERVER_VERSION)); + client.receiveMessage(Protos.TwoWayChannelMessage.newBuilder() + .setInitiate(Protos.Initiate.newBuilder().setExpireTimeSecs(Utils.now().getTime() / 1000) + .setMinAcceptedChannelSize(Utils.COIN.add(BigInteger.ONE).longValue()) + .setMultisigKey(ByteString.copyFrom(new ECKey().getPubKey()))) + .setType(MessageType.INITIATE).build()); + final Protos.TwoWayChannelMessage provideRefund = pair.clientRecorder.checkNextMsg(MessageType.PROVIDE_REFUND); + Transaction refund = new Transaction(params, provideRefund.getProvideRefund().getTx().toByteArray()); + assertEquals(myValue, refund.getOutput(0).getValue()); } @Test