/*!
 * 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
 */

const assert = require('assert');
const BufferReader = require('../utils/reader');
const encoding = require('../utils/encoding');
const Script = require('../script/script');
const Witness = require('../script/witness');
const Output = require('../primitives/output');
const MTX = require('../primitives/mtx');
const TX = require('../primitives/tx');
const KeyRing = require('../primitives/keyring');
const CoinView = require('../coins/coinview');
const ScriptError = require('../script/scripterror');

/*
 * Constants
 */

const packetTypes = {
  ENV: 0,
  EVENT: 1,
  LOG: 2,
  ERROR: 3,
  ERRORRESULT: 4,
  CHECK: 5,
  CHECKRESULT: 6,
  SIGN: 7,
  SIGNRESULT: 8,
  CHECKINPUT: 9,
  CHECKINPUTRESULT: 10,
  SIGNINPUT: 11,
  SIGNINPUTRESULT: 12,
  ECVERIFY: 13,
  ECVERIFYRESULT: 14,
  ECSIGN: 15,
  ECSIGNRESULT: 16,
  MINE: 17,
  MINERESULT: 18,
  SCRYPT: 19,
  SCRYPTRESULT: 20
};

/**
 * 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.');
};

/**
 * EnvPacket
 * @constructor
 */

function EnvPacket(env) {
  Packet.call(this);
  this.env = env || {};
  this.json = JSON.stringify(this.env);
}

Object.setPrototypeOf(EnvPacket.prototype, Packet.prototype);

EnvPacket.prototype.cmd = packetTypes.ENV;

EnvPacket.prototype.getSize = function getSize() {
  return encoding.sizeVarString(this.json, 'utf8');
};

EnvPacket.prototype.toWriter = function toWriter(bw) {
  bw.writeVarString(this.json, 'utf8');
};

EnvPacket.fromRaw = function fromRaw(data) {
  const br = new BufferReader(data, true);
  const packet = new EnvPacket();
  packet.json = br.readVarString('utf8');
  packet.env = JSON.parse(packet.json);
  return packet;
};

/**
 * EventPacket
 * @constructor
 */

function EventPacket(items) {
  Packet.call(this);
  this.items = items || [];
  this.json = JSON.stringify(this.items);
}

Object.setPrototypeOf(EventPacket.prototype, Packet.prototype);

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) {
  const br = new BufferReader(data, true);
  const packet = new EventPacket();
  packet.json = br.readVarString('utf8');
  packet.items = JSON.parse(packet.json);
  return packet;
};

/**
 * LogPacket
 * @constructor
 */

function LogPacket(text) {
  Packet.call(this);
  this.text = text || '';
}

Object.setPrototypeOf(LogPacket.prototype, Packet.prototype);

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) {
  const br = new BufferReader(data, true);
  const packet = new LogPacket();
  packet.text = br.readVarString('utf8');
  return packet;
};

/**
 * ErrorPacket
 * @constructor
 */

function ErrorPacket(error) {
  Packet.call(this);
  this.error = error || new Error();
}

Object.setPrototypeOf(ErrorPacket.prototype, Packet.prototype);

ErrorPacket.prototype.cmd = packetTypes.ERROR;

ErrorPacket.prototype.getSize = function getSize() {
  let size = 0;

  size += encoding.sizeVarString(String(this.error.message), 'utf8');
  size += encoding.sizeVarString(String(this.error.stack), 'utf8');
  size += encoding.sizeVarString(this.error.type || '', 'utf8');

  switch (typeof this.error.code) {
    case 'number':
      size += 1;
      size += 4;
      break;
    case 'string':
      size += 1;
      size += encoding.sizeVarString(this.error.code, 'utf8');
      break;
    default:
      size += 1;
      break;
  }

  return size;
};

ErrorPacket.prototype.toWriter = function toWriter(bw) {
  bw.writeVarString(String(this.error.message), 'utf8');
  bw.writeVarString(String(this.error.stack), 'utf8');
  bw.writeVarString(this.error.type || '', 'utf8');

  switch (typeof this.error.code) {
    case 'number':
      bw.writeU8(2);
      bw.writeI32(this.error.code);
      break;
    case 'string':
      bw.writeU8(1);
      bw.writeVarString(this.error.code, 'utf8');
      break;
    default:
      bw.writeU8(0);
      break;
  }
};

