Uses a multi-module (mod
) pattern, described by ./go.work
.
./shared
: An independent Go module defining data structures and common functionalities for component interactions, such as signing and verification processes. Please pay special attention to the struct definitions within../avs
: An independent Go module defining the functionalities of AVS../mock_secware
: An independent Go module defining the hypothetical functions of SecWare../mock_gateway
: An independent Go module defining the hypothetical functions of Gateway. Provides interfaces identical to those in the production GoPlus Gateway environment../mock_fanout_service
: An independent Go module defining the hypothetical functions of Fanout Service. Provides interfaces identical to those in the production GoPlus Fanout Service environment../scripts
: Stores scripts for building and managing Docker, as well as running and managing various service components.
The Gateway inputs a signed transaction shared/pkg/types.SignedTx
from the end user, reads the Secware configuration information of the end user for this transaction, and constructs multiple shared/pkg/types.SecwareTask
, each corresponding to a Secware.
// SecwareTask is the task to be executed by the specified Secware
type SecwareTask struct {
SecwareId int `json:\"secware_id\"`
SecwareVersion int `json:\"secware_version\"`
SignedTx HexBytes `json:\"signed_tx\"` // The signed transaction to be sent to the target chain
StartTime HexInt64 `json:\"start_time\"` // Task start time
EndTime HexInt64 `json:\"end_time\"` // Task deadline
Args string `json:\"args\"` // Additional parameters required by specific Secware, in JSON string format
}
The Gateway sends []SecwareTask
to the Fanout Service.
After receiving []SecwareTask
from the Gateway, the Fanout Service uses the Gateway's private key to sign each element in the array, resulting in a set of shared/pkg/types.SignedSecwareTask
, where the Operator
field is left empty.
// SignedSecwareTask is the SecwareTask signed by the Gateway, which is the complete input for the Secware
type SignedSecwareTask struct {
Operator HexBytes `json:\"operator,omitempty\"` // Operator's address
Task SecwareTask `json:\"task\"`
SigGateway HexBytes `json:\"sig_gateway\"` // Gateway's signature on the Task
}
The Fanout Service needs to select a group of Operators based on the Fanout policy and send []SignedSecwareTask
to each Operator in the group.
After receiving []SignedSecwareTask
from the Fanout Service, the Operator executes the following for each element:
- Fills its own on-chain Operator address into the
SignedSecwareTask.Operator
field. - According to the
(SecwareId, SecwareVersion)
described inSignedSecwareTask.Task
, sends eachSignedSecwareTask
to the corresponding Secware.
After receiving SignedSecwareTask
from the Operator, the Secware executes:
- Verifies whether
SignedSecwareTask.SigGateway
is valid. - Verifies whether
(SecwareId, SecwareVersion)
matches itself. - Parses the extra parameters in JSON format from
SecwareTask.Args
. - Executes the Task.
- Writes the result into
shared/pkg/types.SecwareResult
. - Combines the Operator address and execution result to compute an HMAC on
SecwareResult
using its own private key, and fills it into theSecwareResult.SigSecware
field. - Returns
SecwareResult
to the Operator.
// SecwareResult fields are normally filled by the Secware; in case of Timeout/Crash, they are filled by the Operator.
type SecwareResult struct {
Code int `json:\"code\"` // Status code: 0 - Normal, 1 - Timeout, 2 - Crash, >=3 - Used freely by Secware to indicate various unsafe states of the transaction
Message string `json:\"message\"` // Status description
Details string `json:\"result\"` // Detailed result output by Secware in JSON string format. Even if empty, should be filled with an empty JSON '{}'
Operator HexBytes `json:\"operator\"` // Operator's address. Used by Secware to generate HMAC
}
// SignedSecwareResult is the complete result after adding the HMAC computed by Secware
type SignedSecwareResult struct {
Result SecwareResult `json:\"result\"`
SigSecware HexBytes `json:\"sig_secware,omitempty\"` // HMAC-SHA256 computed from SecwareResult and Secware's private key
}
Finally, the Operator will, before SecwareTask.EndTime
:
- Summarize the execution results from each Secware (including Timeout/Crash), where each Secware corresponds to a
SecwareResult
. - Sign the contents of
[]SecwareResult
using its own private key. - Fill the
shared/pkg/types.SignedOperatorResult
structure and send it to the Gateway.
The Gateway waits and summarizes the execution results submitted by Operators before each SecwareTask.EndTime
. Then it performs:
- Completes the results of Operators that did not respond.
- Computes consensus.
- If the consensus result is safe, it will forward
SignedTx
to the target network, wait for and collect the execution results from the target network. - Summarizes the execution results of each step and returns them to the end user.
Serialize SecwareTask
in JSON according to the order of field declarations, without spaces between fields. Fields of types HexBytes
and HexInt64
are encoded as strings starting with 0x
. Even if HexBytes
is empty, it retains 0x
.
Compute the SHA3 hash of the serialized []byte
, then perform an ECDSA signature. This process is the same as the signing process in go-ethereum.
Same as the Gateway signature, but the object is SignedSecwareResult
.
Serialize SecwareResult
in JSON according to the order of field declarations to get msg
, use the private key held by this version of Secware as key
, compute HMAC-SHA256(msg, key)
.
Operators regularly request the currently enabled (SecwareId, SecwareVersion)
pairs from the Gateway, and find:
- If there are pairs they don't hold, they pull the Docker images.
- If there are pairs they've already started but are not in the list returned by the Gateway, they shut down the corresponding Docker compose.
- Configuration:
./mock_secware/pkg/config/config.go
- Entry point:
./mock_secware/cmd/main.go
- Test:
./mock_secware/test/task_test.go
The input of the HTTP RPC is defs.SignedSecwareTask
, and you can predefine the behavior of mock_secware
through defs.SignedSecwareTask.Args
.
The Args
field is the JSON serialization of mock_secware/handlers.SecwarerArgs
.
// SecwarerArgs are additional parameters provided to mock_secware, coming from SignedSecwareTask.Task.Args (JSON)
// - result: string, indicates the predefined security audit result returned by mock_secware, used for debugging, such as \"Yes\", \"No\", etc.
// - sleep: int, indicates the duration (in seconds) that mock_secware waits before executing actions
// - crash: bool, indicates whether mock_secware ignores the return and actively crashes
type SecwarerArgs struct {
Result defs.HexBytes `json:\"result,omitempty\"`
Sleep int `json:\"sleep,omitempty\"`
Crash bool `json:\"crash,omitempty\"`
}
Deployer: 0x24Da3571C2CB353D51b5B855B17104769983C1Ca
GoPlusProxyAdmin: 0xd55bda80D67b0FC64181F746136A97C3625CF17f
owner: 0x0A33f7Ad41A2Ed3510EF5a65b6B4397c6307e410
GoPlusServiceManager: 0xa3F64D3102a035db35c42A9001BBc83e08c7a366
Impl: 0x6915dDE03Ff4f34cfB614ED2e64B50e74A6cDD3A
owner: 0x0A33f7Ad41A2Ed3510EF5a65b6B4397c6307e410
RegistryCoordinator: 0x91228C6361997a5a4da1a01EdDB2F6B604536A32
Impl: 0x7eD92F181C787E4B89871f826550D70923E3DdB0
BLSApkRegistry: 0x24BFd4c4ECD2B6D08231891D218b077F0cd35024
Impl: 0x0845f9C8B6a6D7C7535475Ea5F7f9aEC07cd7184
IndexRegistry: 0xC2547047D15c8eaBB02e744b4e3CCbf73E064253
Impl: 0x35e575e1AaE5E22300DD516a995aB9CCB5b5fa07
StakeRegistry: 0xE96A246a0F582B8354B98Fb311eE34d141D35c6B
Impl: 0x4Eaa7ca2991256AC3Cc3E6e38E775729BD517E0E
OperatorStateRetriever: 0xD5D7fB4647cE79740E6e83819EFDf43fa74F8C31
PauserRegistry: 0xBe5eFb78869E0DE135350e813065Ac1D81a2e1FD
ChurnApprover: 0xA6abe31F70311B59b2f1f0Adc9CaBD9bdAb3dc55
Ejector: 0xBc6Ce40A4137F42d14c8CD1afF944000c8921A1D
Deployer: 0x15fbbC47a244aE2A38071A106dCfcF3D57C9D939
GoPlusProxyAdmin: 0x84db75e0565dF040AC426C555A041b787B5559E3
owner: 0x15fbbC47a244aE2A38071A106dCfcF3D57C9D939
GoPlusServiceManager: 0x6E0e0479e177c7F5111682C7025b4412613cd9dE
Impl: 0x59D942eFd3B4038EFCD9C8B95d6174213a849697
owner: 0x15fbbC47a244aE2A38071A106dCfcF3D57C9D939
RegistryCoordinator: 0x61AA80e5891DbfCebD0B78a704F3de996E449FdE
Impl: 0x024943FaEa481b91e6e3D348C620360a365C9071
BLSApkRegistry: 0x3a57A455758b1f53D9f36a7B14E263B3DA081bf6
Impl: 0x759f3bdAbDAC9fDd8C2b252cB8B3624EaB37747c
IndexRegistry: 0x54909D6b0518F93da140DeE19c74F7e4e46f1e31
Impl: 0xA94F3BD1AfC9c1F9CB16b860fb2BA341E2D4b258
StakeRegistry: 0xCB20b2b4e69FD545f40b7676F7d6f069a0Ad9d24
Impl: 0xaA3e077882f0aECF00174DcfecFCC3755A58B9E1
OperatorStateRetriever: 0x5ce26317F7edCBCBD1a569629af5DC41c1622045
PauserRegistry: 0xFCE5c45b496F944588Ea6fF5a7E67cA0292010C2
ChurnApprover: 0x15fbbC47a244aE2A38071A106dCfcF3D57C9D939
Ejector: 0x15fbbC47a244aE2A38071A106dCfcF3D57C9D939
ServiceManager
and ECDSAStakeRegistry
are TUP contracts; the former handles the creation and response of Tasks and interacts with EigenLayer. The latter provides the joining and exiting of Operators.
Both of these TUP contracts have ProxyAdmin
as the owner, and the owner of ProxyAdmin
is the deployer
.