Skip to content

Commit

Permalink
Merge pull request #78 from lzxm160/762
Browse files Browse the repository at this point in the history
support native staking v2 76
  • Loading branch information
coderbradlee authored Apr 21, 2020
2 parents a42b249 + 6db4e71 commit fcb1b3b
Show file tree
Hide file tree
Showing 7 changed files with 327 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0
github.com/iotexproject/go-pkgs v0.1.1
github.com/iotexproject/iotex-address v0.2.1
github.com/iotexproject/iotex-proto v0.2.1-0.20190814190638-f74c55ffedf5
github.com/iotexproject/iotex-proto v0.2.6-0.20200409230611-748f6ab69ca5
github.com/pkg/errors v0.8.1
github.com/stretchr/testify v1.3.0
google.golang.org/grpc v1.20.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ github.com/iotexproject/iotex-address v0.2.1 h1:ZJH2ajx5OBrbaRJ0ZWlWUo685zr5kjWi
github.com/iotexproject/iotex-address v0.2.1/go.mod h1:ONmTqmg6zO7VWF9TcWN+UrreFr/xpazlv9PWOALbLFA=
github.com/iotexproject/iotex-proto v0.2.1-0.20190814190638-f74c55ffedf5 h1:iHfM1nRVDpY8cvyp/Ixtawpt8VxfN9XnzleC9UWM2EE=
github.com/iotexproject/iotex-proto v0.2.1-0.20190814190638-f74c55ffedf5/go.mod h1:962P5o0qlB5sqRT07TJBMX31i2u309kzDqqwCg+cGz0=
github.com/iotexproject/iotex-proto v0.2.6-0.20200409230611-748f6ab69ca5 h1:ggKAkpi4j0aDPnLS5tIgZcfr6MKrWbnDScnqZ4NsyEU=
github.com/iotexproject/iotex-proto v0.2.6-0.20200409230611-748f6ab69ca5/go.mod h1:xKA4yUbg208k1j3+t10Pe7IzT6uHcP+/4rsDanF4Q58=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
Expand Down
186 changes: 186 additions & 0 deletions iotex/caller_staking.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// Copyright (c) 2020 IoTeX
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.

package iotex

import (
"context"
"math/big"

"google.golang.org/grpc"

"github.com/iotexproject/go-pkgs/hash"
"github.com/iotexproject/iotex-address/address"
"github.com/iotexproject/iotex-proto/golang/iotexapi"
"github.com/iotexproject/iotex-proto/golang/iotextypes"

"github.com/iotexproject/iotex-antenna-go/v2/account"
)

type (
stakingBase struct {
account account.Account
api iotexapi.APIServiceClient
payload []byte
gasLimit *uint64
gasPrice *big.Int
nonce *uint64
action interface{}
}
stakingCaller struct {
stakingBase
}
candidateCaller struct {
stakingBase
}
)

//Create Staking
func (c *stakingCaller) Create(candidateName string, amount *big.Int, duration uint32, autoStake bool) StakingAPICaller {
tx := &iotextypes.StakeCreate{
CandidateName: candidateName,
StakedDuration: duration,
AutoStake: autoStake,
StakedAmount: amount.String(),
}
c.stakingBase.action = tx
return c
}

//Unstake Staking
func (c *stakingCaller) Unstake(bucketIndex uint64) StakingAPICaller {
tx := &iotextypes.StakeReclaim{
BucketIndex: bucketIndex,
}
unstake := &reclaim{tx, false}
c.stakingBase.action = unstake
return c
}

//Withdraw Staking
func (c *stakingCaller) Withdraw(bucketIndex uint64) StakingAPICaller {
tx := &iotextypes.StakeReclaim{
BucketIndex: bucketIndex,
}
withdraw := &reclaim{tx, true}
c.stakingBase.action = withdraw
return c
}

//AddDeposit Staking
func (c *stakingCaller) AddDeposit(index uint64, amount *big.Int) StakingAPICaller {
tx := &iotextypes.StakeAddDeposit{
BucketIndex: index,
Amount: amount.String(),
}
c.stakingBase.action = tx
return c
}

//ChangeCandidate Staking
func (c *stakingCaller) ChangeCandidate(candName string, bucketIndex uint64) StakingAPICaller {
tx := &iotextypes.StakeChangeCandidate{
CandidateName: candName,
BucketIndex: bucketIndex,
}
c.stakingBase.action = tx
return c
}

//StakingTransfer Staking
func (c *stakingCaller) StakingTransfer(voterAddress address.Address, bucketIndex uint64) StakingAPICaller {
tx := &iotextypes.StakeTransferOwnership{
VoterAddress: voterAddress.String(),
BucketIndex: bucketIndex,
}
c.stakingBase.action = tx
return c
}

//Restake Staking
func (c *stakingCaller) Restake(index uint64, duration uint32, autoStake bool) StakingAPICaller {
tx := &iotextypes.StakeRestake{
BucketIndex: index,
StakedDuration: duration,
AutoStake: autoStake,
}
c.stakingBase.action = tx
return c
}