ErrorPacket.fromRaw = function fromRaw(data) {
  const br = new BufferReader(data, true);
  const packet = new ErrorPacket();

  packet.error.message = br.readVarString('utf8');
  packet.error.stack = br.readVarString('utf8');
  packet.error.type = br.readVarString('utf8');

  switch (br.readU8()) {
    case 2:
      packet.error.code = br.readI32();
      break;
    case 1:
      packet.error.code = br.readVarString('utf8');
      break;
    default:
      packet.error.code = null;
      break;
  }

  return packet;
};

/**
 * ErrorResultPacket
 * @constructor
 */

function ErrorResultPacket(error) {
  ErrorPacket.call(this, error);
}

Object.setPrototypeOf(ErrorResultPacket.prototype, ErrorPacket.prototype);

ErrorResultPacket.prototype.cmd = packetTypes.ERRORRESULT;

ErrorResultPacket.fromRaw = function fromRaw(data) {
  const packet = new ErrorResultPacket();
  const p = ErrorPacket.fromRaw(data);
  packet.error = p.error;
  return packet;
};

/**
 * CheckPacket
 * @constructor
 */

function CheckPacket(tx, view, flags) {
  Packet.call(this);
  this.tx = tx || null;
  this.view = view || null;
  this.flags = flags != null ? flags : null;
}

Object.setPrototypeOf(CheckPacket.prototype, Packet.prototype);

CheckPacket.prototype.cmd = packetTypes.CHECK;

CheckPacket.prototype.getSize = function getSize() {
  return this.tx.getSize() + this.view.getSize(this.tx) + 4;
};

CheckPacket.prototype.toWriter = function toWriter(bw) {
  this.tx.toWriter(bw);
  this.view.toWriter(bw, this.tx);
  bw.writeI32(this.flags != null ? this.flags : -1);
};

CheckPacket.fromRaw = function fromRaw(data) {
  const br = new BufferReader(data, true);
  const packet = new CheckPacket();

  packet.tx = TX.fromReader(br);
  packet.view = CoinView.fromReader(br, packet.tx);
  packet.flags = br.readI32();

  if (packet.flags === -1)
    packet.flags = null;

  return packet;
};

/**
 * CheckResultPacket
 * @constructor
 */

function CheckResultPacket(error) {
  Packet.call(this);
  this.error = error || null;
}

Object.setPrototypeOf(CheckResultPacket.prototype, Packet.prototype);

CheckResultPacket.prototype.cmd = packetTypes.CHECKRESULT;

CheckResultPacket.prototype.getSize = function getSize() {
  const err = this.error;
  let size = 0;

  if (!err) {
    size += 1;
    return size;
  }

  size += 1;
  size += encoding.sizeVarString(err.code, 'utf8');
  size += encoding.sizeVarString(err.message, 'utf8');
  size += encoding.sizeVarString(String(err.stack), 'utf8');
  size += 1;
  size += 4;

  return size;
};

CheckResultPacket.prototype.toWriter = function toWriter(bw) {
  const err = this.error;

  if (!err) {
    bw.writeU8(0);
    return;
  }

  bw.writeU8(1);
  bw.writeVarString(err.code, 'utf8');
  bw.writeVarString(err.message, 'utf8');
  bw.writeVarString(String(err.stack), 'utf8');
  bw.writeU8(err.op === -1 ? 0xff : err.op);
  bw.writeU32(err.ip === -1 ? 0xffffffff : err.ip);
};

CheckResultPacket.fromRaw = function fromRaw(data) {
  const br = new BufferReader(data, true);
  const packet = new CheckResultPacket();

  if (br.readU8() === 0)
    return packet;

  const err = new ScriptError('');
  err.code = br.readVarString('utf8');
  err.message = br.readVarString('utf8');
  err.stack = br.readVarString('utf8');
  err.op = br.readU8();
  err.ip = br.readU32();

  if (err.op === 0xff)
    err.op = -1;

  if (err.ip === 0xffffffff)
    err.ip = -1;

  packet.error = err;

  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;
}

Object.setPrototypeOf(SignPacket.prototype, Packet.prototype);

SignPacket.prototype.cmd = packetTypes.SIGN;

