API(admin): generate, reshare and discard sinks

- generateSink: generates a sinkID for given group
- reshareSink: regenerate the shares for given id and distribute
- discardSink: discards the given sink id

Note: All these APIs are admin-only
This commit is contained in:
sairajzero 2022-11-15 05:14:25 +05:30
parent c8b70e3fec
commit c5b43291ab
5 changed files with 231 additions and 8 deletions

View File

@ -519,6 +519,7 @@
DUPLICATE_SIGNATURE: '017', DUPLICATE_SIGNATURE: '017',
SESSION_INVALID: '018', SESSION_INVALID: '018',
SESSION_EXPIRED: '019', SESSION_EXPIRED: '019',
INVALID_VALUE: '020',
INVALID_TOKEN_NAME: '021', INVALID_TOKEN_NAME: '021',
INVALID_NUMBER: '022', INVALID_NUMBER: '022',
INVALID_TYPE: '023', INVALID_TYPE: '023',
@ -610,7 +611,7 @@
exchangeAPI.getSink = function (service = serviceList.EXCHANGE) { exchangeAPI.getSink = function (service = serviceList.EXCHANGE) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!(service in serviceList)) if (!(service in serviceList))
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, 'service required', errorCode.INVALID_TYPE)); return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, 'service required', errorCode.INVALID_VALUE));
fetch_api('/get-sink?service=' + service) fetch_api('/get-sink?service=' + service)
.then(result => { .then(result => {
responseParse(result, false) responseParse(result, false)
@ -1557,6 +1558,99 @@
}) })
} }
exchangeAPI.generateSink = function (group, floID, privKey) {
if (!floCrypto.verifyPrivKey(privKey, floID))
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, "Invalid Private Key", errorCode.INVALID_PRIVATE_KEY));
if (floID !== DEFAULT.marketID)
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, "Access Denied", errorCode.ACCESS_DENIED));
let request = {
floID: floID,
group: group,
timestamp: Date.now()
};
request.pubKey = floCrypto.getPubKeyHex(privKey);
request.sign = signRequest({
type: "generate_sink",
group: group,
timestamp: request.timestamp
}, privKey);
console.debug(request);
fetch_api('/generate-sink', {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(result => {
responseParse(result, false)
.then(result => resolve(result))
.catch(error => reject(error))
}).catch(error => reject(error))
}
exchangeAPI.reshareSink = function (sinkID, floID, privKey) {
if (!floCrypto.verifyPrivKey(privKey, floID))
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, "Invalid Private Key", errorCode.INVALID_PRIVATE_KEY));
if (floID !== DEFAULT.marketID)
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, "Access Denied", errorCode.ACCESS_DENIED));
let request = {
floID: floID,
id: sinkID,
timestamp: Date.now()
};
request.pubKey = floCrypto.getPubKeyHex(privKey);
request.sign = signRequest({
type: "reshare_sink",
id: sinkID,
timestamp: request.timestamp
}, privKey);
console.debug(request);
fetch_api('/reshare-sink', {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(result => {
responseParse(result, false)
.then(result => resolve(result))
.catch(error => reject(error))
}).catch(error => reject(error))
}
exchangeAPI.discardSink = function (sinkID, floID, privKey) {
if (!floCrypto.verifyPrivKey(privKey, floID))
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, "Invalid Private Key", errorCode.INVALID_PRIVATE_KEY));
if (floID !== DEFAULT.marketID)
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, "Access Denied", errorCode.ACCESS_DENIED));
let request = {
floID: floID,
id: sinkID,
timestamp: Date.now()
};
request.pubKey = floCrypto.getPubKeyHex(privKey);
request.sign = signRequest({
type: "discard_sink",
id: sinkID,
timestamp: request.timestamp
}, privKey);
console.debug(request);
fetch_api('/discard-sink', {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(result => {
responseParse(result, false)
.then(result => resolve(result))
.catch(error => reject(error))
}).catch(error => reject(error))
}
exchangeAPI.init = function refreshDataFromBlockchain() { exchangeAPI.init = function refreshDataFromBlockchain() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let nodes, assets, tags, lastTx; let nodes, assets, tags, lastTx;

View File

@ -88,6 +88,11 @@ module.exports = function App(secret) {
app.post('/withdraw-token', Request.WithdrawToken); app.post('/withdraw-token', Request.WithdrawToken);
app.post('/get-transact', Request.GetUserTransacts); app.post('/get-transact', Request.GetUserTransacts);
//generate or discard sinks (admin only)
app.post('/generate-sink', Request.GenerateSink);
app.post('/reshare-sink', Request.DiscardSink);
app.post('/discard-sink', Request.DiscardSink);
//convert from or to coin //convert from or to coin
app.get('/get-convert-values', Request.GetConvertValues); app.get('/get-convert-values', Request.GetConvertValues);
app.post('/convert-to', Request.ConvertTo); app.post('/convert-to', Request.ConvertTo);

View File

@ -218,11 +218,8 @@ function informLiveNodes(init) {
} else if (!flag) { } else if (!flag) {
console.log("Starting the exchange..."); console.log("Starting the exchange...");
//generate a sinkID for each group in starting list //generate a sinkID for each group in starting list
keys.sink_groups.generate_list.forEach(group => { keys.sink_groups.initial_list.forEach(group =>
let newSink = floCrypto.generateNewID(); generateSink(group).then(_ => null).catch(e => console.error(e)));
console.debug("Generated sink:", group, newSink.floID);
sendSharesToNodes(newSink.floID, group, generateShares(newSink.privKey));
})
} }
}).catch(error => console.error(error)); }).catch(error => console.error(error));
}); });
@ -276,6 +273,63 @@ function slaveConnect(floID, pubKey, ws, sinks) {
} }
} }
const eCode = require('../docs/scripts/floExchangeAPI').errorCode;
function generateSink(group) {
return new Promise((resolve, reject) => {
if (!keys.sink_groups.generate_list.includes(group))
return reject(INVALID(eCode.INVALID_VALUE, `Invalid Group ${group}`));
try {
let newSink = floCrypto.generateNewID();
console.debug("Generated sink:", group, newSink.floID);
sendSharesToNodes(newSink.floID, group, generateShares(newSink.privKey));
resolve(`Generated ${newSink.floID} (${group})`);
} catch (error) {
reject(error)
}
})
}
function reshareSink(id) {
return new Promise((resolve, reject) => {
if (!floCrypto.validateAddr(data.id))
return reject(INVALID(eCode.INVALID_VALUE, `Invalid ID ${id}`));
else {
let group = keys.sink_chest.find_group(id);
if (!group)
return reject(INVALID(eCode.NOT_FOUND, `ID ${id} not found`));
else keys.checkIfDiscarded(id).then(result => {
if (result)
return reject(INVALID(eCode.NOT_FOUND, `ID is discarded`));
try {
reconstructShares(group, id);
resolve(`Resharing ${id} (${group})`);
} catch (error) {
reject(error);
}
}).catch(error => reject(error))
}
})
}
function discardSink(id) {
return new Promise((resolve, reject) => {
if (!floCrypto.validateAddr(data.id))
return reject(INVALID(eCode.INVALID_VALUE, `Invalid ID ${id}`));
else if (!keys.sink_chest.find_group(id))
return reject(INVALID(eCode.NOT_FOUND, `ID ${id} not found`));
else keys.checkIfDiscarded(id).then(result => {
if (result)
return reject(INVALID(eCode.DUPLICATE_ENTRY, `ID already discarded`));
keys.discardSink(id).then(result => {
console.debug("Discarded sink:", id);
resolve(result);
}).catch(error => reject(error))
}).catch(error => reject(error))
})
}
function checkForDiscardedSinks() { function checkForDiscardedSinks() {
let cur_time = Date.now(), let cur_time = Date.now(),
all_sinks = keys.sink_chest.get_all(); all_sinks = keys.sink_chest.get_all();
@ -401,6 +455,11 @@ function initProcess(app) {
module.exports = { module.exports = {
init: initProcess, init: initProcess,
collectAndCall, collectAndCall,
sink: {
generate: generateSink,
reshare: reshareSink,
discard: discardSink
},
set nodeList(list) { set nodeList(list) {
nodeURL = list; nodeURL = list;
nodeKBucket = new K_Bucket(floGlobals.adminID, Object.keys(nodeURL)); nodeKBucket = new K_Bucket(floGlobals.adminID, Object.keys(nodeURL));

View File

@ -289,14 +289,25 @@ function checkIfDiscarded(id) {
}) })
} }
function discardSink(id) {
return new Promise((resolve, reject) => {
DB.query("INSERT INTO discardedSinks(floID) VALUE (?)", [id])
.then(result => resolve(`Discarded ${id}`))
.catch(error => reject(error))
})
}
//Sink groups and chest //Sink groups and chest
const sink_groups = { const sink_groups = {
get EXCHANGE() { return "exchange" }, get EXCHANGE() { return "exchange" },
get CONVERT() { return "convert" }, get CONVERT() { return "convert" },
get BLOCKCHAIN_BONDS() { return "blockchain_bonds" }, get BLOCKCHAIN_BONDS() { return "blockchain_bonds" },
get BOBS_FUND() { return "bobs_fund" }, get BOBS_FUND() { return "bobs_fund" },
get generate_list() { //list to generate when starting exchange get initial_list() { //list to generate when starting exchange
return [this.EXCHANGE, this.CONVERT] return [this.EXCHANGE, this.CONVERT]
},
get generate_list() { //list allowed to generate
return [this.EXCHANGE, this.CONVERT, this.BLOCKCHAIN_BONDS, this.BOBS_FUND]
} }
}; };
@ -343,6 +354,14 @@ const sink_ids = {}, sink_chest = {
i = floCrypto.randInt(0, ids.length); i = floCrypto.randInt(0, ids.length);
return ids[i]; return ids[i];
}, },
find_group(id) {
let group = null;
for (let g in sink_ids)
if (id in sink_ids[g]) {
group = g; break;
}
return group;
},
get_all() { get_all() {
let ids = {}; let ids = {};
for (let g in sink_ids) for (let g in sink_ids)
@ -359,6 +378,7 @@ module.exports = {
getStoredList, getStoredList,
getDiscardedList, getDiscardedList,
checkIfDiscarded, checkIfDiscarded,
discardSink,
set node_priv(key) { set node_priv(key) {
_.node_priv = key; _.node_priv = key;
}, },

View File

@ -6,6 +6,7 @@ const conversion = require('./services/conversion');
const blockchain_bonds = require("./services/bonds"); const blockchain_bonds = require("./services/bonds");
const bobs_fund = require("./services/bobs-fund"); const bobs_fund = require("./services/bobs-fund");
const background = require("./background"); const background = require("./background");
const sink = require("./backup/head").sink;
const keys = require("./keys"); const keys = require("./keys");
const { const {
@ -307,6 +308,47 @@ function RemoveDistributor(req, res) {
}, () => market.removeDistributor(data.distributor, data.asset)); }, () => market.removeDistributor(data.distributor, data.asset));
} }
function GenerateSink(req, res) {
let data = req.body;
if (data.floID !== floGlobals.adminID)
res.status(INVALID.e_code).send(INVALID.str(eCode.ACCESS_DENIED, "Access Denied"));
else if (!data.pubKey)
res.status(INVALID.e_code).send(INVALID.str(eCode.MISSING_PARAMETER, "Public key missing"));
else processRequest(res, data.floID, data.pubKey, data.sign, "Generate Sink", {
type: "generate_sink",
group: data.group,
timestamp: data.timestamp
}, () => sink.generate(group));
}
function ReshareSink(req, res) {
let data = req.body;
if (data.floID !== floGlobals.adminID)
res.status(INVALID.e_code).send(INVALID.str(eCode.ACCESS_DENIED, "Access Denied"));
else if (!data.pubKey)
res.status(INVALID.e_code).send(INVALID.str(eCode.MISSING_PARAMETER, "Public key missing"));
else if (!floCrypto.validateAddr(data.id))
res.status(INVALID.e_code).send(INVALID.str(eCode.INVALID_VALUE, `Invalid ID ${data.id}`));
else processRequest(res, data.floID, data.pubKey, data.sign, "Reshare Sink", {
type: "reshare_sink",
id: data.id,
timestamp: data.timestamp
}, () => sink.reshare(id));
}
function DiscardSink(req, res) {
let data = req.body;
if (data.floID !== floGlobals.adminID)
res.status(INVALID.e_code).send(INVALID.str(eCode.ACCESS_DENIED, "Access Denied"));
else if (!data.pubKey)
res.status(INVALID.e_code).send(INVALID.str(eCode.MISSING_PARAMETER, "Public key missing"));
else processRequest(res, data.floID, data.pubKey, data.sign, "Discard Sink", {
type: "discard_sink",
id: data.id,
timestamp: data.timestamp
}, () => sink.discard(id));
}
function ConvertTo(req, res) { function ConvertTo(req, res) {
let data = req.body; let data = req.body;
processRequest(res, data.floID, data.pubKey, data.sign, "Conversion", { processRequest(res, data.floID, data.pubKey, data.sign, "Conversion", {
@ -518,7 +560,7 @@ function GetSink(req, res) {
if (!service) if (!service)
res.status(INVALID.e_code).send(INVALID.str(eCode.MISSING_PARAMETER, "Missing service parameter")); res.status(INVALID.e_code).send(INVALID.str(eCode.MISSING_PARAMETER, "Missing service parameter"));
else if (!(service in serviceList)) else if (!(service in serviceList))
res.status(INVALID.e_code).send(INVALID.str(eCode.INVALID_TYPE, "Invalid service parameter")); res.status(INVALID.e_code).send(INVALID.str(eCode.INVALID_VALUE, "Invalid service parameter"));
else { else {
let group; let group;
switch (service) { switch (service) {
@ -640,6 +682,9 @@ module.exports = {
RemoveUserTag, RemoveUserTag,
AddDistributor, AddDistributor,
RemoveDistributor, RemoveDistributor,
GenerateSink,
ReshareSink,
DiscardSink,
GetConvertValues, GetConvertValues,
ConvertTo, ConvertTo,
ConvertFrom, ConvertFrom,