Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

client/rest, modules/coin/rest: moved code around #197

Merged
merged 1 commit into from
Aug 3, 2017
Merged

client/rest, modules/coin/rest: moved code around #197

merged 1 commit into from
Aug 3, 2017

Conversation

odeke-em
Copy link
Collaborator

After offline emails and a video call with @ethanfrey,
a goal was decided to move things around i.e:

  • Move /build/send and /query/account to modules/coin/rest

Due to that move, there is a lot of overlap between needed
code and utils so extracted common code to make
tendermint/tmlibs#33
so make sure to pull in that commit into your tmlibs tree.

@odeke-em
Copy link
Collaborator Author

/cc @ethanfrey

Copy link
Contributor

@ethanfrey ethanfrey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice moving things...
More comments on cleaning it up, making it more configurable.

r.HandleFunc("/sign", doSign).Methods("POST")
r.HandleFunc("/tx", doPostTx).Methods("POST")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you (re)move /tx? It was good here.

/build/send and /query/account are good to have been moved.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's def a mistake, thanks for reporting it.

return
}

if err := proofs.OutputProof(account, proof.BlockHeight()); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OutputProof writes to stdout. Nothing to the request. No need to call it here.

You can just remove it and leave WriteSuccess how it is, but then it is missing the "height" context. Best to look at what OutputProof does to stdout and make a similar function that prints to a ResponseWriter.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that function looks like this
screen shot 2017-08-01 at 11 04 56 pm
and doesn't expose proof, I'll duplicate it then, just letting you know what's up with it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I've added an FoutputProof that does that what that fmt.Println business in OutputProof did.

return
}

tx := coin.NewSendOneTx(*si.From, *si.To, si.Amount)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is key here. And it involved parsing three variables, From, To, and Amount


tx := coin.NewSendOneTx(*si.From, *si.To, si.Amount)
// fees are optional
if si.Fees != nil && !si.Fees.IsZero() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lines from here down until success are all about wrapping the tx. Please pull this into one function, along with the parsing, and place that in client/rest as a helper. Why?

  1. The next task to expose the create_role tx in /modules/roles/rest will duplicate that code.
    -> this means extract into a common function
  2. As soon as I ask you to support an optional assume_role middleware, you will have to change it everywhere. And if a third party wants to add a staking middleware, they will have to change what this common function does, ideally without forking
    -> this means it should be configurable. Below is what I did for cli, it is a start, maybe you have a better idea.

