github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/core/state_transition.go (about) 1 // Copyright 2018 Wanchain Foundation Ltd 2 // Copyright 2014 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 18 package core 19 20 import ( 21 "errors" 22 "math/big" 23 24 "crypto/ecdsa" 25 "strings" 26 27 "github.com/wanchain/go-wanchain/accounts/abi" 28 "github.com/wanchain/go-wanchain/common" 29 "github.com/wanchain/go-wanchain/common/math" 30 "github.com/wanchain/go-wanchain/core/types" 31 "github.com/wanchain/go-wanchain/core/vm" 32 "github.com/wanchain/go-wanchain/crypto" 33 "github.com/wanchain/go-wanchain/log" 34 "github.com/wanchain/go-wanchain/params" 35 ) 36 37 var ( 38 Big0 = big.NewInt(0) 39 errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas") 40 ) 41 42 /* 43 The State Transitioning Model 44 45 A state transition is a change made when a transaction is applied to the current world state 46 The state transitioning model does all all the necessary work to work out a valid new state root. 47 48 1) Nonce handling 49 2) Pre pay gas 50 3) Create a new state object if the recipient is \0*32 51 4) Value transfer 52 == If contract creation == 53 4a) Attempt to run transaction data 54 4b) If valid, use result as code for the new state object 55 == end == 56 5) Run Script section 57 6) Derive new state root 58 */ 59 type StateTransition struct { 60 gp *GasPool 61 msg Message 62 gas uint64 63 gasPrice *big.Int 64 initialGas *big.Int 65 value *big.Int 66 data []byte 67 state vm.StateDB 68 evm *vm.EVM 69 } 70 71 // Message represents a message sent to a contract. 72 type Message interface { 73 From() common.Address 74 //FromFrontier() (common.Address, error) 75 To() *common.Address 76 77 GasPrice() *big.Int 78 Gas() *big.Int 79 Value() *big.Int 80 81 Nonce() uint64 82 CheckNonce() bool 83 Data() []byte 84 85 TxType() uint64 86 } 87 88 // IntrinsicGas computes the 'intrinsic gas' for a message 89 // with the given data. 90 // 91 // TODO convert to uint64 92 func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int { 93 igas := new(big.Int) 94 if contractCreation && homestead { 95 igas.SetUint64(params.TxGasContractCreation) 96 } else { 97 igas.SetUint64(params.TxGas) 98 } 99 if len(data) > 0 { 100 var nz int64 101 for _, byt := range data { 102 if byt != 0 { 103 nz++ 104 } 105 } 106 m := big.NewInt(nz) 107 m.Mul(m, new(big.Int).SetUint64(params.TxDataNonZeroGas)) 108 igas.Add(igas, m) 109 m.SetInt64(int64(len(data)) - nz) 110 m.Mul(m, new(big.Int).SetUint64(params.TxDataZeroGas)) 111 igas.Add(igas, m) 112 } 113 return igas 114 } 115 116 // NewStateTransition initialises and returns a new state transition object. 117 func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { 118 return &StateTransition{ 119 gp: gp, 120 evm: evm, 121 msg: msg, 122 gasPrice: msg.GasPrice(), 123 initialGas: new(big.Int), 124 value: msg.Value(), 125 data: msg.Data(), 126 state: evm.StateDB, 127 } 128 } 129 130 // ApplyMessage computes the new state by applying the given message 131 // against the old state within the environment. 132 // 133 // ApplyMessage returns the bytes returned by any EVM execution (if it took place), 134 // the gas used (which includes gas refunds) and an error if it failed. An error always 135 // indicates a core error meaning that the message would always fail for that particular 136 // state and would never be accepted within a block. 137 func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, bool, error) { 138 st := NewStateTransition(evm, msg, gp) 139 140 ret, _, gasUsed, failed, err := st.TransitionDb() 141 return ret, gasUsed, failed, err 142 } 143 144 func (st *StateTransition) from() vm.AccountRef { 145 f := st.msg.From() 146 if !st.state.Exist(f) { 147 st.state.CreateAccount(f) 148 } 149 return vm.AccountRef(f) 150 } 151 152 func (st *StateTransition) to() vm.AccountRef { 153 if st.msg == nil { 154 return vm.AccountRef{} 155 } 156 to := st.msg.To() 157 if to == nil { 158 return vm.AccountRef{} // contract creation 159 } 160 161 reference := vm.AccountRef(*to) 162 if !st.state.Exist(*to) { 163 st.state.CreateAccount(*to) 164 } 165 return reference 166 } 167 168 func (st *StateTransition) useGas(amount uint64) error { 169 if st.gas < amount { 170 return vm.ErrOutOfGas 171 } 172 st.gas -= amount 173 174 return nil 175 } 176 177 func (st *StateTransition) buyGas() error { 178 mgas := st.msg.Gas() 179 if mgas.BitLen() > 64 { 180 return vm.ErrOutOfGas 181 } 182 183 mgval := new(big.Int).Mul(mgas, st.gasPrice) 184 185 var ( 186 state = st.state 187 sender = st.from() 188 ) 189 190 if state.GetBalance(sender.Address()).Cmp(mgval) < 0 { 191 return errInsufficientBalanceForGas 192 } 193 194 if err := st.gp.SubGas(mgas); err != nil { 195 return err 196 } 197 st.gas += mgas.Uint64() 198 199 st.initialGas.Set(mgas) 200 state.SubBalance(sender.Address(), mgval) 201 return nil 202 } 203 204 func (st *StateTransition) preCheck() error { 205 msg := st.msg 206 sender := st.from() 207 208 // Make sure this transaction's nonce is correct 209 if msg.CheckNonce() { 210 nonce := st.state.GetNonce(sender.Address()) 211 if nonce < msg.Nonce() { 212 return ErrNonceTooHigh 213 } else if nonce > msg.Nonce() { 214 return ErrNonceTooLow 215 } 216 } 217 return st.buyGas() 218 } 219 220 // TransitionDb will transition the state by applying the current message and returning the result 221 // including the required gas for the operation as well as the used gas. It returns an error if it 222 // failed. An error indicates a consensus issue. 223 func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, failed bool, err error) { 224 225 if types.IsNormalTransaction(st.msg.TxType()) { 226 if err = st.preCheck(); err != nil { 227 return 228 } 229 } 230 231 log.Trace("after preCheck", "txType", st.msg.TxType(), "gas pool", st.gp.String()) 232 233 msg := st.msg 234 sender := st.from() // err checked in preCheck 235 236 //homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) 237 contractCreation := msg.To() == nil 238 239 // Pay intrinsic gas 240 // TODO convert to uint64 241 intrinsicGas := IntrinsicGas(st.data, contractCreation, true /*homestead*/) 242 log.Trace("get intrinsic gas", "gas", intrinsicGas.String()) 243 if intrinsicGas.BitLen() > 64 { 244 return nil, nil, nil, false, vm.ErrOutOfGas 245 } 246 247 var stampTotalGas uint64 248 if !types.IsNormalTransaction(st.msg.TxType()) { 249 pureCallData, totalUseableGas, evmUseableGas, err := PreProcessPrivacyTx(st.evm.StateDB, 250 sender.Address().Bytes(), 251 st.data, st.gasPrice, st.value) 252 if err != nil { 253 return nil, nil, nil, false, err 254 } 255 256 stampTotalGas = totalUseableGas 257 st.gas = evmUseableGas 258 st.initialGas.SetUint64(evmUseableGas) 259 st.data = pureCallData[:] 260 log.Trace("pre process privacy tx", "stampTotalGas", stampTotalGas, "evmUseableGas", evmUseableGas) 261 //sub gas from total gas of curent block,prevent gas is overhead gaslimit 262 if err := st.gp.SubGas(new(big.Int).SetUint64(totalUseableGas)); err != nil { 263 return nil, nil, nil, false, err 264 } 265 } 266 267 if err = st.useGas(intrinsicGas.Uint64()); err != nil { 268 return nil, nil, nil, false, err 269 } 270 271 log.Trace("subed intrinsic gas", "gas pool left", st.gp.String()) 272 273 var ( 274 evm = st.evm 275 // vm errors do not effect consensus and are therefor 276 // not assigned to err, except for insufficient balance 277 // error. 278 vmerr error 279 ) 280 if contractCreation { 281 ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) 282 log.Trace("create contract", "left gas", st.gas, "err", vmerr) 283 } else { 284 // Increment the nonce for the next transaction 285 st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1) 286 ret, st.gas, vmerr = evm.Call(sender, st.to().Address(), st.data, st.gas, st.value) 287 log.Trace("no create contract", "left gas", st.gas, "err", vmerr) 288 } 289 290 if vmerr != nil { 291 log.Debug("VM returned with error", "err", vmerr) 292 // The only possible consensus-error would be if there wasn't 293 // sufficient balance to make the transfer happen. The first 294 // balance transfer may never fail. 295 if vmerr == vm.ErrInsufficientBalance { 296 return nil, nil, nil, false, vmerr 297 } 298 } 299 300 if types.IsNormalTransaction(st.msg.TxType()) { 301 requiredGas = st.gasUsed() 302 st.refundGas() 303 usedGas = new(big.Int).Set(st.gasUsed()) 304 log.Trace("calc used gas, normal tx", "required gas", requiredGas, "used gas", usedGas) 305 } else { 306 requiredGas = new(big.Int).SetUint64(stampTotalGas) 307 usedGas = requiredGas 308 log.Trace("calc used gas, privacy tx", "required gas", requiredGas, "used gas", usedGas) 309 } 310 311 st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(usedGas, st.gasPrice)) 312 return ret, requiredGas, usedGas, vmerr != nil, err 313 } 314 315 func (st *StateTransition) refundGas() { 316 // Return eth for remaining gas to the sender account, 317 // exchanged at the original rate. 318 sender := st.from() // err already checked 319 remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) 320 st.state.AddBalance(sender.Address(), remaining) 321 322 // Apply refund counter, capped to half of the used gas. 323 uhalf := remaining.Div(st.gasUsed(), common.Big2) 324 refund := math.BigMin(uhalf, st.state.GetRefund()) 325 st.gas += refund.Uint64() 326 327 st.state.AddBalance(sender.Address(), refund.Mul(refund, st.gasPrice)) 328 329 // Also return remaining gas to the block gas counter so it is 330 // available for the next transaction. 331 st.gp.AddGas(new(big.Int).SetUint64(st.gas)) 332 } 333 334 func (st *StateTransition) gasUsed() *big.Int { 335 return new(big.Int).Sub(st.initialGas, new(big.Int).SetUint64(st.gas)) 336 } 337 338 ///////////////////////added for privacy tx ///////////////////////////// 339 var ( 340 utilAbiDefinition = `[{"constant":false,"type":"function","inputs":[{"name":"RingSignedData","type":"string"},{"name":"CxtCallParams","type":"bytes"}],"name":"combine","outputs":[{"name":"RingSignedData","type":"string"},{"name":"CxtCallParams","type":"bytes"}]}]` 341 342 utilAbi, errAbiInit = abi.JSON(strings.NewReader(utilAbiDefinition)) 343 344 TokenAbi = utilAbi 345 ) 346 347 func init() { 348 if errAbiInit != nil { 349 panic(errAbiInit) 350 } 351 } 352 353 type PrivacyTxInfo struct { 354 PublicKeys []*ecdsa.PublicKey 355 KeyImage *ecdsa.PublicKey 356 W_Random []*big.Int 357 Q_Random []*big.Int 358 CallData []byte 359 StampBalance *big.Int 360 StampTotalGas uint64 361 GasLeftSubRingSign uint64 362 } 363 364 func FetchPrivacyTxInfo(stateDB vm.StateDB, hashInput []byte, in []byte, gasPrice *big.Int) (info *PrivacyTxInfo, err error) { 365 if len(in) < 4 { 366 return nil, vm.ErrInvalidRingSigned 367 } 368 369 var TxDataWithRing struct { 370 RingSignedData string 371 CxtCallParams []byte 372 } 373 374 err = utilAbi.Unpack(&TxDataWithRing, "combine", in[4:]) 375 if err != nil { 376 return 377 } 378 379 ringSignInfo, err := vm.FetchRingSignInfo(stateDB, hashInput, TxDataWithRing.RingSignedData) 380 if err != nil { 381 return 382 } 383 384 stampGasBigInt := new(big.Int).Div(ringSignInfo.OTABalance, gasPrice) 385 if stampGasBigInt.BitLen() > 64 { 386 return nil, vm.ErrOutOfGas 387 } 388 389 StampTotalGas := stampGasBigInt.Uint64() 390 mixLen := len(ringSignInfo.PublicKeys) 391 ringSigDiffRequiredGas := params.RequiredGasPerMixPub * (uint64(mixLen)) 392 393 // ringsign compute gas + ota image key store setting gas 394 preSubGas := ringSigDiffRequiredGas + params.SstoreSetGas 395 if StampTotalGas < preSubGas { 396 return nil, vm.ErrOutOfGas 397 } 398 399 GasLeftSubRingSign := StampTotalGas - preSubGas 400 info = &PrivacyTxInfo{ 401 ringSignInfo.PublicKeys, 402 ringSignInfo.KeyImage, 403 ringSignInfo.W_Random, 404 ringSignInfo.Q_Random, 405 TxDataWithRing.CxtCallParams[:], 406 ringSignInfo.OTABalance, 407 StampTotalGas, 408 GasLeftSubRingSign, 409 } 410 411 return 412 } 413 414 func ValidPrivacyTx(stateDB vm.StateDB, hashInput []byte, in []byte, gasPrice *big.Int, 415 intrGas *big.Int, txValue *big.Int, gasLimit *big.Int) error { 416 if intrGas == nil || intrGas.BitLen() > 64 { 417 return vm.ErrOutOfGas 418 } 419 420 if txValue.Sign() != 0 { 421 return vm.ErrInvalidPrivacyValue 422 } 423 424 if gasPrice == nil || gasPrice.Cmp(common.Big0) <= 0 { 425 return vm.ErrInvalidGasPrice 426 } 427 428 info, err := FetchPrivacyTxInfo(stateDB, hashInput, in, gasPrice) 429 if err != nil { 430 return err 431 } 432 433 if info.StampTotalGas > gasLimit.Uint64() { 434 return ErrGasLimit 435 } 436 437 kix := crypto.FromECDSAPub(info.KeyImage) 438 exist, _, err := vm.CheckOTAImageExist(stateDB, kix) 439 if err != nil { 440 return err 441 } else if exist { 442 return errors.New("stamp has been spended") 443 } 444 445 if info.GasLeftSubRingSign < intrGas.Uint64() { 446 return vm.ErrOutOfGas 447 } 448 449 return nil 450 } 451 452 func PreProcessPrivacyTx(stateDB vm.StateDB, hashInput []byte, in []byte, gasPrice *big.Int, txValue *big.Int) (callData []byte, totalUseableGas uint64, evmUseableGas uint64, err error) { 453 if txValue.Sign() != 0 { 454 return nil, 0, 0, vm.ErrInvalidPrivacyValue 455 } 456 457 info, err := FetchPrivacyTxInfo(stateDB, hashInput, in, gasPrice) 458 if err != nil { 459 return nil, 0, 0, err 460 } 461 462 kix := crypto.FromECDSAPub(info.KeyImage) 463 exist, _, err := vm.CheckOTAImageExist(stateDB, kix) 464 if err != nil || exist { 465 return nil, 0, 0, err 466 } 467 468 vm.AddOTAImage(stateDB, kix, info.StampBalance.Bytes()) 469 470 return info.CallData, info.StampTotalGas, info.GasLeftSubRingSign, nil 471 }