/**
  * Parse transactions from payment message.
  *
  * @param params network parameters (needed for transaction deserialization)
  * @param paymentMessage payment message to parse
  * @return list of transactions
  */
 public static List<Transaction> parseTransactionsFromPaymentMessage(
     NetworkParameters params, Protos.Payment paymentMessage) {
   final List<Transaction> transactions =
       new ArrayList<Transaction>(paymentMessage.getTransactionsCount());
   for (final ByteString transaction : paymentMessage.getTransactionsList())
     transactions.add(params.getDefaultSerializer().makeTransaction(transaction.toByteArray()));
   return transactions;
 }
  @Test
  public void testPaymentAck() throws Exception {
    // Create
    Payment paymentMessage = Protos.Payment.newBuilder().build();
    PaymentACK paymentAck = PaymentProtocol.createPaymentAck(paymentMessage, MEMO);
    byte[] paymentAckBytes = paymentAck.toByteArray();

    // Parse
    PaymentACK parsedPaymentAck = PaymentACK.parseFrom(paymentAckBytes);
    assertEquals(paymentMessage, parsedPaymentAck.getPayment());
    assertEquals(MEMO, parsedPaymentAck.getMemo());
  }
  @Test
  public void testSimplePayment() throws Exception {
    // Create a PaymentRequest and make sure the correct values are parsed by the PaymentSession.
    MockPaymentSession paymentSession = new MockPaymentSession(newSimplePaymentRequest());
    assertEquals(paymentRequestMemo, paymentSession.getMemo());
    assertEquals(nanoCoins, paymentSession.getValue());
    assertEquals(simplePaymentUrl, paymentSession.getPaymentUrl());
    assertTrue(new Date(time * 1000L).equals(paymentSession.getDate()));
    assertTrue(paymentSession.getSendRequest().tx.equals(tx));
    assertFalse(paymentSession.isExpired());

    // Send the payment and verify that the correct information is sent.
    // Add a dummy input to tx so it is considered valid.
    tx.addInput(new TransactionInput(params, tx, outputToMe.getScriptBytes()));
    ArrayList<Transaction> txns = new ArrayList<Transaction>();
    txns.add(tx);
    Address refundAddr = new Address(params, serverKey.getPubKeyHash());
    paymentSession.sendPayment(txns, refundAddr, paymentMemo);
    assertEquals(1, paymentSession.getPaymentLog().size());
    assertEquals(simplePaymentUrl, paymentSession.getPaymentLog().get(0).getUrl().toString());
    Protos.Payment payment = paymentSession.getPaymentLog().get(0).getPayment();
    assertEquals(paymentMemo, payment.getMemo());
    assertEquals(merchantData, payment.getMerchantData());
    assertEquals(1, payment.getRefundToCount());
    assertEquals(nanoCoins.longValue(), payment.getRefundTo(0).getAmount());
    TransactionOutput refundOutput = new TransactionOutput(params, null, nanoCoins, refundAddr);
    ByteString refundScript = ByteString.copyFrom(refundOutput.getScriptBytes());
    assertTrue(refundScript.equals(payment.getRefundTo(0).getScript()));
  }
 /**
  * Create a payment message. This wraps up transaction data along with anything else useful for
  * making a payment.
  *
  * @param transactions transactions to include with the payment message
  * @param refundOutputs list of outputs to refund coins to, or null
  * @param memo arbitrary, user readable memo, or null if none
  * @param merchantData arbitrary merchant data, or null if none
  * @return created payment message
  */
 public static Protos.Payment createPaymentMessage(
     List<Transaction> transactions,
     @Nullable List<Protos.Output> refundOutputs,
     @Nullable String memo,
     @Nullable byte[] merchantData) {
   Protos.Payment.Builder builder = Protos.Payment.newBuilder();
   for (Transaction transaction : transactions) {
     transaction.verify();
     builder.addTransactions(ByteString.copyFrom(transaction.unsafeBitcoinSerialize()));
   }
   if (refundOutputs != null) {
     for (Protos.Output output : refundOutputs) builder.addRefundTo(output);
   }
   if (memo != null) builder.setMemo(memo);
   if (merchantData != null) builder.setMerchantData(ByteString.copyFrom(merchantData));
   return builder.build();
 }
