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