From 7444d7851abddd43fd1f868fb3e592e5a0bdc99e Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Feb 2023 17:34:59 +0000 Subject: [PATCH 01/11] docs update --- documentation/docs/guide/chains_and_nodes/chain-management.md | 2 +- documentation/docs/guide/chains_and_nodes/setting-up-a-chain.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/docs/guide/chains_and_nodes/chain-management.md b/documentation/docs/guide/chains_and_nodes/chain-management.md index 9373ef1215..40111a90b1 100644 --- a/documentation/docs/guide/chains_and_nodes/chain-management.md +++ b/documentation/docs/guide/chains_and_nodes/chain-management.md @@ -68,7 +68,7 @@ chain is. wasp-cli chain rotate ``` -or, if you control the governor address and wish to relinquish the control of the alias output to the chain committe: +or: ```shell wasp-cli chain rotate-with-dkg --peers=<...> diff --git a/documentation/docs/guide/chains_and_nodes/setting-up-a-chain.md b/documentation/docs/guide/chains_and_nodes/setting-up-a-chain.md index 347958638c..464ba728f7 100644 --- a/documentation/docs/guide/chains_and_nodes/setting-up-a-chain.md +++ b/documentation/docs/guide/chains_and_nodes/setting-up-a-chain.md @@ -100,7 +100,7 @@ some [core contracts](../core_concepts/core_contracts/overview.md). You should also have an EVM-JSONRPC server opened on: ```info -/chain//evm/jsonrpc +/chain//evm ``` ### Deploying a Wasm Contract From 009484b2e7fb55bbd03cff11c0cf10b968f78279 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Feb 2023 17:35:35 +0000 Subject: [PATCH 02/11] improve peering import command help --- tools/wasp-cli/peering/export.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/wasp-cli/peering/export.go b/tools/wasp-cli/peering/export.go index cc849fcad5..3d8b73800d 100644 --- a/tools/wasp-cli/peering/export.go +++ b/tools/wasp-cli/peering/export.go @@ -87,7 +87,7 @@ func initImportTrustedJSONCmd() *cobra.Command { var node string cmd := &cobra.Command{ - Use: "import-trusted", + Use: "import-trusted ", Short: "imports a JSON of trusted peers and makes a node trust them.", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { From 32d058b0f787fe4e8fcfb8d3c9ee443c13ee8b81 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Feb 2023 17:38:43 +0000 Subject: [PATCH 03/11] activate chain on own node after deployment --- tools/wasp-cli/chain/activate.go | 53 ++++++++++++++++-------------- tools/wasp-cli/chain/deploy.go | 2 ++ tools/wasp-cli/chain/rundkg.go | 2 +- tools/wasp-cli/peering/distrust.go | 2 +- 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/tools/wasp-cli/chain/activate.go b/tools/wasp-cli/chain/activate.go index 3c643ea2e7..7462272762 100644 --- a/tools/wasp-cli/chain/activate.go +++ b/tools/wasp-cli/chain/activate.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/cobra" "github.com/iotaledger/wasp/clients/apiclient" + "github.com/iotaledger/wasp/packages/isc" "github.com/iotaledger/wasp/tools/wasp-cli/cli/cliclients" "github.com/iotaledger/wasp/tools/wasp-cli/cli/config" "github.com/iotaledger/wasp/tools/wasp-cli/log" @@ -23,41 +24,43 @@ func initActivateCmd() *cobra.Command { Run: func(cmd *cobra.Command, args []string) { node = waspcmd.DefaultWaspNodeFallback(node) chain = defaultChainFallback(chain) - chainID := config.GetChain(chain) - client := cliclients.WaspClient(node) + activateChain(node, chainID) + }, + } - r, httpStatus, err := client.ChainsApi.GetChainInfo(context.Background(), chainID.String()).Execute() //nolint:bodyclose // false positive + waspcmd.WithWaspNodeFlag(cmd, &node) + + withChainFlag(cmd, &chain) + return cmd +} - if err != nil && httpStatus.StatusCode != http.StatusNotFound { - log.Check(err) - } +func activateChain(node string, chainID isc.ChainID) { + client := cliclients.WaspClient(node) + r, httpStatus, err := client.ChainsApi.GetChainInfo(context.Background(), chainID.String()).Execute() //nolint:bodyclose // false positive - if r != nil && r.IsActive { - return - } + if err != nil && httpStatus.StatusCode != http.StatusNotFound { + log.Check(err) + } - if r == nil { - _, err2 := client.ChainsApi.SetChainRecord(context.Background(), chainID.String()).ChainRecord(apiclient.ChainRecord{ - IsActive: true, - AccessNodes: []string{}, - }).Execute() //nolint:bodyclose // false positive + if r != nil && r.IsActive { + return + } - log.Check(err2) - } else { - _, err = client.ChainsApi.ActivateChain(context.Background(), chainID.String()).Execute() //nolint:bodyclose // false positive + if r == nil { + _, err2 := client.ChainsApi.SetChainRecord(context.Background(), chainID.String()).ChainRecord(apiclient.ChainRecord{ + IsActive: true, + AccessNodes: []string{}, + }).Execute() //nolint:bodyclose // false positive - log.Check(err) - } + log.Check(err2) + } else { + _, err = client.ChainsApi.ActivateChain(context.Background(), chainID.String()).Execute() //nolint:bodyclose // false positive - log.Printf("Chain activated") - }, + log.Check(err) } - waspcmd.WithWaspNodeFlag(cmd, &node) - - withChainFlag(cmd, &chain) - return cmd + log.Printf("Chain activated") } func initDeactivateCmd() *cobra.Command { diff --git a/tools/wasp-cli/chain/deploy.go b/tools/wasp-cli/chain/deploy.go index e17b05b322..7d5d615dbd 100644 --- a/tools/wasp-cli/chain/deploy.go +++ b/tools/wasp-cli/chain/deploy.go @@ -106,6 +106,8 @@ func initDeployCmd() *cobra.Command { log.Check(err) config.AddChain(chainName, chainid.String()) + + activateChain(node, chainid) }, } diff --git a/tools/wasp-cli/chain/rundkg.go b/tools/wasp-cli/chain/rundkg.go index b6918591b3..2d61d0af0a 100644 --- a/tools/wasp-cli/chain/rundkg.go +++ b/tools/wasp-cli/chain/rundkg.go @@ -28,7 +28,7 @@ func initRunDKGCmd() *cobra.Command { ) cmd := &cobra.Command{ - Use: "rundkg", + Use: "rundkg --peers=...", Short: "Runs the DKG on specified nodes", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { diff --git a/tools/wasp-cli/peering/distrust.go b/tools/wasp-cli/peering/distrust.go index 99cdaeedf1..c6a37d809a 100644 --- a/tools/wasp-cli/peering/distrust.go +++ b/tools/wasp-cli/peering/distrust.go @@ -18,7 +18,7 @@ import ( func initDistrustCmd() *cobra.Command { var node string cmd := &cobra.Command{ - Use: "distrust ", + Use: "distrust ", Short: "Remove the specified node from a list of trusted nodes. All related public keys are distrusted, if peeringURL is provided.", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { From 04beb4f109aa74c8737207ff56706e5a329c3328 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Feb 2023 17:50:25 +0000 Subject: [PATCH 04/11] allow rotate-with-dkg without peers param --- tools/wasp-cli/chain/rotate.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/wasp-cli/chain/rotate.go b/tools/wasp-cli/chain/rotate.go index d00ea6845d..5bdd95f3e8 100644 --- a/tools/wasp-cli/chain/rotate.go +++ b/tools/wasp-cli/chain/rotate.go @@ -63,7 +63,6 @@ func initRotateWithDKGCmd() *cobra.Command { waspcmd.WithWaspNodeFlag(cmd, &node) waspcmd.WithPeersFlag(cmd, &peers) - log.Check(cmd.MarkFlagRequired("peers")) withChainFlag(cmd, &chain) cmd.Flags().IntVarP(&quorum, "quorum", "", 0, "quorum (default: 3/4s of the number of committee nodes)") return cmd From ecefe959598abedfc0464098f7194ce4bf3263cc Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Feb 2023 19:14:15 +0000 Subject: [PATCH 05/11] add/remove access nodes by peer name --- clients/apiclient/api/openapi.yaml | 22 +++++++----- clients/apiclient/api_chains.go | 24 ++++++------- clients/apiclient/docs/ChainsApi.md | 20 +++++------ clients/apiclient/docs/NodeApi.md | 4 +-- packages/webapi/apierrors/errors.go | 6 ++-- .../webapi/controllers/chain/access_nodes.go | 23 ++++++------ .../webapi/controllers/chain/controller.go | 8 ++--- packages/webapi/interfaces/interfaces.go | 4 +-- packages/webapi/services/node.go | 33 +++++++++++------ tools/cluster/tests/wasp-cli_rotation_test.go | 2 +- tools/wasp-cli/chain/access-nodes.go | 36 +++++++++++++------ tools/wasp-cli/chain/activate.go | 1 - 12 files changed, 105 insertions(+), 78 deletions(-) diff --git a/clients/apiclient/api/openapi.yaml b/clients/apiclient/api/openapi.yaml index a74c83e45d..a16df08f62 100644 --- a/clients/apiclient/api/openapi.yaml +++ b/clients/apiclient/api/openapi.yaml @@ -106,7 +106,7 @@ paths: summary: Get information about a specific chain tags: - chains - /chains/{chainID}/access-node/{publicKey}: + /chains/{chainID}/access-node/{peer}: delete: operationId: removeAccessNode parameters: @@ -117,9 +117,9 @@ paths: schema: format: string type: string - - description: Nodes public key (Hex) + - description: Name of the peer to remove as access node in: path - name: publicKey + name: peer required: true schema: format: string @@ -149,9 +149,9 @@ paths: schema: format: string type: string - - description: Nodes public key (Hex) + - description: Name of the peer to add as access node in: path - name: publicKey + name: peer required: true schema: format: string @@ -3843,7 +3843,7 @@ components: name: InStateOutputMetricItem InfoResponse: example: - peeringURL: peeringURL + peeringURL: 0.0.0.0:4000 l1Params: protocol: rentStructure: @@ -3871,6 +3871,7 @@ components: $ref: '#/components/schemas/L1Params' peeringURL: description: The net id of the node + example: 0.0.0.0:4000 format: string type: string xml: @@ -4393,7 +4394,7 @@ components: name: OutputID PeeringNodeIdentityResponse: example: - peeringURL: peeringURL + peeringURL: localhost:4000 name: name publicKey: 0x0000 isTrusted: true @@ -4411,6 +4412,7 @@ components: name: Name peeringURL: description: The peering URL of the peer + example: localhost:4000 format: string type: string xml: @@ -4540,7 +4542,7 @@ components: PeeringNodeStatusResponse__: example: isAlive: true - peeringURL: peeringURL + peeringURL: localhost:4000 name: name publicKey: 0x0000 numUsers: 1 @@ -4573,6 +4575,7 @@ components: name: NumUsers peeringURL: description: The peering URL of the peer + example: localhost:4000 format: string type: string xml: @@ -4596,7 +4599,7 @@ components: name: PeeringNodeStatusResponse PeeringTrustRequest: example: - peeringURL: peeringURL + peeringURL: localhost:4000 name: name publicKey: 0x0000 properties: @@ -4607,6 +4610,7 @@ components: name: Name peeringURL: description: The peering URL of the peer + example: localhost:4000 format: string type: string xml: diff --git a/clients/apiclient/api_chains.go b/clients/apiclient/api_chains.go index 0df11ef9b1..9e48a50eb1 100644 --- a/clients/apiclient/api_chains.go +++ b/clients/apiclient/api_chains.go @@ -141,7 +141,7 @@ type ApiAddAccessNodeRequest struct { ctx context.Context ApiService *ChainsApiService chainID string - publicKey string + peer string } func (r ApiAddAccessNodeRequest) Execute() (*http.Response, error) { @@ -153,15 +153,15 @@ AddAccessNode Configure a trusted node to be an access node. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param chainID ChainID (Bech32) - @param publicKey Nodes public key (Hex) + @param peer Name of the peer to add as access node @return ApiAddAccessNodeRequest */ -func (a *ChainsApiService) AddAccessNode(ctx context.Context, chainID string, publicKey string) ApiAddAccessNodeRequest { +func (a *ChainsApiService) AddAccessNode(ctx context.Context, chainID string, peer string) ApiAddAccessNodeRequest { return ApiAddAccessNodeRequest{ ApiService: a, ctx: ctx, chainID: chainID, - publicKey: publicKey, + peer: peer, } } @@ -178,9 +178,9 @@ func (a *ChainsApiService) AddAccessNodeExecute(r ApiAddAccessNodeRequest) (*htt return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/chains/{chainID}/access-node/{publicKey}" + localVarPath := localBasePath + "/chains/{chainID}/access-node/{peer}" localVarPath = strings.Replace(localVarPath, "{"+"chainID"+"}", url.PathEscape(parameterValueToString(r.chainID, "chainID")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"publicKey"+"}", url.PathEscape(parameterValueToString(r.publicKey, "publicKey")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"peer"+"}", url.PathEscape(parameterValueToString(r.peer, "peer")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -1346,7 +1346,7 @@ type ApiRemoveAccessNodeRequest struct { ctx context.Context ApiService *ChainsApiService chainID string - publicKey string + peer string } func (r ApiRemoveAccessNodeRequest) Execute() (*http.Response, error) { @@ -1358,15 +1358,15 @@ RemoveAccessNode Remove an access node. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param chainID ChainID (Bech32) - @param publicKey Nodes public key (Hex) + @param peer Name of the peer to remove as access node @return ApiRemoveAccessNodeRequest */ -func (a *ChainsApiService) RemoveAccessNode(ctx context.Context, chainID string, publicKey string) ApiRemoveAccessNodeRequest { +func (a *ChainsApiService) RemoveAccessNode(ctx context.Context, chainID string, peer string) ApiRemoveAccessNodeRequest { return ApiRemoveAccessNodeRequest{ ApiService: a, ctx: ctx, chainID: chainID, - publicKey: publicKey, + peer: peer, } } @@ -1383,9 +1383,9 @@ func (a *ChainsApiService) RemoveAccessNodeExecute(r ApiRemoveAccessNodeRequest) return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/chains/{chainID}/access-node/{publicKey}" + localVarPath := localBasePath + "/chains/{chainID}/access-node/{peer}" localVarPath = strings.Replace(localVarPath, "{"+"chainID"+"}", url.PathEscape(parameterValueToString(r.chainID, "chainID")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"publicKey"+"}", url.PathEscape(parameterValueToString(r.publicKey, "publicKey")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"peer"+"}", url.PathEscape(parameterValueToString(r.peer, "peer")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} diff --git a/clients/apiclient/docs/ChainsApi.md b/clients/apiclient/docs/ChainsApi.md index 48a6f747fe..7f0032b1bd 100644 --- a/clients/apiclient/docs/ChainsApi.md +++ b/clients/apiclient/docs/ChainsApi.md @@ -5,7 +5,7 @@ All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- [**ActivateChain**](ChainsApi.md#ActivateChain) | **Post** /chains/{chainID}/activate | Activate a chain -[**AddAccessNode**](ChainsApi.md#AddAccessNode) | **Put** /chains/{chainID}/access-node/{publicKey} | Configure a trusted node to be an access node. +[**AddAccessNode**](ChainsApi.md#AddAccessNode) | **Put** /chains/{chainID}/access-node/{peer} | Configure a trusted node to be an access node. [**AttachToWebsocket**](ChainsApi.md#AttachToWebsocket) | **Get** /chains/{chainID}/ws | [**ChainsChainIDEvmGet**](ChainsApi.md#ChainsChainIDEvmGet) | **Get** /chains/{chainID}/evm | [**DeactivateChain**](ChainsApi.md#DeactivateChain) | **Post** /chains/{chainID}/deactivate | Deactivate a chain @@ -15,7 +15,7 @@ Method | HTTP request | Description [**GetContracts**](ChainsApi.md#GetContracts) | **Get** /chains/{chainID}/contracts | Get all available chain contracts [**GetRequestIDFromEVMTransactionID**](ChainsApi.md#GetRequestIDFromEVMTransactionID) | **Get** /chains/{chainID}/evm/tx/{txHash} | Get the ISC request ID for the given Ethereum transaction hash [**GetStateValue**](ChainsApi.md#GetStateValue) | **Get** /chains/{chainID}/state/{stateKey} | Fetch the raw value associated with the given key in the chain state -[**RemoveAccessNode**](ChainsApi.md#RemoveAccessNode) | **Delete** /chains/{chainID}/access-node/{publicKey} | Remove an access node. +[**RemoveAccessNode**](ChainsApi.md#RemoveAccessNode) | **Delete** /chains/{chainID}/access-node/{peer} | Remove an access node. [**SetChainRecord**](ChainsApi.md#SetChainRecord) | **Post** /chains/{chainID}/chainrecord | Sets the chain record. @@ -88,7 +88,7 @@ Name | Type | Description | Notes ## AddAccessNode -> AddAccessNode(ctx, chainID, publicKey).Execute() +> AddAccessNode(ctx, chainID, peer).Execute() Configure a trusted node to be an access node. @@ -106,11 +106,11 @@ import ( func main() { chainID := "chainID_example" // string | ChainID (Bech32) - publicKey := "publicKey_example" // string | Nodes public key (Hex) + peer := "peer_example" // string | Name of the peer to add as access node configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ChainsApi.AddAccessNode(context.Background(), chainID, publicKey).Execute() + resp, r, err := apiClient.ChainsApi.AddAccessNode(context.Background(), chainID, peer).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `ChainsApi.AddAccessNode``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -125,7 +125,7 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **chainID** | **string** | ChainID (Bech32) | -**publicKey** | **string** | Nodes public key (Hex) | +**peer** | **string** | Name of the peer to add as access node | ### Other Parameters @@ -762,7 +762,7 @@ Name | Type | Description | Notes ## RemoveAccessNode -> RemoveAccessNode(ctx, chainID, publicKey).Execute() +> RemoveAccessNode(ctx, chainID, peer).Execute() Remove an access node. @@ -780,11 +780,11 @@ import ( func main() { chainID := "chainID_example" // string | ChainID (Bech32) - publicKey := "publicKey_example" // string | Nodes public key (Hex) + peer := "peer_example" // string | Name of the peer to remove as access node configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ChainsApi.RemoveAccessNode(context.Background(), chainID, publicKey).Execute() + resp, r, err := apiClient.ChainsApi.RemoveAccessNode(context.Background(), chainID, peer).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `ChainsApi.RemoveAccessNode``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -799,7 +799,7 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **chainID** | **string** | ChainID (Bech32) | -**publicKey** | **string** | Nodes public key (Hex) | +**peer** | **string** | Name of the peer to remove as access node | ### Other Parameters diff --git a/clients/apiclient/docs/NodeApi.md b/clients/apiclient/docs/NodeApi.md index 615cc2baa0..3872916458 100644 --- a/clients/apiclient/docs/NodeApi.md +++ b/clients/apiclient/docs/NodeApi.md @@ -38,7 +38,7 @@ import ( ) func main() { - peeringTrustRequest := *openapiclient.NewPeeringTrustRequest("Name_example", "PeeringURL_example", "0x0000") // PeeringTrustRequest | Info of the peer to distrust + peeringTrustRequest := *openapiclient.NewPeeringTrustRequest("Name_example", "localhost:4000", "0x0000") // PeeringTrustRequest | Info of the peer to distrust configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) @@ -707,7 +707,7 @@ import ( ) func main() { - peeringTrustRequest := *openapiclient.NewPeeringTrustRequest("Name_example", "PeeringURL_example", "0x0000") // PeeringTrustRequest | Info of the peer to trust + peeringTrustRequest := *openapiclient.NewPeeringTrustRequest("Name_example", "localhost:4000", "0x0000") // PeeringTrustRequest | Info of the peer to trust configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) diff --git a/packages/webapi/apierrors/errors.go b/packages/webapi/apierrors/errors.go index 818e011e0b..d84ac4f779 100644 --- a/packages/webapi/apierrors/errors.go +++ b/packages/webapi/apierrors/errors.go @@ -5,8 +5,6 @@ import ( "fmt" "net/http" "strings" - - "github.com/iotaledger/wasp/packages/cryptolib" ) func ChainNotFoundError(chainID string) *HTTPError { @@ -30,8 +28,8 @@ func InvalidPropertyError(propertyName string, err error) *HTTPError { return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid property: %v", propertyName), err) } -func PeerNotFoundError(publicKey *cryptolib.PublicKey) *HTTPError { - return NewHTTPError(http.StatusNotFound, fmt.Sprintf("couldn't find peer with public key %s", publicKey.String()), nil) +func PeerNameNotFoundError(name string) *HTTPError { + return NewHTTPError(http.StatusNotFound, fmt.Sprintf("couldn't find peer with name %s", name), nil) } func ContractExecutionError(err error) *HTTPError { diff --git a/packages/webapi/controllers/chain/access_nodes.go b/packages/webapi/controllers/chain/access_nodes.go index b3da92e222..2bde45db4d 100644 --- a/packages/webapi/controllers/chain/access_nodes.go +++ b/packages/webapi/controllers/chain/access_nodes.go @@ -6,29 +6,28 @@ import ( "github.com/labstack/echo/v4" - "github.com/iotaledger/wasp/packages/cryptolib" "github.com/iotaledger/wasp/packages/isc" "github.com/iotaledger/wasp/packages/webapi/apierrors" "github.com/iotaledger/wasp/packages/webapi/interfaces" "github.com/iotaledger/wasp/packages/webapi/params" ) -func decodeAccessNodeRequest(e echo.Context) (isc.ChainID, *cryptolib.PublicKey, error) { +func decodeAccessNodeRequest(e echo.Context) (isc.ChainID, string, error) { chainID, err := params.DecodeChainID(e) if err != nil { - return isc.EmptyChainID(), nil, err + return isc.EmptyChainID(), "", err } - publicKey, err := params.DecodePublicKey(e) - if err != nil { - return isc.EmptyChainID(), nil, err + peer := e.Param("peer") + if peer == "" { + return isc.EmptyChainID(), "", errors.New("no peer provided") } - return chainID, publicKey, nil + return chainID, peer, nil } func (c *Controller) addAccessNode(e echo.Context) error { - chainID, publicKey, err := decodeAccessNodeRequest(e) + chainID, peer, err := decodeAccessNodeRequest(e) if err != nil { return err } @@ -37,9 +36,9 @@ func (c *Controller) addAccessNode(e echo.Context) error { return apierrors.ChainNotFoundError(chainID.String()) } - if err := c.nodeService.AddAccessNode(chainID, publicKey); err != nil { + if err := c.nodeService.AddAccessNode(chainID, peer); err != nil { if errors.Is(err, interfaces.ErrPeerNotFound) { - return apierrors.PeerNotFoundError(publicKey) + return apierrors.PeerNameNotFoundError(peer) } return err @@ -49,7 +48,7 @@ func (c *Controller) addAccessNode(e echo.Context) error { } func (c *Controller) removeAccessNode(e echo.Context) error { - chainID, publicKey, err := decodeAccessNodeRequest(e) + chainID, peer, err := decodeAccessNodeRequest(e) if err != nil { return err } @@ -58,7 +57,7 @@ func (c *Controller) removeAccessNode(e echo.Context) error { return apierrors.ChainNotFoundError(chainID.String()) } - if err := c.nodeService.DeleteAccessNode(chainID, publicKey); err != nil { + if err := c.nodeService.DeleteAccessNode(chainID, peer); err != nil { return err } diff --git a/packages/webapi/controllers/chain/controller.go b/packages/webapi/controllers/chain/controller.go index ae0ff7d4f6..36fba1d443 100644 --- a/packages/webapi/controllers/chain/controller.go +++ b/packages/webapi/controllers/chain/controller.go @@ -129,17 +129,17 @@ func (c *Controller) RegisterAdmin(adminAPI echoswagger.ApiGroup, mocker interfa SetSummary("Sets the chain record."). SetOperationId("setChainRecord") - adminAPI.PUT("chains/:chainID/access-node/:publicKey", c.addAccessNode, authentication.ValidatePermissions([]string{permissions.Write})). + adminAPI.PUT("chains/:chainID/access-node/:peer", c.addAccessNode, authentication.ValidatePermissions([]string{permissions.Write})). AddParamPath("", "chainID", "ChainID (Bech32)"). - AddParamPath("", "publicKey", "Nodes public key (Hex)"). + AddParamPath("", "peer", "Name of the peer to add as access node"). AddResponse(http.StatusUnauthorized, "Unauthorized (Wrong permissions, missing token)", authentication.ValidationError{}, nil). AddResponse(http.StatusCreated, "Access node was successfully added", nil, nil). SetSummary("Configure a trusted node to be an access node."). SetOperationId("addAccessNode") - adminAPI.DELETE("chains/:chainID/access-node/:publicKey", c.removeAccessNode, authentication.ValidatePermissions([]string{permissions.Write})). + adminAPI.DELETE("chains/:chainID/access-node/:peer", c.removeAccessNode, authentication.ValidatePermissions([]string{permissions.Write})). AddParamPath("", "chainID", "ChainID (Bech32)"). - AddParamPath("", "publicKey", "Nodes public key (Hex)"). + AddParamPath("", "peer", "Name of the peer to remove as access node"). AddResponse(http.StatusUnauthorized, "Unauthorized (Wrong permissions, missing token)", authentication.ValidationError{}, nil). AddResponse(http.StatusOK, "Access node was successfully removed", nil, nil). SetSummary("Remove an access node."). diff --git a/packages/webapi/interfaces/interfaces.go b/packages/webapi/interfaces/interfaces.go index 7d077c806e..f24e3df0a2 100644 --- a/packages/webapi/interfaces/interfaces.go +++ b/packages/webapi/interfaces/interfaces.go @@ -67,8 +67,8 @@ type MetricsService interface { var ErrPeerNotFound = errors.New("couldn't find peer") type NodeService interface { - AddAccessNode(chainID isc.ChainID, publicKey *cryptolib.PublicKey) error - DeleteAccessNode(chainID isc.ChainID, publicKey *cryptolib.PublicKey) error + AddAccessNode(chainID isc.ChainID, peer string) error + DeleteAccessNode(chainID isc.ChainID, peer string) error SetNodeOwnerCertificate(publicKey *cryptolib.PublicKey, ownerAddress iotago.Address) ([]byte, error) ShutdownNode() } diff --git a/packages/webapi/services/node.go b/packages/webapi/services/node.go index 16cc5e1aa4..22b0c76834 100644 --- a/packages/webapi/services/node.go +++ b/packages/webapi/services/node.go @@ -34,20 +34,29 @@ func NewNodeService(chainRecordRegistryProvider registry.ChainRecordRegistryProv } } -func (n *NodeService) AddAccessNode(chainID isc.ChainID, publicKey *cryptolib.PublicKey) error { - peers, err := n.trustedNetworkManager.TrustedPeers() +func findPeerByName(tnm peering.TrustedNetworkManager, peerName string) (*peering.TrustedPeer, error) { + peers, err := tnm.TrustedPeers() if err != nil { - return errors.New("error getting trusted peers") + return nil, errors.New("error getting trusted peers") } - if _, ok := lo.Find(peers, func(p *peering.TrustedPeer) bool { - return p.PubKey().Equals(publicKey) - }); !ok { - return interfaces.ErrPeerNotFound + peer, ok := lo.Find(peers, func(p *peering.TrustedPeer) bool { + return p.Name == peerName + }) + if !ok { + return nil, interfaces.ErrPeerNotFound + } + return peer, nil +} + +func (n *NodeService) AddAccessNode(chainID isc.ChainID, peerName string) error { + peer, err := findPeerByName(n.trustedNetworkManager, peerName) + if err != nil { + return err } if _, err = n.chainRecordRegistryProvider.UpdateChainRecord(chainID, func(rec *registry.ChainRecord) bool { - return rec.AddAccessNode(publicKey) + return rec.AddAccessNode(peer.PubKey()) }); err != nil { return errors.New("error saving chain record") } @@ -55,9 +64,13 @@ func (n *NodeService) AddAccessNode(chainID isc.ChainID, publicKey *cryptolib.Pu return nil } -func (n *NodeService) DeleteAccessNode(chainID isc.ChainID, publicKey *cryptolib.PublicKey) error { +func (n *NodeService) DeleteAccessNode(chainID isc.ChainID, peerName string) error { + peer, err := findPeerByName(n.trustedNetworkManager, peerName) + if err != nil { + return err + } if _, err := n.chainRecordRegistryProvider.UpdateChainRecord(chainID, func(rec *registry.ChainRecord) bool { - return rec.RemoveAccessNode(publicKey) + return rec.RemoveAccessNode(peer.PubKey()) }); err != nil { return errors.New("error saving chain record") } diff --git a/tools/cluster/tests/wasp-cli_rotation_test.go b/tools/cluster/tests/wasp-cli_rotation_test.go index ef1bb150e3..0caf2d675e 100644 --- a/tools/cluster/tests/wasp-cli_rotation_test.go +++ b/tools/cluster/tests/wasp-cli_rotation_test.go @@ -30,7 +30,7 @@ func TestWaspCLIExternalRotationGovAccessNodes(t *testing.T) { func TestWaspCLIExternalRotationPermitionlessAccessNodes(t *testing.T) { addAccessNode := func(w *WaspCLITest, pubKey string) { for _, idx := range w.Cluster.AllNodes() { - w.MustRun("chain", "access-nodes", "add", pubKey, fmt.Sprintf("--node=%d", idx)) + w.MustRun("chain", "access-nodes", "add", "--peers=next-committee-member", fmt.Sprintf("--node=%d", idx)) } } testWaspCLIExternalRotation(t, addAccessNode) diff --git a/tools/wasp-cli/chain/access-nodes.go b/tools/wasp-cli/chain/access-nodes.go index 517e0cb3ab..ed4409f1a4 100644 --- a/tools/wasp-cli/chain/access-nodes.go +++ b/tools/wasp-cli/chain/access-nodes.go @@ -17,40 +17,54 @@ import ( func initPermitionlessAccessNodesCmd() *cobra.Command { var node string var chain string + var peers []string cmd := &cobra.Command{ - Use: "access-nodes ", + Use: "access-nodes --peers=<...>", Short: "Changes the access nodes of a chain for the target node.", - Args: cobra.ExactArgs(2), + Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { node = waspcmd.DefaultWaspNodeFallback(node) chain = defaultChainFallback(chain) chainID := config.GetChain(chain) action := args[0] - pubKey := args[1] node = waspcmd.DefaultWaspNodeFallback(node) client := cliclients.WaspClient(node) + + var executeActionFunc func(peer string) + switch action { case "add": - _, err := client.ChainsApi. - AddAccessNode(context.Background(), chainID.String(), pubKey). - Execute() //nolint:bodyclose // false positive - log.Check(err) + executeActionFunc = func(peer string) { + _, err := client.ChainsApi. + AddAccessNode(context.Background(), chainID.String(), peer). + Execute() //nolint:bodyclose // false positive + log.Check(err) + log.Printf("added %s as an access node\n", peer) + } case "remove": - _, err := client.ChainsApi. - RemoveAccessNode(context.Background(), chainID.String(), pubKey). - Execute() //nolint:bodyclose // false positive - log.Check(err) + executeActionFunc = func(peer string) { + _, err := client.ChainsApi. + RemoveAccessNode(context.Background(), chainID.String(), peer). + Execute() //nolint:bodyclose // false positive + log.Check(err) + log.Printf("removed %s as an access node\n", peer) + } default: log.Fatalf("unknown action: %s", action) } + + for _, peer := range peers { + executeActionFunc(peer) + } }, } waspcmd.WithWaspNodeFlag(cmd, &node) withChainFlag(cmd, &chain) + waspcmd.WithPeersFlag(cmd, &peers) return cmd } diff --git a/tools/wasp-cli/chain/activate.go b/tools/wasp-cli/chain/activate.go index 7462272762..de5b0dc3a0 100644 --- a/tools/wasp-cli/chain/activate.go +++ b/tools/wasp-cli/chain/activate.go @@ -56,7 +56,6 @@ func activateChain(node string, chainID isc.ChainID) { log.Check(err2) } else { _, err = client.ChainsApi.ActivateChain(context.Background(), chainID.String()).Execute() //nolint:bodyclose // false positive - log.Check(err) } From a1a39052772078c4d0de7cff9d1a40dbb5dea830 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Feb 2023 19:37:11 +0000 Subject: [PATCH 06/11] add apigen task to make file --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index bedd01b414..d4deda8ee9 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,8 @@ lint: lint-wasp-cli lint-wasp-cli: cd ./tools/wasp-cli && golangci-lint run --timeout 5m +apiclient: + clients/apiclient/generate_client.sh gofumpt-list: gofumpt -l ./ From 78e6c821b9d63ea3798b687c5ea864d84390e0e0 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Feb 2023 19:37:18 +0000 Subject: [PATCH 07/11] temporary fix for edge case in tests --- tools/cluster/tests/wasp-cli.go | 10 ++++++++-- tools/cluster/tests/wasp-cli_test.go | 14 +++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/tools/cluster/tests/wasp-cli.go b/tools/cluster/tests/wasp-cli.go index 8487a6f80d..c50bcf08e9 100644 --- a/tools/cluster/tests/wasp-cli.go +++ b/tools/cluster/tests/wasp-cli.go @@ -14,6 +14,7 @@ import ( "time" "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" iotago "github.com/iotaledger/iota.go/v3" "github.com/iotaledger/wasp/clients/apiclient" @@ -195,9 +196,14 @@ func (w *WaspCLITest) Address() iotago.Address { return addr } -func (w *WaspCLITest) ActivateChainOnAllNodes(chainName string) { +// TODO there is a small issue if we try to activate the chain twice (deploy command also activates the chain) +// if this happens, the node will return an error on `getChainInfo` because there is no state yet. +// as a temporary fix, we add `skipOnNodes`, so to not run the activate command on that node +func (w *WaspCLITest) ActivateChainOnAllNodes(chainName string, skipOnNodes ...int) { for _, idx := range w.Cluster.AllNodes() { - w.MustRun("chain", "activate", "--chain="+chainName, fmt.Sprintf("--node=%d", idx)) + if !slices.Contains(skipOnNodes, idx) { + w.MustRun("chain", "activate", "--chain="+chainName, fmt.Sprintf("--node=%d", idx)) + } } // Hack to get the chainID that was deployed diff --git a/tools/cluster/tests/wasp-cli_test.go b/tools/cluster/tests/wasp-cli_test.go index 722d1b2b59..54aa7e8949 100644 --- a/tools/cluster/tests/wasp-cli_test.go +++ b/tools/cluster/tests/wasp-cli_test.go @@ -130,7 +130,7 @@ func TestWaspCLIDeposit(t *testing.T) { committee, quorum := w.ArgCommitteeConfig(0) w.MustRun("chain", "deploy", "--chain=chain1", committee, quorum, "--node=0") - w.ActivateChainOnAllNodes("chain1") + w.ActivateChainOnAllNodes("chain1", 0) t.Run("deposit to own account", func(t *testing.T) { w.MustRun("chain", "deposit", "base:1000000", "--node=0") @@ -221,7 +221,7 @@ func TestWaspCLIContract(t *testing.T) { committee, quorum := w.ArgCommitteeConfig(0) w.MustRun("chain", "deploy", "--chain=chain1", committee, quorum, "--node=0") - w.ActivateChainOnAllNodes("chain1") + w.ActivateChainOnAllNodes("chain1", 0) // for running off-ledger requests w.MustRun("chain", "deposit", "base:10000000", "--node=0") @@ -289,7 +289,7 @@ func TestWaspCLIBlockLog(t *testing.T) { committee, quorum := w.ArgCommitteeConfig(0) w.MustRun("chain", "deploy", "--chain=chain1", committee, quorum, "--node=0") - w.ActivateChainOnAllNodes("chain1") + w.ActivateChainOnAllNodes("chain1", 0) out := w.MustRun("chain", "deposit", "base:100", "--node=0") reqID := findRequestIDInOutput(out) @@ -353,7 +353,7 @@ func TestWaspCLIBlobContract(t *testing.T) { committee, quorum := w.ArgCommitteeConfig(0) w.MustRun("chain", "deploy", "--chain=chain1", committee, quorum, "--node=0") - w.ActivateChainOnAllNodes("chain1") + w.ActivateChainOnAllNodes("chain1", 0) // for running off-ledger requests w.MustRun("chain", "deposit", "base:10", "--node=0") @@ -396,7 +396,7 @@ func TestWaspCLIRejoinChain(t *testing.T) { t, func() { w.MustRun("chain", "deploy", "--chain=chain1", "--peers=0,1,2,3,4,5", "--quorum=4", "--node=0") - w.ActivateChainOnAllNodes("chain1") + w.ActivateChainOnAllNodes("chain1", 0) }) chainName := "chain1" @@ -405,7 +405,7 @@ func TestWaspCLIRejoinChain(t *testing.T) { // test chain deploy command w.MustRun("chain", "deploy", "--chain="+chainName, committee, quorum, "--node=0") - w.ActivateChainOnAllNodes(chainName) + w.ActivateChainOnAllNodes(chainName, 0) var chainID string for _, idx := range w.Cluster.AllNodes() { @@ -453,7 +453,7 @@ func TestWaspCLILongParam(t *testing.T) { committee, quorum := w.ArgCommitteeConfig(0) w.MustRun("chain", "deploy", "--chain=chain1", committee, quorum, "--node=0") - w.ActivateChainOnAllNodes("chain1") + w.ActivateChainOnAllNodes("chain1", 0) // create foundry w.MustRun( From ff703964021060b7a4a5ad0fcd5e2da18506e585 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Feb 2023 19:49:59 +0000 Subject: [PATCH 08/11] disallow adding self as a peer --- packages/webapi/apierrors/errors.go | 4 ++++ packages/webapi/controllers/node/peering.go | 5 +++++ tools/cluster/cluster.go | 3 +++ tools/cluster/tests/wasp-cli_test.go | 23 +++++++++++++++++---- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/webapi/apierrors/errors.go b/packages/webapi/apierrors/errors.go index d84ac4f779..07810b5b69 100644 --- a/packages/webapi/apierrors/errors.go +++ b/packages/webapi/apierrors/errors.go @@ -32,6 +32,10 @@ func PeerNameNotFoundError(name string) *HTTPError { return NewHTTPError(http.StatusNotFound, fmt.Sprintf("couldn't find peer with name %s", name), nil) } +func SelfAsPeerError() *HTTPError { + return NewHTTPError(http.StatusBadRequest, "cannot add self as a peer", nil) +} + func ContractExecutionError(err error) *HTTPError { return NewHTTPError(http.StatusBadRequest, "Failed to execute contract request", err) } diff --git a/packages/webapi/controllers/node/peering.go b/packages/webapi/controllers/node/peering.go index b6607b237a..f6d44040e6 100644 --- a/packages/webapi/controllers/node/peering.go +++ b/packages/webapi/controllers/node/peering.go @@ -71,6 +71,11 @@ func (c *Controller) trustPeer(e echo.Context) error { return apierrors.InvalidPropertyError("publicKey", err) } + selfPubKey := c.peeringService.GetIdentity().PublicKey + if publicKey.Equals(selfPubKey) { + return apierrors.SelfAsPeerError() + } + _, err = c.peeringService.TrustPeer(trustedPeer.Name, publicKey, trustedPeer.PeeringURL) if err != nil { return apierrors.InternalServerError(err) diff --git a/tools/cluster/cluster.go b/tools/cluster/cluster.go index 61f7e18d8c..883cadab02 100644 --- a/tools/cluster/cluster.go +++ b/tools/cluster/cluster.go @@ -139,6 +139,9 @@ func (clu *Cluster) TrustAll() error { for ni := range allNodes { for pi := range allPeers { var err error + if ni == pi { + continue // dont trust self + } if _, err = clu.WaspClient(allNodes[ni]).NodeApi.TrustPeer(context.Background()).PeeringTrustRequest( apiclient.PeeringTrustRequest{ Name: fmt.Sprintf("%d", pi), diff --git a/tools/cluster/tests/wasp-cli_test.go b/tools/cluster/tests/wasp-cli_test.go index 54aa7e8949..a32694336c 100644 --- a/tools/cluster/tests/wasp-cli_test.go +++ b/tools/cluster/tests/wasp-cli_test.go @@ -500,12 +500,12 @@ func TestWaspCLITrustListImport(t *testing.T) { return configParams }, }) - // set cluster2/node0 to trust all nodes from cluster 1 + // set cluster2/node0 to trust all nodes from cluster 1 for _, nodeIndex := range w.Cluster.Config.AllNodes() { - peeringInforOutput := w.MustRun("peering", "info", fmt.Sprintf("--node=%d", nodeIndex)) - pubKey := regexp.MustCompile(`PubKey:\s+([[:alnum:]]+)$`).FindStringSubmatch(peeringInforOutput[0])[1] - peeringURL := regexp.MustCompile(`PeeringURL:\s+(.+)$`).FindStringSubmatch(peeringInforOutput[1])[1] + peeringInfoOutput := w.MustRun("peering", "info", fmt.Sprintf("--node=%d", nodeIndex)) + pubKey := regexp.MustCompile(`PubKey:\s+([[:alnum:]]+)$`).FindStringSubmatch(peeringInfoOutput[0])[1] + peeringURL := regexp.MustCompile(`PeeringURL:\s+(.+)$`).FindStringSubmatch(peeringInfoOutput[1])[1] w2.MustRun("peering", "trust", fmt.Sprintf("external-peer-%d", nodeIndex), pubKey, peeringURL, "--node=0") } @@ -543,3 +543,18 @@ func TestWaspCLITrustListImport(t *testing.T) { ) } } + +func TestWaspCLICantPeerWithSelf(t *testing.T) { + w := newWaspCLITest(t, waspClusterOpts{ + nNodes: 1, + }) + + peeringInfoOutput := w.MustRun("peering", "info") + pubKey := regexp.MustCompile(`PubKey:\s+([[:alnum:]]+)$`).FindStringSubmatch(peeringInfoOutput[0])[1] + + require.Panics( + t, + func() { + w.MustRun("peering", "trust", "self", pubKey, "0.0.0.0:4000") + }) +} From 23bb64c0b2bae19315cc408844063c000c8abad6 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Feb 2023 20:04:13 +0000 Subject: [PATCH 09/11] distrust peer by name --- clients/apiclient/api/openapi.yaml | 76 +++------------------ packages/webapi/controllers/node/peering.go | 8 +-- packages/webapi/interfaces/interfaces.go | 2 +- packages/webapi/services/peering.go | 21 +++++- tools/cluster/tests/wasp-cli_test.go | 23 +++++++ 5 files changed, 55 insertions(+), 75 deletions(-) diff --git a/clients/apiclient/api/openapi.yaml b/clients/apiclient/api/openapi.yaml index a16df08f62..3e92e6b9f3 100644 --- a/clients/apiclient/api/openapi.yaml +++ b/clients/apiclient/api/openapi.yaml @@ -1576,7 +1576,7 @@ paths: application/json: schema: additionalProperties: - example: "true" + example: info format: string type: string type: object @@ -1709,7 +1709,7 @@ paths: application/json: schema: items: - $ref: '#/components/schemas/PeeringNodeStatusResponse__' + $ref: '#/components/schemas/PeeringNodeStatusResponse_' type: array description: A list of all peers "401": @@ -2992,18 +2992,18 @@ components: committeeNodes: - node: isAlive: true - peeringURL: peeringURL + peeringURL: localhost:4000 name: name - publicKey: 61270151fbd8c71e43c17e0eff8c76c1ba991be28f088f72a05d790f302d67c7 - numUsers: 6 + publicKey: 0x0000 + numUsers: 1 isTrusted: true accessAPI: accessAPI - node: isAlive: true - peeringURL: peeringURL + peeringURL: localhost:4000 name: name - publicKey: 61270151fbd8c71e43c17e0eff8c76c1ba991be28f088f72a05d790f302d67c7 - numUsers: 6 + publicKey: 0x0000 + numUsers: 1 isTrusted: true accessAPI: accessAPI chainId: tst1pqm5ckama06xhkl080mmvz6l3xy8c8lulrwy7mx4ll0fc69krxfgka70j0e @@ -3109,10 +3109,10 @@ components: example: node: isAlive: true - peeringURL: peeringURL + peeringURL: localhost:4000 name: name - publicKey: 61270151fbd8c71e43c17e0eff8c76c1ba991be28f088f72a05d790f302d67c7 - numUsers: 6 + publicKey: 0x0000 + numUsers: 1 isTrusted: true accessAPI: accessAPI properties: @@ -4486,60 +4486,6 @@ components: xml: name: PeeringNodeStatusResponse PeeringNodeStatusResponse_: - example: - isAlive: true - peeringURL: peeringURL - name: name - publicKey: 61270151fbd8c71e43c17e0eff8c76c1ba991be28f088f72a05d790f302d67c7 - numUsers: 6 - isTrusted: true - properties: - isAlive: - description: Whether or not the peer is activated - format: boolean - type: boolean - xml: - name: IsAlive - isTrusted: - format: boolean - type: boolean - xml: - name: IsTrusted - name: - format: string - type: string - xml: - name: Name - numUsers: - description: The amount of users attached to the peer - format: int32 - type: integer - xml: - name: NumUsers - peeringURL: - description: The peering URL of the peer - format: string - type: string - xml: - name: PeeringURL - publicKey: - description: The peers public key encoded in Hex - example: 61270151fbd8c71e43c17e0eff8c76c1ba991be28f088f72a05d790f302d67c7 - format: string - type: string - xml: - name: PublicKey - required: - - isAlive - - isTrusted - - name - - numUsers - - peeringURL - - publicKey - type: object - xml: - name: PeeringNodeStatusResponse - PeeringNodeStatusResponse__: example: isAlive: true peeringURL: localhost:4000 diff --git a/packages/webapi/controllers/node/peering.go b/packages/webapi/controllers/node/peering.go index f6d44040e6..b95a21f395 100644 --- a/packages/webapi/controllers/node/peering.go +++ b/packages/webapi/controllers/node/peering.go @@ -91,13 +91,7 @@ func (c *Controller) distrustPeer(e echo.Context) error { return apierrors.InvalidPropertyError("body", err) } - publicKey, err := cryptolib.NewPublicKeyFromString(trustedPeer.PublicKey) - if err != nil { - return apierrors.InvalidPropertyError("publicKey", err) - } - - _, err = c.peeringService.DistrustPeer(publicKey) - if err != nil { + if _, err := c.peeringService.DistrustPeer(trustedPeer.Name); err != nil { return apierrors.InternalServerError(err) } diff --git a/packages/webapi/interfaces/interfaces.go b/packages/webapi/interfaces/interfaces.go index f24e3df0a2..d68b802947 100644 --- a/packages/webapi/interfaces/interfaces.go +++ b/packages/webapi/interfaces/interfaces.go @@ -83,7 +83,7 @@ type CommitteeService interface { } type PeeringService interface { - DistrustPeer(publicKey *cryptolib.PublicKey) (*dto.PeeringNodeIdentity, error) + DistrustPeer(name string) (*dto.PeeringNodeIdentity, error) GetIdentity() *dto.PeeringNodeIdentity GetRegisteredPeers() []*dto.PeeringNodeStatus GetTrustedPeers() ([]*dto.PeeringNodeIdentity, error) diff --git a/packages/webapi/services/peering.go b/packages/webapi/services/peering.go index e533dacf37..a895f851ca 100644 --- a/packages/webapi/services/peering.go +++ b/packages/webapi/services/peering.go @@ -1,9 +1,12 @@ package services import ( + "github.com/samber/lo" + "github.com/iotaledger/wasp/packages/chains" "github.com/iotaledger/wasp/packages/cryptolib" "github.com/iotaledger/wasp/packages/peering" + "github.com/iotaledger/wasp/packages/webapi/apierrors" "github.com/iotaledger/wasp/packages/webapi/dto" ) @@ -87,13 +90,27 @@ func (p *PeeringService) TrustPeer(name string, publicKey *cryptolib.PublicKey, return mappedIdentity, nil } -func (p *PeeringService) DistrustPeer(publicKey *cryptolib.PublicKey) (*dto.PeeringNodeIdentity, error) { - identity, err := p.trustedNetworkManager.DistrustPeer(publicKey) +func (p *PeeringService) DistrustPeer(name string) (*dto.PeeringNodeIdentity, error) { + peers, err := p.trustedNetworkManager.TrustedPeers() + if err != nil { + return nil, err + } + + peerToDistrust, exists := lo.Find(peers, func(p *peering.TrustedPeer) bool { + return p.Name == name + }) + + if !exists { + return nil, apierrors.PeerNameNotFoundError(name) + } + + identity, err := p.trustedNetworkManager.DistrustPeer(peerToDistrust.PubKey()) if err != nil { return nil, err } mappedIdentity := &dto.PeeringNodeIdentity{ + Name: identity.Name, PublicKey: identity.PubKey(), PeeringURL: identity.PeeringURL, IsTrusted: false, diff --git a/tools/cluster/tests/wasp-cli_test.go b/tools/cluster/tests/wasp-cli_test.go index a32694336c..da6b7c1cb5 100644 --- a/tools/cluster/tests/wasp-cli_test.go +++ b/tools/cluster/tests/wasp-cli_test.go @@ -558,3 +558,26 @@ func TestWaspCLICantPeerWithSelf(t *testing.T) { w.MustRun("peering", "trust", "self", pubKey, "0.0.0.0:4000") }) } + +func TestWaspCLIListTrustDistrust(t *testing.T) { + w := newWaspCLITest(t) + out := w.MustRun("peering", "list-trusted", "--node=0") + // one of the entries starts with "1", meaning node 0 trusts node 1 + containsNode1 := func(output []string) bool { + for _, line := range output { + if strings.HasPrefix(line, "1") { + return true + } + } + return false + } + require.True(t, containsNode1(out)) + + // distrust node 1 + w.MustRun("peering", "distrust", "1", "--node=0") + + // 1 is not included anymore in the trusted list + out = w.MustRun("peering", "list-trusted", "--node=0") + // one of the entries starts with "1", meaning node 0 trusts node 1 + require.False(t, containsNode1(out)) +} From ac522e72530dbbeeaceb1216c4687efbd427ab91 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Feb 2023 20:08:24 +0000 Subject: [PATCH 10/11] assert peer names adhere to the slug format --- {tools/wasp-cli => packages}/util/slug.go | 0 packages/webapi/apierrors/errors.go | 4 ++++ packages/webapi/controllers/node/peering.go | 4 ++++ tools/wasp-cli/chain/deploy.go | 2 +- tools/wasp-cli/waspcmd/cmd.go | 2 +- 5 files changed, 10 insertions(+), 2 deletions(-) rename {tools/wasp-cli => packages}/util/slug.go (100%) diff --git a/tools/wasp-cli/util/slug.go b/packages/util/slug.go similarity index 100% rename from tools/wasp-cli/util/slug.go rename to packages/util/slug.go diff --git a/packages/webapi/apierrors/errors.go b/packages/webapi/apierrors/errors.go index 07810b5b69..f7d9b63063 100644 --- a/packages/webapi/apierrors/errors.go +++ b/packages/webapi/apierrors/errors.go @@ -36,6 +36,10 @@ func SelfAsPeerError() *HTTPError { return NewHTTPError(http.StatusBadRequest, "cannot add self as a peer", nil) } +func InvalidPeerName() *HTTPError { + return NewHTTPError(http.StatusBadRequest, "name must be in slug format (lowecase and hyphens only)", nil) +} + func ContractExecutionError(err error) *HTTPError { return NewHTTPError(http.StatusBadRequest, "Failed to execute contract request", err) } diff --git a/packages/webapi/controllers/node/peering.go b/packages/webapi/controllers/node/peering.go index b95a21f395..7d2f035e95 100644 --- a/packages/webapi/controllers/node/peering.go +++ b/packages/webapi/controllers/node/peering.go @@ -6,6 +6,7 @@ import ( "github.com/labstack/echo/v4" "github.com/iotaledger/wasp/packages/cryptolib" + "github.com/iotaledger/wasp/packages/util" "github.com/iotaledger/wasp/packages/webapi/apierrors" "github.com/iotaledger/wasp/packages/webapi/models" ) @@ -76,6 +77,9 @@ func (c *Controller) trustPeer(e echo.Context) error { return apierrors.SelfAsPeerError() } + if !util.IsSlug(trustedPeer.Name) { + return apierrors.InvalidPeerName() + } _, err = c.peeringService.TrustPeer(trustedPeer.Name, publicKey, trustedPeer.PeeringURL) if err != nil { return apierrors.InternalServerError(err) diff --git a/tools/wasp-cli/chain/deploy.go b/tools/wasp-cli/chain/deploy.go index 7d5d615dbd..45d65aa114 100644 --- a/tools/wasp-cli/chain/deploy.go +++ b/tools/wasp-cli/chain/deploy.go @@ -17,13 +17,13 @@ import ( "github.com/iotaledger/wasp/packages/kv/codec" "github.com/iotaledger/wasp/packages/kv/dict" "github.com/iotaledger/wasp/packages/parameters" + "github.com/iotaledger/wasp/packages/util" "github.com/iotaledger/wasp/packages/vm/core/evm" "github.com/iotaledger/wasp/packages/vm/core/root" "github.com/iotaledger/wasp/tools/wasp-cli/cli/cliclients" "github.com/iotaledger/wasp/tools/wasp-cli/cli/config" "github.com/iotaledger/wasp/tools/wasp-cli/cli/wallet" "github.com/iotaledger/wasp/tools/wasp-cli/log" - "github.com/iotaledger/wasp/tools/wasp-cli/util" "github.com/iotaledger/wasp/tools/wasp-cli/waspcmd" ) diff --git a/tools/wasp-cli/waspcmd/cmd.go b/tools/wasp-cli/waspcmd/cmd.go index eb08b0c8c4..3b72c5adb1 100644 --- a/tools/wasp-cli/waspcmd/cmd.go +++ b/tools/wasp-cli/waspcmd/cmd.go @@ -4,9 +4,9 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/iotaledger/wasp/packages/util" "github.com/iotaledger/wasp/tools/wasp-cli/cli/config" "github.com/iotaledger/wasp/tools/wasp-cli/log" - "github.com/iotaledger/wasp/tools/wasp-cli/util" ) func initWaspNodesCmd() *cobra.Command { From 10f3f32422f35a759c6dc3c5d3ca9fb17526eab3 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Feb 2023 20:10:54 +0000 Subject: [PATCH 11/11] test fix --- tools/cluster/tests/wasp-cli_rotation_test.go | 2 +- tools/cluster/tests/wasp-cli_test.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/cluster/tests/wasp-cli_rotation_test.go b/tools/cluster/tests/wasp-cli_rotation_test.go index 0caf2d675e..eca4c4250b 100644 --- a/tools/cluster/tests/wasp-cli_rotation_test.go +++ b/tools/cluster/tests/wasp-cli_rotation_test.go @@ -68,7 +68,7 @@ func testWaspCLIExternalRotation(t *testing.T, addAccessNode func(*WaspCLITest, "--node=0", ) chainID := regexp.MustCompile(`(.*)ChainID:\s*([a-zA-Z0-9_]*),`).FindStringSubmatch(strings.Join(out, ""))[2] - w.ActivateChainOnAllNodes("chain1") + w.ActivateChainOnAllNodes("chain1", 0) // start a new wasp cluster w2 := newWaspCLITest(t, waspClusterOpts{ diff --git a/tools/cluster/tests/wasp-cli_test.go b/tools/cluster/tests/wasp-cli_test.go index da6b7c1cb5..605fc56c0e 100644 --- a/tools/cluster/tests/wasp-cli_test.go +++ b/tools/cluster/tests/wasp-cli_test.go @@ -48,7 +48,7 @@ func TestWaspCLI1Chain(t *testing.T) { // test chain deploy command w.MustRun("chain", "deploy", "--chain="+chainName, committee, quorum, "--node=0") - w.ActivateChainOnAllNodes(chainName) + w.ActivateChainOnAllNodes(chainName, 0) // test chain info command out := w.MustRun("chain", "info", "--node=0") @@ -506,21 +506,21 @@ func TestWaspCLITrustListImport(t *testing.T) { peeringInfoOutput := w.MustRun("peering", "info", fmt.Sprintf("--node=%d", nodeIndex)) pubKey := regexp.MustCompile(`PubKey:\s+([[:alnum:]]+)$`).FindStringSubmatch(peeringInfoOutput[0])[1] peeringURL := regexp.MustCompile(`PeeringURL:\s+(.+)$`).FindStringSubmatch(peeringInfoOutput[1])[1] - w2.MustRun("peering", "trust", fmt.Sprintf("external-peer-%d", nodeIndex), pubKey, peeringURL, "--node=0") + w2.MustRun("peering", "trust", fmt.Sprintf("x%d", nodeIndex), pubKey, peeringURL, "--node=0") } // import the trust from cluster2/node0 to cluster2/node1 trustedFile0, err := os.CreateTemp("", "tmp-trusted-peers.*.json") require.NoError(t, err) defer os.Remove(trustedFile0.Name()) - w2.MustRun("peering", "export-trusted", "--node=0", "-o="+trustedFile0.Name()) + w2.MustRun("peering", "export-trusted", "--node=0", "--peers=x0,x1,x2,x3", "-o="+trustedFile0.Name()) w2.MustRun("peering", "import-trusted", trustedFile0.Name(), "--node=1") // export the trusted nodes from cluster2/node1 and assert the expected result trustedFile1, err := os.CreateTemp("", "tmp-trusted-peers.*.json") require.NoError(t, err) defer os.Remove(trustedFile1.Name()) - w2.MustRun("peering", "export-trusted", "--node=1", "-o="+trustedFile1.Name()) + w2.MustRun("peering", "export-trusted", "--peers=x0,x1,x2,x3", "--node=1", "-o="+trustedFile1.Name()) trustedBytes0, err := io.ReadAll(trustedFile0) require.NoError(t, err)