Skip to content

Commit

Permalink
Simplify EncryptedRPC Client (#1877)
Browse files Browse the repository at this point in the history
* encr client

* cleanup

* fix error bubbling
  • Loading branch information
tudor-malene authored Apr 15, 2024
1 parent 261253b commit 4e6e239
Show file tree
Hide file tree
Showing 17 changed files with 139 additions and 208 deletions.
16 changes: 8 additions & 8 deletions go/common/errutil/evm_serialisable.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
package errutil

// EVMSerialisableError is an API error that encompasses an EVM error with a code and a reason
type EVMSerialisableError struct {
Err string
Reason interface{}
Code int
// DataError is an API error that encompasses an EVM error with a code and a reason
type DataError struct {
Code int `json:"code"`
Err string `json:"message"`
Reason interface{} `json:"data,omitempty"`
}

func (e EVMSerialisableError) Error() string {
func (e DataError) Error() string {
return e.Err
}

func (e EVMSerialisableError) ErrorCode() int {
func (e DataError) ErrorCode() int {
return e.Code
}

func (e EVMSerialisableError) ErrorData() interface{} {
func (e DataError) ErrorData() interface{} {
return e.Reason
}
31 changes: 21 additions & 10 deletions go/common/log_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ten-protocol/go-ten/go/common/viewingkey"
"github.com/ten-protocol/go-ten/lib/gethfork/rpc"
Expand All @@ -25,16 +24,28 @@ type LogSubscription struct {
Filter *FilterCriteriaJSON
}

// IDAndEncLog pairs an encrypted log with the ID of the subscription that generated it.
type IDAndEncLog struct {
SubID rpc.ID
EncLog []byte
}
func CreateAuthenticatedLogSubscriptionPayload(args []interface{}, vk *viewingkey.ViewingKey) (*LogSubscription, error) {
logSubscription := &LogSubscription{
ViewingKey: &viewingkey.RPCSignedViewingKey{
PublicKey: vk.PublicKey,
SignatureWithAccountKey: vk.SignatureWithAccountKey,
SignatureType: vk.SignatureType,
},
}

// IDAndLog pairs a log with the ID of the subscription that generated it.
type IDAndLog struct {
SubID rpc.ID
Log *types.Log
// If there are less than two arguments, it means no filter criteria was passed.
if len(args) < 2 {
logSubscription.Filter = &FilterCriteriaJSON{}
return logSubscription, nil
}

filterCriteria, ok := args[1].(FilterCriteria)
if !ok {
return nil, fmt.Errorf("invalid subscription")
}
fc := FromCriteria(filterCriteria)
logSubscription.Filter = &fc
return logSubscription, nil
}

// FilterCriteriaJSON is a structure that JSON-serialises to a format that can be successfully deserialised into a
Expand Down
4 changes: 2 additions & 2 deletions go/common/subscription/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ func ForwardFromChannels[R any](inputChannels []chan R, unsubscribed *atomic.Boo
continue
}

if unsubscribed.Load() {
if unsubscribed != nil && unsubscribed.Load() {
return
}

switch v := value.Interface().(type) {
case time.Time:
// exit the loop to avoid a goroutine leak
if unsubscribed.Load() {
if unsubscribed != nil && unsubscribed.Load() {
return
}
case R:
Expand Down
2 changes: 1 addition & 1 deletion go/enclave/events/subscription_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func NewSubscriptionManager(storage storage.Storage, chainID int64, logger gethl
func (s *SubscriptionManager) AddSubscription(id gethrpc.ID, encodedSubscription []byte) error {
subscription := &common.LogSubscription{}
if err := json.Unmarshal(encodedSubscription, subscription); err != nil {
return fmt.Errorf("could not decocde log subscription from RLP. Cause: %w", err)
return fmt.Errorf("could not decode log subscription. Cause: %w", err)
}

// verify the viewing key
Expand Down
4 changes: 2 additions & 2 deletions go/enclave/evm/evm_facade.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ func initParams(storage storage.Storage, gethEncodingService gethencoding.Encodi
}

func newErrorWithReasonAndCode(err error) error {
result := &errutil.EVMSerialisableError{
result := &errutil.DataError{
Err: err.Error(),
}

Expand All @@ -316,7 +316,7 @@ func newRevertError(result *gethcore.ExecutionResult) error {
if errUnpack == nil {
err = fmt.Errorf("execution reverted: %v", reason)
}
return &errutil.EVMSerialisableError{
return &errutil.DataError{
Err: err.Error(),
Reason: hexutil.Encode(result.Revert()),
Code: 3, // todo - magic number, really needs thought around the value and made a constant
Expand Down
4 changes: 0 additions & 4 deletions go/enclave/rpc/EstimateGas.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,6 @@ func EstimateGasExecute(builder *CallBuilder[CallParamsWithBlock, hexutil.Uint64
}

// return EVM error
evmErr, err := serializeEVMError(err)
if err == nil {
err = fmt.Errorf(string(evmErr))
}
builder.Err = err
return nil
}
Expand Down
27 changes: 0 additions & 27 deletions go/enclave/rpc/TenEthCall.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package rpc

import (
"encoding/json"
"errors"
"fmt"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ten-protocol/go-ten/go/common/errutil"
"github.com/ten-protocol/go-ten/go/common/gethencoding"
"github.com/ten-protocol/go-ten/go/common/log"
"github.com/ten-protocol/go-ten/go/common/syserr"
Expand Down Expand Up @@ -60,11 +58,6 @@ func TenCallExecute(builder *CallBuilder[CallParamsWithBlock, string], rpc *Encr
return err
}

// extract the EVM error
evmErr, err := serializeEVMError(err)
if err == nil {
err = fmt.Errorf(string(evmErr))
}
builder.Err = err
return nil
}
Expand All @@ -78,23 +71,3 @@ func TenCallExecute(builder *CallBuilder[CallParamsWithBlock, string], rpc *Encr
}
return nil
}

func serializeEVMError(err error) ([]byte, error) {
var errReturn interface{}

// check if it's a serialized error and handle any error wrapping that might have occurred
var e *errutil.EVMSerialisableError
if ok := errors.As(err, &e); ok {
errReturn = e
} else {
// it's a generic error, serialise it
errReturn = &errutil.EVMSerialisableError{Err: err.Error()}
}

// serialise the error object returned by the evm into a json
errSerializedBytes, marshallErr := json.Marshal(errReturn)
if marshallErr != nil {
return nil, marshallErr
}
return errSerializedBytes, nil
}
17 changes: 1 addition & 16 deletions go/host/rpc/clientapi/client_api_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,24 +56,9 @@ func (api *FilterAPI) Logs(ctx context.Context, encryptedParams common.Encrypted
return nil, fmt.Errorf("could not subscribe for logs. Cause: %w", err)
}

// We send the ID of the newly-created subscription, before sending any log events. This is because the wallet
// extension needs to return the subscription ID to the end client, but this information is not exposed to it
// (since the subscription ID is automatically converted to a subscription object).
err = notifier.Notify(subscription.ID, common.IDAndEncLog{
SubID: subscription.ID,
})
if err != nil {
api.host.UnsubscribeLogs(subscription.ID)
return nil, fmt.Errorf("could not send subscription ID to client on subscription %s", subscription.ID)
}

var unsubscribed atomic.Bool
go subscriptioncommon.ForwardFromChannels([]chan []byte{logsFromSubscription}, &unsubscribed, func(elem []byte) error {
msg := &common.IDAndEncLog{
SubID: subscription.ID,
EncLog: elem,
}
return notifier.Notify(subscription.ID, msg)
return notifier.Notify(subscription.ID, elem)
})
go subscriptioncommon.HandleUnsubscribe(subscription, &unsubscribed, func() {
api.host.UnsubscribeLogs(subscription.ID)
Expand Down
2 changes: 1 addition & 1 deletion go/obsclient/authclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ func (ac *AuthObsClient) BalanceAt(ctx context.Context, blockNumber *big.Int) (*
return (*big.Int)(&result), err
}

func (ac *AuthObsClient) SubscribeFilterLogs(ctx context.Context, filterCriteria common.FilterCriteria, ch chan common.IDAndLog) (ethereum.Subscription, error) {
func (ac *AuthObsClient) SubscribeFilterLogs(ctx context.Context, filterCriteria common.FilterCriteria, ch chan types.Log) (ethereum.Subscription, error) {
return ac.rpcClient.Subscribe(ctx, rpc.SubscribeNamespace, ch, rpc.SubscriptionTypeLogs, filterCriteria)
}

Expand Down
19 changes: 15 additions & 4 deletions go/responses/responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package responses

import (
"encoding/json"
"errors"
"fmt"

"github.com/ten-protocol/go-ten/go/common/errutil"

"github.com/ten-protocol/go-ten/go/common/syserr"
)

Expand Down Expand Up @@ -116,9 +119,8 @@ func AsEncryptedEmptyResponse(encryptHandler Encryptor) *EnclaveResponse {

// AsEncryptedError - Encodes and encrypts an error to be returned for a concrete user.
func AsEncryptedError(err error, encrypt Encryptor) *EnclaveResponse {
errStr := err.Error()
userResp := UserResponse[string]{
ErrStr: &errStr,
Err: convertError(err),
}

encoded, err := json.Marshal(userResp)
Expand Down Expand Up @@ -161,9 +163,18 @@ func DecodeResponse[T any](encoded []byte) (*T, error) {
if err != nil {
return nil, err
}
if resp.ErrStr != nil {
return nil, fmt.Errorf(*resp.ErrStr)
if resp.Err != nil {
return nil, resp.Err
}

return resp.Result, nil
}

func convertError(err error) *errutil.DataError {
// check if it's a serialized error and handle any error wrapping that might have occurred
var e *errutil.DataError
if ok := errors.As(err, &e); ok {
return e
}
return &errutil.DataError{Err: err.Error()}
}
10 changes: 3 additions & 7 deletions go/responses/types.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package responses

import (
"fmt"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ten-protocol/go-ten/go/common/errutil"
)

type ViewingKeyEncryptor func([]byte) ([]byte, error)
Expand All @@ -14,15 +13,12 @@ type ViewingKeyEncryptor func([]byte) ([]byte, error)
// which will be decoded only on the client side.
type UserResponse[T any] struct {
Result *T
ErrStr *string
Err *errutil.DataError
}

// Error - converts the encoded string in the response into a normal error and returns it.
func (ur *UserResponse[T]) Error() error {
if ur.ErrStr != nil {
return fmt.Errorf(*ur.ErrStr)
}
return nil
return ur.Err
}

// Responses
Expand Down
Loading

0 comments on commit 4e6e239

Please sign in to comment.