diff --git a/README.md b/README.md index 85b8164..942b774 100644 --- a/README.md +++ b/README.md @@ -33,260 +33,9 @@ var PeerManager = bitcore.PeerManager; #Examples -Some examples are provided at the [examples](/examples) path. Here are some snippets: +Examples are provided [here](examples.md) +Or in form of .js files at [/examples](/examples) folder. -## Validating an address - -Validating a Bitcoin address: - -```js -var bitcore = require('bitcore'); -var Address = bitcore.Address; - -var addrs = [ - '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', - '1A1zP1eP5QGefi2DMPTfTL5SLmv7Dixxxx', - 'A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', - '1600 Pennsylvania Ave NW', -].map(function(addr) { - return new Address(addr); -}); - -addrs.forEach(function(addr) { - var valid = addr.isValid(); - console.log(addr.data + ' is ' + (valid ? '' : 'not ') + 'valid'); -}); -``` - -## Monitoring Blocks and Transactions - -For this example you need a running bitcoind instance. - -```js - var bitcore = require('../bitcore'); - var Peer = bitcore.Peer; - var PeerManager = bitcore.PeerManager; - - var handleBlock = function(info) { - console.log('** Block Received **'); - console.log(info.message); - }; - - var handleTx = function(info) { - var tx = info.message.tx.getStandardizedObject(); - - console.log('** TX Received **'); - console.log(tx); - }; - - var handleInv = function(info) { - console.log('** Inv **'); - console.log(info.message); - - var invs = info.message.invs; - info.conn.sendGetData(invs); - }; - - var peerman = new PeerManager({ - network: 'testnet' - }); - - peerman.addPeer(new Peer('127.0.0.1', 18333)); - - peerman.on('connection', function(conn) { - conn.on('inv', handleInv); - conn.on('block', handleBlock); - conn.on('tx', handleTx); - }); - - peerman.start(); -``` - -PeerManager will emit the following events: 'version', 'verack', 'addr', 'getaddr', 'error' 'disconnect'; and will relay events like: 'tx', 'block', 'inv'. Please see [PeerManager.js](lib/PeerManager.js), [Peer.js](lib/Peer.js) and [Connection.js](lib/Connection.js) - -## Consuming bitcoind RPC - -For this example you need a running bitcoind instance with RPC enabled. - -```js -var bitcore = require('bitcore'); -var RpcClient = bitcore.RpcClient; -var hash = '0000000000b6288775bbd326bedf324ca8717a15191da58391535408205aada4'; - -var config = { - protocol: 'http', - user: 'user', - pass: 'pass', - host: '127.0.0.1', - port: '18332', -}; - -var rpc = new RpcClient(config); - -rpc.getBlock(hash, function(err, ret) { - if (err) { - console.error('An error occured fetching block', hash); - console.error(err); - return; - } - console.log(ret); -}); -``` - -Check the list of all supported RPC call at [RpcClient.js](lib/RpcClient.js) - -## Creating and sending a Transaction through P2P - -The fee of the transaction can be given in `opts` or it will be determined -by the transaction size. Documentation on the parameters of `TransactionBuilder` -can be found on the source file. - -```js - var bitcore = require('bitcore'); - var Peer = bitcore.Peer; - var TransactionBuilder = bitcore.TransactionBuilder; - var PeerManager = bitcore.PeerManager; - - // Unspent transactions can be found via the insight.bitcore.io or blockchain.info APIs - var unspent = [{ - 'txid': '707108b5ba4f78dc951df4647a03365bf36432ea57fb641676045c5044daaea7', - 'vout': 0, - 'address': 'n3QDC7DzsMmN4mcyp3k7XGPX7zFXXHG387', - 'scriptPubKey': '76a914f00c4a92ee2314ab08ac0283dc8d07d9bf2be32388ac', - 'amount': 0.12345600, - 'confirmations': 43537 - }, { - 'txid': '87a158d32833cb555aea27b6a21af569ccaeb8f9b19691e05f1e6c2b3440bdb3', - 'vout': 1, - 'address': 'mxdrp9s4mVxS9X4RBYiLe99v59V81XA5C3', - 'scriptPubKey': '76a914bbc87986da6b17c7876db4efacf59a95e14f6cf588ac', - 'amount': 0.05749800, - 'confirmations': 43536 - } - - ]; - - // Private keys in WIF format (see TransactionBuilder.js for other options) - var keys = [ - 'cQA75LXhV5JkMT8wkkqjR87SnHK4doh3c21p7PAd5tp8tc1tRBAY', - 'cRz85dz9AiDieRpEwoucfXXQa1jdHHghcv6YnnVVGZ3MQyR1X4u2', - 'cSq7yo4fvsbMyWVN945VUGUWMaSazZPWqBVJZyoGsHmNq6W4HVBV', - 'cPa87VgwZfowGZYaEenoQeJgRfKW6PhZ1R65EHTkN1K19cSvc92G', - 'cPQ9DSbBRLva9av5nqeF5AGrh3dsdW8p2E5jS4P8bDWZAoQTeeKB' - ]; - - var peerman = new PeerManager({ - network: 'testnet' - }); - peerman.addPeer(new Peer('127.0.0.1', 18333)); - - peerman.on('connect', function() { - var conn = peerman.getActiveConnection(); - if (conn) { - // define transaction output - var outs = [{ - address: 'mhNCT9TwZAGF1tLPpZdqfkTmtBkY282YDW', - amount: 0.1337 - }]; - // set change address - var opts = { - remainderOut: { - address: 'n4g2TFaQo8UgedwpkYdcQFF6xE2Ei9Czvy' - } - }; - var tx = new TransactionBuilder(opts) - .setUnspent(unspent) - .setOutputs(outs) - .sign(keys) - .build(); - - /* Create and signing can be done in multiple steps: - * - * var builder = new bitcore.TransactionBuilder(opts) - * .setUnspent(utxos) - * .setOutputs(outs); - * - * // Sign with the first key - * builder.sign(key1); - * var tx = builder.build(); // Partially signed transaction - * - * // Sign with the second key - * builder.sign(key2); - * if (builder.isFullySigned()){ - * var tx = builder.build(); - * } - * - * var selectedUnspent = build.getSelectedUnspent(); // Retrieve selected unspent outputs from the transaction - */ - - var txid = tx.getHash().toString('hex'); - console.log('Created transaction with txid '+txid); - var raw_tx = tx.serialize().toString('hex'); - console.log('Transaction raw hex dump:'); - console.log('-------------------------------------'); - console.log(raw_tx); - console.log('-------------------------------------'); - // finally, send transaction to the bitcoin network - conn.sendTx(tx); - - // for now, the network won't respond in any case - // (transaction accepted, transaction rejected) - // in the future, we may listen to 'reject' message - // see https://gist.github.com/gavinandresen/7079034 - } - }); - - peerman.start(); -``` - -## Parsing a Script - -Gets an address strings from a ScriptPubKey Buffer - -```js -var bitcore = require('bitcore'); -var Address = bitcore.Address; -var coinUtil = bitcore.util; -var Script = bitcore.Script; -var network = bitcore.networks.testnet; - -var getAddrStr = function(s) { - var addrStrs = []; - var type = s.classify(); - var addr; - - switch (type) { - case Script.TX_PUBKEY: - var chunk = s.captureOne(); - addr = new Address(network.addressVersion, coinUtil.sha256ripe160(chunk)); - addrStrs.push(addr.toString()); - break; - case Script.TX_PUBKEYHASH: - addr = new Address(network.addressVersion, s.captureOne()); - addrStrs.push(addr.toString()); - break; - case Script.TX_SCRIPTHASH: - addr = new Address(network.P2SHVersion, s.captureOne()); - addrStrs.push(addr.toString()); - break; - case Script.TX_MULTISIG: - var chunks = s.capture(); - chunks.forEach(function(chunk) { - var a = new Address(network.addressVersion, coinUtil.sha256ripe160(chunk)); - addrStrs.push(a.toString()); - }); - break; - case Script.TX_UNKNOWN: - console.log('tx type unkown'); - break; - } - return addrStrs; -}; - -var script = 'DUP HASH160 0x14 0x3744841e13b90b4aca16fe793a7f88da3a23cc71 EQUALVERIFY CHECKSIG'; -var s = Script.fromHumanReadable(script); -console.log(getAddrStr(s)[0]); // mkZBYBiq6DNoQEKakpMJegyDbw2YiNQnHT -``` #Security diff --git a/examples.md b/examples.md new file mode 100755 index 0000000..6bec4be --- /dev/null +++ b/examples.md @@ -0,0 +1,1082 @@ +#Address.js + 'use strict'; + + + var run = function() { + // Replace '../bitcore' with 'bitcore' if you use this code elsewhere. + var bitcore = require('../bitcore'); + var Address = bitcore.Address; + + var addrs = [ + '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', + '1A1zP1eP5QGefi2DMPTfTL5SLmv7Dixxxx', + 'A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', + '1600 Pennsylvania Ave NW', + ].map(function(addr) { + return new Address(addr); + }); + + addrs.forEach(function(addr) { + var valid = addr.isValid(); + console.log(addr.data + ' is ' + (valid ? '' : 'not ') + 'valid'); + }); + + }; + + module.exports.run = run; + if (require.main === module) { + run(); + } + +#Armory.js + var Armory = require('../lib/Armory'); + var Address = require('../lib/Address'); + + // Initial public key can be retrieved from paper backup + + var PublicX = '9df5 23e7 18b9 1f59 a790 2d46 999f 9357 ccf8 7208 24d4 3076 4516 b809 f7ab ce4e'; + var PublicY = '66ba 5d21 4682 0dae 401d 9506 8437 2516 79f9 0c56 4186 cc50 07df c6d0 6989 1ff4'; + var pubkey = '04' + PublicX.split(' ').join('') + PublicY.split(' ').join(''); + + // Chain code can be generated by entering paper backup + // on brainwallet.org/#chains or by using Armory.fromSeed() below + + var chaincode = '84ac14bc4b388b33da099a0b4ee3b507284d99e1476639e36e5ca5e6af86481e'; + + var armory = new Armory(chaincode, pubkey); + + console.log('Deriving public keys for'); + console.log('------------------------'); + console.log('Chain code: %s', chaincode); + console.log('Public key: %s', pubkey); + console.log(''); + + for (var i = 0; i < 5; i++) { + console.log(Address.fromPubKey(armory.pubkey).as('base58')); + armory = armory.next(); + } + + // Derive first public key and chain code from seed + var seed = [ + 'aagh hjfj sihk ietj giik wwai awtd uodh hnji', + 'soss uaku egod utai itos fijj ihgi jhau jtoo' + ]; + + console.log(''); + console.log(''); + console.log('Deriving public keys for'); + console.log('------------------------'); + console.log('Seed: %s', seed.join(' ')); + console.log(''); + + // skip first public key + var a = Armory.fromSeed(seed.join('\n')).next(); + + for (var i = 0; i < 5; i++) { + console.log(Address.fromPubKey(a.pubkey).as('base58')); + a = a.next(); + } + + + var mpk = '045a09a3286873a72f164476bde9d1d8e5c2bc044e35aa47eb6e798e325a86417f7c35b61d9905053533e0b4f2a26eca0330aadf21c638969e45aaace50e4c0c8784ac14bc4b388b33da099a0b4ee3b507284d99e1476639e36e5ca5e6af86481e'; + + console.log(''); + console.log(''); + console.log('Deriving public keys for'); + console.log('------------------------'); + console.log('Master Public Key: %s', mpk); + console.log(''); + + // skip first public key + var b = Armory.fromMasterPublicKey(mpk).next(); + + for (var i = 0; i < 5; i++) { + console.log(Address.fromPubKey(b.pubkey).as('base58')); + b = b.next(); + } + + +#ConnectionTor.js + var Peer = require('../lib/Peer'); + var Connection = require('../lib/Connection'); + var dns = require('dns'); + + // get a peer from dns seed + dns.resolve('dnsseed.bluematt.me', function(err, seeds) { + // use the first peer + var peer = new Peer(seeds[0], 8333); + + //Custom peer: + //var peer = new Peer('180.153.139.246', '8888'); + + // create a connection without an existing socket + // but specify a socks5 proxy to create a socket + // that's bound to that proxy in it's place + var connection = new Connection(null, peer, { + proxy: { host: '127.0.0.1', port: 9050 } + }); + + connection.open(); + + connection.on('connect', function(data) { + console.log('connected through socks5!'); + }); + + connection.on('error', function(err) { + console.log('There was an error running this example.'); + console.log('Are you running Tor? Tor must running for this example to work.'); + console.log('If you still get an error, you may need to use a different proxy from here:'); + console.log('http://sockslist.net/'); + //console.log(err); + }); + + }); + +#CreateAndSignTx-Multisig.js + + var run = function() { + bitcore = typeof (bitcore) === 'undefined' ? require('../bitcore') : bitcore; + var networks = require('../networks'); + var WalletKey = bitcore.WalletKey; + var Builder = bitcore.TransactionBuilder; + var opts = {network: networks.testnet}; + + console.log('## Network: ' + opts.network.name); + + var input = {}; + input.addr = "n2hoFVbPrYQf7RJwiRy1tkbuPPqyhAEfbp"; + input.priv = "cS62Ej4SobZnpFQYN1PEEBr2KWf5sgRYYnELtumcG6WVCfxno39V"; + + // Complete with the corresponding UTXO you want to use + var utxos = [ + { + address: input.addr, + txid: "39c71ebda371f75f4b854a720eaf9898b237facf3c2b101b58cd4383a44a6adc", + vout: 1, + ts: 1396288753, + scriptPubKey: "76a914e867aad8bd361f57c50adc37a0c018692b5b0c9a88ac", + amount: 0.4296, + confirmations: 2 + } + ]; + + var privs = [ + "cP6JBHuQf7yqeqtdKRd22ibF3VehDv7G6BdzxSNABgrv3jFJUGoN", + "cQfRwF7XLSM5xGUpF8PZvob2MZyULvZPA2j5cat2RKDJrja7FtCZ", + "cUkYub4jtFVYymHh38yMMW36nJB4pXG5Pzd5QjResq79kAndkJcg", + "cMyBgowsyrJRufoKWob73rMQB1PBqDdwFt8z4TJ6APN2HkmX1Ttm", + "cN9yZCom6hAZpHtCp8ovE1zFa7RqDf3Cr4W6AwH2tp59Jjh9JcXu", + ]; + + var pubkeys = [] + privs.forEach(function(p) { + var wk = new WalletKey(opts); + wk.fromObj({priv: p}); + pubkeys.push(bitcore.buffertools.toHex(wk.privKey.public)); + }); + + + var outs = [{nreq:3, pubkeys:pubkeys, amount:0.05}]; + var tx = new Builder(opts) + .setUnspent(utxos) + .setOutputs(outs) + .sign([input.priv]) + .build(); + var txHex = tx.serialize().toString('hex'); + console.log('1) SEND TO MULSISIG TX: ', txHex); + console.log('[this example originally generated TXID: e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5 on testnet]\n\n\thttp://test.bitcore.io/tx/e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5\n\n'); + + + //save scriptPubKey + var scriptPubKey = tx.outs[0].s.toString('hex'); + + /* + * + * REDDEEM TX + */ + var utxos2 = [ + { + address: input.addr, + txid: "e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5", + vout: 0, + ts: 1396288753, + scriptPubKey: scriptPubKey, + amount: 0.05, + confirmations: 2 + } + ]; + + outs = [{address:input.addr, amount:0.04}]; + var b = new Builder(opts) + .setUnspent(utxos2) + .setOutputs(outs) + .sign(privs); + + + tx= b.build(); + + + var txHex = tx.serialize().toString('hex'); + console.log('2) REDEEM SCRIPT: ', txHex); + console.log('=> Is signed status:', b.isFullySigned(), tx.countInputMissingSignatures(0) ); + + console.log('[this example originally generated TXID: 1eb388977b2de99562eb0fbcc661a100eaffed99c53bfcfebe5a087002039b83 on testnet]\n\n\thttp://test.bitcore.io/tx/1eb388977b2de99562eb0fbcc661a100eaffed99c53bfcfebe5a087002039b83'); + + }; + + // This is just for browser & mocha compatibility + if (typeof module !== 'undefined') { + module.exports.run = run; + if (require.main === module) { + run(); + } + } else { + run(); + } + + //// + + +#CreateAndSignTx-PayToPubkeyHash.js + + + + var run = function() { + bitcore = typeof (bitcore) === 'undefined' ? require('../bitcore') : bitcore; + + var priv = 'cTgGUrcro89yUtKeG6gHBAS14r3qp25KwTTxG9d4kEzcFxecuZDm'; + var amt = '0.005'; + var toAddress = 'myuAQcCc1REUgXGsCTiYhZvPPc3XxZ36G1'; + var changeAddressString = 'moDz3jEo9q7CxjBDjmb13sL4SKkgo2AACE'; + + var utxos = [{ + address: "mqSjTad2TKbPcKQ3Jq4kgCkKatyN44UMgZ", + txid: "2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1", + vout: 1, + ts: 1394719301, + scriptPubKey: "76a9146ce4e1163eb18939b1440c42844d5f0261c0338288ac", + amount: 0.01, + confirmations: 2 + }]; + + console.log('TX Data: BTC:' + amt + ' => '+ toAddress + ', change To:' + changeAddressString ) ; + console.log('Unspends Outputs:', utxos); + + + var outs = [{address:toAddress, amount:amt}]; + var keys = [priv]; + var opts = {remainderOut: {address: changeAddressString}}; + var Builder = bitcore.TransactionBuilder; + + var tx = new Builder(opts) + .setUnspent(utxos) + .setOutputs(outs) + .sign(keys) + .build(); + + /* create and signing can be done in multiple steps using: + * + * var builder = new bitcore.TransactionBuilder(opts) + * .setUnspent(utxos) + * .setOutputs(outs); + * + * builder.sign(key1); + * builder.sign(key2); + * ... + * if (builder.isFullySigned()){ + * var tx = builder.build(); + * } + * + * The selected Unspent Outputs for the transaction can be retrieved with: + * + * var selectedUnspent = build.getSelectedUnspent(); + */ + + var txHex = tx.serialize().toString('hex'); + console.log('TX HEX IS: ', txHex); + }; + + // This is just for browser & mocha compatibility + if (typeof module !== 'undefined') { + module.exports.run = run; + if (require.main === module) { + run(); + } + } else { + run(); + } + + //// + + +#CreateAndSignTx-PayToScriptHash.js + var run = function() { + bitcore = typeof (bitcore) === 'undefined' ? require('../bitcore') : bitcore; + var networks = require('../networks'); + var WalletKey = bitcore.WalletKey; + var Script = bitcore.Script; + var Builder = bitcore.TransactionBuilder; + var opts = {network: networks.testnet}; + + console.log('## Network: ' + opts.network.name); + + var input = {}; + input.addr = "n2hoFVbPrYQf7RJwiRy1tkbuPPqyhAEfbp"; + input.priv = "cS62Ej4SobZnpFQYN1PEEBr2KWf5sgRYYnELtumcG6WVCfxno39V"; + + // Complete with the corresponding UTXO you want to use + var utxos = [ + { + address: "n2hoFVbPrYQf7RJwiRy1tkbuPPqyhAEfbp", + txid: "e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5", + vout: 1, + ts: 1396290442, + scriptPubKey: "76a914e867aad8bd361f57c50adc37a0c018692b5b0c9a88ac", + amount: 0.3795, + confirmations: 7 + } + ]; + + var privs = [ + "cMpKwGr5oxEacN95WFKNEq6tTcvi11regFwS3muHvGYVxMPJX8JA", + "cVf32m9MR4vxcPwKNJuPepUe8XrHD2z63eCk76d6njRGyCkXpkSM", + "cQ2sVRFX4jQYMLhWyzz6jTQ2xju51P36968ecXnPhRLKLH677eKR", + "cSw7x9ERcmeWCU3yVBT6Nz7b9JiZ5yjUB7JMhBUv9UM7rSaDpwX9", + "cRQBM8qM4ZXJGP1De4D5RtJm7Q6FNWQSMx7YExxzgn2ehjM3haxW", + ]; + + var pubkeys = [] + privs.forEach(function(p) { + var wk = new WalletKey(opts); + wk.fromObj({priv: p}); + pubkeys.push(bitcore.buffertools.toHex(wk.privKey.public)); + }); + + // multisig p2sh + var opts = {nreq:3, pubkeys:pubkeys}; + + // p2scriphash p2sh + //var opts = [{address: an_address}]; + + var info = Builder.infoForP2sh(opts, 'testnet'); + var p2shScript = info.scriptBufHex; + var p2shAddress = info.address; + + + var outs = [{address:p2shAddress, amount:0.05}]; + var tx = new Builder(opts) + .setUnspent(utxos) + .setOutputs(outs) + .sign([input.priv]) + .build(); + + var txHex = tx.serialize().toString('hex'); + + + console.log('## p2sh address: ' + p2shAddress); //TODO + console.log('\n1) SEND TO P2SH TX: ', txHex); + console.log('[this example originally generated TXID: c2e50d1c8c581d8c4408378b751633f7eb86687fc5f0502be7b467173f275ae7 on testnet]\n\n\thttp://test.bitcore.io/tx/c2e50d1c8c581d8c4408378b751633f7eb86687fc5f0502be7b467173f275ae7\n\n'); + + //save scriptPubKey + var scriptPubKey = tx.outs[0].s.toString('hex'); + + /* + * + * REDDEEM TX + */ + var utxos2 = [ + { + address: p2shAddress, + txid: "c2e50d1c8c581d8c4408378b751633f7eb86687fc5f0502be7b467173f275ae7", + vout: 0, + ts: 1396375187, + scriptPubKey: scriptPubKey, + amount: 0.05, + confirmations: 1 + } + ]; + + outs = [{address:input.addr, amount:0.04}]; + + var hashMap = {}; + hashMap[p2shAddress]=p2shScript; + + var b = new Builder(opts) + .setUnspent(utxos2) + .setHashToScriptMap(hashMap) + .setOutputs(outs) + .sign(privs); + + tx= b.build(); + + + console.log('Builder:'); + console.log('\tSignatures:' + tx.countInputMissingSignatures(0) ); + console.log('\t#isFullySigned:' + b.isFullySigned() ); + + console.log('TX:'); + console.log('\t #isComplete:' + tx.isComplete() ); + + var txHex = tx.serialize().toString('hex'); + console.log('2) REDEEM SCRIPT: ', txHex); + console.log('[this example originally generated TXID: 8284aa3b6f9c71c35ecb1d61d05ae78c8ca1f36940eaa615b50584dfc3d95cb7 on testnet]\n\n\thttp://test.bitcore.io/tx/8284aa3b6f9c71c35ecb1d61d05ae78c8ca1f36940eaa615b50584dfc3d95cb7\n\n'); + + /* + // To send TX with RPC: + var RpcClient = bitcore.RpcClient; + var config = { + protocol: 'http', + user: 'user', + pass: 'pass', + host: '127.0.0.1', + port: '18332', + }; + var rpc = new RpcClient(config); + rpc.sendRawTransaction(txHex, function(err, ret) { + console.log('err', err); //TODO + console.log('ret', ret); //TODO + process.exit(-1); + }); + }; + */ + + }; + + + // This is just for browser & mocha compatibility + if (typeof module !== 'undefined') { + module.exports.run = run; + if (require.main === module) { + run(); + } + } else { + run(); + } + +#CreateKey.js + 'use strict'; + + + + var run = function() { + // replace '../bitcore' with 'bitcore' if you use this code elsewhere. + var bitcore = require('../bitcore'); + var networks = require('../networks'); + var WalletKey = bitcore.WalletKey; + + var opts = {network: networks.testnet}; + + function print(wk) { + + console.log('\n## Network: ' + wk.network.name); + console.log ('\t * Hex Representation'); + console.log ('\tPrivate: ' + bitcore.buffertools.toHex(wk.privKey.private)); + console.log ('\tPublic : ' + bitcore.buffertools.toHex(wk.privKey.public)); + console.log ('\tPublic Compressed : ' + (wk.privKey.compressed?'Yes':'No')); + + var wkObj = wk.storeObj(); + console.log ('\n\t * WalletKey Store Object'); + console.log ('\tPrivate: ' + wkObj.priv); + console.log ('\tPublic : ' + wkObj.pub); + console.log ('\tAddr : ' + wkObj.addr); + }; + + //Generate a new one (compressed public key, compressed WIF flag) + var wk = new WalletKey(opts); + wk.generate(); + print(wk); + + //Generate from private Key WIF. Compressed status taken from WIF. + var wk2 = new WalletKey(opts); + wk2.fromObj({priv:'cMpKwGr5oxEacN95WFKNEq6tTcvi11regFwS3muHvGYVxMPJX8JA'}); + print(wk2); + + + }; + + module.exports.run = run; + if (require.main === module) { + run(); + } + +#CreateScript.js + 'use strict'; + + var run = function() { + // replace '../bitcore' with 'bitcore' if you use this code elsewhere. + var bitcore = require('../bitcore'); + var networks = require('../networks'); + var Script = bitcore.Script; + var WalletKey = bitcore.WalletKey; + var buffertools = bitcore.buffertools; + var Address = bitcore.Address; + var util = bitcore.util; + var opts = {network: networks.testnet}; + + var p = console.log; + + var wk = new WalletKey(opts); + wk.generate(); + var wkObj = wk.storeObj(); + + var s = Script.createPubKeyOut(wk.privKey.public); + p('\nScript PubKey:'); + p('\tHex : ' + buffertools.toHex(s.buffer)); + p('\tHuman : ' + s.toHumanReadable()); + p('\tKey -------------------------------'); + console.log ('\tPrivate: ' + wkObj.priv); + console.log ('\tPublic : ' + wkObj.pub); + console.log ('\tAddr : ' + wkObj.addr); + + s = Script.createPubKeyHashOut(wk.privKey.public); + p('\nScript PubKeyHash:'); + p('\tHex : ' + buffertools.toHex(s.buffer)); + p('\tHuman : ' + s.toHumanReadable()); + p('\tKey -------------------------------'); + console.log ('\tPrivate: ' + wkObj.priv); + console.log ('\tPublic : ' + wkObj.pub); + console.log ('\tAddr : ' + wkObj.addr); + + var wks=[]; + var pubs = []; + for (var i =0; i<5; i++) { + wks[i] = new WalletKey(opts); + wks[i].generate(); + pubs.push(wks[i].privKey.public); + } + + s = Script.createMultisig(3,pubs); + p('\nScript MultiSig (3 out of 5 required signatures):'); + p('\tHex : ' + buffertools.toHex(s.buffer)); + p('\tHuman : ' + s.toHumanReadable()); + + for (i =0; i<5; i++) { + wkObj = wks[i].storeObj(); + p('\tKey ['+i+'] -------------------------------'); + console.log ('\tPrivate: ' + wkObj.priv); + console.log ('\tPublic : ' + wkObj.pub); + console.log ('\tAddr : ' + wkObj.addr); + } + + var hash = util.sha256ripe160(s.buffer); + + s = Script.createP2SH(hash); + p('\nScript P2SH:'); + p('\tHex : ' + buffertools.toHex(s.buffer)); + p('\tHuman : ' + s.toHumanReadable()); + p('\tScript Hash: ' + buffertools.toHex(hash)); + var a = new Address(networks.livenet.P2SHVersion,hash); + p('\tp2sh Addr: ' + a.toString()); + + }; + + module.exports.run = run; + if (require.main === module) { + run(); + } + +#ECIES.js + var run = function() { + bitcore = typeof (bitcore) === 'undefined' ? require('../bitcore') : bitcore; + + console.log('ECIES: Elliptic Curve Integrated Encryption Scheme'); + console.log('A way of encrypting with a public key and decrypting with a private key.'); + + var key = bitcore.Key.generateSync(); + console.log('Private key: ' + key.private.toString('hex')); + console.log('Public key: ' + key.public.toString('hex')); + + var message = new Buffer('This is a message to be encrypted'); + console.log('Message: "' + message.toString() + '"'); + + var encrypted = bitcore.ECIES.encrypt(key.public, message); + console.log('Encrypted (with public key): ' + encrypted.toString('hex')); + + var decrypted = bitcore.ECIES.decrypt(key.private, encrypted); + console.log('Decrypted (with private key): "' + decrypted.toString() + '"'); + }; + + + // This is just for browser & mocha compatibility + if (typeof module !== 'undefined') { + module.exports.run = run; + if (require.main === module) { + run(); + } + } else { + run(); + } + +#ElectrumMPK.js + var Electrum = require('../lib/Electrum'); + var Address = require('../lib/Address'); + + var mpk = '92eea4d2f5263651db9e3222caded1fd4c89772f79a7c03fb6afc00e9d2c9d2ed9b86c2c95fc1171e49163079dacb7f048b3c509a27a490e1df9e7128362d468'; + + mpk = new Electrum(mpk); + + var key0 = mpk.generatePubKey(0); + var addr0 = Address.fromPubKey(key0); + + console.log(addr0.as('base58')); + +#HierarchicalKey.js + var run = function() { + bitcore = typeof (bitcore) === 'undefined' ? require('../bitcore') : bitcore; + var HierarchicalKey = bitcore.HierarchicalKey; + var Address = bitcore.Address; + var networks = bitcore.networks; + var coinUtil = bitcore.util; + var crypto = require('crypto'); + + console.log('HierarchicalKey: Hierarchical Deterministic Wallets (BIP32)'); + console.log('https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki\n'); + console.log('1) Make new hkey from randomly generated new seed'); + + var randomBytes = crypto.randomBytes(32); + var hkey = HierarchicalKey.seed(randomBytes); + console.log('master extended private key: ' + hkey.extendedPrivateKeyString()); + console.log('master extended public key: ' + hkey.extendedPublicKeyString()); + console.log('m/0/3/5 extended private key: ' + hkey.derive('m/0/3/5').extendedPrivateKeyString()); + console.log('m/0/3/5 extended public key: ' + hkey.derive('m/0/3/5').extendedPublicKeyString()); + console.log(); + + console.log('2) Make new hkey from known seed'); + var knownBytes = coinUtil.sha256('do not use this password as a brain wallet'); + var hkey = HierarchicalKey.seed(knownBytes); + console.log('master extended private key: ' + hkey.extendedPrivateKeyString()); + console.log('master extended public key: ' + hkey.extendedPublicKeyString()); + console.log('m/0/3/5 extended private key: ' + hkey.derive('m/0/3/5').extendedPrivateKeyString()); + console.log('m/0/3/5 extended public key: ' + hkey.derive('m/0/3/5').extendedPublicKeyString()); + console.log(); + + console.log('3) Make new hkey from known master private key'); + var knownMasterPrivateKey = 'xprv9s21ZrQH143K2LvayFZWVVTomiDKheKWvnupDB8fmjKwxkKG47uvzmFa3vCXoy9fxPJhRYsU19apVfexvMeLpJQuF2XtX1zRF3eao9GqqaQ'; + var hkey = new HierarchicalKey(knownMasterPrivateKey); + console.log('master extended private key: ' + hkey.extendedPrivateKeyString()); + console.log('master extended public key: ' + hkey.extendedPublicKeyString()); + console.log('m/0/3/5 extended private key: ' + hkey.derive('m/0/3/5').extendedPrivateKeyString()); + console.log('m/0/3/5 extended public key: ' + hkey.derive('m/0/3/5').extendedPublicKeyString()); + console.log(); + + console.log('4) Make new hkey from known master public key'); + var knownMasterPublicKey = 'xpub661MyMwAqRbcGpiFufipqsKKBG1NHNwfJKishAEFNqJ6ryLcKeKyFNEZces7gMWd4XGg4uUhXy8DS64o1oPGUECVHeLq957Txjwagxt475H'; + var hkey = new HierarchicalKey(knownMasterPublicKey); + console.log('master extended private key: cannot derive'); + console.log('master extended public key: ' + hkey.extendedPublicKeyString()); + console.log('m/0/3/5 extended private key: cannot derive'); + console.log('m/0/3/5 extended public key: ' + hkey.derive('m/0/3/5').extendedPublicKeyString()); + console.log(); + + console.log('5) Make new hkey from known derived public key'); + var knownPublicKey = 'xpub6CZei1p2zk68UwkcBDqzRonLHJWAiPZZ58sMgHJAn9fmpmnPayVEAvAs3XvTSUMZ1J8dNaxnv4wnt7YpRKr6BsqeWbW8msqeuuhiSzsQEC3'; + var hkey = new HierarchicalKey(knownPublicKey); + console.log('master extended private key: cannot derive'); + console.log('master extended public key: ' + hkey.extendedPublicKeyString()); + console.log('m/0/3/5 extended private key: cannot derive'); + console.log('m/0/3/5 extended public key: ' + hkey.derive('m/0/3/5').extendedPublicKeyString()); + console.log(); + + console.log('6) Make a bunch of new addresses from known public key'); + var knownPublicKey = 'xpub6CZei1p2zk68UwkcBDqzRonLHJWAiPZZ58sMgHJAn9fmpmnPayVEAvAs3XvTSUMZ1J8dNaxnv4wnt7YpRKr6BsqeWbW8msqeuuhiSzsQEC3'; + var hkey = new HierarchicalKey(knownPublicKey); + console.log('m/0 address: ' + Address.fromPubKey(hkey.derive('m/0').eckey.public).toString()); + //console.log('m/1 extended public key: ' + hkey.derive('m/1').extendedPublicKeyString()); + console.log('m/1 address: ' + Address.fromPubKey(hkey.derive('m/1').eckey.public).toString()); + //console.log('m/2 extended public key: ' + hkey.derive('m/2').extendedPublicKeyString()); + console.log('m/2 address: ' + Address.fromPubKey(hkey.derive('m/2').eckey.public).toString()); + //console.log('m/3 extended public key: ' + hkey.derive('m/3').extendedPublicKeyString()); + console.log('m/3 address: ' + Address.fromPubKey(hkey.derive('m/3').eckey.public).toString()); + console.log('...'); + //console.log('m/100 extended public key: ' + hkey.derive('m/100').extendedPublicKeyString()); + console.log('m/100 address: ' + Address.fromPubKey(hkey.derive('m/100').eckey.public).toString()); + console.log(); + + }; + + + // This is just for browser & mocha compatibility + if (typeof module !== 'undefined') { + module.exports.run = run; + if (require.main === module) { + run(); + } + } else { + run(); + } + +#PayToScriptHashAddress.js + var bitcore = require('../bitcore'); + var Address = bitcore.Address; + var bitcoreUtil = bitcore.util; + var Script = bitcore.Script; + var network = bitcore.networks.livenet; + + + var script = ''; // write down your script here + var s = Script.fromHumanReadable(script); + var hash = bitcoreUtil.sha256ripe160(s.getBuffer()); + var version = network.addressScript; + + var addr = new Address(version, hash); + var addrStr = addr.as('base58'); + + // This outputs the "address" of thescript + console.log(addrStr); + +#PeerDiscovery.js + var PeerManager = require('../lib/PeerManager'); + var peerman = new PeerManager(); + + peerman.discover({ limit: 12 }).start(); + +#PeerManager.js + 'use strict'; + + var run = function() { + // Replace '../bitcore' with 'bitcore' if you use this code elsewhere. + var bitcore = require('../bitcore'); + var Peer = bitcore.Peer; + var PeerManager = bitcore.PeerManager; + + var handleBlock = function(info) { + console.log('** Block Received **'); + console.log(info.message); + }; + + var handleTx = function(info) { + var tx = info.message.tx.getStandardizedObject(); + + console.log('** TX Received **'); + console.log(tx); + }; + + var handleInv = function(info) { + console.log('** Inv **'); + console.log(info.message); + + var invs = info.message.invs; + info.conn.sendGetData(invs); + }; + + var peerman = new PeerManager({ + network: 'testnet' + }); + + peerman.addPeer(new Peer('127.0.0.1', 18333)); + + peerman.on('connection', function(conn) { + conn.on('inv', handleInv); + conn.on('block', handleBlock); + conn.on('tx', handleTx); + }); + + peerman.start(); + }; + + module.exports.run = run; + if (require.main === module) { + run(); + } + +#Rpc.js + 'use strict'; + + var run = function() { + // Replace '../bitcore' with 'bitcore' if you use this code elsewhere. + var bitcore = require('../bitcore'); + var RpcClient = bitcore.RpcClient; + var hash = '0000000000b6288775bbd326bedf324ca8717a15191da58391535408205aada4'; + + var config = { + protocol: 'http', + user: 'user', + pass: 'pass', + host: '127.0.0.1', + port: '18332', + }; + + var rpc = new RpcClient(config); + + rpc.getBlock(hash, function(err, ret) { + if (err) { + console.error('An error occured fetching block', hash); + console.error(err); + return; + } + console.log(ret); + }); + }; + + module.exports.run = run; + if (require.main === module) { + run(); + } + +#Script.js + 'use strict'; + + var run = function() { + // Replace '../bitcore' with 'bitcore' if you use this code elsewhere. + var bitcore = require('../bitcore'); + var Address = bitcore.Address; + var coinUtil = bitcore.util; + var Script = bitcore.Script; + var network = bitcore.networks.testnet; + + var getAddrStr = function(s) { + var addrStrs = []; + var type = s.classify(); + var addr; + + switch (type) { + case Script.TX_PUBKEY: + var chunk = s.captureOne(); + addr = new Address(network.addressVersion, coinUtil.sha256ripe160(chunk)); + addrStrs.push(addr.toString()); + break; + case Script.TX_PUBKEYHASH: + addr = new Address(network.addressVersion, s.captureOne()); + addrStrs.push(addr.toString()); + break; + case Script.TX_SCRIPTHASH: + addr = new Address(network.P2SHVersion, s.captureOne()); + addrStrs.push(addr.toString()); + break; + case Script.TX_MULTISIG: + var chunks = s.capture(); + chunks.forEach(function(chunk) { + var a = new Address(network.addressVersion, coinUtil.sha256ripe160(chunk)); + addrStrs.push(a.toString()); + }); + break; + case Script.TX_UNKNOWN: + console.log('tx type unkown'); + break; + } + return addrStrs; + }; + + var script = 'DUP HASH160 0x14 0x3744841e13b90b4aca16fe793a7f88da3a23cc71 EQUALVERIFY CHECKSIG'; + var s = Script.fromHumanReadable(script); + console.log(getAddrStr(s)[0]); // mkZBYBiq6DNoQEKakpMJegyDbw2YiNQnHT + }; + + module.exports.run = run; + if (require.main === module) { + run(); + } + +#SendTx.js + 'use strict'; + + var run = function() { + // Replace '../bitcore' with 'bitcore' if you use this code elsewhere. + var bitcore = require('../bitcore'); + var Peer = bitcore.Peer; + + var TransactionBuilder = bitcore.TransactionBuilder; + var PeerManager = bitcore.PeerManager; + + // Unspent transactions can be found via the insight.bitcore.io or blockchain.info APIs + var unspent = [{ + 'txid': '707108b5ba4f78dc951df4647a03365bf36432ea57fb641676045c5044daaea7', + 'vout': 0, + 'address': 'n3QDC7DzsMmN4mcyp3k7XGPX7zFXXHG387', + 'scriptPubKey': '76a914f00c4a92ee2314ab08ac0283dc8d07d9bf2be32388ac', + 'amount': 0.12345600, + 'confirmations': 43537 + }, { + 'txid': '87a158d32833cb555aea27b6a21af569ccaeb8f9b19691e05f1e6c2b3440bdb3', + 'vout': 1, + 'address': 'mxdrp9s4mVxS9X4RBYiLe99v59V81XA5C3', + 'scriptPubKey': '76a914bbc87986da6b17c7876db4efacf59a95e14f6cf588ac', + 'amount': 0.05749800, + 'confirmations': 43536 + } + + ]; + + // Private keys in WIF format (see TransactionBuilder.js for other options) + var keys = [ + 'cQA75LXhV5JkMT8wkkqjR87SnHK4doh3c21p7PAd5tp8tc1tRBAY', + 'cRz85dz9AiDieRpEwoucfXXQa1jdHHghcv6YnnVVGZ3MQyR1X4u2', + 'cSq7yo4fvsbMyWVN945VUGUWMaSazZPWqBVJZyoGsHmNq6W4HVBV', + 'cPa87VgwZfowGZYaEenoQeJgRfKW6PhZ1R65EHTkN1K19cSvc92G', + 'cPQ9DSbBRLva9av5nqeF5AGrh3dsdW8p2E5jS4P8bDWZAoQTeeKB' + ]; + + var peerman = new PeerManager({ + network: 'testnet' + }); + peerman.addPeer(new Peer('127.0.0.1', 18333)); + + peerman.on('connect', function() { + var conn = peerman.getActiveConnection(); + if (conn) { + // define transaction output + var outs = [{ + address: 'mhNCT9TwZAGF1tLPpZdqfkTmtBkY282YDW', + amount: 0.1337 + }]; + // set change address + var opts = { + remainderOut: { + address: 'n4g2TFaQo8UgedwpkYdcQFF6xE2Ei9Czvy' + } + }; + var tx = new TransactionBuilder(opts) + .setUnspent(unspent) + .setOutputs(outs) + .sign(keys) + .build(); + + /* Create and signing can be done in multiple steps: + * + * var builder = new bitcore.TransactionBuilder(opts) + * .setUnspent(utxos) + * .setOutputs(outs); + * + * // Sign with the first key + * builder.sign(key1); + * var tx = builder.build(); // Partially signed transaction + * + * // Sign with the second key + * builder.sign(key2); + * if (builder.isFullySigned()){ + * var tx = builder.build(); + * } + * + * var selectedUnspent = build.getSelectedUnspent(); // Retrieve selected unspent outputs from the transaction + */ + + var txid = tx.getHash().toString('hex'); + console.log('Created transaction with txid '+txid); + var raw_tx = tx.serialize().toString('hex'); + console.log('Transaction raw hex dump:'); + console.log('-------------------------------------'); + console.log(raw_tx); + console.log('-------------------------------------'); + // finally, send transaction to the bitcoin network + conn.sendTx(tx); + + // for now, the network won't respond in any case + // (transaction accepted, transaction rejected) + // in the future, we may listen to 'reject' message + // see https://gist.github.com/gavinandresen/7079034 + } + }); + + peerman.start(); + + }; + + module.exports.run = run; + if (require.main === module) { + run(); + } + +#SimpleP2Pmonitor.js + /** + * This is a simple script that will display network messages. + * It users the Peer / Connection classes directly instead of + * relying on PeerManager. + */ + + // replace by require('bitcore') if you use somewhere else + var bitcore = require('../'); + + //bitcore.config.logger = 'debug'; + + var Peer = bitcore.Peer, + Connection = bitcore.Connection; + + var peer = new Peer('127.0.0.1', 8333); + + var socket = peer.createConnection(); + + var con = new Connection(socket, peer); + + con.on('error', function (msg) { + var peer = msg.peer, err = msg.err; + console.error('Error connecting to peer', peer.host + ':' + peer.port, '(' + err.message + ')'); + }); + + con.on('disconnect', function (msg) { + console.log('disconnect: ', msg); + }); + + con.on('connect', function (msg) { + console.log('Connected to %s', msg.peer.host + ':' + msg.peer.port); + }); + + /* Listen P2P messages */ + + // Make a log function available to all listeners + // The log function is just like console.log except it prefixes + // messages with [host:port] + function listen (event_name, fn) { + con.on(event_name, function (event) { + fn(event, function () { + var args = Array.prototype.slice.call(arguments); + var str = args.shift(); + str = '[%s:%s] ' + str; + args = [ str, event.peer.host, event.peer.port ].concat(args); + console.log.apply(console, args); + }); + }); + } + + listen('getaddr', function (event, log) { + log('Received message getaddr'); + log(event); + }); + + listen('verack', function (event, log) { + log('Received message verack'); + }); + + listen('version', function (event, log) { + log('Received message version (%s)', event.message.version); + }); + + listen('addr', function (event, log) { + log('Received message addr (%s addresses)', event.message.addrs.length); + }); + + listen('inv', function (event, log) { + log('Received message inv (%s invs)', event.message.count); + console.log(event.message.invs); + }); + + +#VanityAddress.js + 'use strict'; + + + var run = function() { + // Replace '../bitcore' with 'bitcore' if you use this code elsewhere. + var bitcore = require('../bitcore'); + var Key = bitcore.Key; + var Address = bitcore.Address; + + // config your regular expression + var re = /[0-9]{6}$/; // ends in 6 digits + + var a,k,m; + while (true) { + k = Key.generateSync(); + a = Address.fromKey(k); + m = a.toString().match(re); + if (m) break; + } + console.log('Address: '+a.toString()); + console.log('Private Key: '+k.private.toString('hex')); + + }; + + module.exports.run = run; + if (require.main === module) { + run(); + } + \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..2ab3428 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,25 @@ +var gulp = require('gulp'), + concat = require('gulp-concat'), + path = require('path'), + es = require('event-stream'); + +var format = es.through( + function (file) { + if (file.isNull()) return this.emit('data', file); // pass along + if (file.isStream()) return this.emit('error', new Error('Streaming not supported')); + + //add indentation + var contents = "\t" + file.contents.toString("utf8").split("\n").join("\n\t"); + //add header + contents = ["#", path.basename(file.path), "\n", contents].join(""); + file.contents = new Buffer(contents, "utf8"); + this.emit('data', file); + }); + +gulp.task('examples', function () { + //concat .js files from ./examples folder into ./examples.md + return gulp.src("./examples/*.js").pipe(format).pipe(concat('examples.md')).pipe(gulp.dest('./')); +}); + + +gulp.task('default', ["examples"]); diff --git a/package.json b/package.json index 957b1df..cf999d0 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,10 @@ "brfs": "=1.0.0", "chai": "=1.9.1", "uglifyify": "=1.2.3", - "async": "~0.2.10" + "async": "~0.2.10", + "event-stream": "~3.1.5", + "gulp-concat": "~2.2.0", + "gulp": "~3.8.2" }, "testling": { "harness": "mocha-bdd",