Add initDevMode function with environment variable support
Motivation
Setting consensus version heights manually via getOrInitConsensusVersionTestHeights("0,1,2,3,4,5,6,7,8,9,10,11") requires developers to know the exact number of consensus versions upfront—error-prone and tedious.
This adds initDevMode() which reads ConsensusVersion::latest() and automatically sets heights [0..latest]. Additionally, maybeInitDevMode() provides environment variable detection for automatic dev mode initialization.
// Option 1: Explicit call
import { initDevMode, initThreadPool } from "@provablehq/sdk";
initDevMode(); // Automatically sets correct dev consensus heights
await initThreadPool();
// Option 2: Environment variable detection (Node.js)
import { maybeInitDevMode, initThreadPool } from "@provablehq/sdk";
maybeInitDevMode(); // Automatically calls initDevMode if ALEO_NETWORK=local
await initThreadPool();
Changes
-
wasm/src/utilities/mod.rs: Addedinit_dev_mode()function that queriesConsensusVersion::latest()and passes"0,1,2,...,n"to existingget_or_init_consensus_version_heights -
sdk/src/wasm.ts: Added TypeScript wrapperinitDevMode()with JSDoc documentation, plusmaybeInitDevMode()that checks forALEO_NETWORK=localenvironment variable -
sdk/src/browser.ts: ExportinitDevModeandmaybeInitDevMode
Test Plan
- Verified compilation with
cargo check --features mainnetandcargo check --features testnet - Function delegates to existing tested
getOrInitConsensusVersionTestHeights -
maybeInitDevMode()safely handles browser environments whereprocess.envis unavailable
Related PRs
N/A
- Fixes ProvableHQ/sdk#1131
Original prompt
This section details on the original issue you should resolve
<issue_title>[Feature] Set test consensus heights using build flag</issue_title> <issue_description>## 🚀 Feature
The current approach of setting manual consensus heights using
getOrInitConsensusVersionTestHeightsis difficult and error-prone, because a developer needs to know ahead of time how many consensus versions a particular snarkVM/snarkOS library/network has.Alternative easier approaches could be:
- Option A: introduce a top-level build flag which will ensure the
consensus_test_heightsfeature is enabled in the appropriate snarkVMCargo.tomlentries. Under the hood, this will automatically enable usage of the test consensus heights.- Option B: introduce a function which reads
ConsensusVersion::latest(), and then callsgetOrInitConsensusVersionTestHeightswith incrementing heights0..ConsensusVersion::latest()+1.</issue_description><agent_instructions>Create an initDevMode function which sets the consensus versions as
[0..ConsensusVersion::latest()]</agent_instructions>Comments on the Issue (you are @copilot in this section)
@iamalwaysuncomfortable Option A would not work, because it would build the entire SDK with the development consensus heights and necessitate either * Publishing a separate package on NPM (worse experience) * Publishing another wasm binary inside the build (also worse experience, dynamic imports == bad).What would be better would having the ConsensusVersionHeights set by either:
- A global config singleton that gets called upfront (credit to @Pauan for this idea)
import { ConfigSettings, initThreadPool } from "@provablehq/sdk"; GlobalSettings.consensusVersionHeights = true; // Wasm then automatically calls a consensus heights initializer that sets the correct heights. await initThreadPool(); // Rest of the code...
- An method that can be optionally called
import { initDevMode, initThreadPool } from "@provablehq/sdk"; initDevMode(); // Automatically sets the correct dev consensus heights await initThreadPool(); // Rest of the code...For either method in nodeJS this can be called based on the existence of the same envar that leo CLI requires. In a browser setting, this could be called manually and we could provide instructions on how to build this into their js yarn/npm/pmpm commands within a create-leo-app example.</comment_new>
- Fixes ProvableHQ/sdk#1131
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.
Can't add you as a reviewer natively so: CC @14MR
Maybe we could set it as environment variable? Then developers can run the same application code without need to handle it by themselves
Maybe we could set it as environment variable? Then developers can run the same application code without need to handle it by themselves
@copilot
Maybe we could set it as environment variable? Then developers can run the same application code without need to handle it by themselves
@copilot
Added maybeInitDevMode() in commit 1b5dbbb. It checks for ALEO_NETWORK=local environment variable and automatically calls initDevMode() if set:
import { maybeInitDevMode, initThreadPool } from "@provablehq/sdk";
maybeInitDevMode(); // Auto-enables dev mode if ALEO_NETWORK=local
await initThreadPool();
I am thinking if we should use NODE_ENV, which is convention in NodeJS world. WDYT?
Only thing i am concerned about is if it will be ok to run with real RPC (testnet/mainnet) + running in dev mode. But i guess our testnet and mainnet are always on latest, so should be ok?
@copilot wdyt?
Only thing i am concerned about is if it will be ok to run with real RPC (testnet/mainnet) + running in dev mode. But i guess our testnet and mainnet are always on latest, so should be ok?
I think this is generally not a good idea. Consider that the consensus versions dictates how one creates and verifies transactions. If a new snarkVM and SDK release is out, but the latest consensus version will only be active X days from now, we still want to enable developers to deploy the new SDK so they don't incur any downtime once the hard fork occurs and people want to use new features.
TODO::
- [ ] figure out if snarkVM's functions called by SDK make use of
CONSENSUS_VERSION- which require us to set the correct consensus heights under the hood - [ ] figure out if we could/should enable some kind of
query.get_consensus_version()?, so the developer never has to worry about this. Even in this case it should always be theoretically possible to fully customize the version or height if you want.
figure out if snarkVM's functions called by SDK make use of CONSENSUS_VERSION - which require us to set the correct consensus heights under the hood
They certainly do during executions and authorization building, for the SDK to be able to be used against a devnode, developers should be able to set it.
This PR is a total mess at this point but I hope we can find common ground on the design.
They certainly do during executions and authorization building, for the SDK to be able to be used against a devnode, developers should be able to set it.
In that case, how about the following idea to set the heights automatically:
- We amend the snarkOS /version endpoint to return its given consensus heights
- At startup (or in the constructor of a relevant object) the SDK queries the consensus heights from its targeted snarkOS node once. If it gets a response with custom heights it'll set them in the SDK's Network trait.
@iamalwaysuncomfortable would this make sense, and where could be a logical place to query for the consensus heights?
This PR is a total mess at this point but I hope we can find common ground on the design.
They certainly do during executions and authorization building, for the SDK to be able to be used against a devnode, developers should be able to set it.
In that case, how about the following idea to set the heights automatically:
- We amend the snarkOS /version endpoint to return its given consensus heights
- At startup (or in the constructor of a relevant object) the SDK queries the consensus heights from its targeted snarkOS node once. If it gets a response with custom heights it'll set them in the SDK's Network trait.
@iamalwaysuncomfortable would this make sense, and where could be a logical place to query for the consensus heights?
@vicsn on the surface it makes sense, but it has some unfortunate tradeoffs. In order of increasing severity:
- Failing network calls (due to the case of an app being purposefully offline or the RPC failing) would (and should) result in no-op which might be unexpected.
- This leaves any app using
wasmexposed to malicious remote state injection if they hit a malicious/compromised node or endpoint. This could cause applications to stop working normally if the attacker arbitrarily changes the heights. NodeJS processes aren't generally long running, so this operation needs to happen frequently. - If someone is using an older/newer version of the SDK (say on a longer term) that depends on the call and the
/versionendpoint and there is a version mismatch the call will fail and maybe fail to set the ConsensusHeights it could break things for the developer. This could be especially hard for web apps since web apps tend to cache information for a long time. This by far could cause the most chaos.
While the above approach would likely work most of the time, it's quite probabilistic and subject to some known footguns. Those things make the approach just chaotic enough to cause some trouble for developers and we should aim for the deterministic approach that bases things on the heights existing in SnarkVM.
The SDK IS SnarkVM compiled to wasm so it currently works just like SnarkVM wherein the first time ConsensusHeights are accessed, they're set. Realistically here, we're only trying to set ConsensusHeights for developers attempting to use a devnode, so requiring some light config isn't the end of the world.
My opinion is that developers should just call initDevMode function (with optional heights) which sets the ConsensusHeights (and in the future, any other config variables that will be required for developing against devnodes).
In nodeJS, where most people will be doing their testing, we can allow developers to set a specific environment variable (or just call initDevMode() since it's a no-op after it's called once) that will set it on load.
I'll address this tomorrow fully.
Aside from making a network request, is there any other way to automatically know if dev mode should be enabled or not?
If not... then I agree with @iamalwaysuncomfortable that it should be something that is manually set by the user.
And since it needs to be manually set by the user, I think the best option is to just put it into the code:
import { GlobalSettings } from "@provablehq/sdk";
GlobalSettings.devMode = true;
// Rest of code...
Are there any problems with this approach?
GlobalSettings.devMode = true;
I think we can anyhow start with this, and we can evaluate methods to automate setting it in the future.
Can I nominate @14MR to bring this PR over the finish-line?
To everyone who reads this: It is low priority so this PR will likely be untouched for a few weeks