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

feat(contract): Add range field to Resource #234

Draft
wants to merge 7 commits into
base: gg/move/upgrade
Choose a base branch
from
Draft
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
3 changes: 3 additions & 0 deletions examples/snake/ws-resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
"Content-Type": "text/html; charset=utf-8",
"Cache-Control": "max-age=3500"
}
},
"routes": {
"/path/*": "/index.html"
}
}
6 changes: 3 additions & 3 deletions move/walrus_site/Move.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[move]
version = 0
manifest_digest = "E9C7401E4D5BF8E549B5CB4E935992B4BEEEB50757B900BB03D72491F31A7087"
manifest_digest = "6955A2973AF0DB196E469AD72FDB6D203278DF6207C4561B7B9FDC4BD1AC951D"
deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082"

dependencies = [
Expand Down Expand Up @@ -36,6 +36,6 @@ published-version = "1"

[env.testnet]
chain-id = "4c78adac"
original-published-id = "0xe15cd956d3f54ad0b6608b01b96e9999d66552dfd025e698ac16cd0df1787a25"
latest-published-id = "0xe15cd956d3f54ad0b6608b01b96e9999d66552dfd025e698ac16cd0df1787a25"
original-published-id = "0xee40a3dddc38e3c9f594f74f85ae3bda75b0ed05c6f2359554126409cf7e8e9d"
latest-published-id = "0xee40a3dddc38e3c9f594f74f85ae3bda75b0ed05c6f2359554126409cf7e8e9d"
published-version = "1"
3 changes: 3 additions & 0 deletions move/walrus_site/Move.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
[package]
name = "walrus_site"
license = "Apache-2.0"
authors = ["Mysten Labs <[email protected]>"]
version = "0.0.1"
edition = "2024.beta"

[dependencies]
Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" }
Expand Down
104 changes: 89 additions & 15 deletions move/walrus_site/sources/site.move
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
/// The module exposes the functionality to create and update Walrus sites.
module walrus_site::site {
use std::option::Option;
use sui::object::{Self, UID};
use sui::tx_context::TxContext;
use sui::dynamic_field as df;
use std::string::String;
use sui::vec_map;

/// The name of the dynamic field containing the routes.
const ROUTES_FIELD: vector<u8> = b"routes";

/// An insertion of route was attempted, but the related resource does not exist.
const EResourceDoesNotExist: u64 = 0;
const EIncorrectNumberOfRangeValues: u64 = 1;
const EIncorrectRangeBounds: u64 = 2;

/// The site published on Sui.
struct Site has key, store {
public struct Site has key, store {
id: UID,
name: String,
}

/// A resource in a site.
struct Resource has store, drop {
public struct Resource has store, drop {
path: String,
// Response, Representation and Payload headers
// regarding the contents of the resource.
Expand All @@ -23,16 +28,26 @@ module walrus_site::site {
blob_id: u256,
// Contains the hash of the contents of the blob
// to verify its integrity.
blob_hash: u256
blob_hash: u256,
// Defines the byte range of the resource contents
// in the case where multiple resources are stored
// in the same blob. This way, each resource will
// be parsed using its' byte range in the blob.
range: Option<vector<u256>>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: why use an Option<vector<u256>>? Can we use tuples? I don't remember if move allows them.

Suggestion: If it does not, we could strongly type it instead as Range { start: Option<u256>, end: Option<u256> }. Then, add an Option<Range> to the Resource. This may be a bit more readable and easy to parse? And also we don't need the length checks.

}

/// Representation of the resource path.
///
/// Ensures there are no namespace collisions in the dynamic fields.
struct ResourcePath has copy, store, drop {
public struct ResourcePath has copy, store, drop {
path: String,
}

/// The routes for a site.
public struct Routes has store, drop {
route_list: vec_map::VecMap<String, String>,
}

/// Creates a new site.
public fun new_site(name: String, ctx: &mut TxContext): Site {
Site {
Expand All @@ -45,26 +60,35 @@ module walrus_site::site {
public fun new_resource(
path: String,
blob_id: u256,
blob_hash: u256
blob_hash: u256,
range: &mut Option<vector<u256>>
): Resource {
if (option::is_some(range)) {
let extracted_range = option::extract(range);
// Range should contain 2 values.
assert!(vector::length(&extracted_range) == 2, EIncorrectNumberOfRangeValues);
// Upper bound should be greater than lower bound.
assert!(
*vector::borrow(&extracted_range, 0) < *vector::borrow(&extracted_range, 1),
EIncorrectRangeBounds
);
};

Resource {
path,
headers: vec_map::empty(),
blob_id,
blob_hash,
range: *range
}
}

/// Adds a header to the Resource's headers vector.
public fun add_header(resource: &mut Resource, name: String, value: String) {
// Will throw an exception if duplicate key.
vec_map::insert(
&mut resource.headers,
name,
value
);
resource.headers.insert(name, value);
}

/// Creates a new resource path.
fun new_path(path: String): ResourcePath {
ResourcePath { path }
}
Expand Down Expand Up @@ -96,8 +120,58 @@ module walrus_site::site {

/// Changes the path of a resource on a site.
public fun move_resource(site: &mut Site, old_path: String, new_path: String) {
let resource = remove_resource(site, old_path);
let mut resource = remove_resource(site, old_path);
resource.path = new_path;
add_resource(site, resource);
}

// Routes.

/// Creates a new `Routes` object.
fun new_routes(): Routes {
Routes { route_list: vec_map::empty() }
}

/// Inserts a route into the `Routes` object.
///
/// The insertion operation fails if the route already exists.
fun routes_insert(routes: &mut Routes, route: String, resource_path: String) {
routes.route_list.insert(route, resource_path);
}

/// Removes a route from the `Routes` object.
fun routes_remove(routes: &mut Routes, route: &String): (String, String) {
routes.route_list.remove(route)
}

// Routes management on the site.

/// Add the routes dynamic field to the site.
public fun create_routes(site: &mut Site) {
let routes = new_routes();
df::add(&mut site.id, ROUTES_FIELD, routes);
}

/// Remove all routes from the site.
public fun remove_all_routes_if_exist(site: &mut Site): Option<Routes> {
df::remove_if_exists(&mut site.id, ROUTES_FIELD)
}

/// Add a route to the site.
///
/// The insertion operation fails:
/// - if the route already exists; or
/// - if the related resource path does not already exist as a dynamic field on the site.
public fun insert_route(site: &mut Site, route: String, resource_path: String) {
let path_obj = new_path(resource_path);
assert!(df::exists_(&site.id, path_obj), EResourceDoesNotExist);
let routes = df::borrow_mut(&mut site.id, ROUTES_FIELD);
routes_insert(routes, route, resource_path);
}

/// Remove a route from the site.
public fun remove_route(site: &mut Site, route: &String): (String, String) {
let routes = df::borrow_mut(&mut site.id, ROUTES_FIELD);
routes_remove(routes, route)
}
}
20 changes: 10 additions & 10 deletions portal/common/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

export const NETWORK = "testnet"
export const AGGREGATOR = "https://aggregator-devnet.walrus.space:443"
export const SITE_PACKAGE = "0xe15cd956d3f54ad0b6608b01b96e9999d66552dfd025e698ac16cd0df1787a25"
export const MAX_REDIRECT_DEPTH = 3
export const NETWORK = "testnet";
export const AGGREGATOR = "https://aggregator-devnet.walrus.space:443";
export const SITE_PACKAGE = "0xee40a3dddc38e3c9f594f74f85ae3bda75b0ed05c6f2359554126409cf7e8e9d";
export const MAX_REDIRECT_DEPTH = 3;
export const SITE_NAMES: { [key: string]: string } = {
// Any hardcoded (non suins) name -> object_id mappings go here
// e.g.,
// landing: "0x1234..."
};
// The default portal to redirect to if the browser does not support service workers.
export const FALLBACK_PORTAL = "blob.store"
export const FALLBACK_PORTAL = "blob.store";
// The string representing the ResourcePath struct in the walrus_site package.
export const RESOURCE_PATH_MOVE_TYPE = SITE_PACKAGE + "::site::ResourcePath";

const LANDING_PAGE_OID = '0x2d9414edc309535bfd4cd7e80ccbc09fee18bf86b449a185b81e914096059a67';
const FLATLAND_OID = '0xc62fae899d75705d88ef282678d17abc08a3363293def8841f0113aabd053fbb';
const FLATLANDER_OID = '0xabf413f36aa8ba984f81f4d3e334070b351c800dacb5ea5e02d49a7621b02d96';
const LANDING_PAGE_OID = "0x2d9414edc309535bfd4cd7e80ccbc09fee18bf86b449a185b81e914096059a67";
const FLATLAND_OID = "0xc62fae899d75705d88ef282678d17abc08a3363293def8841f0113aabd053fbb";
const FLATLANDER_OID = "0xabf413f36aa8ba984f81f4d3e334070b351c800dacb5ea5e02d49a7621b02d96";
export const SITES_USED_FOR_BENCHING = [
[LANDING_PAGE_OID, "landing page"],
[FLATLAND_OID, "flatland"],
[FLATLANDER_OID, "flatlander"]
]
[FLATLANDER_OID, "flatlander"],
];
18 changes: 9 additions & 9 deletions portal/worker/src/walrus-sites-portal-register-sw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,33 @@ function main() {
} else if (reg.active) {
console.log("SW active, error?");
// Previously-installed SW should have redirected this request to different page
handleError(new Error("Service Worker is installed but not redirecting"));
handleError();
}
})
.catch(handleError);
} else {
const currentUrl = new URL(window.location.href);
console.warn("This browser does not yet support Walrus Sites 💔, redirecting to blob.store");
const domainDetails = getSubdomainAndPath(currentUrl)
console.warn(
"This browser does not yet support Walrus Sites 💔, redirecting to blob.store",
);
const domainDetails = getSubdomainAndPath(currentUrl);
window.location.href = new URL(
`${currentUrl.pathname}${currentUrl.search}${currentUrl.hash}`,
`https://${
domainDetails.subdomain ?
domainDetails.subdomain + '.'
: ''
}${FALLBACK_PORTAL}`
domainDetails.subdomain ? domainDetails.subdomain + "." : ""
}${FALLBACK_PORTAL}`,
).toString();
}
}

function handleError(error) {
function handleError() {
displayErrorMessage(swNotLoadingNode());
}

function swNotLoadingNode() {
return titleSubtitleNode(
"Oh! Something's not right 🚧",
"Please try refreshing the page or unregistering the service worker."
"Please try refreshing the page or unregistering the service worker.",
);
}

Expand Down
2 changes: 1 addition & 1 deletion site-builder/assets/builder-example.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# module: site
# portal: walrus.site
package: 0xe15cd956d3f54ad0b6608b01b96e9999d66552dfd025e698ac16cd0df1787a25
package: 0xee40a3dddc38e3c9f594f74f85ae3bda75b0ed05c6f2359554126409cf7e8e9d
# general:
# rpc_url: https://fullnode.testnet.sui.io:443
# wallet: /path/to/.sui/sui_config/client.yaml
Expand Down
10 changes: 6 additions & 4 deletions site-builder/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod display;
mod preprocessor;
mod publish;
mod site;
mod summary;
mod util;
mod walrus;
use std::path::PathBuf;
Expand All @@ -14,12 +15,12 @@ use clap::{Parser, Subcommand};
use futures::TryFutureExt;
use publish::{ContinuousEditing, PublishOptions, SiteEditor, WhenWalrusUpload};
use serde::Deserialize;
use site::manager::SiteIdentifier;
use site::{manager::SiteIdentifier, RemoteSiteFactory};
use sui_types::base_types::ObjectID;

use crate::{
preprocessor::Preprocessor,
util::{get_existing_resource_ids, id_to_base36, load_wallet_context},
util::{id_to_base36, load_wallet_context},
};

// Define the `GIT_REVISION` and `VERSION` consts.
Expand Down Expand Up @@ -258,8 +259,9 @@ async fn run() -> Result<()> {
// below will be monitored for changes.
Commands::Sitemap { object } => {
let wallet = load_wallet_context(&config.general.wallet)?;
let all_dynamic_fields =
get_existing_resource_ids(&wallet.get_client().await?, object).await?;
let all_dynamic_fields = RemoteSiteFactory::new(&wallet.get_client().await?, object)
.get_existing_resources()
.await?;
println!("Pages in site at object id: {}", object);
for (name, id) in all_dynamic_fields {
println!(" - {:<40} {:?}", name, id);
Expand Down
15 changes: 8 additions & 7 deletions site-builder/src/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ use crate::{
site::{
config::WSResources,
manager::{SiteIdentifier, SiteManager},
resource::{OperationsSummary, ResourceManager},
resource::ResourceManager,
},
summary::{SiteDataDiffSummary, Summarizable},
util::{
get_site_id_from_response,
id_to_base36,
Expand Down Expand Up @@ -145,7 +146,7 @@ impl SiteEditor {

async fn run_single_edit(
&self,
) -> Result<(SuiAddress, SuiTransactionBlockResponse, OperationsSummary)> {
) -> Result<(SuiAddress, SuiTransactionBlockResponse, SiteDataDiffSummary)> {
if self.publish_options.list_directory {
display::action(format!("Preprocessing: {}", self.directory().display()));
Preprocessor::preprocess(self.directory())?;
Expand Down Expand Up @@ -177,9 +178,9 @@ impl SiteEditor {
"Parsing the directory {} and locally computing blob IDs",
self.directory().to_string_lossy()
));
resource_manager.read_dir(self.directory())?;
let local_site_data = resource_manager.read_dir(self.directory())?;
display::done();
tracing::debug!(resources=%resource_manager.resources, "resources loaded from directory");
tracing::debug!(?local_site_data, "resources loaded from directory");

let site_manager = SiteManager::new(
self.config.clone(),
Expand All @@ -190,7 +191,7 @@ impl SiteEditor {
self.when_upload.clone(),
)
.await?;
let (response, summary) = site_manager.update_site(&resource_manager).await?;
let (response, summary) = site_manager.update_site(&local_site_data).await?;
Ok((site_manager.active_address()?, response, summary))
}

Expand Down Expand Up @@ -233,7 +234,7 @@ fn print_summary(
address: &SuiAddress,
site_id: &SiteIdentifier,
response: &SuiTransactionBlockResponse,
summary: &OperationsSummary,
summary: &impl Summarizable,
) -> Result<()> {
if let Some(SuiTransactionBlockEffects::V1(eff)) = response.effects.as_ref() {
if let SuiExecutionStatus::Failure { error } = &eff.status {
Expand All @@ -245,7 +246,7 @@ fn print_summary(
}

display::header("Execution completed");
println!("{}\n", summary);
println!("{}\n", summary.to_summary());
let object_id = match site_id {
SiteIdentifier::ExistingSite(id) => {
println!("Site object ID: {}", id);
Expand Down
Loading
Loading