Skip to content
Closed
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
245 changes: 245 additions & 0 deletions docs/documentation/act.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,248 @@ This section is still being worked on. Check back soon for updates!
* Show example of creating grantee list
* Show example of secure upload
* Show example of secure download


## Create Grantees List
First we create a grantees list with the public keys of anyone we want to grant access to:

```js
import { Bee, PublicKey, BatchId } from '@ethersphere/bee-js';

// Initialize Bee instance
const bee = new Bee('http://localhost:1643');

// Grantee's public key (replace with the actual key)
const grantees = [
new PublicKey('027d0c4759f689ea3dd3eb79222870671c492cb99f3fade275bcbf0ea39cd0ef6e'),
];

// Your postage batch ID (replace with a valid one)
const postageBatchId = new BatchId('f2949db4cfa4f5140ed3ef29f651d189175a8cb9534c992d3c3212b17f0b67f7');

// Function to create grantees list
async function createGranteeList() {
try {
// Create the grantee list using `createGrantees`
const response = await bee.createGrantees(postageBatchId, grantees);

// Log the response (ref and history ref)
console.log('Grantee List Created Successfully:');
console.log('Reference:', response.ref.toHex());
console.log('History Reference:', response.historyref.toHex());
} catch (error) {
console.error('Error creating grantee list:', error);
}
}

// Call the function to create the grantee list
createGranteeList();
```

Example output:

```bash
Grantee List Created Successfully:
Reference: 98bc4076efe5736aa682649c1928cbc9e0ac11d395f7ed0e67126ff660f5410a238e14f8b1d74f7df6121b8450d79ca789a257eeb84c5ca7dda3ed08a6859934
History Reference: 06ee838e1f9b26c6d44077a2e63ad5ba9ecc143f278f9301f477eb99391f5796
```

The first reference `Reference` is used on its own for reviewing the list contents and updating the list. It is encrypted so only the list creator can view the list contents.

The seconde reference `History Reference` is used along with the first `Reference` for creating a new grantee list based on the list referred to by the `Reference`.

## Update Grantees

In order to update grantees we pass an object in this format to the `bee.patchGrantees` method containing the public keys we wish to add or remove from the list along with the `History Reference` and the grantee list `Reference` and a valid postage stamp:

```js
bee.patchGrantees(postageBatchId, granteeListRef, granteeHistoryRef, {
add: [grantee1, grantee2], // Add the new grantee
revoke: [],
});
```

Calling this method will create an entirely new grantees list based on our first list and will return the `Reference` and `History Reference` for the new list.

This ***WILL NOT*** update which users had access to content uploaded using the first grantees list, it is simply creating a new list with a different set of grantees which can be used for uploading content accessible to the new set.

Full example script:

```js
import { Bee, PublicKey, BatchId, Reference } from '@ethersphere/bee-js';

// Initialize Bee instance
const bee = new Bee('http://localhost:1643'); // Correct port is 1643

// Grantee's public key to be added (replace with the actual key)
const grantee = new PublicKey('03636056d1e08f100c5acaf14d10070102de9444c97b2e8215305ab3e97254ede6');

// Grantee list reference and history reference (replace with actual references from `createGrantees`)
const granteeListRef = new Reference('98bc4076efe5736aa682649c1928cbc9e0ac11d395f7ed0e67126ff660f5410a238e14f8b1d74f7df6121b8450d79ca789a257eeb84c5ca7dda3ed08a6859934')
const granteeHistoryRef = new Reference('06ee838e1f9b26c6d44077a2e63ad5ba9ecc143f278f9301f477eb99391f5796')

// Your postage batch ID (replace with a valid one)
const postageBatchId = new BatchId('f2949db4cfa4f5140ed3ef29f651d189175a8cb9534c992d3c3212b17f0b67f7');

// Function to update the grantee list by adding the new public key
async function updateGranteeList() {
try {
// Call the patchGrantees function to add the new public key
const response = await bee.patchGrantees(postageBatchId, granteeListRef, granteeHistoryRef, {
add: [grantee], // Add the new grantee
revoke: [],
});

// Log the updated grantee list references
console.log('Grantee List Updated Successfully:');
console.log('Updated Reference:', response.ref.toHex());
console.log('Updated History Reference:', response.historyref.toHex());
} catch (error) {
console.error('Error updating grantee list:', error.message);
if (error.response) {
// If there's a response object, log the full response for more details
console.error('Response Status:', error.response.status);
console.error('Response Body:', JSON.stringify(error.response.body, null, 2));
}
}
}

// Call the function to update the grantee list
updateGranteeList();
```

