You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/concepts/immutability.md
+46-6Lines changed: 46 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,13 +12,15 @@ related:
12
12
13
13
# Immutability
14
14
15
+
## Overview
16
+
15
17
An immutable object is an object whose state cannot be altered or modified once created. Once a file is added to the IPFS network, the content of that file cannot be changed without altering the [content identifier (CID)](../concepts/content-addressing.md) of the file. This feature is excellent for storing data that does not need to change. However, when it comes to content that needs to be altered or updated, immutability becomes a problem. This page discusses how to keep a mutable _state_ built from immutable building blocks.
16
18
17
19
A CID is an _absolute_ pointer to content. No matter when we request a CID, the CID value will always be the same. This is part of the content's architecture and cannot be changed. To manage _immutable_ files in a _mutable_ system, we need to add another layer that sits on top of CIDs.
18
20
19
21
As a basic example, let's have two blocks of content with the strings `hello` and `world` hashed into two leaf nodes with the CIDs `A` and `B`. If we concatenate these two nodes, then we are given CID `C`. On top of this root CID, we assign a pointer `Pointer`.
20
22
21
-
```
23
+
```shell
22
24
+-----------+
23
25
| Pointer |
24
26
+-----------+
@@ -35,7 +37,7 @@ As a basic example, let's have two blocks of content with the strings `hello` an
35
37
36
38
If we change the content of `B` to `IPFS!`, all the upstream paths will change as well. In this simple example, the only upstream path is `C`. If we request content from the pointer we get back new content since the pointer is now _pointing_ at a completely different node. Node `B` is not being edited, updated, or otherwise changed. Instead, we are creating a new DAG where the pointer points to CID `E` that joins node `A` and a new node, node `D`.
37
39
38
-
```
40
+
```shell
39
41
+-----------+
40
42
| Pointer | --------------+
41
43
+-----------+ |
@@ -52,7 +54,7 @@ If we change the content of `B` to `IPFS!`, all the upstream paths will change a
52
54
53
55
Again, node `B` does not change. It will always refer to the same content, `world`. Node `A` also appears in the new DAG. This does not necessarily mean we copied the memory/buffer that contained the `hello` string into our new message; that would imply the location-addressed paradigm that focuses on the _where_ and not the _what_. In a content-addressed system, any time someone writes the string `hello` it will always have CID `A`, regardless of whether we copied the string from a previous location or we wrote it from scratch.
54
56
55
-
## Website explanation
57
+
###Website explanation
56
58
57
59
Here we have a website that displays two headers called `header_1` and `header_2`. The content of the headers is supplied from the variables `string_1` and `string_2`.
58
60
@@ -73,15 +75,15 @@ The CID of this website is `QmWLdyFMUugMtKZs1xeJCSUKerWd9M627gxjAtp6TLrAgP`. Use
73
75
74
76
Having a user visit the site using the CID is cumbersome since the CID will change every time a variable is updated. So instead, we can use a _pointer_ that maintains the CID of the page with the latest update. This way, users can go to `example.com`, and always be directed to the latest content. This pointer is _mutable_; it can be updated to reflect the changes downstream.
75
77
76
-
```
78
+
```shell
77
79
+--------+ +---------+ +----------+
78
80
| User | --->| Pointer | --->| QmWLd... |
79
81
+--------+ +---------+ +----------+
80
82
```
81
83
82
84
In the website example, when we change a variable, the CID of the webpage is different. The pointer must be updated to redirect users to the latest webpage. What's important is that the _old_ CID still exists. Nothing is overwritten. The original CID `QmWLdyFMUugMtKZs1xeJCSUKerWd9M627gxjAtp6TLrAgP` will always refer to a webpage with the headers `hello` and `world`. What we're doing is constructing a new [DAG](../concepts/merkle-dag.md).
83
85
84
-
```
86
+
```shell
85
87
+--------+ +---------+ +----------+
86
88
| User | --->| Pointer || QmWLd... |
87
89
+--------+ +---------+ +----------+
@@ -93,8 +95,46 @@ In the website example, when we change a variable, the CID of the webpage is dif
93
95
94
96
This process is essentially what the [InterPlantery Naming Service (IPNS)](../concepts/ipns.md) does! CIDs can be difficult to deal with and hard to remember, so IPNS saves users from the cumbersome task of dealing with CIDs directly. More importantly, CIDs change with the content because they are the content. Whereas the inbound reference of URLs/pointers stay the same, and the outbound referral changes:
To avoid the pitfalls of immutability and ensure that CIDs accurately reflect the current state of content, developers can use IPNS to create pointers to CIDs that can be updated. Instead of updating the CID itself, developers can update the IPNS address, which points to the current CID. This allows users to reference a stable, fixed IPNS address while still being able to access the latest version of the content. Learn more about IPNS [here](ipns.md).
109
+
110
+
### Using smart contracts to manage CIDs
111
+
112
+
Another approach is to use smart contract logic to manage the CIDs in an application. For example, if your application receives a CID from a smart contract, you can use smart contract functions to update the CID given to users. This allows you to change the CID without breaking the integrity of the content.
113
+
114
+
First, you will need a smart contract that manages the CID for the content you want to update. This contract should have a function that constructs the `tokenURI` for the content, using the `baseURI` stored in the contract's storage. For example:
115
+
116
+
```py
117
+
deftokenURI(this, tokenID: uint256) -> string:
118
+
return this.baseURI +str(tokenID) +".json"
119
+
```
120
+
121
+
This function returns a `tokenURI`. It will look something along the lines of `ipfs://Qmfoo/1234.json`, where _1234_ is the `tokenID` for the content.
122
+
123
+
Next, you will need to add a setter function to the contract that allows the `baseURI` to be updated. This function should only be accessible to the contract owner to ensure that only authorized users can update the CID. For example:
124
+
125
+
```py
126
+
defsetBaseURI(this, newBaseURI: string):
127
+
require(msg.sender == this.owner)
128
+
this.baseURI = newBaseURI
129
+
```
130
+
131
+
To use this function, you can call it from your contract's code or interact with it using a tool like Remix.
132
+
For example, to update the `baseURI` to `ipfs://Qmbar/`, you could use the following code:
133
+
134
+
```shell
135
+
contract.setBaseURI("ipfs://Qmbar/")
136
+
```
137
+
138
+
This will update the `baseURI` in the contract's storage, and the `tokenURI` function will now return `ipfs://Qmbar/1234.json` instead of `ipfs://Qmfoo/1234.json`.
139
+
140
+
This is one way you can use smart contract logic to manage CIDs, without changing the CID itself. This allows you to ensure that the CID accurately reflects the current state of the content and enables users to access the latest version of the content using a stable, fixed `tokenURI`.
0 commit comments