GraphEntry
GraphEntry is a fundamental data type in the Autonomi Network that represents an immutable, cryptographically signed graph node that can be linked to other graph entries to form directed acyclic graphs (DAGs).
Key Features
Immutable: Once uploaded, cannot be modified
Cryptographically signed: Uses BLS signatures for authenticity
One per owner: Each public key can only have one GraphEntry
Linkable: Can reference other GraphEntries as parents or descendants
Content-addressed: Stored at an address derived from the owner's public key
Size: 32 bytes of content per entry
Structure
owner
: The BLS public key of the entry ownerparents
: References to parent GraphEntriescontent
: 32 bytes of arbitrary datadescendants
: References to descendant entries with associated data (32 bytes per descendant)signature
: BLS signature ensuring integrity
Common Use Cases
Building DAG structures
Creating audit trails
Implementing linked data structures
Foundation for higher-level types like Registers
Client Methods
graph_entry_get Retrieves a GraphEntry from the network by its address.
graph_entry_put Uploads a GraphEntry to the network with payment handling.
graph_entry_cost Estimates the storage cost for a GraphEntry.
Code Examples
use autonomi::Client;
use autonomi::client::payment::PaymentOption;
use autonomi::client::graph::GraphEntry;
use eyre::Result;
async fn graph_entry_example() -> Result<()> {
// initialize a local client and test wallet
let client = Client::init_local().await?;
let wallet = get_funded_wallet();
// create a GraphEntry with some content
let key = autonomi::SecretKey::random();
let content = [42u8; 32]; // 32 bytes of 42s
let graph_entry = GraphEntry::new(&key, vec![], content, vec![]);
// estimate the cost of the graph_entry
let cost = client.graph_entry_cost(&key.public_key()).await?;
println!("graph_entry cost: {cost}");
// put the graph_entry
let payment_option = PaymentOption::from(&wallet);
let (cost, addr) = client
.graph_entry_put(graph_entry.clone(), payment_option)
.await?;
println!("graph_entry put cost: {cost}");
// wait for the graph_entry to be replicated
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
// check that the graph_entry is stored
let entry = client.graph_entry_get(&graph_entry.address()).await?;
assert_eq!(entry, graph_entry.clone());
// try to put a graph entry linking to the first graph entry
let key2 = autonomi::SecretKey::random();
let content2 = [41u8; 32];
let graph_entry2 = GraphEntry::new(&key2, vec![graph_entry.owner], content2, vec![]);
// put the graph_entry
let payment_option = PaymentOption::from(&wallet);
let (cost, addr) = client
.graph_entry_put(graph_entry2.clone(), payment_option)
.await?;
println!("graph_entry2 put cost: {cost}");
// wait for the graph_entry to be replicated
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
// check that the graph_entry is stored
let entry2 = client.graph_entry_get(&graph_entry2.address()).await?;
assert_eq!(entry2, graph_entry2.clone());
Ok(())
}
Forks
It's possible for multiple graph entries to exist for the same key. This can happen when two nodes store (unique) entries simultaneously. These entries are replicated and nodes will store them all (up to a certain amount).
The graph entry API will surface these forks as errors. In case of Rust, the graph_entry_get
will return Result::Err(GraphError::Fork(Vec<GraphEntry>))
, which holds all entries found for the same key.
use autonomi::client::data_types::graph::GraphError;
let graph_entry_addr = todo!();
let entry = match self.graph_entry_get(graph_entry_addr).await {
Ok(entry) => entry,
Err(GraphError::Fork(entries)) => {
// Fork detected.
todo!();
}
Err(err) => todo!(),
};
Last updated