Skip to content
Timo Hanke edited this page Feb 7, 2013 · 22 revisions

Pay-to-Contract

Example 2: Pay-to-Contract (customer-generated payment addresses)

Intro

This example demonstrates how the certificate specification as well as bitcoind can handle a base key from which the customer can generate (i.e. derive) individual payment addresses for each transaction. We call this a pay-to-contract-payment.

As in Example 1 we have only one online-machine and assume to have changed to directory src.

Certificate creation

We first get one fresh pubkey from our keystore:

@onlinemachine: ./bitcoind -testnet getnewaddress "p2cbase" true
02537af4f00677d5f13916618f865abcac79a51e485ad0da26aab2532f499af376

Note that getnewaddress has a (newly introduced) second argument. Setting it to true returns the pubkey instead of the address, which is what we need here. This pubkey is entered into foo1_p2csingle.yml

data:
  version: 0.1
  subjectname: Foo Inc.
  contacts: 
   - type: EMAIL
     value: [email protected]
   - type: URL  
     value: "http://www.fooinc.com"
  paymentkeys:
    - algorithm:
       type: P2CSINGLE
       version: 0.1
      value: [ 02537af4f00677d5f13916618f865abcac79a51e485ad0da26aab2532f499af376 ]

Convert yaml to a binary protobuf message and print for verification:

@onlinemachine: bcert/mkbcrt.py foo1_p2csingle

This has produced the file foo1_p2csingle.bcrt which we can parse and pretty-print:

@onlinemachine: bcert/dumpbcrt.py foo1_p2csingle.bcrt
data {
  version: "0.1"
  subjectname: "Foo Inc."
  contacts {
    type: EMAIL
    value: "[email protected]"
  }
  contacts {
    type: URL
    value: "http://www.fooinc.com"
  }
  paymentkeys {
    usage: PAYMENT
    algorithm {
      type: P2CSINGLE
      version: "0.1"
    }
    value: "\002Sz\364\360\006w\325\3619\026a\217\206Z\274\254y\245\036HZ\320\332&\252\262S/I\232\363v"
  }

Signing

@onlinemachine: HEX=`xxd -p foo1_p2csingle.bcrt | tr -d "\n"`

or

@onlinemachine: HEX=`bcert/dumpbcrt.py -x foo1_p2csingle.bcrt`

Then

@onlinemachine: ./bitcoind -testnet bcsigncert foo1 $HEX
{
    "bcsignresult" : {
        "nFee" : 0.00050000,
        "txid" : "862be784f1d1e1308a67b01c3c440310339c1a2cfb2ebb3b41a3ac0eb7e0e3af",
        "fname" : "ecff20c2e787f20913522799cd8e216d4c69a355"
    }
}

{
    "nFee" : 0.00050000,
    "txid" : "76d34af42d1b166ee81835d5066994930eee8785d119c3b82cd706501aa12e00",
    "fname" : "418dbc6c2567baab3db74dbdb95bacc7f88e02e2"
}
@onlinemachine: bcert/dumpbcrt.py -s foo1
data {
  version: "0.1"
  subjectname: "Foo Inc."
  contacts {
    type: EMAIL
    value: "[email protected]"
  }
  contacts {
    type: URL
    value: "http://www.fooinc.com"
  }
  paymentkeys {
    usage: PAYMENT
    algorithm {
      type: P2CSINGLE
      version: "0.1"
    }
    value: "\002Sz\364\360\006w\325\3619\026a\217\206Z\274\254y\245\036HZ\320\332&\252\262S/I\232\363v"
  }
}
signatures {
  algorithm {
    type: BCPKI
    version: "0.4"
  }
  value: "foo1"
}

Certficate Server

Upload

@onlinemachine: HEX=`bcert/dumpbcrt.py -s -x foo1`
@onlinemachine: wget -O log.html http://btcrypt.org/cgi-bin/transfer.cgi?hexcert=$HEX

Download and import

@onlinemachine: wget -q --content-disposition -P ~/.bitcoin/testnet3/bcerts "http://btcrypt.org/cgi-bin/get.cgi?alias=foo1&format=b"

Verification in blockchain:

@onlinemachine: ./bitcoind -testnet bcverify foo1
{
    "fSigned" : true,
    "txid" : "862be784f1d1e1308a67b01c3c440310339c1a2cfb2ebb3b41a3ac0eb7e0e3af",
    "confirmations" : 2,
    "strTime" : "2013-02-07T13:40:37"
}

Paying

Now we are ready to pay directly to alias foo1 via the P2CSINGLE method (pay-to-contract with a single base key). For that we need a random number that we call the ticket. Either ticket was given to us by the payee or we can generate it ourselves and then submit it to the payee. It is passed to the RPC sendtoalias encoded as a big-endian hexadecimal number up to 256 bits. We come up with a 128 bit random number such as 1294bf2b3f8945d3b78cb55f6cf018a0 (generated by uuidgen).

@onlinemachine: ./bitcoind -testnet sendtoalias foo1 '[1,"1294bf2b3f8945d3b78cb55f6cf018a0"]' 0.5
{
    "dest" : "n4YNcNUb8FfMrWbhe4C7iKS1ELNxCTgNmN",
    "txid" : "1c849cef91405688b1f6ea7cdc2192c9a840b82e0263274477f2c07b4f87126d",
    "vout" : 0
}

The number 1 in the second argument specified the payment method (1 means P2CSINGLE) and requires that foo1's certificate actually has a payment key for that method. The address listed under dest is the derived address. It is the address corresponding to the curve point ticket*G+P where G is the base point of the curve and P is the point stored in foo1's certificate. The output cannot be spent without knowledge of ticket, so sendtoalias has saved ticket in the wallet transaction (only partial output shown):

@onlinemachine: ./bitcoind -testnet gettransaction 1c849cef91405688b1f6ea7cdc2192c9a840b82e0263274477f2c07b4f87126d
{
    [...]
    "p2csingle" : "02537af4f00677d5f13916618f865abcac79a51e485ad0da26aab2532f499af376",
    "ticket" : "1294bf2b3f8945d3b78cb55f6cf018a0",
    "to" : "BCSIG_v0.4_F01<P2CSINGLE:1294bf2b3f8945d3b78cb55f6cf018a0> = n4YNcNUb8FfMrWbhe4C7iKS1ELNxCTgNmN",
    [...]
    "vout" : [
      { "value" : 0.50000000, "n" : 0,
         "scriptPubKey" : { [...] "addresses" : [ " n4YNcNUb8FfMrWbhe4C7iKS1ELNxCTgNmN" ] } }
        ]
}

Receiving and Spending

Before we can spend this output we have to import the private key corresponding to dest by giving both the basekey and ticket to the RPC importticket:

@onlinemachine: ./bitcoind -testnet getaddressesbyaccount p2cbase
[
  "mpxXHdfkZGrWeLXtLAK3ci9kaqn2gREir1" 
]
@onlinemachine: ./bitcoind -testnet importticket mpxXHdfkZGrWeLXtLAK3ci9kaqn2gREir1 1294bf2b3f8945d3b78cb55f6cf018a0
{
    "derivedaddr" : "n4YNcNUb8FfMrWbhe4C7iKS1ELNxCTgNmN"
}

The return value convinces us that we imported the correct key. The RPC importticket has also derived a new account from the account name of the base key, which we set to p2cbase in the beginning.

@onlinemachine: ./bitcoind -testnet getaccount n4YNcNUb8FfMrWbhe4C7iKS1ELNxCTgNmN
p2cbase<1294bf2b3f8945d3b78cb55f6cf018a0>

Checking the balance:

@onlinemachine: ./bitcoind -testnet getbalance "p2cbase<1294bf2b3f8945d3b78cb55f6cf018a0>"
0.50000000

Re-spending the output:

@onlinemachine: ./bitcoind -testnet spendoutpoint 1c849cef91405688b1f6ea7cdc2192c9a840b82e0263274477f2c07b4f87126d 0
{
    "nFee" : 0.00050000,
    "txid" : "a02986a383cd912b931121d8dbf8554f9e15c88fc2ed5091996f7261f943a22b"
}

Revoking

same as in First-Steps.

Next: Multi-Party Previous: First-Steps

Clone this wiki locally