Java Code Examples for org.bitcoin.paymentchannel.Protos#TwoWayChannelMessage

The following examples show how to use org.bitcoin.paymentchannel.Protos#TwoWayChannelMessage . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: PaymentChannelServer.java    From GreenBits with GNU General Public License v3.0 6 votes vote down vote up
@GuardedBy("lock")
private void receiveContractMessage(Protos.TwoWayChannelMessage msg) throws VerificationException {
    checkState(majorVersion == 1 || majorVersion == 2);
    checkState(step == InitStep.WAITING_ON_CONTRACT && msg.hasProvideContract());
    log.info("Got contract, broadcasting and responding with CHANNEL_OPEN");
    final Protos.ProvideContract providedContract = msg.getProvideContract();

    if (majorVersion == 2) {
        state = new PaymentChannelV2ServerState(broadcaster, wallet, myKey, expireTime);
        checkState(providedContract.hasClientKey(), "ProvideContract didn't have a client key in protocol v2");
        ((PaymentChannelV2ServerState)state).provideClientKey(providedContract.getClientKey().toByteArray());
    }

    //TODO notify connection handler that timeout should be significantly extended as we wait for network propagation?
    final Transaction contract = wallet.getParams().getDefaultSerializer().makeTransaction(providedContract.getTx().toByteArray());
    step = InitStep.WAITING_ON_MULTISIG_ACCEPTANCE;
    state.provideContract(contract)
            .addListener(new Runnable() {
                @Override
                public void run() {
                    multisigContractPropogated(providedContract, contract.getHash());
                }
            }, Threading.SAME_THREAD);
}
 
Example 2
Source File: PaymentChannelClient.java    From GreenBits with GNU General Public License v3.0 6 votes vote down vote up
@GuardedBy("lock")
private void receiveClose(Protos.TwoWayChannelMessage msg) throws VerificationException {
    checkState(lock.isHeldByCurrentThread());
    if (msg.hasSettlement()) {
        Transaction settleTx = wallet.getParams().getDefaultSerializer().makeTransaction(msg.getSettlement().getTx().toByteArray());
        log.info("CLOSE message received with settlement tx {}", settleTx.getHash());
        // TODO: set source
        if (state != null && state().isSettlementTransaction(settleTx)) {
            // The wallet has a listener on it that the state object will use to do the right thing at this
            // point (like watching it for confirmations). The tx has been checked by now for syntactical validity
            // and that it correctly spends the multisig contract.
            wallet.receivePending(settleTx, null);
        }
    } else {
        log.info("CLOSE message received without settlement tx");
    }
    if (step == InitStep.WAITING_FOR_CHANNEL_CLOSE)
        conn.destroyConnection(CloseReason.CLIENT_REQUESTED_CLOSE);
    else
        conn.destroyConnection(CloseReason.SERVER_REQUESTED_CLOSE);
    step = InitStep.CHANNEL_CLOSED;
}
 
Example 3
Source File: PaymentChannelServer.java    From green_android with GNU General Public License v3.0 6 votes vote down vote up
@GuardedBy("lock")
private void receiveContractMessage(Protos.TwoWayChannelMessage msg) throws VerificationException {
    checkState(majorVersion == 1 || majorVersion == 2);
    checkState(step == InitStep.WAITING_ON_CONTRACT && msg.hasProvideContract());
    log.info("Got contract, broadcasting and responding with CHANNEL_OPEN");
    final Protos.ProvideContract providedContract = msg.getProvideContract();

    if (majorVersion == 2) {
        state = new PaymentChannelV2ServerState(broadcaster, wallet, myKey, expireTime);
        checkState(providedContract.hasClientKey(), "ProvideContract didn't have a client key in protocol v2");
        ((PaymentChannelV2ServerState)state).provideClientKey(providedContract.getClientKey().toByteArray());
    }

    //TODO notify connection handler that timeout should be significantly extended as we wait for network propagation?
    final Transaction contract = wallet.getParams().getDefaultSerializer().makeTransaction(providedContract.getTx().toByteArray());
    step = InitStep.WAITING_ON_MULTISIG_ACCEPTANCE;
    state.provideContract(contract)
            .addListener(new Runnable() {
                @Override
                public void run() {
                    multisigContractPropogated(providedContract, contract.getHash());
                }
            }, Threading.SAME_THREAD);
}
 
