FindAndDelete again.
This commit is contained in:
parent
6c997e20b5
commit
278ff82658
@ -2026,6 +2026,77 @@ Script.prototype.removeData = function removeData(data) {
|
|||||||
return index.length;
|
return index.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A more accurate, but slower implementation
|
||||||
|
* of FindAndDelete. Shouldn't be necessary
|
||||||
|
* in practice.
|
||||||
|
* @private
|
||||||
|
* @param {Buffer} data
|
||||||
|
* @returns {Buffer}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Script.prototype.findAndDelete = function findAndDelete(data) {
|
||||||
|
var total = 0;
|
||||||
|
var p, raw, a, b, op, size;
|
||||||
|
|
||||||
|
if (data.length === 0)
|
||||||
|
return total;
|
||||||
|
|
||||||
|
// Compare on the byte level.
|
||||||
|
raw = this.encode();
|
||||||
|
|
||||||
|
p = new BufferReader(raw, true);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
while (p.left() >= data.length && utils.icmp(raw, data, p.offset) === 0) {
|
||||||
|
a = raw.slice(0, p.offset);
|
||||||
|
b = raw.slice(p.offset + data.length);
|
||||||
|
raw = Buffer.concat([a, b]);
|
||||||
|
p.data = raw;
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.left() === 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
op = p.readU8();
|
||||||
|
if (op >= 0x01 && op <= 0x4b) {
|
||||||
|
if (p.left() < op)
|
||||||
|
break;
|
||||||
|
p.seek(op);
|
||||||
|
} else if (op === opcodes.OP_PUSHDATA1) {
|
||||||
|
if (p.left() < 1)
|
||||||
|
break;
|
||||||
|
size = p.readU8();
|
||||||
|
if (p.left() < size)
|
||||||
|
break;
|
||||||
|
p.seek(size);
|
||||||
|
} else if (op === opcodes.OP_PUSHDATA2) {
|
||||||
|
if (p.left() < 2)
|
||||||
|
break;
|
||||||
|
size = p.readU16();
|
||||||
|
if (p.left() < size)
|
||||||
|
break;
|
||||||
|
p.seek(size);
|
||||||
|
} else if (op === opcodes.OP_PUSHDATA4) {
|
||||||
|
if (p.left() < 4)
|
||||||
|
break;
|
||||||
|
size = p.readU32();
|
||||||
|
if (p.left() < size)
|
||||||
|
break;
|
||||||
|
p.seek(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total > 0) {
|
||||||
|
this.code = Script.decode(raw);
|
||||||
|
if (this.raw)
|
||||||
|
this.raw = raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a data element in a script.
|
* Find a data element in a script.
|
||||||
* @param {Buffer} data - Data element to match against.
|
* @param {Buffer} data - Data element to match against.
|
||||||
@ -4169,6 +4240,37 @@ Script.encode = function encode(code, writer) {
|
|||||||
return p;
|
return p;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode a single push op. Note that this
|
||||||
|
* will _always_ be a PUSHDATA. Used for
|
||||||
|
* findAndDelete.
|
||||||
|
* @param {Buffer} data
|
||||||
|
* @returns {Buffer}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Script.encodePush = function encodePush(data) {
|
||||||
|
var p = new BufferWriter();
|
||||||
|
if (data.length <= 0x4b) {
|
||||||
|
p.writeU8(data.length);
|
||||||
|
p.writeBytes(data);
|
||||||
|
} else if (data.length <= 0xff) {
|
||||||
|
p.writeU8(opcodes.OP_PUSHDATA1);
|
||||||
|
p.writeU8(data.length);
|
||||||
|
p.writeBytes(data);
|
||||||
|
} else if (data.length <= 0xffff) {
|
||||||
|
p.writeU8(opcodes.OP_PUSHDATA2);
|
||||||
|
p.writeU16(data.length);
|
||||||
|
p.writeBytes(data);
|
||||||
|
} else if (data.length <= 0xffffffff) {
|
||||||
|
p.writeU8(opcodes.OP_PUSHDATA4);
|
||||||
|
p.writeU32(data.length);
|
||||||
|
p.writeBytes(data);
|
||||||
|
} else {
|
||||||
|
assert(false, 'Bad pushdata op.');
|
||||||
|
}
|
||||||
|
return p.render();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether GetOp2 should fail
|
* Determine whether GetOp2 should fail
|
||||||
* on a given op due to a bad push (either
|
* on a given op due to a bad push (either
|
||||||
|
|||||||
@ -352,4 +352,157 @@ describe('Script', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should execute FindAndDelete correctly', function() {
|
||||||
|
var s, d, expect;
|
||||||
|
|
||||||
|
function del(s) {
|
||||||
|
s.mutable = true;
|
||||||
|
delete s.raw;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = bcoin.script.fromString('OP_1 OP_2');
|
||||||
|
del(s);
|
||||||
|
d = new bcoin.script();
|
||||||
|
expect = s.clone();
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 0);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromString('OP_1 OP_2 OP_3');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromString('OP_2');
|
||||||
|
del(d);
|
||||||
|
expect = bcoin.script.fromString('OP_1 OP_3');
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 1);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromString('OP_3 OP_1 OP_3 OP_3 OP_4 OP_3');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromString('OP_3');
|
||||||
|
del(d);
|
||||||
|
expect = bcoin.script.fromString('OP_1 OP_4');
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 4);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromRaw('0302ff03', 'hex');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromRaw('0302ff03', 'hex');
|
||||||
|
del(d);
|
||||||
|
expect = new bcoin.script();
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 1);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromRaw('0302ff030302ff03', 'hex');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromRaw('0302ff03', 'hex');
|
||||||
|
del(d);
|
||||||
|
expect = new bcoin.script();
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 2);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromRaw('0302ff030302ff03', 'hex');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromRaw('02', 'hex');
|
||||||
|
del(d);
|
||||||
|
expect = s.clone();
|
||||||
|
del(expect);
|
||||||
|
//assert.equal(s.findAndDelete(d.encode()), 0);
|
||||||
|
s.findAndDelete(d.encode());
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromRaw('0302ff030302ff03', 'hex');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromRaw('ff', 'hex');
|
||||||
|
del(d);
|
||||||
|
expect = s.clone();
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 0);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromRaw('0302ff030302ff03', 'hex');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromRaw('03', 'hex');
|
||||||
|
del(d);
|
||||||
|
expect = new bcoin.script([new Buffer([0xff, 0x03]), new Buffer([0xff, 0x03])]);
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 2);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromRaw('02feed5169', 'hex');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromRaw('feed51', 'hex');
|
||||||
|
del(d);
|
||||||
|
expect = s.clone();
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 0);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromRaw('02feed5169', 'hex');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromRaw('02feed51', 'hex');
|
||||||
|
del(d);
|
||||||
|
expect = bcoin.script.fromRaw('69', 'hex');
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 1);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromRaw('516902feed5169', 'hex');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromRaw('feed51', 'hex');
|
||||||
|
del(d);
|
||||||
|
expect = s.clone();
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 0);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromRaw('516902feed5169', 'hex');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromRaw('02feed51', 'hex');
|
||||||
|
del(d);
|
||||||
|
expect = bcoin.script.fromRaw('516969', 'hex');
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 1);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromString('OP_0 OP_0 OP_1 OP_1');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromString('OP_0 OP_1');
|
||||||
|
del(d);
|
||||||
|
expect = bcoin.script.fromString('OP_0 OP_1');
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 1);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromString('OP_0 OP_0 OP_1 OP_0 OP_1 OP_1');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromString('OP_0 OP_1');
|
||||||
|
del(d);
|
||||||
|
expect = bcoin.script.fromString('OP_0 OP_1');
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 2);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromRaw('0003feed', 'hex');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromRaw('03feed', 'hex');
|
||||||
|
del(d);
|
||||||
|
expect = bcoin.script.fromRaw('00', 'hex');
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 1);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
|
||||||
|
s = bcoin.script.fromRaw('0003feed', 'hex');
|
||||||
|
del(s);
|
||||||
|
d = bcoin.script.fromRaw('00', 'hex');
|
||||||
|
del(d);
|
||||||
|
expect = bcoin.script.fromRaw('03feed', 'hex');
|
||||||
|
del(expect);
|
||||||
|
assert.equal(s.findAndDelete(d.encode()), 1);
|
||||||
|
assert.deepEqual(s.encode(), expect.encode());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user