Skip to content

Commit

Permalink
Merge pull request #62 from Dapiguabc/master
Browse files Browse the repository at this point in the history
use websocket to get tx result
  • Loading branch information
JeffWScott authored Mar 21, 2023
2 parents 40a01af + d8e8765 commit 636f3da
Show file tree
Hide file tree
Showing 12 changed files with 8,855 additions and 1,154 deletions.
8,789 changes: 8,368 additions & 421 deletions dist/cjs/lamden.js

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions dist/esm/lamden.js

Large diffs are not rendered by default.

866 changes: 303 additions & 563 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lamden-js",
"version": "3.8.1",
"version": "3.8.5",
"description": "A javascript implementaion for creating wallets, submitting transactions and interacting with masternodes on the Lamden Blockchain.",
"main": "dist/cjs/lamden.js",
"types": "src/index.d.ts",
Expand Down Expand Up @@ -49,6 +49,7 @@
"ed25519-hd-key": "^1.2.0",
"node-cryptojs-aes": "^0.4.0",
"node-fetch": "^2.6.1",
"socket.io-client": "^4.6.1",
"tweetnacl": "1.0.1",
"types-validate-assert": "^1.0.1"
},
Expand All @@ -59,7 +60,6 @@
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.0.6",
"buffer": "^6.0.3",
"chromedriver": "^105.0.1",
"dotenv": "^8.2.0",
"expect.js": "^0.3.1",
"koa": "^2.13.4",
Expand All @@ -68,6 +68,7 @@
"rollup": "^2.60.0",
"rollup-plugin-polyfill-node": "^0.7.0",
"rollup-plugin-terser": "^7.0.2",
"selenium-webdriver": "^3.6.0"
"selenium-webdriver": "^3.6.0",
"chromedriver": "^111.0.0"
}
}
86 changes: 67 additions & 19 deletions src/js/blockservice-api.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import validators from "types-validate-assert";
const { validateTypes } = validators;
import fetch from "node-fetch";
import { io } from "socket.io-client";

const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay))

