Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: reconnect to working node #2417

Merged
merged 10 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,4 @@
"optional": true
}
}
}
}
16 changes: 10 additions & 6 deletions src/Executable.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ import GrpcStatus from "./grpc/GrpcStatus.js";
import List from "./transaction/List.js";
import * as hex from "./encoding/hex.js";
import HttpError from "./http/HttpError.js";
import Status from "./Status.js";

/**
* @typedef {import("./account/AccountId.js").default} AccountId
* @typedef {import("./Status.js").default} Status
* @typedef {import("./channel/Channel.js").default} Channel
* @typedef {import("./channel/MirrorChannel.js").default} MirrorChannel
* @typedef {import("./transaction/TransactionId.js").default} TransactionId
Expand All @@ -46,6 +46,7 @@ export const ExecutionState = {
};

export const RST_STREAM = /\brst[^0-9a-zA-Z]stream\b/i;
export const DEFAULT_MAX_ATTEMPTS = 10;

/**
* @abstract
Expand All @@ -62,7 +63,7 @@ export default class Executable {
* @internal
* @type {number}
*/
this._maxAttempts = 10;
this._maxAttempts = DEFAULT_MAX_ATTEMPTS;

/**
* List of node account IDs for each transaction that has been
Expand Down Expand Up @@ -611,7 +612,7 @@ export default class Executable {
// If the node is unhealthy, wait for it to be healthy
// FIXME: This is wrong, we should skip to the next node, and only perform
// a request backoff after we've tried all nodes in the current list.
if (!node.isHealthy()) {
if (!node.isHealthy() && this._nodeAccountIds.length > 1) {
if (this._logger) {
this._logger.debug(
`[${logId}] node is not healthy, skipping waiting ${node.getRemainingTime()}`,
Expand Down Expand Up @@ -706,9 +707,12 @@ export default class Executable {
// For transactions this would be as simple as checking the response status is `OK`
// while for _most_ queries it would check if the response status is `SUCCESS`
// The only odd balls are `TransactionReceiptQuery` and `TransactionRecordQuery`
const [err, shouldRetry] = this._shouldRetry(request, response);
if (err != null) {
persistentError = err;
const [status, shouldRetry] = this._shouldRetry(request, response);
if (
status.toString() !== Status.Ok.toString() &&
status.toString() !== Status.Success.toString()
) {
persistentError = status;
}

// Determine by the executing state what we should do
Expand Down
27 changes: 27 additions & 0 deletions src/RequestType.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ export default class RequestType {
return "NodeDelete";
case RequestType.TokenReject:
return "TokenReject";
case RequestType.TokenAirdrop:
return "TokenAirdrop";
case RequestType.TokenCancelAirdrop:
return "TokenCancelAirdrop";
case RequestType.TokenClaimAirdrop:
return "TokenClaimAirdrop";
default:
return `UNKNOWN (${this._code})`;
}
Expand Down Expand Up @@ -369,6 +375,12 @@ export default class RequestType {
return RequestType.NodeDelete;
case 92:
return RequestType.TokenReject;
case 93:
return RequestType.TokenAirdrop;
case 94:
return RequestType.TokenCancelAirdrop;
case 95:
return RequestType.TokenClaimAirdrop;
}

throw new Error(
Expand Down Expand Up @@ -776,3 +788,18 @@ RequestType.NodeDelete = new RequestType(91);
* Transfer one or more token balances held by the requesting account to the treasury for each token type.
*/
RequestType.TokenReject = new RequestType(92);

/**
* Airdrop one or more tokens to one or more accounts.
*/
RequestType.TokenAirdrop = new RequestType(93);

/**
* Remove one or more pending airdrops from state on behalf of the sender(s) for each airdrop.
*/
RequestType.TokenCancelAirdrop = new RequestType(94);

