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: read state with fresh expiry #938

Merged
merged 5 commits into from
Oct 15, 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
4 changes: 4 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

## Changed

- fix: recalculates body to use a fresh `Expiry` when polling for `read_state` requests. This prevents the request from exceeding the `maximum_ingress_expiry` when the replica is slow to respond.

## [2.1.2] - 2024-09-30
- fix: revert https://github.com/dfinity/agent-js/pull/923 allow option to set agent replica time
- fix: handle v3 traps correctly, pulling the reject_code and message from the certificate in the error response like v2.
Expand Down
17 changes: 10 additions & 7 deletions packages/agent/src/agent/http/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { Ed25519PublicKey } from '../../public_key';
import { decodeTime } from '../../utils/leb';
import { ObservableLog } from '../../observable';
import { BackoffStrategy, BackoffStrategyFactory, ExponentialBackoff } from '../../polling/backoff';
import { DEFAULT_INGRESS_EXPIRY_DELTA_IN_MSECS } from '../../constants';
export * from './transforms';
export { Nonce, makeNonce } from './types';

Expand All @@ -54,9 +55,6 @@ export enum RequestStatusResponseStatus {
Done = 'done',
}

// Default delta for ingress expiry is 5 minutes.
const DEFAULT_INGRESS_EXPIRY_DELTA_IN_MSECS = 5 * 60 * 1000;

// Root public key for the IC, encoded as hex
export const IC_ROOT_KEY =
'308182301d060d2b0601040182dc7c0503010201060c2b0601040182dc7c05030201036100814' +
Expand Down Expand Up @@ -779,7 +777,6 @@ export class HttpAgent implements Agent {

const requestId = await requestIdOf(request);

// TODO: remove this any. This can be a Signed or UnSigned request.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let transformedRequest: HttpAgentRequest = await this._transform({
request: {
Expand Down Expand Up @@ -946,9 +943,8 @@ export class HttpAgent implements Agent {
}
const sender = id?.getPrincipal() || Principal.anonymous();

// TODO: remove this any. This can be a Signed or UnSigned request.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const transformedRequest: any = await this._transform({
const transformedRequest = await this._transform({
request: {
method: 'POST',
headers: {
Expand Down Expand Up @@ -979,7 +975,14 @@ export class HttpAgent implements Agent {
const canister = typeof canisterId === 'string' ? Principal.fromText(canisterId) : canisterId;

const transformedRequest = request ?? (await this.createReadStateRequest(fields, identity));
const body = cbor.encode(transformedRequest.body);

// With read_state, we should always use a fresh expiry, even beyond the point where the initial request would have expired
const bodyWithAdjustedExpiry = {
...transformedRequest.body,
ingress_expiry: new Expiry(DEFAULT_INGRESS_EXPIRY_DELTA_IN_MSECS),
};

const body = cbor.encode(bodyWithAdjustedExpiry);

this.log.print(
`fetching "/api/v2/canister/${canister}/read_state" with request:`,
Expand Down
2 changes: 2 additions & 0 deletions packages/agent/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Default delta for ingress expiry is 5 minutes.
export const DEFAULT_INGRESS_EXPIRY_DELTA_IN_MSECS = 5 * 60 * 1000;
7 changes: 6 additions & 1 deletion packages/agent/src/polling/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Principal } from '@dfinity/principal';
import { Agent, RequestStatusResponseStatus } from '../agent';
import { Agent, Expiry, RequestStatusResponseStatus } from '../agent';
import { Certificate, CreateCertificateOptions, lookupResultToBuffer } from '../certificate';
import { RequestId } from '../request_id';
import { toHex } from '../utils/buffer';

export * as strategy from './strategy';
import { defaultStrategy } from './strategy';
import { DEFAULT_INGRESS_EXPIRY_DELTA_IN_MSECS } from '../constants';
export { defaultStrategy } from './strategy';
export type PollStrategy = (
canisterId: Principal,
Expand Down Expand Up @@ -38,6 +39,10 @@ export async function pollForResponse(
}> {
const path = [new TextEncoder().encode('request_status'), requestId];
const currentRequest = request ?? (await agent.createReadStateRequest?.({ paths: [path] }));

// Use a fresh expiry for the readState call.
currentRequest.body.content.ingress_expiry = new Expiry(DEFAULT_INGRESS_EXPIRY_DELTA_IN_MSECS);

const state = await agent.readState(canisterId, { paths: [path] }, undefined, currentRequest);
if (agent.rootKey == null) throw new Error('Agent root key not initialized before polling');
const cert = await Certificate.create({
Expand Down
Loading