Labels: type: bug, type: correctness, difficulty: intermediate, area: task-registry
Why this matters now
Every Task struct is stored in persistent storage. The task_type field is a free-form string with only a non-empty check. A sponsor can store a 64 KB task_type string, making that single task entry consume enormous ledger rent. Multiply by max_completions of completion records and the registry can be made prohibitively expensive. This must be gated before Phase 4 when real sponsors start creating tasks.
Problem / What
create_task in contracts/task-registry/src/registry.rs validates:
if task_type.is_empty() {
panic!("registry: task type must not be empty");
}
No upper bound. A task_type of 65 535 bytes is accepted.
Similarly, location_hash is already typed as BytesN<32> (fixed size — good). But task_type is an unbounded String. A reasonable cap is 64 bytes (enough for "coastline-cleanup", "urban-tree-planting" etc. with room to spare).
Key Challenges
- Define a constant
MAX_TASK_TYPE_LEN: u32 = 64 and check task_type.len() > MAX_TASK_TYPE_LEN.
- Soroban
String::len() returns u32, not usize — be explicit about the type comparison.
- Existing tests use task types like
"tree-planting" (12 bytes) and "ocean-cleanup" (13 bytes) — all well within 64 bytes, so no existing test should break.
Acceptance Criteria
Relevant files / functions
| File |
Symbol |
contracts/task-registry/src/registry.rs |
create_task |
Out of scope
- Validation of
task_type content/format (e.g., allowed characters) — out of scope for on-chain
- Changes to
reward_amount or max_completions validation
Labels:
type: bug,type: correctness,difficulty: intermediate,area: task-registryWhy this matters now
Every
Taskstruct is stored in persistent storage. Thetask_typefield is a free-form string with only a non-empty check. A sponsor can store a 64 KBtask_typestring, making that single task entry consume enormous ledger rent. Multiply bymax_completionsof completion records and the registry can be made prohibitively expensive. This must be gated before Phase 4 when real sponsors start creating tasks.Problem / What
create_taskincontracts/task-registry/src/registry.rsvalidates:No upper bound. A
task_typeof 65 535 bytes is accepted.Similarly,
location_hashis already typed asBytesN<32>(fixed size — good). Buttask_typeis an unboundedString. A reasonable cap is 64 bytes (enough for"coastline-cleanup","urban-tree-planting"etc. with room to spare).Key Challenges
MAX_TASK_TYPE_LEN: u32 = 64and checktask_type.len() > MAX_TASK_TYPE_LEN.String::len()returnsu32, notusize— be explicit about the type comparison."tree-planting"(12 bytes) and"ocean-cleanup"(13 bytes) — all well within 64 bytes, so no existing test should break.Acceptance Criteria
create_taskpanics with"registry: task type too long"whentask_type.len() > 64.MAX_TASK_TYPE_LENis a named constant.test_create_task_max_length_type(exactly 64 bytes, succeeds) andtest_create_task_oversized_type(65 bytes, panics) added.Relevant files / functions
contracts/task-registry/src/registry.rscreate_taskOut of scope
task_typecontent/format (e.g., allowed characters) — out of scope for on-chainreward_amountormax_completionsvalidation