SignPacket.prototype.getSize = function getSize() {
  let size = 0;

  size += this.tx.getSize();
  size += this.tx.view.getSize(this.tx);
  size += encoding.sizeVarint(this.rings.length);

  for (const ring of this.rings)
    size += ring.getSize();

  size += 1;

  return size;
};

SignPacket.prototype.toWriter = function toWriter(bw) {
  this.tx.toWriter(bw);
  this.tx.view.toWriter(bw, this.tx);

  bw.writeVarint(this.rings.length);

  for (const ring of this.rings)
    ring.toWriter(bw);

  bw.writeU8(this.type);
};

SignPacket.fromRaw = function fromRaw(data) {
  const br = new BufferReader(data, true);
  const packet = new SignPacket();

  packet.tx = MTX.fromReader(br);
  packet.tx.view.fromReader(br, packet.tx);

  const count = br.readVarint();

  for (let i = 0; i < count; i++) {
    const 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 || [];
}

Object.setPrototypeOf(SignResultPacket.prototype, Packet.prototype);

SignResultPacket.prototype.cmd = packetTypes.SIGNRESULT;

SignResultPacket.fromTX = function fromTX(tx, total) {
  const packet = new SignResultPacket(total);

  for (const input of tx.inputs) {
    packet.script.push(input.script);
    packet.witness.push(input.witness);
  }

  return packet;
};

SignResultPacket.prototype.getSize = function getSize() {
  let size = 0;

  size += encoding.sizeVarint(this.total);
  size += encoding.sizeVarint(this.script.length);

  for (let i = 0; i < this.script.length; i++) {
    const script = this.script[i];
    const witness = this.witness[i];
    size += script.getVarSize();
    size += witness.getVarSize();
  }

  return size;
};

SignResultPacket.prototype.toWriter = function toWriter(bw) {
  assert(this.script.length === this.witness.length);

  bw.writeVarint(this.total);
  bw.writeVarint(this.script.length);

  for (let i = 0; i < this.script.length; i++) {
    this.script[i].toWriter(bw);
    this.witness[i].toWriter(bw);
  }
};

SignResultPacket.prototype.inject = function inject(tx) {
  assert(this.script.length === tx.inputs.length);
  assert(this.witness.length === tx.inputs.length);

  for (let i = 0; i < tx.inputs.length; i++) {
    const input = tx.inputs[i];
    input.script = this.script[i];
    input.witness = this.witness[i];
  }
};

SignResultPacket.fromRaw = function fromRaw(data) {
  const br = new BufferReader(data, true);
  const packet = new SignResultPacket();

  packet.total = br.readVarint();

  const count = br.readVarint();

  for (let i = 0; i < count; i++) {
    packet.script.push(Script.fromReader(br));
    packet.witness.push(Witness.fromReader(br));
  }

  return packet;
};

/**
 * CheckInputPacket
 * @constructor
 */

function CheckInputPacket(tx, index, coin, flags) {
  Packet.call(this);
  this.tx = tx || null;
  this.index = index;
  this.coin = coin || null;
  this.flags = flags != null ? flags : null;
}

Object.setPrototypeOf(CheckInputPacket.prototype, Packet.prototype);

CheckInputPacket.prototype.cmd = packetTypes.CHECKINPUT;

CheckInputPacket.prototype.getSize = function getSize() {
  let 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;
};

CheckInputPacket.prototype.toWriter = function toWriter(bw) {
  this.tx.toWriter(bw);
  bw.writeVarint(this.index);
  bw.writeVarint(this.coin.value);
  this.coin.script.toWriter(bw);
  bw.writeI32(this.flags != null ? this.flags : -1);
};

CheckInputPacket.fromRaw = function fromRaw(data) {
  const br = new BufferReader(data, true);
  const packet = new CheckInputPacket();

  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.readI32();

  if (packet.flags === -1)
    packet.flags = null;

  return packet;
};

/**
 * CheckInputResultPacket
 * @constructor
 */

function CheckInputResultPacket(error) {
  CheckResultPacket.call(this, error);
}

Object.setPrototypeOf(
  CheckInputResultPacket.prototype,
  CheckResultPacket.prototype);

CheckInputResultPacket.prototype.cmd = packetTypes.CHECKINPUTRESULT;

CheckInputResultPacket.fromRaw = function fromRaw(data) {
  const p = CheckResultPacket.fromRaw(data);
  const packet = new CheckInputResultPacket();
  packet.error = p.error;
  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;
}

Object.setPrototypeOf(SignInputPacket.prototype, Packet.prototype);

SignInputPacket.prototype.cmd = packetTypes.SIGNINPUT;

SignInputPacket.prototype.getSize = function getSize() {
  let 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(data) {
  const br = new BufferReader(data, true);
  const 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;
}

Object.setPrototypeOf(SignInputResultPacket.prototype, Packet.prototype);

SignInputResultPacket.prototype.cmd = packetTypes.SIGNINPUTRESULT;

SignInputResultPacket.fromTX = function fromTX(tx, i, value) {
  const packet = new SignInputResultPacket(value);
  const 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) {
  const input = tx.inputs[i];
  assert(input);
  input.script = this.script;
  input.witness = this.witness;
};

SignInputResultPacket.fromRaw = function fromRaw(data) {
  const br = new BufferReader(data, true);
  const 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;
}

Object.setPrototypeOf(ECVerifyPacket.prototype, Packet.prototype);

ECVerifyPacket.prototype.cmd = packetTypes.ECVERIFY;

ECVerifyPacket.prototype.getSize = function getSize() {
  let size = 0;
  size += encoding.sizeVarBytes(this.msg);
  size += encoding.sizeVarBytes(this.sig);
  size += encoding.sizeVarBytes(this.key);
  return size;
};

ECVerifyPacket.prototype.toWriter = function toWriter(bw) {
  bw.writeVarBytes(this.msg);
  bw.writeVarBytes(this.sig);
  bw.writeVarBytes(this.key);
};

ECVerifyPacket.fromRaw = function fromRaw(data) {
  const br = new BufferReader(data, true);
  const 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;
}

Object.setPrototypeOf(ECVerifyResultPacket.prototype, Packet.prototype);

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) {
  const br = new BufferReader(data, true);
  const 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;
}

Object.setPrototypeOf(ECSignPacket.prototype, Packet.prototype);

ECSignPacket.prototype.cmd = packetTypes.ECSIGN;

ECSignPacket.prototype.getSize = function getSize() {
  let 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) {
  const br = new BufferReader(data, true);
  const packet = new ECSignPacket();
  packet.msg = br.readVarBytes();
  packet.key = br.readVarBytes();
  return packet;
};

/**
 * ECSignResultPacket
 * @constructor
 */

function ECSignResultPacket(sig) {
  Packet.call(this);
  this.sig = sig;
}

Object.setPrototypeOf(ECSignResultPacket.prototype, Packet.prototype);

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) {
  const br = new BufferReader(data, true);
  const 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;
}

