Dfx generate fetchRootKey broken with vite

I’m using vite, trying to build an extremely simple frontend. I have a simple backend canister that exposes some methods, and I’ve used dfx generate to generate the agent frontend code. No matter what I do I run into errors on the frontend, as if the agent isn’t really setup to work with anything but a node-polyfilled and opinionated webpack frontend.

This is the latest round of errors:

ror: Failed to parse
    at Uint8ArrayDecoder._decode (decoder.js:566:13)
    at Uint8ArrayDecoder.decodeFirst (decoder.js:577:10)
    at decode3 (cbor.ts:131:18)
    at HttpAgent.status (index.ts:528:17)
    at async HttpAgent.fetchRootKey (index.ts:534:24)
(anonymous) @ index.js:31
Promise.catch (async)
createActor @ index.js:27
(anonymous) @ index.js:43
ck-app.ts:46     POST http://127.0.0.1:8000/api/v2/canister/7ugoi-yiaaa-aaaaa-aabaa-cai/call 403 (Forbidden)
(anonymous) @ index.ts:325
_requestAndRetry @ index.ts:350
call @ index.ts:324
await in call (async)
caller @ actor.ts:361
handler @ actor.ts:384
getBalance @ ck-app.ts:46
connectedCallback @ ck-app.ts:20
await in connectedCallback (async)
legacyCustomElement @ custom-element.ts:21
(anonymous) @ custom-element.ts:64
__decorateClass @ ck-app.ts:7
(anonymous) @ ck-app.ts:9
Show 7 more frames
ck-app.ts:46 Server returned an error:
  Code: 403 (Forbidden)
  Body: Failed to authenticate request 0x9c8958c0dcd740d866de9710e19d2a09c59664e106ed390bf77ca647df964387 due to: Invalid delegation: Invalid canister signature: IcCanisterSignature signature could not be verified: public key 0a00000000000000070101364827569d1f66bedaa3311ba159e725920c16783773f549afe4eac95daf8446, signature d9d9f7a26b6365727469666963617465590489d9d9f7a3647472656583018301830183024863616e69737465728301830183024a0000000000000007010183018301830183024e6365727469666965645f6461746182035820d35b0d40c9fd19d39fd20fa1e245a87fe5d14eeb7a42979fe5072956c81ce48782045820fd5b59459758c8afecaf7285da359e4b5adb945fb86a3c1f0efd996c21a96938820458205f037bd92faf11cb7d76ea072ef27ba79499e56ab9344dfeb57609d445dd691182045820aa20324fc55c8061cea61b9b73bb12da019edb6726c5f822a6a1c0cb5abbeee982045820d9ca4c089f657e20f26a6270ebbeb7556f79f598b9120b5b87ccd3bb8e9aadca8204582077f0bb8fe7d6e79bc0060fc41a475527485c94b5bb00d989a77126090a4eccec8204582059607b76078b45de64776b334e2d7f2395c4c2cfddf0f2a8bd35b3591def249e82045820df9c94f7c01a25de910472d76f73e39b020e63266235d64c6ad69620b0f639b7830182045820cc578109fc5dbde591cf79cb3fa6326cdccdd9fa88ea27592ca888824366afe383024474696d6582034997a5aae3aebae4b017697369676e6174757265583097a971738f6cea92494f9c6729f7e3055cb1f59be2c89c390633ec95b6c0f08507faa5551c8abc788c2b30a4c84f60dc6a64656c65676174696f6ea2697375626e65745f6964581d43dcaf1180db82fda708ce3ac7a03a6060abde13e9546c60e8cce65d026b636572746966696361746559026ed9d9f7a264747265658301820458200ec991d75af7076a592939e333a11e1dab4445ede347a645b51246edf9bb15c383018302467375626e657483018301830182045820267fe55111b56e3c3975532ea3373f7b72e9f82072fe8e607ed34486478a5b39830182045820466a70286cf9ace9801ca53e22af6ee059a094fd60498606d484b6854058307d83018301820458208b2f6c15078ae4d3b93470915ca53e373327f37ea74ba1b8177d986bb79b31ae8302581d43dcaf1180db82fda708ce3ac7a03a6060abde13e9546c60e8cce65d02830183024f63616e69737465725f72616e67657382035832d9d9f782824a000000000000000701014a00000000000000070101824a000000000210000001014a00000000021fffff010183024a7075626c69635f6b657982035885308182301d060d2b0601040182dc7c0503010201060c2b0601040182dc7c050302010361008675b634a43e39726238cfe39c9518bc3e3225cb6f5a8479bfcf2b608fba6f8524dcb80f35a8ae44b47f262f0a6620d41279f06fe0c53a739fcca01a48926fe651a3519b5b329ffbecc9f0cb908b098dd3e8845cfb99c56379e049ac465ec806820458202c51db7b5650b7a3dbbb8530a7449cc6f90144778b62f20f3c26d72e95e5069882045820a7f251951eed726811460449388214773c94153c758afe3aaa54f9b51704268682045820df1124435df1c9bae1f1344ef3fda6a60f8faf7d06720e35f01349d8a64fc96483024474696d65820349929ab3b2ec94e0b017697369676e617475726558308e64dedf235872ccea40e5bbf1450f85c246e818b54e3bc5703da959064942a636e4a6e5c7ddc5a788335a3dcf1fe1206474726565830182045820065064c0e21c1539409dcc408d2ad11e5356c8abe1bbc7f990dd7699784972ca83024373696783025820a45b16124e26ecdf787aa9b91cb89fe95672a3f5483c97d4c95e62ad7ac512278301830258205ebc40cdda83ce2f69e0f9f3c562184e9936c70c578e78604b1316a347448430820340820458207f7ac0667c3dd3c683471af468e8edb2e19dfba234126a57d5b4f9e1a53a4d70, error: certificate verification failed: failed to verify threshold signature: certificate_tree_hash=CryptoHash(0x90990f2030e965348d83cfe74adff9ac769e5769c032a037c2b17d042d622608), sig=Blob{48 bytes;8e64dedf235872ccea40e5bbf1450f85c246e818b54e3bc5703da959064942a636e4a6e5c7ddc5a788335a3dcf1fe120}, pk=ThresholdSigPublicKey { internal: ThresBls12_381(0xa5004a15dc60bce9e9a4456648757ff3e1cfa673fd273f6559239b2710017370ea796429e024519075f97ba957795e8f165a5f8eb2a68373437a4246dd8cfc6fe30fef0f064154e1a1e414329f85b20de244d0cfc5a9e48ea5ed8b1730f68214) }, error=ThresBls12_381 signature could not be verified: public key a5004a15dc60bce9e9a4456648757ff3e1cfa673fd273f6559239b2710017370ea796429e024519075f97ba957795e8f165a5f8eb2a68373437a4246dd8cfc6fe30fef0f064154e1a1e414329f85b20de244d0cfc5a9e48ea5ed8b1730f68214, signature 8e64dedf235872ccea40e5bbf1450f85c246e818b54e3bc5703da959064942a636e4a6e5c7ddc5a788335a3dcf1fe120, error: Invalid combined threshold signature

