166 lines
3.6 KiB
JavaScript
166 lines
3.6 KiB
JavaScript
'use strict'
|
|
|
|
var varuint = require('varuint-bitcoin')
|
|
|
|
var ZCIncrementalMerkleTree = require('./incremental_merkle_tree')
|
|
|
|
function ZCIncrementalWitness () {
|
|
this.tree = new ZCIncrementalMerkleTree()
|
|
this.filled = []
|
|
this.cursor = null
|
|
this.cursor_depth = 0
|
|
}
|
|
|
|
ZCIncrementalWitness.fromTree = function (tree) {
|
|
var witness = new ZCIncrementalWitness()
|
|
witness.tree = tree.clone()
|
|
return witness
|
|
}
|
|
|
|
ZCIncrementalWitness.fromBuffer = function (buffer, __noStrict, __depth) {
|
|
var offset = 0
|
|
function readSlice (n) {
|
|
offset += n
|
|
return buffer.slice(offset - n, offset)
|
|
}
|
|
|
|
function readUInt8 () {
|
|
var i = buffer.readUInt8(offset)
|
|
offset += 1
|
|
return i
|
|
}
|
|
|
|
function readVarInt () {
|
|
var vi = varuint.decode(buffer, offset)
|
|
offset += varuint.decode.bytes
|
|
return vi
|
|
}
|
|
|
|
function readOptional (func) {
|
|
var i = readUInt8()
|
|
if (i === 1) {
|
|
return func()
|
|
} else if (i === 0) {
|
|
return null
|
|
} else {
|
|
throw new Error('Invalid optional')
|
|
}
|
|
}
|
|
|
|
function readZCIncrementalMerkleTree () {
|
|
var tree = ZCIncrementalMerkleTree.fromBuffer(buffer.slice(offset), true, __depth)
|
|
offset += tree.byteLength()
|
|
return tree
|
|
}
|
|
|
|
var witness = new ZCIncrementalWitness()
|
|
witness.tree = readZCIncrementalMerkleTree()
|
|
|
|
var filledLen = readVarInt()
|
|
for (var i = 0; i < filledLen; ++i) {
|
|
witness.filled.push(readSlice(32))
|
|
}
|
|
|
|
witness.cursor = readOptional(readZCIncrementalMerkleTree)
|
|
|
|
if (__noStrict && offset <= buffer.length) return witness
|
|
if (offset !== buffer.length) throw new Error('ZCIncrementalWitness has unexpected data')
|
|
|
|
return witness
|
|
}
|
|
|
|
ZCIncrementalWitness.prototype.byteLength = function () {
|
|
return (
|
|
this.tree.byteLength() +
|
|
varuint.encodingLength(this.filled.length) +
|
|
this.filled.length * 32 +
|
|
(this.cursor ? this.cursor.byteLength() + 1 : 1)
|
|
)
|
|
}
|
|
|
|
ZCIncrementalWitness.prototype.toBuffer = function () {
|
|
var buffer = Buffer.alloc(this.byteLength())
|
|
|
|
var offset = 0
|
|
function writeSlice (slice) {
|
|
slice.copy(buffer, offset)
|
|
offset += slice.length
|
|
}
|
|
|
|
function writeUInt8 (i) {
|
|
buffer.writeUInt8(i, offset)
|
|
offset += 1
|
|
}
|
|
|
|
function writeVarInt (i) {
|
|
varuint.encode(i, buffer, offset)
|
|
offset += varuint.encode.bytes
|
|
}
|
|
|
|
function writeOptional (val, func) {
|
|
if (val) {
|
|
writeUInt8(1)
|
|
func(val)
|
|
} else {
|
|
writeUInt8(0)
|
|
}
|
|
}
|
|
|
|
function writeZCIncrementalMerkleTree (tree) {
|
|
writeSlice(tree.toBuffer())
|
|
}
|
|
|
|
writeSlice(this.tree.toBuffer())
|
|
|
|
writeVarInt(this.filled.length)
|
|
this.filled.forEach(function (hash) {
|
|
writeSlice(hash)
|
|
})
|
|
|
|
writeOptional(this.cursor, writeZCIncrementalMerkleTree)
|
|
|
|
return buffer
|
|
}
|
|
|
|
ZCIncrementalWitness.prototype.root = function () {
|
|
return this.tree.root(this.tree.depth, this.partial_path())
|
|
}
|
|
|
|
ZCIncrementalWitness.prototype.partial_path = function () {
|
|
var uncles = this.filled.map(function (entry) {
|
|
return entry
|
|
})
|
|
|
|
if (this.cursor) {
|
|
uncles.push(this.cursor.root(this.cursor_depth))
|
|
}
|
|
|
|
return uncles
|
|
}
|
|
|
|
ZCIncrementalWitness.prototype.append = function (obj) {
|
|
if (this.cursor) {
|
|
this.cursor.append(obj)
|
|
|
|
if (this.cursor.is_complete(this.cursor_depth)) {
|
|
this.filled.push(this.cursor.root(this.cursor_depth))
|
|
this.cursor = null
|
|
}
|
|
} else {
|
|
this.cursor_depth = this.tree.next_depth(this.filled.length)
|
|
|
|
if (this.cursor_depth >= this.tree.depth) {
|
|
throw new Error('tree is full')
|
|
}
|
|
|
|
if (this.cursor_depth === 0) {
|
|
this.filled.push(obj)
|
|
} else {
|
|
this.cursor = new ZCIncrementalMerkleTree(this.tree.depth)
|
|
this.cursor.append(obj)
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = ZCIncrementalWitness
|