@rootzero/contracts 1.12.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +76 -8
  2. package/Codec.sol +21 -0
  3. package/Commands.sol +14 -0
  4. package/Core.sol +4 -4
  5. package/Endpoints.sol +5 -7
  6. package/README.md +62 -35
  7. package/Utils.sol +2 -4
  8. package/codec/Blocks.sol +1606 -0
  9. package/codec/Buffers.sol +165 -0
  10. package/codec/Decoders.sol +558 -0
  11. package/codec/Descriptors.sol +124 -0
  12. package/{blocks → codec}/Keys.sol +4 -28
  13. package/codec/Readers.sol +114 -0
  14. package/{blocks → codec}/Schema.sol +38 -80
  15. package/codec/Specs.sol +218 -0
  16. package/codec/Writers.sol +487 -0
  17. package/commands/Allocate.sol +50 -0
  18. package/commands/Base.sol +71 -37
  19. package/commands/Burn.sol +19 -13
  20. package/commands/Credit.sol +25 -31
  21. package/commands/Debit.sol +28 -38
  22. package/commands/Deposit.sol +39 -39
  23. package/commands/Payout.sol +22 -15
  24. package/commands/Provision.sol +40 -40
  25. package/commands/Recover.sol +21 -20
  26. package/commands/Relay.sol +25 -23
  27. package/commands/Withdraw.sol +18 -20
  28. package/commands/admin/AllowAssets.sol +20 -16
  29. package/commands/admin/Allowance.sol +19 -13
  30. package/commands/admin/Appoint.sol +18 -15
  31. package/commands/admin/Authorize.sol +24 -14
  32. package/commands/admin/Base.sol +1 -1
  33. package/commands/admin/DenyAssets.sol +20 -16
  34. package/commands/admin/Dismiss.sol +18 -15
  35. package/commands/admin/Execute.sol +20 -18
  36. package/commands/admin/Label.sol +18 -13
  37. package/commands/admin/Schemas.sol +19 -14
  38. package/commands/admin/Unauthorize.sol +24 -14
  39. package/core/Calls.sol +7 -14
  40. package/core/Endpoint.sol +43 -126
  41. package/core/Host.sol +10 -2
  42. package/core/Pipeline.sol +29 -25
  43. package/core/Settlement.sol +39 -0
  44. package/core/Types.sol +1 -1
  45. package/docs/Schema.md +38 -32
  46. package/events/Endpoint.sol +2 -2
  47. package/events/Introduction.sol +4 -3
  48. package/events/Schema.sol +5 -5
  49. package/execution/Budget.sol +40 -0
  50. package/execution/Execution.sol +1083 -0
  51. package/guards/Base.sol +8 -9
  52. package/guards/Revoke.sol +11 -9
  53. package/package.json +1 -1
  54. package/ports/AllowAssets.sol +12 -15
  55. package/ports/Allowance.sol +11 -9
  56. package/ports/Base.sol +18 -11
  57. package/ports/Credit.sol +11 -9
  58. package/ports/Debit.sol +11 -9
  59. package/ports/DenyAssets.sol +10 -13
  60. package/ports/Dispatch.sol +13 -15
  61. package/ports/Pipe.sol +14 -12
  62. package/ports/Redeem.sol +12 -9
  63. package/ports/Settle.sol +13 -13
  64. package/queries/Assets.sol +15 -15
  65. package/queries/Balances.sol +17 -17
  66. package/queries/Base.sol +11 -12
  67. package/utils/Actions.sol +1 -0
  68. package/utils/Cursors.sol +308 -0
  69. package/utils/Lanes.sol +14 -0
  70. package/utils/Selectors.sol +2 -2
  71. package/utils/Utils.sol +46 -0
  72. package/Cursors.sol +0 -16
  73. package/blocks/Cursors.sol +0 -1400
  74. package/blocks/Writers.sol +0 -1028
  75. package/core/Payable.sol +0 -53
  76. package/utils/Value.sol +0 -43
@@ -1,33 +1,36 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { AdminBase, CommandContext, Keys } from "./Base.sol";
5
- import { Cursors, Cur } from "../../Cursors.sol";
6
- using Cursors for Cur;
4
+ import { AdminBase, Execution, Executions, Lanes, Specs } from "./Base.sol";
5
+ using Executions for Execution;
7
6
 
8
7
  /// @title Dismiss
9
8
  /// @notice Admin command that revokes guardian status from a list of account IDs.
10
- /// Each ACCOUNT block in the request is disabled as a guardian on the host.
9
+ /// Each ACCOUNT block in the input is disabled as a guardian on the host.
11
10
  /// Only callable by the admin account.
12
11
  abstract contract Dismiss is AdminBase {
13
- bytes32 private immutable descriptor;
12
+ uint private immutable descriptor;
14
13
 
15
14
  constructor() {
16
- (, descriptor) = command("dismiss", Keys.Empty, Keys.Account, Keys.Empty, 0, false, true);
15
+ (, descriptor) = command("dismiss", Specs.Empty, Specs.Account, Specs.Empty, 0, false, true);
17
16
  }
18
17
 
19
- /// @notice Dismiss each ACCOUNT block in the admin request from guardian status.
20
- /// @param c Admin command context; `c.input` must contain ACCOUNT blocks.
18
+ /// @notice Dismiss each ACCOUNT block in the admin input from guardian status.
19
+ /// @param input ACCOUNT block stream.
21
20
  /// @return Empty output state.
21
+ /// @return Empty transaction stream.
22
22
  function dismiss(
23
- CommandContext calldata c
24
- ) external onlyAdmin(c.account) returns (bytes memory) {
25
- (Cur memory input, ) = openInput(c.input, descriptor);
23
+ bytes32 account,
24
+ bytes calldata,
25
+ bytes calldata input
26
+ ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
27
+ Execution memory exec = openInput(input, descriptor, 0);
26
28
 
27
- while (input.i < input.len) {
28
- bytes32 account = input.unpackAccount();
29
- setGuardian(account, false);
29
+ while (exec.more()) {
30
+ bytes32 guardian = exec.unpackAccount(Lanes.Input);
31
+ setGuardian(guardian, false);
30
32
  }
31
- return "";
33
+
34
+ return close(exec, account);
32
35
  }
33
36
  }
@@ -1,36 +1,38 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {AdminBase, CommandContext, Keys} from "./Base.sol";
5
- import {Payable} from "../../core/Payable.sol";
6
- import {Cursors, Cur} from "../../Cursors.sol";
7
- import {Budget} from "../../utils/Value.sol";
4
+ import {AdminBase, Execution, Executions, Lanes, Specs} from "./Base.sol";
8
5
 
9
- using Cursors for Cur;
6
+ using Executions for Execution;
10
7
 
11
8
  /// @title ExecutePayable
12
9
  /// @notice Admin command that forwards raw calldata to one or more target nodes.
13
10
  /// Each CALL block specifies a target node ID, packed resources, and raw calldata payload.
14
11
  /// Only callable by the admin account.
15
- /// Unspent top-level `msg.value` remains on this host.
16
- abstract contract ExecutePayable is AdminBase, Payable {
17
- bytes32 private immutable descriptor;
12
+ /// Unspent top-level `msg.value` is returned as a refund transaction.
13
+ abstract contract ExecutePayable is AdminBase {
14
+ uint private immutable descriptor;
18
15
 
19
16
  constructor() {
20
- (, descriptor) = command("executePayable", Keys.Empty, Keys.Call, Keys.Empty, 0, true, true);
17
+ (, descriptor) = command("executePayable", Specs.Empty, Specs.Call, Specs.Empty, 0, true, true);
21
18
  }
22
19
 
23
- /// @notice Execute each CALL block in the admin request.
24
- /// @param c Admin command context; `c.input` must contain CALL blocks.
20
+ /// @notice Execute each CALL block in the admin input.
21
+ /// @param input CALL block stream.
25
22
  /// @return Empty output state.
26
- function executePayable(CommandContext calldata c) external payable onlyAdmin(c.account) returns (bytes memory) {
27
- (Cur memory input, ) = openInput(c.input, descriptor);
28
- Budget memory budget = openValue();
23
+ /// @return Remaining native value as a refund transaction stream.
24
+ function executePayable(
25
+ bytes32 account,
26
+ bytes calldata,
27
+ bytes calldata input
28
+ ) external payable onlyAdmin(account) returns (bytes memory, bytes memory) {
29
+ Execution memory exec = openInput(input, descriptor, 0);
29
30
 
30
- while (input.i < input.len) {
31
- (uint target, uint resources, bytes calldata data) = input.unpackCall();
32
- rawCall(target, useValue(budget, resources), data);
31
+ while (exec.more()) {
32
+ (uint target, uint resources, bytes calldata data) = exec.unpackCall(Lanes.Input);
33
+ rawCall(target, exec.useValue(resources), data);
33
34
  }
34
- return "";
35
+
36
+ return close(exec, account);
35
37
  }
36
38
  }
@@ -1,31 +1,36 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {AdminBase, CommandContext, Keys} from "./Base.sol";
5
- import {Cursors, Cur} from "../../Cursors.sol";
6
- using Cursors for Cur;
4
+ import {AdminBase, Execution, Executions, Lanes, Specs} from "./Base.sol";
5
+ using Executions for Execution;
7
6
 
8
7
  /// @title Label
9
8
  /// @notice Admin command that publishes namespaced labels for node IDs.
10
- /// Each LABEL block in the request emits one `Labeled` event. Only callable by
9
+ /// Each LABEL block in the input emits one `Labeled` event. Only callable by
11
10
  /// the admin account.
12
11
  abstract contract Label is AdminBase {
13
- bytes32 private immutable descriptor;
12
+ uint private immutable descriptor;
14
13
 
15
14
  constructor() {
16
- (, descriptor) = command("label", Keys.Empty, Keys.Label, Keys.Empty, 0, false, true);
15
+ (, descriptor) = command("label", Specs.Empty, Specs.Label, Specs.Empty, 0, false, true);
17
16
  }
18
17
 
19
- /// @notice Publish each LABEL block in the admin request.
20
- /// @param c Admin command context; `c.input` must contain LABEL blocks.
18
+ /// @notice Publish each LABEL block in the admin input.
19
+ /// @param input LABEL block stream.
21
20
  /// @return Empty output state.
22
- function label(CommandContext calldata c) external onlyAdmin(c.account) returns (bytes memory) {
23
- (Cur memory input, ) = openInput(c.input, descriptor);
21
+ /// @return Empty transaction stream.
22
+ function label(
23
+ bytes32 account,
24
+ bytes calldata,
25
+ bytes calldata input
26
+ ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
27
+ Execution memory exec = openInput(input, descriptor, 0);
24
28
 
25
- while (input.i < input.len) {
26
- (uint node, bytes32 namespace, string memory name) = input.unpackLabel();
29
+ while (exec.more()) {
30
+ (uint node, bytes32 namespace, string memory name) = exec.unpackLabel(Lanes.Input);
27
31
  emit Labeled(node, namespace, name);
28
32
  }
29
- return "";
33
+
34
+ return close(exec, account);
30
35
  }
31
36
  }
@@ -1,31 +1,36 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {AdminBase, CommandContext, Keys} from "./Base.sol";
5
- import {Cursors, Cur} from "../../Cursors.sol";
6
- using Cursors for Cur;
4
+ import {AdminBase, Execution, Executions, Lanes, Specs} from "./Base.sol";
5
+ using Executions for Execution;
7
6
 
8
7
  /// @title PublishSchema
9
8
  /// @notice Admin command that publishes block schemas for keys.
10
- /// Each SCHEMA block in the request emits one `Schema` event. Only callable by
9
+ /// Each SCHEMA block in the input emits one `Schema` event. Only callable by
11
10
  /// the admin account.
12
11
  abstract contract PublishSchema is AdminBase {
13
- bytes32 private immutable descriptor;
12
+ uint private immutable descriptor;
14
13
 
15
14
  constructor() {
16
- (, descriptor) = command("publishSchema", Keys.Empty, Keys.Schema, Keys.Empty, 0, false, true);
15
+ (, descriptor) = command("publishSchema", Specs.Empty, Specs.Schema, Specs.Empty, 0, false, true);
17
16
  }
18
17
 
19
- /// @notice Publish each SCHEMA block in the admin request.
20
- /// @param c Admin command context; `c.input` must contain SCHEMA blocks.
18
+ /// @notice Publish each SCHEMA block in the admin input.
19
+ /// @param input SCHEMA block stream.
21
20
  /// @return Empty output state.
22
- function publishSchema(CommandContext calldata c) external onlyAdmin(c.account) returns (bytes memory) {
23
- (Cur memory input, ) = openInput(c.input, descriptor);
21
+ /// @return Empty transaction stream.
22
+ function publishSchema(
23
+ bytes32 account,
24
+ bytes calldata,
25
+ bytes calldata input
26
+ ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
27
+ Execution memory exec = openInput(input, descriptor, 0);
24
28
 
25
- while (input.i < input.len) {
26
- (bytes4 key, string memory body, bytes32 name) = input.unpackSchema();
27
- emit Schema(host, key, body, name);
29
+ while (exec.more()) {
30
+ (uint spec, string memory body, bytes32 name) = exec.unpackSchema(Lanes.Input);
31
+ emit Schema(host, spec, body, name);
28
32
  }
29
- return "";
33
+
34
+ return close(exec, account);
30
35
  }
31
36
  }
@@ -1,32 +1,42 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {AdminBase, CommandContext, Keys} from "./Base.sol";
5
- import {Cursors, Cur} from "../../Cursors.sol";
6
- using Cursors for Cur;
4
+ import {AdminBase, Execution, Executions, Lanes, Specs} from "./Base.sol";
5
+ using Executions for Execution;
7
6
 
8
7
  /// @title Unauthorize
9
8
  /// @notice Admin command that revokes authorization from a list of node IDs.
10
- /// Each NODE block in the request is deauthorized on the host.
9
+ /// Each NODE block in the input is deauthorized on the host.
11
10
  /// Only callable by the admin account.
12
11
  abstract contract Unauthorize is AdminBase {
13
- bytes32 private immutable descriptor;
14
- uint internal immutable unauthorizeId;
12
+ uint private immutable descriptor;
13
+ uint private immutable id;
15
14
 
16
15
  constructor() {
17
- (unauthorizeId, descriptor) = command("unauthorize", Keys.Empty, Keys.Node, Keys.Empty, 0, false, true);
16
+ (id, descriptor) = command("unauthorize", Specs.Empty, Specs.Node, Specs.Empty, 0, false, true);
18
17
  }
19
18
 
20
- /// @notice Unauthorize each NODE block in the admin request.
21
- /// @param c Admin command context; `c.input` must contain NODE blocks.
19
+ /// @notice Return the registered UNAUTHORIZE command ID.
20
+ function unauthorizeId() internal view returns (uint) {
21
+ return id;
22
+ }
23
+
24
+ /// @notice Unauthorize each NODE block in the admin input.
25
+ /// @param input NODE block stream.
22
26
  /// @return Empty output state.
23
- function unauthorize(CommandContext calldata c) external onlyAdmin(c.account) returns (bytes memory) {
24
- (Cur memory input, ) = openInput(c.input, descriptor);
27
+ /// @return Empty transaction stream.
28
+ function unauthorize(
29
+ bytes32 account,
30
+ bytes calldata,
31
+ bytes calldata input
32
+ ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
33
+ Execution memory exec = openInput(input, descriptor, 0);
25
34
 
26
- while (input.i < input.len) {
27
- uint node = input.unpackNode();
35
+ while (exec.more()) {
36
+ uint node = exec.unpackNode(Lanes.Input);
28
37
  setNode(node, false);
29
38
  }
30
- return "";
39
+
40
+ return close(exec, account);
31
41
  }
32
42
  }
package/core/Calls.sol CHANGED
@@ -2,7 +2,6 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {AccessControl} from "./Access.sol";
5
- import {CommandContext} from "../commands/Base.sol";
6
5
  import {Nodes} from "../utils/Nodes.sol";
7
6
 
8
7
  /// @dev Emitted when a trusted inter-node call fails.
@@ -14,13 +13,6 @@ error FailedCall(address addr, bytes4 selector, bytes err);
14
13
  /// @title NodeCalls
15
14
  /// @notice Shared low-level inter-node call helpers for contracts that can talk to other nodes.
16
15
  abstract contract NodeCalls is AccessControl {
17
- /// @notice Return the host node ID corresponding to the current caller.
18
- /// @dev Encodes `msg.sender` as a host ID using the local-chain host layout.
19
- /// @return Host node ID for `msg.sender`.
20
- function caller() internal view returns (uint) {
21
- return Nodes.toHost(msg.sender);
22
- }
23
-
24
16
  /// @notice Try a raw low-level call to another node and return whether it succeeded.
25
17
  /// @param node Node ID of the callee.
26
18
  /// @param value Native value to forward in wei.
@@ -89,18 +81,19 @@ abstract contract CommandCalls is NodeCalls {
89
81
  /// @param value Native value to forward in wei.
90
82
  /// @param account Command account identifier.
91
83
  /// @param state Current command state block stream.
92
- /// @param request Command input block stream.
93
- /// @return Decoded command output block stream.
84
+ /// @param input Command input block stream.
85
+ /// @return nextState Decoded command output state block stream.
86
+ /// @return transactions Decoded command transaction block stream.
94
87
  function callCommand(
95
88
  uint command,
96
89
  uint128 value,
97
90
  bytes32 account,
98
91
  bytes memory state,
99
- bytes calldata request
100
- ) internal returns (bytes memory) {
92
+ bytes calldata input
93
+ ) internal returns (bytes memory nextState, bytes memory transactions) {
101
94
  bytes4 selector = Nodes.commandSelector(command);
102
- bytes memory data = abi.encodeWithSelector(selector, CommandContext(account, state, request));
103
- return abi.decode(trustedCall(command, value, data), (bytes));
95
+ bytes memory data = abi.encodeWithSelector(selector, account, state, input);
96
+ return abi.decode(trustedCall(command, value, data), (bytes, bytes));
104
97
  }
105
98
  }
106
99
 
package/core/Endpoint.sol CHANGED
@@ -1,159 +1,76 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {Cursors, Cur} from "../Cursors.sol";
5
- import {Keys} from "../blocks/Keys.sol";
4
+ import {Specs} from "../codec/Specs.sol";
5
+ import {Execution, Executions} from "../execution/Execution.sol";
6
6
  import {EndpointEvent} from "../events/Endpoint.sol";
7
7
  import {LabeledEvent} from "../events/Labeled.sol";
8
8
  import {SchemaEvent} from "../events/Schema.sol";
9
+ import {Descriptors} from "../codec/Descriptors.sol";
9
10
  import {Runtime} from "./Runtime.sol";
10
11
 
11
- /// @title Lane
12
- /// @notice Bit offsets for endpoint descriptor lanes.
13
- library Lane {
14
- /// @dev Descriptor shift for the state lane.
15
- uint internal constant State = 184;
16
- /// @dev Descriptor shift for the input lane.
17
- uint internal constant Input = 112;
18
- /// @dev Descriptor shift for the output lane.
19
- uint internal constant Output = 40;
20
- }
21
-
22
12
  /// @title EndpointBase
23
13
  /// @notice Shared endpoint metadata helpers.
24
14
  abstract contract EndpointBase is Runtime, EndpointEvent, LabeledEvent, SchemaEvent {
25
- /// @dev Pack endpoint lanes and flags into a descriptor.
26
- /// A non-empty lane with group 0 defaults to group 1; a zero lane is absent.
27
- /// Layout: `[state:8][group:1][input:8][group:1][output:8][group:1]`
28
- /// `[flags:1][reserved:4]`. Flag bits: funded = 0, admin = 1.
29
- /// @param state Packed state lane plus optional group byte.
30
- /// @param input Packed input lane plus optional group byte.
31
- /// @param output Packed output lane plus optional group byte.
32
- /// @param funded Whether the endpoint accepts nonzero native value.
33
- /// @param admin Whether the endpoint is restricted to the admin account.
34
- /// @return value Packed endpoint descriptor as an integer.
35
- function pack(
36
- bytes9 state,
37
- bytes9 input,
38
- bytes9 output,
39
- bool funded,
40
- bool admin
41
- ) private pure returns (uint value) {
42
- value |= uint(uint72(state)) << Lane.State;
43
- value |= uint(uint72(input)) << Lane.Input;
44
- value |= uint(uint72(output)) << Lane.Output;
45
- value |= uint(funded ? 1 : 0) << 32;
46
- value |= uint(admin ? 1 : 0) << 33;
47
- }
48
-
49
- /// @dev Return a lane's effective group size, defaulting non-empty lanes to one.
50
- /// @param descriptor Packed endpoint descriptor.
51
- /// @param shift Bit offset of the lane to inspect.
52
- /// @return size Effective group size, or zero when the lane is absent.
53
- function laneGroup(bytes32 descriptor, uint shift) private pure returns (uint8 size) {
54
- uint72 lane = uint72(uint(descriptor) >> shift);
55
- if (lane == 0) return 0;
56
-
57
- size = uint8(lane);
58
- if (size == 0) size = 1;
59
- }
60
-
61
- /// @notice Return an 8-byte lane value for a generic LIST containing `item`.
62
- /// @param item Block key expected inside each LIST payload.
63
- /// @return Packed lane key `[Keys.List][item]`.
64
- function many(bytes4 item) internal pure returns (bytes8) {
65
- return bytes8(bytes.concat(Keys.List, item));
66
- }
67
-
68
- /// @notice Append an explicit group size to an 8-byte lane value.
69
- /// @param value Packed lane key `[key][item]`.
70
- /// @param size Explicit per-operation group size for the lane.
71
- /// @return Packed lane key plus group byte.
72
- function group(bytes8 value, uint8 size) internal pure returns (bytes9) {
73
- return bytes9(bytes.concat(value, bytes1(size)));
74
- }
75
-
76
- /// @dev Open a descriptor lane and return its effective group and output counts.
77
- /// An absent lane inherits `expected`; a present lane must match it when nonzero.
78
- /// @param source Block stream to open for the requested lane.
79
- /// @param descriptor Packed endpoint descriptor.
80
- /// @param shift Bit offset of the lane to open.
81
- /// @param expected Required group count, or zero to accept the lane's count.
82
- /// @return cur Cursor scoped to the lane's first block run.
83
- /// @return groups Number of lane groups in `cur`, or `expected` for an absent lane.
84
- /// @return outputs Number of output blocks implied by `groups` and the descriptor output lane.
85
- function openLane(
86
- bytes calldata source,
87
- bytes32 descriptor,
88
- uint shift,
89
- uint expected
90
- ) internal pure returns (Cur memory cur, uint groups, uint outputs) {
91
- (cur, groups) = Cursors.init(source, laneGroup(descriptor, shift));
92
- if (groups == 0) groups = expected;
93
- else if (expected != 0 && groups != expected) revert Cursors.BadRatio();
94
- outputs = groups * laneGroup(descriptor, Lane.Output);
95
- }
96
-
97
- /// @notice Open an endpoint state stream and return the expected output block count.
98
- /// @param source State block stream to open.
99
- /// @param descriptor Packed endpoint descriptor.
100
- /// @return state Cursor scoped to the state lane's first block run.
101
- /// @return outputs Number of output blocks implied by the state group count.
102
- function openState(
103
- bytes calldata source,
104
- bytes32 descriptor
105
- ) internal pure returns (Cur memory state, uint outputs) {
106
- (state, , outputs) = openLane(source, descriptor, Lane.State, 0);
107
- }
108
-
109
- /// @notice Open an endpoint input stream and return the expected output block count.
15
+ /// @notice Open an endpoint input stream with an expected batch count.
110
16
  /// @param source Input block stream to open.
111
17
  /// @param descriptor Packed endpoint descriptor.
112
- /// @return input Cursor scoped to the input lane's first block run.
113
- /// @return outputs Number of output blocks implied by the input group count.
18
+ /// @param batches Required batch count, or zero to accept the input count.
19
+ /// @return exec Execution with its output buffer metadata initialized for the input batch count.
114
20
  function openInput(
115
21
  bytes calldata source,
116
- bytes32 descriptor
117
- ) internal pure returns (Cur memory input, uint outputs) {
118
- (input, , outputs) = openLane(source, descriptor, Lane.Input, 0);
22
+ uint descriptor,
23
+ uint batches
24
+ ) internal view returns (Execution memory exec) {
25
+ return Executions.openInput(source, descriptor, batches);
119
26
  }
120
27
 
121
- /// @notice Publish the default local block schema and return `Keys.Local`.
122
- /// @param body Schema DSL string describing the block payload body.
123
- /// @return The default context-local block key.
124
- function localSchema(string memory body) internal returns (bytes4) {
125
- return localSchema(1, body);
28
+ /// @notice Finalize an execution output and return its encoded block stream.
29
+ /// @param exec Completed endpoint execution.
30
+ /// @return Encoded output block stream.
31
+ function close(Execution memory exec) internal pure returns (bytes memory) {
32
+ return Executions.finish(exec);
126
33
  }
127
34
 
128
- /// @notice Publish a context-local block schema and return its key.
35
+ /// @notice Construct and publish a context-local block specification.
129
36
  /// @param key Context-local key value.
37
+ /// @param min Minimum accepted payload length.
38
+ /// @param max Maximum accepted payload length; zero means unbounded.
39
+ /// @param hint Initial per-block payload capacity.
130
40
  /// @param body Schema DSL string describing the block payload body.
131
- /// @return The context-local block key.
132
- function localSchema(uint32 key, string memory body) internal returns (bytes4) {
133
- bytes4 k = Keys.local(key);
134
- emit Schema(host, k, body, bytes32(0));
135
- return k;
41
+ /// @param name Schema alias name, or zero for unnamed schemas.
42
+ /// @return spec The context-local block specification.
43
+ function schema(
44
+ uint32 key,
45
+ uint32 min,
46
+ uint32 max,
47
+ uint32 hint,
48
+ string memory body,
49
+ bytes32 name
50
+ ) internal returns (uint spec) {
51
+ spec = Specs.create(bytes4(key), min, max, hint);
52
+ emit Schema(host, spec, body, name);
136
53
  }
137
54
 
138
55
  /// @notice Create and publish endpoint metadata with a default label.
139
56
  /// @param id Endpoint node ID.
140
57
  /// @param name Default human-readable endpoint label.
141
- /// @param state Packed state lane plus optional group byte.
142
- /// @param input Packed input lane plus optional group byte.
143
- /// @param output Packed output lane plus optional group byte.
144
- /// @param funded Whether the endpoint accepts nonzero native value.
145
- /// @param admin Whether the endpoint is restricted to the admin account.
58
+ /// @param state State block specification.
59
+ /// @param input Input block specification.
60
+ /// @param output Output block specification.
61
+ /// @param transactions Number of transaction blocks produced per batch, or zero for none.
62
+ /// @param flags Packed endpoint behavior flags.
146
63
  /// @return descriptor Packed endpoint lane metadata and flags.
147
64
  function endpoint(
148
65
  uint id,
149
66
  string memory name,
150
- bytes9 state,
151
- bytes9 input,
152
- bytes9 output,
153
- bool funded,
154
- bool admin
155
- ) internal returns (bytes32 descriptor) {
156
- descriptor = bytes32(pack(state, input, output, funded, admin));
67
+ uint state,
68
+ uint input,
69
+ uint output,
70
+ uint8 transactions,
71
+ uint8 flags
72
+ ) internal returns (uint descriptor) {
73
+ descriptor = Descriptors.create(state, input, output, transactions, flags);
157
74
  emit Endpoint(host, id, descriptor);
158
75
  emit Labeled(id, bytes32(0), name);
159
76
  }
package/core/Host.sol CHANGED
@@ -43,7 +43,15 @@ abstract contract Host is
43
43
  /// on it during construction.
44
44
  constructor(address cmdr) AccessControl(cmdr) {
45
45
  if (cmdr == address(0) || cmdr == address(this) || cmdr.code.length == 0) return;
46
- IHostIntroduction(cmdr).introduce(host, block.number);
46
+ introduceTo(Nodes.toHost(cmdr));
47
+ }
48
+
49
+ /// @notice Introduce this host to the contract address embedded in a local EVM node ID.
50
+ /// @dev Accepts host and endpoint IDs such as commands, ports, queries, and guards.
51
+ /// Reverts when `node` is not local or embeds the zero address.
52
+ /// @param node Local EVM node ID whose underlying contract receives the introduction.
53
+ function introduceTo(uint node) internal {
54
+ IHostIntroduction(Nodes.addr(node)).introduce(host, block.number);
47
55
  }
48
56
 
49
57
  /// @notice Record a host introduction claim.
@@ -51,7 +59,7 @@ abstract contract Host is
51
59
  /// @param peer Host node ID being introduced.
52
60
  /// @param blocknum Block number at which the host was deployed.
53
61
  function introduce(uint peer, uint blocknum) external {
54
- emit Introduction(Nodes.matchHost(peer, msg.sender), blocknum);
62
+ emit Introduction(host, Nodes.matchHost(peer, msg.sender), blocknum);
55
63
  }
56
64
 
57
65
  /// @notice Accept native ETH transfers (e.g. from command value flows).
package/core/Pipeline.sol CHANGED
@@ -1,34 +1,38 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {Cursors, Cur} from "../Cursors.sol";
5
- import {Payable} from "./Payable.sol";
6
- import {Budget} from "../utils/Value.sol";
4
+ import {Decoders, Cur, Readers, Reader} from "../Codec.sol";
5
+ import {Settlement} from "./Settlement.sol";
6
+ import {Budget, Budgets} from "../execution/Budget.sol";
7
7
 
8
- using Cursors for Cur;
8
+ using Decoders for Cur;
9
+ using Readers for Reader;
10
+ using Budgets for Budget;
9
11
 
10
12
  /// @title Pipeline
11
13
  /// @notice Core pipeline functionality shared by higher-level surfaces.
12
- abstract contract Pipeline is Payable {
14
+ abstract contract Pipeline is Settlement {
13
15
  /// @dev Thrown when the pipeline finishes with non-empty threaded state.
14
16
  error UnexpectedState();
15
17
 
16
18
  /// @notice Override to dispatch one piped step.
17
- /// Called once per STEP block. The returned bytes become the state passed to
18
- /// the next step, and the final returned state must be empty.
19
- /// @param target Node ID to invoke or handle.
19
+ /// Called once per STEP block. The returned state becomes the state passed to
20
+ /// the next step, and the final returned state must be empty. Returned
21
+ /// transactions are decoded and passed individually to `settle` before the next step runs.
22
+ /// @param cmd Command node ID to invoke or handle.
20
23
  /// @param account Account identifier for the piped context.
21
24
  /// @param state Current threaded state block stream.
22
- /// @param request Step request block stream.
25
+ /// @param input Step input block stream.
23
26
  /// @param value Native EVM value assigned to this step.
24
- /// @return Updated state block stream for the next step.
27
+ /// @return output Updated state block stream for the next step.
28
+ /// @return transactions Transaction block stream produced by the command.
25
29
  function dispatch(
26
- uint target,
30
+ uint cmd,
27
31
  bytes32 account,
28
32
  bytes memory state,
29
- bytes calldata request,
33
+ bytes calldata input,
30
34
  uint128 value
31
- ) internal virtual returns (bytes memory);
35
+ ) internal virtual returns (bytes memory output, bytes memory transactions);
32
36
 
33
37
  /// @notice Execute a STEP block stream through the pipeline.
34
38
  /// @dev Reverts with `UnexpectedState` if the final threaded state is non-empty.
@@ -37,20 +41,20 @@ abstract contract Pipeline is Payable {
37
41
  /// @param state Initial state block stream passed to the first step.
38
42
  /// @param steps STEP block stream to execute.
39
43
  /// @param budget Mutable native-value budget shared across all steps.
40
- function pipe(
41
- bytes32 account,
42
- bytes memory state,
43
- bytes calldata steps,
44
- Budget memory budget
45
- ) internal {
46
- (Cur memory input, ) = Cursors.init(steps, 1);
47
-
48
- while (input.i < input.len) {
49
- (uint target, uint resources, bytes calldata request) = input.unpackStep();
50
- state = dispatch(target, account, state, request, useValue(budget, resources));
44
+ function pipe(bytes32 account, bytes memory state, bytes calldata steps, Budget memory budget) internal {
45
+ Cur memory cur = Decoders.open(steps, 1);
46
+
47
+ while (cur.more()) {
48
+ (uint cmd, uint resources, bytes calldata input) = cur.unpackStep();
49
+ Reader memory txs;
50
+ (state, txs.source) = dispatch(cmd, account, state, input, budget.use(resources));
51
+
52
+ while (txs.more()) {
53
+ (bytes32 from, bytes32 to, bytes32 asset, uint amount) = txs.unpackTransaction();
54
+ settle(from, to, asset, amount);
55
+ }
51
56
  }
52
57
 
53
58
  if (state.length != 0) revert UnexpectedState();
54
- input.complete();
55
59
  }
56
60
  }