Holochain Upgrade 0.4 → 0.5
For existing hApps that are currently using Holochain 0.4, here’s the guide to get you upgraded to 0.5.
The biggest change in Holochain 0.5 is kitsune2, a new wire protocol implementation promises better gossip performance. Kitsune2 is incompatible with the wire protocols used in Holochain 0.4 and prior, so conductors running 0.5 won’t be able to communicate with conductors running earlier releases.
Quick instructions
To upgrade your hApp written for Holochain 0.5, follow these steps:
Update your
flake.nix
to use the 0.5 version of Holochain. This involves changing the version numbers of two packages. (Depending on the age of your project, you might also need to make extra changes to make it look like the one below.){ description = "Flake for Holochain app development"; inputs = { - holonix.url = "github:holochain/holonix?ref=main-0.4"; + holonix.url = "github:holochain/holonix?ref=main-0.5"; nixpkgs.follows = "holonix/nixpkgs"; flake-parts.follows = "holonix/flake-parts"; - playground.url = "github:darksoil-studio/holochain-playground?ref=main-0.4"; + playground.url = "github:darksoil-studio/holochain-playground?ref=main-0.5"; }; outputs = inputs@{ flake-parts, ... }: flake-parts.lib.mkFlake { inherit inputs; } { systems = builtins.attrNames inputs.holonix.devShells; perSystem = { inputs', pkgs, ... }: { formatter = pkgs.nixpkgs-fmt; devShells.default = pkgs.mkShell { inputsFrom = [ inputs'.holonix.devShells.default ]; packages = (with pkgs; [ nodejs_20 binaryen inputs'.playground.packages.hc-playground ]); shellHook = '' export PS1='\[\033[1;34m\][holonix:\w]\$\[\033[0m\] ' ''; }; }; }; }
This will take effect later when you enter a new Nix shell. It’s important to update your Nix flake lockfile at this point, to ensure you benefit from the cache we provide:
nix flake update && git add flake.nix && nix develop
Update your root
package.json
file with the new package versions, along with a change to accommodate Playground being bundled with Holonix and the local network services being supplied by a new binary:{ "name": "movies-dev", "private": true, "workspaces": [ "ui", "tests" ], "scripts": { "start": "AGENTS=${AGENTS:-2} BOOTSTRAP_PORT=$(get-port) SIGNAL_PORT=$(get-port) npm run network", "network": "hc sandbox clean && npm run build:happ && UI_PORT=$(get-port) concurrently \"npm run start --workspace ui\" \"npm run launch:happ\" \"hc playground\"", "test": "npm run build:zomes && hc app pack workdir --recursive && npm run test --workspace tests", "launch:happ": "hc-spin -n $AGENTS --ui-port $UI_PORT workdir/movies5.happ", "start:tauri": "AGENTS=${AGENTS:-2} BOOTSTRAP_PORT=$(get-port) npm run network:tauri", - "network:tauri": "hc sandbox clean && npm run build:happ && UI_PORT=$(get-port) concurrently \"npm run start --workspace ui\" \"npm run launch:tauri\" \"holochain-playground\"", + "network:tauri": "hc sandbox clean && npm run build:happ && UI_PORT=$(get-port) concurrently \"npm run start --workspace ui\" \"npm run launch:tauri\" \"hc playground\"", - "launch:tauri": "concurrently \"hc run-local-services --bootstrap-port $BOOTSTRAP_PORT --signal-port $SIGNAL_PORT\" \"echo pass | RUST_LOG=warn hc launch --piped -n $AGENTS workdir/movies5.happ --ui-port $UI_PORT network --bootstrap http://127.0.0.1:\"$BOOTSTRAP_PORT\" webrtc ws://127.0.0.1:\"$SIGNAL_PORT\"\"", + "launch:tauri": "concurrently \"kitsune2-bootstrap-srv --listen \"127.0.0.1:$BOOTSTRAP_PORT\"\" \"echo pass | RUST_LOG=warn hc launch --piped -n $AGENTS workdir/movies5.happ --ui-port $UI_PORT network --bootstrap http://127.0.0.1:\"$BOOTSTRAP_PORT\" webrtc ws://127.0.0.1:\"$BOOTSTRAP_PORT\"\"", "package": "npm run build:happ && npm run package --workspace ui && hc web-app pack workdir --recursive", "build:happ": "npm run build:zomes && hc app pack workdir --recursive", "build:zomes": "cargo build --release --target wasm32-unknown-unknown" }, "devDependencies": { - "@holochain-playground/cli": "^0.300.0-rc.0", - "@holochain/hc-spin": "^0.400.1", + "@holochain/hc-spin": "^0.500.1", "concurrently": "^6.5.1", "get-port-cli": "^3.0.0" }, "engines": { "node": ">=16.0.0" }, "hcScaffold": { "template": "svelte" // This might be different for your app } }
Update your project’s package dependencies (see below).
Follow the breaking change update instructions below to get your code working again.
Try running your tests:
npm test
and starting the application:
npm start
Be aware of some changes that won’t break your app but may affect its runtime behavior. Read the guide at the bottom.
Update your package dependencies
Rust
Update the hdk
and hdi
version strings in the project’s root Cargo.toml
file:
[workspace.dependencies]
-hdi = "=0.5.2"
-hdk = "=0.4.2"
+hdi = "=0.6.1" # Pick a later patch version of these libraries if you prefer.
+hdk = "=0.5.1"
The latest version numbers of these libraries can be found on crates.io: hdi
, hdk
.
Once you’ve updated your Cargo.toml
you need to update your Cargo.lock
and check whether your project can still build. To do this in one step you can run:
cargo build
(Optional) Update other Rust dependencies
Running a Cargo build, like suggested above, will update as few dependencies as it can. This is good for stability because it’s just making the changes you asked for. However, sometimes you do need to update other dependencies to resolve build issues.
This section is marked as optional because it’s possible that new dependencies could introduce new issues as well as fixing existing conflicts or problems. To make it possible to roll back this change, it might be a good idea to commit the changes you’ve made so far to source control. Then you can run:
cargo update
This will update your Cargo.lock
with the latest versions of all libraries that the constraints in your Cargo.toml
files will allow. Now you should try building your project again to see if that has resolved your issue.
JavaScript
If you’ve created your hApp using our scaffolding tool, you should be able to follow these instructions. If you’ve created your own project folder layout, adapt these instructions to fit.
Tryorama tests
Edit your project’s tests/package.json
file:
"dependencies": {
// some dependencies
- "@holochain/client": "^0.18.1",
- "@holochain/tryorama": "^0.17.1",
+ "@holochain/client": "^0.19.0",
+ "@holochain/tryorama": "^0.18.0",
// more dependencies
},
UI
You’ll update the UI package dependencies similarly to the test package. Edit ui/package.json
:
"dependencies": {
- "@holochain/client": "^0.18.1",
+ "@holochain/client": "^0.19.0",
// more dependencies
},
Then in your project’s root folder, run your package manager’s update command to update the lockfile and install new package versions for your command-line tools, tests, and UI. Use the command that matches your chosen package manager. For example, if you’re using npm
:
npm install
Update your application code
Enums in the conductor APIs are serialized differently
The admin and app APIs have changed their serialization of enum variants with values: the value is now in its own field, and enum variant names have been normalized to snake_case. For instance, if you subscribe to signals in a JavaScript-based front end, a signal payload may have previously looked like this:
{
"App": {
"cell_id": ["hC0kKUej3Mcu+40AjNGcaID2sQA6uAUcc9hmJV9XIdwUJUE", "hCAkhy0q54imKYjEpFdLTncbqAaCEGK3LCE+7HIA0kGIvTw"],
"zome_name": "movies",
"payload": "hey it's a signal"
}
}
but would now look like this:
{
"type": "app",
"value": {
"cell_id": ["hC0kKUej3Mcu+40AjNGcaID2sQA6uAUcc9hmJV9XIdwUJUE", "hCAkhy0q54imKYjEpFdLTncbqAaCEGK3LCE+7HIA0kGIvTw"],
"zome_name": "movies",
"payload": "hey it's a signal"
}
}
This change happens in many places; we recommend that you run the TypeScript compiler against your UI and tests and look for errors. In the Holonix dev shell, run:
npx tsc -p ui/tsconfig.json
npx tsc -p tests/tsconfig.json
and look for messages that look similar to error TS2322: Type X is not assignable to type Y
.
This won’t catch all errors; you may discover some at runtime. Look for usage of the following types and functions in particular:
CapAccess
andGrantedFunctions
in a capability grantCellInfo
AppWebsocket.disableCloneCell
andAppWebsocket.enableCloneCell
, which now take a newCloneCellId
type for theirclone_id
argumentSignal
origin_time
and quantum_time
are removed
With the new kitsune2 wire protocol, origin_time
and quantum_time
are no longer used. You may find these optional fields anywhere integrity modifiers are used:
In
dna.yaml
manifests, the scaffolding tool in its previous version will have automatically add anorigin_time
field. Remove it, and check for any use of thequantum_time
field too:manifest_version: '1' name: movies integrity: network_seed: null properties: foo: bar baz: 123 - origin_time: 1735841273312901 - quantum_time: 1000000 # ...
You can no longer pass these fields as DNA modifiers when you a install a hApp via the admin API or clone a cell via the app API. For example:
let clonedCell = await client.createCloneCell({ modifiers: { network_seed: "my_network_seed", - origin_time: 1735841273312901, - quantum_time: 1000000 }, name, role_name: "chat", });
AgentInfo::agent_latest_pubkey
behind feature flag
When you call agent_info
from a coordinator zome, the agent_latest_pubkey
field in the return value is now hidden behind the unstable-dpki
feature flag and scheduled to be removed in 0.6. Anywhere you use this field, use agent_initial_pubkey
instead:
use hdk::prelude::*;
fn get_my_agent_id() -> ExternResult<AgentPubKey> {
- Ok(agent_info()?.agent_latest_pubkey)
+ Ok(agent_info()?.agent_initial_pubkey)
}
DNA lineage behind feature flag
Features related to DNA lineage are now hidden behind an unstable-migration
feature flag. If you don’t plan to use this, remove the lineage
line from your dna.yaml
file:
# ...
-lineage:
- - "hC0kKUej3Mcu+40AjNGcaID2sQA6uAUcc9hmJV9XIdwUJUE"
- - "hCAkhy0q54imKYjEpFdLTncbqAaCEGK3LCE+7HIA0kGIvTw"
# ...
The GetCompatibleCells
endpoint in the admin API is also hidden behind this flag.
If you want to use these features, build a custom Holochain binary with unstable-migration
enabled. Note that support for the endpoint has been removed from the JavaScript client.
AppBundleSource::Bundle
removed
Note: This only applies if you’re building a runtime or using Tryorama’s Conductor.prototype.installApp
method. The Bundle
option (deprecated in 0.4.2) is now removed from AppBundleSource
. If you need to pass bundle bytes to the admin API’s InstallApp
endpoint, use AppBundleSource::Bytes
(introduced in 0.4.2) and pass the bytes of an entire hApp bundle file instead.
hc run-local-services
replaced with kitsune2-bootstrap-srv
The old bootstrap and signal server have been combined into one binary called kitsune2-bootstrap-srv
, which is provided in the Holonix dev environment for any new scaffolded hApps. To update an existing hApp, edit its flake.nix
file to include the binary and optionally update its package.json
file to use it if you use the Tauri-based launcher. Locally running hApp instances using hc-spin
and hc-launch
will now use the new binary.
disableCloneCell
, enableCloneCell
, and deleteCloneCell
signatures changed
The object that you pass to the JS client’s AppWebsocket.prototype.disableCloneCell
, AppWebsocket.prototype.enableCloneCell
, and AdminWebsocket.prototype.deleteCloneCell
methods has changed; now you need to explicitly specify whether the identifier is a clone ID or DNA hash using the new enum serialization format.
let cellClonedByRoleName = client.createCloneCell({
- clone_cell_id: "chat.1"
+ clone_cell_id: {
+ type: "clone_id",
+ value: "chat.1"
+ }
});
let dnaHash = decodeHashFromBase64("hC0kKUej3Mcu+40AjNGcaID2sQA6uAUcc9hmJV9XIdwUJUE");
let cellClonedByDnaHash = client.createCloneCell({
- clone_cell_id: dnaHash
+ clone_cell_id: {
+ type: "dna_hash",
+ value: dnaHash
+ }
});
Timestamps moved to holochain_timestamp
The Timestamp
type used all over the HDK and in scaffolded entry types has been moved to a new crate called holochain_timestamp
. This type has historically been made available transitively through hdi::prelude
and hdk::prelude
, so you shouldn’t need to make any code changes unless you reference the kitsune_p2p_timestamp
crate explicitly in any of your Cargo.toml
files or code:
# ...
[dependencies]
-kitsune_p2p_timestamp = "0.4.2"
+holochain_timestamp = "0.5.1"
-use kitsune_p2p_timestamp::Timestamp;
+use holochain_timestamp::Timestamp;
fn get_time() -> ExternResult<Timestamp> {
sys_time()
}
App API’s NetworkInfo
removed
The NetworkInfo
endpoint of the app API has been removed, which means the AppWebsocket.networkInfo
method has also been removed. You can get some network info from the DumpNetworkMetrics
and DumpNetworkStats
endpoints, which are now exposed on the app API.
Networking section of conductor config changed
Note: This only applies if you’re using persistent conductor configs. The network
section of conductor-config.yaml
files has changed. We recommend that you generate a new conductor config using hc sandbox
, then compare it against your existing conductor config to see what changes need to be made. You can find available config keys in the NetworkConfig
documentation.
Admin API’s AgentInfo
return value changed
Note: This is an advanced feature that you’ll only encounter if you’re building a custom runtime that tries to get diagnostic data. The return value of the AgentInfo
endpoint in the admin API has changed. Currently it outputs a vector of JSON-serialized kitsune2_api::AgentInfoSigned
values.
Subtle changes
The following changes don’t break Holochain’s APIs or require updates to your code, but they may require you to reassess whether your hApp will work as expected:
- Your front end can now call the
init
callback in any cell as if it were a regular zome function. This will in turn trigger the init process, which runs all coordinator zomes’init
functions in the order the zomes appear in the DNA manifest. If it succeeds, theinit
callback in the zome you targeted won’t be erroneously run a second time in this call or any subsequent calls. - The admin API’s
DumpNetworkMetrics
andDumpNetworkStats
are now available on the app API as well, which means that a UI written for any web-based launcher can now access them via the JavaScript client’sAppWebsocket.prototype.dumpNetworkMetrics
andAppWebsocket.prototype.dumpNetworkStats
methods. Additionally,DumpNetworkMetrics
now has an option to include a DHT summary. The output of these endpoints has changed as a result of the new network layer.