Example 4
Source File: PaymentChannelServer.java    From bcm-android with GNU General Public License v3.0 6 votes vote down vote up
@GuardedBy("lock")
private void receiveRefundMessage(Protos.TwoWayChannelMessage msg) throws VerificationException {
    checkState(majorVersion == 1);
    checkState(step == InitStep.WAITING_ON_UNSIGNED_REFUND && msg.hasProvideRefund());
    log.info("Got refund transaction, returning signature");

    Protos.ProvideRefund providedRefund = msg.getProvideRefund();
    state = new PaymentChannelV1ServerState(broadcaster, wallet, myKey, expireTime);
    // We can cast to V1 state since this state is only used in the V1 protocol
    byte[] signature = ((PaymentChannelV1ServerState) state)
            .provideRefundTransaction(wallet.getParams().getDefaultSerializer().makeTransaction(providedRefund.getTx().toByteArray()),
                    providedRefund.getMultisigKey().toByteArray());

    step = InitStep.WAITING_ON_CONTRACT;

    Protos.ReturnRefund.Builder returnRefundBuilder = Protos.ReturnRefund.newBuilder()
            .setSignature(ByteString.copyFrom(signature));

    conn.sendToClient(Protos.TwoWayChannelMessage.newBuilder()
            .setReturnRefund(returnRefundBuilder)
            .setType(Protos.TwoWayChannelMessage.MessageType.RETURN_REFUND)
            .build());
}
 
Example 5
Source File: PaymentChannelClient.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
@GuardedBy("lock")
private void receiveRefund(Protos.TwoWayChannelMessage refundMsg, @Nullable KeyParameter userKey) throws VerificationException {
    checkState(majorVersion == 1);
    checkState(step == InitStep.WAITING_FOR_REFUND_RETURN && refundMsg.hasReturnRefund());
    log.info("Got RETURN_REFUND message, providing signed contract");
    Protos.ReturnRefund returnedRefund = refundMsg.getReturnRefund();
    // Cast is safe since we've checked the version number
    ((PaymentChannelV1ClientState) state).provideRefundSignature(returnedRefund.getSignature().toByteArray(), userKey);
    step = InitStep.WAITING_FOR_CHANNEL_OPEN;

    // Before we can send the server the contract (ie send it to the network), we must ensure that our refund
    // transaction is safely in the wallet - thus we store it (this also keeps it up-to-date when we pay)
    state.storeChannelInWallet(serverId);

    Protos.ProvideContract.Builder contractMsg = Protos.ProvideContract.newBuilder()
            .setTx(ByteString.copyFrom(state.getContract().unsafeBitcoinSerialize()));
    try {
        // Make an initial payment of the dust limit, and put it into the message as well. The size of the
        // server-requested dust limit was already sanity checked by this point.
        PaymentChannelClientState.IncrementedPayment payment = state().incrementPaymentBy(Coin.valueOf(minPayment), userKey);
        Protos.UpdatePayment.Builder initialMsg = contractMsg.getInitialPaymentBuilder();
        initialMsg.setSignature(ByteString.copyFrom(payment.signature.encodeToBitcoin()));
        initialMsg.setClientChangeValue(state.getValueRefunded().value);
    } catch (ValueOutOfRangeException e) {
        throw new IllegalStateException(e);  // This cannot happen.
    }

    final Protos.TwoWayChannelMessage.Builder msg = Protos.TwoWayChannelMessage.newBuilder();
    msg.setProvideContract(contractMsg);
    msg.setType(Protos.TwoWayChannelMessage.MessageType.PROVIDE_CONTRACT);
    conn.sendToServer(msg.build());
}
 
Example 6
Source File: ChannelConnectionTest.java    From GreenBits with GNU General Public License v3.0 5 votes vote down vote up
@Test
public void testServerErrorHandling_badTransaction() throws Exception {
    if (!useRefunds()) {
        // This test only applies to versions with refunds
        return;
    }
    // Gives the server crap and checks proper error responses are sent.
    ChannelTestUtils.RecordingPair pair = ChannelTestUtils.makeRecorders(serverWallet, mockBroadcaster);
    PaymentChannelClient client = new PaymentChannelClient(wallet, myKey, COIN, Sha256Hash.ZERO_HASH, null, clientChannelProperties, pair.clientRecorder);
    PaymentChannelServer server = pair.server;
    server.connectionOpen();
    client.connectionOpen();

    // Make sure we get back a BAD_TRANSACTION if we send a bogus refund transaction.
    server.receiveMessage(pair.clientRecorder.checkNextMsg(MessageType.CLIENT_VERSION));
    client.receiveMessage(pair.serverRecorder.checkNextMsg(MessageType.SERVER_VERSION));
    client.receiveMessage(pair.serverRecorder.checkNextMsg(MessageType.INITIATE));
    Protos.TwoWayChannelMessage msg = pair.clientRecorder.checkNextMsg(MessageType.PROVIDE_REFUND);
    server.receiveMessage(Protos.TwoWayChannelMessage.newBuilder()
            .setType(MessageType.PROVIDE_REFUND)
            .setProvideRefund(
                    Protos.ProvideRefund.newBuilder(msg.getProvideRefund())
                            .setMultisigKey(ByteString.EMPTY)
                            .setTx(ByteString.EMPTY)
            ).build());
    final Protos.TwoWayChannelMessage errorMsg = pair.serverRecorder.checkNextMsg(MessageType.ERROR);
    assertEquals(Protos.Error.ErrorCode.BAD_TRANSACTION, errorMsg.getError().getCode());
}
 
Example 7
Source File: PaymentChannelClient.java    From GreenBits with GNU General Public License v3.0 5 votes vote down vote up
@GuardedBy("lock")
private void receiveRefund(Protos.TwoWayChannelMessage refundMsg, @Nullable KeyParameter userKey) throws VerificationException {
    checkState(majorVersion == 1);
    checkState(step == InitStep.WAITING_FOR_REFUND_RETURN && refundMsg.hasReturnRefund());
    log.info("Got RETURN_REFUND message, providing signed contract");
    Protos.ReturnRefund returnedRefund = refundMsg.getReturnRefund();
    // Cast is safe since we've checked the version number
    ((PaymentChannelV1ClientState)state).provideRefundSignature(returnedRefund.getSignature().toByteArray(), userKey);
    step = InitStep.WAITING_FOR_CHANNEL_OPEN;

    // Before we can send the server the contract (ie send it to the network), we must ensure that our refund
    // transaction is safely in the wallet - thus we store it (this also keeps it up-to-date when we pay)
    state.storeChannelInWallet(serverId);

    Protos.ProvideContract.Builder contractMsg = Protos.ProvideContract.newBuilder()
            .setTx(ByteString.copyFrom(state.getContract().unsafeBitcoinSerialize()));
    try {
        // Make an initial payment of the dust limit, and put it into the message as well. The size of the
        // server-requested dust limit was already sanity checked by this point.
        PaymentChannelClientState.IncrementedPayment payment = state().incrementPaymentBy(Coin.valueOf(minPayment), userKey);
        Protos.UpdatePayment.Builder initialMsg = contractMsg.getInitialPaymentBuilder();
        initialMsg.setSignature(ByteString.copyFrom(payment.signature.encodeToBitcoin()));
        initialMsg.setClientChangeValue(state.getValueRefunded().value);
    } catch (ValueOutOfRangeException e) {
        throw new IllegalStateException(e);  // This cannot happen.
    }

    final Protos.TwoWayChannelMessage.Builder msg = Protos.TwoWayChannelMessage.newBuilder();
    msg.setProvideContract(contractMsg);
    msg.setType(Protos.TwoWayChannelMessage.MessageType.PROVIDE_CONTRACT);
    conn.sendToServer(msg.build());
}
 