Should I expect thedfx generate code to work in a browser without webpack? If not, what are the expectations here?

2 Likes

I think I have overcome this (by unfortunately adding node polyfills which is undesirable) though I am not sure.

I am now getting these errors:

-app.ts:48     POST http://127.0.0.1:8000/api/v2/canister/7ugoi-yiaaa-aaaaa-aabaa-cai/call 403 (Forbidden)
(anonymous) @ index.ts:325
_requestAndRetry @ index.ts:350
call @ index.ts:324
await in call (async)
caller @ actor.ts:361
handler @ actor.ts:384
getBalance @ ck-app.ts:48
connectedCallback @ ck-app.ts:20
await in connectedCallback (async)
legacyCustomElement @ custom-element.ts:21
(anonymous) @ custom-element.ts:64
__decorateClass @ ck-app.ts:7
(anonymous) @ ck-app.ts:9
Show 7 more frames
ck-app.ts:48 Server returned an error:
  Code: 403 (Forbidden)
  Body: Failed to authenticate request 0xd8afc1769b8ed135e8f56ca89bb001f60e287d4800d9ee925e18a4aa10738274 due to: Invalid delegation: Invalid canister signature: IcCanisterSignature signature could not be verified: public key 0a00000000000000070101364827569d1f66bedaa3311ba159e725920c16783773f549afe4eac95daf8446, signature d9d9f7a26b6365727469666963617465590489d9d9f7a3647472656583018301830183024863616e69737465728301830183024a0000000000000007010183018301830183024e6365727469666965645f6461746182035820d35b0d40c9fd19d39fd20fa1e245a87fe5d14eeb7a42979fe5072956c81ce48782045820fd5b59459758c8afecaf7285da359e4b5adb945fb86a3c1f0efd996c21a96938820458205f037bd92faf11cb7d76ea072ef27ba79499e56ab9344dfeb57609d445dd691182045820aa20324fc55c8061cea61b9b73bb12da019edb6726c5f822a6a1c0cb5abbeee982045820d9ca4c089f657e20f26a6270ebbeb7556f79f598b9120b5b87ccd3bb8e9aadca8204582077f0bb8fe7d6e79bc0060fc41a475527485c94b5bb00d989a77126090a4eccec8204582059607b76078b45de64776b334e2d7f2395c4c2cfddf0f2a8bd35b3591def249e82045820df9c94f7c01a25de910472d76f73e39b020e63266235d64c6ad69620b0f639b7830182045820cc578109fc5dbde591cf79cb3fa6326cdccdd9fa88ea27592ca888824366afe383024474696d6582034997a5aae3aebae4b017697369676e6174757265583097a971738f6cea92494f9c6729f7e3055cb1f59be2c89c390633ec95b6c0f08507faa5551c8abc788c2b30a4c84f60dc6a64656c65676174696f6ea2697375626e65745f6964581d43dcaf1180db82fda708ce3ac7a03a6060abde13e9546c60e8cce65d026b636572746966696361746559026ed9d9f7a264747265658301820458200ec991d75af7076a592939e333a11e1dab4445ede347a645b51246edf9bb15c383018302467375626e657483018301830182045820267fe55111b56e3c3975532ea3373f7b72e9f82072fe8e607ed34486478a5b39830182045820466a70286cf9ace9801ca53e22af6ee059a094fd60498606d484b6854058307d83018301820458208b2f6c15078ae4d3b93470915ca53e373327f37ea74ba1b8177d986bb79b31ae8302581d43dcaf1180db82fda708ce3ac7a03a6060abde13e9546c60e8cce65d02830183024f63616e69737465725f72616e67657382035832d9d9f782824a000000000000000701014a00000000000000070101824a000000000210000001014a00000000021fffff010183024a7075626c69635f6b657982035885308182301d060d2b0601040182dc7c0503010201060c2b0601040182dc7c050302010361008675b634a43e39726238cfe39c9518bc3e3225cb6f5a8479bfcf2b608fba6f8524dcb80f35a8ae44b47f262f0a6620d41279f06fe0c53a739fcca01a48926fe651a3519b5b329ffbecc9f0cb908b098dd3e8845cfb99c56379e049ac465ec806820458202c51db7b5650b7a3dbbb8530a7449cc6f90144778b62f20f3c26d72e95e5069882045820a7f251951eed726811460449388214773c94153c758afe3aaa54f9b51704268682045820df1124435df1c9bae1f1344ef3fda6a60f8faf7d06720e35f01349d8a64fc96483024474696d65820349929ab3b2ec94e0b017697369676e617475726558308e64dedf235872ccea40e5bbf1450f85c246e818b54e3bc5703da959064942a636e4a6e5c7ddc5a788335a3dcf1fe1206474726565830182045820065064c0e21c1539409dcc408d2ad11e5356c8abe1bbc7f990dd7699784972ca83024373696783025820a45b16124e26ecdf787aa9b91cb89fe95672a3f5483c97d4c95e62ad7ac512278301830258205ebc40cdda83ce2f69e0f9f3c562184e9936c70c578e78604b1316a347448430820340820458207f7ac0667c3dd3c683471af468e8edb2e19dfba234126a57d5b4f9e1a53a4d70, error: certificate verification failed: failed to verify threshold signature: certificate_tree_hash=CryptoHash(0x90990f2030e965348d83cfe74adff9ac769e5769c032a037c2b17d042d622608), sig=Blob{48 bytes;8e64dedf235872ccea40e5bbf1450f85c246e818b54e3bc5703da959064942a636e4a6e5c7ddc5a788335a3dcf1fe120}, pk=ThresholdSigPublicKey { internal: ThresBls12_381(0xa5004a15dc60bce9e9a4456648757ff3e1cfa673fd273f6559239b2710017370ea796429e024519075f97ba957795e8f165a5f8eb2a68373437a4246dd8cfc6fe30fef0f064154e1a1e414329f85b20de244d0cfc5a9e48ea5ed8b1730f68214) }, error=ThresBls12_381 signature could not be verified: public key a5004a15dc60bce9e9a4456648757ff3e1cfa673fd273f6559239b2710017370ea796429e024519075f97ba957795e8f165a5f8eb2a68373437a4246dd8cfc6fe30fef0f064154e1a1e414329f85b20de244d0cfc5a9e48ea5ed8b1730f68214, signature 8e64dedf235872ccea40e5bbf1450f85c246e818b54e3bc5703da959064942a636e4a6e5c7ddc5a788335a3dcf1fe120, error: Invalid combined threshold signature
  Retrying request.