//Register Staking
func (c *candidateCaller) Register(name, operatorAddr, rewardAddr address.Address, amount *big.Int, duration uint32, autoStake bool) StakingAPICaller {
basic := &iotextypes.CandidateBasicInfo{
Name: name.String(),
OperatorAddress: operatorAddr.String(),
RewardAddress: rewardAddr.String(),
}
tx := &iotextypes.CandidateRegister{
Candidate: basic,
StakedAmount: amount.String(),
StakedDuration: duration,
AutoStake: autoStake,
}
c.stakingBase.action = tx
return c
}

//Update Staking
func (c *candidateCaller) Update(name string, operatorAddr, rewardAddr address.Address) StakingAPICaller {
tx := &iotextypes.CandidateBasicInfo{
Name: name,
OperatorAddress: operatorAddr.String(),
RewardAddress: rewardAddr.String(),
}
c.stakingBase.action = tx
return c
}

//SetGasLimit set basic data
func (c *stakingBase) SetGasLimit(g uint64) StakingAPICaller {
c.gasLimit = &g
return c
}

//SetGasPrice set basic data
func (c *stakingBase) SetGasPrice(g *big.Int) StakingAPICaller {
c.gasPrice = g
return c
}

//SetNonce set basic data
func (c *stakingBase) SetNonce(n uint64) StakingAPICaller {
c.nonce = &n
return c
}

//SetPayload set basic data
func (c *stakingBase) SetPayload(pl []byte) StakingAPICaller {
if pl == nil {
return c
}
c.payload = make([]byte, len(pl))
copy(c.payload, pl)
return c
}

//API returns api
func (c *stakingBase) API() iotexapi.APIServiceClient {
return c.api
}

//Call call sendActionCaller
func (c *stakingBase) Call(ctx context.Context, opts ...grpc.CallOption) (hash.Hash256, error) {
sc := &sendActionCaller{
account: c.account,
api: c.api,
gasLimit: c.gasLimit,
gasPrice: c.gasPrice,
nonce: c.nonce,
action: c.action,
}
return sc.Call(ctx, opts...)
}
64 changes: 64 additions & 0 deletions iotex/caller_staking_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package iotex

import (
"context"
"math/big"
"testing"
"time"

"github.com/stretchr/testify/require"

"github.com/iotexproject/go-pkgs/hash"
"github.com/iotexproject/iotex-address/address"
"github.com/iotexproject/iotex-proto/golang/iotexapi"
"github.com/iotexproject/iotex-proto/golang/iotextypes"

"github.com/iotexproject/iotex-antenna-go/v2/account"
"github.com/iotexproject/iotex-antenna-go/v2/utils/unit"
)

func TestStake(t *testing.T) {
require := require.New(t)
conn, err := NewDefaultGRPCConn(_testnet)
require.NoError(err)
defer conn.Close()

acc, err := account.HexStringToAccount(_accountPrivateKey)
require.NoError(err)
c := NewAuthedClient(iotexapi.NewAPIServiceClient(conn), acc)
name, _ := address.FromString("io10a298zmzvrt4guq79a9f4x7qedj59y7ery84he")
operator, _ := address.FromString("io10a298zmzvrt4guq79a9f4x7qedj59y7ery84he")
reward, _ := address.FromString("io10a298zmzvrt4guq79a9f4x7qedj59y7ery84he")

// CandidateRegister
ret, err := c.Candidate().Register(name, operator, reward, big.NewInt(1), 10, false).SetGasPrice(big.NewInt(int64(unit.Qev))).SetGasLimit(1000000).SetPayload([]byte("payload")).Call(context.Background())
require.Error(err)
require.Equal(hash.ZeroHash256, ret)

// need to fix when testnet ready
//time.Sleep(time.Second * 20)
//receipt, err := c.GetReceipt(ret).Call(context.Background())
//require.NoError(err)
//require.Equal(iotextypes.ReceiptStatus_Success, receipt.ReceiptInfo.Receipt.Status)

// StakeCreate
ret, err = c.Staking().Create("io19d0p3ah4g8ww9d7kcxfq87yxe7fnr8rpth5shj", big.NewInt(100), uint32(10000), true).SetGasPrice(big.NewInt(int64(unit.Qev))).SetGasLimit(1000000).SetPayload([]byte("payload")).Call(context.Background())
require.Error(err)
require.Equal(hash.ZeroHash256, ret)

// need to fix when testnet ready
//time.Sleep(time.Second * 10)
//receipt, err = c.GetReceipt(hash).Call(context.Background())
//require.NoError(err)
//require.Equal(iotextypes.ReceiptStatus_Success, receipt.ReceiptInfo.Receipt.Status)

// StakeUnstake
ret, err = c.Staking().Unstake(1).SetGasPrice(big.NewInt(int64(unit.Qev))).SetGasLimit(1000000).SetPayload([]byte("payload")).Call(context.Background())
require.NoError(err)
require.NotEqual(hash.ZeroHash256, ret)
// need to fix when testnet ready
time.Sleep(time.Second * 10)
receipt, err := c.GetReceipt(ret).Call(context.Background())
require.NoError(err)
require.NotEqual(iotextypes.ReceiptStatus_Success, receipt.ReceiptInfo.Receipt.Status)
}
27 changes: 27 additions & 0 deletions iotex/callers.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ type sendActionCaller struct {
nonce *uint64
}