/**
* Claim one or more pending airdrops
*/
RequestType.TokenClaimAirdrop = new RequestType(95);
48 changes: 48 additions & 0 deletions src/Status.js
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,16 @@ export default class Status {
return "UPDATE_NODE_ACCOUNT_NOT_ALLOWED";
case Status.TokenHasNoMetadataOrSupplyKey:
return "TOKEN_HAS_NO_METADATA_OR_SUPPLY_KEY";
case Status.EmptyPendingAirdropIdList:
return "EMPTY_PENDING_AIRDROP_ID_LIST";
case Status.PendingAirdropIdRepeated:
return "PENDING_AIRDROP_ID_REPEATED";
case Status.MaxPendingAirdropIdExceeded:
return "MAX_PENDING_AIRDROP_ID_EXCEEDED";
case Status.PendingNftAirdropAlreadyExists:
return "PENDING_NFT_AIRDROP_ALREADY_EXISTS";
case Status.AccountHasPendingAirdrops:
return "ACCOUNT_HAS_PENDING_AIRDROPS";
default:
return `UNKNOWN (${this._code})`;
}
Expand Down Expand Up @@ -1329,6 +1339,16 @@ export default class Status {
return Status.UpdateNodeAccountNotAllowed;
case 360:
return Status.TokenHasNoMetadataOrSupplyKey;
case 361:
return Status.EmptyPendingAirdropIdList;
case 362:
return Status.PendingAirdropIdRepeated;
case 363:
return Status.MaxPendingAirdropIdExceeded;
case 364:
return Status.PendingNftAirdropAlreadyExists;
case 365:
return Status.AccountHasPendingAirdrops;
default:
throw new Error(
`(BUG) Status.fromCode() does not handle code: ${code}`,
Expand Down Expand Up @@ -2982,3 +3002,31 @@ Status.UpdateNodeAccountNotAllowed = new Status(359);
* The token has no metadata or supply key
*/
Status.TokenHasNoMetadataOrSupplyKey = new Status(360);

/**
* The transaction attempted to the use an empty List of `PendingAirdropId`.
*/
Status.EmptyPendingAirdropIdList = new Status(361);

/**
* The transaction attempted to the same `PendingAirdropId` twice.
*/
Status.PendingAirdropIdRepeated = new Status(362);

/**
* The transaction attempted to use more than the allowed number of `PendingAirdropId`.
*/
Status.MaxPendingAirdropIdExceeded = new Status(363);

/*
* A pending airdrop already exists for the specified NFT.
*/
Status.PendingNftAirdropAlreadyExists = new Status(364);

/*
* The identified account is sender for one or more pending airdrop(s)
* and cannot be deleted.<br/>
* Requester should cancel all pending airdrops before resending
* this transaction.
*/
Status.AccountHasPendingAirdrops = new Status(365);
25 changes: 0 additions & 25 deletions src/client/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ export default class Client {
this._isShutdown = false;

if (props != null && props.scheduleNetworkUpdate !== false) {
this._initialNetworkUpdate();
this._scheduleNetworkUpdate();
}

Expand Down Expand Up @@ -767,30 +766,6 @@ export default class Client {
}, this._networkUpdatePeriod);
}

/**
* @private
*/
_initialNetworkUpdate() {
0xivanov marked this conversation as resolved.
Show resolved Hide resolved
// This is the automatic network update promise that _eventually_ completes
// eslint-disable-next-line @typescript-eslint/no-floating-promises,@typescript-eslint/no-misused-promises
setTimeout(async () => {
try {
const addressBook = await CACHE.addressBookQueryConstructor()
.setFileId(FileId.ADDRESS_BOOK)
.execute(this);
this.setNetworkFromAddressBook(addressBook);
} catch (error) {
if (this._logger) {
this._logger.trace(
`failed to update client address book: ${
/** @type {Error} */ (error).toString()
}`,
);
}
}
}, 1000);
}

/**
* @returns {boolean}
*/
Expand Down