commit
e4741dc96e
@ -25,6 +25,9 @@ From the bitcoin protocol spec: `getdata` is used in response to `inv`, to retri
|
||||
|
||||
GetData inherits from Inventory, as they both have the same structure.
|
||||
|
||||
### NotFound
|
||||
notfound is a response to a getdata, sent if any requested data items could not be relayed, for example, because the requested transaction was not in the memory pool or relay set. Contains inventory information specifying which items were not found.
|
||||
|
||||
### Ping
|
||||
|
||||
Sent to another peer mainly to check the connection is still alive.
|
||||
|
||||
@ -18,6 +18,7 @@ var Pool = p2p.Pool;
|
||||
var Networks = bitcore.Networks;
|
||||
var Messages = p2p.Messages;
|
||||
var Block = bitcore.Block;
|
||||
var Transaction = bitcore.Transaction;
|
||||
|
||||
// config
|
||||
var network = Networks.livenet;
|
||||
@ -25,6 +26,10 @@ var blockHash = {
|
||||
'livenet': '000000000000000013413cf2536b491bf0988f52e90c476ffeb701c8bfdb1db9',
|
||||
'testnet': '0000000058cc069d964711cd25083c0a709f4df2b34c8ff9302ce71fe5b45786'
|
||||
};
|
||||
var txHash = {
|
||||
'livenet': '22231e8219a0617a0ded618b5dc713fdf9b0db8ebd5bb3322d3011a703119d3b',
|
||||
'testnet': '22231e8219a0617a0ded618b5dc713fdf9b0db8ebd5bb3322d3011a703119d3b'
|
||||
};
|
||||
|
||||
// These tests require a running bitcoind instance
|
||||
describe('Integration with ' + network.name + ' bitcoind', function() {
|
||||
@ -126,15 +131,24 @@ describe('Integration with ' + network.name + ' bitcoind', function() {
|
||||
});
|
||||
it('can request block data', function(cb) {
|
||||
connect(function(peer) {
|
||||
peer.on('block', function(message) {
|
||||
peer.once('block', function(message) {
|
||||
(message.block instanceof Block).should.equal(true);
|
||||
cb();
|
||||
});
|
||||
// TODO: replace this for a new Messages.GetData.forTransaction(hash)
|
||||
var message = new Messages.GetData([{
|
||||
type: Messages.Inventory.TYPE.BLOCK,
|
||||
hash: BufferUtil.reverse(new Buffer(blockHash[network.name], 'hex'))
|
||||
}]);
|
||||
var message = Messages.GetData.forBlock(blockHash[network.name]);
|
||||
peer.sendMessage(message);
|
||||
});
|
||||
});
|
||||
it('can handle request tx data not found', function(cb) {
|
||||
connect(function(peer) {
|
||||
var hash = 'e2dfb8afe1575bfacae1a0b4afc49af7ddda69285857267bae0e22be15f74a3a';
|
||||
var expected = Messages.NotFound.forTransaction(hash);
|
||||
peer.once('notfound', function(message) {
|
||||
(message instanceof Messages.NotFound).should.equal(true);
|
||||
message.should.deep.equal(expected);
|
||||
cb();
|
||||
});
|
||||
var message = Messages.GetData.forTransaction(hash);
|
||||
peer.sendMessage(message);
|
||||
});
|
||||
});
|
||||
|
||||
@ -19,7 +19,6 @@ var $ = bitcore.util.preconditions;
|
||||
var Hash = bitcore.crypto.Hash;
|
||||
var Random = bitcore.crypto.Random;
|
||||
var TransactionModel = bitcore.Transaction;
|
||||
var errors = bitcore.Errors;
|
||||
|
||||
var CONNECTION_NONCE = Random.getPseudoRandomBuffer(8);
|
||||
var PROTOCOL_VERSION = 70000;
|
||||
@ -130,7 +129,7 @@ Message.buildMessage = function(command, payload) {
|
||||
*/
|
||||
Message.prototype.fromBuffer = function(payload) {
|
||||
/* jshint unused: false */
|
||||
throw new errors.NotImplemented();
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -148,7 +147,7 @@ Message.prototype.getPayload = function() {
|
||||
* @returns{Buffer} the serialized message
|
||||
*/
|
||||
Message.prototype.serialize = function(network) {
|
||||
$.checkArgument(network);
|
||||
$.checkArgument(network, 'Must specify network for serialization');
|
||||
var commandBuf = new Buffer(this.command, 'ascii');
|
||||
$.checkState(commandBuf.length <= 12, 'Command name too long');
|
||||
var magic = network.networkMagic;
|
||||
@ -264,6 +263,13 @@ module.exports.Version = Message.COMMANDS.version = Version;
|
||||
* @param{Array} inventory - reported elements
|
||||
*/
|
||||
function Inventory(inventory) {
|
||||
$.checkArgument(_.isUndefined(inventory) ||
|
||||
_.isArray(inventory), 'Inventory for ' +
|
||||
this.constructor.name + ' must be an array of objects');
|
||||
$.checkArgument(_.isUndefined(inventory) ||
|
||||
inventory.length === 0 ||
|
||||
(inventory[0] && !_.isUndefined(inventory[0].type) && !_.isUndefined(inventory[0].hash)),
|
||||
'Inventory for ' + this.constructor.name + ' must be an array of objects');
|
||||
this.command = 'inv';
|
||||
/**
|
||||
* @name P2P.Message.Inventory.inventory
|
||||
@ -287,16 +293,26 @@ Inventory.TYPE_NAME = [
|
||||
'FILTERED_BLOCK'
|
||||
];
|
||||
|
||||
Inventory.forItem = function(type, hash) {
|
||||
$.checkArgument(hash);
|
||||
if (_.isString(hash)) {
|
||||
hash = new Buffer(hash, 'hex');
|
||||
hash = BufferUtil.reverse(hash);
|
||||
}
|
||||
return {
|
||||
type: type,
|
||||
typeName: Inventory.TYPE_NAME[type],
|
||||
hash: hash
|
||||
};
|
||||
};
|
||||
|
||||
Inventory.prototype.fromBuffer = function(payload) {
|
||||
var parser = new BufferReader(payload);
|
||||
var count = parser.readVarintNum();
|
||||
for (var i = 0; i < count; i++) {
|
||||
var type = parser.readUInt32LE();
|
||||
this.inventory.push({
|
||||
type: type,
|
||||
typeName: Inventory.TYPE_NAME[type],
|
||||
hash: parser.read(32)
|
||||
});
|
||||
var hash = parser.read(32);
|
||||
this.inventory.push(Inventory.forItem(type, hash));
|
||||
}
|
||||
|
||||
return this;
|
||||
@ -314,8 +330,32 @@ Inventory.prototype.getPayload = function() {
|
||||
return put.buffer();
|
||||
};
|
||||
|
||||
var creatorForItem = function(clazz, type) {
|
||||
return function(hash) {
|
||||
return new clazz([Inventory.forItem(type, hash)]);
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.Inventory = Message.COMMANDS.inv = Inventory;
|
||||
|
||||
/**
|
||||
* notfound is a response to a getdata, sent if any requested data
|
||||
* items could not be relayed, for example, because the requested
|
||||
* transaction was not in the memory pool or relay set.
|
||||
*
|
||||
* (from bitcoin's protocol spec)
|
||||
*
|
||||
* @name P2P.Message.NotFound
|
||||
* @param{Array} inventory - not found elements
|
||||
*/
|
||||
function NotFound(inventory) {
|
||||
Inventory.call(this, inventory);
|
||||
this.command = 'notfound';
|
||||
}
|
||||
|
||||
util.inherits(NotFound, Inventory);
|
||||
module.exports.NotFound = Message.COMMANDS.notfound = NotFound;
|
||||
|
||||
/**
|
||||
* getdata is used in response to inv, to retrieve the content of a specific
|
||||
* object, and is usually sent after receiving an inv packet, after filtering
|
||||
@ -324,22 +364,18 @@ module.exports.Inventory = Message.COMMANDS.inv = Inventory;
|
||||
* chain is not allowed to avoid having clients start to depend on nodes having
|
||||
* full transaction indexes (which modern nodes do not).
|
||||
*
|
||||
* (taken from bitcoin's protocol spec)
|
||||
* (from bitcoin's protocol spec)
|
||||
*
|
||||
* @name P2P.Message.GetData
|
||||
* @param{Array} inventory - requested elements
|
||||
*/
|
||||
function GetData(inventory) {
|
||||
$.checkArgument(_.isUndefined(inventory) ||
|
||||
_.isArray(inventory), 'Inventory for GetData must be an array of objects');
|
||||
$.checkArgument(_.isUndefined(inventory) ||
|
||||
inventory.length === 0 ||
|
||||
(inventory[0] && !_.isUndefined(inventory[0].type) && !_.isUndefined(inventory[0].hash)),
|
||||
'Inventory for GetData must be an array of objects');
|
||||
Inventory.call(this, inventory);
|
||||
this.command = 'getdata';
|
||||
this.inventory = inventory || [];
|
||||
}
|
||||
|
||||
|
||||
util.inherits(GetData, Inventory);
|
||||
module.exports.GetData = Message.COMMANDS.getdata = GetData;
|
||||
|
||||
@ -480,9 +516,6 @@ function GetAddresses() {
|
||||
}
|
||||
|
||||
util.inherits(GetAddresses, Message);
|
||||
GetAddresses.prototype.fromBuffer = function() {
|
||||
return new GetAddresses();
|
||||
};
|
||||
module.exports.GetAddresses = Message.COMMANDS.getaddr = GetAddresses;
|
||||
|
||||
/**
|
||||
@ -495,9 +528,6 @@ function VerAck() {
|
||||
}
|
||||
|
||||
util.inherits(VerAck, Message);
|
||||
VerAck.prototype.fromBuffer = function() {
|
||||
return new VerAck();
|
||||
};
|
||||
module.exports.VerAck = Message.COMMANDS.verack = VerAck;
|
||||
|
||||
/**
|
||||
@ -737,9 +767,6 @@ function GetHeaders(starts, stop) {
|
||||
}
|
||||
|
||||
util.inherits(GetHeaders, GetBlocks);
|
||||
GetHeaders.prototype.fromBuffer = function() {
|
||||
return new GetHeaders();
|
||||
};
|
||||
module.exports.GetHeaders = Message.COMMANDS.getheaders = GetHeaders;
|
||||
|
||||
/**
|
||||
@ -769,3 +796,10 @@ Buffers.prototype.skip = function(i) {
|
||||
this.buffers[0] = new Buffer(this.buffers[0].slice(pos.offset));
|
||||
this.length -= i;
|
||||
};
|
||||
|
||||
|
||||
|
||||
[Inventory, GetData, NotFound].forEach(function(clazz) {
|
||||
clazz.forBlock = creatorForItem(clazz, Inventory.TYPE.BLOCK);
|
||||
clazz.forTransaction = creatorForItem(clazz, Inventory.TYPE.TX);
|
||||
});
|
||||
|
||||
@ -11,6 +11,10 @@
|
||||
"message": "",
|
||||
"payload": ""
|
||||
},
|
||||
"NOTFOUND": {
|
||||
"message": "f9beb4d96e6f74666f756e6400000000250000001d33d53201010000003a4af715be220eae7b2657582869daddf79ac4afb4a0e1cafa5b57e1afb8dfe2",
|
||||
"payload": "01010000003a4af715be220eae7b2657582869daddf79ac4afb4a0e1cafa5b57e1afb8dfe2"
|
||||
},
|
||||
"GETBLOCKS": {
|
||||
"message": "",
|
||||
"payload": ""
|
||||
|
||||
@ -27,7 +27,8 @@ describe('Messages', function() {
|
||||
GetData: 'getdata',
|
||||
GetAddresses: 'getaddr',
|
||||
Headers: 'headers',
|
||||
Transaction: 'tx'
|
||||
Transaction: 'tx',
|
||||
NotFound: 'notfound'
|
||||
};
|
||||
// TODO: add data for these
|
||||
var noPayload = ['Alert', 'Reject', 'GetBlocks', 'GetHeaders', 'GetData', 'Headers'];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user