Permalink
Browse files

Implemented calculating block hashes and saving blocks to db.

  • Loading branch information...
1 parent 006be16 commit 08a9ac53b7084ca3d27983f911a7c6ac420d81c7 @justmoon justmoon committed Mar 14, 2011
Showing with 192 additions and 80 deletions.
  1. +3 −0 .gitmodules
  2. +90 −0 bitcoin/blockchain.js
  3. +19 −12 bitcoin/connection.js
  4. +48 −4 bitcoin/node.js
  5. +12 −11 bitcoin/schema.js
  6. +8 −53 bitcoin/storage.js
  7. +10 −0 bitcoin/util.js
  8. +1 −0 server.js
  9. +1 −0 vendor/mongoose
View
@@ -0,0 +1,3 @@
+[submodule "vendor/mongoose"]
+ path = vendor/mongoose
+ url = https://github.com/justmoon/mongoose
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);
+
+
+ });
+ };
+};
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);
View
@@ -2,13 +2,16 @@ 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 = [];
this.connections = [];
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');
};
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);
Oops, something went wrong.

0 comments on commit 08a9ac5

Please sign in to comment.