From 96a69316b94a5d05c29be33e0c40f1959f7b02b0 Mon Sep 17 00:00:00 2001 From: Chris Kleeschulte Date: Fri, 18 Sep 2015 14:55:33 -0400 Subject: [PATCH 1/3] P2P transaction tests - Added a regtest for sending 400 tis from a peer to bitcoind --- integration/p2p.js | 226 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 +- 2 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 integration/p2p.js diff --git a/integration/p2p.js b/integration/p2p.js new file mode 100644 index 00000000..0ddb3784 --- /dev/null +++ b/integration/p2p.js @@ -0,0 +1,226 @@ +'use strict'; + +var index = require('..'); +var log = index.log; + +if (process.env.BITCORENODE_ENV !== 'test') { + log.info('Please set the environment variable BITCORENODE_ENV=test and make sure bindings are compiled for testing'); + process.exit(); +} +var p2p = require('bitcore-p2p'); +var Peer = p2p.Peer; +var Messages = p2p.Messages; +var chai = require('chai'); +var bitcore = require('bitcore'); +var Transaction = bitcore.Transaction; +var BN = bitcore.crypto.BN; +var async = require('async'); +var rimraf = require('rimraf'); +var bitcoind; + +/* jshint unused: false */ +var should = chai.should(); +var assert = chai.assert; +var sinon = require('sinon'); +var BitcoinRPC = require('bitcoind-rpc'); +var transactionData = []; +var blockHashes = []; +var txs = []; +var client; +var messages; +var peer; +var coinbasePrivateKey; +var privateKey = bitcore.PrivateKey(); +var destKey = bitcore.PrivateKey(); +var BufferUtil = bitcore.util.buffer; +var blocks; + +describe('P2P Functionality', function() { + + before(function(done) { + this.timeout(100000); + + // Add the regtest network + bitcore.Networks.remove(bitcore.Networks.testnet); + bitcore.Networks.add({ + name: 'regtest', + alias: 'regtest', + pubkeyhash: 0x6f, + privatekey: 0xef, + scripthash: 0xc4, + xpubkey: 0x043587cf, + xprivkey: 0x04358394, + networkMagic: 0xfabfb5da, + port: 18444, + dnsSeeds: [ ] + }); + + var regtestNetwork = bitcore.Networks.get('regtest'); + var datadir = __dirname + '/data'; + + rimraf(datadir + '/regtest', function(err) {; + + if (err) { + throw err; + } + + bitcoind = require('../').services.Bitcoin({ + node: { + datadir: datadir, + network: { + name: 'regtest' + } + } + }); + + bitcoind.on('error', function(err) { + log.error('error="%s"', err.message); + }); + + log.info('Waiting for Bitcoin Core to initialize...'); + + bitcoind.start(function() { + log.info('Bitcoind started'); + + client = new BitcoinRPC({ + protocol: 'https', + host: '127.0.0.1', + port: 18332, + user: 'bitcoin', + pass: 'local321', + rejectUnauthorized: false + }); + + peer = new Peer({ + host: '127.0.0.1', + port: '18444', + network: regtestNetwork + }); + + messages = new Messages({ + network: regtestNetwork + }); + + blocks = 500; + + log.info('Generating ' + blocks + ' blocks...'); + + // Generate enough blocks so that the initial coinbase transactions + // can be spent. + + setImmediate(function() { + client.generate(blocks, function(err, response) { + if (err) { + throw err; + } + blockHashes = response.result; + + log.info('Preparing test data...'); + + // Get all of the unspent outputs + client.listUnspent(0, blocks, function(err, response) { + var utxos = response.result; + + async.mapSeries(utxos, function(utxo, next) { + async.series([ + function(finished) { + // Load all of the transactions for later testing + client.getTransaction(utxo.txid, function(err, txresponse) { + if (err) { + throw err; + } + // add to the list of transactions for testing later + transactionData.push(txresponse.result.hex); + finished(); + }); + }, + function(finished) { + // Get the private key for each utxo + client.dumpPrivKey(utxo.address, function(err, privresponse) { + if (err) { + throw err; + } + utxo.privateKeyWIF = privresponse.result; + var tx = bitcore.Transaction(); + tx.from(utxo); + tx.change(privateKey.toAddress()); + tx.to(destKey.toAddress(), utxo.amount * 1e8 - 1000); + tx.sign(bitcore.PrivateKey.fromWIF(utxo.privateKeyWIF)); + txs.push(tx); + finished(); + }); + } + ], next); + }, function(err) { + if (err) { + throw err; + } + peer.on('ready', function() { + log.info('Peer ready'); + done(); + }); + log.info('Connecting to peer'); + peer.connect(); + }); + }); + }); + }); + }); + }); + + }); + + after(function(done) { + this.timeout(20000); + peer.on('disconnect', function() { + log.info('Peer disconnected'); + bitcoind.stop(function(err, result) { + done(); + }); + }); + peer.disconnect(); + }); + + it('will be able to handle many inventory messages and be able to send getdata messages and received the txs', function(done) { + this.timeout(100000); + + var usedTxs = {}; + + bitcoind.on('tx', function(result) { + var txFromResult = new Transaction().fromBuffer(result.buffer); + var tx = usedTxs[txFromResult.id]; + should.exist(tx); + result.buffer.toString('hex').should.equal(tx.serialize()); + result.hash.should.equal(tx.hash); + result.mempool.should.equal(true); + delete usedTxs[tx.id]; + if (Object.keys(usedTxs).length === 0) { + done(); + } + }); + + peer.on('getdata', function(message) { + var hash = message.inventory[0].hash; + var reversedHash = BufferUtil.reverse(hash).toString('hex'); + var tx = usedTxs[reversedHash]; + if (reversedHash === tx.id) { + var txMessage = messages.Transaction(tx); + peer.sendMessage(txMessage); + } + }); + async.whilst(function() { + return txs.length > 0; + }, + function(callback) { + var tx = txs.pop(); + usedTxs[tx.id] = tx; + var message = messages.Inventory.forTransaction(tx.hash); + peer.sendMessage(message); + callback(); + }, + function(err) { + }); + }); + + +}); diff --git a/package.json b/package.json index 772ff776..5c300f0c 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,8 @@ "mocha": "~1.16.2", "proxyquire": "^1.3.1", "rimraf": "^2.4.2", - "sinon": "^1.15.4" + "sinon": "^1.15.4", + "bitcore-p2p": "^0.15.1" }, "engines": { "node": ">=0.12.0" From d794e891ddbbfcf3efa3b56cb3bef1a2e7cfba2f Mon Sep 17 00:00:00 2001 From: Chris Kleeschulte Date: Fri, 18 Sep 2015 14:58:18 -0400 Subject: [PATCH 2/3] Added the p2p test to .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e3812578..e2df2e3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ before_install: script: - _mocha -R spec integration/regtest.js - _mocha -R spec integration/regtest-node.js + - _mocha -R spec integration/p2p.js - _mocha -R spec --recursive cache: directories: From 391a84f490169c9e84f839765aa3aee9aecba6d2 Mon Sep 17 00:00:00 2001 From: Chris Kleeschulte Date: Fri, 18 Sep 2015 16:15:52 -0400 Subject: [PATCH 3/3] - Throw error on err - Spacing --- integration/p2p.js | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/integration/p2p.js b/integration/p2p.js index 0ddb3784..0de4cb1e 100644 --- a/integration/p2p.js +++ b/integration/p2p.js @@ -208,19 +208,22 @@ describe('P2P Functionality', function() { peer.sendMessage(txMessage); } }); - async.whilst(function() { - return txs.length > 0; - }, - function(callback) { - var tx = txs.pop(); - usedTxs[tx.id] = tx; - var message = messages.Inventory.forTransaction(tx.hash); - peer.sendMessage(message); - callback(); - }, - function(err) { - }); + async.whilst( + function() { + return txs.length > 0; + }, + function(callback) { + var tx = txs.pop(); + usedTxs[tx.id] = tx; + var message = messages.Inventory.forTransaction(tx.hash); + peer.sendMessage(message); + callback(); + }, + function(err) { + if (err) { + throw err; + } + }); }); - });