converted vm

This commit is contained in:
obscuren 2015-03-17 11:19:23 +01:00
parent 8ce6a36478
commit 515d9432fc
11 changed files with 88 additions and 72 deletions

View File

@ -4,6 +4,7 @@ import (
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/vm"
@ -11,26 +12,23 @@ import (
type Execution struct {
env vm.Environment
address, input []byte
address *common.Address
input []byte
Gas, price, value *big.Int
}
func NewExecution(env vm.Environment, address, input []byte, gas, gasPrice, value *big.Int) *Execution {
func NewExecution(env vm.Environment, address *common.Address, input []byte, gas, gasPrice, value *big.Int) *Execution {
return &Execution{env: env, address: address, input: input, Gas: gas, price: gasPrice, value: value}
}
func (self *Execution) Addr() []byte {
return self.address
}
func (self *Execution) Call(codeAddr []byte, caller vm.ContextRef) ([]byte, error) {
func (self *Execution) Call(codeAddr common.Address, caller vm.ContextRef) ([]byte, error) {
// Retrieve the executing code
code := self.env.State().GetCode(codeAddr)
return self.exec(code, codeAddr, caller)
return self.exec(&codeAddr, code, caller)
}
func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret []byte, err error) {
func (self *Execution) exec(contextAddr *common.Address, code []byte, caller vm.ContextRef) (ret []byte, err error) {
env := self.env
evm := vm.NewVm(env)
if env.Depth() == vm.MaxCallDepth {
@ -40,14 +38,15 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret
}
vsnapshot := env.State().Copy()
if len(self.address) == 0 {
if self.address == nil {
// Generate a new address
nonce := env.State().GetNonce(caller.Address())
self.address = crypto.CreateAddress(caller.Address(), nonce)
addr := crypto.CreateAddress(caller.Address(), nonce)
self.address = &addr
env.State().SetNonce(caller.Address(), nonce+1)
}
from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(self.address)
from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(*self.address)
err = env.Transfer(from, to, self.value)
if err != nil {
env.State().Set(vsnapshot)
@ -73,8 +72,8 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret
}
func (self *Execution) Create(caller vm.ContextRef) (ret []byte, err error, account *state.StateObject) {
ret, err = self.exec(self.input, nil, caller)
account = self.env.State().GetStateObject(self.address)
ret, err = self.exec(nil, self.input, caller)
account = self.env.State().GetStateObject(*self.address)
return
}

View File

@ -1,9 +1,9 @@
package core
import (
"bytes"
"math"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/state"
)
@ -16,8 +16,8 @@ type FilterOptions struct {
Earliest int64
Latest int64
Address [][]byte
Topics [][][]byte
Address []common.Address
Topics [][]common.Hash
Skip int
Max int
@ -29,9 +29,9 @@ type Filter struct {
earliest int64
latest int64
skip int
address [][]byte
address []common.Address
max int
topics [][][]byte
topics [][]common.Hash
BlockCallback func(*types.Block)
PendingCallback func(*types.Block)
@ -67,11 +67,11 @@ func (self *Filter) SetLatestBlock(latest int64) {
self.latest = latest
}
func (self *Filter) SetAddress(addr [][]byte) {
func (self *Filter) SetAddress(addr []common.Address) {
self.address = addr
}
func (self *Filter) SetTopics(topics [][][]byte) {
func (self *Filter) SetTopics(topics [][]common.Hash) {
self.topics = topics
}
@ -131,9 +131,9 @@ func (self *Filter) Find() state.Logs {
return logs[skip:]
}
func includes(addresses [][]byte, a []byte) bool {
func includes(addresses []common.Address, a common.Address) bool {
for _, addr := range addresses {
if !bytes.Equal(addr, a) {
if addr != a {
return false
}
}
@ -151,13 +151,13 @@ Logs:
continue
}
logTopics := make([][]byte, len(self.topics))
logTopics := make([]common.Hash, len(self.topics))
copy(logTopics, log.Topics())
for i, topics := range self.topics {
for _, topic := range topics {
var match bool
if bytes.Equal(log.Topics()[i], topic) {
if log.Topics()[i] == topic {
match = true
}
if !match {
@ -176,7 +176,7 @@ func (self *Filter) bloomFilter(block *types.Block) bool {
if len(self.address) > 0 {
var included bool
for _, addr := range self.address {
if types.BloomLookup(block.Bloom(), addr) {
if types.BloomLookup(block.Bloom(), addr.Hash()) {
included = true
break
}

View File

@ -6,9 +6,9 @@ import (
"math/big"
"os"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/state"
)
@ -26,12 +26,11 @@ var GenesisDiff = big.NewInt(131072)
var GenesisGasLimit = big.NewInt(3141592)
func GenesisBlock(db common.Database) *types.Block {
genesis := types.NewBlock(ZeroHash256, ZeroHash160, nil, GenesisDiff, 42, "")
genesis := types.NewBlock(common.Hash{}, common.Address{}, common.Hash{}, GenesisDiff, 42, "")
genesis.Header().Number = common.Big0
genesis.Header().GasLimit = GenesisGasLimit
genesis.Header().GasUsed = common.Big0
genesis.Header().Time = 0
genesis.Header().MixDigest = make([]byte, 32)
genesis.Td = common.Big0
@ -49,7 +48,7 @@ func GenesisBlock(db common.Database) *types.Block {
statedb := state.New(genesis.Root(), db)
for addr, account := range accounts {
codedAddr := common.Hex2Bytes(addr)
accountState := statedb.GetAccount(codedAddr)
accountState := statedb.GetAccount(common.BytesToAddress(codedAddr))
accountState.SetBalance(common.Big(account.Balance))
statedb.UpdateStateObject(accountState)
}

View File

@ -31,7 +31,7 @@ var ()
* 6) Derive new state root
*/
type StateTransition struct {
coinbase []byte
coinbase common.Address
msg Message
gas, gasPrice *big.Int
initialGas *big.Int
@ -119,7 +119,7 @@ func (self *StateTransition) BuyGas() error {
sender := self.From()
if sender.Balance().Cmp(MessageGasValue(self.msg)) < 0 {
return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address()[:4], MessageGasValue(self.msg), sender.Balance())
return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], MessageGasValue(self.msg), sender.Balance())
}
coinbase := self.Coinbase()
@ -195,8 +195,9 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er
vmenv := self.env
var ref vm.ContextRef
if MessageCreatesContract(msg) {
contract := makeContract(msg, self.state)
ret, err, ref = vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
//contract := makeContract(msg, self.state)
//addr := contract.Address()
ret, err, ref = vmenv.Create(sender, self.msg.Data(), self.gas, self.gasPrice, self.value)
if err == nil {
dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, vm.GasCreateByte)
@ -230,7 +231,7 @@ func (self *StateTransition) refundGas() {
for addr, ref := range self.state.Refunds() {
refund := common.BigMin(uhalf, ref)
self.gas.Add(self.gas, refund)
self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice()))
self.state.AddBalance(common.StringToAddress(addr), refund.Mul(refund, self.msg.GasPrice()))
}
coinbase.RefundGas(self.gas, self.msg.GasPrice())
@ -242,10 +243,13 @@ func (self *StateTransition) gasUsed() *big.Int {
// Converts an message in to a state object
func makeContract(msg Message, state *state.StateDB) *state.StateObject {
addr := AddressFromMessage(msg)
/*
addr := AddressFromMessage(msg)
contract := state.GetOrNewStateObject(addr)
contract.SetInitCode(msg.Data())
contract := state.GetOrNewStateObject(addr)
contract.SetInitCode(msg.Data())
return contract
return contract
*/
return nil
}

View File

@ -47,9 +47,9 @@ func bloom9(b []byte) *big.Int {
return r
}
func BloomLookup(bin, topic []byte) bool {
bloom := common.BigD(bin)
cmp := bloom9(crypto.Sha3(topic))
func BloomLookup(bin Bloom, topic common.Hash) bool {
bloom := bin.Big()
cmp := bloom9(crypto.Sha3(topic[:]))
return bloom.And(bloom, cmp).Cmp(cmp) == 0
}

View File

@ -1,6 +1,10 @@
package types
import "math/big"
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
)
type BlockProcessor interface {
Process(*Block) (*big.Int, error)
@ -24,3 +28,7 @@ func (b *Bloom) SetBytes(d []byte) {
b[i] = b[i]
}
}
func (b Bloom) Big() *big.Int {
return common.Bytes2Big(b[:])
}

View File

@ -28,24 +28,24 @@ func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types
}
}
func (self *VMEnv) Origin() common.Address { return self.msg.From() }
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() }
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() }
func (self *VMEnv) Time() int64 { return self.block.Time() }
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() }
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() }
func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
func (self *VMEnv) State() *state.StateDB { return self.state }
func (self *VMEnv) Depth() int { return self.depth }
func (self *VMEnv) SetDepth(i int) { self.depth = i }
func (self *VMEnv) VmType() vm.Type { return self.typ }
func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t }
func (self *VMEnv) GetHash(n uint64) []byte {
func (self *VMEnv) Origin() common.Address { return self.msg.From() }
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() }
func (self *VMEnv) Coinbase() common.Address { return self.block.Coinbase() }
func (self *VMEnv) Time() int64 { return self.block.Time() }
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() }
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() }
func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
func (self *VMEnv) State() *state.StateDB { return self.state }
func (self *VMEnv) Depth() int { return self.depth }
func (self *VMEnv) SetDepth(i int) { self.depth = i }
func (self *VMEnv) VmType() vm.Type { return self.typ }
func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t }
func (self *VMEnv) GetHash(n uint64) common.Hash {
if block := self.chain.GetBlockByNumber(n); block != nil {
return block.Hash()
}
return nil
return common.Hash{}
}
func (self *VMEnv) AddLog(log state.Log) {
self.state.AddLog(log)
@ -54,20 +54,21 @@ func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {
return vm.Transfer(from, to, amount)
}
func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *Execution {
func (self *VMEnv) vm(addr *common.Address, data []byte, gas, price, value *big.Int) *Execution {
return NewExecution(self, addr, data, gas, price, value)
}
func (self *VMEnv) Call(me vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
exe := self.vm(addr, data, gas, price, value)
exe := self.vm(&addr, data, gas, price, value)
return exe.Call(addr, me)
}
func (self *VMEnv) CallCode(me vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
exe := self.vm(me.Address(), data, gas, price, value)
maddr := me.Address()
exe := self.vm(&maddr, data, gas, price, value)
return exe.Call(addr, me)
}
func (self *VMEnv) Create(me vm.ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) {
exe := self.vm(common.Address{}, data, gas, price, value)
exe := self.vm(nil, data, gas, price, value)
return exe.Create(me)
}

View File

@ -20,6 +20,7 @@ import (
"github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/pbkdf2"
"golang.org/x/crypto/ripemd160"
)
@ -47,8 +48,10 @@ func Sha3Hash(data ...[]byte) (h common.Hash) {
}
// Creates an ethereum address given the bytes and the nonce
func CreateAddress(b []byte, nonce uint64) []byte {
return Sha3(common.NewValue([]interface{}{b, nonce}).Encode())[12:]
func CreateAddress(b common.Address, nonce uint64) common.Address {
data, _ := rlp.EncodeToBytes([]interface{}{b, nonce})
return common.BytesToAddress(Sha3(data)[12:])
//return Sha3(common.NewValue([]interface{}{b, nonce}).Encode())[12:]
}
func Sha256(data []byte) []byte {

View File

@ -18,7 +18,7 @@ type Context struct {
self ContextRef
Code []byte
CodeAddr common.Address
CodeAddr *common.Address
value, Gas, UsedGas, Price *big.Int
@ -108,7 +108,7 @@ func (self *Context) SetCode(code []byte) {
self.Code = code
}
func (self *Context) SetCallCode(addr common.Address, code []byte) {
func (self *Context) SetCallCode(addr *common.Address, code []byte) {
self.Code = code
self.CodeAddr = addr
}

View File

@ -16,8 +16,8 @@ type Environment interface {
Origin() common.Address
BlockNumber() *big.Int
GetHash(n uint64) []byte
Coinbase() []byte
GetHash(n uint64) common.Hash
Coinbase() common.Address
Time() int64
Difficulty() *big.Int
GasLimit() *big.Int
@ -38,7 +38,7 @@ type Account interface {
SubBalance(amount *big.Int)
AddBalance(amount *big.Int)
Balance() *big.Int
Address() []byte
Address() common.Address
}
// generic transfer method

View File

@ -58,8 +58,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
}()
}
if p := Precompiled[context.CodeAddr.Str()]; p != nil {
return self.RunPrecompiled(p, callData, context)
if context.CodeAddr != nil {
if p := Precompiled[context.CodeAddr.Str()]; p != nil {
return self.RunPrecompiled(p, callData, context)
}
}
var (
@ -500,7 +502,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
n := new(big.Int).Sub(self.env.BlockNumber(), common.Big257)
if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 {
stack.push(common.BigD(self.env.GetHash(num.Uint64())))
stack.push(self.env.GetHash(num.Uint64()).Big())
} else {
stack.push(common.Big0)
}
@ -509,7 +511,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
case COINBASE:
coinbase := self.env.Coinbase()
stack.push(common.BigD(coinbase))
stack.push(coinbase.Big())
self.Printf(" => 0x%x", coinbase)
case TIMESTAMP: