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

View File

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

View File

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

View File

@ -31,7 +31,7 @@ var ()
* 6) Derive new state root * 6) Derive new state root
*/ */
type StateTransition struct { type StateTransition struct {
coinbase []byte coinbase common.Address
msg Message msg Message
gas, gasPrice *big.Int gas, gasPrice *big.Int
initialGas *big.Int initialGas *big.Int
@ -119,7 +119,7 @@ func (self *StateTransition) BuyGas() error {
sender := self.From() sender := self.From()
if sender.Balance().Cmp(MessageGasValue(self.msg)) < 0 { 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() coinbase := self.Coinbase()
@ -195,8 +195,9 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er
vmenv := self.env vmenv := self.env
var ref vm.ContextRef var ref vm.ContextRef
if MessageCreatesContract(msg) { if MessageCreatesContract(msg) {
contract := makeContract(msg, self.state) //contract := makeContract(msg, self.state)
ret, err, ref = vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value) //addr := contract.Address()
ret, err, ref = vmenv.Create(sender, self.msg.Data(), self.gas, self.gasPrice, self.value)
if err == nil { if err == nil {
dataGas := big.NewInt(int64(len(ret))) dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, vm.GasCreateByte) dataGas.Mul(dataGas, vm.GasCreateByte)
@ -230,7 +231,7 @@ func (self *StateTransition) refundGas() {
for addr, ref := range self.state.Refunds() { for addr, ref := range self.state.Refunds() {
refund := common.BigMin(uhalf, ref) refund := common.BigMin(uhalf, ref)
self.gas.Add(self.gas, refund) 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()) 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 // Converts an message in to a state object
func makeContract(msg Message, state *state.StateDB) *state.StateObject { func makeContract(msg Message, state *state.StateDB) *state.StateObject {
/*
addr := AddressFromMessage(msg) addr := AddressFromMessage(msg)
contract := state.GetOrNewStateObject(addr) contract := state.GetOrNewStateObject(addr)
contract.SetInitCode(msg.Data()) contract.SetInitCode(msg.Data())
return contract return contract
*/
return nil
} }

View File

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

View File

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

View File

@ -30,7 +30,7 @@ func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types
func (self *VMEnv) Origin() common.Address { return self.msg.From() } func (self *VMEnv) Origin() common.Address { return self.msg.From() }
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() } func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() }
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() } func (self *VMEnv) Coinbase() common.Address { return self.block.Coinbase() }
func (self *VMEnv) Time() int64 { return self.block.Time() } func (self *VMEnv) Time() int64 { return self.block.Time() }
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() }
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() }
@ -40,12 +40,12 @@ func (self *VMEnv) Depth() int { return self.depth }
func (self *VMEnv) SetDepth(i int) { self.depth = i } func (self *VMEnv) SetDepth(i int) { self.depth = i }
func (self *VMEnv) VmType() vm.Type { return self.typ } func (self *VMEnv) VmType() vm.Type { return self.typ }
func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t } func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t }
func (self *VMEnv) GetHash(n uint64) []byte { func (self *VMEnv) GetHash(n uint64) common.Hash {
if block := self.chain.GetBlockByNumber(n); block != nil { if block := self.chain.GetBlockByNumber(n); block != nil {
return block.Hash() return block.Hash()
} }
return nil return common.Hash{}
} }
func (self *VMEnv) AddLog(log state.Log) { func (self *VMEnv) AddLog(log state.Log) {
self.state.AddLog(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) 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) 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) { 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) return exe.Call(addr, me)
} }
func (self *VMEnv) CallCode(me vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { 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) return exe.Call(addr, me)
} }
func (self *VMEnv) Create(me vm.ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { 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) return exe.Create(me)
} }

View File

@ -20,6 +20,7 @@ import (
"github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/pbkdf2"
"golang.org/x/crypto/ripemd160" "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 // Creates an ethereum address given the bytes and the nonce
func CreateAddress(b []byte, nonce uint64) []byte { func CreateAddress(b common.Address, nonce uint64) common.Address {
return Sha3(common.NewValue([]interface{}{b, nonce}).Encode())[12:] 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 { func Sha256(data []byte) []byte {

View File

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

View File

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

View File

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