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

     1  package action
     2  
     3  import (
     4  	"math/big"
     5  
     6  	"github.com/iotexproject/iotex-proto/golang/iotextypes"
     7  	"github.com/pkg/errors"
     8  
     9  	"github.com/iotexproject/iotex-core/pkg/log"
    10  )
    11  
    12  type (
    13  	// Envelope defines an envelope wrapped on action with some envelope metadata.
    14  	Envelope interface {
    15  		Version() uint32
    16  		Nonce() uint64
    17  		ChainID() uint32
    18  		GasLimit() uint64
    19  		GasPrice() *big.Int
    20  		Destination() (string, bool)
    21  		Cost() (*big.Int, error)
    22  		IntrinsicGas() (uint64, error)
    23  		Action() Action
    24  		Proto() *iotextypes.ActionCore
    25  		LoadProto(pbAct *iotextypes.ActionCore) error
    26  		SetNonce(n uint64)
    27  		SetChainID(chainID uint32)
    28  	}
    29  
    30  	envelope struct {
    31  		version  uint32
    32  		chainID  uint32
    33  		nonce    uint64
    34  		gasLimit uint64
    35  		gasPrice *big.Int
    36  		payload  actionPayload
    37  	}
    38  )
    39  
    40  // Version returns the version
    41  func (elp *envelope) Version() uint32 { return elp.version }
    42  
    43  // ChainID return the chainID value
    44  func (elp *envelope) ChainID() uint32 { return elp.chainID }
    45  
    46  // Nonce returns the nonce
    47  func (elp *envelope) Nonce() uint64 { return elp.nonce }
    48  
    49  // Destination returns the destination address
    50  func (elp *envelope) Destination() (string, bool) {
    51  	r, ok := elp.payload.(hasDestination)
    52  	if !ok {
    53  		return "", false
    54  	}
    55  
    56  	return r.Destination(), true
    57  }
    58  
    59  // GasLimit returns the gas limit
    60  func (elp *envelope) GasLimit() uint64 { return elp.gasLimit }
    61  
    62  // GasPrice returns the gas price
    63  func (elp *envelope) GasPrice() *big.Int {
    64  	p := &big.Int{}
    65  	if elp.gasPrice == nil {
    66  		return p
    67  	}
    68  	return p.Set(elp.gasPrice)
    69  }
    70  
    71  // Cost returns cost of actions
    72  func (elp *envelope) Cost() (*big.Int, error) {
    73  	return elp.payload.Cost()
    74  }
    75  
    76  // IntrinsicGas returns intrinsic gas of action.
    77  func (elp *envelope) IntrinsicGas() (uint64, error) {
    78  	return elp.payload.IntrinsicGas()
    79  }
    80  
    81  // Action returns the action payload.
    82  func (elp *envelope) Action() Action { return elp.payload }
    83  
    84  // Proto convert Envelope to protobuf format.
    85  func (elp *envelope) Proto() *iotextypes.ActionCore {
    86  	actCore := &iotextypes.ActionCore{
    87  		Version:  elp.version,
    88  		Nonce:    elp.nonce,
    89  		GasLimit: elp.gasLimit,
    90  		ChainID:  elp.chainID,
    91  	}
    92  	if elp.gasPrice != nil {
    93  		actCore.GasPrice = elp.gasPrice.String()
    94  	}
    95  
    96  	// TODO assert each action
    97  	switch act := elp.Action().(type) {
    98  	case *Transfer:
    99  		actCore.Action = &iotextypes.ActionCore_Transfer{Transfer: act.Proto()}
   100  	case *Execution:
   101  		actCore.Action = &iotextypes.ActionCore_Execution{Execution: act.Proto()}
   102  	case *GrantReward:
   103  		actCore.Action = &iotextypes.ActionCore_GrantReward{GrantReward: act.Proto()}
   104  	case *ClaimFromRewardingFund:
   105  		actCore.Action = &iotextypes.ActionCore_ClaimFromRewardingFund{ClaimFromRewardingFund: act.Proto()}
   106  	case *DepositToRewardingFund:
   107  		actCore.Action = &iotextypes.ActionCore_DepositToRewardingFund{DepositToRewardingFund: act.Proto()}
   108  	case *PutPollResult:
   109  		actCore.Action = &iotextypes.ActionCore_PutPollResult{PutPollResult: act.Proto()}
   110  	case *CreateStake:
   111  		actCore.Action = &iotextypes.ActionCore_StakeCreate{StakeCreate: act.Proto()}
   112  	case *Unstake:
   113  		actCore.Action = &iotextypes.ActionCore_StakeUnstake{StakeUnstake: act.Proto()}
   114  	case *WithdrawStake:
   115  		actCore.Action = &iotextypes.ActionCore_StakeWithdraw{StakeWithdraw: act.Proto()}
   116  	case *DepositToStake:
   117  		actCore.Action = &iotextypes.ActionCore_StakeAddDeposit{StakeAddDeposit: act.Proto()}
   118  	case *Restake:
   119  		actCore.Action = &iotextypes.ActionCore_StakeRestake{StakeRestake: act.Proto()}
   120  	case *ChangeCandidate:
   121  		actCore.Action = &iotextypes.ActionCore_StakeChangeCandidate{StakeChangeCandidate: act.Proto()}
   122  	case *TransferStake:
   123  		actCore.Action = &iotextypes.ActionCore_StakeTransferOwnership{StakeTransferOwnership: act.Proto()}
   124  	case *CandidateRegister:
   125  		actCore.Action = &iotextypes.ActionCore_CandidateRegister{CandidateRegister: act.Proto()}
   126  	case *CandidateUpdate:
   127  		actCore.Action = &iotextypes.ActionCore_CandidateUpdate{CandidateUpdate: act.Proto()}
   128  	case *CandidateActivate:
   129  		actCore.Action = &iotextypes.ActionCore_CandidateActivate{CandidateActivate: act.Proto()}
   130  	case *CandidateEndorsement:
   131  		actCore.Action = &iotextypes.ActionCore_CandidateEndorsement{CandidateEndorsement: act.Proto()}
   132  	default:
   133  		log.S().Panicf("Cannot convert type of action %T.\r\n", act)
   134  	}
   135  	return actCore
   136  }
   137  
   138  // LoadProto loads fields from protobuf format.
   139  func (elp *envelope) LoadProto(pbAct *iotextypes.ActionCore) error {
   140  	if pbAct == nil {
   141  		return ErrNilProto
   142  	}
   143  	if elp == nil {
   144  		return ErrNilAction
   145  	}
   146  	*elp = envelope{}
   147  	elp.version = pbAct.GetVersion()
   148  	elp.nonce = pbAct.GetNonce()
   149  	elp.gasLimit = pbAct.GetGasLimit()
   150  	elp.chainID = pbAct.GetChainID()
   151  	if pbAct.GetGasPrice() == "" {
   152  		elp.gasPrice = big.NewInt(0)
   153  	} else {
   154  		gp, ok := new(big.Int).SetString(pbAct.GetGasPrice(), 10)
   155  		if !ok {
   156  			return errors.Errorf("invalid gas prcie %s", pbAct.GetGasPrice())
   157  		}
   158  		elp.gasPrice = gp
   159  	}
   160  
   161  	switch {
   162  	case pbAct.GetTransfer() != nil:
   163  		act := &Transfer{}
   164  		if err := act.LoadProto(pbAct.GetTransfer()); err != nil {
   165  			return err
   166  		}
   167  		elp.payload = act
   168  	case pbAct.GetExecution() != nil:
   169  		act := &Execution{}
   170  		if err := act.LoadProto(pbAct.GetExecution()); err != nil {
   171  			return err
   172  		}
   173  		elp.payload = act
   174  	case pbAct.GetGrantReward() != nil:
   175  		act := &GrantReward{}
   176  		if err := act.LoadProto(pbAct.GetGrantReward()); err != nil {
   177  			return err
   178  		}
   179  		elp.payload = act
   180  	case pbAct.GetClaimFromRewardingFund() != nil:
   181  		act := &ClaimFromRewardingFund{}
   182  		if err := act.LoadProto(pbAct.GetClaimFromRewardingFund()); err != nil {
   183  			return err
   184  		}
   185  		elp.payload = act
   186  	case pbAct.GetDepositToRewardingFund() != nil:
   187  		act := &DepositToRewardingFund{}
   188  		if err := act.LoadProto(pbAct.GetDepositToRewardingFund()); err != nil {
   189  			return err
   190  		}
   191  		elp.payload = act
   192  	case pbAct.GetPutPollResult() != nil:
   193  		act := &PutPollResult{}
   194  		if err := act.LoadProto(pbAct.GetPutPollResult()); err != nil {
   195  			return err
   196  		}
   197  		elp.payload = act
   198  
   199  	case pbAct.GetStakeCreate() != nil:
   200  		act := &CreateStake{}
   201  		if err := act.LoadProto(pbAct.GetStakeCreate()); err != nil {
   202  			return err
   203  		}
   204  		elp.payload = act
   205  	case pbAct.GetStakeUnstake() != nil:
   206  		act := &Unstake{}
   207  		if err := act.LoadProto(pbAct.GetStakeUnstake()); err != nil {
   208  			return err
   209  		}
   210  		elp.payload = act
   211  	case pbAct.GetStakeWithdraw() != nil:
   212  		act := &WithdrawStake{}
   213  		if err := act.LoadProto(pbAct.GetStakeWithdraw()); err != nil {
   214  			return err
   215  		}
   216  		elp.payload = act
   217  	case pbAct.GetStakeAddDeposit() != nil:
   218  		act := &DepositToStake{}
   219  		if err := act.LoadProto(pbAct.GetStakeAddDeposit()); err != nil {
   220  			return err
   221  		}
   222  		elp.payload = act
   223  	case pbAct.GetStakeRestake() != nil:
   224  		act := &Restake{}
   225  		if err := act.LoadProto(pbAct.GetStakeRestake()); err != nil {
   226  			return err
   227  		}
   228  		elp.payload = act
   229  	case pbAct.GetStakeChangeCandidate() != nil:
   230  		act := &ChangeCandidate{}
   231  		if err := act.LoadProto(pbAct.GetStakeChangeCandidate()); err != nil {
   232  			return err
   233  		}
   234  		elp.payload = act
   235  	case pbAct.GetStakeTransferOwnership() != nil:
   236  		act := &TransferStake{}
   237  		if err := act.LoadProto(pbAct.GetStakeTransferOwnership()); err != nil {
   238  			return err
   239  		}
   240  		elp.payload = act
   241  	case pbAct.GetCandidateRegister() != nil:
   242  		act := &CandidateRegister{}
   243  		if err := act.LoadProto(pbAct.GetCandidateRegister()); err != nil {
   244  			return err
   245  		}
   246  		elp.payload = act
   247  	case pbAct.GetCandidateUpdate() != nil:
   248  		act := &CandidateUpdate{}
   249  		if err := act.LoadProto(pbAct.GetCandidateUpdate()); err != nil {
   250  			return err
   251  		}
   252  		elp.payload = act
   253  	case pbAct.GetCandidateActivate() != nil:
   254  		act := &CandidateActivate{}
   255  		if err := act.LoadProto(pbAct.GetCandidateActivate()); err != nil {
   256  			return err
   257  		}
   258  		elp.payload = act
   259  	case pbAct.GetCandidateEndorsement() != nil:
   260  		act := &CandidateEndorsement{}
   261  		if err := act.LoadProto(pbAct.GetCandidateEndorsement()); err != nil {
   262  			return err
   263  		}
   264  		elp.payload = act
   265  	default:
   266  		return errors.Errorf("no applicable action to handle proto type %T", pbAct.Action)
   267  	}
   268  	elp.payload.SetEnvelopeContext(elp)
   269  	return nil
   270  }
   271  
   272  // SetNonce sets the nonce value
   273  func (elp *envelope) SetNonce(n uint64) { elp.nonce = n }
   274  
   275  // SetChainID sets the chainID value
   276  func (elp *envelope) SetChainID(chainID uint32) { elp.chainID = chainID }