Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KIP 0025 : Kadena FS: URLs and methods to retrieve #54

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions kip-0025.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
KIP: "0025"
Title: Kadena FS and associated URLs
Author: CryptoPascal
Status: Draft
Type: Standard
Category: General / Pact
Created: "2023-11-17"
---

## Abstract

This KIP proposes to specify a Kadena storage standard for small JSON objects, and define ways to retrieve them.

It targets mostly the NFTs metadata, but can be used for many other purposes as well.

## Motivation

Marmalade V1 was storing the token's metadata on-chain. The main advantage was to guarantee that the NFTs metadata had exactly the same lifetime as the NFT ledger's data (ownership, ...).

Marmalade V2 and later NG decided to switch to off-chain storage. This improves the flexibility and completely disconnects the metadata from the ledger's data. But as a drawback, the NFT metadata have a different lifetime dependent on the reliability and long term storage capability of the chosen scheme (ipfs, centralized http server, ...)

The new Ordinals standard on BTC stores all metadata directly on-chain, with a good success story. Such that storing on-chain metadata starts to become the standard.


The idea behind this KIP is to unify the best of both approaches:
- keep flexibility of a Marmalade ledger by only using a "protocol agnostic" URI.
- propose a URL scheme and access mechanisms, allowing dApp and wallets to retrieve NFTs data similarly as they do for ipfs or https data.
- give a reliable long term storage possibility for the NFTs creators.


## Specification

### `kip.kdafs` interface


The following pact interface is proposed: [1]

```pact
(interface kdafs-v1

(defun kdafs-immutable:bool ())

(defun kdafs-get:object (cid:string) )
)
```

The function ``kdafs-get`` MUST accept a CID (content identifier) and return the corresponding stored object. If the CID doesn't exist, a failure must be thrown.

The function``kdafs-immutable`` MUST return a boolean indicating whether the objects delivered from this module are immutable. This allows gateways to do aggressive caching.

Notes:
- The interface doesn't expose any store like functions. This is implementation dependent and out of this KIP scope.
- Ideally, in the immutability case, the CID SHOULD be the hash of the data.

A basic immutable implementation example of this interface is included: [2]

### kdafs URLs

kdafs URLs are defined by the following scheme:

```
kdafs://network:chain/namespace.module/cid
```

where:
- `kdafs://`
- `network` is the Kadena network name: eg `testnet04`, `mainnet01`
- `chain` is the chain ID: eg 0,1,2,3, ...
- `namesapace.module` is the Fully qualified address of the module. The module MUST implement the ``kdafs`` interface.
- `cid` is the identifier of the resource defined by the ``kdafs`` interface.


### Ways of retrieval

#### On chain

The stored objects can be accessed from other modules by using modrefs calls through the common interface kip.kdafs-v1.


#### Directly by the client

A dApp or wallet can directly retrieve the data by parsing the URI and translating to the following **local** transaction:
*Some fields have been omited*

```yaml
code: ({namespace.module}.kdafs-get "{cid}")

publicMeta:
chainId: "{chain}"

networkId: "{{network}}"
```

#### HTTP Gateway

Data object can be retrieved through a kdafs -> http(s) gateway.

```
GET /kdafs/network:chain/namespace.module/cid

```

It must be noted that the HTTP request is the exact copy of the `kdafs://` URL


The gateway translates the request to a Chainweb Kadena transaction, submits it to the node, and forwards the the result to the HTTP client.

*Example:*

The content of ``kdafs://mainnet01:2/nice-namespace.storage-module/9OZ7g0kCU7BRgvgjMD0QLDGUhFOWSuNk7cT6OtTYAw8``

can be retrieved by
``https://gw.kadena-gw.io/kdafs/mainnet01:2/nice-namespace.storage-module/9OZ7g0kCU7BRgvgjMD0QLDGUhFOWSuNk7cT6OtTYAw8``


**Pact values**:
* Integers must be unwrapped by the gateway and delivered as standard JSON numbers if possible, or as strings.
* Decimals must be unwrapped if necessary by the gateway and delivered as standard JSON numbers if possible, or as strings.
* Others (not expected in data objects) Pact values (like modrefs, guards) must be forwarded as is.

The gateway MUST not use caching mechanisms if the immutable flag is not set by the module.

**HTTP Errors**:
* **404 Not Found:** Returned when the module or the CID does not exist.
* **502 Bad gateway:** Returned when the network or the chain is not recognized by the gateway
* **500 Internal server error:** A generic server error returned when it is not possible to return a better one.


## Provided code

[1] [Pact interface code](./kip-0025/kdafs-interface-v1.pact)

[2] [Example of a storage module implementation](./kip-0025/kdafs-store-one.pact)


## References

[3] https://www.ietf.org/rfc/rfc3986.txt
10 changes: 10 additions & 0 deletions kip-0025/kdafs-interface-v1.pact
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
(interface kdafs-v1

(defun kdafs-immutable:bool ()
@doc "Return true if all objects stored by this module are immutable"
)

(defun kdafs-get:object (cid:string)
@doc "Return a stored object indexed by its CID"
)
)
46 changes: 46 additions & 0 deletions kip-0025/kdafs-store-one.pact
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
(module kdafs-store-one GOVERNANCE
(implements kip.kdafs-v1)
(use free.util-time)

(defcap GOVERNANCE ()
false)

(defschema storage-sch
data:object ; Data itself
storage-time:time ; The storage date
)

(deftable storage-table:{storage-sch})

;; ---------------------------------------------------------------------------
;; Interface implementation
;; ---------------------------------------------------------------------------
(defun kdafs-immutable:bool ()
@doc "Always true because objects stored by this module are immutable"
true)

(defun kdafs-get:object (cid:string)
@doc "Return a stored object indexed by its CID"
(with-read storage-table cid {'data:=data}
data))

;; ---------------------------------------------------------------------------
;; Storage function
;; ---------------------------------------------------------------------------
(defun store:string (obj-to-store:object)
@doc "Store the given object and return the CID"
(let ((cid (hash obj-to-store)))
(insert storage-table cid {'data:obj-to-store,
'storage-time: (now)})
cid)
)

;; ---------------------------------------------------------------------------
;; Metadata (out of the interface)
;; ---------------------------------------------------------------------------
(defun get-storage-time:time (cid:string)
@doc "Return the storage time of the object"
(with-read storage-table cid {'storage-time:=t}
t))

)