Example 8
Source File: PaymentChannelServerListener.java    From green_android with GNU General Public License v3.0 4 votes vote down vote up
public ServerHandler(final SocketAddress address, final int timeoutSeconds) {
    paymentChannelManager = new PaymentChannelServer(broadcaster, wallet, minAcceptedChannelSize, new PaymentChannelServer.ServerConnection() {
        @Override public void sendToClient(Protos.TwoWayChannelMessage msg) {
            socketProtobufHandler.write(msg);
        }

        @Override public void destroyConnection(PaymentChannelCloseException.CloseReason reason) {
            if (closeReason != null)
                closeReason = reason;
            socketProtobufHandler.closeConnection();
        }

        @Override public void channelOpen(Sha256Hash contractHash) {
            socketProtobufHandler.setSocketTimeout(0);
            eventHandler.channelOpen(contractHash);
        }

        @Override public ListenableFuture<ByteString> paymentIncrease(Coin by, Coin to, @Nullable ByteString info) {
            return eventHandler.paymentIncrease(by, to, info);
        }

        @Nullable
        @Override
        public ListenableFuture<KeyParameter> getUserKey() {
            return null;
        }
    });

    protobufHandlerListener = new ProtobufConnection.Listener<Protos.TwoWayChannelMessage>() {
        @Override
        public synchronized void messageReceived(ProtobufConnection<Protos.TwoWayChannelMessage> handler, Protos.TwoWayChannelMessage msg) {
            paymentChannelManager.receiveMessage(msg);
        }

        @Override
        public synchronized void connectionClosed(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            paymentChannelManager.connectionClosed();
            if (closeReason != null)
                eventHandler.channelClosed(closeReason);
            else
                eventHandler.channelClosed(PaymentChannelCloseException.CloseReason.CONNECTION_CLOSED);
            eventHandler.setConnectionChannel(null);
        }

        @Override
        public synchronized void connectionOpen(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            ServerConnectionEventHandler eventHandler = eventHandlerFactory.onNewConnection(address);
            if (eventHandler == null)
                handler.closeConnection();
            else {
                ServerHandler.this.eventHandler = eventHandler;
                ServerHandler.this.eventHandler.setConnectionChannel(socketProtobufHandler);
                paymentChannelManager.connectionOpen();
            }
        }
    };

    socketProtobufHandler = new ProtobufConnection<Protos.TwoWayChannelMessage>
            (protobufHandlerListener, Protos.TwoWayChannelMessage.getDefaultInstance(), Short.MAX_VALUE, timeoutSeconds*1000);
}
 
Example 9
Source File: PaymentChannelServerListener.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
public ServerHandler(final SocketAddress address, final int timeoutSeconds) {
    paymentChannelManager = new PaymentChannelServer(broadcaster, wallet, minAcceptedChannelSize, new PaymentChannelServer.ServerConnection() {
        @Override public void sendToClient(Protos.TwoWayChannelMessage msg) {
            socketProtobufHandler.write(msg);
        }

        @Override public void destroyConnection(PaymentChannelCloseException.CloseReason reason) {
            if (closeReason != null)
                closeReason = reason;
            socketProtobufHandler.closeConnection();
        }

        @Override public void channelOpen(Sha256Hash contractHash) {
            socketProtobufHandler.setSocketTimeout(0);
            eventHandler.channelOpen(contractHash);
        }

        @Override public ListenableFuture<ByteString> paymentIncrease(Coin by, Coin to, @Nullable ByteString info) {
            return eventHandler.paymentIncrease(by, to, info);
        }

        @Nullable
        @Override
        public ListenableFuture<KeyParameter> getUserKey() {
            return null;
        }
    });

    protobufHandlerListener = new ProtobufConnection.Listener<Protos.TwoWayChannelMessage>() {
        @Override
        public synchronized void messageReceived(ProtobufConnection<Protos.TwoWayChannelMessage> handler, Protos.TwoWayChannelMessage msg) {
            paymentChannelManager.receiveMessage(msg);
        }

        @Override
        public synchronized void connectionClosed(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            paymentChannelManager.connectionClosed();
            if (closeReason != null)
                eventHandler.channelClosed(closeReason);
            else
                eventHandler.channelClosed(PaymentChannelCloseException.CloseReason.CONNECTION_CLOSED);
            eventHandler.setConnectionChannel(null);
        }

        @Override
        public synchronized void connectionOpen(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            ServerConnectionEventHandler eventHandler = eventHandlerFactory.onNewConnection(address);
            if (eventHandler == null)
                handler.closeConnection();
            else {
                ServerHandler.this.eventHandler = eventHandler;
                ServerHandler.this.eventHandler.setConnectionChannel(socketProtobufHandler);
                paymentChannelManager.connectionOpen();
            }
        }
    };

    socketProtobufHandler = new ProtobufConnection<Protos.TwoWayChannelMessage>
            (protobufHandlerListener, Protos.TwoWayChannelMessage.getDefaultInstance(), Short.MAX_VALUE, timeoutSeconds*1000);
}
 
