@@ -55,7 +55,9 @@ import {
5555 type ReadStateRequest ,
5656 type HttpHeaderField ,
5757} from './types.ts' ;
58- import { type SubnetStatus , request as canisterStatusRequest } from '../../canisterStatus/index.ts' ;
58+ import { request as canisterStatusRequest } from '../../canisterStatus/index.ts' ;
59+ import { request as subnetStatusRequest } from '../../subnetStatus/index.ts' ;
60+ import { type SubnetNodeKeys } from '../../utils/readState.ts' ;
5961import { Certificate , type HashTree , lookup_path , LookupPathStatus } from '../../certificate.ts' ;
6062import { ed25519 } from '@noble/curves/ed25519' ;
6163import { ExpirableMap } from '../../utils/expirableMap.ts' ;
@@ -315,7 +317,7 @@ export class HttpAgent implements Agent {
315317 #queryPipeline: HttpAgentRequestTransformFn [ ] = [ ] ;
316318 #updatePipeline: HttpAgentRequestTransformFn [ ] = [ ] ;
317319
318- #subnetKeys: ExpirableMap < string , SubnetStatus > = new ExpirableMap ( {
320+ #subnetKeys: ExpirableMap < string , SubnetNodeKeys > = new ExpirableMap ( {
319321 expirationTime : 5 * MINUTE_TO_MSECS ,
320322 } ) ;
321323 #verifyQuerySignatures = true ;
@@ -933,17 +935,17 @@ export class HttpAgent implements Agent {
933935 } ;
934936 } ;
935937
936- const getSubnetStatus = async ( ) : Promise < SubnetStatus > => {
937- const cachedSubnetStatus = this . #subnetKeys. get ( ecid . toString ( ) ) ;
938- if ( cachedSubnetStatus ) {
939- return cachedSubnetStatus ;
938+ const getSubnetNodeKeys = async ( ) : Promise < SubnetNodeKeys > => {
939+ const cachedSubnetNodeKeys = this . #subnetKeys. get ( ecid . toString ( ) ) ;
940+ if ( cachedSubnetNodeKeys ) {
941+ return cachedSubnetNodeKeys ;
940942 }
941943 await this . fetchSubnetKeys ( ecid . toString ( ) ) ;
942- const subnetStatus = this . #subnetKeys. get ( ecid . toString ( ) ) ;
943- if ( ! subnetStatus ) {
944+ const subnetNodeKeys = this . #subnetKeys. get ( ecid . toString ( ) ) ;
945+ if ( ! subnetNodeKeys ) {
944946 throw TrustError . fromCode ( new MissingSignatureErrorCode ( ) ) ;
945947 }
946- return subnetStatus ;
948+ return subnetNodeKeys ;
947949 } ;
948950
949951 try {
@@ -953,16 +955,19 @@ export class HttpAgent implements Agent {
953955 }
954956
955957 // Make query and fetch subnet keys in parallel
956- const [ queryWithDetails , subnetStatus ] = await Promise . all ( [ makeQuery ( ) , getSubnetStatus ( ) ] ) ;
958+ const [ queryWithDetails , subnetNodeKeys ] = await Promise . all ( [
959+ makeQuery ( ) ,
960+ getSubnetNodeKeys ( ) ,
961+ ] ) ;
957962
958963 try {
959- return this . #verifyQueryResponse( queryWithDetails , subnetStatus ) ;
964+ return this . #verifyQueryResponse( queryWithDetails , subnetNodeKeys ) ;
960965 } catch {
961966 // In case the node signatures have changed, refresh the subnet keys and try again
962967 this . log . warn ( 'Query response verification failed. Retrying with fresh subnet keys.' ) ;
963968 this . #subnetKeys. delete ( ecid . toString ( ) ) ;
964- const updatedSubnetStatus = await getSubnetStatus ( ) ;
965- return this . #verifyQueryResponse( queryWithDetails , updatedSubnetStatus ) ;
969+ const updatedSubnetNodeKeys = await getSubnetNodeKeys ( ) ;
970+ return this . #verifyQueryResponse( queryWithDetails , updatedSubnetNodeKeys ) ;
966971 }
967972 } catch ( error ) {
968973 let queryError : AgentError ;
@@ -986,12 +991,12 @@ export class HttpAgent implements Agent {
986991 /**
987992 * See https://internetcomputer.org/docs/current/references/ic-interface-spec/#http-query for details on validation
988993 * @param queryResponse - The response from the query
989- * @param subnetStatus - The subnet status, including all node keys
994+ * @param subnetNodeKeys - The subnet node keys
990995 * @returns ApiQueryResponse
991996 */
992997 #verifyQueryResponse = (
993998 queryResponse : ApiQueryResponse ,
994- subnetStatus : SubnetStatus ,
999+ subnetNodeKeys : SubnetNodeKeys ,
9951000 ) : ApiQueryResponse => {
9961001 if ( this . #verifyQuerySignatures === false ) {
9971002 // This should not be called if the user has disabled verification
@@ -1030,7 +1035,7 @@ export class HttpAgent implements Agent {
10301035 const separatorWithHash = concatBytes ( IC_RESPONSE_DOMAIN_SEPARATOR , hash ) ;
10311036
10321037 // FIX: check for match without verifying N times
1033- const pubKey = subnetStatus . nodeKeys . get ( nodeId ) ;
1038+ const pubKey = subnetNodeKeys . get ( nodeId ) ;
10341039 if ( ! pubKey ) {
10351040 throw ProtocolError . fromCode ( new MalformedPublicKeyErrorCode ( ) ) ;
10361041 }
@@ -1362,21 +1367,25 @@ export class HttpAgent implements Agent {
13621367 this . #identity = Promise . resolve ( identity ) ;
13631368 }
13641369
1365- public async fetchSubnetKeys ( canisterId : Principal | string ) {
1370+ public async fetchSubnetKeys (
1371+ canisterId : Principal | string ,
1372+ ) : Promise < SubnetNodeKeys | undefined > {
13661373 const effectiveCanisterId : Principal = Principal . from ( canisterId ) ;
13671374 await this . #asyncGuard( effectiveCanisterId ) ;
1368- const response = await canisterStatusRequest ( {
1369- canisterId : effectiveCanisterId ,
1370- paths : [ 'subnet' ] ,
1375+
1376+ const subnetId = await this . getSubnetIdFromCanister ( effectiveCanisterId ) ;
1377+
1378+ const response = await subnetStatusRequest ( {
1379+ subnetId,
1380+ paths : [ 'nodeKeys' ] ,
13711381 agent : this ,
13721382 } ) ;
13731383
1374- const subnetResponse = response . get ( 'subnet' ) ;
1375- if ( subnetResponse && typeof subnetResponse === 'object' && ' nodeKeys' in subnetResponse ) {
1376- this . #subnetKeys. set ( effectiveCanisterId . toText ( ) , subnetResponse as SubnetStatus ) ;
1377- return subnetResponse as SubnetStatus ;
1384+ const nodeKeys = response . get ( 'nodeKeys' ) as SubnetNodeKeys | undefined ;
1385+ if ( nodeKeys ) {
1386+ this . #subnetKeys. set ( effectiveCanisterId . toText ( ) , nodeKeys ) ;
1387+ return nodeKeys ;
13781388 }
1379- // If the subnet status is not returned, return undefined
13801389 return undefined ;
13811390 }
13821391
@@ -1398,6 +1407,7 @@ export class HttpAgent implements Agent {
13981407 rootKey : this . rootKey ! ,
13991408 principal : { canisterId : effectiveCanisterId } ,
14001409 agent : this ,
1410+ disableTimeVerification : true , // avoid extra calls to syncTime
14011411 } ) ;
14021412
14031413 if ( ! canisterCertificate . cert . delegation ) {
0 commit comments