From 9bc91ec2e599bcbea9b25e780d8bb30248fda32e Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Tue, 17 Sep 2013 16:31:56 +0200 Subject: [PATCH] Payment channels: Don't swallow ValueOutOfRangeException during initiate. It indicates an empty wallet and should be propagated to the channel open future or the client user, so they know they have insufficient money. --- .../channels/PaymentChannelClient.java | 8 +------ .../PaymentChannelClientConnection.java | 9 ++++++-- .../channels/ChannelConnectionTest.java | 23 +++++++++++++++++++ 3 files changed, 31 insertions(+), 9 deletions(-) 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 0a3ac16d1..bfc9c17ba 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 @@ -201,7 +201,7 @@ public class PaymentChannelClient { * Called when a message is received from the server. Processes the given message and generates events based on its * content. */ - public void receiveMessage(Protos.TwoWayChannelMessage msg) { + public void receiveMessage(Protos.TwoWayChannelMessage msg) throws ValueOutOfRangeException { lock.lock(); try { checkState(connectionOpen); @@ -274,12 +274,6 @@ public class PaymentChannelClient { .setCode(Protos.Error.ErrorCode.BAD_TRANSACTION) .setExplanation(e.getMessage()); closeReason = CloseReason.REMOTE_SENT_INVALID_MESSAGE; - } catch (ValueOutOfRangeException e) { - log.error("Caught value out of range exception handling message from server", e); - errorBuilder = Protos.Error.newBuilder() - .setCode(Protos.Error.ErrorCode.BAD_TRANSACTION) - .setExplanation(e.getMessage()); - closeReason = CloseReason.REMOTE_SENT_INVALID_MESSAGE; } catch (IllegalStateException e) { log.error("Caught illegal state exception handling message from server", e); errorBuilder = Protos.Error.newBuilder() 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 b80a82a93..227eecb9c 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 @@ -88,8 +88,13 @@ public class PaymentChannelClientConnection { wireParser = new ProtobufParser(new ProtobufParser.Listener() { @Override public void messageReceived(ProtobufParser handler, Protos.TwoWayChannelMessage msg) { - channelClient.receiveMessage(msg); - } + try { + channelClient.receiveMessage(msg); + } catch (ValueOutOfRangeException e) { + // We should only get this exception during INITIATE, so channelOpen wasn't called yet. + channelOpenFuture.setException(e); + } + } @Override public void connectionOpen(ProtobufParser handler) { 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 10a1dcc2b..45b0faede 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 @@ -504,6 +504,29 @@ public class ChannelConnectionTest extends TestWithWallet { assertEquals(myValue, refund.getOutput(0).getValue()); } + @Test + public void testEmptyWallet() throws Exception { + Wallet emptyWallet = new Wallet(params); + emptyWallet.addKey(new ECKey()); + ChannelTestUtils.RecordingPair pair = ChannelTestUtils.makeRecorders(serverWallet, mockBroadcaster); + PaymentChannelServer server = pair.server; + PaymentChannelClient client = new PaymentChannelClient(emptyWallet, myKey, Utils.COIN, 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)); + try { + client.receiveMessage(Protos.TwoWayChannelMessage.newBuilder() + .setInitiate(Protos.Initiate.newBuilder().setExpireTimeSecs(Utils.now().getTime() / 1000) + .setMinAcceptedChannelSize(Utils.CENT.longValue()) + .setMultisigKey(ByteString.copyFrom(new ECKey().getPubKey()))) + .setType(MessageType.INITIATE).build()); + fail(); + } catch (ValueOutOfRangeException expected) { + // This should be thrown. + } + } + @Test public void testClientResumeNothing() throws Exception { ChannelTestUtils.RecordingPair pair = ChannelTestUtils.makeRecorders(serverWallet, mockBroadcaster);