https://github.com/tendermint/basecoin/blob/unstable/cmd/basecli/main.go#L55-L62
(it doesn't have to be so complicated with the wrappers, but at least some package exported variable like txcmd.Middleware to set what the wrappers are, even if I have to write it not compose it):

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I can extract that into a helper function, but I might have to keep that in modules/coin/rest because client/rest imports modules/coin/rest so that'd be an import cycle.

if err := ctx.RegisterHandlers(router); err != nil {
return err
}
if err := coinrest.RegisterHandlers(router); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than specifying the two packages where to register the handlers, please accept eg. a slice of RegisterHandler funcs, which can be set in main.go (at least indirectly). In a similar way how the cli allows one to register query functions.

https://github.com/tendermint/basecoin/blob/unstable/cmd/basecli/main.go#L43-L51

I think even ctx should be optional. A use case came up in the retreat where we want a baseserver that only allows queries. No need for key management or /tx or /send... That should be configurable without copying/forking large amounts of code.

@@ -42,39 +39,39 @@ func (k *Keys) GenerateKey(w http.ResponseWriter, r *http.Request) {
ckReq := &CreateKeyRequest{
Algo: k.algo,
}
if err := parseRequestJSON(r, ckReq); err != nil {
writeError(w, err)
if err := common.ParseAndValidateRequestJSON(r, ckReq); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this is good to move into tmlibs/common, just added comments on the PR, so we are happy with the implementation there.

coinrest "github.com/tendermint/basecoin/modules/coin/rest"
)

var ServeCmd = &cobra.Command{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to move this command here.

var port int

func init() {
ServeCmd.PersistentFlags().IntVar(&port, "port", 8998, "the port to run the server on")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use Int() not IntVar(). See next comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also make "port" flag name a constant please.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah Int() doesn't work alright, I think I mentioned this offline, it requires me then to invoke
ServeCmd.Parse(args) of which args aren't available until after we've entered the command .RunE and even then it isn't playing well with the flags cobra passes in []string{}. I spent too much on this that I figured I'd rather make functionality changes than be stuck trying to debug ServeCmd.

return err
}

addr := fmt.Sprintf(":%d", port)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you used Int() above, you could use viper.GetInt(FlagPort) here.
This would allow us to set a BC_PORT variable (12-factor style) or add port = 12345 in the config file (typical unix style) to configure it and not just assume it comes from the command line.

Check out viper. It is pretty crazy. Maybe overkill but we decided on it for the cli here, so we can go all out.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, yeah I used viper.GetInt(flag) and it worked with cobra.PersistentFlags().Int(...), thanks for the advice!

return
}

writeSuccess(w, commit)
common.WriteSuccess(w, commit)
}

func doSign(w http.ResponseWriter, r *http.Request) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is dead code now, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, it is used in "/sign"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I think I tagged the wrong function... scroll down to doSend. There are no references to it in the client/rest package.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, thanks. Yeah, that was moved to modules/coin/rest/handlers.go.

@ethanfrey
Copy link
Contributor

Oh, and if this depends on a special branch in tmlibs, please update the reference in glide.yaml and do glide update to reinitiate glide.lock and vendor dir. All dependencies must be set there to make it reproduceable.

@odeke-em
Copy link
Collaborator Author

odeke-em commented Aug 2, 2017

I've addressed the other comments except for:

  1. The middleware business

func OutputProof(info interface{}, height uint64) error {
wrap := proof{height, info}
res, err := data.ToJSON(wrap)
// FoutputProof writes the output of wrapping height and info
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice!

I like the generalization here that lets it work for http.ResponseWriter as well.

}

const defaultAlgo = "ed25519"

func serve(cmd *cobra.Command, args []string) error {
port := viper.GetInt(envPortFlag)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -63,17 +63,34 @@ func doQueryAccount(w http.ResponseWriter, r *http.Request) {
return
}

if err := proofs.OutputProof(account, proof.BlockHeight()); err != nil {
if err := proofs.FoutputProof(w, account, proof.BlockHeight()); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

common.WriteSuccess(w, account)
}

func PrepareSendTx(si *SendInput) basecoin.Tx {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay separate the validation/parse for the construction. Makes sense, also easier to test.

}

func doSend(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
si := new(SendInput)
if err := common.ParseAndValidateRequestJSON(r, si); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, one question...

This ParseAndValidateRequestJSON does some auto-magic validation logic on the input.
Then below there is validate logic done manually.

I think we should pick one way or the other. Like use your validation checks, but then only ParseRequestJSON.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the check below is misleading if we think of it as "validation", it is a check on a variable passed in the query string, which is disjoint from the parsed struct so common.ParseAndValidateRequestJSON doesn't hurt.

@ethanfrey
Copy link
Contributor

Okay, the middleware/handler registration in main can be a separate pr. I'll make an issue about this.

Things missing for a merge:

  • remove client/rest/doSend or convince me I am wrong
  • pick one validation method in modules/coin/rest/doSend and we'll use that for all rest calls.
  • update the glide.yaml / glide.lock file to the required version of tmlibs

I will look at the tmlibs pr now.

@@ -173,7 +173,7 @@ imports:
- types
- version
- name: github.com/tendermint/tmlibs
version: 2f6f3e6aa70bb19b70a6e73210273fa127041070
version: 75372988e737a9f672c0e7f6308042620bd3e151
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note that tmlibs should be used on branch develop with that hash

@odeke-em
Copy link
Collaborator Author

odeke-em commented Aug 2, 2017

Done rebasing on origin/unstable.

After offline emails and a video call with @ethanfrey,
a goal was decided to move things around i.e:
- [X] Move /build/send and /query/account to modules/coin/rest

Due to that move, there is a lot of overlap between needed
code and utils so extracted common code to make
tendermint/tmlibs#33
so make sure to pull in that commit into your tmlibs tree.

After code review feedback:
client/rest, modules/coin/rest: FoutputProof, PrepareSendTx helper

* Extract OutputProof to FoutputProof helper that can
be used in modules/coin/rest/handlers.go as proofs.FoutputProof
* Revert r.HandleFunc("/tx", doPostTx).Methods("POST") which
was erraneously deleted
* Use function signatures from "tendermint/tmblibs/common"
@odeke-em odeke-em mentioned this pull request Aug 3, 2017
@ethanfrey ethanfrey merged commit cdaee32 into cosmos:unstable Aug 3, 2017
@odeke-em
Copy link
Collaborator Author

odeke-em commented Aug 3, 2017

Thanks for the review and merge @ethanfrey!

ParthDesai pushed a commit to ChorusOne/cosmos-sdk that referenced this pull request Apr 19, 2021
mmsqe added a commit to mmsqe/cosmos-sdk that referenced this pull request Feb 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants