Skip to content

Commit

Permalink
[action] Add abi encoding in other stake actions (iotexproject#3094)
Browse files Browse the repository at this point in the history
  • Loading branch information
Liuhaai authored Feb 28, 2022
1 parent f048dd3 commit 112ffe5
Show file tree
Hide file tree
Showing 14 changed files with 816 additions and 4 deletions.
140 changes: 140 additions & 0 deletions action/candidate_register.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
package action

import (
"bytes"
"math/big"
"strings"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"

Expand All @@ -23,9 +27,63 @@ const (
CandidateRegisterPayloadGas = uint64(100)
// CandidateRegisterBaseIntrinsicGas represents the base intrinsic gas for CandidateRegister
CandidateRegisterBaseIntrinsicGas = uint64(10000)

candidateRegisterInterfaceABI = `[
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "address",
"name": "operatorAddress",
"type": "address"
},
{
"internalType": "address",
"name": "rewardAddress",
"type": "address"
},
{
"internalType": "address",
"name": "ownerAddress",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "uint32",
"name": "duration",
"type": "uint32"
},
{
"internalType": "bool",
"name": "autoStake",
"type": "bool"
},
{
"internalType": "uint8[]",
"name": "data",
"type": "uint8[]"
}
],
"name": "candidateRegister",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]`
)

var (
// _candidateRegisterInterface is the interface of the abi encoding of stake action
_candidateRegisterMethod abi.Method

// ErrInvalidAmount represents that amount is 0 or negative
ErrInvalidAmount = errors.New("invalid amount")
)
Expand All @@ -44,6 +102,18 @@ type CandidateRegister struct {
payload []byte
}

func init() {
candidateRegisterInterface, err := abi.JSON(strings.NewReader(candidateRegisterInterfaceABI))
if err != nil {
panic(err)
}
var ok bool
_candidateRegisterMethod, ok = candidateRegisterInterface.Methods["candidateRegister"]
if !ok {
panic("fail to load the method")
}
}

// NewCandidateRegister creates a CandidateRegister instance
func NewCandidateRegister(
nonce uint64,
Expand Down Expand Up @@ -221,3 +291,73 @@ func (cr *CandidateRegister) SanityCheck() error {

return cr.AbstractAction.SanityCheck()
}

// EncodeABIBinary encodes data in abi encoding
func (cr *CandidateRegister) EncodeABIBinary() ([]byte, error) {
operatorEthAddr := common.BytesToAddress(cr.operatorAddress.Bytes())
rewardEthAddr := common.BytesToAddress(cr.rewardAddress.Bytes())
ownerEthAddr := common.BytesToAddress(cr.ownerAddress.Bytes())
data, err := _candidateRegisterMethod.Inputs.Pack(
cr.name,
operatorEthAddr,
rewardEthAddr,
ownerEthAddr,
cr.amount,
cr.duration,
cr.autoStake,
cr.payload)
if err != nil {
return nil, err
}
return append(_candidateRegisterMethod.ID, data...), nil
}

// NewCandidateRegisterFromABIBinary decodes data into CandidateRegister action
func NewCandidateRegisterFromABIBinary(data []byte) (*CandidateRegister, error) {
var (
paramsMap = map[string]interface{}{}
ok bool
err error
cr CandidateRegister
)
// sanity check
if len(data) <= 4 || !bytes.Equal(_candidateRegisterMethod.ID, data[:4]) {
return nil, errDecodeFailure
}
if err := _candidateRegisterMethod.Inputs.UnpackIntoMap(paramsMap, data[4:]); err != nil {
return nil, err
}
if cr.name, ok = paramsMap["name"].(string); !ok {
return nil, errDecodeFailure
}
if cr.operatorAddress, err = ethAddrToNativeAddr(paramsMap["operatorAddress"]); err != nil {
return nil, err
}
if cr.rewardAddress, err = ethAddrToNativeAddr(paramsMap["rewardAddress"]); err != nil {
return nil, err
}
if cr.ownerAddress, err = ethAddrToNativeAddr(paramsMap["ownerAddress"]); err != nil {
return nil, err
}
if cr.amount, ok = paramsMap["amount"].(*big.Int); !ok {
return nil, errDecodeFailure
}
if cr.duration, ok = paramsMap["duration"].(uint32); !ok {
return nil, errDecodeFailure
}
if cr.autoStake, ok = paramsMap["autoStake"].(bool); !ok {
return nil, errDecodeFailure
}
if cr.payload, ok = paramsMap["data"].([]byte); !ok {
return nil, errDecodeFailure
}
return &cr, nil
}

func ethAddrToNativeAddr(in interface{}) (address.Address, error) {
ethAddr, ok := in.(common.Address)
if !ok {
return nil, errDecodeFailure
}
return address.FromBytes(ethAddr.Bytes())
}
91 changes: 89 additions & 2 deletions action/candidate_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
package action

import (
"bytes"
"math/big"
"strings"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"

Expand All @@ -18,8 +22,41 @@ import (
"github.com/iotexproject/iotex-proto/golang/iotextypes"
)

// CandidateUpdateBaseIntrinsicGas represents the base intrinsic gas for CandidateUpdate
const CandidateUpdateBaseIntrinsicGas = uint64(10000)
const (
// CandidateUpdateBaseIntrinsicGas represents the base intrinsic gas for CandidateUpdate
CandidateUpdateBaseIntrinsicGas = uint64(10000)

candidateUpdateInterfaceABI = `[
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "address",
"name": "operatorAddress",
"type": "address"
},
{
"internalType": "address",
"name": "rewardAddress",
"type": "address"
}
],
"name": "candidateUpdate",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]`
)

var (
// _candidateUpdateMethod is the interface of the abi encoding of stake action
_candidateUpdateMethod abi.Method
)

// CandidateUpdate is the action to update a candidate
type CandidateUpdate struct {
Expand All @@ -30,6 +67,18 @@ type CandidateUpdate struct {
rewardAddress address.Address
}

func init() {
candidateUpdateInterface, err := abi.JSON(strings.NewReader(candidateUpdateInterfaceABI))
if err != nil {
panic(err)
}
var ok bool
_candidateUpdateMethod, ok = candidateUpdateInterface.Methods["candidateUpdate"]
if !ok {
panic("fail to load the method")
}
}

// NewCandidateUpdate creates a CandidateUpdate instance
func NewCandidateUpdate(
nonce uint64,
Expand Down Expand Up @@ -135,3 +184,41 @@ func (cu *CandidateUpdate) Cost() (*big.Int, error) {
fee := big.NewInt(0).Mul(cu.GasPrice(), big.NewInt(0).SetUint64(intrinsicGas))
return fee, nil
}

// EncodeABIBinary encodes data in abi encoding
func (cu *CandidateUpdate) EncodeABIBinary() ([]byte, error) {
operatorEthAddr := common.BytesToAddress(cu.operatorAddress.Bytes())
rewardEthAddr := common.BytesToAddress(cu.rewardAddress.Bytes())
data, err := _candidateUpdateMethod.Inputs.Pack(cu.name, operatorEthAddr, rewardEthAddr)
if err != nil {
return nil, err
}
return append(_candidateUpdateMethod.ID, data...), nil
}

// NewCandidateUpdateFromABIBinary decodes data into CandidateUpdate action
func NewCandidateUpdateFromABIBinary(data []byte) (*CandidateUpdate, error) {
var (
paramsMap = map[string]interface{}{}
ok bool
err error
cu CandidateUpdate
)
// sanity check
if len(data) <= 4 || !bytes.Equal(_candidateUpdateMethod.ID, data[:4]) {
return nil, errDecodeFailure
}
if err := _candidateUpdateMethod.Inputs.UnpackIntoMap(paramsMap, data[4:]); err != nil {
return nil, err
}
if cu.name, ok = paramsMap["name"].(string); !ok {
return nil, errDecodeFailure
}
if cu.operatorAddress, err = ethAddrToNativeAddr(paramsMap["operatorAddress"]); err != nil {
return nil, err
}
if cu.rewardAddress, err = ethAddrToNativeAddr(paramsMap["rewardAddress"]); err != nil {
return nil, err
}
return &cu, nil
}
20 changes: 20 additions & 0 deletions action/candidateregister_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,23 @@ func TestCandidateRegister(t *testing.T) {
}

}

func TestCandidateRegisterABIEncodeAndDecode(t *testing.T) {
require := require.New(t)
test := candidateRegisterTestParams[0]
stake, err := NewCandidateRegister(test.Nonce, test.Name, test.OperatorAddrStr, test.RewardAddrStr, test.OwnerAddrStr, test.AmountStr, test.Duration, test.AutoStake, test.Payload, test.GasLimit, test.GasPrice)
require.NoError(err)

data, err := stake.EncodeABIBinary()
require.NoError(err)
stake, err = NewCandidateRegisterFromABIBinary(data)
require.NoError(err)
require.Equal(test.Name, stake.Name())
require.Equal(test.OperatorAddrStr, stake.OperatorAddress().String())
require.Equal(test.RewardAddrStr, stake.RewardAddress().String())
require.Equal(test.OwnerAddrStr, stake.OwnerAddress().String())
require.Equal(test.AmountStr, stake.Amount().String())
require.Equal(test.Duration, stake.Duration())
require.Equal(test.AutoStake, stake.AutoStake())
require.Equal(test.Payload, stake.Payload())
}
14 changes: 14 additions & 0 deletions action/candidateupdate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,17 @@ func TestCandidateUpdateSignVerify(t *testing.T) {
// verify signature
require.NoError(Verify(selp))
}

func TestCandidateUpdateABIEncodeAndDecode(t *testing.T) {
require := require.New(t)
stake, err := NewCandidateUpdate(cuNonce, cuName, cuOperatorAddrStr, cuRewardAddrStr, cuGasLimit, cuGasPrice)
require.NoError(err)

data, err := stake.EncodeABIBinary()
require.NoError(err)
stake, err = NewCandidateUpdateFromABIBinary(data)
require.NoError(err)
require.Equal(cuName, stake.Name())
require.Equal(cuOperatorAddrStr, stake.OperatorAddress().String())
require.Equal(cuRewardAddrStr, stake.RewardAddress().String())
}
Loading

0 comments on commit 112ffe5

Please sign in to comment.