some more stuff...not complete yet

This commit is contained in:
Stephen Pair 2013-07-09 17:45:21 -04:00
parent 32c690f52b
commit ebddafcaa7
11 changed files with 146 additions and 103 deletions

View File

@ -1,17 +1,17 @@
require('classtool');
function spec(b) {
var Util = b.Util || require('../ext/util');
var util = b.util || require('./util/util');
var Debug1 = b.Debug1 || function() {};
var Script = b.Script || require('./script').class();
var Script = b.Script || require('./Script').class();
var Bignum = b.Bignum || require('bignum');
var Put = b.Put || require('bufferput');
var Step = b.Step || require('step');
var Transaction = b.Transaction || require('./transaction');
var TransactionIn = b.TransactionIn || require('./transactionIn');
var TransactionOut = b.TransactionOut || require('./transactionOut');
var Transaction = b.Transaction || require('./transaction').class();
var TransactionIn = Transaction.In;
var TransactionOut = Transaction.Out;
var COINBASE_OP = Transaction.COINBASE_OP;
var VerificationError = b.VerificationError || require('../ext/error').VerificationError;
var VerificationError = b.VerificationError || require('./util/error').VerificationError;
var BlockRules = {
maxTimeOffset: 2 * 60 * 60, // How far block timestamps can be into the future
largestHash: Bignum(2).pow(256)
@ -23,8 +23,8 @@ function spec(b) {
data = {};
}
this.hash = data.hash || null;
this.prev_hash = data.prev_hash || Util.NULL_HASH;
this.merkle_root = data.merkle_root || Util.NULL_HASH;
this.prev_hash = data.prev_hash || util.NULL_HASH;
this.merkle_root = data.merkle_root || util.NULL_HASH;
this.timestamp = data.timestamp || 0;
this.bits = data.bits || 0;
this.nonce = data.nonce || 0;
@ -32,7 +32,7 @@ function spec(b) {
this.height = data.height || 0;
this.size = data.size || 0;
this.active = data.active || false;
this.chainWork = data.chainWork || Util.EMPTY_BUFFER;
this.chainWork = data.chainWork || util.EMPTY_BUFFER;
this.txs = data.txs || [];
};
@ -50,7 +50,7 @@ function spec(b) {
Block.prototype.calcHash = function calcHash() {
var header = this.getHeader();
return Util.twoSha256(header);
return util.twoSha256(header);
};
Block.prototype.checkHash = function checkHash() {
@ -65,7 +65,7 @@ function spec(b) {
};
Block.prototype.checkProofOfWork = function checkProofOfWork() {
var target = Util.decodeDiffBits(this.bits);
var target = util.decodeDiffBits(this.bits);
// TODO: Create a compare method in node-buffertools that uses the correct
// endian so we don't have to reverse both buffers before comparing.
@ -89,7 +89,7 @@ function spec(b) {
* of all possible hashes would mean that 20 "work" is required to meet it.
*/
Block.prototype.getWork = function getWork() {
var target = Util.decodeDiffBits(this.bits, true);
var target = util.decodeDiffBits(this.bits, true);
return BlockRules.largestHash.div(target.add(1));
};
@ -141,7 +141,7 @@ function spec(b) {
// This function is a direct translation of CBlock::BuildMerkleTree().
if (txs.length == 0) {
return [Util.NULL_HASH.slice(0)];
return [util.NULL_HASH.slice(0)];
}
// Start by adding all the hashes of the transactions as leaves of the tree.
@ -157,7 +157,7 @@ function spec(b) {
var i2 = Math.min(i + 1, size - 1);
var a = tree[j + i];
var b = tree[j + i2];
tree.push(Util.twoSha256(a.concat(b)));
tree.push(util.twoSha256(a.concat(b)));
}
j += size;
}
@ -199,7 +199,7 @@ function spec(b) {
};
Block.getBlockValue = function getBlockValue(height) {
var subsidy = Bignum(50).mul(Util.COIN);
var subsidy = Bignum(50).mul(util.COIN);
subsidy = subsidy.div(Bignum(2).pow(Math.floor(height / 210000)));
return subsidy;
};
@ -209,7 +209,7 @@ function spec(b) {
};
Block.prototype.toString = function toString() {
return "<Block " + Util.formatHashAlt(this.hash) + " height="+this.height+">";
return "<Block " + util.formatHashAlt(this.hash) + " height="+this.height+">";
};
/**
@ -251,7 +251,7 @@ function spec(b) {
var self = this;
var powLimit = blockChain.getMinDiff();
var powLimitTarget = Util.decodeDiffBits(powLimit, true);
var powLimitTarget = util.decodeDiffBits(powLimit, true);
var targetTimespan = blockChain.getTargetTimespan();
var targetSpacing = blockChain.getTargetSpacing();
@ -327,7 +327,7 @@ function spec(b) {
actualTimespan = targetTimespan*4;
}
var oldTarget = Util.decodeDiffBits(self.bits, true);
var oldTarget = util.decodeDiffBits(self.bits, true);
var newTarget = oldTarget.mul(actualTimespan).div(targetTimespan);
if (newTarget.cmp(powLimitTarget) > 0) {
@ -339,7 +339,7 @@ function spec(b) {
Debug1('Before: '+oldTarget.toBuffer().toString('hex'));
Debug1('After: '+newTarget.toBuffer().toString('hex'));
callback(null, Util.encodeDiffBits(newTarget));
callback(null, util.encodeDiffBits(newTarget));
} catch (err) {
callback(err);
}
@ -426,12 +426,12 @@ function spec(b) {
{
var tx = new Transaction();
tx.ins.push(new TransactionIn({
s: Util.EMPTY_BUFFER,
s: util.EMPTY_BUFFER,
q: 0xffffffff,
o: COINBASE_OP
}));
tx.outs.push(new TransactionOut({
v: Util.bigIntToValue(this.getBlockValue()),
v: util.bigIntToValue(this.getBlockValue()),
s: Script.createPubKeyOut(beneficiary).getBuffer()
}));
return tx;
@ -518,7 +518,7 @@ function spec(b) {
Block.prototype.solve = function solve(miner, callback) {
var header = this.getHeader();
var target = Util.decodeDiffBits(this.bits);
var target = util.decodeDiffBits(this.bits);
miner.solve(header, target, callback);
};
@ -529,10 +529,10 @@ function spec(b) {
function getStandardizedObject(txs)
{
var block = {
hash: Util.formatHashFull(this.getHash()),
hash: util.formatHashFull(this.getHash()),
version: this.version,
prev_block: Util.formatHashFull(this.prev_hash),
mrkl_root: Util.formatHashFull(this.merkle_root),
prev_block: util.formatHashFull(this.prev_hash),
mrkl_root: util.formatHashFull(this.merkle_root),
time: this.timestamp,
bits: this.bits,
nonce: this.nonce,
@ -542,13 +542,13 @@ function spec(b) {
if (txs) {
var mrkl_tree = this.getMerkleTree(txs).map(function (buffer) {
return Util.formatHashFull(buffer);
return util.formatHashFull(buffer);
});
block.mrkl_root = mrkl_tree[mrkl_tree.length - 1];
block.n_tx = txs.length;
var totalSize = 80; // Block header
totalSize += Util.getVarIntSize(txs.length); // txn_count
totalSize += util.getVarIntSize(txs.length); // txn_count
txs = txs.map(function (tx) {
tx = tx.getStandardizedObject();
totalSize += tx.size;

View File

@ -2,6 +2,7 @@ require('classtool');
function spec(b) {
var config = b.config || require('./config');
var log = b.log || require('./util/log')(config);
var network = b.network || require('./networks')[config.network];
var MAX_RECEIVE_BUFFER = 10000000;
@ -11,13 +12,12 @@ function spec(b) {
var Put = b.Put || require('bufferput');
var Buffers = b.Buffers || require('buffers');
var noop = function() {};
var log = b.log || require('bitpay/log');
var util = b.util || require('./util/util');
var Parser = b.Parser || require('./util/BinaryParser').class();
var util = require('./util/util');
var doubleSha256 = b.doubleSha256 || util.twoSha256;
var nonce = util.generateNonce();
var Block = require('../model/block').class();
var Block = require('./Block').class();
var BIP0031_VERSION = 60000;
@ -170,7 +170,7 @@ function spec(b) {
Connection.prototype.sendVersion = function () {
var subversion = '/BitcoinX:0.1/';
var put = Put();
var put = new Put();
put.word32le(PROTOCOL_VERSION); // version
put.word64le(1); // services
put.word64le(Math.round(new Date().getTime()/1000)); // timestamp
@ -185,7 +185,7 @@ function spec(b) {
};
Connection.prototype.sendGetBlocks = function (starts, stop) {
var put = Put();
var put = new Put();
put.word32le(this.sendVer);
put.varint(starts.length);
@ -208,7 +208,7 @@ function spec(b) {
};
Connection.prototype.sendGetData = function (invs) {
var put = Put();
var put = new Put();
put.varint(invs.length);
for (var i = 0; i < invs.length; i++) {
put.word32le(invs[i].type);
@ -218,13 +218,13 @@ function spec(b) {
};
Connection.prototype.sendGetAddr = function (invs) {
var put = Put();
var put = new Put();
this.sendMessage('getaddr', put.buffer());
};
Connection.prototype.sendInv = function(data) {
if(!Array.isArray(data)) data = [data];
var put = Put();
var put = new Put();
put.varint(data.length);
data.forEach(function (value) {
if (value instanceof Block) {
@ -240,7 +240,7 @@ function spec(b) {
};
Connection.prototype.sendHeaders = function (headers) {
var put = Put();
var put = new Put();
put.varint(headers.length);
headers.forEach(function (header) {
put.put(header);
@ -256,7 +256,7 @@ function spec(b) {
};
Connection.prototype.sendBlock = function (block, txs) {
var put = Put();
var put = new Put();
// Block header
put.put(block.getHeader());
@ -283,7 +283,7 @@ function spec(b) {
checksum = new Buffer([]);
}
var message = Put(); // -- HEADER --
var message = new Put(); // -- HEADER --
message.put(magic); // magic bytes
message.put(commandBuf); // command name
message.pad(12 - commandBuf.length); // zero-padded

View File

@ -2,11 +2,11 @@ require('classtool');
function spec(b) {
var config = b.config || require('./config');
var log = b.log || require('./util/log')(config);
var network = b.network || require('./networks')[config.network];
var Connection = b.Connection || require('./Connection').createClass({config: config});
var Peer = b.Peer || require('./Peer').class();
var noop = function() {};
var log = b.log || {info: noop, warn: noop, err: noop};
GetAdjustedTime = b.GetAdjustedTime || function () {
// TODO: Implement actual adjustment
@ -31,16 +31,14 @@ function spec(b) {
PeerManager.Connection = Connection;
PeerManager.prototype.start = function()
{
PeerManager.prototype.start = function() {
this.active = true;
if(!this.timer) {
this.timer = setInterval(this.checkStatus.bind(this), this.interval);
}
};
PeerManager.prototype.stop = function ()
{
PeerManager.prototype.stop = function() {
this.active = false;
if(this.timer) {
clearInterval(this.timer);
@ -63,8 +61,7 @@ function spec(b) {
}
};
PeerManager.prototype.checkStatus = function checkStatus()
{
PeerManager.prototype.checkStatus = function checkStatus() {
// Make sure we are connected to all forcePeers
if(this.peers.length) {
var peerIndex = {};

View File

@ -1,6 +1,9 @@
require('classtool');
function spec(b) {
var config = b.config || require('./config');
var log = b.log || require('./util/log')(config);
var Opcode = require('./opcode').class();
// Make opcodes available as pseudo-constants
@ -8,16 +11,15 @@ function spec(b) {
eval(i + " = " + Opcode.map[i] + ";");
}
var logger = b.logger || require('../ext/logger');
var Util = b.Util || require('../ext/util');
var Parser = b.Parser || require('../ext/binaryParser').class();
var util = b.util || require('./util/util');
var Parser = b.Parser || require('./util/BinaryParser').class();
var Put = b.Put || require('bufferput');
function Script(buffer) {
if(buffer) {
this.buffer = buffer;
} else {
this.buffer = Util.EMPTY_BUFFER;
this.buffer = util.EMPTY_BUFFER;
}
this.chunks = [];
this.parse();
@ -84,10 +86,10 @@ function spec(b) {
case 'Address':
return this.chunks[2];
case 'Pubkey':
return Util.sha256ripe160(this.chunks[0]);
return util.sha256ripe160(this.chunks[0]);
default:
logger.scrdbg("Encountered non-standard scriptPubKey");
logger.scrdbg("Strange script was: " + this.toString());
log.debug("Encountered non-standard scriptPubKey");
log.debug("Strange script was: " + this.toString());
return null;
}
};
@ -114,8 +116,8 @@ function spec(b) {
case 'Pubkey':
return null;
default:
logger.scrdbg("Encountered non-standard scriptSig");
logger.scrdbg("Strange script was: " + this.toString());
log.debug("Encountered non-standard scriptSig");
log.debug("Strange script was: " + this.toString());
return null;
}
};
@ -144,7 +146,7 @@ function spec(b) {
}
if (Buffer.isBuffer(chunk)) {
script += "0x"+Util.formatBuffer(chunk, truncate ? null : 0);
script += "0x"+util.formatBuffer(chunk, truncate ? null : 0);
} else {
script += Opcode.reverseMap[chunk];
}

View File

@ -1,6 +1,9 @@
require('classtool');
function spec(b) {
var config = b.config || require('./config');
var log = b.log || require('./util/log')(config);
var Opcode = require('./opcode').class();
// Make opcodes available as pseudo-constants
@ -9,8 +12,7 @@ function spec(b) {
}
var bignum = b.bignum || require('bignum');
var logger = b.logger || require('../ext/logger');
var Util = b.Util || require('../ext/util');
var Util = b.Util || require('./util/util');
var Script = require('./script').class();
function ScriptInterpreter() {
@ -717,7 +719,7 @@ function spec(b) {
executeStep.call(this, cb);
}
} catch (e) {
logger.scrdbg("Script aborted: "+
log.debug("Script aborted: "+
(e.message ? e : e));
cb(e);
}

View File

@ -1,16 +1,17 @@
require('classtool');
function spec(b) {
var Script = b.Script || require('./script').class();
var ScriptInterpreter = b.ScriptInterpreter || require('./scriptInterpreter').class();
var util = b.util || require('../ext/util');
var config = b.config || require('./config');
var log = b.log || require('./util/log')(config);
var Script = b.Script || require('./Script').class();
var ScriptInterpreter = b.ScriptInterpreter || require('./ScriptInterpreter').class();
var util = b.util || require('./util/util');
var bignum = b.bignum || require('bignum');
var Put = b.Put || require('bufferput');
var error = b.error || require('../ext/error');
var logger = b.logger || require('../ext/logger');
var Parser = b.Parser || require('./util/BinaryParser').class();
var Step = b.Step || require('step');
var Parser = b.Parser || require('../ext/binaryParser').class();
var error = b.error || require('./util/error');
var VerificationError = error.VerificationError;
var MissingSourceError = error.MissingSourceError;
@ -265,9 +266,9 @@ function spec(b) {
for (var i = 0, l = results.length; i < l; i++) {
if (!results[i]) {
var txout = getTxOut(self.ins[i]);
logger.scrdbg('Script evaluated to false');
logger.scrdbg('|- scriptSig', ""+self.ins[i].getScript());
logger.scrdbg('`- scriptPubKey', ""+txout.getScript());
log.debug('Script evaluated to false');
log.debug('|- scriptSig', ""+self.ins[i].getScript());
log.debug('`- scriptPubKey', ""+txout.getScript());
throw new VerificationError('Script for input '+i+' evaluated to false');
}
}
@ -302,7 +303,7 @@ function spec(b) {
blockChain.getConflictingTransactions(outpoints, function (err, results) {
if (results.length) {
if (results[0].getHash().compare(self.getHash()) == 0) {
logger.warn("Detected tx re-add (recoverable db corruption): "
log.warn("Detected tx re-add (recoverable db corruption): "
+ util.formatHashAlt(results[0].getHash()));
// TODO: Needs to return an error for the memory pool case?
callback(null, fees);
@ -360,7 +361,7 @@ function spec(b) {
} catch (err) {
// It's not our job to validate, so we just ignore any errors and issue
// a very low level log message.
logger.debug("Unable to determine affected pubkeys: " +
log.debug("Unable to determine affected pubkeys: " +
(err.stack ? err.stack : ""+err));
}
};
@ -395,7 +396,7 @@ function spec(b) {
} catch (err) {
// It's not our job to validate, so we just ignore any errors and issue
// a very low level log message.
logger.debug("Unable to determine affected pubkeys: " +
log.debug("Unable to determine affected pubkeys: " +
(err.stack ? err.stack : ""+err));
}
}
@ -707,7 +708,7 @@ function spec(b) {
cb.apply(null, args);
});
} catch (err) {
logger.error("Callback error after connecting tx inputs: "+
log.err("Callback error after connecting tx inputs: "+
(err.stack ? err.stack : err.toString()));
}
};

View File

@ -1,3 +1,4 @@
module.exports = {
network: 'livenet'
network: 'livenet',
logging: 'normal' // none, normal, debug
};

View File

@ -28,9 +28,12 @@
"classtool": ">=1.0.0",
"base58-native": ">=0.1.1",
"bindings": "1.1.0",
"bufferput": ">=0.1.1"
//"bignum"
//"binary"
"bufferput": ">=0.1.1",
"bignum": "0.6.1",
"binary": "0.3.0",
"step": "0.0.4",
"buffers": "0.0.1",
"buffertools": "1.1.1"
},
"devDependencies": {},
"license": "MIT"

40
util/error.js Normal file
View File

@ -0,0 +1,40 @@
/**
* Used during transcation verification when a source txout is missing.
*
* When a transaction is being verified by the memory pool this error causes
* it to be added to the orphan pool instead of being discarded.
*/
function MissingSourceError(msg, missingTxHash) {
// TODO: Since this happens in normal operation, perhaps we should
// avoid generating a whole stack trace.
Error.call(this);
Error.captureStackTrace(this, arguments.callee);
this.message = msg;
this.missingTxHash = missingTxHash;
this.name = 'MissingSourceError';
};
MissingSourceError.prototype.__proto__ = Error.prototype;
exports.MissingSourceError = MissingSourceError;
/**
* Used in several places to indicate invalid data.
*
* We want to distinguish invalid data errors from program errors, so we use
* this exception to indicate the former.
*/
function VerificationError(msg, missingTxHash) {
// TODO: Since this happens in normal operation, perhaps we should
// avoid generating a whole stack trace.
Error.call(this);
Error.captureStackTrace(this, arguments.callee);
this.message = msg;
this.missingTxHash = missingTxHash;
this.name = 'VerificationError';
};
VerificationError.prototype.__proto__ = Error.prototype;
exports.VerificationError = VerificationError;

14
util/log.js Normal file
View File

@ -0,0 +1,14 @@
var noop = function() {};
var loggers = {
none: {info: noop, warn: noop, err: noop, debug: noop},
normal: {info: console.log, warn: console.log, err: console.log, debug: noop},
debug: {info: console.log, warn: console.log, err: console.log, debug: console.log},
};
module.exports = function(config) {
config = config || {};
if(config.log) return config.log;
if(config.loggers) return config.loggers[config.logging || 'normal'];
return loggers[config.logging || 'normal'];
};

View File

@ -2,14 +2,7 @@ require('buffertools');
var crypto = require('crypto');
var bignum = require('bignum');
var Binary = require('binary');
var Put = require('put');
//var logger = require('./logger');
var ccmodule = require('bindings')('nativetools');
exports.ccmodule = ccmodule;
exports.BitcoinKey = ccmodule.BitcoinKey;
var Put = require('bufferput');
var sha256 = exports.sha256 = function (data) {
return new Buffer(crypto.createHash('sha256').update(data).digest('binary'), 'binary');
@ -31,8 +24,6 @@ var sha256ripe160 = exports.sha256ripe160 = function (data) {
return ripe160(sha256(data));
};
var sha256midstate = exports.sha256midstate = ccmodule.sha256_midstate;
/**
* Format a block hash like the official client does.
*/
@ -119,7 +110,7 @@ var formatValue = exports.formatValue = function (valueBuffer) {
var pubKeyHashToAddress = exports.pubKeyHashToAddress = function (pubKeyHash, addressVersion) {
if (!pubKeyHash) return "";
var put = Put();
var put = new Put();
// Version
if(addressVersion) {
put.word8le(addressVersion);
@ -139,7 +130,6 @@ var addressToPubKeyHash = exports.addressToPubKeyHash = function (address) {
// Check sanity
if (!address.match(/^[1-9A-HJ-NP-Za-km-z]{27,35}$/)) {
//logger.warn("Not a valid Bitcoin address");
return null;
}
@ -155,7 +145,6 @@ var addressToPubKeyHash = exports.addressToPubKeyHash = function (address) {
// Check checksum
var checksum = twoSha256(buffer.slice(0, 21)).slice(0, 4);
if (checksum.compare(parser.vars.checksum) !== 0) {
//logger.warn("Checksum comparison failed");
return null;
}
@ -284,7 +273,7 @@ var reverseBytes32 = exports.reverseBytes32 = function (data) {
if (data.length % 4) {
throw new Error("Util.reverseBytes32(): Data length must be multiple of 4");
}
var put = Put();
var put = new Put();
var parser = Binary.parse(data);
while (!parser.eof()) {
var word = parser.word32le('word').vars.word;
@ -311,19 +300,13 @@ var getVarIntSize = exports.getVarIntSize = function getVarIntSize(i) {
};
// Initializations
try {
var NULL_HASH = exports.NULL_HASH = new Buffer(32).fill(0);
var EMPTY_BUFFER = exports.EMPTY_BUFFER = new Buffer(0);
var ZERO_VALUE = exports.ZERO_VALUE = new Buffer(8).fill(0);
var INT64_MAX = exports.INT64_MAX = decodeHex("ffffffffffffffff");
exports.NULL_HASH = new Buffer(32).fill(0);
exports.EMPTY_BUFFER = new Buffer(0);
exports.ZERO_VALUE = new Buffer(8).fill(0);
INT64_MAX = new Buffer('ffffffffffffffff', 'hex');
// How much of Bitcoin's internal integer coin representation
// makes 1 BTC
var COIN = exports.COIN = 100000000;
// How much of Bitcoin's internal integer coin representation
// makes 1 BTC
exports.COIN = 100000000;
var MAX_TARGET = exports.MAX_TARGET = decodeHex('00000000FFFF0000000000000000000000000000000000000000000000000000');
} catch (e) {
//logger.error("Error while generating utility constants:\n" +
// (e.stack ? e.stack : e.toString()));
process.exit(1);
}
exports.MAX_TARGET = new Buffer('00000000FFFF0000000000000000000000000000000000000000000000000000', 'hex');