coins: refactor compression.

This commit is contained in:
Christopher Jeffrey 2016-11-27 22:23:12 -08:00
parent 7fd2c409ae
commit 1997864ec2
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
4 changed files with 61 additions and 40 deletions

View File

@ -383,7 +383,7 @@ Coins.parseCoin = function parseCoin(data, hash, index) {
if (pos === index) { if (pos === index) {
if (spent) if (spent)
return; return;
decompress.script(br, coin.script); decompress.script(coin.script, br);
coin.value = br.readVarint(); coin.value = br.readVarint();
return coin; return coin;
} }
@ -505,7 +505,7 @@ CoinEntry.prototype.toCoin = function toCoin(coins, index) {
// Seek to the coin's offset. // Seek to the coin's offset.
br.seek(this.offset); br.seek(this.offset);
decompress.script(br, coin.script); decompress.script(coin.script, br);
coin.value = br.readVarint(); coin.value = br.readVarint();

View File

@ -20,7 +20,6 @@ var ec = require('../crypto/ec');
*/ */
function compressScript(script, bw) { function compressScript(script, bw) {
var prefix = 0;
var data; var data;
// Attempt to compress the output scripts. // Attempt to compress the output scripts.
@ -28,62 +27,80 @@ function compressScript(script, bw) {
// they are serialized as minimaldata, as // they are serialized as minimaldata, as
// we need to recreate them when we read // we need to recreate them when we read
// them. // them.
// P2PKH -> 1 | key-hash
// Saves 5 bytes.
if (script.isPubkeyhash(true)) { if (script.isPubkeyhash(true)) {
prefix = 1;
data = script.code[2].data; data = script.code[2].data;
} else if (script.isScripthash()) { bw.writeU8(1);
prefix = 2; bw.writeBytes(data);
data = script.code[1].data; return bw;
} else if (script.isPubkey(true)) {
prefix = 3;
data = script.code[0].data;
// Try to compress the key.
data = compressKey(data);
// If we can't compress it,
// just store the script.
if (!data)
prefix = 0;
} }
bw.writeU8(prefix); // P2SH -> 2 | script-hash
// Saves 3 bytes.
if (prefix === 0) if (script.isScripthash()) {
bw.writeVarBytes(script.toRaw()); data = script.code[1].data;
else bw.writeU8(2);
bw.writeBytes(data); bw.writeBytes(data);
return bw;
}
// P2PK -> 3 | compressed-key
// Only works if the key is valid.
// Saves up to 34 bytes.
if (script.isPubkey(true)) {
data = script.code[0].data;
if (ec.publicKeyVerify(data)) {
data = compressKey(data);
bw.writeU8(3);
bw.writeBytes(data);
return bw;
}
}
// Raw -> 0 | varlen | script
bw.writeU8(0);
bw.writeVarBytes(script.toRaw());
return bw;
} }
/** /**
* Decompress a script from buffer reader. * Decompress a script from buffer reader.
* @param {BufferReader} br
* @param {Script} script * @param {Script} script
* @param {BufferReader} br
*/ */
function decompressScript(br, script) { function decompressScript(script, br) {
var key; var data;
// Decompress the script. // Decompress the script.
switch (br.readU8()) { switch (br.readU8()) {
case 0: case 0:
script.fromRaw(br.readVarBytes()); data = br.readVarBytes();
script.fromRaw(data);
break; break;
case 1: case 1:
script.fromPubkeyhash(br.readBytes(20)); data = br.readBytes(20, true);
script.fromPubkeyhash(data);
break; break;
case 2: case 2:
script.fromScripthash(br.readBytes(20)); data = br.readBytes(20, true);
script.fromScripthash(data);
break; break;
case 3: case 3:
data = br.readBytes(33, true);
// Decompress the key. If this fails, // Decompress the key. If this fails,
// we have database corruption! // we have database corruption!
key = decompressKey(br.readBytes(33)); data = decompressKey(data);
script.fromPubkey(key); script.fromPubkey(data);
break; break;
default: default:
throw new Error('Bad prefix.'); throw new Error('Bad prefix.');
} }
return script;
} }
/** /**
@ -157,10 +174,6 @@ function decompressValue(value) {
function compressKey(key) { function compressKey(key) {
var out; var out;
// We can't compress it if it's not valid.
if (!ec.publicKeyVerify(key))
return;
switch (key[0]) { switch (key[0]) {
case 0x02: case 0x02:
case 0x03: case 0x03:

View File

@ -303,7 +303,7 @@ Coin.prototype.fromCompressed = function fromCompressed(data) {
this.height = bits >>> 1; this.height = bits >>> 1;
this.coinbase = (bits & 1) !== 0; this.coinbase = (bits & 1) !== 0;
this.value = br.readVarint(); this.value = br.readVarint();
decompress.script(br, this.script); decompress.script(this.script, br);
if (this.height === 0x7fffffff) if (this.height === 0x7fffffff)
this.height = -1; this.height = -1;

View File

@ -1507,10 +1507,18 @@ Script.isCode = function isCode(raw) {
*/ */
Script.prototype.fromPubkey = function fromPubkey(key) { Script.prototype.fromPubkey = function fromPubkey(key) {
assert(Buffer.isBuffer(key) && key.length >= 33); assert(Buffer.isBuffer(key) && key.length >= 33 && key.length <= 65);
this.push(key);
this.push(opcodes.OP_CHECKSIG); this.raw = new Buffer(1 + key.length + 1);
this.compile(); this.raw[0] = key.length;
key.copy(this.raw, 1);
this.raw[1 + key.length] = opcodes.OP_CHECKSIG;
key = this.raw.slice(1, 1 + key.length);
this.code.push(new Opcode(key.length, key));
this.code.push(new Opcode(opcodes.OP_CHECKSIG));
return this; return this;
}; };