Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Worker executor response signature support #154

Closed
wants to merge 8 commits into from

Conversation

zees-dev
Copy link
Collaborator

@zees-dev zees-dev commented Jun 15, 2024

Context

This PR adds support for b7s workers to optionally support signing responses (using any arbitrarily provided signature scheme/function as an executor option).
Additionally, support is added for providing additional relevant metadata by workers - as a worker executor option.

  • This is specifically useful when using b7s node as a lib, where you'd want the worker to sign responses with custom provided signature scheme/algorithm (such as in the case of using b7s as AVS)
  • With this change, the head node would return aggregated worker responses, in addition to their respective signatures (assuming the workers opted into signing with some desired scheme)
  • The same applies for metadata, which can be optionally added/injected and then returned in aggregated response from the head-node

@zees-dev zees-dev requested review from Maelkum and dmikey June 15, 2024 02:03
@dmikey
Copy link
Contributor

dmikey commented Jun 20, 2024

Overall I like this. I think it works well with having a signer configurable to a node. I think we will need to shift this into support multiple signing options, but at face value I see now problem with this approach.

@zees-dev
Copy link
Collaborator Author

@dmikey Additionally added support for providing metadata from workers.
With the metadata injection support; one can say we do not need to add the optional signature override - since that can be part of the metadata response.
^ Hence, do let me know if I should remove the option to override the signature.

Copy link
Collaborator

@Maelkum Maelkum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code-wise I think this is great! However I feel this is a little confused when it comes to some concepts, would love to discuss some things in more detail..

  1. I don't really think the executor should know anything about signing. Executor should be dumb and only handle OS-level stuff and not be cognizant of anything else. It takes care of setting up the working directory and cleans up afterwards, sets the process resource limits and executes the process (OS-level exec() type stuff). I don't think the concept of signing fits well here and I think it's mixing up concerns. I think this would be more suited in the node package and the node signs the execution result the executor returns. Basically, I would just move this code to a different place.

  2. I'm not sure the aggregation part is working correctly. Commented in more detail on the relevant part of the code.

  3. If the workers can choose their own signing scheme, we need to pass along the information on what scheme was used, no? It cannot be unlabeled else we don't know how to verify the signature. Also ties into discussion point 4.

  4. Does it make sense for each worker to have the freedom to choose their signing schemes? IMO, they can choose which ones they support, but perhaps it's the client that can request a specific one in the execution request. If a client didn't set one, a head node can request a default scheme we choose, or not use any by default. The workers can then self-select - "if I don't support this signing scheme I won't reply to a roll call". This is super close to what we have with b7s attributes too. Though, at the moment, the attributes are only a strict match, and we don't support a syntax like B7S_SignatureAlgorithms=A,B,C,D to match "C". This is relevant if the node supports multiple signing schemes.

If we do move the signing code to the node package, we need to handle three main paths

I may be wrong on any one of these points or I might have misunderstood something, so feel free to correct me!

}

type MetaProvider interface {
WithMetadata(execute.Request, execute.RuntimeOutput) (interface{}, error)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WithMetadata - This function name is IMO more common for specifying functional options - e.g. server.New(server.WithPort(8888)). I think the name of a function is a bit misleading and is in fact more CreateMetadata or GetMetadata (this one less so because "get" implies extracting something from the input params).

I think just Metadata(req, runtimeOutput) (any, error) is just fine.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick - I prefer using any instead of interface{}. They mean the same, but I think any reads a little nicer.

@@ -66,10 +67,28 @@ func (e *Executor) executeFunction(requestID string, req execute.Request) (execu

out, usage, err := e.executeCommand(cmd)
if err != nil {
return out, execute.Usage{}, fmt.Errorf("command execution failed: %w", err)
return out, execute.Usage{}, []byte{}, nil, fmt.Errorf("command execution failed: %w", err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And other places too - why not return nil instead of []byte{}?

Comment on lines 48 to +59
stats[output] = resultStats{
seen: 0,
peers: make([]peer.ID, 0),
seen: 0,
peers: make([]peer.ID, 0),
signature: res.Signature,
metadata: res.Metadata,
}
}

stat.seen++
stat.peers = append(stat.peers, executingPeer)
stat.signature = res.Signature
stat.metadata = res.Metadata
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will work as intended..

Is this signature like a hash that can be recalculated by anyone or is it a signature that can be tied to the signer (can be verified by a public key)? I assume it's the latter.

Let's say we have 5 execution responses from 5 worker nodes. We will have e.g. the same execution result (stdout of the blockless runtime) but 5 different signatures, and I believe 5 different metadata objects. (I'm not sure if metadata is unique or not, but since it's configurable, it can be anything.)

When aggregating, we iterate through the results, and for the seen results, we increment the number of times it was seen, add the worker ID to the list of peers that have this exact result, and set the signature and metadata to that of the result we just processed. Meaning if we iterate through execution results of worker1 through worker5, we will save the signature of worker5 (if we process that one last, which also isn't guaranteed in a map). In each iteration we override the previous signature/metadata.

I think we will need to have a map that will map worker IDs to signatures and metadata.

For example something like:

{
    "result": "whatever",
    "peers": [
        "worker1",
        "worker2",
        "worker3",
        "worker4",
        "worker5"
    ],
    "frequency": 100,
    "signatures": {
        "worker1": {
            "scheme": "abc", // without specifying the scheme we don't know how to verify the signature, no?
            "sig": "0x1234567890abcdef1234567890abcdef"
        },
        // other workers
    },
    "metadata": {
        "worker1": {
            // metadata object
        },
        // other workers
    }
}

@@ -98,6 +99,7 @@ func (r *Replica) execute(view uint, sequence uint, digest string) error {
RequestTimestamp: request.Timestamp,
Replica: r.id,
},
Signature: hex.EncodeToString(res.Signature),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PBFT already has and mandates signatures - note the msg.Sign() invocation below that will overwrite this value.

@zees-dev
Copy link
Collaborator Author

Closing this PR in favour of #156

@zees-dev zees-dev closed this Jun 28, 2024
@zees-dev zees-dev deleted the feat/worker-response-sig-support branch July 20, 2024 02:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants