Advertisement
Guest User

Untitled

a guest
Aug 11th, 2014
489
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 202.04 KB | None | 0 0
  1. function run(appDir) {
  2. var http = require("http"),
  3. querystring = require("querystring"),
  4. events = require("events"),
  5. util = require("util"),
  6. Step = require("step"),
  7. async = require("async"),
  8. long = require("long"),
  9. Map = require("collections/map"),
  10. SortedArrayMap = require("collections/sorted-array-map"),
  11. crypto = require("crypto"),
  12. extend = require("node.extend"),
  13. curve = require("node-curve25519"),
  14. Datastore = require("nedb"),
  15. db = new Datastore(),
  16. net = require("net"),
  17. swig = require("swig"),
  18. path = require("path"),
  19. fs = require("fs"),
  20. mime = require("mime"),
  21. url = require("url"),
  22. longInt = require("long"),
  23. request = require("request"),
  24. bigint = require("biginteger").BigInteger;
  25. var logger = function() {
  26. var winston = require("winston");
  27. var loggingLevels = {
  28. levels: {
  29. netdbg: 1,
  30. bchdbg: 0,
  31. rpcdbg: 0,
  32. scrdbg: 0,
  33. DBdbg: 1,
  34. transdbg: 1,
  35. debug: 1,
  36. info: 10,
  37. notice: 20,
  38. warn: 30,
  39. error: 40,
  40. crit: 50,
  41. alert: 60,
  42. emerg: 70
  43. },
  44. colors: {
  45. netdbg: "blue",
  46. bchdbg: "blue",
  47. rpcdbg: "blue",
  48. scrdbg: "blue",
  49. transdbg: "blue",
  50. debug: "blue",
  51. info: "green",
  52. notice: "cyan",
  53. warn: "yellow",
  54. error: "red",
  55. crit: "red",
  56. alert: "yellow",
  57. emerg: "red",
  58. DBdbg: "blue"
  59. }
  60. };
  61. var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
  62. var pad = function(n) {
  63. return n < 10 ? "0" + n.toString(10) : n.toString(10)
  64. };
  65. var pad3 = function(n) {
  66. var num = n.toString(10);
  67. while (num.length < 3) num = "0" + num;
  68. return num
  69. };
  70. var timestamp = function() {
  71. var d = new Date();
  72. var time = [pad(d.getHours()), pad(d.getMinutes()), pad(d.getSeconds())].join(":");
  73. time += "." + pad3(d.getMilliseconds());
  74. return [d.getDate(), months[d.getMonth()], time].join(" ")
  75. };
  76. var exports = {};
  77. var logger = exports.logger = new winston.Logger({
  78. transports: [new winston.transports.Console({
  79. colorize: true,
  80. level: "debug",
  81. timestamp: timestamp
  82. }), new winston.transports.File({
  83. level: "debug",
  84. timestamp: timestamp,
  85. filename: process.cwd() + "/logs/logs.log",
  86. maxsize: 1048576,
  87. maxFiles: 2
  88. })],
  89. levels: loggingLevels.levels,
  90. level: "debug"
  91. });
  92. winston.addColors(loggingLevels.colors);
  93. exports.loggerOn = true;
  94. exports.disable = function() {
  95. if (this.logger.loggerOn === false) {
  96. return
  97. }
  98. this.logger.loggerOn = false;
  99. this.logger.remove(winston.transports.Console);
  100. this.logger.remove(winston.transports.File)
  101. };
  102. return logger.extend(exports)
  103. }();
  104. bigint.fromBuffer = function(buf) {
  105. var strHex = buf.toString("hex");
  106. return bigint.parse(strHex.toLocaleUpperCase(), 16)
  107. };
  108. bigint.prototype.toBuffer = function() {
  109. var hexStr = this.toString(16);
  110. if (hexStr.length % 2 === 0) {
  111. return new Buffer(hexStr, "hex")
  112. }
  113. return new Buffer("0" + hexStr, "hex")
  114. };
  115. var Crypto = function() {};
  116. Crypto.getPublicKey = function(secretWord) {
  117. try {
  118. var secretWordHash = curve.sha256(secretWord);
  119. return curve.derivePublicKeyWithClamp(secretWordHash)
  120. } catch (e) {
  121. logger.error(e.stack ? e.stack : e.toString());
  122. return false
  123. }
  124. };
  125. var Utils = function() {
  126. var clearBuffer = function(buf) {
  127. for (var i = 0; i < buf.length; i++) {
  128. buf[i] = 0
  129. }
  130. return buf
  131. };
  132. var two64 = new bigint("18446744073709551616");
  133. var getDateTime = function() {
  134. var date = new Date();
  135. var hour = date.getHours();
  136. hour = (hour < 10 ? "0" : "") + hour;
  137. var min = date.getMinutes();
  138. min = (min < 10 ? "0" : "") + min;
  139. var sec = date.getSeconds();
  140. sec = (sec < 10 ? "0" : "") + sec;
  141. var year = date.getFullYear();
  142. var month = date.getMonth() + 1;
  143. month = (month < 10 ? "0" : "") + month;
  144. var day = date.getDate();
  145. day = (day < 10 ? "0" : "") + day;
  146. return year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec
  147. };
  148. var decodeHex = function(hex) {
  149. return new Buffer(hex, "hex").slice(0)
  150. };
  151. var longToBigInt = function(long) {
  152. return bigint(long.toString())
  153. };
  154. var bigIntToLong = function(bigIntVal) {
  155. var buf = bigIntVal.toBuffer();
  156. return bufferToLongLE(buf)
  157. };
  158. var bigIntToLongBE = function(bigIntVal) {
  159. var buf = bigIntVal.toBuffer();
  160. return bufferToLongBE(buf)
  161. };
  162. var stringToLong = function(str) {
  163. var bi = bigint(str);
  164. return bigIntToLongBE(bi)
  165. };
  166. var bufferToLongLE = function(buf) {
  167. if (buf.length < 8) {
  168. var addLength = 8 - buf.length;
  169. var addBuffer = new Buffer(addLength);
  170. addBuffer = clearBuffer(addBuffer);
  171. buf = Buffer.concat([addBuffer, buf], 8)
  172. }
  173. var lowBits = buf.slice(buf.length - 4, buf.length);
  174. var higthBits = buf.slice(buf.length - 8, buf.length - 4);
  175. return new longInt(lowBits.readInt32LE(0), higthBits.readInt32LE(0), true)
  176. };
  177. var bufferToLongBE = function(buf) {
  178. if (buf.length < 8) {
  179. var addLength = 8 - buf.length;
  180. var addBuffer = new Buffer(addLength);
  181. addBuffer = clearBuffer(addBuffer);
  182. buf = Buffer.concat([addBuffer, buf], 8)
  183. }
  184. var lowBits = buf.slice(buf.length - 4, buf.length);
  185. var higthBits = buf.slice(buf.length - 8, buf.length - 4);
  186. return new longInt(lowBits.readInt32BE(0), higthBits.readInt32BE(0), true)
  187. };
  188. var getBEBigIntFromLENumber = function(num) {
  189. if (typeof num !== "string") {
  190. num = mun.toString()
  191. }
  192. var bi = bigint(num);
  193. var buf = bi.toBuffer();
  194. var buffArr = [];
  195. for (var i = 0; i < buf.length; i++) {
  196. buffArr.push(buf[buf.length - i - 1])
  197. }
  198. buf = new Buffer(buffArr);
  199. return bigint.fromBuffer(buf)
  200. };
  201. var sha256 = function(message) {
  202. var shasum = crypto.createHash("sha256");
  203. shasum.update(message);
  204. return shasum.digest()
  205. };
  206. var roundTo5Float = function(num) {
  207. var numF = parseFloat(nullToNumber(num));
  208. return Math.round(numF * 1e5) / 1e5
  209. };
  210. var isEmptyObj = function(obj) {
  211. if (obj == null) return true;
  212. if (obj.length && obj.length > 0) return false;
  213. if (obj.length === 0) return true;
  214. for (var key in obj) {
  215. if (hasOwnProperty.call(obj, key)) return false
  216. }
  217. return true
  218. };
  219. var nullToNumber = function(val) {
  220. if (val === null) {
  221. return 0
  222. }
  223. return val
  224. };
  225. return {
  226. clearBuffer: clearBuffer,
  227. two64: two64,
  228. getDateTime: getDateTime,
  229. decodeHex: decodeHex,
  230. longToBigInt: longToBigInt,
  231. bigIntToLong: bigIntToLong,
  232. bigIntToLongBE: bigIntToLongBE,
  233. stringToLong: stringToLong,
  234. bufferToLongLE: bufferToLongLE,
  235. bufferToLongBE: bufferToLongBE,
  236. getBEBigIntFromLENumber: getBEBigIntFromLENumber,
  237. sha256: sha256,
  238. roundTo5Float: roundTo5Float,
  239. isEmptyObj: isEmptyObj,
  240. nullToNumber: nullToNumber
  241. }
  242. }();
  243. var Config = function() {
  244. var Config = function() {
  245. return {
  246. port: 19775,
  247. host: "127.0.0.1",
  248. starPeers: ["5.45.124.65:19776", "5.45.114.108:19776"],
  249. peerPort: 19776,
  250. serverKey: "qwerty123456",
  251. devMod: false
  252. }
  253. }();
  254. try {
  255. Config.GEN_BLOCK_WAIT_MS = 6e4;
  256. Config.two64 = new bigint("18446744073709551616");
  257. Config.NULL_HASH = Utils.clearBuffer(new Buffer(32));
  258. Config.EMPTY_BUFFER = new Buffer(0);
  259. Config.ZERO_VALUE = Utils.clearBuffer(new Buffer(8));
  260. Config.INT64_MAX = Utils.decodeHex("ffffffffffffffff");
  261. Config.MAX_BALANCE = 1e9;
  262. Config.COIN = 1e9;
  263. Config.INITIAL_BASE_TARGET = 153722867;
  264. Config.TRANSPARENT_FORGING_BLOCK = 3e4;
  265. Config.MAX_BASE_TARGET = Config.MAX_BALANCE * Config.INITIAL_BASE_TARGET
  266. } catch (e) {
  267. logger.error("Error while generating utility constants:\n" + (e.stack ? e.stack : e.toString()));
  268. process.exit(1)
  269. }
  270. return Config
  271. }();
  272.  
  273. function NodeServer(createNew) {
  274. events.EventEmitter.call(this);
  275. this.state = null;
  276. this.running = false;
  277. this.synced = false;
  278. this.intervalCheckSynced = null;
  279. this.netStatus = Peer.prototype.statuses.DISABLE;
  280. try {
  281. this.blockGenerator = new BlockGenerator(this);
  282. this.peerProcessor = new PeerProcessor(this);
  283. this.addListener("stateChange", this.handleStateChange.bind(this));
  284. this.setupStateTransitions()
  285. } catch (err) {
  286. logger.error("Initialization " + (err.stack ? err.stack : "error: " + err.toString()))
  287. }
  288. if (typeof createNew !== "undefined" && createNew) {
  289. return this
  290. }
  291. if (typeof NodeServer.instance === "undefined") {
  292. NodeServer.instance = this
  293. }
  294. return NodeServer.instance
  295. }
  296. util.inherits(NodeServer, events.EventEmitter);
  297. NodeServer.prototype.start = function() {
  298. this.setState("init")
  299. };
  300. NodeServer.prototype.setState = function(newState) {
  301. var oldState = this.state;
  302. if (newState == "init" && oldState !== null) {
  303. return
  304. }
  305. this.state = newState;
  306. this.emit("stateChange", {
  307. oldState: oldState,
  308. newState: newState
  309. })
  310. };
  311. NodeServer.prototype.setupStateTransitions = function() {
  312. var self = this;
  313. this.addListener("initComplete", function() {
  314. if (self.state == "init") {
  315. self.setState("netConnect")
  316. }
  317. });
  318. this.peerProcessor.addListener("netConnected", function() {
  319. if (self.state == "netConnect") {
  320. self.setState("blockDownload")
  321. }
  322. })
  323. };
  324. NodeServer.prototype.handleStateChange = function(e) {
  325. var self = this;
  326. this.running = !!~["netConnect", "blockDownload", "default"].indexOf(e.newState);
  327. switch (e.oldState) {}
  328. switch (e.newState) {
  329. case "init":
  330. BlockchainProcessor.run(function() {
  331. setInterval(function() {
  332. if (Account.currentAccount) {
  333. logger.info("Account.currentAccount.accountSecret", Account.currentAccount.accountSecret)
  334. } else {
  335. logger.info("You not logged to generate block.")
  336. }
  337. }, 6e4);
  338. self.emit("initComplete")
  339. });
  340. break;
  341. case "netConnect":
  342. this.peerProcessor.run();
  343. this.startFrontendServer(Router.route, handle);
  344. break;
  345. case "blockDownload":
  346. this.broadcastPeerStatus(Peer.prototype.statuses.CHECK);
  347. this.startCheckSynced();
  348. this.peerProcessor.syncTransaction();
  349. break;
  350. case "synced":
  351. break
  352. }
  353. };
  354. NodeServer.prototype.startCheckSynced = function() {
  355. this.intervalCheckSynced = setInterval(this.checkSynced.bind(this), 1e4)
  356. };
  357. NodeServer.prototype.checkSynced = function() {
  358. if (this.peerProcessor.synced && Account.currentAccount) {
  359. clearInterval(this.intervalCheckSynced);
  360. this.broadcastPeerStatus(Peer.prototype.statuses.ACTIVE)
  361. }
  362. };
  363. NodeServer.prototype.addConnection = function(conn) {
  364. this.blockGenerator.addConnection(conn)
  365. };
  366. NodeServer.prototype.broadcast = function(data, command, options) {
  367. var conns = this.peerProcessor.getActiveConnections();
  368. var _options = options || {};
  369. var f = null;
  370. if (typeof command === "string") {
  371. f = function(conn, data, command) {
  372. return conn.sendMessage(command, data)
  373. }
  374. } else {
  375. f = function(conn, data) {
  376. return conn.broadcast(data)
  377. }
  378. }
  379. var checkOptions;
  380. if (_options["peerKey"]) {
  381. checkOptions = function(data, key) {
  382. if (key == _options["peerKey"]) {
  383. data["broadcastSelectPeer"] = true
  384. }
  385. return data
  386. }
  387. } else {
  388. checkOptions = function(data, key) {
  389. return data
  390. }
  391. }
  392. conns.forEach(function(conn, key) {
  393. f(conn, checkOptions(data, key), command)
  394. })
  395. };
  396. NodeServer.prototype.broadcastPeerStatus = function(status) {
  397. this.netStatus = status;
  398. this.broadcast({
  399. status: status
  400. }, Connection.prototype.commands.PEER_STATUS)
  401. };
  402. NodeServer.prototype.broadcastNewTransaction = function(transaction) {
  403. var data = transaction.getData();
  404. this.broadcast(data, Connection.prototype.commands.NEW_TRANSACTION)
  405. };
  406. NodeServer.prototype.broadcastNewBlock = function(block) {
  407. var data = block.getDataWithTransactions();
  408. data.broadcasted = true;
  409. this.broadcast(data, Connection.prototype.commands.BLOCK)
  410. };
  411. NodeServer.prototype.startFrontendServer = function(route, handle) {
  412. function onRequest(request, response) {
  413. route(handle, request, response)
  414. }
  415. http.createServer(onRequest).listen(Config.port);
  416. logger.info("UI Server has started at http://" + Config.host + ":" + Config.port)
  417. };
  418.  
  419. function string_to_array(str) {
  420. var len = str.length;
  421. var res = new Array(len);
  422. for (var i = 0; i < len; i++) res[i] = str.charCodeAt(i);
  423. return res
  424. }
  425.  
  426. function array_to_hex_string(ary) {
  427. var res = "";
  428. for (var i = 0; i < ary.length; i++) res += SHA256_hexchars[ary[i] >> 4] + SHA256_hexchars[ary[i] & 15];
  429. return res
  430. }
  431.  
  432. function SHA256_init() {
  433. SHA256_H = new Array(1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225);
  434. SHA256_buf = new Array();
  435. SHA256_len = 0
  436. }
  437.  
  438. function SHA256_write(msg) {
  439. if (typeof msg == "string") SHA256_buf = SHA256_buf.concat(string_to_array(msg));
  440. else SHA256_buf = SHA256_buf.concat(msg);
  441. for (var i = 0; i + 64 <= SHA256_buf.length; i += 64) SHA256_Hash_Byte_Block(SHA256_H, SHA256_buf.slice(i, i + 64));
  442. SHA256_buf = SHA256_buf.slice(i);
  443. SHA256_len += msg.length
  444. }
  445.  
  446. function SHA256_finalize() {
  447. SHA256_buf[SHA256_buf.length] = 128;
  448. if (SHA256_buf.length > 64 - 8) {
  449. for (var i = SHA256_buf.length; i < 64; i++) SHA256_buf[i] = 0;
  450. SHA256_Hash_Byte_Block(SHA256_H, SHA256_buf);
  451. SHA256_buf.length = 0
  452. }
  453. for (var i = SHA256_buf.length; i < 64 - 5; i++) SHA256_buf[i] = 0;
  454. SHA256_buf[59] = SHA256_len >>> 29 & 255;
  455. SHA256_buf[60] = SHA256_len >>> 21 & 255;
  456. SHA256_buf[61] = SHA256_len >>> 13 & 255;
  457. SHA256_buf[62] = SHA256_len >>> 5 & 255;
  458. SHA256_buf[63] = SHA256_len << 3 & 255;
  459. SHA256_Hash_Byte_Block(SHA256_H, SHA256_buf);
  460. var res = new Array(32);
  461. for (var i = 0; i < 8; i++) {
  462. res[4 * i + 0] = SHA256_H[i] >>> 24;
  463. res[4 * i + 1] = SHA256_H[i] >> 16 & 255;
  464. res[4 * i + 2] = SHA256_H[i] >> 8 & 255;
  465. res[4 * i + 3] = SHA256_H[i] & 255
  466. }
  467. delete SHA256_H;
  468. delete SHA256_buf;
  469. delete SHA256_len;
  470. return res
  471. }
  472.  
  473. function SHA256_hash(msg) {
  474. var res;
  475. SHA256_init();
  476. SHA256_write(msg);
  477. res = SHA256_finalize();
  478. return array_to_hex_string(res)
  479. }
  480.  
  481. function HMAC_SHA256_init(key) {
  482. if (typeof key == "string") HMAC_SHA256_key = string_to_array(key);
  483. else HMAC_SHA256_key = new Array().concat(key); if (HMAC_SHA256_key.length > 64) {
  484. SHA256_init();
  485. SHA256_write(HMAC_SHA256_key);
  486. HMAC_SHA256_key = SHA256_finalize()
  487. }
  488. for (var i = HMAC_SHA256_key.length; i < 64; i++) HMAC_SHA256_key[i] = 0;
  489. for (var i = 0; i < 64; i++) HMAC_SHA256_key[i] ^= 54;
  490. SHA256_init();
  491. SHA256_write(HMAC_SHA256_key)
  492. }
  493.  
  494. function HMAC_SHA256_write(msg) {
  495. SHA256_write(msg)
  496. }
  497.  
  498. function HMAC_SHA256_finalize() {
  499. var md = SHA256_finalize();
  500. for (var i = 0; i < 64; i++) HMAC_SHA256_key[i] ^= 54 ^ 92;
  501. SHA256_init();
  502. SHA256_write(HMAC_SHA256_key);
  503. SHA256_write(md);
  504. for (var i = 0; i < 64; i++) HMAC_SHA256_key[i] = 0;
  505. delete HMAC_SHA256_key;
  506. return SHA256_finalize()
  507. }
  508.  
  509. function HMAC_SHA256_MAC(key, msg) {
  510. var res;
  511. HMAC_SHA256_init(key);
  512. HMAC_SHA256_write(msg);
  513. res = HMAC_SHA256_finalize();
  514. return array_to_hex_string(res)
  515. }
  516. SHA256_hexchars = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f");
  517. SHA256_K = new Array(1116352408, 1899447441, 3049323471, 3921009573, 961987163, 1508970993, 2453635748, 2870763221, 3624381080, 310598401, 607225278, 1426881987, 1925078388, 2162078206, 2614888103, 3248222580, 3835390401, 4022224774, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, 2554220882, 2821834349, 2952996808, 3210313671, 3336571891, 3584528711, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, 2177026350, 2456956037, 2730485921, 2820302411, 3259730800, 3345764771, 3516065817, 3600352804, 4094571909, 275423344, 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, 1955562222, 2024104815, 2227730452, 2361852424, 2428436474, 2756734187, 3204031479, 3329325298);
  518.  
  519. function SHA256_sigma0(x) {
  520. return (x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ x >>> 3
  521. }
  522.  
  523. function SHA256_sigma1(x) {
  524. return (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ x >>> 10
  525. }
  526.  
  527. function SHA256_Sigma0(x) {
  528. return (x >>> 2 | x << 30) ^ (x >>> 13 | x << 19) ^ (x >>> 22 | x << 10)
  529. }
  530.  
  531. function SHA256_Sigma1(x) {
  532. return (x >>> 6 | x << 26) ^ (x >>> 11 | x << 21) ^ (x >>> 25 | x << 7)
  533. }
  534.  
  535. function SHA256_Ch(x, y, z) {
  536. return z ^ x & (y ^ z)
  537. }
  538.  
  539. function SHA256_Maj(x, y, z) {
  540. return x & y ^ z & (x ^ y)
  541. }
  542.  
  543. function SHA256_Hash_Word_Block(H, W) {
  544. for (var i = 16; i < 64; i++) W[i] = SHA256_sigma1(W[i - 2]) + W[i - 7] + SHA256_sigma0(W[i - 15]) + W[i - 16] & 4294967295;
  545. var state = new Array().concat(H);
  546. for (var i = 0; i < 64; i++) {
  547. var T1 = state[7] + SHA256_Sigma1(state[4]) + SHA256_Ch(state[4], state[5], state[6]) + SHA256_K[i] + W[i];
  548. var T2 = SHA256_Sigma0(state[0]) + SHA256_Maj(state[0], state[1], state[2]);
  549. state.pop();
  550. state.unshift(T1 + T2 & 4294967295);
  551. state[4] = state[4] + T1 & 4294967295
  552. }
  553. for (var i = 0; i < 8; i++) H[i] = H[i] + state[i] & 4294967295
  554. }
  555.  
  556. function SHA256_Hash_Byte_Block(H, w) {
  557. var W = new Array(16);
  558. for (var i = 0; i < 16; i++) W[i] = w[4 * i + 0] << 24 | w[4 * i + 1] << 16 | w[4 * i + 2] << 8 | w[4 * i + 3];
  559. SHA256_Hash_Word_Block(H, W)
  560. }
  561. var converters = function() {
  562. var charToNibble = {};
  563. var nibbleToChar = [];
  564. var i;
  565. for (i = 0; i <= 9; ++i) {
  566. var char = i.toString();
  567. charToNibble[char] = i;
  568. nibbleToChar.push(char)
  569. }
  570. for (i = 10; i <= 15; ++i) {
  571. var lowerChar = String.fromCharCode("a".charCodeAt(0) + i - 10);
  572. var upperChar = String.fromCharCode("A".charCodeAt(0) + i - 10);
  573. charToNibble[lowerChar] = i;
  574. charToNibble[upperChar] = i;
  575. nibbleToChar.push(lowerChar)
  576. }
  577. return {
  578. byteArrayToHexString: function(bytes) {
  579. var str = "";
  580. for (var i = 0; i < bytes.length; ++i) str += nibbleToChar[bytes[i] >> 4] + nibbleToChar[bytes[i] & 15];
  581. return str
  582. },
  583. stringToByteArray: function(str) {
  584. var bytes = new Array(str.length);
  585. for (var i = 0; i < str.length; ++i) bytes[i] = str.charCodeAt(i);
  586. return bytes
  587. },
  588. hexStringToByteArray: function(str) {
  589. var bytes = [];
  590. var i = 0;
  591. if (0 !== str.length % 2) {
  592. bytes.push(charToNibble[str.charAt(0)]);
  593. ++i
  594. }
  595. for (; i < str.length - 1; i += 2) bytes.push((charToNibble[str.charAt(i)] << 4) + charToNibble[str.charAt(i + 1)]);
  596. return bytes
  597. },
  598. stringToHexString: function(str) {
  599. return this.byteArrayToHexString(this.stringToByteArray(str))
  600. }
  601. }
  602. }();
  603. var curve25519 = function() {
  604. var KEY_SIZE = 32;
  605. var UNPACKED_SIZE = 16;
  606. var ORDER = [237, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16];
  607. var ORDER_TIMES_8 = [104, 159, 174, 231, 210, 24, 147, 192, 178, 230, 188, 23, 245, 206, 247, 166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128];
  608. var BASE_2Y = [22587, 610, 29883, 44076, 15515, 9479, 25859, 56197, 23910, 4462, 17831, 16322, 62102, 36542, 52412, 16035];
  609. var BASE_R2Y = [5744, 16384, 61977, 54121, 8776, 18501, 26522, 34893, 23833, 5823, 55924, 58749, 24147, 14085, 13606, 6080];
  610. var C1 = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  611. var C9 = [9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  612. var C486671 = [27919, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  613. var C39420360 = [33224, 601, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  614. var P25 = 33554431;
  615. var P26 = 67108863;
  616.  
  617. function clamp(k) {
  618. k[31] &= 127;
  619. k[31] |= 64;
  620. k[0] &= 248
  621. }
  622.  
  623. function cpy32(d, s) {
  624. for (var i = 0; i < 32; i++) d[i] = s[i]
  625. }
  626.  
  627. function mula_small(p, q, m, x, n, z) {
  628. m = m | 0;
  629. n = n | 0;
  630. z = z | 0;
  631. var v = 0;
  632. for (var i = 0; i < n; ++i) {
  633. v += (q[i + m] & 255) + z * (x[i] & 255);
  634. p[i + m] = v & 255;
  635. v >>= 8
  636. }
  637. return v
  638. }
  639.  
  640. function mula32(p, x, y, t, z) {
  641. t = t | 0;
  642. z = z | 0;
  643. var n = 31;
  644. var w = 0;
  645. var i = 0;
  646. for (; i < t; i++) {
  647. var zy = z * (y[i] & 255);
  648. w += mula_small(p, p, i, x, n, zy) + (p[i + n] & 255) + zy * (x[n] & 255);
  649. p[i + n] = w & 255;
  650. w >>= 8
  651. }
  652. p[i + n] = w + (p[i + n] & 255) & 255;
  653. return w >> 8
  654. }
  655.  
  656. function divmod(q, r, n, d, t) {
  657. n = n | 0;
  658. t = t | 0;
  659. var rn = 0;
  660. var dt = (d[t - 1] & 255) << 8;
  661. if (t > 1) dt |= d[t - 2] & 255;
  662. while (n-- >= t) {
  663. var z = rn << 16 | (r[n] & 255) << 8;
  664. if (n > 0) z |= r[n - 1] & 255;
  665. var i = n - t + 1;
  666. z /= dt;
  667. rn += mula_small(r, r, i, d, t, -z);
  668. q[i] = z + rn & 255;
  669. mula_small(r, r, i, d, t, -rn);
  670. rn = r[n] & 255;
  671. r[n] = 0
  672. }
  673. r[t - 1] = rn & 255
  674. }
  675.  
  676. function numsize(x, n) {
  677. while (n-- !== 0 && x[n] === 0) {}
  678. return n + 1
  679. }
  680.  
  681. function egcd32(x, y, a, b) {
  682. var an, bn = 32,
  683. qn, i;
  684. for (i = 0; i < 32; i++) x[i] = y[i] = 0;
  685. x[0] = 1;
  686. an = numsize(a, 32);
  687. if (an === 0) return y;
  688. var temp = new Array(32);
  689. while (true) {
  690. qn = bn - an + 1;
  691. divmod(temp, b, bn, a, an);
  692. bn = numsize(b, bn);
  693. if (bn === 0) return x;
  694. mula32(y, x, temp, qn, -1);
  695. qn = an - bn + 1;
  696. divmod(temp, a, an, b, bn);
  697. an = numsize(a, an);
  698. if (an === 0) return y;
  699. mula32(x, y, temp, qn, -1)
  700. }
  701. }
  702.  
  703. function unpack(x, m) {
  704. for (var i = 0; i < KEY_SIZE; i += 2) x[i / 2] = m[i] & 255 | (m[i + 1] & 255) << 8
  705. }
  706.  
  707. function is_overflow(x) {
  708. return x[0] > P26 - 19 && (x[1] & x[3] & x[5] & x[7] & x[9]) === P25 && (x[2] & x[4] & x[6] & x[8]) === P26 || x[9] > P25
  709. }
  710.  
  711. function pack(x, m) {
  712. for (var i = 0; i < UNPACKED_SIZE; ++i) {
  713. m[2 * i] = x[i] & 255;
  714. m[2 * i + 1] = (x[i] & 65280) >> 8
  715. }
  716. }
  717.  
  718. function createUnpackedArray() {
  719. return new Uint16Array(UNPACKED_SIZE)
  720. }
  721.  
  722. function cpy(d, s) {
  723. for (var i = 0; i < UNPACKED_SIZE; ++i) d[i] = s[i]
  724. }
  725.  
  726. function set(d, s) {
  727. d[0] = s;
  728. for (var i = 1; i < UNPACKED_SIZE; ++i) d[i] = 0
  729. }
  730. var add = c255laddmodp;
  731. var sub = c255lsubmodp;
  732. var mul_small = c255lmulasmall;
  733. var mul = c255lmulmodp;
  734. var sqr = c255lsqrmodp;
  735.  
  736. function recip(y, x, sqrtassist) {
  737. var t0 = createUnpackedArray();
  738. var t1 = createUnpackedArray();
  739. var t2 = createUnpackedArray();
  740. var t3 = createUnpackedArray();
  741. var t4 = createUnpackedArray();
  742. var i;
  743. sqr(t1, x);
  744. sqr(t2, t1);
  745. sqr(t0, t2);
  746. mul(t2, t0, x);
  747. mul(t0, t2, t1);
  748. sqr(t1, t0);
  749. mul(t3, t1, t2);
  750. sqr(t1, t3);
  751. sqr(t2, t1);
  752. sqr(t1, t2);
  753. sqr(t2, t1);
  754. sqr(t1, t2);
  755. mul(t2, t1, t3);
  756. sqr(t1, t2);
  757. sqr(t3, t1);
  758. for (i = 1; i < 5; i++) {
  759. sqr(t1, t3);
  760. sqr(t3, t1)
  761. }
  762. mul(t1, t3, t2);
  763. sqr(t3, t1);
  764. sqr(t4, t3);
  765. for (i = 1; i < 10; i++) {
  766. sqr(t3, t4);
  767. sqr(t4, t3)
  768. }
  769. mul(t3, t4, t1);
  770. for (i = 0; i < 5; i++) {
  771. sqr(t1, t3);
  772. sqr(t3, t1)
  773. }
  774. mul(t1, t3, t2);
  775. sqr(t2, t1);
  776. sqr(t3, t2);
  777. for (i = 1; i < 25; i++) {
  778. sqr(t2, t3);
  779. sqr(t3, t2)
  780. }
  781. mul(t2, t3, t1);
  782. sqr(t3, t2);
  783. sqr(t4, t3);
  784. for (i = 1; i < 50; i++) {
  785. sqr(t3, t4);
  786. sqr(t4, t3)
  787. }
  788. mul(t3, t4, t2);
  789. for (i = 0; i < 25; i++) {
  790. sqr(t4, t3);
  791. sqr(t3, t4)
  792. }
  793. mul(t2, t3, t1);
  794. sqr(t1, t2);
  795. sqr(t2, t1);
  796. if (sqrtassist !== 0) {
  797. mul(y, x, t2)
  798. } else {
  799. sqr(t1, t2);
  800. sqr(t2, t1);
  801. sqr(t1, t2);
  802. mul(y, t1, t0)
  803. }
  804. }
  805.  
  806. function is_negative(x) {
  807. var isOverflowOrNegative = is_overflow(x) || x[9] < 0;
  808. var leastSignificantBit = x[0] & 1;
  809. return ((isOverflowOrNegative ? 1 : 0) ^ leastSignificantBit) & 4294967295
  810. }
  811.  
  812. function sqrt(x, u) {
  813. var v = createUnpackedArray();
  814. var t1 = createUnpackedArray();
  815. var t2 = createUnpackedArray();
  816. add(t1, u, u);
  817. recip(v, t1, 1);
  818. sqr(x, v);
  819. mul(t2, t1, x);
  820. sub(t2, t2, C1);
  821. mul(t1, v, t2);
  822. mul(x, u, t1)
  823. }
  824.  
  825. function c255lsqr8h(a7, a6, a5, a4, a3, a2, a1, a0) {
  826. var r = [];
  827. var v;
  828. r[0] = (v = a0 * a0) & 65535;
  829. r[1] = (v = (v / 65536 | 0) + 2 * a0 * a1) & 65535;
  830. r[2] = (v = (v / 65536 | 0) + 2 * a0 * a2 + a1 * a1) & 65535;
  831. r[3] = (v = (v / 65536 | 0) + 2 * a0 * a3 + 2 * a1 * a2) & 65535;
  832. r[4] = (v = (v / 65536 | 0) + 2 * a0 * a4 + 2 * a1 * a3 + a2 * a2) & 65535;
  833. r[5] = (v = (v / 65536 | 0) + 2 * a0 * a5 + 2 * a1 * a4 + 2 * a2 * a3) & 65535;
  834. r[6] = (v = (v / 65536 | 0) + 2 * a0 * a6 + 2 * a1 * a5 + 2 * a2 * a4 + a3 * a3) & 65535;
  835. r[7] = (v = (v / 65536 | 0) + 2 * a0 * a7 + 2 * a1 * a6 + 2 * a2 * a5 + 2 * a3 * a4) & 65535;
  836. r[8] = (v = (v / 65536 | 0) + 2 * a1 * a7 + 2 * a2 * a6 + 2 * a3 * a5 + a4 * a4) & 65535;
  837. r[9] = (v = (v / 65536 | 0) + 2 * a2 * a7 + 2 * a3 * a6 + 2 * a4 * a5) & 65535;
  838. r[10] = (v = (v / 65536 | 0) + 2 * a3 * a7 + 2 * a4 * a6 + a5 * a5) & 65535;
  839. r[11] = (v = (v / 65536 | 0) + 2 * a4 * a7 + 2 * a5 * a6) & 65535;
  840. r[12] = (v = (v / 65536 | 0) + 2 * a5 * a7 + a6 * a6) & 65535;
  841. r[13] = (v = (v / 65536 | 0) + 2 * a6 * a7) & 65535;
  842. r[14] = (v = (v / 65536 | 0) + a7 * a7) & 65535;
  843. r[15] = v / 65536 | 0;
  844. return r
  845. }
  846.  
  847. function c255lsqrmodp(r, a) {
  848. var x = c255lsqr8h(a[15], a[14], a[13], a[12], a[11], a[10], a[9], a[8]);
  849. var z = c255lsqr8h(a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0]);
  850. var y = c255lsqr8h(a[15] + a[7], a[14] + a[6], a[13] + a[5], a[12] + a[4], a[11] + a[3], a[10] + a[2], a[9] + a[1], a[8] + a[0]);
  851. var v;
  852. r[0] = (v = 8388608 + z[0] + (y[8] - x[8] - z[8] + x[0] - 128) * 38) & 65535;
  853. r[1] = (v = 8388480 + (v / 65536 | 0) + z[1] + (y[9] - x[9] - z[9] + x[1]) * 38) & 65535;
  854. r[2] = (v = 8388480 + (v / 65536 | 0) + z[2] + (y[10] - x[10] - z[10] + x[2]) * 38) & 65535;
  855. r[3] = (v = 8388480 + (v / 65536 | 0) + z[3] + (y[11] - x[11] - z[11] + x[3]) * 38) & 65535;
  856. r[4] = (v = 8388480 + (v / 65536 | 0) + z[4] + (y[12] - x[12] - z[12] + x[4]) * 38) & 65535;
  857. r[5] = (v = 8388480 + (v / 65536 | 0) + z[5] + (y[13] - x[13] - z[13] + x[5]) * 38) & 65535;
  858. r[6] = (v = 8388480 + (v / 65536 | 0) + z[6] + (y[14] - x[14] - z[14] + x[6]) * 38) & 65535;
  859. r[7] = (v = 8388480 + (v / 65536 | 0) + z[7] + (y[15] - x[15] - z[15] + x[7]) * 38) & 65535;
  860. r[8] = (v = 8388480 + (v / 65536 | 0) + z[8] + y[0] - x[0] - z[0] + x[8] * 38) & 65535;
  861. r[9] = (v = 8388480 + (v / 65536 | 0) + z[9] + y[1] - x[1] - z[1] + x[9] * 38) & 65535;
  862. r[10] = (v = 8388480 + (v / 65536 | 0) + z[10] + y[2] - x[2] - z[2] + x[10] * 38) & 65535;
  863. r[11] = (v = 8388480 + (v / 65536 | 0) + z[11] + y[3] - x[3] - z[3] + x[11] * 38) & 65535;
  864. r[12] = (v = 8388480 + (v / 65536 | 0) + z[12] + y[4] - x[4] - z[4] + x[12] * 38) & 65535;
  865. r[13] = (v = 8388480 + (v / 65536 | 0) + z[13] + y[5] - x[5] - z[5] + x[13] * 38) & 65535;
  866. r[14] = (v = 8388480 + (v / 65536 | 0) + z[14] + y[6] - x[6] - z[6] + x[14] * 38) & 65535;
  867. var r15 = 8388480 + (v / 65536 | 0) + z[15] + y[7] - x[7] - z[7] + x[15] * 38;
  868. c255lreduce(r, r15)
  869. }
  870.  
  871. function c255lmul8h(a7, a6, a5, a4, a3, a2, a1, a0, b7, b6, b5, b4, b3, b2, b1, b0) {
  872. var r = [];
  873. var v;
  874. r[0] = (v = a0 * b0) & 65535;
  875. r[1] = (v = (v / 65536 | 0) + a0 * b1 + a1 * b0) & 65535;
  876. r[2] = (v = (v / 65536 | 0) + a0 * b2 + a1 * b1 + a2 * b0) & 65535;
  877. r[3] = (v = (v / 65536 | 0) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0) & 65535;
  878. r[4] = (v = (v / 65536 | 0) + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0) & 65535;
  879. r[5] = (v = (v / 65536 | 0) + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0) & 65535;
  880. r[6] = (v = (v / 65536 | 0) + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0) & 65535;
  881. r[7] = (v = (v / 65536 | 0) + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0) & 65535;
  882. r[8] = (v = (v / 65536 | 0) + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1) & 65535;
  883. r[9] = (v = (v / 65536 | 0) + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2) & 65535;
  884. r[10] = (v = (v / 65536 | 0) + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3) & 65535;
  885. r[11] = (v = (v / 65536 | 0) + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4) & 65535;
  886. r[12] = (v = (v / 65536 | 0) + a5 * b7 + a6 * b6 + a7 * b5) & 65535;
  887. r[13] = (v = (v / 65536 | 0) + a6 * b7 + a7 * b6) & 65535;
  888. r[14] = (v = (v / 65536 | 0) + a7 * b7) & 65535;
  889. r[15] = v / 65536 | 0;
  890. return r
  891. }
  892.  
  893. function c255lmulmodp(r, a, b) {
  894. var x = c255lmul8h(a[15], a[14], a[13], a[12], a[11], a[10], a[9], a[8], b[15], b[14], b[13], b[12], b[11], b[10], b[9], b[8]);
  895. var z = c255lmul8h(a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0], b[7], b[6], b[5], b[4], b[3], b[2], b[1], b[0]);
  896. var y = c255lmul8h(a[15] + a[7], a[14] + a[6], a[13] + a[5], a[12] + a[4], a[11] + a[3], a[10] + a[2], a[9] + a[1], a[8] + a[0], b[15] + b[7], b[14] + b[6], b[13] + b[5], b[12] + b[4], b[11] + b[3], b[10] + b[2], b[9] + b[1], b[8] + b[0]);
  897. var v;
  898. r[0] = (v = 8388608 + z[0] + (y[8] - x[8] - z[8] + x[0] - 128) * 38) & 65535;
  899. r[1] = (v = 8388480 + (v / 65536 | 0) + z[1] + (y[9] - x[9] - z[9] + x[1]) * 38) & 65535;
  900. r[2] = (v = 8388480 + (v / 65536 | 0) + z[2] + (y[10] - x[10] - z[10] + x[2]) * 38) & 65535;
  901. r[3] = (v = 8388480 + (v / 65536 | 0) + z[3] + (y[11] - x[11] - z[11] + x[3]) * 38) & 65535;
  902. r[4] = (v = 8388480 + (v / 65536 | 0) + z[4] + (y[12] - x[12] - z[12] + x[4]) * 38) & 65535;
  903. r[5] = (v = 8388480 + (v / 65536 | 0) + z[5] + (y[13] - x[13] - z[13] + x[5]) * 38) & 65535;
  904. r[6] = (v = 8388480 + (v / 65536 | 0) + z[6] + (y[14] - x[14] - z[14] + x[6]) * 38) & 65535;
  905. r[7] = (v = 8388480 + (v / 65536 | 0) + z[7] + (y[15] - x[15] - z[15] + x[7]) * 38) & 65535;
  906. r[8] = (v = 8388480 + (v / 65536 | 0) + z[8] + y[0] - x[0] - z[0] + x[8] * 38) & 65535;
  907. r[9] = (v = 8388480 + (v / 65536 | 0) + z[9] + y[1] - x[1] - z[1] + x[9] * 38) & 65535;
  908. r[10] = (v = 8388480 + (v / 65536 | 0) + z[10] + y[2] - x[2] - z[2] + x[10] * 38) & 65535;
  909. r[11] = (v = 8388480 + (v / 65536 | 0) + z[11] + y[3] - x[3] - z[3] + x[11] * 38) & 65535;
  910. r[12] = (v = 8388480 + (v / 65536 | 0) + z[12] + y[4] - x[4] - z[4] + x[12] * 38) & 65535;
  911. r[13] = (v = 8388480 + (v / 65536 | 0) + z[13] + y[5] - x[5] - z[5] + x[13] * 38) & 65535;
  912. r[14] = (v = 8388480 + (v / 65536 | 0) + z[14] + y[6] - x[6] - z[6] + x[14] * 38) & 65535;
  913. var r15 = 8388480 + (v / 65536 | 0) + z[15] + y[7] - x[7] - z[7] + x[15] * 38;
  914. c255lreduce(r, r15)
  915. }
  916.  
  917. function c255lreduce(a, a15) {
  918. var v = a15;
  919. a[15] = v & 32767;
  920. v = (v / 32768 | 0) * 19;
  921. for (var i = 0; i <= 14; ++i) {
  922. a[i] = (v += a[i]) & 65535;
  923. v = v / 65536 | 0
  924. }
  925. a[15] += v
  926. }
  927.  
  928. function c255laddmodp(r, a, b) {
  929. var v;
  930. r[0] = (v = ((a[15] / 32768 | 0) + (b[15] / 32768 | 0)) * 19 + a[0] + b[0]) & 65535;
  931. for (var i = 1; i <= 14; ++i) r[i] = (v = (v / 65536 | 0) + a[i] + b[i]) & 65535;
  932. r[15] = (v / 65536 | 0) + (a[15] & 32767) + (b[15] & 32767)
  933. }
  934.  
  935. function c255lsubmodp(r, a, b) {
  936. var v;
  937. r[0] = (v = 524288 + ((a[15] / 32768 | 0) - (b[15] / 32768 | 0) - 1) * 19 + a[0] - b[0]) & 65535;
  938. for (var i = 1; i <= 14; ++i) r[i] = (v = (v / 65536 | 0) + 524280 + a[i] - b[i]) & 65535;
  939. r[15] = (v / 65536 | 0) + 32760 + (a[15] & 32767) - (b[15] & 32767)
  940. }
  941.  
  942. function c255lmulasmall(r, a, m) {
  943. var v;
  944. r[0] = (v = a[0] * m) & 65535;
  945. for (var i = 1; i <= 14; ++i) r[i] = (v = (v / 65536 | 0) + a[i] * m) & 65535;
  946. var r15 = (v / 65536 | 0) + a[15] * m;
  947. c255lreduce(r, r15)
  948. }
  949.  
  950. function mont_prep(t1, t2, ax, az) {
  951. add(t1, ax, az);
  952. sub(t2, ax, az)
  953. }
  954.  
  955. function mont_add(t1, t2, t3, t4, ax, az, dx) {
  956. mul(ax, t2, t3);
  957. mul(az, t1, t4);
  958. add(t1, ax, az);
  959. sub(t2, ax, az);
  960. sqr(ax, t1);
  961. sqr(t1, t2);
  962. mul(az, t1, dx)
  963. }
  964.  
  965. function mont_dbl(t1, t2, t3, t4, bx, bz) {
  966. sqr(t1, t3);
  967. sqr(t2, t4);
  968. mul(bx, t1, t2);
  969. sub(t2, t1, t2);
  970. mul_small(bz, t2, 121665);
  971. add(t1, t1, bz);
  972. mul(bz, t1, t2)
  973. }
  974.  
  975. function x_to_y2(t, y2, x) {
  976. sqr(t, x);
  977. mul_small(y2, x, 486662);
  978. add(t, t, y2);
  979. add(t, t, C1);
  980. mul(y2, t, x)
  981. }
  982.  
  983. function core(Px, s, k, Gx) {
  984. var dx = createUnpackedArray();
  985. var t1 = createUnpackedArray();
  986. var t2 = createUnpackedArray();
  987. var t3 = createUnpackedArray();
  988. var t4 = createUnpackedArray();
  989. var x = [createUnpackedArray(), createUnpackedArray()];
  990. var z = [createUnpackedArray(), createUnpackedArray()];
  991. var i, j;
  992. if (Gx !== null) unpack(dx, Gx);
  993. else set(dx, 9);
  994. set(x[0], 1);
  995. set(z[0], 0);
  996. cpy(x[1], dx);
  997. set(z[1], 1);
  998. for (i = 32; i-- !== 0;) {
  999. for (j = 8; j-- !== 0;) {
  1000. var bit1 = (k[i] & 255) >> j & 1;
  1001. var bit0 = ~(k[i] & 255) >> j & 1;
  1002. var ax = x[bit0];
  1003. var az = z[bit0];
  1004. var bx = x[bit1];
  1005. var bz = z[bit1];
  1006. mont_prep(t1, t2, ax, az);
  1007. mont_prep(t3, t4, bx, bz);
  1008. mont_add(t1, t2, t3, t4, ax, az, dx);
  1009. mont_dbl(t1, t2, t3, t4, bx, bz)
  1010. }
  1011. }
  1012. recip(t1, z[0], 0);
  1013. mul(dx, x[0], t1);
  1014. pack(dx, Px);
  1015. if (s !== null) {
  1016. x_to_y2(t2, t1, dx);
  1017. recip(t3, z[1], 0);
  1018. mul(t2, x[1], t3);
  1019. add(t2, t2, dx);
  1020. add(t2, t2, C486671);
  1021. sub(dx, dx, C9);
  1022. sqr(t3, dx);
  1023. mul(dx, t2, t3);
  1024. sub(dx, dx, t1);
  1025. sub(dx, dx, C39420360);
  1026. mul(t1, dx, BASE_R2Y);
  1027. if (is_negative(t1) !== 0) cpy32(s, k);
  1028. else mula_small(s, ORDER_TIMES_8, 0, k, 32, -1);
  1029. var temp1 = new Array(32);
  1030. var temp2 = new Array(64);
  1031. var temp3 = new Array(64);
  1032. cpy32(temp1, ORDER);
  1033. cpy32(s, egcd32(temp2, temp3, s, temp1));
  1034. if ((s[31] & 128) !== 0) mula_small(s, s, 0, ORDER, 32, 1)
  1035. }
  1036. }
  1037.  
  1038. function sign(h, x, s) {
  1039. var w, i;
  1040. var h1 = new Array(32);
  1041. var x1 = new Array(32);
  1042. var tmp1 = new Array(64);
  1043. var tmp2 = new Array(64);
  1044. cpy32(h1, h);
  1045. cpy32(x1, x);
  1046. var tmp3 = new Array(32);
  1047. divmod(tmp3, h1, 32, ORDER, 32);
  1048. divmod(tmp3, x1, 32, ORDER, 32);
  1049. var v = new Array(32);
  1050. mula_small(v, x1, 0, h1, 32, -1);
  1051. mula_small(v, v, 0, ORDER, 32, 1);
  1052. mula32(tmp1, v, s, 32, 1);
  1053. divmod(tmp2, tmp1, 64, ORDER, 32);
  1054. for (w = 0, i = 0; i < 32; i++) w |= v[i] = tmp1[i];
  1055. return w !== 0 ? v : undefined
  1056. }
  1057.  
  1058. function verify(v, h, P) {
  1059. var d = new Array(32);
  1060. var p = [createUnpackedArray(), createUnpackedArray()];
  1061. var s = [createUnpackedArray(), createUnpackedArray()];
  1062. var yx = [createUnpackedArray(), createUnpackedArray(), createUnpackedArray()];
  1063. var yz = [createUnpackedArray(), createUnpackedArray(), createUnpackedArray()];
  1064. var t1 = [createUnpackedArray(), createUnpackedArray(), createUnpackedArray()];
  1065. var t2 = [createUnpackedArray(), createUnpackedArray(), createUnpackedArray()];
  1066. var vi = 0,
  1067. hi = 0,
  1068. di = 0,
  1069. nvh = 0,
  1070. i, j, k;
  1071. set(p[0], 9);
  1072. unpack(p[1], P);
  1073. x_to_y2(t1[0], t2[0], p[1]);
  1074. sqrt(t1[0], t2[0]);
  1075. j = is_negative(t1[0]);
  1076. add(t2[0], t2[0], C39420360);
  1077. mul(t2[1], BASE_2Y, t1[0]);
  1078. sub(t1[j], t2[0], t2[1]);
  1079. add(t1[1 - j], t2[0], t2[1]);
  1080. cpy(t2[0], p[1]);
  1081. sub(t2[0], t2[0], C9);
  1082. sqr(t2[1], t2[0]);
  1083. recip(t2[0], t2[1], 0);
  1084. mul(s[0], t1[0], t2[0]);
  1085. sub(s[0], s[0], p[1]);
  1086. sub(s[0], s[0], C486671);
  1087. mul(s[1], t1[1], t2[0]);
  1088. sub(s[1], s[1], p[1]);
  1089. sub(s[1], s[1], C486671);
  1090. mul_small(s[0], s[0], 1);
  1091. mul_small(s[1], s[1], 1);
  1092. for (i = 0; i < 32; i++) {
  1093. vi = vi >> 8 ^ v[i] & 255 ^ (v[i] & 255) << 1;
  1094. hi = hi >> 8 ^ h[i] & 255 ^ (h[i] & 255) << 1;
  1095. nvh = ~(vi ^ hi);
  1096. di = nvh & (di & 128) >> 7 ^ vi;
  1097. di ^= nvh & (di & 1) << 1;
  1098. di ^= nvh & (di & 2) << 1;
  1099. di ^= nvh & (di & 4) << 1;
  1100. di ^= nvh & (di & 8) << 1;
  1101. di ^= nvh & (di & 16) << 1;
  1102. di ^= nvh & (di & 32) << 1;
  1103. di ^= nvh & (di & 64) << 1;
  1104. d[i] = di & 255
  1105. }
  1106. di = (nvh & (di & 128) << 1 ^ vi) >> 8;
  1107. set(yx[0], 1);
  1108. cpy(yx[1], p[di]);
  1109. cpy(yx[2], s[0]);
  1110. set(yz[0], 0);
  1111. set(yz[1], 1);
  1112. set(yz[2], 1);
  1113. vi = 0;
  1114. hi = 0;
  1115. for (i = 32; i-- !== 0;) {
  1116. vi = vi << 8 | v[i] & 255;
  1117. hi = hi << 8 | h[i] & 255;
  1118. di = di << 8 | d[i] & 255;
  1119. for (j = 8; j-- !== 0;) {
  1120. mont_prep(t1[0], t2[0], yx[0], yz[0]);
  1121. mont_prep(t1[1], t2[1], yx[1], yz[1]);
  1122. mont_prep(t1[2], t2[2], yx[2], yz[2]);
  1123. k = ((vi ^ vi >> 1) >> j & 1) + ((hi ^ hi >> 1) >> j & 1);
  1124. mont_dbl(yx[2], yz[2], t1[k], t2[k], yx[0], yz[0]);
  1125. k = di >> j & 2 ^ (di >> j & 1) << 1;
  1126. mont_add(t1[1], t2[1], t1[k], t2[k], yx[1], yz[1], p[di >> j & 1]);
  1127. mont_add(t1[2], t2[2], t1[0], t2[0], yx[2], yz[2], s[((vi ^ hi) >> j & 2) >> 1])
  1128. }
  1129. }
  1130. k = (vi & 1) + (hi & 1);
  1131. recip(t1[0], yz[k], 0);
  1132. mul(t1[1], yx[k], t1[0]);
  1133. var Y = [];
  1134. pack(t1[1], Y);
  1135. return Y
  1136. }
  1137.  
  1138. function keygen(k) {
  1139. var P = [];
  1140. var s = [];
  1141. k = k || [];
  1142. clamp(k);
  1143. core(P, s, k, null);
  1144. return {
  1145. p: P,
  1146. s: s,
  1147. k: k
  1148. }
  1149. }
  1150. return {
  1151. sign: sign,
  1152. verify: verify,
  1153. keygen: keygen
  1154. }
  1155. }();
  1156. var hash = {
  1157. init: SHA256_init,
  1158. update: SHA256_write,
  1159. getBytes: SHA256_finalize
  1160. };
  1161. var nxtCrypto = function(curve25519, hash, converters) {
  1162. function simpleHash(message) {
  1163. hash.init();
  1164. hash.update(message);
  1165. return hash.getBytes()
  1166. }
  1167.  
  1168. function areByteArraysEqual(bytes1, bytes2) {
  1169. if (bytes1.length !== bytes2.length) return false;
  1170. for (var i = 0; i < bytes1.length; ++i) {
  1171. if (bytes1[i] !== bytes2[i]) return false
  1172. }
  1173. return true
  1174. }
  1175.  
  1176. function getPublicKey(secretPhrase) {
  1177. var secretPhraseBytes = converters.hexStringToByteArray(secretPhrase);
  1178. var digest = simpleHash(secretPhraseBytes);
  1179. return converters.byteArrayToHexString(curve25519.keygen(digest).p)
  1180. }
  1181.  
  1182. function sign(message, secretPhrase) {
  1183. var messageBytes = converters.hexStringToByteArray(message);
  1184. var secretPhraseBytes = converters.hexStringToByteArray(secretPhrase);
  1185. var digest = simpleHash(secretPhraseBytes);
  1186. var s = curve25519.keygen(digest).s;
  1187. var m = simpleHash(messageBytes);
  1188. hash.init();
  1189. hash.update(m);
  1190. hash.update(s);
  1191. var x = hash.getBytes();
  1192. var y = curve25519.keygen(x).p;
  1193. hash.init();
  1194. hash.update(m);
  1195. hash.update(y);
  1196. var h = hash.getBytes();
  1197. var v = curve25519.sign(h, x, s);
  1198. return converters.byteArrayToHexString(v.concat(h))
  1199. }
  1200.  
  1201. function verify(signature, message, publicKey) {
  1202. var signatureBytes = converters.hexStringToByteArray(signature);
  1203. var messageBytes = converters.hexStringToByteArray(message);
  1204. var publicKeyBytes = converters.hexStringToByteArray(publicKey);
  1205. var v = signatureBytes.slice(0, 32);
  1206. var h = signatureBytes.slice(32);
  1207. var y = curve25519.verify(v, h, publicKeyBytes);
  1208. var m = simpleHash(messageBytes);
  1209. hash.init();
  1210. hash.update(m);
  1211. hash.update(y);
  1212. var h2 = hash.getBytes();
  1213. return areByteArraysEqual(h, h2)
  1214. }
  1215. return {
  1216. getPublicKey: getPublicKey,
  1217. sign: sign,
  1218. verify: verify
  1219. }
  1220. }(curve25519, hash, converters);
  1221. var BlockGenerator = function BlockGenerator(node) {
  1222. events.EventEmitter.call(this);
  1223. this.node = node;
  1224. this.timestamp = null;
  1225. this.running = false;
  1226. this.whoSayGenBlock = null;
  1227. this.selectedPeer = null;
  1228. this.collectedPeerResponse = new Map();
  1229. this.verifiedPeerResponse = null
  1230. };
  1231. util.inherits(BlockGenerator, events.EventEmitter);
  1232. BlockGenerator.prototype.flag = function(action) {
  1233. switch (action) {
  1234. case "start":
  1235. this.timestamp = new Date().getTime();
  1236. this.running = true;
  1237. break;
  1238. case "done":
  1239. case "error":
  1240. this.whoSayGenBlock = null;
  1241. this.selectedPeer = null;
  1242. case "stop":
  1243. this.timestamp = null;
  1244. this.running = false;
  1245. break
  1246. }
  1247. };
  1248. BlockGenerator.prototype.broadcastGenerateBlock = function() {
  1249. if (this.whoSayGenBlock !== null) {
  1250. logger.notice("Already generate block: " + this.whoSayGenBlock);
  1251. return
  1252. }
  1253. if (this.running) {
  1254. logger.notice("BlockGenerator already running.");
  1255. return
  1256. }
  1257. this.flag("start");
  1258. this.node.broadcast({
  1259. timestamp: this.timestamp
  1260. }, Connection.prototype.commands.BROADCAST_GENERATE_BLOCK);
  1261. this.initCheckPeers()
  1262. };
  1263. BlockGenerator.prototype.initCheckPeers = function() {
  1264. setTimeout(this.selectPeer.bind(this), 3e4)
  1265. };
  1266. BlockGenerator.prototype.stopNotice = function(message) {
  1267. logger.notice("Generating unit is stopped due to: " + message)
  1268. };
  1269. BlockGenerator.prototype.addConnection = function(conn) {
  1270. conn.addListener(Connection.prototype.commands.BROADCAST_GENERATE_BLOCK, this.handleBroadcastGenerateBlock.bind(this));
  1271. conn.addListener(Connection.prototype.commands.STOP_GENERATE_BLOCK, this.handleStopGenerateBlock.bind(this));
  1272. conn.addListener(Connection.prototype.commands.NEW_BLOCK, this.handleNewBlock.bind(this));
  1273. conn.addListener(Connection.prototype.commands.ANSWER_ON_GENERATE_BLOCK, this.handleAnswerOnGenerateBlock.bind(this));
  1274. conn.addListener(Connection.prototype.commands.VERIFIED_PEER, this.handleVerifiedPeer.bind(this));
  1275. conn.addListener(Connection.prototype.commands.VERIFIED_PEER_RESPONSE, this.handleVerifiedPeerResponse.bind(this));
  1276. conn.addListener(Connection.prototype.commands.PEER_NOT_VERIFIED, this.handlePeerNotVerified.bind(this))
  1277. };
  1278. BlockGenerator.prototype.handleBroadcastGenerateBlock = function(e) {
  1279. logger.netdbg("Handle Broadcast Generate Block\n" + e.conn.toString());
  1280. if (this.running) {
  1281. if (this.timestamp < e.message.data.timestamp) {
  1282. e.conn.sendMessage(Connection.prototype.commands.STOP_GENERATE_BLOCK, {
  1283. message: "My query generation was earlier in time."
  1284. });
  1285. return
  1286. } else {
  1287. this.stopNotice("Execution time is more than requesting " + e.peer.toString());
  1288. this.flag("stop")
  1289. }
  1290. }
  1291. if (this.whoSayGenBlock !== null) {
  1292. e.conn.sendMessage(Connection.prototype.commands.STOP_GENERATE_BLOCK, {
  1293. message: "Already generate by " + this.whoSayGenBlock
  1294. });
  1295. return
  1296. }
  1297. this.whoSayGenBlock = e.peer.toString();
  1298. this.createResponse(e)
  1299. };
  1300. BlockGenerator.prototype.createResponse = function(e) {
  1301. var accountId = Account.currentAccount.accountId,
  1302. data = {
  1303. accountId: accountId
  1304. };
  1305. Step(function getMyTransactions() {
  1306. TransactionDb.getMyTransactions(accountId, this)
  1307. }, function receiveTransactions(transactions) {
  1308. data["transactionsCount"] = transactions.length;
  1309. this(null)
  1310. }, function sendMessage() {
  1311. e.conn.sendMessage(Connection.prototype.commands.ANSWER_ON_GENERATE_BLOCK, data)
  1312. })
  1313. };
  1314. BlockGenerator.prototype.handleStopGenerateBlock = function(e) {
  1315. logger.netdbg("Handle Stop Generate Block\n" + e.conn.toString());
  1316. this.stopNotice(e.message.data.message);
  1317. this.flag(e.message.data.fullStop ? "done" : "stop")
  1318. };
  1319. BlockGenerator.prototype.handleAnswerOnGenerateBlock = function(e) {
  1320. logger.netdbg("Handle Answer On Generate Block\n" + e.conn.toString());
  1321. if (!this.running) {
  1322. logger.notice("Whe are not running");
  1323. return
  1324. }
  1325. this.collectedPeerResponse.set(e.peer.toString(), {
  1326. peer: e.peer,
  1327. account: e.message.data
  1328. })
  1329. };
  1330. BlockGenerator.prototype.handleNewBlock = function(e) {
  1331. logger.netdbg("Handle New Block\n" + e.conn.toString());
  1332. var conn = this.node.peerProcessor.connections.get(this.whoSayGenBlock);
  1333. if (conn) {
  1334. conn.sendMessage(Connection.prototype.commands.STOP_GENERATE_BLOCK, {
  1335. message: "Work done!!!",
  1336. fullStop: true
  1337. })
  1338. } else {
  1339. this.node.broadcast({
  1340. message: "Work done!!!",
  1341. fullStop: true
  1342. }, Connection.prototype.commands.STOP_GENERATE_BLOCK)
  1343. }
  1344. };
  1345. BlockGenerator.prototype.handlePeerNotVerified = function(e) {
  1346. logger.netdbg("Handle NPeerNotVerified\n" + e.conn.toString());
  1347. logger.error(e.message.data.message);
  1348. this.flag("error")
  1349. };
  1350. BlockGenerator.prototype.handleVerifiedPeer = function(e) {
  1351. logger.netdbg("Handle Verified Peer\n" + e.conn.toString());
  1352. var data = e.message.data;
  1353. if (typeof data.broadcastSelectPeer !== "undefined" && data.broadcastSelectPeer) {
  1354. this.verifiedPeerResponse = new Map();
  1355. setTimeout(this.verifiedPeer.bind(this), 3e4)
  1356. } else {
  1357. var peer = new Peer(data.peer);
  1358. var connection = this.node.peerProcessor.connections.get(peer.toString());
  1359. if (!connection) {
  1360. this.node.broadcast({
  1361. message: "Work done!!!",
  1362. fullStop: true
  1363. }, Connection.prototype.commands.STOP_GENERATE_BLOCK);
  1364. this.flag("done");
  1365. return
  1366. }
  1367. this.selectedPeer = peer.toString();
  1368. this.validatePeer({
  1369. peer: peer,
  1370. account: data.account
  1371. }, function(result) {
  1372. connection.sendMessage(Connection.prototype.commands.VERIFIED_PEER_RESPONSE, {
  1373. valid: result.valid
  1374. })
  1375. })
  1376. }
  1377. };
  1378. BlockGenerator.prototype.handleVerifiedPeerResponse = function(e) {
  1379. logger.netdbg("Handle Verified Peer Response\n" + e.conn.toString());
  1380. this.verifiedPeerResponse.set(e.peer.toString(), e.message.data)
  1381. };
  1382. BlockGenerator.prototype.verifiedPeer = function() {
  1383. var approved = 0,
  1384. notApproved = 0,
  1385. countPeerVerified = this.verifiedPeerResponse.length;
  1386. this.verifiedPeerResponse.forEach(function(data, key) {
  1387. if (data.valid) {
  1388. approved++
  1389. } else {
  1390. notApproved++
  1391. }
  1392. });
  1393. if (approved * 100 / countPeerVerified > 50) {
  1394. this.broadcastSendBlock(this.generateBlock())
  1395. } else {
  1396. this.node.broadcast({
  1397. message: "Approved less then 50%",
  1398. notValid: true
  1399. }, Connection.prototype.commands.PEER_NOT_VERIFIED)
  1400. }
  1401. };
  1402. BlockGenerator.prototype.generateBlock = function() {
  1403. return new Block({
  1404. id: 1
  1405. })
  1406. };
  1407. BlockGenerator.prototype.validatePeer = function(data, callback) {
  1408. var peer = data.peer,
  1409. account = data.account;
  1410. var _data = {};
  1411. Step(function getMyTransactions() {
  1412. TransactionDb.getMyTransactions(account.accountId, this)
  1413. }, function receiveTransactions(transactions) {
  1414. _data = data;
  1415. _data["valid"] = account.transactionsCount === transactions.length;
  1416. callback(_data)
  1417. })
  1418. };
  1419. BlockGenerator.prototype.comparePeers = function(oldPeer, newPeer) {
  1420. if (oldPeer === null) {
  1421. return true
  1422. }
  1423. var now = new Date().getTime(),
  1424. oldDiff = now - oldPeer.timestamp,
  1425. newDiff = now - newPeer.timestamp;
  1426. if (oldDiff > newDiff) {
  1427. return false
  1428. }
  1429. var oldPeerResponse = this.collectedPeerResponse.get(oldPeer.toString()),
  1430. newPeerResponse = this.collectedPeerResponse.get(newPeer.toString());
  1431. return oldPeerResponse.account.transactionsCount < newPeerResponse.account.transactionsCount
  1432. };
  1433. BlockGenerator.prototype.selectPeer = function() {
  1434. if (!this.running) {
  1435. logger.notice("Whe are not running");
  1436. return
  1437. }
  1438. var peerProc = this.node.peerProcessor;
  1439. var filtered = peerProc.connections.filter(function(conn, key) {
  1440. return conn.peer.status === Peer.prototype.statuses.ACTIVE && this.collectedPeerResponse.has(key)
  1441. }.bind(this));
  1442. var self = this;
  1443. async.eachSeries(filtered.toArray(), function(conn, _callback) {
  1444. var key = conn.peer.toString(),
  1445. peerResponse = self.collectedPeerResponse.get(key);
  1446. self.validatePeer(peerResponse, function(data) {
  1447. self.collectedPeerResponse.set(key, data);
  1448. _callback()
  1449. })
  1450. }, function(err) {
  1451. if (err) {
  1452. logger.error("No select peer!!!");
  1453. self.node.broadcast({
  1454. message: "No select peer!!!",
  1455. fullStop: true
  1456. }, Connection.prototype.commands.STOP_GENERATE_BLOCK);
  1457. return
  1458. }
  1459. var curPeer = null,
  1460. currPeerAccount = null;
  1461. filtered.forEach(function(conn, key) {
  1462. var peerResponse = self.collectedPeerResponse.get(key);
  1463. if (curPeer === null || peerResponse.valid && self.comparePeers(curPeer, peerResponse.peer)) {
  1464. curPeer = peerResponse.peer;
  1465. currPeerAccount = peerResponse.account
  1466. }
  1467. });
  1468. if (curPeer) {
  1469. self.selectedPeer = curPeer;
  1470. self.node.broadcast({
  1471. peer: curPeer.getData(),
  1472. account: currPeerAccount
  1473. }, Connection.prototype.commands.VERIFIED_PEER, {
  1474. peerKey: curPeer.toString()
  1475. })
  1476. } else {
  1477. logger.error("No select peer!!!");
  1478. self.node.broadcast({
  1479. message: "No select peer!!!",
  1480. fullStop: true
  1481. }, Connection.prototype.commands.STOP_GENERATE_BLOCK)
  1482. }
  1483. })
  1484. };
  1485. BlockGenerator.prototype.broadcastSendBlock = function(block) {
  1486. if (block instanceof Block) {
  1487. this.node.broadcast({
  1488. block: block.getData()
  1489. }, Connection.prototype.commands.NEW_BLOCK)
  1490. } else {
  1491. logger.error("'block' must be instance of 'models/Block'")
  1492. }
  1493. };
  1494. var DB = function() {
  1495. return {
  1496. db: new Datastore({
  1497. filename: appDir + "/db/nxtl.db",
  1498. autoload: true
  1499. }),
  1500. dbTx: new Datastore({
  1501. filename: appDir + "/db/nxtlTx.db",
  1502. autoload: true
  1503. }),
  1504. dbPeers: new Datastore({
  1505. filename: appDir + "/db/peers.db",
  1506. autoload: true
  1507. })
  1508. }
  1509. }();
  1510. var Genesis = {
  1511. genesisBlockId: "9971962888809300594",
  1512. creatorId: "7684489094182123925",
  1513. creatorPublicKey: new Buffer("03362fbbe6611243d853507a82dbe59844d169157fcda08deb171ed238fa3e19", "hex"),
  1514. genesisRecipients: ["15007997926042764084", "14302536936654097014", "4768052738330486459", "3216421205779526334", "17591617551191551229", "17629803831991308677", "17982531019448340817", "1092564458935116408", "1797803473310418787"],
  1515. genesisAmounts: [6e8, 15e7, 5e7, 5e7, 1e7, 4e7, 5e7, 3e7, 2e7],
  1516. genesisSignatures: ["d10e619bf8a9e31cd3c0ef1234d1efa40e7ab19f8a66e1ce63d065b8a992ae0f3ab0bbe032584229b9b64bbf2a1a19368a139cf52b76544fc9f7c4cfa6524475", "c687b6d33fbe1a8f4175d107e4d6bdbe3cffb5bd89aca5496c3fe0ae2e3d1b0a63278702131d59404eb6c5ca642f27a5eb8a8c68f5f70f64afe869f9fd81da2a", "d7d7b05dea2fc4371029d3d2e7a4250dd29f4a99d9eeb624c0df5155bd147e0c8597148beb1aa370c5b2dfeeaa28c9abfe0762ece014a24bb7c09370690ef963", "7520150c9d1741212d7748cc6841e554f1c89372d488026c1887b62b70a3860f5293f72274b57a64d77aad7eac220e322a0fa36f11b4f6ef58764d8b6e88229c", "2e456ec235841c8ac301e288f20b53ec2dc91ee24b94c2316c1b143a605550096d4192d7bea120a45509f23ae9aa92b16de094ddadf39d9411072e1f0045c75c", "fb0b87dbcf493a226f438ae27725237d7d828638d0a259c2e64996b8140f610f8d7cf644f51e97bc558a45adac66d57954abf7ad5eaf3e490ec6ea2da6e15800", "38af290d4a8cf743ebe14174173658cb08905827b0b68fc38aae257836d58b06b09a1bbd856c2d377f282e065951c886f607f1d3e01d970ef2c2dd9023c2f0ea", "eede7ced4d51b186bdb447e02d14e83fa1cf6ccf8e0752c2064b6d76cdca0f0b64edf1cdeedd14bcd9d4d59cfb70034cb1f28601f8ae0ef30ecc5b44aa1f9bd0", "5c4caafcca29e86b7659bcb56c93dfabb28d682d4ca1bff23e3ec25cc9d6230f86c71a36f4f74617b0beec5a5cb274e1f6577ac52b9e6d8fb7daceef3bd0dba3"],
  1517. genesisBlockSignature: "e0580c1f3feb66a9aa09ba2649f6726dca87b6db14f2dbcda368f7a2269c5604d16866925c706318ff0fdc79e1455c9b4ee88a969eb96899f54b6603a68f319f"
  1518. };
  1519. var TransactionProcessor = function() {
  1520. events.EventEmitter.call(this)
  1521. };
  1522. util.inherits(TransactionProcessor, events.EventEmitter);
  1523. TransactionProcessor.prototype.verifiyTransaction = function(transaction, unconfTransArr, callback) {
  1524. if (typeof unconfTransArr === "function") {
  1525. callback = unconfTransArr;
  1526. unconfTransArr = []
  1527. }
  1528. TransactionDb.hasTransaction(transaction.getId(), function(res) {
  1529. if (res) {
  1530. callback("Transaction " + transaction.getStringId() + " is already in the blockchain")
  1531. }
  1532.  
  1533. function validContinue() {
  1534. if (!transaction.verify()) {
  1535. callback("Signature verification failed for transaction " + transaction.getStringId())
  1536. }
  1537. if (transaction.getId().equals(new long(0))) {
  1538. callback("Invalid transaction id")
  1539. }
  1540. try {
  1541. transaction.validateAttachment()
  1542. } catch (e) {
  1543. callback(e)
  1544. }
  1545. Account.getAccounts(transaction.senderId.toString(), function(accounts) {
  1546. if (accounts == null || transaction.amount + transaction.fee > parseFloat(accounts.nxtlAccount.unconfirmedAmount)) {
  1547. callback("Not Enough money accId:" + transaction.senderId.toString())
  1548. }
  1549. callback(null)
  1550. })
  1551. }
  1552. TransactionDb.hasTransaction(transaction.referencedTransactionId.toString(), function(res) {
  1553. if (!res && transaction.referencedTransactionId != null) {
  1554. var isInUnconfTx = false;
  1555. for (var index = 0; index < unconfTransArr.length; ++index) {
  1556. var tx = unconfTransArr[index];
  1557. if (tx.id.toString() == transaction.referencedTransactionId.toString()) {
  1558. isInUnconfTx = true;
  1559. break
  1560. }
  1561. }
  1562. UnconfirmedTransactions.hasTransaction(transaction.referencedTransactionId.toString(), function(res) {
  1563. if (!res && !isInUnconfTx) {
  1564. callback("Missing referenced transaction " + transaction.referencedTransactionId.toString() + " for transaction " + transaction.getStringId())
  1565. } else {
  1566. validContinue()
  1567. }
  1568. })
  1569. } else {
  1570. validContinue()
  1571. }
  1572. })
  1573. })
  1574. };
  1575. TransactionProcessor.prototype.addTransactionOrConfirmation = function(transaction, withConfirmation) {
  1576. if (typeof withConfirmation === "undefined") {
  1577. withConfirmation = false
  1578. }
  1579. UnconfirmedTransactions.findTransaction(transaction.getId().toString(), function(resTx) {
  1580. if (resTx) {
  1581. if (resTx.confirmations < 1440) {
  1582. logger.info("Add TX confirmation txID: " + transaction.getId().toString());
  1583. UnconfirmedTransactions.addConfirmation(transaction.getId().toString())
  1584. }
  1585. } else {
  1586. logger.info("Add new TX from broadcast txID: " + transaction.getId().toString());
  1587. if (withConfirmation === true) {
  1588. transaction.confirmations += 1
  1589. } else {
  1590. transaction.confirmations = 1
  1591. }
  1592. UnconfirmedTransactions.addTransactions([transaction]);
  1593. var senderAccount = Account.addOrGetAccount(transaction.getSenderId().toString());
  1594. senderAccount.addToUnconfirmedBalance(-Utils.roundTo5Float(transaction.amount) - Utils.roundTo5Float(transaction.fee));
  1595. var recipientAccount = Account.addOrGetAccount(transaction.recipientId.toString());
  1596. recipientAccount.addToUnconfirmedBalance(Utils.roundTo5Float(transaction.amount));
  1597. var blockchain = new Blockchain();
  1598. blockchain.setLastTransaction(transaction);
  1599. logger.info("Added transaction", transaction.getId().toString());
  1600. NodeServer.broadcastNewTransaction(transaction)
  1601. }
  1602. })
  1603. };
  1604. var TransactionType = function() {};
  1605. TransactionType.TYPE_PAYMENT = 0;
  1606. TransactionType.TYPE_MESSAGING = 1;
  1607. TransactionType.TYPE_COLORED_COINS = 2;
  1608. TransactionType.SUBTYPE_PAYMENT_ORDINARY_PAYMENT = 0;
  1609. TransactionType.SUBTYPE_MESSAGING_ARBITRARY_MESSAGE = 0;
  1610. TransactionType.SUBTYPE_MESSAGING_ALIAS_ASSIGNMENT = 1;
  1611. TransactionType.SUBTYPE_MESSAGING_POLL_CREATION = 2;
  1612. TransactionType.SUBTYPE_MESSAGING_VOTE_CASTING = 3;
  1613. TransactionType.SUBTYPE_COLORED_COINS_ASSET_ISSUANCE = 0;
  1614. TransactionType.SUBTYPE_COLORED_COINS_ASSET_TRANSFER = 1;
  1615. TransactionType.SUBTYPE_COLORED_COINS_ASK_ORDER_PLACEMENT = 2;
  1616. TransactionType.SUBTYPE_COLORED_COINS_BID_ORDER_PLACEMENT = 3;
  1617. TransactionType.SUBTYPE_COLORED_COINS_ASK_ORDER_CANCELLATION = 4;
  1618. TransactionType.SUBTYPE_COLORED_COINS_BID_ORDER_CANCELLATION = 5;
  1619. TransactionType.findTransactionType = function(type, subtype) {
  1620. switch (type) {
  1621. case TransactionType.TYPE_PAYMENT:
  1622. switch (subtype) {
  1623. case TransactionType.SUBTYPE_PAYMENT_ORDINARY_PAYMENT:
  1624. return TransactionType.Payment;
  1625. default:
  1626. return null
  1627. }
  1628. default:
  1629. return null
  1630. }
  1631. };
  1632. TransactionType.Payment = function() {};
  1633. TransactionType.Payment.getType = function() {
  1634. return TransactionType.TYPE_PAYMENT
  1635. };
  1636. TransactionType.Payment.getSubtype = function() {
  1637. return TransactionType.SUBTYPE_PAYMENT_ORDINARY_PAYMENT
  1638. };
  1639. TransactionType.Payment.loadAttachment = function(transaction, buffer) {
  1640. TransactionType.Payment.validateAttachment(transaction)
  1641. };
  1642. TransactionType.Payment.loadAttachment = function(transaction, attachmentData) {
  1643. TransactionType.Payment.validateAttachment(transaction)
  1644. };
  1645. TransactionType.Payment.applyAttachmentUnconfirmed = function(transaction, senderAccount) {
  1646. return true
  1647. };
  1648. TransactionType.Payment.applyAttachment = function(transaction, senderAccount, recipientAccount) {
  1649. recipientAccount.addToBalanceAndUnconfirmedBalance(transaction.amount)
  1650. };
  1651. TransactionType.Payment.undoAttachment = function(transaction, senderAccount, recipientAccount) {
  1652. recipientAccount.addToBalanceAndUnconfirmedBalance(-transaction.amount)
  1653. };
  1654. TransactionType.Payment.undoAttachmentUnconfirmed = function(transaction, senderAccount) {};
  1655. TransactionType.Payment.isDuplicate = function(transaction, duplicates) {
  1656. return false
  1657. };
  1658. TransactionType.Payment.updateTotals = function(transaction, accumulatedAmounts, accumulatedAssetQuantities, accumulatedAmount) {};
  1659. TransactionType.Payment.validateAttachment = function(transaction) {
  1660. if (transaction.amount <= 0 || transaction.amount >= Config.MAX_BALANCE) {
  1661. throw new Error("Invalid ordinary payment: " + transaction.attachment.getJSON())
  1662. }
  1663. };
  1664. var Blockchain = function() {
  1665. var lastBlock = null;
  1666. var lastTransaction = null;
  1667. this.getBlock = function(blockId) {};
  1668. this.setLastTransaction = function(transaction) {
  1669. lastTransaction = transaction
  1670. };
  1671. this.getLastTransaction = function() {
  1672. return lastTransaction
  1673. };
  1674. this.setLastBlock = function(block) {
  1675. lastBlock = block
  1676. };
  1677. this.getLastBlock = function() {
  1678. return lastBlock
  1679. };
  1680. this.getAllBlocks = function(callback) {};
  1681. this.getAllTransactions = function(callback) {};
  1682. if (Blockchain.instance) {
  1683. return Blockchain.instance
  1684. }
  1685. Blockchain.instance = this
  1686. };
  1687. var BlockchainProcessor = function() {
  1688. events.EventEmitter.call(this)
  1689. };
  1690. util.inherits(BlockchainProcessor, events.EventEmitter);
  1691. BlockchainProcessor.run = function(callback) {
  1692. Account.addOrGetAccount("7684489094182123925");
  1693. BlockchainProcessor.addGenesisBlock(function() {
  1694. scan(function() {
  1695. logger.info("blockchain run end");
  1696. if (typeof callback == "function") {
  1697. callback()
  1698. }
  1699. })
  1700. })
  1701. };
  1702. BlockchainProcessor.addGenesisBlock = function(callback) {
  1703. BlockDb.hasBlock(Genesis.genesisBlockId, function(has) {
  1704. if (has) {
  1705. logger.info("Genesis block already in database");
  1706. if (typeof callback === "function") {
  1707. callback()
  1708. }
  1709. } else {
  1710. logger.info("Genesis block not in database, starting from scratch");
  1711. try {
  1712. var transactionsMap = {
  1713. count: 0
  1714. };
  1715. for (var i = 0; i < Genesis.genesisRecipients.length; i++) {
  1716. var transaction = new Transaction({
  1717. type: TransactionType.Payment,
  1718. timestamp: 0,
  1719. deadline: 0,
  1720. senderPublicKey: Genesis.creatorPublicKey,
  1721. recipientId: Genesis.genesisRecipients[i],
  1722. amount: Genesis.genesisAmounts[i],
  1723. fee: 0,
  1724. referencedTransactionId: 0,
  1725. signature: Genesis.genesisSignatures[i]
  1726. });
  1727. transactionsMap[transaction.getId().toString()] = transaction;
  1728. transactionsMap.count++
  1729. }
  1730. var digest = crypto.createHash("sha256");
  1731. for (var transactionId in transactionsMap) {
  1732. if (transactionsMap.hasOwnProperty(transactionId) && transactionId != "count") {
  1733. transaction = transactionsMap[transactionId];
  1734. digest.update(transaction.getBytes())
  1735. }
  1736. }
  1737. var genesisBlock = new Block({
  1738. version: -1,
  1739. timestamp: 0,
  1740. previousBlockId: null,
  1741. totalAmount: 1e9,
  1742. totalFee: 0,
  1743. payloadLength: transactionsMap.count * 128,
  1744. payloadHash: digest.digest(),
  1745. generatorPublicKey: Genesis.creatorPublicKey,
  1746. generationSignature: Config.NULL_HASH,
  1747. blockSignature: Genesis.genesisBlockSignature,
  1748. previousBlockHash: null,
  1749. blockTransactions: transactionsMap
  1750. });
  1751. genesisBlock.setPrevious(null);
  1752. logger.info("genesisBlock.verifyBlockSignature()", genesisBlock.verifyBlockSignature());
  1753. BlockchainProcessor.addBlock(genesisBlock, true);
  1754. if (typeof callback === "function") {
  1755. callback()
  1756. }
  1757. } catch (e) {
  1758. logger.error(e.stack ? e.stack : e.toString());
  1759. throw new Error(e)
  1760. }
  1761. }
  1762. })
  1763. };
  1764. BlockchainProcessor.generateBlock = function(secretPhrase) {
  1765. try {
  1766. UnconfirmedTransactions.getAll(function(transactionsArr) {
  1767. if (transactionsArr.count > 0) {
  1768. var totalFee = 0;
  1769. var totalAmount = 0;
  1770. var digest = crypto.createHash("sha256");
  1771. for (var transactionId in transactionsArr) {
  1772. if (transactionsArr.hasOwnProperty(transactionId) && transactionId != "count") {
  1773. var transaction = transactionsArr[transactionId];
  1774. digest.update(transaction.getBytes());
  1775. totalAmount += Utils.roundTo5Float(transaction.amount);
  1776. totalFee += Utils.roundTo5Float(transaction.fee)
  1777. }
  1778. }
  1779. var blockchain = new Blockchain();
  1780. var previousBlock = blockchain.getLastBlock();
  1781. var previousBlockHash = Utils.sha256(previousBlock.getBytes());
  1782. var generatorPublicKey = nxtCrypto.getPublicKey(secretPhrase);
  1783. var generationSignature = null;
  1784. if (previousBlock.height < Config.TRANSPARENT_FORGING_BLOCK) {
  1785. generationSignature = nxtCrypto.sign(previousBlock.generationSignature.toString("hex"), secretPhrase)
  1786. } else {
  1787. digest.update(previousBlock.generationSignature);
  1788. digest.update(generatorPublicKey);
  1789. generationSignature = digest.digest()
  1790. }
  1791. var block = new Block({
  1792. version: 1,
  1793. timestamp: new Date().getTime(),
  1794. previousBlockId: previousBlock.id,
  1795. totalAmount: Utils.roundTo5Float(totalAmount),
  1796. totalFee: Utils.roundTo5Float(totalFee),
  1797. payloadLength: transactionsArr.length * 128,
  1798. payloadHash: digest.digest(),
  1799. generatorPublicKey: generatorPublicKey,
  1800. generationSignature: generationSignature,
  1801. blockSignature: null,
  1802. previousBlockHash: previousBlockHash,
  1803. blockTransactions: transactionsArr
  1804. });
  1805. block.sign(secretPhrase);
  1806. block.setPrevious(previousBlock);
  1807. logger.info("Generating block", block.getId().toString());
  1808. try {
  1809. logger.info(block.verifyBlockSignature());
  1810. block.verifyGenerationSignature(function(res) {
  1811. logger.info(res)
  1812. });
  1813. if (block.verifyBlockSignature()) {
  1814. block.verifyGenerationSignature(function(res) {
  1815. if (!res) {
  1816. logger.error("Account " + block.getGeneratorId() + " generated an incorrect block.")
  1817. }
  1818. BlockchainProcessor.pushBlock(block, function() {
  1819. BlockDb.setNextBlockId(previousBlock.getId().toString(), block.getId().toString(), function() {
  1820. BlockchainProcessor.addBlock(block, false)
  1821. })
  1822. });
  1823. logger.info("Account " + block.getGeneratorId() + " generated block " + block.getStringId())
  1824. })
  1825. } else {
  1826. logger.error("Account " + block.getGeneratorId() + " generated an incorrect block.")
  1827. }
  1828. } catch (err) {
  1829. logger.error("BlockchainProcessor.generateBlock error");
  1830. logger.error(err.toString())
  1831. }
  1832. } else {
  1833. logger.info("No new transactions to generate block.")
  1834. }
  1835. })
  1836. } catch (e) {
  1837. logger.error("Create block ERROR:", e);
  1838. throw new Error(e)
  1839. }
  1840. };
  1841. BlockchainProcessor.pushBlock = function(block, _callback) {
  1842. var curTime = new Date().getTime();
  1843. var blockchain = new Blockchain();
  1844. var previousLastBlock = blockchain.getLastBlock();
  1845. if (previousLastBlock.getId().toString() != block.previousBlockId.toString()) {
  1846. throw new Error("Previous block id doesn't match")
  1847. }
  1848. if (Utils.sha256(previousLastBlock.getBytes()).toString("hex") != block.previousBlockHash.toString("hex")) {
  1849. throw new Error("Previous block hash doesn't match")
  1850. }
  1851. if (parseInt(block.timestamp) > curTime + 15 || parseInt(block.timestamp) <= parseInt(previousLastBlock.timestamp)) {
  1852. throw new Error("Invalid timestamp: " + block.timestamp + " current time is " + curTime + ", previous block timestamp is " + previousLastBlock.timestamp)
  1853. }
  1854. if (block.getId().equals(long.fromInt(0))) {
  1855. throw new Error("Invalid id")
  1856. }
  1857. BlockDb.hasBlock(block.getId(), function(res) {
  1858. if (res) {
  1859. throw new Error("Duplicate ID")
  1860. }
  1861. if (!block.verifyBlockSignature()) {
  1862. throw new Error("Signature verifyBlockSignature verification failed")
  1863. }
  1864. block.verifyGenerationSignature(function(res) {
  1865. if (!res) {
  1866. throw new Error("Signature verifyGenerationSignature verification failed")
  1867. }
  1868. var calculatedTotalAmount = 0,
  1869. calculatedTotalFee = 0,
  1870. duplicates = null,
  1871. accumulatedAmounts = {},
  1872. accumulatedAssetQuantities = null,
  1873. digest = crypto.createHash("sha256");
  1874. var transactionsArr = block.getTransactionsAsArray();
  1875. async.eachSeries(transactionsArr, function(transaction, callback) {
  1876. if (transaction.getExpiration() < block.timestamp) {
  1877. callback("Invalid transaction timestamp " + transaction.timestamp + " for transaction " + transaction.getStringId() + ", current time is " + curTime + ", block timestamp is " + block.timestamp)
  1878. }
  1879. TransactionDb.hasTransaction(transaction.getId(), function(res) {
  1880. if (res) {
  1881. callback("Transaction " + transaction.getStringId() + " is already in the blockchain")
  1882. }
  1883. TransactionDb.hasTransaction(transaction.referencedTransactionId.toString(), function(res) {
  1884. if (!res && transaction.referencedTransactionId != null && block.getTransactionIds().indexOf(transaction.referencedTransactionId.toString()) === -1) {
  1885. callback("Missing referenced transaction " + transaction.referencedTransactionId.toString() + " for transaction " + transaction.getStringId())
  1886. }
  1887. if (!transaction.verify()) {
  1888. callback("Signature verification failed for transaction " + transaction.getStringId())
  1889. }
  1890. if (transaction.getId().equals(new long(0))) {
  1891. callback("Invalid transaction id")
  1892. }
  1893. if (transaction.isDuplicate(duplicates)) {
  1894. callback("Transaction is a duplicate: " + transaction.getStringId())
  1895. }
  1896. try {
  1897. transaction.validateAttachment()
  1898. } catch (e) {
  1899. callback(e)
  1900. }
  1901. calculatedTotalAmount += Utils.roundTo5Float(transaction.amount);
  1902. transaction.updateTotals(accumulatedAmounts, accumulatedAssetQuantities);
  1903. calculatedTotalFee += Utils.roundTo5Float(transaction.fee);
  1904. digest.update(transaction.getBytes());
  1905. callback()
  1906. })
  1907. })
  1908. }, function(err) {
  1909. if (err) {
  1910. logger.error(err);
  1911. throw new Error(err)
  1912. } else {
  1913. logger.info("All transactions passed async verification");
  1914. if (Utils.roundTo5Float(calculatedTotalAmount) != Utils.roundTo5Float(block.totalAmount) || Utils.roundTo5Float(calculatedTotalFee) != Utils.roundTo5Float(block.totalFee)) {
  1915. throw new Error("Total amount or fee don't match transaction totals")
  1916. }
  1917. var digestStr = digest.digest().toString("hex");
  1918. if (digestStr != block.payloadHash.toString("hex")) {
  1919. logger.error("Payload hash doesn't match block ID: " + block.id.toString());
  1920. throw new Error("Payload hash doesn't match")
  1921. }
  1922. var accumulatedAmountsArr = [];
  1923. for (var accumulatedAmountEntryId in accumulatedAmounts) {
  1924. if (accumulatedAmounts.hasOwnProperty(accumulatedAmountEntryId)) {
  1925. accumulatedAmountsArr.push({
  1926. key: accumulatedAmountEntryId,
  1927. amount: accumulatedAmounts[accumulatedAmountEntryId]
  1928. })
  1929. }
  1930. }
  1931. async.each(accumulatedAmountsArr, function(accumulatedAmountEntry, callback) {
  1932. var senderAccount = Account.getAccounts(accumulatedAmountEntry.key, function(senderAccauntNums) {
  1933. if (senderAccauntNums.nxtlAccount.amount < accumulatedAmountEntry.amount) {
  1934. callback("Not enough funds in sender account: " + Convert.toUnsignedLong(senderAccount.getId()))
  1935. } else {
  1936. callback()
  1937. }
  1938. })
  1939. }, function(err) {
  1940. if (err) {
  1941. throw new Error(err)
  1942. }
  1943. if (typeof _callback === "function") {
  1944. _callback()
  1945. }
  1946. })
  1947. }
  1948. })
  1949. })
  1950. })
  1951. };
  1952. BlockchainProcessor.checkExistBlock = function(block, _callback) {
  1953. function blockTransactionsCheck() {
  1954. var txs = block.getTransactionsAsArray();
  1955. async.each(txs, function(transaction, callback) {
  1956. BlockchainProcessor.checkExistTransaction(transaction, callback)
  1957. }, function(err) {
  1958. if (err) {
  1959. _callback(err)
  1960. } else {
  1961. _callback(null)
  1962. }
  1963. })
  1964. }
  1965. if (!block.verifyBlockSignature()) {
  1966. _callback("Signature verifyBlockSignature verification failed: block height " + block.height);
  1967. return
  1968. }
  1969. if (parseInt(block.version) > 0) {
  1970. var prevHeight = block.height - 1;
  1971. BlockDb.findBlockIdAtHeight(prevHeight, function(prevBlock) {
  1972. if (!prevBlock) {
  1973. _callback("Error no prev block find: block height " + block.height)
  1974. } else {
  1975. if (prevBlock.getId().toString() != block.previousBlockId.toString()) {
  1976. _callback("Previous block id doesn't match: block height " + block.height);
  1977. return
  1978. }
  1979. if (Utils.sha256(prevBlock.getBytes()).toString("hex") != block.previousBlockHash.toString("hex")) {
  1980. _callback("Previous block hash doesn't match: block height " + block.height);
  1981. return
  1982. }
  1983. block.verifyGenerationSignature(function(res) {
  1984. if (!res) {
  1985. _callback("Signature verifyGenerationSignature verification failed: block height " + block.height)
  1986. } else {
  1987. blockTransactionsCheck()
  1988. }
  1989. })
  1990. }
  1991. })
  1992. } else {
  1993. blockTransactionsCheck()
  1994. }
  1995. };
  1996. BlockchainProcessor.checkExistTransaction = function(tx, _callback) {
  1997. function txVerify(tx, _callback) {
  1998. if (!tx.verify()) {
  1999. _callback("Signature verification failed for transaction " + transaction.getStringId());
  2000. return
  2001. }
  2002. if (tx.getId().equals(new long(0))) {
  2003. _callback("Invalid transaction id");
  2004. return
  2005. }
  2006. _callback()
  2007. }
  2008. if (tx.blockId.toString() == Genesis.genesisBlockId) {
  2009. txVerify(tx, _callback);
  2010. return
  2011. }
  2012. TransactionDb.hasTransaction(tx.referencedTransactionId.toString(), function(res) {
  2013. if (!res) {
  2014. _callback("Wrong referenced transaction ID");
  2015. return
  2016. } else {
  2017. txVerify(tx, _callback)
  2018. }
  2019. })
  2020. };
  2021.  
  2022. function scan(_callback) {
  2023. logger.info("Scanning blockchain...");
  2024. var blockchain = new Blockchain();
  2025. async.waterfall([
  2026. function(callback) {
  2027. BlockDb.getLastBlock(function(res) {
  2028. blockchain.setLastBlock(res);
  2029. logger.info("Last block set on height " + res.height);
  2030. callback()
  2031. })
  2032. },
  2033. function(callback) {
  2034. TransactionDb.getLastTransaction(function(res) {
  2035. blockchain.setLastTransaction(res);
  2036. logger.info("Last Transaction id is " + res.id)
  2037. });
  2038. callback()
  2039. },
  2040. function(callback) {
  2041. var curHeight = 0;
  2042. var lastHeight = blockchain.getLastBlock().height;
  2043. BlockDb.getAllBlockList(function(blocks) {
  2044. if (!blocks) {
  2045. throw Error("No block finded at height " + curHeight)
  2046. }
  2047. async.eachSeries(blocks, function(blockData, _callback) {
  2048. var block = new Block(blockData);
  2049. BlockDb.findRelatedTransactions(block, function(block) {
  2050. BlockchainProcessor.checkExistBlock(block, function(err) {
  2051. if (err) {
  2052. _callback(err)
  2053. } else {
  2054. block.addConfirmedAndUnconfirmedAmounts();
  2055. setImmediate(function() {
  2056. _callback()
  2057. })
  2058. }
  2059. })
  2060. })
  2061. }, function(err) {
  2062. if (err) {
  2063. callback(err)
  2064. } else {
  2065. callback(null)
  2066. }
  2067. })
  2068. })
  2069. }
  2070. ], function(err, result) {
  2071. if (err) {
  2072. logger.error("Scan blockchain ERROR", err);
  2073. throw new Error(err)
  2074. }
  2075. if (typeof _callback == "function") {
  2076. _callback()
  2077. }
  2078. });
  2079. logger.info("...Scanning blockchain done")
  2080. }
  2081. BlockchainProcessor.addBlock = function(block, withoutBalanceChange, callback) {
  2082. BlockDb.saveBlock(block, function() {
  2083. if (typeof withoutBalanceChange === "undefined" || !withoutBalanceChange) {
  2084. block.addConfirmedAmounts();
  2085. block.addUnconfirmedFee()
  2086. }
  2087. var blockchain = new Blockchain();
  2088. blockchain.setLastBlock(block);
  2089. block.removeUnconfirmedTxs();
  2090. NodeServer.broadcastNewBlock(block);
  2091. if (typeof callback === "function") {
  2092. callback()
  2093. }
  2094. })
  2095. };
  2096. var Nxtl = function() {};
  2097. Nxtl.getBlockchain = function() {
  2098. return new Blockchain()
  2099. };
  2100. var BlockDb = function() {};
  2101. BlockDb.getLastBlock = function(callback) {
  2102. var q = {
  2103. tbl: "block"
  2104. };
  2105. DB.dbTx.find(q).limit(1).sort({
  2106. height: -1
  2107. }).exec(function(err, docs) {
  2108. if (!err) {
  2109. if (typeof callback === "function") {
  2110. if (docs.length > 0) {
  2111. var block = new Block(docs[0]);
  2112. BlockDb.findRelatedTransactions(block, callback)
  2113. } else {
  2114. callback(null)
  2115. }
  2116. }
  2117. } else {
  2118. logger.info("Find BlockTransactions ERROR!!!", err)
  2119. }
  2120. })
  2121. };
  2122. BlockDb.getAllBlockList = function(callback) {
  2123. var q = {
  2124. tbl: "block"
  2125. };
  2126. DB.dbTx.find(q).sort({
  2127. height: 1
  2128. }).exec(function(err, docs) {
  2129. if (!err) {
  2130. if (typeof callback === "function") {
  2131. callback(docs)
  2132. }
  2133. } else {
  2134. logger.info("Find BlockTransactions ERROR!!!", err);
  2135. callback(false)
  2136. }
  2137. })
  2138. };
  2139. BlockDb.getLastBlocksList = function(n, callback) {
  2140. var q = {
  2141. tbl: "block"
  2142. };
  2143. DB.dbTx.find(q).limit(n).sort({
  2144. height: -1
  2145. }).exec(function(err, docs) {
  2146. if (!err) {
  2147. if (typeof callback === "function") {
  2148. callback(docs)
  2149. }
  2150. } else {
  2151. logger.info("Find BlockTransactions ERROR!!!", err);
  2152. callback(false)
  2153. }
  2154. })
  2155. };
  2156. BlockDb.findRelatedTransactions = function(block, callback) {
  2157. TransactionDb.findBlockTransactions(block.id.toString(), function(txs) {
  2158. if (txs === null) {
  2159. txs = {
  2160. count: 0
  2161. }
  2162. }
  2163. block.blockTransactions = txs;
  2164. callback(block)
  2165. })
  2166. };
  2167. BlockDb.findBlock = function(blockId, callback) {
  2168. var q = {
  2169. id: blockId,
  2170. tbl: "block"
  2171. };
  2172. DB.dbTx.find(q, function(err, docs) {
  2173. if (!err) {
  2174. if (typeof callback === "function") {
  2175. var block = false;
  2176. if (docs.length > 0) {
  2177. block = new Block(docs[0]);
  2178. BlockDb.findRelatedTransactions(block, callback)
  2179. } else {
  2180. callback(block)
  2181. }
  2182. }
  2183. } else {
  2184. logger.info("Find BlockTransactions ERROR!!!", err)
  2185. }
  2186. })
  2187. };
  2188. BlockDb.hasBlock = function(blockId, callback) {
  2189. var q = {
  2190. id: blockId,
  2191. tbl: "block"
  2192. };
  2193. DB.dbTx.find(q, function(err, docs) {
  2194. if (!err) {
  2195. if (typeof callback === "function") {
  2196. if (docs.length > 0) {
  2197. callback(true)
  2198. } else {
  2199. callback(false)
  2200. }
  2201. }
  2202. } else {
  2203. logger.info("Find transaction ERROR!!!", err)
  2204. }
  2205. })
  2206. };
  2207. BlockDb.findBlockIdAtHeight = function(height, callback) {
  2208. var q = {
  2209. height: height,
  2210. tbl: "block"
  2211. };
  2212. DB.dbTx.find(q, function(err, docs) {
  2213. if (!err) {
  2214. if (typeof callback === "function") {
  2215. var block = false;
  2216. if (docs.length > 0) {
  2217. block = new Block(docs[0]);
  2218. BlockDb.findRelatedTransactions(block, callback)
  2219. } else {
  2220. callback(block)
  2221. }
  2222. }
  2223. } else {
  2224. logger.info("Find BlockTransactions ERROR!!!", err);
  2225. callback(false)
  2226. }
  2227. })
  2228. };
  2229. BlockDb.findBlockByRs = function(rs, callback) {
  2230. rs.tbl = "block";
  2231. DB.dbTx.find(rs, function(err, docs) {
  2232. if (!err) {
  2233. if (typeof callback === "function") {
  2234. var block = false;
  2235. if (docs.length > 0) {
  2236. block = new Block(docs[0]);
  2237. BlockDb.findRelatedTransactions(block, callback)
  2238. } else {
  2239. callback(block)
  2240. }
  2241. }
  2242. } else {
  2243. logger.info("Find transaction ERROR!!!", err)
  2244. }
  2245. })
  2246. };
  2247. BlockDb.saveBlock = function(block, callback) {
  2248. if (block instanceof Block) {
  2249. var tmpBlock = block.getData();
  2250. tmpBlock.tbl = "block";
  2251. if (block.blockTransactions.count > 0 || block.blockTransactions.length > 0) {
  2252. TransactionDb.deleteTransactions(block.blockTransactions);
  2253. UnconfirmedTransactions.deleteTransactions(block.blockTransactions);
  2254. TransactionDb.saveTransactions(block.blockTransactions)
  2255. }
  2256. DB.dbTx.insert(tmpBlock, function(err, newDoc) {
  2257. if (err) {
  2258. logger.info("Transaction insert ERROR", err)
  2259. } else {
  2260. if (typeof callback === "function") {
  2261. callback()
  2262. }
  2263. }
  2264. })
  2265. }
  2266. };
  2267. BlockDb.setNextBlockId = function(blockId, nextBlockId, callback) {
  2268. if (blockId === 0) {
  2269. callback()
  2270. } else {
  2271. DB.dbTx.update({
  2272. id: blockId,
  2273. tbl: "block"
  2274. }, {
  2275. $set: {
  2276. nextBlockId: nextBlockId
  2277. }
  2278. }, {}, function(err, numReplaced) {
  2279. if (err) {
  2280. logger.info("setNextBlockId error")
  2281. } else {
  2282. if (typeof callback === "function") {
  2283. callback(numReplaced)
  2284. }
  2285. }
  2286. })
  2287. }
  2288. };
  2289. BlockDb.deleteBlockAtHeight = function(height, callback) {
  2290. height = parseInt(height);
  2291. DB.dbTx.remove({
  2292. height: height
  2293. }, {
  2294. multi: true
  2295. }, function(err, numRemoved) {
  2296. if (typeof callback === "function") {
  2297. if (err) {
  2298. callback(err)
  2299. } else {
  2300. callback(numRemoved)
  2301. }
  2302. }
  2303. })
  2304. };
  2305. BlockDb.deleteAll = function() {
  2306. DB.dbTx.remove({}, {}, function(err, numRemoved) {
  2307. if (err) {
  2308. logger.info("Error drop DB", err)
  2309. }
  2310. })
  2311. };
  2312. BlockDb.addConfirmation = function(blockId, callback) {
  2313. var q = {
  2314. id: blockId,
  2315. tbl: "block"
  2316. };
  2317. DB.dbTx.find(q, function(err, docs) {
  2318. if (!err) {
  2319. if (typeof callback === "function") {
  2320. var block = false;
  2321. if (docs.length > 0) {
  2322. block = docs[0];
  2323. var confirmations = block.confirmations + 1;
  2324. DB.dbTx.update(q, {
  2325. $set: {
  2326. confirmations: confirmations
  2327. }
  2328. }, {}, function() {
  2329. callback()
  2330. })
  2331. } else {
  2332. callback(false)
  2333. }
  2334. }
  2335. } else {
  2336. logger.info("Find BlockTransactions ERROR!!!", err);
  2337. callback(err)
  2338. }
  2339. })
  2340. };
  2341. var PeersDb = function() {};
  2342. PeersDb.addPeer = function(peer, callback) {
  2343. var peerTmp = peer.getData();
  2344. peerTmp.id = peer.host + ":" + peer.port;
  2345. DB.dbPeers.insert(peerTmp, function(err, newDoc) {
  2346. if (err) {
  2347. logger.error("Peer insert ERROR", err)
  2348. } else {
  2349. logger.DBdbg("PeersDb.addPeer ok: " + peerTmp.id);
  2350. if (typeof callback === "function") {
  2351. callback(newDoc)
  2352. }
  2353. }
  2354. })
  2355. };
  2356. PeersDb.addReplacePeer = function(peer, callback) {
  2357. var peerTmp = peer.getData();
  2358. peerTmp.id = peer.host + ":" + peer.port;
  2359. DB.dbPeers.update({
  2360. id: peerTmp.id
  2361. }, peerTmp, {}, function(err, numReplaced) {
  2362. if (err) {
  2363. logger.error("Peer insert ERROR", err)
  2364. } else {
  2365. logger.DBdbg("PeersDb.addReplacePeer " + peerTmp.id + " numReplaced " + numReplaced);
  2366. if (numReplaced > 0) {
  2367. if (typeof callback === "function") {
  2368. callback(numReplaced)
  2369. }
  2370. } else {
  2371. PeersDb.addPeer(peer, callback)
  2372. }
  2373. }
  2374. })
  2375. };
  2376. PeersDb.getAllPeersList = function(callback) {
  2377. var q = {};
  2378. PeersDb.getPeersListByRs(q, callback)
  2379. };
  2380. PeersDb.getPeersListByRs = function(q, callback) {
  2381. DB.dbPeers.find(q, function(err, docs) {
  2382. if (!err) {
  2383. if (typeof callback === "function") {
  2384. callback(docs)
  2385. }
  2386. } else {
  2387. logger.error("Find Peer ERROR!!!", err)
  2388. }
  2389. })
  2390. };
  2391. var TransactionDb = function() {};
  2392. TransactionDb.getLastTransaction = function(callback) {
  2393. var q = {
  2394. tbl: "transaction"
  2395. };
  2396. DB.dbTx.find(q).limit(1).sort({
  2397. timestamp: -1,
  2398. id: -1
  2399. }).exec(function(err, docs) {
  2400. if (!err) {
  2401. if (typeof callback === "function") {
  2402. var transaction = false;
  2403. if (docs.length > 0) {
  2404. transaction = new Transaction(docs[0])
  2405. }
  2406. callback(transaction)
  2407. }
  2408. } else {
  2409. logger.info("Find transaction ERROR!!!", err)
  2410. }
  2411. })
  2412. };
  2413. TransactionDb.getLastTransactions = function(n, callback) {
  2414. var q = {
  2415. tbl: "transaction"
  2416. };
  2417. DB.dbTx.find(q).limit(n).sort({
  2418. timestamp: -1,
  2419. id: -1
  2420. }).exec(function(err, docs) {
  2421. if (!err) {
  2422. if (typeof callback === "function") {
  2423. if (docs.length > 0) {
  2424. callback(docs)
  2425. } else {
  2426. callback(null)
  2427. }
  2428. }
  2429. } else {
  2430. logger.info("Find transaction ERROR!!!", err)
  2431. }
  2432. })
  2433. };
  2434. TransactionDb.getUnconfirmedTransactions = function(callback) {
  2435. var q = {
  2436. blockId: null,
  2437. tbl: "transaction"
  2438. };
  2439. DB.dbTx.find(q).sort({
  2440. timestamp: 1
  2441. }).exec(function(err, docs) {
  2442. if (!err) {
  2443. if (typeof callback === "function") {
  2444. var transactionsMap = false;
  2445. if (docs.length > 0) {
  2446. transactionsMap = {
  2447. count: 0
  2448. };
  2449. for (var i in docs) {
  2450. transactionsMap[docs[i].id] = new Transaction(docs[i]);
  2451. transactionsMap.count++
  2452. }
  2453. }
  2454. callback(transactionsMap)
  2455. }
  2456. } else {
  2457. logger.info("Find BlockTransactions ERROR!!!", err)
  2458. }
  2459. })
  2460. };
  2461. TransactionDb.getMyTransactions = function(_accountId, callback) {
  2462. var q = {
  2463. $or: [{
  2464. recipientId: _accountId
  2465. }, {
  2466. senderId: _accountId
  2467. }],
  2468. $not: {
  2469. blockId: null
  2470. },
  2471. type: TransactionType.TYPE_PAYMENT,
  2472. tbl: "transaction"
  2473. };
  2474. TransactionDb.getTransactionsListByRs(q, callback)
  2475. };
  2476. TransactionDb.getMyAllTransactions = function(_accountId, callback) {
  2477. var q = {
  2478. $or: [{
  2479. recipientId: _accountId
  2480. }, {
  2481. senderId: _accountId
  2482. }],
  2483. type: TransactionType.TYPE_PAYMENT,
  2484. tbl: "transaction"
  2485. };
  2486. DB.dbTx.find(q).sort({
  2487. timestamp: -1,
  2488. id: -1
  2489. }).exec(function(err, docs) {
  2490. if (!err) {
  2491. if (typeof callback === "function") {
  2492. callback(docs)
  2493. }
  2494. } else {
  2495. logger.info("Find BlockTransactions ERROR!!!", err)
  2496. }
  2497. })
  2498. };
  2499. TransactionDb.getAllTransactionsList = function(callback) {
  2500. var q = {
  2501. tbl: "transaction"
  2502. };
  2503. TransactionDb.getTransactionsListByRs(q, callback)
  2504. };
  2505. TransactionDb.getTransactionsListByRs = function(q, callback) {
  2506. DB.dbTx.find(q, function(err, docs) {
  2507. if (!err) {
  2508. if (typeof callback === "function") {
  2509. callback(docs)
  2510. }
  2511. } else {
  2512. logger.info("Find BlockTransactions ERROR!!!", err)
  2513. }
  2514. })
  2515. };
  2516. TransactionDb.findTransaction = function(transactionId, callback) {
  2517. var q = {
  2518. id: transactionId,
  2519. tbl: "transaction"
  2520. };
  2521. DB.dbTx.find(q, function(err, docs) {
  2522. if (!err) {
  2523. if (typeof callback === "function") {
  2524. var transaction = false;
  2525. if (docs.length > 0) {
  2526. transaction = new Transaction(docs[0])
  2527. }
  2528. callback(transaction)
  2529. }
  2530. } else {
  2531. logger.info("Find transaction ERROR!!!", err)
  2532. }
  2533. })
  2534. };
  2535. TransactionDb.hasTransaction = function(transactionId, callback) {
  2536. var q = {
  2537. id: transactionId,
  2538. tbl: "transaction"
  2539. };
  2540. DB.dbTx.find(q, function(err, docs) {
  2541. if (!err) {
  2542. if (typeof callback === "function") {
  2543. if (docs.length > 0) {
  2544. callback(true)
  2545. } else {
  2546. callback(false)
  2547. }
  2548. }
  2549. } else {
  2550. logger.info("Find transaction ERROR!!!", err)
  2551. }
  2552. })
  2553. };
  2554. TransactionDb.findTransactionByRs = function(rs, callback) {
  2555. rs.tbl = "transaction";
  2556. DB.dbTx.find(rs, function(err, docs) {
  2557. if (!err) {
  2558. if (typeof callback === "function") {
  2559. var transaction = false;
  2560. if (docs.length > 0) {
  2561. transaction = new Transaction(docs[0])
  2562. }
  2563. callback(transaction)
  2564. }
  2565. } else {
  2566. logger.info("Find transaction ERROR!!!", err)
  2567. }
  2568. })
  2569. };
  2570. TransactionDb.findBlockTransactions = function(blockId, callback) {
  2571. var q = {
  2572. blockId: blockId,
  2573. tbl: "transaction"
  2574. };
  2575. DB.dbTx.find(q).sort({
  2576. timestamp: 1
  2577. }).exec(function(err, docs) {
  2578. if (!err) {
  2579. if (typeof callback === "function") {
  2580. var transactionsMap = {
  2581. count: 0
  2582. };
  2583. if (docs.length > 0) {
  2584. for (var i in docs) {
  2585. transactionsMap[docs[i].id] = new Transaction(docs[i]);
  2586. transactionsMap.count++
  2587. }
  2588. }
  2589. callback(transactionsMap)
  2590. }
  2591. } else {
  2592. logger.info("Find BlockTransactions ERROR!!!", err);
  2593. callback(null)
  2594. }
  2595. })
  2596. };
  2597. TransactionDb.saveTransactions = function(transactions) {
  2598. for (var i in transactions) {
  2599. if (!transactions.hasOwnProperty(i) || i == "count") {
  2600. continue
  2601. }
  2602. var transaction = transactions[i];
  2603. var transactionTmp = transaction.getData();
  2604. transactionTmp.tbl = "transaction";
  2605. DB.dbTx.insert(transactionTmp, function(err, newDoc) {
  2606. if (err) {
  2607. logger.info("Transaction insert ERROR", err)
  2608. }
  2609. })
  2610. }
  2611. };
  2612. TransactionDb.deleteTransactions = function(transactions) {
  2613. for (var i in transactions) {
  2614. if (!transactions.hasOwnProperty(i) || i == "count") {
  2615. continue
  2616. }
  2617. var transaction = transactions[i];
  2618. var transactionTmp = transaction.getData();
  2619. transactionTmp.tbl = "transaction";
  2620. DB.dbTx.remove({
  2621. id: transactionTmp.id,
  2622. tbl: "transaction"
  2623. }, {}, function(err, numRemoved) {})
  2624. }
  2625. };
  2626. var Block = function(data) {
  2627. if ("object" !== typeof data) {
  2628. data = {}
  2629. }
  2630. this.version = data.version || null;
  2631. this.timestamp = data.timestamp || null;
  2632. this.previousBlockId = data.previousBlockId || 0;
  2633. this.generatorPublicKey = data.generatorPublicKey || Config.NULL_HASH;
  2634. this.previousBlockHash = data.previousBlockHash || Config.NULL_HASH;
  2635. this.totalAmount = data.totalAmount || 0;
  2636. this.totalFee = data.totalFee || 0;
  2637. this.payloadLength = data.payloadLength || 0;
  2638. this.generationSignature = data.generationSignature || Config.NULL_HASH;
  2639. this.payloadHash = data.payloadHash || Config.NULL_HASH;
  2640. this.transactionIds = data.transactionIds || [];
  2641. this.blockTransactions = data.blockTransactions || [];
  2642. this.blockSignature = data.blockSignature || null;
  2643. this.cumulativeDifficulty = data.cumulativeDifficulty || new bigint("0");
  2644. this.baseTarget = data.baseTarget || Config.INITIAL_BASE_TARGET;
  2645. this.nextBlockId = data.nextBlockId || null;
  2646. this.height = typeof data.height !== "undefined" ? data.height : -1;
  2647. this.id = data.id || null;
  2648. this.stringId = data.stringId || null;
  2649. this.generatorId = data.generatorId || null;
  2650. this.confirmations = data.confirmations || 0;
  2651. if (typeof this.previousBlockId == "string") {
  2652. this.previousBlockId = Utils.stringToLong(this.previousBlockId)
  2653. }
  2654. if (typeof this.generatorPublicKey == "string") {
  2655. this.generatorPublicKey = new Buffer(this.generatorPublicKey, "hex")
  2656. }
  2657. if (typeof this.previousBlockHash == "string") {
  2658. this.previousBlockHash = new Buffer(this.previousBlockHash, "hex")
  2659. }
  2660. if (typeof this.generationSignature == "string") {
  2661. this.generationSignature = new Buffer(this.generationSignature, "hex")
  2662. }
  2663. if (typeof this.payloadHash == "string") {
  2664. this.payloadHash = new Buffer(this.payloadHash, "hex")
  2665. }
  2666. if (typeof this.blockSignature == "string") {
  2667. this.blockSignature = new Buffer(this.blockSignature, "hex")
  2668. }
  2669. if (typeof this.nextBlockId == "string") {
  2670. this.nextBlockId = Utils.stringToLong(this.nextBlockId)
  2671. }
  2672. if (typeof this.id == "string") {
  2673. this.id = Utils.stringToLong(this.id)
  2674. }
  2675. if (typeof this.cumulativeDifficulty == "string") {
  2676. this.cumulativeDifficulty = new bigint(this.cumulativeDifficulty)
  2677. }
  2678. };
  2679. Block.prototype.getData = function() {
  2680. return {
  2681. version: this.version,
  2682. timestamp: this.timestamp,
  2683. previousBlockId: this.previousBlockId.toString(),
  2684. generatorPublicKey: this.generatorPublicKey.toString("hex"),
  2685. previousBlockHash: this.previousBlockHash.toString("hex"),
  2686. totalAmount: this.totalAmount,
  2687. totalFee: this.totalFee,
  2688. payloadLength: this.payloadLength,
  2689. generationSignature: this.generationSignature.toString("hex"),
  2690. payloadHash: this.payloadHash.toString("hex"),
  2691. blockSignature: this.blockSignature ? this.blockSignature.toString("hex") : null,
  2692. cumulativeDifficulty: this.cumulativeDifficulty.toString(),
  2693. baseTarget: this.baseTarget,
  2694. nextBlockId: this.nextBlockId ? this.nextBlockId.toString() : null,
  2695. height: this.height,
  2696. id: this.id.toString(),
  2697. stringId: this.stringId,
  2698. generatorId: this.generatorId ? this.generatorId.toString() : null,
  2699. confirmations: this.confirmations
  2700. }
  2701. };
  2702. Block.prototype.getDataWithTransactions = function() {
  2703. var data = this.getData();
  2704. data.blockTransactions = this.getTransactionsDataAsArray().slice(0);
  2705. return data
  2706. };
  2707. Block.prototype.getId = function() {
  2708. if (this.id == null) {
  2709. if (this.blockSignature == null) {
  2710. throw new Error("Block is not signed yet")
  2711. }
  2712. var hash = curve.sha256(this.getBytes());
  2713. this.id = Utils.bufferToLongBE(hash);
  2714. this.stringId = this.id.toString()
  2715. }
  2716. return this.id
  2717. };
  2718. Block.prototype.getStringId = function() {
  2719. if (this.stringId == null) {
  2720. this.getId();
  2721. if (this.stringId == null) {
  2722. this.stringId = this.id.toString()
  2723. }
  2724. }
  2725. return this.stringId
  2726. };
  2727. Block.prototype.getGeneratorId = function() {
  2728. if (this.generatorId == null) {
  2729. this.generatorId = Account.getId(this.generatorPublicKey)
  2730. }
  2731. return this.generatorId
  2732. };
  2733. Block.prototype.hashCode = function() {
  2734. var id = this.getId();
  2735. id.toString("16")
  2736. };
  2737. Block.prototype.getBytes = function() {
  2738. var self = this;
  2739. var obj = {
  2740. version: this.version,
  2741. timestamp: this.timestamp,
  2742. previousBlockId: this.previousBlockId.toString(),
  2743. blockTransactions: this.blockTransactions.count,
  2744. totalAmount: this.totalAmount,
  2745. totalFee: this.totalFee,
  2746. payloadLength: this.payloadLength,
  2747. payloadHash: this.payloadHash,
  2748. generatorPublicKey: this.generatorPublicKey,
  2749. generationSignature: this.generationSignature
  2750. };
  2751. if (this.version > 1) {
  2752. obj.previousBlockHash = this.previousBlockHash
  2753. }
  2754. return JSON.stringify(obj)
  2755. };
  2756. Block.prototype.sign = function(secretPhrase) {
  2757. if (this.blockSignature != null) {
  2758. return this.blockSignature
  2759. }
  2760. if (!secretPhrase instanceof Buffer) {
  2761. secretPhrase = curve.sha256(secretPhrase)
  2762. }
  2763. this.blockSignature = nxtCrypto.sign(curve.sha256(this.getBytes()).toString("hex"), secretPhrase.toString("hex"));
  2764. return this.blockSignature
  2765. };
  2766. Block.prototype.verifyBlockSignature = function() {
  2767. var account = Account.addOrGetAccount(this.getGeneratorId());
  2768. if (account == null) {
  2769. return false
  2770. }
  2771. var data = curve.sha256(this.getBytes());
  2772. var isSignVerified = nxtCrypto.verify(this.blockSignature.toString("hex"), data.toString("hex"), this.generatorPublicKey.toString("hex"));
  2773. return isSignVerified && account.setOrVerify(this.generatorPublicKey, this.height)
  2774. };
  2775. Block.prototype.verifyGenerationSignature = function(__callback) {
  2776. var self = this;
  2777. BlockDb.findBlock(this.previousBlockId.toString(), function(previousBlock) {
  2778. try {
  2779. if (previousBlock == null && self.height != 0) {
  2780. __callback(false)
  2781. }
  2782. var isSignVerified = nxtCrypto.verify(self.generationSignature.toString("hex"), previousBlock.generationSignature.toString("hex"), self.generatorPublicKey.toString("hex"));
  2783. if (self.version == 1 && !isSignVerified) {
  2784. __callback(false)
  2785. }
  2786. var account = Account.getAccount(self.getGeneratorId());
  2787. __callback(true)
  2788. } catch (e) {
  2789. logger.error("Error verifying block generation signature", e);
  2790. __callback(false)
  2791. }
  2792. })
  2793. };
  2794. Block.prototype.apply = function() {
  2795. var generatorAccount = Account.addOrGetAccount(this.getGeneratorId());
  2796. generatorAccount.apply(this.generatorPublicKey, this.height);
  2797. generatorAccount.addToBalanceAndUnconfirmedBalance(Utils.roundTo5Float(this.totalFee))
  2798. };
  2799. Block.prototype.setPrevious = function(previousBlock) {
  2800. if (previousBlock != null) {
  2801. if (!previousBlock.getId() == this.previousBlockId) {
  2802. throw new Error("Previous block id doesn't match")
  2803. }
  2804. this.height = previousBlock.height + 1;
  2805. this.calculateBaseTarget(previousBlock)
  2806. } else {
  2807. this.height = 0
  2808. }
  2809. for (var transactionId in this.blockTransactions) {
  2810. var transaction;
  2811. if (this.blockTransactions.hasOwnProperty(transactionId) && transactionId != "count") {
  2812. transaction = this.blockTransactions[transactionId];
  2813. transaction.setBlock(this)
  2814. }
  2815. }
  2816. };
  2817. Block.prototype.calculateBaseTarget = function(previousBlock) {
  2818. if (this.getId() == Genesis.genesisBlockId && this.previousBlockId == null) {
  2819. this.baseTarget = Config.INITIAL_BASE_TARGET;
  2820. this.cumulativeDifficulty = 0
  2821. } else {
  2822. var curBaseTarget = previousBlock.baseTarget;
  2823. var newBaseTarget = new bigint(curBaseTarget).multiply(this.timestamp - previousBlock.timestamp).divide(60);
  2824. newBaseTarget = Utils.bigIntToLongBE(newBaseTarget);
  2825. if (newBaseTarget < 0 || newBaseTarget > Config.MAX_BASE_TARGET) {
  2826. newBaseTarget = Config.MAX_BASE_TARGET
  2827. }
  2828. if (newBaseTarget < curBaseTarget / 2) {
  2829. newBaseTarget = curBaseTarget / 2
  2830. }
  2831. if (newBaseTarget == 0) {
  2832. newBaseTarget = 1
  2833. }
  2834. var twofoldCurBaseTarget = curBaseTarget * 2;
  2835. if (twofoldCurBaseTarget < 0) {
  2836. twofoldCurBaseTarget = Config.MAX_BASE_TARGET
  2837. }
  2838. if (newBaseTarget > twofoldCurBaseTarget) {
  2839. newBaseTarget = twofoldCurBaseTarget
  2840. }
  2841. this.baseTarget = newBaseTarget;
  2842. this.cumulativeDifficulty = previousBlock.cumulativeDifficulty.add(Config.two64.divide(this.baseTarget.toString()))
  2843. }
  2844. };
  2845. Block.prototype.getTransactionIds = function() {
  2846. if (!this.transactionIds || this.transactionIds.length == 0) {
  2847. this.transactionIds = [];
  2848. for (var transactionId in this.blockTransactions) {
  2849. var transaction;
  2850. if (this.blockTransactions.hasOwnProperty(transactionId) && transactionId != "count") {
  2851. transaction = this.blockTransactions[transactionId];
  2852. this.transactionIds.push(transaction.id.toString())
  2853. }
  2854. }
  2855. }
  2856. return this.transactionIds
  2857. };
  2858. Block.prototype.getTransactionsAsArray = function() {
  2859. var transactionsArr = [];
  2860. for (var transactionId in this.blockTransactions) {
  2861. if (this.blockTransactions.hasOwnProperty(transactionId) && transactionId != "count") {
  2862. transactionsArr.push(this.blockTransactions[transactionId])
  2863. }
  2864. }
  2865. return transactionsArr
  2866. };
  2867. Block.prototype.getTransactionsDataAsArray = function() {
  2868. var transactionsArr = [];
  2869. for (var transactionId in this.blockTransactions) {
  2870. if (this.blockTransactions.hasOwnProperty(transactionId) && transactionId != "count") {
  2871. transactionsArr.push(this.blockTransactions[transactionId].getData())
  2872. }
  2873. }
  2874. return transactionsArr
  2875. };
  2876. Block.prototype.addConfirmedAndUnconfirmedAmounts = function() {
  2877. for (var transactionId in this.blockTransactions) {
  2878. if (this.blockTransactions.hasOwnProperty(transactionId) && transactionId != "count") {
  2879. var tx = this.blockTransactions[transactionId];
  2880. var recipientAccount = Account.addOrGetAccount(tx.recipientId.toString());
  2881. recipientAccount.addToBalanceAndUnconfirmedBalance(Utils.roundTo5Float(Utils.nullToNumber(tx.amount)));
  2882. var senderAccount = Account.addOrGetAccount(tx.getSenderId().toString());
  2883. senderAccount.addToBalanceAndUnconfirmedBalance(-Utils.roundTo5Float(Utils.nullToNumber(tx.amount)) - Utils.roundTo5Float(tx.fee))
  2884. }
  2885. }
  2886. var _genereatorAccount = Account.addOrGetAccount(this.generatorId.toString());
  2887. _genereatorAccount.addToBalanceAndUnconfirmedBalance(Utils.roundTo5Float(this.totalFee))
  2888. };
  2889. Block.prototype.addConfirmedAmounts = function() {
  2890. for (var transactionId in this.blockTransactions) {
  2891. if (this.blockTransactions.hasOwnProperty(transactionId) && transactionId != "count") {
  2892. var tx = this.blockTransactions[transactionId];
  2893. var recipientAccount = Account.addOrGetAccount(tx.recipientId.toString());
  2894. recipientAccount.addToBalance(Utils.roundTo5Float(Utils.nullToNumber(tx.amount)));
  2895. var senderAccount = Account.addOrGetAccount(tx.senderId.toString());
  2896. senderAccount.addToBalance(-Utils.roundTo5Float(Utils.nullToNumber(tx.amount)) - Utils.roundTo5Float(tx.fee))
  2897. }
  2898. }
  2899. var _genereatorAccount = Account.addOrGetAccount(this.generatorId.toString());
  2900. _genereatorAccount.addToBalance(Utils.roundTo5Float(this.totalFee))
  2901. };
  2902. Block.prototype.addUnconfirmedFee = function() {
  2903. var _genereatorAccount = Account.addOrGetAccount(this.generatorId.toString());
  2904. _genereatorAccount.addToUnconfirmedBalance(Utils.roundTo5Float(this.totalFee))
  2905. };
  2906. Block.prototype.addUnconfirmedAmounts = function() {
  2907. for (var transactionId in this.blockTransactions) {
  2908. if (this.blockTransactions.hasOwnProperty(transactionId) && transactionId != "count") {
  2909. var tx = this.blockTransactions[transactionId];
  2910. var recipientAccount = Account.addOrGetAccount(tx.recipientId.toString());
  2911. recipientAccount.addToUnconfirmedBalance(Utils.roundTo5Float(Utils.nullToNumber(tx.amount)));
  2912. var senderAccount = Account.addOrGetAccount(tx.senderId.toString());
  2913. senderAccount.addToUnconfirmedBalance(-Utils.roundTo5Float(Utils.nullToNumber(tx.amount)) - Utils.roundTo5Float(tx.fee))
  2914. }
  2915. }
  2916. var _genereatorAccount = Account.addOrGetAccount(this.generatorId.toString());
  2917. _genereatorAccount.addToUnconfirmedBalance(Utils.roundTo5Float(this.totalFee))
  2918. };
  2919. Block.prototype.removeUnconfirmedTxs = function(callback) {
  2920. var txArr = this.getTransactionsAsArray();
  2921. UnconfirmedTransactions.deleteTransactions(txArr, callback)
  2922. };
  2923. var Transaction = function(data) {
  2924. if ("object" !== typeof data) {
  2925. data = {}
  2926. }
  2927. this.deadline = data.deadline || null;
  2928. this.senderPublicKey = data.senderPublicKey || null;
  2929. this.recipientId = data.recipientId || null;
  2930. this.amount = data.amount || 0;
  2931. this.fee = data.fee || null;
  2932. this.referencedTransactionId = data.referencedTransactionId || null;
  2933. this.type = typeof data.type !== "undefined" ? data.type : null;
  2934. this.height = data.height || null;
  2935. this.blockId = data.blockId || null;
  2936. this.block = data.block || null;
  2937. this.signature = data.signature || null;
  2938. this.timestamp = data.timestamp || null;
  2939. this.attachment = data.attachment || null;
  2940. this.id = data.id || null;
  2941. this.null = null;
  2942. this.senderId = data.senderId || null;
  2943. this.hash = data.hash || null;
  2944. this.confirmations = data.confirmations || 0;
  2945. if (typeof this.senderPublicKey == "string") {
  2946. this.senderPublicKey = new Buffer(this.senderPublicKey, "hex")
  2947. }
  2948. if (typeof this.recipientId == "string") {
  2949. this.recipientId = Utils.stringToLong(this.recipientId)
  2950. }
  2951. if (typeof this.referencedTransactionId == "string") {
  2952. this.referencedTransactionId = Utils.stringToLong(this.referencedTransactionId)
  2953. }
  2954. if (typeof this.type == "string" || typeof this.type == "number") {
  2955. this.type = TransactionType.findTransactionType(this.type, 0)
  2956. }
  2957. if (typeof this.blockId == "string") {
  2958. this.blockId = Utils.stringToLong(this.blockId)
  2959. }
  2960. if (typeof this.signature == "string") {
  2961. this.signature = new Buffer(this.signature, "hex")
  2962. }
  2963. if (typeof this.id == "string") {
  2964. this.id = Utils.stringToLong(this.id)
  2965. }
  2966. if (typeof this.senderId == "string") {
  2967. this.senderId = Utils.stringToLong(this.senderId)
  2968. }
  2969. if (typeof this.hash == "string") {
  2970. this.hash = new Buffer(this.hash, "hex")
  2971. }
  2972. };
  2973. Transaction.prototype.getData = function() {
  2974. var type = null;
  2975. if (this.type) {
  2976. type = this.type.getType()
  2977. }
  2978. return {
  2979. deadline: this.deadline,
  2980. senderPublicKey: this.senderPublicKey.toString("hex"),
  2981. recipientId: this.recipientId.toString(),
  2982. amount: this.amount,
  2983. fee: this.fee,
  2984. referencedTransactionId: this.referencedTransactionId ? this.referencedTransactionId.toString() : this.referencedTransactionId,
  2985. type: type,
  2986. height: this.height,
  2987. blockId: this.blockId ? this.blockId.toString() : null,
  2988. signature: this.signature ? this.signature.toString("hex") : null,
  2989. timestamp: this.timestamp,
  2990. attachment: this.attachment,
  2991. id: this.getId().toString(),
  2992. "null": null,
  2993. senderId: this.getSenderId().toString(),
  2994. hash: this.hash.toString("hex"),
  2995. confirmations: this.confirmations
  2996. }
  2997. };
  2998. Transaction.prototype.getBlock = function() {
  2999. if (this.block == null) {
  3000. var self = this;
  3001. BlockDb.findBlock(self.blockId, function(block) {
  3002. self.block = block
  3003. })
  3004. }
  3005. return this.block
  3006. };
  3007. Transaction.prototype.setBlock = function(block) {
  3008. this.block = block;
  3009. this.blockId = block.getId();
  3010. this.height = block.height
  3011. };
  3012. Transaction.prototype.getExpiration = function() {
  3013. return this.timestamp + this.deadline * 60 * 60 * 1e3
  3014. };
  3015. Transaction.prototype.getId = function() {
  3016. if (this.id == null) {
  3017. if (this.signature == null) {
  3018. return false
  3019. }
  3020. this.hash = curve.sha256(this.getBytes());
  3021. this.id = Utils.bufferToLongBE(this.hash);
  3022. this.stringId = this.id.toString()
  3023. }
  3024. return this.id
  3025. };
  3026. Transaction.prototype.getStringId = function() {
  3027. if (this.stringId == null) {
  3028. this.getId();
  3029. if (this.stringId == null) {
  3030. this.stringId = this.id.toString()
  3031. }
  3032. }
  3033. return this.stringId
  3034. };
  3035. Transaction.prototype.getSenderId = function() {
  3036. if (this.senderId == null) {
  3037. this.senderId = Account.getId(this.senderPublicKey)
  3038. }
  3039. return this.senderId
  3040. };
  3041. Transaction.prototype.getStringId = function() {
  3042. if (this.stringId == null) {
  3043. this.getId();
  3044. if (this.stringId == null) {
  3045. this.stringId = this.id.toString()
  3046. }
  3047. }
  3048. return this.stringId
  3049. };
  3050. Transaction.prototype.compareTo = function(o) {
  3051. if (this.height < o.height) {
  3052. return -1
  3053. }
  3054. if (this.height > o.height) {
  3055. return 1
  3056. }
  3057. if (Utils.nullToNumber(this.fee) * o.getSize() > Utils.nullToNumber(o.fee) * this.getSize() || this.fee === null && o.fee !== null) {
  3058. return -1
  3059. }
  3060. if (Utils.nullToNumber(this.fee) * o.getSize() < Utils.nullToNumber(o.fee) * this.getSize()) {
  3061. return 1
  3062. }
  3063. if (this.timestamp < o.timestamp) {
  3064. return -1
  3065. }
  3066. if (this.timestamp > o.timestamp) {
  3067. return 1
  3068. }
  3069. return 0
  3070. };
  3071. Transaction.prototype.TRANSACTION_BYTES_LENGTH = 1 + 1 + 4 + 2 + 32 + 8 + 4 + 4 + 8 + 64;
  3072. Transaction.prototype.getSize = function() {
  3073. return this.TRANSACTION_BYTES_LENGTH + (this.attachment == null ? 0 : this.attachment.getSize())
  3074. };
  3075. Transaction.prototype.getBytes = function() {
  3076. var self = this;
  3077. var obj = {
  3078. type: self.type.getType(),
  3079. subtype: self.type.getSubtype(),
  3080. timestamp: self.timestamp,
  3081. deadline: self.deadline,
  3082. senderPublicKey: self.senderPublicKey,
  3083. recipientId: self.recipientId,
  3084. amount: self.amount,
  3085. fee: self.fee,
  3086. referencedTransactionId: self.referencedTransactionId
  3087. };
  3088. if (self.attachment != null) {
  3089. obj.attachment = self.attachment.getBytes()
  3090. }
  3091. return JSON.stringify(obj)
  3092. };
  3093. Transaction.prototype.sign = function(secretPhrase) {
  3094. if (this.signature != null) {
  3095. return this.signature
  3096. }
  3097. console.log("Transaction sign", curve.sha256(this.getBytes()));
  3098. this.signature = nxtCrypto.sign(curve.sha256(this.getBytes()).toString("hex"), secretPhrase.toString("hex"));
  3099. try {
  3100. while (!this.verify()) {
  3101. this.timestamp++;
  3102. this.signature = nxtCrypto.sign(curve.sha256(this.getBytes()).toString("hex"), secretPhrase.toString("hex"))
  3103. }
  3104. return this.signature
  3105. } catch (e) {
  3106. console.log("Error signing transaction", e);
  3107. return false
  3108. }
  3109. };
  3110. Transaction.prototype.getHash = function() {
  3111. if (this.hash == null) {
  3112. var data = this.getBytes();
  3113. var hash = curve.sha256(data);
  3114. this.hash = hash.toString("hex")
  3115. }
  3116. return this.hash
  3117. };
  3118. Transaction.prototype.hashCode = function() {
  3119. var id = this.getId();
  3120. id.toString("16")
  3121. };
  3122. Transaction.prototype.verify = function() {
  3123. var account = Account.addOrGetAccount(this.getSenderId().toString());
  3124. if (account == null) {
  3125. return false
  3126. }
  3127. var data = curve.sha256(this.getBytes());
  3128. console.log("Transaction data virify", data);
  3129. var isSignVerified = nxtCrypto.verify(this.signature.toString("hex"), data.toString("hex"), this.senderPublicKey.toString("hex"));
  3130. return isSignVerified && account.setOrVerify(this.senderPublicKey, this.height)
  3131. };
  3132. Transaction.prototype.applyUnconfirmed = function() {
  3133. var senderAccount = Account.getAccount(this.getSenderId());
  3134. if (senderAccount == null) {
  3135. return false
  3136. }
  3137. return this.type.applyUnconfirmed(this, senderAccount)
  3138. };
  3139. Transaction.prototype.apply = function() {
  3140. var senderAccount = Account.getAccount(this.getSenderId());
  3141. senderAccount.apply(this.senderPublicKey, this.height);
  3142. var recipientAccount = Account.getAccount(this.recipientId);
  3143. if (recipientAccount == null) {
  3144. recipientAccount = Account.addOrGetAccount(recipientId)
  3145. }
  3146. this.type.apply(this, senderAccount, recipientAccount)
  3147. };
  3148. Transaction.prototype.undoUnconfirmed = function() {
  3149. var senderAccount = Account.getAccount(this.getSenderId());
  3150. this.type.undoUnconfirmed(this, senderAccount)
  3151. };
  3152. Transaction.prototype.undo = function() {
  3153. var senderAccount = Account.getAccount(this.senderId);
  3154. senderAccount.undo(this.height);
  3155. var recipientAccount = Account.getAccount(this.recipientId);
  3156. this.type.undo(this, senderAccount, recipientAccount)
  3157. };
  3158. Transaction.prototype.updateTotals = function(accumulatedAmounts, accumulatedAssetQuantities) {
  3159. var senderId = this.getSenderId();
  3160. var accumulatedAmount = accumulatedAmounts === null || typeof accumulatedAmounts[senderId.toString()] === "undefined" ? null : accumulatedAmounts[senderId.toString()];
  3161. if (accumulatedAmount == null) {
  3162. accumulatedAmount = 0
  3163. }
  3164. accumulatedAmounts[senderId.toString()] = Utils.roundTo5Float(accumulatedAmount) + (Utils.roundTo5Float(this.amount) + Utils.roundTo5Float(this.fee));
  3165. this.type.updateTotals(this, accumulatedAmounts, accumulatedAssetQuantities, accumulatedAmount)
  3166. };
  3167. Transaction.prototype.isDuplicate = function(duplicates) {
  3168. return this.type.isDuplicate(this, duplicates)
  3169. };
  3170. Transaction.prototype.validateAttachment = function() {
  3171. this.type.validateAttachment(this)
  3172. };
  3173. var UnconfirmedTransactions = function() {};
  3174. UnconfirmedTransactions.addConfirmation = function(id, callback) {
  3175. var q = {
  3176. id: id,
  3177. tbl: "transaction"
  3178. };
  3179. db.update(q, {
  3180. $inc: {
  3181. confirmations: 1
  3182. }
  3183. }, {}, function() {
  3184. if (typeof callback === "function") {
  3185. callback()
  3186. }
  3187. })
  3188. };
  3189. UnconfirmedTransactions.getLastTransaction = function(callback) {
  3190. var q = {
  3191. tbl: "transaction"
  3192. };
  3193. db.find(q).limit(1).sort({
  3194. timestamp: -1,
  3195. id: -1
  3196. }).exec(function(err, docs) {
  3197. if (!err) {
  3198. if (typeof callback === "function") {
  3199. var transaction = false;
  3200. if (docs.length > 0) {
  3201. transaction = new Transaction(docs[0])
  3202. }
  3203. callback(transaction)
  3204. }
  3205. } else {
  3206. logger.info("Find transaction ERROR!!!", err)
  3207. }
  3208. })
  3209. };
  3210. UnconfirmedTransactions.getLastTransactions = function(n, callback) {
  3211. var q = {
  3212. tbl: "transaction"
  3213. };
  3214. db.find(q).limit(n).sort({
  3215. timestamp: -1,
  3216. id: -1
  3217. }).exec(function(err, docs) {
  3218. if (!err) {
  3219. if (typeof callback === "function") {
  3220. if (docs.length > 0) {
  3221. callback(docs)
  3222. } else {
  3223. callback(null)
  3224. }
  3225. }
  3226. } else {
  3227. logger.info("Find transaction ERROR!!!", err)
  3228. }
  3229. })
  3230. };
  3231. UnconfirmedTransactions.getAll = function(callback) {
  3232. var q = {
  3233. blockId: null,
  3234. tbl: "transaction"
  3235. };
  3236. db.find(q).sort({
  3237. timestamp: 1,
  3238. id: 1
  3239. }).exec(function(err, docs) {
  3240. if (!err) {
  3241. if (typeof callback === "function") {
  3242. var transactionsMap = false;
  3243. if (docs.length > 0) {
  3244. transactionsMap = {
  3245. count: 0
  3246. };
  3247. for (var i in docs) {
  3248. transactionsMap[docs[i].id] = new Transaction(docs[i]);
  3249. transactionsMap.count++
  3250. }
  3251. }
  3252. callback(transactionsMap)
  3253. }
  3254. } else {
  3255. logger.info("Find BlockTransactions ERROR!!!", err)
  3256. }
  3257. })
  3258. };
  3259. UnconfirmedTransactions.getMyTransactions = function(_accountId, callback) {
  3260. var q = {
  3261. $or: [{
  3262. recipientId: _accountId
  3263. }, {
  3264. senderId: _accountId
  3265. }],
  3266. $not: {
  3267. blockId: null
  3268. },
  3269. type: TransactionType.TYPE_PAYMENT,
  3270. tbl: "transaction"
  3271. };
  3272. UnconfirmedTransactions.getTransactionsListByRs(q, callback)
  3273. };
  3274. UnconfirmedTransactions.getMyAllTransactions = function(_accountId, callback) {
  3275. var q = {
  3276. $or: [{
  3277. recipientId: _accountId
  3278. }, {
  3279. senderId: _accountId
  3280. }],
  3281. type: TransactionType.TYPE_PAYMENT,
  3282. tbl: "transaction"
  3283. };
  3284. db.find(q).sort({
  3285. timestamp: -1,
  3286. id: -1
  3287. }).exec(function(err, docs) {
  3288. if (!err) {
  3289. if (typeof callback === "function") {
  3290. callback(docs)
  3291. }
  3292. } else {
  3293. logger.info("Find BlockTransactions ERROR!!!", err)
  3294. }
  3295. })
  3296. };
  3297. UnconfirmedTransactions.getAllTransactionsList = function(callback) {
  3298. var q = {
  3299. tbl: "transaction"
  3300. };
  3301. db.find(q).sort({
  3302. timestamp: -1,
  3303. id: -1
  3304. }).exec(function(err, docs) {
  3305. if (!err) {
  3306. if (typeof callback === "function") {
  3307. callback(docs)
  3308. }
  3309. } else {
  3310. logger.info("Find BlockTransactions ERROR!!!", err)
  3311. }
  3312. })
  3313. };
  3314. UnconfirmedTransactions.getTransactionsListByRs = function(q, callback) {
  3315. db.find(q, function(err, docs) {
  3316. if (!err) {
  3317. if (typeof callback === "function") {
  3318. callback(docs)
  3319. }
  3320. } else {
  3321. logger.info("Find BlockTransactions ERROR!!!", err)
  3322. }
  3323. })
  3324. };
  3325. UnconfirmedTransactions.findTransaction = function(transactionId, callback) {
  3326. var q = {
  3327. id: transactionId,
  3328. tbl: "transaction"
  3329. };
  3330. db.find(q, function(err, docs) {
  3331. if (!err) {
  3332. if (typeof callback === "function") {
  3333. var transaction = false;
  3334. if (docs.length > 0) {
  3335. transaction = new Transaction(docs[0])
  3336. }
  3337. callback(transaction)
  3338. }
  3339. } else {
  3340. logger.info("Find transaction ERROR!!!", err)
  3341. }
  3342. })
  3343. };
  3344. UnconfirmedTransactions.hasTransaction = function(transactionId, callback) {
  3345. var q = {
  3346. id: transactionId,
  3347. tbl: "transaction"
  3348. };
  3349. db.find(q, function(err, docs) {
  3350. if (!err) {
  3351. if (typeof callback === "function") {
  3352. if (docs.length > 0) {
  3353. callback(true)
  3354. } else {
  3355. callback(false)
  3356. }
  3357. }
  3358. } else {
  3359. logger.error("Find transaction ERROR!!!", err)
  3360. }
  3361. })
  3362. };
  3363. UnconfirmedTransactions.findTransactionByRs = function(rs, callback) {
  3364. rs.tbl = "transaction";
  3365. db.find(rs, function(err, docs) {
  3366. if (!err) {
  3367. if (typeof callback === "function") {
  3368. var transaction = false;
  3369. if (docs.length > 0) {
  3370. transaction = new Transaction(docs[0])
  3371. }
  3372. callback(transaction)
  3373. }
  3374. } else {
  3375. logger.info("Find transaction ERROR!!!", err)
  3376. }
  3377. })
  3378. };
  3379. UnconfirmedTransactions.addTransactions = function(transactions) {
  3380. for (var i in transactions) {
  3381. if (!transactions.hasOwnProperty(i) || i == "count") {
  3382. continue
  3383. }
  3384. var transaction = transactions[i];
  3385. var transactionTmp = transaction.getData();
  3386. transactionTmp.tbl = "transaction";
  3387. db.insert(transactionTmp, function(err, newDoc) {
  3388. if (err) {
  3389. logger.info("Transaction insert ERROR", err)
  3390. }
  3391. })
  3392. }
  3393. };
  3394. UnconfirmedTransactions.addTransactionsData = function(transactionsData, callback) {
  3395. for (var i in transactionsData) {
  3396. if (!transactionsData.hasOwnProperty(i) || i == "count") {
  3397. continue
  3398. }
  3399. var transactionTmp = transactionsData[i];
  3400. transactionTmp.tbl = "transaction";
  3401. db.insert(transactionTmp, function(err, newDoc) {
  3402. if (err) {
  3403. logger.info("Transaction insert ERROR", err);
  3404. callback(false)
  3405. } else {
  3406. callback(true)
  3407. }
  3408. })
  3409. }
  3410. };
  3411. UnconfirmedTransactions.addTransactionsData = function(transactionsData, callback) {
  3412. for (var i in transactionsData) {
  3413. if (!transactionsData.hasOwnProperty(i) || i == "count") {
  3414. continue
  3415. }
  3416. var transactionTmp = transactionsData[i];
  3417. transactionTmp.tbl = "transaction";
  3418. db.insert(transactionTmp, function(err, newDoc) {
  3419. if (err) {
  3420. logger.info("Transaction insert ERROR", err);
  3421. callback(false)
  3422. } else {
  3423. callback(true)
  3424. }
  3425. })
  3426. }
  3427. };
  3428. UnconfirmedTransactions.deleteTransactions = function(transactions, callback) {
  3429. for (var i in transactions) {
  3430. if (!transactions.hasOwnProperty(i) || i == "count") {
  3431. continue
  3432. }
  3433. var transaction = transactions[i];
  3434. var transactionTmp = transaction.getData();
  3435. transactionTmp.tbl = "transaction";
  3436. db.remove({
  3437. id: transactionTmp.id,
  3438. tbl: "transaction"
  3439. }, {}, function(err, numRemoved) {
  3440. if (typeof callback === "function") {
  3441. callback()
  3442. }
  3443. })
  3444. }
  3445. };
  3446.  
  3447. function Connection(socket, peer) {
  3448. events.EventEmitter.call(this);
  3449. this.socket = socket;
  3450. this.peer = peer;
  3451. this.buffer = "";
  3452. this.active = false;
  3453. this.inbound = !!socket.server;
  3454. this.setupHandlers()
  3455. }
  3456. util.inherits(Connection, events.EventEmitter);
  3457. Connection.prototype.commands = {
  3458. VERSION: "version",
  3459. READY: "verack",
  3460. ADDRESSES: "addr",
  3461. GET_ADDRESSES: "getaddr",
  3462. GET_TRANSACTIONS: "gettrans",
  3463. GET_LAST_TRANSACTION: "getlasttrans",
  3464. LAST_TRANSACTION: "lasttrans",
  3465. GET_NEXT_BLOCK: "getnextblock",
  3466. NEW_TRANSACTION: "newtrans",
  3467. BLOCK: "block",
  3468. GET_PREV_TRANSACTION: "getprevtrans",
  3469. BROADCAST: "broadcast",
  3470. PEER_STATUS: "peerstatus",
  3471. BROADCAST_GENERATE_BLOCK: "bcgenblk",
  3472. STOP_GENERATE_BLOCK: "stopgenblk",
  3473. ANSWER_ON_GENERATE_BLOCK: "answergenblk",
  3474. NEW_BLOCK: "newblk",
  3475. VERIFIED_PEER: "verifpeer",
  3476. VERIFIED_PEER_RESPONSE: "verifpeerresp",
  3477. PEER_NOT_VERIFIED: "peernotverif",
  3478. UNCONFIRMED_TRANSACTIONS: "unconftrans"
  3479. };
  3480. Connection.prototype.toString = function() {
  3481. return "Connection: '" + this.peer.toString() + "',\n" + "inbound(isServer): " + this.inbound
  3482. };
  3483. Connection.prototype.setupHandlers = function() {
  3484. this.socket.addListener("connect", this.handleConnect.bind(this));
  3485. this.socket.addListener("error", this.handleError.bind(this));
  3486. this.socket.addListener("end", this.handleDisconnect.bind(this));
  3487. this.socket.addListener("data", function(data) {
  3488. var _data = data.toString(),
  3489. DATA_LENGTH_SHOW = 31,
  3490. dataMsg = _data.length > DATA_LENGTH_SHOW ? _data.substring(0, DATA_LENGTH_SHOW) + "..." : _data;
  3491. logger.netdbg("[" + this.peer + "] " + "Received " + dataMsg + " bytes of data: " + Buffer.byteLength(_data, "utf8"));
  3492. logger.netdbg(this.toString())
  3493. }.bind(this));
  3494. this.socket.addListener("data", this.handleData.bind(this))
  3495. };
  3496. Connection.prototype.handleConnect = function() {
  3497. if (!this.inbound) {
  3498. this.sendVersion()
  3499. }
  3500. this.emit("connect", {
  3501. conn: this,
  3502. socket: this.socket,
  3503. peer: this.peer
  3504. })
  3505. };
  3506. Connection.prototype.handleError = function(err) {
  3507. if (err.errno == 110 || err.errno == "ETIMEDOUT") {
  3508. logger.netdbg("Connection timed out for " + this.peer)
  3509. } else if (err.errno == 111 || err.errno == "ECONNREFUSED") {
  3510. logger.netdbg("Connection refused for " + this.peer)
  3511. } else {
  3512. logger.warn("Connection with " + this.peer + " " + err.toString())
  3513. }
  3514. this.emit("error", {
  3515. conn: this,
  3516. socket: this.socket,
  3517. peer: this.peer,
  3518. err: err
  3519. })
  3520. };
  3521. Connection.prototype.handleDisconnect = function() {
  3522. this.emit("disconnect", {
  3523. conn: this,
  3524. socket: this.socket,
  3525. peer: this.peer
  3526. })
  3527. };
  3528. Connection.prototype.handleData = function(data) {
  3529. this.buffer += data.toString();
  3530. if (this.buffer.indexOf("___|||___") == -1) {
  3531. return
  3532. }
  3533. var datas = this.buffer.split("___|||___");
  3534. this.buffer = datas[datas.length - 1];
  3535. delete datas[datas.length - 1];
  3536. var self = this;
  3537. datas.forEach(function(_data) {
  3538. var message;
  3539. try {
  3540. message = self.parseMessage(_data)
  3541. } catch (e) {
  3542. logger.error("Error while parsing message " + _data + "\n from [" + self.peer + "]\nmessage: " + e.toString())
  3543. }
  3544. if (message) {
  3545. self.peer.uploadBytes += Buffer.byteLength(_data, "utf8");
  3546. self.handleMessage(message)
  3547. }
  3548. })
  3549. };
  3550. Connection.prototype.handleMessage = function(message) {
  3551. logger.netdbg("Handle Message (message command: '" + message.command + "')\n" + this.toString());
  3552. switch (message.command) {
  3553. case Connection.prototype.commands.VERSION:
  3554. if (this.inbound) {
  3555. this.sendVersion()
  3556. }
  3557. this.sendMessage(Connection.prototype.commands.READY);
  3558. break;
  3559. case Connection.prototype.commands.READY:
  3560. this.active = true;
  3561. break
  3562. }
  3563. this.emit(message.command, {
  3564. conn: this,
  3565. socket: this.socket,
  3566. peer: this.peer,
  3567. message: message
  3568. })
  3569. };
  3570. Connection.prototype.parseMessage = function(message) {
  3571. message = JSON.parse(message);
  3572. var notExist = true;
  3573. for (var command in Connection.prototype.commands) {
  3574. if (Connection.prototype.commands[command] == message.command) {
  3575. notExist = false;
  3576. break
  3577. }
  3578. }
  3579. if (notExist) {
  3580. logger.error("Connection.parseMessage(): Command not implemented", {
  3581. cmd: message.command
  3582. });
  3583. return null
  3584. }
  3585. switch (message.command) {
  3586. case Connection.prototype.commands.ADDRESSES:
  3587. message.addrs = message.data.addrs;
  3588. message.netStatus = message.data.netStatus;
  3589. break
  3590. }
  3591. return message
  3592. };
  3593. Connection.prototype.sendVersion = function() {
  3594. var data = {
  3595. version: 1,
  3596. timestamp: new Date().getTime()
  3597. };
  3598. this.sendMessage(Connection.prototype.commands.VERSION, data)
  3599. };
  3600. Connection.prototype.sendGetAddr = function() {
  3601. this.sendMessage(Connection.prototype.commands.GET_ADDRESSES)
  3602. };
  3603. Connection.prototype.sendLastTransaction = function(data) {
  3604. this.sendMessage(Connection.prototype.commands.LAST_TRANSACTION, data)
  3605. };
  3606. Connection.prototype.sendGetLastTransaction = function() {
  3607. this.sendMessage(Connection.prototype.commands.GET_LAST_TRANSACTION)
  3608. };
  3609. Connection.prototype.sendGetNextBlock = function(data) {
  3610. this.sendMessage(Connection.prototype.commands.GET_NEXT_BLOCK, data)
  3611. };
  3612. Connection.prototype.sendNewTransaction = function(data) {
  3613. this.sendMessage(Connection.prototype.commands.NEW_TRANSACTION, data)
  3614. };
  3615. Connection.prototype.sendBlock = function(data) {
  3616. this.sendMessage(Connection.prototype.commands.BLOCK, data)
  3617. };
  3618. Connection.prototype.sendUnconfirmedTransactions = function(data) {
  3619. this.sendMessage(Connection.prototype.commands.UNCONFIRMED_TRANSACTIONS, data)
  3620. };
  3621. Connection.prototype.sendMessage = function(command, data) {
  3622. try {
  3623. if (typeof data === "undefined") {
  3624. data = null
  3625. }
  3626. var message = {
  3627. command: command,
  3628. data: data
  3629. };
  3630. logger.netdbg("[" + this.peer + "] Sending message " + message.command);
  3631. message = JSON.stringify(message) + "___|||___";
  3632. this.peer.downloadBytes += Buffer.byteLength(message, "utf8");
  3633. this.socket.write(message)
  3634. } catch (err) {
  3635. logger.error("Error while sending message to peer " + this.peer + ": " + (err.stack ? err.stack : err.toString()))
  3636. }
  3637. };
  3638. Connection.prototype.broadcast = function(data) {
  3639. this.sendMessage(Connection.prototype.commands.broadcast, data)
  3640. };
  3641.  
  3642. function Peer(host, port, services) {
  3643. if ("string" === typeof host) {
  3644. if (host.indexOf(":") && !port) {
  3645. var parts = host.split(":");
  3646. host = parts[0];
  3647. port = parts[1]
  3648. }
  3649. this.host = host;
  3650. this.port = +port || 8333
  3651. } else if (host instanceof Peer) {
  3652. this.host = host.host;
  3653. this.port = host.port
  3654. } else if (Buffer.isBuffer(host)) {
  3655. this.host = host.toString("hex").match(/(.{1,4})/g).join(":");
  3656. this.port = +port || 8333
  3657. } else if (host instanceof Object) {
  3658. return this.fromData(host)
  3659. } else {
  3660. throw new Error("Could not instantiate peer, invalid parameter type: " + typeof host)
  3661. }
  3662. this.services = services ? services : null;
  3663. this.MAX_LOST_CONNECTION = 10;
  3664. this.lostConnection = 0;
  3665. this.connection = null;
  3666. this.uploadBytes = 0;
  3667. this.downloadBytes = 0;
  3668. this.timestamp = null;
  3669. this.lastSeen = null;
  3670. this.status = Peer.prototype.statuses.DISABLE;
  3671. this.oldStatus = null
  3672. }
  3673. Peer.prototype.statuses = {
  3674. ACTIVE: "active",
  3675. CHECK: "check",
  3676. PENDING: "pending",
  3677. SYNCED: "synced",
  3678. DISABLE: "disable"
  3679. };
  3680. Peer.prototype.getData = function() {
  3681. return {
  3682. port: this.port,
  3683. host: this.host,
  3684. uploadBytes: this.uploadBytes,
  3685. downloadBytes: this.downloadBytes,
  3686. services: this.services,
  3687. MAX_LOST_CONNECTION: this.MAX_LOST_CONNECTION,
  3688. lostConnection: this.lostConnection,
  3689. status: this.status
  3690. }
  3691. };
  3692. Peer.prototype.fromData = function(data) {
  3693. this.port = data.port || null;
  3694. this.host = data.host || null;
  3695. this.uploadBytes = data.uploadBytes || 0;
  3696. this.downloadBytes = data.downloadBytes || 0;
  3697. this.services = data.services || null;
  3698. this.MAX_LOST_CONNECTION = data.MAX_LOST_CONNECTION || 0;
  3699. this.lostConnection = data.lostConnection || 0;
  3700. this.status = data.status || Peer.prototype.statuses.DISABLE;
  3701. return this
  3702. };
  3703. Peer.prototype.isLost = function() {
  3704. if (this.lostConnection >= this.MAX_LOST_CONNECTION) {
  3705. this.status = Peer.prototype.statuses.DISABLE;
  3706. return true
  3707. }
  3708. return false
  3709. };
  3710. Peer.prototype.connectionLost = function() {
  3711. if (this.lostConnection === 0) {
  3712. this.updateLastSeen()
  3713. }
  3714. this.lostConnection++;
  3715. this.connection = null;
  3716. this.timestamp = null;
  3717. this.oldStatus = this.status;
  3718. this.status = Peer.prototype.statuses.PENDING
  3719. };
  3720. Peer.prototype.updateLastSeen = function() {
  3721. this.lastSeen = new Date().getTime()
  3722. };
  3723. Peer.prototype.updateUpTime = function() {
  3724. this.timestamp = new Date().getTime()
  3725. };
  3726. Peer.prototype.getConnection = function() {
  3727. if (this.connection === null) {
  3728. this.updateUpTime();
  3729. this.connection = net.createConnection(this.port, this.host);
  3730. this.status = this.oldStatus === null ? Peer.prototype.statuses.DISABLE : this.oldStatus
  3731. }
  3732. return this.connection
  3733. };
  3734. Peer.prototype.getHostAsBuffer = function() {
  3735. return new Buffer(this.host.split("."))
  3736. };
  3737. Peer.prototype.toString = function() {
  3738. return this.host + ":" + this.port
  3739. };
  3740. Peer.prototype.toBuffer = function() {
  3741. return ""
  3742. };
  3743.  
  3744. function PeerProcessor(node) {
  3745. events.EventEmitter.call(this);
  3746. var self = this;
  3747. var client, server;
  3748. this.node = node;
  3749. this.synced = false;
  3750. this.enabled = false;
  3751. this.timer = null;
  3752. this.peers = new Map();
  3753. this.forcePeers = new Map();
  3754. this.connections = new Map();
  3755. this.isConnected = false;
  3756. this.peerDiscovery = true;
  3757. this.interval = 5e3;
  3758. this.minConnections = 8;
  3759. this.MAX_ADDR_COUNT = 1e3
  3760. }
  3761. util.inherits(PeerProcessor, events.EventEmitter);
  3762. PeerProcessor.prototype.getActivePeersArr = function() {
  3763. var activePeers = [];
  3764. this.connections.map(function(connection, key) {
  3765. activePeers.push(connection.peer)
  3766. }.bind(this));
  3767. return activePeers
  3768. };
  3769. PeerProcessor.prototype.run = function() {
  3770. this.enabled = true;
  3771. var initialPeers = Config.starPeers;
  3772. var forcePeers = Config.starPeers;
  3773. initialPeers.forEach(function(peer) {
  3774. if ("string" !== typeof peer) {
  3775. throw new Error("PeerManager.enable(): Invalid Configuration for initial" + "peers.")
  3776. }
  3777. this.addPeer(peer)
  3778. }.bind(this));
  3779. forcePeers.forEach(function(peer) {
  3780. if ("string" !== typeof peer) {
  3781. throw new Error("PeerManager.enable(): Invalid Configuration for initial" + "peers.")
  3782. }
  3783. var _peer = new Peer(peer);
  3784. this.forcePeers.set(_peer.toString(), _peer)
  3785. }.bind(this));
  3786. this.server = net.createServer(function(socketConn) {
  3787. try {
  3788. var peer = new Peer(socketConn.remoteAddress, Config.peerPort);
  3789. this.addConnection(socketConn, peer)
  3790. } catch (e) {
  3791. logger.error("Add peer errror: " + JSON.stringify(e))
  3792. }
  3793. }.bind(this));
  3794. logger.netdbg("this.server.listen on port: " + Config.peerPort);
  3795. this.server.listen(Config.peerPort);
  3796. if (!this.timer) {
  3797. this.pingStatus()
  3798. }
  3799. };
  3800. PeerProcessor.prototype.addPeer = function(peer, port) {
  3801. if (peer instanceof Peer) {
  3802. logger.netdbg("Add peer: " + peer.toString());
  3803. var defStatus = Peer.prototype.statuses.DISABLE;
  3804. if (!this.peers.has(peer.toString())) {
  3805. PeersDb.addReplacePeer(peer);
  3806. this.peers.set(peer.toString(), peer)
  3807. } else if (peer.status != defStatus) {
  3808. var _peer;
  3809. if (this.connections.has(peer.toString()) && (_peer = this.connections.get(peer.toString()).peer).status == defStatus) {
  3810. _peer.status = peer.status
  3811. }
  3812. if ((_peer = this.peers.get(peer.toString())).status == defStatus) {
  3813. _peer.status = peer.status
  3814. }
  3815. }
  3816. } else if ("string" == typeof peer) {
  3817. this.addPeer(new Peer(peer, port))
  3818. } else {
  3819. logger.log("error", "Node.addPeer(): Invalid value provided for peer", {
  3820. val: peer
  3821. });
  3822. throw "Node.addPeer(): Invalid value provided for peer."
  3823. }
  3824. };
  3825. PeerProcessor.prototype.connectTo = function(peer) {
  3826. logger.netdbg("Connecting to peer " + peer);
  3827. try {
  3828. return this.addConnection(peer.getConnection(), peer)
  3829. } catch (e) {
  3830. logger.error("Error creating connection", e);
  3831. return null
  3832. }
  3833. };
  3834. PeerProcessor.prototype.addConnection = function(socketConn, peer) {
  3835. var conn = new Connection(socketConn, peer);
  3836. this.connections.set(conn.peer.toString(), conn);
  3837. this.node.addConnection(conn);
  3838. conn.addListener("connect", this.handleConnect.bind(this));
  3839. conn.addListener("error", this.handleError.bind(this));
  3840. conn.addListener("disconnect", this.handleDisconnect.bind(this));
  3841. conn.addListener(Connection.prototype.commands.VERSION, this.handleVersion.bind(this));
  3842. conn.addListener(Connection.prototype.commands.READY, this.handleReady.bind(this));
  3843. conn.addListener(Connection.prototype.commands.ADDRESSES, this.handleAddr.bind(this));
  3844. conn.addListener(Connection.prototype.commands.GET_ADDRESSES, this.handleGetAddr.bind(this));
  3845. conn.addListener(Connection.prototype.commands.GET_LAST_TRANSACTION, this.handleGetLastTransaction.bind(this));
  3846. conn.addListener(Connection.prototype.commands.LAST_TRANSACTION, this.handleLastTransaction.bind(this));
  3847. conn.addListener(Connection.prototype.commands.BLOCK, this.handleBlock.bind(this));
  3848. conn.addListener(Connection.prototype.commands.GET_NEXT_BLOCK, this.handleGetNextBlock.bind(this));
  3849. conn.addListener(Connection.prototype.commands.NEW_TRANSACTION, this.handleNewTransaction.bind(this));
  3850. conn.addListener(Connection.prototype.commands.BROADCAST, this.handleBroadcast.bind(this));
  3851. conn.addListener(Connection.prototype.commands.PEER_STATUS, this.handlePeerStatus.bind(this));
  3852. conn.addListener(Connection.prototype.commands.UNCONFIRMED_TRANSACTIONS, this.handleUnconfirmedTransactions.bind(this));
  3853. return conn
  3854. };
  3855. PeerProcessor.prototype.getActiveConnections = function() {
  3856. return this.connections
  3857. };
  3858. PeerProcessor.prototype.handleConnect = function(e) {
  3859. logger.netdbg("Handle Connect\n" + e.conn.toString());
  3860. this.addPeer(e.peer)
  3861. };
  3862. PeerProcessor.prototype.handleVersion = function(e) {
  3863. logger.netdbg("Handle Version\n" + e.conn.toString());
  3864. if (!e.conn.inbound) {
  3865. this.addPeer(e.peer)
  3866. }
  3867. if (this.peerDiscovery) {
  3868. e.conn.sendGetAddr();
  3869. e.conn.getaddr = true
  3870. }
  3871. };
  3872. PeerProcessor.prototype.handleReady = function(e) {
  3873. logger.netdbg("Handle Ready\n" + e.conn.toString());
  3874. this.addPeer(e.peer);
  3875. this.emit("connect", {
  3876. pm: this,
  3877. conn: e.conn,
  3878. socket: e.socket,
  3879. peer: e.peer
  3880. });
  3881. if (this.isConnected == false) {
  3882. this.emit("netConnected");
  3883. this.isConnected = true
  3884. }
  3885. };
  3886. PeerProcessor.prototype.handleAddr = function(e) {
  3887. if (!this.peerDiscovery) {
  3888. return
  3889. }
  3890. logger.netdbg("Handle Addr\n" + e.conn.toString());
  3891. if (typeof e.message.addrs !== "undefined") {
  3892. var peer, defStatus = Peer.prototype.statuses.DISABLE;
  3893. e.peer.status = e.message.netStatus || defStatus;
  3894. e.message.addrs.forEach(function(addr) {
  3895. try {
  3896. peer = new Peer(addr.ip, addr.port, addr.services);
  3897. peer.status = addr.status || defStatus;
  3898. this.addPeer(peer)
  3899. } catch (e) {
  3900. logger.warn("Invalid addr received: " + e.message)
  3901. }
  3902. }.bind(this));
  3903. if (e.message.addrs.length < 1e3) {
  3904. e.conn.getaddr = false
  3905. }
  3906. }
  3907. };
  3908. PeerProcessor.prototype.handleGetAddr = function(e) {
  3909. logger.netdbg("Handle GetAddr\n", e.conn.toString());
  3910. var addressesCount = this.peers.length;
  3911. if (addressesCount > this.MAX_ADDR_COUNT) {
  3912. addressesCount = this.MAX_ADDR_COUNT
  3913. }
  3914. var peers = this.peers.values();
  3915. var addrs = [],
  3916. connection = null,
  3917. status, defStatus = Peer.prototype.statuses.DISABLE;
  3918. for (var i = 0; i < addressesCount; i++) {
  3919. if (e.peer.host === peers[i].host) {
  3920. continue
  3921. }
  3922. connection = this.connections.get(peers[i].toString());
  3923. status = defStatus;
  3924. if (typeof connection !== "undefined") {
  3925. status = connection.peer.status
  3926. }
  3927. addrs.push({
  3928. services: peers[i].services,
  3929. ip: peers[i].host,
  3930. port: peers[i].port,
  3931. status: status
  3932. })
  3933. }
  3934. e.conn.sendMessage(Connection.prototype.commands.ADDRESSES, {
  3935. addrs: addrs,
  3936. netStatus: this.node.netStatus
  3937. })
  3938. };
  3939. PeerProcessor.prototype.handleError = function(e) {
  3940. logger.netdbg("Handle Error\n" + e.conn.toString());
  3941. this.handleDisconnect.apply(this, [].slice.call(arguments))
  3942. };
  3943. PeerProcessor.prototype.handleDisconnect = function(e) {
  3944. logger.netdbg("Handle Disconnect\n" + e.conn.toString());
  3945. logger.netdbg("Disconnected from peer " + e.peer);
  3946. var key = e.peer.toString();
  3947. if (this.connections.has(key)) {
  3948. this.connections.delete(key)
  3949. }
  3950. if (this.peers.has(key)) {
  3951. this.peers.get(key).connectionLost()
  3952. }
  3953. e.peer.connectionLost();
  3954. if (!this.connections.length) {
  3955. this.emit("netDisconnected");
  3956. this.isConnected = false
  3957. }
  3958. };
  3959. PeerProcessor.prototype.pingStatus = function pingStatus() {
  3960. if (!this.enabled) {
  3961. return
  3962. }
  3963. this.checkStatus();
  3964. this.clearLostPeers();
  3965. this.timer = setTimeout(this.pingStatus.bind(this), this.interval)
  3966. };
  3967. PeerProcessor.prototype.checkStatus = function checkStatus() {
  3968. if (this.forcePeers.length) {
  3969. this.forcePeers.map(function(peer, key) {
  3970. if (!this.connections.has(key)) {
  3971. this.connectTo(peer)
  3972. }
  3973. }.bind(this))
  3974. }
  3975. var connectablePeers = [];
  3976. this.peers.map(function(peer, key) {
  3977. if (!this.connections.has(key)) {
  3978. connectablePeers.push(peer)
  3979. }
  3980. }.bind(this));
  3981. while (this.connections.length < this.minConnections && connectablePeers.length) {
  3982. var peer = connectablePeers.splice(Math.random() * connectablePeers.length, 1);
  3983. this.connectTo(peer[0])
  3984. }
  3985. };
  3986. PeerProcessor.prototype.clearLostPeers = function() {
  3987. var lostPeers = this.peers.filter(function(peer, key) {
  3988. if (!this.connections.has(key)) {
  3989. peer.connectionLost()
  3990. }
  3991. if (peer.isLost()) {
  3992. logger.netdbg("Removed peer " + key);
  3993. return true
  3994. }
  3995. return false
  3996. }.bind(this));
  3997. if (lostPeers.length) {
  3998. this.peers.deleteEach(lostPeers.keys())
  3999. }
  4000. };
  4001. PeerProcessor.prototype.sendTransaction = function(trans) {
  4002. if (this.forcePeers.length) {
  4003. var connectionCount = 0;
  4004. var connection = null;
  4005. this.forcePeers.map(function(peer, key) {
  4006. if (this.connections.has(key)) {
  4007. connection = this.connections.get(key);
  4008. connection.sendNewTransaction();
  4009. connectionCount++
  4010. }
  4011. }.bind(this));
  4012. if (connectionCount === 0) {
  4013. logger.netdbg("Error: no connection to force peers.")
  4014. }
  4015. } else {
  4016. logger.netdbg("Error: forcePeers is empty.")
  4017. }
  4018. };
  4019. PeerProcessor.prototype.syncTransaction = function() {
  4020. if (this.forcePeers.length) {
  4021. var connectionCount = 0;
  4022. var connection = null;
  4023. this.forcePeers.some(function(peer, key) {
  4024. if (this.connections.has(key)) {
  4025. connection = this.connections.get(key);
  4026. connection.sendGetLastTransaction();
  4027. connectionCount++
  4028. }
  4029. }.bind(this));
  4030. if (connectionCount === 0) {
  4031. logger.netdbg("Error: no connection to force peers.")
  4032. }
  4033. } else {
  4034. logger.netdbg("Error: forcePeers is empty.")
  4035. }
  4036. };
  4037. PeerProcessor.prototype.handleLastTransaction = function(e) {
  4038. logger.netdbg("Handle Last Transaction \n", e.conn.toString());
  4039. if (!e.message.data) {
  4040. logger.error('Error: no data for "handleLastTransaction"');
  4041. return
  4042. }
  4043. var blockchain = new Blockchain();
  4044. var transaction = new Transaction(e.message.data);
  4045. var result = blockchain.getLastTransaction().compareTo(transaction);
  4046. var nextHeight = blockchain.getLastBlock().height + 1;
  4047. e.conn.sendGetNextBlock(nextHeight)
  4048. };
  4049. PeerProcessor.prototype.handleGetLastTransaction = function(e) {
  4050. logger.netdbg("Handle Get Last Transaction \n", e.conn.toString());
  4051. var blockchain = new Blockchain();
  4052. e.conn.sendLastTransaction(blockchain.getLastTransaction().getData())
  4053. };
  4054. var blockSyncBuffer = new Map();
  4055. var syncBlockRunning = false;
  4056. var unconfTxsSyncBuffer = new Map();
  4057. var syncUnconfTxsRunning = false;
  4058. PeerProcessor.prototype.handleBlock = function(e) {
  4059. var self = this;
  4060. logger.netdbg("Handle Block\n", e.conn.toString());
  4061. var blockData = e.message.data;
  4062. var tyransactionsArr = e.message.data.blockTransactions;
  4063. txArr = {
  4064. count: 0
  4065. };
  4066. tyransactionsArr.forEach(function(transactionData) {
  4067. var tx = new Transaction(transactionData);
  4068. txArr[tx.getId().toString()] = tx;
  4069. txArr.count += 1
  4070. });
  4071. blockData.blockTransactions = txArr;
  4072. var block = new Block(blockData);
  4073. var broadcasted = false;
  4074. if (typeof e.message.data.broadcasted !== "undefined" && e.message.data.broadcasted) {
  4075. broadcasted = true
  4076. }
  4077. blockSyncBuffer.set(blockData.id.toString(), {
  4078. block: block,
  4079. conn: e.conn,
  4080. broadcasted: broadcasted
  4081. });
  4082. this.processSyncBlock()
  4083. };
  4084. PeerProcessor.prototype.processSyncBlock = function() {
  4085. var self = this;
  4086. if (syncBlockRunning) {
  4087. return
  4088. }
  4089. syncBlockRunning = true;
  4090. var blockSyncBufferArr = blockSyncBuffer.toArray();
  4091. async.eachSeries(blockSyncBufferArr, function(data, callback) {
  4092. var conn = data.conn;
  4093. var block = data.block;
  4094. var broadcasted = data.broadcasted;
  4095. blockSyncBuffer.delete(block.id.toString());
  4096. BlockDb.hasBlock(block.id.toString(), function(exist) {
  4097. if (!exist) {
  4098. BlockchainProcessor.pushBlock(block, function() {
  4099. logger.warn("block pushed OK id:" + block.id.toString());
  4100. BlockDb.setNextBlockId(block.previousBlockId.toString(), block.getId().toString(), function() {
  4101. block.confirmations = block.confirmations + 1;
  4102. BlockchainProcessor.addBlock(block, false, function() {
  4103. logger.warn("Block saved OK id:" + block.id.toString());
  4104. if (!broadcasted) {
  4105. block.addUnconfirmedAmounts();
  4106. conn.sendGetLastTransaction()
  4107. }
  4108. callback()
  4109. })
  4110. })
  4111. })
  4112. } else {
  4113. logger.info("Block exist, continue on height: " + block.height);
  4114. BlockDb.addConfirmation(block.id.toString(), function() {
  4115. callback()
  4116. })
  4117. }
  4118. })
  4119. }, function(err, callback) {
  4120. if (err) {
  4121. logger.error(err)
  4122. }
  4123. syncBlockRunning = false
  4124. })
  4125. };
  4126. PeerProcessor.prototype.handleGetNextBlock = function(e) {
  4127. logger.netdbg("Handle Get Next Block \n", e.conn.toString());
  4128. var height = e.message.data || null;
  4129. var blockchain = new Blockchain();
  4130. if (parseInt(height) > blockchain.getLastBlock().height) {
  4131. UnconfirmedTransactions.getAllTransactionsList(function(unconfTxsData) {
  4132. e.conn.sendUnconfirmedTransactions(unconfTxsData)
  4133. })
  4134. } else if (height) {
  4135. BlockDb.findBlockIdAtHeight(height, function(block) {
  4136. if (block) {
  4137. logger.transdbg("Send block at heifght - " + e.height);
  4138. e.conn.sendBlock(block.getDataWithTransactions())
  4139. } else {
  4140. logger.warn("No block at heifght - " + e.height)
  4141. }
  4142. })
  4143. } else {
  4144. e.conn.sendBlock({})
  4145. }
  4146. };
  4147. var newTxsSyncBuffer = [];
  4148. var newTxsRunning = false;
  4149. PeerProcessor.prototype.handleNewTransaction = function(e) {
  4150. var transactionData = e.message.data || null;
  4151. logger.netdbg("Handle New Transaction \n", e.conn.toString());
  4152. if (!transactionData) {
  4153. return
  4154. }
  4155. newTxsSyncBuffer.push(transactionData);
  4156. this.processNewTransaction()
  4157. };
  4158. PeerProcessor.prototype.processNewTransaction = function() {
  4159. if (newTxsRunning) {
  4160. return
  4161. }
  4162. newTxsRunning = true;
  4163. async.eachSeries(newTxsSyncBuffer, function(transactionData, callback) {
  4164. var transaction = new Transaction(transactionData);
  4165. var transactionProcessor = new TransactionProcessor();
  4166. transactionProcessor.verifiyTransaction(transaction, function(err) {
  4167. if (err) {
  4168. logger.warn(err);
  4169. callback()
  4170. } else {
  4171. transactionProcessor.addTransactionOrConfirmation(transaction, false);
  4172. callback()
  4173. }
  4174. })
  4175. }, function(err) {
  4176. newTxsRunning = false;
  4177. newTxsSyncBuffer = []
  4178. })
  4179. };
  4180. PeerProcessor.prototype.handleUnconfirmedTransactions = function(e) {
  4181. var self = this;
  4182. logger.netdbg("Handle Unconfirmed Transactions\n", e.conn.toString());
  4183. var unconfTxsData = e.message.data || null;
  4184. if (syncUnconfTxsRunning) {
  4185. return
  4186. }
  4187. syncUnconfTxsRunning = true;
  4188. if (unconfTxsData.length) {
  4189. async.eachSeries(unconfTxsData, function(txData, callback) {
  4190. UnconfirmedTransactions.hasTransaction(txData.id, function(exist) {
  4191. if (!exist) {
  4192. var transaction = new Transaction(txData);
  4193. var transactionProcessor = new TransactionProcessor();
  4194. transactionProcessor.verifiyTransaction(transaction, unconfTxsData, function(err) {
  4195. if (err) {
  4196. logger.warn(err);
  4197. callback(err)
  4198. } else {
  4199. transactionProcessor.addTransactionOrConfirmation(transaction, true);
  4200. callback()
  4201. }
  4202. })
  4203. }
  4204. })
  4205. }, function(err) {
  4206. if (err) {
  4207. logger.error("ERROR PeerProcessor.prototype.handleUnconfirmedTransactions " + err);
  4208. syncUnconfTxsRunning = false
  4209. } else {
  4210. syncUnconfTxsRunning = false;
  4211. self.synced = true;
  4212. self.node.setState("synced");
  4213. self.node.broadcastPeerStatus(Peer.prototype.statuses.SYNCED)
  4214. }
  4215. })
  4216. } else {
  4217. this.synced = true;
  4218. self.node.setState("synced");
  4219. this.node.broadcastPeerStatus(Peer.prototype.statuses.SYNCED)
  4220. }
  4221. };
  4222. PeerProcessor.prototype.handleBroadcast = function(e) {
  4223. logger.netdbg("Handle Broadcast\n", e.conn.toString())
  4224. };
  4225. PeerProcessor.prototype.handlePeerStatus = function(e) {
  4226. logger.netdbg("Handle Peer Status\n", e.conn.toString());
  4227. e.peer.status = e.message.data.status || Peer.prototype.statuses.DISABLE
  4228. };
  4229. var AccountHandlers = function() {};
  4230. AccountHandlers.loginAccount = function loginAccount(response, params, request) {
  4231. if (!NodeServer.peerProcessor.synced) {
  4232. ResponseHelper.end500(response, "Not synced yet!!")
  4233. }
  4234. var user = new User(params.userId);
  4235. var accountId = user.loginAccount(params.walletKey);
  4236. var publicKey = user.getPublicKey().toString("hex");
  4237. logger.info("user.getPublicKey()", publicKey);
  4238. Account.insertNewAccount({
  4239. accountId: accountId,
  4240. publicKey: publicKey
  4241. }, request);
  4242. Account.addOrGetAccount(accountId.toString());
  4243. Account.setCurrentAccount({
  4244. accountId: accountId,
  4245. accountSecret: user.getSecretWord().toString("hex")
  4246. });
  4247. Account.getAccounts(accountId, function(accounts) {
  4248. TransactionDb.getLastTransactions(10, function(recentTransactions) {
  4249. TransactionDb.getMyAllTransactions(accountId, function(myTransactions) {
  4250. UnconfirmedTransactions.getMyAllTransactions(accountId, function(unconfTrans) {
  4251. myTransactions = unconfTrans.concat(myTransactions);
  4252. ResponseHelper.end200Text(response, JSON.stringify({
  4253. accountId: accountId,
  4254. accountSecret: user.getSecretWord().toString("hex"),
  4255. accountTypes: accounts,
  4256. recentTransactions: recentTransactions || [],
  4257. myTransactions: myTransactions
  4258. }))
  4259. })
  4260. })
  4261. })
  4262. })
  4263. };
  4264. AccountHandlers.getAccountTransactions = function getAccountTransactions(response, params, request) {
  4265. TransactionDb.getLastTransactions(10, function(recentTransactions) {
  4266. TransactionDb.getMyAllTransactions(params.accountId, function(myTransactions) {
  4267. UnconfirmedTransactions.getMyAllTransactions(params.accountId, function(unconfTrans) {
  4268. UnconfirmedTransactions.getAllTransactionsList(function(unconfTransAll) {
  4269. myTransactions = unconfTrans.concat(myTransactions);
  4270. recentTransactions = unconfTransAll.concat(recentTransactions);
  4271. ResponseHelper.end200Text(response, JSON.stringify({
  4272. recentTransactions: recentTransactions || [],
  4273. myTransactions: myTransactions
  4274. }))
  4275. })
  4276. })
  4277. })
  4278. })
  4279. };
  4280. AccountHandlers.getMyTransactions = function getMyTransactions(response, params, request) {
  4281. TransactionDb.getMyAllTransactions(params.accountId, function(myTransactions) {
  4282. ResponseHelper.end200Text(response, JSON.stringify({
  4283. myTransactions: myTransactions
  4284. }))
  4285. })
  4286. };
  4287. AccountHandlers.logoutAccount = function logoutAccount(response) {
  4288. Account.currentAccount = null;
  4289. NodeServer.broadcastPeerStatus(Peer.prototype.statuses.DISABLE);
  4290. NodeServer.startCheckSynced();
  4291. ResponseHelper.end200Text(response, JSON.stringify({
  4292. logout: true
  4293. }))
  4294. };
  4295. AccountHandlers.getAccountByHash = function getAccountByHash(response, params, request) {
  4296. if (typeof params.secret === "undefined") {
  4297. ResponseHelper.end403(response);
  4298. return
  4299. }
  4300. var account = Account.createFromSecretWord(params.secret);
  4301. Account.getAccounts(account.id, function(accountNums) {
  4302. account.accountTypes = accountNums;
  4303. TransactionDb.getLastTransactions(10, function(recentTransactions) {
  4304. account.recentTransactions = recentTransactions;
  4305. ResponseHelper.end200Text(response, JSON.stringify(account))
  4306. })
  4307. })
  4308. };
  4309. AccountHandlers.showAccounts = function showAccounts(response, params) {
  4310. if (params.key === Config.serverKey) {
  4311. Account.getRegisteredAccounts(function(err, docs) {
  4312. response.writeHead(200, {
  4313. "Content-Type": "text/html"
  4314. });
  4315. var tplStr = swig.renderFile(appDir + "/frontend/showAcc.html", {
  4316. accounts: docs
  4317. });
  4318. response.end(tplStr)
  4319. })
  4320. } else {
  4321. ResponseHelper.end403(response)
  4322. }
  4323. };
  4324. AccountHandlers.getAccounts = function getAccounts(response, params, request) {
  4325. ResponseHelper.end200Text(response, JSON.stringify(Account.accounts))
  4326. };
  4327. var BlockHandlers = function() {};
  4328. BlockHandlers.showAllBlocks = function(response, params, request) {
  4329. BlockDb.getLastBlocksList(25, function(res) {
  4330. var data = [];
  4331. async.eachSeries(res, function(blockData, _callback) {
  4332. var block = new Block(blockData);
  4333. BlockDb.findRelatedTransactions(block, function(block) {
  4334. data.push(block.getDataWithTransactions());
  4335. _callback()
  4336. })
  4337. }, function(err) {
  4338. if (err) {
  4339. ResponseHelper.end500(response, err)
  4340. } else {
  4341. response.writeHead(200, {
  4342. "Content-Type": "text/plain"
  4343. });
  4344. response.write(JSON.stringify(data));
  4345. response.end()
  4346. }
  4347. })
  4348. })
  4349. };
  4350. var BlockchainexplHandlers = function() {};
  4351. BlockchainexplHandlers.index = function(response, params, request) {
  4352. response.writeHead(200, {
  4353. "Content-Type": "text/html"
  4354. });
  4355. var tplStr = swig.renderFile(appDir + "/frontend/blockchainExpl.html", {});
  4356. response.end(tplStr)
  4357. };
  4358. var PeersHandlers = function() {};
  4359. PeersHandlers.getAllPeersText = function(response, params, request) {
  4360. var peersObj = NodeServer.peerProcessor;
  4361. var peers = peersObj.getActivePeersArr();
  4362. var activePeersStr = "";
  4363. for (var id in peers) {
  4364. if (peers.hasOwnProperty(id)) {
  4365. activePeersStr += JSON.stringify(peers[id].getData()) + "\n<br/>"
  4366. }
  4367. }
  4368. PeersDb.getAllPeersList(function(archivedPeers) {
  4369. ResponseHelper.end200Text(response, "Active peers:\n" + JSON.stringify(activePeersStr + "\n<br/><br/><br/>\n\nArchived Peers:\n" + JSON.stringify(archivedPeers)))
  4370. })
  4371. };
  4372. PeersHandlers.getAllPeersJSON = function(response, params, request) {
  4373. var peersObj = NodeServer.peerProcessor;
  4374. var peersData = [];
  4375. var peers = peersObj.getActivePeersArr();
  4376. for (var id in peers) {
  4377. if (peers.hasOwnProperty(id)) {
  4378. peersData.push(peers[id].getData())
  4379. }
  4380. }
  4381. ResponseHelper.end200Text(response, JSON.stringify(peersData))
  4382. };
  4383. RequestHandlers = function() {};
  4384. swig.setDefaults({
  4385. locals: {
  4386. host: Config.host,
  4387. port: Config.port
  4388. }
  4389. });
  4390. RequestHandlers.start = function(response) {
  4391. response.writeHead(200, {
  4392. "Content-Type": "text/html"
  4393. });
  4394. var tplStr = swig.renderFile(appDir + "/frontend/index.html", {});
  4395. response.end(tplStr)
  4396. };
  4397. RequestHandlers.broadcast = function(response, params) {
  4398. response.writeHead(200, {
  4399. "Content-Type": "text/plain"
  4400. });
  4401. NodeServer.broadcast({
  4402. message: params.message
  4403. });
  4404. response.write("sending");
  4405. response.end()
  4406. };
  4407. RequestHandlers.checkLoading = function(response, prams) {
  4408. ResponseHelper.end200Text(response, JSON.stringify({
  4409. loading: !NodeServer.peerProcessor.synced
  4410. }))
  4411. };
  4412. var TransactionHandlers = function() {};
  4413. TransactionHandlers.showAllTransactions = function(response, params, request) {
  4414. UnconfirmedTransactions.getAllTransactionsList(function(res) {
  4415. response.writeHead(200, {
  4416. "Content-Type": "text/plain"
  4417. });
  4418. response.write(JSON.stringify(res));
  4419. response.end()
  4420. })
  4421. };
  4422. TransactionHandlers.validateTransactionParams = function(response, params) {
  4423. var result = {
  4424. err: false,
  4425. result: null
  4426. };
  4427. logger.info(params);
  4428. var errs = {};
  4429. if (typeof params.recipientId == "undefined" || params.recipientId == "") {
  4430. errs.recipientId = true
  4431. }
  4432. var account = Account.createFromSecretWord(params.accountSecret);
  4433. if (account.id.toString() == params.recipientId) {
  4434. errs.recipientId = true
  4435. }
  4436. logger.info("parseFloat(params.amount)", parseFloat(params.amount));
  4437. var regEx = /^([0-9])*\.{0,1}([0-9])*$/g;
  4438. if (typeof params.amount == "undefined" || params.amount == 0 || parseFloat(params.amount) < 1e-5 || !params.amount.match(regEx)) {
  4439. errs.amount = true
  4440. }
  4441. if (typeof params.accountSecret == "undefined" || params.accountSecret == "") {
  4442. errs.accountSecret = true
  4443. }
  4444. if (!Utils.isEmptyObj(errs)) {
  4445. result.err = errs;
  4446. response.writeHead(200, {
  4447. "Content-Type": "text/plain"
  4448. });
  4449. response.write(JSON.stringify(result));
  4450. response.end();
  4451. return false
  4452. }
  4453. return result
  4454. };
  4455. TransactionHandlers.validateTransactionAmount = function(response, params, result, account, accounts) {
  4456. if (accounts == null || params.amount + params.fee > parseFloat(accounts.nxtlAccount.unconfirmedAmount)) {
  4457. logger.info("Not Enough money accId:", account.accountId);
  4458. result.err = {
  4459. amount: true
  4460. };
  4461. response.writeHead(200, {
  4462. "Content-Type": "text/plain"
  4463. });
  4464. response.write(JSON.stringify(result));
  4465. response.end();
  4466. return false
  4467. }
  4468. return true
  4469. };
  4470. TransactionHandlers.validateTransaction = function(response, params, request) {
  4471. var result = TransactionHandlers.validateTransactionParams(response, params);
  4472. if (result === false) {
  4473. return false
  4474. }
  4475. params.amount = Utils.roundTo5Float(params.amount);
  4476. params.fee = Utils.roundTo5Float(params.amount * .0035) > 1e-5 ? Utils.roundTo5Float(params.amount * .0035) : 1e-5;
  4477. var account = Account.createFromSecretWord(params.accountSecret);
  4478. Account.getAccounts(account.id, function(accounts) {
  4479. if (TransactionHandlers.validateTransactionAmount(response, params, result, account, accounts) === false) {
  4480. return false
  4481. } else {
  4482. result.result = true;
  4483. response.writeHead(200, {
  4484. "Content-Type": "text/plain"
  4485. });
  4486. response.write(JSON.stringify(result));
  4487. response.end();
  4488. return true
  4489. }
  4490. });
  4491. return true
  4492. };
  4493. TransactionHandlers.addTransaction = function(response, params, request) {
  4494. var result = TransactionHandlers.validateTransactionParams(response, params);
  4495. if (result === false) {
  4496. return false
  4497. }
  4498. var blockchain = new Blockchain();
  4499. params.amount = Utils.roundTo5Float(params.amount);
  4500. params.fee = Utils.roundTo5Float(params.amount * .0035) > 1e-5 ? Utils.roundTo5Float(params.amount * .0035) : 1e-5;
  4501. var referencedTransactionId = blockchain.getLastTransaction();
  4502. var account = Account.createFromSecretWord(params.accountSecret);
  4503. Account.getAccounts(account.id, function(accounts) {
  4504. if (TransactionHandlers.validateTransactionAmount(response, params, result, account, accounts) === false) {
  4505. return false
  4506. }
  4507. var transaction = new Transaction({
  4508. type: TransactionType.Payment,
  4509. timestamp: new Date().getTime(),
  4510. deadline: params.deadline,
  4511. senderPublicKey: account.publicKey,
  4512. recipientId: params.recipientId,
  4513. amount: params.amount,
  4514. fee: params.fee,
  4515. referencedTransactionId: referencedTransactionId.id,
  4516. signature: null
  4517. });
  4518. transaction.sign(params.accountSecret);
  4519. var transactionProcessor = new TransactionProcessor();
  4520. transactionProcessor.addTransactionOrConfirmation(transaction);
  4521. result.result = {
  4522. transactionId: transaction.getId().toString()
  4523. };
  4524. response.writeHead(200, {
  4525. "Content-Type": "text/plain"
  4526. });
  4527. response.write(JSON.stringify(result));
  4528. response.end();
  4529. return true
  4530. });
  4531. return true
  4532. };
  4533. TransactionHandlers.getLastTransaction = function(response, params, request) {
  4534. TransactionDb.getLastTransaction(function(res) {
  4535. response.writeHead(200, {
  4536. "Content-Type": "text/plain"
  4537. });
  4538. response.write(JSON.stringify(res));
  4539. response.end()
  4540. })
  4541. };
  4542. TransactionHandlers.getTransactionByUser = function(response, params, request) {
  4543. TransactionDb.getMyAllTransactions(params.userId, function(res) {
  4544. response.writeHead(200, {
  4545. "Content-Type": "text/plain"
  4546. });
  4547. response.write(JSON.stringify(res));
  4548. response.end()
  4549. })
  4550. };
  4551. var handle = {};
  4552. handle["/"] = RequestHandlers.start;
  4553. handle["/app/checkLoading"] = RequestHandlers.checkLoading;
  4554. handle["/account/login"] = AccountHandlers.loginAccount;
  4555. handle["/account/getAccountTransactions"] = AccountHandlers.getAccountTransactions;
  4556. handle["/account/getMyTransactions"] = AccountHandlers.getMyTransactions;
  4557. handle["/account/getAccounts"] = AccountHandlers.getAccounts;
  4558. handle["/account/getAccountByHash"] = AccountHandlers.getAccountByHash;
  4559. handle["/account/logoutAccount"] = AccountHandlers.logoutAccount;
  4560. handle["/showAccounts"] = AccountHandlers.showAccounts;
  4561. handle["/block/showAllBlocks"] = BlockHandlers.showAllBlocks;
  4562. handle["/transaction/showAllTransactions"] = TransactionHandlers.showAllTransactions;
  4563. handle["/transaction/addTransaction"] = TransactionHandlers.addTransaction;
  4564. handle["/transaction/validateTransaction"] = TransactionHandlers.validateTransaction;
  4565. handle["/transaction/getLastTransaction"] = TransactionHandlers.getLastTransaction;
  4566. handle["/transaction/getTransactionByUser"] = TransactionHandlers.getTransactionByUser;
  4567. handle["/blockchainexpl/"] = BlockchainexplHandlers.index;
  4568. handle["/getAllPeersText"] = PeersHandlers.getAllPeersText;
  4569. handle["/getAllPeersJSON"] = PeersHandlers.getAllPeersJSON;
  4570. handle["/api/broadcast"] = RequestHandlers.broadcast;
  4571. var PostRequestProcess = function() {};
  4572. PostRequestProcess.processPost = function processPost(request, response, callback) {
  4573. var queryData = "";
  4574. if (typeof callback !== "function") return null;
  4575. if (request.method == "POST") {
  4576. request.on("data", function(data) {
  4577. queryData += data;
  4578. if (queryData.length > 1e6) {
  4579. queryData = "";
  4580. response.writeHead(413, {
  4581. "Content-Type": "text/plain"
  4582. }).end();
  4583. request.connection.destroy()
  4584. }
  4585. });
  4586. request.on("end", function() {
  4587. response.post = querystring.parse(queryData);
  4588. callback()
  4589. })
  4590. } else {
  4591. response.writeHead(405, {
  4592. "Content-Type": "text/plain"
  4593. });
  4594. response.end()
  4595. }
  4596. };
  4597. var ResponseHelper = function() {};
  4598. ResponseHelper.end404 = function(response) {
  4599. response.writeHead(404, {
  4600. "Content-Type": "text/plain"
  4601. });
  4602. response.write("404 Not found");
  4603. response.end()
  4604. };
  4605. ResponseHelper.end403 = function(response) {
  4606. response.writeHead(403, {
  4607. "Content-Type": "text/plain"
  4608. });
  4609. response.write("You can't access this area.");
  4610. response.end()
  4611. };
  4612. ResponseHelper.end500 = function(response, err) {
  4613. response.writeHead(500, {
  4614. "Content-Type": "text/plain"
  4615. });
  4616. response.write(err + "\n");
  4617. response.end()
  4618. };
  4619. ResponseHelper.end200Text = function(response, data) {
  4620. response.writeHead(200, {
  4621. "Content-Type": "text/plain"
  4622. });
  4623. response.write(data);
  4624. response.end()
  4625. };
  4626. var Router = function() {};
  4627. Router.route = function route(handle, request, response) {
  4628. var urlParts = url.parse(request.url, true);
  4629. var pathname = urlParts.pathname;
  4630. if (typeof handle[pathname] === "function") {
  4631. if (request.method === "POST") {
  4632. PostRequestProcess.processPost(request, response, function() {
  4633. handle[pathname](response, response.post, request)
  4634. })
  4635. } else {
  4636. handle[pathname](response, urlParts.query, request)
  4637. }
  4638. } else {
  4639. var staticFilesPath = appDir + "/frontend/";
  4640. var filename = path.join(staticFilesPath, pathname);
  4641. logger.info("filename", filename);
  4642. fs.exists(filename, function(exists) {
  4643. if (!exists) {
  4644. logger.info("No request handler found for " + pathname);
  4645. ResponseHelper.end404(response);
  4646. return
  4647. }
  4648. if (fs.statSync(filename).isDirectory()) {
  4649. ResponseHelper.end403(response);
  4650. return
  4651. }
  4652. fs.readFile(filename, "binary", function(err, file) {
  4653. if (err) {
  4654. ResponseHelper.end500(response, err);
  4655. return
  4656. }
  4657. var type = mime.lookup(filename);
  4658. response.writeHead(200, {
  4659. "Content-Type": type
  4660. });
  4661. response.write(file, "binary");
  4662. response.end()
  4663. })
  4664. })
  4665. }
  4666. };
  4667. var User = function(_userId) {
  4668. var userId;
  4669. var secretWord;
  4670. var publicKey;
  4671. var isInactive = false;
  4672. userId = _userId;
  4673. this.getId = function() {
  4674. return userId
  4675. };
  4676. this.getPublicKey = function() {
  4677. return publicKey
  4678. };
  4679. this.getSecretWord = function() {
  4680. return secretWord
  4681. };
  4682. this.getIsInactive = function() {
  4683. return isInactive
  4684. };
  4685. this.setIsInactive = function(_isInactive) {
  4686. if (typeof _isInactive === "boolean") isInactive = _isInactive
  4687. };
  4688. this.loginAccount = function(_secretWord) {
  4689. secretWord = curve.sha256(_secretWord);
  4690. var nxtlPublicKeyHex = nxtCrypto.getPublicKey(secretWord.toString("hex"));
  4691. console.log("nxtCrypto", nxtlPublicKeyHex);
  4692. publicKey = new Buffer(nxtlPublicKeyHex, "hex");
  4693. return Account.getId(publicKey)
  4694. };
  4695. this.logoutAccount = function() {
  4696. secretWord = null
  4697. }
  4698. };
  4699. var Account = function(id) {
  4700. this.id = id;
  4701. this.height = 0;
  4702. this.publicKey = null;
  4703. this.keyHeight = null;
  4704. this.balance = 0;
  4705. this.unconfirmedBalance = 0;
  4706. this.guaranteedBalances = {};
  4707. this.assetBalances = {};
  4708. this.unconfirmedAssetBalances = {};
  4709. this.accountTypes = {}
  4710. };
  4711. Account.accounts = {};
  4712. Account.currentAccount = null;
  4713. Account.setCurrentAccount = function(account) {
  4714. if (Account.currentAccount !== null) {
  4715. logger.warn("Current account already set");
  4716. return false
  4717. }
  4718. Account.currentAccount = account
  4719. };
  4720. Account.createFromSecretWord = function(secret) {
  4721. if (secret instanceof Buffer) {
  4722. secret = secret.toString("hex")
  4723. }
  4724. var publicKey = nxtCrypto.getPublicKey(secret);
  4725. var accountId = Account.getId(new Buffer(publicKey, "hex"));
  4726. var account = Account.addOrGetAccount(accountId.toString());
  4727. account.publicKey = new Buffer(publicKey, "hex");
  4728. return account
  4729. };
  4730. Account.getId = function(publicKey) {
  4731. var publicKeyHash = curve.sha256(publicKey);
  4732. var longVal = Utils.bufferToLongLE(publicKeyHash);
  4733. return longVal.toString()
  4734. };
  4735. Account.getAccounts = function(accountId, _callback) {
  4736. var nxtlAccount = {};
  4737. var dollarAccount = {};
  4738. var euroAccount = {};
  4739. var btcAccount = {};
  4740. var accountNums;
  4741. async.waterfall([
  4742. function(callback) {
  4743. NxtlAccount.init(accountId, function(res) {
  4744. nxtlAccount = res;
  4745. callback(null)
  4746. })
  4747. },
  4748. function(callback) {
  4749. DollarAccount.init(accountId, function(res) {
  4750. dollarAccount = res;
  4751. callback(null)
  4752. })
  4753. },
  4754. function(callback) {
  4755. EuroAccount.init(accountId, function(res) {
  4756. euroAccount = res;
  4757. callback(null)
  4758. })
  4759. },
  4760. function(callback) {
  4761. BtcAccount.init(accountId, function(res) {
  4762. btcAccount = res;
  4763. callback(null)
  4764. })
  4765. }
  4766. ], function(err, result) {
  4767. if (err) {
  4768. console.log("Account.getAccounts Error", err)
  4769. }
  4770. accountNums = {
  4771. nxtlAccount: nxtlAccount.getSettings(),
  4772. dollarAccount: dollarAccount.getSettings(),
  4773. euroAccount: euroAccount.getSettings(),
  4774. btcAccount: btcAccount.getSettings()
  4775. };
  4776. if (typeof _callback === "function") {
  4777. _callback(accountNums)
  4778. }
  4779. })
  4780. };
  4781. Account.getAccount = function(_id) {
  4782. return Account.accounts[_id]
  4783. };
  4784. Account.addOrGetAccount = function(id) {
  4785. var account = new Account(id);
  4786. if (typeof Account.accounts[id] === "undefined") {
  4787. Account.accounts[id] = account
  4788. }
  4789. return Account.accounts[id]
  4790. };
  4791. Account.insertNewAccount = function(params, request, callback) {
  4792. if (typeof params === "undefined") {
  4793. console.log("empty params for new account insert.");
  4794. return false
  4795. }
  4796. var doc = {
  4797. type: "account",
  4798. accountId: params.accountId,
  4799. publicKeyStr: params.publicKey,
  4800. ip: request.connection.remoteAddress,
  4801. time: Utils.getDateTime()
  4802. };
  4803. logger.info("user doc", doc);
  4804. DB.db.insert(doc, function(err, newDocs) {
  4805. if (!err) {
  4806. if (typeof callback === "function") {
  4807. callback(newDocs)
  4808. }
  4809. } else {
  4810. console.log("insert_callback error", err)
  4811. }
  4812. });
  4813. return true
  4814. };
  4815. Account.getRegisteredAccounts = function(callback) {
  4816. if (typeof callback !== "function") {
  4817. callback = function(err, docs) {}
  4818. }
  4819. DB.db.find({
  4820. type: "account"
  4821. }).sort({
  4822. time: 1
  4823. }).exec(callback)
  4824. };
  4825. Account.prototype.setOrVerify = function(key, height) {
  4826. if (this.publicKey == null) {
  4827. this.publicKey = key;
  4828. this.keyHeight = -1;
  4829. return true
  4830. } else if (this.publicKey.toString("hex") == key.toString("hex")) {
  4831. return true
  4832. } else if (this.keyHeight == -1) {
  4833. console.log("DUPLICATE KEY!!!");
  4834. console.log("Account key for " + this.id + " was already set to a different one at the same height " + ", current height is " + height + ", rejecting new key");
  4835. return false
  4836. } else if (this.keyHeight >= height) {
  4837. console.log("DUPLICATE KEY!!!");
  4838. console.log("Changing key for account " + this.id + " at height " + height + ", was previously set to a different one at height " + this.keyHeight);
  4839. this.publicKey = key;
  4840. this.keyHeight = height;
  4841. return true
  4842. }
  4843. console.log("DUPLICATE KEY!!!");
  4844. console.log("Invalid key for account " + this.id + " at height " + height + ", was already set to a different one at height " + this.keyHeight);
  4845. return false
  4846. };
  4847. Account.prototype.apply = function(key, height) {};
  4848. Account.prototype.addToBalanceAndUnconfirmedBalance = function(amount) {
  4849. this.balance += amount;
  4850. this.unconfirmedBalance += amount
  4851. };
  4852. Account.prototype.addToBalance = function(amount) {
  4853. this.balance += amount
  4854. };
  4855. Account.prototype.addToUnconfirmedBalance = function(amount) {
  4856. this.unconfirmedBalance += amount
  4857. };
  4858. Account.isLogginedForForge = function() {
  4859. return !!Account.currentAccount
  4860. };
  4861. var AccountClass = function() {
  4862. var settings = {
  4863. name: "",
  4864. id: "",
  4865. postfix: "",
  4866. amount: 0,
  4867. unconfirmedAmount: 0
  4868. };
  4869. this.setId = function(_id) {
  4870. settings.id = _id
  4871. };
  4872. this.setName = function(_name) {
  4873. settings.name = _name
  4874. };
  4875. this.setAmount = function(_ammount) {
  4876. settings.amount = _ammount
  4877. };
  4878. this.setUnconfirmedAmount = function(_ammount) {
  4879. settings.unconfirmedAmount = _ammount
  4880. };
  4881. this.setPostfix = function(_postfix) {
  4882. settings.postfix = _postfix
  4883. };
  4884. this.getPostfix = function() {
  4885. return settings.postfix
  4886. };
  4887. this.getSettings = function() {
  4888. return settings
  4889. }
  4890. };
  4891. var BtcAccount = function() {
  4892. AccountClass.apply(this, Array.prototype.slice.call(arguments))
  4893. };
  4894. BtcAccount.prototype = new AccountClass();
  4895. BtcAccount.init = function(_id, _callback) {
  4896. var self = new BtcAccount();
  4897. self.setName("btc");
  4898. self.setPostfix("BTC");
  4899. self.setId("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W");
  4900. _callback(self)
  4901. };
  4902. var DollarAccount = function() {
  4903. AccountClass.apply(this, Array.prototype.slice.call(arguments))
  4904. };
  4905. DollarAccount.prototype = new AccountClass();
  4906. DollarAccount.init = function(_id, _callback) {
  4907. var self = new DollarAccount();
  4908. self.setName("dollar");
  4909. self.setPostfix("USD");
  4910. self.setId(_id + self.getPostfix());
  4911. _callback(self)
  4912. };
  4913. var EuroAccount = function() {
  4914. AccountClass.apply(this, Array.prototype.slice.call(arguments))
  4915. };
  4916. EuroAccount.prototype = new AccountClass();
  4917. EuroAccount.init = function(_id, _callback) {
  4918. var self = new EuroAccount();
  4919. self.setName("euro");
  4920. self.setPostfix("EUR");
  4921. self.setId(_id + self.getPostfix());
  4922. _callback(self)
  4923. };
  4924. var NxtlAccount = function() {
  4925. AccountClass.apply(this, Array.prototype.slice.call(arguments))
  4926. };
  4927. NxtlAccount.prototype = new AccountClass();
  4928. NxtlAccount.init = function(_id, _callback) {
  4929. var self = new NxtlAccount(_id);
  4930. async.waterfall([
  4931. function(callback) {
  4932. self.setName("nxtl");
  4933. self.setPostfix("NODE");
  4934. self.setId(_id + self.getPostfix());
  4935. callback(null)
  4936. },
  4937. function(callback) {
  4938. var account = Account.getAccount(_id.toString());
  4939. self.setAmount(Utils.roundTo5Float(account.balance));
  4940. self.setUnconfirmedAmount(Utils.roundTo5Float(account.unconfirmedBalance));
  4941. callback(null, "ok")
  4942. }
  4943. ], function(err, result) {
  4944. if (typeof _callback === "function") {
  4945. _callback(self)
  4946. }
  4947. })
  4948. };
  4949. NodeServer = new NodeServer();
  4950. NodeServer.start()
  4951. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement