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  }