From 512fc397da9ae0658c33b232a6f69b65cd60ba80 Mon Sep 17 00:00:00 2001 From: optclblast Date: Fri, 14 Jun 2024 20:47:58 +0300 Subject: [PATCH] +1 --- backend/internal/factory/interactors.go | 6 +- .../internal/infrastructure/ethapi/client.go | 104 ++++++++++++++++++ .../usecase/interactors/chain/chain.go | 78 ++----------- 3 files changed, 117 insertions(+), 71 deletions(-) create mode 100644 backend/internal/infrastructure/ethapi/client.go diff --git a/backend/internal/factory/interactors.go b/backend/internal/factory/interactors.go index aea1208..3f7db17 100644 --- a/backend/internal/factory/interactors.go +++ b/backend/internal/factory/interactors.go @@ -3,6 +3,7 @@ package factory import ( "log/slog" + "github.com/emochka2007/block-accounting/internal/infrastructure/ethapi" "github.com/emochka2007/block-accounting/internal/infrastructure/repository/auth" "github.com/emochka2007/block-accounting/internal/infrastructure/repository/cache" orepo "github.com/emochka2007/block-accounting/internal/infrastructure/repository/organizations" @@ -60,5 +61,8 @@ func provideChainInteractor( txRepository txRepo.Repository, orgInteractor organizations.OrganizationsInteractor, ) chain.ChainInteractor { - return chain.NewChainInteractor(log, config, txRepository, orgInteractor) + return chain.NewChainInteractor(log, config, txRepository, orgInteractor, ethapi.NewEthAPIClient( + config.ChainAPI.Host, + log.WithGroup("eth-api-client"), + )) } diff --git a/backend/internal/infrastructure/ethapi/client.go b/backend/internal/infrastructure/ethapi/client.go new file mode 100644 index 0000000..e41d95c --- /dev/null +++ b/backend/internal/infrastructure/ethapi/client.go @@ -0,0 +1,104 @@ +package ethapi + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "log/slog" + "net/http" + + "github.com/emochka2007/block-accounting/internal/pkg/ctxmeta" + "github.com/ethereum/go-ethereum/common" +) + +type EthAPIClient interface { + DeployMultisig( + ctx context.Context, + ownersPubKeys []string, + confirmations int, + ) (string, error) +} + +type ethAPIClient struct { + host string + c *http.Client + log *slog.Logger +} + +func NewEthAPIClient( + address string, + log *slog.Logger, +) EthAPIClient { + return ðAPIClient{ + host: address, + c: &http.Client{}, + log: log, + } +} + +func (c *ethAPIClient) DeployMultisig( + ctx context.Context, + ownersPubKeys []string, + confirmations int, +) (string, error) { + endpoint := c.host + "/multi-sig/deploy" + + user, err := ctxmeta.User(ctx) + if err != nil { + return "", fmt.Errorf("error fetch user from context. %w", err) + } + + requestBody, err := json.Marshal(map[string]any{ + "owners": ownersPubKeys, + "confirmations": confirmations, + }) + if err != nil { + return "", fmt.Errorf("error marshal request body. %w", err) + } + + body := bytes.NewBuffer(requestBody) + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, body) + if err != nil { + return "", fmt.Errorf("error create a new request. %w", err) + } + + req.Header.Add("Content-Type", "application/json") + req.Header.Add("X-Seed", common.Bytes2Hex(user.Seed())) + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", fmt.Errorf("error send deploy multisig request. %w", err) + } + + defer resp.Body.Close() + + raw, err := io.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("error read response body. %w", err) + } + + c.log.Debug( + "deploy multisig response", + slog.Int("code", resp.StatusCode), + slog.String("body", string(raw)), + ) + + respBody := make(map[string]string, 1) + + if err := json.Unmarshal(raw, &respBody); err != nil { + return "", fmt.Errorf("error parse chain-api response body. %w", err) + } + + if address, ok := respBody["address"]; ok { + if address == "" { + return "", fmt.Errorf("error empty address") + } + + return address, nil + } + + return "", fmt.Errorf("error deploy multisig. %+v", respBody) +} diff --git a/backend/internal/usecase/interactors/chain/chain.go b/backend/internal/usecase/interactors/chain/chain.go index 6aaaaa6..fd9f80e 100644 --- a/backend/internal/usecase/interactors/chain/chain.go +++ b/backend/internal/usecase/interactors/chain/chain.go @@ -10,6 +10,7 @@ import ( "net/http" "time" + "github.com/emochka2007/block-accounting/internal/infrastructure/ethapi" "github.com/emochka2007/block-accounting/internal/infrastructure/repository/transactions" "github.com/emochka2007/block-accounting/internal/pkg/config" "github.com/emochka2007/block-accounting/internal/pkg/ctxmeta" @@ -36,6 +37,7 @@ type chainInteractor struct { config config.Config txRepository transactions.Repository organizationsInteractor organizations.OrganizationsInteractor + client ethapi.EthAPIClient } func NewChainInteractor( @@ -43,6 +45,7 @@ func NewChainInteractor( config config.Config, txRepository transactions.Repository, organizationsInteractor organizations.OrganizationsInteractor, + client ethapi.EthAPIClient, ) ChainInteractor { return &chainInteractor{ log: log, @@ -58,10 +61,6 @@ type NewMultisigParams struct { Confirmations int } -type newMultisigChainResponse struct { - Address string `json:"address"` -} - func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigParams) error { endpoint := i.config.ChainAPI.Host + "/multi-sig/deploy" @@ -81,14 +80,6 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar pks[i] = "0x" + common.Bytes2Hex(owner.GetUser().PublicKey()) } - requestBody, err := json.Marshal(map[string]any{ - "owners": pks, - "confirmations": params.Confirmations, - }) - if err != nil { - return fmt.Errorf("error marshal request body. %w", err) - } - user, err := ctxmeta.User(ctx) if err != nil { return fmt.Errorf("error fetch user from context. %w", err) @@ -99,7 +90,7 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar return fmt.Errorf("error fetch organization id from context. %w", err) } - go func() { // TODO remove this subroutine shit and replace it with worker pools + go func() { // TODO remove this subroutine shit and replace it with worker queue tasks pid := uuid.Must(uuid.NewV7()).String() startTime := time.Now() @@ -142,23 +133,9 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar requestContext, cancel := context.WithTimeout(context.TODO(), time.Minute*15) defer cancel() - body := bytes.NewBuffer(requestBody) + requestContext = ctxmeta.UserContext(requestContext, user) - req, err := http.NewRequestWithContext(requestContext, http.MethodPost, endpoint, body) - if err != nil { - i.log.Error( - "error build request", - logger.Err(err), - ) - - return - } - - req.Header.Add("Content-Type", "application/json") - req.Header.Add("X-Seed", common.Bytes2Hex(user.Seed())) - - // TODO replace http.DefaultClient with custom ChainAPi client from infrastructure/ethapi mod - resp, err := http.DefaultClient.Do(req) + address, err := i.client.DeployMultisig(requestContext, pks, params.Confirmations) if err != nil { i.log.Error( "error send deploy multisig request", @@ -169,38 +146,7 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar return } - defer resp.Body.Close() - - raw, err := io.ReadAll(resp.Body) - if err != nil { - i.log.Error( - "error read body", - logger.Err(err), - ) - - return - } - - respObject := new(newMultisigChainResponse) - - if err := json.Unmarshal(raw, &respObject); err != nil { - i.log.Error( - "error parse chain-api response body", - logger.Err(err), - ) - - return - } - - if respObject.Address == "" { - i.log.Error( - "error multisig address is empty", - ) - - return - } - - multisigAddress := common.Hex2Bytes(respObject.Address[2:]) + multisigAddress := common.Hex2Bytes(address[2:]) createdAt := time.Now() @@ -215,14 +161,6 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar UpdatedAt: createdAt, } - i.log.Debug( - "deploy multisig response", - slog.Int("code", resp.StatusCode), - slog.String("body", string(raw)), - slog.Any("parsed", respObject), - slog.Any("multisig object", msg), - ) - if err := i.txRepository.AddMultisig(requestContext, msg); err != nil { i.log.Error( "error add new multisig", @@ -272,7 +210,7 @@ func (i *chainInteractor) PubKey(ctx context.Context, user *models.User) ([]byte pubKeyStr := string(respBody)[2:] if pubKeyStr == "" { - return nil, fmt.Errorf("error empty public key") + return nil, fmt.Errorf("error empty public key...") } return common.Hex2Bytes(pubKeyStr), nil