Skip to content

Commit

Permalink
go/oasis-node/cmd/stake: Add gen_{allow,withdraw} subcommands
Browse files Browse the repository at this point in the history
  • Loading branch information
kostko committed Dec 10, 2020
1 parent 1cd1fb3 commit 780e576
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 8 deletions.
1 change: 1 addition & 0 deletions .changelog/3511.feature.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
go/oasis-node/cmd/stake: Add gen_{allow,withdraw} subcommands
104 changes: 104 additions & 0 deletions go/oasis-node/cmd/stake/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ const (

// CfgCommissionScheduleBounds configures the commission schedule rate bound steps.
CfgCommissionScheduleBounds = "stake.commission_schedule.bounds"

// CfgAllowBeneficiary configures the beneficiary address.
CfgAllowBeneficiary = "stake.allow.beneficiary"

// CfgAllowAmountChange configures the allowance change.
CfgAllowAmountChange = "stake.allow.amount_change"

// CfgWithdrawSource configures the withdrawal source address.
CfgWithdrawSource = "stake.withdraw.source"
)

var (
Expand All @@ -50,6 +59,8 @@ var (
commissionScheduleFlags = flag.NewFlagSet("", flag.ContinueOnError)
accountTransferFlags = flag.NewFlagSet("", flag.ContinueOnError)
accountBurnFlags = flag.NewFlagSet("", flag.ContinueOnError)
accountAllowFlags = flag.NewFlagSet("", flag.ContinueOnError)
accountWithdrawFlags = flag.NewFlagSet("", flag.ContinueOnError)

accountCmd = &cobra.Command{
Use: "account",
Expand Down Expand Up @@ -97,6 +108,18 @@ var (
Short: "generate an amend commission schedule transaction",
Run: doAccountAmendCommissionSchedule,
}

accountAllowCmd = &cobra.Command{
Use: "gen_allow",
Short: "generate an allow transaction",
Run: doAccountAllow,
}

accountWithdrawCmd = &cobra.Command{
Use: "gen_withdraw",
Short: "generate a withdraw transaction",
Run: doAccountWithdraw,
}
)

// getCtxWithInfo returns a new context with values that contain additional
Expand Down Expand Up @@ -339,6 +362,71 @@ func doAccountAmendCommissionSchedule(cmd *cobra.Command, args []string) {
cmdConsensus.SignAndSaveTx(getCtxWithInfo(genesis), tx, nil)
}

func doAccountAllow(cmd *cobra.Command, args []string) {
if err := cmdCommon.Init(); err != nil {
cmdCommon.EarlyLogAndExit(err)
}

genesis := cmdConsensus.InitGenesis()
cmdConsensus.AssertTxFileOK()

var allow api.Allow
if err := allow.Beneficiary.UnmarshalText([]byte(viper.GetString(CfgAllowBeneficiary))); err != nil {
logger.Error("failed to parse beneficiary account address",
"err", err,
)
os.Exit(1)
}
amountRaw := viper.GetString(CfgAllowAmountChange)
if len(amountRaw) < 1 {
logger.Error("malformed allowance change amount")
os.Exit(1)
}
if amountRaw[0] == '-' {
allow.Negative = true
amountRaw = amountRaw[1:]
}
if err := allow.AmountChange.UnmarshalText([]byte(amountRaw)); err != nil {
logger.Error("failed to parse allowance change amount",
"err", err,
)
os.Exit(1)
}

nonce, fee := cmdConsensus.GetTxNonceAndFee()
tx := api.NewAllowTx(nonce, fee, &allow)

cmdConsensus.SignAndSaveTx(getCtxWithInfo(genesis), tx, nil)
}

func doAccountWithdraw(cmd *cobra.Command, args []string) {
if err := cmdCommon.Init(); err != nil {
cmdCommon.EarlyLogAndExit(err)
}

genesis := cmdConsensus.InitGenesis()
cmdConsensus.AssertTxFileOK()

var withdraw api.Withdraw
if err := withdraw.From.UnmarshalText([]byte(viper.GetString(CfgWithdrawSource))); err != nil {
logger.Error("failed to parse source account address",
"err", err,
)
os.Exit(1)
}
if err := withdraw.Amount.UnmarshalText([]byte(viper.GetString(CfgAmount))); err != nil {
logger.Error("failed to parse withdraw amount",
"err", err,
)
os.Exit(1)
}

nonce, fee := cmdConsensus.GetTxNonceAndFee()
tx := api.NewWithdrawTx(nonce, fee, &withdraw)

cmdConsensus.SignAndSaveTx(getCtxWithInfo(genesis), tx, nil)
}

func registerAccountCmd() {
for _, v := range []*cobra.Command{
accountInfoCmd,
Expand All @@ -348,6 +436,8 @@ func registerAccountCmd() {
accountEscrowCmd,
accountReclaimEscrowCmd,
accountAmendCommissionScheduleCmd,
accountAllowCmd,
accountWithdrawCmd,
} {
accountCmd.AddCommand(v)
}
Expand All @@ -361,6 +451,8 @@ func registerAccountCmd() {
accountReclaimEscrowCmd.Flags().AddFlagSet(commonEscrowFlags)
accountReclaimEscrowCmd.Flags().AddFlagSet(sharesFlags)
accountAmendCommissionScheduleCmd.Flags().AddFlagSet(commissionScheduleFlags)
accountAllowCmd.Flags().AddFlagSet(accountAllowFlags)
accountWithdrawCmd.Flags().AddFlagSet(accountWithdrawFlags)
}

func init() {
Expand Down Expand Up @@ -403,4 +495,16 @@ func init() {
_ = viper.BindPFlags(commissionScheduleFlags)
commissionScheduleFlags.AddFlagSet(cmdConsensus.TxFlags)
commissionScheduleFlags.AddFlagSet(cmdFlags.AssumeYesFlag)

accountAllowFlags.String(CfgAllowBeneficiary, "", "allowance beneficiary address")
accountAllowFlags.String(CfgAllowAmountChange, "0", "allowance change amount (in base units)")
_ = viper.BindPFlags(accountAllowFlags)
accountAllowFlags.AddFlagSet(cmdConsensus.TxFlags)
accountAllowFlags.AddFlagSet(cmdFlags.AssumeYesFlag)

accountWithdrawFlags.String(CfgWithdrawSource, "", "withdraw source address")
_ = viper.BindPFlags(accountWithdrawFlags)
accountWithdrawFlags.AddFlagSet(cmdConsensus.TxFlags)
accountWithdrawFlags.AddFlagSet(amountFlags)
accountWithdrawFlags.AddFlagSet(cmdFlags.AssumeYesFlag)
}
143 changes: 135 additions & 8 deletions go/oasis-test-runner/scenario/e2e/stake_cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"

"github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
fileSigner "github.com/oasisprotocol/oasis-core/go/common/crypto/signature/signers/file"
"github.com/oasisprotocol/oasis-core/go/common/entity"
"github.com/oasisprotocol/oasis-core/go/common/prettyprint"
"github.com/oasisprotocol/oasis-core/go/common/quantity"
Expand All @@ -19,6 +20,7 @@ import (
"github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common/consensus"
"github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common/flags"
"github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common/grpc"
cmdSigner "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common/signer"
"github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/stake"
"github.com/oasisprotocol/oasis-core/go/oasis-test-runner/env"
"github.com/oasisprotocol/oasis-core/go/oasis-test-runner/oasis"
Expand All @@ -43,6 +45,12 @@ const (
// Test reclaim escrow shares.
reclaimEscrowShares = 1234

// Test allowance amount.
allowAmount = 1000

// Test withdraw amount.
withdrawAmount = 500

// Transaction fee amount.
feeAmount = 10

Expand All @@ -63,9 +71,6 @@ var (
// Testing source account address.
srcAddress = api.NewAddress(signature.NewPublicKey(srcPubkeyHex))

// Testing destination account address.
dstAddress = api.NewAddress(signature.NewPublicKey(dstPubkeyHex))

// Testing escrow account address.
escrowAddress = api.NewAddress(signature.NewPublicKey(escrowPubkeyHex))

Expand Down Expand Up @@ -136,13 +141,30 @@ func (sc *stakeCLIImpl) Fixture() (*oasis.NetworkFixture, error) {
MaxRateSteps: 4,
MaxBoundSteps: 12,
},
MaxAllowances: 32,
},
}

return f, nil
}

func (sc *stakeCLIImpl) Run(childEnv *env.Env) error {
// Generate beneficiary entity.
beneficiaryEntityDir, err := childEnv.NewSubDir("beneficiary-entity")
if err != nil {
return fmt.Errorf("failed to create directory: %w", err)
}
signerFactory, err := fileSigner.NewFactory(beneficiaryEntityDir.String(), signature.SignerEntity)
if err != nil {
return fmt.Errorf("failed to generate beneficiary entity: %w", err)
}
_, beneficiarySigner, err := entity.Generate(beneficiaryEntityDir.String(), signerFactory, nil)
if err != nil {
return fmt.Errorf("failed to generate beneficiary entity: %w", err)
}
beneficiaryAddress := api.NewAddress(beneficiarySigner.Public())

// Start the network.
if err := sc.Net.Start(); err != nil {
return err
}
Expand Down Expand Up @@ -195,7 +217,6 @@ func (sc *stakeCLIImpl) Run(childEnv *env.Env) error {
expectError bool
}{
{signature.NewPublicKey(srcPubkeyHex).String(), srcAddress.String(), false},
{signature.NewPublicKey(dstPubkeyHex).String(), dstAddress.String(), false},
{signature.NewPublicKey(escrowPubkeyHex).String(), escrowAddress.String(), false},
// Empty public key.
{"", "", true},
Expand All @@ -214,7 +235,7 @@ func (sc *stakeCLIImpl) Run(childEnv *env.Env) error {
}

// Transfer
if err = sc.testTransfer(childEnv, cli, srcAddress, dstAddress); err != nil {
if err = sc.testTransfer(childEnv, cli, srcAddress, beneficiaryAddress); err != nil {
return fmt.Errorf("error while running Transfer test: %w", err)
}

Expand All @@ -235,7 +256,12 @@ func (sc *stakeCLIImpl) Run(childEnv *env.Env) error {

// AmendCommissionSchedule
if err = sc.testAmendCommissionSchedule(childEnv, cli, srcAddress); err != nil {
return fmt.Errorf("error while running AmendCommissionSchedule: %w", err)
return fmt.Errorf("error while running AmendCommissionSchedule test: %w", err)
}

// Allow and Withdraw
if err = sc.testAllowWithdraw(childEnv, cli, srcAddress, beneficiaryAddress, beneficiaryEntityDir.String()); err != nil {
return fmt.Errorf("error while running AllowWithdraw test: %w", err)
}

// Stop the network.
Expand Down Expand Up @@ -569,6 +595,63 @@ func (sc *stakeCLIImpl) testAmendCommissionSchedule(childEnv *env.Env, cli *cli.
return nil
}

// testAllowWithdraw tests setting an allowance and withdrawing.
func (sc *stakeCLIImpl) testAllowWithdraw(childEnv *env.Env, cli *cli.Helpers, src, beneficiary api.Address, beneficiaryEntityDir string) error {
var srcNonce uint64 = 5
ctx := contextWithTokenInfo()

// Set allowance.
allowTxPath := filepath.Join(childEnv.Dir(), "stake_allow.json")
if err := sc.genAllowTx(childEnv, allowAmount, srcNonce, beneficiary, allowTxPath); err != nil {
return err
}
if err := sc.showTx(childEnv, allowTxPath); err != nil {
return err
}

if err := cli.Consensus.SubmitTx(allowTxPath); err != nil {
return fmt.Errorf("failed to submit Allow tx: %w", err)
}

// Withdraw.
withdrawTxPath := filepath.Join(childEnv.Dir(), "stake_withdraw.json")
if err := sc.genWithdrawTx(childEnv, withdrawAmount, 0, src, beneficiaryEntityDir, withdrawTxPath); err != nil {
return err
}
if err := sc.showTx(childEnv, withdrawTxPath); err != nil {
return err
}

if err := cli.Consensus.SubmitTx(withdrawTxPath); err != nil {
return fmt.Errorf("failed to submit Withdraw tx: %w", err)
}

// Check source general balance.
expectedGeneralBalance := mustInitQuantity(
initBalance - transferAmount - burnAmount - escrowAmount + reclaimEscrowAmount - withdrawAmount - 6*feeAmount,
)
if err := sc.checkGeneralAccount(ctx, childEnv, src, &api.GeneralAccount{
Balance: expectedGeneralBalance,
Nonce: srcNonce + 1,
Allowances: map[api.Address]quantity.Quantity{
beneficiary: mustInitQuantity(allowAmount - withdrawAmount),
},
}); err != nil {
return err
}
// Check beneficiary general balance.
expectedGeneralBalance = mustInitQuantity(
transferAmount - feeAmount + withdrawAmount,
)
if err := sc.checkGeneralAccount(
ctx, childEnv, beneficiary, &api.GeneralAccount{Balance: expectedGeneralBalance, Nonce: 1},
); err != nil {
return err
}

return nil
}

func (sc *stakeCLIImpl) getInfo(childEnv *env.Env) error {
sc.Logger.Info("querying common staking info")
args := []string{
Expand Down Expand Up @@ -668,7 +751,7 @@ func (sc *stakeCLIImpl) checkGeneralAccount(
match := regexp.MustCompile(regexPattern).FindStringSubmatch(accountInfo)
if match == nil {
return fmt.Errorf(
"checkGeneralAccount: couldn't find expected general account %+v in account info", expectedAccount,
"checkGeneralAccount: couldn't find expected general account %+v in account info: %s", expectedAccount, accountInfo,
)
}

Expand Down Expand Up @@ -841,7 +924,7 @@ func (sc *stakeCLIImpl) genBurnTx(childEnv *env.Env, amount int, nonce uint64, t
}

func (sc *stakeCLIImpl) genEscrowTx(childEnv *env.Env, amount int, nonce uint64, escrow api.Address, txPath string) error {
sc.Logger.Info("generating stake escrow tx", "stake.CfgEscrowAccount", escrow)
sc.Logger.Info("generating stake escrow tx", stake.CfgEscrowAccount, escrow)

args := []string{
"stake", "account", "gen_escrow",
Expand Down Expand Up @@ -909,3 +992,47 @@ func (sc *stakeCLIImpl) genAmendCommissionScheduleTx(childEnv *env.Env, nonce ui
}
return nil
}

func (sc *stakeCLIImpl) genAllowTx(childEnv *env.Env, amount int, nonce uint64, beneficiary api.Address, txPath string) error {
sc.Logger.Info("generating stake allow tx", stake.CfgAllowBeneficiary, beneficiary)

args := []string{
"stake", "account", "gen_allow",
"--" + consensus.CfgTxNonce, strconv.FormatUint(nonce, 10),
"--" + consensus.CfgTxFile, txPath,
"--" + stake.CfgAllowAmountChange, strconv.Itoa(amount),
"--" + stake.CfgAllowBeneficiary, beneficiary.String(),
"--" + consensus.CfgTxFeeAmount, strconv.Itoa(feeAmount),
"--" + consensus.CfgTxFeeGas, strconv.Itoa(feeGas),
"--" + flags.CfgDebugDontBlameOasis,
"--" + flags.CfgDebugTestEntity,
"--" + common.CfgDebugAllowTestKeys,
"--" + flags.CfgGenesisFile, sc.Net.GenesisPath(),
}
if out, err := cli.RunSubCommandWithOutput(childEnv, sc.Logger, "gen_allow", sc.Net.Config().NodeBinary, args); err != nil {
return fmt.Errorf("genAllowTx: failed to generate allow tx: error: %w output: %s", err, out.String())
}
return nil
}

func (sc *stakeCLIImpl) genWithdrawTx(childEnv *env.Env, amount int, nonce uint64, src api.Address, entityDir, txPath string) error {
sc.Logger.Info("generating stake withdraw tx", stake.CfgWithdrawSource, src)

args := []string{
"stake", "account", "gen_withdraw",
"--" + consensus.CfgTxNonce, strconv.FormatUint(nonce, 10),
"--" + consensus.CfgTxFile, txPath,
"--" + stake.CfgAmount, strconv.Itoa(amount),
"--" + stake.CfgWithdrawSource, src.String(),
"--" + consensus.CfgTxFeeAmount, strconv.Itoa(feeAmount),
"--" + consensus.CfgTxFeeGas, strconv.Itoa(feeGas),
"--" + flags.CfgDebugDontBlameOasis,
"--" + common.CfgDebugAllowTestKeys,
"--" + cmdSigner.CfgCLISignerDir, entityDir,
"--" + flags.CfgGenesisFile, sc.Net.GenesisPath(),
}
if out, err := cli.RunSubCommandWithOutput(childEnv, sc.Logger, "gen_withdraw", sc.Net.Config().NodeBinary, args); err != nil {
return fmt.Errorf("genAllowTx: failed to generate withdraw tx: error: %w output: %s", err, out.String())
}
return nil
}

0 comments on commit 780e576

Please sign in to comment.