export class LamdenBlockservice_API {
constructor(networkInfoObj) {
if (!validateTypes.isObjectWithKeys(networkInfoObj))
throw new Error(`Expected Network to be Object and got Type: ${typeof networkInfoObj}`);
if (validateTypes.isArrayWithValues(networkInfoObj.blockservice_hosts)){
this.hosts = this.validateHosts(networkInfoObj.blockservice_hosts);
}else{
this.hosts = []
constructor(networkInfoObj) {
if (!validateTypes.isObjectWithKeys(networkInfoObj))
throw new Error(`Expected Network to be Object and got Type: ${typeof networkInfoObj}`);
if (validateTypes.isArrayWithValues(networkInfoObj.blockservice_hosts)){
this.hosts = this.validateHosts(networkInfoObj.blockservice_hosts);
}else{
this.hosts = []
}

this.socket = io(this.host);
}
}
//This will throw an error if the protocol wasn't included in the host string
vaidateProtocol(host) {
let protocols = ["https://", "http://"];
Expand Down Expand Up @@ -117,16 +122,16 @@ async getCurrentKeysValues(keys, callback){
}
}

async getTransaction(hash, callback) {
const parms = { hash };
return this.send("GET", "/tx", { parms })
.then(res => res.json())
.then(json => {
if (callback) callback(json, null)
return json
})
.catch(err => {
if (err.message.includes("invalid json response body")) {
async getTransaction(hash, callback) {
const parms = { hash };
return this.send("GET", "/tx", { parms })
.then(res => res.json())
.then(json => {
if (callback) callback(json, null)
return json
})
.catch(err => {
if (err.message.includes("invalid json response body")) {
if (callback) callback(null, null)
return null
}else{
Expand Down Expand Up @@ -154,5 +159,48 @@ async getContractInfo(contractName) {
return {error: err.message}
})
}
}

async subscribeTx (txHash) {
// ensure socket connected
while(this.socket && !this.socket.connected){
await sleep(500)
}
// check whether the socket is connected
if (this.socket && !this.socket) {
return {error: "Subscribe tx result failed. Blockservice socket disconnected"}
}
// join the tx hash room
this.socket.emit('join', txHash);

return new Promise((resolve) => {

const processResult = (data) => {
const { room, message } = JSON.parse(data)
if (room !== txHash) {
return
}

// leave tx room
this.socket.emit('leave', txHash);
// off the listener
this.socket.off(txHash, processResult)

resolve({
hlc_timestamp: message.hlc_timestamp,
blockNum: message.blockNum,
affectedContractsList: message.affectedContractsList,
affectedVariablesList: message.affectedVariablesList,
affectedRootKeysList: message.affectedRootKeysList,
affectedRawKeysList: message.affectedRawKeysList,
state_changes_obj: typeof(message.state_changes_obj) === "string"? JSON.parse(message.state_changes_obj) : message.state_changes_obj,
txHash: message.txInfo.hash,
txInfo: message.txInfo,
senderVk: message.sender,
rewards: message.rewards
})
}
// listen for the event
this.socket.on("new-state-changes-by-transaction", processResult);
})
}
}
53 changes: 9 additions & 44 deletions src/js/transactionBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,60 +311,25 @@ export class TransactionBuilder extends Network {
}

async checkBlockserviceForTransactionResult(callback = undefined) {
if (!this.txHash) {
throw new Error("No transaction hash to check.")
}
if (!this.txHash) {
throw new Error("No transaction hash to check.")
}

// Check if the blockservice is up
let serverAvailable = await this.blockservice.pingServer()
//If it's not then fail over to checking from the masternode
if (!serverAvailable) {
console.log("Blockservice not available, failing back to masternode.")
return this.checkForTransactionResult(callback).then(
(res) => {
return {txinfo: res, ...res}
}
)
return this.checkForTransactionResult(callback).then((res) => {
return {txinfo: res, ...res}
}
)
}

let count = this.maxBlockToCheck
return new Promise(async (resolve) => {
let lastLatestBlock = this.startBlock || 0
// Get the next 10 blocks from the blockservice starting with the block the transction was sent from
const getLatestBlock = async () => {
if (count < 1) {
this.txCheckResult.errors = [`No transaction result found within ${this.maxBlockToCheck} attempts.`]
this.txCheckResult.status = 2
resolve(this.handleMasterNodeResponse(this.txCheckResult, callback));
}
count = count - 1
let latestBlock = await this.blockservice.getLastetBlock()
if (latestBlock !== lastLatestBlock){
lastLatestBlock = latestBlock
checkForTrasaction()
}else{
setTimeout(getLatestBlock, 5000)
}
}

// Check all the transaction in these blocks for our transction hash
const checkForTrasaction = async () => {
let txResults = await this.blockservice.getTransaction(this.txHash)
if (txResults){
this.txCheckResult = {...txResults, ...txResults.txInfo}
resolve(this.handleMasterNodeResponse(this.txCheckResult, callback));
}else{
if (count < 1){
this.txCheckResult.errors = [`No transaction result found within ${this.maxBlockToCheck} attempts.`]
this.txCheckResult.status = 2
let txResults = await this.blockservice.subscribeTx(this.txHash)
this.txCheckResult = {...txResults, ...txResults.txInfo}
resolve(this.handleMasterNodeResponse(this.txCheckResult, callback));
}else{
setTimeout(getLatestBlock, 5000)
}
}
}

getLatestBlock()
});
}
handleMasterNodeResponse(result, callback = undefined) {
Expand Down
53 changes: 51 additions & 2 deletions test/blockservice_api-test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
const expect = require("expect.js");
require("dotenv").config();
const Lamden = require("../dist/cjs/lamden");
const { Blockservice_API, wallet } = Lamden;


const { vk, sk } = process.env;

const senderWallet = { vk, sk };

let recieverWallet = Lamden.wallet.new_wallet();

let senderVk = senderWallet.vk;
let contractName = "currency";
let methodName = "transfer";
let stampLimit = 100;

let kwargs = {
to: recieverWallet.vk,
amount: 1,
};

let txInfo_noNonce = { senderVk, contractName, methodName, kwargs, stampLimit };


let goodNetwork = {
type: "testnet",
version: 2,
name: "Lamden Public Testnet",
blockservice_hosts: ["http://165.227.181.34:3535"],
blockservice_hosts: ["https://testnet-v2-bs-bang.lamden.io"],
hosts: ["https://testnet-v2-master-bang.lamden.io"],
};
let goodNetwork_api = new Blockservice_API(goodNetwork);

Expand All @@ -20,7 +43,7 @@ let badNetwork_api = new Blockservice_API(badNetwork);
function copyObject(object) {
return JSON.parse(JSON.stringify(object));
}
let good_tx_hash = "b9f9d598c56ae579b8392651a9a463335b68bdf4d6fd60391fca19a7b1fdb46b"
let good_tx_hash = "08e229b123c2997329d217baab9e22311d57851ef7b6d2314eb87017316eab55"
let bad_tx_hash = "this_is_a_bad_tx_hash"

let keyPair = wallet.new_wallet();
Expand Down Expand Up @@ -48,6 +71,14 @@ const notExistKeysToGet = [{
key: 'nope_key_123973'
}]

function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}

describe("Test Blockservice_API", () => {
context("constructor", () => {
it("can create an instance", () => {
Expand Down Expand Up @@ -293,4 +324,22 @@ describe("Test Blockservice_API", () => {
});
})
});

context(".subscribeTx()", () => {
context("Promise", () => {
it("returns a result", async function () {
this.timeout(10000);
let newTx = new Lamden.TransactionBuilder(goodNetwork, txInfo_noNonce);
await newTx.getNonce();
//Sign transaction
newTx.sign(senderWallet.sk);

//Send Tx
await newTx.send();
let hash = newTx.txSendResult.hash;
let res = await goodNetwork_api.subscribeTx(hash);
expect(res.txHash).to.equal(hash);
});
})
});
});
4 changes: 2 additions & 2 deletions test/browsers/masternode_api-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ describe("Browsers Tests: Test Masternode API returns", () => {
let callback = arguments[arguments.length-1];
let api = new Lamden.Masternode_API(goodNetwork);
let response = await api.getCurrencyBalance(balanceCheckWallet.float);
callback(response);
callback(response.toNumber());
}, goodNetwork, balanceCheckWallet).then(res => {
expect(res).to.above(0);
})
Expand All @@ -146,7 +146,7 @@ describe("Browsers Tests: Test Masternode API returns", () => {
let callback = arguments[arguments.length-1];
let api = new Lamden.Masternode_API(goodNetwork);
let response = await api.getCurrencyBalance(balanceCheckWallet.int);
callback(response);
callback(response.toNumber());
}, goodNetwork, balanceCheckWallet).then(res => {
expect(res).to.above(0);
})
Expand Down
5 changes: 2 additions & 3 deletions test/browsers/network-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,14 @@ describe("Browsers Tests: Test Netowrk class", () => {

context("Constructor", () => {
it("can create an instance", async () => {
let network = await driver.executeScript("return new Lamden.Network(arguments[0])", goodNetwork);
let network = await driver.executeScript("return new Lamden.Network(arguments[0]).getNetworkInfo()", goodNetwork);
expect(network).to.exist;
expect(JSON.stringify(network.hosts)).to.be(JSON.stringify(goodNetwork.hosts));
expect(network.hosts[0]).to.be(goodNetwork.hosts[0]);
expect(network.hosts[0]).to.be(goodNetwork.hosts[0]);
expect(network.type).to.be(goodNetwork.type);
expect(network.name).to.be(goodNetwork.name);
expect(network.lamden).to.be(goodNetwork.lamden);
expect(network.blockExplorer).to.be(goodNetwork.blockExplorer);
});

it("rejects missing hosts Array", async () => {
Expand Down Expand Up @@ -85,7 +84,7 @@ describe("Browsers Tests: Test Netowrk class", () => {
it("defaults missing type to custom", async () => {
let networkInfo = copyObject(goodNetwork);
networkInfo.type = "";
let network = await driver.executeScript("return new Lamden.Network(arguments[0])", networkInfo);
let network = await driver.executeScript("return new Lamden.Network(arguments[0]).getNetworkInfo()", networkInfo);
expect(network.type).to.be("custom");
});
it("rejects arg not being an object", async () => {
Expand Down
6 changes: 3 additions & 3 deletions test/browsers/transactionBatcher-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ describe("Browsers Tests: Test TransactionBuilder class", async () => {

context("new TransactionBuilder", () => {
it("can create an instance", async () => {
let txb = await driver.executeScript(function (networkInfo) {
return new Lamden.TransactionBatcher(networkInfo);
let res = await driver.executeScript(function (networkInfo) {
return new Lamden.TransactionBatcher(networkInfo).running;
}, networkInfo)
expect(txb.running).to.be(false);
expect(res).to.be(false);
});
}); /*
context('TransactionBatcher.addTransaction()', () => {
Expand Down
Loading

0 comments on commit 636f3da

Please sign in to comment.