Source: workers/packets.js

  1. /*!
  2. * packets.js - worker packets for hsd
  3. * Copyright (c) 2017-2018, Christopher Jeffrey (MIT License).
  4. * https://github.com/handshake-org/hsd
  5. */
  6. 'use strict';
  7. /**
  8. * @module workers/packets
  9. */
  10. const assert = require('bsert');
  11. const bio = require('bufio');
  12. const Witness = require('../script/witness');
  13. const Output = require('../primitives/output');
  14. const MTX = require('../primitives/mtx');
  15. const TX = require('../primitives/tx');
  16. const KeyRing = require('../primitives/keyring');
  17. const CoinView = require('../coins/coinview');
  18. const ScriptError = require('../script/scripterror');
  19. const {encoding} = bio;
  20. /*
  21. * Constants
  22. */
  23. const packetTypes = {
  24. ENV: 0,
  25. EVENT: 1,
  26. LOG: 2,
  27. ERROR: 3,
  28. ERRORRESULT: 4,
  29. CHECK: 5,
  30. CHECKRESULT: 6,
  31. SIGN: 7,
  32. SIGNRESULT: 8,
  33. CHECKINPUT: 9,
  34. CHECKINPUTRESULT: 10,
  35. SIGNINPUT: 11,
  36. SIGNINPUTRESULT: 12,
  37. ECVERIFY: 13,
  38. ECVERIFYRESULT: 14,
  39. ECSIGN: 15,
  40. ECSIGNRESULT: 16,
  41. MINE: 17,
  42. MINERESULT: 18,
  43. SCRYPT: 19,
  44. SCRYPTRESULT: 20
  45. };
  46. /**
  47. * Packet
  48. */
  49. class Packet extends bio.Struct {
  50. constructor() {
  51. super();
  52. this.id = ++Packet.id >>> 0;
  53. this.cmd = -1;
  54. }
  55. getSize() {
  56. throw new Error('Abstract method.');
  57. }
  58. write(bw) {
  59. throw new Error('Abstract method.');
  60. }
  61. read(br) {
  62. throw new Error('Abstract method.');
  63. }
  64. decode(data, extra) {
  65. const br = bio.read(data, true);
  66. this.read(br, extra);
  67. return this;
  68. }
  69. }
  70. Packet.id = 0;
  71. /**
  72. * EnvPacket
  73. */
  74. class EnvPacket extends Packet {
  75. constructor(env) {
  76. super();
  77. this.cmd = packetTypes.ENV;
  78. this.env = env || {};
  79. this.json = JSON.stringify(this.env);
  80. }
  81. getSize() {
  82. return encoding.sizeVarString(this.json, 'utf8');
  83. }
  84. write(bw) {
  85. bw.writeVarString(this.json, 'utf8');
  86. return bw;
  87. }
  88. read(br) {
  89. this.json = br.readVarString('utf8');
  90. this.env = JSON.parse(this.json);
  91. return this;
  92. }
  93. }
  94. /**
  95. * EventPacket
  96. */
  97. class EventPacket extends Packet {
  98. constructor(items) {
  99. super();
  100. this.cmd = packetTypes.EVENT;
  101. this.items = items || [];
  102. this.json = JSON.stringify(this.items);
  103. }
  104. getSize() {
  105. return encoding.sizeVarString(this.json, 'utf8');
  106. }
  107. write(bw) {
  108. bw.writeVarString(this.json, 'utf8');
  109. return bw;
  110. }
  111. read(br) {
  112. this.json = br.readVarString('utf8');
  113. this.items = JSON.parse(this.json);
  114. return this;
  115. }
  116. }
  117. /**
  118. * LogPacket
  119. */
  120. class LogPacket extends Packet {
  121. constructor(text) {
  122. super();
  123. this.cmd = packetTypes.LOG;
  124. this.text = text || '';
  125. }
  126. getSize() {
  127. return encoding.sizeVarString(this.text, 'utf8');
  128. }
  129. write(bw) {
  130. bw.writeVarString(this.text, 'utf8');
  131. return bw;
  132. }
  133. read(br) {
  134. this.text = br.readVarString('utf8');
  135. return this;
  136. }
  137. }
  138. /**
  139. * ErrorPacket
  140. */
  141. class ErrorPacket extends Packet {
  142. constructor(error) {
  143. super();
  144. this.cmd = packetTypes.ERROR;
  145. this.error = error || new Error();
  146. }
  147. getSize() {
  148. const err = this.error;
  149. let size = 0;
  150. size += encoding.sizeVarString(stringify(err.message), 'utf8');
  151. size += encoding.sizeVarString(stringify(err.stack), 'utf8');
  152. size += encoding.sizeVarString(stringify(err.type), 'utf8');
  153. switch (typeof err.code) {
  154. case 'number':
  155. size += 1;
  156. size += 4;
  157. break;
  158. case 'string':
  159. size += 1;
  160. size += encoding.sizeVarString(err.code, 'utf8');
  161. break;
  162. default:
  163. size += 1;
  164. break;
  165. }
  166. return size;
  167. }
  168. write(bw) {
  169. const err = this.error;
  170. bw.writeVarString(stringify(err.message), 'utf8');
  171. bw.writeVarString(stringify(err.stack), 'utf8');
  172. bw.writeVarString(stringify(err.type), 'utf8');
  173. switch (typeof err.code) {
  174. case 'number':
  175. bw.writeU8(2);
  176. bw.writeI32(err.code);
  177. break;
  178. case 'string':
  179. bw.writeU8(1);
  180. bw.writeVarString(err.code, 'utf8');
  181. break;
  182. default:
  183. bw.writeU8(0);
  184. break;
  185. }
  186. return bw;
  187. }
  188. read(br) {
  189. const err = this.error;
  190. err.message = br.readVarString('utf8');
  191. err.stack = br.readVarString('utf8');
  192. err.type = br.readVarString('utf8');
  193. switch (br.readU8()) {
  194. case 2:
  195. err.code = br.readI32();
  196. break;
  197. case 1:
  198. err.code = br.readVarString('utf8');
  199. break;
  200. default:
  201. err.code = null;
  202. break;
  203. }
  204. return this;
  205. }
  206. }
  207. /**
  208. * ErrorResultPacket
  209. */
  210. class ErrorResultPacket extends ErrorPacket {
  211. constructor(error) {
  212. super(error);
  213. this.cmd = packetTypes.ERRORRESULT;
  214. }
  215. }
  216. /**
  217. * CheckPacket
  218. */
  219. class CheckPacket extends Packet {
  220. constructor(tx, view, flags) {
  221. super();
  222. this.cmd = packetTypes.CHECK;
  223. this.tx = tx || null;
  224. this.view = view || null;
  225. this.flags = flags != null ? flags : null;
  226. }
  227. getSize() {
  228. return this.tx.getSize() + this.view.getSize(this.tx) + 4;
  229. }
  230. write(bw) {
  231. this.tx.write(bw);
  232. this.view.write(bw, this.tx);
  233. bw.writeI32(this.flags != null ? this.flags : -1);
  234. return bw;
  235. }
  236. read(br) {
  237. this.tx = TX.read(br);
  238. this.view = CoinView.read(br, this.tx);
  239. this.flags = br.readI32();
  240. if (this.flags === -1)
  241. this.flags = null;
  242. return this;
  243. }
  244. }
  245. /**
  246. * CheckResultPacket
  247. */
  248. class CheckResultPacket extends Packet {
  249. constructor(error) {
  250. super();
  251. this.cmd = packetTypes.CHECKRESULT;
  252. this.error = error || null;
  253. }
  254. getSize() {
  255. const err = this.error;
  256. let size = 0;
  257. if (!err) {
  258. size += 1;
  259. return size;
  260. }
  261. size += 1;
  262. size += encoding.sizeVarString(stringify(err.message), 'utf8');
  263. size += encoding.sizeVarString(stringify(err.stack), 'utf8');
  264. size += encoding.sizeVarString(stringify(err.code), 'utf8');
  265. size += 1;
  266. size += 4;
  267. return size;
  268. }
  269. write(bw) {
  270. const err = this.error;
  271. if (!err) {
  272. bw.writeU8(0);
  273. return bw;
  274. }
  275. bw.writeU8(1);
  276. bw.writeVarString(stringify(err.message), 'utf8');
  277. bw.writeVarString(stringify(err.stack), 'utf8');
  278. bw.writeVarString(stringify(err.code), 'utf8');
  279. bw.writeU8(err.op === -1 ? 0xff : err.op);
  280. bw.writeU32(err.ip === -1 ? 0xffffffff : err.ip);
  281. return bw;
  282. }
  283. read(br) {
  284. if (br.readU8() === 0)
  285. return this;
  286. const err = new ScriptError('');
  287. err.message = br.readVarString('utf8');
  288. err.stack = br.readVarString('utf8');
  289. err.code = br.readVarString('utf8');
  290. err.op = br.readU8();
  291. err.ip = br.readU32();
  292. if (err.op === 0xff)
  293. err.op = -1;
  294. if (err.ip === 0xffffffff)
  295. err.ip = -1;
  296. this.error = err;
  297. return this;
  298. }
  299. }
  300. /**
  301. * SignPacket
  302. */
  303. class SignPacket extends Packet {
  304. constructor(tx, rings, type) {
  305. super();
  306. this.cmd = packetTypes.SIGN;
  307. this.tx = tx || null;
  308. this.rings = rings || [];
  309. this.type = type != null ? type : 1;
  310. }
  311. getSize() {
  312. let size = 0;
  313. size += this.tx.getSize();
  314. size += this.tx.view.getSize(this.tx);
  315. size += encoding.sizeVarint(this.rings.length);
  316. for (const ring of this.rings)
  317. size += ring.getSize();
  318. size += 1;
  319. return size;
  320. }
  321. write(bw) {
  322. this.tx.write(bw);
  323. this.tx.view.write(bw, this.tx);
  324. bw.writeVarint(this.rings.length);
  325. for (const ring of this.rings)
  326. ring.write(bw);
  327. bw.writeU8(this.type);
  328. return bw;
  329. }
  330. read(br) {
  331. this.tx = MTX.read(br);
  332. this.tx.view.read(br, this.tx);
  333. const count = br.readVarint();
  334. for (let i = 0; i < count; i++) {
  335. const ring = KeyRing.read(br);
  336. this.rings.push(ring);
  337. }
  338. this.type = br.readU8();
  339. return this;
  340. }
  341. }
  342. /**
  343. * SignResultPacket
  344. */
  345. class SignResultPacket extends Packet {
  346. constructor(total, witness, script) {
  347. super();
  348. this.cmd = packetTypes.SIGNRESULT;
  349. this.total = total || 0;
  350. this.witness = witness || [];
  351. }
  352. fromTX(tx, total) {
  353. this.total = total;
  354. for (const input of tx.inputs)
  355. this.witness.push(input.witness);
  356. return this;
  357. }
  358. static fromTX(tx, total) {
  359. return new SignResultPacket().fromTX(tx, total);
  360. }
  361. getSize() {
  362. let size = 0;
  363. size += encoding.sizeVarint(this.total);
  364. size += encoding.sizeVarint(this.witness.length);
  365. for (let i = 0; i < this.witness.length; i++) {
  366. const witness = this.witness[i];
  367. size += witness.getVarSize();
  368. }
  369. return size;
  370. }
  371. write(bw) {
  372. bw.writeVarint(this.total);
  373. bw.writeVarint(this.witness.length);
  374. for (let i = 0; i < this.witness.length; i++)
  375. this.witness[i].write(bw);
  376. return bw;
  377. }
  378. inject(tx) {
  379. assert(this.witness.length === tx.inputs.length);
  380. for (let i = 0; i < tx.inputs.length; i++) {
  381. const input = tx.inputs[i];
  382. input.witness = this.witness[i];
  383. }
  384. }
  385. read(br) {
  386. this.total = br.readVarint();
  387. const count = br.readVarint();
  388. for (let i = 0; i < count; i++)
  389. this.witness.push(Witness.read(br));
  390. return this;
  391. }
  392. }
  393. /**
  394. * CheckInputPacket
  395. */
  396. class CheckInputPacket extends Packet {
  397. constructor(tx, index, coin, flags) {
  398. super();
  399. this.cmd = packetTypes.CHECKINPUT;
  400. this.tx = tx || null;
  401. this.index = index;
  402. this.coin = coin || null;
  403. this.flags = flags != null ? flags : null;
  404. }
  405. getSize() {
  406. let size = 0;
  407. size += this.tx.getSize();
  408. size += encoding.sizeVarint(this.index);
  409. size += encoding.sizeVarint(this.coin.value);
  410. size += this.coin.script.getVarSize();
  411. size += 4;
  412. return size;
  413. }
  414. write(bw) {
  415. this.tx.write(bw);
  416. bw.writeVarint(this.index);
  417. bw.writeVarint(this.coin.value);
  418. this.coin.script.write(bw);
  419. bw.writeI32(this.flags != null ? this.flags : -1);
  420. return bw;
  421. }
  422. read(br) {
  423. this.tx = TX.read(br);
  424. this.index = br.readVarint();
  425. this.coin = new Output();
  426. this.coin.value = br.readVarint();
  427. this.coin.script.read(br);
  428. this.flags = br.readI32();
  429. if (this.flags === -1)
  430. this.flags = null;
  431. return this;
  432. }
  433. }
  434. /**
  435. * CheckInputResultPacket
  436. */
  437. class CheckInputResultPacket extends CheckResultPacket {
  438. constructor(error) {
  439. super(error);
  440. this.cmd = packetTypes.CHECKINPUTRESULT;
  441. }
  442. }
  443. /**
  444. * SignInputPacket
  445. */
  446. class SignInputPacket extends Packet {
  447. constructor(tx, index, coin, ring, type) {
  448. super();
  449. this.cmd = packetTypes.SIGNINPUT;
  450. this.tx = tx || null;
  451. this.index = index;
  452. this.coin = coin || null;
  453. this.ring = ring || null;
  454. this.type = type != null ? type : 1;
  455. }
  456. getSize() {
  457. let size = 0;
  458. size += this.tx.getSize();
  459. size += encoding.sizeVarint(this.index);
  460. size += encoding.sizeVarint(this.coin.value);
  461. size += this.coin.script.getVarSize();
  462. size += this.ring.getSize();
  463. size += 1;
  464. return size;
  465. }
  466. write(bw) {
  467. this.tx.write(bw);
  468. bw.writeVarint(this.index);
  469. bw.writeVarint(this.coin.value);
  470. this.coin.script.write(bw);
  471. this.ring.write(bw);
  472. bw.writeU8(this.type);
  473. return bw;
  474. }
  475. read(br) {
  476. this.tx = MTX.read(br);
  477. this.index = br.readVarint();
  478. this.coin = new Output();
  479. this.coin.value = br.readVarint();
  480. this.coin.script.read(br);
  481. this.ring = KeyRing.read(br);
  482. this.type = br.readU8();
  483. return this;
  484. }
  485. }
  486. /**
  487. * SignInputResultPacket
  488. */
  489. class SignInputResultPacket extends Packet {
  490. constructor(value, witness) {
  491. super();
  492. this.cmd = packetTypes.SIGNINPUTRESULT;
  493. this.value = value || false;
  494. this.witness = witness || null;
  495. }
  496. fromTX(tx, i, value) {
  497. const input = tx.inputs[i];
  498. assert(input);
  499. this.value = value;
  500. this.witness = input.witness;
  501. return this;
  502. }
  503. static fromTX(tx, i, value) {
  504. return new SignInputResultPacket().fromTX(tx, i, value);
  505. }
  506. getSize() {
  507. return 1 + this.witness.getVarSize();
  508. }
  509. write(bw) {
  510. bw.writeU8(this.value ? 1 : 0);
  511. this.witness.write(bw);
  512. return bw;
  513. }
  514. inject(tx, i) {
  515. const input = tx.inputs[i];
  516. assert(input);
  517. input.witness = this.witness;
  518. }
  519. read(br) {
  520. this.value = br.readU8() === 1;
  521. this.witness = Witness.read(br);
  522. return this;
  523. }
  524. }
  525. /**
  526. * ECVerifyPacket
  527. */
  528. class ECVerifyPacket extends Packet {
  529. constructor(msg, sig, key) {
  530. super();
  531. this.cmd = packetTypes.ECVERIFY;
  532. this.msg = msg || null;
  533. this.sig = sig || null;
  534. this.key = key || null;
  535. }
  536. getSize() {
  537. let size = 0;
  538. size += encoding.sizeVarBytes(this.msg);
  539. size += encoding.sizeVarBytes(this.sig);
  540. size += encoding.sizeVarBytes(this.key);
  541. return size;
  542. }
  543. write(bw) {
  544. bw.writeVarBytes(this.msg);
  545. bw.writeVarBytes(this.sig);
  546. bw.writeVarBytes(this.key);
  547. return bw;
  548. }
  549. read(br) {
  550. this.msg = br.readVarBytes();
  551. this.sig = br.readVarBytes();
  552. this.key = br.readVarBytes();
  553. return this;
  554. }
  555. }
  556. /**
  557. * ECVerifyResultPacket
  558. */
  559. class ECVerifyResultPacket extends Packet {
  560. constructor(value) {
  561. super();
  562. this.cmd = packetTypes.ECVERIFYRESULT;
  563. this.value = value;
  564. }
  565. getSize() {
  566. return 1;
  567. }
  568. write(bw) {
  569. bw.writeU8(this.value ? 1 : 0);
  570. return bw;
  571. }
  572. read(br) {
  573. this.value = br.readU8() === 1;
  574. return this;
  575. }
  576. }
  577. /**
  578. * ECSignPacket
  579. */
  580. class ECSignPacket extends Packet {
  581. constructor(msg, key) {
  582. super();
  583. this.cmd = packetTypes.ECSIGN;
  584. this.msg = msg || null;
  585. this.key = key || null;
  586. }
  587. getSize() {
  588. let size = 0;
  589. size += encoding.sizeVarBytes(this.msg);
  590. size += encoding.sizeVarBytes(this.key);
  591. return size;
  592. }
  593. write(bw) {
  594. bw.writeVarBytes(this.msg);
  595. bw.writeVarBytes(this.key);
  596. return bw;
  597. }
  598. read(br) {
  599. this.msg = br.readVarBytes();
  600. this.key = br.readVarBytes();
  601. return this;
  602. }
  603. }
  604. /**
  605. * ECSignResultPacket
  606. */
  607. class ECSignResultPacket extends Packet {
  608. constructor(sig) {
  609. super();
  610. this.cmd = packetTypes.ECSIGNRESULT;
  611. this.sig = sig;
  612. }
  613. getSize() {
  614. return encoding.sizeVarBytes(this.sig);
  615. }
  616. write(bw) {
  617. bw.writeVarBytes(this.sig);
  618. return bw;
  619. }
  620. read(br) {
  621. this.sig = br.readVarBytes();
  622. return this;
  623. }
  624. }
  625. /**
  626. * MinePacket
  627. */
  628. class MinePacket extends Packet {
  629. constructor(hdr, target, rounds) {
  630. super();
  631. this.cmd = packetTypes.MINE;
  632. this.hdr = hdr || null;
  633. this.target = target || null;
  634. this.rounds = rounds != null ? rounds : -1;
  635. }
  636. getSize() {
  637. return 256 + 32 + 4;
  638. }
  639. write(bw) {
  640. bw.writeBytes(this.hdr);
  641. bw.writeBytes(this.target);
  642. bw.writeU32(this.rounds);
  643. return bw;
  644. }
  645. read(br) {
  646. this.hdr = br.readBytes(256);
  647. this.target = br.readBytes(32);
  648. this.rounds = br.readU32();
  649. return this;
  650. }
  651. }
  652. /**
  653. * MineResultPacket
  654. */
  655. class MineResultPacket extends Packet {
  656. constructor(nonce, solved) {
  657. super();
  658. this.cmd = packetTypes.MINERESULT;
  659. this.nonce = nonce || 0;
  660. this.solved = solved || false;
  661. }
  662. getSize() {
  663. return 4 + 1;
  664. }
  665. write(bw) {
  666. bw.writeU32(this.nonce);
  667. bw.writeU8(this.solved ? 1 : 0);
  668. return bw;
  669. }
  670. read(br) {
  671. this.nonce = br.readU32();
  672. this.solved = br.readU8() === 1;
  673. return this;
  674. }
  675. }
  676. /**
  677. * ScryptPacket
  678. */
  679. class ScryptPacket extends Packet {
  680. constructor(passwd, salt, N, r, p, len) {
  681. super();
  682. this.cmd = packetTypes.SCRYPT;
  683. this.passwd = passwd || null;
  684. this.salt = salt || null;
  685. this.N = N != null ? N : -1;
  686. this.r = r != null ? r : -1;
  687. this.p = p != null ? p : -1;
  688. this.len = len != null ? len : -1;
  689. }
  690. getSize() {
  691. let size = 0;
  692. size += encoding.sizeVarBytes(this.passwd);
  693. size += encoding.sizeVarBytes(this.salt);
  694. size += 16;
  695. return size;
  696. }
  697. write(bw) {
  698. bw.writeVarBytes(this.passwd);
  699. bw.writeVarBytes(this.salt);
  700. bw.writeU32(this.N);
  701. bw.writeU32(this.r);
  702. bw.writeU32(this.p);
  703. bw.writeU32(this.len);
  704. return bw;
  705. }
  706. read(br) {
  707. this.passwd = br.readVarBytes();
  708. this.salt = br.readVarBytes();
  709. this.N = br.readU32();
  710. this.r = br.readU32();
  711. this.p = br.readU32();
  712. this.len = br.readU32();
  713. return this;
  714. }
  715. }
  716. /**
  717. * ScryptResultPacket
  718. */
  719. class ScryptResultPacket extends Packet {
  720. constructor(key) {
  721. super();
  722. this.cmd = packetTypes.SCRYPTRESULT;
  723. this.key = key || null;
  724. }
  725. getSize() {
  726. return encoding.sizeVarBytes(this.key);
  727. }
  728. write(bw) {
  729. bw.writeVarBytes(this.key);
  730. return bw;
  731. }
  732. read(br) {
  733. this.key = br.readVarBytes();
  734. return this;
  735. }
  736. }
  737. /*
  738. * Helpers
  739. */
  740. function stringify(value) {
  741. if (typeof value !== 'string')
  742. return '';
  743. return value;
  744. }
  745. /*
  746. * Expose
  747. */
  748. exports.types = packetTypes;
  749. exports.EnvPacket = EnvPacket;
  750. exports.EventPacket = EventPacket;
  751. exports.LogPacket = LogPacket;
  752. exports.ErrorPacket = ErrorPacket;
  753. exports.ErrorResultPacket = ErrorResultPacket;
  754. exports.CheckPacket = CheckPacket;
  755. exports.CheckResultPacket = CheckResultPacket;
  756. exports.SignPacket = SignPacket;
  757. exports.SignResultPacket = SignResultPacket;
  758. exports.CheckInputPacket = CheckInputPacket;
  759. exports.CheckInputResultPacket = CheckInputResultPacket;
  760. exports.SignInputPacket = SignInputPacket;
  761. exports.SignInputResultPacket = SignInputResultPacket;
  762. exports.ECVerifyPacket = ECVerifyPacket;
  763. exports.ECVerifyResultPacket = ECVerifyResultPacket;
  764. exports.ECSignPacket = ECSignPacket;
  765. exports.ECSignResultPacket = ECSignResultPacket;
  766. exports.MinePacket = MinePacket;
  767. exports.MineResultPacket = MineResultPacket;
  768. exports.ScryptPacket = ScryptPacket;
  769. exports.ScryptResultPacket = ScryptResultPacket;