Skip to content

Instantly share code, notes, and snippets.

@homura
Created May 8, 2022 15:07
Show Gist options
  • Save homura/ad64330e43a09a4c65f1bc70d2d9f9fe to your computer and use it in GitHub Desktop.
Save homura/ad64330e43a09a4c65f1bc70d2d9f9fe to your computer and use it in GitHub Desktop.
BTC payment protocols

image

Related BIP

  • BIP20 已经被 BIP21 替换,看了下有些冗余,并且没有考虑到客户端实现不一致的情况
  • BIP21 目前适用性最广的 payment URI
  • BIP70 由于各种原因已经从 bitcoin@20.0 中被移除了,但感觉有一些参考价值

BIP21

BIP21 是一个 URI Schema,目的是让用户只需要通过点击或者扫码就可以进行支付

最佳实践是针对每一笔支付,生成一个新地址,URI 是 payment 的 identity 而不是个体的 identity

URI 语法

 bitcoinurn     = "bitcoin:" bitcoinaddress [ "?" bitcoinparams ]
 bitcoinaddress = *base58
 bitcoinparams  = bitcoinparam [ "&" bitcoinparams ]
 bitcoinparam   = [ amountparam / labelparam / messageparam / otherparam / reqparam ]
 amountparam    = "amount=" *digit [ "." *digit ]
 labelparam     = "label=" *qchar
 messageparam   = "message=" *qchar
 otherparam     = qchar *qchar [ "=" *qchar ]
 reqparam       = "req-" qchar *qchar [ "=" *qchar ]

这是一个向 Luke-Jr 支付 20.3 BTC 的例子,并附言 "Donation for project xyz"

bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=50&label=Luke-Jr&message=Donation%20for%20project%20xyz

有个需要留意的点是,由于客户端实现可能有不同用途,如果 req- 开头的 param 客户端无法识别,则视为这是一个无效的 URI

BIP70

虽然 BIP70 被移除了,但里面提到的一些问题可能值得留意 BIP21 是一个简介的协议,在支付过程中还会遇到一些痛点,为了解决这些痛点

  • BTC 地址是一串人类不可读的字符,这给中间人攻击留下了空间
  • 可能与支付商家发生纠纷
  • 支付可能发生退款的情况

BIP70 通过 X.509 来解决中间人攻击以及人类不可读的 BTC 地址的问题,并且在支付时就早早将退款地址作为支付请求发给了商户

发现 BTC 社区其实非常地在意去中心化, X.509 的引入相当于将国家或者政府机构作为信任中心了,猜测很大可能是因此废弃的

而且钱包的实现组织认为 BIP70 看起来更像是一个 加密数字货币钱包的协议,而不是 BTC 钱包协议,这给实现带来了更大的不确定性

package payments;
option java_package = "org.bitcoin.protocols.payments";
option java_outer_classname = "Protos";

// Generalized form of "send payment to this/these bitcoin addresses"
message Output {
        optional uint64 amount = 1 [default = 0]; // amount is integer-number-of-satoshis
        required bytes script = 2; // usually one of the standard Script forms
}
message PaymentDetails {
        optional string network = 1 [default = "main"]; // "main" or "test"
        repeated Output outputs = 2;        // Where payment should be sent
        required uint64 time = 3;           // Timestamp; when payment request created
        optional uint64 expires = 4;        // Timestamp; when this request should be considered invalid
        optional string memo = 5;           // Human-readable description of request for the customer
        optional string payment_url = 6;    // URL to send Payment and get PaymentACK
        optional bytes merchant_data = 7;   // Arbitrary data to include in the Payment message
}
message PaymentRequest {
        optional uint32 payment_details_version = 1 [default = 1];
        optional string pki_type = 2 [default = "none"];  // none / x509+sha256 / x509+sha1
        optional bytes pki_data = 3;                      // depends on pki_type
        required bytes serialized_payment_details = 4;    // PaymentDetails
        optional bytes signature = 5;                     // pki-dependent signature
}
message X509Certificates {
        repeated bytes certificate = 1;    // DER-encoded X.509 certificate chain
}
message Payment {
        optional bytes merchant_data = 1;  // From PaymentDetails.merchant_data
        repeated bytes transactions = 2;   // Signed transactions that satisfy PaymentDetails.outputs
        repeated Output refund_to = 3;     // Where to send refunds, if a refund is necessary
        optional string memo = 4;          // Human-readable message for the merchant
}
message PaymentACK {
        required Payment payment = 1;      // Payment message that triggered this ACK
        optional string memo = 2;          // human-readable message for customer
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment