-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Conversation
/cc @ethanfrey |
There was a problem hiding this 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.
client/rest/handlers.go
Outdated
r.HandleFunc("/sign", doSign).Methods("POST") | ||
r.HandleFunc("/tx", doPostTx).Methods("POST") |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
modules/coin/rest/handlers.go
Outdated
return | ||
} | ||
|
||
if err := proofs.OutputProof(account, proof.BlockHeight()); err != nil { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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.
modules/coin/rest/handlers.go
Outdated
return | ||
} | ||
|
||
tx := coin.NewSendOneTx(*si.From, *si.To, si.Amount) |
There was a problem hiding this comment.
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
modules/coin/rest/handlers.go
Outdated
|
||
tx := coin.NewSendOneTx(*si.From, *si.To, si.Amount) | ||
// fees are optional | ||
if si.Fees != nil && !si.Fees.IsZero() { |
There was a problem hiding this comment.
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?
- The next task to expose the
create_role
tx in/modules/roles/rest
will duplicate that code.
-> this means extract into a common function - 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):
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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.
client/rest/handlers.go
Outdated
@@ -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 { |
There was a problem hiding this comment.
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{ |
There was a problem hiding this comment.
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.
client/rest/cmd.go
Outdated
var port int | ||
|
||
func init() { | ||
ServeCmd.PersistentFlags().IntVar(&port, "port", 8998, "the port to run the server on") |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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"
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
Oh, and if this depends on a special branch in tmlibs, please update the reference in |
I've addressed the other comments except for:
|
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 |
There was a problem hiding this comment.
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.
client/rest/cmd.go
Outdated
} | ||
|
||
const defaultAlgo = "ed25519" | ||
|
||
func serve(cmd *cobra.Command, args []string) error { | ||
port := viper.GetInt(envPortFlag) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
modules/coin/rest/handlers.go
Outdated
@@ -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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice
modules/coin/rest/handlers.go
Outdated
common.WriteSuccess(w, account) | ||
} | ||
|
||
func PrepareSendTx(si *SendInput) basecoin.Tx { |
There was a problem hiding this comment.
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.
modules/coin/rest/handlers.go
Outdated
} | ||
|
||
func doSend(w http.ResponseWriter, r *http.Request) { | ||
defer r.Body.Close() | ||
si := new(SendInput) | ||
if err := common.ParseAndValidateRequestJSON(r, si); err != nil { |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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.
Okay, the middleware/handler registration in main can be a separate pr. I'll make an issue about this. Things missing for a merge:
I will look at the tmlibs pr now. |
@@ -173,7 +173,7 @@ imports: | |||
- types | |||
- version | |||
- name: github.com/tendermint/tmlibs | |||
version: 2f6f3e6aa70bb19b70a6e73210273fa127041070 | |||
version: 75372988e737a9f672c0e7f6308042620bd3e151 |
There was a problem hiding this comment.
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
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"
Thanks for the review and merge @ethanfrey! |
Problem: v0.47.x is outdated
After offline emails and a video call with @ethanfrey,
a goal was decided to move things around i.e:
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.