Example 10
Source File: PaymentChannelClientConnection.java    From green_android with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Attempts to open a new connection to and open a payment channel with the given host and port, blocking until the
 * connection is open.  The server is requested to keep the channel open for {@param timeWindow}
 * seconds. If the server proposes a longer time the channel will be closed.
 *
 * @param server The host/port pair where the server is listening.
 * @param timeoutSeconds The connection timeout and read timeout during initialization. This should be large enough
 *                       to accommodate ECDSA signature operations and network latency.
 * @param wallet The wallet which will be paid from, and where completed transactions will be committed.
 *               Can be encrypted if user key is supplied when needed. Must already have a
 *               {@link StoredPaymentChannelClientStates} object in its extensions set.
 * @param myKey A freshly generated keypair used for the multisig contract and refund output.
 * @param maxValue The maximum value this channel is allowed to request
 * @param serverId A unique ID which is used to attempt reopening of an existing channel.
 *                 This must be unique to the server, and, if your application is exposing payment channels to some
 *                 API, this should also probably encompass some caller UID to avoid applications opening channels
 *                 which were created by others.
 * @param userKeySetup Key derived from a user password, used to decrypt myKey, if it is encrypted, during setup.
 * @param clientChannelProperties Modifier to change the channel's configuration.
 *
 * @throws IOException if there's an issue using the network.
 * @throws ValueOutOfRangeException if the balance of wallet is lower than maxValue.
 */
public PaymentChannelClientConnection(InetSocketAddress server, int timeoutSeconds, Wallet wallet, ECKey myKey,
                                      Coin maxValue, String serverId,
                                      @Nullable KeyParameter userKeySetup, final ClientChannelProperties clientChannelProperties)
        throws IOException, ValueOutOfRangeException {
    // Glue the object which vends/ingests protobuf messages in order to manage state to the network object which
    // reads/writes them to the wire in length prefixed form.
    channelClient = new PaymentChannelClient(wallet, myKey, maxValue, Sha256Hash.of(serverId.getBytes()),
            userKeySetup, clientChannelProperties, new PaymentChannelClient.ClientConnection() {
        @Override
        public void sendToServer(Protos.TwoWayChannelMessage msg) {
            wireParser.write(msg);
        }

        @Override
        public void destroyConnection(PaymentChannelCloseException.CloseReason reason) {
            channelOpenFuture.setException(new PaymentChannelCloseException("Payment channel client requested that the connection be closed: " + reason, reason));
            wireParser.closeConnection();
        }

        @Override
        public boolean acceptExpireTime(long expireTime) {
            return expireTime <= (clientChannelProperties.timeWindow() + Utils.currentTimeSeconds() + 60);  // One extra minute to compensate for time skew and latency
        }

        @Override
        public void channelOpen(boolean wasInitiated) {
            wireParser.setSocketTimeout(0);
            // Inform the API user that we're done and ready to roll.
            channelOpenFuture.set(PaymentChannelClientConnection.this);
        }
    });

    // And glue back in the opposite direction - network to the channelClient.
    wireParser = new ProtobufConnection<Protos.TwoWayChannelMessage>(new ProtobufConnection.Listener<Protos.TwoWayChannelMessage>() {
        @Override
        public void messageReceived(ProtobufConnection<Protos.TwoWayChannelMessage> handler, Protos.TwoWayChannelMessage msg) {
            try {
                channelClient.receiveMessage(msg);
            } catch (InsufficientMoneyException e) {
                // We should only get this exception during INITIATE, so channelOpen wasn't called yet.
                channelOpenFuture.setException(e);
            }
        }

        @Override
        public void connectionOpen(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            channelClient.connectionOpen();
        }

        @Override
        public void connectionClosed(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            channelClient.connectionClosed();
            channelOpenFuture.setException(new PaymentChannelCloseException("The TCP socket died",
                    PaymentChannelCloseException.CloseReason.CONNECTION_CLOSED));
        }
    }, Protos.TwoWayChannelMessage.getDefaultInstance(), Short.MAX_VALUE, timeoutSeconds*1000);

    // Initiate the outbound network connection. We don't need to keep this around. The wireParser object will handle
    // things from here on out.
    new NioClient(server, wireParser, timeoutSeconds * 1000);
}
 
Example 11
Source File: ChannelTestUtils.java    From bcm-android with GNU General Public License v3.0 4 votes vote down vote up
public Protos.TwoWayChannelMessage checkNextMsg(Protos.TwoWayChannelMessage.MessageType expectedType) throws InterruptedException {
    Protos.TwoWayChannelMessage msg = getNextMsg();
    assertEquals(expectedType, msg.getType());
    return msg;
}
 
Example 12
Source File: ChannelTestUtils.java    From bcm-android with GNU General Public License v3.0 4 votes vote down vote up
@Override
public void sendToClient(Protos.TwoWayChannelMessage msg) {
    q.add(msg);
}
 
Example 13
Source File: ChannelTestUtils.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
public Protos.TwoWayChannelMessage checkNextMsg(Protos.TwoWayChannelMessage.MessageType expectedType) throws InterruptedException {
    Protos.TwoWayChannelMessage msg = getNextMsg();
    assertEquals(expectedType, msg.getType());
    return msg;
}
 
Example 14
Source File: ChannelTestUtils.java    From green_android with GNU General Public License v3.0 4 votes vote down vote up
@Override
public void sendToClient(Protos.TwoWayChannelMessage msg) {
    q.add(msg);
}
 
Example 15
Source File: PaymentChannelServer.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
@GuardedBy("lock")
private void receiveVersionMessage(Protos.TwoWayChannelMessage msg) throws VerificationException {
    checkState(step == InitStep.WAITING_ON_CLIENT_VERSION && msg.hasClientVersion());
    final Protos.ClientVersion clientVersion = msg.getClientVersion();
    majorVersion = clientVersion.getMajor();
    if (!SERVER_VERSIONS.containsKey(majorVersion)) {
        error("This server needs one of protocol versions " + SERVER_VERSIONS.keySet() + " , client offered " + majorVersion,
                Protos.Error.ErrorCode.NO_ACCEPTABLE_VERSION, CloseReason.NO_ACCEPTABLE_VERSION);
        return;
    }

    Protos.ServerVersion.Builder versionNegotiationBuilder = Protos.ServerVersion.newBuilder()
            .setMajor(majorVersion).setMinor(SERVER_VERSIONS.get(majorVersion));
    conn.sendToClient(Protos.TwoWayChannelMessage.newBuilder()
            .setType(Protos.TwoWayChannelMessage.MessageType.SERVER_VERSION)
            .setServerVersion(versionNegotiationBuilder)
            .build());
    ByteString reopenChannelContractHash = clientVersion.getPreviousChannelContractHash();
    if (reopenChannelContractHash != null && reopenChannelContractHash.size() == 32) {
        Sha256Hash contractHash = Sha256Hash.wrap(reopenChannelContractHash.toByteArray());
        log.info("New client that wants to resume {}", contractHash);
        StoredPaymentChannelServerStates channels = (StoredPaymentChannelServerStates)
                wallet.getExtensions().get(StoredPaymentChannelServerStates.EXTENSION_ID);
        if (channels != null) {
            StoredServerChannel storedServerChannel = channels.getChannel(contractHash);
            if (storedServerChannel != null) {
                final PaymentChannelServer existingHandler = storedServerChannel.setConnectedHandler(this, false);
                if (existingHandler != this) {
                    log.warn("  ... and that channel is already in use, disconnecting other user.");
                    existingHandler.close();
                    storedServerChannel.setConnectedHandler(this, true);
                }

                log.info("Got resume version message, responding with VERSIONS and CHANNEL_OPEN");
                state = storedServerChannel.getOrCreateState(wallet, broadcaster);
                step = InitStep.CHANNEL_OPEN;
                conn.sendToClient(Protos.TwoWayChannelMessage.newBuilder()
                        .setType(Protos.TwoWayChannelMessage.MessageType.CHANNEL_OPEN)
                        .build());
                conn.channelOpen(contractHash);
                return;
            } else {
                log.error(" ... but we do not have any record of that contract! Resume failed.");
            }
        } else {
            log.error(" ... but we do not have any stored channels! Resume failed.");
        }
    }
    log.info("Got initial version message, responding with VERSIONS and INITIATE: min value={}",
            minAcceptedChannelSize.value);

    myKey = new ECKey();
    wallet.freshReceiveKey();

    expireTime = Utils.currentTimeSeconds() + truncateTimeWindow(clientVersion.getTimeWindowSecs());
    switch (majorVersion) {
        case 1:
            step = InitStep.WAITING_ON_UNSIGNED_REFUND;
            break;
        case 2:
            step = InitStep.WAITING_ON_CONTRACT;
            break;
        default:
            error("Protocol version " + majorVersion + " not supported", Protos.Error.ErrorCode.NO_ACCEPTABLE_VERSION, CloseReason.NO_ACCEPTABLE_VERSION);
            break;
    }

    Protos.Initiate.Builder initiateBuilder = Protos.Initiate.newBuilder()
            .setMultisigKey(ByteString.copyFrom(myKey.getPubKey()))
            .setExpireTimeSecs(expireTime)
            .setMinAcceptedChannelSize(minAcceptedChannelSize.value)
            .setMinPayment(minPayment.value);

    conn.sendToClient(Protos.TwoWayChannelMessage.newBuilder()
            .setInitiate(initiateBuilder)
            .setType(Protos.TwoWayChannelMessage.MessageType.INITIATE)
            .build());
}
 
