mirror of
https://github.com/transatoshi-mw/grin-web-wallet.git
synced 2025-10-06 15:52:47 +00:00
438 lines
8.8 KiB
JavaScript
Executable File
438 lines
8.8 KiB
JavaScript
Executable File
// Use strict
|
|
"use strict";
|
|
|
|
|
|
// Classes
|
|
|
|
// Identifier class
|
|
class Identifier {
|
|
|
|
// Public
|
|
|
|
// Constructor
|
|
constructor(serializedIdentifier = Identifier.DEFAULT_SERIALIZED_IDENTIFIER) {
|
|
|
|
// Set depth
|
|
this.depth = 0;
|
|
|
|
// Set paths
|
|
this.paths = new Uint32Array(Identifier.MAX_DEPTH);
|
|
|
|
// Set value to serialized identifier
|
|
this.setValue(serializedIdentifier);
|
|
}
|
|
|
|
// Get depth
|
|
getDepth() {
|
|
|
|
// Return depth
|
|
return this.depth;
|
|
}
|
|
|
|
// Get paths
|
|
getPaths() {
|
|
|
|
// Return paths
|
|
return this.paths;
|
|
}
|
|
|
|
// Set value
|
|
setValue(serializedIdentifierOrDepth, firstValue, secondValue, thirdValue, fourthValue) {
|
|
|
|
// Check if value is provided in a serialized format
|
|
if(typeof serializedIdentifierOrDepth === "string") {
|
|
|
|
// Get serialized identifier
|
|
var serializedIdentifier = serializedIdentifierOrDepth;
|
|
|
|
// Check if serialized identifier ia a hex string
|
|
if(Common.isHexString(serializedIdentifier) === true) {
|
|
|
|
// Get serialized value
|
|
var serializedValue = Common.fromHexString(serializedIdentifier);
|
|
|
|
// Check if serialized value is valid
|
|
if(serializedValue["length"] === Identifier.LENGTH) {
|
|
|
|
// Set depth
|
|
this.depth = Math.min(serializedValue[Identifier.DEPTH_INDEX], Identifier.MAX_DEPTH);
|
|
|
|
// Go through all paths
|
|
var serializedValueDataView = new DataView(serializedValue["buffer"]);
|
|
|
|
for(var i = 0; i < this.getPaths()["length"]; ++i)
|
|
|
|
// Set path
|
|
this.paths[i] = serializedValueDataView.getUint32(Identifier.PATHS_INDEX + i * Uint32Array["BYTES_PER_ELEMENT"], false);
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Throw error
|
|
throw "Invalid identifier.";
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Throw error
|
|
throw "Invalid identifier.";
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Get depth
|
|
var depth = serializedIdentifierOrDepth;
|
|
|
|
// Check if depth is valid
|
|
if(depth <= Identifier.MAX_DEPTH) {
|
|
|
|
// Set depth
|
|
this.depth = depth;
|
|
|
|
// Check if paths are provided as an array
|
|
if(firstValue instanceof Uint32Array === true) {
|
|
|
|
// Get paths
|
|
var paths = firstValue;
|
|
|
|
// Check if paths are valid
|
|
if(paths["length"] === this.getPaths()["length"]) {
|
|
|
|
// Go through all paths
|
|
for(var i = 0; i < this.getPaths()["length"]; ++i) {
|
|
|
|
// Set path to path
|
|
this.paths[i] = paths[i];
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Throw error
|
|
throw "Invalid identifier.";
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Set paths
|
|
this.paths[0] = firstValue;
|
|
this.paths[1] = secondValue;
|
|
this.paths[2] = thirdValue;
|
|
this.paths[3] = fourthValue;
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Throw error
|
|
throw "Invalid identifier.";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get value
|
|
getValue() {
|
|
|
|
// Initialize buffer
|
|
var buffer = new Uint8Array(Identifier.LENGTH);
|
|
|
|
// Set buffer's depth
|
|
buffer[Identifier.DEPTH_INDEX] = this.getDepth();
|
|
|
|
// Go through all paths
|
|
var bufferView = new DataView(buffer["buffer"]);
|
|
|
|
for(var i = 0; i < this.getPaths()["length"]; ++i)
|
|
|
|
// Set buffer's path
|
|
bufferView.setUint32(Identifier.PATHS_INDEX + i * Uint32Array["BYTES_PER_ELEMENT"], this.getPaths()[i], false);
|
|
|
|
// Return buffer
|
|
return buffer;
|
|
}
|
|
|
|
// Equals value
|
|
equalsValue(identifier) {
|
|
|
|
// Check if depths differ
|
|
if(this.getDepth() !== identifier.getDepth())
|
|
|
|
// Return false
|
|
return false;
|
|
|
|
// Return if paths are equal
|
|
return Common.arraysAreEqual(this.getPaths(), identifier.getPaths() === true);
|
|
}
|
|
|
|
// Includes value
|
|
includesValue(identifier) {
|
|
|
|
// Check if depths differ
|
|
if(this.getDepth() !== identifier.getDepth())
|
|
|
|
// Return false
|
|
return false;
|
|
|
|
// Return if last path is greater than or equal to the value's last path
|
|
return this.getLastPath() >= identifier.getLastPath();
|
|
}
|
|
|
|
// Get last path index
|
|
getLastPath() {
|
|
|
|
// Return last path
|
|
return (this.getDepth() === 0) ? 0 : this.getPaths()[this.getDepth() - 1];
|
|
}
|
|
|
|
// Get next
|
|
getNext(height = Identifier.NO_HEIGHT) {
|
|
|
|
// Create next as a clone of self
|
|
var next = this.clone();
|
|
|
|
// Increment next's last path to value
|
|
++next.paths[next.getDepth() - 1];
|
|
|
|
// Check if height exists
|
|
if(height !== Identifier.NO_HEIGHT) {
|
|
|
|
// Check wallet type
|
|
switch(Consensus.getWalletType()) {
|
|
|
|
// MWC wallet
|
|
case Consensus.MWC_WALLET_TYPE:
|
|
|
|
// Set next's height path as the height limited by its maximum value
|
|
next.paths[Identifier.HEIGHT_PATH_INDEX] = Math.max(height.modulo(Identifier.MAXIMUM_HEIGHT + 1).toNumber(), 1);
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return next
|
|
return next;
|
|
}
|
|
|
|
// Get parent
|
|
getParent() {
|
|
|
|
// Create parent as a clone of self
|
|
var parent = this.clone();
|
|
|
|
// Check if previous depth exists
|
|
if(this.getDepth() > 0) {
|
|
|
|
// Clear parent's last path
|
|
parent.paths[parent.getDepth() - 1] = 0;
|
|
|
|
// Decrement parent's depth
|
|
--parent.depth;
|
|
}
|
|
|
|
// Return parent
|
|
return parent;
|
|
}
|
|
|
|
// Get child
|
|
getChild(height = Identifier.NO_HEIGHT) {
|
|
|
|
// Create child as a clone of self
|
|
var child = this.clone();
|
|
|
|
// Check if next depth exists
|
|
if(this.getDepth() < Identifier.MAX_DEPTH) {
|
|
|
|
// Increment child's depth
|
|
++child.depth;
|
|
}
|
|
|
|
// Check if height exists
|
|
if(height !== Identifier.NO_HEIGHT) {
|
|
|
|
// Check wallet type
|
|
switch(Consensus.getWalletType()) {
|
|
|
|
// MWC wallet
|
|
case Consensus.MWC_WALLET_TYPE:
|
|
|
|
// Set child's height path as the height limited by its maximum value
|
|
child.paths[Identifier.HEIGHT_PATH_INDEX] = Math.max(height.modulo(Identifier.MAXIMUM_HEIGHT + 1).toNumber(), 1);
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return child
|
|
return child;
|
|
}
|
|
|
|
// Get height
|
|
getHeight() {
|
|
|
|
// Check wallet type
|
|
switch(Consensus.getWalletType()) {
|
|
|
|
// MWC wallet
|
|
case Consensus.MWC_WALLET_TYPE:
|
|
|
|
// Get height from height path
|
|
var height = this.getPaths()[Identifier.HEIGHT_PATH_INDEX];
|
|
|
|
// Check if height exists
|
|
if(height !== Consensus.FIRST_BLOCK_HEIGHT) {
|
|
|
|
// Return height
|
|
return new BigNumber(height);
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return no height
|
|
return Identifier.NO_HEIGHT;
|
|
}
|
|
}
|
|
|
|
// Return no height
|
|
return Identifier.NO_HEIGHT;
|
|
}
|
|
|
|
// Remove extras
|
|
removeExtras() {
|
|
|
|
// Create copy as a clone of self
|
|
var copy = this.clone();
|
|
|
|
// Check wallet type
|
|
switch(Consensus.getWalletType()) {
|
|
|
|
// MWC wallet
|
|
case Consensus.MWC_WALLET_TYPE:
|
|
|
|
// Set copy's height path to not exist
|
|
copy.paths[Identifier.HEIGHT_PATH_INDEX] = Consensus.FIRST_BLOCK_HEIGHT;
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
|
|
// Return copy
|
|
return copy;
|
|
}
|
|
|
|
// Is path hardened
|
|
static isPathHardened(path) {
|
|
|
|
// Return if path is hardened
|
|
return (path & Identifier.PATH_HARDENED_MASK) !== 0;
|
|
}
|
|
|
|
// Length
|
|
static get LENGTH() {
|
|
|
|
// Return length
|
|
return 1 * Uint8Array["BYTES_PER_ELEMENT"] + Identifier.MAX_DEPTH * Uint32Array["BYTES_PER_ELEMENT"];
|
|
}
|
|
|
|
// Max depth
|
|
static get MAX_DEPTH() {
|
|
|
|
// Return max depth
|
|
return 4;
|
|
}
|
|
|
|
// Root serialized identifier
|
|
static get ROOT_SERIALIZED_IDENTIFIER() {
|
|
|
|
// Return root serialized identifier
|
|
return "0000000000000000000000000000000000";
|
|
}
|
|
|
|
// Paths index
|
|
static get PATHS_INDEX() {
|
|
|
|
// Return paths index
|
|
return Identifier.DEPTH_INDEX + 1;
|
|
}
|
|
|
|
// No identifier
|
|
static get NO_IDENTIFIER() {
|
|
|
|
// Return no identifier
|
|
return null;
|
|
}
|
|
|
|
// No heights
|
|
static get NO_HEIGHT() {
|
|
|
|
// Return no height
|
|
return null;
|
|
}
|
|
|
|
// Maximum height
|
|
static get MAXIMUM_HEIGHT() {
|
|
|
|
// Return maximum height
|
|
return Common.UINT32_MAX_VALUE;
|
|
}
|
|
|
|
// Private
|
|
|
|
// Clone
|
|
clone() {
|
|
|
|
// Create a copy of self
|
|
var copy = new Identifier();
|
|
|
|
copy.setValue(this.getDepth(), this.getPaths());
|
|
|
|
// Return copy
|
|
return copy;
|
|
}
|
|
|
|
// Default serialized identifier
|
|
static get DEFAULT_SERIALIZED_IDENTIFIER() {
|
|
|
|
// Return default serialized identifier
|
|
return "0200000000000000000000000000000000";
|
|
}
|
|
|
|
// Depth index
|
|
static get DEPTH_INDEX() {
|
|
|
|
// Return depth index
|
|
return 0;
|
|
}
|
|
|
|
// Path hardened mask
|
|
static get PATH_HARDENED_MASK() {
|
|
|
|
// Return path hardened mask
|
|
return 0x80000000;
|
|
}
|
|
|
|
// Height path index
|
|
static get HEIGHT_PATH_INDEX() {
|
|
|
|
// Return height path index
|
|
return Identifier.MAX_DEPTH - 1;
|
|
}
|
|
}
|
|
|
|
|
|
// Main function
|
|
|
|
// Set global object's identifier
|
|
globalThis["Identifier"] = Identifier;
|