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

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
https://github.com/tendermint/tmlibs/pull/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"
This commit is contained in:
Emmanuel Odeke
2017-08-02 12:57:29 -06:00
parent 67f25f54ed
commit 1a45755027
8 changed files with 219 additions and 247 deletions
+123
View File
@@ -0,0 +1,123 @@
package rest
import (
"fmt"
"net/http"
"strings"
"github.com/gorilla/mux"
"github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/client/commands"
"github.com/tendermint/basecoin/client/commands/proofs"
"github.com/tendermint/basecoin/modules/auth"
"github.com/tendermint/basecoin/modules/base"
"github.com/tendermint/basecoin/modules/coin"
"github.com/tendermint/basecoin/modules/fee"
"github.com/tendermint/basecoin/modules/nonce"
"github.com/tendermint/basecoin/stack"
lightclient "github.com/tendermint/light-client"
"github.com/tendermint/tmlibs/common"
)
// SendInput is the request to send an amount from one actor to another.
// Note: Not using the `validator:""` tags here because SendInput has
// many fields so it would be nice to figure out all the invalid
// inputs and report them back to the caller, in one shot.
type SendInput struct {
Fees *coin.Coin `json:"fees"`
Multi bool `json:"multi,omitempty"`
Sequence uint32 `json:"sequence"`
To *basecoin.Actor `json:"to"`
From *basecoin.Actor `json:"from"`
Amount coin.Coins `json:"amount"`
}
func RegisterHandlers(r *mux.Router) error {
r.HandleFunc("/build/send", doSend).Methods("POST")
r.HandleFunc("/query/account/{signature}", doQueryAccount).Methods("GET")
return nil
}
// doQueryAccount is the HTTP handlerfunc to query an account
// It expects a query string with
func doQueryAccount(w http.ResponseWriter, r *http.Request) {
query := mux.Vars(r)
signature := query["signature"]
actor, err := commands.ParseActor(signature)
if err != nil {
common.WriteError(w, err)
return
}
actor = coin.ChainAddr(actor)
key := stack.PrefixedKey(coin.NameCoin, actor.Bytes())
account := new(coin.Account)
proof, err := proofs.GetAndParseAppProof(key, account)
if lightclient.IsNoDataErr(err) {
err := fmt.Errorf("account bytes are empty for address: %q", signature)
common.WriteError(w, err)
return
} else if err != nil {
common.WriteError(w, err)
return
}
if err := proofs.FoutputProof(w, account, proof.BlockHeight()); err != nil {
common.WriteError(w, err)
}
}
func PrepareSendTx(si *SendInput) basecoin.Tx {
tx := coin.NewSendOneTx(*si.From, *si.To, si.Amount)
// fees are optional
if si.Fees != nil && !si.Fees.IsZero() {
tx = fee.NewFee(tx, *si.Fees, *si.From)
}
// only add the actual signer to the nonce
signers := []basecoin.Actor{*si.From}
tx = nonce.NewTx(si.Sequence, signers, tx)
tx = base.NewChainTx(commands.GetChainID(), 0, tx)
if si.Multi {
tx = auth.NewMulti(tx).Wrap()
} else {
tx = auth.NewSig(tx).Wrap()
}
return tx
}
func doSend(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
si := new(SendInput)
if err := common.ParseRequestAndValidateJSON(r, si); err != nil {
common.WriteError(w, err)
return
}
var errsList []string
if si.From == nil {
errsList = append(errsList, `"from" cannot be nil`)
}
if si.Sequence <= 0 {
errsList = append(errsList, `"sequence" must be > 0`)
}
if si.To == nil {
errsList = append(errsList, `"to" cannot be nil`)
}
if len(si.Amount) == 0 {
errsList = append(errsList, `"amount" cannot be empty`)
}
if len(errsList) > 0 {
code := http.StatusBadRequest
err := &common.ErrorResponse{
Err: strings.Join(errsList, ", "),
Code: code,
}
common.WriteCode(w, err, code)
return
}
tx := PrepareSendTx(si)
common.WriteSuccess(w, tx)
}