Example 16
Source File: ChannelTestUtils.java    From green_android with GNU General Public License v3.0 4 votes vote down vote up
public Protos.TwoWayChannelMessage checkNextMsg(Protos.TwoWayChannelMessage.MessageType expectedType) throws InterruptedException {
    Protos.TwoWayChannelMessage msg = getNextMsg();
    assertEquals(expectedType, msg.getType());
    return msg;
}
 
Example 17
Source File: PaymentChannelClientConnection.java    From bcm-android with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Attempts to open a new connection to and open a payment channel with the given host and port, blocking until the
 * connection is open.  The server is requested to keep the channel open for {@code timeoutSeconds}
 * seconds. If the server proposes a longer time the channel will be closed.
 *
 * @param server                  The host/port pair where the server is listening.
 * @param timeoutSeconds          The connection timeout and read timeout during initialization. This should be large enough
 *                                to accommodate ECDSA signature operations and network latency.
 * @param wallet                  The wallet which will be paid from, and where completed transactions will be committed.
 *                                Can be encrypted if user key is supplied when needed. Must already have a
 *                                {@link StoredPaymentChannelClientStates} object in its extensions set.
 * @param myKey                   A freshly generated keypair used for the multisig contract and refund output.
 * @param maxValue                The maximum value this channel is allowed to request
 * @param serverId                A unique ID which is used to attempt reopening of an existing channel.
 *                                This must be unique to the server, and, if your application is exposing payment channels to some
 *                                API, this should also probably encompass some caller UID to avoid applications opening channels
 *                                which were created by others.
 * @param userKeySetup            Key derived from a user password, used to decrypt myKey, if it is encrypted, during setup.
 * @param clientChannelProperties Modifier to change the channel's configuration.
 * @throws IOException              if there's an issue using the network.
 * @throws ValueOutOfRangeException if the balance of wallet is lower than maxValue.
 */