Beispiel #5
0
 /**
  * Generates a Payment message based on the information in the PaymentRequest. Provide
  * transactions built by the wallet. If the PaymentRequest did not specify a payment_url, returns
  * null.
  *
  * @param txns list of transactions to be included with the Payment message.
  * @param refundAddr will be used by the merchant to send money back if there was a problem.
  * @param memo is a message to include in the payment message sent to the merchant.
  */
 public @Nullable Protos.Payment getPayment(
     List<Transaction> txns, @Nullable Address refundAddr, @Nullable String memo)
     throws IOException {
   if (!paymentDetails.hasPaymentUrl()) return null;
   Protos.Payment.Builder payment = Protos.Payment.newBuilder();
   if (paymentDetails.hasMerchantData()) payment.setMerchantData(paymentDetails.getMerchantData());
   if (refundAddr != null) {
     Protos.Output.Builder refundOutput = Protos.Output.newBuilder();
     refundOutput.setAmount(totalValue.longValue());
     refundOutput.setScript(
         ByteString.copyFrom(ScriptBuilder.createOutputScript(refundAddr).getProgram()));
     payment.addRefundTo(refundOutput);
   }
   if (memo != null) {
     payment.setMemo(memo);
   }
   for (Transaction txn : txns) {
     txn.verify();
     ByteArrayOutputStream o = new ByteArrayOutputStream();
     txn.bitcoinSerialize(o);
     payment.addTransactions(ByteString.copyFrom(o.toByteArray()));
   }
   return payment.build();
 }
  @Override
  public Boolean call() {

    if (serverSocket.isClosed()) {
      log.warn("Server socket is closed. Aborting.");
      return false;
    } else {

      try {
        // Wait for a client connection
        log.debug("Await client connection to SSLSocket");
        SSLSocket socket = (SSLSocket) serverSocket.accept();
        socket.startHandshake();

        log.debug("Sending PaymentACK");
        InputStream inputStream = socket.getInputStream();
        OutputStream outputStream = socket.getOutputStream();

        // Read the inputStream - this is expected to be a header followed by a serialised Payment
        Reader reader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(reader);
        String line;
        int contentLength = -1;
        StringBuilder builder = new StringBuilder();
        while (!"".equals((line = bufferedReader.readLine()))) {
          builder.append(line).append("\n");
          log.debug("Read line: {}", line);
          if (line.startsWith("Content-Length")) {
            String[] tokens = line.replaceAll(" ", "").split(":");
            if (tokens.length >= 2) {
              contentLength = Integer.parseInt(tokens[1]);
            }
          }
        }
        log.debug("Calculated contentLength: {}", contentLength);
        log.debug("Read the header:\n{}\n", builder.toString());

        // Get the Content-Length and read those - this is expected to be the serialised Payment
        if (contentLength > -1) {
          byte buffer[] = new byte[contentLength];
          for (int i = 0; i < contentLength; i++) {
            buffer[i] = (byte) inputStream.read();
          }

          log.debug("Read:\n", HexUtils.toHexBytes(buffer));

          try {
            Protos.Payment payment = Protos.Payment.parseFrom(buffer);

            log.debug("Successfully parsed a payment {}", payment);

            // Create a PaymentACK for the payment
            Protos.PaymentACK paymentAck =
                PaymentProtocol.createPaymentAck(payment, "You sent: '" + payment.getMemo() + "'");

            log.debug("Sending paymentACK as a response: {}", paymentAck);
            // Write the HTTP header
            outputStream.write("HTTP/1.0 200 OK\n".getBytes(Charsets.UTF_8));
            outputStream.write("Content-Type: ".getBytes(Charsets.UTF_8));
            outputStream.write(contentType.getBytes(Charsets.UTF_8));
            outputStream.write("\n\n".getBytes(Charsets.UTF_8));

            // Write the protobuf response
            paymentAck.writeTo(outputStream);

            // ByteArrayInputStream responseInputStream = new ByteArrayInputStream(paymentAckBytes);
            // ByteStreams.copy(responseInputStream, outputStream);

          } catch (com.google.protobuf.InvalidProtocolBufferException ipbe) {
            log.error("Was expecting a Payment on the socket but saw something else");
            ipbe.printStackTrace();
          } catch (Exception e) {
            e.printStackTrace();
          } finally {
            // Release resources
            log.debug("Flush then close client socket...");
            socket.getOutputStream().flush();
            socket.close();
          }
        } else {
          log.debug("Could not find a Content-Length in the header so not reading payment");
        }
        return true;

      } catch (IOException e) {
        throw new IllegalStateException("Unexpected IOException", e);
      }
    }
  }