_

My understanding is that fetchRootKey is now called automatically by createActor, but it doesn’t seem to be working. And when I call it myself it seems to have no effect either. Here’s my frontend code:

    async getBalance() {
        const agent = new HttpAgent({
            host: '127.0.0.1:8000',
            identity: this.identity
        });

        await agent.fetchRootKey();

        const walletBackend = createActor('7ugoi-yiaaa-aaaaa-aabaa-cai', {
            agent
        });

        const result = await walletBackend.getBalance();

        this.balance = result;
    }

I’m running my vite server on http://localhost:5173/ and my replica on http://127.0.0.1:8000 could this have anything to do with it? I haven’t deployed my asset canister, I’m just running a vite server.

Here is a vite config that I’ve been using: auth-client-demo/vite.config.js at main · krpeacock/auth-client-demo · GitHub

I haven’t cleaned it up for a universal dfx new starter yet, since there are still a couple sticky issues with the way that the fallback canisterIds are handled from dfx generate, but it should help

1 Like

So you don’t have any node polyfills defined, just the global thing? I can’t get past these 403 errors for some reason, I don’t know what’s going on. I’ve tried from the vite server and deploying as an asset canister.

The root and build configs are irrelevant, but the steps that I recommend following are:

  • define global as window
  • set up a dev server proxy
  • configure EnvironmentPlugin to replace CANISTER_ and DFX_ prefixed environment variables