Example output:

```bash
Grantee List Updated Successfully:
Updated Reference: 363430f8c500e7ea7d23eff1f14674cf6d46ce1640684edad7cc2e5631c37bbaf9dc5b0f5ea42f919191c77187a7f1f40adfd1ab60bc84f1ae4f2d7bf42b98bd
Updated History Reference: c2a43bea8abaae8ef31141ef8ec953097c76f48c2a14c1a6119bb110675e5378
```

## Get Grantees List

In order to view the members of our grantees list we need to use the `Reference` returned when we create or update a list. We will view both our original list and the updated list based on the original list using the respective `Reference` from each list:

```js
import { Bee, Reference } from '@ethersphere/bee-js';

// Initialize Bee instance with the correct port (1643)
const bee = new Bee('http://localhost:1643');


// Grantee list references (the reference returned from the `createGrantees` function)
const granteeListRef_01 = new Reference('98bc4076efe5736aa682649c1928cbc9e0ac11d395f7ed0e67126ff660f5410a238e14f8b1d74f7df6121b8450d79ca789a257eeb84c5ca7dda3ed08a6859934');
const granteeListRef_02 = new Reference('363430f8c500e7ea7d23eff1f14674cf6d46ce1640684edad7cc2e5631c37bbaf9dc5b0f5ea42f919191c77187a7f1f40adfd1ab60bc84f1ae4f2d7bf42b98bd');

// Function to get the grantee list
async function getGranteeList(granteeListRef) {
try {
// Call the getGrantees function with the reference
const result = await bee.getGrantees(granteeListRef);

// Log the full response
console.log('Grantee List Retrieved:');
console.log('Status:', result.status);
console.log('Status Text:', result.statusText);

// Log the as an array of their string representations (compressed hex values)
console.log('Grantees:', result.grantees.map(grantee => grantee.toCompressedHex()));

} catch (error) {
console.error('Error retrieving grantee list:', error);
}
}

// Call the function to fetch the grantee list
getGranteeList(granteeListRef_01);
getGranteeList(granteeListRef_02);
```

Example output:

```bash
Grantee List Retrieved:
Status: 200
Status Text: OK
Grantees: [
'027d0c4759f689ea3dd3eb79222870671c492cb99f3fade275bcbf0ea39cd0ef6e'
]
Grantee List Retrieved:
Status: 200
Status Text: OK
Grantees: [
'027d0c4759f689ea3dd3eb79222870671c492cb99f3fade275bcbf0ea39cd0ef6e',
'03636056d1e08f100c5acaf14d10070102de9444c97b2e8215305ab3e97254ede6'
]
```

The first list of grantees contains the first public key we gave access to when we created the list, while the second one contains both the first and the second one we added when we created our second list based on the first one.

## Upload With ACT

We can upload our content with either of the two lists we created depending on which set of users we wish to give access too. In the example below, we use both lists.

```js
import { Bee, BatchId, Reference } from '@ethersphere/bee-js';

// Initialize Bee instance with the correct port (1643)
const bee = new Bee('http://localhost:1643');

// Your postage batch ID (replace with a valid one)
const postageBatchId = new BatchId('f2949db4cfa4f5140ed3ef29f651d189175a8cb9534c992d3c3212b17f0b67f7');

// Grantee history reference (the reference returned from the `createGrantees` function)
const granteeHistoryRef1 = new Reference('06ee838e1f9b26c6d44077a2e63ad5ba9ecc143f278f9301f477eb99391f5796');
const granteeHistoryRef2 = new Reference('c2a43bea8abaae8ef31141ef8ec953097c76f48c2a14c1a6119bb110675e5378');

// Sample data to upload
const fileData = 'This is a sample string that will be uploaded securely using ACT. ABCDE.';

// Function to upload the data with ACT
async function uploadWithACT(historyRef) {
try {
// Upload the string with ACT enabled
const result = await bee.uploadFile(postageBatchId, fileData, 'samplefile.txt', {
act: true, // Enable ACT for the uploaded data
actHistoryAddress: historyRef, // Provide the grantee list reference for ACT
contentType: 'text/plain',
});

console.log('File uploaded successfully with ACT:');
console.log('Reference:', result.reference.toHex());
console.log("History reference")
console.log(result.historyAddress.value.toHex())
} catch (error) {
console.error('Error uploading file with ACT:', error);
}
}

// Call the function to upload the file
uploadWithACT(granteeHistoryRef1);
uploadWithACT(granteeHistoryRef2);
```

Example output:

```bash
File uploaded successfully with ACT:
Reference: d3d4485efcc22acdf4d20a31d79edc3220655151bd15cec0df9111e0c0f89e86
History reference
06ee838e1f9b26c6d44077a2e63ad5ba9ecc143f278f9301f477eb99391f5796
File uploaded successfully with ACT:
Reference: d3d4485efcc22acdf4d20a31d79edc3220655151bd15cec0df9111e0c0f89e86
History reference
c2a43bea8abaae8ef31141ef8ec953097c76f48c2a14c1a6119bb110675e5378
```

The reference hash is the same for each upload since the content is the same. The reference hash along with a `History Reference` and the uploader's public key are required in order to access the content uploaded with ACT.

You can choose which `History Reference` to share depending on which set of public keys you wish to authorize to download the content.

## Download With ACT

The example below uses the first `History Reference`, and so can only gives access to the single public key in the grantees list it refers to. If we wish to give both public keys access then we could share the other key.

```bash
curl -X GET "http://localhost:1633/bzz/d3d4485efcc22acdf4d20a31d79edc3220655151bd15cec0df9111e0c0f89e86/" -H "swarm-act-publisher: 0295562f9c1013d1db29f7aaa0c997c4bb3f1fc053bd0ed49a3d98584490cc8f96" -H "swarm-act-history-address: 06ee838e1f9b26c6d44077a2e63ad5ba9ecc143f278f9301f477eb99391f5796" --output downloaded_file.txt
```
144 changes: 143 additions & 1 deletion docs/documentation/gsoc.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,146 @@ This section is still being worked on. Check back soon for updates!

