164 lines
2.9 KiB
JavaScript
164 lines
2.9 KiB
JavaScript
/*!
|
|
* common.js - commonly required functions for wallet.
|
|
* Copyright (c) 2017-2018, Christopher Jeffrey (MIT License).
|
|
* https://github.com/handshake-org/hsd
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const {BufferMap} = require('buffer-map');
|
|
|
|
/** @typedef {import('../primitives/tx')} TX */
|
|
/** @typedef {import('../primitives/txmeta')} TXMeta */
|
|
/** @typedef {import('../primitives/coin')} Coin */
|
|
|
|
/**
|
|
* @exports wallet/common
|
|
*/
|
|
|
|
const common = exports;
|
|
|
|
/**
|
|
* Test whether a string is eligible
|
|
* to be used as a name or ID.
|
|
* @param {String} key
|
|
* @returns {Boolean}
|
|
*/
|
|
|
|
common.isName = function isName(key) {
|
|
if (typeof key !== 'string')
|
|
return false;
|
|
|
|
if (key.length === 0)
|
|
return false;
|
|
|
|
if (!/^[\-\._0-9A-Za-z]+$/.test(key))
|
|
return false;
|
|
|
|
// Prevents __proto__
|
|
// from being used.
|
|
switch (key[0]) {
|
|
case '_':
|
|
case '-':
|
|
case '.':
|
|
return false;
|
|
}
|
|
|
|
switch (key[key.length - 1]) {
|
|
case '_':
|
|
case '-':
|
|
case '.':
|
|
return false;
|
|
}
|
|
|
|
return key.length >= 1 && key.length <= 40;
|
|
};
|
|
|
|
/**
|
|
* Sort an array of transactions by time.
|
|
* @param {TXMeta[]} txs
|
|
* @returns {TXMeta[]}
|
|
*/
|
|
|
|
common.sortTX = function sortTX(txs) {
|
|
return txs.sort((a, b) => {
|
|
return a.mtime - b.mtime;
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Sort an array of coins by height.
|
|
* @param {Coin[]} coins
|
|
* @returns {Coin[]}
|
|
*/
|
|
|
|
common.sortCoins = function sortCoins(coins) {
|
|
return coins.sort((a, b) => {
|
|
const ah = a.height === -1 ? 0x7fffffff : a.height;
|
|
const bh = b.height === -1 ? 0x7fffffff : b.height;
|
|
return ah - bh;
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Sort an array of transactions in dependency order.
|
|
* @param {TX[]} txs
|
|
* @returns {TX[]}
|
|
*/
|
|
|
|
common.sortDeps = function sortDeps(txs) {
|
|
const map = new BufferMap();
|
|
|
|
for (const tx of txs) {
|
|
const hash = tx.hash();
|
|
map.set(hash, tx);
|
|
}
|
|
|
|
const depMap = new BufferMap();
|
|
const depCount = new BufferMap();
|
|
const top = [];
|
|
|
|
for (const [hash, tx] of map) {
|
|
depCount.set(hash, 0);
|
|
|
|
let hasDeps = false;
|
|
|
|
for (const input of tx.inputs) {
|
|
const prev = input.prevout.hash;
|
|
|
|
if (!map.has(prev))
|
|
continue;
|
|
|
|
const count = depCount.get(hash);
|
|
depCount.set(hash, count + 1);
|
|
hasDeps = true;
|
|
|
|
if (!depMap.has(prev))
|
|
depMap.set(prev, []);
|
|
|
|
depMap.get(prev).push(tx);
|
|
}
|
|
|
|
if (hasDeps)
|
|
continue;
|
|
|
|
top.push(tx);
|
|
}
|
|
|
|
const result = [];
|
|
|
|
for (const tx of top) {
|
|
const hash = tx.hash();
|
|
const deps = depMap.get(hash);
|
|
|
|
result.push(tx);
|
|
|
|
if (!deps)
|
|
continue;
|
|
|
|
for (const tx of deps) {
|
|
const hash = tx.hash();
|
|
|
|
let count = depCount.get(hash);
|
|
|
|
if (--count === 0)
|
|
top.push(tx);
|
|
|
|
depCount.set(hash, count);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Wallet coin selection types.
|
|
* @enum {String}
|
|
*/
|
|
|
|
common.coinSelectionTypes = {
|
|
DB_ALL: 'db-all',
|
|
DB_VALUE: 'db-value',
|
|
DB_SWEEPDUST: 'db-sweepdust',
|
|
DB_AGE: 'db-age'
|
|
};
|