Scratchpad
Scratchpad is a native data type in the Autonomi Network:
Key-addressed: Network address is derived from a BLS public key
Size: Up to 4MB mutable storage
Pay-once, free updates: Unlimited updates for free after initial payment
Versioned & signed: Includes a version counter and cryptographically verifiable signatures
Encrypted: Content is automatically encrypted with the owner's key
Client Methods
scratchpad_get_from_public_key
Retrieves a scratchpad from the network using the owner's public key.
Input:
public_key: &PublicKey- The owner's public key
Output:
Rust:
Result<Scratchpad, ScratchpadError>Python:
Scratchpador raises exceptionNode.js:
Promise<Scratchpad>
scratchpad_get
Retrieves a scratchpad from the network by its address.
Input:
address: &ScratchpadAddress- The scratchpad address
Output:
Rust:
Result<Scratchpad, ScratchpadError>Python:
Scratchpador raises exceptionNode.js:
Promise<Scratchpad>
scratchpad_check_existence
Checks if a scratchpad exists on the network. Much faster than scratchpad_get.
Input:
address: &ScratchpadAddress- The scratchpad address
Output:
Rust:
Result<bool, ScratchpadError>Python:
boolor raises exceptionNode.js:
Promise<boolean>
scratchpad_verify
Verifies a scratchpad's signature and size constraints.
Input:
scratchpad: &Scratchpad- The scratchpad to verify
Output:
Rust:
Result<(), ScratchpadError>Python:
Noneor raises exceptionNode.js:
void(throws on error)
scratchpad_put
Manually uploads a scratchpad to the network. Requires the scratchpad to be already created and signed.
Input:
scratchpad: Scratchpad- The scratchpad to storepayment_option: PaymentOption- Payment method
Output:
Rust:
Result<(AttoTokens, ScratchpadAddress), ScratchpadError>Python:
tuple[str, ScratchpadAddress](cost as string) or raises exceptionNode.js:
Promise<ScratchpadPut>withcost: stringandaddr: ScratchpadAddress
scratchpad_create
Creates and uploads a new scratchpad to the network. Encrypts the content automatically.
Input:
owner: &SecretKey- The owner's secret keycontent_type: u64- Application-specific content type identifierinitial_data: &Bytes- The initial data to storepayment_option: PaymentOption- Payment method
Output:
Rust:
Result<(AttoTokens, ScratchpadAddress), ScratchpadError>Python:
tuple[str, ScratchpadAddress](cost as string) or raises exceptionNode.js:
Promise<ScratchpadPut>withcost: stringandaddr: ScratchpadAddress
scratchpad_update
Updates an existing scratchpad with new content. This operation is free.
Input:
owner: &SecretKey- The owner's secret keycontent_type: u64- Content type identifierdata: &Bytes- The new data to store
Output:
Rust:
Result<(), ScratchpadError>Python:
Noneor raises exceptionNode.js:
Promise<void>
scratchpad_update_from
Updates an existing scratchpad from a specific scratchpad instance. Used internally by scratchpad_update.
Input:
current: &Scratchpad- The current scratchpadowner: &SecretKey- The owner's secret keycontent_type: u64- Content type identifierdata: &Bytes- The new data to store
Output:
Rust:
Result<Scratchpad, ScratchpadError>Python:
Scratchpador raises exceptionNode.js: Not directly exposed
scratchpad_cost
Estimates the storage cost for a new scratchpad.
Input:
owner: &PublicKey- The owner's public key
Output:
Rust:
Result<AttoTokens, CostError>Python:
str(cost as string) or raises exceptionNode.js:
Promise<string>
Language-Specific Type Differences
Error Handling
Rust: Uses
Result<T, ScratchpadError>with detailed error variantsPython: Raises exceptions with simplified error messages as strings
Node.js: Uses Promise rejection with Error objects containing simplified messages
Numeric Types
Rust: Uses
u64for content_type,AttoTokensfor costsPython: Uses
intfor content_type,strfor costsNode.js: Uses
bigintfor content_type,stringfor costs
Data Types
Rust: Uses
Bytestype for dataPython: Uses
bytesfor dataNode.js: Uses
Bufferfor data
Examples
use autonomi::{Client, SecretKey, AttoTokens, Bytes};
use autonomi::client::payment::PaymentOption;
async fn scratchpad_example() -> Result<(), Box<dyn std::error::Error>> {
// Initialize client and wallet
let client = Client::init_local().await?;
let wallet = get_funded_wallet();
let payment = PaymentOption::from(&wallet);
// Create secret key for scratchpad
let key = SecretKey::random();
let public_key = key.public_key();
// Check cost
let cost = client.scratchpad_cost(&public_key).await?;
println!("Scratchpad cost: {}", cost);
// Create scratchpad
let content_type = 42;
let initial_data = Bytes::from("Hello, Autonomi!");
let (cost, addr) = client
.scratchpad_create(&key, content_type, &initial_data, payment.clone())
.await?;
println!("Created at {:?}, cost: {}", addr, cost);
// Get scratchpad
let scratchpad = client.scratchpad_get(&addr).await?;
assert_eq!(scratchpad.counter(), 0);
// Decrypt content
let decrypted = scratchpad.decrypt_data(&key)?;
assert_eq!(decrypted, initial_data);
// Update scratchpad
let new_data = Bytes::from("Updated content!");
client.scratchpad_update(&key, content_type, &new_data).await?;
// Get updated scratchpad
let updated = client.scratchpad_get(&addr).await?;
assert_eq!(updated.counter(), 1);
let updated_content = updated.decrypt_data(&key)?;
assert_eq!(updated_content, new_data);
Ok(())
}import asyncio
from autonomi_client import Client, SecretKey, Wallet, PaymentOption, Network
async def scratchpad_example():
# Initialize client and wallet
client = await Client.init_local()
network = Network(True)
private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
wallet = Wallet.new_from_private_key(network, private_key)
payment = PaymentOption.wallet(wallet)
# Create secret key for scratchpad
key = SecretKey()
public_key = key.public_key()
try:
# Check cost
cost = await client.scratchpad_cost(public_key)
print(f"Scratchpad cost: {cost}")
# Create scratchpad
content_type = 42
initial_data = b"Hello, Autonomi!"
cost, addr = await client.scratchpad_create(key, content_type, initial_data, payment)
print(f"Created at {addr.hex}, cost: {cost}")
# Get scratchpad
scratchpad = await client.scratchpad_get(addr)
assert scratchpad.counter() == 0
# Decrypt content
decrypted = scratchpad.decrypt_data(key)
assert decrypted == initial_data
# Update scratchpad (free)
new_data = b"Updated content!"
await client.scratchpad_update(key, content_type, new_data)
# Get updated scratchpad
updated = await client.scratchpad_get(addr)
assert updated.counter() == 1
updated_content = updated.decrypt_data(key)
assert updated_content == new_data
except Exception as e:
print(f"Error: {e}")
asyncio.run(scratchpad_example()) import { Client, SecretKey, Wallet, Network, PaymentOption } from '@withautonomi/autonomi';
async function scratchpadExample() {
try {
// Initialize client and wallet
const client = await Client.initLocal();
const network = new Network(true);
const privateKey = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
const wallet = Wallet.newFromPrivateKey(network, privateKey);
const payment = PaymentOption.fromWallet(wallet);
// Create secret key for scratchpad
const key = SecretKey.random();
const publicKey = key.publicKey();
// Check cost
const cost = await client.scratchpadCost(publicKey);
console.log(`Scratchpad cost: ${cost}`);
// Create scratchpad
const contentType = 42n;
const initialData = Buffer.from("Hello, Autonomi!");
const { cost: createCost, addr } = await client.scratchpadCreate(key, contentType, initialData, payment);
console.log(`Created at ${addr.toHex()}, cost: ${createCost}`);
// Get scratchpad
const scratchpad = await client.scratchpadGet(addr);
console.assert(scratchpad.counter() === 0n);
// Decrypt content
const decrypted = scratchpad.decryptData(key);
console.assert(Buffer.compare(decrypted, initialData) === 0);
// Update scratchpad (free)
const newData = Buffer.from("Updated content!");
await client.scratchpadUpdate(key, contentType, newData);
// Get updated scratchpad
const updated = await client.scratchpadGet(addr);
console.assert(updated.counter() === 1n);
const updatedContent = updated.decryptData(key);
console.assert(Buffer.compare(updatedContent, newData) === 0);
console.log("Scratchpad operations completed successfully!");
} catch (error) {
console.error('Error:', error.message);
}
}
scratchpadExample();Error Handling
Rust Errors
The ScratchpadError enum provides detailed error variants:
PutError- Failed to store scratchpadPay- Payment failureGetError- Failed to retrieve scratchpadCorrupt- Invalid scratchpad dataSerialization- Serialization errorScratchpadAlreadyExists- Scratchpad already exists at addressCannotUpdateNewScratchpad- Cannot update non-existent scratchpadScratchpadTooBig- Exceeds maximum size (4MB)BadSignature- Invalid signatureFork- Multiple conflicting versions detected
Node.js Error Handling
try {
const scratchpad = await client.scratchpadGet(addr);
} catch (error) {
if (error.message.includes('RecordNotFound')) {
console.log('Scratchpad does not exist');
} else if (error.message.includes('BadSignature')) {
console.log('Invalid scratchpad signature');
} else {
console.error('Unexpected error:', error.message);
}
}Due to compatibility issues, Python and Node.js bindings simplify types (and error types to string messages within exceptions/rejections). For full experience and control it's recommended to use Rust.
Last updated