Skip to content

Commit

Permalink
[api] web3 rewarding action (#3691)
Browse files Browse the repository at this point in the history
* add rewarding execute action

* add rewarding execute test

* add commmet for public type

* add builder test

* complete web3 rewarding read

* complete web3 rewarding read test

* remove read api and receive create rewarding action enterance

* add test to rlp tx test

* change name

* revert fix amount bug for deposit cost bug

* change check error style

* add entrance for web3 rewarding

Co-authored-by: dustinxie <dahuaxie@gmail.com>
  • Loading branch information
ququzone and dustinxie authored Dec 22, 2022
1 parent 09ece37 commit 308c59d
Show file tree
Hide file tree
Showing 8 changed files with 559 additions and 1 deletion.
30 changes: 29 additions & 1 deletion action/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ type Builder struct {
}

var (
_stakingProtocolAddr, _ = address.FromString(address.StakingProtocolAddr)
_stakingProtocolAddr, _ = address.FromString(address.StakingProtocolAddr)
_rewardingProtocolAddr, _ = address.FromString(address.RewardingProtocol)
)

// SetVersion sets action's version.
Expand Down Expand Up @@ -202,6 +203,20 @@ func (b *EnvelopeBuilder) BuildStakingAction(tx *types.Transaction) (Envelope, e
return b.build(), nil
}

// BuildRewardingAction loads rewarding action into envelope from abi-encoded data
func (b *EnvelopeBuilder) BuildRewardingAction(tx *types.Transaction) (Envelope, error) {
if !bytes.Equal(tx.To().Bytes(), _rewardingProtocolAddr.Bytes()) {
return nil, ErrInvalidAct
}
b.setEnvelopeCommonFields(tx)
act, err := newRewardingActionFromABIBinary(tx.Data())
if err != nil {
return nil, err
}
b.elp.payload = act
return b.build(), nil
}

func newStakingActionFromABIBinary(data []byte) (actionPayload, error) {
if len(data) <= 4 {
return nil, ErrInvalidABI
Expand Down Expand Up @@ -235,3 +250,16 @@ func newStakingActionFromABIBinary(data []byte) (actionPayload, error) {
}
return nil, ErrInvalidABI
}

func newRewardingActionFromABIBinary(data []byte) (actionPayload, error) {
if len(data) <= 4 {
return nil, ErrInvalidABI
}
if act, err := NewClaimFromRewardingFundFromABIBinary(data); err == nil {
return act, nil
}
if act, err := NewDepositToRewardingFundFromABIBinary(data); err == nil {
return act, nil
}
return nil, ErrInvalidABI
}
41 changes: 41 additions & 0 deletions action/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@
package action

import (
"encoding/hex"
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/iotexproject/iotex-core/pkg/version"
)
Expand All @@ -27,3 +31,40 @@ func TestActionBuilder(t *testing.T) {
assert.Equal(t, uint64(10003), act.GasLimit())
assert.Equal(t, big.NewInt(10004), act.GasPrice())
}

func TestBuildRewardingAction(t *testing.T) {
r := require.New(t)

eb := &EnvelopeBuilder{}
eb.SetChainID(2)

claimData, _ := hex.DecodeString("2df163ef000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000")
tx := types.NewTransaction(1, common.HexToAddress("0x0000000000000000000000000000000000000001"), big.NewInt(100), 10000, big.NewInt(10004), claimData)

env, err := eb.BuildRewardingAction(tx)
r.Nil(env)
r.EqualValues("invalid action type", err.Error())

tx = types.NewTransaction(1, common.HexToAddress(_rewardingProtocolAddr.Hex()), big.NewInt(100), 10000, big.NewInt(10004), claimData)
env, err = eb.BuildRewardingAction(tx)
r.Nil(err)
r.IsType(&ClaimFromRewardingFund{}, env.Action())
r.EqualValues(big.NewInt(10004), env.GasPrice())
r.EqualValues(10000, env.GasLimit())
r.EqualValues(big.NewInt(101), env.Action().(*ClaimFromRewardingFund).Amount())

depositData, _ := hex.DecodeString("27852a6b000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003")
tx = types.NewTransaction(1, common.HexToAddress("0x0000000000000000000000000000000000000001"), big.NewInt(100), 10000, big.NewInt(10004), depositData)

env, err = eb.BuildRewardingAction(tx)
r.Nil(env)
r.EqualValues("invalid action type", err.Error())

tx = types.NewTransaction(1, common.HexToAddress(_rewardingProtocolAddr.Hex()), big.NewInt(100), 10000, big.NewInt(10004), depositData)
env, err = eb.BuildRewardingAction(tx)
r.Nil(err)
r.IsType(&DepositToRewardingFund{}, env.Action())
r.EqualValues(big.NewInt(10004), env.GasPrice())
r.EqualValues(10000, env.GasLimit())
r.EqualValues(big.NewInt(101), env.Action().(*DepositToRewardingFund).Amount())
}
87 changes: 87 additions & 0 deletions action/claimreward.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,63 @@
package action

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

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

"github.com/iotexproject/iotex-address/address"
"github.com/iotexproject/iotex-core/pkg/util/byteutil"
"github.com/iotexproject/iotex-proto/golang/iotextypes"
)

const _claimRewardingInterfaceABI = `[
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "uint8[]",
"name": "data",
"type": "uint8[]"
}
],
"name": "claim",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]`

var (
// ClaimFromRewardingFundBaseGas represents the base intrinsic gas for claimFromRewardingFund
ClaimFromRewardingFundBaseGas = uint64(10000)
// ClaimFromRewardingFundGasPerByte represents the claimFromRewardingFund payload gas per uint
ClaimFromRewardingFundGasPerByte = uint64(100)

_claimRewardingMethod abi.Method
)

func init() {
claimRewardInterface, err := abi.JSON(strings.NewReader(_claimRewardingInterfaceABI))
if err != nil {
panic(err)
}
var ok bool
_claimRewardingMethod, ok = claimRewardInterface.Methods["claim"]
if !ok {
panic("fail to load the claim method")
}
}

// ClaimFromRewardingFund is the action to claim reward from the rewarding fund
type ClaimFromRewardingFund struct {
AbstractAction
Expand Down Expand Up @@ -108,3 +149,49 @@ func (b *ClaimFromRewardingFundBuilder) Build() ClaimFromRewardingFund {
b.claim.AbstractAction = b.Builder.Build()
return b.claim
}

// encodeABIBinary encodes data in abi encoding
func (c *ClaimFromRewardingFund) encodeABIBinary() ([]byte, error) {
data, err := _claimRewardingMethod.Inputs.Pack(c.Amount(), c.Data())
if err != nil {
return nil, err
}
return append(_claimRewardingMethod.ID, data...), nil
}

// ToEthTx converts action to eth-compatible tx
func (c *ClaimFromRewardingFund) ToEthTx() (*types.Transaction, error) {
addr, err := address.FromString(address.RewardingProtocol)
if err != nil {
return nil, err
}
ethAddr := common.BytesToAddress(addr.Bytes())
data, err := c.encodeABIBinary()
if err != nil {
return nil, err
}
return types.NewTransaction(c.Nonce(), ethAddr, big.NewInt(0), c.GasLimit(), c.GasPrice(), data), nil
}

// NewClaimFromRewardingFundFromABIBinary decodes data into action
func NewClaimFromRewardingFundFromABIBinary(data []byte) (*ClaimFromRewardingFund, error) {
var (
paramsMap = map[string]interface{}{}
ok bool
ac ClaimFromRewardingFund
)
// sanity check
if len(data) <= 4 || !bytes.Equal(_claimRewardingMethod.ID[:], data[:4]) {
return nil, errDecodeFailure
}
if err := _claimRewardingMethod.Inputs.UnpackIntoMap(paramsMap, data[4:]); err != nil {
return nil, err
}
if ac.amount, ok = paramsMap["amount"].(*big.Int); !ok {
return nil, errDecodeFailure
}
if ac.data, ok = paramsMap["data"].([]byte); !ok {
return nil, errDecodeFailure
}
return &ac, nil
}
146 changes: 146 additions & 0 deletions action/claimreward_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package action

import (
"encoding/hex"
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/iotexproject/iotex-address/address"
"github.com/stretchr/testify/require"
)

var (
_defaultGasPrice = big.NewInt(1000000000000)
_errNegativeNumberMsg = "negative value"
)

func TestClaimRewardSerialize(t *testing.T) {
r := require.New(t)

rc := &ClaimFromRewardingFund{}
data := rc.Serialize()
r.NotNil(data)

rc.amount = big.NewInt(100)
rc.data = []byte{1}
data = rc.Serialize()
r.NotNil(data)
r.EqualValues("0a03313030120101", hex.EncodeToString(data))
}

func TestClaimRewardIntrinsicGas(t *testing.T) {
r := require.New(t)

rc := &ClaimFromRewardingFund{}
gas, err := rc.IntrinsicGas()
r.NoError(err)
r.EqualValues(10000, gas)

rc.amount = big.NewInt(100000000)
gas, err = rc.IntrinsicGas()
r.NoError(err)
r.EqualValues(10000, gas)

rc.data = []byte{1}
gas, err = rc.IntrinsicGas()
r.NoError(err)
r.EqualValues(10100, gas)
}

func TestClaimRewardSanityCheck(t *testing.T) {
r := require.New(t)

rc := &ClaimFromRewardingFund{}

rc.amount = big.NewInt(1)
err := rc.SanityCheck()
r.NoError(err)

rc.amount = big.NewInt(-1)
err = rc.SanityCheck()
r.NotNil(err)
r.EqualValues(_errNegativeNumberMsg, err.Error())
}

func TestClaimRewardCost(t *testing.T) {
r := require.New(t)

rc := &ClaimFromRewardingFund{}
rc.gasPrice = _defaultGasPrice
cost, err := rc.Cost()
r.Nil(err)
r.EqualValues("10000000000000000", cost.String())

rc.amount = big.NewInt(100)
cost, err = rc.Cost()
r.Nil(err)
r.EqualValues("10000000000000000", cost.String())

rc.data = []byte{1}
cost, err = rc.Cost()
r.Nil(err)
r.EqualValues("10100000000000000", cost.String())
}

func TestClaimRewardEncodeABIBinary(t *testing.T) {
r := require.New(t)

rc := &ClaimFromRewardingFund{}
rc.amount = big.NewInt(101)
data, err := rc.encodeABIBinary()
r.Nil(err)
r.EqualValues(
"2df163ef000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000",
hex.EncodeToString(data),
)

rc.data = []byte{1, 2, 3}
data, err = rc.encodeABIBinary()
r.Nil(err)
r.EqualValues(
"2df163ef000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
hex.EncodeToString(data),
)
}

func TestClaimRewardToEthTx(t *testing.T) {
r := require.New(t)

rewardingPool, _ := address.FromString(address.RewardingProtocol)
rewardEthAddr := common.BytesToAddress(rewardingPool.Bytes())

rc := &ClaimFromRewardingFund{}

rc.amount = big.NewInt(101)
tx, err := rc.ToEthTx()
r.Nil(err)
r.EqualValues(rewardEthAddr, *tx.To())
r.EqualValues(
"2df163ef000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000",
hex.EncodeToString(tx.Data()),
)
r.EqualValues("0", tx.Value().String())

rc.data = []byte{1, 2, 3}
tx, err = rc.ToEthTx()
r.Nil(err)
r.EqualValues(rewardEthAddr, *tx.To())
r.EqualValues(
"2df163ef000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
hex.EncodeToString(tx.Data()),
)
r.EqualValues("0", tx.Value().String())
}

func TestNewRewardingClaimFromABIBinary(t *testing.T) {
r := require.New(t)

data, _ := hex.DecodeString("2df163ef000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003")

rc, err := NewClaimFromRewardingFundFromABIBinary(data)
r.Nil(err)
r.IsType(&ClaimFromRewardingFund{}, rc)
r.EqualValues("101", rc.Amount().String())
r.EqualValues([]byte{1, 2, 3}, rc.Data())
}
Loading

0 comments on commit 308c59d

Please sign in to comment.