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{}frominclude/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.
Msg- Message to computeState- State containing assignment and logger
{ok, StateWithResults}- State updated with computation results- Throws
{cu_error, Error}on computation failure
-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:
- Full Assignment Mode - Carrier contains full assignment with body and assignment
- Reference Mode - Carrier references process and slot via tags
Supports selective result commitment via commit-to tag.
- Carrier data contains
bodyandassignment - Executes using embedded assignment
- Returns full results bundle
- Carrier tags contain
processandslot - Fetches and executes by reference
- More efficient for known slots
- Use
commit-totag with message ID - Returns only commitment for specific message
- Returns 404 if requested message not in results
-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 failureExecute - 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 resultsExecute - 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 resultsCommit-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
- External Execution: Delegates computation to external CU via
hb_client - Dual Mode: Supports both full assignment and reference-based execution
- Selective Results: Commit-to feature reduces bandwidth for specific messages
- Error Handling: Throws
{cu_error, Error}on computation failures - Signed Commitments: All commitments are signed with node wallet
- Bundle Integration: Works with ANS-104 bundles for results
- Process Resolution: Automatically resolves process context from assignment
- Store Access: Uses configured store for process state lookup
- Wallet Access: Uses
hb:wallet()for signing commitments - Status Codes: HTTP-style status codes (200, 404) for commitment responses