cmd/evm, core/vm, test: refactored VM and core
* Moved `vm.Transfer` to `core` package and changed execution to call `env.Transfer` instead of `core.Transfer` directly. * core/vm: byte code VM moved to jump table instead of switch * Moved `vm.Transfer` to `core` package and changed execution to call `env.Transfer` instead of `core.Transfer` directly. * Byte code VM now shares the same code as the JITVM * Renamed Context to Contract * Changed initialiser of state transition & unexported methods * Removed the Execution object and refactor `Call`, `CallCode` & `Create` in to their own functions instead of being methods. * Removed the hard dep on the state for the VM. The VM now depends on a Database interface returned by the environment. In the process the core now depends less on the statedb by usage of the env * Moved `Log` from package `core/state` to package `core/vm`.
This commit is contained in:
@ -51,7 +51,7 @@ type StateTransition struct {
|
||||
initialGas *big.Int
|
||||
value *big.Int
|
||||
data []byte
|
||||
state *state.StateDB
|
||||
state vm.Database
|
||||
|
||||
env vm.Environment
|
||||
}
|
||||
@ -95,11 +95,7 @@ func IntrinsicGas(data []byte) *big.Int {
|
||||
}
|
||||
|
||||
func ApplyMessage(env vm.Environment, msg Message, gp GasPool) ([]byte, *big.Int, error) {
|
||||
return NewStateTransition(env, msg, gp).transitionState()
|
||||
}
|
||||
|
||||
func NewStateTransition(env vm.Environment, msg Message, gp GasPool) *StateTransition {
|
||||
return &StateTransition{
|
||||
var st = StateTransition{
|
||||
gp: gp,
|
||||
env: env,
|
||||
msg: msg,
|
||||
@ -108,18 +104,22 @@ func NewStateTransition(env vm.Environment, msg Message, gp GasPool) *StateTrans
|
||||
initialGas: new(big.Int),
|
||||
value: msg.Value(),
|
||||
data: msg.Data(),
|
||||
state: env.State(),
|
||||
state: env.Db(),
|
||||
}
|
||||
return st.transitionDb()
|
||||
}
|
||||
|
||||
func (self *StateTransition) From() (*state.StateObject, error) {
|
||||
func (self *StateTransition) from() (vm.Account, error) {
|
||||
f, err := self.msg.From()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return self.state.GetOrNewStateObject(f), nil
|
||||
if !self.state.Exist(f) {
|
||||
return self.state.CreateAccount(f), nil
|
||||
}
|
||||
return self.state.GetAccount(f), nil
|
||||
}
|
||||
func (self *StateTransition) To() *state.StateObject {
|
||||
func (self *StateTransition) to() vm.Account {
|
||||
if self.msg == nil {
|
||||
return nil
|
||||
}
|
||||
@ -127,10 +127,14 @@ func (self *StateTransition) To() *state.StateObject {
|
||||
if to == nil {
|
||||
return nil // contract creation
|
||||
}
|
||||
return self.state.GetOrNewStateObject(*to)
|
||||
|
||||
if !self.state.Exist(*to) {
|
||||
return self.state.CreateAccount(*to)
|
||||
}
|
||||
return self.state.GetAccount(*to)
|
||||
}
|
||||
|
||||
func (self *StateTransition) UseGas(amount *big.Int) error {
|
||||
func (self *StateTransition) useGas(amount *big.Int) error {
|
||||
if self.gas.Cmp(amount) < 0 {
|
||||
return vm.OutOfGasError
|
||||
}
|
||||
@ -139,15 +143,15 @@ func (self *StateTransition) UseGas(amount *big.Int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *StateTransition) AddGas(amount *big.Int) {
|
||||
func (self *StateTransition) addGas(amount *big.Int) {
|
||||
self.gas.Add(self.gas, amount)
|
||||
}
|
||||
|
||||
func (self *StateTransition) BuyGas() error {
|
||||
func (self *StateTransition) buyGas() error {
|
||||
mgas := self.msg.Gas()
|
||||
mgval := new(big.Int).Mul(mgas, self.gasPrice)
|
||||
|
||||
sender, err := self.From()
|
||||
sender, err := self.from()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -157,7 +161,7 @@ func (self *StateTransition) BuyGas() error {
|
||||
if err = self.gp.SubGas(mgas, self.gasPrice); err != nil {
|
||||
return err
|
||||
}
|
||||
self.AddGas(mgas)
|
||||
self.addGas(mgas)
|
||||
self.initialGas.Set(mgas)
|
||||
sender.SubBalance(mgval)
|
||||
return nil
|
||||
@ -165,18 +169,19 @@ func (self *StateTransition) BuyGas() error {
|
||||
|
||||
func (self *StateTransition) preCheck() (err error) {
|
||||
msg := self.msg
|
||||
sender, err := self.From()
|
||||
sender, err := self.from()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make sure this transaction's nonce is correct
|
||||
if sender.Nonce() != msg.Nonce() {
|
||||
return NonceError(msg.Nonce(), sender.Nonce())
|
||||
//if sender.Nonce() != msg.Nonce() {
|
||||
if n := self.state.GetNonce(sender.Address()); n != msg.Nonce() {
|
||||
return NonceError(msg.Nonce(), n)
|
||||
}
|
||||
|
||||
// Pre-pay gas / Buy gas of the coinbase account
|
||||
if err = self.BuyGas(); err != nil {
|
||||
if err = self.buyGas(); err != nil {
|
||||
if state.IsGasLimitErr(err) {
|
||||
return err
|
||||
}
|
||||
@ -186,28 +191,28 @@ func (self *StateTransition) preCheck() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, err error) {
|
||||
func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err error) {
|
||||
if err = self.preCheck(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
msg := self.msg
|
||||
sender, _ := self.From() // err checked in preCheck
|
||||
sender, _ := self.from() // err checked in preCheck
|
||||
|
||||
// Pay intrinsic gas
|
||||
if err = self.UseGas(IntrinsicGas(self.data)); err != nil {
|
||||
if err = self.useGas(IntrinsicGas(self.data)); err != nil {
|
||||
return nil, nil, InvalidTxError(err)
|
||||
}
|
||||
|
||||
vmenv := self.env
|
||||
var ref vm.ContextRef
|
||||
var addr common.Address
|
||||
if MessageCreatesContract(msg) {
|
||||
ret, err, ref = vmenv.Create(sender, self.data, self.gas, self.gasPrice, self.value)
|
||||
ret, addr, err = vmenv.Create(sender, self.data, self.gas, self.gasPrice, self.value)
|
||||
if err == nil {
|
||||
dataGas := big.NewInt(int64(len(ret)))
|
||||
dataGas.Mul(dataGas, params.CreateDataGas)
|
||||
if err := self.UseGas(dataGas); err == nil {
|
||||
ref.SetCode(ret)
|
||||
if err := self.useGas(dataGas); err == nil {
|
||||
self.state.SetCode(addr, ret)
|
||||
} else {
|
||||
ret = nil // does not affect consensus but useful for StateTests validations
|
||||
glog.V(logger.Core).Infoln("Insufficient gas for creating code. Require", dataGas, "and have", self.gas)
|
||||
@ -216,8 +221,8 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er
|
||||
glog.V(logger.Core).Infoln("VM create err:", err)
|
||||
} else {
|
||||
// Increment the nonce for the next transaction
|
||||
self.state.SetNonce(sender.Address(), sender.Nonce()+1)
|
||||
ret, err = vmenv.Call(sender, self.To().Address(), self.data, self.gas, self.gasPrice, self.value)
|
||||
self.state.SetNonce(sender.Address(), self.state.GetNonce(sender.Address())+1)
|
||||
ret, err = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.gasPrice, self.value)
|
||||
glog.V(logger.Core).Infoln("VM call err:", err)
|
||||
}
|
||||
|
||||
@ -241,13 +246,13 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er
|
||||
}
|
||||
|
||||
func (self *StateTransition) refundGas() {
|
||||
sender, _ := self.From() // err already checked
|
||||
sender, _ := self.from() // err already checked
|
||||
// Return remaining gas
|
||||
remaining := new(big.Int).Mul(self.gas, self.gasPrice)
|
||||
sender.AddBalance(remaining)
|
||||
|
||||
uhalf := remaining.Div(self.gasUsed(), common.Big2)
|
||||
refund := common.BigMin(uhalf, self.state.Refunds())
|
||||
refund := common.BigMin(uhalf, self.state.GetRefund())
|
||||
self.gas.Add(self.gas, refund)
|
||||
self.state.AddBalance(sender.Address(), refund.Mul(refund, self.gasPrice))
|
||||
|
||||
|
Reference in New Issue
Block a user