floBlockchainAPI v2.1.1
- improved sendTx to check if the utxo is already used but unconfirmed (ie, still in mempool) and ignore those utxos. This allows users to send multiple tx from the same floID without the need to wait for confirmation of prev tx as long as enough utxos are available. - Optional parameter: strict_utxo (boolean): Default=true (safe mode). If false, allows unconfirmed UTXOs to be included in the txn. This will allow users to chain send tx as long as enough balance FLO is available. WARNING: if one tx in the chain is dropped, all next tx dependent on that tx will be dropped too. - writeData (as it invokes sendTx) also have the above improvements
This commit is contained in:
parent
f8954a2532
commit
5c21a01b68
@ -7290,7 +7290,7 @@ Bitcoin.Util = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script id="floBlockchainAPI" version="2.1.0">
|
<script id="floBlockchainAPI" version="2.1.1">
|
||||||
/* 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 = {
|
||||||
|
|
||||||
@ -7355,57 +7355,75 @@ Bitcoin.Util = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
//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 {
|
|
||||||
var trx = bitjs.transaction();
|
//get unconfirmed tx list
|
||||||
var utxoAmt = 0.0;
|
this.promisedAPI(`api/addr/${senderAddr}`).then(result => {
|
||||||
var fee = floGlobals.fee;
|
this.readTxs(senderAddr, 0, result.unconfirmedTxApperances).then(result => {
|
||||||
this.promisedAPI(`api/addr/${senderAddr}/utxo`).then(utxos => {
|
let unconfirmedSpent = {};
|
||||||
for (var i = utxos.length - 1;
|
for (let tx of result.items)
|
||||||
(i >= 0) && (utxoAmt < sendAmt + fee); i--) {
|
if (tx.confirmations == 0)
|
||||||
if (utxos[i].confirmations) {
|
for (let vin of tx.vin)
|
||||||
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i]
|
if (vin.addr === senderAddr) {
|
||||||
.scriptPubKey)
|
if (Array.isArray(unconfirmedSpent[vin.txid]))
|
||||||
utxoAmt += utxos[i].amount;
|
unconfirmedSpent[vin.txid].push(vin.vout);
|
||||||
} else break;
|
else
|
||||||
}
|
unconfirmedSpent[vin.txid] = [vin.vout];
|
||||||
if (utxoAmt < sendAmt + fee)
|
}
|
||||||
reject("Insufficient FLO balance!");
|
//get utxos list
|
||||||
else {
|
this.promisedAPI(`api/addr/${senderAddr}/utxo`).then(utxos => {
|
||||||
trx.addoutput(receiverAddr, sendAmt);
|
//form/construct the transaction data
|
||||||
var change = utxoAmt - sendAmt - fee;
|
var trx = bitjs.transaction();
|
||||||
if (change > 0)
|
var utxoAmt = 0.0;
|
||||||
trx.addoutput(senderAddr, change);
|
var fee = floGlobals.fee;
|
||||||
trx.addflodata(floData.replace(/\n/g, ' '));
|
for (var i = utxos.length - 1;
|
||||||
var signedTxHash = trx.sign(privKey, 1);
|
(i >= 0) && (utxoAmt < sendAmt + fee); i--) {
|
||||||
this.broadcastTx(signedTxHash)
|
//use only utxos with confirmations (strict_utxo mode)
|
||||||
.then(txid => resolve(txid))
|
if (utxos[i].confirmations || !strict_utxo) {
|
||||||
.catch(error => reject(error))
|
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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (utxoAmt < sendAmt + fee)
|
||||||
|
reject("Insufficient FLO balance!");
|
||||||
|
else {
|
||||||
|
trx.addoutput(receiverAddr, sendAmt);
|
||||||
|
var change = utxoAmt - sendAmt - fee;
|
||||||
|
if (change > 0)
|
||||||
|
trx.addoutput(senderAddr, change);
|
||||||
|
trx.addflodata(floData.replace(/\n/g, ' '));
|
||||||
|
var signedTxHash = trx.sign(privKey, 1);
|
||||||
|
this.broadcastTx(signedTxHash)
|
||||||
|
.then(txid => resolve(txid))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
}
|
||||||
|
}).catch(error => reject(error))
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
}
|
}).catch(error => reject(error))
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -7425,8 +7443,7 @@ Bitcoin.Util = {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7611,8 +7628,7 @@ Bitcoin.Util = {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user