I don’t have any node polyfills. If you have the host set to undefined during local development and you’re using the proxy server, it should work fine. You can omit host from your getBalance method

Also, i don’t really know why, but vite seems to ignore vite.config.js in my experience, so make sure you specify the -c vite.config.js in your package.json script

I would like to avoid creating a proxy server, is that necessary?

It’s not a new server - you’re already using the vite development server, so this is just proxying traffic to the replica on /api the same way a canister frontend on ic0.app works

My ideal experience would have been to just boot up any frontend server, import the generated code, and have it work. I understand the global issue (easy to get around in a variety of ways) and even polyfilling process.env (again easy), but the hosts and root key fetching seem very brittle and I think it’s undesirable to require all of this process

My frontend’s deployed URL is http://ryjl3-tyaaa-aaaaa-aaaba-cai.localhost:8000/.

My agent looks like this:

        const agent = new HttpAgent({
            host: '127.0.0.1:8000',
            identity: this.identity
        });

Why should I need a proxy server?

I’ve been trying other configurations as well, the goal is 0 config for vite, so far doesn’t seem necessary (the process/global are easy enough).

I think you may need to specify http//:127.0.0.1:8000 but otherwise should be fine. Cutting out fetchRootKey would be nice, but isn’t within my authority due to security constraints

Problem is I can’t do 127.0.0.1 with subdomains in the browser, and for some reason host in the HttpAgent settings doesn’t allow localhost.

yeah, it’s almost like the proxy configuration is less painful :slightly_smiling_face:

edit: apologies - this was unnecessarily snarky

