Updated Standard Operations to v2.1.0e
This commit is contained in:
parent
59218260ab
commit
dffecbb573
@ -152,8 +152,7 @@
|
|||||||
|
|
||||||
//Required for blockchain API operators
|
//Required for blockchain API operators
|
||||||
apiURL: {
|
apiURL: {
|
||||||
FLO: ['https://livenet.flocha.in/', 'https://flosight.duckdns.org/'
|
FLO: ['https://livenet.flocha.in/', 'https://flosight.duckdns.org/'],
|
||||||
],
|
|
||||||
FLO_TEST: ['https://testnet-flosight.duckdns.org/', 'https://testnet.flocha.in/']
|
FLO_TEST: ['https://testnet-flosight.duckdns.org/', 'https://testnet.flocha.in/']
|
||||||
},
|
},
|
||||||
adminID: "FKAEdnPfjXLHSYwrXQu377ugN4tXU7VGdf",
|
adminID: "FKAEdnPfjXLHSYwrXQu377ugN4tXU7VGdf",
|
||||||
@ -186,6 +185,12 @@
|
|||||||
}).catch(error => console.error(error))
|
}).catch(error => console.error(error))
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body onload="onLoadStartUp()">
|
||||||
|
TEST_MODE
|
||||||
|
(use console)
|
||||||
|
|
||||||
<script id="init_lib" version="1.0.1">
|
<script id="init_lib" version="1.0.1">
|
||||||
//All util libraries required for Standard operations (DO NOT EDIT ANY)
|
//All util libraries required for Standard operations (DO NOT EDIT ANY)
|
||||||
|
|
||||||
@ -5222,11 +5227,8 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2011 Stefan Thomas
|
Copyright (c) 2011 Stefan Thomas
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -7067,11 +7069,9 @@
|
|||||||
else if (value === null)
|
else if (value === null)
|
||||||
delete obj[key];// null, remove it
|
delete obj[key];// null, remove it
|
||||||
});
|
});
|
||||||
if (obj.constructor.toString().indexOf("Array") != -1) {
|
if(obj.constructor.toString().indexOf("Array") != -1) {obj = obj.filter(function (el) {
|
||||||
obj = obj.filter(function (el) {
|
|
||||||
return el != null;
|
return el != null;
|
||||||
});
|
});}
|
||||||
}
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7427,17 +7427,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script id="floBlockchainAPI" version="2.0.1c">
|
<script id="floBlockchainAPI" version="2.1.1a">
|
||||||
/* FLO Blockchain Operator to send/receive data from blockchain using API calls*/
|
/* FLO Blockchain Operator to send/receive data from blockchain using API calls*/
|
||||||
const floBlockchainAPI = {
|
const floBlockchainAPI = {
|
||||||
|
|
||||||
util: {
|
util: {
|
||||||
serverList: floGlobals.apiURL[floGlobals.blockchain].slice(0),
|
serverList: floGlobals.apiURL[floGlobals.blockchain].slice(0),
|
||||||
curPos: floCrypto.randInt(0, floGlobals.apiURL[floGlobals.blockchain].length),
|
curPos: floCrypto.randInt(0, floGlobals.apiURL[floGlobals.blockchain].length - 1),
|
||||||
fetch_retry: function (apicall) {
|
fetch_retry: function(apicall, rm_flosight) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.serverList.splice(this.curPos, 1);
|
let i = this.serverList.indexOf(rm_flosight)
|
||||||
this.curPos = floCrypto.randInt(0, this.serverList.length - 1)
|
if (i != -1) this.serverList.splice(i, 1);
|
||||||
|
this.curPos = floCrypto.randInt(0, this.serverList.length - 1);
|
||||||
this.fetch_api(apicall)
|
this.fetch_api(apicall)
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => reject(error));
|
.catch(error => reject(error));
|
||||||
@ -7446,30 +7447,35 @@
|
|||||||
fetch_api: function(apicall) {
|
fetch_api: function(apicall) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (this.serverList.length === 0)
|
if (this.serverList.length === 0)
|
||||||
reject("No floSight server working")
|
reject("No floSight server working");
|
||||||
else {
|
else {
|
||||||
fetch(this.serverList[this.curPos] + apicall).then(response => {
|
let flosight = this.serverList[this.curPos];
|
||||||
|
fetch(flosight + apicall).then(response => {
|
||||||
if (response.ok)
|
if (response.ok)
|
||||||
response.json().then(data => resolve(data));
|
response.json().then(data => resolve(data));
|
||||||
else {
|
else {
|
||||||
this.fetch_retry(apicall)
|
this.fetch_retry(apicall, flosight)
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => reject(error));
|
.catch(error => reject(error));
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
this.fetch_retry(apicall)
|
this.fetch_retry(apicall, flosight)
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => reject(error));
|
.catch(error => reject(error));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
current: function() {
|
||||||
|
return this.serverList[this.curPos];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
//Promised function to get data from API
|
//Promised function to get data from API
|
||||||
promisedAPI: function(apicall) {
|
promisedAPI: function(apicall) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
console.log(apicall)
|
//console.log(apicall);
|
||||||
this.util.fetch_api(apicall)
|
this.util.fetch_api(apicall)
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => reject(error));
|
.catch(error => reject(error));
|
||||||
@ -7486,44 +7492,61 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
//Write Data into blockchain
|
//Write Data into blockchain
|
||||||
writeData: function (senderAddr, data, privKey, receiverAddr = floGlobals.adminID) {
|
writeData: function(senderAddr, data, privKey, receiverAddr = floGlobals.adminID, strict_utxo = true) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (typeof data != "string")
|
if (typeof data != "string")
|
||||||
data = JSON.stringify(data);
|
data = JSON.stringify(data);
|
||||||
this.sendTx(senderAddr, receiverAddr, floGlobals.sendAmt, privKey, data)
|
this.sendTx(senderAddr, receiverAddr, floGlobals.sendAmt, privKey, data, strict_utxo)
|
||||||
.then(txid => resolve(txid))
|
.then(txid => resolve(txid))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
//Send Tx to blockchain
|
//Send Tx to blockchain
|
||||||
sendTx: function (senderAddr, receiverAddr, sendAmt, privKey, floData = '') {
|
sendTx: function(senderAddr, receiverAddr, sendAmt, privKey, floData = '', strict_utxo = true) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!floCrypto.validateASCII(floData))
|
if (!floCrypto.validateASCII(floData))
|
||||||
return reject("Invalid FLO_Data: only printable ASCII characters are allowed");
|
return reject("Invalid FLO_Data: only printable ASCII characters are allowed");
|
||||||
if (!floCrypto.validateAddr(senderAddr))
|
else if (!floCrypto.validateAddr(senderAddr))
|
||||||
reject(`Invalid address : ${senderAddr}`);
|
return reject(`Invalid address : ${senderAddr}`);
|
||||||
else if (!floCrypto.validateAddr(receiverAddr))
|
else if (!floCrypto.validateAddr(receiverAddr))
|
||||||
reject(`Invalid address : ${receiverAddr}`);
|
return reject(`Invalid address : ${receiverAddr}`);
|
||||||
if (privKey.length < 1 || !floCrypto.verifyPrivKey(privKey, senderAddr))
|
else if (privKey.length < 1 || !floCrypto.verifyPrivKey(privKey, senderAddr))
|
||||||
reject("Invalid Private key!");
|
return reject("Invalid Private key!");
|
||||||
else if (typeof sendAmt !== 'number' || sendAmt <= 0)
|
else if (typeof sendAmt !== 'number' || sendAmt <= 0)
|
||||||
reject(`Invalid sendAmt : ${sendAmt}`);
|
return reject(`Invalid sendAmt : ${sendAmt}`);
|
||||||
else {
|
|
||||||
|
//get unconfirmed tx list
|
||||||
|
this.promisedAPI(`api/addr/${senderAddr}`).then(result => {
|
||||||
|
this.readTxs(senderAddr, 0, result.unconfirmedTxApperances).then(result => {
|
||||||
|
let unconfirmedSpent = {};
|
||||||
|
for (let tx of result.items)
|
||||||
|
if (tx.confirmations == 0)
|
||||||
|
for (let vin of tx.vin)
|
||||||
|
if (vin.addr === senderAddr) {
|
||||||
|
if (Array.isArray(unconfirmedSpent[vin.txid]))
|
||||||
|
unconfirmedSpent[vin.txid].push(vin.vout);
|
||||||
|
else
|
||||||
|
unconfirmedSpent[vin.txid] = [vin.vout];
|
||||||
|
}
|
||||||
|
//get utxos list
|
||||||
|
this.promisedAPI(`api/addr/${senderAddr}/utxo`).then(utxos => {
|
||||||
|
//form/construct the transaction data
|
||||||
var trx = bitjs.transaction();
|
var trx = bitjs.transaction();
|
||||||
var utxoAmt = 0.0;
|
var utxoAmt = 0.0;
|
||||||
var fee = floGlobals.fee;
|
var fee = floGlobals.fee;
|
||||||
this.promisedAPI(`api/addr/${senderAddr}/utxo`).then(utxos => {
|
|
||||||
for (var i = utxos.length - 1;
|
for (var i = utxos.length - 1;
|
||||||
(i >= 0) && (utxoAmt < sendAmt + fee); i--) {
|
(i >= 0) && (utxoAmt < sendAmt + fee); i--) {
|
||||||
if (utxos[i].confirmations) {
|
//use only utxos with confirmations (strict_utxo mode)
|
||||||
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i]
|
if (utxos[i].confirmations || !strict_utxo) {
|
||||||
.scriptPubKey)
|
if (utxos[i].txid in unconfirmedSpent && unconfirmedSpent[utxos[i].txid].includes(utxos[i].vout))
|
||||||
|
continue; //A transaction has already used this utxo, but is unconfirmed.
|
||||||
|
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i].scriptPubKey);
|
||||||
utxoAmt += utxos[i].amount;
|
utxoAmt += utxos[i].amount;
|
||||||
} else break;
|
};
|
||||||
}
|
}
|
||||||
if (utxoAmt < sendAmt + fee)
|
if (utxoAmt < sendAmt + fee)
|
||||||
reject("Insufficient balance!");
|
reject("Insufficient FLO balance!");
|
||||||
else {
|
else {
|
||||||
trx.addoutput(receiverAddr, sendAmt);
|
trx.addoutput(receiverAddr, sendAmt);
|
||||||
var change = utxoAmt - sendAmt - fee;
|
var change = utxoAmt - sendAmt - fee;
|
||||||
@ -7536,7 +7559,8 @@
|
|||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
}
|
}
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
}
|
}).catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -7546,21 +7570,18 @@
|
|||||||
if (!floCrypto.validateAddr(floID))
|
if (!floCrypto.validateAddr(floID))
|
||||||
return reject(`Invalid floID`);
|
return reject(`Invalid floID`);
|
||||||
if (!floCrypto.verifyPrivKey(privKey, floID))
|
if (!floCrypto.verifyPrivKey(privKey, floID))
|
||||||
return reject("Invalid Private Key")
|
return reject("Invalid Private Key");
|
||||||
if (!floCrypto.validateASCII(floData))
|
if (!floCrypto.validateASCII(floData))
|
||||||
return reject("Invalid FLO_Data: only printable ASCII characters are allowed");
|
return reject("Invalid FLO_Data: only printable ASCII characters are allowed");
|
||||||
|
|
||||||
var trx = bitjs.transaction();
|
var trx = bitjs.transaction();
|
||||||
var utxoAmt = 0.0;
|
var utxoAmt = 0.0;
|
||||||
var fee = floGlobals.fee;
|
var fee = floGlobals.fee;
|
||||||
this.promisedAPI(`api/addr/${floID}/utxo`).then(utxos => {
|
this.promisedAPI(`api/addr/${floID}/utxo`).then(utxos => {
|
||||||
for (var i = utxos.length - 1; i >= 0; i--) {
|
for (var i = utxos.length - 1; i >= 0; i--)
|
||||||
if (utxos[i].confirmations) {
|
if (utxos[i].confirmations) {
|
||||||
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i]
|
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i].scriptPubKey);
|
||||||
.scriptPubKey)
|
|
||||||
utxoAmt += utxos[i].amount;
|
utxoAmt += utxos[i].amount;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
trx.addoutput(floID, utxoAmt - fee);
|
trx.addoutput(floID, utxoAmt - fee);
|
||||||
trx.addflodata(floData.replace(/\n/g, ' '));
|
trx.addflodata(floData.replace(/\n/g, ' '));
|
||||||
var signedTxHash = trx.sign(privKey, 1);
|
var signedTxHash = trx.sign(privKey, 1);
|
||||||
@ -7581,15 +7602,15 @@
|
|||||||
writeDataMultiple: function(senderPrivKeys, data, receivers = [floGlobals.adminID], preserveRatio = true) {
|
writeDataMultiple: function(senderPrivKeys, data, receivers = [floGlobals.adminID], preserveRatio = true) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!Array.isArray(senderPrivKeys))
|
if (!Array.isArray(senderPrivKeys))
|
||||||
return reject("Invalid senderPrivKeys: SenderPrivKeys must be Array")
|
return reject("Invalid senderPrivKeys: SenderPrivKeys must be Array");
|
||||||
if (!preserveRatio) {
|
if (!preserveRatio) {
|
||||||
let tmp = {};
|
let tmp = {};
|
||||||
let amount = (floGlobals.sendAmt * receivers.length) / senderPrivKeys.length;
|
let amount = (floGlobals.sendAmt * receivers.length) / senderPrivKeys.length;
|
||||||
senderPrivKeys.forEach(key => tmp[key] = amount);
|
senderPrivKeys.forEach(key => tmp[key] = amount);
|
||||||
senderPrivKeys = tmp
|
senderPrivKeys = tmp;
|
||||||
}
|
}
|
||||||
if (!Array.isArray(receivers))
|
if (!Array.isArray(receivers))
|
||||||
return reject("Invalid receivers: Receivers must be Array")
|
return reject("Invalid receivers: Receivers must be Array");
|
||||||
else {
|
else {
|
||||||
let tmp = {};
|
let tmp = {};
|
||||||
let amount = floGlobals.sendAmt;
|
let amount = floGlobals.sendAmt;
|
||||||
@ -7652,9 +7673,8 @@
|
|||||||
if (!key)
|
if (!key)
|
||||||
invalids.InvalidSenderPrivKeys.push(key);
|
invalids.InvalidSenderPrivKeys.push(key);
|
||||||
else {
|
else {
|
||||||
if (typeof senderPrivKeys[key] !== 'number' || senderPrivKeys[
|
if (typeof senderPrivKeys[key] !== 'number' || senderPrivKeys[key] <= 0)
|
||||||
key] <= 0)
|
invalids.InvalidSenderAmountFor.push(key);
|
||||||
invalids.InvalidSenderAmountFor.push(key)
|
|
||||||
else
|
else
|
||||||
inputVal += senderPrivKeys[key];
|
inputVal += senderPrivKeys[key];
|
||||||
let floID = floCrypto.getFloID(key);
|
let floID = floCrypto.getFloID(key);
|
||||||
@ -7672,9 +7692,9 @@
|
|||||||
//Validate the receiver IDs and receive amount
|
//Validate the receiver IDs and receive amount
|
||||||
for (let floID in receivers) {
|
for (let floID in receivers) {
|
||||||
if (!floCrypto.validateAddr(floID))
|
if (!floCrypto.validateAddr(floID))
|
||||||
invalids.InvalidReceiverIDs.push(floID)
|
invalids.InvalidReceiverIDs.push(floID);
|
||||||
if (typeof receivers[floID] !== 'number' || receivers[floID] <= 0)
|
if (typeof receivers[floID] !== 'number' || receivers[floID] <= 0)
|
||||||
invalids.InvalidReceiveAmountFor.push(floID)
|
invalids.InvalidReceiveAmountFor.push(floID);
|
||||||
else
|
else
|
||||||
outputVal += receivers[floID];
|
outputVal += receivers[floID];
|
||||||
}
|
}
|
||||||
@ -7686,15 +7706,14 @@
|
|||||||
return reject(invalids);
|
return reject(invalids);
|
||||||
//Reject if given inputVal and outputVal are not equal
|
//Reject if given inputVal and outputVal are not equal
|
||||||
if (!preserveRatio && inputVal != outputVal)
|
if (!preserveRatio && inputVal != outputVal)
|
||||||
return reject(
|
return reject(`Input Amount (${inputVal}) not equal to Output Amount (${outputVal})`);
|
||||||
`Input Amount (${inputVal}) not equal to Output Amount (${outputVal})`)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return reject(error)
|
return reject(error)
|
||||||
}
|
}
|
||||||
//Get balance of senders
|
//Get balance of senders
|
||||||
let promises = []
|
let promises = [];
|
||||||
for (let floID in senders)
|
for (let floID in senders)
|
||||||
promises.push(this.getBalance(floID))
|
promises.push(this.getBalance(floID));
|
||||||
Promise.all(promises).then(results => {
|
Promise.all(promises).then(results => {
|
||||||
let totalBalance = 0,
|
let totalBalance = 0,
|
||||||
totalFee = floGlobals.fee,
|
totalFee = floGlobals.fee,
|
||||||
@ -7706,10 +7725,9 @@
|
|||||||
let insufficient = [];
|
let insufficient = [];
|
||||||
for (let floID in senders) {
|
for (let floID in senders) {
|
||||||
balance[floID] = parseFloat(results.shift());
|
balance[floID] = parseFloat(results.shift());
|
||||||
if (isNaN(balance[floID]) || (preserveRatio && balance[floID] <=
|
if (isNaN(balance[floID]) || (preserveRatio && balance[floID] <= totalFee) ||
|
||||||
totalFee) || (!preserveRatio && balance[floID] < senders[floID]
|
(!preserveRatio && balance[floID] < senders[floID].coins + dividedFee))
|
||||||
.coins + dividedFee))
|
insufficient.push(floID);
|
||||||
insufficient.push(floID)
|
|
||||||
totalBalance += balance[floID];
|
totalBalance += balance[floID];
|
||||||
}
|
}
|
||||||
if (insufficient.length)
|
if (insufficient.length)
|
||||||
@ -7721,11 +7739,11 @@
|
|||||||
for (floID in receivers)
|
for (floID in receivers)
|
||||||
totalSendAmt += receivers[floID];
|
totalSendAmt += receivers[floID];
|
||||||
if (totalBalance < totalSendAmt)
|
if (totalBalance < totalSendAmt)
|
||||||
return reject("Insufficient total Balance")
|
return reject("Insufficient total Balance");
|
||||||
//Get the UTXOs of the senders
|
//Get the UTXOs of the senders
|
||||||
let promises = []
|
let promises = [];
|
||||||
for (floID in senders)
|
for (floID in senders)
|
||||||
promises.push(this.promisedAPI(`api/addr/${floID}/utxo`))
|
promises.push(this.promisedAPI(`api/addr/${floID}/utxo`));
|
||||||
Promise.all(promises).then(results => {
|
Promise.all(promises).then(results => {
|
||||||
let wifSeq = [];
|
let wifSeq = [];
|
||||||
var trx = bitjs.transaction();
|
var trx = bitjs.transaction();
|
||||||
@ -7742,8 +7760,7 @@
|
|||||||
for (let i = utxos.length - 1;
|
for (let i = utxos.length - 1;
|
||||||
(i >= 0) && (utxoAmt < sendAmt); i--) {
|
(i >= 0) && (utxoAmt < sendAmt); i--) {
|
||||||
if (utxos[i].confirmations) {
|
if (utxos[i].confirmations) {
|
||||||
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i]
|
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i].scriptPubKey);
|
||||||
.scriptPubKey)
|
|
||||||
wifSeq.push(wif);
|
wifSeq.push(wif);
|
||||||
utxoAmt += utxos[i].amount;
|
utxoAmt += utxos[i].amount;
|
||||||
}
|
}
|
||||||
@ -7773,7 +7790,7 @@
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var request = new XMLHttpRequest();
|
var request = new XMLHttpRequest();
|
||||||
var url = this.util.serverList[this.util.curPos] + 'api/tx/send';
|
var url = this.util.serverList[this.util.curPos] + 'api/tx/send';
|
||||||
console.log(url)
|
console.log(url);
|
||||||
if (signedTxHash.length < 1)
|
if (signedTxHash.length < 1)
|
||||||
reject("Empty Signature");
|
reject("Empty Signature");
|
||||||
else {
|
else {
|
||||||
@ -7829,28 +7846,26 @@
|
|||||||
receivedOnly: filters only received data
|
receivedOnly: filters only received data
|
||||||
pattern : filters data that with JSON pattern
|
pattern : filters data that with JSON pattern
|
||||||
filter : custom filter funtion for floData (eg . filter: d => {return d[0] == '$'})
|
filter : custom filter funtion for floData (eg . filter: d => {return d[0] == '$'})
|
||||||
txid : (boolean) resolve txid or not
|
tx : (boolean) resolve tx data or not (resolves an Array of Object with tx details)
|
||||||
sender : flo-id(s) of sender
|
sender : flo-id(s) of sender
|
||||||
receiver : flo-id(s) of receiver
|
receiver : flo-id(s) of receiver
|
||||||
*/
|
*/
|
||||||
readData: function(addr, options = {}) {
|
readData: function(addr, options = {}) {
|
||||||
options.limit = options.limit || 0
|
options.limit = options.limit || 0;
|
||||||
options.ignoreOld = options.ignoreOld || 0
|
options.ignoreOld = options.ignoreOld || 0;
|
||||||
if (typeof options.sender === "string") options.sender = [options.sender];
|
if (typeof options.sender === "string") options.sender = [options.sender];
|
||||||
if (typeof options.receiver === "string") options.receiver = [options.receiver];
|
if (typeof options.receiver === "string") options.receiver = [options.receiver];
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.promisedAPI(`api/addrs/${addr}/txs?from=0&to=1`).then(response => {
|
this.promisedAPI(`api/addrs/${addr}/txs?from=0&to=1`).then(response => {
|
||||||
var newItems = response.totalItems - options.ignoreOld;
|
var newItems = response.totalItems - options.ignoreOld;
|
||||||
this.promisedAPI(`api/addrs/${addr}/txs?from=0&to=${newItems * 2}`).then(
|
this.promisedAPI(`api/addrs/${addr}/txs?from=0&to=${newItems*2}`).then(response => {
|
||||||
response => {
|
|
||||||
if (options.limit <= 0)
|
if (options.limit <= 0)
|
||||||
options.limit = response.items.length;
|
options.limit = response.items.length;
|
||||||
var filteredData = [];
|
var filteredData = [];
|
||||||
for (i = 0; i < (response.totalItems - options.ignoreOld) &&
|
for (let i = 0; i < (response.totalItems - options.ignoreOld) && filteredData.length < options.limit; i++) {
|
||||||
filteredData.length < options.limit; i++) {
|
|
||||||
if (options.pattern) {
|
if (options.pattern) {
|
||||||
try {
|
try {
|
||||||
let jsonContent = JSON.parse(response.items[i].floData)
|
let jsonContent = JSON.parse(response.items[i].floData);
|
||||||
if (!Object.keys(jsonContent).includes(options.pattern))
|
if (!Object.keys(jsonContent).includes(options.pattern))
|
||||||
continue;
|
continue;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -7895,7 +7910,16 @@
|
|||||||
}
|
}
|
||||||
if (options.filter && !options.filter(response.items[i].floData))
|
if (options.filter && !options.filter(response.items[i].floData))
|
||||||
continue;
|
continue;
|
||||||
filteredData.push(options.txid ? [response.items[i].txid, response.items[i].floData] : response.items[i].floData);
|
|
||||||
|
if (options.tx) {
|
||||||
|
let d = {}
|
||||||
|
d.txid = response.items[i].txid;
|
||||||
|
d.time = response.items[i].time;
|
||||||
|
d.blockheight = response.items[i].blockheight;
|
||||||
|
d.data = response.items[i].floData;
|
||||||
|
filteredData.push(d);
|
||||||
|
} else
|
||||||
|
filteredData.push(response.items[i].floData);
|
||||||
}
|
}
|
||||||
resolve({
|
resolve({
|
||||||
totalTxs: response.totalItems,
|
totalTxs: response.totalItems,
|
||||||
@ -8164,7 +8188,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script id="floCloudAPI" version="2.0.2e">
|
<script id="floCloudAPI" version="2.1.0a">
|
||||||
/* FLO Cloud operations to send/request application data*/
|
/* FLO Cloud operations to send/request application data*/
|
||||||
const floCloudAPI = {
|
const floCloudAPI = {
|
||||||
|
|
||||||
@ -8309,23 +8333,16 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
inactive: new Set(),
|
inactive: new Set(),
|
||||||
connect(snID) {
|
|
||||||
|
ws_connect(snID) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!(snID in floGlobals.supernodes))
|
if (!(snID in floGlobals.supernodes))
|
||||||
return reject(`${snID} is not a supernode`)
|
return reject(`${snID} is not a supernode`)
|
||||||
let inactive = this.inactive
|
let inactive = this.inactive
|
||||||
if (inactive.has(snID))
|
if (inactive.has(snID))
|
||||||
return reject(`${snID} is not active`)
|
return reject(`${snID} is not active`)
|
||||||
var wsConn = new WebSocket("wss://" + floGlobals.supernodes[snID].uri + "/ws");
|
var wsConn = new WebSocket("wss://" + floGlobals.supernodes[snID].uri + "/");
|
||||||
wsConn.onmessage = (evt) => {
|
wsConn.onopen = evt => resolve(wsConn);
|
||||||
if (evt.data == '$+')
|
|
||||||
resolve(wsConn)
|
|
||||||
else if (evt.data == '$-') {
|
|
||||||
wsConn.close();
|
|
||||||
inactive.add(snID)
|
|
||||||
reject(`${snID} is not active`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wsConn.onerror = evt => {
|
wsConn.onerror = evt => {
|
||||||
inactive.add(snID)
|
inactive.add(snID)
|
||||||
reject(`${snID} is unavailable`)
|
reject(`${snID} is unavailable`)
|
||||||
@ -8333,51 +8350,88 @@
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
connectActive(snID, reverse = false) {
|
ws_activeConnect(snID, reverse = false) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (this.inactive.size === this.kBucket.SNCO.length)
|
if (this.inactive.size === this.kBucket.SNCO.length)
|
||||||
return reject('Cloud offline')
|
return reject('Cloud offline');
|
||||||
if (!(snID in floGlobals.supernodes))
|
if (!(snID in floGlobals.supernodes))
|
||||||
snID = this.kBucket.closestNode(snID);
|
snID = this.kBucket.closestNode(snID);
|
||||||
this.connect(snID)
|
this.ws_connect(snID)
|
||||||
.then(node => resolve(node))
|
.then(node => resolve(node))
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
if (reverse)
|
if (reverse)
|
||||||
var nxtNode = this.kBucket.prevNode(snID);
|
var nxtNode = this.kBucket.prevNode(snID);
|
||||||
else
|
else
|
||||||
var nxtNode = this.kBucket.nextNode(snID);
|
var nxtNode = this.kBucket.nextNode(snID);
|
||||||
this.connectActive(nxtNode, reverse)
|
this.ws_activeConnect(nxtNode, reverse)
|
||||||
.then(node => resolve(node))
|
.then(node => resolve(node))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
singleRequest: function (floID, data) {
|
fetch_API: function(snID, data) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.connectActive(floID).then(node => {
|
if (this.inactive.has(snID))
|
||||||
let randID = floCrypto.randString(5);
|
return reject(`${snID} is not active`);
|
||||||
node.send(`${floID}|${randID}:${JSON.stringify(data)}`);
|
let fetcher, sn_url = "https://" + floGlobals.supernodes[snID].uri;
|
||||||
node.onmessage = (evt) => {
|
if (typeof data === "string")
|
||||||
if (evt.data.startsWith(randID, 1)) {
|
fetcher = fetch(sn_url + "?" + data);
|
||||||
try {
|
else if (typeof data === "object" && data.method === "POST")
|
||||||
let data = JSON.parse(evt.data.substring(42))
|
fetcher = fetch(sn_url, data);
|
||||||
resolve(data)
|
fetcher.then(response => {
|
||||||
} catch (error) {
|
if (response.ok)
|
||||||
reject(evt.data.substring(42))
|
resolve(response);
|
||||||
} finally {
|
else
|
||||||
node.close()
|
reject(response);
|
||||||
}
|
}).catch(error => reject(error))
|
||||||
}
|
})
|
||||||
}
|
|
||||||
}).catch(error => reject(error));
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
liveRequest: function (floID, datareq, callback) {
|
fetch_ActiveAPI: function(snID, data, reverse = false) {
|
||||||
let request = {
|
return new Promise((resolve, reject) => {
|
||||||
...datareq.request
|
if (this.inactive.size === this.kBucket.SNCO.length)
|
||||||
|
return reject('Cloud offline');
|
||||||
|
if (!(snID in floGlobals.supernodes))
|
||||||
|
snID = this.kBucket.closestNode(snID);
|
||||||
|
this.fetch_API(snID, data)
|
||||||
|
.then(result => resolve(result))
|
||||||
|
.catch(error => {
|
||||||
|
this.inactive.add(snID)
|
||||||
|
if (reverse)
|
||||||
|
var nxtNode = this.kBucket.prevNode(snID);
|
||||||
|
else
|
||||||
|
var nxtNode = this.kBucket.nextNode(snID);
|
||||||
|
this.fetch_ActiveAPI(nxtNode, data, reverse)
|
||||||
|
.then(result => resolve(result))
|
||||||
|
.catch(error => reject(error));
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
singleRequest: function(floID, data_obj, method = "POST") {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let data;
|
||||||
|
if (method === "POST")
|
||||||
|
data = {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data_obj)
|
||||||
};
|
};
|
||||||
|
else
|
||||||
|
data = new URLSearchParams(JSON.parse(JSON.stringify(data_obj))).toString();
|
||||||
|
this.fetch_ActiveAPI(floID, data).then(response => {
|
||||||
|
response.json()
|
||||||
|
.then(result => resolve(this.objectifier(result)))
|
||||||
|
.catch(error => {
|
||||||
|
response.text()
|
||||||
|
.then(result => reject(result)) //Error Message from Node
|
||||||
|
.catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
liveRequest: function(floID, request, callback) {
|
||||||
const checkFilter = (v, d, r) =>
|
const checkFilter = (v, d, r) =>
|
||||||
(!r.atVectorClock || r.atVectorClock == v) &&
|
(!r.atVectorClock || r.atVectorClock == v) &&
|
||||||
(r.atVectorClock || !r.lowerVectorClock || r.lowerVectorClock <= v) &&
|
(r.atVectorClock || !r.lowerVectorClock || r.lowerVectorClock <= v) &&
|
||||||
@ -8388,25 +8442,20 @@
|
|||||||
(!r.type || r.type == d.type) &&
|
(!r.type || r.type == d.type) &&
|
||||||
(!r.senderIDs || r.senderIDs.includes(d.senderID));
|
(!r.senderIDs || r.senderIDs.includes(d.senderID));
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.connectActive(floID).then(node => {
|
this.ws_activeConnect(floID).then(node => {
|
||||||
let randID = floCrypto.randString(5);
|
let randID = floCrypto.randString(5);
|
||||||
node.send(`${floID}|${randID}:${JSON.stringify(datareq)}`);
|
node.send(JSON.stringify(request));
|
||||||
node.onmessage = (evt) => {
|
node.onmessage = (evt) => {
|
||||||
if (evt.data.startsWith(randID, 1))
|
|
||||||
var i = 42
|
|
||||||
else if (evt.data.startsWith(floID, 1))
|
|
||||||
var i = 36
|
|
||||||
else return;
|
|
||||||
let d = e = null;
|
let d = e = null;
|
||||||
try {
|
try {
|
||||||
let data = JSON.parse(evt.data.substring(i))
|
let data = this.objectifier(JSON.parse(evt.data)),
|
||||||
let filter = {}
|
filter = {};
|
||||||
for (let v in data)
|
for (let v in data)
|
||||||
if (checkFilter(v, data[v], request))
|
if (checkFilter(v, data[v], request))
|
||||||
filter[v] = data[v]
|
filter[v] = data[v];
|
||||||
d = filter
|
d = filter;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
e = evt.data.substring(i)
|
e = evt.data
|
||||||
} finally {
|
} finally {
|
||||||
callback(d, e)
|
callback(d, e)
|
||||||
}
|
}
|
||||||
@ -8452,9 +8501,8 @@
|
|||||||
floGlobals.appObjects[dataSet[vc].type] = dataSet[vc].message.reset;
|
floGlobals.appObjects[dataSet[vc].type] = dataSet[vc].message.reset;
|
||||||
break;
|
break;
|
||||||
case "UPDATE":
|
case "UPDATE":
|
||||||
if (dataSet[vc].message.update)
|
if (dataSet[vc].message.diff)
|
||||||
floGlobals.appObjects[dataSet[vc].type] = mergeDiff(floGlobals
|
floGlobals.appObjects[dataSet[vc].type] = mergeDiff(floGlobals.appObjects[dataSet[vc].type], dataSet[vc].message.diff)
|
||||||
.appObjects[dataSet[vc].type], message.diff)
|
|
||||||
}
|
}
|
||||||
floGlobals.lastVC[dataSet[vc].type] = vc;
|
floGlobals.lastVC[dataSet[vc].type] = vc;
|
||||||
updatedObjects.add(dataSet[vc].type)
|
updatedObjects.add(dataSet[vc].type)
|
||||||
@ -8481,6 +8529,15 @@
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
objectifier: function(data) {
|
||||||
|
if (!Array.isArray(data))
|
||||||
|
data = [data];
|
||||||
|
return Object.fromEntries(data.map(d => {
|
||||||
|
d.message = this.decodeMessage(d.message);
|
||||||
|
return [d.vectorClock, d];
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -8501,12 +8558,8 @@
|
|||||||
.map(d => data[d]).join("|")
|
.map(d => data[d]).join("|")
|
||||||
data.sign = floCrypto.signData(hashcontent, myPrivKey)
|
data.sign = floCrypto.signData(hashcontent, myPrivKey)
|
||||||
this.util.singleRequest(data.receiverID, data)
|
this.util.singleRequest(data.receiverID, data)
|
||||||
.then(result => {
|
.then(result => resolve(result))
|
||||||
data.message = message
|
.catch(error => reject(error))
|
||||||
resolve({
|
|
||||||
[result.vectorClock]: data
|
|
||||||
})
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -8524,30 +8577,24 @@
|
|||||||
atVectorClock: options.atVectorClock || undefined,
|
atVectorClock: options.atVectorClock || undefined,
|
||||||
mostRecent: options.mostRecent || undefined,
|
mostRecent: options.mostRecent || undefined,
|
||||||
}
|
}
|
||||||
var datareq = {
|
|
||||||
time: Date.now(),
|
|
||||||
request
|
|
||||||
}
|
|
||||||
if (options.callback instanceof Function) {
|
if (options.callback instanceof Function) {
|
||||||
let callback = (d, e) => {
|
this.util.liveRequest(request.receiverID, request, options.callback)
|
||||||
for (let v in d)
|
|
||||||
d[v].message = this.util.decodeMessage(d[v].message)
|
|
||||||
options.callback(d, e)
|
|
||||||
}
|
|
||||||
this.util.liveRequest(request.receiverID, datareq, callback)
|
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
} else {
|
} else {
|
||||||
this.util.singleRequest(request.receiverID, datareq).then(data => {
|
if (options.method === "POST")
|
||||||
for (let v in data)
|
request = {
|
||||||
data[v].message = this.util.decodeMessage(data[v].message)
|
time: Date.now(),
|
||||||
resolve(data)
|
request
|
||||||
}).catch(error => reject(error))
|
};
|
||||||
|
this.util.singleRequest(request.receiverID, request, options.method || "GET")
|
||||||
|
.then(data => resolve(data)).catch(error => reject(error))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
//delete data from supernode cloud (received only)
|
//(NEEDS UPDATE) delete data from supernode cloud (received only)
|
||||||
deleteApplicationData: function(vectorClocks, options = {}) {
|
deleteApplicationData: function(vectorClocks, options = {}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var delreq = {
|
var delreq = {
|
||||||
@ -8573,7 +8620,7 @@
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
//edit comment of data in supernode cloud (mutable comments only)
|
//(NEEDS UPDATE) edit comment of data in supernode cloud (mutable comments only)
|
||||||
editApplicationData: function(vectorClock, newComment, oldData, options = {}) {
|
editApplicationData: function(vectorClock, newComment, oldData, options = {}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let p0
|
let p0
|
||||||
@ -8735,7 +8782,7 @@
|
|||||||
if (!conn)
|
if (!conn)
|
||||||
return reject('Request not found')
|
return reject('Request not found')
|
||||||
conn.onclose = evt => {
|
conn.onclose = evt => {
|
||||||
delete this.util.liveRequest[requestID]
|
delete this.util.liveRequest[requestID];
|
||||||
resolve('Request connection closed')
|
resolve('Request connection closed')
|
||||||
}
|
}
|
||||||
conn.close()
|
conn.close()
|
||||||
@ -9591,5 +9638,4 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Loading…
Reference in New Issue
Block a user