Skip to content

Commit

Permalink
fix: 🐛 Remove nearest endpoints fetching
Browse files Browse the repository at this point in the history
The nearest endpoints fetching created problems when dApps on https call directly a node which are not.
Then we can "Cannot reach Archethic node"
This fix uses the single endpoint passed as parameter of the Archethic's constructor
  • Loading branch information
samuelmanzanera committed Oct 18, 2024
1 parent 9ea597f commit 2429751
Show file tree
Hide file tree
Showing 6 changed files with 18 additions and 166 deletions.
20 changes: 10 additions & 10 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Transaction from "./transaction.js";
* @param query
* @param endpoint
*/
export async function rawGraphQLQuery(query: string, endpoint: string): Promise<any> {
export async function rawGraphQLQuery(query: string, endpoint: string | URL): Promise<any> {
const url = new URL("/api", endpoint);
return fetch(url, {
method: "POST",
Expand All @@ -36,7 +36,7 @@ export async function rawGraphQLQuery(query: string, endpoint: string): Promise<
* @param endpoint The Archethic API endpoint
* @returns {Promise<NearestEndpoint[]>} A list of nearest endpoints
*/
export async function getNearestEndpoints(endpoint: string): Promise<NearestEndpoint[]> {
export async function getNearestEndpoints(endpoint: string | URL): Promise<NearestEndpoint[]> {
const url = new URL("/api", endpoint);
return fetch(url, {
method: "POST",
Expand Down Expand Up @@ -68,7 +68,7 @@ export async function getNearestEndpoints(endpoint: string): Promise<NearestEndp
* @param address address to get the transaction index
* @param endpoint The Archethic API endpoint
*/
export async function getTransactionIndex(address: string | Uint8Array, endpoint: string): Promise<number> {
export async function getTransactionIndex(address: string | Uint8Array, endpoint: string | URL): Promise<number> {
address = maybeUint8ArrayToHex(address);

const url = new URL("/api", endpoint);
Expand Down Expand Up @@ -101,7 +101,7 @@ export async function getTransactionIndex(address: string | Uint8Array, endpoint
* @param endpoint The Archethic API endpoint
* @returns {Promise<string>} The balance of the address
*/
export async function getStorageNoncePublicKey(endpoint: string): Promise<string> {
export async function getStorageNoncePublicKey(endpoint: string | URL): Promise<string> {
const url = new URL("/api", endpoint);
return fetch(url, {
method: "POST",
Expand Down Expand Up @@ -136,7 +136,7 @@ export async function getStorageNoncePublicKey(endpoint: string): Promise<string
*/
export async function getTransactionOwnerships(
address: string | Uint8Array,
endpoint: string,
endpoint: string | URL,
last: boolean = false
): Promise<Ownership[]> {
address = maybeUint8ArrayToHex(address);
Expand Down Expand Up @@ -180,7 +180,7 @@ export async function getTransactionOwnerships(
* @param tokenAddress address of the token
* @param endpoint The Archethic API endpoint
*/
export async function getToken(tokenAddress: string | Uint8Array, endpoint: string): Promise<{} | Token> {
export async function getToken(tokenAddress: string | Uint8Array, endpoint: string | URL): Promise<{} | Token> {
tokenAddress = maybeUint8ArrayToHex(tokenAddress);

const url = new URL("/api", endpoint);
Expand Down Expand Up @@ -214,7 +214,7 @@ export async function getToken(tokenAddress: string | Uint8Array, endpoint: stri
* @param endpoint The Archethic API endpoint
* @param timestamp The timestamp of the data to get
*/
export async function getOracleData(endpoint: string, timestamp: undefined | number = undefined): Promise<OracleData> {
export async function getOracleData(endpoint: string | URL, timestamp: undefined | number = undefined): Promise<OracleData> {
let query;

if (timestamp === undefined) {
Expand Down Expand Up @@ -268,7 +268,7 @@ export async function getOracleData(endpoint: string, timestamp: undefined | num
* @param endpoint The Archethic API endpoint
* @param handler The handler to call when a new update is received
*/
export async function subscribeToOracleUpdates(endpoint: string, handler: Function): Promise<any> {
export async function subscribeToOracleUpdates(endpoint: string | URL, handler: Function): Promise<any> {
const { host, protocol } = new URL(endpoint);
const ws_protocol = protocol == "https:" ? "wss" : "ws";

Expand Down Expand Up @@ -299,7 +299,7 @@ export async function subscribeToOracleUpdates(endpoint: string, handler: Functi
* @param endpoint The Archethic API endpoint
* @param address The address to get the balance of
*/
export async function getBalance(address: string | Uint8Array, endpoint: string): Promise<Balance> {
export async function getBalance(address: string | Uint8Array, endpoint: string | URL): Promise<Balance> {
address = maybeUint8ArrayToHex(address);

const url = new URL("/api", endpoint);
Expand Down Expand Up @@ -332,7 +332,7 @@ export async function getBalance(address: string | Uint8Array, endpoint: string)
});
}

export async function getContractCode(address: string | Uint8Array, endpoint: string): Promise<string> {
export async function getContractCode(address: string | Uint8Array, endpoint: string | URL): Promise<string> {
address = maybeUint8ArrayToHex(address);

const url = new URL("/api", endpoint);
Expand Down
3 changes: 0 additions & 3 deletions src/api/wallet_rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ export class ArchethicWalletClient {

_dispatchConnectionState(state?: ConnectionState) {
const connectionState = state ?? this.connectionState
console.log(`Connection state updated : ${connectionState}`);
this._connectionStateEventTarget.dispatchEvent(new Event(connectionState));
}

Expand All @@ -100,8 +99,6 @@ export class ArchethicWalletClient {
*/
async connect(): Promise<void> {
return new Promise(async (resolve, reject) => {
console.log('Connection attempt');

if (this.connectionState != ConnectionState.Closed) {
return reject(new Error("Connection already established. Cancelling new connection request"));
}
Expand Down
2 changes: 0 additions & 2 deletions src/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export class EndpointFactory {
*/
build(endpoint: string | undefined): Endpoint {
if (endpoint === undefined) {
console.log('Using AWC client');
return new AWCEndpoint(
AWCWebBrowserExtension.awc ??
new ArchethicWalletClient(new AWCWebsocketStreamChannel(`ws://localhost:12345`))
Expand All @@ -26,7 +25,6 @@ export class EndpointFactory {

const url: URL = new URL(endpoint);
if (url.protocol === "http:" || url.protocol === "https:") {
console.log('Using direct endpoint');
return new DirectEndpoint(endpoint);
}

Expand Down
29 changes: 7 additions & 22 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ export default class Archethic {
rpcWallet: ArchethicWalletClient | undefined;
rpcNode: NodeRPCClient | undefined;
transaction: Transaction;
nearestEndpoints: Set<string>;
account: Account;
network: Network;

Expand All @@ -40,7 +39,6 @@ export default class Archethic {
}
this.account = new Account(this);
this.network = new Network(this);
this.nearestEndpoints = new Set<string>();
this.transaction = new Transaction(this);
this.rpcNode = new NodeRPCClient(this);
}
Expand All @@ -49,32 +47,19 @@ export default class Archethic {
if (this.endpoint instanceof AWCEndpoint) {
await this.endpoint.resolve();
}
const nodes = this.endpoint.nodeEndpoint === null ?
[] :
await Api.getNearestEndpoints(this.endpoint.nodeEndpoint.toString());

let nearestEndpoints = nodes.map(({ ip, port }) => {
return `http://${ip}:${port}`;
});

nearestEndpoints.push(this.endpoint.origin.toString()); // Add the main endpoint as fallback

this.nearestEndpoints = new Set(nearestEndpoints);
return this;
}

async requestNode(call: (endpoint: string) => Promise<any>): Promise<any> {
const node = this.nearestEndpoints.values().next().value;
async requestNode(call: (endpoint: URL) => Promise<any>): Promise<any> {
if (!this.endpoint.nodeEndpoint) {
throw new Error("Archethic node's endpoint is undefined");
}

try {
return await call(node);
return await call(this.endpoint.nodeEndpoint);
} catch (err) {
this.nearestEndpoints.delete(node);
if (this.nearestEndpoints.size == 0) {
console.log(err);
throw new Error("Cannot reach Archethic node");
}
return this.requestNode(call);
console.log(err);
throw new Error("Cannot reach Archethic node");
}
}
}
2 changes: 1 addition & 1 deletion src/transaction_sender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export default class TransactionSender {

async send(
tx: TransactionBuilder,
endpoint: string,
endpoint: string | URL,
confirmationThreshold: number = 100,
timeout: number = 60
): Promise<TransactionSender> {
Expand Down
128 changes: 0 additions & 128 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,132 +14,4 @@ describe("Archethic", () => {
expect(archethic.transaction).not.toBeUndefined();
});

describe("connect", () => {
it("should request endpoint to get list of nearest nodes", async () => {
nock("http://localhost:4000", {})
.post("/api", {
query: `query {
nearestEndpoints {
ip,
port
}
}`
})
.reply(200, {
data: {
nearestEndpoints: [
{ ip: "localhost", port: 4000 },
{ ip: "30.193.101.100", port: 40000 }
]
}
});

const archethic = new Archethic("http://localhost:4000");
await archethic.connect();

expect(archethic.nearestEndpoints).toStrictEqual(
new Set(["http://localhost:4000", "http://30.193.101.100:40000"])
);
});
});

describe("requestNode", () => {
it("should request the first nearest node", async () => {
nock("http://localhost:4000", {})
.post("/api", {
query: `query {
nearestEndpoints {
ip,
port
}
}`
})
.reply(200, {
data: {
nearestEndpoints: [
{ ip: "localhost", port: 4000 },
{ ip: "30.193.101.100", port: 40000 }
]
}
});
const archethic = new Archethic("http://localhost:4000");
await archethic.connect();

nock("http://localhost:4000", {})
.post("/api", {
query: `query {
sharedSecrets {
storageNoncePublicKey
}
}`
})
.reply(200, {
data: {
sharedSecrets: {
storageNoncePublicKey: "publicKey"
}
}
});

const publicKey = await archethic.requestNode((endpoint) => {
return API.getStorageNoncePublicKey(endpoint);
});

expect(publicKey).toBe("publicKey");
});

it("should request the next nearest node when the first failed", async () => {
nock("http://localhost:4000", {})
.post("/api", {
query: `query {
nearestEndpoints {
ip,
port
}
}`
})
.reply(200, {
data: {
nearestEndpoints: [
{ ip: "localhost", port: 4000 },
{ ip: "30.193.101.100", port: 40000 }
]
}
});
const archethic = new Archethic("http://localhost:4000");
await archethic.connect();

nock("http://localhost:4000", {})
.post("/api", {
query: `query {
sharedSecrets {
storageNoncePublicKey
}
}`
})
.reply(500, "Internal Server Error");

nock("http://30.193.101.100:40000", {})
.post("/api", {
query: `query {
sharedSecrets {
storageNoncePublicKey
}
}`
})
.reply(200, {
data: {
sharedSecrets: {
storageNoncePublicKey: "publicKey"
}
}
});

const publicKey = await archethic.requestNode((endpoint) => {
return API.getStorageNoncePublicKey(endpoint);
});

expect(publicKey).toBe("publicKey");
});
});
});

0 comments on commit 2429751

Please sign in to comment.