// reclaim type to differentiate unstake and withdraw
type reclaim struct {
action interface{}
isWithdraw bool
}

func (c *sendActionCaller) Call(ctx context.Context, opts ...grpc.CallOption) (hash.Hash256, error) {
if c.nonce == nil {
res, err := c.api.GetAccount(ctx, &iotexapi.GetAccountRequest{Address: c.account.Address().String()}, opts...)
Expand All @@ -55,6 +61,27 @@ func (c *sendActionCaller) Call(ctx context.Context, opts ...grpc.CallOption) (h
core.Action = &iotextypes.ActionCore_Transfer{Transfer: a}
case *iotextypes.ClaimFromRewardingFund:
core.Action = &iotextypes.ActionCore_ClaimFromRewardingFund{ClaimFromRewardingFund: a}
case *iotextypes.StakeCreate:
core.Action = &iotextypes.ActionCore_StakeCreate{StakeCreate: a}
// special reclaim type to differentiate unstake and withdraw
case *reclaim:
if a.isWithdraw {
core.Action = &iotextypes.ActionCore_StakeWithdraw{StakeWithdraw: a.action.(*iotextypes.StakeReclaim)}
} else {
core.Action = &iotextypes.ActionCore_StakeUnstake{StakeUnstake: a.action.(*iotextypes.StakeReclaim)}
}
case *iotextypes.StakeAddDeposit:
core.Action = &iotextypes.ActionCore_StakeAddDeposit{StakeAddDeposit: a}
case *iotextypes.StakeRestake:
core.Action = &iotextypes.ActionCore_StakeRestake{StakeRestake: a}
case *iotextypes.StakeTransferOwnership:
core.Action = &iotextypes.ActionCore_StakeTransferOwnership{StakeTransferOwnership: a}
case *iotextypes.StakeChangeCandidate:
core.Action = &iotextypes.ActionCore_StakeChangeCandidate{StakeChangeCandidate: a}
case *iotextypes.CandidateRegister:
core.Action = &iotextypes.ActionCore_CandidateRegister{CandidateRegister: a}
case *iotextypes.CandidateBasicInfo:
core.Action = &iotextypes.ActionCore_CandidateUpdate{CandidateUpdate: a}
default:
return hash.ZeroHash256, errcodes.New("not support action call", errcodes.InternalError)
}
Expand Down
18 changes: 18 additions & 0 deletions iotex/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,24 @@ func (c *authedClient) DeployContract(data []byte) DeployContractCaller {
}
}

//Staking interface
func (c *authedClient) Staking() StakingCaller {
return &stakingCaller{
stakingBase{
account: c.account,
api: c.api,
}}
}

//Candidate interface
func (c *authedClient) Candidate() CandidateCaller {
return &candidateCaller{
stakingBase{
account: c.account,
api: c.api,
}}
}

func (c *authedClient) Account() account.Account { return c.account }

// NewReadOnlyClient creates a ReadOnlyClient.
Expand Down
29 changes: 29 additions & 0 deletions iotex/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ type AuthedClient interface {
Transfer(to address.Address, value *big.Int) TransferCaller
ClaimReward(value *big.Int) ClaimRewardCaller
DeployContract(data []byte) DeployContractCaller
// staking related
Staking() StakingCaller
Candidate() CandidateCaller
Account() account.Account
}

Expand Down Expand Up @@ -103,3 +106,29 @@ type Contract interface {
type ReadOnlyContract interface {
Read(method string, args ...interface{}) ReadContractCaller
}

// StakingCaller is used to perform a staking call.
type StakingCaller interface {
Create(candidateName string, amount *big.Int, duration uint32, autoStake bool) StakingAPICaller
Unstake(bucketIndex uint64) StakingAPICaller
Withdraw(bucketIndex uint64) StakingAPICaller
AddDeposit(index uint64, amount *big.Int) StakingAPICaller
ChangeCandidate(candName string, bucketIndex uint64) StakingAPICaller
StakingTransfer(voterAddress address.Address, bucketIndex uint64) StakingAPICaller
Restake(index uint64, duration uint32, autoStake bool) StakingAPICaller
}

// CandidateCaller is used to perform a candidate call.
type CandidateCaller interface {
Register(name, operatorAddr, rewardAddr address.Address, amount *big.Int, duration uint32, autoStake bool) StakingAPICaller
Update(name string, operatorAddr, rewardAddr address.Address) StakingAPICaller
}

// StakingAPICaller is used to perform extra info call.
type StakingAPICaller interface {
SendActionCaller
SetGasPrice(*big.Int) StakingAPICaller
SetGasLimit(uint64) StakingAPICaller
SetNonce(uint64) StakingAPICaller
SetPayload([]byte) StakingAPICaller
}

0 comments on commit fcb1b3b

Please sign in to comment.