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 }