Skip to content

Commit

Permalink
feat(rpc): Transaction proxy for staking tx types (celestiaorg#984)
Browse files Browse the repository at this point in the history
* staking tx types in `core_access.go`

* extending Accessor interface with new staking tx types

* adding transaction types to rpc

* docs: adding punctuation, removing todo

* fix: setting bech32 prefix for validators inside node, new undelegation request types

* Update service/rpc/state.go

Co-authored-by: rene <[email protected]>

Co-authored-by: rene <[email protected]>
  • Loading branch information
distractedm1nd and renaynay committed Sep 19, 2022
1 parent 5e5bab0 commit 48109c3
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 4 deletions.
1 change: 1 addition & 0 deletions cmd/cel-key/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func main() {
func run() error {
cfg := sdk.GetConfig()
cfg.SetBech32PrefixForAccount(app.Bech32PrefixAccAddr, app.Bech32PrefixAccPub)
cfg.SetBech32PrefixForValidator(app.Bech32PrefixValAddr, app.Bech32PrefixValPub)
cfg.Seal()

ctx := context.WithValue(context.Background(), client.ClientContextKey, &initClientCtx)
Expand Down
1 change: 1 addition & 0 deletions cmd/celestia/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func init() {
// as in the celestia application.
cfg := sdk.GetConfig()
cfg.SetBech32PrefixForAccount(app.Bech32PrefixAccAddr, app.Bech32PrefixAccPub)
cfg.SetBech32PrefixForValidator(app.Bech32PrefixValAddr, app.Bech32PrefixValPub)
cfg.Seal()

rootCmd.AddCommand(
Expand Down
4 changes: 4 additions & 0 deletions service/rpc/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ func (h *Handler) RegisterEndpoints(rpc *Server) {
rpc.RegisterHandlerFunc(submitTxEndpoint, h.handleSubmitTx, http.MethodPost)
rpc.RegisterHandlerFunc(submitPFDEndpoint, h.handleSubmitPFD, http.MethodPost)
rpc.RegisterHandlerFunc(transferEndpoint, h.handleTransfer, http.MethodPost)
rpc.RegisterHandlerFunc(delegationEndpoint, h.handleDelegation, http.MethodPost)
rpc.RegisterHandlerFunc(undelegationEndpoint, h.handleUndelegation, http.MethodPost)
rpc.RegisterHandlerFunc(cancelUnbondingEndpoint, h.handleCancelUnbonding, http.MethodPost)
rpc.RegisterHandlerFunc(beginRedelegationEndpoint, h.handleRedelegation, http.MethodPost)

// share endpoints
rpc.RegisterHandlerFunc(fmt.Sprintf("%s/{%s}/height/{%s}", namespacedSharesEndpoint, nIDKey, heightKey),
Expand Down
184 changes: 180 additions & 4 deletions service/rpc/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ import (
)

const (
balanceEndpoint = "/balance"
submitTxEndpoint = "/submit_tx"
submitPFDEndpoint = "/submit_pfd"
transferEndpoint = "/transfer"
balanceEndpoint = "/balance"
submitTxEndpoint = "/submit_tx"
submitPFDEndpoint = "/submit_pfd"
transferEndpoint = "/transfer"
delegationEndpoint = "/delegate"
undelegationEndpoint = "/begin_unbonding"
cancelUnbondingEndpoint = "/cancel_unbond"
beginRedelegationEndpoint = "/begin_redelegate"
)

var addrKey = "address"
Expand All @@ -40,6 +44,37 @@ type transferRequest struct {
GasLimit uint64 `json:"gas_limit"`
}

// delegationRequest represents a request for both delegation
// and for beginning and canceling undelegation
type delegationRequest struct {
To string `json:"to"`
Amount int64 `json:"amount"`
GasLimit uint64 `json:"gas_limit"`
}

// redelegationRequest represents a request for redelegation
type redelegationRequest struct {
From string `json:"from"`
To string `json:"to"`
Amount int64 `json:"amount"`
GasLimit uint64 `json:"gas_limit"`
}

// unbondRequest represents a request to begin unbonding
type unbondRequest struct {
From string `json:"from"`
Amount int64 `json:"amount"`
GasLimit uint64 `json:"gas_limit"`
}

// cancelUnbondRequest represents a request to cancel unbonding
type cancelUnbondRequest struct {
From string `json:"from"`
Amount int64 `json:"amount"`
Height int64 `json:"height"`
GasLimit uint64 `json:"gas_limit"`
}

func (h *Handler) handleBalanceRequest(w http.ResponseWriter, r *http.Request) {
var (
bal *state.Balance
Expand Down Expand Up @@ -172,3 +207,144 @@ func (h *Handler) handleTransfer(w http.ResponseWriter, r *http.Request) {
log.Errorw("writing response", "endpoint", transferEndpoint, "err", err)
}
}

func (h *Handler) handleDelegation(w http.ResponseWriter, r *http.Request) {
var req delegationRequest
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
writeError(w, http.StatusBadRequest, delegationEndpoint, err)
return
}
if req.Amount <= 0 {
writeError(w, http.StatusBadRequest, delegationEndpoint, errors.New("amount must be greater than 0"))
return
}
addr, err := types.ValAddressFromBech32(req.To)
if err != nil {
writeError(w, http.StatusBadRequest, delegationEndpoint, err)
return
}
amount := types.NewInt(req.Amount)

txResp, err := h.state.Delegate(r.Context(), addr, amount, req.GasLimit)
if err != nil {
writeError(w, http.StatusInternalServerError, delegationEndpoint, err)
return
}
resp, err := json.Marshal(txResp)
if err != nil {
writeError(w, http.StatusInternalServerError, delegationEndpoint, err)
return
}
_, err = w.Write(resp)
if err != nil {
log.Errorw("writing response", "endpoint", delegationEndpoint, "err", err)
}
}

func (h *Handler) handleUndelegation(w http.ResponseWriter, r *http.Request) {
var req unbondRequest
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
writeError(w, http.StatusBadRequest, undelegationEndpoint, err)
return
}
if req.Amount <= 0 {
writeError(w, http.StatusBadRequest, undelegationEndpoint, errors.New("amount must be greater than 0"))
return
}
addr, err := types.ValAddressFromBech32(req.From)
if err != nil {
writeError(w, http.StatusBadRequest, undelegationEndpoint, err)
return
}
amount := types.NewInt(req.Amount)

txResp, err := h.state.Undelegate(r.Context(), addr, amount, req.GasLimit)
if err != nil {
writeError(w, http.StatusInternalServerError, undelegationEndpoint, err)
return
}
resp, err := json.Marshal(txResp)
if err != nil {
writeError(w, http.StatusInternalServerError, undelegationEndpoint, err)
return
}
_, err = w.Write(resp)
if err != nil {
log.Errorw("writing response", "endpoint", undelegationEndpoint, "err", err)
}
}

func (h *Handler) handleCancelUnbonding(w http.ResponseWriter, r *http.Request) {
var req cancelUnbondRequest
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
writeError(w, http.StatusBadRequest, cancelUnbondingEndpoint, err)
return
}
if req.Amount <= 0 {
writeError(w, http.StatusBadRequest, cancelUnbondingEndpoint, errors.New("amount must be greater than 0"))
return
}
addr, err := types.ValAddressFromBech32(req.From)
if err != nil {
writeError(w, http.StatusBadRequest, cancelUnbondingEndpoint, err)
return
}
amount := types.NewInt(req.Amount)
height := types.NewInt(req.Height)
txResp, err := h.state.CancelUnbondingDelegation(r.Context(), addr, amount, height, req.GasLimit)
if err != nil {
writeError(w, http.StatusInternalServerError, cancelUnbondingEndpoint, err)
return
}
resp, err := json.Marshal(txResp)
if err != nil {
writeError(w, http.StatusInternalServerError, cancelUnbondingEndpoint, err)
return
}
_, err = w.Write(resp)
if err != nil {
log.Errorw("writing response", "endpoint", cancelUnbondingEndpoint, "err", err)
}
}

func (h *Handler) handleRedelegation(w http.ResponseWriter, r *http.Request) {
var req redelegationRequest
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
writeError(w, http.StatusBadRequest, beginRedelegationEndpoint, err)
return
}
if req.Amount <= 0 {
writeError(w, http.StatusBadRequest, beginRedelegationEndpoint, errors.New("amount must be greater than 0"))
return
}
srcAddr, err := types.ValAddressFromBech32(req.From)
if err != nil {
writeError(w, http.StatusBadRequest, beginRedelegationEndpoint, err)
return
}
dstAddr, err := types.ValAddressFromBech32(req.To)
if err != nil {
writeError(w, http.StatusBadRequest, beginRedelegationEndpoint, err)
return
}
amount := types.NewInt(req.Amount)

txResp, err := h.state.BeginRedelegate(r.Context(), srcAddr, dstAddr, amount, req.GasLimit)
if err != nil {
writeError(w, http.StatusInternalServerError, beginRedelegationEndpoint, err)
return
}
resp, err := json.Marshal(txResp)
if err != nil {
writeError(w, http.StatusInternalServerError, beginRedelegationEndpoint, err)
return
}
_, err = w.Write(resp)
if err != nil {
log.Errorw("writing response", "endpoint", beginRedelegationEndpoint, "err", err)
}
}
99 changes: 99 additions & 0 deletions service/state/core_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
sdktypes "github.com/cosmos/cosmos-sdk/types"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
proofutils "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types"
logging "github.com/ipfs/go-log/v2"
rpcclient "github.com/tendermint/tendermint/rpc/client"
Expand Down Expand Up @@ -233,3 +234,101 @@ func (ca *CoreAccessor) Transfer(
}
return ca.SubmitTx(ctx, signedTx)
}

func (ca *CoreAccessor) CancelUnbondingDelegation(
ctx context.Context,
valAddr Address,
amount,
height Int,
gasLim uint64,
) (*TxResponse, error) {
validator, ok := valAddr.(sdktypes.ValAddress)
if !ok {
return nil, fmt.Errorf("state: unsupported address type")
}
from, err := ca.signer.GetSignerInfo().GetAddress()
if err != nil {
return nil, err
}
coins := sdktypes.NewCoin(app.BondDenom, amount)
msg := stakingtypes.NewMsgCancelUnbondingDelegation(from, validator, height.Int64(), coins)
signedTx, err := ca.constructSignedTx(ctx, msg, apptypes.SetGasLimit(gasLim))
if err != nil {
return nil, err
}
return ca.SubmitTx(ctx, signedTx)
}

func (ca *CoreAccessor) BeginRedelegate(
ctx context.Context,
srcValAddr,
dstValAddr Address,
amount Int,
gasLim uint64,
) (*TxResponse, error) {
srcValidator, ok := srcValAddr.(sdktypes.ValAddress)
if !ok {
return nil, fmt.Errorf("state: unsupported address type")
}
dstValidator, ok := dstValAddr.(sdktypes.ValAddress)
if !ok {
return nil, fmt.Errorf("state: unsupported address type")
}
from, err := ca.signer.GetSignerInfo().GetAddress()
if err != nil {
return nil, err
}
coins := sdktypes.NewCoin(app.BondDenom, amount)
msg := stakingtypes.NewMsgBeginRedelegate(from, srcValidator, dstValidator, coins)
signedTx, err := ca.constructSignedTx(ctx, msg, apptypes.SetGasLimit(gasLim))
if err != nil {
return nil, err
}
return ca.SubmitTx(ctx, signedTx)
}

func (ca *CoreAccessor) Undelegate(
ctx context.Context,
delAddr Address,
amount Int,
gasLim uint64,
) (*TxResponse, error) {
delegate, ok := delAddr.(sdktypes.ValAddress)
if !ok {
return nil, fmt.Errorf("state: unsupported address type")
}
from, err := ca.signer.GetSignerInfo().GetAddress()
if err != nil {
return nil, err
}
coins := sdktypes.NewCoin(app.BondDenom, amount)
msg := stakingtypes.NewMsgUndelegate(from, delegate, coins)
signedTx, err := ca.constructSignedTx(ctx, msg, apptypes.SetGasLimit(gasLim))
if err != nil {
return nil, err
}
return ca.SubmitTx(ctx, signedTx)
}

func (ca *CoreAccessor) Delegate(
ctx context.Context,
delAddr Address,
amount Int,
gasLim uint64,
) (*TxResponse, error) {
delegate, ok := delAddr.(sdktypes.ValAddress)
if !ok {
return nil, fmt.Errorf("state: unsupported address type")
}
from, err := ca.signer.GetSignerInfo().GetAddress()
if err != nil {
return nil, err
}
coins := sdktypes.NewCoin(app.BondDenom, amount)
msg := stakingtypes.NewMsgDelegate(from, delegate, coins)
signedTx, err := ca.constructSignedTx(ctx, msg, apptypes.SetGasLimit(gasLim))
if err != nil {
return nil, err
}
return ca.SubmitTx(ctx, signedTx)
}
9 changes: 9 additions & 0 deletions service/state/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,13 @@ type Accessor interface {
SubmitTx(ctx context.Context, tx Tx) (*TxResponse, error)
// SubmitPayForData builds, signs and submits a PayForData transaction.
SubmitPayForData(ctx context.Context, nID namespace.ID, data []byte, gasLim uint64) (*TxResponse, error)

// CancelUnbondingDelegation cancels a user's pending undelegation from a validator.
CancelUnbondingDelegation(ctx context.Context, valAddr Address, amount, height Int, gasLim uint64) (*TxResponse, error)
// BeginRedelegate sends a user's delegated tokens to a new validator for redelegation.
BeginRedelegate(ctx context.Context, srcValAddr, dstValAddr Address, amount Int, gasLim uint64) (*TxResponse, error)
// Undelegate undelegates a user's delegated tokens, unbonding them from the current validator.
Undelegate(ctx context.Context, delAddr Address, amount Int, gasLim uint64) (*TxResponse, error)
// Delegate sends a user's liquid tokens to a validator for delegation.
Delegate(ctx context.Context, delAddr Address, amount Int, gasLim uint64) (*TxResponse, error)
}
28 changes: 28 additions & 0 deletions service/state/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,34 @@ func (s *Service) Transfer(ctx context.Context, to Address, amount Int, gasLimit
return s.accessor.Transfer(ctx, to, amount, gasLimit)
}

func (s *Service) CancelUnbondingDelegation(
ctx context.Context,
valAddr Address,
amount,
height Int,
gasLim uint64,
) (*TxResponse, error) {
return s.accessor.CancelUnbondingDelegation(ctx, valAddr, amount, height, gasLim)
}

func (s *Service) BeginRedelegate(
ctx context.Context,
srcValAddr,
dstValAddr Address,
amount Int,
gasLim uint64,
) (*TxResponse, error) {
return s.accessor.BeginRedelegate(ctx, srcValAddr, dstValAddr, amount, gasLim)
}

func (s *Service) Undelegate(ctx context.Context, delAddr Address, amount Int, gasLim uint64) (*TxResponse, error) {
return s.accessor.Undelegate(ctx, delAddr, amount, gasLim)
}

func (s *Service) Delegate(ctx context.Context, delAddr Address, amount Int, gasLim uint64) (*TxResponse, error) {
return s.accessor.Delegate(ctx, delAddr, amount, gasLim)
}

func (s *Service) Start(context.Context) error {
s.ctx, s.cancel = context.WithCancel(context.Background())
return nil
Expand Down

0 comments on commit 48109c3

Please sign in to comment.