Blockchain By Example
上QQ阅读APP看书,第一时间看更新

Requesting payment details

As defined by the protocol, when the customer clicks on the payment link, its wallet (bitcoin client) will request the /request endpoint to get the merchant's payment request with all the necessary data:

  var urlencodedParser = bodyParser.urlencoded({ extended: false });
app.get("/request", urlencodedParser, function(req, res) {
var amount = req.query.amount;
amount = (amount === undefined) ? 0 : amount; // set amount to 0 if undefined
var merchant_outputs = []; // Where payment should be sent
var outputs = new PaymentProtocol().makeOutput();
outputs.set('amount', amount);
var script = bitcore_lib.Script.buildPublicKeyHashOut(Merchant_address.toString());
outputs.set('script', script.toBuffer());
merchant_outputs.push(outputs.message);
});

Here, the merchant's server constructs a P2PKH transaction with the amount handed from the client side. Then, within the same route, we wrap inside a PaymentRequest message with relevant details about the payment as follows:

var details = new PaymentProtocol().makePaymentDetails();
var now = Date.now() / 1000 | 0;
details.set('network', 'test');
details.set('outputs', merchant_outputs);
details.set('time', now); //Unix timestamp when the PaymentRequest was created.
details.set('expires', now + 60 * 60 * 24); //timestamp after which the PaymentRequest should be considered invalid.
details.set('memo', 'A payment request from the merchant.');
details.set('payment_url', "http://"+IP+":"+http_port+"/payment?id=12345"); //location where a Payment message may be sent to obtain a PaymentACK.
details.set('merchant_data', new Buffer("Transaction N 12345")); //identify the payment request

For more information about these fields, you can visit the official BIP 70 documentation (https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#paymentdetailspaymentrequest). After defining the payment request details, we form the final request as follows:

 var request = new PaymentProtocol().makePaymentRequest();
request.set('payment_details_version', 1);
var certificates = new PaymentProtocol().makeX509Certificates();
certificates.set('certificate',dcert);
request.set('pki_type', 'x509+sha256');
request.set('pki_data', certificates.serialize());
request.set('serialized_payment_details', details.serialize());
request.sign(mkey);
var rawbody = request.serialize(); // serialize the request
res.set({
'Content-Type': PaymentProtocol.PAYMENT_REQUEST_CONTENT_TYPE,
'Content-Length': request.length,
'Content-Transfer-Encoding': 'binary'
});

A PaymentRequest is optionally tied to a merchant's identity using  public-key infrastructure (PKI) specified in pki_type. We sign it using the private key that corresponds to the public key in pki_data before forwarding it to the client side. The response format changes depending on the requester, be it a bitcoin client or a browser:

if (req.query.browser==1) {
var buf = new Buffer(rawbody, 'binary').toString('base64');
res.contentType(PaymentProtocol.PAYMENT_REQUEST_CONTENT_TYPE);
res.send(buf);
} else {
//response for bitcoin core client
res.status(200).send(rawbody);
}