public PaymentChannelClientConnection(InetSocketAddress server, int timeoutSeconds, Wallet wallet, ECKey myKey,
                                      Coin maxValue, String serverId,
                                      @Nullable KeyParameter userKeySetup, final ClientChannelProperties clientChannelProperties)
        throws IOException, ValueOutOfRangeException {
    // Glue the object which vends/ingests protobuf messages in order to manage state to the network object which
    // reads/writes them to the wire in length prefixed form.
    channelClient = new PaymentChannelClient(wallet, myKey, maxValue, Sha256Hash.of(serverId.getBytes()),
            userKeySetup, clientChannelProperties, new PaymentChannelClient.ClientConnection() {
        @Override
        public void sendToServer(Protos.TwoWayChannelMessage msg) {
            wireParser.write(msg);
        }

        @Override
        public void destroyConnection(PaymentChannelCloseException.CloseReason reason) {
            channelOpenFuture.setException(new PaymentChannelCloseException("Payment channel client requested that the connection be closed: " + reason, reason));
            wireParser.closeConnection();
        }

        @Override
        public boolean acceptExpireTime(long expireTime) {
            return expireTime <= (clientChannelProperties.timeWindow() + Utils.currentTimeSeconds() + 60);  // One extra minute to compensate for time skew and latency
        }

        @Override
        public void channelOpen(boolean wasInitiated) {
            wireParser.setSocketTimeout(0);
            // Inform the API user that we're done and ready to roll.
            channelOpenFuture.set(PaymentChannelClientConnection.this);
        }
    });

    // And glue back in the opposite direction - network to the channelClient.
    wireParser = new ProtobufConnection<Protos.TwoWayChannelMessage>(new ProtobufConnection.Listener<Protos.TwoWayChannelMessage>() {
        @Override
        public void messageReceived(ProtobufConnection<Protos.TwoWayChannelMessage> handler, Protos.TwoWayChannelMessage msg) {
            try {
                channelClient.receiveMessage(msg);
            } catch (InsufficientMoneyException e) {
                // We should only get this exception during INITIATE, so channelOpen wasn't called yet.
                channelOpenFuture.setException(e);
            }
        }

        @Override
        public void connectionOpen(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            channelClient.connectionOpen();
        }

        @Override
        public void connectionClosed(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            channelClient.connectionClosed();
            channelOpenFuture.setException(new PaymentChannelCloseException("The TCP socket died",
                    PaymentChannelCloseException.CloseReason.CONNECTION_CLOSED));
        }
    }, Protos.TwoWayChannelMessage.getDefaultInstance(), Short.MAX_VALUE, timeoutSeconds * 1000);

    // Initiate the outbound network connection. We don't need to keep this around. The wireParser object will handle
    // things from here on out.
    new NioClient(server, wireParser, timeoutSeconds * 1000);
}
 
Example 18
Source File: IPaymentChannelClient.java    From bcm-android with GNU General Public License v3.0 2 votes vote down vote up
/**
 * <p>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.</p>
 * <p>
 * <p>If the send fails, no exception should be thrown, however
 * {@link 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 <i>after</i> the failed payment.</p>
 * <p>
 * <p>Called while holding a lock on the {@link PaymentChannelClient} object - be careful about reentrancy</p>
 */
void sendToServer(Protos.TwoWayChannelMessage msg);
 
Example 19
Source File: PaymentChannelServer.java    From green_android with GNU General Public License v3.0 2 votes vote down vote up
/**
 * <p>Requests that the given message be sent to the client. There are no blocking requirements for this method,
 * however the order of messages must be preserved.</p>
 *
 * <p>If the send fails, no exception should be thrown, however
 * {@link PaymentChannelServer#connectionClosed()} should be called immediately.</p>
 *
 * <p>Called while holding a lock on the {@link PaymentChannelServer} object - be careful about reentrancy</p>
 */
void sendToClient(Protos.TwoWayChannelMessage msg);
 
Example 20
Source File: IPaymentChannelClient.java    From GreenBits with GNU General Public License v3.0 2 votes vote down vote up
/**
 * 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;