Object.setPrototypeOf(MinePacket.prototype, Packet.prototype);

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) {
  const br = new BufferReader(data, true);
  const 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;
}

Object.setPrototypeOf(MineResultPacket.prototype, Packet.prototype);

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) {
  const br = new BufferReader(data, true);
  const 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;
}

Object.setPrototypeOf(ScryptPacket.prototype, Packet.prototype);

ScryptPacket.prototype.cmd = packetTypes.SCRYPT;

ScryptPacket.prototype.getSize = function getSize() {
  let size = 0;
  size += encoding.sizeVarBytes(this.passwd);
  size += encoding.sizeVarBytes(this.salt);
  size += 16;
  return size;
};

ScryptPacket.prototype.toWriter = function toWriter(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) {
  const br = new BufferReader(data, true);
  const 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;
}

Object.setPrototypeOf(ScryptResultPacket.prototype, Packet.prototype);

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) {
  const br = new BufferReader(data, true);
  const packet = new ScryptResultPacket();
  packet.key = br.readVarBytes();
  return packet;
};

/*
 * Expose
 */

exports.types = packetTypes;
exports.EnvPacket = EnvPacket;
exports.EventPacket = EventPacket;
exports.LogPacket = LogPacket;
exports.ErrorPacket = ErrorPacket;
exports.ErrorResultPacket = ErrorResultPacket;
exports.CheckPacket = CheckPacket;
exports.CheckResultPacket = CheckResultPacket;
exports.SignPacket = SignPacket;
exports.SignResultPacket = SignResultPacket;
exports.CheckInputPacket = CheckInputPacket;
exports.CheckInputResultPacket = CheckInputResultPacket;
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;
