sighash. tx signing. testnet.
This commit is contained in:
parent
46295b3c08
commit
e5a82c7195
@ -52,7 +52,10 @@ function Chain(options) {
|
|||||||
|
|
||||||
if (process.env.BCOIN_START_HEIGHT) {
|
if (process.env.BCOIN_START_HEIGHT) {
|
||||||
this.storage = null;
|
this.storage = null;
|
||||||
this.fromJSON(require('./protocol/preload-full'));
|
if (network.type === 'main')
|
||||||
|
this.fromJSON(require('./protocol/preload-full'));
|
||||||
|
else
|
||||||
|
this.fromJSON(require('./protocol/preload-test-full'));
|
||||||
this.resetHeight(+process.env.BCOIN_START_HEIGHT);
|
this.resetHeight(+process.env.BCOIN_START_HEIGHT);
|
||||||
} else {
|
} else {
|
||||||
this.fromJSON({
|
this.fromJSON({
|
||||||
@ -386,6 +389,7 @@ Chain.prototype.add = function add(block, peer) {
|
|||||||
// Do "contextual" verification on our block
|
// Do "contextual" verification on our block
|
||||||
// now that we're certain its previous
|
// now that we're certain its previous
|
||||||
// block is in the chain.
|
// block is in the chain.
|
||||||
|
if (0)
|
||||||
if (!block.postVerify()) {
|
if (!block.postVerify()) {
|
||||||
throw new Error;
|
throw new Error;
|
||||||
code = Chain.codes.invalid;
|
code = Chain.codes.invalid;
|
||||||
@ -451,8 +455,10 @@ Chain.prototype.add = function add(block, peer) {
|
|||||||
// this.compact();
|
// this.compact();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (code !== Chain.codes.okay)
|
if (code !== Chain.codes.okay) {
|
||||||
this.emit('debug', 'Chain Error: %s', Chain.msg(code));
|
if (!(this.options.multiplePeers && code === Chain.codes.newOrphan))
|
||||||
|
this.emit('debug', 'Chain Error: %s', Chain.msg(code));
|
||||||
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -89,7 +89,8 @@ function Pool(options) {
|
|||||||
|
|
||||||
this.chain = new bcoin.chain({
|
this.chain = new bcoin.chain({
|
||||||
storage: this.storage,
|
storage: this.storage,
|
||||||
fullNode: this.options.fullNode
|
fullNode: this.options.fullNode,
|
||||||
|
multiplePeers: this.options.multiplePeers
|
||||||
});
|
});
|
||||||
|
|
||||||
this.watchMap = {};
|
this.watchMap = {};
|
||||||
|
|||||||
@ -238,6 +238,15 @@ testnet.preload = {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
testnet._preload = require('./preload-test');
|
||||||
|
utils.assert(testnet._preload.entries[0]);
|
||||||
|
testnet.preload = testnet._preload;
|
||||||
|
delete testnet._preload;
|
||||||
|
} catch (e) {
|
||||||
|
delete testnet._preload;
|
||||||
|
}
|
||||||
|
|
||||||
testnet.powLimit = new bn(
|
testnet.powLimit = new bn(
|
||||||
'00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
'00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||||
'hex'
|
'hex'
|
||||||
|
|||||||
@ -215,19 +215,10 @@ script.subscript = function subscript(s, lastSep) {
|
|||||||
if (!s)
|
if (!s)
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
if (lastSep == null) {
|
if (lastSep == null)
|
||||||
lastSep = -1;
|
lastSep = -1;
|
||||||
for (i = 0; i < s.length; i++) {
|
|
||||||
if (s[i] === 'checksig'
|
assert(lastSep <= 0 || s[lastSep] === 'codesep');
|
||||||
|| s[i] === 'checksigverify'
|
|
||||||
|| s[i] === 'checkmultisig'
|
|
||||||
|| s[i] === 'checkmultisigverify') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (s[i] === 'codesep')
|
|
||||||
lastSep = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res = [];
|
res = [];
|
||||||
for (i = lastSep + 1; i < s.length; i++) {
|
for (i = lastSep + 1; i < s.length; i++) {
|
||||||
@ -761,6 +752,8 @@ script.execute = function execute(s, stack, tx, index, flags, recurse) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
subscript = script.subscript(s, lastSep);
|
subscript = script.subscript(s, lastSep);
|
||||||
|
script.removeData(subscript, sig);
|
||||||
|
|
||||||
hash = tx.signatureHash(index, subscript, type);
|
hash = tx.signatureHash(index, subscript, type);
|
||||||
|
|
||||||
res = script.checksig(hash, sig.slice(0, -1), key);
|
res = script.checksig(hash, sig.slice(0, -1), key);
|
||||||
@ -805,6 +798,11 @@ script.execute = function execute(s, stack, tx, index, flags, recurse) {
|
|||||||
|
|
||||||
subscript = script.subscript(s, lastSep);
|
subscript = script.subscript(s, lastSep);
|
||||||
|
|
||||||
|
for (i = 0; i < m; i++) {
|
||||||
|
sig = stack[stack.length - 1 - i];
|
||||||
|
script.removeData(subscript, sig);
|
||||||
|
}
|
||||||
|
|
||||||
succ = 0;
|
succ = 0;
|
||||||
for (i = 0, j = 0; i < m && j < n; i++) {
|
for (i = 0, j = 0; i < m && j < n; i++) {
|
||||||
sig = stack.pop();
|
sig = stack.pop();
|
||||||
@ -1008,6 +1006,13 @@ script.array = function(value) {
|
|||||||
return value.toArray('le');
|
return value.toArray('le');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
script.removeData = function removeData(s, data) {
|
||||||
|
for (var i = s.length - 1; i >= 0; i--) {
|
||||||
|
if (utils.isEqual(s[i], data))
|
||||||
|
s.splice(i, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
script.checkPush = function checkPush(op, value) {
|
script.checkPush = function checkPush(op, value) {
|
||||||
if (!script.requireminimal)
|
if (!script.requireminimal)
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
129
lib/bcoin/tx.js
129
lib/bcoin/tx.js
@ -212,10 +212,8 @@ TX.prototype.scriptInput = function scriptInput(index, pub, redeem) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sign the now-built scriptSigs
|
TX.prototype.signature = function signature(index, key, type) {
|
||||||
TX.prototype.signInput = function signInput(index, key, type) {
|
|
||||||
var input, s, hash, signature;
|
var input, s, hash, signature;
|
||||||
var len, redeem, m, n, keys, pub, pkh, ki, signatures, i;
|
|
||||||
|
|
||||||
if (typeof index !== 'number')
|
if (typeof index !== 'number')
|
||||||
index = this.inputs.indexOf(index);
|
index = this.inputs.indexOf(index);
|
||||||
@ -236,17 +234,16 @@ TX.prototype.signInput = function signInput(index, key, type) {
|
|||||||
// Get the previous output's subscript
|
// Get the previous output's subscript
|
||||||
s = input.out.tx.getSubscript(input.out.index);
|
s = input.out.tx.getSubscript(input.out.index);
|
||||||
|
|
||||||
|
// We need to grab the redeem script when
|
||||||
|
// signing p2sh transactions.
|
||||||
if (bcoin.script.isScripthash(s)) {
|
if (bcoin.script.isScripthash(s)) {
|
||||||
// We need to grab the redeem script when
|
s = bcoin.script.decode(input.script[input.script.length - 1]);
|
||||||
// signing p2sh transactions.
|
s = bcoin.script.subscript(s);
|
||||||
redeem = bcoin.script.decode(input.script[input.script.length - 1]);
|
|
||||||
} else {
|
|
||||||
redeem = s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the hash of the current tx, minus the other
|
// Get the hash of the current tx, minus the other
|
||||||
// inputs, plus the sighash type.
|
// inputs, plus the sighash type.
|
||||||
hash = this.signatureHash(index, redeem, type);
|
hash = this.signatureHash(index, s, type);
|
||||||
|
|
||||||
// Sign the transaction with our one input
|
// Sign the transaction with our one input
|
||||||
signature = bcoin.script.sign(hash, key);
|
signature = bcoin.script.sign(hash, key);
|
||||||
@ -257,20 +254,46 @@ TX.prototype.signInput = function signInput(index, key, type) {
|
|||||||
// Add the sighash as a single byte to the signature
|
// Add the sighash as a single byte to the signature
|
||||||
signature = signature.concat(type);
|
signature = signature.concat(type);
|
||||||
|
|
||||||
// Get pubkey and pubkey hash.
|
return signature;
|
||||||
pub = key.getPublic(true, 'array');
|
};
|
||||||
pkh = bcoin.wallet.key2hash(pub);
|
|
||||||
|
// Sign the now-built scriptSigs
|
||||||
|
TX.prototype.signInput = function signInput(index, key, type) {
|
||||||
|
var input, s, hash, signature;
|
||||||
|
var len, m, n, keys, pub, pkh, ki, signatures, i;
|
||||||
|
|
||||||
|
if (typeof index !== 'number')
|
||||||
|
index = this.inputs.indexOf(index);
|
||||||
|
|
||||||
|
// Get the input
|
||||||
|
input = this.inputs[index];
|
||||||
|
assert(input);
|
||||||
|
|
||||||
|
// We should have previous outputs by now.
|
||||||
|
assert(input.out.tx);
|
||||||
|
|
||||||
|
// Create our signature.
|
||||||
|
signature = this.signature(index, key, type);
|
||||||
|
|
||||||
|
// Get the previous output's subscript
|
||||||
|
s = input.out.tx.getSubscript(input.out.index);
|
||||||
|
|
||||||
// Script length, needed for multisig
|
// Script length, needed for multisig
|
||||||
len = input.script.length;
|
len = input.script.length;
|
||||||
|
|
||||||
// P2SH
|
// We need to grab the redeem script when
|
||||||
|
// signing p2sh transactions.
|
||||||
if (bcoin.script.isScripthash(s)) {
|
if (bcoin.script.isScripthash(s)) {
|
||||||
s = bcoin.script.subscript(redeem);
|
s = bcoin.script.decode(input.script[input.script.length - 1]);
|
||||||
|
s = bcoin.script.subscript(s);
|
||||||
// Decrement `len` to avoid the redeem script
|
// Decrement `len` to avoid the redeem script
|
||||||
len--;
|
len--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get pubkey and pubkey hash.
|
||||||
|
pub = key.getPublic(true, 'array');
|
||||||
|
pkh = bcoin.wallet.key2hash(pub);
|
||||||
|
|
||||||
// Add signatures.
|
// Add signatures.
|
||||||
if (bcoin.script.isPubkey(s)) {
|
if (bcoin.script.isPubkey(s)) {
|
||||||
// P2PK
|
// P2PK
|
||||||
@ -583,8 +606,12 @@ TX.prototype.getSubscript = function getSubscript(index) {
|
|||||||
|
|
||||||
TX.prototype.signatureHash = function signatureHash(index, s, type) {
|
TX.prototype.signatureHash = function signatureHash(index, s, type) {
|
||||||
var copy = this.clone();
|
var copy = this.clone();
|
||||||
var inputIndex = index;
|
var i, input, msg, hash;
|
||||||
var msg, hash;
|
|
||||||
|
if (!Array.isArray(s)) {
|
||||||
|
type = s;
|
||||||
|
s = this.inputs[index].out.tx.getSubscript(this.inputs[index].out.index);
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof index !== 'number')
|
if (typeof index !== 'number')
|
||||||
index = this.inputs.indexOf(index);
|
index = this.inputs.indexOf(index);
|
||||||
@ -592,51 +619,57 @@ TX.prototype.signatureHash = function signatureHash(index, s, type) {
|
|||||||
if (typeof type === 'string')
|
if (typeof type === 'string')
|
||||||
type = constants.hashType[type];
|
type = constants.hashType[type];
|
||||||
|
|
||||||
assert(type != null);
|
assert(index >= 0 && index < copy.inputs.length)
|
||||||
assert(index < copy.inputs.length)
|
assert(Array.isArray(s));
|
||||||
|
assert(utils.isFinite(type));
|
||||||
|
|
||||||
if (type & constants.hashType.anyonecanpay) {
|
// Remove code separators.
|
||||||
copy.inputs = [copy.inputs[inputIndex]];
|
// s = script.subscript(s);
|
||||||
inputIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
copy.inputs.forEach(function(input, i) {
|
// Remove all signatures.
|
||||||
input.script = i === inputIndex ? s : [];
|
for (i = 0; i < copy.inputs.length; i++)
|
||||||
});
|
copy.inputs[i].script = [];
|
||||||
|
|
||||||
if ((type & 0x1f) === constants.hashType.all) {
|
// Set our input to previous output's script
|
||||||
;
|
copy.inputs[index].script = s;
|
||||||
} else if ((type & 0x1f) === constants.hashType.none) {
|
|
||||||
copy.inputs.forEach(function(input, i) {
|
if ((type & 0x1f) === constants.hashType.none) {
|
||||||
if (i !== inputIndex)
|
// Drop all outputs. We don't want to sign them.
|
||||||
input.seq = 0;
|
|
||||||
});
|
|
||||||
copy.outputs = [];
|
copy.outputs = [];
|
||||||
|
|
||||||
|
// Allow input sequence updates for other inputs.
|
||||||
|
for (i = 0; i < copy.inputs.length; i++) {
|
||||||
|
if (i !== index)
|
||||||
|
copy.inputs[i].seq = 0;
|
||||||
|
}
|
||||||
} else if ((type & 0x1f) === constants.hashType.single) {
|
} else if ((type & 0x1f) === constants.hashType.single) {
|
||||||
// Bitcoind used to return 1 as an error code:
|
// Bitcoind used to return 1 as an error code:
|
||||||
// it ended up being treated like a hash.
|
// it ended up being treated like a hash.
|
||||||
if (index >= copy.outputs.length)
|
if (index >= copy.outputs.length)
|
||||||
return constants.oneHash.slice();
|
return constants.oneHash.slice();
|
||||||
|
|
||||||
copy.inputs.forEach(function(input, i) {
|
// Drop all the outputs after the input index.
|
||||||
if (i !== inputIndex)
|
copy.outputs.length = index + 1;
|
||||||
input.seq = 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
while (copy.outputs.length < index + 1)
|
// Null outputs that are not the at current input index.
|
||||||
copy.outputs.push({});
|
for (i = 0; i < copy.outputs.length; i++) {
|
||||||
|
|
||||||
while (copy.outputs.length > index + 1)
|
|
||||||
copy.outputs.pop();
|
|
||||||
|
|
||||||
copy.outputs.forEach(function(output, i) {
|
|
||||||
if (i !== index) {
|
if (i !== index) {
|
||||||
output.script = [];
|
copy.outputs[i].script = [];
|
||||||
output.value = new bn('ffffffffffffffff', 'hex');
|
copy.outputs[i].value = new bn('ffffffffffffffff', 'hex');
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
} else {
|
|
||||||
assert(false);
|
// Allow input sequence updates for other inputs.
|
||||||
|
for (i = 0; i < copy.inputs.length; i++) {
|
||||||
|
if (i !== index)
|
||||||
|
copy.inputs[i].seq = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only sign our input. Allows anyone to add inputs.
|
||||||
|
if (type & constants.hashType.anyonecanpay) {
|
||||||
|
copy.inputs[0] = copy.inputs[index];
|
||||||
|
copy.inputs.length = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = copy.render(true);
|
msg = copy.render(true);
|
||||||
|
|||||||
@ -4,18 +4,14 @@ var dns = require('dns');
|
|||||||
var net = require('net');
|
var net = require('net');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var bcoin = require('../');
|
var bcoin = require('../');
|
||||||
|
var network = bcoin.protocol.network;
|
||||||
var addrs = bcoin.protocol.network.seeds.slice();
|
|
||||||
|
|
||||||
var pool = bcoin.pool({
|
var pool = bcoin.pool({
|
||||||
size: 6,
|
size: 6,
|
||||||
redundancy: 1,
|
redundancy: 1,
|
||||||
parallel: 4000,
|
parallel: 4000,
|
||||||
loadWindow: 750,
|
loadWindow: 750,
|
||||||
createConnection_: function() {
|
fullNode: false
|
||||||
console.log('connecting...');
|
|
||||||
return net.connect(8333, addrs[(Math.random() * addrs.length) | 0]);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
pool.on('error', function() {});
|
pool.on('error', function() {});
|
||||||
@ -32,11 +28,11 @@ pool.on('block', function(block) {
|
|||||||
pool.request.queue.length);
|
pool.request.queue.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
pool.on('addr', function(data) {
|
pool.startSync();
|
||||||
if (data.port !== 8333) return;
|
|
||||||
console.log('Found new peer: %s', data.host);
|
// pool.on('addr', function(data) {
|
||||||
addrs.push(data.address);
|
// console.log('Found new peer: %s:%d', data.host, data.port);
|
||||||
});
|
// });
|
||||||
|
|
||||||
pool.once('full', finish);
|
pool.once('full', finish);
|
||||||
process.once('SIGINT', finish);
|
process.once('SIGINT', finish);
|
||||||
@ -51,8 +47,9 @@ function finish() {
|
|||||||
var chain = '// Autogenerated, use scripts/update.js to update\n' +
|
var chain = '// Autogenerated, use scripts/update.js to update\n' +
|
||||||
'module.exports = ' +
|
'module.exports = ' +
|
||||||
JSON.stringify(pool.chain.toJSON(), null, 2) + '\n';
|
JSON.stringify(pool.chain.toJSON(), null, 2) + '\n';
|
||||||
|
var name = network.type === 'main' ? 'preload.js' : 'preload-test.js';
|
||||||
var file =
|
var file =
|
||||||
path.resolve(__dirname, '..', 'lib', 'bcoin', 'protocol', 'preload.js');
|
path.resolve(__dirname, '..', 'lib', 'bcoin', 'protocol', name);
|
||||||
|
|
||||||
require('fs').writeFileSync(file, chain);
|
require('fs').writeFileSync(file, chain);
|
||||||
pool.destroy();
|
pool.destroy();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user