From b384f7eed2412fc042fe34f67a8874e9e9447cbe Mon Sep 17 00:00:00 2001 From: Maksym Hrynenko Date: Fri, 17 May 2024 14:50:55 +0300 Subject: [PATCH 1/2] add: state_root query; update: docs, get gist proof by state root, not block number, split business logic and user request data --- ...dentity-provider-service@v1@gist-data.yaml | 5 ++ go.mod | 1 + .../service/api/handlers/get_gist_data.go | 62 +------------------ .../service/api/requests/get_gist_data.go | 62 ++++++++++++++++--- internal/service/issuer/main.go | 2 +- 5 files changed, 62 insertions(+), 70 deletions(-) diff --git a/docs/spec/paths/intergrations@identity-provider-service@v1@gist-data.yaml b/docs/spec/paths/intergrations@identity-provider-service@v1@gist-data.yaml index 7636a95..23b82cb 100644 --- a/docs/spec/paths/intergrations@identity-provider-service@v1@gist-data.yaml +++ b/docs/spec/paths/intergrations@identity-provider-service@v1@gist-data.yaml @@ -9,6 +9,11 @@ get: required: true schema: type: string + - in: query + name: state_root + required: true + schema: + type: string responses: '200': description: Success diff --git a/go.mod b/go.mod index b407887..bf3a23c 100644 --- a/go.mod +++ b/go.mod @@ -34,6 +34,7 @@ require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect github.com/andybalholm/brotli v1.1.0 // indirect + github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect diff --git a/internal/service/api/handlers/get_gist_data.go b/internal/service/api/handlers/get_gist_data.go index 4824a01..1d8a0bc 100644 --- a/internal/service/api/handlers/get_gist_data.go +++ b/internal/service/api/handlers/get_gist_data.go @@ -1,21 +1,16 @@ package handlers import ( - "context" - validation "github.com/go-ozzo/ozzo-validation/v4" - "gitlab.com/distributed_lab/logan/v3/errors" "math/big" "net/http" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/iden3/contracts-abi/state/go/abi" core "github.com/iden3/go-iden3-core/v2" - "github.com/iden3/go-iden3-core/v2/w3c" "github.com/rarimo/passport-identity-provider/internal/service/api/requests" "github.com/rarimo/passport-identity-provider/resources" "gitlab.com/distributed_lab/ape" "gitlab.com/distributed_lab/ape/problems" - "gitlab.com/distributed_lab/logan/v3" ) func GetGistData(w http.ResponseWriter, r *http.Request) { @@ -25,72 +20,21 @@ func GetGistData(w http.ResponseWriter, r *http.Request) { return } - userDID, err := w3c.ParseDID(req.UserDID) - if err != nil { - Log(r).WithError(err).Error("failed to parse user DID") - ape.RenderErr(w, problems.BadRequest(err)...) - return - } - - userID, err := core.IDFromDID(*userDID) + userID, err := core.IDFromDID(*req.UserDID) if err != nil { Log(r).WithError(err).Error("failed to parse user ID") ape.RenderErr(w, problems.InternalError()) return } - blockNum, err := EthClient(r).BlockNumber(context.Background()) - if err != nil { - Log(r).WithError(err).Error("failed to get block number") - ape.RenderErr(w, problems.InternalError()) - return - } - - if req.BlockNumber > blockNum { - Log(r).WithFields(logan.F{ - "requested_block_number": req.BlockNumber, - "latest_block_number": blockNum, - }).Error("Requested block number is higher than latest") - ape.RenderErr(w, problems.BadRequest(validation.Errors{ - "/block_number": errors.New("Requested block number is higher than latest"), - })...) - return - } - - if req.BlockNumber != 0 { - blockNum = req.BlockNumber - } - - stateContract := StateContract(r) - - gistProof, err := stateContract.GetGISTProof(&bind.CallOpts{ - BlockNumber: new(big.Int).SetUint64(blockNum), - }, userID.BigInt()) + gistProof, err := StateContract(r).GetGISTProofByRoot(&bind.CallOpts{}, req.StateRoot, userID.BigInt()) if err != nil { Log(r).WithError(err).Error("failed to get GIST proof") ape.RenderErr(w, problems.InternalError()) return } - gistRoot, err := stateContract.GetGISTRoot(&bind.CallOpts{ - BlockNumber: new(big.Int).SetUint64(blockNum), - }) - if err != nil { - Log(r).WithError(err).Error("failed to get GIST root") - ape.RenderErr(w, problems.InternalError()) - return - } - - if gistProof.Root.Cmp(gistRoot) != 0 { - Log(r).WithFields(logan.F{ - "gist_root": gistRoot.String(), - "gist_proof_root": gistProof.Root.String(), - }).Warn("gist root does not match") - } - - response := newGistDataResponse(req.UserDID, gistProof, gistRoot) - - ape.Render(w, response) + ape.Render(w, newGistDataResponse(req.UserDID.String(), gistProof, gistProof.Root)) } func newGistDataResponse(userDID string, proof abi.IStateGistProof, root *big.Int) resources.GistDataResponse { diff --git a/internal/service/api/requests/get_gist_data.go b/internal/service/api/requests/get_gist_data.go index 767ba30..36cf100 100644 --- a/internal/service/api/requests/get_gist_data.go +++ b/internal/service/api/requests/get_gist_data.go @@ -1,30 +1,72 @@ package requests import ( + "math/big" + "net/http" + validation "github.com/go-ozzo/ozzo-validation/v4" + "github.com/go-ozzo/ozzo-validation/v4/is" + "github.com/iden3/go-iden3-core/v2/w3c" + "gitlab.com/distributed_lab/logan/v3" "gitlab.com/distributed_lab/logan/v3/errors" "gitlab.com/distributed_lab/urlval" - "net/http" ) type GetGistDataRequest struct { - UserDID string `url:"user_did"` - BlockNumber uint64 `url:"block_number"` + UserDID *w3c.DID + StateRoot *big.Int +} + +type getGistDataQuery struct { + UserDID string `url:"user_did"` + StateRoot string `url:"state_root"` } func NewGetGistDataRequest(r *http.Request) (GetGistDataRequest, error) { - var req GetGistDataRequest + var query getGistDataQuery - err := urlval.Decode(r.URL.Query(), &req) + err := urlval.Decode(r.URL.Query(), &query) if err != nil { - return GetGistDataRequest{}, errors.Wrap(err, "failed to decode url") + return GetGistDataRequest{}, validation.Errors{ + "url": errors.Wrap(err, "failed to decode url"), + } } - return req, validateGetGistDataRequest(req) + return parseGistDataQuery(query) } -func validateGetGistDataRequest(r GetGistDataRequest) error { - return validation.Errors{ - "/user_did": validation.Validate(r.UserDID, validation.Required), +func parseGistDataQuery(query getGistDataQuery) (GetGistDataRequest, error) { + var ( + err error + ok bool + req GetGistDataRequest + ) + + err = validation.Errors{ + "/user_did": validation.Validate(query.UserDID, validation.Required), + "/state_root": validation.Validate(query.StateRoot, validation.Required, is.Hexadecimal), }.Filter() + if err != nil { + return req, err + } + + req.UserDID, err = w3c.ParseDID(query.UserDID) + if err != nil { + return req, validation.Errors{ + "/user_did": errors.Wrap(err, "failed to parse user DID", logan.F{ + "user_did": req.UserDID, + }), + }.Filter() + } + + req.StateRoot, ok = new(big.Int).SetString(query.StateRoot, 16) + if !ok { + return req, validation.Errors{ + "/state_root": errors.From(errors.New("failed to parse state root"), logan.F{ + "state_root": req.StateRoot, + }), + } + } + + return req, nil } diff --git a/internal/service/issuer/main.go b/internal/service/issuer/main.go index 3c47a75..b8dc07d 100644 --- a/internal/service/issuer/main.go +++ b/internal/service/issuer/main.go @@ -1,11 +1,11 @@ package issuer import ( - "github.com/google/uuid" "math/big" "strconv" "time" + "github.com/google/uuid" "github.com/iden3/go-iden3-crypto/poseidon" "github.com/imroc/req/v3" "github.com/rarimo/passport-identity-provider/internal/config" From 23f952ead2f110e375abffe0e916ab0d4b6acf12 Mon Sep 17 00:00:00 2001 From: Maksym Hrynenko Date: Fri, 17 May 2024 15:38:00 +0300 Subject: [PATCH 2/2] update: put function arguments according to the signature --- internal/service/api/handlers/get_gist_data.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/api/handlers/get_gist_data.go b/internal/service/api/handlers/get_gist_data.go index 1d8a0bc..2e003c8 100644 --- a/internal/service/api/handlers/get_gist_data.go +++ b/internal/service/api/handlers/get_gist_data.go @@ -27,7 +27,7 @@ func GetGistData(w http.ResponseWriter, r *http.Request) { return } - gistProof, err := StateContract(r).GetGISTProofByRoot(&bind.CallOpts{}, req.StateRoot, userID.BigInt()) + gistProof, err := StateContract(r).GetGISTProofByRoot(&bind.CallOpts{}, userID.BigInt(), req.StateRoot) if err != nil { Log(r).WithError(err).Error("failed to get GIST proof") ape.RenderErr(w, problems.InternalError())