This commit is contained in:
r8zavetr8v 2024-06-14 20:47:58 +03:00
parent 24bc9fd7f2
commit 512fc397da
3 changed files with 117 additions and 71 deletions

View File

@ -3,6 +3,7 @@ package factory
import ( import (
"log/slog" "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/auth"
"github.com/emochka2007/block-accounting/internal/infrastructure/repository/cache" "github.com/emochka2007/block-accounting/internal/infrastructure/repository/cache"
orepo "github.com/emochka2007/block-accounting/internal/infrastructure/repository/organizations" orepo "github.com/emochka2007/block-accounting/internal/infrastructure/repository/organizations"
@ -60,5 +61,8 @@ func provideChainInteractor(
txRepository txRepo.Repository, txRepository txRepo.Repository,
orgInteractor organizations.OrganizationsInteractor, orgInteractor organizations.OrganizationsInteractor,
) chain.ChainInteractor { ) 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"),
))
} }

View File

@ -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 &ethAPIClient{
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)
}

View File

@ -10,6 +10,7 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/emochka2007/block-accounting/internal/infrastructure/ethapi"
"github.com/emochka2007/block-accounting/internal/infrastructure/repository/transactions" "github.com/emochka2007/block-accounting/internal/infrastructure/repository/transactions"
"github.com/emochka2007/block-accounting/internal/pkg/config" "github.com/emochka2007/block-accounting/internal/pkg/config"
"github.com/emochka2007/block-accounting/internal/pkg/ctxmeta" "github.com/emochka2007/block-accounting/internal/pkg/ctxmeta"
@ -36,6 +37,7 @@ type chainInteractor struct {
config config.Config config config.Config
txRepository transactions.Repository txRepository transactions.Repository
organizationsInteractor organizations.OrganizationsInteractor organizationsInteractor organizations.OrganizationsInteractor
client ethapi.EthAPIClient
} }
func NewChainInteractor( func NewChainInteractor(
@ -43,6 +45,7 @@ func NewChainInteractor(
config config.Config, config config.Config,
txRepository transactions.Repository, txRepository transactions.Repository,
organizationsInteractor organizations.OrganizationsInteractor, organizationsInteractor organizations.OrganizationsInteractor,
client ethapi.EthAPIClient,
) ChainInteractor { ) ChainInteractor {
return &chainInteractor{ return &chainInteractor{
log: log, log: log,
@ -58,10 +61,6 @@ type NewMultisigParams struct {
Confirmations int Confirmations int
} }
type newMultisigChainResponse struct {
Address string `json:"address"`
}
func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigParams) error { func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigParams) error {
endpoint := i.config.ChainAPI.Host + "/multi-sig/deploy" 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()) 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) user, err := ctxmeta.User(ctx)
if err != nil { if err != nil {
return fmt.Errorf("error fetch user from context. %w", err) 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) 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() pid := uuid.Must(uuid.NewV7()).String()
startTime := time.Now() 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) requestContext, cancel := context.WithTimeout(context.TODO(), time.Minute*15)
defer cancel() defer cancel()
body := bytes.NewBuffer(requestBody) requestContext = ctxmeta.UserContext(requestContext, user)
req, err := http.NewRequestWithContext(requestContext, http.MethodPost, endpoint, body) address, err := i.client.DeployMultisig(requestContext, pks, params.Confirmations)
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)
if err != nil { if err != nil {
i.log.Error( i.log.Error(
"error send deploy multisig request", "error send deploy multisig request",
@ -169,38 +146,7 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar
return return
} }
defer resp.Body.Close() multisigAddress := common.Hex2Bytes(address[2:])
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:])
createdAt := time.Now() createdAt := time.Now()
@ -215,14 +161,6 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar
UpdatedAt: createdAt, 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 { if err := i.txRepository.AddMultisig(requestContext, msg); err != nil {
i.log.Error( i.log.Error(
"error add new multisig", "error add new multisig",
@ -272,7 +210,7 @@ func (i *chainInteractor) PubKey(ctx context.Context, user *models.User) ([]byte
pubKeyStr := string(respBody)[2:] pubKeyStr := string(respBody)[2:]
if pubKeyStr == "" { if pubKeyStr == "" {
return nil, fmt.Errorf("error empty public key") return nil, fmt.Errorf("error empty public key...")
} }
return common.Hex2Bytes(pubKeyStr), nil return common.Hex2Bytes(pubKeyStr), nil