Skip to content

Commit

Permalink
Merge branch 'main' into feature/new-metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasmenendez committed Jan 11, 2024
2 parents f9a9f96 + 02786db commit f694b41
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 7 deletions.
64 changes: 58 additions & 6 deletions api/strategies.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strconv"

"github.com/ethereum/go-ethereum/common"
gocid "github.com/ipfs/go-cid"
queries "github.com/vocdoni/census3/db/sqlc"
"github.com/vocdoni/census3/internal"
"github.com/vocdoni/census3/lexer"
Expand Down Expand Up @@ -290,12 +291,37 @@ func (capi *census3API) launchStrategyImport(msg *api.APIdata, ctx *httprouter.H
if ipfsCID == "" {
return ErrMalformedStrategy.With("no IPFS cID provided")
}
// check if the cID is valid
if cid, err := gocid.Decode(ipfsCID); err != nil {
return ErrMalformedStrategy.WithErr(err)
} else {
ipfsCID = cid.String()
}
// import the strategy from IPFS in background generating a queueID
queueID := capi.queue.Enqueue()
go func() {
internalCtx, cancel := context.WithTimeout(context.Background(), getStrategyTimeout)
defer cancel()
// check if the strategy exists in the database using the IPFS URI
ipfsURI := fmt.Sprintf("%s%s", capi.downloader.RemoteStorage.URIprefix(), ipfsCID)
exists, err := capi.db.QueriesRO.ExistsStrategyByURI(internalCtx, ipfsURI)
if err != nil {
if ok := capi.queue.Update(queueID, true, nil, err); !ok {
log.Errorf("error updating import strategy queue %s", queueID)
}
return
}
if exists {
err := ErrCantImportStrategy.WithErr(fmt.Errorf("strategy already exists"))
if ok := capi.queue.Update(queueID, true, nil, err); !ok {
log.Errorf("error updating import strategy queue %s", queueID)
}
return
}
// download the strategy from IPFS and import it into the database if it
// does not exist
capi.downloader.AddToQueue(ipfsURI, func(_ string, dump []byte) {
strategyID, err := capi.importStrategyDump(dump)
strategyID, err := capi.importStrategyDump(ipfsURI, dump)
if err != nil {
if ok := capi.queue.Update(queueID, true, nil, err); !ok {
log.Errorf("error updating import strategy queue %s", queueID)
Expand All @@ -316,15 +342,20 @@ func (capi *census3API) launchStrategyImport(msg *api.APIdata, ctx *httprouter.H
return ctx.Send(res, api.HTTPstatusOK)
}

func (capi *census3API) importStrategyDump(dump []byte) (uint64, error) {
func (capi *census3API) importStrategyDump(ipfsURI string, dump []byte) (uint64, error) {
// init the internal context
internalCtx, cancel := context.WithTimeout(context.Background(), importStrategyTimeout)
defer cancel()

// decode strategy
importedStrategy := GetStrategyResponse{}
if err := json.Unmarshal(dump, &importedStrategy); err != nil {
return 0, ErrCantImportStrategy.WithErr(err)
}
// check if the strategy includes any token
if len(importedStrategy.Tokens) == 0 {
return 0, ErrCantImportStrategy.With("the imported strategy does not include any token")
}
log.Debugw("importing strategy", "strategy", importedStrategy)
// init db transaction
tx, err := capi.db.RW.BeginTx(internalCtx, nil)
if err != nil {
Expand All @@ -336,11 +367,32 @@ func (capi *census3API) importStrategyDump(dump []byte) (uint64, error) {
}
}()
qtx := capi.db.QueriesRW.WithTx(tx)
// ensure that all the tokens included in the strategy are registered in
// the database
for _, token := range importedStrategy.Tokens {
exists, err := qtx.ExistsTokenByChainIDAndExternalID(internalCtx,
queries.ExistsTokenByChainIDAndExternalIDParams{
ID: common.HexToAddress(token.ID).Bytes(),
ChainID: token.ChainID,
ExternalID: token.ExternalID,
})
if err != nil {
return 0, ErrCantGetToken.WithErr(err)
}
if !exists {
return 0, ErrNotFoundToken.Withf("the imported strategy includes a no registered token: %s", token.ID)
}
}
// check the strategy predicate
lx := lexer.NewLexer(strategyoperators.ValidOperatorsTags)
if _, err := lx.Parse(importedStrategy.Predicate); err != nil {
return 0, ErrInvalidStrategyPredicate.With("the imported strategy includes a invalid predicate")
}
// create the strategy to get the ID and then create the strategy tokens
result, err := qtx.CreateStategy(internalCtx, queries.CreateStategyParams{
Alias: importedStrategy.Alias,
Predicate: importedStrategy.Predicate,
Uri: importedStrategy.URI,
Uri: ipfsURI,
})
if err != nil {
return 0, ErrCantCreateStrategy.WithErr(err)
Expand All @@ -349,7 +401,7 @@ func (capi *census3API) importStrategyDump(dump []byte) (uint64, error) {
if err != nil {
return 0, ErrCantCreateStrategy.WithErr(err)
}
// iterate over the token included in the predicate and create them in the
// iterate over the token included in the strategy and create them in the
// database
for symbol, token := range importedStrategy.Tokens {
// decode the min balance for the current token if it is provided,
Expand All @@ -362,7 +414,7 @@ func (capi *census3API) importStrategyDump(dump []byte) (uint64, error) {
}
// create the strategy token in the database
if _, err := qtx.CreateStrategyToken(internalCtx, queries.CreateStrategyTokenParams{
StrategyID: importedStrategy.ID,
StrategyID: uint64(strategyID),
TokenID: common.HexToAddress(token.ID).Bytes(),
MinBalance: minBalance.String(),
ChainID: token.ChainID,
Expand Down
3 changes: 3 additions & 0 deletions db/queries/strategies.sql
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ VALUES (
?, ?, ?, ?, ?
);

-- name: ExistsStrategyByURI :one
SELECT EXISTS(SELECT 1 FROM strategies WHERE uri = ?);

-- name: StrategyTokensByStrategyID :many
SELECT st.token_id as id, st.min_balance, t.symbol, t.chain_address, t.chain_id, t.external_id
FROM strategy_tokens st
Expand Down
11 changes: 11 additions & 0 deletions db/sqlc/strategies.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/frankban/quicktest v1.14.6
github.com/google/uuid v1.4.0
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/ipfs/go-cid v0.4.1
github.com/mattn/go-sqlite3 v1.14.18
github.com/pressly/goose/v3 v3.10.0
github.com/spf13/pflag v1.0.5
Expand Down Expand Up @@ -109,7 +110,6 @@ require (
github.com/ipfs/go-bitfield v1.1.0 // indirect
github.com/ipfs/go-block-format v0.2.0 // indirect
github.com/ipfs/go-blockservice v0.5.1 // indirect
github.com/ipfs/go-cid v0.4.1 // indirect
github.com/ipfs/go-cidutil v0.1.0 // indirect
github.com/ipfs/go-datastore v0.6.0 // indirect
github.com/ipfs/go-ds-badger v0.3.0 // indirect
Expand Down

0 comments on commit f694b41

Please sign in to comment.