* Show mining the writer private key for the targeted overlay address [Gist](https://gist.github.com/Cafe137/e76ef081263aaec7a715139d700f3433)
* Show a simple listener, and a simple send invocation [Gist1](https://gist.github.com/Cafe137/7f02fb54ad5a79833f3b718b94df0d41) [Gist2](https://gist.github.com/Cafe137/6277f1d112b3b78ba36f717551357c3b)
* Show Identifier class usage [Gist](https://gist.github.com/Cafe137/25a244d85758480aa1e15c80ff147b72)
* Show Identifier class usage [Gist](https://gist.github.com/Cafe137/25a244d85758480aa1e15c80ff147b72)


The GSOC (Graffiti Several Owner Chunk) feature allows a **full node** to receive messages from many other nodes using a shared Single Owner Chunk (SOC). This enables real-time communication and notification over Swarm.

## Overview

GSOC messages are updates to a pre-mined SOC that lands in the **neighborhood** of the recipient node. Only full nodes receive these updates because light nodes do not sync neighborhood chunks. However, **any node** (light or full) can send GSOC messages.

### GSOC vs PSS

GSOC shares some similarities with PSS - both features allow for full nodes to receive messages from other nodes.

However, there are several key differences:

- Unlike PSS, **GSOC only needs to mine the target chunk once**—multiple messages reuse it, making it **faster, cheaper**, and **more efficient** for recurring updates.
- Unlike PSS, **No encryption** is used by default, making it unsuitable for handling sensitive data.


## Requirements

To use the example scripts below, you need:

- A Bee full node with a fully synced reserve for receiving GSOC messages.
- A light node for sending GSOC messages.
- The batch ID of a usable postage batch. If you don't have one already, you will need to [buy a batch](/docs/storage/#purchasing-storage) to upload data. If you do have one, you will need to [get and save](/docs/storage/#selecting-a-batch) its batch ID.

## Create an Identifier (Receiver and Sender)

Identifiers in GSOC are similar to topics in PSS — they define the stream of messages a receiver node is subscribed to. The sender must use the same identifier so that their messages are received.

Each identifier is a 64-digit hex string (32 bytes). It can be initialized with an a hex string of your choice or any arbitrary string using the `Identifier` utility class. You can also use the zero-initialized `NULL_IDENTIFIER` as a default identifier for cases where you don't need a unique identifier:


```js
import { Identifier, NULL_IDENTIFIER } from '@ethersphere/bee-js'

// Use default (all zeros):
const identifier = NULL_IDENTIFIER

// From a hex string:
const identifier = new Identifier('6527217e549e84f98e51b1d8b1ead62ff5cad59acd9713825754555d6975f103')

// From a human-readable string:
const identifier = Identifier.fromString('chat:v1')
```

- Use `NULL_IDENTIFIER` is a 64 digit hex string of all zeros - use it for quick testing or when uniqueness doesn't matter.
- Use any hex string to initialize a new `Identifier` object .
- Use `Identifier.fromString()` to generate an identifier derived from your string of choice (allows for easy to remember human readable identifiers `"notifications"`, `"chat:user1"`).

## Get Target Overlay (Receiver Node)

This step **is performed by the receiving full node** to retrieve its overlay address. This overlay address is then shared with the sender node to use as a target overlay for its GSOC messages:

```js
import { Bee } from '@ethersphere/bee-js'

const bee = new Bee('http://localhost:1633')

async function checkAddresses() {
const addresses = await bee.getNodeAddresses()
console.log('Node Addresses:', addresses)
}

checkAddresses()
```

Example output:

```bash
Node Addresses:
Overlay: 1e2054bec3e681aeb0b365a1f9a574a03782176bd3ec0bcf810ebcaf551e4070
Ethereum: 9a73f283cd9211b96b5ec63f7a81a0ddc847cd93
Public Key: 7d0c4759f689ea3dd3eb79222870671c492cb99f3fade275bcbf0ea39cd0ef6e25edd43c99985983e49aa528f3f2b6711085354a31acb4e7b03559b02ec868f0
PSS Public Key: 5ade58d20be7e04ee8f875eabeebf9c53375a8fc73917683155c7c0b572f47ef790daa3328f48482663954d12f6e4739f748572c1e86bfa89af99f17e7dd4d33
Underlay: [
'/ip4/127.0.0.1/tcp/1634/p2p/QmcpSJPHuuQYRgDkNfwziihVcpuVteoNxePvfzaJyp9z7j',
'/ip4/172.17.0.2/tcp/1634/p2p/QmcpSJPHuuQYRgDkNfwziihVcpuVteoNxePvfzaJyp9z7j',
'/ip6/::1/tcp/1634/p2p/QmcpSJPHuuQYRgDkNfwziihVcpuVteoNxePvfzaJyp9z7j'
]
```

The `Overlay` should be saved and shared with sender nodes.

## Set Up a Listener (Receiver Node)

This must be run on a full node. It mines a key that lands within its own neighborhood and starts listening.

```js
import { Bee, Identifier, NULL_IDENTIFIER } from '@ethersphere/bee-js'

const bee = new Bee('http://localhost:1633')
const identifier = Identifier.fromString(NULL_IDENTIFIER)

async function listen() {
const { overlay } = await bee.getNodeAddresses()

// The signer is initialized using the receiving node's own overlay and chosen identifier
const signer = bee.gsocMine(overlay, identifier)

// A GSOC subscription is established using the blockchain address derived from the signer and the identifier
bee.gsocSubscribe(signer.publicKey().address(), identifier, {
// A callback function is used to handle incoming updates - you can include your application logic here
onMessage: message => console.log('Received:', message.toUtf8()),
onError: error => console.error('Subscription error:', error),
})

console.log('Listening for GSOC updates...')
}

listen()
```

## Send a Message (Sender Node)

The sending node must have a ***usable postage batch id*** and also know the ***target overlay address*** and ***identifier*** in order to send a message:

```js
import { Bee, Identifier, NULL_IDENTIFIER } from '@ethersphere/bee-js'

const bee = new Bee('http://localhost:1643')

// The identifier is initialized using the same data as the receiving node
const identifier = Identifier.fromString(NULL_IDENTIFIER)
const batchId = '6c84b6d3f5273b969c3df875cde7ccd9920f5580122929aedaf440bfe4484405'

const recipientOverlay = '1e2054bec3e681aeb0b365a1f9a574a03782176bd3ec0bcf810ebcaf551e4070'

async function sendMessage() {
// The signer is initialized using the overlay address and identifier shared by the receiving node
const signer = bee.gsocMine(recipientOverlay, identifier)

// bee.gsocSend is called with the batch id, initialized signer, identifier, and message payload in order to send a GSOC message
await bee.gsocSend(batchId, signer, identifier, 'Hello via GSOC!')
console.log('Message sent')
}

sendMessage()
```

For more information about GSOC, refer to the [Bee documentation](https://docs.ethswarm.org/docs/develop/tools-and-features/gsoc).

Loading