Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Implemented calculating block hashes and saving blocks to db.

  • Loading branch information...
commit 08a9ac53b7084ca3d27983f911a7c6ac420d81c7 1 parent 006be16
Stefan Thomas justmoon authored
3  .gitmodules
View
@@ -0,0 +1,3 @@
+[submodule "vendor/mongoose"]
+ path = vendor/mongoose
+ url = https://github.com/justmoon/mongoose
90 bitcoin/blockchain.js
View
@@ -0,0 +1,90 @@
+var winston = require('winston'); // logging
+var Binary = require('binary');
+var Util = require('./util');
+
+var genesis_block = {
+ 'height': 1.0,
+ 'nonce': 2083236893,
+ 'version': 1,
+ 'hash': new Buffer('o\xe2\x8c\n\xb6\xf1\xb3r\xc1\xa6\xa2F\xaec\xf7O\x93\x1e\x83e\xe1Z\x08\x9ch\xd6\x19\x00\x00\x00\x00\x00', 'binary'),
+ 'prev_hash': new Buffer('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 'binary'),
+ 'timestamp': 1231006505,
+ 'merkle_root': new Buffer(';\xa3\xed\xfdz{\x12\xb2z\xc7,>gv\x8fa\x7f\xc8\x1b\xc3\x88\x8aQ2:\x9f\xb8\xaaK\x1e^J', 'binary'),
+ 'bits': 486604799
+};
+
+var genesis_block_tx = {
+ 'outs': [{
+ 'script': new Buffer("A\x04g\x8a\xfd\xb0\xfeUH'\x19g\xf1\xa6q0\xb7\x10\\\xd6\xa8(\xe09\t\xa6yb\xe0\xea\x1fa\xde\xb6I\xf6\xbc?L\xef8\xc4\xf3U\x04\xe5\x1e\xc1\x12\xde\\8M\xf7\xba\x0b\x8dW\x8aLp+k\xf1\x1d_\xac", 'binary'),
+ 'value': 5000000000
+ }],
+ 'lock_time': 0,
+ 'version': 1,
+ 'hash': null,
+ 'ins': [{
+ 'sequence': 4294967295,
+ 'outpoint': {
+ 'index': 4294967295,
+ 'hash': new Buffer('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 'binary')
+ },
+ 'script': new Buffer('\x04\xff\xff\x00\x1d\x01\x04EThe Times 03/Jan/2009 Chancellor on brink of second bailout for banks', 'binary')
+ }]
+};
+
+var BlockChain = exports.BlockChain = function (storage) {
+ this.storage = storage;
+
+ var Block = this.storage.Block;
+
+ function createGenesisBlock(callback) {
+ winston.info("Loading genesis block");
+
+ Block.create(genesis_block, callback);
+ };
+
+ this.getGenesisBlock = function getGenesisBlock(callback) {
+ Block.findOne({hash: genesis_block.hash}, function (err, docs) {
+ if (err) return callback(err);
+
+ if (!docs) createGenesisBlock(callback);
+ //else callback(err, docs); // no action necessary
+ });
+ };
+
+ this.getTopBlock = function getTopBlock(callback) {
+ Block
+ .find()
+ .sort('height', -1)
+ .limit(1)
+ .exec(function (err, result) {
+ if (err) return callback(err);
+
+ callback(null, result[0]);
+ });
+ };
+
+ this.getHeader = function (block) {
+ put = Binary.put();
+ put.word32le(block.version);
+ put.put(block.prev_hash);
+ put.put(block.merkle_root);
+ put.word32le(block.timestamp);
+ put.word32le(block.bits);
+ put.word32le(block.nonce);
+ return put.buffer();
+ };
+
+ this.calcHash = function (block) {
+ var header = this.getHeader(block);
+
+ return Util.twoSha256(header);
+ };
+
+ this.add = function add(block, callback) {
+ Block.create(block, function (err, block) {
+ if (err) return callback(err);
+
+
+ });
+ };
+};
31 bitcoin/connection.js
View
@@ -1,15 +1,11 @@
var sys = require('sys');
var events = require('events');
-var crypto = require('crypto');
var winston = require('winston'); // logging
var Binary = require('binary');
+var Util = require('./util');
var magic = new Buffer('F9BEB4D9', 'hex');
-function sha256(data) {
- return new Buffer(crypto.createHash('sha256').update(data).digest('binary'), 'binary');
-};
-
Binary.put.prototype.var_uint = function (i) {
if (i < 0xFD) {
// unsigned char
@@ -160,7 +156,7 @@ Connection.prototype.sendMessage = function (command, payload) {
var checksum;
if (this.sendVer >= 209) {
- checksum = (sha256(sha256(payload))).slice(0, 4);
+ checksum = Util.twoSha256(payload).slice(0, 4);
} else {
checksum = new Buffer([]);
}
@@ -209,7 +205,7 @@ Connection.prototype.setupParser = function (parser, callback) {
winston.error('Connection.setupParser(): Payload has incorrect length');
}
if ("undefined" !== typeof vars.checksum) {
- var checksum = (new Buffer(sha256(sha256(vars.payload)), 'binary'));
+ var checksum = (new Buffer(Util.twoSha256(vars.payload), 'binary'));
if (vars.checksum[0] != checksum[0] ||
vars.checksum[1] != checksum[1] ||
vars.checksum[2] != checksum[2] ||
@@ -230,6 +226,9 @@ Connection.prototype.setupParser = function (parser, callback) {
Connection.prototype.parseMessage = function (command, payload, callback) {
var parser = Binary.parse(payload);
+
+ parser.vars.command = command;
+
switch (command) {
case 'version': // https://en.bitcoin.it/wiki/Protocol_specification#version
parser.word32le('version');
@@ -257,7 +256,15 @@ Connection.prototype.parseMessage = function (command, payload, callback) {
break;
case 'block':
- // TODO: Parse
+ parser.word32le('version');
+ parser.buffer('prev_hash', 32);
+ parser.buffer('merkle_root', 32);
+ parser.word32le('timestamp');
+ parser.word32le('bits');
+ parser.word32le('nonce');
+ this.parseVarInt(parser, 'txn_count');
+
+ // TODO: Parse tx
break;
case 'addr':
@@ -272,6 +279,10 @@ Connection.prototype.parseMessage = function (command, payload, callback) {
// Empty message, nothing to parse
break;
+ case 'ping':
+ // Empty message, nothing to parse
+ break;
+
default:
winston.error('Connection.parseMessage(): Command not implemented',
{cmd: command});
@@ -280,8 +291,6 @@ Connection.prototype.parseMessage = function (command, payload, callback) {
var message = parser.vars;
- message.command = command;
-
callback(message);
};
@@ -290,8 +299,6 @@ Connection.prototype.parseVarInt = function (parser, name) {
parser.word8(name+'_byte');
- console.log('first byte: '+parser.vars[name+'_byte']);
-
switch (parser.vars[name+'_byte']) {
case 0xFD:
parser.word16le(name);
52 bitcoin/node.js
View
@@ -2,6 +2,7 @@ var winston = require('winston'); // logging
var Peer = require('./peer').Peer;
var Connection = require('./connection').Connection;
+var BlockChain = require('./blockchain').BlockChain;
var Node = function (storage) {
this.peers = [];
@@ -9,6 +10,8 @@ var Node = function (storage) {
this.storage = storage;
this.nonce = new Buffer('a8deb8a83928aff8', 'hex');
this.version = 32001;
+
+ this.blockChain = new BlockChain(storage);
};
Node.prototype.start = function () {
@@ -36,10 +39,35 @@ Node.prototype.addConnection = function (conn) {
};
Node.prototype.handleConnect = function (e) {
- this.storage.getEnds(function (err, heads, tails) {
- e.conn.sendGetBlocks(heads, '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0');
- //e.conn.sendGetAddr();
- });
+ this.startBlockChainDownload();
+};
+
+Node.prototype.startBlockChainDownload = function () {
+ // TODO: Figure out a way to spread load across peers
+ this.blockChain.getGenesisBlock((function (err, genesisBlock) {
+ if (err) {
+ winston.error(err);
+ return;
+ }
+
+ this.blockChain.getTopBlock((function (err, topBlock) {
+ if (err) {
+ winston.error(err);
+ return;
+ }
+
+ var starts = [];
+
+ if (topBlock.hash.compare(genesisBlock.hash) !== 0) {
+ console.log('using top block');
+ starts.push(topBlock.hash);
+ }
+
+ starts.push(genesisBlock.hash);
+
+ this.connections[0].sendGetBlocks(starts, genesisBlock.hash);
+ }).bind(this));
+ }).bind(this));
};
Node.prototype.handleInv = function (e) {
@@ -77,6 +105,22 @@ Node.prototype.handleInv = function (e) {
};
Node.prototype.handleBlock = function (e) {
+ var block = {
+ "version": 1,
+ "prev_hash": e.message['prev_hash'],
+ "merkle_root": e.message['merkle_root'],
+ "timestamp": e.message.timestamp,
+ "bits": e.message.bits,
+ "nonce": e.message.nonce
+ };
+ block.hash = this.blockChain.calcHash(block);
+ this.blockChain.add(block, function (err, block) {
+ if (err) {
+ winston.error("Error while adding block to chain: "+err);
+ return;
+ }
+ winston.info('block created successfully', block);
+ });
winston.info('TODO handle block');
};
23 bitcoin/schema.js
View
@@ -1,24 +1,24 @@
-var mongoose = require('mongoose'); // database
+var mongoose = require('../vendor/mongoose/lib/mongoose/index'); // database
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var TransactionIn = new Schema({
- script: String,
+ script: Buffer,
sequence: Number,
outpoint: {
- hash: String,
+ hash: Buffer,
index: Number
}
});
var TransactionOut = new Schema({
value: Number,
- script: String
+ script: Buffer
});
var Transaction = new Schema({
- hash: { type: String, unique: true },
+ hash: { type: Buffer, unique: true },
block: ObjectId,
sequence: Number,
version: String,
@@ -28,15 +28,16 @@ var Transaction = new Schema({
});
var Block = new Schema({
- hash: { type: String, unique: true },
- prev_hash: { type: String, index: true },
- merkle_root: String,
+ hash: { type: Buffer, unique: true, default: function () {
+ console.log('bla', this);
+ } },
+ prev_hash: { type: Buffer, index: true },
+ merkle_root: Buffer,
timestamp: Number,
bits: Number,
- nonce: String,
+ nonce: Number,
version: String,
- height: { type: Number, index: true },
- txs: [Transaction]
+ height: { type: Number, index: true }
});
mongoose.model('Block', Block);
61 bitcoin/storage.js
View
@@ -1,66 +1,16 @@
var winston = require('winston'); // logging
-var mongoose = require('mongoose'); // database
+var mongoose = require('../vendor/mongoose/lib/mongoose/index'); // database
require('./schema');
-var genesis_block = {
- 'height': 1.0,
- 'nonce': '\x1d\xac+|',
- 'version': 1,
- 'hash': 'o\xe2\x8c\n\xb6\xf1\xb3r\xc1\xa6\xa2F\xaec\xf7O\x93\x1e\x83e\xe1Z\x08\x9ch\xd6\x19\x00\x00\x00\x00\x00',
- 'txs': [{
- 'outs': [{
- 'script': "A\x04g\x8a\xfd\xb0\xfeUH'\x19g\xf1\xa6q0\xb7\x10\\\xd6\xa8(\xe09\t\xa6yb\xe0\xea\x1fa\xde\xb6I\xf6\xbc?L\xef8\xc4\xf3U\x04\xe5\x1e\xc1\x12\xde\\8M\xf7\xba\x0b\x8dW\x8aLp+k\xf1\x1d_\xac",
- 'value': 5000000000
- }],
- 'lock_time': 0,
- 'version': 1,
- 'hash': null,
- 'ins': [{
- 'sequence': 4294967295,
- 'outpoint': {
- 'index': 4294967295,
- 'hash': '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
- },
- 'script': '\x04\xff\xff\x00\x1d\x01\x04EThe Times 03/Jan/2009 Chancellor on brink of second bailout for banks'}]}],
- 'prev_hash': '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- 'timestamp': 1231006505,
- 'merkle_root': ';\xa3\xed\xfdz{\x12\xb2z\xc7,>gv\x8fa\x7f\xc8\x1b\xc3\x88\x8aQ2:\x9f\xb8\xaaK\x1e^J',
- 'bits': 486604799
-};
-
var Storage = exports.Storage = function (uri) {
this.connection = mongoose.createConnection(uri);
- var Block = this.connection.model('Block');
-
- function ensureGenesisBlock(callback) {
- Block.find({hash: genesis_block.hash}, function (err, docs) {
- if (err) return callback(err);
-
- if (!docs.length) createGenesisBlock(callback);
- else callback(); // no action necessary
- });
- };
-
- function createGenesisBlock(callback) {
- winston.info("Loading genesis block");
-
- var g = new Block(genesis_block);
- g.save(callback);
- };
+ var Block = this.Block = this.connection.model('Block');
function difficulty(bits) {
};
- this.getEnds = function (callback) {
- ensureGenesisBlock(function (err) {
- if (err) return callback(err);
-
- callback(null, [genesis_block.hash], []); // success
- });
- };
-
this.knowsBlock = function (hash, callback) {
if (hash instanceof Buffer) {
hash = hash.toString('binary');
@@ -69,8 +19,13 @@ var Storage = exports.Storage = function (uri) {
return;
}
- Block.find({'hash': hash.toString('binary')}).count(function (err, count) {
+ Block.find({'hash': hash}).count(function (err, count) {
callback(err, !!count);
});
};
+
+ this.knowsTransaction = function (hash, callback) {
+ // TODO: Implement
+ callback(null, true);
+ };
};
10 bitcoin/util.js
View
@@ -0,0 +1,10 @@
+
+var crypto = require('crypto');
+
+var sha256 = exports.sha256 = function (data) {
+ return new Buffer(crypto.createHash('sha256').update(data).digest('binary'), 'binary');
+};
+
+var twoSha256 = exports.twoSha256 = function (data) {
+ return sha256(sha256(data));
+};
1  server.js
View
@@ -1,3 +1,4 @@
+require('buffertools');
var Storage = require('./bitcoin/storage').Storage;
var Node = require('./bitcoin/node').Node;
1  vendor/mongoose
@@ -0,0 +1 @@
+Subproject commit 7f657d05d7fd3dcb9ddeaf1ffec02d309d376480
Please sign in to comment.
Something went wrong with that request. Please try again.