diff --git a/.gitignore b/.gitignore index 5effac1..4aa6b97 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,7 @@ browser/bundle.js browser/vendor.js node_modules/ *.swp +*.swo *~ .project +README.html diff --git a/Connection.js b/Connection.js index 990e723..4672d16 100644 --- a/Connection.js +++ b/Connection.js @@ -527,6 +527,7 @@ function spec(b) { case 'getaddr': case 'verack': + case 'reject': // Empty message, nothing to parse break; diff --git a/Gruntfile.js b/Gruntfile.js index 1aabd16..11ae9ac 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -6,6 +6,7 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-browserify'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-mocha-test'); + grunt.loadNpmTasks('grunt-markdown'); // Project Configuration grunt.initConfig({ @@ -31,6 +32,10 @@ module.exports = function(grunt) { } }, watch: { + readme: { + files: ['README.md'], + tasks: ['markdown'] + }, scripts: { files: ['**/*.js', '**/*.html', '!**/node_modules/**', '!**/bundle.js', '!**/vendor.js'], tasks: ['browserify'/*, 'mochaTest'*/], @@ -42,6 +47,19 @@ module.exports = function(grunt) { }, src: ['test/*.js'], }, + markdown: { + all: { + files: [ + { + expand: true, + src: 'README.md', + dest: '.', + ext: '.html' + } + ] + } + } + }); diff --git a/README.md b/README.md index 2061474..16b8fc3 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,12 @@ var Address = require('bitcore/Address').class(); #Examples +Some examples are provided at the [examples](/examples) path. Here are some snippets: + +## Address handling Validating a Bitcoin address: ``` var Address = require('bitcore/Address').class(); - var addr = new Address("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"); try { @@ -38,6 +40,155 @@ try { } ``` +## Monitoring Blocks and Transactions +``` +var networks = require('bitcore/networks'); +var Peer = require('bitcore/Peer').class(); +var PeerManager = require('bitcore/PeerManager').createClass({ + network: networks.livenet +}); + +var handleBlock = function(b) { + console.log('block received:', b); +}; +var handleTx = function(b) { + console.log('block tx:', b); +}; +var peerman = new PeerManager(); +peerman.addPeer( new Peer('62.75.216.13',8333) ); +peerman.addPeer( new Peer('62.75.253.91',8333) ); +peerman.on('connection', function(conn) { + 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](PeerManager.js), [Peer.js](Peer.js) and [Connection.js](Connection.js) + + +## Create and send a Transaction thought P2P +``` +var networks = require('bitcore/networks'); +var Peer = require('bitcore/Peer').class(); +var Transaction = require('bitcore/Transaction').class(); +var Address = require('bitcore/Address').class(); +var Script = require('bitcore/Script').class(); +var coinUtil = require('bitcore/util/util'); +var PeerManager = require('bitcore/PeerManager').createClass({ + network: networks.testnet +}); + +var createTx = function() { + var TXIN='d05f35e0bbc495f6dcab03e599c8f5e32a07cdb4bc76964de201d06a2a7d8265'; + var TXIN_N=0; + var ADDR='muHct3YZ9Nd5Pq7uLYYhXRAxeW4EnpcaLz'; + var VAL='1.234'; + var txobj = {}; + txobj.version = 1; + txobj.lock_time = 0; + txobj.ins = []; + txobj.outs = []; + var txin = {}; + txin.s = coinUtil.EMPTY_BUFFER; //Add signature + txin.q = 0xffffffff; + + var hash = new Buffer(TXIN, 'hex'); + hash.reverse(); + var vout = parseInt(TXIN_N); + var voutBuf = new Buffer(4); + voutBuf.writeUInt32LE(vout, 0); + txin.o = Buffer.concat([hash, voutBuf]); + txobj.ins.push(txin); + + var addr = new Address(ADDR); + var script = Script.createPubKeyHashOut(addr.payload()); + var valueNum = coinUtil.parseValue(VAL); + var value = coinUtil.bigIntToValue(valueNum); + + var txout = { + v: value, + s: script.getBuffer(), + }; + txobj.outs.push(txout); + + return new Transaction(txobj); +}; + +var peerman = new PeerManager(); +peerman.addPeer( new Peer('127.0.0.1',18333) ); +peerman.on('connect', function(conn) { + var conn = peerman.getActiveConnection(); + if (conn) + conn.sendTx(createTx()); + conn.on('reject', function () { console.log('Transaction Rejected'); } ); +}); +peerman.start(); +``` + +## RPC Client +``` +var RpcClient = require('../RpcClient').class(); +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) { + console.log(err); + console.log(util.inspect(ret, { depth: 10} )); +}); +``` +Check the list of all supported RPC call at [RpcClient.js](RpcClient.js) + +## Script Parsing + +Gets an address strings from a ScriptPubKey Buffer + +``` + var Address = require('bitcore/Address').class(); + var coinUtil= require('bitcore/util/util'); + + 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.addressPubkey, coinUtil.sha256ripe160(chunk)); + addrStrs.push(addr.toString()); + break; + case Script.TX_PUBKEYHASH: + addr = new Address(network.addressPubkey, s.captureOne()); + addrStrs.push(addr.toString()); + break; + case Script.TX_SCRIPTHASH: + addr = new Address(network.addressScript, s.captureOne()); + addrStrs.push(addr.toString()); + break; + case Script.TX_MULTISIG: + var chunks = s.capture(); + chunks.forEach(function(chunk) { + var a = new Address(network.addressPubkey, coinUtil.sha256ripe160(chunk)); + addrStrs.push(a.toString()); + }); + break; + case Script.TX_UNKNOWN: + break; + } + return addrStrs; + }; + + var s = new Script(scriptBuffer); + console.log(getAddrStr(s); + +``` + #Security Please use at your own risk. @@ -53,6 +204,7 @@ npm install -g grunt-cli grunt browserify ``` + #License **Code released under [the MIT license](https://github.com/bitpay/bitcore/blob/master/LICENSE).** diff --git a/examples/Address.js b/examples/Address.js new file mode 100644 index 0000000..6525d39 --- /dev/null +++ b/examples/Address.js @@ -0,0 +1,23 @@ + + +// Replace path '..' to 'bitcore' if you are using this example +// in a different project +var Address = require('../Address').class(); + +var addrStrings = [ + "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", + "1A1zP1eP5QGefi2DMPTfTL5SLmv7Dixxxx", + "A1zP1eP5QGefi2DMPTfTL5SLmv7Dixxxx", + "1600 Pennsylvania Ave NW", +]; + +addrStrings.forEach(function(addrStr){ + var addr = new Address(addrStr); + + try { + addr.validate(); + console.log(addr.data + ": is valid"); + } catch(e) { + console.log(addr.data + ": is not a valid address. " + e); + } +}); diff --git a/examples/PeerManager.js b/examples/PeerManager.js new file mode 100644 index 0000000..5e6af05 --- /dev/null +++ b/examples/PeerManager.js @@ -0,0 +1,26 @@ + +// Replace path '..' to 'bitcore' if you are using this example +// in a different project +var networks = require('../networks'); +var Peer = require('../Peer').class(); +var PeerManager = require('../PeerManager').createClass({ + network: networks.testnet +}); + + +var handleBlock = function(b) { + console.log('block received:', b); +}; + +var handleTx = function(b) { + console.log('block tx:', b); +}; + +var peerman = new PeerManager(); +peerman.addPeer( new Peer('127.0.0.1',18333) ); +peerman.on('connect', function(conn) { + conn.on('block', handleBlock); + conn.on('tx', handleTx); +}); +peerman.start(); + diff --git a/examples/Rpc.js b/examples/Rpc.js new file mode 100644 index 0000000..0d27c44 --- /dev/null +++ b/examples/Rpc.js @@ -0,0 +1,23 @@ + +var util = require('util'); + +// Replace path '..' to 'bitcore' if you are using this example +// in a different project +var RpcClient = require('../RpcClient').class(); +var hash = process.argv[2] + || '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) { + console.log(err); + console.log(util.inspect(ret, { depth: 10} )); +}); diff --git a/examples/SendTx.js b/examples/SendTx.js new file mode 100644 index 0000000..9323d0b --- /dev/null +++ b/examples/SendTx.js @@ -0,0 +1,60 @@ +// Replace path '..' to 'bitcore' if you are using this example +// in a different project +var networks = require('../networks'); +var Peer = require('../Peer').class(); +var Transaction = require('../Transaction').class(); +var Address = require('../Address').class(); +var Script = require('../Script').class(); +var PeerManager = require('../PeerManager').createClass({ + network: networks.testnet +}); +var coinUtil = require('../util/util'); + + +var createTx = function() { + var TXIN='d05f35e0bbc495f6dcab03e599c8f5e32a07cdb4bc76964de201d06a2a7d8265'; + var TXIN_N=0; + var ADDR='muHct3YZ9Nd5Pq7uLYYhXRAxeW4EnpcaLz'; + var VAL='1.234'; + var txobj = {}; + txobj.version = 1; + txobj.lock_time = 0; + txobj.ins = []; + txobj.outs = []; + var txin = {}; + txin.s = coinUtil.EMPTY_BUFFER; //Add signature + txin.q = 0xffffffff; + + var hash = new Buffer(TXIN, 'hex'); + hash.reverse(); + var vout = parseInt(TXIN_N); + var voutBuf = new Buffer(4); + voutBuf.writeUInt32LE(vout, 0); + txin.o = Buffer.concat([hash, voutBuf]); + txobj.ins.push(txin); + + var addr = new Address(ADDR); + var script = Script.createPubKeyHashOut(addr.payload()); + var valueNum = coinUtil.parseValue(VAL); + var value = coinUtil.bigIntToValue(valueNum); + + var txout = { + v: value, + s: script.getBuffer(), + }; + txobj.outs.push(txout); + + return new Transaction(txobj); +}; + +var peerman = new PeerManager(); +peerman.addPeer( new Peer('127.0.0.1',18333) ); +peerman.on('connect', function(conn) { + var conn = peerman.getActiveConnection(); + if (conn) + conn.sendTx(createTx()); + conn.on('reject', function () { console.log('Transaction Rejected'); } ); +}); +peerman.start(); + + diff --git a/package.json b/package.json index c423586..7e6478b 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "grunt-contrib-watch": "~0.5.3", "grunt-mocha-test": "~0.8.2", "grunt-browserify": "~1.3.0", + "grunt-markdown": "~0.5.0", "chai": "~1.9.0" }, "license": "MIT"