SuperNodeStorage/src/cloud.js
tripathyr 0a7927d5ca
Update cloud.js
1. Fixing the leading 00 byte routing problem by removing bigInteger step in decodeID
2. Optimization of decodeID while building buckets
2025-08-21 06:57:54 +05:30

167 lines
5.2 KiB
JavaScript

'use strict';
function K_Bucket(masterID, nodeList) {
const decodeID = function (floID) {
if (floID.startsWith("0x") || floID.length === 40)
floID = proxyID(floID);
const bytes = bitjs.Base58.decode(floID);
bytes.shift();
bytes.splice(-4, 4);
return new Uint8Array(bytes);
};
const _KB = new BuildKBucket({
localNodeId: decodeID(masterID)
});
nodeList.forEach(id => _KB.add({
id: decodeID(id),
floID: id
}));
const localId = _KB.localNodeId;
const _CO = nodeList
.map(sn => [_KB.distance(localId, decodeID(sn)), sn])
.sort((a, b) => a[0] - b[0])
.map(a => a[1]);
const self = this;
Object.defineProperty(self, 'order', {
get: () => Array.from(_CO)
});
self.innerNodes = function(id1, id2) {
if (!_CO.includes(id1) || !_CO.includes(id2))
throw Error('Given nodes are not in KB');
let iNodes = [];
for (let i = _CO.indexOf(id1) + 1; _CO[i] != id2; i++) {
if (i < _CO.length)
iNodes.push(_CO[i]);
else i = -1;
};
return iNodes;
};
self.outterNodes = function(id1, id2) {
if (!_CO.includes(id1) || !_CO.includes(id2))
throw Error('Given nodes are not in KB');
let oNodes = [];
for (let i = _CO.indexOf(id2) + 1; _CO[i] != id1; i++) {
if (i < _CO.length)
oNodes.push(_CO[i]);
else i = -1;
};
return oNodes;
};
self.prevNode = function(id, N = 1) {
let n = N || _CO.length;
if (!_CO.includes(id))
throw Error('Given node is not KB');
let pNodes = [];
for (let i = 0, j = _CO.indexOf(id) - 1; i < n; j--) {
if (j == _CO.indexOf(id))
break;
else if (j > -1)
pNodes[i++] = _CO[j];
else j = _CO.length;
};
return (N == 1 ? pNodes[0] : pNodes);
};
self.nextNode = function(id, N = 1) {
let n = N || _CO.length;
if (!_CO.includes(id))
throw Error('Given node is not KB');
let nNodes = [];
for (let i = 0, j = _CO.indexOf(id) + 1; i < n; j++) {
if (j == _CO.indexOf(id))
break;
else if (j < _CO.length)
nNodes[i++] = _CO[j];
else j = -1;
};
return (N == 1 ? nNodes[0] : nNodes);
};
self.closestNode = function(id, N = 1) {
let decodedId = decodeID(id);
let n = N || _CO.length;
let cNodes = _KB.closest(decodedId, n)
.map(k => k.floID);
return (N == 1 ? cNodes[0] : cNodes);
};
}
const blockchainPrefix = 0x23;
function proxyID(address) {
if (!address)
return;
var bytes;
if (address.length == 34) { //legacy encoding
let decode = bitjs.Base58.decode(address);
bytes = decode.slice(0, decode.length - 4);
let checksum = decode.slice(decode.length - 4),
hash = Crypto.SHA256(Crypto.SHA256(bytes, {
asBytes: true
}), {
asBytes: true
});
hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3] ?
bytes = undefined : bytes.shift();
} else if (!address.startsWith("0x") && (address.length == 42 || address.length == 62)) { //bech encoding
if (typeof coinjs !== 'function')
throw "library missing (lib_btc.js)";
let decode = coinjs.bech32_decode(address);
if (decode) {
bytes = decode.data;
bytes.shift();
bytes = coinjs.bech32_convert(bytes, 5, 8, false);
if (address.length == 62) //for long bech, aggregate once more to get 160 bit
bytes = coinjs.bech32_convert(bytes, 5, 8, false);
}
} else if (address.length == 66) { //public key hex
bytes = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(address), {
asBytes: true
}));
} else if ((address.length == 42 && address.startsWith("0x")) || (address.length == 40 && !address.startsWith("0x"))) { //Ethereum Address
if (address.startsWith("0x")) { address = address.substring(2); }
bytes = Crypto.util.hexToBytes(address);
}
if (!bytes)
throw "Invalid address: " + address;
else {
bytes.unshift(blockchainPrefix);
let hash = Crypto.SHA256(Crypto.SHA256(bytes, {
asBytes: true
}), {
asBytes: true
});
return bitjs.Base58.encode(bytes.concat(hash.slice(0, 4)));
}
}
var kBucket;
const cloud = module.exports = function Cloud(masterID, nodeList) {
kBucket = new K_Bucket(masterID, nodeList);
}
cloud.proxyID = (a) => proxyID(a);
cloud.closestNode = (id, N = 1) => kBucket.closestNode(proxyID(id), N);
cloud.prevNode = (id, N = 1) => kBucket.prevNode(id, N);
cloud.nextNode = (id, N = 1) => kBucket.nextNode(id, N);
cloud.innerNodes = (id1, id2) => kBucket.innerNodes(id1, id2);
cloud.outterNodes = (id1, id2) => kBucket.outterNodes(id1, id2);
Object.defineProperties(cloud, {
kb: {
get: () => kBucket
},
order: {
get: () => kBucket.order
}
});