/*! * packets.js - worker packets for bcoin * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). * https://github.com/bcoin-org/bcoin */ 'use strict'; /** * @module workers/packets */ var assert = require('assert'); var util = require('../utils/util'); var BufferReader = require('../utils/reader'); var encoding = require('../utils/encoding'); var Script = require('../script/script'); var Witness = require('../script/witness'); var Output = require('../primitives/output'); /* * Constants */ var packetTypes = { EVENT: 0, LOG: 1, ERROR: 2, ERRORRESULT: 3, VERIFY: 4, VERIFYRESULT: 5, SIGN: 6, SIGNRESULT: 7, VERIFYINPUT: 8, VERIFYINPUTRESULT: 9, SIGNINPUT: 10, SIGNINPUTRESULT: 11, ECVERIFY: 12, ECVERIFYRESULT: 13, ECSIGN: 14, ECSIGNRESULT: 15, MINE: 16, MINERESULT: 17, SCRYPT: 18, SCRYPTRESULT: 19 }; /** * Packet * @constructor */ function Packet() { this.id = ++Packet.id >>> 0; } Packet.id = 0; Packet.prototype.cmd = -1; Packet.prototype.toWriter = function toWriter() { throw new Error('Abstract method.'); }; /** * EventPacket * @constructor */ function EventPacket(items) { Packet.call(this); this.items = items || []; this.json = JSON.stringify(this.items); } util.inherits(EventPacket, Packet); EventPacket.prototype.cmd = packetTypes.EVENT; EventPacket.prototype.getSize = function getSize() { return encoding.sizeVarString(this.json, 'utf8'); }; EventPacket.prototype.toWriter = function toWriter(bw) { bw.writeVarString(this.json, 'utf8'); }; EventPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new EventPacket(); packet.items = JSON.parse(br.readVarString('utf8')); return packet; }; /** * LogPacket * @constructor */ function LogPacket(text) { Packet.call(this); this.text = text || ''; } util.inherits(LogPacket, Packet); LogPacket.prototype.cmd = packetTypes.LOG; LogPacket.prototype.getSize = function getSize() { return encoding.sizeVarString(this.text, 'utf8'); }; LogPacket.prototype.toWriter = function toWriter(bw) { bw.writeVarString(this.text, 'utf8'); }; LogPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new LogPacket(); packet.text = br.readVarString('utf8'); return packet; }; /** * ErrorPacket * @constructor */ function ErrorPacket(error) { Packet.call(this); this.error = error || new Error(); } util.inherits(ErrorPacket, Packet); ErrorPacket.prototype.cmd = packetTypes.ERROR; ErrorPacket.prototype.getSize = function getSize() { var size = 0; size += encoding.sizeVarString(this.error.message + '', 'utf8'); size += encoding.sizeVarString(this.error.stack + '', 'utf8'); size += encoding.sizeVarString((this.error.type || ''), 'utf8'); return size; }; ErrorPacket.prototype.toWriter = function toWriter(bw) { bw.writeVarString(this.error.message + '', 'utf8'); bw.writeVarString(this.error.stack + '', 'utf8'); bw.writeVarString((this.error.type || ''), 'utf8'); }; ErrorPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new ErrorPacket(); packet.error.message = br.readVarString('utf8'); packet.error.stack = br.readVarString('utf8'); packet.error.type = br.readVarString('utf8'); return packet; }; /** * ErrorResultPacket * @constructor */ function ErrorResultPacket(error) { Packet.call(this); this.error = error || new Error(); } util.inherits(ErrorResultPacket, Packet); ErrorResultPacket.prototype.cmd = packetTypes.ERRORRESULT; ErrorResultPacket.prototype.getSize = function getSize() { var size = 0; size += encoding.sizeVarString(this.error.message + '', 'utf8'); size += encoding.sizeVarString(this.error.stack + '', 'utf8'); size += encoding.sizeVarString((this.error.type || ''), 'utf8'); return size; }; ErrorResultPacket.prototype.toWriter = function toWriter(bw) { bw.writeVarString(this.error.message + '', 'utf8'); bw.writeVarString(this.error.stack + '', 'utf8'); bw.writeVarString((this.error.type || ''), 'utf8'); }; ErrorResultPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new ErrorResultPacket(); packet.error.message = br.readVarString('utf8'); packet.error.stack = br.readVarString('utf8'); packet.error.type = br.readVarString('utf8'); return packet; }; /** * VerifyPacket * @constructor */ function VerifyPacket(tx, view, flags) { Packet.call(this); this.tx = tx || null; this.view = view || null; this.flags = flags != null ? flags : null; } util.inherits(VerifyPacket, Packet); VerifyPacket.prototype.cmd = packetTypes.VERIFY; VerifyPacket.prototype.getSize = function() { return this.tx.getSize() + this.view.getFastSize(this.tx) + 4; }; VerifyPacket.prototype.toWriter = function(bw) { this.tx.toWriter(bw); this.view.toFast(bw, this.tx); bw.write32(this.flags != null ? this.flags : -1); }; VerifyPacket.fromRaw = function fromRaw(TX, CoinView, data) { var br = new BufferReader(data, true); var packet = new VerifyPacket(); packet.tx = TX.fromReader(br); packet.view = CoinView.fromFast(br, packet.tx); packet.flags = br.read32(); if (packet.flags === -1) packet.flags = null; return packet; }; /** * VerifyResultPacket * @constructor */ function VerifyResultPacket(value) { Packet.call(this); this.value = value; } util.inherits(VerifyResultPacket, Packet); VerifyResultPacket.prototype.cmd = packetTypes.VERIFYRESULT; VerifyResultPacket.prototype.getSize = function getSize() { return 1; }; VerifyResultPacket.prototype.toWriter = function toWriter(bw) { bw.writeU8(this.value ? 1 : 0); }; VerifyResultPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new VerifyResultPacket(); packet.value = br.readU8() === 1; return packet; }; /** * SignPacket * @constructor */ function SignPacket(tx, rings, type) { Packet.call(this); this.tx = tx || null; this.rings = rings || []; this.type = type != null ? type : 1; } util.inherits(SignPacket, Packet); SignPacket.prototype.cmd = packetTypes.SIGN; SignPacket.prototype.getSize = function getSize() { var size = 0; var i, ring; size += this.tx.getSize(); size += this.tx.view.getFastSize(this.tx); size += encoding.sizeVarint(this.rings.length); for (i = 0; i < this.rings.length; i++) { ring = this.rings[i]; size += ring.getSize(); } size += 1; return size; }; SignPacket.prototype.toWriter = function toWriter(bw) { var i, ring; this.tx.toWriter(bw); this.tx.view.toFast(bw, this.tx); bw.writeVarint(this.rings.length); for (i = 0; i < this.rings.length; i++) { ring = this.rings[i]; ring.toWriter(bw); } bw.writeU8(this.type); }; SignPacket.fromRaw = function fromRaw(MTX, KeyRing, data) { var br = new BufferReader(data, true); var packet = new SignPacket(); var i, count, ring; packet.tx = MTX.fromReader(br); packet.tx.view.fromFast(br, packet.tx); count = br.readVarint(); for (i = 0; i < count; i++) { ring = KeyRing.fromReader(br); packet.rings.push(ring); } packet.type = br.readU8(); return packet; }; /** * SignResultPacket * @constructor */ function SignResultPacket(total, witness, script) { Packet.call(this); this.total = total || 0; this.script = script || []; this.witness = witness || []; } util.inherits(SignResultPacket, Packet); SignResultPacket.prototype.cmd = packetTypes.SIGNRESULT; SignResultPacket.fromTX = function fromTX(tx, total) { var packet = new SignResultPacket(total); var i, input; for (i = 0; i < tx.inputs.length; i++) { input = tx.inputs[i]; packet.script.push(input.script); packet.witness.push(input.witness); } return packet; }; SignResultPacket.prototype.getSize = function getSize() { var size = 0; var i, script, witness; size += encoding.sizeVarint(this.total); size += encoding.sizeVarint(this.script.length); for (i = 0; i < this.script.length; i++) { script = this.script[i]; witness = this.witness[i]; size += script.getVarSize(); size += witness.getVarSize(); } return size; }; SignResultPacket.prototype.toWriter = function toWriter(bw) { var i; assert(this.script.length === this.witness.length); bw.writeVarint(this.total); bw.writeVarint(this.script.length); for (i = 0; i < this.script.length; i++) { this.script[i].toWriter(bw); this.witness[i].toWriter(bw); } }; SignResultPacket.prototype.inject = function inject(tx) { var i, input; assert(this.script.length === tx.inputs.length); assert(this.witness.length === tx.inputs.length); for (i = 0; i < tx.inputs.length; i++) { input = tx.inputs[i]; input.script = this.script[i]; input.witness = this.witness[i]; } }; SignResultPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new SignResultPacket(); var i, count; packet.total = br.readVarint(); count = br.readVarint(); for (i = 0; i < count; i++) { packet.script.push(Script.fromReader(br)); packet.witness.push(Witness.fromReader(br)); } return packet; }; /** * VerifyInputPacket * @constructor */ function VerifyInputPacket(tx, index, coin, flags) { Packet.call(this); this.tx = tx || null; this.index = index; this.coin = coin || null; this.flags = flags != null ? flags : null; } util.inherits(VerifyInputPacket, Packet); VerifyInputPacket.prototype.cmd = packetTypes.VERIFYINPUT; VerifyInputPacket.prototype.getSize = function getSize() { var size = 0; size += this.tx.getSize(); size += encoding.sizeVarint(this.index); size += encoding.sizeVarint(this.coin.value); size += this.coin.script.getVarSize(); size += 4; return size; }; VerifyInputPacket.prototype.toWriter = function toWriter(bw) { this.tx.toWriter(bw); bw.writeVarint(this.index); bw.writeVarint(this.coin.value); this.coin.script.toWriter(bw); bw.write32(this.flags != null ? this.flags : -1); }; VerifyInputPacket.fromRaw = function fromRaw(TX, data) { var br = new BufferReader(data, true); var packet = new VerifyInputPacket(); packet.tx = TX.fromReader(br); packet.index = br.readVarint(); packet.coin = new Output(); packet.coin.value = br.readVarint(); packet.coin.script.fromReader(br); packet.flags = br.read32(); if (packet.flags === -1) packet.flags = null; return packet; }; /** * VerifyInputResultPacket * @constructor */ function VerifyInputResultPacket(value) { Packet.call(this); this.value = value; } util.inherits(VerifyInputResultPacket, Packet); VerifyInputResultPacket.prototype.cmd = packetTypes.VERIFYINPUTRESULT; VerifyInputResultPacket.prototype.getSize = function getSize() { return 1; }; VerifyInputResultPacket.prototype.toWriter = function toWriter(bw) { bw.writeU8(this.value ? 1 : 0); }; VerifyInputResultPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new VerifyInputResultPacket(); packet.value = br.readU8() === 1; return packet; }; /** * SignInputPacket * @constructor */ function SignInputPacket(tx, index, coin, ring, type) { Packet.call(this); this.tx = tx || null; this.index = index; this.coin = coin || null; this.ring = ring || null; this.type = type != null ? type : 1; } util.inherits(SignInputPacket, Packet); SignInputPacket.prototype.cmd = packetTypes.SIGNINPUT; SignInputPacket.prototype.getSize = function getSize() { var size = 0; size += this.tx.getSize(); size += encoding.sizeVarint(this.index); size += encoding.sizeVarint(this.coin.value); size += this.coin.script.getVarSize(); size += this.ring.getSize(); size += 1; return size; }; SignInputPacket.prototype.toWriter = function toWriter(bw) { this.tx.toWriter(bw); bw.writeVarint(this.index); bw.writeVarint(this.coin.value); this.coin.script.toWriter(bw); this.ring.toWriter(bw); bw.writeU8(this.type); }; SignInputPacket.fromRaw = function fromRaw(MTX, KeyRing, data) { var br = new BufferReader(data, true); var packet = new SignInputPacket(); packet.tx = MTX.fromReader(br); packet.index = br.readVarint(); packet.coin = new Output(); packet.coin.value = br.readVarint(); packet.coin.script.fromReader(br); packet.ring = KeyRing.fromReader(br); packet.type = br.readU8(); return packet; }; /** * SignInputResultPacket * @constructor */ function SignInputResultPacket(value, witness, script) { Packet.call(this); this.value = value || false; this.script = script || null; this.witness = witness || null; } util.inherits(SignInputResultPacket, Packet); SignInputResultPacket.prototype.cmd = packetTypes.SIGNINPUTRESULT; SignInputResultPacket.fromTX = function fromTX(tx, i, value) { var packet = new SignInputResultPacket(value); var input = tx.inputs[i]; assert(input); packet.script = input.script; packet.witness = input.witness; return packet; }; SignInputResultPacket.prototype.getSize = function getSize() { return 1 + this.script.getVarSize() + this.witness.getVarSize(); }; SignInputResultPacket.prototype.toWriter = function toWriter(bw) { bw.writeU8(this.value ? 1 : 0); this.script.toWriter(bw); this.witness.toWriter(bw); }; SignInputResultPacket.prototype.inject = function inject(tx, i) { var input = tx.inputs[i]; assert(input); input.script = this.script; input.witness = this.witness; }; SignInputResultPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new SignInputResultPacket(); packet.value = br.readU8() === 1; packet.script = Script.fromReader(br); packet.witness = Witness.fromReader(br); return packet; }; /** * ECVerifyPacket * @constructor */ function ECVerifyPacket(msg, sig, key) { Packet.call(this); this.msg = msg || null; this.sig = sig || null; this.key = key || null; } util.inherits(ECVerifyPacket, Packet); ECVerifyPacket.prototype.cmd = packetTypes.ECVERIFY; ECVerifyPacket.prototype.getSize = function getSize() { var size = 0; size += encoding.sizeVarBytes(this.msg); size += encoding.sizeVarBytes(this.sig); size += encoding.sizeVarBytes(this.key); return size; }; ECVerifyPacket.prototype.toWriter = function(bw) { bw.writeVarBytes(this.msg); bw.writeVarBytes(this.sig); bw.writeVarBytes(this.key); }; ECVerifyPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new ECVerifyPacket(); packet.msg = br.readVarBytes(); packet.sig = br.readVarBytes(); packet.key = br.readVarBytes(); return packet; }; /** * ECVerifyResultPacket * @constructor */ function ECVerifyResultPacket(value) { Packet.call(this); this.value = value; } util.inherits(ECVerifyResultPacket, Packet); ECVerifyResultPacket.prototype.cmd = packetTypes.ECVERIFYRESULT; ECVerifyResultPacket.prototype.getSize = function getSize() { return 1; }; ECVerifyResultPacket.prototype.toWriter = function toWriter(bw) { bw.writeU8(this.value ? 1 : 0); }; ECVerifyResultPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new ECVerifyResultPacket(); packet.value = br.readU8() === 1; return packet; }; /** * ECSignPacket * @constructor */ function ECSignPacket(msg, key) { Packet.call(this); this.msg = msg || null; this.key = key || null; } util.inherits(ECSignPacket, Packet); ECSignPacket.prototype.cmd = packetTypes.ECSIGN; ECSignPacket.prototype.getSize = function getSize() { var size = 0; size += encoding.sizeVarBytes(this.msg); size += encoding.sizeVarBytes(this.key); return size; }; ECSignPacket.prototype.toWriter = function toWriter(bw) { bw.writeVarBytes(this.msg); bw.writeVarBytes(this.key); }; ECSignPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new ECSignPacket(); packet.msg = br.readVarBytes(); packet.key = br.readVarBytes(); return packet; }; /** * ECSignResultPacket * @constructor */ function ECSignResultPacket(sig) { Packet.call(this); this.sig = sig; } util.inherits(ECSignResultPacket, Packet); ECSignResultPacket.prototype.cmd = packetTypes.ECSIGNRESULT; ECSignResultPacket.prototype.getSize = function getSize() { return encoding.sizeVarBytes(this.sig); }; ECSignResultPacket.prototype.toWriter = function toWriter(bw) { bw.writeVarBytes(this.sig); }; ECSignResultPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new ECSignResultPacket(); packet.sig = br.readVarBytes(); return packet; }; /** * MinePacket * @constructor */ function MinePacket(data, target, min, max) { Packet.call(this); this.data = data || null; this.target = target || null; this.min = min != null ? min : -1; this.max = max != null ? max : -1; } util.inherits(MinePacket, Packet); MinePacket.prototype.cmd = packetTypes.MINE; MinePacket.prototype.getSize = function getSize() { return 120; }; MinePacket.prototype.toWriter = function toWriter(bw) { bw.writeBytes(this.data); bw.writeBytes(this.target); bw.writeU32(this.min); bw.writeU32(this.max); }; MinePacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new MinePacket(); packet.data = br.readBytes(80); packet.target = br.readBytes(32); packet.min = br.readU32(); packet.max = br.readU32(); return packet; }; /** * MineResultPacket * @constructor */ function MineResultPacket(nonce) { Packet.call(this); this.nonce = nonce != null ? nonce : -1; } util.inherits(MineResultPacket, Packet); MineResultPacket.prototype.cmd = packetTypes.MINERESULT; MineResultPacket.prototype.getSize = function getSize() { return 4; }; MineResultPacket.prototype.toWriter = function toWriter(bw) { bw.writeU32(this.nonce); }; MineResultPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new MineResultPacket(); packet.nonce = br.readU32(); if ((packet.nonce >> 0) === -1) packet.nonce = -1; return packet; }; /** * ScryptPacket * @constructor */ function ScryptPacket(passwd, salt, N, r, p, len) { Packet.call(this); this.passwd = passwd || null; this.salt = salt || null; this.N = N != null ? N : -1; this.r = r != null ? r : -1; this.p = p != null ? p : -1; this.len = len != null ? len : -1; } util.inherits(ScryptPacket, Packet); ScryptPacket.prototype.cmd = packetTypes.SCRYPT; ScryptPacket.prototype.getSize = function getSize() { var size = 0; size += encoding.sizeVarBytes(this.passwd); size += encoding.sizeVarBytes(this.salt); size += 16; return size; }; ScryptPacket.prototype.toWriter = function(bw) { bw.writeVarBytes(this.passwd); bw.writeVarBytes(this.salt); bw.writeU32(this.N); bw.writeU32(this.r); bw.writeU32(this.p); bw.writeU32(this.len); }; ScryptPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new ScryptPacket(); packet.passwd = br.readVarBytes(); packet.salt = br.readVarBytes(); packet.N = br.readU32(); packet.r = br.readU32(); packet.p = br.readU32(); packet.len = br.readU32(); return packet; }; /** * ScryptResultPacket * @constructor */ function ScryptResultPacket(key) { Packet.call(this); this.key = key || null; } util.inherits(ScryptResultPacket, Packet); ScryptResultPacket.prototype.cmd = packetTypes.SCRYPTRESULT; ScryptResultPacket.prototype.getSize = function getSize() { return encoding.sizeVarBytes(this.key); }; ScryptResultPacket.prototype.toWriter = function toWriter(bw) { bw.writeVarBytes(this.key); }; ScryptResultPacket.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); var packet = new ScryptResultPacket(); packet.key = br.readVarBytes(); return packet; }; /* * Expose */ exports.types = packetTypes; exports.EventPacket = EventPacket; exports.LogPacket = LogPacket; exports.ErrorPacket = ErrorPacket; exports.ErrorResultPacket = ErrorResultPacket; exports.VerifyPacket = VerifyPacket; exports.VerifyResultPacket = VerifyResultPacket; exports.SignPacket = SignPacket; exports.SignResultPacket = SignResultPacket; exports.VerifyInputPacket = VerifyInputPacket; exports.VerifyInputResultPacket = VerifyInputResultPacket; exports.SignInputPacket = SignInputPacket; exports.SignInputResultPacket = SignInputResultPacket; exports.ECVerifyPacket = ECVerifyPacket; exports.ECVerifyResultPacket = ECVerifyResultPacket; exports.ECSignPacket = ECSignPacket; exports.ECSignResultPacket = ECSignResultPacket; exports.MinePacket = MinePacket; exports.MineResultPacket = MineResultPacket; exports.ScryptPacket = ScryptPacket; exports.ScryptResultPacket = ScryptResultPacket;