all classes working with soop and test passing
This commit is contained in:
parent
fa1e323d39
commit
c0c325dabd
23
Address.js
23
Address.js
|
@ -1,22 +1,19 @@
|
|||
require('classtool');
|
||||
'use strict';
|
||||
var imports = require('soop').imports();
|
||||
var parent = imports.parent || require('./util/VersionedData');
|
||||
|
||||
function ClassSpec(b) {
|
||||
var superclass = b.superclass || require('./util/VersionedData').class();
|
||||
|
||||
function Address() {
|
||||
function Address() {
|
||||
Address.super(this, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
Address.superclass = superclass;
|
||||
superclass.applyEncodingsTo(Address);
|
||||
Address.parent = parent;
|
||||
parent.applyEncodingsTo(Address);
|
||||
|
||||
Address.prototype.validate = function() {
|
||||
Address.prototype.validate = function() {
|
||||
this.doAsBinary(function() {
|
||||
Address.super(this, 'validate', arguments);
|
||||
if(this.data.length !== 21) throw new Error('invalid data length');
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
return Address;
|
||||
}
|
||||
module.defineClass(ClassSpec);
|
||||
module.exports = require('soop')(Address);
|
||||
|
|
193
Block.js
193
Block.js
|
@ -1,25 +1,24 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
|
||||
function spec(b) {
|
||||
var util = b.util || require('./util/util');
|
||||
var Debug1 = b.Debug1 || function() {};
|
||||
var Script = b.Script || require('./Script').class();
|
||||
var Bignum = b.Bignum || require('bignum');
|
||||
var Binary = b.Binary || require('binary');
|
||||
var Step = b.Step || require('step');
|
||||
var buffertools = b.buffertools || require('buffertools');
|
||||
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('./util/error').VerificationError;
|
||||
var BlockRules = {
|
||||
var util = imports.util || require('./util/util');
|
||||
var Debug1 = imports.Debug1 || function() {};
|
||||
var Script = imports.Script || require('./Script');
|
||||
var Bignum = imports.Bignum || require('bignum');
|
||||
var Binary = imports.Binary || require('binary');
|
||||
var Step = imports.Step || require('step');
|
||||
var buffertools = imports.buffertools || require('buffertools');
|
||||
var Transaction = imports.Transaction || require('./Transaction');
|
||||
var TransactionIn = Transaction.In;
|
||||
var TransactionOut = Transaction.Out;
|
||||
var COINBASE_OP = Transaction.COINBASE_OP;
|
||||
var VerificationError = imports.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)
|
||||
};
|
||||
};
|
||||
|
||||
function Block(data)
|
||||
{
|
||||
function Block(data)
|
||||
{
|
||||
if ("object" !== typeof data) {
|
||||
data = {};
|
||||
}
|
||||
|
@ -35,9 +34,9 @@ function spec(b) {
|
|||
this.active = data.active || false;
|
||||
this.chainWork = data.chainWork || util.EMPTY_BUFFER;
|
||||
this.txs = data.txs || [];
|
||||
}
|
||||
}
|
||||
|
||||
Block.prototype.getHeader = function getHeader() {
|
||||
Block.prototype.getHeader = function getHeader() {
|
||||
var buf = new Buffer(80);
|
||||
var ofs = 0;
|
||||
buf.writeUInt32LE(this.version, ofs); ofs += 4;
|
||||
|
@ -47,9 +46,9 @@ function spec(b) {
|
|||
buf.writeUInt32LE(this.bits, ofs); ofs += 4;
|
||||
buf.writeUInt32LE(this.nonce, ofs); ofs += 4;
|
||||
return buf;
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.parse = function parse(parser, headerOnly) {
|
||||
Block.prototype.parse = function parse(parser, headerOnly) {
|
||||
this.version = parser.word32le();
|
||||
this.prev_hash = parser.buffer(32);
|
||||
this.merkle_root = parser.buffer(32);
|
||||
|
@ -70,26 +69,26 @@ function spec(b) {
|
|||
tx.parse(parser);
|
||||
this.txs.push(tx);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.calcHash = function calcHash() {
|
||||
Block.prototype.calcHash = function calcHash() {
|
||||
var header = this.getHeader();
|
||||
|
||||
return util.twoSha256(header);
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.checkHash = function checkHash() {
|
||||
Block.prototype.checkHash = function checkHash() {
|
||||
if (!this.hash || !this.hash.length) return false;
|
||||
return buffertools.compare(this.calcHash(), this.hash) == 0;
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.getHash = function getHash() {
|
||||
Block.prototype.getHash = function getHash() {
|
||||
if (!this.hash || !this.hash.length) this.hash = this.calcHash();
|
||||
|
||||
return this.hash;
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.checkProofOfWork = function checkProofOfWork() {
|
||||
Block.prototype.checkProofOfWork = function checkProofOfWork() {
|
||||
var target = util.decodeDiffBits(this.bits);
|
||||
|
||||
// TODO: Create a compare method in node-buffertools that uses the correct
|
||||
|
@ -104,30 +103,30 @@ function spec(b) {
|
|||
buffertools.reverse(this.hash);
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the amount of work that went into this block.
|
||||
*
|
||||
* Work is defined as the average number of tries required to meet this
|
||||
* block's difficulty target. For example a target that is greater than 5%
|
||||
* of all possible hashes would mean that 20 "work" is required to meet it.
|
||||
*/
|
||||
Block.prototype.getWork = function getWork() {
|
||||
Block.prototype.getWork = function getWork() {
|
||||
var target = util.decodeDiffBits(this.bits, true);
|
||||
return BlockRules.largestHash.div(target.add(1));
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.checkTimestamp = function checkTimestamp() {
|
||||
Block.prototype.checkTimestamp = function checkTimestamp() {
|
||||
var currentTime = new Date().getTime() / 1000;
|
||||
if (this.timestamp > currentTime + BlockRules.maxTimeOffset) {
|
||||
throw new VerificationError('Timestamp too far into the future');
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.checkTransactions = function checkTransactions(txs) {
|
||||
Block.prototype.checkTransactions = function checkTransactions(txs) {
|
||||
if (!Array.isArray(txs) || txs.length <= 0) {
|
||||
throw new VerificationError('No transactions');
|
||||
}
|
||||
|
@ -141,15 +140,15 @@ function spec(b) {
|
|||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Build merkle tree.
|
||||
*
|
||||
* Ported from Java. Original code: BitcoinJ by Mike Hearn
|
||||
* Copyright (c) 2011 Google Inc.
|
||||
*/
|
||||
Block.prototype.getMerkleTree = function getMerkleTree(txs) {
|
||||
Block.prototype.getMerkleTree = function getMerkleTree(txs) {
|
||||
// The merkle hash is based on a tree of hashes calculated from the transactions:
|
||||
//
|
||||
// merkleHash
|
||||
|
@ -188,14 +187,14 @@ function spec(b) {
|
|||
}
|
||||
|
||||
return tree;
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.calcMerkleRoot = function calcMerkleRoot(txs) {
|
||||
Block.prototype.calcMerkleRoot = function calcMerkleRoot(txs) {
|
||||
var tree = this.getMerkleTree(txs);
|
||||
return tree[tree.length - 1];
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.checkMerkleRoot = function checkMerkleRoot(txs) {
|
||||
Block.prototype.checkMerkleRoot = function checkMerkleRoot(txs) {
|
||||
if (!this.merkle_root || !this.merkle_root.length) {
|
||||
throw new VerificationError('No merkle root');
|
||||
}
|
||||
|
@ -205,9 +204,9 @@ function spec(b) {
|
|||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.checkBlock = function checkBlock(txs) {
|
||||
Block.prototype.checkBlock = function checkBlock(txs) {
|
||||
if (!this.checkHash()) {
|
||||
throw new VerificationError("Block hash invalid");
|
||||
}
|
||||
|
@ -221,31 +220,31 @@ function spec(b) {
|
|||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
Block.getBlockValue = function getBlockValue(height) {
|
||||
Block.getBlockValue = function getBlockValue(height) {
|
||||
var subsidy = Bignum(50).mul(util.COIN);
|
||||
subsidy = subsidy.div(Bignum(2).pow(Math.floor(height / 210000)));
|
||||
return subsidy;
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.getBlockValue = function getBlockValue() {
|
||||
Block.prototype.getBlockValue = function getBlockValue() {
|
||||
return Block.getBlockValue(this.height);
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.toString = function toString() {
|
||||
Block.prototype.toString = function toString() {
|
||||
return "<Block " + util.formatHashAlt(this.hash) + " height="+this.height+">";
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Initializes some properties based on information from the parent block.
|
||||
*/
|
||||
Block.prototype.attachTo = function attachTo(parent) {
|
||||
Block.prototype.attachTo = function attachTo(parent) {
|
||||
this.height = parent.height + 1;
|
||||
this.setChainWork(parent.getChainWork().add(this.getWork()));
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.setChainWork = function setChainWork(chainWork) {
|
||||
Block.prototype.setChainWork = function setChainWork(chainWork) {
|
||||
if (Buffer.isBuffer(chainWork)) {
|
||||
// Nothing to do
|
||||
} else if ("function" === typeof chainWork.toBuffer) { // duck-typing bignum
|
||||
|
@ -255,24 +254,24 @@ function spec(b) {
|
|||
}
|
||||
|
||||
this.chainWork = chainWork;
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.getChainWork = function getChainWork() {
|
||||
Block.prototype.getChainWork = function getChainWork() {
|
||||
return Bignum.fromBuffer(this.chainWork);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Compares the chainWork of two blocks.
|
||||
*/
|
||||
Block.prototype.moreWorkThan = function moreWorkThan(otherBlock) {
|
||||
Block.prototype.moreWorkThan = function moreWorkThan(otherBlock) {
|
||||
return this.getChainWork().cmp(otherBlock.getChainWork()) > 0;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the difficulty target for the next block after this one.
|
||||
*/
|
||||
Block.prototype.getNextWork =
|
||||
function getNextWork(blockChain, nextBlock, callback) {
|
||||
Block.prototype.getNextWork =
|
||||
function getNextWork(blockChain, nextBlock, callback) {
|
||||
var self = this;
|
||||
|
||||
var powLimit = blockChain.getMinDiff();
|
||||
|
@ -371,13 +370,13 @@ function spec(b) {
|
|||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var medianTimeSpan = 11;
|
||||
var medianTimeSpan = 11;
|
||||
|
||||
Block.prototype.getMedianTimePast =
|
||||
function getMedianTimePast(blockChain, callback)
|
||||
{
|
||||
Block.prototype.getMedianTimePast =
|
||||
function getMedianTimePast(blockChain, callback)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
Step(
|
||||
|
@ -407,11 +406,11 @@ function spec(b) {
|
|||
},
|
||||
callback
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.verifyChild =
|
||||
function verifyChild(blockChain, child, callback)
|
||||
{
|
||||
Block.prototype.verifyChild =
|
||||
function verifyChild(blockChain, child, callback)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
Step(
|
||||
|
@ -444,11 +443,11 @@ function spec(b) {
|
|||
},
|
||||
callback
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.createCoinbaseTx =
|
||||
function createCoinbaseTx(beneficiary)
|
||||
{
|
||||
Block.prototype.createCoinbaseTx =
|
||||
function createCoinbaseTx(beneficiary)
|
||||
{
|
||||
var tx = new Transaction();
|
||||
tx.ins.push(new TransactionIn({
|
||||
s: util.EMPTY_BUFFER,
|
||||
|
@ -460,11 +459,11 @@ function spec(b) {
|
|||
s: Script.createPubKeyOut(beneficiary).getBuffer()
|
||||
}));
|
||||
return tx;
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.prepareNextBlock =
|
||||
function prepareNextBlock(blockChain, beneficiary, time, callback)
|
||||
{
|
||||
Block.prototype.prepareNextBlock =
|
||||
function prepareNextBlock(blockChain, beneficiary, time, callback)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
var newBlock = new Block();
|
||||
|
@ -512,11 +511,11 @@ function spec(b) {
|
|||
},
|
||||
callback
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.mineNextBlock =
|
||||
function mineNextBlock(blockChain, beneficiary, time, miner, callback)
|
||||
{
|
||||
Block.prototype.mineNextBlock =
|
||||
function mineNextBlock(blockChain, beneficiary, time, miner, callback)
|
||||
{
|
||||
this.prepareNextBlock(blockChain, beneficiary, time, function (err, data) {
|
||||
try {
|
||||
if (err) throw err;
|
||||
|
@ -539,20 +538,20 @@ function spec(b) {
|
|||
callback(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.solve = function solve(miner, callback) {
|
||||
Block.prototype.solve = function solve(miner, callback) {
|
||||
var header = this.getHeader();
|
||||
var target = util.decodeDiffBits(this.bits);
|
||||
miner.solve(header, target, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns an object with the same field names as jgarzik's getblock patch.
|
||||
*/
|
||||
Block.prototype.getStandardizedObject =
|
||||
function getStandardizedObject(txs)
|
||||
{
|
||||
Block.prototype.getStandardizedObject =
|
||||
function getStandardizedObject(txs)
|
||||
{
|
||||
var block = {
|
||||
hash: util.formatHashFull(this.getHash()),
|
||||
version: this.version,
|
||||
|
@ -587,8 +586,6 @@ function spec(b) {
|
|||
block.size = this.size;
|
||||
}
|
||||
return block;
|
||||
};
|
||||
|
||||
return Block;
|
||||
};
|
||||
module.defineClass(spec);
|
||||
|
||||
module.exports = require('soop')(Block);
|
||||
|
|
57
Bloom.js
57
Bloom.js
|
@ -1,31 +1,28 @@
|
|||
require('classtool');
|
||||
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
||||
var MAX_HASH_FUNCS = 50;
|
||||
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
|
||||
var LN2 = 0.6931471805599453094172321214581765680755001343602552;
|
||||
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80];
|
||||
|
||||
function ClassSpec(b) {
|
||||
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
||||
var MAX_HASH_FUNCS = 50;
|
||||
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
|
||||
var LN2 = 0.6931471805599453094172321214581765680755001343602552;
|
||||
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80];
|
||||
|
||||
function Bloom() {
|
||||
function Bloom() {
|
||||
this.data = '';
|
||||
this.hashFuncs = 0;
|
||||
};
|
||||
};
|
||||
|
||||
function ROTL32(x, r) {
|
||||
function ROTL32(x, r) {
|
||||
return (x << r) | (x >> (32 - r));
|
||||
};
|
||||
};
|
||||
|
||||
function getBlockU32(blockIdx, data) {
|
||||
function getBlockU32(blockIdx, data) {
|
||||
var idx = blockIdx * 4;
|
||||
var v = (data[idx + 0] << (0 * 8)) |
|
||||
(data[idx + 1] << (1 * 8)) |
|
||||
(data[idx + 2] << (2 * 8)) |
|
||||
(data[idx + 3] << (3 * 8));
|
||||
return v;
|
||||
};
|
||||
};
|
||||
|
||||
Bloom.prototype.hash = function(hashNum, data) {
|
||||
Bloom.prototype.hash = function(hashNum, data) {
|
||||
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1));
|
||||
var c1 = 0xcc9e2d51;
|
||||
var c2 = 0x1b873593;
|
||||
|
@ -68,16 +65,16 @@ function ClassSpec(b) {
|
|||
h1 ^= h1 >> 16;
|
||||
|
||||
return h1 % (this.data.length * 8);
|
||||
};
|
||||
};
|
||||
|
||||
Bloom.prototype.insert = function(data) {
|
||||
Bloom.prototype.insert = function(data) {
|
||||
for (var i = 0; i < this.hashFuncs; i++) {
|
||||
var index = this.hash(i, data);
|
||||
this.data[index >> 3] |= bit_mask[7 & index];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Bloom.prototype.contains = function(data) {
|
||||
Bloom.prototype.contains = function(data) {
|
||||
for (var i = 0; i < this.hashFuncs; i++) {
|
||||
var index = this.hash(i, data);
|
||||
if (!(this.data[index >> 3] & bit_mask[7 & index]))
|
||||
|
@ -85,32 +82,30 @@ function ClassSpec(b) {
|
|||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
Bloom.prototype.sizeOk = function() {
|
||||
Bloom.prototype.sizeOk = function() {
|
||||
return this.data.length <= MAX_BLOOM_FILTER_SIZE &&
|
||||
this.hashFuncs <= MAX_HASH_FUNCS;
|
||||
};
|
||||
};
|
||||
|
||||
function toInt(v) {
|
||||
function toInt(v) {
|
||||
return ~~v;
|
||||
}
|
||||
}
|
||||
|
||||
function min(a, b) {
|
||||
function min(a, b) {
|
||||
if (a < b)
|
||||
return a;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
Bloom.prototype.init = function(elements, FPRate) {
|
||||
Bloom.prototype.init = function(elements, FPRate) {
|
||||
var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)),
|
||||
MAX_BLOOM_FILTER_SIZE * 8) / 8;
|
||||
this.data[filterSize] = 0;
|
||||
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2),
|
||||
MAX_HASH_FUNCS);
|
||||
};
|
||||
|
||||
return Bloom;
|
||||
};
|
||||
module.defineClass(ClassSpec);
|
||||
|
||||
|
||||
module.exports = require('soop')(Bloom);
|
||||
|
|
129
Connection.js
129
Connection.js
|
@ -1,29 +1,28 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
|
||||
function spec(b) {
|
||||
var config = b.config || require('./config');
|
||||
var log = b.log || require('./util/log');
|
||||
var network = b.network || require('./networks')[config.network];
|
||||
var config = imports.config || require('./config');
|
||||
var log = imports.log || require('./util/log');
|
||||
var network = imports.network || require('./networks')[config.network];
|
||||
|
||||
var MAX_RECEIVE_BUFFER = 10000000;
|
||||
var PROTOCOL_VERSION = 70000;
|
||||
var MAX_RECEIVE_BUFFER = 10000000;
|
||||
var PROTOCOL_VERSION = 70000;
|
||||
|
||||
var Binary = b.Binary || require('binary');
|
||||
var Put = b.Put || require('bufferput');
|
||||
var Buffers = b.Buffers || require('buffers');
|
||||
require('./Buffers.monkey').patch(Buffers);
|
||||
var noop = function() {};
|
||||
var Block = require('./Block').class();
|
||||
var Transaction = require('./Transaction').class();
|
||||
var util = b.util || require('./util/util');
|
||||
var Parser = b.Parser || require('./util/BinaryParser').class();
|
||||
var buffertools = b.buffertools || require('buffertools');
|
||||
var doubleSha256 = b.doubleSha256 || util.twoSha256;
|
||||
var nonce = util.generateNonce();
|
||||
var Binary = imports.Binary || require('binary');
|
||||
var Put = imports.Put || require('bufferput');
|
||||
var Buffers = imports.Buffers || require('buffers');
|
||||
require('./Buffers.monkey').patch(Buffers);
|
||||
|
||||
var BIP0031_VERSION = 60000;
|
||||
var Block = require('./Block');
|
||||
var Transaction = require('./Transaction');
|
||||
var util = imports.util || require('./util/util');
|
||||
var Parser = imports.Parser || require('./util/BinaryParser');
|
||||
var buffertools = imports.buffertools || require('buffertools');
|
||||
var doubleSha256 = imports.doubleSha256 || util.twoSha256;
|
||||
var nonce = util.generateNonce();
|
||||
|
||||
function Connection(socket, peer) {
|
||||
var BIP0031_VERSION = 60000;
|
||||
|
||||
function Connection(socket, peer) {
|
||||
Connection.super(this, arguments);
|
||||
this.socket = socket;
|
||||
this.peer = peer;
|
||||
|
@ -52,10 +51,10 @@ function spec(b) {
|
|||
}
|
||||
|
||||
this.setupHandlers();
|
||||
}
|
||||
Connection.superclass = b.superclass || require('events').EventEmitter;
|
||||
}
|
||||
Connection.parent = imports.parent || require('events').EventEmitter;
|
||||
|
||||
Connection.prototype.setupHandlers = function () {
|
||||
Connection.prototype.setupHandlers = function () {
|
||||
this.socket.addListener('connect', this.handleConnect.bind(this));
|
||||
this.socket.addListener('error', this.handleError.bind(this));
|
||||
this.socket.addListener('end', this.handleDisconnect.bind(this));
|
||||
|
@ -68,9 +67,9 @@ function spec(b) {
|
|||
(data.length > dumpLen ? '...' : ''));
|
||||
}).bind(this));
|
||||
this.socket.addListener('data', this.handleData.bind(this));
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.handleConnect = function () {
|
||||
Connection.prototype.handleConnect = function () {
|
||||
if (!this.inbound) {
|
||||
this.sendVersion();
|
||||
}
|
||||
|
@ -79,9 +78,9 @@ function spec(b) {
|
|||
socket: this.socket,
|
||||
peer: this.peer
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.handleError = function(err) {
|
||||
Connection.prototype.handleError = function(err) {
|
||||
if (err.errno == 110 || err.errno == 'ETIMEDOUT') {
|
||||
log.info('connection timed out for '+this.peer);
|
||||
} else if (err.errno == 111 || err.errno == 'ECONNREFUSED') {
|
||||
|
@ -95,17 +94,17 @@ function spec(b) {
|
|||
peer: this.peer,
|
||||
err: err
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.handleDisconnect = function () {
|
||||
Connection.prototype.handleDisconnect = function () {
|
||||
this.emit('disconnect', {
|
||||
conn: this,
|
||||
socket: this.socket,
|
||||
peer: this.peer
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.handleMessage = function(message) {
|
||||
Connection.prototype.handleMessage = function(message) {
|
||||
if (!message) {
|
||||
// Parser was unable to make sense of the message, drop it
|
||||
return;
|
||||
|
@ -163,13 +162,13 @@ function spec(b) {
|
|||
peer: this.peer,
|
||||
message: message
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.sendPong = function (nonce) {
|
||||
Connection.prototype.sendPong = function (nonce) {
|
||||
this.sendMessage('pong', nonce);
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.sendVersion = function () {
|
||||
Connection.prototype.sendVersion = function () {
|
||||
var subversion = '/BitcoinX:0.1/';
|
||||
|
||||
var put = new Put();
|
||||
|
@ -184,9 +183,9 @@ function spec(b) {
|
|||
put.word32le(0);
|
||||
|
||||
this.sendMessage('version', put.buffer());
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.sendGetBlocks = function (starts, stop, wantHeaders) {
|
||||
Connection.prototype.sendGetBlocks = function (starts, stop, wantHeaders) {
|
||||
var put = new Put();
|
||||
put.word32le(this.sendVer);
|
||||
|
||||
|
@ -210,13 +209,13 @@ function spec(b) {
|
|||
if (wantHeaders)
|
||||
command = 'getheaders';
|
||||
this.sendMessage(command, put.buffer());
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.sendGetHeaders = function(starts, stop) {
|
||||
Connection.prototype.sendGetHeaders = function(starts, stop) {
|
||||
this.sendGetBlocks(starts, stop, true);
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.sendGetData = function (invs) {
|
||||
Connection.prototype.sendGetData = function (invs) {
|
||||
var put = new Put();
|
||||
put.varint(invs.length);
|
||||
for (var i = 0; i < invs.length; i++) {
|
||||
|
@ -224,14 +223,14 @@ function spec(b) {
|
|||
put.put(invs[i].hash);
|
||||
}
|
||||
this.sendMessage('getdata', put.buffer());
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.sendGetAddr = function (invs) {
|
||||
Connection.prototype.sendGetAddr = function (invs) {
|
||||
var put = new Put();
|
||||
this.sendMessage('getaddr', put.buffer());
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.sendInv = function(data) {
|
||||
Connection.prototype.sendInv = function(data) {
|
||||
if(!Array.isArray(data)) data = [data];
|
||||
var put = new Put();
|
||||
put.varint(data.length);
|
||||
|
@ -246,9 +245,9 @@ function spec(b) {
|
|||
put.put(value.getHash());
|
||||
});
|
||||
this.sendMessage('inv', put.buffer());
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.sendHeaders = function (headers) {
|
||||
Connection.prototype.sendHeaders = function (headers) {
|
||||
var put = new Put();
|
||||
put.varint(headers.length);
|
||||
headers.forEach(function (header) {
|
||||
|
@ -258,13 +257,13 @@ function spec(b) {
|
|||
put.word8(0);
|
||||
});
|
||||
this.sendMessage('headers', put.buffer());
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.sendTx = function (tx) {
|
||||
Connection.prototype.sendTx = function (tx) {
|
||||
this.sendMessage('tx', tx.serialize());
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.sendBlock = function (block, txs) {
|
||||
Connection.prototype.sendBlock = function (block, txs) {
|
||||
var put = new Put();
|
||||
|
||||
// Block header
|
||||
|
@ -277,9 +276,9 @@ function spec(b) {
|
|||
});
|
||||
|
||||
this.sendMessage('block', put.buffer());
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.sendMessage = function (command, payload) {
|
||||
Connection.prototype.sendMessage = function (command, payload) {
|
||||
try {
|
||||
var magic = network.magic;
|
||||
var commandBuf = new Buffer(command, 'ascii');
|
||||
|
@ -313,9 +312,9 @@ function spec(b) {
|
|||
log.err("Error while sending message to peer "+this.peer+": "+
|
||||
(err.stack ? err.stack : err.toString()));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.handleData = function (data) {
|
||||
Connection.prototype.handleData = function (data) {
|
||||
this.buffers.push(data);
|
||||
|
||||
if (this.buffers.length > MAX_RECEIVE_BUFFER) {
|
||||
|
@ -326,9 +325,9 @@ function spec(b) {
|
|||
}
|
||||
|
||||
this.processData();
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.processData = function () {
|
||||
Connection.prototype.processData = function () {
|
||||
// If there are less than 20 bytes there can't be a message yet.
|
||||
if (this.buffers.length < 20) return;
|
||||
|
||||
|
@ -402,9 +401,9 @@ function spec(b) {
|
|||
|
||||
this.buffers.skip(endPos);
|
||||
this.processData();
|
||||
};
|
||||
};
|
||||
|
||||
Connection.prototype.parseMessage = function (command, payload) {
|
||||
Connection.prototype.parseMessage = function (command, payload) {
|
||||
var parser = new Parser(payload);
|
||||
|
||||
var data = {
|
||||
|
@ -444,8 +443,8 @@ function spec(b) {
|
|||
data.headers = [];
|
||||
for (i = 0; i < data.count; i++) {
|
||||
var header = new Block();
|
||||
header.parse(parser);
|
||||
data.headers.push(header);
|
||||
header.parse(parser);
|
||||
data.headers.push(header);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -540,8 +539,6 @@ function spec(b) {
|
|||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
return Connection;
|
||||
};
|
||||
module.defineClass(spec);
|
||||
|
||||
module.exports = require('soop')(Connection);
|
||||
|
|
25
Opcode.js
25
Opcode.js
|
@ -1,15 +1,14 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
|
||||
function spec(b) {
|
||||
function Opcode(num) {
|
||||
function Opcode(num) {
|
||||
this.code = num;
|
||||
};
|
||||
};
|
||||
|
||||
Opcode.prototype.toString = function () {
|
||||
Opcode.prototype.toString = function () {
|
||||
return Opcode.reverseMap[this.code];
|
||||
};
|
||||
};
|
||||
|
||||
Opcode.map = {
|
||||
Opcode.map = {
|
||||
// push value
|
||||
OP_FALSE : 0,
|
||||
OP_0 : 0,
|
||||
|
@ -146,16 +145,14 @@ function spec(b) {
|
|||
OP_PUBKEYHASH : 253,
|
||||
OP_PUBKEY : 254,
|
||||
OP_INVALIDOPCODE : 255
|
||||
};
|
||||
};
|
||||
|
||||
Opcode.reverseMap = [];
|
||||
Opcode.reverseMap = [];
|
||||
|
||||
for (var k in Opcode.map) {
|
||||
for (var k in Opcode.map) {
|
||||
if(Opcode.map.hasOwnProperty(k)) {
|
||||
Opcode.reverseMap[Opcode.map[k]] = k.substr(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Opcode;
|
||||
};
|
||||
module.defineClass(spec);
|
||||
module.exports = require('soop')(Opcode);
|
||||
|
|
35
Peer.js
35
Peer.js
|
@ -1,11 +1,10 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
|
||||
function spec(b) {
|
||||
var Net = b.Net || require('net');
|
||||
var Binary = b.Binary || require('binary');
|
||||
var buffertools = b.buffertools || require('buffertools');
|
||||
var Net = imports.Net || require('net');
|
||||
var Binary = imports.Binary || require('binary');
|
||||
var buffertools = imports.buffertools || require('buffertools');
|
||||
|
||||
function Peer(host, port, services) {
|
||||
function Peer(host, port, services) {
|
||||
if ("string" === typeof host) {
|
||||
if (host.indexOf(':') && !port) {
|
||||
var parts = host.split(':');
|
||||
|
@ -30,32 +29,30 @@ function spec(b) {
|
|||
|
||||
this.services = (services) ? services : null;
|
||||
this.lastSeen = 0;
|
||||
};
|
||||
};
|
||||
|
||||
Peer.IPV6_IPV4_PADDING = new Buffer([0,0,0,0,0,0,0,0,0,0,255,255]);
|
||||
Peer.IPV6_IPV4_PADDING = new Buffer([0,0,0,0,0,0,0,0,0,0,255,255]);
|
||||
|
||||
Peer.prototype.createConnection = function () {
|
||||
Peer.prototype.createConnection = function () {
|
||||
var c = Net.createConnection(this.port, this.host);
|
||||
return c;
|
||||
};
|
||||
};
|
||||
|
||||
Peer.prototype.getHostAsBuffer = function () {
|
||||
Peer.prototype.getHostAsBuffer = function () {
|
||||
return new Buffer(this.host.split('.'));
|
||||
};
|
||||
};
|
||||
|
||||
Peer.prototype.toString = function () {
|
||||
Peer.prototype.toString = function () {
|
||||
return this.host + ":" + this.port;
|
||||
};
|
||||
};
|
||||
|
||||
Peer.prototype.toBuffer = function () {
|
||||
Peer.prototype.toBuffer = function () {
|
||||
var put = Binary.put();
|
||||
put.word32le(this.lastSeen);
|
||||
put.word64le(this.services);
|
||||
put.put(this.getHostAsBuffer());
|
||||
put.word16be(this.port);
|
||||
return put.buffer();
|
||||
};
|
||||
|
||||
return Peer;
|
||||
};
|
||||
module.defineClass(spec);
|
||||
|
||||
module.exports = require('soop')(Peer);
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
require('classtool');
|
||||
|
||||
function spec(b) {
|
||||
var config = b.config || require('./config');
|
||||
var log = b.log || require('./util/log');
|
||||
var network = b.network || require('./networks')[config.network];
|
||||
var Connection = b.Connection || require('./Connection').createClass(
|
||||
{config: config, network: network});
|
||||
var Peer = b.Peer || require('./Peer').class();
|
||||
var noop = function() {};
|
||||
var imports = require('soop').imports();
|
||||
var config = imports.config || require('./config');
|
||||
var log = imports.log || require('./util/log');
|
||||
var network = imports.network || require('./networks')[config.network];
|
||||
var Connection = imports.Connection ||
|
||||
require('soop').load('./Connection', {config: config, network: network});
|
||||
|
||||
GetAdjustedTime = b.GetAdjustedTime || function () {
|
||||
var Peer = imports.Peer || require('./Peer');
|
||||
|
||||
GetAdjustedTime = imports.GetAdjustedTime || function () {
|
||||
// TODO: Implement actual adjustment
|
||||
return Math.floor(new Date().getTime() / 1000);
|
||||
};
|
||||
};
|
||||
|
||||
function PeerManager() {
|
||||
function PeerManager() {
|
||||
this.active = false;
|
||||
this.timer = null;
|
||||
|
||||
|
@ -27,19 +26,19 @@ function spec(b) {
|
|||
this.interval = 5000;
|
||||
this.minConnections = 8;
|
||||
this.minKnownPeers = 10;
|
||||
};
|
||||
PeerManager.superclass = b.superclass || require('events').EventEmitter;
|
||||
};
|
||||
|
||||
PeerManager.Connection = Connection;
|
||||
PeerManager.parent = imports.parent || require('events').EventEmitter;
|
||||
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);
|
||||
|
@ -48,9 +47,9 @@ function spec(b) {
|
|||
for(var i=0; i<this.connections.length; i++) {
|
||||
this.connections[i].socket.end();
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
PeerManager.prototype.addPeer = function(peer, port) {
|
||||
PeerManager.prototype.addPeer = function(peer, port) {
|
||||
if(peer instanceof Peer) {
|
||||
this.peers.push(peer);
|
||||
} else if ("string" == typeof peer) {
|
||||
|
@ -60,9 +59,9 @@ function spec(b) {
|
|||
{val: peer});
|
||||
throw 'Node.addPeer(): Invalid value provided for peer.';
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
PeerManager.prototype.checkStatus = function checkStatus() {
|
||||
PeerManager.prototype.checkStatus = function checkStatus() {
|
||||
// Make sure we are connected to all forcePeers
|
||||
if(this.peers.length) {
|
||||
var peerIndex = {};
|
||||
|
@ -82,9 +81,9 @@ function spec(b) {
|
|||
this.connectTo(peerIndex[i]);
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
PeerManager.prototype.connectTo = function(peer) {
|
||||
PeerManager.prototype.connectTo = function(peer) {
|
||||
log.info('connecting to '+peer);
|
||||
try {
|
||||
return this.addConnection(peer.createConnection(), peer);
|
||||
|
@ -92,9 +91,9 @@ function spec(b) {
|
|||
log.err('creating connection',e);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
PeerManager.prototype.addConnection = function(socketConn, peer) {
|
||||
PeerManager.prototype.addConnection = function(socketConn, peer) {
|
||||
var conn = new Connection(socketConn, peer);
|
||||
this.connections.push(conn);
|
||||
this.emit('connection', conn);
|
||||
|
@ -107,9 +106,9 @@ function spec(b) {
|
|||
conn.addListener('disconnect', this.handleDisconnect.bind(this));
|
||||
|
||||
return conn;
|
||||
};
|
||||
};
|
||||
|
||||
PeerManager.prototype.handleVersion = function(e) {
|
||||
PeerManager.prototype.handleVersion = function(e) {
|
||||
if (!e.conn.inbound) {
|
||||
// TODO: Advertise our address (if listening)
|
||||
}
|
||||
|
@ -119,9 +118,9 @@ function spec(b) {
|
|||
e.conn.sendGetAddr();
|
||||
e.conn.getaddr = true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
PeerManager.prototype.handleReady = function (e) {
|
||||
PeerManager.prototype.handleReady = function (e) {
|
||||
log.info('connected to '+e.conn.peer.host+':'+e.conn.peer.port);
|
||||
this.emit('connect', {
|
||||
pm: this,
|
||||
|
@ -134,9 +133,9 @@ function spec(b) {
|
|||
this.emit('netConnected');
|
||||
this.isConnected = true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
PeerManager.prototype.handleAddr = function (e) {
|
||||
PeerManager.prototype.handleAddr = function (e) {
|
||||
if(!this.peerDiscovery) return;
|
||||
|
||||
var now = GetAdjustedTime();
|
||||
|
@ -160,18 +159,18 @@ function spec(b) {
|
|||
if (e.message.addrs.length < 1000 ) {
|
||||
e.conn.getaddr = false;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
PeerManager.prototype.handleGetAddr = function(e) {
|
||||
PeerManager.prototype.handleGetAddr = function(e) {
|
||||
// TODO: Reply with addr message.
|
||||
};
|
||||
};
|
||||
|
||||
PeerManager.prototype.handleError = function(e) {
|
||||
PeerManager.prototype.handleError = function(e) {
|
||||
log.err('unkown error with peer '+e.peer+' (disconnecting): '+e.err);
|
||||
this.handleDisconnect.apply(this, [].slice.call(arguments));
|
||||
};
|
||||
};
|
||||
|
||||
PeerManager.prototype.handleDisconnect = function(e) {
|
||||
PeerManager.prototype.handleDisconnect = function(e) {
|
||||
log.info('disconnected from peer '+e.peer);
|
||||
var i = this.connections.indexOf(e.conn);
|
||||
if(i != -1) this.connections.splice(i, 1);
|
||||
|
@ -180,9 +179,9 @@ function spec(b) {
|
|||
this.emit('netDisconnected');
|
||||
this.isConnected = false;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
PeerManager.prototype.getActiveConnection = function () {
|
||||
PeerManager.prototype.getActiveConnection = function () {
|
||||
var activeConnections = this.connections.filter(function (conn) {
|
||||
return conn.active;
|
||||
});
|
||||
|
@ -204,12 +203,10 @@ function spec(b) {
|
|||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
PeerManager.prototype.getActiveConnections = function () {
|
||||
return this.connections.slice(0);
|
||||
};
|
||||
|
||||
return PeerManager;
|
||||
};
|
||||
module.defineClass(spec);
|
||||
|
||||
PeerManager.prototype.getActiveConnections = function () {
|
||||
return this.connections.slice(0);
|
||||
};
|
||||
|
||||
module.exports = require('soop')(PeerManager);
|
||||
|
|
|
@ -1,29 +1,28 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
|
||||
function ClassSpec(b) {
|
||||
var superclass = b.superclass || require('./util/VersionedData').class();
|
||||
var parent = imports.parent || require('./util/VersionedData');
|
||||
|
||||
//compressed is true if public key is compressed; false otherwise
|
||||
function PrivateKey(version, buf, compressed) {
|
||||
//compressed is true if public key is compressed; false otherwise
|
||||
function PrivateKey(version, buf, compressed) {
|
||||
PrivateKey.super(this, arguments);
|
||||
if (compressed !== undefined)
|
||||
this.compressed(compressed);
|
||||
};
|
||||
};
|
||||
|
||||
PrivateKey.superclass = superclass;
|
||||
superclass.applyEncodingsTo(PrivateKey);
|
||||
PrivateKey.parent = parent;
|
||||
parent.applyEncodingsTo(PrivateKey);
|
||||
|
||||
PrivateKey.prototype.validate = function() {
|
||||
PrivateKey.prototype.validate = function() {
|
||||
this.doAsBinary(function() {
|
||||
PrivateKey.super(this, 'validate', arguments);
|
||||
if (this.data.length < 32 || (this.data.length > 1+32 && !this.compressed()) || (this.data.length==1+32+1 && this.data[1+32+1-1]!=1) || this.data.length>1+32+1)
|
||||
throw new Error('invalid data length');
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
// get or set the payload data (as a Buffer object)
|
||||
// overloaded from VersionedData
|
||||
PrivateKey.prototype.payload = function(data) {
|
||||
// get or set the payload data (as a Buffer object)
|
||||
// overloaded from VersionedData
|
||||
PrivateKey.prototype.payload = function(data) {
|
||||
if(data) {
|
||||
this.doAsBinary(function() {data.copy(this.data,1);});
|
||||
return data;
|
||||
|
@ -33,10 +32,10 @@ function ClassSpec(b) {
|
|||
return buf.slice(1,1+32);
|
||||
else if (buf.length==1+32)
|
||||
return buf.slice(1);
|
||||
};
|
||||
};
|
||||
|
||||
// get or set whether the corresponding public key is compressed
|
||||
PrivateKey.prototype.compressed = function(compressed) {
|
||||
// get or set whether the corresponding public key is compressed
|
||||
PrivateKey.prototype.compressed = function(compressed) {
|
||||
if (compressed !== undefined) {
|
||||
this.doAsBinary(function(){
|
||||
var len=1+32+1;
|
||||
|
@ -60,8 +59,6 @@ function ClassSpec(b) {
|
|||
else
|
||||
throw new Error('invalid private key');
|
||||
}
|
||||
};
|
||||
|
||||
return PrivateKey;
|
||||
};
|
||||
module.defineClass(ClassSpec);
|
||||
|
||||
module.exports = require('soop')(PrivateKey);
|
||||
|
|
42
RpcClient.js
42
RpcClient.js
|
@ -1,14 +1,13 @@
|
|||
// RpcClient.js
|
||||
// MIT/X11-like license. See LICENSE.txt.
|
||||
// Copyright 2013 BitPay, Inc.
|
||||
require('classtool');
|
||||
//
|
||||
var imports = require('soop').imports();
|
||||
var http = imports.http || require('http');
|
||||
var https = imports.https || require('https');
|
||||
var log = imports.log || require('./util/log');
|
||||
|
||||
function ClassSpec(b) {
|
||||
var http = b.http || require('http');
|
||||
var https = b.https || require('https');
|
||||
var log = b.log || require('./util/log');
|
||||
|
||||
function RpcClient(opts) {
|
||||
function RpcClient(opts) {
|
||||
opts = opts || {};
|
||||
this.host = opts.host || '127.0.0.1';
|
||||
this.port = opts.port || 8332;
|
||||
|
@ -17,16 +16,16 @@ function ClassSpec(b) {
|
|||
this.protocol = (opts.protocol == 'http') ? http : https;
|
||||
this.batchedCalls = null;
|
||||
this.disableAgent = opts.disableAgent || false;
|
||||
}
|
||||
}
|
||||
|
||||
RpcClient.prototype.batch = function(batchCallback, resultCallback) {
|
||||
RpcClient.prototype.batch = function(batchCallback, resultCallback) {
|
||||
this.batchedCalls = [];
|
||||
batchCallback();
|
||||
rpc.call(this, this.batchedCalls, resultCallback);
|
||||
this.batchedCalls = null;
|
||||
}
|
||||
}
|
||||
|
||||
var callspec = {
|
||||
var callspec = {
|
||||
addMultiSigAddress: '',
|
||||
addNode: '',
|
||||
backupWallet: '',
|
||||
|
@ -93,13 +92,13 @@ function ClassSpec(b) {
|
|||
walletLock: '',
|
||||
walletPassPhrase: 'string int',
|
||||
walletPassphraseChange: '',
|
||||
};
|
||||
};
|
||||
|
||||
var slice = function(arr, start, end) {
|
||||
var slice = function(arr, start, end) {
|
||||
return Array.prototype.slice.call(arr, start, end);
|
||||
};
|
||||
};
|
||||
|
||||
function generateRPCMethods(constructor, apiCalls, rpc) {
|
||||
function generateRPCMethods(constructor, apiCalls, rpc) {
|
||||
function createRPCMethod(methodName, argMap) {
|
||||
return function() {
|
||||
var limit = arguments.length - 1;
|
||||
|
@ -137,9 +136,9 @@ function ClassSpec(b) {
|
|||
constructor.prototype[methodName] = constructor.prototype[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function rpc(request, callback) {
|
||||
function rpc(request, callback) {
|
||||
var self = this;
|
||||
var request;
|
||||
request = JSON.stringify(request);
|
||||
|
@ -201,10 +200,9 @@ function ClassSpec(b) {
|
|||
req.setHeader('Authorization', 'Basic ' + auth);
|
||||
req.write(request);
|
||||
req.end();
|
||||
};
|
||||
|
||||
generateRPCMethods(RpcClient, callspec, rpc);
|
||||
return RpcClient;
|
||||
};
|
||||
module.defineClass(ClassSpec);
|
||||
|
||||
generateRPCMethods(RpcClient, callspec, rpc);
|
||||
|
||||
module.exports = require('soop')(RpcClient);
|
||||
|
||||
|
|
45
SIN.js
45
SIN.js
|
@ -1,10 +1,7 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
var parent = imports.parent || require('./util/VersionedData');
|
||||
|
||||
function ClassSpec(b) {
|
||||
var superclass = b.superclass || require('./util/VersionedData').class();
|
||||
|
||||
|
||||
function SIN(type, payload) {
|
||||
function SIN(type, payload) {
|
||||
if (typeof type != 'number') {
|
||||
SIN.super(this, arguments);
|
||||
return;
|
||||
|
@ -14,47 +11,45 @@ function ClassSpec(b) {
|
|||
this.prefix(0x0F); // SIN magic number, in numberspace
|
||||
this.type(type);
|
||||
this.payload(payload);
|
||||
};
|
||||
SIN.superclass = superclass;
|
||||
superclass.applyEncodingsTo(SIN);
|
||||
};
|
||||
SIN.parent = parent;
|
||||
parent.applyEncodingsTo(SIN);
|
||||
|
||||
SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX
|
||||
SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX
|
||||
SIN.SIN_EPHEM = 0x02; // generate off-net at any time
|
||||
SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX
|
||||
SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX
|
||||
SIN.SIN_EPHEM = 0x02; // generate off-net at any time
|
||||
|
||||
// get or set the prefix data (the first byte of the address)
|
||||
SIN.prototype.prefix = function(num) {
|
||||
// get or set the prefix data (the first byte of the address)
|
||||
SIN.prototype.prefix = function(num) {
|
||||
if(num || (num === 0)) {
|
||||
this.doAsBinary(function() {this.data.writeUInt8(num, 0);});
|
||||
return num;
|
||||
}
|
||||
return this.as('binary').readUInt8(0);
|
||||
};
|
||||
};
|
||||
|
||||
// get or set the SIN-type data (the second byte of the address)
|
||||
SIN.prototype.type = function(num) {
|
||||
// get or set the SIN-type data (the second byte of the address)
|
||||
SIN.prototype.type = function(num) {
|
||||
if(num || (num === 0)) {
|
||||
this.doAsBinary(function() {this.data.writeUInt8(num, 1);});
|
||||
return num;
|
||||
}
|
||||
return this.as('binary').readUInt8(1);
|
||||
};
|
||||
};
|
||||
|
||||
// get or set the payload data (as a Buffer object)
|
||||
SIN.prototype.payload = function(data) {
|
||||
// get or set the payload data (as a Buffer object)
|
||||
SIN.prototype.payload = function(data) {
|
||||
if(data) {
|
||||
this.doAsBinary(function() {data.copy(this.data, 2);});
|
||||
return data;
|
||||
}
|
||||
return this.as('binary').slice(1);
|
||||
};
|
||||
};
|
||||
|
||||
SIN.prototype.validate = function() {
|
||||
SIN.prototype.validate = function() {
|
||||
this.doAsBinary(function() {
|
||||
SIN.super(this, 'validate', arguments);
|
||||
if (this.data.length != 22) throw new Error('invalid data length');
|
||||
});
|
||||
};
|
||||
return SIN;
|
||||
};
|
||||
module.defineClass(ClassSpec);
|
||||
module.exports = require('soop')(SIN);
|
||||
|
|
30
SINKey.js
30
SINKey.js
|
@ -1,29 +1,26 @@
|
|||
require('classtool');
|
||||
var coinUtil = require('./util/util');
|
||||
var timeUtil = require('./util/time');
|
||||
var KeyModule = require('./Key');
|
||||
var SIN = require('./SIN');
|
||||
|
||||
function ClassSpec(b) {
|
||||
var coinUtil = require('./util/util');
|
||||
var timeUtil = require('./util/time');
|
||||
var KeyModule = require('./Key');
|
||||
var SIN = require('./SIN').class();
|
||||
|
||||
function SINKey(cfg) {
|
||||
function SINKey(cfg) {
|
||||
if (typeof cfg != 'object')
|
||||
cfg = {};
|
||||
|
||||
this.created = cfg.created;
|
||||
this.privKey = cfg.privKey;
|
||||
};
|
||||
};
|
||||
|
||||
SINKey.prototype.generate = function() {
|
||||
SINKey.prototype.generate = function() {
|
||||
this.privKey = KeyModule.Key.generateSync();
|
||||
this.created = timeUtil.curtime();
|
||||
};
|
||||
};
|
||||
|
||||
SINKey.prototype.pubkeyHash = function() {
|
||||
SINKey.prototype.pubkeyHash = function() {
|
||||
return coinUtil.sha256ripe160(this.privKey.public);
|
||||
};
|
||||
};
|
||||
|
||||
SINKey.prototype.storeObj = function() {
|
||||
SINKey.prototype.storeObj = function() {
|
||||
var pubKey = this.privKey.public.toString('hex');
|
||||
var pubKeyHash = this.pubkeyHash();
|
||||
var sin = new SIN(SIN.SIN_EPHEM, pubKeyHash);
|
||||
|
@ -35,9 +32,6 @@ function ClassSpec(b) {
|
|||
};
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
return SINKey;
|
||||
};
|
||||
module.defineClass(ClassSpec);
|
||||
|
||||
module.exports = require('soop')(SINKey);
|
||||
|
|
290
Script.js
290
Script.js
|
@ -1,36 +1,33 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
var config = imports.config || require('./config');
|
||||
var log = imports.log || require('./util/log');
|
||||
var Opcode = imports.Opcode || require('./Opcode');
|
||||
var buffertools = imports.buffertools || require('buffertools');
|
||||
|
||||
function spec(b) {
|
||||
var config = b.config || require('./config');
|
||||
var log = b.log || require('./util/log');
|
||||
// Make opcodes available as pseudo-constants
|
||||
for (var i in Opcode.map) {
|
||||
eval(i + ' = ' + Opcode.map[i] + ';');
|
||||
}
|
||||
|
||||
var Opcode = b.Opcode || require('./Opcode').class();
|
||||
var buffertools = b.buffertools || require('buffertools');
|
||||
var util = imports.util || require('./util/util');
|
||||
var Parser = imports.Parser || require('./util/BinaryParser');
|
||||
var Put = imports.Put || require('bufferput');
|
||||
|
||||
// Make opcodes available as pseudo-constants
|
||||
for (var i in Opcode.map) {
|
||||
eval(i + " = " + Opcode.map[i] + ";");
|
||||
}
|
||||
var TX_UNKNOWN = 0;
|
||||
var TX_PUBKEY = 1;
|
||||
var TX_PUBKEYHASH = 2;
|
||||
var TX_MULTISIG = 3;
|
||||
var TX_SCRIPTHASH = 4;
|
||||
|
||||
var util = b.util || require('./util/util');
|
||||
var Parser = b.Parser || require('./util/BinaryParser').class();
|
||||
var Put = b.Put || require('bufferput');
|
||||
|
||||
var TX_UNKNOWN = 0;
|
||||
var TX_PUBKEY = 1;
|
||||
var TX_PUBKEYHASH = 2;
|
||||
var TX_MULTISIG = 3;
|
||||
var TX_SCRIPTHASH = 4;
|
||||
|
||||
var TX_TYPES = [
|
||||
var TX_TYPES = [
|
||||
'unknown',
|
||||
'pubkey',
|
||||
'pubkeyhash',
|
||||
'multisig',
|
||||
'scripthash'
|
||||
];
|
||||
];
|
||||
|
||||
function Script(buffer) {
|
||||
function Script(buffer) {
|
||||
if(buffer) {
|
||||
this.buffer = buffer;
|
||||
} else {
|
||||
|
@ -38,16 +35,16 @@ function spec(b) {
|
|||
}
|
||||
this.chunks = [];
|
||||
this.parse();
|
||||
};
|
||||
this.class = Script;
|
||||
};
|
||||
this.class = Script;
|
||||
|
||||
Script.TX_UNKNOWN=TX_UNKNOWN;
|
||||
Script.TX_PUBKEY=TX_PUBKEY;
|
||||
Script.TX_PUBKEYHASH=TX_PUBKEYHASH;
|
||||
Script.TX_MULTISIG=TX_MULTISIG;
|
||||
Script.TX_SCRIPTHASH=TX_SCRIPTHASH;
|
||||
Script.TX_UNKNOWN=TX_UNKNOWN;
|
||||
Script.TX_PUBKEY=TX_PUBKEY;
|
||||
Script.TX_PUBKEYHASH=TX_PUBKEYHASH;
|
||||
Script.TX_MULTISIG=TX_MULTISIG;
|
||||
Script.TX_SCRIPTHASH=TX_SCRIPTHASH;
|
||||
|
||||
Script.prototype.parse = function () {
|
||||
Script.prototype.parse = function () {
|
||||
this.chunks = [];
|
||||
|
||||
var parser = new Parser(this.buffer);
|
||||
|
@ -71,35 +68,35 @@ function spec(b) {
|
|||
this.chunks.push(opcode);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.isPushOnly = function ()
|
||||
{
|
||||
Script.prototype.isPushOnly = function ()
|
||||
{
|
||||
for (var i = 0; i < this.chunks.length; i++)
|
||||
if (!Buffer.isBuffer(this.chunks[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.isP2SH = function ()
|
||||
{
|
||||
Script.prototype.isP2SH = function ()
|
||||
{
|
||||
return (this.chunks.length == 3 &&
|
||||
this.chunks[0] == OP_HASH160 &&
|
||||
Buffer.isBuffer(this.chunks[1]) &&
|
||||
this.chunks[1].length == 20 &&
|
||||
this.chunks[2] == OP_EQUAL);
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.isPubkey = function ()
|
||||
{
|
||||
Script.prototype.isPubkey = function ()
|
||||
{
|
||||
return (this.chunks.length == 2 &&
|
||||
Buffer.isBuffer(this.chunks[0]) &&
|
||||
this.chunks[1] == OP_CHECKSIG);
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.isPubkeyHash = function ()
|
||||
{
|
||||
Script.prototype.isPubkeyHash = function ()
|
||||
{
|
||||
return (this.chunks.length == 5 &&
|
||||
this.chunks[0] == OP_DUP &&
|
||||
this.chunks[1] == OP_HASH160 &&
|
||||
|
@ -107,24 +104,24 @@ function spec(b) {
|
|||
this.chunks[2].length == 20 &&
|
||||
this.chunks[3] == OP_EQUALVERIFY &&
|
||||
this.chunks[4] == OP_CHECKSIG);
|
||||
};
|
||||
};
|
||||
|
||||
function isSmallIntOp(opcode)
|
||||
{
|
||||
function isSmallIntOp(opcode)
|
||||
{
|
||||
return ((opcode == OP_0) ||
|
||||
((opcode >= OP_1) && (opcode <= OP_16)));
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.isMultiSig = function ()
|
||||
{
|
||||
Script.prototype.isMultiSig = function ()
|
||||
{
|
||||
return (this.chunks.length > 3 &&
|
||||
isSmallIntOp(this.chunks[0]) &&
|
||||
isSmallIntOp(this.chunks[this.chunks.length-2]) &&
|
||||
this.chunks[this.chunks.length-1] == OP_CHECKMULTISIG);
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.finishedMultiSig = function()
|
||||
{
|
||||
Script.prototype.finishedMultiSig = function()
|
||||
{
|
||||
var nsigs = 0;
|
||||
for (var i = 0; i < this.chunks.length-1; i++)
|
||||
if (this.chunks[i] !== 0)
|
||||
|
@ -138,10 +135,10 @@ function spec(b) {
|
|||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Script.prototype.removePlaceHolders = function()
|
||||
{
|
||||
Script.prototype.removePlaceHolders = function()
|
||||
{
|
||||
var chunks = [];
|
||||
for (var i in this.chunks)
|
||||
{
|
||||
|
@ -154,10 +151,10 @@ function spec(b) {
|
|||
this.chunks = chunks;
|
||||
this.updateBuffer();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
Script.prototype.prependOp0 = function()
|
||||
{
|
||||
Script.prototype.prependOp0 = function()
|
||||
{
|
||||
var chunks = [0];
|
||||
for (i in this.chunks) {
|
||||
if (this.chunks.hasOwnProperty(i)) {
|
||||
|
@ -167,74 +164,74 @@ function spec(b) {
|
|||
this.chunks = chunks;
|
||||
this.updateBuffer();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// is this a script form we know?
|
||||
Script.prototype.classify = function ()
|
||||
{
|
||||
// is this a script form we know?
|
||||
Script.prototype.classify = function ()
|
||||
{
|
||||
if (this.isPubkeyHash())
|
||||
return TX_PUBKEYHASH;
|
||||
if (this.isP2SH())
|
||||
if (this.isP2SH())
|
||||
return TX_SCRIPTHASH;
|
||||
if (this.isMultiSig())
|
||||
if (this.isMultiSig())
|
||||
return TX_MULTISIG;
|
||||
if (this.isPubkey())
|
||||
if (this.isPubkey())
|
||||
return TX_PUBKEY;
|
||||
return TX_UNKNOWN;
|
||||
};
|
||||
return TX_UNKNOWN;
|
||||
};
|
||||
|
||||
// extract useful data items from known scripts
|
||||
Script.prototype.capture = function ()
|
||||
{
|
||||
// extract useful data items from known scripts
|
||||
Script.prototype.capture = function ()
|
||||
{
|
||||
var txType = this.classify();
|
||||
var res = [];
|
||||
switch (txType) {
|
||||
case TX_PUBKEY:
|
||||
var res = [];
|
||||
switch (txType) {
|
||||
case TX_PUBKEY:
|
||||
res.push(this.chunks[0]);
|
||||
break;
|
||||
case TX_PUBKEYHASH:
|
||||
case TX_PUBKEYHASH:
|
||||
res.push(this.chunks[2]);
|
||||
break;
|
||||
case TX_MULTISIG:
|
||||
case TX_MULTISIG:
|
||||
for (var i = 1; i < (this.chunks.length - 2); i++)
|
||||
res.push(this.chunks[i]);
|
||||
break;
|
||||
case TX_SCRIPTHASH:
|
||||
case TX_SCRIPTHASH:
|
||||
res.push(this.chunks[1]);
|
||||
break;
|
||||
|
||||
case TX_UNKNOWN:
|
||||
default:
|
||||
case TX_UNKNOWN:
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
return res;
|
||||
};
|
||||
|
||||
// return first extracted data item from script
|
||||
Script.prototype.captureOne = function ()
|
||||
{
|
||||
// return first extracted data item from script
|
||||
Script.prototype.captureOne = function ()
|
||||
{
|
||||
var arr = this.capture();
|
||||
return arr[0];
|
||||
};
|
||||
return arr[0];
|
||||
};
|
||||
|
||||
Script.prototype.getOutType = function ()
|
||||
{
|
||||
Script.prototype.getOutType = function ()
|
||||
{
|
||||
var txType = this.classify();
|
||||
switch (txType) {
|
||||
case TX_PUBKEY: return 'Pubkey';
|
||||
case TX_PUBKEYHASH: return 'Address';
|
||||
default: return 'Strange';
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.getRawOutType = function() {
|
||||
Script.prototype.getRawOutType = function() {
|
||||
return TX_TYPES[this.classify()];
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.simpleOutHash = function ()
|
||||
{
|
||||
Script.prototype.simpleOutHash = function ()
|
||||
{
|
||||
switch (this.getOutType()) {
|
||||
case 'Address':
|
||||
return this.chunks[2];
|
||||
|
@ -245,10 +242,10 @@ function spec(b) {
|
|||
log.debug("Strange script was: " + this.toString());
|
||||
return null;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.getInType = function ()
|
||||
{
|
||||
Script.prototype.getInType = function ()
|
||||
{
|
||||
if (this.chunks.length == 1) {
|
||||
// Direct IP to IP transactions only have the public key in their scriptSig.
|
||||
return 'Pubkey';
|
||||
|
@ -259,10 +256,10 @@ function spec(b) {
|
|||
} else {
|
||||
return 'Strange';
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.simpleInPubKey = function ()
|
||||
{
|
||||
Script.prototype.simpleInPubKey = function ()
|
||||
{
|
||||
switch (this.getInType()) {
|
||||
case 'Address':
|
||||
return this.chunks[1];
|
||||
|
@ -273,15 +270,15 @@ function spec(b) {
|
|||
log.debug("Strange script was: " + this.toString());
|
||||
return null;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.getBuffer = function ()
|
||||
{
|
||||
Script.prototype.getBuffer = function ()
|
||||
{
|
||||
return this.buffer;
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.getStringContent = function (truncate, maxEl)
|
||||
{
|
||||
Script.prototype.getStringContent = function (truncate, maxEl)
|
||||
{
|
||||
if (truncate === null) {
|
||||
truncate = true;
|
||||
}
|
||||
|
@ -310,19 +307,19 @@ function spec(b) {
|
|||
}
|
||||
}
|
||||
return script;
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.toString = function (truncate, maxEl)
|
||||
{
|
||||
Script.prototype.toString = function (truncate, maxEl)
|
||||
{
|
||||
var script = "<Script ";
|
||||
script += this.getStringContent(truncate, maxEl);
|
||||
script += ">";
|
||||
return script;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Script.prototype.writeOp = function (opcode)
|
||||
{
|
||||
Script.prototype.writeOp = function (opcode)
|
||||
{
|
||||
var buf = Buffer(this.buffer.length + 1);
|
||||
this.buffer.copy(buf);
|
||||
buf.writeUInt8(opcode, this.buffer.length);
|
||||
|
@ -330,10 +327,10 @@ function spec(b) {
|
|||
this.buffer = buf;
|
||||
|
||||
this.chunks.push(opcode);
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.writeN = function (n)
|
||||
{
|
||||
Script.prototype.writeN = function (n)
|
||||
{
|
||||
if (n < 0 || n > 16)
|
||||
throw new Error("writeN: out of range value " + n);
|
||||
|
||||
|
@ -341,10 +338,10 @@ function spec(b) {
|
|||
this.writeOp(OP_0);
|
||||
else
|
||||
this.writeOp(OP_1 + n - 1);
|
||||
};
|
||||
};
|
||||
|
||||
function prefixSize(data_length)
|
||||
{
|
||||
function prefixSize(data_length)
|
||||
{
|
||||
if (data_length < OP_PUSHDATA1) {
|
||||
return 1;
|
||||
} else if (data_length <= 0xff) {
|
||||
|
@ -354,9 +351,9 @@ function spec(b) {
|
|||
} else {
|
||||
return 1 + 4;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function encodeLen(data_length) {
|
||||
function encodeLen(data_length) {
|
||||
var buf = undefined;
|
||||
if (data_length < OP_PUSHDATA1) {
|
||||
buf = new Buffer(1);
|
||||
|
@ -382,22 +379,22 @@ function spec(b) {
|
|||
}
|
||||
|
||||
return buf;
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.writeBytes = function (data)
|
||||
{
|
||||
Script.prototype.writeBytes = function (data)
|
||||
{
|
||||
var newSize = this.buffer.length + prefixSize(data.length) + data.length;
|
||||
this.buffer = Buffer.concat([this.buffer, encodeLen(data.length), data]);
|
||||
this.chunks.push(data);
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.updateBuffer = function ()
|
||||
{
|
||||
Script.prototype.updateBuffer = function ()
|
||||
{
|
||||
this.buffer = Script.chunksToBuffer(this.chunks);
|
||||
};
|
||||
};
|
||||
|
||||
Script.prototype.findAndDelete = function (chunk)
|
||||
{
|
||||
Script.prototype.findAndDelete = function (chunk)
|
||||
{
|
||||
var dirty = false;
|
||||
if (Buffer.isBuffer(chunk)) {
|
||||
for (var i = 0, l = this.chunks.length; i < l; i++) {
|
||||
|
@ -420,25 +417,25 @@ function spec(b) {
|
|||
if (dirty) {
|
||||
this.updateBuffer();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Creates a simple OP_CHECKSIG with pubkey output script.
|
||||
*
|
||||
* These are used for coinbase transactions and at some point were used for
|
||||
* IP-based transactions as well.
|
||||
*/
|
||||
Script.createPubKeyOut = function (pubkey) {
|
||||
Script.createPubKeyOut = function (pubkey) {
|
||||
var script = new Script();
|
||||
script.writeBytes(pubkey);
|
||||
script.writeOp(OP_CHECKSIG);
|
||||
return script;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Creates a standard txout script.
|
||||
*/
|
||||
Script.createPubKeyHashOut = function (pubKeyHash) {
|
||||
Script.createPubKeyHashOut = function (pubKeyHash) {
|
||||
var script = new Script();
|
||||
script.writeOp(OP_DUP);
|
||||
script.writeOp(OP_HASH160);
|
||||
|
@ -446,9 +443,9 @@ function spec(b) {
|
|||
script.writeOp(OP_EQUALVERIFY);
|
||||
script.writeOp(OP_CHECKSIG);
|
||||
return script;
|
||||
};
|
||||
};
|
||||
|
||||
Script.createMultisig = function(n_required, keys) {
|
||||
Script.createMultisig = function(n_required, keys) {
|
||||
var script = new Script();
|
||||
script.writeN(n_required);
|
||||
keys.forEach(function(key) {
|
||||
|
@ -457,17 +454,17 @@ function spec(b) {
|
|||
script.writeN(keys.length);
|
||||
script.writeOp(OP_CHECKMULTISIG);
|
||||
return script;
|
||||
};
|
||||
};
|
||||
|
||||
Script.createP2SH = function(scriptHash) {
|
||||
Script.createP2SH = function(scriptHash) {
|
||||
var script = new Script();
|
||||
script.writeOp(OP_HASH160);
|
||||
script.writeBytes(scriptHash);
|
||||
script.writeOp(OP_EQUAL);
|
||||
return script;
|
||||
};
|
||||
};
|
||||
|
||||
Script.fromTestData = function (testData) {
|
||||
Script.fromTestData = function (testData) {
|
||||
testData = testData.map(function (chunk) {
|
||||
if ("string" === typeof chunk) {
|
||||
return new Buffer(chunk, 'hex');
|
||||
|
@ -480,16 +477,16 @@ function spec(b) {
|
|||
script.chunks = testData;
|
||||
script.updateBuffer();
|
||||
return script;
|
||||
};
|
||||
};
|
||||
|
||||
Script.fromChunks = function (chunks) {
|
||||
Script.fromChunks = function (chunks) {
|
||||
var script = new Script();
|
||||
script.chunks = chunks;
|
||||
script.updateBuffer();
|
||||
return script;
|
||||
};
|
||||
};
|
||||
|
||||
Script.chunksToBuffer = function (chunks) {
|
||||
Script.chunksToBuffer = function (chunks) {
|
||||
var buf = new Put();
|
||||
|
||||
for (var i = 0, l = chunks.length; i < l; i++) {
|
||||
|
@ -515,9 +512,6 @@ function spec(b) {
|
|||
}
|
||||
}
|
||||
return buf.buffer();
|
||||
};
|
||||
|
||||
return Script;
|
||||
};
|
||||
module.defineClass(spec);
|
||||
|
||||
module.exports = require('soop')(Script);
|
||||
|
|
|
@ -1,29 +1,27 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
|
||||
function spec(b) {
|
||||
var assert = require('assert');
|
||||
var config = b.config || require('./config');
|
||||
var log = b.log || require('./util/log');
|
||||
var assert = require('assert');
|
||||
var config = imports.config || require('./config');
|
||||
var log = imports.log || require('./util/log');
|
||||
var Opcode = imports.Opcode || require('./Opcode');
|
||||
var buffertools = imports.buffertools || require('buffertools');
|
||||
|
||||
var Opcode = b.Opcode || require('./Opcode').class();
|
||||
var buffertools = b.buffertools || require('buffertools');
|
||||
|
||||
// Make opcodes available as pseudo-constants
|
||||
for (var i in Opcode.map) {
|
||||
// Make opcodes available as pseudo-constants
|
||||
for (var i in Opcode.map) {
|
||||
eval(i + " = " + Opcode.map[i] + ";");
|
||||
}
|
||||
}
|
||||
|
||||
var bignum = b.bignum || require('bignum');
|
||||
var Util = b.Util || require('./util/util');
|
||||
var Script = require('./Script').class();
|
||||
var bignum = imports.bignum || require('bignum');
|
||||
var Util = imports.Util || require('./util/util');
|
||||
var Script = require('./Script');
|
||||
|
||||
function ScriptInterpreter() {
|
||||
function ScriptInterpreter() {
|
||||
this.stack = [];
|
||||
this.disableUnsafeOpcodes = true;
|
||||
};
|
||||
};
|
||||
|
||||
ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, callback)
|
||||
{
|
||||
ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, callback)
|
||||
{
|
||||
if ("function" !== typeof callback) {
|
||||
throw new Error("ScriptInterpreter.eval() requires a callback");
|
||||
}
|
||||
|
@ -726,11 +724,11 @@ function spec(b) {
|
|||
cb(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
ScriptInterpreter.prototype.evalTwo =
|
||||
function evalTwo(scriptSig, scriptPubkey, tx, n, hashType, callback)
|
||||
{
|
||||
ScriptInterpreter.prototype.evalTwo =
|
||||
function evalTwo(scriptSig, scriptPubkey, tx, n, hashType, callback)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
self.eval(scriptSig, tx, n, hashType, function (e) {
|
||||
|
@ -741,15 +739,15 @@ function spec(b) {
|
|||
|
||||
self.eval(scriptPubkey, tx, n, hashType, callback);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get the top element of the stack.
|
||||
*
|
||||
* Using the offset parameter this function can also access lower elements
|
||||
* from the stack.
|
||||
*/
|
||||
ScriptInterpreter.prototype.stackTop = function stackTop(offset) {
|
||||
ScriptInterpreter.prototype.stackTop = function stackTop(offset) {
|
||||
offset = +offset || 1;
|
||||
if (offset < 1) offset = 1;
|
||||
|
||||
|
@ -758,25 +756,25 @@ function spec(b) {
|
|||
}
|
||||
|
||||
return this.stack[this.stack.length-offset];
|
||||
};
|
||||
};
|
||||
|
||||
ScriptInterpreter.prototype.stackBack = function stackBack()
|
||||
{
|
||||
ScriptInterpreter.prototype.stackBack = function stackBack()
|
||||
{
|
||||
return this.stack[-1];
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Pop the top element off the stack and return it.
|
||||
*/
|
||||
ScriptInterpreter.prototype.stackPop = function stackPop() {
|
||||
ScriptInterpreter.prototype.stackPop = function stackPop() {
|
||||
if (this.stack.length < 1) {
|
||||
throw new Error('ScriptInterpreter.stackTop(): Stack underrun');
|
||||
}
|
||||
|
||||
return this.stack.pop();
|
||||
};
|
||||
};
|
||||
|
||||
ScriptInterpreter.prototype.stackSwap = function stackSwap(a, b) {
|
||||
ScriptInterpreter.prototype.stackSwap = function stackSwap(a, b) {
|
||||
if (this.stack.length < a || this.stack.length < b) {
|
||||
throw new Error('ScriptInterpreter.stackTop(): Stack underrun');
|
||||
}
|
||||
|
@ -787,15 +785,15 @@ function spec(b) {
|
|||
var tmp = s[l - a];
|
||||
s[l - a] = s[l - b];
|
||||
s[l - b] = tmp;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns a version of the stack with only primitive types.
|
||||
*
|
||||
* The return value is an array. Any single byte buffer is converted to an
|
||||
* integer. Any longer Buffer is converted to a hex string.
|
||||
*/
|
||||
ScriptInterpreter.prototype.getPrimitiveStack = function getPrimitiveStack() {
|
||||
ScriptInterpreter.prototype.getPrimitiveStack = function getPrimitiveStack() {
|
||||
return this.stack.map(function (entry) {
|
||||
if (entry.length > 2) {
|
||||
return buffertools.toHex(entry.slice(0));
|
||||
|
@ -807,9 +805,9 @@ function spec(b) {
|
|||
return buffertools.toHex(entry.slice(0));
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
var castBool = ScriptInterpreter.castBool = function castBool(v) {
|
||||
var castBool = ScriptInterpreter.castBool = function castBool(v) {
|
||||
for (var i = 0, l = v.length; i < l; i++) {
|
||||
if (v[i] != 0) {
|
||||
// Negative zero is still zero
|
||||
|
@ -820,11 +818,11 @@ function spec(b) {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
var castInt = ScriptInterpreter.castInt = function castInt(v) {
|
||||
};
|
||||
var castInt = ScriptInterpreter.castInt = function castInt(v) {
|
||||
return castBigint(v).toNumber();
|
||||
};
|
||||
var castBigint = ScriptInterpreter.castBigint = function castBigint(v) {
|
||||
};
|
||||
var castBigint = ScriptInterpreter.castBigint = function castBigint(v) {
|
||||
if (!v.length) {
|
||||
return bignum(0);
|
||||
}
|
||||
|
@ -844,8 +842,8 @@ function spec(b) {
|
|||
// Positive number
|
||||
return bignum.fromBuffer(w);
|
||||
}
|
||||
};
|
||||
var bigintToBuffer = ScriptInterpreter.bigintToBuffer = function bigintToBuffer(v) {
|
||||
};
|
||||
var bigintToBuffer = ScriptInterpreter.bigintToBuffer = function bigintToBuffer(v) {
|
||||
if ("number" === typeof v) {
|
||||
v = bignum(v);
|
||||
}
|
||||
|
@ -877,19 +875,19 @@ function spec(b) {
|
|||
return buffertools.reverse(b);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
ScriptInterpreter.prototype.getResult = function getResult() {
|
||||
ScriptInterpreter.prototype.getResult = function getResult() {
|
||||
if (this.stack.length === 0) {
|
||||
throw new Error("Empty stack after script evaluation");
|
||||
}
|
||||
|
||||
return castBool(this.stack[this.stack.length-1]);
|
||||
};
|
||||
};
|
||||
|
||||
ScriptInterpreter.verify =
|
||||
function verify(scriptSig, scriptPubKey, txTo, n, hashType, callback)
|
||||
{
|
||||
ScriptInterpreter.verify =
|
||||
function verify(scriptSig, scriptPubKey, txTo, n, hashType, callback)
|
||||
{
|
||||
if ("function" !== typeof callback) {
|
||||
throw new Error("ScriptInterpreter.verify() requires a callback");
|
||||
}
|
||||
|
@ -916,92 +914,92 @@ function spec(b) {
|
|||
});
|
||||
|
||||
return si;
|
||||
};
|
||||
};
|
||||
|
||||
function verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
|
||||
function verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
|
||||
hashType, opts, callback, si, siCopy)
|
||||
{
|
||||
if (siCopy.stack.length == 0) {
|
||||
{
|
||||
if (siCopy.stack.length == 0) {
|
||||
callback(null, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
callback(null, castBool(siCopy.stackBack()));
|
||||
}
|
||||
callback(null, castBool(siCopy.stackBack()));
|
||||
}
|
||||
|
||||
function verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
|
||||
function verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
|
||||
hashType, opts, callback, si, siCopy)
|
||||
{
|
||||
if (si.stack.length == 0) {
|
||||
{
|
||||
if (si.stack.length == 0) {
|
||||
callback(null, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (castBool(si.stackBack()) == false) {
|
||||
callback(null, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if not P2SH, we're done
|
||||
if (!opts.verifyP2SH || !scriptPubKey.isP2SH()) {
|
||||
// if not P2SH, we're done
|
||||
if (!opts.verifyP2SH || !scriptPubKey.isP2SH()) {
|
||||
callback(null, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!scriptSig.isPushOnly()) {
|
||||
if (!scriptSig.isPushOnly()) {
|
||||
callback(null, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
assert.notEqual(siCopy.length, 0);
|
||||
assert.notEqual(siCopy.length, 0);
|
||||
|
||||
var subscript = new Script(siCopy.stackPop());
|
||||
var subscript = new Script(siCopy.stackPop());
|
||||
|
||||
ok = true;
|
||||
siCopy.eval(subscript, txTo, nIn, hashType, function (err) {
|
||||
ok = true;
|
||||
siCopy.eval(subscript, txTo, nIn, hashType, function (err) {
|
||||
if (err)
|
||||
callback(err);
|
||||
else
|
||||
verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
|
||||
hashType, opts, callback, si, siCopy);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
|
||||
function verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
|
||||
hashType, opts, callback, si, siCopy)
|
||||
{
|
||||
if (opts.verifyP2SH) {
|
||||
{
|
||||
if (opts.verifyP2SH) {
|
||||
si.stack.forEach(function(item) {
|
||||
siCopy.stack.push(item);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
si.eval(scriptPubKey, txTo, nIn, hashType, function (err) {
|
||||
si.eval(scriptPubKey, txTo, nIn, hashType, function (err) {
|
||||
if (err)
|
||||
callback(err);
|
||||
else
|
||||
verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
|
||||
hashType, opts, callback, si, siCopy);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ScriptInterpreter.verifyFull =
|
||||
function verifyFull(scriptSig, scriptPubKey, txTo, nIn, hashType,
|
||||
ScriptInterpreter.verifyFull =
|
||||
function verifyFull(scriptSig, scriptPubKey, txTo, nIn, hashType,
|
||||
opts, callback)
|
||||
{
|
||||
{
|
||||
var si = new ScriptInterpreter();
|
||||
var siCopy = new ScriptInterpreter();
|
||||
|
||||
si.eval(scriptSig, txTo, nIn, hashType, function (err) {
|
||||
si.eval(scriptSig, txTo, nIn, hashType, function (err) {
|
||||
if (err)
|
||||
callback(err);
|
||||
else
|
||||
verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
|
||||
hashType, opts, callback, si, siCopy);
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
var checkSig = ScriptInterpreter.checkSig =
|
||||
function (sig, pubkey, scriptCode, tx, n, hashType, callback) {
|
||||
var checkSig = ScriptInterpreter.checkSig =
|
||||
function (sig, pubkey, scriptCode, tx, n, hashType, callback) {
|
||||
if (!sig.length) {
|
||||
callback(null, false);
|
||||
return;
|
||||
|
@ -1026,8 +1024,6 @@ function spec(b) {
|
|||
} catch (err) {
|
||||
callback(null, false);
|
||||
}
|
||||
};
|
||||
|
||||
return ScriptInterpreter;
|
||||
};
|
||||
module.defineClass(spec);
|
||||
|
||||
module.exports = require('soop')(ScriptInterpreter);
|
||||
|
|
212
Transaction.js
212
Transaction.js
|
@ -1,25 +1,23 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
|
||||
function spec(b) {
|
||||
var config = b.config || require('./config');
|
||||
var log = b.log || require('./util/log');
|
||||
var Address = b.Address || require('./Address').class();
|
||||
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 Parser = b.Parser || require('./util/BinaryParser').class();
|
||||
var Step = b.Step || require('step');
|
||||
var buffertools = b.buffertools || require('buffertools');
|
||||
var config = imports.config || require('./config');
|
||||
var log = imports.log || require('./util/log');
|
||||
var Address = imports.Address || require('./Address');
|
||||
var Script = imports.Script || require('./Script');
|
||||
var ScriptInterpreter = imports.ScriptInterpreter || require('./ScriptInterpreter');
|
||||
var util = imports.util || require('./util/util');
|
||||
var bignum = imports.bignum || require('bignum');
|
||||
var Put = imports.Put || require('bufferput');
|
||||
var Parser = imports.Parser || require('./util/BinaryParser');
|
||||
var Step = imports.Step || require('step');
|
||||
var buffertools = imports.buffertools || require('buffertools');
|
||||
var error = imports.error || require('./util/error');
|
||||
var VerificationError = error.VerificationError;
|
||||
var MissingSourceError = error.MissingSourceError;
|
||||
|
||||
var error = b.error || require('./util/error');
|
||||
var VerificationError = error.VerificationError;
|
||||
var MissingSourceError = error.MissingSourceError;
|
||||
var COINBASE_OP = Buffer.concat([util.NULL_HASH, new Buffer('FFFFFFFF', 'hex')]);
|
||||
|
||||
var COINBASE_OP = Buffer.concat([util.NULL_HASH, new Buffer('FFFFFFFF', 'hex')]);
|
||||
|
||||
function TransactionIn(data) {
|
||||
function TransactionIn(data) {
|
||||
if ("object" !== typeof data) {
|
||||
data = {};
|
||||
}
|
||||
|
@ -29,69 +27,69 @@ function spec(b) {
|
|||
this.s = Buffer.isBuffer(data.s) ? data.s :
|
||||
Buffer.isBuffer(data.script) ? data.script : util.EMPTY_BUFFER;
|
||||
this.q = data.q ? data.q : data.sequence;
|
||||
}
|
||||
}
|
||||
|
||||
TransactionIn.prototype.getScript = function getScript() {
|
||||
TransactionIn.prototype.getScript = function getScript() {
|
||||
return new Script(this.s);
|
||||
};
|
||||
};
|
||||
|
||||
TransactionIn.prototype.isCoinBase = function isCoinBase() {
|
||||
TransactionIn.prototype.isCoinBase = function isCoinBase() {
|
||||
return buffertools.compare(this.o, COINBASE_OP) === 0;
|
||||
};
|
||||
};
|
||||
|
||||
TransactionIn.prototype.serialize = function serialize() {
|
||||
TransactionIn.prototype.serialize = function serialize() {
|
||||
var slen = util.varIntBuf(this.s.length);
|
||||
var qbuf = new Buffer(4);
|
||||
qbuf.writeUInt32LE(this.q, 0);
|
||||
|
||||
return Buffer.concat([this.o, slen, this.s, qbuf]);
|
||||
};
|
||||
};
|
||||
|
||||
TransactionIn.prototype.getOutpointHash = function getOutpointHash() {
|
||||
TransactionIn.prototype.getOutpointHash = function getOutpointHash() {
|
||||
if ("undefined" !== typeof this.o.outHashCache) {
|
||||
return this.o.outHashCache;
|
||||
}
|
||||
|
||||
return this.o.outHashCache = this.o.slice(0, 32);
|
||||
};
|
||||
};
|
||||
|
||||
TransactionIn.prototype.getOutpointIndex = function getOutpointIndex() {
|
||||
TransactionIn.prototype.getOutpointIndex = function getOutpointIndex() {
|
||||
return (this.o[32] ) +
|
||||
(this.o[33] << 8) +
|
||||
(this.o[34] << 16) +
|
||||
(this.o[35] << 24);
|
||||
};
|
||||
};
|
||||
|
||||
TransactionIn.prototype.setOutpointIndex = function setOutpointIndex(n) {
|
||||
TransactionIn.prototype.setOutpointIndex = function setOutpointIndex(n) {
|
||||
this.o[32] = n & 0xff;
|
||||
this.o[33] = n >> 8 & 0xff;
|
||||
this.o[34] = n >> 16 & 0xff;
|
||||
this.o[35] = n >> 24 & 0xff;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
function TransactionOut(data) {
|
||||
function TransactionOut(data) {
|
||||
if ("object" !== typeof data) {
|
||||
data = {};
|
||||
}
|
||||
this.v = data.v ? data.v : data.value;
|
||||
this.s = data.s ? data.s : data.script;
|
||||
};
|
||||
};
|
||||
|
||||
TransactionOut.prototype.getValue = function getValue() {
|
||||
TransactionOut.prototype.getValue = function getValue() {
|
||||
return new Parser(this.v).word64lu();
|
||||
};
|
||||
};
|
||||
|
||||
TransactionOut.prototype.getScript = function getScript() {
|
||||
TransactionOut.prototype.getScript = function getScript() {
|
||||
return new Script(this.s);
|
||||
};
|
||||
};
|
||||
|
||||
TransactionOut.prototype.serialize = function serialize() {
|
||||
TransactionOut.prototype.serialize = function serialize() {
|
||||
var slen = util.varIntBuf(this.s.length);
|
||||
return Buffer.concat([this.v, slen, this.s]);
|
||||
};
|
||||
};
|
||||
|
||||
function Transaction(data) {
|
||||
function Transaction(data) {
|
||||
if ("object" !== typeof data) {
|
||||
data = {};
|
||||
}
|
||||
|
@ -112,16 +110,16 @@ function spec(b) {
|
|||
return txout;
|
||||
}) : [];
|
||||
if (data.buffer) this._buffer = data.buffer;
|
||||
};
|
||||
this.class = Transaction;
|
||||
Transaction.In = TransactionIn;
|
||||
Transaction.Out = TransactionOut;
|
||||
};
|
||||
this.class = Transaction;
|
||||
Transaction.In = TransactionIn;
|
||||
Transaction.Out = TransactionOut;
|
||||
|
||||
Transaction.prototype.isCoinBase = function () {
|
||||
Transaction.prototype.isCoinBase = function () {
|
||||
return this.ins.length == 1 && this.ins[0].isCoinBase();
|
||||
};
|
||||
};
|
||||
|
||||
Transaction.prototype.isStandard = function isStandard() {
|
||||
Transaction.prototype.isStandard = function isStandard() {
|
||||
var i;
|
||||
for (i = 0; i < this.ins.length; i++) {
|
||||
if (this.ins[i].getScript().getInType() == "Strange") {
|
||||
|
@ -134,9 +132,9 @@ function spec(b) {
|
|||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
Transaction.prototype.serialize = function serialize() {
|
||||
Transaction.prototype.serialize = function serialize() {
|
||||
var bufs = [];
|
||||
|
||||
var buf = new Buffer(4);
|
||||
|
@ -159,34 +157,34 @@ function spec(b) {
|
|||
|
||||
this._buffer = Buffer.concat(bufs);
|
||||
return this._buffer;
|
||||
};
|
||||
};
|
||||
|
||||
Transaction.prototype.getBuffer = function getBuffer() {
|
||||
Transaction.prototype.getBuffer = function getBuffer() {
|
||||
if (this._buffer) return this._buffer;
|
||||
|
||||
return this.serialize();
|
||||
};
|
||||
};
|
||||
|
||||
Transaction.prototype.calcHash = function calcHash() {
|
||||
Transaction.prototype.calcHash = function calcHash() {
|
||||
this.hash = util.twoSha256(this.getBuffer());
|
||||
return this.hash;
|
||||
};
|
||||
};
|
||||
|
||||
Transaction.prototype.checkHash = function checkHash() {
|
||||
Transaction.prototype.checkHash = function checkHash() {
|
||||
if (!this.hash || !this.hash.length) return false;
|
||||
|
||||
return buffertools.compare(this.calcHash(), this.hash) === 0;
|
||||
};
|
||||
};
|
||||
|
||||
Transaction.prototype.getHash = function getHash() {
|
||||
Transaction.prototype.getHash = function getHash() {
|
||||
if (!this.hash || !this.hash.length) {
|
||||
this.hash = this.calcHash();
|
||||
}
|
||||
return this.hash;
|
||||
};
|
||||
};
|
||||
|
||||
// convert encoded list of inputs to easy-to-use JS list-of-lists
|
||||
Transaction.prototype.inputs = function inputs() {
|
||||
// convert encoded list of inputs to easy-to-use JS list-of-lists
|
||||
Transaction.prototype.inputs = function inputs() {
|
||||
var res = [];
|
||||
for (var i = 0; i < this.ins.length; i++) {
|
||||
var txin = this.ins[i];
|
||||
|
@ -196,9 +194,9 @@ function spec(b) {
|
|||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Load and cache transaction inputs.
|
||||
*
|
||||
* This function will try to load the inputs for a transaction.
|
||||
|
@ -209,15 +207,15 @@ function spec(b) {
|
|||
* met (or a timeout occurs.)
|
||||
* @param {Function} callback Function to call on completion.
|
||||
*/
|
||||
Transaction.prototype.cacheInputs =
|
||||
function cacheInputs(blockChain, txStore, wait, callback) {
|
||||
Transaction.prototype.cacheInputs =
|
||||
function cacheInputs(blockChain, txStore, wait, callback) {
|
||||
var self = this;
|
||||
|
||||
var txCache = new TransactionInputsCache(this);
|
||||
txCache.buffer(blockChain, txStore, wait, callback);
|
||||
};
|
||||
};
|
||||
|
||||
Transaction.prototype.verify = function verify(txCache, blockChain, callback) {
|
||||
Transaction.prototype.verify = function verify(txCache, blockChain, callback) {
|
||||
var self = this;
|
||||
|
||||
var txIndex = txCache.txIndex;
|
||||
|
@ -341,22 +339,22 @@ function spec(b) {
|
|||
},
|
||||
callback
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
Transaction.prototype.verifyInput = function verifyInput(n, scriptPubKey, callback) {
|
||||
Transaction.prototype.verifyInput = function verifyInput(n, scriptPubKey, callback) {
|
||||
return ScriptInterpreter.verify(this.ins[n].getScript(),
|
||||
scriptPubKey,
|
||||
this, n, 0,
|
||||
callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns an object containing all pubkey hashes affected by this transaction.
|
||||
*
|
||||
* The return object contains the base64-encoded pubKeyHash values as keys
|
||||
* and the original pubKeyHash buffers as values.
|
||||
*/
|
||||
Transaction.prototype.getAffectedKeys = function getAffectedKeys(txCache) {
|
||||
Transaction.prototype.getAffectedKeys = function getAffectedKeys(txCache) {
|
||||
// TODO: Function won't consider results cached if there are no affected
|
||||
// accounts.
|
||||
if (!(this.affects && this.affects.length)) {
|
||||
|
@ -423,22 +421,22 @@ function spec(b) {
|
|||
});
|
||||
|
||||
return affectedKeys;
|
||||
};
|
||||
};
|
||||
|
||||
var OP_CODESEPARATOR = 171;
|
||||
var OP_CODESEPARATOR = 171;
|
||||
|
||||
var SIGHASH_ALL = 1;
|
||||
var SIGHASH_NONE = 2;
|
||||
var SIGHASH_SINGLE = 3;
|
||||
var SIGHASH_ANYONECANPAY = 80;
|
||||
var SIGHASH_ALL = 1;
|
||||
var SIGHASH_NONE = 2;
|
||||
var SIGHASH_SINGLE = 3;
|
||||
var SIGHASH_ANYONECANPAY = 80;
|
||||
|
||||
Transaction.SIGHASH_ALL=SIGHASH_ALL;
|
||||
Transaction.SIGHASH_NONE=SIGHASH_NONE;
|
||||
Transaction.SIGHASH_SINGLE=SIGHASH_SINGLE;
|
||||
Transaction.SIGHASH_ANYONECANPAY=SIGHASH_ANYONECANPAY;
|
||||
Transaction.SIGHASH_ALL=SIGHASH_ALL;
|
||||
Transaction.SIGHASH_NONE=SIGHASH_NONE;
|
||||
Transaction.SIGHASH_SINGLE=SIGHASH_SINGLE;
|
||||
Transaction.SIGHASH_ANYONECANPAY=SIGHASH_ANYONECANPAY;
|
||||
|
||||
Transaction.prototype.hashForSignature =
|
||||
function hashForSignature(script, inIndex, hashType) {
|
||||
Transaction.prototype.hashForSignature =
|
||||
function hashForSignature(script, inIndex, hashType) {
|
||||
if (+inIndex !== inIndex ||
|
||||
inIndex < 0 || inIndex >= this.ins.length) {
|
||||
throw new Error("Input index '"+inIndex+"' invalid or out of bounds "+
|
||||
|
@ -540,12 +538,12 @@ function spec(b) {
|
|||
buffer = Buffer.concat([buffer, new Buffer([parseInt(hashType), 0, 0, 0])]);
|
||||
|
||||
return util.twoSha256(buffer);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns an object with the same field names as jgarzik's getblock patch.
|
||||
*/
|
||||
Transaction.prototype.getStandardizedObject = function getStandardizedObject() {
|
||||
Transaction.prototype.getStandardizedObject = function getStandardizedObject() {
|
||||
var tx = {
|
||||
hash: util.formatHashFull(this.getHash()),
|
||||
version: this.version,
|
||||
|
@ -587,14 +585,14 @@ function spec(b) {
|
|||
tx["out"] = outs;
|
||||
|
||||
return tx;
|
||||
};
|
||||
};
|
||||
|
||||
// Add some Mongoose compatibility functions to the plain object
|
||||
Transaction.prototype.toObject = function toObject() {
|
||||
// Add some Mongoose compatibility functions to the plain object
|
||||
Transaction.prototype.toObject = function toObject() {
|
||||
return this;
|
||||
};
|
||||
};
|
||||
|
||||
Transaction.prototype.fromObj = function fromObj(obj) {
|
||||
Transaction.prototype.fromObj = function fromObj(obj) {
|
||||
var txobj = {};
|
||||
txobj.version = obj.version || 1;
|
||||
txobj.lock_time = obj.lock_time || 0;
|
||||
|
@ -636,9 +634,9 @@ function spec(b) {
|
|||
this.version = txobj.version;
|
||||
this.ins = txobj.ins;
|
||||
this.outs = txobj.outs;
|
||||
}
|
||||
}
|
||||
|
||||
Transaction.prototype.parse = function (parser) {
|
||||
Transaction.prototype.parse = function (parser) {
|
||||
if (Buffer.isBuffer(parser)) {
|
||||
parser = new Parser(parser);
|
||||
}
|
||||
|
@ -672,11 +670,11 @@ function spec(b) {
|
|||
|
||||
this.lock_time = parser.word32le();
|
||||
this.calcHash();
|
||||
};
|
||||
};
|
||||
|
||||
var TransactionInputsCache = exports.TransactionInputsCache =
|
||||
function TransactionInputsCache(tx)
|
||||
{
|
||||
var TransactionInputsCache = exports.TransactionInputsCache =
|
||||
function TransactionInputsCache(tx)
|
||||
{
|
||||
var txList = [];
|
||||
var txList64 = [];
|
||||
var reqOuts = {};
|
||||
|
@ -703,10 +701,10 @@ function spec(b) {
|
|||
this.txIndex = {};
|
||||
this.requiredOuts = reqOuts;
|
||||
this.callbacks = [];
|
||||
};
|
||||
};
|
||||
|
||||
TransactionInputsCache.prototype.buffer = function buffer(blockChain, txStore, wait, callback)
|
||||
{
|
||||
TransactionInputsCache.prototype.buffer = function buffer(blockChain, txStore, wait, callback)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
var complete = false;
|
||||
|
@ -789,11 +787,11 @@ function spec(b) {
|
|||
},
|
||||
self.callback.bind(self)
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
TransactionInputsCache.prototype.callback = function callback(err)
|
||||
{
|
||||
TransactionInputsCache.prototype.callback = function callback(err)
|
||||
{
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
|
||||
// Empty the callback array first (because downstream functions could add new
|
||||
|
@ -809,8 +807,6 @@ function spec(b) {
|
|||
log.err("Callback error after connecting tx inputs: "+
|
||||
(err.stack ? err.stack : err.toString()));
|
||||
}
|
||||
};
|
||||
|
||||
return Transaction;
|
||||
};
|
||||
module.defineClass(spec);
|
||||
|
||||
module.exports = require('soop')(Transaction);
|
||||
|
|
64
Wallet.js
64
Wallet.js
|
@ -1,15 +1,15 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
|
||||
var hex = function(hex) {return new Buffer(hex, 'hex');};
|
||||
|
||||
function ClassSpec(b) {
|
||||
var fs = require('fs');
|
||||
var EncFile = require('./util/EncFile');
|
||||
var Address = require('./Address').class();
|
||||
var networks = require('./networks');
|
||||
var util = b.util || require('./util/util');
|
||||
var ENC_METHOD = 'aes-256-cbc';
|
||||
var fs = require('fs');
|
||||
var EncFile = require('./util/EncFile');
|
||||
var Address = require('./Address');
|
||||
var networks = require('./networks');
|
||||
var util = imports.util || require('./util/util');
|
||||
var ENC_METHOD = 'aes-256-cbc';
|
||||
|
||||
var skeleton = {
|
||||
var skeleton = {
|
||||
client: 'libcoin',
|
||||
client_version: '0.0.1',
|
||||
network: 'testnet',
|
||||
|
@ -19,9 +19,9 @@ function ClassSpec(b) {
|
|||
keys: [],
|
||||
sin: {},
|
||||
scripts: {},
|
||||
};
|
||||
};
|
||||
|
||||
function Wallet(cfg) {
|
||||
function Wallet(cfg) {
|
||||
if (typeof cfg !== 'object')
|
||||
cfg = {};
|
||||
|
||||
|
@ -33,15 +33,15 @@ function ClassSpec(b) {
|
|||
|
||||
this.network = undefined;
|
||||
this.dirty = cfg.dirty || true;
|
||||
};
|
||||
};
|
||||
|
||||
Wallet.prototype.readSync = function(filename, passphrase) {
|
||||
Wallet.prototype.readSync = function(filename, passphrase) {
|
||||
this.datastore = EncFile.readJFileSync(ENC_METHOD,
|
||||
passphrase, filename);
|
||||
this.dirty = false;
|
||||
};
|
||||
};
|
||||
|
||||
Wallet.prototype.writeSync = function(filename, passphrase) {
|
||||
Wallet.prototype.writeSync = function(filename, passphrase) {
|
||||
var tmp_fn = filename + ".tmp";
|
||||
|
||||
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn,
|
||||
|
@ -49,9 +49,9 @@ function ClassSpec(b) {
|
|||
fs.renameSync(tmp_fn, filename);
|
||||
|
||||
this.dirty = false;
|
||||
};
|
||||
};
|
||||
|
||||
Wallet.prototype.setNetwork = function(netname) {
|
||||
Wallet.prototype.setNetwork = function(netname) {
|
||||
if (!netname)
|
||||
netname = this.datastore.network;
|
||||
|
||||
|
@ -70,19 +70,19 @@ function ClassSpec(b) {
|
|||
// store+canonicalize name
|
||||
this.datastore['network'] = this.network.name;
|
||||
this.dirty = true;
|
||||
};
|
||||
};
|
||||
|
||||
Wallet.prototype.addKey = function(wkey) {
|
||||
Wallet.prototype.addKey = function(wkey) {
|
||||
this.datastore.keys.push(wkey);
|
||||
this.dirty = true;
|
||||
};
|
||||
};
|
||||
|
||||
Wallet.prototype.addSIN = function(sinObj) {
|
||||
Wallet.prototype.addSIN = function(sinObj) {
|
||||
this.datastore.sin[sinObj.sin] = sinObj;
|
||||
this.dirty = true;
|
||||
};
|
||||
};
|
||||
|
||||
Wallet.prototype.findKeyHash = function(pubKeyHash) {
|
||||
Wallet.prototype.findKeyHash = function(pubKeyHash) {
|
||||
var pkhStr = pubKeyHash.toString();
|
||||
|
||||
for (var i = 0; i < this.datastore.keys.length; i++) {
|
||||
|
@ -94,9 +94,9 @@ function ClassSpec(b) {
|
|||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
};
|
||||
|
||||
Wallet.prototype.expandKey = function(key) {
|
||||
Wallet.prototype.expandKey = function(key) {
|
||||
var addr = new Address(key);
|
||||
var isAddr = true;
|
||||
|
||||
|
@ -113,9 +113,9 @@ function ClassSpec(b) {
|
|||
if (!key.match(re))
|
||||
throw new Error("Unknown key type");
|
||||
return hex(key);
|
||||
};
|
||||
};
|
||||
|
||||
Wallet.prototype.expandKeys = function(keys) {
|
||||
Wallet.prototype.expandKeys = function(keys) {
|
||||
var res = [];
|
||||
var us = this;
|
||||
keys.forEach(function(key) {
|
||||
|
@ -123,9 +123,9 @@ function ClassSpec(b) {
|
|||
res.push(expKey);
|
||||
});
|
||||
return res;
|
||||
};
|
||||
};
|
||||
|
||||
Wallet.prototype.addScript = function(script) {
|
||||
Wallet.prototype.addScript = function(script) {
|
||||
var buf = script.getBuffer();
|
||||
var hash = util.sha256ripe160(buf);
|
||||
var addr = new Address(this.network.addressScript, hash);
|
||||
|
@ -134,9 +134,7 @@ function ClassSpec(b) {
|
|||
this.dirty = true;
|
||||
|
||||
return addrStr;
|
||||
};
|
||||
|
||||
return Wallet;
|
||||
};
|
||||
module.defineClass(ClassSpec);
|
||||
|
||||
module.exports = require('soop')(Wallet);
|
||||
|
||||
|
|
33
WalletKey.js
33
WalletKey.js
|
@ -1,26 +1,25 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
|
||||
function ClassSpec(b) {
|
||||
var coinUtil = require('./util/util');
|
||||
var timeUtil = require('./util/time');
|
||||
var KeyModule = require('./Key');
|
||||
var PrivateKey = require('./PrivateKey').class();
|
||||
var Address = require('./Address').class();
|
||||
var coinUtil = require('./util/util');
|
||||
var timeUtil = require('./util/time');
|
||||
var KeyModule = require('./Key');
|
||||
var PrivateKey = require('./PrivateKey');
|
||||
var Address = require('./Address');
|
||||
|
||||
function WalletKey(cfg) {
|
||||
function WalletKey(cfg) {
|
||||
if (!cfg) cfg = {};
|
||||
if (!cfg.network) throw new Error('network parameter is required');
|
||||
this.network = cfg.network; // required
|
||||
this.created = cfg.created;
|
||||
this.privKey = cfg.privKey;
|
||||
};
|
||||
};
|
||||
|
||||
WalletKey.prototype.generate = function() {
|
||||
WalletKey.prototype.generate = function() {
|
||||
this.privKey = KeyModule.Key.generateSync();
|
||||
this.created = timeUtil.curtime();
|
||||
};
|
||||
};
|
||||
|
||||
WalletKey.prototype.storeObj = function() {
|
||||
WalletKey.prototype.storeObj = function() {
|
||||
var pubKey = this.privKey.public.toString('hex');
|
||||
var pubKeyHash = coinUtil.sha256ripe160(this.privKey.public);
|
||||
var addr = new Address(this.network.addressPubkey, pubKeyHash);
|
||||
|
@ -33,9 +32,9 @@ function ClassSpec(b) {
|
|||
};
|
||||
|
||||
return obj;
|
||||
};
|
||||
};
|
||||
|
||||
WalletKey.prototype.fromObj = function(obj) {
|
||||
WalletKey.prototype.fromObj = function(obj) {
|
||||
this.created = obj.created;
|
||||
this.privKey = new KeyModule.Key();
|
||||
if (obj.priv.length==64) {
|
||||
|
@ -48,8 +47,6 @@ function ClassSpec(b) {
|
|||
this.privKey.compressed = priv.compressed();
|
||||
}
|
||||
this.privKey.regenerateSync();
|
||||
};
|
||||
|
||||
return WalletKey;
|
||||
};
|
||||
module.defineClass(ClassSpec);
|
||||
|
||||
module.exports = require('soop')(WalletKey);
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('Address', function() {
|
|||
should.exist(AddressModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
Address = AddressModule.class();
|
||||
Address = AddressModule;
|
||||
should.exist(Address);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -12,7 +12,7 @@ describe('Block', function() {
|
|||
should.exist(BlockModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
Block = BlockModule.class();
|
||||
Block = BlockModule;
|
||||
should.exist(Block);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('Bloom', function() {
|
|||
should.exist(BloomModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
Bloom = BloomModule.class();
|
||||
Bloom = BloomModule;
|
||||
should.exist(Bloom);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -14,7 +14,7 @@ describe('Connection', function() {
|
|||
should.exist(ConnectionModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
Connection = ConnectionModule.class();
|
||||
Connection = ConnectionModule;
|
||||
should.exist(Connection);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('EncodedData', function() {
|
|||
should.exist(EncodedDataModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
EncodedData = EncodedDataModule.class();
|
||||
EncodedData = EncodedDataModule;
|
||||
should.exist(EncodedData);
|
||||
});
|
||||
it('should be able to create an instance', function() {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('Opcode', function() {
|
|||
should.exist(OpcodeModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
Opcode = OpcodeModule.class();
|
||||
Opcode = OpcodeModule;
|
||||
should.exist(Opcode);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('Peer', function() {
|
|||
should.exist(PeerModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
Peer = PeerModule.class();
|
||||
Peer = PeerModule;
|
||||
should.exist(Peer);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('PeerManager', function() {
|
|||
should.exist(PeerManagerModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
PeerManager = PeerManagerModule.class();
|
||||
PeerManager = PeerManagerModule;
|
||||
should.exist(PeerManager);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -15,7 +15,7 @@ describe('PrivateKey', function() {
|
|||
should.exist(PrivateKeyModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
PrivateKey = PrivateKeyModule.class();
|
||||
PrivateKey = PrivateKeyModule;
|
||||
should.exist(PrivateKey);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -7,7 +7,7 @@ var should = chai.should();
|
|||
|
||||
var RpcClientModule = bitcore.RpcClient;
|
||||
var RpcClient;
|
||||
RpcClient = RpcClientModule.class();
|
||||
RpcClient = RpcClientModule;
|
||||
|
||||
describe('RpcClient', function() {
|
||||
it('should initialze the main object', function() {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('SIN', function() {
|
|||
should.exist(SINModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
SIN = SINModule.class();
|
||||
SIN = SINModule;
|
||||
should.exist(SIN);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -16,7 +16,7 @@ describe('SINKey', function() {
|
|||
should.exist(SINKeyModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
SINKey = SINKeyModule.class();
|
||||
SINKey = SINKeyModule;
|
||||
should.exist(SINKey);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -6,7 +6,7 @@ var bitcore = require('../bitcore');
|
|||
var should = chai.should();
|
||||
|
||||
var ScriptModule = bitcore.Script;
|
||||
var Address = bitcore.Address.class();
|
||||
var Address = bitcore.Address;
|
||||
var networks = bitcore.networks;
|
||||
var Script;
|
||||
|
||||
|
@ -15,7 +15,7 @@ describe('Script', function() {
|
|||
should.exist(ScriptModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
Script = ScriptModule.class();
|
||||
Script = ScriptModule;
|
||||
should.exist(Script);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('ScriptInterpreter', function() {
|
|||
should.exist(ScriptInterpreterModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
ScriptInterpreter = ScriptInterpreterModule.class();
|
||||
ScriptInterpreter = ScriptInterpreterModule;
|
||||
should.exist(ScriptInterpreter);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('Transaction', function() {
|
|||
should.exist(TransactionModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
Transaction = TransactionModule.class();
|
||||
Transaction = TransactionModule;
|
||||
should.exist(Transaction);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('VersionedData', function() {
|
|||
should.exist(VersionedDataModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
VersionedData = VersionedDataModule.class();
|
||||
VersionedData = VersionedDataModule;
|
||||
should.exist(VersionedData);
|
||||
});
|
||||
it('should be able to create an instance', function() {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('Wallet', function() {
|
|||
should.exist(WalletModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
Wallet = WalletModule.class();
|
||||
Wallet = WalletModule;
|
||||
should.exist(Wallet);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -14,7 +14,7 @@ describe('WalletKey', function() {
|
|||
should.exist(WalletKeyModule);
|
||||
});
|
||||
it('should be able to create class', function() {
|
||||
WalletKey = WalletKeyModule.class();
|
||||
WalletKey = WalletKeyModule;
|
||||
should.exist(WalletKey);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
|
|
|
@ -4,8 +4,8 @@ var chai = require('chai');
|
|||
var bitcore = require('../bitcore');
|
||||
var should = chai.should();
|
||||
|
||||
var Address = bitcore.Address.class();
|
||||
var PrivateKey = bitcore.PrivateKey.class();
|
||||
var Address = bitcore.Address;
|
||||
var PrivateKey = bitcore.PrivateKey;
|
||||
var networks = bitcore.networks;
|
||||
var KeyModule = bitcore.KeyModule;
|
||||
|
||||
|
|
|
@ -2,20 +2,20 @@
|
|||
* Simple synchronous parser based on node-binary.
|
||||
*/
|
||||
|
||||
function spec(b) {
|
||||
function Parser(buffer)
|
||||
{
|
||||
var imports = require('soop').imports();
|
||||
function Parser(buffer)
|
||||
{
|
||||
this.subject = buffer;
|
||||
this.pos = 0;
|
||||
};
|
||||
};
|
||||
|
||||
Parser.prototype.buffer = function buffer(len) {
|
||||
Parser.prototype.buffer = function buffer(len) {
|
||||
var buf = this.subject.slice(this.pos, this.pos+len);
|
||||
this.pos += len;
|
||||
return buf;
|
||||
};
|
||||
};
|
||||
|
||||
Parser.prototype.search = function search(needle) {
|
||||
Parser.prototype.search = function search(needle) {
|
||||
var len;
|
||||
|
||||
if ("string" === typeof needle || Buffer.isBuffer(needle)) {
|
||||
|
@ -38,12 +38,12 @@ function spec(b) {
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Like search(), but returns the skipped bytes
|
||||
*/
|
||||
Parser.prototype.scan = function scan(needle) {
|
||||
Parser.prototype.scan = function scan(needle) {
|
||||
var startPos = this.pos;
|
||||
var len = this.search(needle);
|
||||
if (len !== -1) {
|
||||
|
@ -51,55 +51,55 @@ function spec(b) {
|
|||
} else {
|
||||
throw new Error('No match');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Parser.prototype.eof = function eof() {
|
||||
Parser.prototype.eof = function eof() {
|
||||
return this.pos >= this.subject.length;
|
||||
};
|
||||
};
|
||||
|
||||
// convert byte strings to unsigned little endian numbers
|
||||
function decodeLEu (bytes) {
|
||||
// convert byte strings to unsigned little endian numbers
|
||||
function decodeLEu (bytes) {
|
||||
var acc = 0;
|
||||
for (var i = 0; i < bytes.length; i++) {
|
||||
acc += Math.pow(256,i) * bytes[i];
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
|
||||
// convert byte strings to unsigned big endian numbers
|
||||
function decodeBEu (bytes) {
|
||||
// convert byte strings to unsigned big endian numbers
|
||||
function decodeBEu (bytes) {
|
||||
var acc = 0;
|
||||
for (var i = 0; i < bytes.length; i++) {
|
||||
acc += Math.pow(256, bytes.length - i - 1) * bytes[i];
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
|
||||
// convert byte strings to signed big endian numbers
|
||||
function decodeBEs (bytes) {
|
||||
// convert byte strings to signed big endian numbers
|
||||
function decodeBEs (bytes) {
|
||||
var val = decodeBEu(bytes);
|
||||
if ((bytes[0] & 0x80) == 0x80) {
|
||||
val -= Math.pow(256, bytes.length);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
// convert byte strings to signed little endian numbers
|
||||
function decodeLEs (bytes) {
|
||||
// convert byte strings to signed little endian numbers
|
||||
function decodeLEs (bytes) {
|
||||
var val = decodeLEu(bytes);
|
||||
if ((bytes[bytes.length - 1] & 0x80) == 0x80) {
|
||||
val -= Math.pow(256, bytes.length);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
function getDecoder(len, fn) {
|
||||
function getDecoder(len, fn) {
|
||||
return function () {
|
||||
var buf = this.buffer(len);
|
||||
return fn(buf);
|
||||
};
|
||||
};
|
||||
[ 1, 2, 4, 8 ].forEach(function (bytes) {
|
||||
};
|
||||
[ 1, 2, 4, 8 ].forEach(function (bytes) {
|
||||
var bits = bytes * 8;
|
||||
|
||||
Parser.prototype['word' + bits + 'le']
|
||||
|
@ -118,10 +118,10 @@ function spec(b) {
|
|||
|
||||
Parser.prototype.word8 = Parser.prototype.word8u = Parser.prototype.word8be;
|
||||
Parser.prototype.word8s = Parser.prototype.word8bs;
|
||||
});
|
||||
});
|
||||
|
||||
Parser.prototype.varInt = function ()
|
||||
{
|
||||
Parser.prototype.varInt = function ()
|
||||
{
|
||||
var firstByte = this.word8();
|
||||
switch (firstByte) {
|
||||
case 0xFD:
|
||||
|
@ -136,13 +136,11 @@ function spec(b) {
|
|||
default:
|
||||
return firstByte;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Parser.prototype.varStr = function () {
|
||||
Parser.prototype.varStr = function () {
|
||||
var len = this.varInt();
|
||||
return this.buffer(len);
|
||||
};
|
||||
|
||||
return Parser;
|
||||
};
|
||||
module.defineClass(spec);
|
||||
|
||||
module.exports = require('soop')(Parser);
|
||||
|
|
|
@ -1,92 +1,91 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
var base58 = imports.base58 || require('base58-native').base58Check;
|
||||
|
||||
function ClassSpec(b) {
|
||||
var base58 = b.base58 || require('base58-native').base58Check;
|
||||
|
||||
// Constructor. Takes the following forms:
|
||||
// new EncodedData(<base58_address_string>)
|
||||
// new EncodedData(<binary_buffer>)
|
||||
// new EncodedData(<data>, <encoding>)
|
||||
// new EncodedData(<version>, <20-byte-hash>)
|
||||
function EncodedData(data, encoding) {
|
||||
// Constructor. Takes the following forms:
|
||||
// new EncodedData(<base58_address_string>)
|
||||
// new EncodedData(<binary_buffer>)
|
||||
// new EncodedData(<data>, <encoding>)
|
||||
// new EncodedData(<version>, <20-byte-hash>)
|
||||
function EncodedData(data, encoding) {
|
||||
this.data = data;
|
||||
if(!encoding && (typeof data == 'string')) {
|
||||
this.__proto__ = this.encodings['base58'];
|
||||
} else {
|
||||
this.__proto__ = this.encodings[encoding || 'binary'];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// get or set the encoding used (transforms data)
|
||||
EncodedData.prototype.encoding = function(encoding) {
|
||||
// get or set the encoding used (transforms data)
|
||||
EncodedData.prototype.encoding = function(encoding) {
|
||||
if(encoding && (encoding != this._encoding)) {
|
||||
this.data = this.as(encoding);
|
||||
this.__proto__ = this.encodings[encoding];
|
||||
}
|
||||
return this._encoding;
|
||||
};
|
||||
};
|
||||
|
||||
// answer a new instance having the given encoding
|
||||
EncodedData.prototype.withEncoding = function(encoding) {
|
||||
// answer a new instance having the given encoding
|
||||
EncodedData.prototype.withEncoding = function(encoding) {
|
||||
return new EncodedData(this.as(encoding), encoding);
|
||||
};
|
||||
};
|
||||
|
||||
// answer the data in the given encoding
|
||||
EncodedData.prototype.as = function(encoding) {
|
||||
// answer the data in the given encoding
|
||||
EncodedData.prototype.as = function(encoding) {
|
||||
if(!encodings[encoding]) throw new Error('invalid encoding');
|
||||
return this.converters[encoding].call(this);
|
||||
};
|
||||
};
|
||||
|
||||
// validate that we can convert to binary
|
||||
EncodedData.prototype._validate = function() {
|
||||
// validate that we can convert to binary
|
||||
EncodedData.prototype._validate = function() {
|
||||
this.withEncoding('binary');
|
||||
};
|
||||
};
|
||||
|
||||
// Boolean protocol for testing if valid
|
||||
EncodedData.prototype.isValid = function() {
|
||||
// Boolean protocol for testing if valid
|
||||
EncodedData.prototype.isValid = function() {
|
||||
try {
|
||||
this.validate();
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// subclasses can override to do more stuff
|
||||
EncodedData.prototype.validate = function() {
|
||||
// subclasses can override to do more stuff
|
||||
EncodedData.prototype.validate = function() {
|
||||
this._validate();
|
||||
};
|
||||
};
|
||||
|
||||
// Boolean protocol for testing if valid
|
||||
EncodedData.prototype.isValid = function() {
|
||||
// Boolean protocol for testing if valid
|
||||
EncodedData.prototype.isValid = function() {
|
||||
try {
|
||||
this.validate();
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// convert to a string (in base58 form)
|
||||
EncodedData.prototype.toString = function() {
|
||||
// convert to a string (in base58 form)
|
||||
EncodedData.prototype.toString = function() {
|
||||
return this.as('base58');
|
||||
};
|
||||
};
|
||||
|
||||
// utility
|
||||
EncodedData.prototype.doAsBinary = function(callback) {
|
||||
// utility
|
||||
EncodedData.prototype.doAsBinary = function(callback) {
|
||||
var oldEncoding = this.encoding();
|
||||
this.encoding('binary');
|
||||
callback.apply(this);
|
||||
this.encoding(oldEncoding);
|
||||
};
|
||||
};
|
||||
|
||||
// Setup support for various address encodings. The object for
|
||||
// each encoding inherits from the EncodedData prototype. This
|
||||
// allows any encoding to override any method...changing the encoding
|
||||
// for an instance will change the encoding it inherits from. Note,
|
||||
// this will present some problems for anyone wanting to inherit from
|
||||
// EncodedData (we'll deal with that when needed).
|
||||
var encodings = {
|
||||
// Setup support for various address encodings. The object for
|
||||
// each encoding inherits from the EncodedData prototype. This
|
||||
// allows any encoding to override any method...changing the encoding
|
||||
// for an instance will change the encoding it inherits from. Note,
|
||||
// this will present some problems for anyone wanting to inherit from
|
||||
// EncodedData (we'll deal with that when needed).
|
||||
var encodings = {
|
||||
'binary': {
|
||||
converters: {
|
||||
'binary': function() {
|
||||
|
@ -128,18 +127,18 @@ function ClassSpec(b) {
|
|||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
var no_conversion = function() {return this.data;};
|
||||
for(var k in encodings) {
|
||||
var no_conversion = function() {return this.data;};
|
||||
for(var k in encodings) {
|
||||
if(encodings.hasOwnProperty(k)){
|
||||
if(!encodings[k].converters[k])
|
||||
encodings[k].converters[k] = no_conversion;
|
||||
encodings[k]._encoding = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EncodedData.applyEncodingsTo = function(aClass) {
|
||||
EncodedData.applyEncodingsTo = function(aClass) {
|
||||
var tmp = {};
|
||||
for(var k in encodings) {
|
||||
var enc = encodings[k];
|
||||
|
@ -151,9 +150,9 @@ function ClassSpec(b) {
|
|||
tmp[k] = obj;
|
||||
}
|
||||
aClass.prototype.encodings = tmp;
|
||||
};
|
||||
};
|
||||
|
||||
EncodedData.applyEncodingsTo(EncodedData);
|
||||
|
||||
module.exports = require('soop')(EncodedData);
|
||||
|
||||
EncodedData.applyEncodingsTo(EncodedData);
|
||||
return EncodedData;
|
||||
}
|
||||
module.defineClass(ClassSpec);
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
require('classtool');
|
||||
var imports = require('soop').imports();
|
||||
var base58 = imports.base58 || require('base58-native').base58Check;
|
||||
var superclass = imports.parent || require('./EncodedData');
|
||||
|
||||
function ClassSpec(b) {
|
||||
var superclass = b.superclass || require('./EncodedData').class();
|
||||
|
||||
function VersionedData(version, payload) {
|
||||
function VersionedData(version, payload) {
|
||||
if(typeof version != 'number') {
|
||||
VersionedData.super(this, arguments);
|
||||
return;
|
||||
|
@ -12,28 +11,27 @@ function ClassSpec(b) {
|
|||
this.__proto__ = this.encodings['binary'];
|
||||
this.version(version);
|
||||
this.payload(payload);
|
||||
};
|
||||
VersionedData.superclass = superclass;
|
||||
superclass.applyEncodingsTo(VersionedData);
|
||||
};
|
||||
|
||||
// get or set the version data (the first byte of the address)
|
||||
VersionedData.prototype.version = function(num) {
|
||||
VersionedData.parent = superclass || require('./Person');
|
||||
superclass.applyEncodingsTo(VersionedData);
|
||||
|
||||
// get or set the version data (the first byte of the address)
|
||||
VersionedData.prototype.version = function(num) {
|
||||
if(num || (num === 0)) {
|
||||
this.doAsBinary(function() {this.data.writeUInt8(num, 0);});
|
||||
return num;
|
||||
}
|
||||
return this.as('binary').readUInt8(0);
|
||||
};
|
||||
};
|
||||
|
||||
// get or set the payload data (as a Buffer object)
|
||||
VersionedData.prototype.payload = function(data) {
|
||||
// get or set the payload data (as a Buffer object)
|
||||
VersionedData.prototype.payload = function(data) {
|
||||
if(data) {
|
||||
this.doAsBinary(function() {data.copy(this.data,1);});
|
||||
return data;
|
||||
}
|
||||
return this.as('binary').slice(1);
|
||||
};
|
||||
|
||||
return VersionedData;
|
||||
};
|
||||
module.defineClass(ClassSpec);
|
||||
|
||||
module.exports = require('soop')(VersionedData);
|
||||
|
|
Loading…
Reference in New Issue