{"id":18679036,"url":"https://github.com/xujiandong/ckb-script-ipc","last_synced_at":"2025-08-31T01:31:30.688Z","repository":{"id":258058244,"uuid":"872722315","full_name":"XuJiandong/ckb-script-ipc","owner":"XuJiandong","description":"Libraries for IPC in CKB on-chain scripts","archived":false,"fork":false,"pushed_at":"2025-07-08T08:31:34.000Z","size":232,"stargazers_count":4,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-13T01:32:41.813Z","etag":null,"topics":["ckb","ipc","rust","script"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/XuJiandong.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-10-15T00:39:14.000Z","updated_at":"2025-07-08T08:31:38.000Z","dependencies_parsed_at":"2024-11-07T09:43:39.794Z","dependency_job_id":"dec68c8a-f891-4373-9349-5ab295b56fe2","html_url":"https://github.com/XuJiandong/ckb-script-ipc","commit_stats":null,"previous_names":["xujiandong/ckb-script-ipc"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/XuJiandong/ckb-script-ipc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XuJiandong%2Fckb-script-ipc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XuJiandong%2Fckb-script-ipc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XuJiandong%2Fckb-script-ipc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XuJiandong%2Fckb-script-ipc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/XuJiandong","download_url":"https://codeload.github.com/XuJiandong/ckb-script-ipc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XuJiandong%2Fckb-script-ipc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272929996,"owners_count":25017057,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ckb","ipc","rust","script"],"created_at":"2024-11-07T09:42:08.891Z","updated_at":"2025-08-31T01:31:30.680Z","avatar_url":"https://github.com/XuJiandong.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CKB Script IPC\n\nThis project consists of two main components: a proc-macro library for\ngenerating Inter-Process Communication (IPC) code for CKB scripts, and a common\nruntime library for CKB script IPC functionality. The proc-macro library is\ninspired from [tarpc](https://github.com/google/tarpc).\n\n\n## Overview\n\nThe `ckb-script-ipc` crate provides procedural macros that simplify the process\nof creating IPC code for CKB scripts. It automates the generation of\nserialization, deserialization, and communication boilerplate, allowing\ndevelopers to focus on the core logic of their scripts.\n\nThe `ckb-script-ipc-common` crate offers a set of tools and runtime support for\nIPC in CKB scripts. It includes necessary dependencies and features to\nfacilitate communication between different parts of a CKB script. It is used by\n`ckb-script-ipc` crate.\n\n## Features\n\n- Automatic generation of IPC message structures\n- Serialization and deserialization of IPC messages\n- Easy-to-use macros for defining IPC interfaces\n\n## Usage\n1. Import necessary crates:\n\n```toml\nckb-script-ipc = { version = \"...\" }\nckb-script-ipc-common = { version = \"...\" }\nserde = { version = \"...\", default-features = false, features = [\"derive\"] }\n```\nReplace \"...\" with the latest versions.\n\n2. Define IPC interface:\n\n```rust,ignore\n#[ckb_script_ipc::service]\npub trait World {\n    fn hello(name: String) -\u003e Result\u003cString, u64\u003e;\n}\n```\n\nPlace this trait definition in a library that is shared by both client and\nserver scripts. Note that this trait does not involve `self`. The proc-macro\nwill automatically append the necessary implementations.\n\nThe arguments and returned types in methods should implement the Serialize and\nDeserialize traits from serde.\n\n3. Start the server:\n\n```rust,ignore\nuse ckb_script_ipc_common::spawn::spawn_server;\n\nlet (read_pipe, write_pipe) = spawn_server(\n    0,\n    Source::CellDep,\n    \u0026[CString::new(\"demo\").unwrap().as_ref()],\n)?;\n```\nYou can also use `spawn_cell_server` with `code_hash/hash_type`. The pipes\nreturned will be used in client side.\n\n4. Implement and run the server:\n\n```rust,ignore\nuse crate::def::World;\nuse ckb_script_ipc_common::spawn::run_server;\n\nstruct WorldServer;\n\nimpl World for WorldServer {\n    fn hello(\u0026mut self, name: String) -\u003e Result\u003cString, u64\u003e {\n        if name == \"error\" {\n            Err(1)\n        } else {\n            Ok(format!(\"hello, {}\", name))\n        }\n    }\n}\n\nrun_server(WorldServer.server()).map_err(|_| Error::ServerError)\n```\nThe `run_server` contains a infinite loop and never returns. The method `server`\nis implemented by proc-macro implicitly.\n\n5. Create and use the client:\n\n```rust,ignore\nuse crate::def::WorldClient;\n\nlet mut client = WorldClient::new(read_pipe, write_pipe);\nlet ret = client.hello(\"world\".into()).unwrap();\n```\nThe `read_pipe`/`write_pipe` are passed into server from `spawn_server`.\n\nFor a complete example, see [ckb-script-ipc-demo](https://github.com/XuJiandong/ckb-script-ipc/tree/main/contracts/ckb-script-ipc-demo).\n\n\n## On-chain Scripts Providing Off-chain Services\nOn-chain scripts can provide services to both on-chain and off-chain components.\nHere's how to interact with these services from off-chain native code:\n\n1. Enable the `std` feature in `ckb-script-ipc-common`\n\n2. Initialize the server:\n   ```rust,ignore\n   let script_binary = std::fs::read(\"path/to/on-chain-script-binary\").unwrap();\n   let (read_pipe, write_pipe) = ckb_script_ipc_common::native::spawn_server(\u0026script_binary, \u0026[]).unwrap();\n   ```\n\n3. Create and interact with the client:\n   ```rust,ignore\n   let mut client = UnitTestsClient::new(read_pipe, write_pipe);\n   client.test_primitive_types(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, true);\n   ```\n\nNote: Steps 2 and 3 are executed on the native machine (off-chain). See full example in [test](./tests/src/tests_native.rs).\n\n## Wire format\n### Concept of Packet\n\nSince the `read`/`write` operations related to `spawn` are based on streams,\nthey don't fully meet our requirements. Therefore, we introduce a concept\nsimilar to packets. Each packet needs to contain a header to indicate basic\ninformation such as packet length, service information, error codes, etc.\n\nWe use [VLQ](https://en.wikipedia.org/wiki/Variable-length_quantity) to define\nthe length information in the packet header. Compared to fixed-length\nrepresentations, VLQ is more compact and suitable for this scenario. Packets are\ndivided into the following two categories:\n\n### Request\n\nContains the following fields without any format. That is, all fields are\ndirectly arranged without any additional header. Therefore, in the shortest\ncase, version + method id + length only occupies 3 bytes.\n- version (VLQ)\n- method id (VLQ)\n- length (VLQ)\n- payload (variable length data)\n\n### Response\n\n- version (VLQ)\n- error code (VLQ)\n- length (VLQ)\n- payload (variable length data)\n\n### Communication Details\n\n- Difference between Request and Response:\n    - All sent data belongs to Request; all received data belongs to Response.\n    - After a Request is sent, it will be processed immediately and a Response\n      will be returned. Therefore, the Response does not need to specify which\n      Request it corresponds to.\n- Packet Field Parsing:\n    - version: Indicates the version, currently 0.\n    - length: Indicates the length of the subsequent payload.\n    - method id: Represents the method ID. Some services require multiple\n      Request/Response interactions, so they are composed of multiple method\n      IDs. The range of `method id` is defined as 0 to 2^64. This field can be\n      not used because users can include it in the payload through\n      serialization/deserialization.\n    - error code: Only appears in Response, range is 0 to 2^64.\n    - payload: Defined by the service provider, developers can choose freely.\n      You can use `json` to define the data, or choose other methods.\n\nIn theory, VLQ can represent integers of any length, but considering practical\nimplementation, we need to set a boundary for easier code processing. Currently,\nwe define the range of all VLQ from 0 to 2^64, including length, method_id, error_code.\n\n\n## FAQ\nQ: What types can be used in IPC methods?\n\nA: Any arguments and returned types to IPC methods should be implemented by trait\nSerialize and Deserialize from serde. By default, all primitive types and types\nfrom standard libraries should be fine. Any user defined structure type should\nbe annotated. For example:\n```rust,ignore\n#[derive(Serialize, Deserialize)]\npub struct Struct0 {\n    pub f0: u8,\n    pub f1: u64,\n    pub f2: [u8; 3],\n}\n```\n\nQ: What serialize/deserialize format is used for message packing and unpacking?\n\nA: [serde_json](https://crates.io/crates/serde_json)\n\nQ: How can I view code expanded by `#[ckb_script_ipc::service]`?\n\nA: [cargo expand](https://github.com/dtolnay/cargo-expand)\n\nQ: Why is it called IPC and not RPC?\n\nA: The code operates within a script process that is part of a transaction, and\nit can only run on the same machine. This makes it more akin to Inter-Process\nCommunication (IPC) rather than Remote Procedure Call (RPC). RPC encompasses\nadditional features such as encryption, authentication, error propagation,\nretries and timeouts, scaling, and more. This crate focuses on a limited subset of\nthese features, primarily those relevant to IPC.\n\nQ: Is there a C implementation available?\n\nA: Yes, there is a C implementation available. See [C implementation](./c/README.md) for details. The C implementation provides the core IPC functionality but does not include built-in serialization/deserialization support. Developers using the C implementation will need to handle data serialization manually, typically using a custom format.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxujiandong%2Fckb-script-ipc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxujiandong%2Fckb-script-ipc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxujiandong%2Fckb-script-ipc/lists"}