private void multisigContractPropogated( Protos.ProvideContract providedContract, Sha256Hash contractHash) { lock.lock(); try { if (!connectionOpen || channelSettling) return; state.storeChannelInWallet(PaymentChannelServer.this); try { receiveUpdatePaymentMessage(providedContract.getInitialPayment(), false /* no ack msg */); } catch (VerificationException e) { log.error("Initial payment failed to verify", e); error( e.getMessage(), Protos.Error.ErrorCode.BAD_TRANSACTION, CloseReason.REMOTE_SENT_INVALID_MESSAGE); return; } catch (ValueOutOfRangeException e) { log.error("Initial payment value was out of range", e); error( e.getMessage(), Protos.Error.ErrorCode.BAD_TRANSACTION, CloseReason.REMOTE_SENT_INVALID_MESSAGE); return; } catch (InsufficientMoneyException e) { // This shouldn't happen because the server shouldn't allow itself to get into this // situation in the // first place, by specifying a min up front payment. log.error( "Tried to settle channel and could not afford the fees whilst updating payment", e); error( e.getMessage(), Protos.Error.ErrorCode.BAD_TRANSACTION, CloseReason.REMOTE_SENT_INVALID_MESSAGE); return; } conn.sendToClient( Protos.TwoWayChannelMessage.newBuilder() .setType(Protos.TwoWayChannelMessage.MessageType.CHANNEL_OPEN) .build()); step = InitStep.CHANNEL_OPEN; conn.channelOpen(contractHash); } finally { lock.unlock(); } }
@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(); final int major = clientVersion.getMajor(); if (major != SERVER_MAJOR_VERSION) { error( "This server needs protocol version " + SERVER_MAJOR_VERSION + " , client offered " + major, Protos.Error.ErrorCode.NO_ACCEPTABLE_VERSION, CloseReason.NO_ACCEPTABLE_VERSION); return; } Protos.ServerVersion.Builder versionNegotiationBuilder = Protos.ServerVersion.newBuilder() .setMajor(SERVER_MAJOR_VERSION) .setMinor(SERVER_MINOR_VERSION); 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 = new Sha256Hash(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()); step = InitStep.WAITING_ON_UNSIGNED_REFUND; Protos.Initiate.Builder initiateBuilder = Protos.Initiate.newBuilder() .setMultisigKey(ByteString.copyFrom(myKey.getPubKey())) .setExpireTimeSecs(expireTime) .setMinAcceptedChannelSize(minAcceptedChannelSize.value) .setMinPayment(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.value); conn.sendToClient( Protos.TwoWayChannelMessage.newBuilder() .setInitiate(initiateBuilder) .setType(Protos.TwoWayChannelMessage.MessageType.INITIATE) .build()); }