-
Notifications
You must be signed in to change notification settings - Fork 0
Multi Party
This example demonstrates a case where two parties A and B jointly issue a certificate that contains a multisignature base key which they split among themselves. Think of A and B as business partners who do not want either one of them to be able to control incoming payments alone (without the other partner). For simplicity we assume A and B have their machines running online. In practive, of course, the owner and receiving base keys should be generated on an offline machine. The joint project is called fooproject.
A and B create their receiving base keys:
@onlineA: ./bitcoind -testnet getnewaddress fooproj_recvA true
0285b2eb2c0f2e4a12646dbcf38d08c29ef557b5616048575b133a2084a56bb84a
@onlineB: ./bitcoind -testnet getnewaddress "fooproj_recvB" true
03ba3137ddbee4e164390b7b67e0975d12969ef23ac1fd7b1f7e880319d072b323
A and B create their owner keys (revokation keys) for the certificate:
@rsonlineA: ./bitcoind -testnet getnewaddress "fooproj_ownerA" true
0397badc73e72ab8ddde12fa6512bc52e2de58870b682dffe9e08c31620f71b8e4
@onlineB: ./bitcoind -testnet getnewaddress "fooproj_ownerB" true
025c62affbfb6889603a204ccbde287d4d84c993b30e74a86e4ed51a56584ca822
B sends both his base pubkeys to A, who drafts the certificate using his and B's receiving base pubkey in the file fooproject.yml:
data:
version: 0.1
subjectname: Foo Project
contacts:
- type: EMAIL
value: [email protected]
- type: EMAIL
value: [email protected]
- type: URL
value: "http://www.fooproject.com"
paymentkeys:
- algorithm:
type: P2CMULTI
version: 0.1
value: [ 2, 0285b2eb2c0f2e4a12646dbcf38d08c29ef557b5616048575b133a2084a56bb84a, 03ba3137ddbee4e164390b7b67e0975d12969ef23ac1fd7b1f7e880319d072b323 ]
A signs the certificate:
@onlineA: bcert/mkbcrt.py fooproject.yml
@onlineA: HEX=`xxd -p fooproject.bcrt | tr -d "\n"`
@onlineA: ./bitcoind -testnet bcsigncert '{"alias":"fooproject","owners":["0397badc73e72ab8ddde12fa6512bc52e2de58870b682dffe9e08c31620f71b8e4","025c62affbfb6889603a204ccbde287d4d84c993b30e74a86e4ed51a56584ca822"]}' $HEX
{
"bcsignresult" : {
"nFee" : 0.00050000,
"txid" : "efa92a4d7475f7c6ac22c5635a422e65a6d90035cd148b8c6cdaed806c0119ff",
"fname" : "ad3ac8fe7136a922e2595417ddcebfdf5c764ca1"
}
}
The result of mkbcrt.py
is fooproject.bcrt.
A sends the file ~/.bitcoin/testnet3/bcerts/ad3ac8fe7136a922e2595417ddcebfdf5c764ca1.bcrt
to B (email).
B verifies that his receiving base pubkey appears in the cert and the signature value is fooproject
,
and then imports it to his bitcoind:
@onlineB: bcert/dumpbcrt.py ad3ac8fe7136a922e2595417ddcebfdf5c764ca1.bcrt
data {
version: "0.1"
subjectname: "Foo Project"
contacts {
type: EMAIL
value: "[email protected]"
}
contacts {
type: EMAIL
value: "[email protected]"
}
contacts {
type: URL
value: "http://www.fooproject.com"
}
paymentkeys {
usage: PAYMENT
algorithm {
type: P2CMULTI
version: "0.1"
}
value: "2"
value: "\002\205\262\353,\017.J\022dm\274\363\215\010\302\236\365W\265a`HW[\023: \204\245k\270J"
value: "\003\27217\335\276\344\341d9\013{g\340\227]\022\226\236\362:\301\375{\037~\210\003\031\320r\263#"
}
}
signatures {
algorithm {
type: BCPKI
version: "0.4"
}
value: "fooproject"
}
@onlineB: mv ad3ac8fe7136a922e2595417ddcebfdf5c764ca1.bcrt ~/.bitcoin/testnet3/bcerts/
B verifies the signature in the blockchain:
@onlineB: ./bitcoind -testnet bcverify fooproject
{
"fSigned" : true,
"txid" : "efa92a4d7475f7c6ac22c5635a422e65a6d90035cd148b8c6cdaed806c0119ff",
"confirmations" : 1,
"strTime" : "2013-02-07T15:28:05"
}
B also looks at the scriptPubKeys to verify that his owner pubkey 025c62affbfb6889603a204ccbde287d4d84c993b30e74a86e4ed51a56584ca822
is indeed required to revoke the certificate:
@onlineB: ./bitcoind -testnet bclist fooproject
{
"fRegistered" : true,
"txid" : "efa92a4d7475f7c6ac22c5635a422e65a6d90035cd148b8c6cdaed806c0119ff",
"confirmations" : 1,
"strTime" : "2013-02-07T15:28:05",
"values" : [
{
"vout" : 1,
"id" : "ad3ac8fe7136a922e2595417ddcebfdf5c764ca1",
"ownersReq" : 2,
"amount" : 0.05000000,
"owner" : "0397badc73e72ab8ddde12fa6512bc52e2de58870b682dffe9e08c31620f71b8e4",
"owner" : "025c62affbfb6889603a204ccbde287d4d84c993b30e74a86e4ed51a56584ca822"
},
{
"vout" : 2,
"id" : "2451b6d25d8217cc13b44b2f78ef01e0fcec6841",
"ownersReq" : 2,
"amount" : 0.05000000,
"owner" : "0397badc73e72ab8ddde12fa6512bc52e2de58870b682dffe9e08c31620f71b8e4",
"owner" : "025c62affbfb6889603a204ccbde287d4d84c993b30e74a86e4ed51a56584ca822"
}
]
}
Note that B needs to verify this for both outpoints. Now the project can start.
A and B both add the receiving base address to their wallet:
@onlineA|B: ./bitcoind -testnet addmultisigaddress 2 '["0285b2eb2c0f2e4a12646dbcf38d08c29ef557b5616048575b133a2084a56bb84a","03ba3137ddbee4e164390b7b67e0975d12969ef23ac1fd7b1f7e880319d072b323"]' fooproj_recv
2NAM5kqrMNAVUFtwN9cQeTJyMJ5mSukorvH
They upload the certificate to a server:
@onlineB: HEX=`bcert/dumpbcrt.py -s -x fooproject`
@onlineB: wget -O log.html "http://btcrypt.org/cgi-bin/transfer.cgi?hexcert=$HEX"
A third party C imports the certificate from a server:
@onlineC: wget -q --content-disposition -P ~/.bitcoin/testnet3/bcerts "http://btcrypt.org/cgi-bin/get.cgi?alias=fooproject&format=b"
C pays directly to fooproject via the P2CMULTI method (pay-to-contract with multiple base keys).
Say the chosen ticket is 4febe382ed164145bf248b448444b807
.
@onlineC: ./bitcoind -testnet sendtoalias fooproject '[2,"4febe382ed164145bf248b448444b807"]' 0.5
{
"dest" : "2Msp2TjXvUPr4qopYhQGujq7s4HukzfivAR",
"txid" : "8320db2222fce16cadceea89ec59c16e6e972e9457046fbd9007b8ff073d1202",
"vout" : 0
}
Here, the number 2
is the payment method and means P2CMULTI.
The derived destination is the P2SH address that we see.
Look at the transaction:
@onlineC: ./bitcoind -testnet gettransaction 8320db2222fce16cadceea89ec59c16e6e972e9457046fbd9007b8ff073d1202
{
[...]
"p2cmulti" : "0285b2eb2c0f2e4a12646dbcf38d08c29ef557b5616048575b133a2084a56bb84a 03ba3137ddbee4e164390b7b67e0975d12969ef23ac1fd7b1f7e880319d072b323 ",
"ticket" : "4febe382ed164145bf248b448444b807",
"to" : "BCSIG_v0.4_F0PR0JECT<P2CMULTI:4febe382ed164145bf248b448444b807> = 2 038bf68f4f9eb98f38b5d2f4ded5707ff7a5e5b450a99ad75aa0e2de2022836570 0204a656ffeb67fe17d0e281ae182fd96dd5632f5469dc5295ca0a535dc672c1a8 2 OP_CHECKMULTISIG",
[...]
"vout" : [
{
"value" : 0.50000000,
"n" : 0,
"scriptPubKey" : {
"asm" : "OP_HASH160 06341acebd4d3248d447a201b7a912baed8c0e99 OP_EQUAL",
"hex" : "a91406341acebd4d3248d447a201b7a912baed8c0e9987",
"reqSigs" : 1,
"type" : "scripthash",
"addresses" : [
"2Msp2TjXvUPr4qopYhQGujq7s4HukzfivAR"
]
}
},
[...]
}
We see A and B's base receiving pubkeys in the field p2cmulti and the derived pubkeys in the script under to. The output is the P2SH of that script.
A and B import the ticket
@onlineA|B: ./bitcoind -testnet importticket 2NAM5kqrMNAVUFtwN9cQeTJyMJ5mSukorvH 4febe382ed164145bf248b448444b807
{
"derived" : "2Msp2TjXvUPr4qopYhQGujq7s4HukzfivAR"
}
(This may be slow due to a rescan) This has created an account:
@onlineA|B: ./bitcoind -testnet getaccount 2Msp2TjXvUPr4qopYhQGujq7s4HukzfivAR
fooproj_recv<4febe382ed164145bf248b448444b807>
Unfortunately, bitcoind does not allow to watch arbitrary addresses without having the private key at hand, nor to watch non-wallet transactions.
So A and B have to use a different client or an online service to watch for the incoming payment on 2Msp2TjXvUPr4qopYhQGujq7s4HukzfivAR
and see the confirmations.
A creates a transaction that spends the coin received for 2Msp2TjXvUPr4qopYhQGujq7s4HukzfivAR
, and partially signs it:
@onlineA: ./bitcoind -testnet getnewaddress
msFrMcXFB4R8vHQJAMXZa8H3RAD6BJkPD8
@onlineA: RAWTX=`./bitcoind -testnet createrawtransaction '[{"txid":"8320db2222fce16cadceea89ec59c16e6e972e9457046fbd9007b8ff073d1202","vout":0}]' '{"msFrMcXFB4R8vHQJAMXZa8H3RAD6BJkPD8":0.45}'`
@onlineA: ./bitcoind -testnet signrawtransaction $RAWTX
{
"hex" : "010000000102123d07ffb80790bd6f0457942e976e6ec159ec89eacead6ce1fc22 ...",
"complete" : false
}
B signs it too and commits it:
@onlineB: ./bitcoind -testnet signrawtransaction 010000000102123d07ffb80790bd6f0457942e976e6ec159ec89eacead6ce1fc22...
{
"hex" : "010000000102123d07ffb80790bd6f0457942e976e6ec159ec89eacead6ce1fc2222db208300000000dc00493046022100d22d5e1ddbee47b6468ff6b63d7b76fe857c4db4f8e9b9c64a6771cd148f4ee3022100a4a20cd7647543978f0adbd05f369a3879b55c15cc8c459926d24afe821f17d701483045022100d2c1d00fb86a30cbc5c3d7860ebc296f273abfc4080c86bc6750396bb59d5f6c02200c13c7910d270b6f8b092f2958197b0a9e8d3fdd27a602e9f80d884b366555eb01475221038bf68f4f9eb98f38b5d2f4ded5707ff7a5e5b450a99ad75aa0e2de2022836570210204a656ffeb67fe17d0e281ae182fd96dd5632f5469dc5295ca0a535dc672c1a852aeffffffff0140a5ae02000000001976a91480c6500a42d6b7281f18ff544c339396aa60a11b88ac00000000",
"complete" : true
}
@onlineB: ./bitcoind -testnet sendrawtransaction 010000000102123d07ffb80790bd6f0457942e976e6ec159ec89eacead6ce1fc2222db208300000000dc00493046022100d22d5e1ddbee47b6468ff6b63d7b76fe857c4db4f8e9b9c64a6771cd148f4ee3022100a4a20cd7647543978f0adbd05f369a3879b55c15cc8c459926d24afe821f17d701483045022100d2c1d00fb86a30cbc5c3d7860ebc296f273abfc4080c86bc6750396bb59d5f6c02200c13c7910d270b6f8b092f2958197b0a9e8d3fdd27a602e9f80d884b366555eb01475221038bf68f4f9eb98f38b5d2f4ded5707ff7a5e5b450a99ad75aa0e2de2022836570210204a656ffeb67fe17d0e281ae182fd96dd5632f5469dc5295ca0a535dc672c1a852aeffffffff0140a5ae02000000001976a91480c6500a42d6b7281f18ff544c339396aa60a11b88ac00000000
1299682d4d0ad6418535cf9fec09e6cb95ee312f9345255fa088647b4ac4a234
A imports the private key corresponding to alias:
@onlineA: ./bitcoind -testnet aliasdump fooproject
{
"normalized" : "BCSIG_v0.4_F0PR0JECT",
"bcvalue" : "3c66a8afea592deb11d7d40ee07ec2b48d0e4256",
"privkey" : "cMahea7zqjxrtgAbB7kjubh5TML4cbhdrrYHznStWYM1vj83F5qr",
"pubkey" : "02b92c312b79b6c4910489997e640da4e749b4c9173acf10ea6c364fc918eb0d41",
"id" : "ad3ac8fe7136a922e2595417ddcebfdf5c764ca1",
"addr" : "mwJuchk8iqmFEXSVE7CpXUXRnEMFRqXqi6"
}
@onlineA: ./bitcoind -testnet importprivkey cMahea7zqjxrtgAbB7kjubh5TML4cbhdrrYHznStWYM1vj83F5qr
A looks at the relevant outpoint of the signing transaction, creates a revokation transaction, and partially signs it:
@onlineA: ./bitcoind -testnet bclist fooproject
{
"fRegistered" : true,
"txid" : "efa92a4d7475f7c6ac22c5635a422e65a6d90035cd148b8c6cdaed806c0119ff",
"confirmations" : 1,
"strTime" : "2013-02-07T15:28:05",
"values" : [
{
"vout" : 1,
"id" : "ad3ac8fe7136a922e2595417ddcebfdf5c764ca1",
"ownersReq" : 2,
"amount" : 0.05000000,
"owner" : "0397badc73e72ab8ddde12fa6512bc52e2de58870b682dffe9e08c31620f71b8e4",
"owner" : "025c62affbfb6889603a204ccbde287d4d84c993b30e74a86e4ed51a56584ca822"
},
{
"vout" : 2,
"id" : "2451b6d25d8217cc13b44b2f78ef01e0fcec6841",
"ownersReq" : 2,
"amount" : 0.05000000,
"owner" : "0397badc73e72ab8ddde12fa6512bc52e2de58870b682dffe9e08c31620f71b8e4",
"owner" : "025c62affbfb6889603a204ccbde287d4d84c993b30e74a86e4ed51a56584ca822"
}
]
}
@onlineA: RAWTX=`./bitcoind -testnet createrawtransaction '[{"txid":"efa92a4d7475f7c6ac22c5635a422e65a6d90035cd148b8c6cdaed806c0119ff","vout":1}]' '{"mgZL8xBMo2kpVeJHSSEi2x14pCJw5wndfp":0.0495}'`
@onlineA: ./bitcoind -testnet signrawtransaction $RAWTX
{
"hex" : "0100000001ff19016c80edda6c8c8b14cd3500d9a6652e425a63c522acc6f775744d2aa9ef010000009300483045022100db90e45e03b712ec013fd49170446e1bcabff5928c4c42084dba75fe200e848f0220616032f9a964cab4b955dc92bf86ea9848718c679993eff7afb1e29e9f3fbe3b0147304402207da9924b61d8bb7c4599fd8421bae6f9e33f2ffb0ea58e5fdc673c89a12d7df3022005b377833ec46bb5a2758da83baea7d84add50c1240494ba8de4317854c33d540100ffffffff01f0874b00000000001976a9140b6b30fe9fc8b5023dbecd403a336434b87c1a9688ac00000000",
"complete" : false
}
B also signs and commits:
@onlineB: ./bitcoind -testnet signrawtransaction 0100000001ff19016c80edda6c8c8b14cd3500d9a6652e425a63c522acc6f775744d2aa9ef010000009300483045022100db90e45e03b712ec013fd49170446e1bcabff5928c4c42084dba75fe200e848f0220616032f9a964cab4b955dc92bf86ea9848718c679993eff7afb1e29e9f3fbe3b0147304402207da9924b61d8bb7c4599fd8421bae6f9e33f2ffb0ea58e5fdc673c89a12d7df3022005b377833ec46bb5a2758da83baea7d84add50c1240494ba8de4317854c33d540100ffffffff01f0874b00000000001976a9140b6b30fe9fc8b5023dbecd403a336434b87c1a9688ac00000000
{
"hex" : "0100000001...
"complete" : true
}
@onlineB: ./bitcoind -testnet sendrawtransaction 0100000001...
After the revoking is confirmed we verify:
@onlineB: ./bitcoind -testnet bclist fooproject
{
"fRegistered" : false
}
Previous: Pay-to-contract