Skip to content

Commit

Permalink
740-4 use new wallet package (#778)
Browse files Browse the repository at this point in the history
* Use new wallet package

* batch signing

* fix wails title for get account unciphered

* fix 647:

* rename guarded password

* move constants

* move wallet manager

* fix ci e2e

* CR

rename to errResp

correlation id is memguarded

delete walletmanager package in favor of wallet package

lint code

accounts are now sync.Map type

test: reduce duplication
  • Loading branch information
Thykof authored Oct 26, 2023
1 parent 71d423b commit 1c7f31b
Show file tree
Hide file tree
Showing 67 changed files with 1,434 additions and 2,086 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ jobs:
- uses: actions/checkout@v3
- uses: ./.github/actions/install
- name: build
run: go build -tags desktop,production -ldflags "-w -s" -o tests/test_wallet main.go
run: go build -tags desktop,production -ldflags "-w -s" -o build/test_wallet main.go
- name: Run app
run: WALLET_PASSWORD=bonjour STANDALONE=1 xvfb-run ./tests/test_wallet &
run: WALLET_PASSWORD=bonjour STANDALONE=1 xvfb-run ./build/test_wallet &
- name: Move account file
run: |
mkdir -p ~/.config/massa-station-wallet
Expand Down
7 changes: 7 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,10 @@ Wails is a native GUI library for Go. It allows us to build a native GUI app wit
Folder: `wails-frontend`.

This folder contains the source code of the wails frontend app. It is a React app.

### Error handling

* Use sentinel error
* Functions don't return a middleware responder, but an error
* for http error response, use as much as possible `internal/handler/wallet/newErrorResponse`
* for wails error code: use `pkg/utils/WailsErrorCode`
2 changes: 1 addition & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ tasks:
test:
cmds:
- task: clean
- cmd: go test -v -timeout 60s ./...
- cmd: go test -v -timeout 20s ./...

fmt:
cmds:
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ require (
github.com/stretchr/testify v1.8.4
github.com/wailsapp/wails/v2 v2.6.0
golang.org/x/crypto v0.14.0
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
gopkg.in/yaml.v2 v2.4.0
)

Expand Down Expand Up @@ -47,6 +46,7 @@ require (
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
howett.net/plist v1.0.0 // indirect
)

Expand All @@ -73,6 +73,6 @@ require (
golang.org/x/net v0.17.0
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
gopkg.in/yaml.v3 v3.0.1
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.1.7
)
10 changes: 5 additions & 5 deletions internal/handler/wallet/add_asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type addAsset struct {
massaClient network.NodeFetcherInterface
}

func (h *addAsset) Handle(params operations.AddAssetParams) middleware.Responder {
func (a *addAsset) Handle(params operations.AddAssetParams) middleware.Responder {
// Check if the address is valid
if !address.IsValidAddress(params.AssetAddress) {
// Return an error indicating the address is not valid
Expand All @@ -34,29 +34,29 @@ func (h *addAsset) Handle(params operations.AddAssetParams) middleware.Responder
}

// First, check if the asset exists in the network
if !h.massaClient.AssetExistInNetwork(params.AssetAddress) {
if !a.massaClient.AssetExistInNetwork(params.AssetAddress) {
// If the asset does not exist in the network, return a 404 response
errorMsg := "Asset with the provided address not found in the network."
return operations.NewAddAssetNotFound().WithPayload(&models.Error{Code: errorAssetNotFound, Message: errorMsg})
}

// Check if the address exists in the loaded JSON
if h.AssetsStore.AssetExists(params.Nickname, params.AssetAddress) {
if a.AssetsStore.AssetExists(params.Nickname, params.AssetAddress) {
// Return that the asset already exists
errorMsg := "Asset with the provided address already exists."
return operations.NewAddAssetBadRequest().WithPayload(&models.Error{Code: errorAssetExists, Message: errorMsg})
}

// Fetch the asset information from the SC
assetInfoFromSC, err := assets.AssetInfo(params.AssetAddress, h.massaClient)
assetInfoFromSC, err := assets.AssetInfo(params.AssetAddress, a.massaClient)
if err != nil {
// Return error occurred during SC fetch
errorMsg := "Failed to fetch asset information from the smart contract."
return operations.NewAddAssetInternalServerError().WithPayload(&models.Error{Code: errorFetchAssetSC, Message: errorMsg})
}

// Add Asset and persist in JSON file.
if err := h.AssetsStore.AddAsset(params.Nickname, params.AssetAddress, *assetInfoFromSC); err != nil {
if err := a.AssetsStore.AddAsset(params.Nickname, params.AssetAddress, *assetInfoFromSC); err != nil {
// Return error occurred while persisting the asset
errorMsg := "Failed to add the asset to the JSON file."
return operations.NewAddAssetInternalServerError().WithPayload(&models.Error{Code: errorAddAssetJSON, Message: errorMsg})
Expand Down
12 changes: 5 additions & 7 deletions internal/handler/wallet/add_assets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import (
"os"
"testing"

"github.com/awnumar/memguard"
"github.com/massalabs/station-massa-wallet/api/server/models"
"github.com/massalabs/station-massa-wallet/api/server/restapi/operations"
utils "github.com/massalabs/station-massa-wallet/pkg/assets"
"github.com/massalabs/station-massa-wallet/pkg/wallet"
"github.com/massalabs/station-massa-wallet/pkg/wallet/account"
"github.com/massalabs/station/pkg/logger"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
Expand All @@ -28,8 +29,8 @@ func TestAddAssetHandler(t *testing.T) {
nickname := "GoodNickname"
password := "zePassword"

_, errGenerate := wallet.Generate(nickname, password)
assert.Nil(t, errGenerate)
_, err = account.Generate(memguard.NewBufferFromBytes([]byte(password)), nickname)
assert.Nil(t, err)

type testCase struct {
Name string
Expand Down Expand Up @@ -104,9 +105,6 @@ func TestAddAssetHandler(t *testing.T) {
// Remove the json file created
err = RemoveJSONFile()
assert.NoError(t, err)

err = cleanupTestData([]string{nickname})
assert.NoError(t, err)
})

// Remove the json file created
Expand All @@ -124,7 +122,7 @@ func addAssetTest(t *testing.T, api *operations.MassaWalletAPI, nickname, assetA
resp, err := handleHTTPRequest(handler, "POST", fmt.Sprintf("/api/accounts/%s/assets?assetAddress=%s", nickname, assetAddress), "")
assert.NoError(t, err)

assert.Equal(t, http.StatusCreated, resp.Result().StatusCode)
assert.Equal(t, http.StatusCreated, resp.Result().StatusCode, "response is %s", resp.Body.String())

// Parse the response body to get the added asset
var addedAsset models.AssetInfo
Expand Down
42 changes: 28 additions & 14 deletions internal/handler/wallet/api.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package wallet

import (
"errors"
"net/http"

"github.com/bluele/gcache"
"github.com/go-openapi/runtime/middleware"
"github.com/massalabs/station-massa-wallet/api/server/models"
"github.com/massalabs/station-massa-wallet/api/server/restapi/operations"
"github.com/massalabs/station-massa-wallet/pkg/assets"
"github.com/massalabs/station-massa-wallet/pkg/network"
"github.com/massalabs/station-massa-wallet/pkg/openapi"
"github.com/massalabs/station-massa-wallet/pkg/prompt"
"github.com/massalabs/station-massa-wallet/pkg/wallet"
walletpkg "github.com/massalabs/station-massa-wallet/pkg/wallet"
"github.com/massalabs/station-massa-wallet/pkg/wallet/account"
"github.com/massalabs/station/pkg/logger"
)

// AppendEndpoints appends wallet endpoints to the API
Expand All @@ -17,35 +24,42 @@ func AppendEndpoints(api *operations.MassaWalletAPI, prompterApp prompt.WalletPr
api.CreateAccountHandler = NewCreateAccount(prompterApp, massaClient)
api.DeleteAccountHandler = NewDelete(prompterApp, massaClient)
api.ImportAccountHandler = NewImport(prompterApp, massaClient)
api.AccountListHandler = NewGetAll(massaClient)
api.AccountListHandler = NewGetAll(prompterApp.App().Wallet, massaClient)
api.SignHandler = NewSign(prompterApp, gc)
api.SignMessageHandler = NewSignMessage(prompterApp, gc)
api.GetAccountHandler = NewGet(prompterApp, massaClient)
api.ExportAccountFileHandler = operations.ExportAccountFileHandlerFunc(HandleExportFile)
api.ExportAccountFileHandler = NewWalletExportFile(prompterApp.App().Wallet)
api.TransferCoinHandler = NewTransferCoin(prompterApp, massaClient)
api.TradeRollsHandler = NewTradeRolls(prompterApp, massaClient)
api.BackupAccountHandler = NewBackupAccount(prompterApp)
api.UpdateAccountHandler = NewUpdateAccount(prompterApp, massaClient)
api.AddAssetHandler = NewAddAsset(AssetsStore, massaClient)
api.GetAllAssetsHandler = NewGetAllAssets(AssetsStore, massaClient)
api.GetAllAssetsHandler = NewGetAllAssets(prompterApp.App().Wallet, AssetsStore, massaClient)
api.DeleteAssetHandler = NewDeleteAsset(AssetsStore)
}

// loadWallet loads a wallet from the file system or returns an error.
func loadWallet(nickname string) (*wallet.Wallet, middleware.Responder) {
w, err := wallet.Load(nickname)
// loadAccount loads a wallet from the file system or returns an error.
// Here it is acceptable to return a middleware.Responder to simplify the code.
func loadAccount(wallet *wallet.Wallet, nickname string) (*account.Account, middleware.Responder) {
acc, err := wallet.GetAccount(nickname)
if err == nil {
return w, nil
return acc, nil
}

errorObj := models.Error{
Code: errorGetWallets,
Message: err.Error(),
if errors.Is(err, walletpkg.AccountNotFoundError) {
return nil, newErrorResponse(err.Error(), errorGetAccount, http.StatusNotFound)
} else {
return nil, newErrorResponse(err.Error(), errorGetAccount, http.StatusBadRequest)
}
}

if err.Error() == wallet.ErrorAccountNotFound(nickname).Error() {
return nil, operations.NewGetAccountNotFound().WithPayload(&errorObj)
} else {
return nil, operations.NewGetAccountBadRequest().WithPayload(&errorObj)
func newErrorResponse(message, code string, statusCode int) middleware.Responder {
logger.Error(message)

payload := &models.Error{
Code: code,
Message: message,
}

return openapi.NewPayloadResponder(statusCode, payload)
}
14 changes: 13 additions & 1 deletion internal/handler/wallet/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
walletapp "github.com/massalabs/station-massa-wallet/pkg/app"
"github.com/massalabs/station-massa-wallet/pkg/assets"
"github.com/massalabs/station-massa-wallet/pkg/prompt"
"github.com/massalabs/station-massa-wallet/pkg/wallet"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -49,7 +50,17 @@ func MockAPI() (*operations.MassaWalletAPI, prompt.WalletPrompterInterface, *ass

resultChannel := make(chan walletapp.EventData)

prompterApp := NewWalletPrompterMock(walletapp.NewWalletApp(), resultChannel)
walletPath, err := os.MkdirTemp(os.TempDir(), "*-wallet-dir")
if err != nil {
log.Fatalf("while creating temporary wallet directory: %s", err.Error())
}

wallet, err := wallet.New(walletPath)
if err != nil {
return nil, nil, nil, nil, err
}

prompterApp := NewWalletPrompterMock(walletapp.NewWalletApp(wallet), resultChannel)

assetsJSONPath, err := assets.GetAssetsJSONPath()
if err != nil {
Expand All @@ -62,6 +73,7 @@ func MockAPI() (*operations.MassaWalletAPI, prompt.WalletPrompterInterface, *ass
}

massaNodeMock := NewNodeFetcherMock()

// Set wallet API endpoints
AppendEndpoints(massaWalletAPI, prompterApp, massaNodeMock, AssetsStore, gcache.New(20).LRU().Build())

Expand Down
Loading

0 comments on commit 1c7f31b

Please sign in to comment.