state_transition.go 6.36 KB
Newer Older
obscuren's avatar
obscuren committed
1
package core
2 3 4

import (
	"fmt"
5
	"math/big"
6

obscuren's avatar
obscuren committed
7
	"github.com/ethereum/go-ethereum/common"
obscuren's avatar
obscuren committed
8 9
	"github.com/ethereum/go-ethereum/core/state"
	"github.com/ethereum/go-ethereum/core/vm"
obscuren's avatar
obscuren committed
10
	"github.com/ethereum/go-ethereum/crypto"
obscuren's avatar
obscuren committed
11 12
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/logger/glog"
13
	"github.com/ethereum/go-ethereum/params"
14 15
)

16 17
const tryJit = false

obscuren's avatar
obscuren committed
18
var ()
obscuren's avatar
obscuren committed
19

obscuren's avatar
obscuren committed
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
 * The State transitioning model
 *
 * A state transition is a change made when a transaction is applied to the current world state
 * The state transitioning model does all all the necessary work to work out a valid new state root.
 * 1) Nonce handling
 * 2) Pre pay / buy gas of the coinbase (miner)
 * 3) Create a new state object if the recipient is \0*32
 * 4) Value transfer
 * == If contract creation ==
 * 4a) Attempt to run transaction data
 * 4b) If valid, use result as code for the new state object
 * == end ==
 * 5) Run Script section
 * 6) Derive new state root
 */
36
type StateTransition struct {
obscuren's avatar
obscuren committed
37
	coinbase      common.Address
38 39 40 41 42 43
	msg           Message
	gas, gasPrice *big.Int
	initialGas    *big.Int
	value         *big.Int
	data          []byte
	state         *state.StateDB
44

obscuren's avatar
obscuren committed
45
	cb, rec, sen *state.StateObject
46

47
	env vm.Environment
48 49
}

50
// Message represents a message sent to a contract.
51
type Message interface {
52 53
	From() (common.Address, error)
	To() *common.Address
54 55 56 57 58 59 60

	GasPrice() *big.Int
	Gas() *big.Int
	Value() *big.Int

	Nonce() uint64
	Data() []byte
61
}
obscuren's avatar
obscuren committed
62 63 64 65 66

func AddressFromMessage(msg Message) common.Address {
	from, _ := msg.From()
	return crypto.CreateAddress(from, msg.Nonce())
}
67

obscuren's avatar
obscuren committed
68
func MessageCreatesContract(msg Message) bool {
69
	return msg.To() == nil
obscuren's avatar
obscuren committed
70 71
}

obscuren's avatar
obscuren committed
72 73 74 75
func MessageGasValue(msg Message) *big.Int {
	return new(big.Int).Mul(msg.Gas(), msg.GasPrice())
}

76 77 78
// IntrinsicGas computes the 'intrisic gas' for a message
// with the given data.
func IntrinsicGas(data []byte) *big.Int {
obscuren's avatar
obscuren committed
79
	igas := new(big.Int).Set(params.TxGas)
80
	for _, byt := range data {
obscuren's avatar
obscuren committed
81 82 83 84 85 86 87 88 89
		if byt != 0 {
			igas.Add(igas, params.TxDataNonZeroGas)
		} else {
			igas.Add(igas, params.TxDataZeroGas)
		}
	}
	return igas
}

90 91 92 93
func ApplyMessage(env vm.Environment, msg Message, coinbase *state.StateObject) ([]byte, *big.Int, error) {
	return NewStateTransition(env, msg, coinbase).transitionState()
}

94 95 96 97 98 99 100 101 102 103 104 105
func NewStateTransition(env vm.Environment, msg Message, coinbase *state.StateObject) *StateTransition {
	return &StateTransition{
		coinbase:   coinbase.Address(),
		env:        env,
		msg:        msg,
		gas:        new(big.Int),
		gasPrice:   new(big.Int).Set(msg.GasPrice()),
		initialGas: new(big.Int),
		value:      msg.Value(),
		data:       msg.Data(),
		state:      env.State(),
		cb:         coinbase,
106
	}
107 108
}

obscuren's avatar
obscuren committed
109
func (self *StateTransition) Coinbase() *state.StateObject {
obscuren's avatar
obscuren committed
110
	return self.state.GetOrNewStateObject(self.coinbase)
111
}
112 113 114 115 116 117
func (self *StateTransition) From() (*state.StateObject, error) {
	f, err := self.msg.From()
	if err != nil {
		return nil, err
	}
	return self.state.GetOrNewStateObject(f), nil
118
}
119
func (self *StateTransition) To() *state.StateObject {
120
	if self.msg == nil {
121 122
		return nil
	}
123 124 125 126 127
	to := self.msg.To()
	if to == nil {
		return nil // contract creation
	}
	return self.state.GetOrNewStateObject(*to)
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
}

func (self *StateTransition) UseGas(amount *big.Int) error {
	if self.gas.Cmp(amount) < 0 {
		return OutOfGasError()
	}
	self.gas.Sub(self.gas, amount)

	return nil
}

func (self *StateTransition) AddGas(amount *big.Int) {
	self.gas.Add(self.gas, amount)
}

func (self *StateTransition) BuyGas() error {
	var err error

146 147 148 149
	sender, err := self.From()
	if err != nil {
		return err
	}
obscuren's avatar
obscuren committed
150
	if sender.Balance().Cmp(MessageGasValue(self.msg)) < 0 {
obscuren's avatar
obscuren committed
151
		return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], MessageGasValue(self.msg), sender.Balance())
152 153 154
	}

	coinbase := self.Coinbase()
155
	err = coinbase.SubGas(self.msg.Gas(), self.msg.GasPrice())
156 157 158 159
	if err != nil {
		return err
	}

160
	self.AddGas(self.msg.Gas())
obscuren's avatar
obscuren committed
161
	self.initialGas.Set(self.msg.Gas())
162
	sender.SubBalance(MessageGasValue(self.msg))
163 164 165 166

	return nil
}

167
func (self *StateTransition) preCheck() (err error) {
168 169 170 171 172
	msg := self.msg
	sender, err := self.From()
	if err != nil {
		return err
	}
173 174

	// Make sure this transaction's nonce is correct
175 176
	if sender.Nonce() != msg.Nonce() {
		return NonceError(msg.Nonce(), sender.Nonce())
177 178 179 180
	}

	// Pre-pay gas / Buy gas of the coinbase account
	if err = self.BuyGas(); err != nil {
obscuren's avatar
obscuren committed
181 182 183
		if state.IsGasLimitErr(err) {
			return err
		}
184
		return InvalidTxError(err)
185 186 187 188 189
	}

	return nil
}

190
func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, err error) {
191 192 193 194
	if err = self.preCheck(); err != nil {
		return
	}

195 196
	msg := self.msg
	sender, _ := self.From() // err checked in preCheck
197

obscuren's avatar
obscuren committed
198
	// Pay intrinsic gas
199
	if err = self.UseGas(IntrinsicGas(self.msg.Data())); err != nil {
200
		return nil, nil, InvalidTxError(err)
201 202
	}

203
	vmenv := self.env
obscuren's avatar
obscuren committed
204
	var ref vm.ContextRef
obscuren's avatar
obscuren committed
205
	if MessageCreatesContract(msg) {
obscuren's avatar
obscuren committed
206
		ret, err, ref = vmenv.Create(sender, self.msg.Data(), self.gas, self.gasPrice, self.value)
207 208
		if err == nil {
			dataGas := big.NewInt(int64(len(ret)))
209
			dataGas.Mul(dataGas, params.CreateDataGas)
obscuren's avatar
obscuren committed
210
			if err := self.UseGas(dataGas); err == nil {
211
				ref.SetCode(ret)
212
			} else {
213
				ret = nil // does not affect consensus but useful for StateTests validations
obscuren's avatar
obscuren committed
214
				glog.V(logger.Core).Infoln("Insufficient gas for creating code. Require", dataGas, "and have", self.gas)
215 216
			}
		}
obscuren's avatar
obscuren committed
217
	} else {
obscuren's avatar
obscuren committed
218
		// Increment the nonce for the next transaction
219
		self.state.SetNonce(sender.Address(), sender.Nonce()+1)
220
		ret, err = vmenv.Call(sender, self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
obscuren's avatar
obscuren committed
221
	}
222

obscuren's avatar
obscuren committed
223
	if err != nil && IsValueTransferErr(err) {
224
		return nil, nil, InvalidTxError(err)
225 226
	}

227
	if vm.Debug {
228
		vm.StdErrFormat(vmenv.StructLogs())
229 230
	}

231 232
	self.refundGas()
	self.state.AddBalance(self.coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
233

234
	return ret, self.gasUsed(), err
235
}
obscuren's avatar
obscuren committed
236

237
func (self *StateTransition) refundGas() {
238 239
	coinbase := self.Coinbase()
	sender, _ := self.From() // err already checked
240 241
	// Return remaining gas
	remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice())
242
	sender.AddBalance(remaining)
243

obscuren's avatar
obscuren committed
244
	uhalf := new(big.Int).Div(self.gasUsed(), common.Big2)
245 246 247
	refund := common.BigMin(uhalf, self.state.Refunds())
	self.gas.Add(self.gas, refund)
	self.state.AddBalance(sender.Address(), refund.Mul(refund, self.msg.GasPrice()))
obscuren's avatar
obscuren committed
248

249
	coinbase.AddGas(self.gas, self.msg.GasPrice())
obscuren's avatar
obscuren committed
250 251
}

252
func (self *StateTransition) gasUsed() *big.Int {
obscuren's avatar
obscuren committed
253 254
	return new(big.Int).Sub(self.initialGas, self.gas)
}