From f52d92a40e2ae021e6f74ff7efee9d94b1f9280d Mon Sep 17 00:00:00 2001 From: Emmanuel Odeke Date: Thu, 3 Aug 2017 17:28:42 -0600 Subject: [PATCH] modules/coin/rest: implemented CreateRole * Note: Role must be a hex string, as enforced in tests/rest/cli.sh ```shell $ curl -X POST http://localhost:8998/build/create_role --data \ '{ "role":"DEADBEEF", "seq": 1, "min_sigs": 1, "signers": [{ "addr": "4FF759D47C81754D8F553DCCAC8651D0AF74C7F9", "app": "role" }] }' ``` ```HTTP HTTP/1.1 200 OK Content-Type: application/json Date: Tue, 08 Aug 2017 19:15:13 GMT Content-Length: 387 { "type": "chain/tx", "data": { "chain_id": "test_chain_id", "expires_at": 0, "tx": { "type": "role/create", "data": { "role": "DEADBEEF", "min_sigs": 1, "signers": [ { "chain": "", "app": "role", "addr": "4FF759D47C81754D8F553DCCAC8651D0AF74C7F9" } ] } } } } ``` Updates #200 --- cmd/baseserver/README.md | 48 +++++++++++++++++++++- cmd/baseserver/main.go | 4 ++ modules/coin/rest/handlers.go | 1 + modules/roles/rest/handlers.go | 74 ++++++++++++++++++++++++++++++++++ tests/cli/rest.sh | 33 ++++++++++++++- 5 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 modules/roles/rest/handlers.go diff --git a/cmd/baseserver/README.md b/cmd/baseserver/README.md index 3b7c9acec..a45e160b6 100644 --- a/cmd/baseserver/README.md +++ b/cmd/baseserver/README.md @@ -24,11 +24,17 @@ Route | Method | Completed | Description /sign|POST|✔️|Sign a transaction /tx|POST|✖️|Post a transaction to the blockchain /seeds/status|GET|✖️|Returns the information on the last seed +/build/create_role|POST|✔️|Creates a role. Please note that the role MUST be valid hex for example instead of sending "role", send its hex encoded equivalent "726f6c65" + +## Preamble: +In the examples below, we assume that URL is set to `http://localhost:8889` +which can be set for example +URL=http://localhost:8889 ## Sample usage - Generate a key ```shell -$ curl -X POST http://localhost8998/keys --data '{"algo": "ed25519", "name": "SampleX", "passphrase": "Say no more"}' +$ curl -X POST $URL/keys --data '{"algo": "ed25519", "name": "SampleX", "passphrase": "Say no more"}' ``` ```json @@ -47,7 +53,7 @@ $ curl -X POST http://localhost8998/keys --data '{"algo": "ed25519", "name": "Sa - Sign a key ```shell -$ curl -X POST http://localhost:8998/sign --data '{ +$ curl -X POST $URL/sign --data '{ "name": "matt", "password": "Say no more", "tx": { @@ -114,3 +120,41 @@ $ curl -X POST http://localhost:8998/sign --data '{ } } ``` + +- Create a role +```shell +$ curl -X POST $URL/build/create_role --data \ +'{ + "role": "deadbeef", + "signers": [{ + "addr": "4FF759D47C81754D8F553DCCAC8651D0AF74C7F9", + "app": "role" + }], + "min_sigs": 1, + "seq": 1 +}' +``` + +```json +{ + "type": "chain/tx", + "data": { + "chain_id": "test_chain_id", + "expires_at": 0, + "tx": { + "type": "role/create", + "data": { + "role": "DEADBEEF", + "min_sigs": 1, + "signers": [ + { + "chain": "", + "app": "role", + "addr": "4FF759D47C81754D8F553DCCAC8651D0AF74C7F9" + } + ] + } + } + } +} +``` diff --git a/cmd/baseserver/main.go b/cmd/baseserver/main.go index fee1552a3..82cff3d7b 100644 --- a/cmd/baseserver/main.go +++ b/cmd/baseserver/main.go @@ -13,6 +13,7 @@ import ( "github.com/tendermint/basecoin/client/commands" rest "github.com/tendermint/basecoin/client/rest" coinrest "github.com/tendermint/basecoin/modules/coin/rest" + rolerest "github.com/tendermint/basecoin/modules/roles/rest" "github.com/tendermint/tmlibs/cli" ) @@ -50,6 +51,9 @@ func serve(cmd *cobra.Command, args []string) error { // Coin query account handler coinrest.RegisterQueryAccount, + // Roles createRole handler + rolerest.RegisterCreateRole, + // Basecoin sign transactions handler rest.RegisterSignTx, // Basecoin post transaction handler diff --git a/modules/coin/rest/handlers.go b/modules/coin/rest/handlers.go index c3393de50..0b1c3d4de 100644 --- a/modules/coin/rest/handlers.go +++ b/modules/coin/rest/handlers.go @@ -152,3 +152,4 @@ func RegisterAll(r *mux.Router) error { } // End of mux.Router registrars + diff --git a/modules/roles/rest/handlers.go b/modules/roles/rest/handlers.go new file mode 100644 index 000000000..700191b61 --- /dev/null +++ b/modules/roles/rest/handlers.go @@ -0,0 +1,74 @@ +package rest + +import ( + "encoding/hex" + "net/http" + + "github.com/gorilla/mux" + + abci "github.com/tendermint/abci/types" + "github.com/tendermint/basecoin" + "github.com/tendermint/basecoin/client/commands" + "github.com/tendermint/basecoin/errors" + "github.com/tendermint/basecoin/modules/base" + "github.com/tendermint/basecoin/modules/nonce" + "github.com/tendermint/basecoin/modules/roles" + "github.com/tendermint/tmlibs/common" +) + +type RoleInput struct { + Role string `json:"role" validate:"required,min=2"` + + MinimumSigners uint32 `json:"min_sigs" validate:"required,min=1"` + + Signers []basecoin.Actor `json:"signers" validate:"required,min=1"` + + Sequence uint32 `json:"seq" validate:"required,min=1"` +} + +func parseRole(roleInHex string) ([]byte, error) { + parsedRole, err := hex.DecodeString(common.StripHex(roleInHex)) + if err != nil { + err = errors.WithMessage("invalid hex", err, abci.CodeType_EncodingError) + return nil, err + } + return parsedRole, nil +} + +// mux.Router registrars + +// RegisterQueryAccount is a mux.Router handler that exposes GET +// method access on route /query/account/{signature} to query accounts +func RegisterCreateRole(r *mux.Router) error { + r.HandleFunc("/build/create_role", doCreateRole).Methods("POST") + return nil +} + +func doCreateRole(w http.ResponseWriter, r *http.Request) { + ri := new(RoleInput) + if err := common.ParseRequestAndValidateJSON(r, ri); err != nil { + common.WriteError(w, err) + return + } + + parsedRole, err := parseRole(ri.Role) + if err != nil { + common.WriteError(w, err) + return + } + + // Note the ordering of Tx wrapping matters: + // 1. NonceTx + tx := (nonce.Tx{}).Wrap() + tx = nonce.NewTx(ri.Sequence, ri.Signers, tx) + + // 2. CreateRoleTx + tx = roles.NewCreateRoleTx(parsedRole, ri.MinimumSigners, ri.Signers) + + // 3. ChainTx + tx = base.NewChainTx(commands.GetChainID(), 0, tx) + + common.WriteSuccess(w, tx) +} + +// End of mux.Router registrars diff --git a/tests/cli/rest.sh b/tests/cli/rest.sh index e99538845..1ed86e798 100755 --- a/tests/cli/rest.sh +++ b/tests/cli/rest.sh @@ -40,13 +40,12 @@ restAccount() { ACCT=$(curl ${URL}/query/account/sigs:$1 2>/dev/null) if [ -n "$DEBUG" ]; then echo $ACCT; echo; fi assertEquals "line=${LINENO}, proper money" "$2" $(echo $ACCT | jq .coins[0].amount) - # assertEquals "line=${LINENO}, proper money" "$2" $(echo $ACCT | jq .data.coins[0].amount) return $? } restNoAccount() { ERROR=$(curl ${URL}/query/account/sigs:$1 2>/dev/null) - assertEquals "line=${LINENO}, should error" 406 $(echo $ERROR | jq .code) + assertEquals "line=${LINENO}, should error" 400 $(echo $ERROR | jq .code) } test00GetAccount() { @@ -57,6 +56,36 @@ test00GetAccount() { restNoAccount $RECV } +# XXX Ex Usage: restCreateRole $PAYLOAD $EXPECTED +# Desc: Tests that the first returned signer.addr matches the expected +restCreateRole() { + assertNotNull "line=${LINENO}, data required" "$1" + ROLE=$(curl ${URL}/build/create_role --data "$1" 2>/dev/null) + if [ -n "$DEBUG" ]; then echo -e "$ROLE\n"; fi + assertEquals "line=${LINENO}, role required" "$2" $(echo $ROLE | jq .data.tx.data.signers[0].addr) + return $? +} + +test03CreateRole() { + DATA="{\"role\": \"726f6c65\", \"seq\": 1, \"min_sigs\": 1, \"signers\": [{\"addr\": \"4FF759D47C81754D8F553DCCAC8651D0AF74C7F9\", \"app\": \"role\"}]}" + restCreateRole "$DATA" \""4FF759D47C81754D8F553DCCAC8651D0AF74C7F9"\" +} + +test04CreateRoleInvalid() { + ERROR=$(curl ${URL}/build/create_role --data '{}' 2>/dev/null) + assertEquals "line=${LINENO}, should report validation failed" 0 $(echo $ERROR | grep "failed" > /dev/null && echo 0 || echo 1) + + ERROR=$(curl ${URL}/build/create_role --data '{"role": "foo"}' 2>/dev/null) + assertEquals "line=${LINENO}, should report validation failed" 0 $(echo $ERROR | grep "failed" > /dev/null && echo 0 || echo 1) + + ERROR=$(curl ${URL}/build/create_role --data '{"min_sigs": 2, "role": "abcdef"}' 2>/dev/null) + assertEquals "line=${LINENO}, should report validation failed" 0 $(echo $ERROR | grep "failed" > /dev/null && echo 0 || echo 1) + + ## Non-hex roles should be rejected + ERROR=$(curl ${URL}/build/create_role --data "{\"role\": \"foobar\", \"seq\": 2, \"signers\": [{\"addr\": \"4FF759D47C81754D8F553DCCAC8651D0AF74C7F9\", \"app\": \"role\"}], \"min_sigs\": 1}" 2>/dev/null) + assertEquals "line=${LINENO}, should report validation failed" 0 $(echo $ERROR | grep "invalid hex" > /dev/null && echo 0 || echo 1) +} + test01SendTx() { SENDER=$(restAddr $RICH) RECV=$(restAddr $POOR)