client/rest: implement /query/account/{signature}

Allows us to query account balance from the blockchain
for example:
/query/account/sigs:BDADF167E6CF2CDF2D621E590FF1FED2787A40E0
This commit is contained in:
Emmanuel Odeke 2017-07-29 13:20:48 -06:00
parent d4ab79ece0
commit c0743af51c
No known key found for this signature in database
GPG Key ID: 1CA47A292F89DD40
1 changed files with 57 additions and 0 deletions

View File

@ -1,6 +1,7 @@
package rest
import (
"fmt"
"net/http"
"strings"
@ -9,13 +10,16 @@ import (
"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"
keysutils "github.com/tendermint/go-crypto/cmd"
keys "github.com/tendermint/go-crypto/keys"
lightclient "github.com/tendermint/light-client"
)
type Keys struct {
@ -144,10 +148,63 @@ func (ctx *Context) RegisterHandlers(r *mux.Router) error {
r.HandleFunc("/build/send", doSend).Methods("POST")
r.HandleFunc("/sign", doSign).Methods("POST")
r.HandleFunc("/tx", doPostTx).Methods("POST")
r.HandleFunc("/query/account/{signature}", doAccountQuery).Methods("GET")
return nil
}
func extractAddress(signature string) (address string, err *ErrorResponse) {
// Expecting the signature of the form:
// sig:<ADDRESS>
splits := strings.Split(signature, ":")
if len(splits) < 2 {
return "", &ErrorResponse{
Error: `expecting the signature of the form "sig:<ADDRESS>"`,
Code: 406,
}
}
if splits[0] != "sigs" {
return "", &ErrorResponse{
Error: `expecting the signature of the form "sig:<ADDRESS>"`,
Code: 406,
}
}
return splits[1], nil
}
func doAccountQuery(w http.ResponseWriter, r *http.Request) {
query := mux.Vars(r)
signature := query["signature"]
address, errResp := extractAddress(signature)
if errResp != nil {
writeCode(w, errResp, errResp.Code)
return
}
actor, err := commands.ParseActor(address)
if err != nil {
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", address)
writeError(w, err)
return
} else if err != nil {
writeError(w, err)
return
}
if err := proofs.OutputProof(account, proof.BlockHeight()); err != nil {
writeError(w, err)
return
}
writeSuccess(w, account)
}
func doPostTx(w http.ResponseWriter, r *http.Request) {
tx := new(basecoin.Tx)
if err := parseRequestJSON(r, tx); err != nil {