Fork me on GitHub

The New Bitcore API

Decentralized multi-sig, payment channels, and much more.



Eric Martindale

@martindale • Google Interview • April 2nd, 2015

What is this Bitcoin thing, anyway?

(we're actually talking about the "blockchain")

Computer Science Perspective...

distributed consensus algorithm

Financial Perspective...

triple-entry accounting system

Hacker's Perspective...

crack-proof decentralized database

    Built for BitPay's needs:

    Secure, modular, and extensible

Abstract classes for taking Bitcoin beyond currency

PublicKey , PrivateKey , Script , Peer , ...

and much more:

bitcore.io/docs

  • Isomorphic; server and client run the same code.
  • 98% test coverage
  • Passes all of Bitcoin Core's Tests

Constructing Transactions


var Transaction = require('bitcore').Transaction;
var transaction = new Transaction();

transaction
  .from( unspent1 )
  .to( destination , 230000 )
  .fee( 10000 )
  .change( change )
  .sign( privateKey1 );
            

var bitcore       = require('bitcore');
var Transaction   = bitcore.Transaction;
var Address       = bitcore.Address;
var PrivateKey    = bitcore.PrivateKey;
var UnspentOutput = bitcore.Transaction.UnspentOutput;

var change      = new Address('mursDVxqNQmmwWHACpM9VHwVVSfTddGsEM');
var privateKey1 = PrivateKey.fromWIF('cW1wwrvnJB3V2qe9HE6aW85vkGhuVX9JSaDLQ6k6uRuhMFhdi3jC');

var unspent1 = UnspentOutput({
  "txid" : "0516af39393b4173e8e2e6732c2d5dc22aa4c55c1258d20a2e07836e26f4e8de",
  "vout" : 0,
  "address" : "mqM8h7jDiuTiqgeDDkibNHmKxCmbqAF7Gy",
  "scriptPubKey" : "76a9146bd5c7192e244326a6ddc41268227a805c0cb35288ac",
  "amount" : 0.00240000
});

var destination = new Address('mnCXgzs3x4dfMMGacuPRCLmVci1x93C42u');

var transaction = Transaction();
transaction
  .from(unspent1)
  .to(destination, 230000)
  .fee(10000)
  .change(change)
  .sign(privateKey1);

            

Broadcasting Transactions


var serialized = transaction.serialize();
console.log(serialized);

/*
0100000001dee8f4266e83072e0ad258125cc5a42ac25d2d2c73e6e2e873413b3939af
1605000000006a473044022017ce08556eaab402c74bc9156c09a2981438e18b585afb
cb245ffa8c84205c7202200df7200871add40f69d18cb41278a27957cf2a67346cfb84
ed693385bc0871e701210226ab3b46f85bf32f63778c680e16ef8b3fcb51d638a7980d
651bfaeae6c17752ffffffff0170820300000000001976a914494cdabd3ec1ba39bea8
4e4f3628d9861ceada6a88ac00000000
*/

            
Bitcoin Core: "sendrawtransaction" (json-rpc console) txid: 7d62d8ac87f1250f77d76c51b69fd193883b6a77f473c318a10e4e0c5bcd3d67

Plugins: bitcore-p2p


var Peer = require('bitcore-p2p').Peer;
var peer = new Peer('5.9.85.34');

// handle events
peer.on('inv', function(message) {
  // message.inventory[]
});

peer.on('tx', function(message) {
  // message.transaction
});

peer.on('addr', function(message) {
  // message.addresses[]
});

peer.connect();
            

Plugins: bitcore-p2p


var Pool = require('bitcore-p2p').Pool;
var Networks = require('bitcore').Networks;
var pool = new Pool(Networks.livenet);

// connect to the network
pool.connect();

// attach peer events
pool.on('peerinv', function(peer, message) {
  // a new peer message has arrived
});

// will disconnect all peers
pool.disconnect();
            

bitcore-channel: consumer


var Consumer = require('bitcore-channel').Consumer;

var providerPublicKey = '027f10e67bea70f847b3ab92c18776c6a97a78f84def158afc31fd98513d42912e';
var refundAddress = 'mzCXqcsLBerwyoRZzBFQELHaJ1ZtBSxxe6';
var providerAddress = 'mrCHmWgn54hJNty2srFF4XLmkey5GnCv5m';

var consumer = new Consumer({
  network: 'testnet',
  providerPublicKey: providerPublicKey,
  providerAddress: providerAddress,
  refundAddress: refundAddress
});

console.info('Send bitcoins to ' + consumer.fundingAddress.toString() ' to fund the channel');
consumer.processFunding([{...}, {...}, {...}]);

var messageToProvider = consumer.setupRefund();
            

bitcore-channel: provider


var Provider = require('bitcore-channel').Provider;

var paymentAddress = 'mig4mc6q7PTQ2YZ9ax5YtR4gjARfoqJSZd';

var provider = new Provider({
  network: 'testnet',
  paymentAddress: paymentAddress
});

console.info('Share this public key with potential consumers: ' + provider.getPublicKey());

var messageToConsumer = provider.signRefund(receivedRefund);

assert( consumer.validateRefund(messageFromProvider) );
sendToProvider( consumer.incrementPaymentBy(400 * SATOSHIS) );
sendToProvider( consumer.incrementPaymentBy(4 * BITS) );

assert(provider.validPayment(messageFromConsumer));
assert(provider.currentAmount === 8 * BITS);

// interrupt and broadcast
provider.getPaymentTx();
            

Miner Fee with Data


var unspent2 = UnspentOutput({
  "txid" : "0fdf4e24ca0936f77effad80081396ccab293232bcd7eb76544960576e03150e",
  "vout" : 0,
  "address" : "mwsXqRzBdnP7vLKpGadwNSJPW6LcFCrX8S",
  "scriptPubKey" : "76a914b36654943f895765d2769b3bd0d6fbdcbe0dfc2288ac",
  "amount" : 0.00050000,
  "confirmations" : 40037
});

var privateKey2 = PrivateKey.fromWIF('cRq6hUM6jsQ4j5t188cEC5jvjLGtZzgJ8UZgEz5933vbv2rA4gge');

var transaction2 = Transaction();
transaction2
  .from(unspent2)
  .fee(50000);

// Uses OP_RETURN 
transaction2.addData('hello, world');
transaction2.sign(privateKey2);

var serialized2 = transaction2.uncheckedSerialize();
          
testnet3 txid: 4b163326f01992f60a2a30ba414807a99d5c233039c4cb95f07c71bf73a56146

Multi-sig


var multiSigTransaction = new Transaction();
var alicePubKey = new PublicKey();
var bobPubKey = new PublicKey();

var unspentInput = UnspentOutput({
  "txid" : "1256eddc7fcb279664dcb58853bc6172d0648ac8a07d91aa2e70db8ecc2c95e3",
  "vout" : 1,
  "address" : "n1QYBu3YpCkt7tH2BhWogwUVU3zgC2vS8J",
  "scriptPubKey" : "76a914da2be5a960dd2fcfdfb71c7ed5f6822370e6b94588ac",
  "amount" : 0.04160000
});

multiSigTransaction.from(unspentInput);
multiSigTransaction.fee(10000);

multiSigTransaction.addOutput(new Output({
  script: Script.buildMultisigOut([ alicePubKey , bobPubKey ], 1),
  satoshis: 4150000
}));

multiSigTransaction.sign( inputPrivateKey );

var serialized = multiSigTransaction.serialize();
            
testnet3 txid: 098acedb2bc18a1f46410b0390b9e2726e3544fe49732c1235516a004df8e9ec

    The "Wallet for Everyone."

    Easy to manage, securely.

copay.io

github.com/bitpay/...

bitcore-wallet
bitcore-wallet-service
bitcore-wallet-client

Up next...

- Foxtrot, for all network messages.

- Air-gapping, hardware wallet support.

- Decentralized identity management.

- CoinJoin?

ChainDB
      by bitpay

blockchain database framework

define your own, custom transaction rules

Secured by the Bitcoin Blockchain.

What is a blockchain?

  • Distributed system
  • Tamper-resistant history
  • Rewind, Replay, Resume
  • Data Consistency

var ChainDB = require('chaindb');
var chaindb = new ChainDB({
  consensus: {
    type: 'pof', // proof of fee
    xprivkey: 'someprivkey', // bitcoin HD private key with funds
  },
  db: {
    type: 'simple', // simple key-value datastore
    path: './pof-simple.db' // actual on-disk storage
  }
});

chaindb.on('ready', function() {
  // set value...
  chaindb.set( 'somekey' , 'somevalue' , function(err) {} );
  
  // retrieve value!
  chaindb.get( 'somekey' , function(err, value) {
    console.log('somekey:', value );
  });

});

chaindb.initialize();
            

Proof of Fee

resolve chain conflicts not based on block height,

but based on the Bitcoin spent for the entire chain,

weighted towards older blocks.

Applications (Short Term)

  • Key-value stores
    • Proof of Existence
    • DNS for Public Key Hashes
    • DNS for, well, DNS
  • Document stores
    • Tamper-proofing existing databases
    • Atomic snapshots
    • Verifiable state history

Applications (Long Term)

  • Replace the SSL/TLS PKI (eliminate CAs)
  • Identity Assertion
  • Proof of Ownership
    • Deeds
    • Titles
    • Equity
  • Smart Contracts

Other Projects

Namecoin

namecoin.org

DNSChain

github.com/okTurtles/dnschain

Blockstore

github.com/openname/blockstore

DEJE

github.com/DJDNS/go-deje

bitcore.io

Discussion & Questions

eric@bitpay.com    •    @martindale

github.com/martindale