Merge remote-tracking branch 'harding/generatingtxes'

This commit is contained in:
David A. Harding 2014-06-10 13:51:27 -04:00
commit b428cbde26
No known key found for this signature in database
GPG key ID: 4B29C30FF29EC4B7
18 changed files with 2135 additions and 755 deletions

View file

@ -127,14 +127,11 @@ parent key:
parent private key:
parent private and public keys: parent key
parent public key:
Payment message: pp payment
payment protocol:
"payment protocol's": payment protocol
PaymentACK:
PaymentDetails:
PaymentRequest:
PaymentRequests: paymentrequest
'`payment_url`': pp payment url
peer:
peers: peer
peer-to-peer network: network
@ -160,7 +157,6 @@ recurrent rebilling:
redeemScript:
refund:
refunds: refund
'`refund_to`': pp refund to
root certificate:
root seed:
RPCs: rpc
@ -222,6 +218,8 @@ BIP21:
BIP32:
BIP39:
BIP70:
BIP71:
BIP72:
## RPCs
'`addmultisigaddress`': rpc addmultisigaddress

View file

@ -0,0 +1,455 @@
## Payment Processing
### Payment Protocol
{% autocrossref %}
To request payment using the payment protocol, you use an extended (but
backwards-compatible) `bitcoin:` URI. For example:
~~~
bitcoin:mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN\
?amount=0.10\
&label=Example+Merchant\
&message=Order+of+flowers+%26+chocolates\
&r=https://example.com/pay.php/invoice%3Dda39a3ee
~~~
The browser, QR code reader, or other program processing the URI opens
the spender's Bitcoin wallet program on the URI. If the wallet program is
aware of the payment protocol, it accesses the URL specified in the `r`
parameter, which should provide it with a serialized PaymentRequest
served with the [MIME][] type `application/bitcoin-paymentrequest`<!--noref-->.
**Resource:** Gavin Andresen's [Payment Request Generator][] generates
custom example URIs and payment requests for use with testnet.
{% endautocrossref %}
#### PaymentRequest & PaymentDetails
{% autocrossref %}
The [PaymentRequest][]{:#term-paymentrequest}{:.term} is created with data structures built using
Google's Protocol Buffers. BIP70 describes these data
structures in the non-sequential way they're defined in the payment
request protocol buffer code, but the text below will describe them in
a more linear order using a simple (but functional) Python CGI
program. (For brevity and clarity, many normal CGI best practices are
not used in this program.)
The full sequence of events is illustrated below, starting with the
spender clicking a `bitcoin:` URI or scanning a `bitcoin:` QR code.
![BIP70 Payment Protocol](/img/dev/en-payment-protocol.svg)
For the script to use the protocol buffer, you will need a copy of
Google's Protocol Buffer compiler (`protoc`), which is available in most
modern Linux package managers and [directly from Google.][protobuf] Non-Google
protocol buffer compilers are available for a variety of
programming languages. You will also need a copy of the PaymentRequest
[Protocol Buffer description][core paymentrequest.proto] from the Bitcoin Core source code.
{% endautocrossref %}
##### Initialization Code
{% autocrossref %}
With the Python code generated by `protoc`, we can start our simple
CGI program.
{% highlight python %}
#!/usr/bin/env python
## This is the code generated by protoc --python_out=./ paymentrequest.proto
from paymentrequest_pb2 import *
## Load some functions
from time import time
from sys import stdout
from OpenSSL.crypto import FILETYPE_PEM, load_privatekey, sign
## Copy three of the classes created by protoc into objects we can use
details = PaymentDetails()
request = PaymentRequest()
x509 = X509Certificates()
{% endhighlight %}
The startup code above is quite simple, requiring nothing but the epoch
(Unix date) time function, the standard out file descriptor, a few
functions from the OpenSSL library, and the data structures and
functions created by `protoc`.
{% endautocrossref %}
##### Configuration Code
{% autocrossref %}
Next, we'll set configuration settings which will typically only change
when the receiver wants to do something differently. The code pushes a
few settings into the `request` (PaymentRequest) and `details`
(PaymentDetails) objects. When we serialize them,
[PaymentDetails][]{:#term-paymentdetails}{:.term} will be contained
within the PaymentRequest.
{% highlight python %}
## SSL Signature method
request.pki_type = "x509+sha256" ## Default: none
## Mainnet or Testnet?
details.network = "test" ## Default: main
## Postback URL
details.payment_url = "https://example.com/pay.py"
## PaymentDetails version number
request.payment_details_version = 1 ## Default: 1
## Certificate chain
x509.certificate.append(file("/etc/apache2/example.com-cert.der", "r").read())
#x509.certificate.append(file("/some/intermediate/cert.der", "r").read())
## Load private SSL key into memory for signing later
priv_key = "/etc/apache2/example.com-key.pem"
pw = "test" ## Key password
private_key = load_privatekey(FILETYPE_PEM, file(priv_key, "r").read(), pw)
{% endhighlight %}
Each line is described below.
{% highlight python %}
request.pki_type = "x509+sha256" ## Default: none
{% endhighlight %}
`pki_type`: (optional) tell the receiving wallet program what [Public-Key
Infrastructure][PKI]{:#term-pki}{:.term} (PKI) type you're using to
cryptographically sign your PaymentRequest so that it can't be modified
by a man-in-the-middle attack.
If you don't want to sign the PaymentRequest, you can choose a
[`pki_type`][pp pki type]{:#term-pp-pki-type}{:.term} of `none`
(the default).
If you do choose the sign the PaymentRequest, you currently have two
options defined by BIP70: `x509+sha1` and `x509+sha256`. Both options
use the X.509 certificate system, the same system used for HTTP Secure
(HTTPS). To use either option, you will need a certificate signed by a
certificate authority or one of their intermediaries. (A self-signed
certificate will not work.)
Each wallet program may choose which certificate authorities to trust,
but it's likely that they'll trust whatever certificate authorities their
operating system trusts. If the wallet program doesn't have a full
operating system, as might be the case for small hardware wallets, BIP70
suggests they use the [Mozilla Root Certificate Store][mozrootstore]. In
general, if a certificate works in your web browser when you connect to
your webserver, it will work for your PaymentRequests.
{% highlight python %}
details.network = "test" ## Default: main
{% endhighlight %}
`network`:<!--noref--> (optional) tell the spender's wallet program what Bitcoin network you're
using; BIP70 defines "main" for mainnet (actual payments) and "test" for
testnet (like mainnet, but fake satoshis are used). If the wallet
program doesn't run on the network you indicate, it will reject the
PaymentRequest.
{% highlight python %}
details.payment_url = "https://example.com/pay.py"
{% endhighlight %}
`payment_url`: (required) tell the spender's wallet program where to send the Payment
message (described later). This can be a static URL, as in this example,
or a variable URL such as `https://example.com/pay.py?invoice=123.`
It should usually be an HTTPS address to prevent man-in-the-middle
attacks from modifying the message.
{% highlight python %}
request.payment_details_version = 1 ## Default: 1
{% endhighlight %}
`payment_details_version`: (optional) tell the spender's wallet program what version of the
PaymentDetails you're using. As of this writing, the only version is
version 1.
{% highlight python %}
## This is the pubkey/certificate corresponding to the private SSL key
## that we'll use to sign:
x509.certificate.append(file("/etc/apache2/example.com-cert.der", "r").read())
{% endhighlight %}
`x509certificates`:<!--noref--> (required for signed PaymentRequests) you must
provide the public SSL key/certificate corresponding to the private SSL
key you'll use to sign the PaymentRequest. The certificate must be in
ASN.1/DER format.
{% highlight python %}
## If the pubkey/cert above didn't have the signature of a root
## certificate authority, we'd then append the intermediate certificate
## which signed it:
#x509.certificate.append(file("/some/intermediate/cert.der", "r").read())
{% endhighlight %}
You must also provide any intermediate certificates necessary to link
your certificate to the root certificate of a certificate authority
trusted by the spender's software, such as a certificate from the
Mozilla root store.
The certificates must be provided in a specific order---the same order
used by Apache's `SSLCertificateFile` directive and other server
software. The figure below shows the [certificate chain][]{:#term-certificate-chain}{:.term} of the
www.bitcoin.org X.509 certificate and how each certificate (except the
root certificate) would be loaded into the [X509Certificates][]{:#term-x509certificates}{:.term} protocol
buffer message.
![X509Certificates Loading Order](/img/dev/en-cert-order.svg)
To be specific, the first certificate provided must be the
X.509 certificate corresponding to the private SSL key which will make the
signature<!--noref-->, called the [leaf certificate][]{:#term-leaf-certificate}{:.term}. Any [intermediate
certificates][intermediate certificate]{:#term-intermediate-certificate}{:.term} necessary to link that signed public SSL
key to the [root
certificate][]{:#term-root-certificate}{:.term} (the certificate authority) are attached separately, with each
certificate in DER format bearing the signature<!--noref--> of the certificate that
follows it all the way to (but not including) the root certificate.
{% highlight python %}
priv_key = "/etc/apache2/example.com-key.pem"
pw = "test" ## Key password
private_key = load_privatekey(FILETYPE_PEM, file(priv_key, "r").read(), pw)
{% endhighlight %}
(Required for signed PaymentRequests) you will need a private SSL key in
a format your SSL library supports (DER format is not required). In this
program, we'll load it from a PEM file. (Embedding your passphrase in
your CGI code, as done here, is obviously a bad idea in real life.)
The private SSL key will not be transmitted with your request. We're
only loading it into memory here so we can use it to sign the request
later.
{% endautocrossref %}
##### Code Variables
{% autocrossref %}
Now let's look at the variables your CGI program will likely set for
each payment.
{% highlight python %}
## Amount of the request
amount = 10000000 ## In satoshis
## P2PKH pubkey hash
pubkey_hash = "2b14950b8d31620c6cc923c5408a701b1ec0a020"
## P2PKH output script entered as hex and converted to binary
# OP_DUP OP_HASH160 <push 20 bytes> <pubKey hash> OP_EQUALVERIFY OP_CHECKSIG
# 76 a9 14 <pubKey hash> 88 ac
hex_script = "76" + "a9" + "14" + pubkey_hash + "88" + "ac"
serialized_script = hex_script.decode("hex")
## Load amount and script into PaymentDetails
details.outputs.add(amount = amount, script = serialized_script)
## Memo to display to the spender
details.memo = "Flowers & chocolates"
## Data which should be returned to you with the payment
details.merchant_data = "Invoice #123"
{% endhighlight python %}
Each line is described below.
{% highlight python %}
amount = 10000000 ## In satoshis (=100 mBTC)
{% endhighlight %}
`amount`: (optional) the [amount][pp amount]{:#term-pp-amount}{:.term} you want the spender to pay. You'll probably get
this value from your shopping cart application or fiat-to-BTC exchange
rate conversion tool. If you leave the amount blank, the wallet
program will prompt the spender how much to pay (which can be useful
for donations).
{% highlight python %}
pubkey_hash = "2b14950b8d31620c6cc923c5408a701b1ec0a020"
# OP_DUP OP_HASH160 <push 20 bytes> <pubKey hash> OP_EQUALVERIFY OP_CHECKSIG
# 76 a9 14 <pubKey hash> 88 ac
hex_script = "76" + "a9" + "14" + pubkey_hash + "88" + "ac"
serialized_script = hex_script.decode("hex")
{% endhighlight %}
`script`: (required) You must specify the output script you want the spender to
pay---any valid script is acceptable. In this example, we'll request
payment to a P2PKH output script.
First we get a pubkey hash. The hash above is the hash form of the
address used in the URI examples throughout this section,
mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN.
Next, we plug that hash into the standard P2PKH output script using hex,
as illustrated by the code comments.
Finally, we convert the output script from hex into its serialized form.
{% highlight python %}
details.outputs.add(amount = amount, script = serialized_script)
{% endhighlight %}
`outputs`:<!--noref--> (required) add the output script and (optional) amount to the
PaymentDetails outputs<!--noref--> array.
It's possible to specify multiple [`scripts`][pp
script]{:#term-pp-script}{:.term} and `amounts` as part of a merge
avoidance strategy, described later in the [Merge Avoidance
subsection][]. However, effective merge avoidance is not possible under
the base BIP70 rules in which the spender pays each `script` the exact
amount specified by its paired `amount`. If the amounts are omitted from
all `amount`/`script` pairs, the spender will be prompted to choose an
amount to pay.
{% highlight python %}
details.memo = "Flowers & chocolates"
{% endhighlight %}
`memo`: (optional) add a memo which will be displayed to the spender as
plain UTF-8 text. Embedded HTML or other markup will not be processed.
{% highlight python %}
details.merchant_data = "Invoice #123"
{% endhighlight %}
`merchant_data`: (optional) add arbitrary data which should be sent back to the
receiver when the invoice is paid. You can use this to track your
invoices, although you can more reliably track payments by generating a
unique address for each payment and then tracking when it gets paid.
The [`memo`][pp memo]{:#term-pp-memo}{:.term} field and the [`merchant_data`][pp merchant data]{:#term-pp-merchant-data}{:.term} field can be arbitrarily long,
but if you make them too long, you'll run into the 50,000 byte limit on
the entire PaymentRequest, which includes the often several kilobytes
given over to storing the certificate chain. As will be described in a
later subsection, the `memo` field can be used by the spender after
payment as part of a cryptographically-proven receipt.
{% endautocrossref %}
##### Derivable Data
{% autocrossref %}
Next, let's look at some information your CGI program can
automatically derive.
{% highlight python %}
## Request creation time
details.time = int(time()) ## Current epoch (Unix) time
## Request expiration time
details.expires = int(time()) + 60 * 10 ## 10 minutes from now
## PaymentDetails is complete; serialize it and store it in PaymentRequest
request.serialized_payment_details = details.SerializeToString()
## Serialized certificate chain
request.pki_data = x509.SerializeToString()
## Initialize signature field so we can sign the full PaymentRequest
request.signature = ""
## Sign PaymentRequest
request.signature = sign(private_key, request.SerializeToString(), "sha256")
{% endhighlight %}
Each line is described below.
{% highlight python %}
details.time = int(time()) ## Current epoch (Unix) time
{% endhighlight %}
`time`: (required) PaymentRequests must indicate when they were created
in number of seconds elapsed since 1970-01-01T00:00 UTC (Unix
epoch time format).
{% highlight python %}
details.expires = int(time()) + 60 * 10 ## 10 minutes from now
{% endhighlight %}
`expires`: (optional) the PaymentRequest may also set an [`expires`][pp
expires]{:#term-pp-expires}{:.term} time after
which they're no longer valid. You probably want to give receivers
the ability to configure the expiration time delta; here we used the
reasonable choice of 10 minutes. If this request is tied to an order
total based on a fiat-to-satoshis exchange rate, you probably want to
base this on a delta from the time you got the exchange rate.
{% highlight python %}
request.serialized_payment_details = details.SerializeToString()
{% endhighlight %}
`serialized_payment_details`: (required) we've now set everything we need to create the
PaymentDetails, so we'll use the SerializeToString function from the
protocol buffer code to store the PaymentDetails in the appropriate
field of the PaymentRequest.
{% highlight python %}
request.pki_data = x509.SerializeToString()
{% endhighlight %}
`pki_data`: (required for signed PaymentRequests) serialize the certificate chain
[PKI data][pp PKI data]{:#term-pp-pki-data}{:.term} and store it in the
PaymentRequest
{% highlight python %}
request.signature = ""
{% endhighlight %}
We've filled out everything in the PaymentRequest except the signature,
but before we sign it, we have to initialize the signature field by
setting it to a zero-byte placeholder.
{% highlight python %}
request.signature = sign(private_key, request.SerializeToString(), "sha256")
{% endhighlight %}
`signature`:<!--noref--> (required for signed PaymentRequests) now we
make the [signature][ssl signature]{:#term-ssl-signature}{:.term} by
signing the completed and serialized PaymentRequest. We'll use the
private key we stored in memory in the configuration section and the
same hashing formula we specified in `pki_type` (sha256 in this case)
{% endautocrossref %}
##### Output Code
{% autocrossref %}
Now that we have PaymentRequest all filled out, we can serialize it and
send it along with the HTTP headers, as shown in the code below.
{% highlight python %}
print "Content-Type: application/bitcoin-paymentrequest"
print "Content-Transfer-Encoding: binary"
print ""
{% endhighlight %}
(Required) BIP71 defines the content types for PaymentRequests,
Payments, and PaymentACKs.
{% highlight python %}
file.write(stdout, request.SerializeToString())
{% endhighlight %}
`request`: (required) now, to finish, we just dump out the serialized
PaymentRequest (which contains the serialized PaymentDetails). The
serialized data is in binary, so we can't use Python's print()
because it would add an extraneous newline.
The following screenshot shows how the authenticated PaymentDetails
created by the program above appears in the GUI from Bitcoin Core 0.9.
![Bitcoin Core Showing Validated Payment Request](/img/dev/en-btcc-payment-request.png)
{% endautocrossref %}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,7 @@
<!--Temporary disclaimer BEGIN-->
<div id="develdocdisclaimer" class="develdocdisclaimer"><div>
<b>BETA</b>: This documentation has been written recently and still needs more reviews to ensure all content is covered correctly and accurately; if you find a mistake, please <a href="https://github.com/bitcoin/bitcoin.org/issues/new" onmouseover="updateIssue(event);">report an issue</a> on GitHub. <a href="#" onclick="disclaimerClose(event);">Click here</a> to close this disclaimer.
<a class="develdocdisclaimerclose" href="#" onclick="disclaimerClose(event);">X</a>
</div></div>
<script>disclaimerAutoClose();</script>
<!--Temporary disclaimer END-->

View file

@ -150,8 +150,6 @@ or [millibits][]{:#term-millibits}{:.term} (mBTC). Choosing between BTC and mBTC
but other software also lets its users select denomination amounts from
some or all of the following options:
{% endautocrossref %}
| Bitcoins | Unit (Abbreviation) |
|-------------|---------------------|
| 1.0 | bitcoin (BTC) |
@ -160,20 +158,8 @@ some or all of the following options:
| 0.000001 | microbit (uBTC) |
| 0.00000001 | [satoshi][]{:#term-satoshi}{:.term} |
{% autocrossref %}
Because of the widespread popularity of BTC and mBTC, it may be more
useful to specify the amount in both denominations when the text is
meant to be copied and pasted. For example:
{% endautocrossref %}
~~~
Pay: mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN
Amount: 100 BTC (100000 mBTC)
You must pay by: 2014-04-01 at 23:00 UTC
~~~
#### bitcoin: URI
{% autocrossref %}
@ -191,38 +177,23 @@ bitcoin:mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN?amount=100
{% autocrossref %}
Only the address is required, and if it is the only thing specified,
wallets will pre-fill a payment request with it and let the spender enter
an amount.
Only the address is required, and if it is the only thing
specified, wallets will pre-fill a payment request with it and let
the spender enter an amount. The amount specified is always in
decimal bitcoins (BTC).
The amount specified is always in decimal bitcoins (BTC), although requests
only for whole bitcoins (as in the example above), may omit the decimal
point. The amount field must not contain any commas. Fractional bitcoins
may be specified with or without a leading zero; for example, either of
the URIs below requesting one millibit are valid:
{% endautocrossref %}
~~~
bitcoin:mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN?amount=.001
bitcoin:mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN?amount=0.001
~~~
{% autocrossref %}
Two other parameters are widely supported. The [`label`][label]{:#term-label}{:.term} parameter is
generally used to provide wallet software with the recipient's name. The
[`message`][message]{:#term-message}{:.term} parameter is generally used to describe the payment request to
the spender. Both the label and the message are commonly stored by the
spender's wallet software---but they are never added to the actual
transaction, so other Bitcoin users cannot see them. Both the label and
the message must be [URI encoded][].
Two other parameters are widely supported. The
[`label`][label]{:#term-label}{:.term} parameter is generally used to
provide wallet software with the recipient's name. The
[`message`][message]{:#term-message}{:.term} parameter is generally used
to describe the payment request to the spender. Both the label and the
message are commonly stored by the spender's wallet software---but they
are never added to the actual transaction, so other Bitcoin users cannot
see them. Both the label and the message must be [URI encoded][].
All four parameters used together, with appropriate URI encoding, can be
seen in the line-wrapped example below.
{% endautocrossref %}
~~~
bitcoin:mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN\
?amount=0.10\
@ -230,32 +201,6 @@ bitcoin:mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN\
&message=Order+of+flowers+%26+chocolates
~~~
{% autocrossref %}
The URI above could be encoded in HTML as follows, providing compatibility
with wallet software which can't accept URI links and allowing you to
specify an expiration date to the spender.
{% endautocrossref %}
~~~
<a href="bitcoin:mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN\
?amount=0.10\
&label=Example+Merchant\
&message=Order+of+flowers+%26+chocolates"
>Order flowers & chocolate using Bitcoin</a>
(Pay 0.10 BTC [100 mBTC] to mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN by 2014-04-01 at 23:00 UTC)
~~~
Which produces:
> <a href="bitcoin:mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN?amount=0.10&label=Example+Merchant&message=Order+of+flowers+%26+chocolates">Order flowers & chocolates using Bitcoin</a> (Pay 0.10 BTC [100 mBTC] to mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN by 2014-04-01 at 23:00 UTC)
{% autocrossref %}
Some payment processors use Javascript to display countdown timers
indicating the number of minutes and seconds until the offer expires.
The URI scheme can be extended, as will be seen in the payment protocol
section below, with both new optional and required parameters. As of this
writing, the only widely-used parameter besides the four described above
@ -276,27 +221,14 @@ images, or in videos. Most mobile Bitcoin wallet apps, and some desktop
wallets, support scanning QR codes to pre-fill their payment screens.
The figure below shows the same `bitcoin:` URI code encoded as four
different [Bitcoin QR codes][URI QR code]{:#term-uri-qr-code}{:.term} at different error correction levels (described
below the image). The QR code can include the `label` and `message`
different [Bitcoin QR codes][URI QR code]{:#term-uri-qr-code}{:.term} at four
different error correction levels. The QR code can include the `label` and `message`
parameters---and any other optional parameters---but they were
omitted here to keep the QR code small and easy to scan with unsteady
or low-resolution mobile cameras.
![Bitcoin QR Codes](/img/dev/en-qr-code.svg)
QR encoders offer four possible levels of error correction:
1. Low: corrects up to 7% damage
2. Medium: corrects up to 15% damage but results in approximately 8%
larger images over low-level damage correction.
3. Quartile: corrects corrects up to 25% damage but results in
approximately 20% larger images over low-level damage correction.
4. High: corrects up to 30% damage but results in approximately 26%
larger images over low-level damage correction.
The error correction is combined with a checksum to ensure the Bitcoin QR code
cannot be successfully decoded with data missing or accidentally altered,
so your applications should choose the appropriate level of error
@ -332,662 +264,143 @@ as "www.bitcoin.org".
To request payment using the payment protocol, you use an extended (but
backwards-compatible) `bitcoin:` URI. For example:
{% endautocrossref %}
~~~
bitcoin:mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN\
?amount=0.10\
&label=Example+Merchant\
&message=Order+of+flowers+%26+chocolates\
&r=http://example.com/pay.php/invoice%3Dda39a3ee
&r=https://example.com/pay/mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN
~~~
{% autocrossref %}
None of the parameters provided above, except `r`, are required for the
payment protocol---but your applications may include them for backwards
compatibility with wallet programs which don't yet handle the payment
protocol.
The [`r`][r]{:#term-r-parameter}{:.term} parameter tells payment-protocol-aware wallet programs to ignore
the other parameters and fetch a PaymentRequest from the URL provided. If the
request will be signed, which is recommended but not required, it can be
fetched from an HTTP server---although fetching it from an HTTPS server
would still be preferable.
the other parameters and fetch a PaymentRequest from the URL provided.
The browser, QR code reader, or other program processing the URI opens
the spender's Bitcoin wallet program on the URI. If the wallet program is
aware of the payment protocol, it accesses the URL specified in the `r`
parameter, which should provide it with a serialized PaymentRequest
served with the [MIME][] type `application/bitcoin-paymentrequest`<!--noref-->.
**Resource:** Gavin Andresen's [Payment Request Generator][] generates
custom example URIs and payment requests for use with testnet.
{% endautocrossref %}
##### PaymentRequest & PaymentDetails
{% autocrossref %}
The [PaymentRequest][]{:#term-paymentrequest}{:.term} is created with data structures built using
Google's Protocol Buffers. BIP70 describes these data
structures in the non-sequential way they're defined in the payment
request protocol buffer code, but the text below will describe them in
a more linear order using a simple (but functional) Python CGI
program. (For brevity and clarity, many normal CGI best practices are
not used in this program.)
The full sequence of events is illustrated below, starting with the
spender clicking a `bitcoin:` URI or scanning a `bitcoin:` QR code.
the spender's Bitcoin wallet program on the URI.
![BIP70 Payment Protocol](/img/dev/en-payment-protocol.svg)
For the script to use the protocol buffer, you will need a copy of
Google's Protocol Buffer compiler (`protoc`), which is available in most
modern Linux package managers and [directly from Google.][protobuf] Non-Google
protocol buffer compilers are available for a variety of
programming languages. You will also need a copy of the PaymentRequest
[Protocol Buffer description][core paymentrequest.proto] from the Bitcoin Core source code.
###### Initialization Code
With the Python code generated by `protoc`, we can start our simple
CGI program.
{% endautocrossref %}
{% highlight python %}
#!/usr/bin/env python
## This is the code generated by protoc --python_out=./ paymentrequest.proto
from paymentrequest_pb2 import *
## Load some functions
from time import time
from sys import stdout
from OpenSSL.crypto import FILETYPE_PEM, load_privatekey, sign
## Copy three of the classes created by protoc into objects we can use
details = PaymentDetails()
request = PaymentRequest()
x509 = X509Certificates()
{% endhighlight %}
{% autocrossref %}
The startup code above is quite simple, requiring nothing but the epoch
(Unix date) time function, the standard out file descriptor, a few
functions from the OpenSSL library, and the data structures and
functions created by `protoc`.
{% endautocrossref %}
###### Configuration Code
{% autocrossref %}
Next, we'll set configuration settings which will typically only change
when the receiver wants to do something differently. The code pushes a
few settings into the `request` (PaymentRequest) and `details`
(PaymentDetails) objects. When we serialize them,
[PaymentDetails][]{:#term-paymentdetails}{:.term} will be contained
within the PaymentRequest.
{% endautocrossref %}
{% highlight python %}
## SSL Signature method
request.pki_type = "x509+sha256" ## Default: none
## Mainnet or Testnet?
details.network = "test" ## Default: main
## Postback URL
details.payment_url = "https://example.com/pay.py"
## PaymentDetails version number
request.payment_details_version = 1 ## Default: 1
## Certificate chain
x509.certificate.append(file("/etc/apache2/example.com-cert.der", "r").read())
#x509.certificate.append(file("/some/intermediate/cert.der", "r").read())
## Load private SSL key into memory for signing later
priv_key = "/etc/apache2/example.com-key.pem"
pw = "test" ## Key password
private_key = load_privatekey(FILETYPE_PEM, file(priv_key, "r").read(), pw)
{% endhighlight %}
Each line is described below.
{% highlight python %}
request.pki_type = "x509+sha256" ## Default: none
{% endhighlight %}
{% autocrossref %}
`pki_type`: (optional) tell the receiving wallet program what [Public-Key
Infrastructure][PKI]{:#term-pki}{:.term} (PKI) type you're using to
cryptographically sign your PaymentRequest so that it can't be modified
by a man-in-the-middle attack.
If you don't want to sign the PaymentRequest, you can choose a
[`pki_type`][pp pki type]{:#term-pp-pki-type}{:.term} of `none`
(the default).
If you do choose the sign the PaymentRequest, you currently have two
options defined by BIP70: `x509+sha1` and `x509+sha256`. Both options
use the X.509 certificate system, the same system used for HTTP Secure
(HTTPS). To use either option, you will need a certificate signed by a
certificate authority or one of their intermediaries. (A self-signed
certificate will not work.)
Each wallet program may choose which certificate authorities to trust,
but it's likely that they'll trust whatever certificate authorities their
operating system trusts. If the wallet program doesn't have a full
operating system, as might be the case for small hardware wallets, BIP70
suggests they use the [Mozilla Root Certificate Store][mozrootstore]. In
general, if a certificate works in your web browser when you connect to
your webserver, it will work for your PaymentRequests.
{% endautocrossref %}
{% highlight python %}
details.network = "test" ## Default: main
{% endhighlight %}
{% autocrossref %}
`network`:<!--noref--> (optional) tell the spender's wallet program what Bitcoin network you're
using; BIP70 defines "main" for mainnet (actual payments) and "test" for
testnet (like mainnet, but fake satoshis are used). If the wallet
program doesn't run on the network you indicate, it will reject the
PaymentRequest.
{% endautocrossref %}
{% highlight python %}
details.payment_url = "https://example.com/pay.py"
{% endhighlight %}
{% autocrossref %}
`payment_url`: (required) tell the spender's wallet program where to send the Payment
message (described later). This can be a static URL, as in this example,
or a variable URL such as `https://example.com/pay.py?invoice=123.`
It should usually be an HTTPS address to prevent man-in-the-middle
attacks from modifying the message.
{% endautocrossref %}
{% highlight python %}
request.payment_details_version = 1 ## Default: 1
{% endhighlight %}
{% autocrossref %}
`payment_details_version`: (optional) tell the spender's wallet program what version of the
PaymentDetails you're using. As of this writing, the only version is
version 1.
{% endautocrossref %}
{% highlight python %}
## This is the pubkey/certificate corresponding to the private SSL key
## that we'll use to sign:
x509.certificate.append(file("/etc/apache2/example.com-cert.der", "r").read())
{% endhighlight %}
{% autocrossref %}
`x509certificates`:<!--noref--> (required for signed PaymentRequests) you must
provide the public SSL key/certificate corresponding to the private SSL
key you'll use to sign the PaymentRequest. The certificate must be in
ASN.1/DER format.
{% endautocrossref %}
{% highlight python %}
## If the pubkey/cert above didn't have the signature of a root
## certificate authority, we'd then append the intermediate certificate
## which signed it:
#x509.certificate.append(file("/some/intermediate/cert.der", "r").read())
{% endhighlight %}
{% autocrossref %}
You must also provide any intermediate certificates necessary to link
your certificate to the root certificate of a certificate authority
trusted by the spender's software, such as a certificate from the
Mozilla root store.
The certificates must be provided in a specific order---the same order
used by Apache's `SSLCertificateFile` directive and other server
software. The figure below shows the [certificate chain][]{:#term-certificate-chain}{:.term} of the
www.bitcoin.org X.509 certificate and how each certificate (except the
root certificate) would be loaded into the [X509Certificates][]{:#term-x509certificates}{:.term} protocol
buffer message.
![X509Certificates Loading Order](/img/dev/en-cert-order.svg)
To be specific, the first certificate provided must be the
X.509 certificate corresponding to the private SSL key which will make the
signature<!--noref-->, called the [leaf certificate][]{:#term-leaf-certificate}{:.term}. Any [intermediate
certificates][intermediate certificate]{:#term-intermediate-certificate}{:.term} necessary to link that signed public SSL
key to the [root
certificate][]{:#term-root-certificate}{:.term} (the certificate authority) are attached separately, with each
certificate in DER format bearing the signature<!--noref--> of the certificate that
follows it all the way to (but not including) the root certificate.
{% endautocrossref %}
{% highlight python %}
priv_key = "/etc/apache2/example.com-key.pem"
pw = "test" ## Key password
private_key = load_privatekey(FILETYPE_PEM, file(priv_key, "r").read(), pw)
{% endhighlight %}
{% autocrossref %}
(Required for signed PaymentRequests) you will need a private SSL key in
a format your SSL library supports (DER format is not required). In this
program, we'll load it from a PEM file. (Embedding your passphrase in
your CGI code, as done here, is obviously a bad idea in real life.)
The private SSL key will not be transmitted with your request. We're
only loading it into memory here so we can use it to sign the request
later.
{% endautocrossref %}
###### Code Variables
{% autocrossref %}
Now let's look at the variables your CGI program will likely set for
each payment.
{% endautocrossref %}
{% highlight python %}
## Amount of the request
amount = 10000000 ## In satoshis
## P2PKH pubkey hash
pubkey_hash = "2b14950b8d31620c6cc923c5408a701b1ec0a020"
## P2PKH output script entered as hex and converted to binary
# OP_DUP OP_HASH160 <push 20 bytes> <pubKey hash> OP_EQUALVERIFY OP_CHECKSIG
# 76 a9 14 <pubKey hash> 88 ac
hex_script = "76" + "a9" + "14" + pubkey_hash + "88" + "ac"
serialized_script = hex_script.decode("hex")
## Load amount and script into PaymentDetails
details.outputs.add(amount = amount, script = serialized_script)
## Memo to display to the spender
details.memo = "Flowers & chocolates"
## Data which should be returned to you with the payment
details.merchant_data = "Invoice #123"
{% endhighlight python %}
Each line is described below.
{% highlight python %}
amount = 10000000 ## In satoshis (=100 mBTC)
{% endhighlight %}
{% autocrossref %}
`amount`: (optional) the [amount][pp amount]{:#term-pp-amount}{:.term} you want the spender to pay. You'll probably get
this value from your shopping cart application or fiat-to-BTC exchange
rate conversion tool. If you leave the amount blank, the wallet
program will prompt the spender how much to pay (which can be useful
for donations).
{% endautocrossref %}
{% highlight python %}
pubkey_hash = "2b14950b8d31620c6cc923c5408a701b1ec0a020"
# OP_DUP OP_HASH160 <push 20 bytes> <pubKey hash> OP_EQUALVERIFY OP_CHECKSIG
# 76 a9 14 <pubKey hash> 88 ac
hex_script = "76" + "a9" + "14" + pubkey_hash + "88" + "ac"
serialized_script = hex_script.decode("hex")
{% endhighlight %}
{% autocrossref %}
`script`: (required) You must specify the output script you want the spender to
pay---any valid script is acceptable. In this example, we'll request
payment to a P2PKH output script.
First we get a pubkey hash. The hash above is the hash form of the
address used in the URI examples throughout this section,
mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN.
Next, we plug that hash into the standard P2PKH output script using hex,
as illustrated by the code comments.
Finally, we convert the output script from hex into its serialized form.
{% endautocrossref %}
{% highlight python %}
details.outputs.add(amount = amount, script = serialized_script)
{% endhighlight %}
{% autocrossref %}
`outputs`:<!--noref--> (required) add the output script and (optional) amount to the
PaymentDetails outputs<!--noref--> array.
It's possible to specify multiple [`scripts`][pp
script]{:#term-pp-script}{:.term} and `amounts` as part of a merge
avoidance strategy, described later in the [Merge Avoidance
subsection][]. However, effective merge avoidance is not possible under
the base BIP70 rules in which the spender pays each `script` the exact
amount specified by its paired `amount`. If the amounts are omitted from
all `amount`/`script` pairs, the spender will be prompted to choose an
amount to pay.
{% endautocrossref %}
{% highlight python %}
details.memo = "Flowers & chocolates"
{% endhighlight %}
{% autocrossref %}
`memo`: (optional) add a memo which will be displayed to the spender as
plain UTF-8 text. Embedded HTML or other markup will not be processed.
{% endautocrossref %}
{% highlight python %}
details.merchant_data = "Invoice #123"
{% endhighlight %}
{% autocrossref %}
`merchant_data`: (optional) add arbitrary data which should be sent back to the
receiver when the invoice is paid. You can use this to track your
invoices, although you can more reliably track payments by generating a
unique address for each payment and then tracking when it gets paid.
The [`memo`][pp memo]{:#term-pp-memo}{:.term} field and the [`merchant_data`][pp merchant data]{:#term-pp-merchant-data}{:.term} field can be arbitrarily long,
but if you make them too long, you'll run into the 50,000 byte limit on
the entire PaymentRequest, which includes the often several kilobytes
given over to storing the certificate chain. As will be described in a
later subsection, the `memo` field can be used by the spender after
payment as part of a cryptographically-proven receipt.
{% endautocrossref %}
###### Derivable Data
{% autocrossref %}
Next, let's look at some information your CGI program can
automatically derive.
{% endautocrossref %}
{% highlight python %}
## Request creation time
details.time = int(time()) ## Current epoch (Unix) time
## Request expiration time
details.expires = int(time()) + 60 * 10 ## 10 minutes from now
## PaymentDetails is complete; serialize it and store it in PaymentRequest
request.serialized_payment_details = details.SerializeToString()
## Serialized certificate chain
request.pki_data = x509.SerializeToString()
## Initialize signature field so we can sign the full PaymentRequest
request.signature = ""
## Sign PaymentRequest
request.signature = sign(private_key, request.SerializeToString(), "sha256")
{% endhighlight %}
Each line is described below.
{% highlight python %}
details.time = int(time()) ## Current epoch (Unix) time
{% endhighlight %}
{% autocrossref %}
`time`: (required) PaymentRequests must indicate when they were created
in number of seconds elapsed since 1970-01-01T00:00 UTC (Unix
epoch time format).
{% endautocrossref %}
{% highlight python %}
details.expires = int(time()) + 60 * 10 ## 10 minutes from now
{% endhighlight %}
{% autocrossref %}
`expires`: (optional) the PaymentRequest may also set an [`expires`][pp
expires]{:#term-pp-expires}{:.term} time after
which they're no longer valid. You probably want to give receivers
the ability to configure the expiration time delta; here we used the
reasonable choice of 10 minutes. If this request is tied to an order
total based on a fiat-to-satoshis exchange rate, you probably want to
base this on a delta from the time you got the exchange rate.
{% endautocrossref %}
{% highlight python %}
request.serialized_payment_details = details.SerializeToString()
{% endhighlight %}
{% autocrossref %}
`serialized_payment_details`: (required) we've now set everything we need to create the
PaymentDetails, so we'll use the SerializeToString function from the
protocol buffer code to store the PaymentDetails in the appropriate
field of the PaymentRequest.
{% endautocrossref %}
{% highlight python %}
request.pki_data = x509.SerializeToString()
{% endhighlight %}
{% autocrossref %}
`pki_data`: (required for signed PaymentRequests) serialize the certificate chain
[PKI data][pp PKI data]{:#term-pp-pki-data}{:.term} and store it in the
PaymentRequest
{% endautocrossref %}
{% highlight python %}
request.signature = ""
{% endhighlight %}
{% autocrossref %}
We've filled out everything in the PaymentRequest except the signature,
but before we sign it, we have to initialize the signature field by
setting it to a zero-byte placeholder.
{% endautocrossref %}
{% highlight python %}
request.signature = sign(private_key, request.SerializeToString(), "sha256")
{% endhighlight %}
{% autocrossref %}
`signature`:<!--noref--> (required for signed PaymentRequests) now we
make the [signature][ssl signature]{:#term-ssl-signature}{:.term} by
signing the completed and serialized PaymentRequest. We'll use the
private key we stored in memory in the configuration section and the
same hashing formula we specified in `pki_type` (sha256 in this case)
{% endautocrossref %}
###### Output Code
{% autocrossref %}
Now that we have PaymentRequest all filled out, we can serialize it and
send it along with the HTTP headers, as shown in the code below.
{% endautocrossref %}
{% highlight python %}
print "Content-Type: application/bitcoin-paymentrequest"
print "Content-Transfer-Encoding: binary"
print ""
{% endhighlight %}
{% autocrossref %}
(Required) BIP71 defines the content types for PaymentRequests,
Payments, and PaymentACKs.
{% endautocrossref %}
{% highlight python %}
file.write(stdout, request.SerializeToString())
{% endhighlight %}
{% autocrossref %}
`request`: (required) now, to finish, we just dump out the serialized
PaymentRequest (which contains the serialized PaymentDetails). The
serialized data is in binary, so we can't use Python's print()
because it would add an extraneous newline.
The following screenshot shows how the authenticated PaymentDetails
created by the program above appears in the GUI from Bitcoin Core 0.9.
The Payment Protocol is described in depth in BIP70, BIP71, and BIP72.
An example CGI program and description of all the parameters which can
be used in the Payment Protocol is provided in the Developer Examples
[Payment Protocol][devex payment protocol] subsection. In this
subsection, we will briefly describe in story format how the Payment
Protocol is typically used.
Charlie, the client, is shopping on a website run by Bob, the
businessman. Charlie adds a few items to his shopping cart and clicks
the "Checkout With Bitcoin" button.
Bob's server automatically adds the following information to its
invoice database:
* The details of Charlie's order, including items ordered and
shipping address.
* An order total in satoshis, perhaps created by converting prices in
fiat to prices in satoshis.
* An expiration time when that total will no longer be acceptable.
* An output script to which Charlie should send payment. Typically this
will be a P2PKH or P2SH output script containing a unique (never
before used) public key.
After adding all that information to the database, Bob's server displays
a `bitcoin:` URI for Charlie to click to pay.
Charlie clicks on the `bitcoin:` URI in his browser. His browser's URI
handler sends the URI to his wallet program. The wallet is aware of the
Payment Protocol, so it parses the `r` parameter and sends an HTTP GET
to that URL looking for a PaymentRequest message.
The PaymentRequest message returned may include private information, such as Charlie's
mailing address, but the wallet must be able to access it without using prior
authentication, such as HTTP cookies, so a publicly-accessible HTTPS URL
with a guess-resistant part is typically used. The
unique public key created for the payment request can be used to create
a unique identifier. This is why, in the example URI above, the PaymentRequest
URL contains the P2PKH address:
`https://example.com/pay/mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN`
After receiving the HTTP GET to the URL above, the
PaymentRequest-generating CGI program on Bob's webserver takes the
unique identifier from the URL and looks up the corresponding details in
the database. It then creates a PaymentDetails message with the
following information:
* The amount of the order in satoshis and the output script to be paid.
* A memo containing the list of items ordered, so Charlie knows what
he's paying for. It may also include Charlie's mailing address so he can
double-check it.
* The time the PaymentDetails message was created plus the time
it expires.
* A URL to which Charlie's wallet should send its completed transaction.
That PaymentDetails message is put inside a PaymentRequest message.
The payment request lets Bob's server sign the entire Request with the
server's X.509 SSL certificate. (The Payment Protocol has been designed
to allow other signing methods in the future.) Bob's server sends the
payment request to Charlie's wallet in the reply to the HTTP GET.
![Bitcoin Core Showing Validated Payment Request](/img/dev/en-btcc-payment-request.png)
{% endautocrossref %}
Charlie's wallet receives the PaymentRequest message, checks its signature, and
then displays the details from the PaymentDetails message to Charlie. Charlie
agrees to pay, so the wallet constructs a payment to the output script
Bob's server provided. Unlike a traditional Bitcoin payment, Charlie's
wallet doesn't necessarily automatically broadcast this payment to the
network. Instead, the wallet constructs a Payment message and sends it to
the URL provided in the PaymentDetails message as an HTTP POST. Among
other things, the Payment message contains:
##### Payment
* The signed transaction in which Charlie pays Bob.
{% autocrossref %}
* An optional memo Charlie can send to Bob. (There's no guarantee that
Bob will read it.)
If the spender declines to pay, the wallet program will not send any
further messages to the receiver's server unless the spender clicks
another URI pointing to that server. If the spender does decide to pay,
the wallet program will create at least one transaction paying each of
the outputs in the PaymentDetails section. The wallet may broadcast
the transaction or transactions, as Bitcoin Core 0.9 does, but it
doesn't need to.
* A refund address (output script) which Bob can pay if he needs to
return some or all of Charlie's satoshis.
Whether or not it broadcasts the transaction or transactions, the wallet
program composes a reply to the PaymentRequest; the reply is called the
Payment. [Payment][pp payment]{:#term-pp-payment}{:.term} contains four fields:
Bob's server receives the Payment message, verifies the transaction pays
the requested amount to the address provided, and then broadcasts the
transaction to the network. It also replies to the HTTP POSTed Payment
message with a PaymentACK message, which includes an optional memo
from Bob's server thanking Charlie for his patronage and providing other
information about the order, such as the expected arrival date.
* `merchant_data`: (optional) an exact copy of the
`merchant_data` from the PaymentDetails. This is
optional in the case that the PaymentDetails doesn't provide
`merchant_data`. Receivers should be aware that malicious spenders can
modify the merchant data before sending it back, so receivers may wish to
cryptographically sign it before giving it to the spender and then
validate it before relying on it.
Charlie's wallet sees the PaymentACK and tells Charlie that the payment
has been sent. The PaymentACK doesn't mean that Bob has verified
Charlie's payment---see the Verifying Payment subsection below---but it does mean
that Charlie can go do something else while the transaction gets confirmed.
After Bob's server verifies from the block chain that Charlie's
transaction has been suitably confirmed, it authorizes shipping
Charlie's order.
* [`transactions`][pp transactions]{:#term-pp-transactions}{:.term}: (required) one or more signed transactions which pay the outputs
specified in the PaymentDetails.
In the case of a dispute, Charlie can generate a cryptographically-proven
[receipt][]{:#term-receipt}{:.term} out of the various signed or
otherwise-proven information.
<!-- BIP70 implies that refund_to is required (i.e. "one or more..."),
but Mike Hearn implied on bitcoin-devel that it's optional (i.e. "wallets have
to either never submit refund data, or always submit it").
I'll use the BIP70 version here until I hear differently. -harding -->
* The PaymentDetails message signed by Bob's webserver proves Charlie
received an invoice to pay a specified output script for a specified
number of satoshis for goods specified in the memo field.
* [`refund_to`][pp refund to]{:#term-pp-refund-to}{:.term}: (required) one or more output scripts to which the
receiver can send a partial or complete refund. As of this writing, a
proposal is gaining traction to expire refund output scripts after a
certain amount of time (not defined yet) so spenders don't need to
worry about receiving refunds to addresses they no longer monitor.
* The Bitcoin block chain can prove that the output script specified by
Bob was paid the specified number of satoshis.
* `memo`: (optional) a plain UTF-8 text memo sent to the receiver. It
should not contain HTML or any other markup. Spenders should not depend
on receivers reading their memos.
The Payment is sent to the [`payment_url`][pp payment
url]{:#term-pp-payment-url}{:.term} provided in the PaymentDetails.
The URL should be a HTTPS address to prevent a man-in-the-middle attack
from modifying the spender's `refund_to` output scripts. When sending the
Payment, the wallet program must set the following HTTP client headers:
{% endautocrossref %}
~~~
Content-Type: application/bitcoin-payment
Accept: application/bitcoin-paymentack
~~~
##### PaymentACK
{% autocrossref %}
The receiver's CGI program at the `payment_url` receives the Payment message and
decodes it using its Protocol Buffers code. The `transactions` are
checked to see if they pay the output scripts the receiver requested in
PaymentDetails and are then broadcast to the network (unless the network
already has them).
The CGI program checks the `merchant_data` parameter if necessary and issues
a [PaymentACK][]{:#term-paymentack}{:.term} (acknowledgment) with the following HTTP headers:
{% endautocrossref %}
~~~
Content-Type: application/bitcoin-paymentack
Content-Transfer-Encoding: binary
~~~
{% autocrossref %}
Then it sends another Protocol-Buffers-encoded message with one or two
fields:
* `payment`: (required) A copy of the the entire Payment message (in
serialized form) which is being acknowledged.
* `memo`: (optional) A plain UTF-8 text memo displayed to the spender
informing them about the status of their payment. It should not
contain HTML or any other markup. Receivers should not depend on
spenders reading their memos.
The PaymentACK does not mean that the payment is final; it just means
that everything seems to be correct. The payment is final once the
payment transactions are block-chain confirmed to the receiver's
satisfaction.
However, the spender's wallet program should indicate to the spender that
the payment was accepted for processing so the spender can direct his or
her attention elsewhere.
{% endautocrossref %}
##### Receipts
{% autocrossref %}
Unlike PaymentRequest, PaymentDetails, [Payment][pp payment]{:.auto-link}, and PaymentACK, there is
no specific [receipt][]{:#term-receipt}{:.term} object. However, a cryptographically-verifiable
receipt can be derived from a signed PaymentDetails and one or more confirmed
transactions.
A signed PaymentDetails indicates what output scripts should be paid
(`script`), how much they should be paid (`amount`), and by when
(`expires`). The Bitcoin block chain indicates whether those outputs
were paid the requested amount and can provide a rough idea of when the
transactions were generated. Together, this information provides
verifiable proof that the spender paid somebody with the
receiver's private SSL key.
If a refund needs to be issued, Bob's server can safely pay the
refund-to output script provided by Charlie. (Note: a proposal has been
discussed to give refund-to addresses an implicit expiration date so
users and software don't need to worry about payments being sent to
addresses which are no longer monitored.) See the Refunds section below
for more details.
{% endautocrossref %}

View file

@ -225,7 +225,7 @@ design these minimalist wallets:
* Pre-populate a database with a number of public keys or addresses, and
then distribute on request an output script or address using one of
the database entries. To [avoid key reuse][devguide avoiding key
resuse], webservers should keep track
reuse], webservers should keep track
of used keys and never run out of public keys. This can be made easier
by using parent public keys as suggested in the next method.

View file

@ -17,7 +17,7 @@
[broadcast]: /en/developer-guide#transaction-broadcasting "Sending transactions or blocks to all other peers on the Bitcoin network (compare to privately transmitting to a single peer or partner"
[broadcasts]: /en/developer-guide#transaction-broadcasting "Sending transactions or blocks to all other peers on the Bitcoin network (compare to privately transmitting to a single peer or partner"
[broadcasting]: /en/developer-guide#transaction-broadcasting "Sending transactions or blocks to all other peers on the Bitcoin network (compare to privately transmitting to a single peer or partner)"
[certificate chain]: /en/developer-guide#term-certificate-chain "A chain of certificates connecting a individual's leaf certificate to the certificate authority's root certificate"
[certificate chain]: /en/developer-examples#term-certificate-chain "A chain of certificates connecting a individual's leaf certificate to the certificate authority's root certificate"
[chain code]: /en/developer-guide#term-chain-code "In HD wallets, 256 bits of entropy added to the master public and private keys to help them generate secure child keys; the chain code is usually derived from a seed along with the master private key"
[change address]: /en/developer-guide#term-change-output "An output used by a spender to send back to himself some of the satoshis from the inputs"
[change output]: /en/developer-guide#term-change-output "An output used by a spender to send back to himself some of the satoshis from the inputs"
@ -45,11 +45,11 @@
[high-priority transactions]: /en/developer-guide#term-high-priority-transactions "Transactions which don't pay a transaction fee; only transactions spending long-idle outputs are eligible"
[input]: /en/developer-guide#term-input "The input to a transaction linking to the output of a previous transaction which permits spending of satoshis"
[inputs]: /en/developer-guide#term-input "The input to a transaction linking to the output of a previous transaction which permits spending of satoshis"
[intermediate certificate]: /en/developer-guide#term-intermediate-certificate "A intermediate certificate authority certificate which helps connect a leaf (receiver) certificate to a root certificate authority"
[intermediate certificate]: /en/developer-examples#term-intermediate-certificate "A intermediate certificate authority certificate which helps connect a leaf (receiver) certificate to a root certificate authority"
[key index]: /en/developer-guide#term-key-index "An index number used in the HD wallet formula to generate child keys from a parent key"
[key pair]: /en/developer-guide#term-key-pair "A private key and its derived public key"
[label]: /en/developer-guide#term-label "The label parameter of a bitcoin: URI which provides the spender with the receiver's name (unauthenticated)"
[leaf certificate]: /en/developer-guide#term-leaf-certificate "The end-node in a certificate chain; in the payment protocol, it is the certificate belonging to the receiver of satoshis"
[leaf certificate]: /en/developer-examples#term-leaf-certificate "The end-node in a certificate chain; in the payment protocol, it is the certificate belonging to the receiver of satoshis"
[locktime]: /en/developer-guide#term-locktime "Part of a transaction which indicates the earliest time or earliest block when that transaction can be added to the block chain"
[long-term fork]: /en/developer-guide#term-long-term-fork "When a series of blocks have corresponding block heights, indicating a possibly serious problem"
[mainnet]: /en/developer-guide#term-mainnet "The Bitcoin main network used to transfer satoshis (compare to testnet, the test network)"
@ -90,29 +90,24 @@
[parent private key]: /en/developer-guide#term-parent-private-key "A private key which has created child private keys"
[parent public key]: /en/developer-guide#term-parent-public-key "A public key corresponding to a parent private key which has child private keys"
[payment protocol]: /en/developer-guide#term-payment-protocol "The protocol defined in BIP70 which lets spenders get signed payment details from receivers"
[PaymentACK]: /en/developer-guide#term-paymentack "The PaymentACK of the payment protocol which allows the receiver to indicate to the spender that the payment is being processed"
[PaymentDetails]: /en/developer-guide#term-paymentdetails "The PaymentDetails of the payment protocol which allows the receiver to specify the payment details to the spender"
[PaymentRequest]: /en/developer-guide#term-paymentrequest "The PaymentRequest of the payment protocol which contains and allows signing of the PaymentDetails"
[PaymentRequests]: /en/developer-guide#term-paymentrequest "The PaymentRequest of the payment protocol which contains and allows signing of the PaymentDetails"
[PaymentDetails]: /en/developer-examples#term-paymentdetails "The PaymentDetails of the payment protocol which allows the receiver to specify the payment details to the spender"
[PaymentRequest]: /en/developer-examples#term-paymentrequest "The PaymentRequest of the payment protocol which contains and allows signing of the PaymentDetails"
[PaymentRequests]: /en/developer-examples#term-paymentrequest "The PaymentRequest of the payment protocol which contains and allows signing of the PaymentDetails"
[peer]: /en/developer-guide#term-peer "Peer on the P2P network who receives and broadcasts transactions and blocks"
[peers]: /en/developer-guide#term-peer "Peers on the P2P network who receive and broadcast transactions and blocks"
[PKI]: /en/developer-guide#term-pki "Public Key Infrastructure; usually meant to indicate the X.509 certificate system used for HTTP Secure (https)."
[PKI]: /en/developer-examples#term-pki "Public Key Infrastructure; usually meant to indicate the X.509 certificate system used for HTTP Secure (https)."
[point function]: /en/developer-guide#term-point-function "The ECDSA function used to create a public key from a private key"
[private key]: /en/developer-guide#term-private-key "The private portion of a keypair which can create signatures which other people can verify using the public key"
[private keys]: /en/developer-guide#term-private-key "The private portion of a keypair which can create signatures which other people can verify using the public key"
[pubkey hash]: /en/developer-guide#term-pubkey-hash "The hash of a public key which can be included in a P2PKH output"
[public key]: /en/developer-guide#term-public-key "The public portion of a keypair which can be safely distributed to other people so they can verify a signature created with the corresponding private key"
[pp amount]: /en/developer-guide#term-pp-amount "Part of the Output part of the PaymentDetails part of a payment protocol where receivers can specify the amount of satoshis they want paid to a particular output script"
[pp expires]: /en/developer-guide#term-pp-expires "The expires field of a PaymentDetails where the receiver tells the spender when the PaymentDetails expires"
[pp memo]: /en/developer-guide#term-pp-memo "The memo fields of PaymentDetails, Payment, and PaymentACK which allow spenders and receivers to send each other memos"
[pp merchant data]: /en/developer-guide#term-pp-merchant-data "The merchant_data part of PaymentDetails and Payment which allows the receiver to send arbitrary data to the spender in PaymentDetails and receive it back in Payments"
[pp Payment]: /en/developer-guide#term-pp-payment "The Payment message of the PaymentProtocol which allows the spender to send payment details to the receiver"
[pp PKI data]: /en/developer-guide#term-pp-pki-data "The pki_data field of a PaymentRequest which provides details such as certificates necessary to validate the request"
[pp pki type]: /en/developer-guide#term-pp-pki-type "The PKI field of a PaymentRequest which tells spenders how to validate this request as being from a specific recipient"
[pp refund to]: /en/developer-guide#term-pp-refund-to "The refund_to field of a Payment where the spender tells the receiver what outputs to send refunds to"
[pp script]: /en/developer-guide#term-pp-script "The script field of a PaymentDetails where the receiver tells the spender what output scripts to pay"
[pp transactions]: /en/developer-guide#term-pp-transactions "The transactions field of a Payment where the spender provides copies of signed transactions to the receiver"
[pp payment url]: /en/developer-guide#term-pp-payment-url "The payment_url of the PaymentDetails which allows the receiver to specify where the sender should post payment"
[pp amount]: /en/developer-examples#term-pp-amount "Part of the Output part of the PaymentDetails part of a payment protocol where receivers can specify the amount of satoshis they want paid to a particular output script"
[pp expires]: /en/developer-examples#term-pp-expires "The expires field of a PaymentDetails where the receiver tells the spender when the PaymentDetails expires"
[pp memo]: /en/developer-examples#term-pp-memo "The memo fields of PaymentDetails, Payment, and PaymentACK which allow spenders and receivers to send each other memos"
[pp merchant data]: /en/developer-examples#term-pp-merchant-data "The merchant_data part of PaymentDetails and Payment which allows the receiver to send arbitrary data to the spender in PaymentDetails and receive it back in Payments"
[pp PKI data]: /en/developer-examples#term-pp-pki-data "The pki_data field of a PaymentRequest which provides details such as certificates necessary to validate the request"
[pp pki type]: /en/developer-examples#term-pp-pki-type "The PKI field of a PaymentRequest which tells spenders how to validate this request as being from a specific recipient"
[pp script]: /en/developer-examples#term-pp-script "The script field of a PaymentDetails where the receiver tells the spender what output scripts to pay"
[proof of work]: /en/developer-guide#term-proof-of-work "Proof that computationally-difficult work was performed which helps secure blocks against modification, protecting transaction history"
[Pubkey]: /en/developer-guide#term-pubkey "A standard output script which specifies the full public key to match a signature; used in coinbase transactions"
[r]: /en/developer-guide#term-r-parameter "The payment request parameter in a bitcoin: URI"
@ -121,7 +116,7 @@
[recurrent rebilling]: /en/developer-guide#rebilling-recurring-payments "Billing a spender on a regular schedule"
[redeemScript]: /en/developer-guide#term-redeemscript "A script created by the recipient, hashed, and given to the spender for use in a P2SH output"
[refund]: /en/developer-guide#issuing-refunds "A transaction which refunds some or all satoshis received in a previous transaction"
[root certificate]: /en/developer-guide#term-root-certificate "A certificate belonging to a certificate authority (CA)"
[root certificate]: /en/developer-examples#term-root-certificate "A certificate belonging to a certificate authority (CA)"
[root seed]: /en/developer-guide#term-root-seed "A potentially-short value used as a seed to generate a master private key and master chain code for an HD wallet"
[satoshi]: /en/developer-guide#term-satoshi "The smallest unit of Bitcoin value; 0.00000001 bitcoins. Also used generically for any value of bitcoins"
[satoshis]: /en/developer-guide#term-satoshi "The smallest unit of Bitcoin value; 0.00000001 bitcoins. Also used generically for any value of bitcoins"
@ -140,7 +135,7 @@
[signature]: /en/developer-guide#term-signature "The result of combining a private key and some data in an ECDSA signature operation which allows anyone with the corresponding public key to verify the signature"
[signature hash]: /en/developer-guide#term-signature-hash "A byte appended onto signatures generated in Bitcoin which allows the signer to specify what data was signed, allowing modification of the unsigned data"
[spv]: /en/developer-guide#simplified-payment-verification-spv "A method for verifying particular transactions were included in blocks without downloading the entire contents of the block chain"
[ssl signature]: /en/developer-guide#term-ssl-signature "Signatures created and recognized by major SSL implementations such as OpenSSL"
[ssl signature]: /en/developer-examples#term-ssl-signature "Signatures created and recognized by major SSL implementations such as OpenSSL"
[stack]: /en/developer-guide#term-stack "An evaluation stack used in Bitcoin's script language"
[standard script]: /en/developer-guide#standard-transactions "An output script which matches the isStandard() patterns specified in Bitcoin Core---or a transaction containing only standard outputs. Only standard transactions are mined or broadcast by peers running the default Bitcoin Core software"
[target]: /en/developer-guide#term-target "The threshold below which a block header hash must be in order for the block to be added to the block chain"
@ -163,13 +158,15 @@
[wallet]: /en/developer-guide#wallets "Software which stores private keys to allow users to spend and receive satoshis"
[Wallet Import Format]: /en/developer-guide#term-wallet-import-format "A private key specially formatted to allow easy import into a wallet"
[wallets]: /en/developer-guide#wallets "Software which stores private keys to allow users to spend and receive satoshis"
[X509Certificates]: /en/developer-guide#term-x509certificates
[X509Certificates]: /en/developer-examples#term-x509certificates
[BFGMiner]: https://github.com/luke-jr/bfgminer
[BIP21]: https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki
[BIP32]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
[BIP39]: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
[BIP70]: https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki
[BIP71]: https://github.com/bitcoin/bips/blob/master/bip-0071.mediawiki
[BIP72]: https://github.com/bitcoin/bips/blob/master/bip-0072.mediawiki
[bitcoin-documentation mailing list]: https://groups.google.com/forum/#!forum/bitcoin-documentation
[bitcoinpdf]: https://bitcoin.org/bitcoin.pdf
[block170]: http://blockexplorer.com/block/00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee
@ -180,6 +177,8 @@
[core paymentrequest.proto]: https://github.com/bitcoin/bitcoin/blob/master/src/qt/paymentrequest.proto
[core script.h]: https://github.com/bitcoin/bitcoin/blob/master/src/script.h
[DER]: https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One
[devex payment protocol]: /en/developer-examples#payment-protocol
[devguide]: /en/developer-guide
[devguide avoiding key reuse]: /en/developer-guide#avoiding-key-reuse
[devguide payment processing]: /en/developer-guide#payment-processing
[devguide wallets]: /en/developer-guide#wallets

View file

@ -198,7 +198,6 @@ body{
.docreference a{
zoom:1;
display:inline;
width:200px;
}
.downloadbox{

View file

@ -642,8 +642,9 @@ table td,table th{
}
.docreference a{
display:inline-block;
margin:0 15px 40px 15px;
margin:0 0 40px 0;
font-size:125%;
width:210px;
}
.docreference img{
display:block;
@ -782,6 +783,21 @@ table td,table th{
.toccontent a.term:visited code{
color:#646464;
}
.toccontent .multicode{
background-color:#f5f5f5;
overflow-y:auto;
padding:17px;
border:1px solid #ccc;
-webkit-border-radius:3px;
-moz-border-radius:3px;
border-radius:3px;
}
.toccontent .multicode pre{
border:0px none;
padding:0;
margin:0;
overflow-y:visible;
}
.anchorAf{
position:relative;

View file

@ -63,6 +63,8 @@ require 'yaml'
(?![^\[]*\]) ## No subst if key inside [brackets]
(?![^\{]*\}) ## No subst if key inside {braces}
(?![^\s]*<!--noref-->) ## No subst if <!--noref--> after key
(?![\S ]*<\/span>) ## No subst on a line with a close span. This
## prevents matching in highlight blocks
(?![^\(]*(\.svg|\.png)) ## No subst if key inside an image name. This
## simple regex has the side effect that we can't
## use .svg or .png in non-image base text; if that
@ -71,7 +73,7 @@ require 'yaml'
(?!\w) ## Don't match inside words
/xmi, "[\\&][#{term[1]}]{:.auto-link}")
}
output.gsub!('<!--noref-->','') ## Remove all <!--noref--> comments
output.gsub!(/<!--.*?-->/m,'') ## Remove all HTML comments
output
end

View file

@ -10,8 +10,9 @@ title: "Developer Documentation - Bitcoin"
<p class="summary">Find useful resources, guides and reference material for developers.</p>
<div class="docreference">
<a href="/en/developer-guide"><img src="/img/main_ico_guide.svg" alt="icon"><span>Developer Guide</span><span>(How Bitcoin works)</span></a>
<a href="/en/developer-guide"><img src="/img/main_ico_compass.svg" alt="icon"><span>Developer Guide</span><span>(How Bitcoin works)</span></a>
<a href="/en/developer-reference"><img src="/img/main_ico_guide.svg" alt="icon"><span>Developer Reference</span><span>(Specifications and APIs)</span></a>
<a href="/en/developer-examples"><img src="/img/main_ico_hash.svg" alt="icon"><span>Developer Examples</span><span>(Examples you can use)</span></a>
</div>
<div class="resources">
@ -23,6 +24,7 @@ title: "Developer Documentation - Bitcoin"
<h2><img src="/img/ico_micro.svg" class="titleicon" alt="Icon">Transactions</h2>
<p><a href="/en/developer-guide#transactions">Transactions Guide</a></p>
<p><a href="/en/developer-reference#transactions">Transactions Reference</a></p>
<p><a href="/en/developer-examples#transactions">Transaction Examples</a></p>
</div>
</div>
<div>
@ -47,6 +49,7 @@ title: "Developer Documentation - Bitcoin"
<div>
<h2><img src="/img/ico_bill.svg" class="titleicon" alt="Icon">Payment Processing</h2>
<p><a href="/en/developer-guide#payment-processing">Payment Processing Guide</a></p>
<p><a href="/en/developer-examples#payment-processing">Payment Processing Examples</a></p>
<div class="resourcesext">
<p><a href="https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki">Payment Protocol</a> - BIP70</p>
</div>

34
en/developer-examples.md Normal file
View file

@ -0,0 +1,34 @@
---
layout: base
lang: en
id: developer-examples
title: "Developer Examples - Bitcoin"
---
# Bitcoin Developer Examples
<p class="summary">Find examples of how to build programs using Bitcoin.</p>
<div markdown="1" id="toc" class="toc"><div markdown="1">
* Table of contents
{:toc}
<ul class="goback"><li><a href="/en/developer-documentation">Return To Overview</a></li></ul>
<ul class="reportissue"><li><a href="https://github.com/bitcoin/bitcoin.org/issues/new" onmouseover="updateIssue(event);">Report An Issue</a></li></ul>
</div></div>
<div markdown="1" class="toccontent">
{% include fragment_reviews_needed.md %}
{% include example_transactions.md %}
{% include example_payment_processing.md %}
{% include references.md %}
</div>
<script>updateToc();</script>
<script>addAnchorLinks();</script>

View file

@ -21,18 +21,12 @@ title: "Developer Guide - Bitcoin"
<div markdown="1" class="toccontent">
<!--Temporary disclaimer BEGIN-->
<div id="develdocdisclaimer" class="develdocdisclaimer"><div>
<b>BETA</b>: This documentation has been written recently and still needs more reviews to ensure all content is covered correctly and accurately; if you find a mistake, please <a href="https://github.com/bitcoin/bitcoin.org/issues/new" onmouseover="updateIssue(event);">report an issue</a> on GitHub. <a href="#" onclick="disclaimerClose(event);">Click here</a> to close this disclaimer.
<a class="develdocdisclaimerclose" href="#" onclick="disclaimerClose(event);">X</a>
</div></div>
<script>disclaimerAutoClose();</script>
<!--Temporary disclaimer END-->
<!-- includes should be separated by an empty line to prevent a
paragraph at the end of one file from breaking the heading at the start
of the following file. -->
{% include fragment_reviews_needed.md %}
{% include guide_intro.md %}
{% include guide_block_chain.md %}

View file

@ -20,16 +20,12 @@ title: "Developer Reference - Bitcoin"
</div></div>
<div markdown="1" class="toccontent">
<!--Temporary disclaimer BEGIN-->
<div id="develdocdisclaimer" class="develdocdisclaimer"><div>
<b>BETA</b>: This documentation has been written recently and still needs more reviews to ensure all content is covered correctly and accurately; if you find a mistake, please <a href="https://github.com/bitcoin/bitcoin.org/issues/new" onmouseover="updateIssue(event);">report an issue</a> on GitHub. <a href="#" onclick="disclaimerClose(event);">Click here</a> to close this disclaimer.
<a class="develdocdisclaimerclose" href="#" onclick="disclaimerClose(event);">X</a>
</div></div>
<script>disclaimerAutoClose();</script>
<!--Temporary disclaimer END-->
{% include fragment_reviews_needed.md %}
{% include ref_block_chain.md %}
{% include ref_transactions.md %}
{% include ref_wallets.md %}
## Bitcoin Core APIs

BIN
img/main_ico_compass.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

127
img/main_ico_compass.svg Normal file
View file

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xml:space="preserve"
width="48"
height="48"
style="fill-rule:evenodd"
viewBox="0 0 13.546666 13.546666"
id="svg2"
version="1.1"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="Compass_rose_en_04p.svg"><metadata
id="metadata34"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="800"
id="namedview32"
showgrid="false"
inkscape:zoom="1"
inkscape:cx="40.338701"
inkscape:cy="32.568949"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" />
<defs
id="defs4">
<style
type="text/css"
id="style6">
.str1 {stroke:#999999;stroke-width:0.0762}
.str0 {stroke:#B2B2B2;stroke-width:0.0762}
.fil0 {fill:none}
.fil1 {fill:#9999FF}
.fil2 {fill:#E5E5E5}
.fil3 {fill:black;fill-rule:nonzero}
</style>
</defs>
<circle
d="M 76.5,45 C 76.5,62.39697 62.39697,76.5 45,76.5 27.60303,76.5 13.5,62.39697 13.5,45 13.5,27.60303 27.60303,13.5 45,13.5 62.39697,13.5 76.5,27.60303 76.5,45 z"
style="fill:none;stroke:#000000;stroke-width:0.28222221;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
sodipodi:ry="31.5"
sodipodi:rx="31.5"
sodipodi:cy="45"
sodipodi:cx="45"
id="circle10"
r="31.5"
cy="45"
cx="45"
class="fil0 str0"
transform="matrix(0.18698133,0,0,-0.18698133,-1.7495191,15.188054)" /><polygon
id="_125488368"
class="fil1 str1"
points="45.5813,45.003 53.596,37.003 45.5813,10.003 "
style="fill:#000000;stroke:#000000;stroke-width:0.56444442;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
transform="matrix(0.18698133,0,0,-0.18698133,-1.7495191,15.188054)" /><polygon
id="_125485752"
class="fil2 str1"
points="45.5813,45.003 37.5666,37.003 45.5813,10.003 "
style="fill:#ffffff;stroke:#000000;stroke-width:0.56444442;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
transform="matrix(0.18698133,0,0,-0.18698133,-1.7495191,15.188054)" /><polygon
id="_125486160"
class="fil1 str1"
points="45.5813,45.003 53.5813,53.0177 80.5813,45.003 "
style="fill:#000000;stroke:#000000;stroke-width:0.56444442;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
transform="matrix(0.18698133,0,0,-0.18698133,-1.7495191,15.188054)" /><polygon
id="_125485464"
class="fil2 str1"
points="45.5813,45.003 53.5813,36.9883 80.5813,45.003 "
style="fill:#ffffff;stroke:#000000;stroke-width:0.56444442;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
transform="matrix(0.18698133,0,0,-0.18698133,-1.7495191,15.188054)" /><polygon
id="_125486136"
class="fil1 str1"
points="45.5813,45.003 37.5666,53.003 45.5813,80.003 "
style="fill:#000000;stroke:#000000;stroke-width:0.56444442;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
transform="matrix(0.18698133,0,0,-0.18698133,-1.7495191,15.188054)" /><polygon
id="_125485440"
class="fil2 str1"
points="45.5813,45.003 53.596,53.003 45.5813,80.003 "
style="fill:#ffffff;stroke:#000000;stroke-width:0.56444442;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
transform="matrix(0.18698133,0,0,-0.18698133,-1.7495191,15.188054)" /><polygon
id="_125488056"
class="fil1 str1"
points="45.5813,45.003 37.5813,36.9883 10.5813,45.003 "
style="fill:#000000;stroke:#000000;stroke-width:0.56444442;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
transform="matrix(0.18698133,0,0,-0.18698133,-1.7495191,15.188054)" /><polygon
id="_125486208"
class="fil2 str1"
points="45.5813,45.003 37.5813,53.0177 10.5813,45.003 "
style="fill:#ffffff;stroke:#000000;stroke-width:0.56444442;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
transform="matrix(0.18698133,0,0,-0.18698133,-1.7495191,15.188054)" /><path
style="fill:none;stroke:#000000;stroke-width:0.15696824px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 8.9329554,4.7290382 11.932577,1.7294216"
id="path3804"
inkscape:connector-curvature="0" /><path
style="fill:none;stroke:#000000;stroke-width:0.16438642px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 8.8605813,8.8551168 12.004951,11.993504"
id="path3804-4"
inkscape:connector-curvature="0" /><path
style="fill:none;stroke:#000000;stroke-width:0.16195713px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 1.659623,1.6832236 4.757519,4.7752362"
id="path3804-4-5"
inkscape:connector-curvature="0" /><path
style="fill:none;stroke:#000000;stroke-width:0.15696824px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 1.7087612,11.924122 4.7083808,8.9244992"
id="path3804-5"
inkscape:connector-curvature="0" /></svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
img/main_ico_hash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 B

67
img/main_ico_hash.svg Normal file
View file

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48"
height="48"
id="svg3896"
version="1.1"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="hashbang.svg">
<defs
id="defs3898" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="45.392857"
inkscape:cy="37.178572"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1278"
inkscape:window-height="778"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0" />
<metadata
id="metadata3901">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1004.3622)">
<text
xml:space="preserve"
style="font-size:67.09772491px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
x="2.3275659"
y="1052.3116"
id="text3904"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3906"
x="2.3275659"
y="1052.3116">#</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB