Skip to content

dev_cu.erl - Compute Unit Device

Overview

Purpose: Execute computations on assignments via external Compute Units (CU)
Module: dev_cu
Pattern: Assignment-based computation with result commitment
Integration: HyperBEAM process execution pipeline

This module implements a compute device that executes assignments using external compute units through the hb_client:compute/2 interface. It supports selective result commitment, allowing clients to request specific messages from the computation results bundle.

Dependencies

  • HyperBEAM: hb_client, hb_util, hb_opts, hb_process, hb
  • Arweave: ar_bundles
  • Records: #tx{} from include/hb.hrl

Public Functions Overview

%% Computation
-spec push(Msg, State) -> {ok, StateWithResults} | {error, Reason}.
-spec execute(CarrierMsg, State) -> {ok, StateWithResults} | {error, Reason}.

Public Functions

1. push/2

-spec push(Msg, State) -> {ok, StateWithResults} | {error, Reason}
    when
        Msg :: map(),
        State :: #{assignment := Assignment, logger := Logger},
        Assignment :: map(),
        Logger :: term(),
        StateWithResults :: #{results => Results},
        Results :: term(),
        Reason :: term().

Description: Push a message to an external Compute Unit for execution. Uses hb_client:compute/2 to delegate computation to an external CU based on the assignment.

Parameters:
  • Msg - Message to compute
  • State - State containing assignment and logger
Returns:
  • {ok, StateWithResults} - State updated with computation results
  • Throws {cu_error, Error} on computation failure
Test Code:
-module(dev_cu_push_test).
-include_lib("eunit/include/eunit.hrl").
-include("include/hb.hrl").
 
push_success_test() ->
    % Verify module exports push/2
    code:ensure_loaded(dev_cu),
    ?assert(erlang:function_exported(dev_cu, push, 2)).
 
push_error_test() ->
    % Verify push requires assignment in state
    Exports = dev_cu:module_info(exports),
    ?assert(lists:member({push, 2}, Exports)).

2. execute/2

-spec execute(CarrierMsg, State) -> {ok, StateWithResults} | {error, Reason}
    when
        CarrierMsg :: #tx{},
        State :: map(),
        StateWithResults :: #{results := Results},
        Results :: #tx{},
        Reason :: term().

Description: Execute a computation based on a carrier message. Supports two execution modes:

  1. Full Assignment Mode - Carrier contains full assignment with body and assignment
  2. Reference Mode - Carrier references process and slot via tags

Supports selective result commitment via commit-to tag.

Execution Modes: Full Assignment:
  • Carrier data contains body and assignment
  • Executes using embedded assignment
  • Returns full results bundle
Reference Mode:
  • Carrier tags contain process and slot
  • Fetches and executes by reference
  • More efficient for known slots
Selective Commitment:
  • Use commit-to tag with message ID
  • Returns only commitment for specific message
  • Returns 404 if requested message not in results
Test Code:
-module(dev_cu_execute_test).
-include_lib("eunit/include/eunit.hrl").
-include("include/hb.hrl").
 
execute_exports_test() ->
    % Verify module exports execute/2
    code:ensure_loaded(dev_cu),
    ?assert(erlang:function_exported(dev_cu, execute, 2)).
 
execute_module_info_test() ->
    Exports = dev_cu:module_info(exports),
    ?assert(lists:member({execute, 2}, Exports)),
    ?assert(lists:member({push, 2}, Exports)).

Common Patterns

%% Execute assignment with full context
Assignment = #{
    <<"process">> => ProcessID,
    <<"slot">> => Slot,
    <<"message">> => Message
},
State = #{
    assignment => Assignment,
    logger => Logger
},
{ok, StateWithResults} = dev_cu:push(Message, State),
Results = maps:get(results, StateWithResults).
 
%% Execute via carrier message (full assignment)
CarrierMsg = #tx{
    data = #{
        <<"body">> => Message,
        <<"assignment">> => Assignment
    }
},
{ok, ResultState} = dev_cu:execute(CarrierMsg, #{}),
Results = maps:get(results, ResultState).
 
%% Execute via carrier message (reference mode)
CarrierMsg = #tx{
    tags = [
        {<<"process">>, ProcessID},
        {<<"slot">>, Slot}
    ]
},
{ok, ResultState} = dev_cu:execute(CarrierMsg, #{}),
Results = maps:get(results, ResultState).
 
%% Request specific message commitment
TargetMessageID = hb_util:encode(MessageID),
CarrierMsg = #tx{
    tags = [
        {<<"process">>, ProcessID},
        {<<"slot">>, Slot},
        {<<"commit-to">>, TargetMessageID}
    ]
},
{ok, ResultState} = dev_cu:execute(CarrierMsg, #{}),
Commitment = maps:get(results, ResultState),
Status = proplists:get_value(<<"status">>, Commitment#tx.tags).

Execution Flow

Push Execution

1. Receive message and assignment
2. Log execution details
3. Call hb_client:compute(Assignment, Msg)
4. Return results in state
5. Throw error on failure

Execute - Full Assignment Mode

1. Extract bundle head from carrier
2. Detect full assignment (body + assignment in data)
3. Extract process ID from assignment tags
4. Call hb_process:result with assignment ID
5. Handle commit-to if present
6. Return results

Execute - Reference Mode

1. Extract process and slot from carrier tags
2. Call hb_process:result with process and slot
3. Handle commit-to if present
4. Return results

Commit-To Handling

1. Check for commit-to tag in carrier
2. Decode target message ID
3. Search for message in results bundle
4. If found: Return signed commitment (status 200)
5. If not found: Return error commitment (status 404)

State Management

Input State

#{
    assignment => Assignment,  % Required for push/2
    logger => Logger          % Optional logger
}

Output State

#{
    results => Results  % Computation results or commitment
}

Commitment Response Format

Success Commitment (200)

#tx{
    tags = [
        {<<"status">>, 200},
        {<<"commitment-for">>, EncodedMessageID}
    ],
    data = <<>>
}

Not Found (404)

#tx{
    tags = [
        {<<"status">>, 404}
    ],
    data = <<"Requested message to commit to not in results bundle.">>
}

References

  • HyperBEAM Client - hb_client.erl
  • Process Execution - hb_process.erl
  • Bundles - ar_bundles.erl
  • Assignment Handling - HyperBEAM process model

Notes

  1. External Execution: Delegates computation to external CU via hb_client
  2. Dual Mode: Supports both full assignment and reference-based execution
  3. Selective Results: Commit-to feature reduces bandwidth for specific messages
  4. Error Handling: Throws {cu_error, Error} on computation failures
  5. Signed Commitments: All commitments are signed with node wallet
  6. Bundle Integration: Works with ANS-104 bundles for results
  7. Process Resolution: Automatically resolves process context from assignment
  8. Store Access: Uses configured store for process state lookup
  9. Wallet Access: Uses hb:wallet() for signing commitments
  10. Status Codes: HTTP-style status codes (200, 404) for commitment responses