No you’re good :slight_smile: I just see a few small issues that if cleaned up would seem to me to make things more composable and work well with various setups.

I think there’s a better way though, it shouldn’t be necessary with a few fixes in the agent code. HttpAgent should accept localhost or 127.0.0.1, because it doesn’t this seems to be breaking things.

I don’t think it’s forbidden anywhere in the agent itself - in fact we use localhost in e2e tests: agent-js/counter.ts at 1d35889e0d0c0fd4a33d02a341bd90ee156da1cd · dfinity/agent-js · GitHub

I don’t think we do it in-browser anywhere though.

I think the localhost vs 127.0.0.1 discrepancy is a dependency issue somewhere in the vite ecosystem. The same behavior started taking place in webpack starting with Node 17, if I recall

1 Like

I can see that the root key is fetched by looking at the network tab in Chrome devtools, but I keep getting these errors:

127.0.0.1:8000/api/v2/canister/7ugoi-yiaaa-aaaaa-aabaa-cai/call 403 (Forbidden)
(anony
-app.ts:48 Server returned an error:
  Code: 403 (Forbidden)
  Body: Failed to authenticate request 0x06fb68ba0987ef20247b14f4c60e4dd7c242b9d9145c4453eb25c8bbea1aa80f due to: Invalid delegation: Invalid canister signature: IcCanisterSignature signature could not be verified: public key 0a00000000000000070101364827569d1f66bedaa3311ba159e725920c16783773f549afe4eac95daf8446, signature d9d9f7a26b6365727469666963617465590489d9d9f7a3647472656583018301830183024863616e69737465728301830183024a0000000000000007010183018301830183024e6365727469666965645f6461746182035820d35b0d40c9fd19d39fd20fa1e245a87fe5d14eeb7a42979fe5072956c81ce48782045820fd5b59459758c8afecaf7285da359e4b5adb945fb86a3c1f0efd996c21a96938820458205f037bd92faf11cb7d76ea072ef27ba79499e56ab9344dfeb57609d445dd691182045820aa20324fc55c8061cea61b9b73bb12da019edb6726c5f822a6a1c0cb5abbeee982045820d9ca4c089f657e20f26a6270ebbeb7556f79f598b9120b5b87ccd3bb8e9aadca8204582077f0bb8fe7d6e79bc0060fc41a475527485c94b5bb00d989a77126090a4eccec8204582059607b76078b45de64776b334e2d7f2395c4c2cfddf0f2a8bd35b3591def249e82045820df9c94f7c01a25de910472d76f73e39b020e63266235d64c6ad69620b0f639b7830182045820cc578109fc5dbde591cf79cb3fa6326cdccdd9fa88ea27592ca888824366afe383024474696d6582034997a5aae3aebae4b017697369676e6174757265583097a971738f6cea92494f9c6729f7e3055cb1f59be2c89c390633ec95b6c0f08507faa5551c8abc788c2b30a4c84f60dc6a64656c65676174696f6ea2697375626e65745f6964581d43dcaf1180db82fda708ce3ac7a03a6060abde13e9546c60e8cce65d026b636572746966696361746559026ed9d9f7a264747265658301820458200ec991d75af7076a592939e333a11e1dab4445ede347a645b51246edf9bb15c383018302467375626e657483018301830182045820267fe55111b56e3c3975532ea3373f7b72e9f82072fe8e607ed34486478a5b39830182045820466a70286cf9ace9801ca53e22af6ee059a094fd60498606d484b6854058307d83018301820458208b2f6c15078ae4d3b93470915ca53e373327f37ea74ba1b8177d986bb79b31ae8302581d43dcaf1180db82fda708ce3ac7a03a6060abde13e9546c60e8cce65d02830183024f63616e69737465725f72616e67657382035832d9d9f782824a000000000000000701014a00000000000000070101824a000000000210000001014a00000000021fffff010183024a7075626c69635f6b657982035885308182301d060d2b0601040182dc7c0503010201060c2b0601040182dc7c050302010361008675b634a43e39726238cfe39c9518bc3e3225cb6f5a8479bfcf2b608fba6f8524dcb80f35a8ae44b47f262f0a6620d41279f06fe0c53a739fcca01a48926fe651a3519b5b329ffbecc9f0cb908b098dd3e8845cfb99c56379e049ac465ec806820458202c51db7b5650b7a3dbbb8530a7449cc6f90144778b62f20f3c26d72e95e5069882045820a7f251951eed726811460449388214773c94153c758afe3aaa54f9b51704268682045820df1124435df1c9bae1f1344ef3fda6a60f8faf7d06720e35f01349d8a64fc96483024474696d65820349929ab3b2ec94e0b017697369676e617475726558308e64dedf235872ccea40e5bbf1450f85c246e818b54e3bc5703da959064942a636e4a6e5c7ddc5a788335a3dcf1fe1206474726565830182045820065064c0e21c1539409dcc408d2ad11e5356c8abe1bbc7f990dd7699784972ca83024373696783025820a45b16124e26ecdf787aa9b91cb89fe95672a3f5483c97d4c95e62ad7ac512278301830258205ebc40cdda83ce2f69e0f9f3c562184e9936c70c578e78604b1316a347448430820340820458207f7ac0667c3dd3c683471af468e8edb2e19dfba234126a57d5b4f9e1a53a4d70, error: certificate verification failed: failed to verify threshold signature: certificate_tree_hash=CryptoHash(0x90990f2030e965348d83cfe74adff9ac769e5769c032a037c2b17d042d622608), sig=Blob{48 bytes;8e64dedf235872ccea40e5bbf1450f85c246e818b54e3bc5703da959064942a636e4a6e5c7ddc5a788335a3dcf1fe120}, pk=ThresholdSigPublicKey { internal: ThresBls12_381(0xa5004a15dc60bce9e9a4456648757ff3e1cfa673fd273f6559239b2710017370ea796429e024519075f97ba957795e8f165a5f8eb2a68373437a4246dd8cfc6fe30fef0f064154e1a1e414329f85b20de244d0cfc5a9e48ea5ed8b1730f68214) }, error=ThresBls12_381 signature could not be verified: public key a5004a15dc60bce9e9a4456648757ff3e1cfa673fd273f6559239b2710017370ea796429e024519075f97ba957795e8f165a5f8eb2a68373437a4246dd8cfc6fe30fef0f064154e1a1e414329f85b20de244d0cfc5a9e48ea5ed8b1730f68214, signature 8e64dedf235872ccea40e5bbf1450f85c246e818b54e3bc5703da959064942a636e4a6e5c7ddc5a788335a3dcf1fe120, error: Invalid combined threshold signature
  Retrying request.
_

Is that because the host of the agent and the actually host in the URL must be exactly the same?

It seems to work sometimes but not others, what is the criteria for validation?

So to simplify, currently I just want to use vite to build the static assets and deploy them, and then access the frontend from this URL: http://ryjl3-tyaaa-aaaaa-aaaba-cai.localhost:8000/.

My agent code looks like this:

    async getBalance() {
        const agent = new HttpAgent({
            identity: this.identity
        });

        const walletBackend = createActor('7ugoi-yiaaa-aaaaa-aabaa-cai', {
            agent
        });

        const result = await walletBackend.getBalance();

        this.balance = result;
    }

I’ve started my replica like this:

dfx start --clean --host 127.0.0.1:8000 --enable-bitcoin

And the root key looks like it is fetched, here’s the response to http://ryjl3-tyaaa-aaaaa-aaaba-cai.localhost:8000/api/v2/status:

����nic_api_versionf0.18.0hroot_keyX�0��0
+��|+��|a�J�`���EfHu��Ϧs�'?eY#�'sp�yd)�$Q�u�{�Wy^�Z_����sCzBF݌�o��AT��2���
�D��ũ䎥�0��limpl_versione0.8.0iimpl_hashx@e7d9c995fabd40679cf2a6025f5825a93e2520329ebe7751b2e94cd4a2b454e2ureplica_health_statusghealthy

But I keep getting:

403 forbidden
iled to authenticate request 0xb8a21f89cc90587074ae5c8a1197680946e02419c626942433d0d3275d0c43a4 due to: Invalid delegation: Invalid canister signature: IcCanisterSignature signature could not be verified: public key 0
valid combined threshold signature