junderw
6 years ago
45 changed files with 2964 additions and 2965 deletions
@ -1,100 +1,91 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const networks = require("./networks"); |
const networks = require('./networks'); |
||||
const payments = require("./payments"); |
const payments = require('./payments'); |
||||
const bscript = require("./script"); |
const bscript = require('./script'); |
||||
const types = require("./types"); |
const types = require('./types'); |
||||
const bech32 = require('bech32'); |
const bech32 = require('bech32'); |
||||
const bs58check = require('bs58check'); |
const bs58check = require('bs58check'); |
||||
const typeforce = require('typeforce'); |
const typeforce = require('typeforce'); |
||||
function fromBase58Check(address) { |
function fromBase58Check(address) { |
||||
const payload = bs58check.decode(address); |
const payload = bs58check.decode(address); |
||||
// TODO: 4.0.0, move to "toOutputScript"
|
// TODO: 4.0.0, move to "toOutputScript"
|
||||
if (payload.length < 21) |
if (payload.length < 21) throw new TypeError(address + ' is too short'); |
||||
throw new TypeError(address + ' is too short'); |
if (payload.length > 21) throw new TypeError(address + ' is too long'); |
||||
if (payload.length > 21) |
const version = payload.readUInt8(0); |
||||
throw new TypeError(address + ' is too long'); |
const hash = payload.slice(1); |
||||
const version = payload.readUInt8(0); |
return { version, hash }; |
||||
const hash = payload.slice(1); |
|
||||
return { version, hash }; |
|
||||
} |
} |
||||
exports.fromBase58Check = fromBase58Check; |
exports.fromBase58Check = fromBase58Check; |
||||
function fromBech32(address) { |
function fromBech32(address) { |
||||
const result = bech32.decode(address); |
const result = bech32.decode(address); |
||||
const data = bech32.fromWords(result.words.slice(1)); |
const data = bech32.fromWords(result.words.slice(1)); |
||||
return { |
return { |
||||
version: result.words[0], |
version: result.words[0], |
||||
prefix: result.prefix, |
prefix: result.prefix, |
||||
data: Buffer.from(data), |
data: Buffer.from(data), |
||||
}; |
}; |
||||
} |
} |
||||
exports.fromBech32 = fromBech32; |
exports.fromBech32 = fromBech32; |
||||
function toBase58Check(hash, version) { |
function toBase58Check(hash, version) { |
||||
typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments); |
typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments); |
||||
const payload = Buffer.allocUnsafe(21); |
const payload = Buffer.allocUnsafe(21); |
||||
payload.writeUInt8(version, 0); |
payload.writeUInt8(version, 0); |
||||
hash.copy(payload, 1); |
hash.copy(payload, 1); |
||||
return bs58check.encode(payload); |
return bs58check.encode(payload); |
||||
} |
} |
||||
exports.toBase58Check = toBase58Check; |
exports.toBase58Check = toBase58Check; |
||||
function toBech32(data, version, prefix) { |
function toBech32(data, version, prefix) { |
||||
const words = bech32.toWords(data); |
const words = bech32.toWords(data); |
||||
words.unshift(version); |
words.unshift(version); |
||||
return bech32.encode(prefix, words); |
return bech32.encode(prefix, words); |
||||
} |
} |
||||
exports.toBech32 = toBech32; |
exports.toBech32 = toBech32; |
||||
function fromOutputScript(output, network) { |
function fromOutputScript(output, network) { |
||||
// TODO: Network
|
// TODO: Network
|
||||
network = network || networks.bitcoin; |
network = network || networks.bitcoin; |
||||
try { |
try { |
||||
return payments.p2pkh({ output, network }).address; |
return payments.p2pkh({ output, network }).address; |
||||
} |
} catch (e) {} |
||||
catch (e) { } |
try { |
||||
try { |
return payments.p2sh({ output, network }).address; |
||||
return payments.p2sh({ output, network }).address; |
} catch (e) {} |
||||
} |
try { |
||||
catch (e) { } |
return payments.p2wpkh({ output, network }).address; |
||||
try { |
} catch (e) {} |
||||
return payments.p2wpkh({ output, network }).address; |
try { |
||||
} |
return payments.p2wsh({ output, network }).address; |
||||
catch (e) { } |
} catch (e) {} |
||||
try { |
throw new Error(bscript.toASM(output) + ' has no matching Address'); |
||||
return payments.p2wsh({ output, network }).address; |
|
||||
} |
|
||||
catch (e) { } |
|
||||
throw new Error(bscript.toASM(output) + ' has no matching Address'); |
|
||||
} |
} |
||||
exports.fromOutputScript = fromOutputScript; |
exports.fromOutputScript = fromOutputScript; |
||||
function toOutputScript(address, network) { |
function toOutputScript(address, network) { |
||||
network = network || networks.bitcoin; |
network = network || networks.bitcoin; |
||||
let decodeBase58; |
let decodeBase58; |
||||
let decodeBech32; |
let decodeBech32; |
||||
|
try { |
||||
|
decodeBase58 = fromBase58Check(address); |
||||
|
} catch (e) {} |
||||
|
if (decodeBase58) { |
||||
|
if (decodeBase58.version === network.pubKeyHash) |
||||
|
return payments.p2pkh({ hash: decodeBase58.hash }).output; |
||||
|
if (decodeBase58.version === network.scriptHash) |
||||
|
return payments.p2sh({ hash: decodeBase58.hash }).output; |
||||
|
} else { |
||||
try { |
try { |
||||
decodeBase58 = fromBase58Check(address); |
decodeBech32 = fromBech32(address); |
||||
} |
} catch (e) {} |
||||
catch (e) { } |
if (decodeBech32) { |
||||
if (decodeBase58) { |
if (decodeBech32.prefix !== network.bech32) |
||||
if (decodeBase58.version === network.pubKeyHash) |
throw new Error(address + ' has an invalid prefix'); |
||||
return payments.p2pkh({ hash: decodeBase58.hash }).output; |
if (decodeBech32.version === 0) { |
||||
if (decodeBase58.version === network.scriptHash) |
if (decodeBech32.data.length === 20) |
||||
return payments.p2sh({ hash: decodeBase58.hash }).output; |
return payments.p2wpkh({ hash: decodeBech32.data }).output; |
||||
} |
if (decodeBech32.data.length === 32) |
||||
else { |
return payments.p2wsh({ hash: decodeBech32.data }).output; |
||||
try { |
} |
||||
decodeBech32 = fromBech32(address); |
|
||||
} |
|
||||
catch (e) { } |
|
||||
if (decodeBech32) { |
|
||||
if (decodeBech32.prefix !== network.bech32) |
|
||||
throw new Error(address + ' has an invalid prefix'); |
|
||||
if (decodeBech32.version === 0) { |
|
||||
if (decodeBech32.data.length === 20) |
|
||||
return payments.p2wpkh({ hash: decodeBech32.data }).output; |
|
||||
if (decodeBech32.data.length === 32) |
|
||||
return payments.p2wsh({ hash: decodeBech32.data }).output; |
|
||||
} |
|
||||
} |
|
||||
} |
} |
||||
throw new Error(address + ' has no matching Script'); |
} |
||||
|
throw new Error(address + ' has no matching Script'); |
||||
} |
} |
||||
exports.toOutputScript = toOutputScript; |
exports.toOutputScript = toOutputScript; |
||||
|
@ -1,222 +1,242 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bufferutils_1 = require("./bufferutils"); |
const bufferutils_1 = require('./bufferutils'); |
||||
const bcrypto = require("./crypto"); |
const bcrypto = require('./crypto'); |
||||
const transaction_1 = require("./transaction"); |
const transaction_1 = require('./transaction'); |
||||
const types = require("./types"); |
const types = require('./types'); |
||||
const fastMerkleRoot = require('merkle-lib/fastRoot'); |
const fastMerkleRoot = require('merkle-lib/fastRoot'); |
||||
const typeforce = require('typeforce'); |
const typeforce = require('typeforce'); |
||||
const varuint = require('varuint-bitcoin'); |
const varuint = require('varuint-bitcoin'); |
||||
const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions'); |
const errorMerkleNoTxes = new TypeError( |
||||
const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block'); |
'Cannot compute merkle root for zero transactions', |
||||
|
); |
||||
|
const errorWitnessNotSegwit = new TypeError( |
||||
|
'Cannot compute witness commit for non-segwit block', |
||||
|
); |
||||
class Block { |
class Block { |
||||
constructor() { |
constructor() { |
||||
this.version = 1; |
this.version = 1; |
||||
this.prevHash = undefined; |
this.prevHash = undefined; |
||||
this.merkleRoot = undefined; |
this.merkleRoot = undefined; |
||||
this.timestamp = 0; |
this.timestamp = 0; |
||||
this.witnessCommit = undefined; |
this.witnessCommit = undefined; |
||||
this.bits = 0; |
this.bits = 0; |
||||
this.nonce = 0; |
this.nonce = 0; |
||||
this.transactions = undefined; |
this.transactions = undefined; |
||||
} |
} |
||||
static fromBuffer(buffer) { |
static fromBuffer(buffer) { |
||||
if (buffer.length < 80) |
if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)'); |
||||
throw new Error('Buffer too small (< 80 bytes)'); |
let offset = 0; |
||||
let offset = 0; |
const readSlice = n => { |
||||
const readSlice = (n) => { |
offset += n; |
||||
offset += n; |
return buffer.slice(offset - n, offset); |
||||
return buffer.slice(offset - n, offset); |
}; |
||||
}; |
const readUInt32 = () => { |
||||
const readUInt32 = () => { |
const i = buffer.readUInt32LE(offset); |
||||
const i = buffer.readUInt32LE(offset); |
offset += 4; |
||||
offset += 4; |
return i; |
||||
return i; |
}; |
||||
}; |
const readInt32 = () => { |
||||
const readInt32 = () => { |
const i = buffer.readInt32LE(offset); |
||||
const i = buffer.readInt32LE(offset); |
offset += 4; |
||||
offset += 4; |
return i; |
||||
return i; |
}; |
||||
}; |
const block = new Block(); |
||||
const block = new Block(); |
block.version = readInt32(); |
||||
block.version = readInt32(); |
block.prevHash = readSlice(32); |
||||
block.prevHash = readSlice(32); |
block.merkleRoot = readSlice(32); |
||||
block.merkleRoot = readSlice(32); |
block.timestamp = readUInt32(); |
||||
block.timestamp = readUInt32(); |
block.bits = readUInt32(); |
||||
block.bits = readUInt32(); |
block.nonce = readUInt32(); |
||||
block.nonce = readUInt32(); |
if (buffer.length === 80) return block; |
||||
if (buffer.length === 80) |
const readVarInt = () => { |
||||
return block; |
const vi = varuint.decode(buffer, offset); |
||||
const readVarInt = () => { |
offset += varuint.decode.bytes; |
||||
const vi = varuint.decode(buffer, offset); |
return vi; |
||||
offset += varuint.decode.bytes; |
}; |
||||
return vi; |
const readTransaction = () => { |
||||
}; |
const tx = transaction_1.Transaction.fromBuffer( |
||||
const readTransaction = () => { |
buffer.slice(offset), |
||||
const tx = transaction_1.Transaction.fromBuffer(buffer.slice(offset), true); |
true, |
||||
offset += tx.byteLength(); |
); |
||||
return tx; |
offset += tx.byteLength(); |
||||
}; |
return tx; |
||||
const nTransactions = readVarInt(); |
}; |
||||
block.transactions = []; |
const nTransactions = readVarInt(); |
||||
for (let i = 0; i < nTransactions; ++i) { |
block.transactions = []; |
||||
const tx = readTransaction(); |
for (let i = 0; i < nTransactions; ++i) { |
||||
block.transactions.push(tx); |
const tx = readTransaction(); |
||||
} |
block.transactions.push(tx); |
||||
const witnessCommit = block.getWitnessCommit(); |
} |
||||
// This Block contains a witness commit
|
const witnessCommit = block.getWitnessCommit(); |
||||
if (witnessCommit) |
// This Block contains a witness commit
|
||||
block.witnessCommit = witnessCommit; |
if (witnessCommit) block.witnessCommit = witnessCommit; |
||||
return block; |
return block; |
||||
} |
} |
||||
static fromHex(hex) { |
static fromHex(hex) { |
||||
return Block.fromBuffer(Buffer.from(hex, 'hex')); |
return Block.fromBuffer(Buffer.from(hex, 'hex')); |
||||
} |
} |
||||
static calculateTarget(bits) { |
static calculateTarget(bits) { |
||||
const exponent = ((bits & 0xff000000) >> 24) - 3; |
const exponent = ((bits & 0xff000000) >> 24) - 3; |
||||
const mantissa = bits & 0x007fffff; |
const mantissa = bits & 0x007fffff; |
||||
const target = Buffer.alloc(32, 0); |
const target = Buffer.alloc(32, 0); |
||||
target.writeUIntBE(mantissa, 29 - exponent, 3); |
target.writeUIntBE(mantissa, 29 - exponent, 3); |
||||
return target; |
return target; |
||||
} |
} |
||||
static calculateMerkleRoot(transactions, forWitness) { |
static calculateMerkleRoot(transactions, forWitness) { |
||||
typeforce([{ getHash: types.Function }], transactions); |
typeforce([{ getHash: types.Function }], transactions); |
||||
if (transactions.length === 0) |
if (transactions.length === 0) throw errorMerkleNoTxes; |
||||
throw errorMerkleNoTxes; |
if (forWitness && !txesHaveWitnessCommit(transactions)) |
||||
if (forWitness && !txesHaveWitnessCommit(transactions)) |
throw errorWitnessNotSegwit; |
||||
throw errorWitnessNotSegwit; |
const hashes = transactions.map(transaction => |
||||
const hashes = transactions.map(transaction => transaction.getHash(forWitness)); |
transaction.getHash(forWitness), |
||||
const rootHash = fastMerkleRoot(hashes, bcrypto.hash256); |
); |
||||
return forWitness |
const rootHash = fastMerkleRoot(hashes, bcrypto.hash256); |
||||
? bcrypto.hash256(Buffer.concat([rootHash, transactions[0].ins[0].witness[0]])) |
return forWitness |
||||
: rootHash; |
? bcrypto.hash256( |
||||
} |
Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]), |
||||
getWitnessCommit() { |
) |
||||
if (!txesHaveWitnessCommit(this.transactions)) |
: rootHash; |
||||
return null; |
} |
||||
// The merkle root for the witness data is in an OP_RETURN output.
|
getWitnessCommit() { |
||||
// There is no rule for the index of the output, so use filter to find it.
|
if (!txesHaveWitnessCommit(this.transactions)) return null; |
||||
// The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed
|
// The merkle root for the witness data is in an OP_RETURN output.
|
||||
// If multiple commits are found, the output with highest index is assumed.
|
// There is no rule for the index of the output, so use filter to find it.
|
||||
const witnessCommits = this.transactions[0].outs.filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))).map(out => out.script.slice(6, 38)); |
// The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed
|
||||
if (witnessCommits.length === 0) |
// If multiple commits are found, the output with highest index is assumed.
|
||||
return null; |
const witnessCommits = this.transactions[0].outs |
||||
// Use the commit with the highest output (should only be one though)
|
.filter(out => |
||||
const result = witnessCommits[witnessCommits.length - 1]; |
out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), |
||||
if (!(result instanceof Buffer && result.length === 32)) |
) |
||||
return null; |
.map(out => out.script.slice(6, 38)); |
||||
return result; |
if (witnessCommits.length === 0) return null; |
||||
} |
// Use the commit with the highest output (should only be one though)
|
||||
hasWitnessCommit() { |
const result = witnessCommits[witnessCommits.length - 1]; |
||||
if (this.witnessCommit instanceof Buffer && |
if (!(result instanceof Buffer && result.length === 32)) return null; |
||||
this.witnessCommit.length === 32) |
return result; |
||||
return true; |
} |
||||
if (this.getWitnessCommit() !== null) |
hasWitnessCommit() { |
||||
return true; |
if ( |
||||
return false; |
this.witnessCommit instanceof Buffer && |
||||
} |
this.witnessCommit.length === 32 |
||||
hasWitness() { |
) |
||||
return anyTxHasWitness(this.transactions); |
return true; |
||||
} |
if (this.getWitnessCommit() !== null) return true; |
||||
byteLength(headersOnly) { |
return false; |
||||
if (headersOnly || !this.transactions) |
} |
||||
return 80; |
hasWitness() { |
||||
return (80 + |
return anyTxHasWitness(this.transactions); |
||||
varuint.encodingLength(this.transactions.length) + |
} |
||||
this.transactions.reduce((a, x) => a + x.byteLength(), 0)); |
byteLength(headersOnly) { |
||||
} |
if (headersOnly || !this.transactions) return 80; |
||||
getHash() { |
return ( |
||||
return bcrypto.hash256(this.toBuffer(true)); |
80 + |
||||
} |
varuint.encodingLength(this.transactions.length) + |
||||
getId() { |
this.transactions.reduce((a, x) => a + x.byteLength(), 0) |
||||
return bufferutils_1.reverseBuffer(this.getHash()).toString('hex'); |
); |
||||
} |
} |
||||
getUTCDate() { |
getHash() { |
||||
const date = new Date(0); // epoch
|
return bcrypto.hash256(this.toBuffer(true)); |
||||
date.setUTCSeconds(this.timestamp); |
} |
||||
return date; |
getId() { |
||||
} |
return bufferutils_1.reverseBuffer(this.getHash()).toString('hex'); |
||||
// TODO: buffer, offset compatibility
|
} |
||||
toBuffer(headersOnly) { |
getUTCDate() { |
||||
const buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)); |
const date = new Date(0); // epoch
|
||||
let offset = 0; |
date.setUTCSeconds(this.timestamp); |
||||
const writeSlice = (slice) => { |
return date; |
||||
slice.copy(buffer, offset); |
} |
||||
offset += slice.length; |
// TODO: buffer, offset compatibility
|
||||
}; |
toBuffer(headersOnly) { |
||||
const writeInt32 = (i) => { |
const buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)); |
||||
buffer.writeInt32LE(i, offset); |
let offset = 0; |
||||
offset += 4; |
const writeSlice = slice => { |
||||
}; |
slice.copy(buffer, offset); |
||||
const writeUInt32 = (i) => { |
offset += slice.length; |
||||
buffer.writeUInt32LE(i, offset); |
}; |
||||
offset += 4; |
const writeInt32 = i => { |
||||
}; |
buffer.writeInt32LE(i, offset); |
||||
writeInt32(this.version); |
offset += 4; |
||||
writeSlice(this.prevHash); |
}; |
||||
writeSlice(this.merkleRoot); |
const writeUInt32 = i => { |
||||
writeUInt32(this.timestamp); |
buffer.writeUInt32LE(i, offset); |
||||
writeUInt32(this.bits); |
offset += 4; |
||||
writeUInt32(this.nonce); |
}; |
||||
if (headersOnly || !this.transactions) |
writeInt32(this.version); |
||||
return buffer; |
writeSlice(this.prevHash); |
||||
varuint.encode(this.transactions.length, buffer, offset); |
writeSlice(this.merkleRoot); |
||||
offset += varuint.encode.bytes; |
writeUInt32(this.timestamp); |
||||
this.transactions.forEach(tx => { |
writeUInt32(this.bits); |
||||
const txSize = tx.byteLength(); // TODO: extract from toBuffer?
|
writeUInt32(this.nonce); |
||||
tx.toBuffer(buffer, offset); |
if (headersOnly || !this.transactions) return buffer; |
||||
offset += txSize; |
varuint.encode(this.transactions.length, buffer, offset); |
||||
}); |
offset += varuint.encode.bytes; |
||||
return buffer; |
this.transactions.forEach(tx => { |
||||
} |
const txSize = tx.byteLength(); // TODO: extract from toBuffer?
|
||||
toHex(headersOnly) { |
tx.toBuffer(buffer, offset); |
||||
return this.toBuffer(headersOnly).toString('hex'); |
offset += txSize; |
||||
} |
}); |
||||
checkTxRoots() { |
return buffer; |
||||
// If the Block has segwit transactions but no witness commit,
|
} |
||||
// there's no way it can be valid, so fail the check.
|
toHex(headersOnly) { |
||||
const hasWitnessCommit = this.hasWitnessCommit(); |
return this.toBuffer(headersOnly).toString('hex'); |
||||
if (!hasWitnessCommit && this.hasWitness()) |
} |
||||
return false; |
checkTxRoots() { |
||||
return (this.__checkMerkleRoot() && |
// If the Block has segwit transactions but no witness commit,
|
||||
(hasWitnessCommit ? this.__checkWitnessCommit() : true)); |
// there's no way it can be valid, so fail the check.
|
||||
} |
const hasWitnessCommit = this.hasWitnessCommit(); |
||||
checkProofOfWork() { |
if (!hasWitnessCommit && this.hasWitness()) return false; |
||||
const hash = bufferutils_1.reverseBuffer(this.getHash()); |
return ( |
||||
const target = Block.calculateTarget(this.bits); |
this.__checkMerkleRoot() && |
||||
return hash.compare(target) <= 0; |
(hasWitnessCommit ? this.__checkWitnessCommit() : true) |
||||
} |
); |
||||
__checkMerkleRoot() { |
} |
||||
if (!this.transactions) |
checkProofOfWork() { |
||||
throw errorMerkleNoTxes; |
const hash = bufferutils_1.reverseBuffer(this.getHash()); |
||||
const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); |
const target = Block.calculateTarget(this.bits); |
||||
return this.merkleRoot.compare(actualMerkleRoot) === 0; |
return hash.compare(target) <= 0; |
||||
} |
} |
||||
__checkWitnessCommit() { |
__checkMerkleRoot() { |
||||
if (!this.transactions) |
if (!this.transactions) throw errorMerkleNoTxes; |
||||
throw errorMerkleNoTxes; |
const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); |
||||
if (!this.hasWitnessCommit()) |
return this.merkleRoot.compare(actualMerkleRoot) === 0; |
||||
throw errorWitnessNotSegwit; |
} |
||||
const actualWitnessCommit = Block.calculateMerkleRoot(this.transactions, true); |
__checkWitnessCommit() { |
||||
return this.witnessCommit.compare(actualWitnessCommit) === 0; |
if (!this.transactions) throw errorMerkleNoTxes; |
||||
} |
if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit; |
||||
|
const actualWitnessCommit = Block.calculateMerkleRoot( |
||||
|
this.transactions, |
||||
|
true, |
||||
|
); |
||||
|
return this.witnessCommit.compare(actualWitnessCommit) === 0; |
||||
|
} |
||||
} |
} |
||||
exports.Block = Block; |
exports.Block = Block; |
||||
function txesHaveWitnessCommit(transactions) { |
function txesHaveWitnessCommit(transactions) { |
||||
return (transactions instanceof Array && |
return ( |
||||
transactions[0] && |
transactions instanceof Array && |
||||
transactions[0].ins && |
transactions[0] && |
||||
transactions[0].ins instanceof Array && |
transactions[0].ins && |
||||
transactions[0].ins[0] && |
transactions[0].ins instanceof Array && |
||||
transactions[0].ins[0].witness && |
transactions[0].ins[0] && |
||||
transactions[0].ins[0].witness instanceof Array && |
transactions[0].ins[0].witness && |
||||
transactions[0].ins[0].witness.length > 0); |
transactions[0].ins[0].witness instanceof Array && |
||||
|
transactions[0].ins[0].witness.length > 0 |
||||
|
); |
||||
} |
} |
||||
function anyTxHasWitness(transactions) { |
function anyTxHasWitness(transactions) { |
||||
return (transactions instanceof Array && |
return ( |
||||
transactions.some(tx => typeof tx === 'object' && |
transactions instanceof Array && |
||||
tx.ins instanceof Array && |
transactions.some( |
||||
tx.ins.some(input => typeof input === 'object' && |
tx => |
||||
input.witness instanceof Array && |
typeof tx === 'object' && |
||||
input.witness.length > 0))); |
tx.ins instanceof Array && |
||||
|
tx.ins.some( |
||||
|
input => |
||||
|
typeof input === 'object' && |
||||
|
input.witness instanceof Array && |
||||
|
input.witness.length > 0, |
||||
|
), |
||||
|
) |
||||
|
); |
||||
} |
} |
||||
|
@ -1,42 +1,40 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
// https://github.com/feross/buffer/blob/master/index.js#L1127
|
// https://github.com/feross/buffer/blob/master/index.js#L1127
|
||||
function verifuint(value, max) { |
function verifuint(value, max) { |
||||
if (typeof value !== 'number') |
if (typeof value !== 'number') |
||||
throw new Error('cannot write a non-number as a number'); |
throw new Error('cannot write a non-number as a number'); |
||||
if (value < 0) |
if (value < 0) |
||||
throw new Error('specified a negative value for writing an unsigned value'); |
throw new Error('specified a negative value for writing an unsigned value'); |
||||
if (value > max) |
if (value > max) throw new Error('RangeError: value out of range'); |
||||
throw new Error('RangeError: value out of range'); |
if (Math.floor(value) !== value) |
||||
if (Math.floor(value) !== value) |
throw new Error('value has a fractional component'); |
||||
throw new Error('value has a fractional component'); |
|
||||
} |
} |
||||
function readUInt64LE(buffer, offset) { |
function readUInt64LE(buffer, offset) { |
||||
const a = buffer.readUInt32LE(offset); |
const a = buffer.readUInt32LE(offset); |
||||
let b = buffer.readUInt32LE(offset + 4); |
let b = buffer.readUInt32LE(offset + 4); |
||||
b *= 0x100000000; |
b *= 0x100000000; |
||||
verifuint(b + a, 0x001fffffffffffff); |
verifuint(b + a, 0x001fffffffffffff); |
||||
return b + a; |
return b + a; |
||||
} |
} |
||||
exports.readUInt64LE = readUInt64LE; |
exports.readUInt64LE = readUInt64LE; |
||||
function writeUInt64LE(buffer, value, offset) { |
function writeUInt64LE(buffer, value, offset) { |
||||
verifuint(value, 0x001fffffffffffff); |
verifuint(value, 0x001fffffffffffff); |
||||
buffer.writeInt32LE(value & -1, offset); |
buffer.writeInt32LE(value & -1, offset); |
||||
buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); |
buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); |
||||
return offset + 8; |
return offset + 8; |
||||
} |
} |
||||
exports.writeUInt64LE = writeUInt64LE; |
exports.writeUInt64LE = writeUInt64LE; |
||||
function reverseBuffer(buffer) { |
function reverseBuffer(buffer) { |
||||
if (buffer.length < 1) |
if (buffer.length < 1) return buffer; |
||||
return buffer; |
let j = buffer.length - 1; |
||||
let j = buffer.length - 1; |
let tmp = 0; |
||||
let tmp = 0; |
for (let i = 0; i < buffer.length / 2; i++) { |
||||
for (let i = 0; i < buffer.length / 2; i++) { |
tmp = buffer[i]; |
||||
tmp = buffer[i]; |
buffer[i] = buffer[j]; |
||||
buffer[i] = buffer[j]; |
buffer[j] = tmp; |
||||
buffer[j] = tmp; |
j--; |
||||
j--; |
} |
||||
} |
return buffer; |
||||
return buffer; |
|
||||
} |
} |
||||
exports.reverseBuffer = reverseBuffer; |
exports.reverseBuffer = reverseBuffer; |
||||
|
@ -1,75 +1,59 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const script_1 = require("./script"); |
const script_1 = require('./script'); |
||||
const multisig = require("./templates/multisig"); |
const multisig = require('./templates/multisig'); |
||||
const nullData = require("./templates/nulldata"); |
const nullData = require('./templates/nulldata'); |
||||
const pubKey = require("./templates/pubkey"); |
const pubKey = require('./templates/pubkey'); |
||||
const pubKeyHash = require("./templates/pubkeyhash"); |
const pubKeyHash = require('./templates/pubkeyhash'); |
||||
const scriptHash = require("./templates/scripthash"); |
const scriptHash = require('./templates/scripthash'); |
||||
const witnessCommitment = require("./templates/witnesscommitment"); |
const witnessCommitment = require('./templates/witnesscommitment'); |
||||
const witnessPubKeyHash = require("./templates/witnesspubkeyhash"); |
const witnessPubKeyHash = require('./templates/witnesspubkeyhash'); |
||||
const witnessScriptHash = require("./templates/witnessscripthash"); |
const witnessScriptHash = require('./templates/witnessscripthash'); |
||||
const types = { |
const types = { |
||||
P2MS: 'multisig', |
P2MS: 'multisig', |
||||
NONSTANDARD: 'nonstandard', |
NONSTANDARD: 'nonstandard', |
||||
NULLDATA: 'nulldata', |
NULLDATA: 'nulldata', |
||||
P2PK: 'pubkey', |
P2PK: 'pubkey', |
||||
P2PKH: 'pubkeyhash', |
P2PKH: 'pubkeyhash', |
||||
P2SH: 'scripthash', |
P2SH: 'scripthash', |
||||
P2WPKH: 'witnesspubkeyhash', |
P2WPKH: 'witnesspubkeyhash', |
||||
P2WSH: 'witnessscripthash', |
P2WSH: 'witnessscripthash', |
||||
WITNESS_COMMITMENT: 'witnesscommitment', |
WITNESS_COMMITMENT: 'witnesscommitment', |
||||
}; |
}; |
||||
exports.types = types; |
exports.types = types; |
||||
function classifyOutput(script) { |
function classifyOutput(script) { |
||||
if (witnessPubKeyHash.output.check(script)) |
if (witnessPubKeyHash.output.check(script)) return types.P2WPKH; |
||||
return types.P2WPKH; |
if (witnessScriptHash.output.check(script)) return types.P2WSH; |
||||
if (witnessScriptHash.output.check(script)) |
if (pubKeyHash.output.check(script)) return types.P2PKH; |
||||
return types.P2WSH; |
if (scriptHash.output.check(script)) return types.P2SH; |
||||
if (pubKeyHash.output.check(script)) |
// XXX: optimization, below functions .decompile before use
|
||||
return types.P2PKH; |
const chunks = script_1.decompile(script); |
||||
if (scriptHash.output.check(script)) |
if (!chunks) throw new TypeError('Invalid script'); |
||||
return types.P2SH; |
if (multisig.output.check(chunks)) return types.P2MS; |
||||
// XXX: optimization, below functions .decompile before use
|
if (pubKey.output.check(chunks)) return types.P2PK; |
||||
const chunks = script_1.decompile(script); |
if (witnessCommitment.output.check(chunks)) return types.WITNESS_COMMITMENT; |
||||
if (!chunks) |
if (nullData.output.check(chunks)) return types.NULLDATA; |
||||
throw new TypeError('Invalid script'); |
return types.NONSTANDARD; |
||||
if (multisig.output.check(chunks)) |
|
||||
return types.P2MS; |
|
||||
if (pubKey.output.check(chunks)) |
|
||||
return types.P2PK; |
|
||||
if (witnessCommitment.output.check(chunks)) |
|
||||
return types.WITNESS_COMMITMENT; |
|
||||
if (nullData.output.check(chunks)) |
|
||||
return types.NULLDATA; |
|
||||
return types.NONSTANDARD; |
|
||||
} |
} |
||||
exports.output = classifyOutput; |
exports.output = classifyOutput; |
||||
function classifyInput(script, allowIncomplete) { |
function classifyInput(script, allowIncomplete) { |
||||
// XXX: optimization, below functions .decompile before use
|
// XXX: optimization, below functions .decompile before use
|
||||
const chunks = script_1.decompile(script); |
const chunks = script_1.decompile(script); |
||||
if (!chunks) |
if (!chunks) throw new TypeError('Invalid script'); |
||||
throw new TypeError('Invalid script'); |
if (pubKeyHash.input.check(chunks)) return types.P2PKH; |
||||
if (pubKeyHash.input.check(chunks)) |
if (scriptHash.input.check(chunks, allowIncomplete)) return types.P2SH; |
||||
return types.P2PKH; |
if (multisig.input.check(chunks, allowIncomplete)) return types.P2MS; |
||||
if (scriptHash.input.check(chunks, allowIncomplete)) |
if (pubKey.input.check(chunks)) return types.P2PK; |
||||
return types.P2SH; |
return types.NONSTANDARD; |
||||
if (multisig.input.check(chunks, allowIncomplete)) |
|
||||
return types.P2MS; |
|
||||
if (pubKey.input.check(chunks)) |
|
||||
return types.P2PK; |
|
||||
return types.NONSTANDARD; |
|
||||
} |
} |
||||
exports.input = classifyInput; |
exports.input = classifyInput; |
||||
function classifyWitness(script, allowIncomplete) { |
function classifyWitness(script, allowIncomplete) { |
||||
// XXX: optimization, below functions .decompile before use
|
// XXX: optimization, below functions .decompile before use
|
||||
const chunks = script_1.decompile(script); |
const chunks = script_1.decompile(script); |
||||
if (!chunks) |
if (!chunks) throw new TypeError('Invalid script'); |
||||
throw new TypeError('Invalid script'); |
if (witnessPubKeyHash.input.check(chunks)) return types.P2WPKH; |
||||
if (witnessPubKeyHash.input.check(chunks)) |
if (witnessScriptHash.input.check(chunks, allowIncomplete)) |
||||
return types.P2WPKH; |
return types.P2WSH; |
||||
if (witnessScriptHash.input.check(chunks, allowIncomplete)) |
return types.NONSTANDARD; |
||||
return types.P2WSH; |
|
||||
return types.NONSTANDARD; |
|
||||
} |
} |
||||
exports.witness = classifyWitness; |
exports.witness = classifyWitness; |
||||
|
@ -1,36 +1,35 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const createHash = require('create-hash'); |
const createHash = require('create-hash'); |
||||
function ripemd160(buffer) { |
function ripemd160(buffer) { |
||||
try { |
try { |
||||
return createHash('rmd160') |
return createHash('rmd160') |
||||
.update(buffer) |
.update(buffer) |
||||
.digest(); |
.digest(); |
||||
} |
} catch (err) { |
||||
catch (err) { |
return createHash('ripemd160') |
||||
return createHash('ripemd160') |
.update(buffer) |
||||
.update(buffer) |
.digest(); |
||||
.digest(); |
} |
||||
} |
|
||||
} |
} |
||||
exports.ripemd160 = ripemd160; |
exports.ripemd160 = ripemd160; |
||||
function sha1(buffer) { |
function sha1(buffer) { |
||||
return createHash('sha1') |
return createHash('sha1') |
||||
.update(buffer) |
.update(buffer) |
||||
.digest(); |
.digest(); |
||||
} |
} |
||||
exports.sha1 = sha1; |
exports.sha1 = sha1; |
||||
function sha256(buffer) { |
function sha256(buffer) { |
||||
return createHash('sha256') |
return createHash('sha256') |
||||
.update(buffer) |
.update(buffer) |
||||
.digest(); |
.digest(); |
||||
} |
} |
||||
exports.sha256 = sha256; |
exports.sha256 = sha256; |
||||
function hash160(buffer) { |
function hash160(buffer) { |
||||
return ripemd160(sha256(buffer)); |
return ripemd160(sha256(buffer)); |
||||
} |
} |
||||
exports.hash160 = hash160; |
exports.hash160 = hash160; |
||||
function hash256(buffer) { |
function hash256(buffer) { |
||||
return sha256(sha256(buffer)); |
return sha256(sha256(buffer)); |
||||
} |
} |
||||
exports.hash256 = hash256; |
exports.hash256 = hash256; |
||||
|
@ -1,98 +1,91 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const NETWORKS = require("./networks"); |
const NETWORKS = require('./networks'); |
||||
const types = require("./types"); |
const types = require('./types'); |
||||
const ecc = require('tiny-secp256k1'); |
const ecc = require('tiny-secp256k1'); |
||||
const randomBytes = require('randombytes'); |
const randomBytes = require('randombytes'); |
||||
const typeforce = require('typeforce'); |
const typeforce = require('typeforce'); |
||||
const wif = require('wif'); |
const wif = require('wif'); |
||||
const isOptions = typeforce.maybe(typeforce.compile({ |
const isOptions = typeforce.maybe( |
||||
|
typeforce.compile({ |
||||
compressed: types.maybe(types.Boolean), |
compressed: types.maybe(types.Boolean), |
||||
network: types.maybe(types.Network), |
network: types.maybe(types.Network), |
||||
})); |
}), |
||||
|
); |
||||
class ECPair { |
class ECPair { |
||||
constructor(__D, __Q, options) { |
constructor(__D, __Q, options) { |
||||
this.__D = __D; |
this.__D = __D; |
||||
this.__Q = __Q; |
this.__Q = __Q; |
||||
if (options === undefined) |
if (options === undefined) options = {}; |
||||
options = {}; |
this.compressed = |
||||
this.compressed = |
options.compressed === undefined ? true : options.compressed; |
||||
options.compressed === undefined ? true : options.compressed; |
this.network = options.network || NETWORKS.bitcoin; |
||||
this.network = options.network || NETWORKS.bitcoin; |
if (__Q !== undefined) this.__Q = ecc.pointCompress(__Q, this.compressed); |
||||
if (__Q !== undefined) |
} |
||||
this.__Q = ecc.pointCompress(__Q, this.compressed); |
get privateKey() { |
||||
} |
return this.__D; |
||||
get privateKey() { |
} |
||||
return this.__D; |
get publicKey() { |
||||
} |
if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__D, this.compressed); |
||||
get publicKey() { |
return this.__Q; |
||||
if (!this.__Q) |
} |
||||
this.__Q = ecc.pointFromScalar(this.__D, this.compressed); |
toWIF() { |
||||
return this.__Q; |
if (!this.__D) throw new Error('Missing private key'); |
||||
} |
return wif.encode(this.network.wif, this.__D, this.compressed); |
||||
toWIF() { |
} |
||||
if (!this.__D) |
sign(hash) { |
||||
throw new Error('Missing private key'); |
if (!this.__D) throw new Error('Missing private key'); |
||||
return wif.encode(this.network.wif, this.__D, this.compressed); |
return ecc.sign(hash, this.__D); |
||||
} |
} |
||||
sign(hash) { |
verify(hash, signature) { |
||||
if (!this.__D) |
return ecc.verify(hash, this.publicKey, signature); |
||||
throw new Error('Missing private key'); |
} |
||||
return ecc.sign(hash, this.__D); |
|
||||
} |
|
||||
verify(hash, signature) { |
|
||||
return ecc.verify(hash, this.publicKey, signature); |
|
||||
} |
|
||||
} |
} |
||||
function fromPrivateKey(buffer, options) { |
function fromPrivateKey(buffer, options) { |
||||
typeforce(types.Buffer256bit, buffer); |
typeforce(types.Buffer256bit, buffer); |
||||
if (!ecc.isPrivate(buffer)) |
if (!ecc.isPrivate(buffer)) |
||||
throw new TypeError('Private key not in range [1, n)'); |
throw new TypeError('Private key not in range [1, n)'); |
||||
typeforce(isOptions, options); |
typeforce(isOptions, options); |
||||
return new ECPair(buffer, undefined, options); |
return new ECPair(buffer, undefined, options); |
||||
} |
} |
||||
exports.fromPrivateKey = fromPrivateKey; |
exports.fromPrivateKey = fromPrivateKey; |
||||
function fromPublicKey(buffer, options) { |
function fromPublicKey(buffer, options) { |
||||
typeforce(ecc.isPoint, buffer); |
typeforce(ecc.isPoint, buffer); |
||||
typeforce(isOptions, options); |
typeforce(isOptions, options); |
||||
return new ECPair(undefined, buffer, options); |
return new ECPair(undefined, buffer, options); |
||||
} |
} |
||||
exports.fromPublicKey = fromPublicKey; |
exports.fromPublicKey = fromPublicKey; |
||||
function fromWIF(wifString, network) { |
function fromWIF(wifString, network) { |
||||
const decoded = wif.decode(wifString); |
const decoded = wif.decode(wifString); |
||||
const version = decoded.version; |
const version = decoded.version; |
||||
// list of networks?
|
// list of networks?
|
||||
if (types.Array(network)) { |
if (types.Array(network)) { |
||||
network = network |
network = network |
||||
.filter((x) => { |
.filter(x => { |
||||
return version === x.wif; |
return version === x.wif; |
||||
}) |
}) |
||||
.pop(); |
.pop(); |
||||
if (!network) |
if (!network) throw new Error('Unknown network version'); |
||||
throw new Error('Unknown network version'); |
// otherwise, assume a network object (or default to bitcoin)
|
||||
// otherwise, assume a network object (or default to bitcoin)
|
} else { |
||||
} |
network = network || NETWORKS.bitcoin; |
||||
else { |
if (version !== network.wif) throw new Error('Invalid network version'); |
||||
network = network || NETWORKS.bitcoin; |
} |
||||
if (version !== network.wif) |
return fromPrivateKey(decoded.privateKey, { |
||||
throw new Error('Invalid network version'); |
compressed: decoded.compressed, |
||||
} |
network: network, |
||||
return fromPrivateKey(decoded.privateKey, { |
}); |
||||
compressed: decoded.compressed, |
|
||||
network: network, |
|
||||
}); |
|
||||
} |
} |
||||
exports.fromWIF = fromWIF; |
exports.fromWIF = fromWIF; |
||||
function makeRandom(options) { |
function makeRandom(options) { |
||||
typeforce(isOptions, options); |
typeforce(isOptions, options); |
||||
if (options === undefined) |
if (options === undefined) options = {}; |
||||
options = {}; |
const rng = options.rng || randomBytes; |
||||
const rng = options.rng || randomBytes; |
let d; |
||||
let d; |
do { |
||||
do { |
d = rng(32); |
||||
d = rng(32); |
typeforce(types.Buffer256bit, d); |
||||
typeforce(types.Buffer256bit, d); |
} while (!ecc.isPrivate(d)); |
||||
} while (!ecc.isPrivate(d)); |
return fromPrivateKey(d, options); |
||||
return fromPrivateKey(d, options); |
|
||||
} |
} |
||||
exports.makeRandom = makeRandom; |
exports.makeRandom = makeRandom; |
||||
|
@ -1,24 +1,24 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bip32 = require("bip32"); |
const bip32 = require('bip32'); |
||||
exports.bip32 = bip32; |
exports.bip32 = bip32; |
||||
const address = require("./address"); |
const address = require('./address'); |
||||
exports.address = address; |
exports.address = address; |
||||
const crypto = require("./crypto"); |
const crypto = require('./crypto'); |
||||
exports.crypto = crypto; |
exports.crypto = crypto; |
||||
const ECPair = require("./ecpair"); |
const ECPair = require('./ecpair'); |
||||
exports.ECPair = ECPair; |
exports.ECPair = ECPair; |
||||
const networks = require("./networks"); |
const networks = require('./networks'); |
||||
exports.networks = networks; |
exports.networks = networks; |
||||
const payments = require("./payments"); |
const payments = require('./payments'); |
||||
exports.payments = payments; |
exports.payments = payments; |
||||
const script = require("./script"); |
const script = require('./script'); |
||||
exports.script = script; |
exports.script = script; |
||||
var block_1 = require("./block"); |
var block_1 = require('./block'); |
||||
exports.Block = block_1.Block; |
exports.Block = block_1.Block; |
||||
var script_1 = require("./script"); |
var script_1 = require('./script'); |
||||
exports.opcodes = script_1.OPS; |
exports.opcodes = script_1.OPS; |
||||
var transaction_1 = require("./transaction"); |
var transaction_1 = require('./transaction'); |
||||
exports.Transaction = transaction_1.Transaction; |
exports.Transaction = transaction_1.Transaction; |
||||
var transaction_builder_1 = require("./transaction_builder"); |
var transaction_builder_1 = require('./transaction_builder'); |
||||
exports.TransactionBuilder = transaction_builder_1.TransactionBuilder; |
exports.TransactionBuilder = transaction_builder_1.TransactionBuilder; |
||||
|
@ -1,35 +1,35 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
exports.bitcoin = { |
exports.bitcoin = { |
||||
messagePrefix: '\x18Bitcoin Signed Message:\n', |
messagePrefix: '\x18Bitcoin Signed Message:\n', |
||||
bech32: 'bc', |
bech32: 'bc', |
||||
bip32: { |
bip32: { |
||||
public: 0x0488b21e, |
public: 0x0488b21e, |
||||
private: 0x0488ade4, |
private: 0x0488ade4, |
||||
}, |
}, |
||||
pubKeyHash: 0x00, |
pubKeyHash: 0x00, |
||||
scriptHash: 0x05, |
scriptHash: 0x05, |
||||
wif: 0x80, |
wif: 0x80, |
||||
}; |
}; |
||||
exports.regtest = { |
exports.regtest = { |
||||
messagePrefix: '\x18Bitcoin Signed Message:\n', |
messagePrefix: '\x18Bitcoin Signed Message:\n', |
||||
bech32: 'bcrt', |
bech32: 'bcrt', |
||||
bip32: { |
bip32: { |
||||
public: 0x043587cf, |
public: 0x043587cf, |
||||
private: 0x04358394, |
private: 0x04358394, |
||||
}, |
}, |
||||
pubKeyHash: 0x6f, |
pubKeyHash: 0x6f, |
||||
scriptHash: 0xc4, |
scriptHash: 0xc4, |
||||
wif: 0xef, |
wif: 0xef, |
||||
}; |
}; |
||||
exports.testnet = { |
exports.testnet = { |
||||
messagePrefix: '\x18Bitcoin Signed Message:\n', |
messagePrefix: '\x18Bitcoin Signed Message:\n', |
||||
bech32: 'tb', |
bech32: 'tb', |
||||
bip32: { |
bip32: { |
||||
public: 0x043587cf, |
public: 0x043587cf, |
||||
private: 0x04358394, |
private: 0x04358394, |
||||
}, |
}, |
||||
pubKeyHash: 0x6f, |
pubKeyHash: 0x6f, |
||||
scriptHash: 0xc4, |
scriptHash: 0xc4, |
||||
wif: 0xef, |
wif: 0xef, |
||||
}; |
}; |
||||
|
@ -1,51 +1,49 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const networks_1 = require("../networks"); |
const networks_1 = require('../networks'); |
||||
const bscript = require("../script"); |
const bscript = require('../script'); |
||||
const lazy = require("./lazy"); |
const lazy = require('./lazy'); |
||||
const typef = require('typeforce'); |
const typef = require('typeforce'); |
||||
const OPS = bscript.OPS; |
const OPS = bscript.OPS; |
||||
function stacksEqual(a, b) { |
function stacksEqual(a, b) { |
||||
if (a.length !== b.length) |
if (a.length !== b.length) return false; |
||||
return false; |
return a.every((x, i) => { |
||||
return a.every((x, i) => { |
return x.equals(b[i]); |
||||
return x.equals(b[i]); |
}); |
||||
}); |
|
||||
} |
} |
||||
// output: OP_RETURN ...
|
// output: OP_RETURN ...
|
||||
function p2data(a, opts) { |
function p2data(a, opts) { |
||||
if (!a.data && !a.output) |
if (!a.data && !a.output) throw new TypeError('Not enough data'); |
||||
throw new TypeError('Not enough data'); |
opts = Object.assign({ validate: true }, opts || {}); |
||||
opts = Object.assign({ validate: true }, opts || {}); |
typef( |
||||
typef({ |
{ |
||||
network: typef.maybe(typef.Object), |
network: typef.maybe(typef.Object), |
||||
output: typef.maybe(typef.Buffer), |
output: typef.maybe(typef.Buffer), |
||||
data: typef.maybe(typef.arrayOf(typef.Buffer)), |
data: typef.maybe(typef.arrayOf(typef.Buffer)), |
||||
}, a); |
}, |
||||
const network = a.network || networks_1.bitcoin; |
a, |
||||
const o = { network }; |
); |
||||
lazy.prop(o, 'output', () => { |
const network = a.network || networks_1.bitcoin; |
||||
if (!a.data) |
const o = { network }; |
||||
return; |
lazy.prop(o, 'output', () => { |
||||
return bscript.compile([OPS.OP_RETURN].concat(a.data)); |
if (!a.data) return; |
||||
}); |
return bscript.compile([OPS.OP_RETURN].concat(a.data)); |
||||
lazy.prop(o, 'data', () => { |
}); |
||||
if (!a.output) |
lazy.prop(o, 'data', () => { |
||||
return; |
if (!a.output) return; |
||||
return bscript.decompile(a.output).slice(1); |
return bscript.decompile(a.output).slice(1); |
||||
}); |
}); |
||||
// extended validation
|
// extended validation
|
||||
if (opts.validate) { |
if (opts.validate) { |
||||
if (a.output) { |
if (a.output) { |
||||
const chunks = bscript.decompile(a.output); |
const chunks = bscript.decompile(a.output); |
||||
if (chunks[0] !== OPS.OP_RETURN) |
if (chunks[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid'); |
||||
throw new TypeError('Output is invalid'); |
if (!chunks.slice(1).every(typef.Buffer)) |
||||
if (!chunks.slice(1).every(typef.Buffer)) |
throw new TypeError('Output is invalid'); |
||||
throw new TypeError('Output is invalid'); |
if (a.data && !stacksEqual(a.data, o.data)) |
||||
if (a.data && !stacksEqual(a.data, o.data)) |
throw new TypeError('Data mismatch'); |
||||
throw new TypeError('Data mismatch'); |
|
||||
} |
|
||||
} |
} |
||||
return Object.assign(o, a); |
} |
||||
|
return Object.assign(o, a); |
||||
} |
} |
||||
exports.p2data = p2data; |
exports.p2data = p2data; |
||||
|
@ -1,18 +1,18 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const embed_1 = require("./embed"); |
const embed_1 = require('./embed'); |
||||
exports.embed = embed_1.p2data; |
exports.embed = embed_1.p2data; |
||||
const p2ms_1 = require("./p2ms"); |
const p2ms_1 = require('./p2ms'); |
||||
exports.p2ms = p2ms_1.p2ms; |
exports.p2ms = p2ms_1.p2ms; |
||||
const p2pk_1 = require("./p2pk"); |
const p2pk_1 = require('./p2pk'); |
||||
exports.p2pk = p2pk_1.p2pk; |
exports.p2pk = p2pk_1.p2pk; |
||||
const p2pkh_1 = require("./p2pkh"); |
const p2pkh_1 = require('./p2pkh'); |
||||
exports.p2pkh = p2pkh_1.p2pkh; |
exports.p2pkh = p2pkh_1.p2pkh; |
||||
const p2sh_1 = require("./p2sh"); |
const p2sh_1 = require('./p2sh'); |
||||
exports.p2sh = p2sh_1.p2sh; |
exports.p2sh = p2sh_1.p2sh; |
||||
const p2wpkh_1 = require("./p2wpkh"); |
const p2wpkh_1 = require('./p2wpkh'); |
||||
exports.p2wpkh = p2wpkh_1.p2wpkh; |
exports.p2wpkh = p2wpkh_1.p2wpkh; |
||||
const p2wsh_1 = require("./p2wsh"); |
const p2wsh_1 = require('./p2wsh'); |
||||
exports.p2wsh = p2wsh_1.p2wsh; |
exports.p2wsh = p2wsh_1.p2wsh; |
||||
// TODO
|
// TODO
|
||||
// witness commitment
|
// witness commitment
|
||||
|
@ -1,32 +1,31 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
function prop(object, name, f) { |
function prop(object, name, f) { |
||||
Object.defineProperty(object, name, { |
Object.defineProperty(object, name, { |
||||
|
configurable: true, |
||||
|
enumerable: true, |
||||
|
get() { |
||||
|
const _value = f.call(this); |
||||
|
this[name] = _value; |
||||
|
return _value; |
||||
|
}, |
||||
|
set(_value) { |
||||
|
Object.defineProperty(this, name, { |
||||
configurable: true, |
configurable: true, |
||||
enumerable: true, |
enumerable: true, |
||||
get() { |
value: _value, |
||||
const _value = f.call(this); |
writable: true, |
||||
this[name] = _value; |
}); |
||||
return _value; |
}, |
||||
}, |
}); |
||||
set(_value) { |
|
||||
Object.defineProperty(this, name, { |
|
||||
configurable: true, |
|
||||
enumerable: true, |
|
||||
value: _value, |
|
||||
writable: true, |
|
||||
}); |
|
||||
}, |
|
||||
}); |
|
||||
} |
} |
||||
exports.prop = prop; |
exports.prop = prop; |
||||
function value(f) { |
function value(f) { |
||||
let _value; |
let _value; |
||||
return () => { |
return () => { |
||||
if (_value !== undefined) |
if (_value !== undefined) return _value; |
||||
return _value; |
_value = f(); |
||||
_value = f(); |
return _value; |
||||
return _value; |
}; |
||||
}; |
|
||||
} |
} |
||||
exports.value = value; |
exports.value = value; |
||||
|
@ -1,141 +1,141 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const networks_1 = require("../networks"); |
const networks_1 = require('../networks'); |
||||
const bscript = require("../script"); |
const bscript = require('../script'); |
||||
const lazy = require("./lazy"); |
const lazy = require('./lazy'); |
||||
const OPS = bscript.OPS; |
const OPS = bscript.OPS; |
||||
const typef = require('typeforce'); |
const typef = require('typeforce'); |
||||
const ecc = require('tiny-secp256k1'); |
const ecc = require('tiny-secp256k1'); |
||||
const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1
|
const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1
|
||||
function stacksEqual(a, b) { |
function stacksEqual(a, b) { |
||||
if (a.length !== b.length) |
if (a.length !== b.length) return false; |
||||
return false; |
return a.every((x, i) => { |
||||
return a.every((x, i) => { |
return x.equals(b[i]); |
||||
return x.equals(b[i]); |
}); |
||||
}); |
|
||||
} |
} |
||||
// input: OP_0 [signatures ...]
|
// input: OP_0 [signatures ...]
|
||||
// output: m [pubKeys ...] n OP_CHECKMULTISIG
|
// output: m [pubKeys ...] n OP_CHECKMULTISIG
|
||||
function p2ms(a, opts) { |
function p2ms(a, opts) { |
||||
if (!a.input && |
if ( |
||||
!a.output && |
!a.input && |
||||
!(a.pubkeys && a.m !== undefined) && |
!a.output && |
||||
!a.signatures) |
!(a.pubkeys && a.m !== undefined) && |
||||
throw new TypeError('Not enough data'); |
!a.signatures |
||||
opts = Object.assign({ validate: true }, opts || {}); |
) |
||||
function isAcceptableSignature(x) { |
throw new TypeError('Not enough data'); |
||||
return (bscript.isCanonicalScriptSignature(x) || |
opts = Object.assign({ validate: true }, opts || {}); |
||||
(opts.allowIncomplete && x === OPS.OP_0) !== undefined); |
function isAcceptableSignature(x) { |
||||
|
return ( |
||||
|
bscript.isCanonicalScriptSignature(x) || |
||||
|
(opts.allowIncomplete && x === OPS.OP_0) !== undefined |
||||
|
); |
||||
|
} |
||||
|
typef( |
||||
|
{ |
||||
|
network: typef.maybe(typef.Object), |
||||
|
m: typef.maybe(typef.Number), |
||||
|
n: typef.maybe(typef.Number), |
||||
|
output: typef.maybe(typef.Buffer), |
||||
|
pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)), |
||||
|
signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), |
||||
|
input: typef.maybe(typef.Buffer), |
||||
|
}, |
||||
|
a, |
||||
|
); |
||||
|
const network = a.network || networks_1.bitcoin; |
||||
|
const o = { network }; |
||||
|
let chunks = []; |
||||
|
let decoded = false; |
||||
|
function decode(output) { |
||||
|
if (decoded) return; |
||||
|
decoded = true; |
||||
|
chunks = bscript.decompile(output); |
||||
|
o.m = chunks[0] - OP_INT_BASE; |
||||
|
o.n = chunks[chunks.length - 2] - OP_INT_BASE; |
||||
|
o.pubkeys = chunks.slice(1, -2); |
||||
|
} |
||||
|
lazy.prop(o, 'output', () => { |
||||
|
if (!a.m) return; |
||||
|
if (!o.n) return; |
||||
|
if (!a.pubkeys) return; |
||||
|
return bscript.compile( |
||||
|
[].concat( |
||||
|
OP_INT_BASE + a.m, |
||||
|
a.pubkeys, |
||||
|
OP_INT_BASE + o.n, |
||||
|
OPS.OP_CHECKMULTISIG, |
||||
|
), |
||||
|
); |
||||
|
}); |
||||
|
lazy.prop(o, 'm', () => { |
||||
|
if (!o.output) return; |
||||
|
decode(o.output); |
||||
|
return o.m; |
||||
|
}); |
||||
|
lazy.prop(o, 'n', () => { |
||||
|
if (!o.pubkeys) return; |
||||
|
return o.pubkeys.length; |
||||
|
}); |
||||
|
lazy.prop(o, 'pubkeys', () => { |
||||
|
if (!a.output) return; |
||||
|
decode(a.output); |
||||
|
return o.pubkeys; |
||||
|
}); |
||||
|
lazy.prop(o, 'signatures', () => { |
||||
|
if (!a.input) return; |
||||
|
return bscript.decompile(a.input).slice(1); |
||||
|
}); |
||||
|
lazy.prop(o, 'input', () => { |
||||
|
if (!a.signatures) return; |
||||
|
return bscript.compile([OPS.OP_0].concat(a.signatures)); |
||||
|
}); |
||||
|
lazy.prop(o, 'witness', () => { |
||||
|
if (!o.input) return; |
||||
|
return []; |
||||
|
}); |
||||
|
// extended validation
|
||||
|
if (opts.validate) { |
||||
|
if (a.output) { |
||||
|
decode(a.output); |
||||
|
if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); |
||||
|
if (!typef.Number(chunks[chunks.length - 2])) |
||||
|
throw new TypeError('Output is invalid'); |
||||
|
if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) |
||||
|
throw new TypeError('Output is invalid'); |
||||
|
if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3) |
||||
|
throw new TypeError('Output is invalid'); |
||||
|
if (!o.pubkeys.every(x => ecc.isPoint(x))) |
||||
|
throw new TypeError('Output is invalid'); |
||||
|
if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch'); |
||||
|
if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch'); |
||||
|
if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys)) |
||||
|
throw new TypeError('Pubkeys mismatch'); |
||||
} |
} |
||||
typef({ |
if (a.pubkeys) { |
||||
network: typef.maybe(typef.Object), |
if (a.n !== undefined && a.n !== a.pubkeys.length) |
||||
m: typef.maybe(typef.Number), |
throw new TypeError('Pubkey count mismatch'); |
||||
n: typef.maybe(typef.Number), |
o.n = a.pubkeys.length; |
||||
output: typef.maybe(typef.Buffer), |
if (o.n < o.m) throw new TypeError('Pubkey count cannot be less than m'); |
||||
pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)), |
|
||||
signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), |
|
||||
input: typef.maybe(typef.Buffer), |
|
||||
}, a); |
|
||||
const network = a.network || networks_1.bitcoin; |
|
||||
const o = { network }; |
|
||||
let chunks = []; |
|
||||
let decoded = false; |
|
||||
function decode(output) { |
|
||||
if (decoded) |
|
||||
return; |
|
||||
decoded = true; |
|
||||
chunks = bscript.decompile(output); |
|
||||
o.m = chunks[0] - OP_INT_BASE; |
|
||||
o.n = chunks[chunks.length - 2] - OP_INT_BASE; |
|
||||
o.pubkeys = chunks.slice(1, -2); |
|
||||
} |
} |
||||
lazy.prop(o, 'output', () => { |
if (a.signatures) { |
||||
if (!a.m) |
if (a.signatures.length < o.m) |
||||
return; |
throw new TypeError('Not enough signatures provided'); |
||||
if (!o.n) |
if (a.signatures.length > o.m) |
||||
return; |
throw new TypeError('Too many signatures provided'); |
||||
if (!a.pubkeys) |
|
||||
return; |
|
||||
return bscript.compile([].concat(OP_INT_BASE + a.m, a.pubkeys, OP_INT_BASE + o.n, OPS.OP_CHECKMULTISIG)); |
|
||||
}); |
|
||||
lazy.prop(o, 'm', () => { |
|
||||
if (!o.output) |
|
||||
return; |
|
||||
decode(o.output); |
|
||||
return o.m; |
|
||||
}); |
|
||||
lazy.prop(o, 'n', () => { |
|
||||
if (!o.pubkeys) |
|
||||
return; |
|
||||
return o.pubkeys.length; |
|
||||
}); |
|
||||
lazy.prop(o, 'pubkeys', () => { |
|
||||
if (!a.output) |
|
||||
return; |
|
||||
decode(a.output); |
|
||||
return o.pubkeys; |
|
||||
}); |
|
||||
lazy.prop(o, 'signatures', () => { |
|
||||
if (!a.input) |
|
||||
return; |
|
||||
return bscript.decompile(a.input).slice(1); |
|
||||
}); |
|
||||
lazy.prop(o, 'input', () => { |
|
||||
if (!a.signatures) |
|
||||
return; |
|
||||
return bscript.compile([OPS.OP_0].concat(a.signatures)); |
|
||||
}); |
|
||||
lazy.prop(o, 'witness', () => { |
|
||||
if (!o.input) |
|
||||
return; |
|
||||
return []; |
|
||||
}); |
|
||||
// extended validation
|
|
||||
if (opts.validate) { |
|
||||
if (a.output) { |
|
||||
decode(a.output); |
|
||||
if (!typef.Number(chunks[0])) |
|
||||
throw new TypeError('Output is invalid'); |
|
||||
if (!typef.Number(chunks[chunks.length - 2])) |
|
||||
throw new TypeError('Output is invalid'); |
|
||||
if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) |
|
||||
throw new TypeError('Output is invalid'); |
|
||||
if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3) |
|
||||
throw new TypeError('Output is invalid'); |
|
||||
if (!o.pubkeys.every(x => ecc.isPoint(x))) |
|
||||
throw new TypeError('Output is invalid'); |
|
||||
if (a.m !== undefined && a.m !== o.m) |
|
||||
throw new TypeError('m mismatch'); |
|
||||
if (a.n !== undefined && a.n !== o.n) |
|
||||
throw new TypeError('n mismatch'); |
|
||||
if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys)) |
|
||||
throw new TypeError('Pubkeys mismatch'); |
|
||||
} |
|
||||
if (a.pubkeys) { |
|
||||
if (a.n !== undefined && a.n !== a.pubkeys.length) |
|
||||
throw new TypeError('Pubkey count mismatch'); |
|
||||
o.n = a.pubkeys.length; |
|
||||
if (o.n < o.m) |
|
||||
throw new TypeError('Pubkey count cannot be less than m'); |
|
||||
} |
|
||||
if (a.signatures) { |
|
||||
if (a.signatures.length < o.m) |
|
||||
throw new TypeError('Not enough signatures provided'); |
|
||||
if (a.signatures.length > o.m) |
|
||||
throw new TypeError('Too many signatures provided'); |
|
||||
} |
|
||||
if (a.input) { |
|
||||
if (a.input[0] !== OPS.OP_0) |
|
||||
throw new TypeError('Input is invalid'); |
|
||||
if (o.signatures.length === 0 || |
|
||||
!o.signatures.every(isAcceptableSignature)) |
|
||||
throw new TypeError('Input has invalid signature(s)'); |
|
||||
if (a.signatures && !stacksEqual(a.signatures, o.signatures)) |
|
||||
throw new TypeError('Signature mismatch'); |
|
||||
if (a.m !== undefined && a.m !== a.signatures.length) |
|
||||
throw new TypeError('Signature count mismatch'); |
|
||||
} |
|
||||
} |
} |
||||
return Object.assign(o, a); |
if (a.input) { |
||||
|
if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid'); |
||||
|
if ( |
||||
|
o.signatures.length === 0 || |
||||
|
!o.signatures.every(isAcceptableSignature) |
||||
|
) |
||||
|
throw new TypeError('Input has invalid signature(s)'); |
||||
|
if (a.signatures && !stacksEqual(a.signatures, o.signatures)) |
||||
|
throw new TypeError('Signature mismatch'); |
||||
|
if (a.m !== undefined && a.m !== a.signatures.length) |
||||
|
throw new TypeError('Signature count mismatch'); |
||||
|
} |
||||
|
} |
||||
|
return Object.assign(o, a); |
||||
} |
} |
||||
exports.p2ms = p2ms; |
exports.p2ms = p2ms; |
||||
|
@ -1,75 +1,72 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const networks_1 = require("../networks"); |
const networks_1 = require('../networks'); |
||||
const bscript = require("../script"); |
const bscript = require('../script'); |
||||
const lazy = require("./lazy"); |
const lazy = require('./lazy'); |
||||
const typef = require('typeforce'); |
const typef = require('typeforce'); |
||||
const OPS = bscript.OPS; |
const OPS = bscript.OPS; |
||||
const ecc = require('tiny-secp256k1'); |
const ecc = require('tiny-secp256k1'); |
||||
// input: {signature}
|
// input: {signature}
|
||||
// output: {pubKey} OP_CHECKSIG
|
// output: {pubKey} OP_CHECKSIG
|
||||
function p2pk(a, opts) { |
function p2pk(a, opts) { |
||||
if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) |
if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) |
||||
throw new TypeError('Not enough data'); |
throw new TypeError('Not enough data'); |
||||
opts = Object.assign({ validate: true }, opts || {}); |
opts = Object.assign({ validate: true }, opts || {}); |
||||
typef({ |
typef( |
||||
network: typef.maybe(typef.Object), |
{ |
||||
output: typef.maybe(typef.Buffer), |
network: typef.maybe(typef.Object), |
||||
pubkey: typef.maybe(ecc.isPoint), |
output: typef.maybe(typef.Buffer), |
||||
signature: typef.maybe(bscript.isCanonicalScriptSignature), |
pubkey: typef.maybe(ecc.isPoint), |
||||
input: typef.maybe(typef.Buffer), |
signature: typef.maybe(bscript.isCanonicalScriptSignature), |
||||
}, a); |
input: typef.maybe(typef.Buffer), |
||||
const _chunks = lazy.value(() => { |
}, |
||||
return bscript.decompile(a.input); |
a, |
||||
}); |
); |
||||
const network = a.network || networks_1.bitcoin; |
const _chunks = lazy.value(() => { |
||||
const o = { network }; |
return bscript.decompile(a.input); |
||||
lazy.prop(o, 'output', () => { |
}); |
||||
if (!a.pubkey) |
const network = a.network || networks_1.bitcoin; |
||||
return; |
const o = { network }; |
||||
return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]); |
lazy.prop(o, 'output', () => { |
||||
}); |
if (!a.pubkey) return; |
||||
lazy.prop(o, 'pubkey', () => { |
return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]); |
||||
if (!a.output) |
}); |
||||
return; |
lazy.prop(o, 'pubkey', () => { |
||||
return a.output.slice(1, -1); |
if (!a.output) return; |
||||
}); |
return a.output.slice(1, -1); |
||||
lazy.prop(o, 'signature', () => { |
}); |
||||
if (!a.input) |
lazy.prop(o, 'signature', () => { |
||||
return; |
if (!a.input) return; |
||||
return _chunks()[0]; |
return _chunks()[0]; |
||||
}); |
}); |
||||
lazy.prop(o, 'input', () => { |
lazy.prop(o, 'input', () => { |
||||
if (!a.signature) |
if (!a.signature) return; |
||||
return; |
return bscript.compile([a.signature]); |
||||
return bscript.compile([a.signature]); |
}); |
||||
}); |
lazy.prop(o, 'witness', () => { |
||||
lazy.prop(o, 'witness', () => { |
if (!o.input) return; |
||||
if (!o.input) |
return []; |
||||
return; |
}); |
||||
return []; |
// extended validation
|
||||
}); |
if (opts.validate) { |
||||
// extended validation
|
if (a.output) { |
||||
if (opts.validate) { |
if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) |
||||
if (a.output) { |
throw new TypeError('Output is invalid'); |
||||
if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) |
if (!ecc.isPoint(o.pubkey)) |
||||
throw new TypeError('Output is invalid'); |
throw new TypeError('Output pubkey is invalid'); |
||||
if (!ecc.isPoint(o.pubkey)) |
if (a.pubkey && !a.pubkey.equals(o.pubkey)) |
||||
throw new TypeError('Output pubkey is invalid'); |
throw new TypeError('Pubkey mismatch'); |
||||
if (a.pubkey && !a.pubkey.equals(o.pubkey)) |
|
||||
throw new TypeError('Pubkey mismatch'); |
|
||||
} |
|
||||
if (a.signature) { |
|
||||
if (a.input && !a.input.equals(o.input)) |
|
||||
throw new TypeError('Signature mismatch'); |
|
||||
} |
|
||||
if (a.input) { |
|
||||
if (_chunks().length !== 1) |
|
||||
throw new TypeError('Input is invalid'); |
|
||||
if (!bscript.isCanonicalScriptSignature(o.signature)) |
|
||||
throw new TypeError('Input has invalid signature'); |
|
||||
} |
|
||||
} |
} |
||||
return Object.assign(o, a); |
if (a.signature) { |
||||
|
if (a.input && !a.input.equals(o.input)) |
||||
|
throw new TypeError('Signature mismatch'); |
||||
|
} |
||||
|
if (a.input) { |
||||
|
if (_chunks().length !== 1) throw new TypeError('Input is invalid'); |
||||
|
if (!bscript.isCanonicalScriptSignature(o.signature)) |
||||
|
throw new TypeError('Input has invalid signature'); |
||||
|
} |
||||
|
} |
||||
|
return Object.assign(o, a); |
||||
} |
} |
||||
exports.p2pk = p2pk; |
exports.p2pk = p2pk; |
||||
|
@ -1,185 +1,178 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bcrypto = require("../crypto"); |
const bcrypto = require('../crypto'); |
||||
const networks_1 = require("../networks"); |
const networks_1 = require('../networks'); |
||||
const bscript = require("../script"); |
const bscript = require('../script'); |
||||
const lazy = require("./lazy"); |
const lazy = require('./lazy'); |
||||
const typef = require('typeforce'); |
const typef = require('typeforce'); |
||||
const OPS = bscript.OPS; |
const OPS = bscript.OPS; |
||||
const bs58check = require('bs58check'); |
const bs58check = require('bs58check'); |
||||
function stacksEqual(a, b) { |
function stacksEqual(a, b) { |
||||
if (a.length !== b.length) |
if (a.length !== b.length) return false; |
||||
return false; |
return a.every((x, i) => { |
||||
return a.every((x, i) => { |
return x.equals(b[i]); |
||||
return x.equals(b[i]); |
}); |
||||
}); |
|
||||
} |
} |
||||
// input: [redeemScriptSig ...] {redeemScript}
|
// input: [redeemScriptSig ...] {redeemScript}
|
||||
// witness: <?>
|
// witness: <?>
|
||||
// output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL
|
// output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL
|
||||
function p2sh(a, opts) { |
function p2sh(a, opts) { |
||||
if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) |
if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) |
||||
throw new TypeError('Not enough data'); |
throw new TypeError('Not enough data'); |
||||
opts = Object.assign({ validate: true }, opts || {}); |
opts = Object.assign({ validate: true }, opts || {}); |
||||
typef({ |
typef( |
||||
|
{ |
||||
|
network: typef.maybe(typef.Object), |
||||
|
address: typef.maybe(typef.String), |
||||
|
hash: typef.maybe(typef.BufferN(20)), |
||||
|
output: typef.maybe(typef.BufferN(23)), |
||||
|
redeem: typef.maybe({ |
||||
network: typef.maybe(typef.Object), |
network: typef.maybe(typef.Object), |
||||
address: typef.maybe(typef.String), |
output: typef.maybe(typef.Buffer), |
||||
hash: typef.maybe(typef.BufferN(20)), |
|
||||
output: typef.maybe(typef.BufferN(23)), |
|
||||
redeem: typef.maybe({ |
|
||||
network: typef.maybe(typef.Object), |
|
||||
output: typef.maybe(typef.Buffer), |
|
||||
input: typef.maybe(typef.Buffer), |
|
||||
witness: typef.maybe(typef.arrayOf(typef.Buffer)), |
|
||||
}), |
|
||||
input: typef.maybe(typef.Buffer), |
input: typef.maybe(typef.Buffer), |
||||
witness: typef.maybe(typef.arrayOf(typef.Buffer)), |
witness: typef.maybe(typef.arrayOf(typef.Buffer)), |
||||
}, a); |
}), |
||||
let network = a.network; |
input: typef.maybe(typef.Buffer), |
||||
if (!network) { |
witness: typef.maybe(typef.arrayOf(typef.Buffer)), |
||||
network = (a.redeem && a.redeem.network) || networks_1.bitcoin; |
}, |
||||
|
a, |
||||
|
); |
||||
|
let network = a.network; |
||||
|
if (!network) { |
||||
|
network = (a.redeem && a.redeem.network) || networks_1.bitcoin; |
||||
|
} |
||||
|
const o = { network }; |
||||
|
const _address = lazy.value(() => { |
||||
|
const payload = bs58check.decode(a.address); |
||||
|
const version = payload.readUInt8(0); |
||||
|
const hash = payload.slice(1); |
||||
|
return { version, hash }; |
||||
|
}); |
||||
|
const _chunks = lazy.value(() => { |
||||
|
return bscript.decompile(a.input); |
||||
|
}); |
||||
|
const _redeem = lazy.value(() => { |
||||
|
const chunks = _chunks(); |
||||
|
return { |
||||
|
network, |
||||
|
output: chunks[chunks.length - 1], |
||||
|
input: bscript.compile(chunks.slice(0, -1)), |
||||
|
witness: a.witness || [], |
||||
|
}; |
||||
|
}); |
||||
|
// output dependents
|
||||
|
lazy.prop(o, 'address', () => { |
||||
|
if (!o.hash) return; |
||||
|
const payload = Buffer.allocUnsafe(21); |
||||
|
payload.writeUInt8(o.network.scriptHash, 0); |
||||
|
o.hash.copy(payload, 1); |
||||
|
return bs58check.encode(payload); |
||||
|
}); |
||||
|
lazy.prop(o, 'hash', () => { |
||||
|
// in order of least effort
|
||||
|
if (a.output) return a.output.slice(2, 22); |
||||
|
if (a.address) return _address().hash; |
||||
|
if (o.redeem && o.redeem.output) return bcrypto.hash160(o.redeem.output); |
||||
|
}); |
||||
|
lazy.prop(o, 'output', () => { |
||||
|
if (!o.hash) return; |
||||
|
return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]); |
||||
|
}); |
||||
|
// input dependents
|
||||
|
lazy.prop(o, 'redeem', () => { |
||||
|
if (!a.input) return; |
||||
|
return _redeem(); |
||||
|
}); |
||||
|
lazy.prop(o, 'input', () => { |
||||
|
if (!a.redeem || !a.redeem.input || !a.redeem.output) return; |
||||
|
return bscript.compile( |
||||
|
[].concat(bscript.decompile(a.redeem.input), a.redeem.output), |
||||
|
); |
||||
|
}); |
||||
|
lazy.prop(o, 'witness', () => { |
||||
|
if (o.redeem && o.redeem.witness) return o.redeem.witness; |
||||
|
if (o.input) return []; |
||||
|
}); |
||||
|
if (opts.validate) { |
||||
|
let hash = Buffer.from([]); |
||||
|
if (a.address) { |
||||
|
if (_address().version !== network.scriptHash) |
||||
|
throw new TypeError('Invalid version or Network mismatch'); |
||||
|
if (_address().hash.length !== 20) throw new TypeError('Invalid address'); |
||||
|
hash = _address().hash; |
||||
} |
} |
||||
const o = { network }; |
if (a.hash) { |
||||
const _address = lazy.value(() => { |
if (hash.length > 0 && !hash.equals(a.hash)) |
||||
const payload = bs58check.decode(a.address); |
throw new TypeError('Hash mismatch'); |
||||
const version = payload.readUInt8(0); |
else hash = a.hash; |
||||
const hash = payload.slice(1); |
} |
||||
return { version, hash }; |
if (a.output) { |
||||
}); |
if ( |
||||
const _chunks = lazy.value(() => { |
a.output.length !== 23 || |
||||
return bscript.decompile(a.input); |
a.output[0] !== OPS.OP_HASH160 || |
||||
}); |
a.output[1] !== 0x14 || |
||||
const _redeem = lazy.value(() => { |
a.output[22] !== OPS.OP_EQUAL |
||||
const chunks = _chunks(); |
) |
||||
return { |
throw new TypeError('Output is invalid'); |
||||
network, |
const hash2 = a.output.slice(2, 22); |
||||
output: chunks[chunks.length - 1], |
if (hash.length > 0 && !hash.equals(hash2)) |
||||
input: bscript.compile(chunks.slice(0, -1)), |
throw new TypeError('Hash mismatch'); |
||||
witness: a.witness || [], |
else hash = hash2; |
||||
}; |
} |
||||
}); |
// inlined to prevent 'no-inner-declarations' failing
|
||||
// output dependents
|
const checkRedeem = redeem => { |
||||
lazy.prop(o, 'address', () => { |
// is the redeem output empty/invalid?
|
||||
if (!o.hash) |
if (redeem.output) { |
||||
return; |
const decompile = bscript.decompile(redeem.output); |
||||
const payload = Buffer.allocUnsafe(21); |
if (!decompile || decompile.length < 1) |
||||
payload.writeUInt8(o.network.scriptHash, 0); |
throw new TypeError('Redeem.output too short'); |
||||
o.hash.copy(payload, 1); |
// match hash against other sources
|
||||
return bs58check.encode(payload); |
const hash2 = bcrypto.hash160(redeem.output); |
||||
}); |
if (hash.length > 0 && !hash.equals(hash2)) |
||||
lazy.prop(o, 'hash', () => { |
throw new TypeError('Hash mismatch'); |
||||
// in order of least effort
|
else hash = hash2; |
||||
if (a.output) |
} |
||||
return a.output.slice(2, 22); |
if (redeem.input) { |
||||
if (a.address) |
const hasInput = redeem.input.length > 0; |
||||
return _address().hash; |
const hasWitness = redeem.witness && redeem.witness.length > 0; |
||||
if (o.redeem && o.redeem.output) |
if (!hasInput && !hasWitness) throw new TypeError('Empty input'); |
||||
return bcrypto.hash160(o.redeem.output); |
if (hasInput && hasWitness) |
||||
}); |
throw new TypeError('Input and witness provided'); |
||||
lazy.prop(o, 'output', () => { |
if (hasInput) { |
||||
if (!o.hash) |
const richunks = bscript.decompile(redeem.input); |
||||
return; |
if (!bscript.isPushOnly(richunks)) |
||||
return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]); |
throw new TypeError('Non push-only scriptSig'); |
||||
}); |
|
||||
// input dependents
|
|
||||
lazy.prop(o, 'redeem', () => { |
|
||||
if (!a.input) |
|
||||
return; |
|
||||
return _redeem(); |
|
||||
}); |
|
||||
lazy.prop(o, 'input', () => { |
|
||||
if (!a.redeem || !a.redeem.input || !a.redeem.output) |
|
||||
return; |
|
||||
return bscript.compile([].concat(bscript.decompile(a.redeem.input), a.redeem.output)); |
|
||||
}); |
|
||||
lazy.prop(o, 'witness', () => { |
|
||||
if (o.redeem && o.redeem.witness) |
|
||||
return o.redeem.witness; |
|
||||
if (o.input) |
|
||||
return []; |
|
||||
}); |
|
||||
if (opts.validate) { |
|
||||
let hash = Buffer.from([]); |
|
||||
if (a.address) { |
|
||||
if (_address().version !== network.scriptHash) |
|
||||
throw new TypeError('Invalid version or Network mismatch'); |
|
||||
if (_address().hash.length !== 20) |
|
||||
throw new TypeError('Invalid address'); |
|
||||
hash = _address().hash; |
|
||||
} |
|
||||
if (a.hash) { |
|
||||
if (hash.length > 0 && !hash.equals(a.hash)) |
|
||||
throw new TypeError('Hash mismatch'); |
|
||||
else |
|
||||
hash = a.hash; |
|
||||
} |
|
||||
if (a.output) { |
|
||||
if (a.output.length !== 23 || |
|
||||
a.output[0] !== OPS.OP_HASH160 || |
|
||||
a.output[1] !== 0x14 || |
|
||||
a.output[22] !== OPS.OP_EQUAL) |
|
||||
throw new TypeError('Output is invalid'); |
|
||||
const hash2 = a.output.slice(2, 22); |
|
||||
if (hash.length > 0 && !hash.equals(hash2)) |
|
||||
throw new TypeError('Hash mismatch'); |
|
||||
else |
|
||||
hash = hash2; |
|
||||
} |
|
||||
// inlined to prevent 'no-inner-declarations' failing
|
|
||||
const checkRedeem = (redeem) => { |
|
||||
// is the redeem output empty/invalid?
|
|
||||
if (redeem.output) { |
|
||||
const decompile = bscript.decompile(redeem.output); |
|
||||
if (!decompile || decompile.length < 1) |
|
||||
throw new TypeError('Redeem.output too short'); |
|
||||
// match hash against other sources
|
|
||||
const hash2 = bcrypto.hash160(redeem.output); |
|
||||
if (hash.length > 0 && !hash.equals(hash2)) |
|
||||
throw new TypeError('Hash mismatch'); |
|
||||
else |
|
||||
hash = hash2; |
|
||||
} |
|
||||
if (redeem.input) { |
|
||||
const hasInput = redeem.input.length > 0; |
|
||||
const hasWitness = redeem.witness && redeem.witness.length > 0; |
|
||||
if (!hasInput && !hasWitness) |
|
||||
throw new TypeError('Empty input'); |
|
||||
if (hasInput && hasWitness) |
|
||||
throw new TypeError('Input and witness provided'); |
|
||||
if (hasInput) { |
|
||||
const richunks = bscript.decompile(redeem.input); |
|
||||
if (!bscript.isPushOnly(richunks)) |
|
||||
throw new TypeError('Non push-only scriptSig'); |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
if (a.input) { |
|
||||
const chunks = _chunks(); |
|
||||
if (!chunks || chunks.length < 1) |
|
||||
throw new TypeError('Input too short'); |
|
||||
if (!Buffer.isBuffer(_redeem().output)) |
|
||||
throw new TypeError('Input is invalid'); |
|
||||
checkRedeem(_redeem()); |
|
||||
} |
|
||||
if (a.redeem) { |
|
||||
if (a.redeem.network && a.redeem.network !== network) |
|
||||
throw new TypeError('Network mismatch'); |
|
||||
if (a.input) { |
|
||||
const redeem = _redeem(); |
|
||||
if (a.redeem.output && !a.redeem.output.equals(redeem.output)) |
|
||||
throw new TypeError('Redeem.output mismatch'); |
|
||||
if (a.redeem.input && !a.redeem.input.equals(redeem.input)) |
|
||||
throw new TypeError('Redeem.input mismatch'); |
|
||||
} |
|
||||
checkRedeem(a.redeem); |
|
||||
} |
|
||||
if (a.witness) { |
|
||||
if (a.redeem && |
|
||||
a.redeem.witness && |
|
||||
!stacksEqual(a.redeem.witness, a.witness)) |
|
||||
throw new TypeError('Witness and redeem.witness mismatch'); |
|
||||
} |
} |
||||
|
} |
||||
|
}; |
||||
|
if (a.input) { |
||||
|
const chunks = _chunks(); |
||||
|
if (!chunks || chunks.length < 1) throw new TypeError('Input too short'); |
||||
|
if (!Buffer.isBuffer(_redeem().output)) |
||||
|
throw new TypeError('Input is invalid'); |
||||
|
checkRedeem(_redeem()); |
||||
|
} |
||||
|
if (a.redeem) { |
||||
|
if (a.redeem.network && a.redeem.network !== network) |
||||
|
throw new TypeError('Network mismatch'); |
||||
|
if (a.input) { |
||||
|
const redeem = _redeem(); |
||||
|
if (a.redeem.output && !a.redeem.output.equals(redeem.output)) |
||||
|
throw new TypeError('Redeem.output mismatch'); |
||||
|
if (a.redeem.input && !a.redeem.input.equals(redeem.input)) |
||||
|
throw new TypeError('Redeem.input mismatch'); |
||||
|
} |
||||
|
checkRedeem(a.redeem); |
||||
|
} |
||||
|
if (a.witness) { |
||||
|
if ( |
||||
|
a.redeem && |
||||
|
a.redeem.witness && |
||||
|
!stacksEqual(a.redeem.witness, a.witness) |
||||
|
) |
||||
|
throw new TypeError('Witness and redeem.witness mismatch'); |
||||
} |
} |
||||
return Object.assign(o, a); |
} |
||||
|
return Object.assign(o, a); |
||||
} |
} |
||||
exports.p2sh = p2sh; |
exports.p2sh = p2sh; |
||||
|
@ -1,177 +1,176 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bcrypto = require("../crypto"); |
const bcrypto = require('../crypto'); |
||||
const networks_1 = require("../networks"); |
const networks_1 = require('../networks'); |
||||
const bscript = require("../script"); |
const bscript = require('../script'); |
||||
const lazy = require("./lazy"); |
const lazy = require('./lazy'); |
||||
const typef = require('typeforce'); |
const typef = require('typeforce'); |
||||
const OPS = bscript.OPS; |
const OPS = bscript.OPS; |
||||
const bech32 = require('bech32'); |
const bech32 = require('bech32'); |
||||
const EMPTY_BUFFER = Buffer.alloc(0); |
const EMPTY_BUFFER = Buffer.alloc(0); |
||||
function stacksEqual(a, b) { |
function stacksEqual(a, b) { |
||||
if (a.length !== b.length) |
if (a.length !== b.length) return false; |
||||
return false; |
return a.every((x, i) => { |
||||
return a.every((x, i) => { |
return x.equals(b[i]); |
||||
return x.equals(b[i]); |
}); |
||||
}); |
|
||||
} |
} |
||||
// input: <>
|
// input: <>
|
||||
// witness: [redeemScriptSig ...] {redeemScript}
|
// witness: [redeemScriptSig ...] {redeemScript}
|
||||
// output: OP_0 {sha256(redeemScript)}
|
// output: OP_0 {sha256(redeemScript)}
|
||||
function p2wsh(a, opts) { |
function p2wsh(a, opts) { |
||||
if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness) |
if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness) |
||||
throw new TypeError('Not enough data'); |
throw new TypeError('Not enough data'); |
||||
opts = Object.assign({ validate: true }, opts || {}); |
opts = Object.assign({ validate: true }, opts || {}); |
||||
typef({ |
typef( |
||||
|
{ |
||||
|
network: typef.maybe(typef.Object), |
||||
|
address: typef.maybe(typef.String), |
||||
|
hash: typef.maybe(typef.BufferN(32)), |
||||
|
output: typef.maybe(typef.BufferN(34)), |
||||
|
redeem: typef.maybe({ |
||||
|
input: typef.maybe(typef.Buffer), |
||||
network: typef.maybe(typef.Object), |
network: typef.maybe(typef.Object), |
||||
address: typef.maybe(typef.String), |
output: typef.maybe(typef.Buffer), |
||||
hash: typef.maybe(typef.BufferN(32)), |
|
||||
output: typef.maybe(typef.BufferN(34)), |
|
||||
redeem: typef.maybe({ |
|
||||
input: typef.maybe(typef.Buffer), |
|
||||
network: typef.maybe(typef.Object), |
|
||||
output: typef.maybe(typef.Buffer), |
|
||||
witness: typef.maybe(typef.arrayOf(typef.Buffer)), |
|
||||
}), |
|
||||
input: typef.maybe(typef.BufferN(0)), |
|
||||
witness: typef.maybe(typef.arrayOf(typef.Buffer)), |
witness: typef.maybe(typef.arrayOf(typef.Buffer)), |
||||
}, a); |
}), |
||||
const _address = lazy.value(() => { |
input: typef.maybe(typef.BufferN(0)), |
||||
const result = bech32.decode(a.address); |
witness: typef.maybe(typef.arrayOf(typef.Buffer)), |
||||
const version = result.words.shift(); |
}, |
||||
const data = bech32.fromWords(result.words); |
a, |
||||
return { |
); |
||||
version, |
const _address = lazy.value(() => { |
||||
prefix: result.prefix, |
const result = bech32.decode(a.address); |
||||
data: Buffer.from(data), |
const version = result.words.shift(); |
||||
}; |
const data = bech32.fromWords(result.words); |
||||
}); |
return { |
||||
const _rchunks = lazy.value(() => { |
version, |
||||
return bscript.decompile(a.redeem.input); |
prefix: result.prefix, |
||||
}); |
data: Buffer.from(data), |
||||
let network = a.network; |
}; |
||||
if (!network) { |
}); |
||||
network = (a.redeem && a.redeem.network) || networks_1.bitcoin; |
const _rchunks = lazy.value(() => { |
||||
|
return bscript.decompile(a.redeem.input); |
||||
|
}); |
||||
|
let network = a.network; |
||||
|
if (!network) { |
||||
|
network = (a.redeem && a.redeem.network) || networks_1.bitcoin; |
||||
|
} |
||||
|
const o = { network }; |
||||
|
lazy.prop(o, 'address', () => { |
||||
|
if (!o.hash) return; |
||||
|
const words = bech32.toWords(o.hash); |
||||
|
words.unshift(0x00); |
||||
|
return bech32.encode(network.bech32, words); |
||||
|
}); |
||||
|
lazy.prop(o, 'hash', () => { |
||||
|
if (a.output) return a.output.slice(2); |
||||
|
if (a.address) return _address().data; |
||||
|
if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output); |
||||
|
}); |
||||
|
lazy.prop(o, 'output', () => { |
||||
|
if (!o.hash) return; |
||||
|
return bscript.compile([OPS.OP_0, o.hash]); |
||||
|
}); |
||||
|
lazy.prop(o, 'redeem', () => { |
||||
|
if (!a.witness) return; |
||||
|
return { |
||||
|
output: a.witness[a.witness.length - 1], |
||||
|
input: EMPTY_BUFFER, |
||||
|
witness: a.witness.slice(0, -1), |
||||
|
}; |
||||
|
}); |
||||
|
lazy.prop(o, 'input', () => { |
||||
|
if (!o.witness) return; |
||||
|
return EMPTY_BUFFER; |
||||
|
}); |
||||
|
lazy.prop(o, 'witness', () => { |
||||
|
// transform redeem input to witness stack?
|
||||
|
if ( |
||||
|
a.redeem && |
||||
|
a.redeem.input && |
||||
|
a.redeem.input.length > 0 && |
||||
|
a.redeem.output && |
||||
|
a.redeem.output.length > 0 |
||||
|
) { |
||||
|
const stack = bscript.toStack(_rchunks()); |
||||
|
// assign, and blank the existing input
|
||||
|
o.redeem = Object.assign({ witness: stack }, a.redeem); |
||||
|
o.redeem.input = EMPTY_BUFFER; |
||||
|
return [].concat(stack, a.redeem.output); |
||||
} |
} |
||||
const o = { network }; |
if (!a.redeem) return; |
||||
lazy.prop(o, 'address', () => { |
if (!a.redeem.output) return; |
||||
if (!o.hash) |
if (!a.redeem.witness) return; |
||||
return; |
return [].concat(a.redeem.witness, a.redeem.output); |
||||
const words = bech32.toWords(o.hash); |
}); |
||||
words.unshift(0x00); |
// extended validation
|
||||
return bech32.encode(network.bech32, words); |
if (opts.validate) { |
||||
}); |
let hash = Buffer.from([]); |
||||
lazy.prop(o, 'hash', () => { |
if (a.address) { |
||||
if (a.output) |
if (_address().prefix !== network.bech32) |
||||
return a.output.slice(2); |
throw new TypeError('Invalid prefix or Network mismatch'); |
||||
if (a.address) |
if (_address().version !== 0x00) |
||||
return _address().data; |
throw new TypeError('Invalid address version'); |
||||
if (o.redeem && o.redeem.output) |
if (_address().data.length !== 32) |
||||
return bcrypto.sha256(o.redeem.output); |
throw new TypeError('Invalid address data'); |
||||
}); |
hash = _address().data; |
||||
lazy.prop(o, 'output', () => { |
|
||||
if (!o.hash) |
|
||||
return; |
|
||||
return bscript.compile([OPS.OP_0, o.hash]); |
|
||||
}); |
|
||||
lazy.prop(o, 'redeem', () => { |
|
||||
if (!a.witness) |
|
||||
return; |
|
||||
return { |
|
||||
output: a.witness[a.witness.length - 1], |
|
||||
input: EMPTY_BUFFER, |
|
||||
witness: a.witness.slice(0, -1), |
|
||||
}; |
|
||||
}); |
|
||||
lazy.prop(o, 'input', () => { |
|
||||
if (!o.witness) |
|
||||
return; |
|
||||
return EMPTY_BUFFER; |
|
||||
}); |
|
||||
lazy.prop(o, 'witness', () => { |
|
||||
// transform redeem input to witness stack?
|
|
||||
if (a.redeem && |
|
||||
a.redeem.input && |
|
||||
a.redeem.input.length > 0 && |
|
||||
a.redeem.output && |
|
||||
a.redeem.output.length > 0) { |
|
||||
const stack = bscript.toStack(_rchunks()); |
|
||||
// assign, and blank the existing input
|
|
||||
o.redeem = Object.assign({ witness: stack }, a.redeem); |
|
||||
o.redeem.input = EMPTY_BUFFER; |
|
||||
return [].concat(stack, a.redeem.output); |
|
||||
} |
|
||||
if (!a.redeem) |
|
||||
return; |
|
||||
if (!a.redeem.output) |
|
||||
return; |
|
||||
if (!a.redeem.witness) |
|
||||
return; |
|
||||
return [].concat(a.redeem.witness, a.redeem.output); |
|
||||
}); |
|
||||
// extended validation
|
|
||||
if (opts.validate) { |
|
||||
let hash = Buffer.from([]); |
|
||||
if (a.address) { |
|
||||
if (_address().prefix !== network.bech32) |
|
||||
throw new TypeError('Invalid prefix or Network mismatch'); |
|
||||
if (_address().version !== 0x00) |
|
||||
throw new TypeError('Invalid address version'); |
|
||||
if (_address().data.length !== 32) |
|
||||
throw new TypeError('Invalid address data'); |
|
||||
hash = _address().data; |
|
||||
} |
|
||||
if (a.hash) { |
|
||||
if (hash.length > 0 && !hash.equals(a.hash)) |
|
||||
throw new TypeError('Hash mismatch'); |
|
||||
else |
|
||||
hash = a.hash; |
|
||||
} |
|
||||
if (a.output) { |
|
||||
if (a.output.length !== 34 || |
|
||||
a.output[0] !== OPS.OP_0 || |
|
||||
a.output[1] !== 0x20) |
|
||||
throw new TypeError('Output is invalid'); |
|
||||
const hash2 = a.output.slice(2); |
|
||||
if (hash.length > 0 && !hash.equals(hash2)) |
|
||||
throw new TypeError('Hash mismatch'); |
|
||||
else |
|
||||
hash = hash2; |
|
||||
} |
|
||||
if (a.redeem) { |
|
||||
if (a.redeem.network && a.redeem.network !== network) |
|
||||
throw new TypeError('Network mismatch'); |
|
||||
// is there two redeem sources?
|
|
||||
if (a.redeem.input && |
|
||||
a.redeem.input.length > 0 && |
|
||||
a.redeem.witness && |
|
||||
a.redeem.witness.length > 0) |
|
||||
throw new TypeError('Ambiguous witness source'); |
|
||||
// is the redeem output non-empty?
|
|
||||
if (a.redeem.output) { |
|
||||
if (bscript.decompile(a.redeem.output).length === 0) |
|
||||
throw new TypeError('Redeem.output is invalid'); |
|
||||
// match hash against other sources
|
|
||||
const hash2 = bcrypto.sha256(a.redeem.output); |
|
||||
if (hash.length > 0 && !hash.equals(hash2)) |
|
||||
throw new TypeError('Hash mismatch'); |
|
||||
else |
|
||||
hash = hash2; |
|
||||
} |
|
||||
if (a.redeem.input && !bscript.isPushOnly(_rchunks())) |
|
||||
throw new TypeError('Non push-only scriptSig'); |
|
||||
if (a.witness && |
|
||||
a.redeem.witness && |
|
||||
!stacksEqual(a.witness, a.redeem.witness)) |
|
||||
throw new TypeError('Witness and redeem.witness mismatch'); |
|
||||
} |
|
||||
if (a.witness) { |
|
||||
if (a.redeem && |
|
||||
a.redeem.output && |
|
||||
!a.redeem.output.equals(a.witness[a.witness.length - 1])) |
|
||||
throw new TypeError('Witness and redeem.output mismatch'); |
|
||||
} |
|
||||
} |
} |
||||
return Object.assign(o, a); |
if (a.hash) { |
||||
|
if (hash.length > 0 && !hash.equals(a.hash)) |
||||
|
throw new TypeError('Hash mismatch'); |
||||
|
else hash = a.hash; |
||||
|
} |
||||
|
if (a.output) { |
||||
|
if ( |
||||
|
a.output.length !== 34 || |
||||
|
a.output[0] !== OPS.OP_0 || |
||||
|
a.output[1] !== 0x20 |
||||
|
) |
||||
|
throw new TypeError('Output is invalid'); |
||||
|
const hash2 = a.output.slice(2); |
||||
|
if (hash.length > 0 && !hash.equals(hash2)) |
||||
|
throw new TypeError('Hash mismatch'); |
||||
|
else hash = hash2; |
||||
|
} |
||||
|
if (a.redeem) { |
||||
|
if (a.redeem.network && a.redeem.network !== network) |
||||
|
throw new TypeError('Network mismatch'); |
||||
|
// is there two redeem sources?
|
||||
|
if ( |
||||
|
a.redeem.input && |
||||
|
a.redeem.input.length > 0 && |
||||
|
a.redeem.witness && |
||||
|
a.redeem.witness.length > 0 |
||||
|
) |
||||
|
throw new TypeError('Ambiguous witness source'); |
||||
|
// is the redeem output non-empty?
|
||||
|
if (a.redeem.output) { |
||||
|
if (bscript.decompile(a.redeem.output).length === 0) |
||||
|
throw new TypeError('Redeem.output is invalid'); |
||||
|
// match hash against other sources
|
||||
|
const hash2 = bcrypto.sha256(a.redeem.output); |
||||
|
if (hash.length > 0 && !hash.equals(hash2)) |
||||
|
throw new TypeError('Hash mismatch'); |
||||
|
else hash = hash2; |
||||
|
} |
||||
|
if (a.redeem.input && !bscript.isPushOnly(_rchunks())) |
||||
|
throw new TypeError('Non push-only scriptSig'); |
||||
|
if ( |
||||
|
a.witness && |
||||
|
a.redeem.witness && |
||||
|
!stacksEqual(a.witness, a.redeem.witness) |
||||
|
) |
||||
|
throw new TypeError('Witness and redeem.witness mismatch'); |
||||
|
} |
||||
|
if (a.witness) { |
||||
|
if ( |
||||
|
a.redeem && |
||||
|
a.redeem.output && |
||||
|
!a.redeem.output.equals(a.witness[a.witness.length - 1]) |
||||
|
) |
||||
|
throw new TypeError('Witness and redeem.output mismatch'); |
||||
|
} |
||||
|
} |
||||
|
return Object.assign(o, a); |
||||
} |
} |
||||
exports.p2wsh = p2wsh; |
exports.p2wsh = p2wsh; |
||||
|
@ -1,65 +1,61 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
function decode(buffer, maxLength, minimal) { |
function decode(buffer, maxLength, minimal) { |
||||
maxLength = maxLength || 4; |
maxLength = maxLength || 4; |
||||
minimal = minimal === undefined ? true : minimal; |
minimal = minimal === undefined ? true : minimal; |
||||
const length = buffer.length; |
const length = buffer.length; |
||||
if (length === 0) |
if (length === 0) return 0; |
||||
return 0; |
if (length > maxLength) throw new TypeError('Script number overflow'); |
||||
if (length > maxLength) |
if (minimal) { |
||||
throw new TypeError('Script number overflow'); |
if ((buffer[length - 1] & 0x7f) === 0) { |
||||
if (minimal) { |
if (length <= 1 || (buffer[length - 2] & 0x80) === 0) |
||||
if ((buffer[length - 1] & 0x7f) === 0) { |
throw new Error('Non-minimally encoded script number'); |
||||
if (length <= 1 || (buffer[length - 2] & 0x80) === 0) |
|
||||
throw new Error('Non-minimally encoded script number'); |
|
||||
} |
|
||||
} |
} |
||||
// 40-bit
|
} |
||||
if (length === 5) { |
// 40-bit
|
||||
const a = buffer.readUInt32LE(0); |
if (length === 5) { |
||||
const b = buffer.readUInt8(4); |
const a = buffer.readUInt32LE(0); |
||||
if (b & 0x80) |
const b = buffer.readUInt8(4); |
||||
return -((b & ~0x80) * 0x100000000 + a); |
if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a); |
||||
return b * 0x100000000 + a; |
return b * 0x100000000 + a; |
||||
} |
} |
||||
// 32-bit / 24-bit / 16-bit / 8-bit
|
// 32-bit / 24-bit / 16-bit / 8-bit
|
||||
let result = 0; |
let result = 0; |
||||
for (let i = 0; i < length; ++i) { |
for (let i = 0; i < length; ++i) { |
||||
result |= buffer[i] << (8 * i); |
result |= buffer[i] << (8 * i); |
||||
} |
} |
||||
if (buffer[length - 1] & 0x80) |
if (buffer[length - 1] & 0x80) |
||||
return -(result & ~(0x80 << (8 * (length - 1)))); |
return -(result & ~(0x80 << (8 * (length - 1)))); |
||||
return result; |
return result; |
||||
} |
} |
||||
exports.decode = decode; |
exports.decode = decode; |
||||
function scriptNumSize(i) { |
function scriptNumSize(i) { |
||||
return i > 0x7fffffff |
return i > 0x7fffffff |
||||
? 5 |
? 5 |
||||
: i > 0x7fffff |
: i > 0x7fffff |
||||
? 4 |
? 4 |
||||
: i > 0x7fff |
: i > 0x7fff |
||||
? 3 |
? 3 |
||||
: i > 0x7f |
: i > 0x7f |
||||
? 2 |
? 2 |
||||
: i > 0x00 |
: i > 0x00 |
||||
? 1 |
? 1 |
||||
: 0; |
: 0; |
||||
} |
} |
||||
function encode(_number) { |
function encode(_number) { |
||||
let value = Math.abs(_number); |
let value = Math.abs(_number); |
||||
const size = scriptNumSize(value); |
const size = scriptNumSize(value); |
||||
const buffer = Buffer.allocUnsafe(size); |
const buffer = Buffer.allocUnsafe(size); |
||||
const negative = _number < 0; |
const negative = _number < 0; |
||||
for (let i = 0; i < size; ++i) { |
for (let i = 0; i < size; ++i) { |
||||
buffer.writeUInt8(value & 0xff, i); |
buffer.writeUInt8(value & 0xff, i); |
||||
value >>= 8; |
value >>= 8; |
||||
} |
} |
||||
if (buffer[size - 1] & 0x80) { |
if (buffer[size - 1] & 0x80) { |
||||
buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); |
buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); |
||||
} |
} else if (negative) { |
||||
else if (negative) { |
buffer[size - 1] |= 0x80; |
||||
buffer[size - 1] |= 0x80; |
} |
||||
} |
return buffer; |
||||
return buffer; |
|
||||
} |
} |
||||
exports.encode = encode; |
exports.encode = encode; |
||||
|
@ -1,53 +1,52 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const types = require("./types"); |
const types = require('./types'); |
||||
const bip66 = require('bip66'); |
const bip66 = require('bip66'); |
||||
const typeforce = require('typeforce'); |
const typeforce = require('typeforce'); |
||||
const ZERO = Buffer.alloc(1, 0); |
const ZERO = Buffer.alloc(1, 0); |
||||
function toDER(x) { |
function toDER(x) { |
||||
let i = 0; |
let i = 0; |
||||
while (x[i] === 0) |
while (x[i] === 0) ++i; |
||||
++i; |
if (i === x.length) return ZERO; |
||||
if (i === x.length) |
x = x.slice(i); |
||||
return ZERO; |
if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length); |
||||
x = x.slice(i); |
return x; |
||||
if (x[0] & 0x80) |
|
||||
return Buffer.concat([ZERO, x], 1 + x.length); |
|
||||
return x; |
|
||||
} |
} |
||||
function fromDER(x) { |
function fromDER(x) { |
||||
if (x[0] === 0x00) |
if (x[0] === 0x00) x = x.slice(1); |
||||
x = x.slice(1); |
const buffer = Buffer.alloc(32, 0); |
||||
const buffer = Buffer.alloc(32, 0); |
const bstart = Math.max(0, 32 - x.length); |
||||
const bstart = Math.max(0, 32 - x.length); |
x.copy(buffer, bstart); |
||||
x.copy(buffer, bstart); |
return buffer; |
||||
return buffer; |
|
||||
} |
} |
||||
// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed)
|
// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed)
|
||||
function decode(buffer) { |
function decode(buffer) { |
||||
const hashType = buffer.readUInt8(buffer.length - 1); |
const hashType = buffer.readUInt8(buffer.length - 1); |
||||
const hashTypeMod = hashType & ~0x80; |
const hashTypeMod = hashType & ~0x80; |
||||
if (hashTypeMod <= 0 || hashTypeMod >= 4) |
if (hashTypeMod <= 0 || hashTypeMod >= 4) |
||||
throw new Error('Invalid hashType ' + hashType); |
throw new Error('Invalid hashType ' + hashType); |
||||
const decoded = bip66.decode(buffer.slice(0, -1)); |
const decoded = bip66.decode(buffer.slice(0, -1)); |
||||
const r = fromDER(decoded.r); |
const r = fromDER(decoded.r); |
||||
const s = fromDER(decoded.s); |
const s = fromDER(decoded.s); |
||||
const signature = Buffer.concat([r, s], 64); |
const signature = Buffer.concat([r, s], 64); |
||||
return { signature, hashType }; |
return { signature, hashType }; |
||||
} |
} |
||||
exports.decode = decode; |
exports.decode = decode; |
||||
function encode(signature, hashType) { |
function encode(signature, hashType) { |
||||
typeforce({ |
typeforce( |
||||
signature: types.BufferN(64), |
{ |
||||
hashType: types.UInt8, |
signature: types.BufferN(64), |
||||
}, { signature, hashType }); |
hashType: types.UInt8, |
||||
const hashTypeMod = hashType & ~0x80; |
}, |
||||
if (hashTypeMod <= 0 || hashTypeMod >= 4) |
{ signature, hashType }, |
||||
throw new Error('Invalid hashType ' + hashType); |
); |
||||
const hashTypeBuffer = Buffer.allocUnsafe(1); |
const hashTypeMod = hashType & ~0x80; |
||||
hashTypeBuffer.writeUInt8(hashType, 0); |
if (hashTypeMod <= 0 || hashTypeMod >= 4) |
||||
const r = toDER(signature.slice(0, 32)); |
throw new Error('Invalid hashType ' + hashType); |
||||
const s = toDER(signature.slice(32, 64)); |
const hashTypeBuffer = Buffer.allocUnsafe(1); |
||||
return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); |
hashTypeBuffer.writeUInt8(hashType, 0); |
||||
|
const r = toDER(signature.slice(0, 32)); |
||||
|
const s = toDER(signature.slice(32, 64)); |
||||
|
return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); |
||||
} |
} |
||||
exports.encode = encode; |
exports.encode = encode; |
||||
|
@ -1,6 +1,6 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const input = require("./input"); |
const input = require('./input'); |
||||
exports.input = input; |
exports.input = input; |
||||
const output = require("./output"); |
const output = require('./output'); |
||||
exports.output = output; |
exports.output = output; |
||||
|
@ -1,23 +1,23 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// OP_0 [signatures ...]
|
// OP_0 [signatures ...]
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
const script_1 = require("../../script"); |
const script_1 = require('../../script'); |
||||
function partialSignature(value) { |
function partialSignature(value) { |
||||
return (value === script_1.OPS.OP_0 || bscript.isCanonicalScriptSignature(value)); |
return ( |
||||
|
value === script_1.OPS.OP_0 || bscript.isCanonicalScriptSignature(value) |
||||
|
); |
||||
} |
} |
||||
function check(script, allowIncomplete) { |
function check(script, allowIncomplete) { |
||||
const chunks = bscript.decompile(script); |
const chunks = bscript.decompile(script); |
||||
if (chunks.length < 2) |
if (chunks.length < 2) return false; |
||||
return false; |
if (chunks[0] !== script_1.OPS.OP_0) return false; |
||||
if (chunks[0] !== script_1.OPS.OP_0) |
if (allowIncomplete) { |
||||
return false; |
return chunks.slice(1).every(partialSignature); |
||||
if (allowIncomplete) { |
} |
||||
return chunks.slice(1).every(partialSignature); |
return chunks.slice(1).every(bscript.isCanonicalScriptSignature); |
||||
} |
|
||||
return chunks.slice(1).every(bscript.isCanonicalScriptSignature); |
|
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'multisig input'; |
return 'multisig input'; |
||||
}; |
}; |
||||
|
@ -1,36 +1,27 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// m [pubKeys ...] n OP_CHECKMULTISIG
|
// m [pubKeys ...] n OP_CHECKMULTISIG
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
const script_1 = require("../../script"); |
const script_1 = require('../../script'); |
||||
const types = require("../../types"); |
const types = require('../../types'); |
||||
const OP_INT_BASE = script_1.OPS.OP_RESERVED; // OP_1 - 1
|
const OP_INT_BASE = script_1.OPS.OP_RESERVED; // OP_1 - 1
|
||||
function check(script, allowIncomplete) { |
function check(script, allowIncomplete) { |
||||
const chunks = bscript.decompile(script); |
const chunks = bscript.decompile(script); |
||||
if (chunks.length < 4) |
if (chunks.length < 4) return false; |
||||
return false; |
if (chunks[chunks.length - 1] !== script_1.OPS.OP_CHECKMULTISIG) return false; |
||||
if (chunks[chunks.length - 1] !== script_1.OPS.OP_CHECKMULTISIG) |
if (!types.Number(chunks[0])) return false; |
||||
return false; |
if (!types.Number(chunks[chunks.length - 2])) return false; |
||||
if (!types.Number(chunks[0])) |
const m = chunks[0] - OP_INT_BASE; |
||||
return false; |
const n = chunks[chunks.length - 2] - OP_INT_BASE; |
||||
if (!types.Number(chunks[chunks.length - 2])) |
if (m <= 0) return false; |
||||
return false; |
if (n > 16) return false; |
||||
const m = chunks[0] - OP_INT_BASE; |
if (m > n) return false; |
||||
const n = chunks[chunks.length - 2] - OP_INT_BASE; |
if (n !== chunks.length - 3) return false; |
||||
if (m <= 0) |
if (allowIncomplete) return true; |
||||
return false; |
const keys = chunks.slice(1, -2); |
||||
if (n > 16) |
return keys.every(bscript.isCanonicalPubKey); |
||||
return false; |
|
||||
if (m > n) |
|
||||
return false; |
|
||||
if (n !== chunks.length - 3) |
|
||||
return false; |
|
||||
if (allowIncomplete) |
|
||||
return true; |
|
||||
const keys = chunks.slice(1, -2); |
|
||||
return keys.every(bscript.isCanonicalPubKey); |
|
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'multi-sig output'; |
return 'multi-sig output'; |
||||
}; |
}; |
||||
|
@ -1,15 +1,15 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
// OP_RETURN {data}
|
// OP_RETURN {data}
|
||||
const bscript = require("../script"); |
const bscript = require('../script'); |
||||
const OPS = bscript.OPS; |
const OPS = bscript.OPS; |
||||
function check(script) { |
function check(script) { |
||||
const buffer = bscript.compile(script); |
const buffer = bscript.compile(script); |
||||
return buffer.length > 1 && buffer[0] === OPS.OP_RETURN; |
return buffer.length > 1 && buffer[0] === OPS.OP_RETURN; |
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'null data output'; |
return 'null data output'; |
||||
}; |
}; |
||||
const output = { check }; |
const output = { check }; |
||||
exports.output = output; |
exports.output = output; |
||||
|
@ -1,6 +1,6 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const input = require("./input"); |
const input = require('./input'); |
||||
exports.input = input; |
exports.input = input; |
||||
const output = require("./output"); |
const output = require('./output'); |
||||
exports.output = output; |
exports.output = output; |
||||
|
@ -1,13 +1,12 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// {signature}
|
// {signature}
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
function check(script) { |
function check(script) { |
||||
const chunks = bscript.decompile(script); |
const chunks = bscript.decompile(script); |
||||
return (chunks.length === 1 && |
return chunks.length === 1 && bscript.isCanonicalScriptSignature(chunks[0]); |
||||
bscript.isCanonicalScriptSignature(chunks[0])); |
|
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'pubKey input'; |
return 'pubKey input'; |
||||
}; |
}; |
||||
|
@ -1,15 +1,17 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// {pubKey} OP_CHECKSIG
|
// {pubKey} OP_CHECKSIG
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
const script_1 = require("../../script"); |
const script_1 = require('../../script'); |
||||
function check(script) { |
function check(script) { |
||||
const chunks = bscript.decompile(script); |
const chunks = bscript.decompile(script); |
||||
return (chunks.length === 2 && |
return ( |
||||
bscript.isCanonicalPubKey(chunks[0]) && |
chunks.length === 2 && |
||||
chunks[1] === script_1.OPS.OP_CHECKSIG); |
bscript.isCanonicalPubKey(chunks[0]) && |
||||
|
chunks[1] === script_1.OPS.OP_CHECKSIG |
||||
|
); |
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'pubKey output'; |
return 'pubKey output'; |
||||
}; |
}; |
||||
|
@ -1,6 +1,6 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const input = require("./input"); |
const input = require('./input'); |
||||
exports.input = input; |
exports.input = input; |
||||
const output = require("./output"); |
const output = require('./output'); |
||||
exports.output = output; |
exports.output = output; |
||||
|
@ -1,14 +1,16 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// {signature} {pubKey}
|
// {signature} {pubKey}
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
function check(script) { |
function check(script) { |
||||
const chunks = bscript.decompile(script); |
const chunks = bscript.decompile(script); |
||||
return (chunks.length === 2 && |
return ( |
||||
bscript.isCanonicalScriptSignature(chunks[0]) && |
chunks.length === 2 && |
||||
bscript.isCanonicalPubKey(chunks[1])); |
bscript.isCanonicalScriptSignature(chunks[0]) && |
||||
|
bscript.isCanonicalPubKey(chunks[1]) |
||||
|
); |
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'pubKeyHash input'; |
return 'pubKeyHash input'; |
||||
}; |
}; |
||||
|
@ -1,18 +1,20 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
|
// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
const script_1 = require("../../script"); |
const script_1 = require('../../script'); |
||||
function check(script) { |
function check(script) { |
||||
const buffer = bscript.compile(script); |
const buffer = bscript.compile(script); |
||||
return (buffer.length === 25 && |
return ( |
||||
buffer[0] === script_1.OPS.OP_DUP && |
buffer.length === 25 && |
||||
buffer[1] === script_1.OPS.OP_HASH160 && |
buffer[0] === script_1.OPS.OP_DUP && |
||||
buffer[2] === 0x14 && |
buffer[1] === script_1.OPS.OP_HASH160 && |
||||
buffer[23] === script_1.OPS.OP_EQUALVERIFY && |
buffer[2] === 0x14 && |
||||
buffer[24] === script_1.OPS.OP_CHECKSIG); |
buffer[23] === script_1.OPS.OP_EQUALVERIFY && |
||||
|
buffer[24] === script_1.OPS.OP_CHECKSIG |
||||
|
); |
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'pubKeyHash output'; |
return 'pubKeyHash output'; |
||||
}; |
}; |
||||
|
@ -1,6 +1,6 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const input = require("./input"); |
const input = require('./input'); |
||||
exports.input = input; |
exports.input = input; |
||||
const output = require("./output"); |
const output = require('./output'); |
||||
exports.output = output; |
exports.output = output; |
||||
|
@ -1,44 +1,50 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// <scriptSig> {serialized scriptPubKey script}
|
// <scriptSig> {serialized scriptPubKey script}
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
const p2ms = require("../multisig"); |
const p2ms = require('../multisig'); |
||||
const p2pk = require("../pubkey"); |
const p2pk = require('../pubkey'); |
||||
const p2pkh = require("../pubkeyhash"); |
const p2pkh = require('../pubkeyhash'); |
||||
const p2wpkho = require("../witnesspubkeyhash/output"); |
const p2wpkho = require('../witnesspubkeyhash/output'); |
||||
const p2wsho = require("../witnessscripthash/output"); |
const p2wsho = require('../witnessscripthash/output'); |
||||
function check(script, allowIncomplete) { |
function check(script, allowIncomplete) { |
||||
const chunks = bscript.decompile(script); |
const chunks = bscript.decompile(script); |
||||
if (chunks.length < 1) |
if (chunks.length < 1) return false; |
||||
return false; |
const lastChunk = chunks[chunks.length - 1]; |
||||
const lastChunk = chunks[chunks.length - 1]; |
if (!Buffer.isBuffer(lastChunk)) return false; |
||||
if (!Buffer.isBuffer(lastChunk)) |
const scriptSigChunks = bscript.decompile( |
||||
return false; |
bscript.compile(chunks.slice(0, -1)), |
||||
const scriptSigChunks = bscript.decompile(bscript.compile(chunks.slice(0, -1))); |
); |
||||
const redeemScriptChunks = bscript.decompile(lastChunk); |
const redeemScriptChunks = bscript.decompile(lastChunk); |
||||
// is redeemScript a valid script?
|
// is redeemScript a valid script?
|
||||
if (!redeemScriptChunks) |
if (!redeemScriptChunks) return false; |
||||
return false; |
// is redeemScriptSig push only?
|
||||
// is redeemScriptSig push only?
|
if (!bscript.isPushOnly(scriptSigChunks)) return false; |
||||
if (!bscript.isPushOnly(scriptSigChunks)) |
// is witness?
|
||||
return false; |
if (chunks.length === 1) { |
||||
// is witness?
|
return ( |
||||
if (chunks.length === 1) { |
p2wsho.check(redeemScriptChunks) || p2wpkho.check(redeemScriptChunks) |
||||
return (p2wsho.check(redeemScriptChunks) || p2wpkho.check(redeemScriptChunks)); |
); |
||||
} |
} |
||||
// match types
|
// match types
|
||||
if (p2pkh.input.check(scriptSigChunks) && |
if ( |
||||
p2pkh.output.check(redeemScriptChunks)) |
p2pkh.input.check(scriptSigChunks) && |
||||
return true; |
p2pkh.output.check(redeemScriptChunks) |
||||
if (p2ms.input.check(scriptSigChunks, allowIncomplete) && |
) |
||||
p2ms.output.check(redeemScriptChunks)) |
return true; |
||||
return true; |
if ( |
||||
if (p2pk.input.check(scriptSigChunks) && |
p2ms.input.check(scriptSigChunks, allowIncomplete) && |
||||
p2pk.output.check(redeemScriptChunks)) |
p2ms.output.check(redeemScriptChunks) |
||||
return true; |
) |
||||
return false; |
return true; |
||||
|
if ( |
||||
|
p2pk.input.check(scriptSigChunks) && |
||||
|
p2pk.output.check(redeemScriptChunks) |
||||
|
) |
||||
|
return true; |
||||
|
return false; |
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'scriptHash input'; |
return 'scriptHash input'; |
||||
}; |
}; |
||||
|
@ -1,16 +1,18 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// OP_HASH160 {scriptHash} OP_EQUAL
|
// OP_HASH160 {scriptHash} OP_EQUAL
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
const script_1 = require("../../script"); |
const script_1 = require('../../script'); |
||||
function check(script) { |
function check(script) { |
||||
const buffer = bscript.compile(script); |
const buffer = bscript.compile(script); |
||||
return (buffer.length === 23 && |
return ( |
||||
buffer[0] === script_1.OPS.OP_HASH160 && |
buffer.length === 23 && |
||||
buffer[1] === 0x14 && |
buffer[0] === script_1.OPS.OP_HASH160 && |
||||
buffer[22] === script_1.OPS.OP_EQUAL); |
buffer[1] === 0x14 && |
||||
|
buffer[22] === script_1.OPS.OP_EQUAL |
||||
|
); |
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'scriptHash output'; |
return 'scriptHash output'; |
||||
}; |
}; |
||||
|
@ -1,4 +1,4 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const output = require("./output"); |
const output = require('./output'); |
||||
exports.output = output; |
exports.output = output; |
||||
|
@ -1,32 +1,34 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// OP_RETURN {aa21a9ed} {commitment}
|
// OP_RETURN {aa21a9ed} {commitment}
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
const script_1 = require("../../script"); |
const script_1 = require('../../script'); |
||||
const types = require("../../types"); |
const types = require('../../types'); |
||||
const typeforce = require('typeforce'); |
const typeforce = require('typeforce'); |
||||
const HEADER = Buffer.from('aa21a9ed', 'hex'); |
const HEADER = Buffer.from('aa21a9ed', 'hex'); |
||||
function check(script) { |
function check(script) { |
||||
const buffer = bscript.compile(script); |
const buffer = bscript.compile(script); |
||||
return (buffer.length > 37 && |
return ( |
||||
buffer[0] === script_1.OPS.OP_RETURN && |
buffer.length > 37 && |
||||
buffer[1] === 0x24 && |
buffer[0] === script_1.OPS.OP_RETURN && |
||||
buffer.slice(2, 6).equals(HEADER)); |
buffer[1] === 0x24 && |
||||
|
buffer.slice(2, 6).equals(HEADER) |
||||
|
); |
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'Witness commitment output'; |
return 'Witness commitment output'; |
||||
}; |
}; |
||||
function encode(commitment) { |
function encode(commitment) { |
||||
typeforce(types.Hash256bit, commitment); |
typeforce(types.Hash256bit, commitment); |
||||
const buffer = Buffer.allocUnsafe(36); |
const buffer = Buffer.allocUnsafe(36); |
||||
HEADER.copy(buffer, 0); |
HEADER.copy(buffer, 0); |
||||
commitment.copy(buffer, 4); |
commitment.copy(buffer, 4); |
||||
return bscript.compile([script_1.OPS.OP_RETURN, buffer]); |
return bscript.compile([script_1.OPS.OP_RETURN, buffer]); |
||||
} |
} |
||||
exports.encode = encode; |
exports.encode = encode; |
||||
function decode(buffer) { |
function decode(buffer) { |
||||
typeforce(check, buffer); |
typeforce(check, buffer); |
||||
return bscript.decompile(buffer)[1].slice(4, 36); |
return bscript.decompile(buffer)[1].slice(4, 36); |
||||
} |
} |
||||
exports.decode = decode; |
exports.decode = decode; |
||||
|
@ -1,6 +1,6 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const input = require("./input"); |
const input = require('./input'); |
||||
exports.input = input; |
exports.input = input; |
||||
const output = require("./output"); |
const output = require('./output'); |
||||
exports.output = output; |
exports.output = output; |
||||
|
@ -1,17 +1,19 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// {signature} {pubKey}
|
// {signature} {pubKey}
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
function isCompressedCanonicalPubKey(pubKey) { |
function isCompressedCanonicalPubKey(pubKey) { |
||||
return bscript.isCanonicalPubKey(pubKey) && pubKey.length === 33; |
return bscript.isCanonicalPubKey(pubKey) && pubKey.length === 33; |
||||
} |
} |
||||
function check(script) { |
function check(script) { |
||||
const chunks = bscript.decompile(script); |
const chunks = bscript.decompile(script); |
||||
return (chunks.length === 2 && |
return ( |
||||
bscript.isCanonicalScriptSignature(chunks[0]) && |
chunks.length === 2 && |
||||
isCompressedCanonicalPubKey(chunks[1])); |
bscript.isCanonicalScriptSignature(chunks[0]) && |
||||
|
isCompressedCanonicalPubKey(chunks[1]) |
||||
|
); |
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'witnessPubKeyHash input'; |
return 'witnessPubKeyHash input'; |
||||
}; |
}; |
||||
|
@ -1,13 +1,17 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// OP_0 {pubKeyHash}
|
// OP_0 {pubKeyHash}
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
const script_1 = require("../../script"); |
const script_1 = require('../../script'); |
||||
function check(script) { |
function check(script) { |
||||
const buffer = bscript.compile(script); |
const buffer = bscript.compile(script); |
||||
return buffer.length === 22 && buffer[0] === script_1.OPS.OP_0 && buffer[1] === 0x14; |
return ( |
||||
|
buffer.length === 22 && |
||||
|
buffer[0] === script_1.OPS.OP_0 && |
||||
|
buffer[1] === 0x14 |
||||
|
); |
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'Witness pubKeyHash output'; |
return 'Witness pubKeyHash output'; |
||||
}; |
}; |
||||
|
@ -1,6 +1,6 @@ |
|||||
"use strict"; |
'use strict'; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const input = require("./input"); |
const input = require('./input'); |
||||
exports.input = input; |
exports.input = input; |
||||
const output = require("./output"); |
const output = require('./output'); |
||||
exports.output = output; |
exports.output = output; |
||||
|
@ -1,36 +1,39 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// <scriptSig> {serialized scriptPubKey script}
|
// <scriptSig> {serialized scriptPubKey script}
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
const typeforce = require('typeforce'); |
const typeforce = require('typeforce'); |
||||
const p2ms = require("../multisig"); |
const p2ms = require('../multisig'); |
||||
const p2pk = require("../pubkey"); |
const p2pk = require('../pubkey'); |
||||
const p2pkh = require("../pubkeyhash"); |
const p2pkh = require('../pubkeyhash'); |
||||
function check(chunks, allowIncomplete) { |
function check(chunks, allowIncomplete) { |
||||
typeforce(typeforce.Array, chunks); |
typeforce(typeforce.Array, chunks); |
||||
if (chunks.length < 1) |
if (chunks.length < 1) return false; |
||||
return false; |
const witnessScript = chunks[chunks.length - 1]; |
||||
const witnessScript = chunks[chunks.length - 1]; |
if (!Buffer.isBuffer(witnessScript)) return false; |
||||
if (!Buffer.isBuffer(witnessScript)) |
const witnessScriptChunks = bscript.decompile(witnessScript); |
||||
return false; |
// is witnessScript a valid script?
|
||||
const witnessScriptChunks = bscript.decompile(witnessScript); |
if (!witnessScriptChunks || witnessScriptChunks.length === 0) return false; |
||||
// is witnessScript a valid script?
|
const witnessRawScriptSig = bscript.compile(chunks.slice(0, -1)); |
||||
if (!witnessScriptChunks || witnessScriptChunks.length === 0) |
// match types
|
||||
return false; |
if ( |
||||
const witnessRawScriptSig = bscript.compile(chunks.slice(0, -1)); |
p2pkh.input.check(witnessRawScriptSig) && |
||||
// match types
|
p2pkh.output.check(witnessScriptChunks) |
||||
if (p2pkh.input.check(witnessRawScriptSig) && |
) |
||||
p2pkh.output.check(witnessScriptChunks)) |
return true; |
||||
return true; |
if ( |
||||
if (p2ms.input.check(witnessRawScriptSig, allowIncomplete) && |
p2ms.input.check(witnessRawScriptSig, allowIncomplete) && |
||||
p2ms.output.check(witnessScriptChunks)) |
p2ms.output.check(witnessScriptChunks) |
||||
return true; |
) |
||||
if (p2pk.input.check(witnessRawScriptSig) && |
return true; |
||||
p2pk.output.check(witnessScriptChunks)) |
if ( |
||||
return true; |
p2pk.input.check(witnessRawScriptSig) && |
||||
return false; |
p2pk.output.check(witnessScriptChunks) |
||||
|
) |
||||
|
return true; |
||||
|
return false; |
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'witnessScriptHash input'; |
return 'witnessScriptHash input'; |
||||
}; |
}; |
||||
|
@ -1,13 +1,17 @@ |
|||||
"use strict"; |
'use strict'; |
||||
// OP_0 {scriptHash}
|
// OP_0 {scriptHash}
|
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
const bscript = require("../../script"); |
const bscript = require('../../script'); |
||||
const script_1 = require("../../script"); |
const script_1 = require('../../script'); |
||||
function check(script) { |
function check(script) { |
||||
const buffer = bscript.compile(script); |
const buffer = bscript.compile(script); |
||||
return buffer.length === 34 && buffer[0] === script_1.OPS.OP_0 && buffer[1] === 0x20; |
return ( |
||||
|
buffer.length === 34 && |
||||
|
buffer[0] === script_1.OPS.OP_0 && |
||||
|
buffer[1] === 0x20 |
||||
|
); |
||||
} |
} |
||||
exports.check = check; |
exports.check = check; |
||||
check.toJSON = () => { |
check.toJSON = () => { |
||||
return 'Witness scriptHash output'; |
return 'Witness scriptHash output'; |
||||
}; |
}; |
||||
|
File diff suppressed because it is too large
Loading…
Reference in new issue