├── .config └── nextest.toml ├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug.yaml │ ├── docs.yaml │ ├── feature.yaml │ └── other.yaml ├── PULL_REQUEST_TEMPLATE.md ├── actions │ ├── build-mdbook │ │ └── action.yaml │ ├── diffs │ │ └── action.yml │ ├── run_tarpaulin │ │ └── action.yml │ └── set-up-walrus │ │ └── action.yaml ├── dependabot.yml └── workflows │ ├── attach-binaries-to-release.yml │ ├── code.yml │ ├── create-release-announce.yml │ ├── create-tx-for-multisig.yml │ ├── issues-monitor.yaml │ ├── lint.yml │ ├── pages-preview.yaml │ ├── publish-docs.yaml │ ├── scheduled_reports.yml │ ├── tag.yml │ ├── trigger-artifacts-builds.yml │ ├── update-operators-cache.yml │ ├── update-ws-binaries.yaml │ ├── updates.yml │ └── validate-release-notes-pre-land.yml ├── .gitignore ├── .licensesnip ├── .licensesnipignore ├── .markdownlint-cli2.yaml ├── .pre-commit-config.yaml ├── .rustfmt.toml ├── .taplo.toml ├── .tarpaulin.toml ├── .yamlfmt.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── _typos.toml ├── binary-build-list.json ├── book.toml ├── clippy.toml ├── contracts ├── .prettierrc ├── README.md ├── subsidies │ ├── Move.lock │ ├── Move.toml │ ├── sources │ │ └── subsidies.move │ └── tests │ │ └── subsidies_tests.move ├── wal │ ├── Move.lock │ ├── Move.toml │ └── sources │ │ └── wal.move ├── wal_exchange │ ├── Move.lock │ ├── Move.toml │ └── sources │ │ └── wal_exchange.move └── walrus │ ├── Move.lock │ ├── Move.toml │ ├── docs │ └── msg_formats.txt │ ├── sources │ ├── display.move │ ├── init.move │ ├── staking.move │ ├── staking │ │ ├── active_set.move │ │ ├── apportionment_queue.move │ │ ├── auth.move │ │ ├── committee.move │ │ ├── exchange_rate.move │ │ ├── node_metadata.move │ │ ├── pending_values.move │ │ ├── staked_wal.move │ │ ├── staking_inner.move │ │ ├── staking_pool.move │ │ ├── storage_node.move │ │ └── walrus_context.move │ ├── system.move │ ├── system │ │ ├── blob.move │ │ ├── bls_aggregate.move │ │ ├── encoding.move │ │ ├── epoch_parameters.move │ │ ├── event_blob.move │ │ ├── events.move │ │ ├── messages.move │ │ ├── metadata.move │ │ ├── redstuff.move │ │ ├── shared_blob.move │ │ ├── storage_accounting.move │ │ ├── storage_resource.move │ │ └── system_state_inner.move │ ├── upgrade.move │ └── utils │ │ ├── extended_field.move │ │ └── sort.move │ └── tests │ ├── e2e_runner.move │ ├── e2e_tests.move │ ├── staking │ ├── active_set_tests.move │ ├── committee_tests.move │ ├── staked_wal_tests.move │ ├── staking_inner_compute_tests.move │ ├── staking_inner_tests.move │ ├── staking_pool │ │ ├── pool_commission_tests.move │ │ ├── pool_direct_withdraw_tests.move │ │ ├── pool_early_withdraw_tests.move │ │ ├── pool_rounding_tests.move │ │ └── staking_pool_tests.move │ └── walrus_context_tests.move │ ├── system │ ├── blob_tests.move │ ├── bls_tests.move │ ├── deny_list_tests.move │ ├── event_blob_tests.move │ ├── invalid_tests.move │ ├── metadata_tests.move │ ├── ringbuffer_tests.move │ ├── storage_resource_tests.move │ └── system_state_inner_tests.move │ ├── test_node.move │ ├── test_utils.move │ └── upgrade_tests.move ├── crates ├── checkpoint-downloader │ ├── Cargo.toml │ └── src │ │ ├── config.rs │ │ ├── downloader.rs │ │ ├── lib.rs │ │ ├── metrics.rs │ │ └── types.rs ├── typed-store │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── metrics.rs │ │ ├── rocks.rs │ │ ├── rocks │ │ ├── errors.rs │ │ ├── safe_iter.rs │ │ └── tests.rs │ │ └── traits.rs ├── walrus-core │ ├── Cargo.toml │ ├── benches │ │ ├── basic_encoding.rs │ │ └── blob_encoding.rs │ └── src │ │ ├── bft.rs │ │ ├── by_axis.rs │ │ ├── encoding.rs │ │ ├── encoding │ │ ├── basic_encoding.rs │ │ ├── blob_encoding.rs │ │ ├── common.rs │ │ ├── config.rs │ │ ├── errors.rs │ │ ├── mapping.rs │ │ ├── quilt_encoding.rs │ │ ├── slivers.rs │ │ ├── symbols.rs │ │ └── utils.rs │ │ ├── inconsistency.rs │ │ ├── keys.rs │ │ ├── lib.rs │ │ ├── merkle.rs │ │ ├── messages.rs │ │ ├── messages │ │ ├── certificate.rs │ │ ├── invalid_blob_id.rs │ │ ├── proof_of_possession.rs │ │ ├── storage_confirmation.rs │ │ └── sync_shard.rs │ │ ├── metadata.rs │ │ ├── test_utils.rs │ │ └── utils.rs ├── walrus-e2e-tests │ ├── Cargo.toml │ └── tests │ │ ├── test_client.rs │ │ └── test_event_blobs.rs ├── walrus-orchestrator │ ├── Cargo.toml │ ├── assets │ │ ├── dashboard-template.json │ │ └── settings-template.yaml │ ├── readme.md │ └── src │ │ ├── benchmark.rs │ │ ├── client.rs │ │ ├── client │ │ ├── aws.rs │ │ └── vultr.rs │ │ ├── display.rs │ │ ├── error.rs │ │ ├── faults.rs │ │ ├── logs.rs │ │ ├── main.rs │ │ ├── measurements.rs │ │ ├── monitor.rs │ │ ├── orchestrator.rs │ │ ├── protocol.rs │ │ ├── protocol │ │ └── target.rs │ │ ├── settings.rs │ │ ├── ssh.rs │ │ └── testbed.rs ├── walrus-proc-macros │ ├── Cargo.toml │ └── src │ │ ├── derive_api_errors.rs │ │ ├── lib.rs │ │ └── walrus_simtest.rs ├── walrus-proxy │ ├── Cargo.toml │ └── src │ │ ├── admin.rs │ │ ├── config.rs │ │ ├── consumer.rs │ │ ├── fixtures │ │ ├── allowlist.yaml │ │ └── config.yaml │ │ ├── handlers.rs │ │ ├── histogram_relay.rs │ │ ├── lib.rs │ │ ├── main.rs │ │ ├── metrics.rs │ │ ├── middleware.rs │ │ ├── prom_to_mimir.rs │ │ ├── providers.rs │ │ ├── providers │ │ ├── walrus.rs │ │ └── walrus │ │ │ ├── provider.rs │ │ │ └── query.rs │ │ └── remote_write.rs ├── walrus-sdk │ ├── Cargo.toml │ ├── client_config_example.yaml │ └── src │ │ ├── active_committees.rs │ │ ├── blocklist.rs │ │ ├── client.rs │ │ ├── client │ │ ├── client_types.rs │ │ ├── communication.rs │ │ ├── communication │ │ │ ├── factory.rs │ │ │ └── node.rs │ │ ├── metrics.rs │ │ ├── refresh.rs │ │ ├── resource.rs │ │ └── responses.rs │ │ ├── config.rs │ │ ├── config │ │ ├── committees_refresh_config.rs │ │ ├── communication_config.rs │ │ ├── reqwest_config.rs │ │ └── sliver_write_extra_time.rs │ │ ├── error.rs │ │ ├── lib.rs │ │ ├── store_when.rs │ │ └── utils.rs ├── walrus-service │ ├── Cargo.toml │ ├── aggregator_openapi.html │ ├── aggregator_openapi.yaml │ ├── bin │ │ ├── backup.rs │ │ ├── client.rs │ │ ├── deploy.rs │ │ └── node.rs │ ├── build.rs │ ├── daemon_openapi.html │ ├── daemon_openapi.yaml │ ├── migrations │ │ ├── 00000000000000_diesel_initial_setup │ │ │ ├── down.sql │ │ │ └── up.sql │ │ ├── 2025-01-20-173100_create_stream_events │ │ │ ├── down.sql │ │ │ └── up.sql │ │ └── 2025-02-24-213538_add-gc-field │ │ │ ├── down.sql │ │ │ └── up.sql │ ├── node_config_example.yaml │ ├── publisher_openapi.html │ ├── publisher_openapi.yaml │ ├── src │ │ ├── backup.rs │ │ ├── backup │ │ │ ├── config.rs │ │ │ ├── garbage_collector.rs │ │ │ ├── metrics.rs │ │ │ ├── models.rs │ │ │ ├── schema.rs │ │ │ └── service.rs │ │ ├── client.rs │ │ ├── client │ │ │ ├── cli.rs │ │ │ ├── cli │ │ │ │ ├── args.rs │ │ │ │ ├── cli_output.rs │ │ │ │ └── runner.rs │ │ │ ├── config.rs │ │ │ ├── daemon.rs │ │ │ ├── daemon │ │ │ │ ├── auth.rs │ │ │ │ ├── cache.rs │ │ │ │ ├── openapi.rs │ │ │ │ └── routes.rs │ │ │ ├── multiplexer.rs │ │ │ ├── refill.rs │ │ │ └── responses.rs │ │ ├── common.rs │ │ ├── common │ │ │ ├── api.rs │ │ │ ├── config.rs │ │ │ ├── event_blob_downloader.rs │ │ │ ├── telemetry.rs │ │ │ └── utils.rs │ │ ├── lib.rs │ │ ├── node.rs │ │ ├── node │ │ │ ├── blob_event_processor.rs │ │ │ ├── blob_retirement_notifier.rs │ │ │ ├── blob_sync.rs │ │ │ ├── committee.rs │ │ │ ├── committee │ │ │ │ ├── committee_service.rs │ │ │ │ ├── node_service.rs │ │ │ │ ├── request_futures.rs │ │ │ │ └── test_committee_service.rs │ │ │ ├── config.rs │ │ │ ├── config_synchronizer.rs │ │ │ ├── consistency_check.rs │ │ │ ├── contract_service.rs │ │ │ ├── db_checkpoint.rs │ │ │ ├── dbtool.rs │ │ │ ├── epoch_change_driver.rs │ │ │ ├── errors.rs │ │ │ ├── events.rs │ │ │ ├── events │ │ │ │ ├── event_blob.rs │ │ │ │ ├── event_blob_writer.rs │ │ │ │ ├── event_processor.rs │ │ │ │ └── event_processor_runtime.rs │ │ │ ├── metrics.rs │ │ │ ├── node_recovery.rs │ │ │ ├── recovery_symbol_service.rs │ │ │ ├── server.rs │ │ │ ├── server │ │ │ │ ├── extract.rs │ │ │ │ ├── openapi.rs │ │ │ │ ├── responses.rs │ │ │ │ └── routes.rs │ │ │ ├── shard_sync.rs │ │ │ ├── start_epoch_change_finisher.rs │ │ │ ├── storage.rs │ │ │ ├── storage │ │ │ │ ├── blob_info.rs │ │ │ │ ├── constants.rs │ │ │ │ ├── database_config.rs │ │ │ │ ├── event_cursor_table.rs │ │ │ │ ├── event_sequencer.rs │ │ │ │ ├── metrics.rs │ │ │ │ └── shard.rs │ │ │ ├── system_events.rs │ │ │ └── thread_pool.rs │ │ ├── test_utils.rs │ │ └── testbed.rs │ ├── storage_openapi.html │ ├── storage_openapi.yaml │ └── tests │ │ └── epoch_change.rs ├── walrus-simtest │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── test_utils.rs │ └── tests │ │ ├── simtest.rs │ │ ├── simtest_event_blob.rs │ │ ├── simtest_failure.rs │ │ └── simtest_param_sync.rs ├── walrus-storage-node-client │ ├── Cargo.toml │ └── src │ │ ├── api.rs │ │ ├── api │ │ └── errors.rs │ │ ├── client.rs │ │ ├── client │ │ ├── builder.rs │ │ └── middleware.rs │ │ ├── error.rs │ │ ├── lib.rs │ │ ├── node_response.rs │ │ └── tls.rs ├── walrus-stress │ ├── Cargo.toml │ └── src │ │ ├── generator.rs │ │ ├── generator │ │ ├── blob.rs │ │ └── write_client.rs │ │ └── main.rs ├── walrus-sui │ ├── Cargo.toml │ ├── benches │ │ └── gas_cost_bench.rs │ ├── build.rs │ ├── src │ │ ├── client.rs │ │ ├── client │ │ │ ├── contract_config.rs │ │ │ ├── metrics.rs │ │ │ ├── read_client.rs │ │ │ ├── retry_client.rs │ │ │ ├── retry_client │ │ │ │ ├── download_handler.rs │ │ │ │ ├── failover.rs │ │ │ │ ├── fallible.rs │ │ │ │ ├── retriable_rpc_client.rs │ │ │ │ ├── retriable_rpc_client │ │ │ │ │ └── fallback_client.rs │ │ │ │ ├── retriable_rpc_error.rs │ │ │ │ ├── retriable_sui_client.rs │ │ │ │ └── retry_count_guard.rs │ │ │ ├── rpc_config.rs │ │ │ └── transaction_builder.rs │ │ ├── config.rs │ │ ├── contracts.rs │ │ ├── lib.rs │ │ ├── system_setup.rs │ │ ├── test_utils.rs │ │ ├── test_utils │ │ │ └── system_setup.rs │ │ ├── types.rs │ │ ├── types │ │ │ ├── events.rs │ │ │ ├── move_errors.rs │ │ │ └── move_structs.rs │ │ ├── utils.rs │ │ └── wallet.rs │ └── tests │ │ └── test_walrus_sui.rs ├── walrus-test-utils │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── walrus-utils │ ├── Cargo.toml │ └── src │ ├── backoff.rs │ ├── config.rs │ ├── http.rs │ ├── lib.rs │ ├── metrics.rs │ ├── metrics │ ├── monitored_scope.rs │ └── tokio.rs │ └── tracing_sampled.rs ├── deny.toml ├── diesel.toml ├── docker ├── grafana-local │ ├── docker-compose.yaml │ ├── grafana-datasources.yaml │ ├── prometheus.yaml │ └── tempo.yaml ├── local-testbed │ ├── README.md │ ├── build-local-image.sh │ ├── docker-compose.yaml │ └── files │ │ ├── deploy-walrus.sh │ │ └── run-walrus.sh ├── walrus-antithesis │ ├── build-test-config-image │ │ ├── Dockerfile │ │ ├── docker-compose.yaml │ │ ├── files │ │ │ ├── complete-setup.sh │ │ │ ├── deploy-walrus.sh │ │ │ ├── run-staking.sh │ │ │ ├── run-stress.sh │ │ │ └── run-walrus.sh │ │ └── pipeline.sh │ ├── build-walrus-image-for-antithesis │ │ ├── Dockerfile │ │ ├── build.sh │ │ └── update_move_toml.sh │ └── sui_version.toml ├── walrus-orchestrator │ ├── Dockerfile │ └── build.sh ├── walrus-proxy │ └── Dockerfile ├── walrus-service │ ├── Dockerfile │ ├── Dockerfile.walrus-backup │ └── build.sh └── walrus-stress │ ├── Dockerfile │ └── build.sh ├── docs ├── assets │ ├── blob-hash.png │ └── sliver-hash.png ├── book │ ├── SUMMARY.md │ ├── assets │ │ ├── WriteFlow.png │ │ ├── operators.json │ │ ├── suins-asset.png │ │ ├── walrus-site-diagram.svg │ │ ├── walrus-sites-hash-mismatch.png │ │ └── walrus-sites-portal-diagram.svg │ ├── blog │ │ ├── 00_intro.md │ │ ├── 01_announcing_walrus.md │ │ ├── 02_devnet_update.md │ │ ├── 03_whitepaper.md │ │ ├── 04_testnet_update.md │ │ ├── 05_testnet_redeployment.md │ │ └── 06_mainnet.md │ ├── design │ │ ├── architecture.md │ │ ├── encoding.md │ │ ├── future.md │ │ ├── objectives_use_cases.md │ │ ├── operations-off-chain.md │ │ ├── operations-sui.md │ │ ├── operations.md │ │ ├── overview.md │ │ └── properties.md │ ├── dev-guide │ │ ├── components.md │ │ ├── costs.md │ │ ├── data-security.md │ │ ├── dev-guide.md │ │ ├── dev-operations.md │ │ └── sui-struct.md │ ├── glossary.md │ ├── index.md │ ├── legal │ │ ├── privacy.md │ │ ├── testnet_tos.md │ │ └── walrus_general_tos.md │ ├── operator-guide │ │ ├── aggregator.md │ │ └── auth-publisher.md │ ├── setup │ │ ├── client_config.yaml │ │ ├── client_config_example.yaml │ │ ├── client_config_mainnet.yaml │ │ ├── client_config_testnet.yaml │ │ └── walrus-install.sh │ ├── usage │ │ ├── client-cli.md │ │ ├── examples.md │ │ ├── interacting.md │ │ ├── json-api.md │ │ ├── networks.md │ │ ├── sdks.md │ │ ├── setup.md │ │ ├── stake.md │ │ ├── started.md │ │ ├── troubleshooting.md │ │ └── web-api.md │ ├── walrus-sites │ │ ├── advanced.md │ │ ├── authentication.md │ │ ├── bring-your-own-domain.md │ │ ├── builder-config.md │ │ ├── ci-cd.md │ │ ├── commands.md │ │ ├── intro.md │ │ ├── linking.md │ │ ├── overview.md │ │ ├── portal.md │ │ ├── privacy.md │ │ ├── redirects.md │ │ ├── restrictions.md │ │ ├── routing.md │ │ ├── tutorial-install.md │ │ ├── tutorial-publish.md │ │ ├── tutorial-suins.md │ │ └── tutorial.md │ ├── walrus.pdf │ ├── walrus_whitepaper_v1.pdf │ └── walrus_whitepaper_v2.pdf ├── examples │ ├── CONFIG │ │ ├── bin │ │ │ └── README.md │ │ └── config_dir │ │ │ └── README.md │ ├── javascript │ │ ├── README.md │ │ ├── blob_upload_download_webapi.html │ │ └── system_stats.html │ ├── move │ │ └── walrus_dep │ │ │ ├── Move.toml │ │ │ ├── README.md │ │ │ └── sources │ │ │ ├── tests │ │ │ └── walrus_dep_tests.move │ │ │ └── wrapped_blob.move │ └── python │ │ ├── README.md │ │ ├── hello_walrus_jsonapi.py │ │ ├── hello_walrus_webapi.py │ │ ├── requirements.txt │ │ ├── track_walrus_events.py │ │ └── utils.py ├── mdbook-admonish.css ├── red-stuff.md ├── telemetry-attributes.csv └── theme │ ├── head.hbs │ ├── tabs.css │ └── tabs.js ├── licensesnip.config.jsonc ├── mainnet-contracts ├── .prettierrc ├── subsidies │ ├── Move.lock │ ├── Move.toml │ ├── sources │ │ └── subsidies.move │ └── tests │ │ └── subsidies_tests.move ├── wal │ ├── Move.lock │ ├── Move.toml │ └── sources │ │ └── wal.move └── walrus │ ├── Move.lock │ ├── Move.toml │ ├── docs │ └── msg_formats.txt │ ├── sources │ ├── display.move │ ├── init.move │ ├── staking.move │ ├── staking │ │ ├── active_set.move │ │ ├── apportionment_queue.move │ │ ├── auth.move │ │ ├── committee.move │ │ ├── exchange_rate.move │ │ ├── node_metadata.move │ │ ├── pending_values.move │ │ ├── staked_wal.move │ │ ├── staking_inner.move │ │ ├── staking_pool.move │ │ ├── storage_node.move │ │ └── walrus_context.move │ ├── system.move │ ├── system │ │ ├── blob.move │ │ ├── bls_aggregate.move │ │ ├── encoding.move │ │ ├── epoch_parameters.move │ │ ├── event_blob.move │ │ ├── events.move │ │ ├── messages.move │ │ ├── metadata.move │ │ ├── redstuff.move │ │ ├── shared_blob.move │ │ ├── storage_accounting.move │ │ ├── storage_resource.move │ │ └── system_state_inner.move │ ├── upgrade.move │ └── utils │ │ ├── extended_field.move │ │ └── sort.move │ └── tests │ ├── e2e_runner.move │ ├── e2e_tests.move │ ├── staking │ ├── active_set_tests.move │ ├── committee_tests.move │ ├── staked_wal_tests.move │ ├── staking_inner_compute_tests.move │ ├── staking_inner_tests.move │ ├── staking_pool │ │ ├── pool_commission_tests.move │ │ ├── pool_direct_withdraw_tests.move │ │ ├── pool_early_withdraw_tests.move │ │ ├── pool_rounding_tests.move │ │ └── staking_pool_tests.move │ └── walrus_context_tests.move │ ├── system │ ├── blob_tests.move │ ├── bls_tests.move │ ├── deny_list_tests.move │ ├── event_blob_tests.move │ ├── invalid_tests.move │ ├── metadata_tests.move │ ├── ringbuffer_tests.move │ ├── storage_resource_tests.move │ └── system_state_inner_tests.move │ ├── test_node.move │ ├── test_utils.move │ └── upgrade_tests.move ├── rust-toolchain.toml ├── scripts ├── cache-inference │ ├── .gitignore │ ├── README.md │ ├── cache-inference.ts │ ├── package-lock.json │ ├── package.json │ ├── tsconfig.json │ └── types.ts ├── crash_recovery.sh ├── create_multisig_tx.sh ├── local-testbed.sh ├── move_coverage.sh ├── plot_contract_cost.py ├── release_notes.py └── simtest │ ├── cargo-simtest │ ├── install.sh │ ├── seed-search.py │ └── simtest-run.sh ├── setup ├── client_config.yaml ├── client_config_mainnet.yaml ├── client_config_testnet.yaml └── walrus-install.sh └── testnet-contracts ├── .prettierrc ├── README.md ├── subsidies ├── Move.lock ├── Move.toml ├── sources │ └── subsidies.move └── tests │ └── subsidies_tests.move ├── wal ├── Move.lock ├── Move.toml └── sources │ └── wal.move ├── wal_exchange ├── Move.lock ├── Move.toml └── sources │ └── wal_exchange.move └── walrus ├── Move.lock ├── Move.toml ├── docs └── msg_formats.txt ├── sources ├── display.move ├── init.move ├── staking.move ├── staking │ ├── active_set.move │ ├── apportionment_queue.move │ ├── auth.move │ ├── committee.move │ ├── exchange_rate.move │ ├── node_metadata.move │ ├── pending_values.move │ ├── staked_wal.move │ ├── staking_inner.move │ ├── staking_pool.move │ ├── storage_node.move │ └── walrus_context.move ├── system.move ├── system │ ├── blob.move │ ├── bls_aggregate.move │ ├── encoding.move │ ├── epoch_parameters.move │ ├── event_blob.move │ ├── events.move │ ├── messages.move │ ├── metadata.move │ ├── redstuff.move │ ├── shared_blob.move │ ├── storage_accounting.move │ ├── storage_resource.move │ └── system_state_inner.move ├── upgrade.move └── utils │ ├── extended_field.move │ └── sort.move └── tests ├── e2e_runner.move ├── e2e_tests.move ├── staking ├── active_set_tests.move ├── committee_tests.move ├── staked_wal_tests.move ├── staking_inner_compute_tests.move ├── staking_inner_tests.move ├── staking_pool │ ├── pool_commission_tests.move │ ├── pool_direct_withdraw_tests.move │ ├── pool_early_withdraw_tests.move │ ├── pool_rounding_tests.move │ └── staking_pool_tests.move └── walrus_context_tests.move ├── system ├── blob_tests.move ├── bls_tests.move ├── deny_list_tests.move ├── event_blob_tests.move ├── invalid_tests.move ├── metadata_tests.move ├── ringbuffer_tests.move ├── storage_resource_tests.move └── system_state_inner_tests.move ├── test_node.move ├── test_utils.move └── upgrade_tests.move /.config/nextest.toml: -------------------------------------------------------------------------------- 1 | # See https://nexte.st/docs/configuration/ for configuration parameters. 2 | 3 | [profile.default] 4 | fail-fast = false # do not stop at first failure 5 | slow-timeout = { period = "1m", terminate-after = 5 } 6 | 7 | [[profile.default.overrides]] 8 | filter = 'package(walrus-e2e-tests)' 9 | threads-required = 4 10 | 11 | [profile.ci] 12 | retries = 2 # retry twice for a total of 3 attempts 13 | slow-timeout = { period = "1m", terminate-after = 10 } # Timeout tests after 10 minutes 14 | 15 | [[profile.ci.overrides]] 16 | filter = 'package(walrus-e2e-tests) or package(walrus-sui) or test(nodes_drive_epoch_change)' 17 | slow-timeout = { period = "2m", terminate-after = 5 } # Mark E2E tests as slow only after 2 minutes 18 | threads-required = 4 19 | 20 | [[profile.ci.overrides]] 21 | filter = 'test(check_and_update_example_config) or test(check_and_update_openapi)' 22 | retries = 0 # Do not retry these tests as they always succeed on the second run 23 | 24 | [profile.simtest] 25 | slow-timeout = { period = "5m", terminate-after = 6 } # Timeout tests after 30 minutes 26 | test-threads = "num-cpus" 27 | 28 | [profile.simtestnightly] 29 | # Print out output for failing tests as soon as they fail, and also at the end 30 | # of the run (for easy scrollability). 31 | failure-output = "immediate" 32 | # Show skipped tests in the CI output. 33 | status-level = "fail" 34 | # Do not cancel the test run on the first failure. 35 | fail-fast = false 36 | # Mark tests as slow after 30m, terminate after 1.5h 37 | slow-timeout = { period = "30m", terminate-after = 5 } 38 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | charset = utf-8 9 | end_of_line = lf 10 | indent_size = 4 11 | indent_style = space 12 | insert_final_newline = true 13 | max_line_length = 100 14 | trim_trailing_whitespace = true 15 | 16 | # Some markdown files are additionally checked using markdownlint. 17 | [*.md] 18 | indent_size = unset 19 | max_line_length = 150 20 | 21 | # Some markdown files are additionally checked using markdownlint. 22 | [docs/book/**/*.md] 23 | indent_size = unset 24 | max_line_length = unset 25 | trim_trailing_whitespace = unset 26 | 27 | [{*.css,*.html,*.json,*.sh,*.toml,*.yml,*.yaml,cargo-simtest}] 28 | indent_size = 2 29 | max_line_length = 150 30 | 31 | [crates/walrus-orchestrator/src/monitor.rs] 32 | indent_size = unset 33 | 34 | # Ignore paths 35 | [{.git/**/*,**/*.lock,**/Move.toml,LICENSE,docs/devnet-public/glossary.md,crates/walrus-orchestrator/assets/*,.editorconfig,venv/**/*,crates/walrus-service/*.html,crates/walrus-service/*.yaml,docker/walrus-antithesis/build-walrus-image-for-antithesis/update_move_toml.sh,docs/mdbook-admonish.css,docs/theme/**/*,.github/workflows/issues-monitor.yaml,scripts/simtest/seed-search.py}] 36 | charset = unset 37 | end_of_line = unset 38 | indent_size = unset 39 | indent_style = unset 40 | insert_final_newline = unset 41 | max_line_length = unset 42 | trim_trailing_whitespace = unset 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/docs.yaml: -------------------------------------------------------------------------------- 1 | name: Documentation Issue 2 | description: Report an issue or potential improvement with the documentation. 3 | labels: ["documentation"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: Thanks for taking the time to improve the Walrus documentation! 8 | - type: textarea 9 | id: description 10 | attributes: 11 | label: Description 12 | description: > 13 | A clear and concise description of what could be improved about the documentation. 14 | placeholder: "It should be better documented how to ..." 15 | validations: 16 | required: true 17 | - type: checkboxes 18 | id: terms 19 | attributes: 20 | label: Code of Conduct 21 | description: > 22 | By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/MystenLabs/walrus/blob/main/CODE_OF_CONDUCT.md). 23 | options: 24 | - label: I agree to follow this project's Code of Conduct. 25 | required: true 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.yaml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: File a feature request. 3 | labels: ["enhancement"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: Thanks for taking the time to improve Walrus! 8 | - type: textarea 9 | id: description 10 | attributes: 11 | label: Description 12 | description: > 13 | A clear and concise description of the new feature and what would be the benefit. 14 | value: "I would like to be able to ..." 15 | validations: 16 | required: true 17 | - type: checkboxes 18 | id: terms 19 | attributes: 20 | label: Code of Conduct 21 | description: > 22 | By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/MystenLabs/walrus/blob/main/CODE_OF_CONDUCT.md). 23 | options: 24 | - label: I agree to follow this project's Code of Conduct. 25 | required: true 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/other.yaml: -------------------------------------------------------------------------------- 1 | name: Other Issue 2 | description: Report any other potential improvement. 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: Thanks for taking the time to improve Walrus! 7 | - type: textarea 8 | id: description 9 | attributes: 10 | label: Description 11 | description: > 12 | A clear and concise description of the issue. 13 | placeholder: "The CI should also test ..." 14 | validations: 15 | required: true 16 | - type: checkboxes 17 | id: terms 18 | attributes: 19 | label: Code of Conduct 20 | description: > 21 | By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/MystenLabs/walrus/blob/main/CODE_OF_CONDUCT.md). 22 | options: 23 | - label: I agree to follow this project's Code of Conduct. 24 | required: true 25 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Describe the changes or additions included in this PR. 4 | 5 | ## Test plan 6 | 7 | How did you test the new or updated feature? 8 | 9 | --- 10 | 11 | ## Release notes 12 | 13 | Check each box that your changes affect. If none of the boxes relate to your changes, release notes aren't required. 14 | For each box you select, include information after the relevant heading that describes the impact of your changes that 15 | a user might notice and any actions they must take to implement updates. (Add release notes after the colon for each item) 16 | 17 | - [ ] Storage node: 18 | - [ ] Aggregator: 19 | - [ ] Publisher: 20 | - [ ] CLI: 21 | -------------------------------------------------------------------------------- /.github/actions/run_tarpaulin/action.yml: -------------------------------------------------------------------------------- 1 | name: Test coverage 2 | description: Run all tests and report coverage 3 | 4 | runs: 5 | using: "composite" 6 | steps: 7 | - run: cargo install --locked cargo-tarpaulin@0.31.2 8 | shell: bash 9 | 10 | - name: Run tests (including integration E2E tests) and record coverage 11 | run: cargo tarpaulin 12 | shell: bash 13 | 14 | - name: Upload coverage report 15 | uses: actions/upload-artifact@v4 16 | with: 17 | name: Coverage report 18 | path: tarpaulin-report.html 19 | - name: Code-coverage report 20 | uses: irongut/CodeCoverageSummary@51cc3a756ddcd398d447c044c02cb6aa83fdae95 # pin@v1.3.0 21 | with: 22 | filename: cobertura.xml 23 | badge: true 24 | fail_below_min: false 25 | format: markdown 26 | hide_branch_rate: false 27 | hide_complexity: true 28 | indicators: true 29 | output: both 30 | thresholds: '50 75' 31 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Documentation for all configuration options: 2 | # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: "cargo" 7 | directory: "/" 8 | schedule: 9 | interval: "weekly" 10 | day: "sunday" 11 | commit-message: 12 | prefix: "fix" 13 | prefix-development: "chore" 14 | include: "scope" 15 | groups: 16 | cargo-minor-and-patch-dependencies: 17 | update-types: 18 | - "minor" 19 | - "patch" 20 | ignore: 21 | - dependency-name: futures-timer 22 | - dependency-name: move-* 23 | - dependency-name: mysten-metrics 24 | - dependency-name: protobuf # TODO: remove after fixing WAL-458 25 | - dependency-name: sui 26 | - dependency-name: sui-* 27 | - dependency-name: telemetry-subscribers 28 | - dependency-name: test-cluster 29 | - dependency-name: tokio 30 | - dependency-name: typed-store 31 | 32 | - package-ecosystem: "github-actions" 33 | directory: "/" 34 | schedule: 35 | interval: "monthly" 36 | commit-message: 37 | prefix: "chore" 38 | include: "scope" 39 | groups: 40 | github-actions-all: 41 | patterns: ["*"] 42 | -------------------------------------------------------------------------------- /.github/workflows/issues-monitor.yaml: -------------------------------------------------------------------------------- 1 | name: GitHub Issues Monitor 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | 7 | jobs: 8 | comment: 9 | if: ${{ !github.event.issue.pull_request }} 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Add Comment to New Issue 13 | uses: actions/github-script@v7 14 | with: 15 | script: | 16 | github.rest.issues.createComment({ 17 | issue_number: context.issue.number, 18 | owner: context.repo.owner, 19 | repo: context.repo.repo, 20 | body: "Thank you for opening this issue, a team member will review it shortly. Until then, please do not interact with any users that claim to be from Sui or Walrus support and do not click on any links!" 21 | }) 22 | -------------------------------------------------------------------------------- /.github/workflows/pages-preview.yaml: -------------------------------------------------------------------------------- 1 | name: Build and deploy GitHub Pages preview for PRs 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - reopened 8 | - synchronize 9 | - closed 10 | paths: 11 | - "book.toml" 12 | - "docs/book/**" 13 | - "docs/theme/**" 14 | - "docs/mdbook-admonish.css" 15 | - "setup/**" 16 | - ".github/actions/build-mdbook/action.yaml" 17 | - ".github/workflows/pages-preview.yaml" 18 | 19 | concurrency: preview-${{ github.ref }} 20 | 21 | permissions: 22 | contents: write 23 | pull-requests: write 24 | 25 | jobs: 26 | build-with-linkcheck: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4 30 | - uses: ./.github/actions/build-mdbook 31 | if: github.event.action != 'closed' 32 | 33 | preview: 34 | runs-on: ubuntu-latest 35 | if: github.repository_owner == 'MystenLabs' 36 | steps: 37 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4 38 | - uses: ./.github/actions/build-mdbook 39 | with: 40 | with_linkcheck: "false" 41 | if: github.event.action != 'closed' 42 | - name: Deploy preview 43 | uses: rossjrw/pr-preview-action@2fb559e4766555e23d07b73d313fe97c4f8c3cfe # pin@v1.6.1 44 | with: 45 | source-dir: docs/build/html 46 | -------------------------------------------------------------------------------- /.github/workflows/tag.yml: -------------------------------------------------------------------------------- 1 | name: Tag Walrus Branch 2 | 3 | on: 4 | repository_dispatch: 5 | types: [tag-walrus-branch] 6 | 7 | workflow_call: 8 | inputs: 9 | walrus_commit: 10 | description: 'Walrus repo commit to tag' 11 | type: string 12 | required: true 13 | tag_name: 14 | description: 'Tag Name' 15 | type: string 16 | required: true 17 | workflow_dispatch: 18 | inputs: 19 | walrus_commit: 20 | description: 'Walrus repo commit to tag' 21 | type: string 22 | required: true 23 | tag_name: 24 | description: 'Tag Name' 25 | type: string 26 | required: true 27 | 28 | env: 29 | WALRUS_COMMIT: "${{ github.event.client_payload.walrus_commit || inputs.walrus_commit }}" 30 | TAG_NAME: "${{ github.event.client_payload.tag_name || inputs.tag_name }}" 31 | 32 | jobs: 33 | tag: 34 | name: Tag 35 | runs-on: ubuntu-latest 36 | 37 | steps: 38 | - name: Checkout 39 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4 40 | 41 | - name: Tag 42 | uses: julbme/gh-action-manage-tag@8daf6387badea2c6b8f989bd0f82b5a9ef1d84e6 # pin@v1 43 | with: 44 | name: ${{ env.TAG_NAME }} 45 | state: present 46 | from: ${{ env.WALRUS_COMMIT }} 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 49 | -------------------------------------------------------------------------------- /.github/workflows/trigger-artifacts-builds.yml: -------------------------------------------------------------------------------- 1 | name: Trigger Build Artifacts 2 | run-name: Trigger Build Artifacts → ${{ github.ref_name }} 3 | 4 | on: 5 | workflow_dispatch: 6 | push: 7 | branches: 8 | - devnet 9 | - testnet 10 | - mainnet 11 | 12 | concurrency: ${{ github.workflow }}-${{ github.ref_name }} 13 | 14 | jobs: 15 | trigger-artifact-builds: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Dispatch Walrus Artifact Builds in MystenLabs/sui-operations 19 | uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # pin@v3.0.0 20 | with: 21 | repository: MystenLabs/sui-operations 22 | token: ${{ secrets.SUI_OPS_DISPATCH_TOKEN }} 23 | event-type: walrus-build-artifacts 24 | client-payload: '{"branch": "${{ github.ref_name }}"}' 25 | -------------------------------------------------------------------------------- /.github/workflows/update-ws-binaries.yaml: -------------------------------------------------------------------------------- 1 | name: Update bin.wal.app with latest binaries 2 | 3 | on: 4 | repository_dispatch: 5 | types: [update-sites-bins] 6 | # every week 7 | schedule: 8 | - cron: "14 3 * * 0" 9 | # on demand 10 | workflow_dispatch: 11 | 12 | concurrency: ci-${{ github.ref }} 13 | 14 | permissions: 15 | contents: read 16 | 17 | jobs: 18 | # We store the data for the Sui wallet and the site object in GitHub variables 19 | # (https://github.com/MystenLabs/walrus/settings/variables/actions) and secrets 20 | # (https://github.com/MystenLabs/walrus/settings/secrets/actions). 21 | update-bin-walrus-site: 22 | name: Update Walrus Site bin.wal.app 23 | runs-on: ubuntu-ghcloud 24 | env: 25 | # Colors don't seem to work properly with the multiline commands. 26 | NO_COLOR: 1 27 | RUST_LOG: info 28 | EPOCHS: 10 29 | BUILD_DIR: site 30 | steps: 31 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4 32 | - uses: ./.github/actions/set-up-walrus 33 | with: 34 | SUI_ADDRESS: "${{ vars.SUI_ADDRESS }}" 35 | SUI_KEYSTORE: "${{ secrets.SUI_KEYSTORE }}" 36 | WALRUS_CONFIG: "${{ vars.WALRUS_CONFIG }}" 37 | SUI_NETWORK: mainnet 38 | 39 | - name: Create temporary directory 40 | run: "mkdir -p ${{ env.BUILD_DIR }}" 41 | - name: Download latest mainnet and testnet binaries 42 | run: | 43 | for arch in ubuntu-x86_64 ubuntu-x86_64-generic macos-x86_64 macos-arm64 windows-x86_64.exe; do 44 | for env in mainnet testnet; do 45 | name=walrus-$env-latest-$arch 46 | curl https://storage.googleapis.com/mysten-walrus-binaries/$name -o ${{ env.BUILD_DIR }}/$name 47 | done 48 | done 49 | 50 | - name: Update Walrus Site 51 | run: > 52 | site-builder 53 | update --list-directory ${{ env.BUILD_DIR }} ${{ vars.WALRUS_SITE_OBJECT_BIN }} 54 | --epochs ${{ env.EPOCHS }} 55 | --permanent 56 | --check-extend 57 | -------------------------------------------------------------------------------- /.github/workflows/validate-release-notes-pre-land.yml: -------------------------------------------------------------------------------- 1 | name: Validate Release Notes 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'main' 7 | - 'devnet' 8 | - 'testnet' 9 | - 'mainnet' 10 | pull_request: 11 | types: [opened, synchronize, reopened, edited, ready_for_review] 12 | workflow_dispatch: 13 | inputs: 14 | sui_repo_ref: 15 | description: "Branch / commit to test" 16 | type: string 17 | required: false 18 | default: '' 19 | 20 | concurrency: 21 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 22 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 23 | 24 | jobs: 25 | diff: 26 | name: Determine PR eligibility for ${{ github.event.pull_request.number }} 27 | if: github.event.pull_request.number != '' 28 | runs-on: [ubuntu-latest] 29 | outputs: 30 | isReleaseNotesEligible: ${{ steps.diff.outputs.isReleaseNotesEligible }} 31 | steps: 32 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4 33 | with: 34 | ref: ${{ github.event.inputs.sui_repo_ref || github.ref }} 35 | - name: Detect Changes 36 | uses: './.github/actions/diffs' 37 | id: diff 38 | 39 | release-notes-description-check: 40 | name: Validate Release Notes in ${{ github.event.pull_request.number }} 41 | needs: diff 42 | if: needs.diff.outputs.isReleaseNotesEligible == 'true' && github.event.pull_request.number != '' 43 | permissions: 44 | contents: read 45 | pull-requests: read 46 | runs-on: [ubuntu-latest] 47 | steps: 48 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4 49 | with: 50 | ref: ${{ github.event.inputs.sui_repo_ref || github.ref }} 51 | - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # pin@v5.6.0 52 | with: 53 | python-version: 3.10.10 54 | - name: Validate PR's release notes 55 | shell: bash 56 | run: | 57 | WALRUS_REPO_TOKEN=${{ secrets.GITHUB_TOKEN }} python ./scripts/release_notes.py check ${{ github.event.pull_request.number }} 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Editors/OS 2 | **/.history/ 3 | **/.idea/ 4 | .vscode/* 5 | 6 | .nvimrc 7 | .DS_Store 8 | 9 | # Rust build and test files 10 | **/target 11 | tarpaulin-report.html 12 | build_rs_cov.profraw 13 | cobertura.xml 14 | flamegraph.svg 15 | 16 | # Move-related files 17 | build/ 18 | .trace 19 | .coverage_map.mvcov 20 | 21 | # Custom pre-commit configuration 22 | .custom-pre-commit-config.yaml 23 | 24 | # mdBook 25 | docs/build/ 26 | 27 | # Walrus binary and configuration 28 | ./walrus 29 | ./client_config.yaml 30 | docs/examples/CONFIG/bin/walrus 31 | docs/examples/CONFIG/config_dir/client_config.yaml 32 | 33 | # Misc 34 | *.key 35 | .env 36 | working_dir/ 37 | *.log 38 | venv/ 39 | **/tmp 40 | out/ 41 | 42 | # Deployment assets 43 | crates/walrus-orchestrator/assets/ 44 | !crates/walrus-orchestrator/assets/dashboard-template.json 45 | !crates/walrus-orchestrator/assets/settings-template.yaml 46 | -------------------------------------------------------------------------------- /.licensesnip: -------------------------------------------------------------------------------- 1 | Copyright (c) Walrus Foundation 2 | SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /.licensesnipignore: -------------------------------------------------------------------------------- 1 | crates/walrus-service/storage_openapi.html 2 | crates/walrus-service/daemon_openapi.html 3 | crates/walrus-service/aggregator_openapi.html 4 | crates/walrus-service/publisher_openapi.html 5 | docs/mdbook-admonish.css 6 | docs/theme/tabs.css 7 | docs/theme/tabs.js 8 | scripts/move_coverage.sh 9 | crates/typed-store/src/rocks/safe_iter.rs 10 | crates/typed-store/src/rocks/tests.rs 11 | crates/typed-store/src/rocks/mod.rs 12 | crates/typed-store/src/metrics.rs 13 | crates/typed-store/src/lib.rs 14 | crates/typed-store/src/traits.rs 15 | crates/typed-store/src/rocks/errors.rs 16 | crates/typed-store/src/rocks/safe_iter.rs 17 | crates/typed-store/src/rocks/tests.rs 18 | -------------------------------------------------------------------------------- /.markdownlint-cli2.yaml: -------------------------------------------------------------------------------- 1 | # See https://github.com/DavidAnson/markdownlint-cli2?tab=readme-ov-file#markdownlint-cli2jsonc 2 | # for configuration options and https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md 3 | # for available rules. 4 | 5 | # Note: Keep globs in sync with .github/workflows/lint.yml. 6 | globs: 7 | - "docs/book/**/*.md" 8 | - "CONTRIBUTING.md" 9 | - "README.md" 10 | gitignore: true 11 | config: 12 | default: true 13 | line-length: 14 | line_length: 100 15 | heading_line_length: 80 16 | code_block_line_length: 150 17 | tables: false 18 | stern: false 19 | heading-style: 20 | style: atx 21 | ul-style: 22 | style: dash 23 | ol-prefix: 24 | style: one 25 | emphasis-style: 26 | style: asterisk 27 | bold-style: 28 | style: asterisk 29 | proper-names: 30 | code_blocks: false 31 | html_elements: false 32 | names: 33 | - Byzantine 34 | - dApp 35 | - GitHub 36 | - internet 37 | - JavaScript 38 | - Mainnet 39 | - Merkle 40 | - Mysten Labs 41 | - Python 42 | - Rust 43 | - Sui 44 | - SUI 45 | - SuiNS 46 | - Testnet 47 | - testnets 48 | - Walrus 49 | - Walrus Site 50 | - Walrus Sites 51 | - web 52 | - web2 53 | - web3 54 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | style_edition = "2024" 2 | -------------------------------------------------------------------------------- /.taplo.toml: -------------------------------------------------------------------------------- 1 | exclude = [ 2 | # automatically generated file 3 | "crates/walrus-sdk/client_config_example.yaml", 4 | ] 5 | include = ["**/*.toml"] 6 | 7 | [formatting] 8 | 9 | [[rule]] 10 | 11 | [rule.formatting] 12 | align_comments = false 13 | array_auto_collapse = false 14 | array_auto_expand = true 15 | array_trailing_comma = true 16 | column_width = 150 17 | indent_entries = false 18 | reorder_arrays = true 19 | reorder_keys = true 20 | trailing_newline = true 21 | 22 | [[rule]] 23 | include = ["**/Cargo.toml", "**/Move.toml"] 24 | keys = ["bench", "package", "workspace.package"] 25 | 26 | [rule.formatting] 27 | align_comments = true 28 | reorder_keys = false 29 | 30 | [[rule]] 31 | include = ["deny.toml"] 32 | 33 | [rule.formatting] 34 | reorder_keys = false 35 | -------------------------------------------------------------------------------- /.tarpaulin.toml: -------------------------------------------------------------------------------- 1 | [default] 2 | out = ["Html", "Xml"] 3 | packages = [ 4 | "walrus-core", 5 | "walrus-e2e-tests", 6 | "walrus-rest-client", 7 | "walrus-service", 8 | "walrus-sui", 9 | "walrus-utils", 10 | ] 11 | run-types = ["Lib", "Tests"] 12 | skip-clean = true 13 | # Use separate target directory to avoid interference with other builds. 14 | target-dir = "target/tarpaulin" 15 | # Increase timeout for longer-running tests to 5 minutes. 16 | timeout = "5min" 17 | # Don't include test and benchmark code in the coverage result. 18 | exclude-files = [ 19 | "crates/**/benches/**/*", 20 | "crates/**/test_utils/**/*", 21 | "crates/**/tests/**/*", 22 | "crates/walrus-e2e-tests/**/*", 23 | "crates/walrus-orchestrator/**/*", 24 | "crates/walrus-proc-macros/**/*", 25 | "crates/walrus-simtest/**/*", 26 | "crates/walrus-stress/**/*", 27 | "crates/walrus-test-utils/**/*", 28 | ] 29 | # Include all tests, even longer integration tests. 30 | args = ["--include-ignored"] 31 | -------------------------------------------------------------------------------- /.yamlfmt.yml: -------------------------------------------------------------------------------- 1 | exclude: 2 | - "crates/walrus-sdk/client_config_example.yaml" # autogenerated file 3 | - "crates/walrus-service/storage_openapi.yaml" # autogenerated file 4 | - "crates/walrus-service/daemon_openapi.yaml" # autogenerated file 5 | - "crates/walrus-service/aggregator_openapi.yaml" # autogenerated file 6 | - "crates/walrus-service/publisher_openapi.yaml" # autogenerated file 7 | formatter: 8 | type: basic 9 | retain_line_breaks_single: true 10 | scan_folded_as_literal: true 11 | max_line_length: 120 12 | drop_merge_tag: true 13 | disable_alias_key_correction: true 14 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Walrus Code of Conduct 2 | 3 | Walrus is a part of the Sui ecosystem and follows the same code of conduct. 4 | 5 | As an open source project, we encourage free discussion rooted in respect. 6 | We endeavor to always be mindful of others' perspectives and ask all 7 | fellow contributors to do the same. We welcome you to the Sui platform 8 | and ask you to help us grow it with relevant, on-point contributions. 9 | 10 | ## Our pledge 11 | 12 | We as members, contributors, and leaders pledge to make participation in our 13 | community a harassment-free experience for everyone, regardless of age, body 14 | size, visible or invisible disability, ethnicity, sex characteristics, gender 15 | identity and expression, level of experience, education, socio-economic status, 16 | nationality, personal appearance, race, caste, color, religion, or sexual 17 | identity and orientation. 18 | 19 | We pledge to act and interact in ways that contribute to an open, welcoming, 20 | diverse, inclusive, and healthy community. 21 | 22 | ## More information 23 | 24 | See the central [Sui Code of Conduct](https://docs.sui.io/code-of-conduct) for 25 | full details. 26 | 27 | Our Code of Conduct is adapted from the 28 | [Contributor Covenant version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html). 29 | -------------------------------------------------------------------------------- /_typos.toml: -------------------------------------------------------------------------------- 1 | [files] 2 | extend-exclude = ["*.svg"] 3 | -------------------------------------------------------------------------------- /binary-build-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "release_binaries": [ "walrus", "walrus-node" ] 3 | } 4 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Mysten Labs "] 3 | language = "en" 4 | multilingual = false 5 | src = "docs/book" 6 | title = "Walrus" 7 | 8 | [build] 9 | build-dir = "docs/build" 10 | 11 | [output.html] 12 | additional-css = ["docs/mdbook-admonish.css", "docs/theme/tabs.css"] 13 | additional-js = ["docs/theme/tabs.js"] 14 | theme = "docs/theme" 15 | 16 | [output.linkcheck] 17 | exclude = [ 18 | 'faucet\.sui\.io', 19 | 'github\.com', 20 | 'google\.com', 21 | 'x\.com', 22 | ] 23 | follow-web-links = true 24 | optional = true 25 | traverse-parent-directories = true 26 | warning-policy = "error" 27 | 28 | [preprocessor] 29 | 30 | [preprocessor.admonish] 31 | assets_version = "3.0.3" # do not edit: managed by `mdbook-admonish install` 32 | command = "mdbook-admonish" 33 | on_failure = "bail" 34 | 35 | [preprocessor.katex] 36 | # Using `\(` and `\)` for inline math and `\[` and `\]` for math blocks. 37 | block-delimiter = { left = "\\[", right = "\\]" } 38 | inline-delimiter = { left = "\\(", right = "\\)" } 39 | 40 | [preprocessor.gettext] 41 | after = ["links"] 42 | 43 | [preprocessor.templates] 44 | command = "mdbook-templates" 45 | path = "docs/book/assets/operators.json" 46 | 47 | [preprocessor.tabs] 48 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | allow-unwrap-in-tests = true 2 | -------------------------------------------------------------------------------- /contracts/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useModuleLabel": true, 3 | "autoGroupImports": "package" 4 | } 5 | -------------------------------------------------------------------------------- /contracts/README.md: -------------------------------------------------------------------------------- 1 | # Contracts Development 2 | 3 | This directory contains the contracts that are currently under development. The `VERSION` in 4 | the contracts sources (`walrus/sources/staking.move`, `walrus/sources/system.move`, 5 | `subsidies/sources/subsidies.move`) must be `1` more than the values in `testnet-contracts`. 6 | The `mainnet-contracts` directory contains the contracts currently deployed on Mainnet, 7 | whereas `testnet-contracts` contains the contracts deployed on Testnet. 8 | -------------------------------------------------------------------------------- /contracts/subsidies/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "FDB57BEED108EE7FC9A42405078A5EE89943E3567ED410E8EC005F588D9F35C9" 6 | deps_digest = "060AD7E57DFB13104F21BE5F5C3759D03F0553FC3229247D9A7A6B45F50D03A3" 7 | dependencies = [ 8 | { id = "Sui", name = "Sui" }, 9 | { id = "WAL", name = "WAL" }, 10 | { id = "Walrus", name = "Walrus" }, 11 | ] 12 | 13 | [[move.package]] 14 | id = "MoveStdlib" 15 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.49.1", subdir = "crates/sui-framework/packages/move-stdlib" } 16 | 17 | [[move.package]] 18 | id = "Sui" 19 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.49.1", subdir = "crates/sui-framework/packages/sui-framework" } 20 | 21 | dependencies = [ 22 | { id = "MoveStdlib", name = "MoveStdlib" }, 23 | ] 24 | 25 | [[move.package]] 26 | id = "WAL" 27 | source = { local = "../wal" } 28 | 29 | dependencies = [ 30 | { id = "Sui", name = "Sui" }, 31 | ] 32 | 33 | [[move.package]] 34 | id = "Walrus" 35 | source = { local = "../walrus" } 36 | 37 | dependencies = [ 38 | { id = "Sui", name = "Sui" }, 39 | { id = "WAL", name = "WAL" }, 40 | ] 41 | 42 | [move.toolchain-version] 43 | compiler-version = "1.49.1" 44 | edition = "2024.beta" 45 | flavor = "sui" 46 | 47 | [env] 48 | 49 | [env.mainnet] 50 | chain-id = "35834a8a" 51 | original-published-id = "0xd843c37d213ea683ec3519abe4646fd618f52d7fce1c4e9875a4144d53e21ebc" 52 | latest-published-id = "0xd843c37d213ea683ec3519abe4646fd618f52d7fce1c4e9875a4144d53e21ebc" 53 | published-version = "1" 54 | -------------------------------------------------------------------------------- /contracts/subsidies/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "Subsidies" 3 | license = "Apache-2.0" 4 | authors = ["Mysten Labs "] 5 | edition = "2024.beta" 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "testnet-v1.49.1" } 9 | WAL = { local = "../wal" } 10 | Walrus = { local = "../walrus" } 11 | 12 | [addresses] 13 | subsidies = "0x0" 14 | -------------------------------------------------------------------------------- /contracts/wal/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "51CB714557C4E8C9F741CAFF9C078A8BEFF7782BBEBDC46DFF34743EE0F81B20" 6 | deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082" 7 | dependencies = [ 8 | { id = "Sui", name = "Sui" }, 9 | ] 10 | 11 | [[move.package]] 12 | id = "MoveStdlib" 13 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.49.1", subdir = "crates/sui-framework/packages/move-stdlib" } 14 | 15 | [[move.package]] 16 | id = "Sui" 17 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.49.1", subdir = "crates/sui-framework/packages/sui-framework" } 18 | 19 | dependencies = [ 20 | { id = "MoveStdlib", name = "MoveStdlib" }, 21 | ] 22 | 23 | [move.toolchain-version] 24 | compiler-version = "1.49.1" 25 | edition = "2024.beta" 26 | flavor = "sui" 27 | 28 | [env.mainnet] 29 | chain-id = "35834a8a" 30 | original-published-id = "0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59" 31 | latest-published-id = "0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59" 32 | published-version = "1" 33 | -------------------------------------------------------------------------------- /contracts/wal/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "WAL" 3 | license = "Apache-2.0" 4 | authors = ["Mysten Labs "] 5 | edition = "2024.beta" 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "testnet-v1.49.1" } 9 | 10 | [addresses] 11 | wal = "0x0" 12 | -------------------------------------------------------------------------------- /contracts/wal_exchange/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "80A026835683A6C1D4F7E24881BA4748E8519E576E168876CF8148F72AD8C762" 6 | deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" 7 | dependencies = [ 8 | { id = "Sui", name = "Sui" }, 9 | { id = "WAL", name = "WAL" }, 10 | ] 11 | 12 | [[move.package]] 13 | id = "MoveStdlib" 14 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.49.1", subdir = "crates/sui-framework/packages/move-stdlib" } 15 | 16 | [[move.package]] 17 | id = "Sui" 18 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.49.1", subdir = "crates/sui-framework/packages/sui-framework" } 19 | 20 | dependencies = [ 21 | { id = "MoveStdlib", name = "MoveStdlib" }, 22 | ] 23 | 24 | [[move.package]] 25 | id = "WAL" 26 | source = { local = "../wal" } 27 | 28 | dependencies = [ 29 | { id = "Sui", name = "Sui" }, 30 | ] 31 | 32 | [move.toolchain-version] 33 | compiler-version = "1.49.1" 34 | edition = "2024.beta" 35 | flavor = "sui" 36 | -------------------------------------------------------------------------------- /contracts/wal_exchange/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "WAL_exchange" 3 | license = "Apache-2.0" 4 | authors = ["Mysten Labs "] 5 | edition = "2024.beta" 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "testnet-v1.49.1" } 9 | WAL = { local = "../wal" } 10 | 11 | [addresses] 12 | wal_exchange = "0x0" 13 | -------------------------------------------------------------------------------- /contracts/walrus/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "BB08DBA0DA9A723E04427642B78C97A7F0921CE453ED0E142EC982B2D2906B48" 6 | deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" 7 | dependencies = [ 8 | { id = "Sui", name = "Sui" }, 9 | { id = "WAL", name = "WAL" }, 10 | ] 11 | 12 | [[move.package]] 13 | id = "MoveStdlib" 14 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.49.1", subdir = "crates/sui-framework/packages/move-stdlib" } 15 | 16 | [[move.package]] 17 | id = "Sui" 18 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.49.1", subdir = "crates/sui-framework/packages/sui-framework" } 19 | 20 | dependencies = [ 21 | { id = "MoveStdlib", name = "MoveStdlib" }, 22 | ] 23 | 24 | [[move.package]] 25 | id = "WAL" 26 | source = { local = "../wal" } 27 | 28 | dependencies = [ 29 | { id = "Sui", name = "Sui" }, 30 | ] 31 | 32 | [move.toolchain-version] 33 | compiler-version = "1.49.1" 34 | edition = "2024.beta" 35 | flavor = "sui" 36 | 37 | [env] 38 | 39 | [env.mainnet] 40 | chain-id = "35834a8a" 41 | original-published-id = "0xfdc88f7d7cf30afab2f82e8380d11ee8f70efb90e863d1de8616fae1bb09ea77" 42 | latest-published-id = "0xfdc88f7d7cf30afab2f82e8380d11ee8f70efb90e863d1de8616fae1bb09ea77" 43 | published-version = "1" 44 | -------------------------------------------------------------------------------- /contracts/walrus/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "Walrus" 3 | license = "Apache-2.0" 4 | authors = ["Mysten Labs "] 5 | edition = "2024.beta" 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "testnet-v1.49.1" } 9 | WAL = { local = "../wal" } 10 | 11 | [addresses] 12 | walrus = "0x0" 13 | -------------------------------------------------------------------------------- /contracts/walrus/sources/staking/auth.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::auth; 5 | 6 | /// Authentication for either a sender or an object. 7 | /// Unlike the `Authorized` type, it cannot be stored and must be used or ignored in the same 8 | /// transaction. 9 | public enum Authenticated has drop { 10 | Sender(address), 11 | Object(ID), 12 | } 13 | 14 | /// Defines the ways to authorize an action. It can be either an address - checked 15 | /// with `ctx.sender()`, - or an object - checked with `object::id(..)`. 16 | public enum Authorized has copy, drop, store { 17 | Address(address), 18 | ObjectID(ID), 19 | } 20 | 21 | /// Authenticates the sender as the authorizer. 22 | public fun authenticate_sender(ctx: &TxContext): Authenticated { 23 | Authenticated::Sender(ctx.sender()) 24 | } 25 | 26 | /// Authenticates an object as the authorizer. 27 | public fun authenticate_with_object(obj: &T): Authenticated { 28 | Authenticated::Object(object::id(obj)) 29 | } 30 | 31 | /// Returns the `Authorized` as an address. 32 | public fun authorized_address(addr: address): Authorized { 33 | Authorized::Address(addr) 34 | } 35 | 36 | /// Returns the `Authorized` as an object. 37 | public fun authorized_object(id: ID): Authorized { 38 | Authorized::ObjectID(id) 39 | } 40 | 41 | /// Checks if the authentication matches the authorization. 42 | public(package) fun matches(authenticated: &Authenticated, authorized: &Authorized): bool { 43 | match (authenticated) { 44 | Authenticated::Sender(sender) => { 45 | match (authorized) { 46 | Authorized::Address(addr) => sender == addr, 47 | _ => false, 48 | } 49 | }, 50 | Authenticated::Object(id) => { 51 | match (authorized) { 52 | Authorized::ObjectID(obj_id) => id == obj_id, 53 | _ => false, 54 | } 55 | }, 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /contracts/walrus/sources/staking/walrus_context.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Module: `walrus_context` 5 | /// 6 | /// Implements the `WalrusContext` struct which is used to store the current 7 | /// state of the system. Improves testing and readability of signatures by 8 | /// aggregating the parameters into a single struct. Context is used almost 9 | /// everywhere in the system, so it is important to have a single source of 10 | /// truth for the current state. 11 | module walrus::walrus_context; 12 | 13 | use sui::vec_map::VecMap; 14 | 15 | /// Represents the current values in the Walrus system. Helps avoid passing 16 | /// too many parameters to functions, and allows for easier testing. 17 | public struct WalrusContext has drop { 18 | /// Current Walrus epoch 19 | epoch: u32, 20 | /// Whether the committee has been selected for the next epoch. 21 | committee_selected: bool, 22 | /// The current committee in the system. 23 | committee: VecMap>, 24 | } 25 | 26 | /// Create a new `WalrusContext` object. 27 | public(package) fun new( 28 | epoch: u32, 29 | committee_selected: bool, 30 | committee: VecMap>, 31 | ): WalrusContext { 32 | WalrusContext { epoch, committee_selected, committee } 33 | } 34 | 35 | /// Read the current `epoch` from the context. 36 | public(package) fun epoch(self: &WalrusContext): u32 { self.epoch } 37 | 38 | /// Read the current `committee_selected` from the context. 39 | public(package) fun committee_selected(self: &WalrusContext): bool { self.committee_selected } 40 | 41 | /// Read the current `committee` from the context. 42 | public(package) fun committee(self: &WalrusContext): &VecMap> { &self.committee } 43 | -------------------------------------------------------------------------------- /contracts/walrus/sources/system/encoding.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::encoding; 5 | 6 | use walrus::redstuff; 7 | 8 | // Supported Encoding Types 9 | // RedStuff with Reed-Solomon 10 | const RS2: u8 = 1; 11 | 12 | // Error codes 13 | // Error types in `walrus-sui/types/move_errors.rs` are auto-generated from the Move error codes. 14 | /// The encoding type is invalid. 15 | const EInvalidEncodingType: u64 = 0; 16 | 17 | /// Computes the encoded length of a blob given its unencoded length, encoding type 18 | /// and number of shards `n_shards`. 19 | public fun encoded_blob_length(unencoded_length: u64, encoding_type: u8, n_shards: u16): u64 { 20 | // Currently only supports the two RedStuff variants. 21 | assert!(encoding_type == RS2, EInvalidEncodingType); 22 | redstuff::encoded_blob_length(unencoded_length, n_shards) 23 | } 24 | -------------------------------------------------------------------------------- /contracts/walrus/sources/system/epoch_parameters.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::epoch_parameters; 5 | 6 | /// The epoch parameters for the system. 7 | public struct EpochParams has copy, drop, store { 8 | /// The storage capacity of the system. 9 | total_capacity_size: u64, 10 | /// The price per unit size of storage. 11 | storage_price_per_unit_size: u64, 12 | /// The write price per unit size. 13 | write_price_per_unit_size: u64, 14 | } 15 | 16 | // === Constructor === 17 | 18 | public(package) fun new( 19 | total_capacity_size: u64, 20 | storage_price_per_unit_size: u64, 21 | write_price_per_unit_size: u64, 22 | ): EpochParams { 23 | EpochParams { 24 | total_capacity_size, 25 | storage_price_per_unit_size, 26 | write_price_per_unit_size, 27 | } 28 | } 29 | 30 | // === Accessors === 31 | 32 | /// The storage capacity of the system. 33 | public(package) fun capacity(self: &EpochParams): u64 { 34 | self.total_capacity_size 35 | } 36 | 37 | /// The price per unit size of storage. 38 | public(package) fun storage_price(self: &EpochParams): u64 { 39 | self.storage_price_per_unit_size 40 | } 41 | 42 | /// The write price per unit size. 43 | public(package) fun write_price(self: &EpochParams): u64 { 44 | self.write_price_per_unit_size 45 | } 46 | 47 | // === Test only === 48 | 49 | #[test_only] 50 | public fun epoch_params_for_testing(): EpochParams { 51 | EpochParams { 52 | total_capacity_size: 1_000_000_000, 53 | storage_price_per_unit_size: 5, 54 | write_price_per_unit_size: 1, 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /contracts/walrus/sources/system/metadata.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Contains the metadata for Blobs on Walrus. 5 | module walrus::metadata; 6 | 7 | use std::string::String; 8 | use sui::vec_map::{Self, VecMap}; 9 | 10 | /// The metadata struct for Blob objects. 11 | public struct Metadata has drop, store { 12 | metadata: VecMap, 13 | } 14 | 15 | /// Creates a new instance of Metadata. 16 | public fun new(): Metadata { 17 | Metadata { 18 | metadata: vec_map::empty(), 19 | } 20 | } 21 | 22 | /// Inserts a key-value pair into the metadata. 23 | /// 24 | /// If the key is already present, the value is updated. 25 | public fun insert_or_update(self: &mut Metadata, key: String, value: String) { 26 | if (self.metadata.contains(&key)) { 27 | self.metadata.remove(&key); 28 | }; 29 | self.metadata.insert(key, value); 30 | } 31 | 32 | /// Removes the metadata associated with the given key. 33 | public fun remove(self: &mut Metadata, key: &String): (String, String) { 34 | self.metadata.remove(key) 35 | } 36 | 37 | /// Removes the metadata associated with the given key, if it exists. 38 | /// 39 | /// Optionally returns the previous value associated with the key. 40 | public fun remove_if_exists(self: &mut Metadata, key: &String): option::Option { 41 | if (self.metadata.contains(key)) { 42 | let (_, value) = self.metadata.remove(key); 43 | option::some(value) 44 | } else { 45 | option::none() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/walrus/sources/system/shared_blob.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::shared_blob; 5 | 6 | use sui::{balance::{Self, Balance}, coin::Coin}; 7 | use wal::wal::WAL; 8 | use walrus::{blob::Blob, system::System}; 9 | 10 | /// A wrapper around `Blob` that acts as a "tip jar" that can be funded by anyone and allows 11 | /// keeping the wrapped `Blob` alive indefinitely. 12 | public struct SharedBlob has key, store { 13 | id: UID, 14 | blob: Blob, 15 | funds: Balance, 16 | } 17 | 18 | /// Shares the provided `blob` as a `SharedBlob` with zero funds. 19 | public fun new(blob: Blob, ctx: &mut TxContext) { 20 | transfer::share_object(SharedBlob { 21 | id: object::new(ctx), 22 | blob, 23 | funds: balance::zero(), 24 | }) 25 | } 26 | 27 | /// Shares the provided `blob` as a `SharedBlob` with funds. 28 | public fun new_funded(blob: Blob, funds: Coin, ctx: &mut TxContext) { 29 | transfer::share_object(SharedBlob { 30 | id: object::new(ctx), 31 | blob, 32 | funds: funds.into_balance(), 33 | }) 34 | } 35 | 36 | /// Adds the provided `Coin` to the stored funds. 37 | public fun fund(self: &mut SharedBlob, added_funds: Coin) { 38 | self.funds.join(added_funds.into_balance()); 39 | } 40 | 41 | /// Extends the lifetime of the wrapped `Blob` by `extended_epochs` epochs if the stored funds are 42 | /// sufficient and the new lifetime does not exceed the maximum lifetime. 43 | public fun extend( 44 | self: &mut SharedBlob, 45 | system: &mut System, 46 | extended_epochs: u32, 47 | ctx: &mut TxContext, 48 | ) { 49 | let mut coin = self.funds.withdraw_all().into_coin(ctx); 50 | system.extend_blob(&mut self.blob, extended_epochs, &mut coin); 51 | self.funds.join(coin.into_balance()); 52 | } 53 | 54 | /// Returns a reference to the wrapped `Blob`. 55 | public fun blob(self: &SharedBlob): &Blob { 56 | &self.blob 57 | } 58 | 59 | /// Returns the balance of funds stored in the `SharedBlob`. 60 | public fun funds(self: &SharedBlob): &Balance { 61 | &self.funds 62 | } 63 | -------------------------------------------------------------------------------- /contracts/walrus/sources/utils/extended_field.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Module: extended_field 5 | module walrus::extended_field; 6 | 7 | use sui::dynamic_field as df; 8 | 9 | /// Extended field acts as a field, but stored in a dynamic field, hence, it does 10 | /// not bloat the original object's storage, storing only `UID` of the extended 11 | /// field. 12 | public struct ExtendedField has key, store { id: UID } 13 | 14 | /// Key to store the value in the extended field. Never changes. 15 | public struct Key() has copy, drop, store; 16 | 17 | /// Creates a new extended field with the given value. 18 | public fun new(value: T, ctx: &mut TxContext): ExtendedField { 19 | let mut id = object::new(ctx); 20 | df::add(&mut id, Key(), value); 21 | ExtendedField { id } 22 | } 23 | 24 | /// Borrows the value stored in the extended field. 25 | public fun borrow(field: &ExtendedField): &T { 26 | df::borrow(&field.id, Key()) 27 | } 28 | 29 | /// Borrows the value stored in the extended field mutably. 30 | public fun borrow_mut(field: &mut ExtendedField): &mut T { 31 | df::borrow_mut(&mut field.id, Key()) 32 | } 33 | 34 | /// Swaps the value stored in the extended field with the given value. 35 | public fun swap(field: &mut ExtendedField, value: T): T { 36 | let old = df::remove(&mut field.id, Key()); 37 | df::add(&mut field.id, Key(), value); 38 | old 39 | } 40 | 41 | /// Destroys the extended field and returns the value stored in it. 42 | public fun destroy(field: ExtendedField): T { 43 | let ExtendedField { mut id } = field; 44 | let value = df::remove(&mut id, Key()); 45 | id.delete(); 46 | value 47 | } 48 | -------------------------------------------------------------------------------- /contracts/walrus/sources/utils/sort.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Implements sorting macros for commonly used data structures. 5 | module walrus::sort; 6 | 7 | use sui::vec_map::{Self, VecMap}; 8 | 9 | /// Sort the given `VecMap` by the node ID transformed into `u256`. 10 | /// 11 | /// Uses the insertion sort algorithm, given that the `VecMap` is already mostly sorted. 12 | public macro fun sort_vec_map_by_node_id<$V>($self: VecMap): VecMap { 13 | let self = $self; 14 | 15 | if (self.size() <= 1) return self; 16 | let (mut keys, mut values) = self.into_keys_values(); 17 | let len = keys.length(); 18 | let mut i = 1; 19 | 20 | while (i < len) { 21 | let mut j = i; 22 | while (j > 0 && keys[j - 1].to_address().to_u256() > keys[j].to_address().to_u256()) { 23 | keys.swap(j - 1, j); 24 | values.swap(j - 1, j); 25 | j = j - 1; 26 | }; 27 | i = i + 1; 28 | }; 29 | 30 | vec_map::from_keys_values(keys, values) 31 | } 32 | 33 | /// Check if the given `VecMap` is sorted by the node ID transformed into `u256`. 34 | public macro fun is_vec_map_sorted_by_node_id<$V>($self: &VecMap): bool { 35 | let self = $self; 36 | 37 | let len = self.size(); 38 | if (len <= 1) return true; 39 | let mut i = 1; 40 | while (i < len) { 41 | let (lhs, _) = self.get_entry_by_idx(i - 1); 42 | let (rhs, _) = self.get_entry_by_idx(i); 43 | if (lhs.to_address().to_u256() > rhs.to_address().to_u256()) { 44 | return false 45 | }; 46 | i = i + 1; 47 | }; 48 | 49 | true 50 | } 51 | -------------------------------------------------------------------------------- /contracts/walrus/tests/staking/walrus_context_tests.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::walrus_context_tests; 5 | 6 | use sui::vec_map; 7 | use walrus::walrus_context; 8 | 9 | #[test] 10 | // Scenario: Test the WalrusContext flow 11 | fun test_walrus_context_flow() { 12 | let walrus_ctx = walrus_context::new(1, true, vec_map::empty()); 13 | 14 | // assert that the WalrusContext is created correctly 15 | assert!(walrus_ctx.epoch() == 1); 16 | assert!(walrus_ctx.committee_selected() == true); 17 | } 18 | -------------------------------------------------------------------------------- /contracts/walrus/tests/system/metadata_tests.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #[test_only] 5 | module walrus::metadata_tests; 6 | 7 | use sui::vec_map::EKeyDoesNotExist; 8 | use walrus::metadata; 9 | 10 | #[test] 11 | public fun test_metadata_success() { 12 | let mut metadata = metadata::new(); 13 | metadata.insert_or_update(b"key1".to_string(), b"value1".to_string()); 14 | metadata.insert_or_update(b"key2".to_string(), b"value2".to_string()); 15 | // Update the value corresponding to key1. 16 | metadata.insert_or_update(b"key1".to_string(), b"value3".to_string()); 17 | let (key, value) = metadata.remove(&b"key1".to_string()); 18 | assert!(key == b"key1".to_string()); 19 | assert!(value == b"value3".to_string()); 20 | } 21 | 22 | #[test, expected_failure(abort_code = EKeyDoesNotExist)] 23 | public fun test_metadata_failure() { 24 | let mut metadata = metadata::new(); 25 | metadata.insert_or_update(b"key1".to_string(), b"value1".to_string()); 26 | metadata.remove(&b"key2".to_string()); 27 | } 28 | -------------------------------------------------------------------------------- /contracts/walrus/tests/system/ringbuffer_tests.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #[test_only] 5 | module walrus::ringbuffer_tests; 6 | 7 | use sui::test_utils::destroy; 8 | use walrus::storage_accounting::{Self as sa, FutureAccountingRingBuffer}; 9 | 10 | #[test] 11 | public fun test_basic_ring_buffer() { 12 | let mut buffer: FutureAccountingRingBuffer = sa::ring_new(3); 13 | 14 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 0)) == 0, 100); 15 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 1)) == 1, 100); 16 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 2)) == 2, 100); 17 | 18 | let entry = sa::ring_pop_expand(&mut buffer); 19 | assert!(sa::epoch(&entry) == 0, 100); 20 | sa::delete_empty_future_accounting(entry); 21 | 22 | let entry = sa::ring_pop_expand(&mut buffer); 23 | assert!(sa::epoch(&entry) == 1, 100); 24 | sa::delete_empty_future_accounting(entry); 25 | 26 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 0)) == 2, 100); 27 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 1)) == 3, 100); 28 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 2)) == 4, 100); 29 | 30 | destroy(buffer) 31 | } 32 | 33 | #[test, expected_failure(abort_code = sa::ETooFarInFuture)] 34 | public fun test_oob_fail_ring_buffer() { 35 | let mut buffer: FutureAccountingRingBuffer = sa::ring_new(3); 36 | 37 | sa::epoch(sa::ring_lookup_mut(&mut buffer, 3)); 38 | 39 | abort 40 | } 41 | -------------------------------------------------------------------------------- /crates/checkpoint-downloader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "checkpoint-downloader" 3 | publish = false 4 | authors.workspace = true 5 | version.workspace = true 6 | edition.workspace = true 7 | license.workspace = true 8 | 9 | [dependencies] 10 | anyhow.workspace = true 11 | async-channel.workspace = true 12 | mysten-metrics.workspace = true 13 | prometheus.workspace = true 14 | rand.workspace = true 15 | serde = { workspace = true, features = ["derive"] } 16 | serde_with.workspace = true 17 | sui-macros.workspace = true 18 | sui-rpc-api.workspace = true 19 | sui-types.workspace = true 20 | telemetry-subscribers.workspace = true 21 | tokio = { workspace = true, features = ["full"] } 22 | tokio-util.workspace = true 23 | tracing.workspace = true 24 | typed-store.workspace = true 25 | walrus-sui.workspace = true 26 | walrus-utils = { workspace = true, features = ["backoff", "log"] } 27 | 28 | [lints] 29 | workspace = true 30 | 31 | [dev-dependencies] 32 | rocksdb.workspace = true 33 | tempfile.workspace = true 34 | -------------------------------------------------------------------------------- /crates/checkpoint-downloader/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Checkpoint downloader for parallel downloading of checkpoints. 5 | //! 6 | //! This crate provides functionality for downloading checkpoints in parallel with adaptive worker 7 | //! scaling. 8 | 9 | mod config; 10 | mod downloader; 11 | mod metrics; 12 | mod types; 13 | 14 | pub use config::{AdaptiveDownloaderConfig, ChannelConfig, ParallelDownloaderConfig}; 15 | pub use downloader::ParallelCheckpointDownloader; 16 | pub use types::CheckpointEntry; 17 | -------------------------------------------------------------------------------- /crates/checkpoint-downloader/src/metrics.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Metrics for the checkpoint downloader. 5 | 6 | use prometheus::{IntGauge, register_int_gauge_with_registry}; 7 | use walrus_utils::metrics::Registry; 8 | 9 | #[derive(Clone, Debug)] 10 | pub(crate) struct AdaptiveDownloaderMetrics { 11 | /// The number of checkpoint downloader workers. 12 | pub num_workers: IntGauge, 13 | /// The current checkpoint lag between the local store and the full node. 14 | pub checkpoint_lag: IntGauge, 15 | } 16 | 17 | impl AdaptiveDownloaderMetrics { 18 | pub fn new(registry: &Registry) -> Self { 19 | Self { 20 | num_workers: register_int_gauge_with_registry!( 21 | "checkpoint_downloader_num_workers", 22 | "Number of workers active in the worker pool", 23 | registry, 24 | ) 25 | .expect("this is a valid metrics registration"), 26 | checkpoint_lag: register_int_gauge_with_registry!( 27 | "checkpoint_downloader_checkpoint_lag", 28 | "Current checkpoint lag between local store and full node", 29 | registry, 30 | ) 31 | .expect("this is a valid metrics registration"), 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /crates/checkpoint-downloader/src/types.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Types for the checkpoint downloader. 5 | 6 | use anyhow::Result; 7 | use sui_types::{ 8 | full_checkpoint_content::CheckpointData, 9 | messages_checkpoint::CheckpointSequenceNumber, 10 | }; 11 | use tokio::sync::mpsc; 12 | 13 | /// Worker message types. 14 | pub(crate) enum WorkerMessage { 15 | /// Download a checkpoint with the given sequence number. 16 | Download(CheckpointSequenceNumber), 17 | /// Shutdown the worker. 18 | Shutdown, 19 | } 20 | 21 | /// Entry in the checkpoint fetcher queue. 22 | #[derive(Debug)] 23 | pub struct CheckpointEntry { 24 | /// The sequence number of the checkpoint. 25 | pub sequence_number: u64, 26 | /// The result of the checkpoint download. 27 | pub result: Result, 28 | } 29 | 30 | impl CheckpointEntry { 31 | /// Creates a new checkpoint entry. 32 | pub fn new(sequence_number: u64, result: Result) -> Self { 33 | Self { 34 | sequence_number, 35 | result, 36 | } 37 | } 38 | } 39 | 40 | /// Channels for the pool monitor. 41 | #[derive(Clone)] 42 | pub(crate) struct PoolMonitorChannels { 43 | pub(crate) message_sender: async_channel::Sender, 44 | pub(crate) message_receiver: async_channel::Receiver, 45 | pub(crate) checkpoint_sender: mpsc::Sender, 46 | } 47 | -------------------------------------------------------------------------------- /crates/typed-store/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "typed-store" 3 | publish = false 4 | authors.workspace = true 5 | version.workspace = true 6 | edition.workspace = true 7 | license.workspace = true 8 | 9 | [dependencies] 10 | async-trait.workspace = true 11 | bcs.workspace = true 12 | bincode.workspace = true 13 | collectable.workspace = true 14 | eyre.workspace = true 15 | fdlimit.workspace = true 16 | hdrhistogram.workspace = true 17 | itertools.workspace = true 18 | once_cell.workspace = true 19 | prometheus.workspace = true 20 | rand.workspace = true 21 | rocksdb = { version = "0.22.0", default-features = false, features = ["lz4", "multi-threaded-cf", "snappy", "zlib", "zstd"] } 22 | serde.workspace = true 23 | sui-macros.workspace = true 24 | tap.workspace = true 25 | thiserror.workspace = true 26 | tokio = { workspace = true, features = ["full", "test-util"] } 27 | tracing.workspace = true 28 | 29 | [dev-dependencies] 30 | once_cell.workspace = true 31 | rand.workspace = true 32 | rstest.workspace = true 33 | tempfile.workspace = true 34 | uint.workspace = true 35 | 36 | [target.'cfg(msim)'.dependencies] 37 | sui-simulator.workspace = true 38 | 39 | [lints] 40 | workspace = true 41 | -------------------------------------------------------------------------------- /crates/typed-store/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! A type-safe wrapper around RocksDB that provides a key-value store interface. 5 | //! This crate provides functionality for storing and retrieving typed data in RocksDB, 6 | //! with support for column families, batch operations, and metrics. 7 | 8 | // TODO(WAL-869): Remove this attribute and fix corresponding warnings. 9 | #![allow( 10 | clippy::cast_possible_truncation, 11 | clippy::cast_possible_wrap, 12 | clippy::unwrap_used 13 | )] 14 | #![warn(rust_2018_idioms)] 15 | 16 | /// Re-export rocksdb so that consumers can use the version of rocksdb via typed-store 17 | pub use rocksdb; 18 | 19 | /// The rocksdb database 20 | pub mod rocks; 21 | 22 | /// The traits for the typed store 23 | pub mod traits; 24 | 25 | /// The error type for the typed store 26 | pub use rocks::errors::TypedStoreError; 27 | /// The traits for the typed store 28 | pub use traits::Map; 29 | 30 | /// The metrics for the typed store 31 | pub mod metrics; 32 | pub use metrics::DBMetrics; 33 | -------------------------------------------------------------------------------- /crates/walrus-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walrus-core" 3 | publish = false 4 | authors.workspace = true 5 | version.workspace = true 6 | edition.workspace = true 7 | license.workspace = true 8 | 9 | [features] 10 | sui-types = ["dep:sui-types"] 11 | test-utils = ["walrus-test-utils"] 12 | 13 | [dependencies] 14 | base64.workspace = true 15 | bcs.workspace = true 16 | enum_dispatch = { workspace = true } 17 | fastcrypto.workspace = true 18 | hex.workspace = true 19 | p256 = { workspace = true, features = ["pem", "pkcs8"] } 20 | rand.workspace = true 21 | reed-solomon-simd.workspace = true 22 | serde.workspace = true 23 | serde_with.workspace = true 24 | sui-types = { workspace = true, optional = true } 25 | thiserror.workspace = true 26 | tracing.workspace = true 27 | utoipa = { workspace = true, optional = true } 28 | walrus-test-utils = { workspace = true, optional = true } 29 | 30 | [dev-dependencies] 31 | anyhow.workspace = true 32 | criterion.workspace = true 33 | serde_test.workspace = true 34 | tracing-subscriber.workspace = true 35 | walrus-test-utils.workspace = true 36 | 37 | [lints] 38 | workspace = true 39 | 40 | [lib] 41 | bench = false 42 | 43 | [[bench]] 44 | name = "basic_encoding" 45 | harness = false 46 | 47 | [[bench]] 48 | name = "blob_encoding" 49 | harness = false 50 | -------------------------------------------------------------------------------- /crates/walrus-core/src/bft.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Definitions and computations related to Byzantine fault tolerance (BFT). 5 | 6 | use core::num::NonZeroU16; 7 | 8 | /// Returns the maximum number of faulty/Byzantine failures in a BFT system with `n` components. 9 | /// 10 | /// This number is often called `f` and must be strictly less than `n as f64 / 3.0`. 11 | #[inline] 12 | pub fn max_n_faulty(n: NonZeroU16) -> u16 { 13 | (n.get() - 1) / 3 14 | } 15 | 16 | /// Returns the minimum number of correct (non-faulty) instances in a BFT system with `n` 17 | /// components. 18 | /// 19 | /// If `n == 3f + 1`, then this is equal to `2f + 1`. In other cases, this can be slightly higher. 20 | #[inline] 21 | pub fn min_n_correct(n: NonZeroU16) -> NonZeroU16 { 22 | (n.get() - max_n_faulty(n)) 23 | .try_into() 24 | .expect("max_n_faulty < n") 25 | } 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | use walrus_test_utils::param_test; 30 | 31 | use super::*; 32 | 33 | param_test! { 34 | test_bft_computations: [ 35 | one: (1, 0, 1), 36 | three: (3, 0, 3), 37 | four: (4, 1, 3), 38 | five: (5, 1, 4), 39 | six: (6, 1, 5), 40 | hundred: (100, 33, 67), 41 | multiple_of_three: (300, 99, 201), 42 | ] 43 | } 44 | fn test_bft_computations( 45 | n_shards: u16, 46 | expected_max_n_faulty: u16, 47 | expected_min_n_correct: u16, 48 | ) { 49 | let nonzero_n_shards = n_shards.try_into().unwrap(); 50 | let actual_max_n_faulty = max_n_faulty(nonzero_n_shards); 51 | let actual_min_n_correct = min_n_correct(nonzero_n_shards); 52 | assert_eq!(actual_max_n_faulty, expected_max_n_faulty); 53 | assert_eq!( 54 | actual_min_n_correct, 55 | expected_min_n_correct.try_into().unwrap() 56 | ); 57 | assert!(3 * actual_max_n_faulty < n_shards); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /crates/walrus-core/src/encoding.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Blob encoding functionality, using the RedStuff algorithm. 5 | 6 | // TODO(giac): Link or import the `../../../docs/red-stuff.md` documentation here (#307). 7 | 8 | mod basic_encoding; 9 | pub use basic_encoding::{Decoder, ReedSolomonDecoder, ReedSolomonEncoder}; 10 | 11 | mod blob_encoding; 12 | pub use blob_encoding::{BlobDecoder, BlobDecoderEnum, BlobEncoder}; 13 | 14 | mod quilt_encoding; 15 | pub use quilt_encoding::{QuiltDecoderV1, QuiltEncoderV1, QuiltV1}; 16 | 17 | mod common; 18 | pub use common::{EncodingAxis, Primary, Secondary}; 19 | 20 | mod config; 21 | pub use config::{ 22 | EncodingConfig, 23 | EncodingConfigEnum, 24 | EncodingConfigTrait, 25 | MAX_SOURCE_SYMBOLS, 26 | ReedSolomonEncodingConfig, 27 | encoded_blob_length_for_n_shards, 28 | encoded_slivers_length_for_n_shards, 29 | max_blob_size_for_n_shards, 30 | max_sliver_size_for_n_secondary, 31 | max_sliver_size_for_n_shards, 32 | metadata_length_for_n_shards, 33 | source_symbols_for_n_shards, 34 | }; 35 | 36 | mod errors; 37 | pub use errors::{ 38 | DataTooLargeError, 39 | DecodingVerificationError, 40 | EncodeError, 41 | InvalidDataSizeError, 42 | QuiltError, 43 | RecoverySymbolError, 44 | SliverRecoveryError, 45 | SliverRecoveryOrVerificationError, 46 | SliverVerificationError, 47 | SymbolVerificationError, 48 | WrongSliverVariantError, 49 | WrongSymbolSizeError, 50 | }; 51 | 52 | mod mapping; 53 | pub use mapping::{SliverAssignmentError, rotate_pairs, rotate_pairs_unchecked}; 54 | 55 | mod slivers; 56 | pub use slivers::{PrimarySliver, SecondarySliver, SliverData, SliverPair}; 57 | 58 | mod symbols; 59 | pub use symbols::{ 60 | DecodingSymbol, 61 | EitherDecodingSymbol, 62 | GeneralRecoverySymbol, 63 | PrimaryRecoverySymbol, 64 | RecoverySymbol, 65 | RecoverySymbolPair, 66 | SecondaryRecoverySymbol, 67 | Symbols, 68 | min_symbols_for_recovery, 69 | }; 70 | 71 | mod utils; 72 | -------------------------------------------------------------------------------- /crates/walrus-core/src/encoding/common.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use serde::{Deserialize, Serialize}; 5 | 6 | use crate::SliverType; 7 | 8 | /// Marker trait to indicate the encoding axis (primary or secondary). 9 | pub trait EncodingAxis: Clone + PartialEq + Eq + Default + core::fmt::Debug { 10 | /// The complementary encoding axis. 11 | type OrthogonalAxis: EncodingAxis; 12 | /// Whether this corresponds to the primary (true) or secondary (false) encoding. 13 | const IS_PRIMARY: bool; 14 | /// String representation of this type. 15 | const NAME: &'static str; 16 | 17 | /// The associated [`SliverType`]. 18 | fn sliver_type() -> SliverType { 19 | SliverType::for_encoding::() 20 | } 21 | } 22 | 23 | /// Marker type to indicate the primary encoding. 24 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)] 25 | pub struct Primary; 26 | impl EncodingAxis for Primary { 27 | type OrthogonalAxis = Secondary; 28 | const IS_PRIMARY: bool = true; 29 | const NAME: &'static str = "primary"; 30 | } 31 | 32 | /// Marker type to indicate the secondary encoding. 33 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)] 34 | pub struct Secondary; 35 | impl EncodingAxis for Secondary { 36 | type OrthogonalAxis = Primary; 37 | const IS_PRIMARY: bool = false; 38 | const NAME: &'static str = "secondary"; 39 | } 40 | -------------------------------------------------------------------------------- /crates/walrus-e2e-tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walrus-e2e-tests" 3 | publish = false 4 | authors.workspace = true 5 | version.workspace = true 6 | edition.workspace = true 7 | license.workspace = true 8 | 9 | [dev-dependencies] 10 | anyhow.workspace = true 11 | prometheus.workspace = true 12 | rand.workspace = true 13 | # explicitly import reqwest in test to disable its system proxy cache. It causes indeterminism in simtest. 14 | futures.workspace = true 15 | indicatif.workspace = true 16 | reqwest = { version = "0.12.12", default-features = false, features = ["__internal_proxy_sys_no_cache", "http2", "json", "rustls-tls"] } 17 | serde_yaml.workspace = true 18 | sui-macros.workspace = true 19 | sui-protocol-config.workspace = true 20 | sui-simulator.workspace = true 21 | sui-types.workspace = true 22 | telemetry-subscribers.workspace = true 23 | tempfile.workspace = true 24 | tokio.workspace = true 25 | tokio-stream.workspace = true 26 | tracing.workspace = true 27 | tracing-subscriber.workspace = true 28 | walrus-core.workspace = true 29 | walrus-proc-macros = { workspace = true, features = ["walrus-simtest"] } 30 | walrus-sdk = { workspace = true, features = ["test-utils"] } 31 | walrus-service = { workspace = true, features = ["test-utils"] } 32 | walrus-storage-node-client.workspace = true 33 | walrus-sui.workspace = true 34 | walrus-test-utils.workspace = true 35 | walrus-utils.workspace = true 36 | 37 | [lints] 38 | workspace = true 39 | -------------------------------------------------------------------------------- /crates/walrus-orchestrator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walrus-orchestrator" 3 | publish = false 4 | version.workspace = true 5 | authors.workspace = true 6 | edition.workspace = true 7 | license.workspace = true 8 | 9 | [dependencies] 10 | aws-config = "1.5.18" 11 | aws-runtime = "1.5.7" 12 | aws-sdk-ec2 = "1.116.0" 13 | clap.workspace = true 14 | color-eyre = "0.6.5" 15 | crossterm = "0.29.0" 16 | eyre = "0.6.12" 17 | futures.workspace = true 18 | prettytable.workspace = true 19 | # TODO(alberto): Remove this dependency again (#284). 20 | prometheus-parse = { git = "https://github.com/asonnino/prometheus-parser", rev = "75334db" } 21 | reqwest.workspace = true 22 | serde.workspace = true 23 | serde_json.workspace = true 24 | serde_with.workspace = true 25 | serde_yaml.workspace = true 26 | ssh2 = "0.9.5" 27 | sui-sdk.workspace = true 28 | thiserror.workspace = true 29 | tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } 30 | walrus-core.workspace = true 31 | walrus-service = { workspace = true, features = ["deploy", "node"] } 32 | walrus-sui.workspace = true 33 | walrus-utils = { workspace = true, features = ["config"] } 34 | 35 | [dev-dependencies] 36 | tempfile.workspace = true 37 | 38 | [lints] 39 | workspace = true 40 | 41 | [[bin]] 42 | name = "walrus-orchestrator" 43 | path = "src/main.rs" 44 | -------------------------------------------------------------------------------- /crates/walrus-orchestrator/assets/settings-template.yaml: -------------------------------------------------------------------------------- 1 | testbed_id: "${USER}-walrus" 2 | cloud_provider: aws 3 | token_file: "/Users/${USER}/.aws/credentials" 4 | ssh_private_key_file: "/Users/${USER}/.ssh/aws" 5 | regions: 6 | - us-west-1 7 | specs: m5d.8xlarge 8 | repository: 9 | url: https://github.com/mystenlabs/walrus.git 10 | commit: main 11 | -------------------------------------------------------------------------------- /crates/walrus-orchestrator/src/logs.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use std::cmp::max; 5 | 6 | use crate::display; 7 | 8 | /// A simple log analyzer counting the number of errors and panics. 9 | #[derive(Default, PartialEq, Eq)] 10 | pub struct LogsAnalyzer { 11 | /// The number of errors in the nodes' log files. 12 | pub node_errors: usize, 13 | /// Whether a node panicked. 14 | pub node_panic: bool, 15 | /// The number of errors in the clients' log files. 16 | pub client_errors: usize, 17 | /// Whether a client panicked. 18 | pub client_panic: bool, 19 | } 20 | 21 | impl PartialOrd for LogsAnalyzer { 22 | fn partial_cmp(&self, other: &Self) -> Option { 23 | Some(self.cmp(other)) 24 | } 25 | } 26 | 27 | impl Ord for LogsAnalyzer { 28 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 29 | if self.node_panic 30 | || self.client_panic 31 | || self.client_errors > other.client_errors 32 | || self.node_errors > other.node_errors 33 | { 34 | std::cmp::Ordering::Greater 35 | } else { 36 | std::cmp::Ordering::Less 37 | } 38 | } 39 | } 40 | 41 | impl LogsAnalyzer { 42 | /// Deduce the number of clients errors from the logs. 43 | pub fn set_client_errors(&mut self, log: &str) { 44 | self.client_errors = max(self.client_errors, log.matches(" ERROR").count()); 45 | self.client_panic = log.contains("panic"); 46 | } 47 | 48 | /// Print a summary of the errors. 49 | pub fn print_summary(&self) { 50 | if self.node_panic { 51 | display::error("Node(s) panicked!"); 52 | } else if self.client_panic { 53 | display::error("Client(s) panicked!"); 54 | } else if self.node_errors != 0 || self.client_errors != 0 { 55 | display::newline(); 56 | display::warn(format!( 57 | "Logs contain errors (node: {}, client: {})", 58 | self.node_errors, self.client_errors 59 | )); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /crates/walrus-proc-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walrus-proc-macros" 3 | publish = false 4 | authors.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | version.workspace = true 8 | 9 | [features] 10 | default = [] 11 | derive-api-errors = [ 12 | "dep:darling", 13 | "dep:proc-macro2", 14 | ] 15 | walrus-simtest = [ 16 | "dep:sui-macros", 17 | ] 18 | 19 | [dependencies] 20 | darling = { version = "0.20.11", optional = true } 21 | proc-macro2 = { version = "1.0.95", optional = true } 22 | quote.workspace = true 23 | sui-macros = { workspace = true, optional = true } 24 | syn.workspace = true 25 | 26 | [lib] 27 | proc-macro = true 28 | 29 | [lints] 30 | workspace = true 31 | -------------------------------------------------------------------------------- /crates/walrus-proc-macros/src/walrus_simtest.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use proc_macro::TokenStream; 5 | use quote::quote; 6 | use syn::{ItemFn, Token, parse::Parser, parse_macro_input, punctuated::Punctuated}; 7 | 8 | pub fn attribute_macro(args: TokenStream, item: TokenStream) -> TokenStream { 9 | // Parse the input tokens into a syntax tree 10 | let input = parse_macro_input!(item as ItemFn); 11 | 12 | let arg_parser = Punctuated::::parse_terminated; 13 | let args = arg_parser 14 | .parse(args) 15 | .expect("should be able to parse arguments") 16 | .into_iter(); 17 | 18 | // If running simtests, add a "simtest_" prefix to the function name. 19 | let output = if cfg!(msim) { 20 | let mut input = input; 21 | let fn_name = &input.sig.ident; 22 | input.sig.ident = syn::Ident::new(&format!("simtest_{}", fn_name), fn_name.span()); 23 | quote! { 24 | #[sui_macros::sim_test(#(#args),*)] 25 | #input 26 | } 27 | } else { 28 | quote! { 29 | #[tokio::test(#(#args),*)] 30 | #input 31 | } 32 | }; 33 | 34 | // Return the final tokens 35 | TokenStream::from(output) 36 | } 37 | -------------------------------------------------------------------------------- /crates/walrus-proxy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walrus-proxy" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | publish = false 8 | 9 | [dependencies] 10 | anyhow.workspace = true 11 | axum.workspace = true 12 | axum-extra = { workspace = true, features = ["typed-header"] } 13 | base64.workspace = true 14 | bytes.workspace = true 15 | clap.workspace = true 16 | const-str = "0.6.2" 17 | fastcrypto.workspace = true 18 | futures.workspace = true 19 | git-version.workspace = true 20 | hyper.workspace = true 21 | itertools.workspace = true 22 | once_cell = "1.21.3" 23 | prometheus.workspace = true 24 | prost = "0.13" 25 | protobuf = { version = "2.28", features = ["with-bytes"] } 26 | rand.workspace = true 27 | reqwest.workspace = true 28 | serde.workspace = true 29 | serde_json.workspace = true 30 | serde_with.workspace = true 31 | serde_yaml.workspace = true 32 | snap.workspace = true 33 | sui-sdk.workspace = true 34 | sui-types.workspace = true 35 | tokio.workspace = true 36 | tower.workspace = true 37 | tower-http.workspace = true 38 | tracing.workspace = true 39 | tracing-subscriber.workspace = true 40 | uuid.workspace = true 41 | walrus-sui.workspace = true 42 | walrus-utils = { workspace = true, features = ["backoff", "metrics"] } 43 | 44 | 45 | [lints] 46 | workspace = true 47 | -------------------------------------------------------------------------------- /crates/walrus-proxy/src/fixtures/allowlist.yaml: -------------------------------------------------------------------------------- 1 | - name: Mysten Labs K8s 2 | network_address: uc1-tnt-sto-00.walrus-testnet.walrus.space:9185 3 | network_public_key: Ant1DDlh4WuwfvKdx9lzqoL0NeeUdThbN9F64EnA7oL6 4 | - name: Mysten Labs Baremetal 5 | network_address: mia-tnt-sto-00.walrus-testnet.walrus.space:9185 6 | network_public_key: Aj8JerPMpxcOypmtqrudZivZb70TpC18j0Og6vF7MlsE 7 | -------------------------------------------------------------------------------- /crates/walrus-proxy/src/fixtures/config.yaml: -------------------------------------------------------------------------------- 1 | labels: 2 | network: joenet 3 | listen-address: 127.0.0.1:8080 4 | remote-write: 5 | url: https://metrics-gw.testnet.walrus.space/api/v1/push 6 | username: incoming_metrics 7 | password: fooman 8 | dynamic-peers: 9 | url: https://fullnode.testnet.sui.io:443 10 | interval: 60 11 | system-object-id: 0x98ebc47370603fe81d9e15491b2f1443d619d1dab720d586e429ed233e1255c1 12 | staking-object-id: 0x20266a17b4f1a216727f3eef5772f8d486a9e3b5e319af80a5b75809c035561d 13 | allowlist-path: ./allowlist.yaml 14 | metrics-address: localhost:9184 15 | histogram-address: localhost:9185 16 | -------------------------------------------------------------------------------- /crates/walrus-proxy/src/providers.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// walrus specific provider implementation for nodes in committee 5 | mod walrus; 6 | 7 | // Re-export for easier access 8 | pub use crate::providers::walrus::{ 9 | provider::WalrusNodeProvider, 10 | query::{NodeInfo, get_walrus_nodes}, 11 | }; 12 | -------------------------------------------------------------------------------- /crates/walrus-proxy/src/providers/walrus.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// walrus node provider implementation 5 | pub(crate) mod provider; 6 | /// walrus to sui rpc queries to obtain committee information 7 | /// we use this to filter clients 8 | pub(crate) mod query; 9 | -------------------------------------------------------------------------------- /crates/walrus-sdk/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walrus-sdk" 3 | authors.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | version.workspace = true 7 | 8 | [features] 9 | test-utils = [ 10 | "dep:tempfile", 11 | ] 12 | 13 | [dependencies] 14 | anyhow.workspace = true 15 | bimap.workspace = true 16 | chrono.workspace = true 17 | enum_dispatch.workspace = true 18 | fastcrypto.workspace = true 19 | futures.workspace = true 20 | home.workspace = true 21 | humantime.workspace = true 22 | indexmap.workspace = true 23 | indicatif.workspace = true 24 | indoc.workspace = true 25 | itertools.workspace = true 26 | jsonwebtoken.workspace = true 27 | pin-project.workspace = true 28 | prometheus.workspace = true 29 | rand.workspace = true 30 | rayon.workspace = true 31 | reqwest.workspace = true 32 | rustls.workspace = true 33 | rustls-native-certs.workspace = true 34 | serde.workspace = true 35 | serde_with.workspace = true 36 | serde_yaml.workspace = true 37 | sui-sdk.workspace = true 38 | sui-types.workspace = true 39 | tempfile = { workspace = true, optional = true } 40 | thiserror.workspace = true 41 | tokio.workspace = true 42 | tokio-util.workspace = true 43 | tracing.workspace = true 44 | utoipa.workspace = true 45 | walrus-core = { workspace = true, features = ["sui-types", "utoipa"] } 46 | walrus-storage-node-client.workspace = true 47 | walrus-sui = { workspace = true, features = ["utoipa"] } 48 | walrus-test-utils.workspace = true 49 | walrus-utils = { workspace = true, features = ["log"] } 50 | 51 | [lints] 52 | workspace = true 53 | -------------------------------------------------------------------------------- /crates/walrus-sdk/client_config_example.yaml: -------------------------------------------------------------------------------- 1 | system_object: 0xa2637d13d171b278eadfa8a3fbe8379b5e471e1f3739092e5243da17fc8090eb 2 | staking_object: 0xca7cf321e47a1fc9bfd032abc31b253f5063521fd5b4c431f2cdd3fee1b4ec00 3 | subsidies_object: 0xa9b00f69d3b033e7b64acff2672b54fbb7c31361954251e235395dea8bd6dcac 4 | exchange_objects: 5 | - 0x26a8a417b553b18d13027c23e8016c3466b81e7083225436b55143c127f3c0cb 6 | - 0xaf3819c82de2e0257c0cc2177dfce6432efa42ca6c04c0b774dbb3c5ca2573cd 7 | wallet_config: null 8 | rpc_urls: 9 | - https://fullnode.testnet.sui.io:443 10 | communication_config: 11 | max_concurrent_writes: null 12 | max_concurrent_sliver_reads: null 13 | max_concurrent_metadata_reads: 3 14 | max_concurrent_status_reads: null 15 | max_data_in_flight: null 16 | reqwest_config: 17 | total_timeout_millis: 30000 18 | pool_idle_timeout_millis: null 19 | http2_keep_alive_timeout_millis: 5000 20 | http2_keep_alive_interval_millis: 30000 21 | http2_keep_alive_while_idle: true 22 | request_rate_config: 23 | max_node_connections: 10 24 | backoff_config: 25 | min_backoff_millis: 1000 26 | max_backoff_millis: 30000 27 | max_retries: 5 28 | disable_proxy: false 29 | disable_native_certs: false 30 | sliver_write_extra_time: 31 | factor: 0.5 32 | base_millis: 500 33 | registration_delay_millis: 200 34 | max_total_blob_size: 1073741824 35 | committee_change_backoff: 36 | min_backoff_millis: 1000 37 | max_backoff_millis: 5000 38 | max_retries: 5 39 | sui_client_request_timeout_millis: null 40 | refresh_config: 41 | refresh_grace_period_secs: 10 42 | max_auto_refresh_interval_secs: 30 43 | min_auto_refresh_interval_secs: 5 44 | epoch_change_distance_threshold_secs: 300 45 | refresher_channel_size: 100 46 | -------------------------------------------------------------------------------- /crates/walrus-sdk/src/client/communication.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Logic to handle the communication between the client and the storage nodes. 5 | 6 | pub mod factory; 7 | pub(crate) mod node; 8 | 9 | pub use factory::NodeCommunicationFactory; 10 | pub(crate) use node::{ 11 | NodeCommunication, 12 | NodeReadCommunication, 13 | NodeResult, 14 | NodeWriteCommunication, 15 | }; 16 | -------------------------------------------------------------------------------- /crates/walrus-sdk/src/config/sliver_write_extra_time.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use std::time::Duration; 5 | 6 | use serde::{Deserialize, Serialize}; 7 | use serde_with::{DurationMilliSeconds, serde_as}; 8 | 9 | /// The additional time allowed to sliver writes, to allow for more nodes to receive them. 10 | #[serde_as] 11 | #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] 12 | #[serde(default)] 13 | pub struct SliverWriteExtraTime { 14 | /// The multiplication factor for the time it took to store n-f sliver. 15 | pub factor: f64, 16 | /// The minimum extra time. 17 | #[serde(rename = "base_millis")] 18 | #[serde_as(as = "DurationMilliSeconds")] 19 | pub base: Duration, 20 | } 21 | 22 | impl SliverWriteExtraTime { 23 | /// Returns the extra time for the given time. 24 | /// 25 | /// The extra time is computed as `store_time * factor + base`. 26 | pub fn extra_time(&self, store_time: Duration) -> Duration { 27 | #[allow(clippy::cast_possible_truncation)] 28 | let extra_time = Duration::from_nanos((store_time.as_nanos() as f64 * self.factor) as u64); 29 | self.base + extra_time 30 | } 31 | } 32 | 33 | impl Default for SliverWriteExtraTime { 34 | fn default() -> Self { 35 | Self { 36 | factor: 0.5, // 1/2 of the time it took to store n-f slivers. 37 | base: Duration::from_millis(500), // +0.5s every time. 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /crates/walrus-sdk/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! The Walrus Rust SDK. 5 | 6 | pub mod active_committees; 7 | pub mod blocklist; 8 | pub mod client; 9 | pub mod config; 10 | pub mod error; 11 | pub mod store_when; 12 | pub mod utils; 13 | 14 | pub use sui_types::{base_types::ObjectID, event::EventID}; 15 | pub use walrus_core as core; 16 | pub use walrus_sui as sui; 17 | pub use walrus_utils as core_utils; 18 | 19 | /// Format the event ID as the transaction digest and the sequence number. 20 | pub fn format_event_id(event_id: &EventID) -> String { 21 | format!("(tx: {}, seq: {})", event_id.tx_digest, event_id.event_seq) 22 | } 23 | -------------------------------------------------------------------------------- /crates/walrus-sdk/src/store_when.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Storage conditions. 5 | 6 | /// Represents how the store operation should be carried out by the client. 7 | #[derive(Debug, Clone, Copy)] 8 | pub enum StoreWhen { 9 | /// Store the blob if not stored, but do not check the resources in the current wallet. 10 | /// 11 | /// With this command, the client does not check for usable registrations or 12 | /// storage space. This is useful when using the publisher, to avoid wasting multiple round 13 | /// trips to the fullnode. 14 | NotStoredIgnoreResources, 15 | /// Check the status of the blob before storing it, and store it only if it is not already. 16 | NotStored, 17 | /// Store the blob always, without checking the status. 18 | Always, 19 | /// Store the blob always, without checking the status, and ignore the resources in the wallet. 20 | AlwaysIgnoreResources, 21 | } 22 | 23 | impl StoreWhen { 24 | /// Returns `true` if the operation ignore the blob status. 25 | /// 26 | /// If `true`, the client should store the blob, even if the blob is already stored on Walrus 27 | /// for a sufficient number of epochs. 28 | pub fn is_ignore_status(&self) -> bool { 29 | matches!(self, Self::Always | Self::AlwaysIgnoreResources) 30 | } 31 | 32 | /// Returns `true` if the operation should ignore the resources in the wallet. 33 | pub fn is_ignore_resources(&self) -> bool { 34 | matches!( 35 | self, 36 | Self::NotStoredIgnoreResources | Self::AlwaysIgnoreResources 37 | ) 38 | } 39 | 40 | /// Returns [`Self`] based on the value of the `force` and `ignore-resources` flags. 41 | pub fn from_flags(force: bool, ignore_resources: bool) -> Self { 42 | match (force, ignore_resources) { 43 | (true, true) => Self::AlwaysIgnoreResources, 44 | (true, false) => Self::Always, 45 | (false, true) => Self::NotStoredIgnoreResources, 46 | (false, false) => Self::NotStored, 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /crates/walrus-service/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Build script for the walrus-service crate. 5 | 6 | use std::env; 7 | 8 | use chrono::{DateTime, Utc}; 9 | 10 | fn main() { 11 | #[cfg(feature = "backup")] 12 | println!("cargo:rerun-if-changed=migrations"); 13 | 14 | // Check the SOURCE_DATE_EPOCH environment variable to enable reproducible builds, see 15 | // https://reproducible-builds.org/docs/source-date-epoch/. 16 | let build_time = if let Ok(timestamp) = env::var("SOURCE_DATE_EPOCH") { 17 | DateTime::from_timestamp( 18 | timestamp 19 | .parse::() 20 | .expect("SOURCE_DATE_EPOCH must be set to a valid UNIX timestamp"), 21 | 0, 22 | ) 23 | .expect("SOURCE_DATE_EPOCH must be set to a valid UNIX timestamp") 24 | } else { 25 | Utc::now() 26 | }; 27 | println!("cargo:rerun-if-env-changed=SOURCE_DATE_EPOCH"); 28 | println!("cargo::rustc-env=BUILD_TIME={}", build_time.timestamp()); 29 | } 30 | -------------------------------------------------------------------------------- /crates/walrus-service/migrations/00000000000000_diesel_initial_setup/down.sql: -------------------------------------------------------------------------------- 1 | -- This file was automatically created by Diesel to setup helper functions 2 | -- and other internal bookkeeping. This file is safe to edit, any future 3 | -- changes will be added to existing projects as new migrations. 4 | 5 | DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass); 6 | DROP FUNCTION IF EXISTS diesel_set_updated_at(); 7 | -------------------------------------------------------------------------------- /crates/walrus-service/migrations/00000000000000_diesel_initial_setup/up.sql: -------------------------------------------------------------------------------- 1 | -- This file was automatically created by Diesel to setup helper functions 2 | -- and other internal bookkeeping. This file is safe to edit, any future 3 | -- changes will be added to existing projects as new migrations. 4 | 5 | 6 | 7 | 8 | -- Sets up a trigger for the given table to automatically set a column called 9 | -- `updated_at` whenever the row is modified (unless `updated_at` was included 10 | -- in the modified columns) 11 | -- 12 | -- # Example 13 | -- 14 | -- ```sql 15 | -- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW()); 16 | -- 17 | -- SELECT diesel_manage_updated_at('users'); 18 | -- ``` 19 | CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$ 20 | BEGIN 21 | EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s 22 | FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl); 23 | END; 24 | $$ LANGUAGE plpgsql; 25 | 26 | CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$ 27 | BEGIN 28 | IF ( 29 | NEW IS DISTINCT FROM OLD AND 30 | NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at 31 | ) THEN 32 | NEW.updated_at := current_timestamp; 33 | END IF; 34 | RETURN NEW; 35 | END; 36 | $$ LANGUAGE plpgsql; 37 | -------------------------------------------------------------------------------- /crates/walrus-service/migrations/2025-01-20-173100_create_stream_events/down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE stream_event; 2 | DROP TABLE blob_state; 3 | DROP TABLE epoch_change_start_event; 4 | -------------------------------------------------------------------------------- /crates/walrus-service/migrations/2025-02-24-213538_add-gc-field/down.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE blob_state DROP COLUMN IF EXISTS initiate_gc_after; 2 | ALTER TABLE blob_state DROP COLUMN IF EXISTS md5; 3 | ALTER TABLE blob_state DROP COLUMN IF EXISTS sha256; 4 | ALTER TABLE blob_state DROP COLUMN IF EXISTS size; 5 | -------------------------------------------------------------------------------- /crates/walrus-service/migrations/2025-02-24-213538_add-gc-field/up.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE blob_state 2 | ADD COLUMN initiate_gc_after TIMESTAMP WITH TIME ZONE NULL; 3 | ALTER TABLE blob_state 4 | ADD COLUMN size BIGINT NULL; 5 | ALTER TABLE blob_state 6 | ADD COLUMN sha256 BYTEA NULL; 7 | ALTER TABLE blob_state 8 | ADD COLUMN md5 BYTEA NULL; 9 | -------------------------------------------------------------------------------- /crates/walrus-service/src/backup/schema.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // @generated automatically by Diesel CLI. 5 | 6 | diesel::table! { 7 | blob_state (blob_id) { 8 | blob_id -> Bytea, 9 | end_epoch -> Int8, 10 | state -> Text, 11 | backup_url -> Nullable, 12 | orchestrator_version -> Text, 13 | fetcher_version -> Nullable, 14 | created_at -> Timestamptz, 15 | initiate_fetch_after -> Nullable, 16 | retry_count -> Nullable, 17 | last_error -> Nullable, 18 | initiate_gc_after -> Nullable, 19 | size -> Nullable, 20 | sha256 -> Nullable, 21 | md5 -> Nullable, 22 | } 23 | } 24 | 25 | diesel::table! { 26 | epoch_change_start_event (epoch) { 27 | epoch -> Int8, 28 | created_at -> Timestamptz, 29 | } 30 | } 31 | 32 | diesel::table! { 33 | stream_event (element_index) { 34 | checkpoint_sequence_number -> Int8, 35 | counter -> Int8, 36 | transaction_digest -> Bytea, 37 | event_index -> Int8, 38 | element_index -> Int8, 39 | element -> Jsonb, 40 | } 41 | } 42 | 43 | diesel::allow_tables_to_appear_in_same_query!(blob_state, epoch_change_start_event, stream_event,); 44 | -------------------------------------------------------------------------------- /crates/walrus-service/src/client.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Client for the Walrus service. 5 | 6 | pub mod cli; 7 | pub mod responses; 8 | 9 | pub(crate) mod config; 10 | pub use walrus_sdk::{ 11 | config::{ClientCommunicationConfig, ClientConfig, default_configuration_paths}, 12 | utils::string_prefix, 13 | }; 14 | 15 | mod daemon; 16 | pub use daemon::{ClientDaemon, PublisherQuery, WalrusWriteClient, auth::Claim}; 17 | 18 | mod refill; 19 | pub use refill::{RefillHandles, Refiller}; 20 | mod multiplexer; 21 | -------------------------------------------------------------------------------- /crates/walrus-service/src/common.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Service functionality for Walrus shared by client and storage node. 5 | 6 | pub(crate) mod api; 7 | pub mod config; 8 | pub(crate) mod telemetry; 9 | pub mod utils; 10 | 11 | #[cfg(feature = "client")] 12 | pub mod event_blob_downloader; 13 | -------------------------------------------------------------------------------- /crates/walrus-service/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Walrus client, server, and associated utilities. 5 | #![recursion_limit = "256"] 6 | 7 | #[cfg(any(feature = "client", feature = "backup"))] 8 | pub mod client; 9 | 10 | #[cfg(feature = "node")] 11 | pub mod node; 12 | #[cfg(feature = "node")] 13 | pub use node::ConfigLoader; 14 | #[cfg(feature = "node")] 15 | pub use node::StorageNodeConfigLoader; 16 | #[cfg(feature = "node")] 17 | pub use node::errors::SyncNodeConfigError; 18 | 19 | #[cfg(feature = "deploy")] 20 | pub mod testbed; 21 | 22 | pub mod backup; 23 | 24 | #[cfg(any(feature = "client", feature = "node"))] 25 | pub mod common; 26 | #[cfg(any(feature = "client", feature = "node"))] 27 | pub use common::utils; 28 | 29 | #[cfg(any(test, feature = "test-utils"))] 30 | pub mod test_utils; 31 | 32 | pub use node::db_checkpoint::DbCheckpointManager; 33 | -------------------------------------------------------------------------------- /crates/walrus-service/tests/epoch_change.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Contains end-to-end tests for the epoch change mechanism. 5 | 6 | #[ignore = "ignore E2E tests by default"] 7 | #[cfg(msim)] 8 | #[walrus_proc_macros::walrus_simtest] 9 | async fn nodes_drive_epoch_change() -> walrus_test_utils::Result { 10 | use std::time::Duration; 11 | 12 | use tokio::time; 13 | use walrus_core::Epoch; 14 | use walrus_service::test_utils::{StorageNodeHandleTrait, TestNodesConfig, test_cluster}; 15 | 16 | telemetry_subscribers::init_for_testing(); 17 | let epoch_duration = Duration::from_secs(5); 18 | let (_sui, storage_nodes, _, _) = test_cluster::E2eTestSetupBuilder::new() 19 | .with_epoch_duration(epoch_duration) 20 | .with_test_nodes_config(TestNodesConfig { 21 | node_weights: vec![1, 1], 22 | ..Default::default() 23 | }) 24 | .with_default_num_checkpoints_per_blob() 25 | .build() 26 | .await?; 27 | 28 | let target_epoch: Epoch = 3; 29 | // Allow five times the expected time to reach the desired epoch. 30 | let time_to_reach_epoch = epoch_duration * target_epoch * 5; 31 | 32 | time::timeout( 33 | time_to_reach_epoch, 34 | storage_nodes.wait_for_nodes_to_reach_epoch(target_epoch), 35 | ) 36 | .await 37 | .expect("target epoch much be reached in allotted time"); 38 | 39 | // Shut the nodes down gracefully to prevent panics when event handles are dropped. 40 | storage_nodes.nodes.iter().for_each(|node| node.cancel()); 41 | tokio::time::sleep(Duration::from_secs(1)).await; 42 | 43 | Ok(()) 44 | } 45 | -------------------------------------------------------------------------------- /crates/walrus-simtest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walrus-simtest" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | 8 | [dependencies] 9 | anyhow.workspace = true 10 | futures.workspace = true 11 | prometheus.workspace = true 12 | rand.workspace = true 13 | # explicitly import reqwest in test to disable its system proxy cache. It causes indeterminism in simtest. 14 | reqwest = { version = "0.12.12", default-features = false, features = ["__internal_proxy_sys_no_cache", "http2", "json", "rustls-tls"] } 15 | sui-macros.workspace = true 16 | sui-protocol-config.workspace = true 17 | sui-rpc-api.workspace = true 18 | sui-types.workspace = true 19 | tokio.workspace = true 20 | tracing.workspace = true 21 | walrus-core.workspace = true 22 | walrus-proc-macros = { workspace = true, features = ["walrus-simtest"] } 23 | walrus-sdk.workspace = true 24 | walrus-service = { workspace = true, features = ["test-utils"] } 25 | walrus-storage-node-client.workspace = true 26 | walrus-sui.workspace = true 27 | walrus-test-utils.workspace = true 28 | 29 | [lints] 30 | workspace = true 31 | 32 | [target.'cfg(msim)'.dependencies] 33 | sui-simulator.workspace = true 34 | -------------------------------------------------------------------------------- /crates/walrus-simtest/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![recursion_limit = "256"] 5 | 6 | //! Contains test utilities for the Walrus simulation tests. 7 | //! This crate provides utilities for testing Walrus in a simulated environment. 8 | 9 | /// Contains test utilities for the Walrus simulation tests. 10 | pub mod test_utils; 11 | -------------------------------------------------------------------------------- /crates/walrus-storage-node-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walrus-storage-node-client" 3 | publish = false 4 | authors.workspace = true 5 | version.workspace = true 6 | edition.workspace = true 7 | license.workspace = true 8 | 9 | [features] 10 | default = [] 11 | 12 | [dependencies] 13 | bcs.workspace = true 14 | bytes.workspace = true 15 | fastcrypto.workspace = true 16 | futures.workspace = true 17 | http = "1.3.1" 18 | mime.workspace = true 19 | opentelemetry.workspace = true 20 | p256 = { workspace = true, features = ["ecdsa"] } 21 | pin-project.workspace = true 22 | prometheus.workspace = true 23 | rand.workspace = true 24 | reqwest.workspace = true 25 | rustls.workspace = true 26 | rustls-native-certs.workspace = true 27 | serde.workspace = true 28 | serde_json.workspace = true 29 | serde_with.workspace = true 30 | sui-types.workspace = true 31 | thiserror.workspace = true 32 | tokio.workspace = true 33 | tower = { workspace = true, features = ["util"] } 34 | tracing.workspace = true 35 | tracing-opentelemetry.workspace = true 36 | utoipa.workspace = true 37 | walrus-core = { workspace = true, features = ["sui-types"] } 38 | walrus-utils = { workspace = true, features = ["http", "metrics"] } 39 | x509-cert.workspace = true 40 | 41 | [dev-dependencies] 42 | axum.workspace = true 43 | axum-server.workspace = true 44 | rcgen.workspace = true 45 | walrus-core = { workspace = true, features = ["sui-types", "test-utils"] } 46 | walrus-test-utils.workspace = true 47 | 48 | [lints] 49 | workspace = true 50 | 51 | [package.metadata.docs.rs] 52 | all-features = true 53 | 54 | [target.'cfg(msim)'.dependencies] 55 | sui-simulator.workspace = true 56 | -------------------------------------------------------------------------------- /crates/walrus-storage-node-client/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Code for interacting with the Walrus system. 5 | 6 | use std::fmt::Write; 7 | 8 | use fastcrypto::traits::ToFromBytes as _; 9 | use walrus_core::NetworkPublicKey; 10 | 11 | pub use self::{ 12 | client::{RecoverySymbolsFilter, StorageNodeClient, StorageNodeClientBuilder, SymbolIdFilter}, 13 | error::{ClientBuildError, NodeError}, 14 | }; 15 | 16 | pub mod api; 17 | pub mod client; 18 | pub mod error; 19 | 20 | mod node_response; 21 | mod tls; 22 | 23 | /// Returns a string `.network.walrus.alt` corresponding to the public key. 24 | pub fn server_name_from_public_key(public_key: &NetworkPublicKey) -> String { 25 | const N_PUBLIC_KEY_BYTES_IN_SUBJECT: usize = 4; 26 | 27 | let public_key_bytes = public_key.as_bytes(); 28 | 29 | let mut server_name = String::new(); 30 | for byte in public_key_bytes.iter().take(N_PUBLIC_KEY_BYTES_IN_SUBJECT) { 31 | write!(&mut server_name, "{byte:x}").expect("write on a string always succeeds"); 32 | } 33 | server_name.push_str(".network.walrus.alt"); 34 | server_name 35 | } 36 | -------------------------------------------------------------------------------- /crates/walrus-stress/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walrus-stress" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | 8 | [dependencies] 9 | anyhow.workspace = true 10 | clap.workspace = true 11 | futures.workspace = true 12 | humantime.workspace = true 13 | indicatif.workspace = true 14 | mysten-metrics.workspace = true 15 | prometheus.workspace = true 16 | rand.workspace = true 17 | sui-sdk.workspace = true 18 | sui-types.workspace = true 19 | tokio.workspace = true 20 | tracing.workspace = true 21 | tracing-subscriber.workspace = true 22 | walrus-core.workspace = true 23 | walrus-sdk.workspace = true 24 | walrus-service = { workspace = true, features = ["client"] } 25 | walrus-sui.workspace = true 26 | walrus-test-utils.workspace = true 27 | walrus-utils = { workspace = true, features = ["backoff"] } 28 | 29 | [lints] 30 | workspace = true 31 | -------------------------------------------------------------------------------- /crates/walrus-sui/src/client/contract_config.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Module for the configuration of contract packages and shared objects. 5 | 6 | use serde::{Deserialize, Serialize}; 7 | use sui_types::base_types::ObjectID; 8 | 9 | #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] 10 | /// Configuration for the contract packages and shared objects. 11 | pub struct ContractConfig { 12 | /// Object ID of the Walrus system object. 13 | pub system_object: ObjectID, 14 | /// Object ID of the Walrus staking object. 15 | pub staking_object: ObjectID, 16 | /// Object ID of the Walrus subsidies object. 17 | #[serde(default, skip_serializing_if = "Option::is_none")] 18 | pub subsidies_object: Option, 19 | } 20 | 21 | impl ContractConfig { 22 | /// Creates a [`ContractConfig`] with the system, staking, and subsidies objects. 23 | pub fn new_with_subsidies( 24 | system_object: ObjectID, 25 | staking_object: ObjectID, 26 | subsidies_object: Option, 27 | ) -> Self { 28 | Self { 29 | system_object, 30 | staking_object, 31 | subsidies_object, 32 | } 33 | } 34 | /// Creates a basic [`ContractConfig`] with just the system and staking objects. 35 | pub fn new(system_object: ObjectID, staking_object: ObjectID) -> Self { 36 | Self { 37 | system_object, 38 | staking_object, 39 | subsidies_object: None, 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /crates/walrus-sui/src/client/retry_client/retry_count_guard.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! A guard that records the number of retries and the result of an RPC call. 5 | use std::sync::Arc; 6 | 7 | use super::ToErrorType; 8 | use crate::client::SuiClientMetricSet; 9 | 10 | /// A guard that records the number of retries and the result of an RPC call. 11 | pub(crate) struct RetryCountGuard { 12 | pub(crate) method: String, 13 | pub(crate) count: u64, 14 | pub(crate) metrics: Arc, 15 | pub(crate) status: String, 16 | } 17 | 18 | impl RetryCountGuard { 19 | pub(crate) fn new(metrics: Arc, method: &str) -> Self { 20 | Self { 21 | method: method.to_string(), 22 | count: 0, 23 | metrics, 24 | status: "success".to_string(), 25 | } 26 | } 27 | 28 | pub fn record_result(&mut self, value: Result<&T, &E>) 29 | where 30 | E: ToErrorType, 31 | { 32 | match value { 33 | Ok(_) => self.status = "success".to_string(), 34 | Err(e) => self.status = e.to_error_type(), 35 | } 36 | self.count += 1; 37 | } 38 | } 39 | 40 | impl Drop for RetryCountGuard { 41 | fn drop(&mut self) { 42 | if self.count > 1 { 43 | #[cfg(msim)] 44 | tracing::debug!( 45 | "RPC call {} failed {} times, status: {}", 46 | self.method, 47 | self.count, 48 | self.status 49 | ); 50 | self.metrics 51 | .record_rpc_retry_count(self.method.as_str(), self.count, &self.status); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /crates/walrus-sui/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Bindings to call the Walrus contracts from Rust. 5 | 6 | #[macro_use] 7 | pub mod utils; 8 | pub mod client; 9 | pub mod config; 10 | pub mod contracts; 11 | pub mod system_setup; 12 | pub mod wallet; 13 | 14 | #[cfg(any(test, feature = "test-utils"))] 15 | pub mod test_utils; 16 | 17 | pub mod types; 18 | 19 | /// Schema for the [`sui_types::event::EventID`] type. 20 | #[cfg(feature = "utoipa")] 21 | #[allow(unused)] 22 | #[derive(Debug, utoipa::ToSchema)] 23 | #[schema( 24 | as = EventID, 25 | rename_all = "camelCase", 26 | examples(json!({ 27 | "txDigest": "EhtoQF9UpPyg5PsPUs69LdkcRrjQ3R4cTsHnwxZVTNrC", 28 | "eventSeq": 0 29 | })) 30 | )] 31 | pub struct EventIdSchema { 32 | #[schema(format = Byte)] 33 | tx_digest: Vec, 34 | #[schema(value_type = String)] 35 | event_seq: u64, 36 | } 37 | 38 | /// Schema for the `ObjectID` type. 39 | #[cfg(feature = "utoipa")] 40 | #[derive(Debug, utoipa::ToSchema)] 41 | #[schema( 42 | as = ObjectID, 43 | value_type = String, 44 | title = "Sui object ID", 45 | description = "Sui object ID as a hexadecimal string", 46 | examples("0x56ae1c86e17db174ea002f8340e28880bc8a8587c56e8604a4fa6b1170b23a60"), 47 | )] 48 | pub struct ObjectIdSchema(()); 49 | 50 | /// Schema for Sui addresses. 51 | #[cfg(feature = "utoipa")] 52 | #[derive(Debug, utoipa::ToSchema)] 53 | #[schema( 54 | as = SuiAddress, 55 | value_type = String, 56 | title = "Sui address", 57 | description = "Sui address encoded as a hexadecimal string", 58 | examples("0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de0"), 59 | )] 60 | pub struct SuiAddressSchema(()); 61 | -------------------------------------------------------------------------------- /crates/walrus-test-utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walrus-test-utils" 3 | publish = false 4 | authors.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | version.workspace = true 8 | 9 | [dependencies] 10 | anyhow.workspace = true 11 | rand.workspace = true 12 | tempfile.workspace = true 13 | 14 | [lints] 15 | workspace = true 16 | 17 | [dev-dependencies] 18 | tokio = { workspace = true, features = ["macros", "rt", "test-util", "time"] } 19 | -------------------------------------------------------------------------------- /crates/walrus-utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walrus-utils" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | 8 | [features] 9 | backoff = ["dep:anyhow", "dep:rand", "dep:serde", "dep:serde_with", "dep:tracing", "tokio/time"] 10 | config = ["dep:anyhow", "dep:home", "dep:serde", "dep:tracing"] 11 | default = [] 12 | http = ["dep:bytes", "dep:http-body", "dep:pin-project"] 13 | log = ["dep:humantime", "dep:once_cell", "dep:tracing"] 14 | metrics = ["dep:once_cell", "dep:prometheus", "dep:tap", "dep:thiserror"] 15 | test-utils = ["dep:tempfile", "tokio/sync"] 16 | tokio-metrics = ["dep:tokio-metrics"] 17 | 18 | [dependencies] 19 | anyhow = { workspace = true, optional = true } 20 | bytes = { workspace = true, optional = true } 21 | home = { workspace = true, optional = true } 22 | http-body = { version = "1", optional = true } 23 | humantime = { workspace = true, optional = true } 24 | once_cell = { workspace = true, optional = true } 25 | pin-project = { workspace = true, optional = true } 26 | prometheus = { workspace = true, optional = true } 27 | rand = { workspace = true, optional = true } 28 | serde = { workspace = true, features = ["derive"], optional = true } 29 | serde_json = { workspace = true, optional = true } 30 | serde_with = { workspace = true, optional = true } 31 | serde_yaml = { workspace = true } 32 | tap = { workspace = true, optional = true } 33 | tempfile = { workspace = true, optional = true } 34 | thiserror = { workspace = true, optional = true } 35 | tokio = { workspace = true, features = ["macros", "rt-multi-thread"], optional = true } 36 | tokio-metrics = { version = "0.4.2", optional = true, default-features = false } 37 | tokio-util = { workspace = true, optional = true } 38 | tracing = { workspace = true, optional = true } 39 | tracing-subscriber = { workspace = true, optional = true } 40 | 41 | [dev-dependencies] 42 | http-body-util.workspace = true 43 | tempfile.workspace = true 44 | tokio.workspace = true 45 | tracing-subscriber.workspace = true 46 | walrus-test-utils.workspace = true 47 | -------------------------------------------------------------------------------- /diesel.toml: -------------------------------------------------------------------------------- 1 | # For documentation on how to configure this file, 2 | # see https://diesel.rs/guides/configuring-diesel-cli 3 | 4 | [print_schema.walrus-backup] 5 | custom_type_derives = ["Clone", "diesel::query_builder::QueryId", "std::fmt::Debug"] 6 | file = "crates/walrus-service/src/backup/schema.rs" 7 | 8 | [migrations_directory] 9 | dir = "crates/walrus-service/migrations" 10 | -------------------------------------------------------------------------------- /docker/grafana-local/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | tempo: 4 | image: grafana/tempo:latest 5 | command: ["-config.file=/etc/tempo.yaml"] 6 | volumes: 7 | - ./tempo.yaml:/etc/tempo.yaml 8 | - ${TMPDIR}/tempo-data:/tmp/tempo 9 | ports: 10 | - "14268:14268" # jaeger ingest 11 | - "3200:3200" # tempo 12 | - "9095:9095" # tempo grpc 13 | - "4317:4317" # otlp grpc 14 | - "4318:4318" # otlp http 15 | - "9411:9411" # zipkin 16 | 17 | prometheus: 18 | image: prom/prometheus:latest 19 | command: 20 | - --config.file=/etc/prometheus.yaml 21 | - --web.enable-remote-write-receiver 22 | - --enable-feature=exemplar-storage 23 | volumes: 24 | - ./prometheus.yaml:/etc/prometheus.yaml 25 | ports: 26 | - "9090:9090" 27 | 28 | grafana: 29 | image: grafana/grafana:10.1.1 30 | volumes: 31 | - ./grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml 32 | - ./dashboards:/etc/grafana/provisioning/dashboards 33 | environment: 34 | - GF_AUTH_ANONYMOUS_ENABLED=true 35 | - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin 36 | - GF_AUTH_DISABLE_LOGIN_FORM=true 37 | - GF_FEATURE_TOGGLES_ENABLE=traceqlEditor 38 | ports: 39 | - "3000:3000" 40 | 41 | node-exporter: 42 | image: prom/node-exporter:latest 43 | container_name: node-exporter 44 | restart: unless-stopped 45 | volumes: 46 | - /proc:/host/proc:ro 47 | - /sys:/host/sys:ro 48 | - /:/rootfs:ro 49 | command: 50 | - '--path.procfs=/host/proc' 51 | - '--path.rootfs=/rootfs' 52 | - '--path.sysfs=/host/sys' 53 | - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)' 54 | ports: 55 | - "9100:9100" 56 | -------------------------------------------------------------------------------- /docker/grafana-local/grafana-datasources.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: Prometheus 5 | type: prometheus 6 | uid: prometheus 7 | access: proxy 8 | orgId: 1 9 | url: http://prometheus:9090 10 | basicAuth: false 11 | isDefault: false 12 | version: 1 13 | editable: false 14 | jsonData: 15 | httpMethod: GET 16 | - name: Tempo 17 | type: tempo 18 | access: proxy 19 | orgId: 1 20 | url: http://tempo:3200 21 | basicAuth: false 22 | isDefault: true 23 | version: 1 24 | editable: false 25 | apiVersion: 1 26 | uid: tempo 27 | jsonData: 28 | httpMethod: GET 29 | serviceMap: 30 | datasourceUid: prometheus 31 | -------------------------------------------------------------------------------- /docker/grafana-local/prometheus.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | evaluation_interval: 15s 4 | 5 | scrape_configs: 6 | - job_name: "prometheus" 7 | static_configs: 8 | - targets: ["localhost:9090", "host.docker.internal:9184"] 9 | - job_name: "Storage_0" 10 | static_configs: 11 | - targets: ["host.docker.internal:9184"] 12 | labels: 13 | host: storage0 14 | network: local 15 | - job_name: "Storage_1" 16 | static_configs: 17 | - targets: ["host.docker.internal:9185"] 18 | labels: 19 | host: storage1 20 | network: local 21 | - job_name: "Storage_2" 22 | static_configs: 23 | - targets: ["host.docker.internal:9186"] 24 | labels: 25 | host: storage2 26 | network: local 27 | - job_name: "Storage_3" 28 | static_configs: 29 | - targets: ["host.docker.internal:9187"] 30 | labels: 31 | host: storage3 32 | network: local 33 | - job_name: "Storage_4" 34 | static_configs: 35 | - targets: ["host.docker.internal:9188"] 36 | labels: 37 | host: storage4 38 | network: local 39 | - job_name: "Storage_5" 40 | static_configs: 41 | - targets: ["host.docker.internal:9189"] 42 | labels: 43 | host: storage5 44 | network: local 45 | - job_name: "tempo" 46 | static_configs: 47 | - targets: ["tempo:3200"] 48 | - job_name: "node" 49 | static_configs: 50 | - targets: ["host.docker.internal:9100"] 51 | labels: 52 | host: node 53 | network: local 54 | -------------------------------------------------------------------------------- /docker/grafana-local/tempo.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | http_listen_port: 3200 3 | 4 | query_frontend: 5 | search: 6 | duration_slo: 5s 7 | throughput_bytes_slo: 1.073741824e+09 8 | trace_by_id: 9 | duration_slo: 5s 10 | 11 | distributor: 12 | receivers: # this configuration will listen on all ports and protocols that tempo is capable of. 13 | jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can 14 | protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver 15 | thrift_http: # 16 | grpc: # for a production deployment you should only enable the receivers you need! 17 | thrift_binary: 18 | thrift_compact: 19 | zipkin: 20 | otlp: 21 | protocols: 22 | http: 23 | grpc: 24 | opencensus: 25 | 26 | ingester: 27 | max_block_duration: 5m # cut the headblock when this much time passes. 28 | 29 | compactor: 30 | compaction: 31 | block_retention: 1h # overall Tempo trace retention. set for demo purposes 32 | 33 | metrics_generator: 34 | registry: 35 | external_labels: 36 | source: tempo 37 | cluster: docker-compose 38 | storage: 39 | path: /tmp/tempo/generator/wal 40 | remote_write: 41 | - url: http://prometheus:9090/api/v1/write 42 | send_exemplars: true 43 | 44 | storage: 45 | trace: 46 | backend: local # backend configuration to use 47 | wal: 48 | path: /tmp/tempo/wal # where to store the wal locally 49 | local: 50 | path: /tmp/tempo/blocks 51 | 52 | overrides: 53 | max_global_traces_per_user: 10000000 54 | max_traces_per_user: 10000000 55 | ingestion_rate_strategy: local 56 | ingestion_rate_limit_bytes: 1500000000 57 | max_bytes_per_trace: 500000000 58 | -------------------------------------------------------------------------------- /docker/local-testbed/build-local-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | PLATFORM=linux/arm64 6 | GIT_REVISION=$(git rev-parse HEAD) 7 | IMAGE_NAME=local-testbed_walrus-service:${GIT_REVISION} 8 | DOCKER_COMPOSE_FILE=docker/local-testbed/docker-compose.yaml 9 | 10 | cd ../.. # go to the root directory (walrus) 11 | 12 | docker build -t ${IMAGE_NAME} \ 13 | -f docker/walrus-service/Dockerfile \ 14 | --target walrus-service \ 15 | --platform $PLATFORM . 16 | 17 | # echo the IMAGE_NAME and PLATFORM to the .env file 18 | rm -f docker/local-testbed/.env 19 | echo "WALRUS_IMAGE_NAME=${IMAGE_NAME}" >>docker/local-testbed/.env 20 | echo "WALRUS_PLATFORM=${PLATFORM}" >>docker/local-testbed/.env 21 | -------------------------------------------------------------------------------- /docker/local-testbed/files/deploy-walrus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # use EPOCH_DURATION to set the epoch duration, default is 2 minutes 6 | # in antithesis test. The exhaustive behavior exploration in antithesis test requires 7 | # epoch duration to be as short as possible in order to explore more epoch change behaviors. 8 | EPOCH_DURATION=${EPOCH_DURATION:-2m} 9 | 10 | rm -rf walrus-docs 11 | git clone https://github.com/MystenLabs/walrus-docs.git 12 | cp -r walrus-docs/contracts /opt/walrus/testnet-contracts 13 | 14 | cd /opt/walrus 15 | 16 | rm -rf /opt/walrus/outputs/* 17 | 18 | /opt/walrus/bin/walrus-deploy deploy-system-contract \ 19 | --working-dir /opt/walrus/outputs \ 20 | --contract-dir /opt/walrus/contracts \ 21 | --do-not-copy-contracts \ 22 | --sui-network 'http://sui-localnet:9000;http://sui-localnet:9123/gas' \ 23 | --n-shards 100 \ 24 | --host-addresses 10.0.0.10 10.0.0.11 10.0.0.12 10.0.0.13 \ 25 | --storage-price 5 \ 26 | --write-price 1 \ 27 | --epoch-duration "$EPOCH_DURATION" >/opt/walrus/outputs/deploy 28 | 29 | /opt/walrus/bin/walrus-deploy generate-dry-run-configs \ 30 | --working-dir /opt/walrus/outputs 31 | -------------------------------------------------------------------------------- /docker/local-testbed/files/run-walrus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | ## ----------------------------------------------------------------------------- 6 | ## Prepare the environment 7 | ## ----------------------------------------------------------------------------- 8 | 9 | HOSTNAME=$(hostname) 10 | 11 | # create directories 12 | mkdir -p /root/.sui/sui_config 13 | mkdir -p /root/.config/walrus 14 | mkdir -p /opt/walrus/outputs 15 | 16 | # copy from deploy outputs 17 | cp /opt/walrus/outputs/${HOSTNAME}-sui.yaml /root/.sui/sui_config/client.yaml 18 | cp /opt/walrus/outputs/${HOSTNAME}.aliases /root/.sui/sui_config/sui.aliases 19 | 20 | # extract object IDs from the deploy outputs 21 | SYSTEM_OBJECT=$(grep "system_object" /opt/walrus/outputs/deploy | awk '{print $2}') 22 | STAKING_OBJECT=$(grep "staking_object" /opt/walrus/outputs/deploy | awk '{print $2}') 23 | EXCHANGE_OBJECT=$(grep "exchange_object" /opt/walrus/outputs/deploy | awk '{print $2}') 24 | 25 | # copy binaries 26 | cp /root/sui_bin/sui /usr/local/bin/ 27 | cp /opt/walrus/bin/walrus /usr/local/bin/ 28 | 29 | cat </root/.config/walrus/client_config.yaml 30 | system_object: ${SYSTEM_OBJECT} 31 | staking_object: ${STAKING_OBJECT} 32 | exchange_objects: [${EXCHANGE_OBJECT}] 33 | EOF 34 | 35 | # get some sui tokens 36 | sui client faucet --url http://sui-localnet:9123/gas 37 | sleep 3 38 | 39 | # exchange for WAL tokens (500 WAL) 40 | walrus get-wal --amount 500000000000 41 | sui client balance 42 | 43 | ## ----------------------------------------------------------------------------- 44 | ## Start the node 45 | ## ----------------------------------------------------------------------------- 46 | /opt/walrus/bin/walrus-node run --config-path /opt/walrus/outputs/${HOSTNAME}.yaml 47 | -------------------------------------------------------------------------------- /docker/walrus-antithesis/build-test-config-image/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim AS setup 2 | 3 | RUN apt update 4 | RUN apt install python3 python3-pip -y 5 | 6 | WORKDIR / 7 | 8 | # Walrus commit picked to run the stress test. 9 | ARG WALRUS_COMMIT_HASH 10 | ARG WALRUS_RUST_LOG 11 | 12 | # Set SUI_VERSION to the version.toml value 13 | COPY ./docker/walrus-antithesis/sui_version.toml . 14 | 15 | RUN echo "WALRUS_RUST_LOG=$WALRUS_RUST_LOG" >> /.env && echo "WALRUS_RUST_LOG: $WALRUS_RUST_LOG" 16 | RUN echo "WALRUS_IMAGE_NAME=walrus-service:$WALRUS_COMMIT_HASH" >> /.env && \ 17 | echo "WALRUS_IMAGE_NAME: walrus-service:$WALRUS_COMMIT_HASH" 18 | RUN echo "WALRUS_PLATFORM=linux/amd64" >> /.env && echo "WALRUS_PLATFORM: linux/amd64" 19 | 20 | # Set SUI_VERSION to the version.toml value so that it can pull the correct sui image. 21 | # Note that we have to run all of these in one command to make sure that SUI_VERSION is set. 22 | RUN export SUI_VERSION=$(grep SUI_VERSION sui_version.toml | cut -d'"' -f2) && \ 23 | echo "SUI_VERSION: $SUI_VERSION" && \ 24 | echo "SUI_IMAGE_NAME=mysten/sui-tools:$SUI_VERSION" >> /.env && \ 25 | echo "SUI_IMAGE_NAME: mysten/sui-tools:$SUI_VERSION" 26 | 27 | COPY ./docker/walrus-antithesis/build-test-config-image/docker-compose.yaml /docker-compose.yaml 28 | COPY ./docker/walrus-antithesis/build-test-config-image/files /files 29 | 30 | FROM scratch 31 | 32 | COPY --from=setup /docker-compose.yaml /docker-compose.yaml 33 | COPY --from=setup /.env /.env 34 | COPY --from=setup /files /files 35 | -------------------------------------------------------------------------------- /docker/walrus-antithesis/build-test-config-image/files/complete-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | 6 | echo "about to signal complete setup" 7 | 8 | # Emit the JSONL message 9 | echo '{"antithesis_setup": { "status": "complete", "details": null }}' > "$ANTITHESIS_OUTPUT_DIR/sdk.jsonl" 10 | -------------------------------------------------------------------------------- /docker/walrus-antithesis/build-test-config-image/files/deploy-walrus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | die() { 6 | echo "$0: error: $*" >&2 7 | exit 1 8 | } 9 | 10 | # use EPOCH_DURATION to set the epoch duration, default is 10 minutes in antithesis test. 11 | EPOCH_DURATION=${EPOCH_DURATION:-10m} 12 | 13 | cd /opt/walrus || die "/opt/walrus does not exist?" 14 | 15 | rm -rf /opt/walrus/outputs/* 16 | ls -al /opt/walrus/contracts 17 | 18 | echo "Deploying system contract" 19 | /opt/walrus/bin/walrus-deploy deploy-system-contract \ 20 | --working-dir /opt/walrus/outputs \ 21 | --contract-dir /opt/walrus/contracts \ 22 | --do-not-copy-contracts \ 23 | --sui-network 'http://10.0.0.20:9000;http://10.0.0.20:9123/gas' \ 24 | --n-shards 10 \ 25 | --host-addresses 10.0.0.10 10.0.0.11 10.0.0.12 10.0.0.13 \ 26 | --storage-price 5 \ 27 | --write-price 1 \ 28 | --with-wal-exchange \ 29 | --epoch-duration "$EPOCH_DURATION" >/opt/walrus/outputs/deploy \ 30 | || die "Failed to deploy system contract" 31 | 32 | echo "Generating dry run configs" 33 | 34 | /opt/walrus/bin/walrus-deploy generate-dry-run-configs \ 35 | --working-dir /opt/walrus/outputs \ 36 | --extra-client-wallets stress,staking \ 37 | --admin-wallet-path /opt/walrus/outputs/sui_admin.yaml \ 38 | --sui-amount 1000000000000 \ 39 | --sui-client-request-timeout 90s \ 40 | || die "Failed to generate dry-run configs" 41 | -------------------------------------------------------------------------------- /docker/walrus-antithesis/build-test-config-image/files/run-staking.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | ## ----------------------------------------------------------------------------- 6 | ## Prepare the environment 7 | ## ----------------------------------------------------------------------------- 8 | 9 | HOSTNAME=$(hostname) 10 | 11 | # create directories 12 | mkdir -p /root/.sui/sui_config 13 | mkdir -p /root/.config/walrus 14 | mkdir -p /opt/walrus/outputs 15 | 16 | # copy from deploy outputs so that we can use `sui client` directly, otherwise, we don't really need 17 | # this copying. 18 | cp /opt/walrus/outputs/staking.yaml /root/.sui/sui_config/client.yaml 19 | cp /opt/walrus/outputs/staking.keystore /root/.sui/sui_config/sui.keystore 20 | cp /opt/walrus/outputs/staking.aliases /root/.sui/sui_config/sui.aliases 21 | 22 | echo "Disk space usage:" 23 | df -h 24 | 25 | # copy binaries 26 | cp /root/sui_bin/sui /usr/local/bin/ 27 | cp /opt/walrus/bin/walrus /usr/local/bin/ 28 | 29 | echo "WAL balance" 30 | while ! sui client balance; do 31 | echo "Failed to get balance, retrying in 5 seconds..." 32 | sleep 5 33 | done 34 | 35 | echo "starting staking client" 36 | ## ----------------------------------------------------------------------------- 37 | ## Start the node 38 | ## ----------------------------------------------------------------------------- 39 | RUST_BACKTRACE=full RUST_LOG=info /opt/walrus/bin/walrus-stress \ 40 | --config-path /opt/walrus/outputs/client_config_staking.yaml \ 41 | --sui-network "http://10.0.0.20:9000;http://10.0.0.20:9123/gas" \ 42 | staking 43 | -------------------------------------------------------------------------------- /docker/walrus-antithesis/build-test-config-image/files/run-stress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | ## ----------------------------------------------------------------------------- 6 | ## Prepare the environment 7 | ## ----------------------------------------------------------------------------- 8 | 9 | HOSTNAME=$(hostname) 10 | 11 | # create directories 12 | mkdir -p /root/.sui/sui_config 13 | mkdir -p /root/.config/walrus 14 | mkdir -p /opt/walrus/outputs 15 | 16 | # copy from deploy outputs so that we can use `sui client` directly, otherwise, we don't really need 17 | # this copying. 18 | cp /opt/walrus/outputs/stress.yaml /root/.sui/sui_config/client.yaml 19 | cp /opt/walrus/outputs/stress.keystore /root/.sui/sui_config/sui.keystore 20 | cp /opt/walrus/outputs/stress.aliases /root/.sui/sui_config/sui.aliases 21 | 22 | 23 | echo "Disk space usage:" 24 | df -h 25 | 26 | # copy binaries 27 | cp /root/sui_bin/sui /usr/local/bin/ 28 | cp /opt/walrus/bin/walrus /usr/local/bin/ 29 | 30 | echo "WAL balance" 31 | while ! sui client balance; do 32 | echo "Failed to get balance, retrying in 5 seconds..." 33 | sleep 5 34 | done 35 | 36 | echo "starting stress client" 37 | ## ----------------------------------------------------------------------------- 38 | ## Start the node 39 | ## ----------------------------------------------------------------------------- 40 | RUST_BACKTRACE=full RUST_LOG=info /opt/walrus/bin/walrus-stress \ 41 | --config-path /opt/walrus/outputs/client_config_stress.yaml \ 42 | --sui-network "http://10.0.0.20:9000;http://10.0.0.20:9123/gas" \ 43 | stress \ 44 | --write-load 10 \ 45 | --read-load 10 \ 46 | --n-clients 2 \ 47 | --gas-refill-period-millis 60000 48 | -------------------------------------------------------------------------------- /docker/walrus-antithesis/build-walrus-image-for-antithesis/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # fast fail. 6 | set -e 7 | 8 | DIR="$(cd "$(dirname "$0")" && pwd)" 9 | REPO_ROOT="$(git rev-parse --show-toplevel)" 10 | DOCKERFILE="$DIR/Dockerfile" 11 | GIT_REVISION="$(git describe --always --abbrev=12 --dirty --exclude '*')" 12 | BUILD_DATE="$(date -u +'%Y-%m-%d')" 13 | 14 | echo 15 | printf "Building '%s' docker images\n" "$WALRUS_IMAGE_NAME" 16 | printf "Dockerfile: \t%s\n" "$DOCKERFILE" 17 | printf "docker context: %s\n" "$REPO_ROOT" 18 | printf "build date: \t%s\n" "$BUILD_DATE" 19 | printf "git revision: \t%s\n" "$GIT_REVISION" 20 | echo 21 | 22 | docker build \ 23 | --progress plain \ 24 | -f "$DOCKERFILE" "$REPO_ROOT" \ 25 | --build-arg GIT_REVISION="$GIT_REVISION" \ 26 | --build-arg BUILD_DATE="$BUILD_DATE" \ 27 | --platform linux/"$(uname -m)" \ 28 | "$@" 29 | -------------------------------------------------------------------------------- /docker/walrus-antithesis/build-walrus-image-for-antithesis/update_move_toml.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | 6 | # List of contract directories to process 7 | contracts=( 8 | wal 9 | wal_exchange 10 | walrus 11 | subsidies 12 | ) 13 | 14 | for contract in "${contracts[@]}"; do 15 | toml_file="/contracts/${contract}/Move.toml" 16 | sed 's|^Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework".*|Sui = { local = "/opt/sui/crates/sui-framework/packages/sui-framework" }|' \ 17 | < "$toml_file" > "${toml_file}.new" 18 | mv "${toml_file}.new" "$toml_file" 19 | done 20 | -------------------------------------------------------------------------------- /docker/walrus-antithesis/sui_version.toml: -------------------------------------------------------------------------------- 1 | SUI_VERSION = "testnet-v1.49.1" 2 | -------------------------------------------------------------------------------- /docker/walrus-orchestrator/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build application 2 | # 3 | # Copy in all crates, Cargo.toml and Cargo.lock unmodified, 4 | # and build the application. 5 | FROM rust:1.87-bookworm AS builder 6 | ARG PROFILE=release 7 | ARG GIT_REVISION 8 | ENV GIT_REVISION=$GIT_REVISION 9 | WORKDIR "$WORKDIR/walrus" 10 | RUN apt-get update && apt-get install -y cmake clang 11 | 12 | COPY Cargo.toml Cargo.lock ./ 13 | COPY crates crates 14 | 15 | RUN cargo build --profile $PROFILE --bin walrus-orchestrator 16 | 17 | # Production Image for walrus orchestrator 18 | FROM debian:bookworm-slim AS walrus-orchestrator 19 | RUN apt-get update && apt-get install -y ca-certificates curl 20 | ARG PROFILE=release 21 | WORKDIR "$WORKDIR/walrus" 22 | # Both bench and release profiles copy from release dir 23 | COPY --from=builder /walrus/target/release/walrus-orchestrator /opt/walrus/bin/walrus-orchestrator 24 | 25 | ARG BUILD_DATE 26 | ARG GIT_REVISION 27 | LABEL build-date=$BUILD_DATE 28 | LABEL git-revision=$GIT_REVISION 29 | -------------------------------------------------------------------------------- /docker/walrus-orchestrator/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # fast fail. 6 | set -e 7 | 8 | DIR="$(cd "$(dirname "$0")" && pwd)" 9 | REPO_ROOT="$(git rev-parse --show-toplevel)" 10 | DOCKERFILE="$DIR/Dockerfile" 11 | GIT_REVISION="$(git describe --always --abbrev=12 --dirty --exclude '*')" 12 | BUILD_DATE="$(date -u +'%Y-%m-%d')" 13 | 14 | # option to build using debug symbols 15 | if [ "$1" = "--debug-symbols" ]; then 16 | PROFILE="bench" 17 | echo "Building with full debug info enabled ... WARNING: binary size might significantly increase" 18 | shift 19 | else 20 | PROFILE="release" 21 | fi 22 | 23 | echo 24 | echo "Building walrus-orchestrator docker image" 25 | echo "Dockerfile: \t$DOCKERFILE" 26 | echo "docker context: $REPO_ROOT" 27 | echo "build date: \t$BUILD_DATE" 28 | echo "git revision: \t$GIT_REVISION" 29 | echo 30 | 31 | docker build -f "$DOCKERFILE" "$REPO_ROOT" \ 32 | --build-arg GIT_REVISION="$GIT_REVISION" \ 33 | --build-arg BUILD_DATE="$BUILD_DATE" \ 34 | --build-arg PROFILE="$PROFILE" \ 35 | "$@" 36 | -------------------------------------------------------------------------------- /docker/walrus-proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.87-bookworm as builder 2 | 3 | ARG PROFILE=release 4 | WORKDIR /work 5 | 6 | RUN apt-get update && apt-get install -y cmake clang 7 | 8 | COPY .git/ .git/ 9 | COPY Cargo.toml Cargo.lock ./ 10 | COPY crates crates 11 | COPY contracts contracts 12 | 13 | RUN cargo build --profile ${PROFILE} --bin walrus-proxy 14 | 15 | FROM gcr.io/distroless/cc-debian12 as deploy 16 | 17 | COPY --from=builder --chmod=755 /work/target/release/walrus-proxy /opt/walrus/bin/walrus-proxy 18 | -------------------------------------------------------------------------------- /docker/walrus-service/Dockerfile.walrus-backup: -------------------------------------------------------------------------------- 1 | # Build walrus-backup image. 2 | # 3 | # Copy in all crates, Cargo.toml and Cargo.lock unmodified, 4 | # and build the application. 5 | FROM rust:1.87-bookworm AS builder 6 | ARG PROFILE=release 7 | ARG RUST_LOG=info,walrus_service::common::event_blob_downloader=warn 8 | ARG GIT_REVISION 9 | ENV GIT_REVISION=$GIT_REVISION 10 | WORKDIR "$WORKDIR/walrus" 11 | RUN apt-get update && apt-get install -y cmake clang 12 | 13 | COPY Cargo.toml Cargo.lock ./ 14 | COPY crates crates 15 | COPY contracts ./contracts 16 | COPY contracts /contracts 17 | 18 | RUN cargo build \ 19 | --features walrus-service/backup \ 20 | --profile $PROFILE \ 21 | --bin walrus-backup 22 | 23 | # Production Image for walrus backup CLI 24 | FROM debian:bookworm-slim AS walrus-backup 25 | RUN apt-get update && apt-get install -y ca-certificates curl libpq-dev 26 | ARG PROFILE=release 27 | 28 | ENV RUST_LOG=$RUST_LOG 29 | WORKDIR "$WORKDIR/walrus" 30 | # Both bench and release profiles copy from release dir 31 | COPY --from=builder /walrus/target/release/walrus-backup /opt/walrus/bin/walrus-backup 32 | 33 | ARG BUILD_DATE 34 | ARG GIT_REVISION 35 | LABEL build-date=$BUILD_DATE 36 | LABEL git-revision=$GIT_REVISION 37 | -------------------------------------------------------------------------------- /docker/walrus-service/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # fast fail. 6 | set -e 7 | 8 | DIR="$(cd "$(dirname "$0")" && pwd)" 9 | REPO_ROOT="$(git rev-parse --show-toplevel)" 10 | DOCKERFILE="$DIR/Dockerfile" 11 | GIT_REVISION="$(git describe --always --abbrev=12 --dirty --exclude '*')" 12 | BUILD_DATE="$(date -u +'%Y-%m-%d')" 13 | 14 | # option to build using debug symbols 15 | if [ "$1" = "--debug-symbols" ]; then 16 | PROFILE="bench" 17 | echo "Building with full debug info enabled ... WARNING: binary size might significantly increase" 18 | shift 19 | else 20 | PROFILE="release" 21 | fi 22 | 23 | echo 24 | echo "Building walrus-services docker images" 25 | echo "Dockerfile: \t$DOCKERFILE" 26 | echo "docker context: $REPO_ROOT" 27 | echo "build date: \t$BUILD_DATE" 28 | echo "git revision: \t$GIT_REVISION" 29 | echo 30 | 31 | docker build -f "$DOCKERFILE" "$REPO_ROOT" \ 32 | --build-arg GIT_REVISION="$GIT_REVISION" \ 33 | --build-arg BUILD_DATE="$BUILD_DATE" \ 34 | --build-arg PROFILE="$PROFILE" \ 35 | --target walrus-service \ 36 | "$@" 37 | -------------------------------------------------------------------------------- /docker/walrus-stress/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build application 2 | # 3 | # Copy in all crates, Cargo.toml and Cargo.lock unmodified, 4 | # and build the application. 5 | FROM rust:1.87-bookworm AS builder 6 | ARG PROFILE=release 7 | ARG GIT_REVISION 8 | ENV GIT_REVISION=$GIT_REVISION 9 | WORKDIR "$WORKDIR/walrus" 10 | RUN apt-get update && apt-get install -y cmake clang 11 | 12 | COPY Cargo.toml Cargo.lock ./ 13 | COPY crates crates 14 | COPY contracts contracts 15 | 16 | RUN cargo build --profile $PROFILE --bin walrus-stress --bin walrus 17 | 18 | # Production Image for walrus stress 19 | FROM debian:bookworm-slim AS walrus-stress 20 | RUN apt-get update && apt-get install -y ca-certificates curl 21 | ARG PROFILE=release 22 | WORKDIR "$WORKDIR/walrus" 23 | # Both bench and release profiles copy from release dir 24 | COPY --from=builder /walrus/target/release/walrus-stress /opt/walrus/bin/walrus-stress 25 | COPY --from=builder /walrus/target/release/walrus /opt/walrus/bin/walrus 26 | 27 | ARG BUILD_DATE 28 | ARG GIT_REVISION 29 | LABEL build-date=$BUILD_DATE 30 | LABEL git-revision=$GIT_REVISION 31 | -------------------------------------------------------------------------------- /docker/walrus-stress/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # fast fail. 6 | set -e 7 | 8 | DIR="$(cd "$(dirname "$0")" && pwd)" 9 | REPO_ROOT="$(git rev-parse --show-toplevel)" 10 | DOCKERFILE="$DIR/Dockerfile" 11 | GIT_REVISION="$(git describe --always --abbrev=12 --dirty --exclude '*')" 12 | BUILD_DATE="$(date -u +'%Y-%m-%d')" 13 | 14 | # option to build using debug symbols 15 | if [ "$1" = "--debug-symbols" ]; then 16 | PROFILE="bench" 17 | echo "Building with full debug info enabled ... WARNING: binary size might significantly increase" 18 | shift 19 | else 20 | PROFILE="release" 21 | fi 22 | 23 | echo 24 | echo "Building walrus-stress docker images" 25 | echo "Dockerfile: \t$DOCKERFILE" 26 | echo "docker context: $REPO_ROOT" 27 | echo "build date: \t$BUILD_DATE" 28 | echo "git revision: \t$GIT_REVISION" 29 | echo 30 | 31 | docker build \ 32 | --progress plain \ 33 | -f "$DOCKERFILE" "$REPO_ROOT" \ 34 | --build-arg GIT_REVISION="$GIT_REVISION" \ 35 | --build-arg BUILD_DATE="$BUILD_DATE" \ 36 | --build-arg PROFILE="$PROFILE" \ 37 | --target walrus-stress \ 38 | "$@" 39 | -------------------------------------------------------------------------------- /docs/assets/blob-hash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MystenLabs/walrus/ff441d22f77712c2291e0c7b6b34cc358d8cd448/docs/assets/blob-hash.png -------------------------------------------------------------------------------- /docs/assets/sliver-hash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MystenLabs/walrus/ff441d22f77712c2291e0c7b6b34cc358d8cd448/docs/assets/sliver-hash.png -------------------------------------------------------------------------------- /docs/book/assets/WriteFlow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MystenLabs/walrus/ff441d22f77712c2291e0c7b6b34cc358d8cd448/docs/book/assets/WriteFlow.png -------------------------------------------------------------------------------- /docs/book/assets/suins-asset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MystenLabs/walrus/ff441d22f77712c2291e0c7b6b34cc358d8cd448/docs/book/assets/suins-asset.png -------------------------------------------------------------------------------- /docs/book/assets/walrus-sites-hash-mismatch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MystenLabs/walrus/ff441d22f77712c2291e0c7b6b34cc358d8cd448/docs/book/assets/walrus-sites-hash-mismatch.png -------------------------------------------------------------------------------- /docs/book/blog/00_intro.md: -------------------------------------------------------------------------------- 1 | # The Walrus Dev Blog 2 | 3 | This part of the Walrus documentation is used to publish news and updates about Walrus's 4 | development! 5 | 6 | ```admonish warning 7 | We generally keep older blog posts unchanged besides possibly fixing typos and updating or removing 8 | broken links. As a result they may contain information that is no longer accurate. 9 | ``` 10 | -------------------------------------------------------------------------------- /docs/book/design/future.md: -------------------------------------------------------------------------------- 1 | # Future discussion 2 | 3 | In this document, we left out details of the following features: 4 | 5 | - **Shard transfer and recovery upon storage epoch change:** The encoding scheme used in Walrus has 6 | been designed to allow for highly efficient recovery in case of shard failures. A storage node 7 | attempting to recover slivers only needs to get data of the same magnitude as the missing data to 8 | reconstruct them. 9 | - **Details of light clients that can be used to sample availability:** Individual clients may 10 | sample the certified blobs from Sui metadata and sample the availability of some slivers that 11 | they store. On-chain bounties may be used to retrieve these slivers for missing blobs. 12 | -------------------------------------------------------------------------------- /docs/book/design/operations.md: -------------------------------------------------------------------------------- 1 | # Operations 2 | 3 | Walrus operations can be separated in [interactions with the Sui chain](./operations-sui.md), which 4 | is used by Walrus for coordination and governance, and [off-chain 5 | interactions](./operations-off-chain.md) between clients and storage nodes. 6 | -------------------------------------------------------------------------------- /docs/book/design/overview.md: -------------------------------------------------------------------------------- 1 | # System overview 2 | 3 | This chapter provides an overview of the [architecture](./architecture.md) and [encoding 4 | mechanisms](./encoding.md) of the Walrus system. 5 | 6 | Use the [glossary](../glossary.md) as a reference for many of the bolded terms used in this 7 | documentation. 8 | -------------------------------------------------------------------------------- /docs/book/dev-guide/components.md: -------------------------------------------------------------------------------- 1 | # Components 2 | 3 | From a developer perspective, some Walrus components are objects and smart contracts on 4 | Sui, and some components are Walrus-specific binaries and services. As a rule, Sui is used to 5 | manage blob and storage node metadata, while Walrus-specific services are used to store and 6 | read blob contents, which can be very large. 7 | 8 | Walrus defines a number of objects and smart contracts on Sui: 9 | 10 | - A shared *system object* records and manages the current committee of storage nodes. 11 | - *Storage resources* represent empty storage space that may be used to store blobs. 12 | - *Blob resources* represent blobs being registered and certified as stored. 13 | - Changes to these objects emit *Walrus-related events*. 14 | 15 | The Walrus system object ID can be found in the Walrus `client_config.yaml` file (see 16 | [Configuration](../usage/setup.md#configuration)). You may use any Sui explorer to look at its 17 | content, as well as explore the content of blob objects. There is more information about these in 18 | the [quick reference to the Walrus Sui structures](sui-struct.md). 19 | 20 | Walrus is also composed of a number of Walrus-specific services and binaries: 21 | 22 | - A client (binary) can be executed locally and provides a 23 | [Command Line Interface (CLI)](../usage/client-cli.md), a [JSON API](../usage/json-api.md) 24 | and an [HTTP API](../usage/web-api.md) to perform Walrus operations. 25 | - Aggregator services allow reading blobs via HTTP requests. 26 | - Publisher services are used to store blobs to Walrus. 27 | - A set of storage nodes store encoded blobs. These nodes form the decentralized 28 | storage infrastructure of Walrus. 29 | 30 | Aggregators, publishers, and other services use the client APIs to interact with Walrus. End users 31 | of services using Walrus interact with the store via custom services, aggregators, or publishers 32 | that expose HTTP APIs to avoid the need to run locally a binary client. 33 | -------------------------------------------------------------------------------- /docs/book/dev-guide/data-security.md: -------------------------------------------------------------------------------- 1 | # Data security 2 | 3 | Walrus provides decentralized storage for application and user data. 4 | Walrus ensures availability and integrity but does not provide native encryption for data. 5 | By default, all blobs stored in Walrus are public and discoverable by all. 6 | If your app needs encryption or access control, secure data before uploading to Walrus. 7 | 8 | ## Securing data with Seal 9 | 10 | Use [Seal](https://github.com/MystenLabs/seal) for encryption and onchain access control. 11 | 12 | Seal allows you to: 13 | 14 | - Encrypt data using threshold encryption, where no single party holds the full decryption key. 15 | - Define onchain access policies that determine who can decrypt the data and under what conditions. 16 | - Store encrypted content on Walrus while keeping decryption logic verifiable and flexible. 17 | 18 | Seal integrates naturally with Walrus and is recommended for any use case involving: 19 | 20 | - Sensitive offchain content (e.g., user documents, game assets, private messages) 21 | - Time-locked or token-gated data 22 | - Data shared between trusted parties or roles 23 | 24 | To get started, refer to the [Seal SDK](https://www.npmjs.com/package/@mysten/seal). 25 | -------------------------------------------------------------------------------- /docs/book/dev-guide/dev-guide.md: -------------------------------------------------------------------------------- 1 | # Developer guide 2 | 3 | This guide introduces all the concepts needed to build applications that use Walrus as a storage 4 | or availability layer. The [overview](../design/overview.md) provides more background and explains 5 | in more detail how Walrus operates internally. 6 | 7 | This developer guide describes the following: 8 | 9 | - [Components](components.md) of Walrus of interest to developers that wish to use it for 10 | storage or availability. 11 | - [Operations](dev-operations.md) supported through client binaries, APIs, or Sui operations. 12 | - [Cost](costs.md) components of storage, how they are measured, and considerations for managing those. 13 | - [The Sui structures](sui-struct.md) Walrus uses to store metadata, and how they can be read 14 | from Sui smart contracts, or through the Sui SDK. 15 | - [Data security](data-security.md) guidance for encryption and access control of data stored on Walrus. 16 | 17 | Refer again to the [glossary](../glossary.md) of terms as a reference. 18 | -------------------------------------------------------------------------------- /docs/book/setup/client_config.yaml: -------------------------------------------------------------------------------- 1 | ../../../setup/client_config.yaml -------------------------------------------------------------------------------- /docs/book/setup/client_config_example.yaml: -------------------------------------------------------------------------------- 1 | ../../../crates/walrus-sdk/client_config_example.yaml -------------------------------------------------------------------------------- /docs/book/setup/client_config_mainnet.yaml: -------------------------------------------------------------------------------- 1 | ../../../setup/client_config_mainnet.yaml -------------------------------------------------------------------------------- /docs/book/setup/client_config_testnet.yaml: -------------------------------------------------------------------------------- 1 | ../../../setup/client_config_testnet.yaml -------------------------------------------------------------------------------- /docs/book/setup/walrus-install.sh: -------------------------------------------------------------------------------- 1 | ../../../setup/walrus-install.sh -------------------------------------------------------------------------------- /docs/book/usage/interacting.md: -------------------------------------------------------------------------------- 1 | # Interacting with Walrus 2 | 3 | We provide 3 ways to interact directly with the Walrus storage system: 4 | 5 | - Through the Walrus [client command line interface (CLI)](./client-cli.md). 6 | - Through a [JSON API](./json-api.md) of the Walrus CLI. 7 | - Through an [HTTP API](./web-api.md) exposed by a public or local Walrus client daemon. 8 | 9 | Furthermore, users can [stake and unstake](./stake.md) through the staking dApp or Sui smart 10 | contracts. 11 | -------------------------------------------------------------------------------- /docs/book/usage/json-api.md: -------------------------------------------------------------------------------- 1 | # JSON mode 2 | 3 | All Walrus client commands are also available in JSON mode. In this mode, all the command-line flags 4 | of the original CLI command can be specified in JSON format. The JSON mode therefore simplifies 5 | programmatic access to the CLI. 6 | 7 | For example, to store a blob, run: 8 | 9 | ```sh 10 | walrus json \ 11 | '{ 12 | "config": "path/to/client_config.yaml", 13 | "command": { 14 | "store": { 15 | "files": ["README.md", "LICENSE"], 16 | "epochs": 100 17 | } 18 | } 19 | }' 20 | ``` 21 | 22 | Or, to read a blob knowing the blob ID: 23 | 24 | ```sh 25 | walrus json \ 26 | '{ 27 | "config": "path/to/client_config.yaml", 28 | "command": { 29 | "read": { 30 | "blobId": "4BKcDC0Ih5RJ8R0tFMz3MZVNZV8b2goT6_JiEEwNHQo" 31 | } 32 | } 33 | }' 34 | ``` 35 | 36 | All options, default values, and commands are equal to those of the "standard" CLI mode, except that 37 | they are written in "camelCase" instead of "kebab-case". 38 | 39 | The `json` command also accepts input from `stdin`. 40 | 41 | The output of a `json` command will itself be JSON-formatted, again to simplify parsing the results 42 | in a programmatic way. For example, the JSON output can be piped to the `jq` command for parsing and 43 | manually extracting relevant fields. 44 | -------------------------------------------------------------------------------- /docs/book/usage/started.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | You want to get a taste of Walrus? Here are some sites that are built on and/or use Walrus: 4 | 5 | - [Mint a toy NFT](https://flatland.wal.app) on the flatland application. 6 | - [Browse scientific papers](https://snowreads.wal.app). 7 | 8 | You can explore blobs that are stored on Walrus through the [Walruscan explorer](https://walruscan.com). 9 | -------------------------------------------------------------------------------- /docs/book/usage/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | ```admonish tip title="Debug logging" 4 | You can enable debug logging for Walrus by setting the environment variable `RUST_LOG=walrus=debug`. 5 | ``` 6 | 7 | ## Latest binary 8 | 9 | Before undertaking any other steps, make sure you have the [latest `walrus` 10 | binary](./setup.md#installation). If you have multiple versions in different locations, find the 11 | binary that will actually be used with `which walrus`. 12 | 13 | ## Old hardware or incompatible VMs 14 | 15 | Our standard Ubuntu binary is known to cause problems on certain old hardware and in certain 16 | virtualized environments. If you experience errors like "Illegal instruction (core dumped)", 17 | [install](./setup.md#installation) the `ubuntu-x86_64-generic` version instead, which is compiled 18 | specifically to be compatible with almost all physical and virtual x86-64 CPUs. 19 | 20 | ## Correct Sui network configuration 21 | 22 | If you get an error like "the specified Walrus system object does not exist", make sure your wallet 23 | is set up for the correct Sui network (Mainnet or Testnet as you may require) and you use the latest 24 | [configuration](./setup.md#configuration). 25 | 26 | ## Latest Walrus configuration 27 | 28 | The Walrus Testnet is wiped periodically and requires updating to the latest binary and 29 | configuration. If you get an error like "could not retrieve enough confirmations to certify the 30 | blob", you are probably using an outdated configuration pointing to an inactive Walrus system. In 31 | this case, update your configuration file with the latest [configuration](./setup.md#configuration) 32 | and make sure the CLI uses the intended configuration. 33 | 34 | ```admonish tip 35 | When setting `RUST_LOG=info`, the `walrus` client binary prints information about the used 36 | configuration when starting execution, including the path to the Walrus configuration file and the 37 | Sui wallet. 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/book/walrus-sites/advanced.md: -------------------------------------------------------------------------------- 1 | # Advanced functionality 2 | 3 | Keep reading to learn about the advanced features of Walrus Sites, including configuring the site 4 | builder, specifying headers and routing for site resources, and *redirecting Sui objects to Walrus 5 | Sites* to create per-object websites! 6 | -------------------------------------------------------------------------------- /docs/book/walrus-sites/bring-your-own-domain.md: -------------------------------------------------------------------------------- 1 | # Bringing your own domain 2 | 3 | In the previous section, we learned how to [deploy a Walrus Sites portal](./portal.md). Now, 4 | there might be cases where you want your Walrus Site under a specific domain, without following 5 | the default naming convention of `https://.`. 6 | 7 | Fro example, you might want to use a domain like `https://example.com`, instead of 8 | `https://example.wal.app`, where `example.com` is a classic DNS domain that you can purchase 9 | from any domain registrar. It will point to the IP and port of your portal. 10 | 11 | Finally, you will need to configure your portal so that it only accepts requests for your own site, 12 | and other subdomains (i.e. other Walrus Sites) will not be served. 13 | 14 | The steps you have to follow are: 15 | 16 | 1. [Deploy a local portal](./portal.md) and include these additional environment variables to 17 | your `.env.local`: 18 | 19 | ```bash 20 | LANDING_PAGE_OID_B36=34kgqayivjvwuwtk6lckk792g4qhpnimt58eol8i0b2tdgb0y # Example b36 ID 21 | BRING_YOUR_OWN_DOMAIN=true 22 | ``` 23 | 24 | The `LANDING_PAGE_OID_B36`, should be the b36 object ID of your Walrus Site. 25 | 26 | Set `BRING_YOUR_OWN_DOMAIN` to true to ensure the portal only serves your domain and no other 27 | sites. i.e. `https://.example.com` should throw a 404 error. 28 | 29 | 1. Configure your DNS provider to point your domain to the IP and port of your portal. 30 | 31 | And that's it! You now have a Walrus Site under your own domain. 32 | -------------------------------------------------------------------------------- /docs/book/walrus-sites/privacy.md: -------------------------------------------------------------------------------- 1 | # Privacy policy 2 | -------------------------------------------------------------------------------- /docs/book/walrus-sites/redirects.md: -------------------------------------------------------------------------------- 1 | # Redirecting objects to Walrus Sites 2 | 3 | We have seen in the [overview](./overview.md) how a Walrus Site object on Sui looks like. We will 4 | discuss now how you can create ensure that a *set of arbitrary objects* can all be tied to a 5 | specific, and possibly unique, Walrus Site. 6 | 7 | ## The goal 8 | 9 | Consider a collection of NFTs, such as the one published by . As we 10 | show there, each minted NFT has its own Walrus Site, which can be personalized based on the contents 11 | (e.g., the color) of the NFT itself. How can we achieve this? 12 | 13 | ## Redirect links 14 | 15 | The solution is simple: We add a "redirect" in the NFT's 16 | [`Display`](https://docs.sui.io/standards/display#sui-utility-objects) property. Each time an NFT's 17 | object ID is browsed through a portal, the portal will check the `Display` of the NFT and, if it 18 | encounters the `walrus site address` key, it will go fetch the Walrus Site that is at the 19 | corresponding object ID. 20 | 21 | ### Redirects in Move 22 | 23 | Practically speaking, when creating the `Display` of the NFT, you can include the key-value pair 24 | that points to the Walrus Site that is to be used. 25 | 26 | ``` move 27 | ... 28 | const VISUALIZATION_SITE: address = @0x901fb0...; 29 | display.add(b"walrus site address".to_string(), VISUALIZATION_SITE.to_string()); 30 | ... 31 | ``` 32 | 33 | ### How to change the site based on the NFT? 34 | 35 | The code above will only open the specified Walrus Site when browsing the object ID of the NFT. How 36 | do we ensure that the properties of the NFT can be used to personalize the site? 37 | 38 | This needs to be done in the `VISUALIZATION_SITE`: Since the subdomain is still pointing to the 39 | NFT's object ID, the Walrus Site that is loaded can check its `origin` in JavaScript, and use the 40 | subdomain to determine the NFT, fetch it from chain, and use its internal fields to modify the 41 | displayed site. 42 | 43 | For an end-to-end example, see the `flatland` 44 | [repo](https://github.com/MystenLabs/example-walrus-sites/tree/main/flatland). 45 | -------------------------------------------------------------------------------- /docs/book/walrus-sites/tutorial.md: -------------------------------------------------------------------------------- 1 | # Your first Walrus Site 2 | 3 | This tutorial walks you through the steps necessary to publish a Walrus Site. We also provide the 4 | instructions on how to add a SuiNS name to it for convenient browsing. 5 | -------------------------------------------------------------------------------- /docs/book/walrus.pdf: -------------------------------------------------------------------------------- 1 | walrus_whitepaper_v2.pdf -------------------------------------------------------------------------------- /docs/book/walrus_whitepaper_v1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MystenLabs/walrus/ff441d22f77712c2291e0c7b6b34cc358d8cd448/docs/book/walrus_whitepaper_v1.pdf -------------------------------------------------------------------------------- /docs/book/walrus_whitepaper_v2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MystenLabs/walrus/ff441d22f77712c2291e0c7b6b34cc358d8cd448/docs/book/walrus_whitepaper_v2.pdf -------------------------------------------------------------------------------- /docs/examples/CONFIG/bin/README.md: -------------------------------------------------------------------------------- 1 | # Walrus binary 2 | 3 | Place the `walrus` client binary for your system in this directory. 4 | 5 | See [the installation documentation](https://docs.wal.app/usage/setup.html#installation) for how 6 | to obtain the binary. 7 | -------------------------------------------------------------------------------- /docs/examples/CONFIG/config_dir/README.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | Place the `client_config.yaml` configuration file in this directory. 4 | 5 | See [the configuration documentation](https://docs.wal.app/usage/setup.html#configuration) for 6 | details of the available parameters and how to obtain the mandatory parameters. 7 | -------------------------------------------------------------------------------- /docs/examples/javascript/README.md: -------------------------------------------------------------------------------- 1 | # Walrus HTML + JavaScript Examples 2 | 3 | ## Prerequisites 4 | 5 | - Set up Sui and Walrus as described in the 6 | [documentation](https://docs.wal.app/usage/setup.html). 7 | - If you don't want to use the public aggregator and publisher: Run the client in [daemon 8 | mode](https://docs.wal.app/usage/web-api.html). 9 | 10 | ## Index of examples 11 | 12 | - [`blob_upload_download_webapi.html`](./blob_upload_download_webapi.html) shows how to store a blob 13 | using JavaScript and to embed the blob accessible from a Walrus aggregator in an HTML document. 14 | - [`system_stats.html`](./system_stats.html) shows how to read the system parameters from Sui and 15 | display some of them in a table. 16 | -------------------------------------------------------------------------------- /docs/examples/move/walrus_dep/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walrus_dep" 3 | edition = "2024.beta" 4 | 5 | [dependencies] 6 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "testnet-v1.35.0" } 7 | Walrus = { git = "https://github.com/MystenLabs/walrus.git", rev = "main", subdir = "contracts/walrus" } 8 | 9 | [addresses] 10 | sui = "0x2" 11 | walrus_dep = "0x0" 12 | -------------------------------------------------------------------------------- /docs/examples/move/walrus_dep/README.md: -------------------------------------------------------------------------------- 1 | # Example Move package depending on Walrus 2 | 3 | A simple example of depending on the Walrus Testnet Move package. 4 | 5 | You can build, test, and publish this with the following commands (from this directory): 6 | 7 | ```sh 8 | sui move build 9 | sui move test 10 | sui client publish --skip-dependency-verification 11 | ``` 12 | -------------------------------------------------------------------------------- /docs/examples/move/walrus_dep/sources/tests/walrus_dep_tests.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #[test_only] 5 | #[allow(unused_use)] 6 | module walrus_dep::walrus_dep_tests { 7 | use walrus_dep::wrapped_blob; 8 | 9 | const ENotImplemented: u64 = 0; 10 | 11 | #[test] 12 | fun test_walrus_dep() { 13 | // pass 14 | } 15 | 16 | #[test, expected_failure(abort_code = ::walrus_dep::walrus_dep_tests::ENotImplemented)] 17 | fun test_walrus_dep_fail() { 18 | abort ENotImplemented 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docs/examples/move/walrus_dep/sources/wrapped_blob.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus_dep::wrapped_blob { 5 | use walrus::blob::Blob; 6 | 7 | public struct WrappedBlob has key { 8 | id: UID, 9 | blob: Blob, 10 | } 11 | 12 | public fun wrap(blob: Blob, ctx: &mut TxContext): WrappedBlob { 13 | WrappedBlob { id: object::new(ctx), blob } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docs/examples/python/README.md: -------------------------------------------------------------------------------- 1 | # Walrus Python Examples 2 | 3 | ## Prerequisites 4 | 5 | - Set up Sui and Walrus as described [here](https://docs.wal.app/usage/setup.html). 6 | - Optional: Set up a Python virtual environment: 7 | 8 | ```sh 9 | python -m venv .venv 10 | source .venv/bin/activate 11 | ``` 12 | 13 | - Install the dependencies: 14 | 15 | ```sh 16 | pip install -r requirements.txt 17 | ``` 18 | 19 | - Update the paths `PATH_TO_WALRUS` and `PATH_TO_WALRUS_CONFIG` and other constant in `utils.py`. 20 | 21 | ## Index of examples 22 | 23 | - `hello_walrus_jsonapi.py` shows how to store and read blobs using the JSON API of the Walrus 24 | client. 25 | - `hello_walrus_webapi.py` shows how to store and read blobs using the HTTP API of the Walrus 26 | client. 27 | - `track_walrus_events.py` is a simple script to track all Walrus-related events on Sui. 28 | -------------------------------------------------------------------------------- /docs/examples/python/requirements.txt: -------------------------------------------------------------------------------- 1 | requests>=2.22.0 2 | -------------------------------------------------------------------------------- /docs/examples/python/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Walrus Foundation 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import base64 5 | 6 | # Configure these paths to match your system 7 | FULL_NODE_URL = "https://fullnode.testnet.sui.io:443" 8 | PATH_TO_WALRUS = "../CONFIG/bin/walrus" 9 | PATH_TO_WALRUS_CONFIG = "../CONFIG/config_dir/client_config.yaml" 10 | 11 | 12 | # Convert a numeric (u256) blob_id to a base64 encoded Blob ID 13 | def num_to_blob_id(blob_id_num): 14 | extracted_bytes = [] 15 | for i in range(32): 16 | extracted_bytes += [blob_id_num & 0xFF] 17 | blob_id_num = blob_id_num >> 8 18 | assert blob_id_num == 0 19 | blob_id_bytes = bytes(extracted_bytes) 20 | encoded = base64.urlsafe_b64encode(blob_id_bytes) 21 | return encoded.decode("ascii").strip("=") 22 | 23 | 24 | if __name__ == "__main__": 25 | # A test case for the num_to_blob_id function 26 | blob_id_num = ( 27 | 46269954626831698189342469164469112511517843773769981308926739591706762839432 28 | ) 29 | blob_id_base64 = "iIWkkUTzPZx-d1E_A7LqUynnYFD-ztk39_tP8MLdS2Y" 30 | assert num_to_blob_id(blob_id_num) == blob_id_base64 31 | -------------------------------------------------------------------------------- /docs/telemetry-attributes.csv: -------------------------------------------------------------------------------- 1 | id;type;brief;note 2 | walrus.blob_id;string;Url-safe base64 encoded blob ID. 3 | walrus.epoch;int;Walrus epoch. 4 | walrus.node.public_key;string;Base64 encoded public key of a walrus node. 5 | walrus.shard_index;int;Index of a shard within the Walrus committee. 6 | walrus.sliver.pair_index;int;Index of a sliver pair within the encoding of a blob. 7 | walrus.sliver.remote_pair_index;int;Index of a sliver pair located at a remote node. 8 | walrus.sliver.type;string;Type of the encoded sliver.;One of `primary`, `secondary`. 9 | walrus.recovery.symbol_type;string;Type of the recovery symbol;One of `primary`, `secondary`. 10 | walrus.event.tx_digest;string;Digest of the Sui transaction that generated the event. 11 | walrus.event.epoch;int;Epoch in which the event was generated. 12 | walrus.event.event_seq;int;Sequence number of the event in the Sui transaction that generated it. 13 | walrus.event.kind;string;Type of the Walrus event;One of `certified`, `registered`, `invalid-blob`. 14 | walrus.event.index;int;Index of the Walrus event in the stream of all events. 15 | # TODO(jsmith): Change string repr of shard index 16 | -------------------------------------------------------------------------------- /docs/theme/tabs.css: -------------------------------------------------------------------------------- 1 | .mdbook-tabs { 2 | display: flex; 3 | } 4 | 5 | .mdbook-tab { 6 | background-color: var(--table-alternate-bg); 7 | padding: 0.5rem 1rem; 8 | cursor: pointer; 9 | border: none; 10 | font-size: 1.6rem; 11 | line-height: 1.45em; 12 | } 13 | 14 | .mdbook-tab.active { 15 | background-color: var(--table-header-bg); 16 | font-weight: bold; 17 | } 18 | 19 | .mdbook-tab-content { 20 | padding: 1rem 0rem; 21 | } 22 | 23 | .mdbook-tab-content table { 24 | margin: unset; 25 | } 26 | -------------------------------------------------------------------------------- /licensesnip.config.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "use_gitignore": true, 3 | "file_types": { 4 | "move": { 5 | "before_line": "// " 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /mainnet-contracts/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useModuleLabel": true, 3 | "autoGroupImports": "package" 4 | } 5 | -------------------------------------------------------------------------------- /mainnet-contracts/subsidies/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "9A2082DC6F53FA70312454FB0E4E66F3442B2529705FE6BCB044AC8E71B81E04" 6 | deps_digest = "060AD7E57DFB13104F21BE5F5C3759D03F0553FC3229247D9A7A6B45F50D03A3" 7 | dependencies = [ 8 | { id = "Sui", name = "Sui" }, 9 | { id = "WAL", name = "WAL" }, 10 | { id = "Walrus", name = "Walrus" }, 11 | ] 12 | 13 | [[move.package]] 14 | id = "MoveStdlib" 15 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.44.3", subdir = "crates/sui-framework/packages/move-stdlib" } 16 | 17 | [[move.package]] 18 | id = "Sui" 19 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.44.3", subdir = "crates/sui-framework/packages/sui-framework" } 20 | 21 | dependencies = [ 22 | { id = "MoveStdlib", name = "MoveStdlib" }, 23 | ] 24 | 25 | [[move.package]] 26 | id = "WAL" 27 | source = { local = "../wal" } 28 | 29 | dependencies = [ 30 | { id = "Sui", name = "Sui" }, 31 | ] 32 | 33 | [[move.package]] 34 | id = "Walrus" 35 | source = { local = "../walrus" } 36 | 37 | dependencies = [ 38 | { id = "Sui", name = "Sui" }, 39 | { id = "WAL", name = "WAL" }, 40 | ] 41 | 42 | [move.toolchain-version] 43 | compiler-version = "1.44.3" 44 | edition = "2024.beta" 45 | flavor = "sui" 46 | 47 | [env] 48 | 49 | [env.mainnet] 50 | chain-id = "35834a8a" 51 | original-published-id = "0xd843c37d213ea683ec3519abe4646fd618f52d7fce1c4e9875a4144d53e21ebc" 52 | latest-published-id = "0xd843c37d213ea683ec3519abe4646fd618f52d7fce1c4e9875a4144d53e21ebc" 53 | published-version = "1" 54 | -------------------------------------------------------------------------------- /mainnet-contracts/subsidies/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "Subsidies" 3 | license = "Apache-2.0" 4 | authors = ["Mysten Labs "] 5 | edition = "2024.beta" 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "testnet-v1.44.3" } 9 | WAL = { local = "../wal" } 10 | Walrus = { local = "../walrus" } 11 | 12 | [addresses] 13 | subsidies = "0x0" 14 | -------------------------------------------------------------------------------- /mainnet-contracts/wal/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "498CF889960139A5523E778325E052F14A68529E0BA1DAEF212FAD88D50CAEC9" 6 | deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082" 7 | dependencies = [ 8 | { id = "Sui", name = "Sui" }, 9 | ] 10 | 11 | [[move.package]] 12 | id = "MoveStdlib" 13 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.43.0", subdir = "crates/sui-framework/packages/move-stdlib" } 14 | 15 | [[move.package]] 16 | id = "Sui" 17 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.43.0", subdir = "crates/sui-framework/packages/sui-framework" } 18 | 19 | dependencies = [ 20 | { id = "MoveStdlib", name = "MoveStdlib" }, 21 | ] 22 | 23 | [move.toolchain-version] 24 | compiler-version = "1.43.0" 25 | edition = "2024.beta" 26 | flavor = "sui" 27 | 28 | [env.mainnet] 29 | chain-id = "35834a8a" 30 | original-published-id = "0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59" 31 | latest-published-id = "0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59" 32 | published-version = "1" 33 | -------------------------------------------------------------------------------- /mainnet-contracts/wal/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "WAL" 3 | license = "Apache-2.0" 4 | authors = ["Mysten Labs "] 5 | edition = "2024.beta" 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "testnet-v1.44.3" } 9 | 10 | [addresses] 11 | wal = "0x0" 12 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "4BC589454DF8DC51D8FEC230BFFDCA8B2013DD09197792A169A73B22DDF64907" 6 | deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" 7 | dependencies = [ 8 | { id = "Sui", name = "Sui" }, 9 | { id = "WAL", name = "WAL" }, 10 | ] 11 | 12 | [[move.package]] 13 | id = "MoveStdlib" 14 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.44.3", subdir = "crates/sui-framework/packages/move-stdlib" } 15 | 16 | [[move.package]] 17 | id = "Sui" 18 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.44.3", subdir = "crates/sui-framework/packages/sui-framework" } 19 | 20 | dependencies = [ 21 | { id = "MoveStdlib", name = "MoveStdlib" }, 22 | ] 23 | 24 | [[move.package]] 25 | id = "WAL" 26 | source = { local = "../wal" } 27 | 28 | dependencies = [ 29 | { id = "Sui", name = "Sui" }, 30 | ] 31 | 32 | [move.toolchain-version] 33 | compiler-version = "1.49.2" 34 | edition = "2024.beta" 35 | flavor = "sui" 36 | 37 | [env] 38 | 39 | [env.mainnet] 40 | chain-id = "35834a8a" 41 | original-published-id = "0xfdc88f7d7cf30afab2f82e8380d11ee8f70efb90e863d1de8616fae1bb09ea77" 42 | latest-published-id = "0x5bb4a7183558164440dbd04a0501efb50467b504005337a5bd0686ad5b0420e4" 43 | published-version = "2" 44 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "Walrus" 3 | license = "Apache-2.0" 4 | authors = ["Mysten Labs "] 5 | edition = "2024.beta" 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "testnet-v1.44.3" } 9 | WAL = { local = "../wal" } 10 | 11 | [addresses] 12 | walrus = "0x0" 13 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/sources/staking/auth.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::auth; 5 | 6 | /// Authentication for either a sender or an object. 7 | /// Unlike the `Authorized` type, it cannot be stored and must be used or ignored in the same 8 | /// transaction. 9 | public enum Authenticated has drop { 10 | Sender(address), 11 | Object(ID), 12 | } 13 | 14 | /// Defines the ways to authorize an action. It can be either an address - checked 15 | /// with `ctx.sender()`, - or an object - checked with `object::id(..)`. 16 | public enum Authorized has copy, drop, store { 17 | Address(address), 18 | ObjectID(ID), 19 | } 20 | 21 | /// Authenticates the sender as the authorizer. 22 | public fun authenticate_sender(ctx: &TxContext): Authenticated { 23 | Authenticated::Sender(ctx.sender()) 24 | } 25 | 26 | /// Authenticates an object as the authorizer. 27 | public fun authenticate_with_object(obj: &T): Authenticated { 28 | Authenticated::Object(object::id(obj)) 29 | } 30 | 31 | /// Returns the `Authorized` as an address. 32 | public fun authorized_address(addr: address): Authorized { 33 | Authorized::Address(addr) 34 | } 35 | 36 | /// Returns the `Authorized` as an object. 37 | public fun authorized_object(id: ID): Authorized { 38 | Authorized::ObjectID(id) 39 | } 40 | 41 | /// Checks if the authentication matches the authorization. 42 | public(package) fun matches(authenticated: &Authenticated, authorized: &Authorized): bool { 43 | match (authenticated) { 44 | Authenticated::Sender(sender) => { 45 | match (authorized) { 46 | Authorized::Address(addr) => sender == addr, 47 | _ => false, 48 | } 49 | }, 50 | Authenticated::Object(id) => { 51 | match (authorized) { 52 | Authorized::ObjectID(obj_id) => id == obj_id, 53 | _ => false, 54 | } 55 | }, 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/sources/staking/walrus_context.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Module: `walrus_context` 5 | /// 6 | /// Implements the `WalrusContext` struct which is used to store the current 7 | /// state of the system. Improves testing and readability of signatures by 8 | /// aggregating the parameters into a single struct. Context is used almost 9 | /// everywhere in the system, so it is important to have a single source of 10 | /// truth for the current state. 11 | module walrus::walrus_context; 12 | 13 | use sui::vec_map::VecMap; 14 | 15 | /// Represents the current values in the Walrus system. Helps avoid passing 16 | /// too many parameters to functions, and allows for easier testing. 17 | public struct WalrusContext has drop { 18 | /// Current Walrus epoch 19 | epoch: u32, 20 | /// Whether the committee has been selected for the next epoch. 21 | committee_selected: bool, 22 | /// The current committee in the system. 23 | committee: VecMap>, 24 | } 25 | 26 | /// Create a new `WalrusContext` object. 27 | public(package) fun new( 28 | epoch: u32, 29 | committee_selected: bool, 30 | committee: VecMap>, 31 | ): WalrusContext { 32 | WalrusContext { epoch, committee_selected, committee } 33 | } 34 | 35 | /// Read the current `epoch` from the context. 36 | public(package) fun epoch(self: &WalrusContext): u32 { self.epoch } 37 | 38 | /// Read the current `committee_selected` from the context. 39 | public(package) fun committee_selected(self: &WalrusContext): bool { self.committee_selected } 40 | 41 | /// Read the current `committee` from the context. 42 | public(package) fun committee(self: &WalrusContext): &VecMap> { &self.committee } 43 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/sources/system/encoding.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::encoding; 5 | 6 | use walrus::redstuff; 7 | 8 | // Supported Encoding Types 9 | // RedStuff with Reed-Solomon 10 | const RS2: u8 = 1; 11 | 12 | // Error codes 13 | // Error types in `walrus-sui/types/move_errors.rs` are auto-generated from the Move error codes. 14 | /// The encoding type is invalid. 15 | const EInvalidEncodingType: u64 = 0; 16 | 17 | /// Computes the encoded length of a blob given its unencoded length, encoding type 18 | /// and number of shards `n_shards`. 19 | public fun encoded_blob_length(unencoded_length: u64, encoding_type: u8, n_shards: u16): u64 { 20 | // Currently only supports the two RedStuff variants. 21 | assert!(encoding_type == RS2, EInvalidEncodingType); 22 | redstuff::encoded_blob_length(unencoded_length, n_shards) 23 | } 24 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/sources/system/epoch_parameters.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::epoch_parameters; 5 | 6 | /// The epoch parameters for the system. 7 | public struct EpochParams has copy, drop, store { 8 | /// The storage capacity of the system. 9 | total_capacity_size: u64, 10 | /// The price per unit size of storage. 11 | storage_price_per_unit_size: u64, 12 | /// The write price per unit size. 13 | write_price_per_unit_size: u64, 14 | } 15 | 16 | // === Constructor === 17 | 18 | public(package) fun new( 19 | total_capacity_size: u64, 20 | storage_price_per_unit_size: u64, 21 | write_price_per_unit_size: u64, 22 | ): EpochParams { 23 | EpochParams { 24 | total_capacity_size, 25 | storage_price_per_unit_size, 26 | write_price_per_unit_size, 27 | } 28 | } 29 | 30 | // === Accessors === 31 | 32 | /// The storage capacity of the system. 33 | public(package) fun capacity(self: &EpochParams): u64 { 34 | self.total_capacity_size 35 | } 36 | 37 | /// The price per unit size of storage. 38 | public(package) fun storage_price(self: &EpochParams): u64 { 39 | self.storage_price_per_unit_size 40 | } 41 | 42 | /// The write price per unit size. 43 | public(package) fun write_price(self: &EpochParams): u64 { 44 | self.write_price_per_unit_size 45 | } 46 | 47 | // === Test only === 48 | 49 | #[test_only] 50 | public fun epoch_params_for_testing(): EpochParams { 51 | EpochParams { 52 | total_capacity_size: 1_000_000_000, 53 | storage_price_per_unit_size: 5, 54 | write_price_per_unit_size: 1, 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/sources/system/metadata.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Contains the metadata for Blobs on Walrus. 5 | module walrus::metadata; 6 | 7 | use std::string::String; 8 | use sui::vec_map::{Self, VecMap}; 9 | 10 | /// The metadata struct for Blob objects. 11 | public struct Metadata has drop, store { 12 | metadata: VecMap, 13 | } 14 | 15 | /// Creates a new instance of Metadata. 16 | public fun new(): Metadata { 17 | Metadata { 18 | metadata: vec_map::empty(), 19 | } 20 | } 21 | 22 | /// Inserts a key-value pair into the metadata. 23 | /// 24 | /// If the key is already present, the value is updated. 25 | public fun insert_or_update(self: &mut Metadata, key: String, value: String) { 26 | if (self.metadata.contains(&key)) { 27 | self.metadata.remove(&key); 28 | }; 29 | self.metadata.insert(key, value); 30 | } 31 | 32 | /// Removes the metadata associated with the given key. 33 | public fun remove(self: &mut Metadata, key: &String): (String, String) { 34 | self.metadata.remove(key) 35 | } 36 | 37 | /// Removes the metadata associated with the given key, if it exists. 38 | /// 39 | /// Optionally returns the previous value associated with the key. 40 | public fun remove_if_exists(self: &mut Metadata, key: &String): option::Option { 41 | if (self.metadata.contains(key)) { 42 | let (_, value) = self.metadata.remove(key); 43 | option::some(value) 44 | } else { 45 | option::none() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/sources/system/shared_blob.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::shared_blob; 5 | 6 | use sui::{balance::{Self, Balance}, coin::Coin}; 7 | use wal::wal::WAL; 8 | use walrus::{blob::Blob, system::System}; 9 | 10 | /// A wrapper around `Blob` that acts as a "tip jar" that can be funded by anyone and allows 11 | /// keeping the wrapped `Blob` alive indefinitely. 12 | public struct SharedBlob has key, store { 13 | id: UID, 14 | blob: Blob, 15 | funds: Balance, 16 | } 17 | 18 | /// Shares the provided `blob` as a `SharedBlob` with zero funds. 19 | public fun new(blob: Blob, ctx: &mut TxContext) { 20 | transfer::share_object(SharedBlob { 21 | id: object::new(ctx), 22 | blob, 23 | funds: balance::zero(), 24 | }) 25 | } 26 | 27 | /// Shares the provided `blob` as a `SharedBlob` with funds. 28 | public fun new_funded(blob: Blob, funds: Coin, ctx: &mut TxContext) { 29 | transfer::share_object(SharedBlob { 30 | id: object::new(ctx), 31 | blob, 32 | funds: funds.into_balance(), 33 | }) 34 | } 35 | 36 | /// Adds the provided `Coin` to the stored funds. 37 | public fun fund(self: &mut SharedBlob, added_funds: Coin) { 38 | self.funds.join(added_funds.into_balance()); 39 | } 40 | 41 | /// Extends the lifetime of the wrapped `Blob` by `extended_epochs` epochs if the stored funds are 42 | /// sufficient and the new lifetime does not exceed the maximum lifetime. 43 | public fun extend( 44 | self: &mut SharedBlob, 45 | system: &mut System, 46 | extended_epochs: u32, 47 | ctx: &mut TxContext, 48 | ) { 49 | let mut coin = self.funds.withdraw_all().into_coin(ctx); 50 | system.extend_blob(&mut self.blob, extended_epochs, &mut coin); 51 | self.funds.join(coin.into_balance()); 52 | } 53 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/sources/utils/extended_field.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Module: extended_field 5 | module walrus::extended_field; 6 | 7 | use sui::dynamic_field as df; 8 | 9 | /// Extended field acts as a field, but stored in a dynamic field, hence, it does 10 | /// not bloat the original object's storage, storing only `UID` of the extended 11 | /// field. 12 | public struct ExtendedField has key, store { id: UID } 13 | 14 | /// Key to store the value in the extended field. Never changes. 15 | public struct Key() has copy, drop, store; 16 | 17 | /// Creates a new extended field with the given value. 18 | public fun new(value: T, ctx: &mut TxContext): ExtendedField { 19 | let mut id = object::new(ctx); 20 | df::add(&mut id, Key(), value); 21 | ExtendedField { id } 22 | } 23 | 24 | /// Borrows the value stored in the extended field. 25 | public fun borrow(field: &ExtendedField): &T { 26 | df::borrow(&field.id, Key()) 27 | } 28 | 29 | /// Borrows the value stored in the extended field mutably. 30 | public fun borrow_mut(field: &mut ExtendedField): &mut T { 31 | df::borrow_mut(&mut field.id, Key()) 32 | } 33 | 34 | /// Swaps the value stored in the extended field with the given value. 35 | public fun swap(field: &mut ExtendedField, value: T): T { 36 | let old = df::remove(&mut field.id, Key()); 37 | df::add(&mut field.id, Key(), value); 38 | old 39 | } 40 | 41 | /// Destroys the extended field and returns the value stored in it. 42 | public fun destroy(field: ExtendedField): T { 43 | let ExtendedField { mut id } = field; 44 | let value = df::remove(&mut id, Key()); 45 | id.delete(); 46 | value 47 | } 48 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/sources/utils/sort.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Implements sorting macros for commonly used data structures. 5 | module walrus::sort; 6 | 7 | use sui::vec_map::{Self, VecMap}; 8 | 9 | /// Sort the given `VecMap` by the node ID transformed into `u256`. 10 | /// 11 | /// Uses the insertion sort algorithm, given that the `VecMap` is already mostly sorted. 12 | public macro fun sort_vec_map_by_node_id<$V>($self: VecMap): VecMap { 13 | let self = $self; 14 | 15 | if (self.size() <= 1) return self; 16 | let (mut keys, mut values) = self.into_keys_values(); 17 | let len = keys.length(); 18 | let mut i = 1; 19 | 20 | while (i < len) { 21 | let mut j = i; 22 | while (j > 0 && keys[j - 1].to_address().to_u256() > keys[j].to_address().to_u256()) { 23 | keys.swap(j - 1, j); 24 | values.swap(j - 1, j); 25 | j = j - 1; 26 | }; 27 | i = i + 1; 28 | }; 29 | 30 | vec_map::from_keys_values(keys, values) 31 | } 32 | 33 | /// Check if the given `VecMap` is sorted by the node ID transformed into `u256`. 34 | public macro fun is_vec_map_sorted_by_node_id<$V>($self: &VecMap): bool { 35 | let self = $self; 36 | 37 | let len = self.size(); 38 | if (len <= 1) return true; 39 | let mut i = 1; 40 | while (i < len) { 41 | let (lhs, _) = self.get_entry_by_idx(i - 1); 42 | let (rhs, _) = self.get_entry_by_idx(i); 43 | if (lhs.to_address().to_u256() > rhs.to_address().to_u256()) { 44 | return false 45 | }; 46 | i = i + 1; 47 | }; 48 | 49 | true 50 | } 51 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/tests/staking/walrus_context_tests.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::walrus_context_tests; 5 | 6 | use sui::vec_map; 7 | use walrus::walrus_context; 8 | 9 | #[test] 10 | // Scenario: Test the WalrusContext flow 11 | fun test_walrus_context_flow() { 12 | let walrus_ctx = walrus_context::new(1, true, vec_map::empty()); 13 | 14 | // assert that the WalrusContext is created correctly 15 | assert!(walrus_ctx.epoch() == 1); 16 | assert!(walrus_ctx.committee_selected() == true); 17 | } 18 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/tests/system/metadata_tests.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #[test_only] 5 | module walrus::metadata_tests; 6 | 7 | use sui::vec_map::EKeyDoesNotExist; 8 | use walrus::metadata; 9 | 10 | #[test] 11 | public fun test_metadata_success() { 12 | let mut metadata = metadata::new(); 13 | metadata.insert_or_update(b"key1".to_string(), b"value1".to_string()); 14 | metadata.insert_or_update(b"key2".to_string(), b"value2".to_string()); 15 | // Update the value corresponding to key1. 16 | metadata.insert_or_update(b"key1".to_string(), b"value3".to_string()); 17 | let (key, value) = metadata.remove(&b"key1".to_string()); 18 | assert!(key == b"key1".to_string()); 19 | assert!(value == b"value3".to_string()); 20 | } 21 | 22 | #[test, expected_failure(abort_code = EKeyDoesNotExist)] 23 | public fun test_metadata_failure() { 24 | let mut metadata = metadata::new(); 25 | metadata.insert_or_update(b"key1".to_string(), b"value1".to_string()); 26 | metadata.remove(&b"key2".to_string()); 27 | } 28 | -------------------------------------------------------------------------------- /mainnet-contracts/walrus/tests/system/ringbuffer_tests.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #[test_only] 5 | module walrus::ringbuffer_tests; 6 | 7 | use sui::test_utils::destroy; 8 | use walrus::storage_accounting::{Self as sa, FutureAccountingRingBuffer}; 9 | 10 | #[test] 11 | public fun test_basic_ring_buffer() { 12 | let mut buffer: FutureAccountingRingBuffer = sa::ring_new(3); 13 | 14 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 0)) == 0, 100); 15 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 1)) == 1, 100); 16 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 2)) == 2, 100); 17 | 18 | let entry = sa::ring_pop_expand(&mut buffer); 19 | assert!(sa::epoch(&entry) == 0, 100); 20 | sa::delete_empty_future_accounting(entry); 21 | 22 | let entry = sa::ring_pop_expand(&mut buffer); 23 | assert!(sa::epoch(&entry) == 1, 100); 24 | sa::delete_empty_future_accounting(entry); 25 | 26 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 0)) == 2, 100); 27 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 1)) == 3, 100); 28 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 2)) == 4, 100); 29 | 30 | destroy(buffer) 31 | } 32 | 33 | #[test, expected_failure(abort_code = sa::ETooFarInFuture)] 34 | public fun test_oob_fail_ring_buffer() { 35 | let mut buffer: FutureAccountingRingBuffer = sa::ring_new(3); 36 | 37 | sa::epoch(sa::ring_lookup_mut(&mut buffer, 3)); 38 | 39 | abort 40 | } 41 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.87" 3 | components = ["clippy", "rustfmt"] 4 | -------------------------------------------------------------------------------- /scripts/cache-inference/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /scripts/cache-inference/README.md: -------------------------------------------------------------------------------- 1 | # Cache Inference Script 2 | 3 | Detects and updates cache configuration for Walrus aggregators by analyzing response headers and request timing. 4 | 5 | ## Overview 6 | 7 | The script makes two sequential requests to each aggregator and determines caching status through: 8 | 1. **Headers**: Detects cache-related headers with "hit" values 9 | 2. **Performance**: Identifies caching through response time improvements (>1000ms) 10 | 11 | ## Usage 12 | 13 | ```bash 14 | npm install --prefix scripts/cache-inference 15 | npx ts-node ./cache-inference.ts [testnetBlobId] [--verbose] 16 | ``` 17 | 18 | ### Arguments 19 | 20 | - `mainnetBlobId`: Blob ID for mainnet testing 21 | - `testnetBlobId`: (Optional) Blob ID for testnet testing 22 | - `--verbose`: Enable detailed logging 23 | 24 | ## How It Works 25 | 26 | 1. Reads aggregator URLs from `docs/book/assets/operators.json` 27 | 2. For each aggregator: 28 | - Makes two requests to `v1/blobs/{blobId}` 29 | - Checks headers and timing 30 | - Updates cache status 31 | 32 | ## Output 33 | 34 | JSON containing updated cache information for all aggregators. With `--verbose`, includes: 35 | - Cache headers 36 | - Response times with speedup 37 | -------------------------------------------------------------------------------- /scripts/cache-inference/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cache-inference", 3 | "version": "1.0.0", 4 | "description": "Infers cache status for aggregators in docs/book/assets/operators.json.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/node": "^22.14.1", 14 | "@types/yargs": "^17.0.33" 15 | }, 16 | "dependencies": { 17 | "yargs": "^17.7.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scripts/cache-inference/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | // For importing json 5 | "resolveJsonModule": true, 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /scripts/cache-inference/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export type Network = "mainnet" | "testnet"; 5 | 6 | export type AggregatorData = { 7 | cache?: boolean; 8 | operator?: string; 9 | [key: string]: unknown; 10 | } 11 | 12 | export type PublisherData = { 13 | operator?: string 14 | [key: string]: unknown; 15 | }; 16 | 17 | export type NetworkData = { 18 | aggregators: Record; 19 | publishers?: Record; 20 | }; 21 | 22 | export type Operators = Record 23 | 24 | type NotExisting = undefined; 25 | type NullHeaderValue = null; 26 | export type HeaderValue = string | NotExisting | NullHeaderValue 27 | 28 | // Includes more info on the measured request for debugging purposes 29 | // Enabled using `--verbose` 30 | export type AggregatorDataVerbose = AggregatorData & { 31 | cacheHeaders?: Record; 32 | cacheSpeedupMs?: [number, [number, number]]; 33 | }; 34 | 35 | export type NetworkDataVerbose = { 36 | aggregators?: Record; 37 | publishers?: Record; 38 | }; 39 | -------------------------------------------------------------------------------- /scripts/simtest/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Walrus Foundation 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | cd "$(dirname "${BASH_SOURCE[0]}")" 6 | 7 | BIN_DIR="$HOME/.cargo/bin" 8 | SOURCE_DIR=$(pwd) 9 | 10 | if [ ! -d "$BIN_DIR" ]; then 11 | echo "$BIN_DIR not found." 12 | echo "Please place cargo-simtest (from this directory) somewhere in your PATH" 13 | exit 1 14 | fi 15 | 16 | SIMTEST=$BIN_DIR/cargo-simtest 17 | 18 | cat < "$SIMTEST" || exit 1 19 | #!/bin/bash 20 | 21 | REPO_ROOT=\$(git rev-parse --show-toplevel) 22 | source "\$REPO_ROOT/scripts/simtest/cargo-simtest" 23 | EOF 24 | 25 | chmod +x "$SIMTEST" 26 | 27 | echo "Installed cargo-simtest to $SIMTEST" 28 | echo "You can now run simulator tests via \`cargo simtest\`" 29 | -------------------------------------------------------------------------------- /setup/client_config.yaml: -------------------------------------------------------------------------------- 1 | contexts: 2 | mainnet: 3 | system_object: 0x2134d52768ea07e8c43570ef975eb3e4c27a39fa6396bef985b5abc58d03ddd2 4 | staking_object: 0x10b9d30c28448939ce6c4d6c6e0ffce4a7f8a4ada8248bdad09ef8b70e4a3904 5 | subsidies_object: 0xb606eb177899edc2130c93bf65985af7ec959a2755dc126c953755e59324209e 6 | exchange_objects: [] 7 | wallet_config: 8 | # Path to the wallet config file. 9 | path: ~/.sui/sui_config/client.yaml 10 | # Sui environment to use. 11 | active_env: mainnet 12 | # Optional override for the Sui address to use. 13 | # active_address: 0x0000000000000000000000000000000000000000000000000000000000000000 14 | rpc_urls: 15 | - https://fullnode.mainnet.sui.io:443 16 | testnet: 17 | system_object: 0x6c2547cbbc38025cf3adac45f63cb0a8d12ecf777cdc75a4971612bf97fdf6af 18 | staking_object: 0xbe46180321c30aab2f8b3501e24048377287fa708018a5b7c2792b35fe339ee3 19 | subsidies_object: 0xda799d85db0429765c8291c594d334349ef5bc09220e79ad397b30106161a0af 20 | exchange_objects: 21 | - 0xf4d164ea2def5fe07dc573992a029e010dba09b1a8dcbc44c5c2e79567f39073 22 | - 0x19825121c52080bb1073662231cfea5c0e4d905fd13e95f21e9a018f2ef41862 23 | - 0x83b454e524c71f30803f4d6c302a86fb6a39e96cdfb873c2d1e93bc1c26a3bc5 24 | - 0x8d63209cf8589ce7aef8f262437163c67577ed09f3e636a9d8e0813843fb8bf1 25 | wallet_config: 26 | # Path to the wallet config file. 27 | path: ~/.sui/sui_config/client.yaml 28 | # Sui environment to use. 29 | active_env: testnet 30 | # Optional override for the Sui address to use. 31 | # active_address: 0x0000000000000000000000000000000000000000000000000000000000000000 32 | rpc_urls: 33 | - https://fullnode.testnet.sui.io:443 34 | default_context: mainnet 35 | -------------------------------------------------------------------------------- /setup/client_config_mainnet.yaml: -------------------------------------------------------------------------------- 1 | system_object: 0x2134d52768ea07e8c43570ef975eb3e4c27a39fa6396bef985b5abc58d03ddd2 2 | staking_object: 0x10b9d30c28448939ce6c4d6c6e0ffce4a7f8a4ada8248bdad09ef8b70e4a3904 3 | subsidies_object: 0xb606eb177899edc2130c93bf65985af7ec959a2755dc126c953755e59324209e 4 | rpc_urls: 5 | - https://fullnode.mainnet.sui.io:443 6 | -------------------------------------------------------------------------------- /setup/client_config_testnet.yaml: -------------------------------------------------------------------------------- 1 | system_object: 0x6c2547cbbc38025cf3adac45f63cb0a8d12ecf777cdc75a4971612bf97fdf6af 2 | staking_object: 0xbe46180321c30aab2f8b3501e24048377287fa708018a5b7c2792b35fe339ee3 3 | subsidies_object: 0xda799d85db0429765c8291c594d334349ef5bc09220e79ad397b30106161a0af 4 | exchange_objects: 5 | - 0xf4d164ea2def5fe07dc573992a029e010dba09b1a8dcbc44c5c2e79567f39073 6 | - 0x19825121c52080bb1073662231cfea5c0e4d905fd13e95f21e9a018f2ef41862 7 | - 0x83b454e524c71f30803f4d6c302a86fb6a39e96cdfb873c2d1e93bc1c26a3bc5 8 | - 0x8d63209cf8589ce7aef8f262437163c67577ed09f3e636a9d8e0813843fb8bf1 9 | rpc_urls: 10 | - https://fullnode.testnet.sui.io:443 11 | -------------------------------------------------------------------------------- /testnet-contracts/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useModuleLabel": true, 3 | "autoGroupImports": "package" 4 | } 5 | -------------------------------------------------------------------------------- /testnet-contracts/README.md: -------------------------------------------------------------------------------- 1 | # Walrus Testnet Move contracts 2 | 3 | This is the Move source code for the current Walrus Testnet instance, which are deployed on Sui 4 | Testnet. The latest version information can be found at the bottom of the 5 | [`walrus/Move.lock`](./walrus/Move.lock) file. 6 | 7 | ## Updating the contracts 8 | 9 | To update the contracts, you need access to the wallet that published the contracts (address 10 | `0x181816cd2efb860628385e8653b37260d0d065c844803b23852799cc19ee2c28`). Then, do the following: 11 | 12 | 1. Modify the source files in this directory and commit your changes. 13 | 1. Create a draft PR and have it reviewed. 14 | 1. Publish the updated contracts: 15 | - Either as quorum-based upgrade by having the storage nodes vote on the upgrade (using the 16 | `walrus node-admin vote-for-upgrade` command, and then deploying the upgrade using 17 | `walrus-deploy upgrade`). 18 | - Or by using the `walrus-deploy emergency-upgrade` command. 19 | 1. Create a commit, push your changes, get the PR approved, and merge your changes. 20 | -------------------------------------------------------------------------------- /testnet-contracts/subsidies/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "7D3EC9AC3AE1895448AFE91D1E31951D29DA5580478064B100D1B6E0596B6E8F" 6 | deps_digest = "060AD7E57DFB13104F21BE5F5C3759D03F0553FC3229247D9A7A6B45F50D03A3" 7 | dependencies = [ 8 | { id = "Sui", name = "Sui" }, 9 | { id = "WAL", name = "WAL" }, 10 | { id = "Walrus", name = "Walrus" }, 11 | ] 12 | 13 | [[move.package]] 14 | id = "MoveStdlib" 15 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.45.2", subdir = "crates/sui-framework/packages/move-stdlib" } 16 | 17 | [[move.package]] 18 | id = "Sui" 19 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.45.2", subdir = "crates/sui-framework/packages/sui-framework" } 20 | 21 | dependencies = [ 22 | { id = "MoveStdlib", name = "MoveStdlib" }, 23 | ] 24 | 25 | [[move.package]] 26 | id = "WAL" 27 | source = { local = "../wal" } 28 | 29 | dependencies = [ 30 | { id = "Sui", name = "Sui" }, 31 | ] 32 | 33 | [[move.package]] 34 | id = "Walrus" 35 | source = { local = "../walrus" } 36 | 37 | dependencies = [ 38 | { id = "Sui", name = "Sui" }, 39 | { id = "WAL", name = "WAL" }, 40 | ] 41 | 42 | [move.toolchain-version] 43 | compiler-version = "1.48.2" 44 | edition = "2024.beta" 45 | flavor = "sui" 46 | 47 | [env] 48 | 49 | [env.testnet] 50 | chain-id = "4c78adac" 51 | original-published-id = "0x015906b499d8cdc40f23ab94431bf3fe488a8548f8ae17199a72b2e9df341ca5" 52 | latest-published-id = "0x5ec2288d2596e72025e04f0db241e636f3e531b0c02c073e5d436c16faee150e" 53 | published-version = "2" 54 | -------------------------------------------------------------------------------- /testnet-contracts/subsidies/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "Subsidies" 3 | license = "Apache-2.0" 4 | authors = ["Mysten Labs "] 5 | edition = "2024.beta" 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "testnet-v1.45.2" } 9 | WAL = { local = "../wal" } 10 | Walrus = { local = "../walrus" } 11 | 12 | [addresses] 13 | subsidies = "0x0" 14 | -------------------------------------------------------------------------------- /testnet-contracts/wal/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "4920D3E9D7A8BCF314A0D311035D2D8A5B76557D2548D203C7A730654B3713F8" 6 | deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082" 7 | dependencies = [ 8 | { id = "Sui", name = "Sui" }, 9 | ] 10 | 11 | [[move.package]] 12 | id = "MoveStdlib" 13 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.45.2", subdir = "crates/sui-framework/packages/move-stdlib" } 14 | 15 | [[move.package]] 16 | id = "Sui" 17 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.45.2", subdir = "crates/sui-framework/packages/sui-framework" } 18 | 19 | dependencies = [ 20 | { id = "MoveStdlib", name = "MoveStdlib" }, 21 | ] 22 | 23 | [move.toolchain-version] 24 | compiler-version = "1.45.2" 25 | edition = "2024.beta" 26 | flavor = "sui" 27 | 28 | [env] 29 | 30 | [env.testnet] 31 | chain-id = "4c78adac" 32 | original-published-id = "0x8270feb7375eee355e64fdb69c50abb6b5f9393a722883c1cf45f8e26048810a" 33 | latest-published-id = "0x8270feb7375eee355e64fdb69c50abb6b5f9393a722883c1cf45f8e26048810a" 34 | published-version = "1" 35 | -------------------------------------------------------------------------------- /testnet-contracts/wal/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "WAL" 3 | license = "Apache-2.0" 4 | authors = ["Mysten Labs "] 5 | edition = "2024.beta" 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "testnet-v1.45.2" } 9 | 10 | [addresses] 11 | wal = "0x0" 12 | -------------------------------------------------------------------------------- /testnet-contracts/wal_exchange/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "0941FEB8236855102019EC19D531BB66DB5287B683D74F972A8959EA2B95C55C" 6 | deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" 7 | dependencies = [ 8 | { id = "Sui", name = "Sui" }, 9 | { id = "WAL", name = "WAL" }, 10 | ] 11 | 12 | [[move.package]] 13 | id = "MoveStdlib" 14 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.45.2", subdir = "crates/sui-framework/packages/move-stdlib" } 15 | 16 | [[move.package]] 17 | id = "Sui" 18 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.45.2", subdir = "crates/sui-framework/packages/sui-framework" } 19 | 20 | dependencies = [ 21 | { id = "MoveStdlib", name = "MoveStdlib" }, 22 | ] 23 | 24 | [[move.package]] 25 | id = "WAL" 26 | source = { local = "../wal" } 27 | 28 | dependencies = [ 29 | { id = "Sui", name = "Sui" }, 30 | ] 31 | 32 | [move.toolchain-version] 33 | compiler-version = "1.45.2" 34 | edition = "2024.beta" 35 | flavor = "sui" 36 | 37 | [env] 38 | 39 | [env.testnet] 40 | chain-id = "4c78adac" 41 | original-published-id = "0x82593828ed3fcb8c6a235eac9abd0adbe9c5f9bbffa9b1e7a45cdd884481ef9f" 42 | latest-published-id = "0x82593828ed3fcb8c6a235eac9abd0adbe9c5f9bbffa9b1e7a45cdd884481ef9f" 43 | published-version = "1" 44 | -------------------------------------------------------------------------------- /testnet-contracts/wal_exchange/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "WAL_exchange" 3 | license = "Apache-2.0" 4 | authors = ["Mysten Labs "] 5 | edition = "2024.beta" 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "testnet-v1.45.2" } 9 | WAL = { local = "../wal" } 10 | 11 | [addresses] 12 | wal_exchange = "0x0" 13 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "B19E2F7794666D554736D7DD3B21005ADC920AF0A56F1C6C705491FAB00B363F" 6 | deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" 7 | dependencies = [ 8 | { id = "Sui", name = "Sui" }, 9 | { id = "WAL", name = "WAL" }, 10 | ] 11 | 12 | [[move.package]] 13 | id = "MoveStdlib" 14 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.45.2", subdir = "crates/sui-framework/packages/move-stdlib" } 15 | 16 | [[move.package]] 17 | id = "Sui" 18 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet-v1.45.2", subdir = "crates/sui-framework/packages/sui-framework" } 19 | 20 | dependencies = [ 21 | { id = "MoveStdlib", name = "MoveStdlib" }, 22 | ] 23 | 24 | [[move.package]] 25 | id = "WAL" 26 | source = { local = "../wal" } 27 | 28 | dependencies = [ 29 | { id = "Sui", name = "Sui" }, 30 | ] 31 | 32 | [move.toolchain-version] 33 | compiler-version = "1.45.2" 34 | edition = "2024.beta" 35 | flavor = "sui" 36 | 37 | [env] 38 | 39 | [env.testnet] 40 | chain-id = "4c78adac" 41 | original-published-id = "0xd84704c17fc870b8764832c535aa6b11f21a95cd6f5bb38a9b07d2cf42220c66" 42 | latest-published-id = "0xd84704c17fc870b8764832c535aa6b11f21a95cd6f5bb38a9b07d2cf42220c66" 43 | published-version = "1" 44 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "Walrus" 3 | license = "Apache-2.0" 4 | authors = ["Mysten Labs "] 5 | edition = "2024.beta" 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "testnet-v1.45.2" } 9 | WAL = { local = "../wal" } 10 | 11 | [addresses] 12 | walrus = "0x0" 13 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/sources/staking/auth.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::auth; 5 | 6 | /// Authentication for either a sender or an object. 7 | /// Unlike the `Authorized` type, it cannot be stored and must be used or ignored in the same 8 | /// transaction. 9 | public enum Authenticated has drop { 10 | Sender(address), 11 | Object(ID), 12 | } 13 | 14 | /// Defines the ways to authorize an action. It can be either an address - checked 15 | /// with `ctx.sender()`, - or an object - checked with `object::id(..)`. 16 | public enum Authorized has copy, drop, store { 17 | Address(address), 18 | ObjectID(ID), 19 | } 20 | 21 | /// Authenticates the sender as the authorizer. 22 | public fun authenticate_sender(ctx: &TxContext): Authenticated { 23 | Authenticated::Sender(ctx.sender()) 24 | } 25 | 26 | /// Authenticates an object as the authorizer. 27 | public fun authenticate_with_object(obj: &T): Authenticated { 28 | Authenticated::Object(object::id(obj)) 29 | } 30 | 31 | /// Returns the `Authorized` as an address. 32 | public fun authorized_address(addr: address): Authorized { 33 | Authorized::Address(addr) 34 | } 35 | 36 | /// Returns the `Authorized` as an object. 37 | public fun authorized_object(id: ID): Authorized { 38 | Authorized::ObjectID(id) 39 | } 40 | 41 | /// Checks if the authentication matches the authorization. 42 | public(package) fun matches(authenticated: &Authenticated, authorized: &Authorized): bool { 43 | match (authenticated) { 44 | Authenticated::Sender(sender) => { 45 | match (authorized) { 46 | Authorized::Address(addr) => sender == addr, 47 | _ => false, 48 | } 49 | }, 50 | Authenticated::Object(id) => { 51 | match (authorized) { 52 | Authorized::ObjectID(obj_id) => id == obj_id, 53 | _ => false, 54 | } 55 | }, 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/sources/staking/walrus_context.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Module: `walrus_context` 5 | /// 6 | /// Implements the `WalrusContext` struct which is used to store the current 7 | /// state of the system. Improves testing and readability of signatures by 8 | /// aggregating the parameters into a single struct. Context is used almost 9 | /// everywhere in the system, so it is important to have a single source of 10 | /// truth for the current state. 11 | module walrus::walrus_context; 12 | 13 | use sui::vec_map::VecMap; 14 | 15 | /// Represents the current values in the Walrus system. Helps avoid passing 16 | /// too many parameters to functions, and allows for easier testing. 17 | public struct WalrusContext has drop { 18 | /// Current Walrus epoch 19 | epoch: u32, 20 | /// Whether the committee has been selected for the next epoch. 21 | committee_selected: bool, 22 | /// The current committee in the system. 23 | committee: VecMap>, 24 | } 25 | 26 | /// Create a new `WalrusContext` object. 27 | public(package) fun new( 28 | epoch: u32, 29 | committee_selected: bool, 30 | committee: VecMap>, 31 | ): WalrusContext { 32 | WalrusContext { epoch, committee_selected, committee } 33 | } 34 | 35 | /// Read the current `epoch` from the context. 36 | public(package) fun epoch(self: &WalrusContext): u32 { self.epoch } 37 | 38 | /// Read the current `committee_selected` from the context. 39 | public(package) fun committee_selected(self: &WalrusContext): bool { self.committee_selected } 40 | 41 | /// Read the current `committee` from the context. 42 | public(package) fun committee(self: &WalrusContext): &VecMap> { &self.committee } 43 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/sources/system/encoding.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::encoding; 5 | 6 | use walrus::redstuff; 7 | 8 | // Supported Encoding Types 9 | // RedStuff with Reed-Solomon 10 | const RS2: u8 = 1; 11 | 12 | // Error codes 13 | // Error types in `walrus-sui/types/move_errors.rs` are auto-generated from the Move error codes. 14 | /// The encoding type is invalid. 15 | const EInvalidEncodingType: u64 = 0; 16 | 17 | /// Computes the encoded length of a blob given its unencoded length, encoding type 18 | /// and number of shards `n_shards`. 19 | public fun encoded_blob_length(unencoded_length: u64, encoding_type: u8, n_shards: u16): u64 { 20 | // Currently only supports the two RedStuff variants. 21 | assert!(encoding_type == RS2, EInvalidEncodingType); 22 | redstuff::encoded_blob_length(unencoded_length, n_shards) 23 | } 24 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/sources/system/epoch_parameters.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::epoch_parameters; 5 | 6 | /// The epoch parameters for the system. 7 | public struct EpochParams has copy, drop, store { 8 | /// The storage capacity of the system. 9 | total_capacity_size: u64, 10 | /// The price per unit size of storage. 11 | storage_price_per_unit_size: u64, 12 | /// The write price per unit size. 13 | write_price_per_unit_size: u64, 14 | } 15 | 16 | // === Constructor === 17 | 18 | public(package) fun new( 19 | total_capacity_size: u64, 20 | storage_price_per_unit_size: u64, 21 | write_price_per_unit_size: u64, 22 | ): EpochParams { 23 | EpochParams { 24 | total_capacity_size, 25 | storage_price_per_unit_size, 26 | write_price_per_unit_size, 27 | } 28 | } 29 | 30 | // === Accessors === 31 | 32 | /// The storage capacity of the system. 33 | public(package) fun capacity(self: &EpochParams): u64 { 34 | self.total_capacity_size 35 | } 36 | 37 | /// The price per unit size of storage. 38 | public(package) fun storage_price(self: &EpochParams): u64 { 39 | self.storage_price_per_unit_size 40 | } 41 | 42 | /// The write price per unit size. 43 | public(package) fun write_price(self: &EpochParams): u64 { 44 | self.write_price_per_unit_size 45 | } 46 | 47 | // === Test only === 48 | 49 | #[test_only] 50 | public fun epoch_params_for_testing(): EpochParams { 51 | EpochParams { 52 | total_capacity_size: 1_000_000_000, 53 | storage_price_per_unit_size: 5, 54 | write_price_per_unit_size: 1, 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/sources/system/metadata.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Contains the metadata for Blobs on Walrus. 5 | module walrus::metadata; 6 | 7 | use std::string::String; 8 | use sui::vec_map::{Self, VecMap}; 9 | 10 | /// The metadata struct for Blob objects. 11 | public struct Metadata has drop, store { 12 | metadata: VecMap, 13 | } 14 | 15 | /// Creates a new instance of Metadata. 16 | public fun new(): Metadata { 17 | Metadata { 18 | metadata: vec_map::empty(), 19 | } 20 | } 21 | 22 | /// Inserts a key-value pair into the metadata. 23 | /// 24 | /// If the key is already present, the value is updated. 25 | public fun insert_or_update(self: &mut Metadata, key: String, value: String) { 26 | if (self.metadata.contains(&key)) { 27 | self.metadata.remove(&key); 28 | }; 29 | self.metadata.insert(key, value); 30 | } 31 | 32 | /// Removes the metadata associated with the given key. 33 | public fun remove(self: &mut Metadata, key: &String): (String, String) { 34 | self.metadata.remove(key) 35 | } 36 | 37 | /// Removes the metadata associated with the given key, if it exists. 38 | /// 39 | /// Optionally returns the previous value associated with the key. 40 | public fun remove_if_exists(self: &mut Metadata, key: &String): option::Option { 41 | if (self.metadata.contains(key)) { 42 | let (_, value) = self.metadata.remove(key); 43 | option::some(value) 44 | } else { 45 | option::none() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/sources/system/shared_blob.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::shared_blob; 5 | 6 | use sui::{balance::{Self, Balance}, coin::Coin}; 7 | use wal::wal::WAL; 8 | use walrus::{blob::Blob, system::System}; 9 | 10 | /// A wrapper around `Blob` that acts as a "tip jar" that can be funded by anyone and allows 11 | /// keeping the wrapped `Blob` alive indefinitely. 12 | public struct SharedBlob has key, store { 13 | id: UID, 14 | blob: Blob, 15 | funds: Balance, 16 | } 17 | 18 | /// Shares the provided `blob` as a `SharedBlob` with zero funds. 19 | public fun new(blob: Blob, ctx: &mut TxContext) { 20 | transfer::share_object(SharedBlob { 21 | id: object::new(ctx), 22 | blob, 23 | funds: balance::zero(), 24 | }) 25 | } 26 | 27 | /// Shares the provided `blob` as a `SharedBlob` with funds. 28 | public fun new_funded(blob: Blob, funds: Coin, ctx: &mut TxContext) { 29 | transfer::share_object(SharedBlob { 30 | id: object::new(ctx), 31 | blob, 32 | funds: funds.into_balance(), 33 | }) 34 | } 35 | 36 | /// Adds the provided `Coin` to the stored funds. 37 | public fun fund(self: &mut SharedBlob, added_funds: Coin) { 38 | self.funds.join(added_funds.into_balance()); 39 | } 40 | 41 | /// Extends the lifetime of the wrapped `Blob` by `extended_epochs` epochs if the stored funds are 42 | /// sufficient and the new lifetime does not exceed the maximum lifetime. 43 | public fun extend( 44 | self: &mut SharedBlob, 45 | system: &mut System, 46 | extended_epochs: u32, 47 | ctx: &mut TxContext, 48 | ) { 49 | let mut coin = self.funds.withdraw_all().into_coin(ctx); 50 | system.extend_blob(&mut self.blob, extended_epochs, &mut coin); 51 | self.funds.join(coin.into_balance()); 52 | } 53 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/sources/utils/extended_field.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Module: extended_field 5 | module walrus::extended_field; 6 | 7 | use sui::dynamic_field as df; 8 | 9 | /// Extended field acts as a field, but stored in a dynamic field, hence, it does 10 | /// not bloat the original object's storage, storing only `UID` of the extended 11 | /// field. 12 | public struct ExtendedField has key, store { id: UID } 13 | 14 | /// Key to store the value in the extended field. Never changes. 15 | public struct Key() has copy, drop, store; 16 | 17 | /// Creates a new extended field with the given value. 18 | public fun new(value: T, ctx: &mut TxContext): ExtendedField { 19 | let mut id = object::new(ctx); 20 | df::add(&mut id, Key(), value); 21 | ExtendedField { id } 22 | } 23 | 24 | /// Borrows the value stored in the extended field. 25 | public fun borrow(field: &ExtendedField): &T { 26 | df::borrow(&field.id, Key()) 27 | } 28 | 29 | /// Borrows the value stored in the extended field mutably. 30 | public fun borrow_mut(field: &mut ExtendedField): &mut T { 31 | df::borrow_mut(&mut field.id, Key()) 32 | } 33 | 34 | /// Swaps the value stored in the extended field with the given value. 35 | public fun swap(field: &mut ExtendedField, value: T): T { 36 | let old = df::remove(&mut field.id, Key()); 37 | df::add(&mut field.id, Key(), value); 38 | old 39 | } 40 | 41 | /// Destroys the extended field and returns the value stored in it. 42 | public fun destroy(field: ExtendedField): T { 43 | let ExtendedField { mut id } = field; 44 | let value = df::remove(&mut id, Key()); 45 | id.delete(); 46 | value 47 | } 48 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/sources/utils/sort.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Implements sorting macros for commonly used data structures. 5 | module walrus::sort; 6 | 7 | use sui::vec_map::{Self, VecMap}; 8 | 9 | /// Sort the given `VecMap` by the node ID transformed into `u256`. 10 | /// 11 | /// Uses the insertion sort algorithm, given that the `VecMap` is already mostly sorted. 12 | public macro fun sort_vec_map_by_node_id<$V>($self: VecMap): VecMap { 13 | let self = $self; 14 | 15 | if (self.size() <= 1) return self; 16 | let (mut keys, mut values) = self.into_keys_values(); 17 | let len = keys.length(); 18 | let mut i = 1; 19 | 20 | while (i < len) { 21 | let mut j = i; 22 | while (j > 0 && keys[j - 1].to_address().to_u256() > keys[j].to_address().to_u256()) { 23 | keys.swap(j - 1, j); 24 | values.swap(j - 1, j); 25 | j = j - 1; 26 | }; 27 | i = i + 1; 28 | }; 29 | 30 | vec_map::from_keys_values(keys, values) 31 | } 32 | 33 | /// Check if the given `VecMap` is sorted by the node ID transformed into `u256`. 34 | public macro fun is_vec_map_sorted_by_node_id<$V>($self: &VecMap): bool { 35 | let self = $self; 36 | 37 | let len = self.size(); 38 | if (len <= 1) return true; 39 | let mut i = 1; 40 | while (i < len) { 41 | let (lhs, _) = self.get_entry_by_idx(i - 1); 42 | let (rhs, _) = self.get_entry_by_idx(i); 43 | if (lhs.to_address().to_u256() > rhs.to_address().to_u256()) { 44 | return false 45 | }; 46 | i = i + 1; 47 | }; 48 | 49 | true 50 | } 51 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/tests/staking/walrus_context_tests.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | module walrus::walrus_context_tests; 5 | 6 | use sui::vec_map; 7 | use walrus::walrus_context; 8 | 9 | #[test] 10 | // Scenario: Test the WalrusContext flow 11 | fun test_walrus_context_flow() { 12 | let walrus_ctx = walrus_context::new(1, true, vec_map::empty()); 13 | 14 | // assert that the WalrusContext is created correctly 15 | assert!(walrus_ctx.epoch() == 1); 16 | assert!(walrus_ctx.committee_selected() == true); 17 | } 18 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/tests/system/metadata_tests.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #[test_only] 5 | module walrus::metadata_tests; 6 | 7 | use sui::vec_map::EKeyDoesNotExist; 8 | use walrus::metadata; 9 | 10 | #[test] 11 | public fun test_metadata_success() { 12 | let mut metadata = metadata::new(); 13 | metadata.insert_or_update(b"key1".to_string(), b"value1".to_string()); 14 | metadata.insert_or_update(b"key2".to_string(), b"value2".to_string()); 15 | // Update the value corresponding to key1. 16 | metadata.insert_or_update(b"key1".to_string(), b"value3".to_string()); 17 | let (key, value) = metadata.remove(&b"key1".to_string()); 18 | assert!(key == b"key1".to_string()); 19 | assert!(value == b"value3".to_string()); 20 | } 21 | 22 | #[test, expected_failure(abort_code = EKeyDoesNotExist)] 23 | public fun test_metadata_failure() { 24 | let mut metadata = metadata::new(); 25 | metadata.insert_or_update(b"key1".to_string(), b"value1".to_string()); 26 | metadata.remove(&b"key2".to_string()); 27 | } 28 | -------------------------------------------------------------------------------- /testnet-contracts/walrus/tests/system/ringbuffer_tests.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Walrus Foundation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #[test_only] 5 | module walrus::ringbuffer_tests; 6 | 7 | use sui::test_utils::destroy; 8 | use walrus::storage_accounting::{Self as sa, FutureAccountingRingBuffer}; 9 | 10 | #[test] 11 | public fun test_basic_ring_buffer() { 12 | let mut buffer: FutureAccountingRingBuffer = sa::ring_new(3); 13 | 14 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 0)) == 0, 100); 15 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 1)) == 1, 100); 16 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 2)) == 2, 100); 17 | 18 | let entry = sa::ring_pop_expand(&mut buffer); 19 | assert!(sa::epoch(&entry) == 0, 100); 20 | sa::delete_empty_future_accounting(entry); 21 | 22 | let entry = sa::ring_pop_expand(&mut buffer); 23 | assert!(sa::epoch(&entry) == 1, 100); 24 | sa::delete_empty_future_accounting(entry); 25 | 26 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 0)) == 2, 100); 27 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 1)) == 3, 100); 28 | assert!(sa::epoch(sa::ring_lookup_mut(&mut buffer, 2)) == 4, 100); 29 | 30 | destroy(buffer) 31 | } 32 | 33 | #[test, expected_failure(abort_code = sa::ETooFarInFuture)] 34 | public fun test_oob_fail_ring_buffer() { 35 | let mut buffer: FutureAccountingRingBuffer = sa::ring_new(3); 36 | 37 | sa::epoch(sa::ring_lookup_mut(&mut buffer, 3)); 38 | 39 | abort 40 | } 41 | --------------------------------------------------------------------------------