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:
Jeffrey Wilcke
2015-08-30 10:19:10 +02:00
parent f7a71996fb
commit 361082ec4b
39 changed files with 966 additions and 1082 deletions

View File

@ -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))