github.com/iotexproject/iotex-core@v1.14.1-rc1/action/builder.go (about)

     1  // Copyright (c) 2019 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package action
     7  
     8  import (
     9  	"bytes"
    10  	"math/big"
    11  
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/ethereum/go-ethereum/core/types"
    14  	"github.com/iotexproject/iotex-address/address"
    15  
    16  	"github.com/iotexproject/iotex-core/pkg/version"
    17  )
    18  
    19  var (
    20  	_stakingProtocolEthAddr   = common.BytesToAddress(address.StakingProtocolAddrHash[:])
    21  	_rewardingProtocolEthAddr = common.BytesToAddress(address.RewardingProtocolAddrHash[:])
    22  )
    23  
    24  // Builder is used to build an action.
    25  type Builder struct {
    26  	act AbstractAction
    27  }
    28  
    29  // SetVersion sets action's version.
    30  func (b *Builder) SetVersion(v uint32) *Builder {
    31  	b.act.version = v
    32  	return b
    33  }
    34  
    35  // SetNonce sets action's nonce.
    36  func (b *Builder) SetNonce(n uint64) *Builder {
    37  	b.act.nonce = n
    38  	return b
    39  }
    40  
    41  // SetGasLimit sets action's gas limit.
    42  func (b *Builder) SetGasLimit(l uint64) *Builder {
    43  	b.act.gasLimit = l
    44  	return b
    45  }
    46  
    47  // SetGasPrice sets action's gas price.
    48  func (b *Builder) SetGasPrice(p *big.Int) *Builder {
    49  	if p == nil {
    50  		return b
    51  	}
    52  	b.act.gasPrice = &big.Int{}
    53  	b.act.gasPrice.Set(p)
    54  	return b
    55  }
    56  
    57  // SetGasPriceByBytes sets action's gas price from a byte slice source.
    58  func (b *Builder) SetGasPriceByBytes(buf []byte) *Builder {
    59  	if len(buf) == 0 {
    60  		return b
    61  	}
    62  	b.act.gasPrice = &big.Int{}
    63  	b.act.gasPrice.SetBytes(buf)
    64  	return b
    65  }
    66  
    67  // Build builds a new action.
    68  func (b *Builder) Build() AbstractAction {
    69  	if b.act.gasPrice == nil {
    70  		b.act.gasPrice = big.NewInt(0)
    71  	}
    72  	if b.act.version == 0 {
    73  		b.act.version = version.ProtocolVersion
    74  	}
    75  	return b.act
    76  }
    77  
    78  // EnvelopeBuilder is the builder to build Envelope.
    79  // TODO: change envelope to *envelope
    80  type EnvelopeBuilder struct {
    81  	elp envelope
    82  }
    83  
    84  // SetVersion sets action's version.
    85  func (b *EnvelopeBuilder) SetVersion(v uint32) *EnvelopeBuilder {
    86  	b.elp.version = v
    87  	return b
    88  }
    89  
    90  // SetNonce sets action's nonce.
    91  func (b *EnvelopeBuilder) SetNonce(n uint64) *EnvelopeBuilder {
    92  	b.elp.nonce = n
    93  	return b
    94  }
    95  
    96  // SetGasLimit sets action's gas limit.
    97  func (b *EnvelopeBuilder) SetGasLimit(l uint64) *EnvelopeBuilder {
    98  	b.elp.gasLimit = l
    99  	return b
   100  }
   101  
   102  // SetGasPrice sets action's gas price.
   103  func (b *EnvelopeBuilder) SetGasPrice(p *big.Int) *EnvelopeBuilder {
   104  	if p == nil {
   105  		return b
   106  	}
   107  	b.elp.gasPrice = &big.Int{}
   108  	b.elp.gasPrice.Set(p)
   109  	return b
   110  }
   111  
   112  // SetGasPriceByBytes sets action's gas price from a byte slice source.
   113  func (b *EnvelopeBuilder) SetGasPriceByBytes(buf []byte) *EnvelopeBuilder {
   114  	if len(buf) == 0 {
   115  		return b
   116  	}
   117  	b.elp.gasPrice = &big.Int{}
   118  	b.elp.gasPrice.SetBytes(buf)
   119  	return b
   120  }
   121  
   122  // SetAction sets the action payload for the Envelope Builder is building.
   123  func (b *EnvelopeBuilder) SetAction(action actionPayload) *EnvelopeBuilder {
   124  	b.elp.payload = action
   125  	return b
   126  }
   127  
   128  // SetChainID sets action's chainID.
   129  func (b *EnvelopeBuilder) SetChainID(chainID uint32) *EnvelopeBuilder {
   130  	b.elp.chainID = chainID
   131  	return b
   132  }
   133  
   134  // Build builds a new action.
   135  func (b *EnvelopeBuilder) Build() Envelope {
   136  	return b.build()
   137  }
   138  
   139  func (b *EnvelopeBuilder) build() Envelope {
   140  	if b.elp.gasPrice == nil {
   141  		b.elp.gasPrice = big.NewInt(0)
   142  	}
   143  	if b.elp.version == 0 {
   144  		b.elp.version = version.ProtocolVersion
   145  	}
   146  	if b.elp.payload == nil {
   147  		panic("cannot build Envelope w/o a valid payload")
   148  	}
   149  	b.elp.payload.SetEnvelopeContext(&b.elp)
   150  	return &b.elp
   151  }
   152  
   153  // BuildTransfer loads transfer action into envelope
   154  func (b *EnvelopeBuilder) BuildTransfer(tx *types.Transaction) (Envelope, error) {
   155  	if tx.To() == nil {
   156  		return nil, ErrInvalidAct
   157  	}
   158  	b.setEnvelopeCommonFields(tx)
   159  	tsf, err := NewTransfer(tx.Nonce(), tx.Value(), getRecipientAddr(tx.To()), tx.Data(), tx.Gas(), tx.GasPrice())
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	b.elp.payload = tsf
   164  	return b.build(), nil
   165  }
   166  
   167  func (b *EnvelopeBuilder) setEnvelopeCommonFields(tx *types.Transaction) {
   168  	b.elp.nonce = tx.Nonce()
   169  	b.elp.gasPrice = new(big.Int).Set(tx.GasPrice())
   170  	b.elp.gasLimit = tx.Gas()
   171  }
   172  
   173  func getRecipientAddr(addr *common.Address) string {
   174  	if addr == nil {
   175  		return ""
   176  	}
   177  	ioAddr, _ := address.FromBytes(addr.Bytes())
   178  	return ioAddr.String()
   179  }
   180  
   181  // BuildExecution loads executino action into envelope
   182  func (b *EnvelopeBuilder) BuildExecution(tx *types.Transaction) (Envelope, error) {
   183  	b.setEnvelopeCommonFields(tx)
   184  	exec, err := NewExecutionWithAccessList(getRecipientAddr(tx.To()), tx.Nonce(), tx.Value(), tx.Gas(), tx.GasPrice(), tx.Data(), tx.AccessList())
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  	b.elp.payload = exec
   189  	return b.build(), nil
   190  }
   191  
   192  // BuildStakingAction loads staking action into envelope from abi-encoded data
   193  func (b *EnvelopeBuilder) BuildStakingAction(tx *types.Transaction) (Envelope, error) {
   194  	if !bytes.Equal(tx.To().Bytes(), _stakingProtocolEthAddr.Bytes()) {
   195  		return nil, ErrInvalidAct
   196  	}
   197  	b.setEnvelopeCommonFields(tx)
   198  	act, err := newStakingActionFromABIBinary(tx.Data())
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  	b.elp.payload = act
   203  	return b.build(), nil
   204  }
   205  
   206  // BuildRewardingAction loads rewarding action into envelope from abi-encoded data
   207  func (b *EnvelopeBuilder) BuildRewardingAction(tx *types.Transaction) (Envelope, error) {
   208  	if !bytes.Equal(tx.To().Bytes(), _rewardingProtocolEthAddr.Bytes()) {
   209  		return nil, ErrInvalidAct
   210  	}
   211  	b.setEnvelopeCommonFields(tx)
   212  	act, err := newRewardingActionFromABIBinary(tx.Data())
   213  	if err != nil {
   214  		return nil, err
   215  	}
   216  	b.elp.payload = act
   217  	return b.build(), nil
   218  }
   219  
   220  func newStakingActionFromABIBinary(data []byte) (actionPayload, error) {
   221  	if len(data) <= 4 {
   222  		return nil, ErrInvalidABI
   223  	}
   224  	if act, err := NewCreateStakeFromABIBinary(data); err == nil {
   225  		return act, nil
   226  	}
   227  	if act, err := NewDepositToStakeFromABIBinary(data); err == nil {
   228  		return act, nil
   229  	}
   230  	if act, err := NewChangeCandidateFromABIBinary(data); err == nil {
   231  		return act, nil
   232  	}
   233  	if act, err := NewUnstakeFromABIBinary(data); err == nil {
   234  		return act, nil
   235  	}
   236  	if act, err := NewWithdrawStakeFromABIBinary(data); err == nil {
   237  		return act, nil
   238  	}
   239  	if act, err := NewRestakeFromABIBinary(data); err == nil {
   240  		return act, nil
   241  	}
   242  	if act, err := NewTransferStakeFromABIBinary(data); err == nil {
   243  		return act, nil
   244  	}
   245  	if act, err := NewCandidateRegisterFromABIBinary(data); err == nil {
   246  		return act, nil
   247  	}
   248  	if act, err := NewCandidateUpdateFromABIBinary(data); err == nil {
   249  		return act, nil
   250  	}
   251  	if act, err := NewCandidateActivateFromABIBinary(data); err == nil {
   252  		return act, nil
   253  	}
   254  	if act, err := NewCandidateEndorsementFromABIBinary(data); err == nil {
   255  		return act, nil
   256  	}
   257  	return nil, ErrInvalidABI
   258  }
   259  
   260  func newRewardingActionFromABIBinary(data []byte) (actionPayload, error) {
   261  	if len(data) <= 4 {
   262  		return nil, ErrInvalidABI
   263  	}
   264  	if act, err := NewClaimFromRewardingFundFromABIBinary(data); err == nil {
   265  		return act, nil
   266  	}
   267  	if act, err := NewDepositToRewardingFundFromABIBinary(data); err == nil {
   268  		return act, nil
   269  	}
   270  	return nil, ErrInvalidABI
   271  }