Changed prev_hash to block_hash, state transition now uses vm env

* PREVHASH => BLOCKHASH( N )
* State transition object uses VMEnv as it's query interface
* Updated vm.Enviroment has GetHash( n ) for BLOCKHASH instruction
* Added GetHash to xeth, core, utils & test environments
This commit is contained in:
obscuren 2015-01-03 17:18:43 +01:00
parent 16f417f5af
commit ca1b2a1a91
13 changed files with 91 additions and 57 deletions

View File

@ -151,7 +151,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
block := self.lib.eth.ChainManager().CurrentBlock() block := self.lib.eth.ChainManager().CurrentBlock()
env := utils.NewEnv(statedb, block, account.Address(), value) env := utils.NewEnv(self.lib.eth.ChainManager(), statedb, block, account.Address(), value)
self.Logf("callsize %d", len(script)) self.Logf("callsize %d", len(script))
go func() { go func() {

View File

@ -10,6 +10,7 @@ import (
) )
type VMEnv struct { type VMEnv struct {
chain *core.ChainManager
state *state.StateDB state *state.StateDB
block *types.Block block *types.Block
@ -20,8 +21,9 @@ type VMEnv struct {
Gas *big.Int Gas *big.Int
} }
func NewEnv(state *state.StateDB, block *types.Block, transactor []byte, value *big.Int) *VMEnv { func NewEnv(chain *core.ChainManager, state *state.StateDB, block *types.Block, transactor []byte, value *big.Int) *VMEnv {
return &VMEnv{ return &VMEnv{
chain: chain,
state: state, state: state,
block: block, block: block,
transactor: transactor, transactor: transactor,
@ -35,12 +37,18 @@ func (self *VMEnv) PrevHash() []byte { return self.block.ParentHash() }
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() } func (self *VMEnv) Coinbase() []byte { 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) BlockHash() []byte { return self.block.Hash() }
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() }
func (self *VMEnv) Value() *big.Int { return self.value } func (self *VMEnv) Value() *big.Int { return self.value }
func (self *VMEnv) State() *state.StateDB { return self.state } func (self *VMEnv) State() *state.StateDB { return self.state }
func (self *VMEnv) Depth() int { return self.depth } 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) GetHash(n uint64) []byte {
if block := self.chain.GetBlockByNumber(n); block != nil {
return block.Hash()
}
return nil
}
func (self *VMEnv) AddLog(log state.Log) { func (self *VMEnv) AddLog(log state.Log) {
self.state.AddLog(log) self.state.AddLog(log)
} }

View File

@ -113,7 +113,7 @@ done:
txGas := new(big.Int).Set(tx.Gas()) txGas := new(big.Int).Set(tx.Gas())
cb := state.GetStateObject(coinbase.Address()) cb := state.GetStateObject(coinbase.Address())
st := NewStateTransition(cb, tx, state, block) st := NewStateTransition(NewEnv(state, self.bc, tx, block), tx, cb)
_, err = st.TransitionState() _, err = st.TransitionState()
if err != nil { if err != nil {
switch { switch {
@ -232,6 +232,8 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
// Sync the current block's state to the database and cancelling out the deferred Undo // Sync the current block's state to the database and cancelling out the deferred Undo
state.Sync() state.Sync()
state.Manifest().SetHash(block.Hash())
messages := state.Manifest().Messages messages := state.Manifest().Messages
state.Manifest().Reset() state.Manifest().Reset()
@ -342,7 +344,7 @@ func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent
To: block.Header().Coinbase, To: block.Header().Coinbase,
Input: nil, Input: nil,
Origin: nil, Origin: nil,
Block: block.Hash(), Timestamp: int64(block.Header().Time), Coinbase: block.Header().Coinbase, Number: block.Header().Number, Timestamp: int64(block.Header().Time), Coinbase: block.Header().Coinbase, Number: block.Header().Number,
Value: new(big.Int).Add(reward, block.Reward), Value: new(big.Int).Add(reward, block.Reward),
}) })

View File

@ -271,15 +271,15 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
self.mu.RLock() self.mu.RLock()
defer self.mu.RUnlock() defer self.mu.RUnlock()
block := self.currentBlock var block *types.Block
if num <= self.currentBlock.Number().Uint64() {
block = self.currentBlock
for ; block != nil; block = self.GetBlock(block.Header().ParentHash) { for ; block != nil; block = self.GetBlock(block.Header().ParentHash) {
if block.Header().Number.Uint64() == num { if block.Header().Number.Uint64() == num {
break break
} }
} }
if block != nil && block.Header().Number.Uint64() == 0 && num != 0 {
return nil
} }
return block return block

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/state"
@ -28,18 +27,17 @@ import (
* 6) Derive new state root * 6) Derive new state root
*/ */
type StateTransition struct { type StateTransition struct {
coinbase, receiver []byte coinbase []byte
msg Message msg Message
gas, gasPrice *big.Int gas, gasPrice *big.Int
initialGas *big.Int initialGas *big.Int
value *big.Int value *big.Int
data []byte data []byte
state *state.StateDB state *state.StateDB
block *types.Block
cb, rec, sen *state.StateObject cb, rec, sen *state.StateObject
Env vm.Environment env vm.Environment
} }
type Message interface { type Message interface {
@ -69,16 +67,19 @@ func MessageGasValue(msg Message) *big.Int {
return new(big.Int).Mul(msg.Gas(), msg.GasPrice()) return new(big.Int).Mul(msg.Gas(), msg.GasPrice())
} }
func NewStateTransition(coinbase *state.StateObject, msg Message, state *state.StateDB, block *types.Block) *StateTransition { func NewStateTransition(env vm.Environment, msg Message, coinbase *state.StateObject) *StateTransition {
return &StateTransition{coinbase.Address(), msg.To(), msg, new(big.Int), new(big.Int).Set(msg.GasPrice()), new(big.Int), msg.Value(), msg.Data(), state, block, coinbase, nil, nil, nil} return &StateTransition{
} coinbase: coinbase.Address(),
env: env,
func (self *StateTransition) VmEnv() vm.Environment { msg: msg,
if self.Env == nil { gas: new(big.Int),
self.Env = NewEnv(self.state, self.msg, self.block) gasPrice: new(big.Int).Set(msg.GasPrice()),
initialGas: new(big.Int),
value: msg.Value(),
data: msg.Data(),
state: env.State(),
cb: coinbase,
} }
return self.Env
} }
func (self *StateTransition) Coinbase() *state.StateObject { func (self *StateTransition) Coinbase() *state.StateObject {
@ -183,7 +184,7 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
return return
} }
vmenv := self.VmEnv() 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)

View File

@ -13,10 +13,12 @@ type VMEnv struct {
block *types.Block block *types.Block
msg Message msg Message
depth int depth int
chain *ChainManager
} }
func NewEnv(state *state.StateDB, msg Message, block *types.Block) *VMEnv { func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types.Block) *VMEnv {
return &VMEnv{ return &VMEnv{
chain: chain,
state: state, state: state,
block: block, block: block,
msg: msg, msg: msg,
@ -25,16 +27,21 @@ func NewEnv(state *state.StateDB, msg Message, block *types.Block) *VMEnv {
func (self *VMEnv) Origin() []byte { return self.msg.From() } func (self *VMEnv) Origin() []byte { 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) PrevHash() []byte { return self.block.ParentHash() }
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() } func (self *VMEnv) Coinbase() []byte { 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) BlockHash() []byte { return self.block.Hash() }
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() }
func (self *VMEnv) Value() *big.Int { return self.msg.Value() } func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
func (self *VMEnv) State() *state.StateDB { return self.state } func (self *VMEnv) State() *state.StateDB { return self.state }
func (self *VMEnv) Depth() int { return self.depth } 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) GetHash(n uint64) []byte {
if block := self.chain.GetBlockByNumber(n); block != nil {
return block.Hash()
}
return nil
}
func (self *VMEnv) AddLog(log state.Log) { func (self *VMEnv) AddLog(log state.Log) {
self.state.AddLog(log) self.state.AddLog(log)
} }

View File

@ -30,6 +30,12 @@ func (self *Manifest) AddMessage(msg *Message) *Message {
return msg return msg
} }
func (self *Manifest) SetHash(hash []byte) {
for _, message := range self.Messages {
message.Block = hash
}
}
type Messages []*Message type Messages []*Message
type Message struct { type Message struct {
To, From []byte To, From []byte

View File

@ -55,9 +55,11 @@ func (self *Env) PrevHash() []byte { return self.parent }
func (self *Env) Coinbase() []byte { return self.coinbase } func (self *Env) Coinbase() []byte { return self.coinbase }
func (self *Env) Time() int64 { return self.time } func (self *Env) Time() int64 { return self.time }
func (self *Env) Difficulty() *big.Int { return self.difficulty } func (self *Env) Difficulty() *big.Int { return self.difficulty }
func (self *Env) BlockHash() []byte { return nil }
func (self *Env) State() *state.StateDB { return self.state } func (self *Env) State() *state.StateDB { return self.state }
func (self *Env) GasLimit() *big.Int { return self.gasLimit } func (self *Env) GasLimit() *big.Int { return self.gasLimit }
func (self *Env) GetHash(n uint64) []byte {
return nil
}
func (self *Env) AddLog(log state.Log) { func (self *Env) AddLog(log state.Log) {
self.logs = append(self.logs, log) self.logs = append(self.logs, log)
} }
@ -126,10 +128,9 @@ func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state.
message := NewMessage(keyPair.Address(), to, data, value, gas, price) message := NewMessage(keyPair.Address(), to, data, value, gas, price)
Log.DebugDetailf("message{ to: %x, from %x, value: %v, gas: %v, price: %v }\n", message.to[:4], message.from[:4], message.value, message.gas, message.price) Log.DebugDetailf("message{ to: %x, from %x, value: %v, gas: %v, price: %v }\n", message.to[:4], message.from[:4], message.value, message.gas, message.price)
st := core.NewStateTransition(coinbase, message, statedb, nil)
vmenv := NewEnvFromMap(statedb, env, tx) vmenv := NewEnvFromMap(statedb, env, tx)
st := core.NewStateTransition(vmenv, message, coinbase)
vmenv.origin = keyPair.Address() vmenv.origin = keyPair.Address()
st.Env = vmenv
ret, err := st.TransitionState() ret, err := st.TransitionState()
statedb.Update(vmenv.Gas) statedb.Update(vmenv.Gas)

View File

@ -14,11 +14,10 @@ type Environment interface {
Origin() []byte Origin() []byte
BlockNumber() *big.Int BlockNumber() *big.Int
PrevHash() []byte GetHash(n uint64) []byte
Coinbase() []byte Coinbase() []byte
Time() int64 Time() int64
Difficulty() *big.Int Difficulty() *big.Int
BlockHash() []byte
GasLimit() *big.Int GasLimit() *big.Int
Transfer(from, to Account, amount *big.Int) error Transfer(from, to Account, amount *big.Int) error
AddLog(state.Log) AddLog(state.Log)

View File

@ -59,7 +59,7 @@ const (
const ( const (
// 0x40 range - block operations // 0x40 range - block operations
PREVHASH OpCode = 0x40 + iota BLOCKHASH OpCode = 0x40 + iota
COINBASE COINBASE
TIMESTAMP TIMESTAMP
NUMBER NUMBER
@ -216,7 +216,7 @@ var opCodeToString = map[OpCode]string{
GASPRICE: "TXGASPRICE", GASPRICE: "TXGASPRICE",
// 0x40 range - block operations // 0x40 range - block operations
PREVHASH: "PREVHASH", BLOCKHASH: "BLOCKHASH",
COINBASE: "COINBASE", COINBASE: "COINBASE",
TIMESTAMP: "TIMESTAMP", TIMESTAMP: "TIMESTAMP",
NUMBER: "NUMBER", NUMBER: "NUMBER",

View File

@ -44,7 +44,7 @@ func (self *DebugVm) Run(me, caller ContextRef, code []byte, value, gas, price *
To: me.Address(), From: caller.Address(), To: me.Address(), From: caller.Address(),
Input: callData, Input: callData,
Origin: self.env.Origin(), Origin: self.env.Origin(),
Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(),
Value: value, Value: value,
}) })
context := NewContext(msg, caller, me, code, gas, price) context := NewContext(msg, caller, me, code, gas, price)
@ -516,12 +516,15 @@ func (self *DebugVm) Run(me, caller ContextRef, code []byte, value, gas, price *
self.Printf(" => %v", context.Price) self.Printf(" => %v", context.Price)
// 0x40 range // 0x40 range
case PREVHASH: case BLOCKHASH:
prevHash := self.env.PrevHash() num := stack.Pop()
if num.Cmp(new(big.Int).Sub(self.env.BlockNumber(), ethutil.Big256)) < 0 {
stack.Push(ethutil.Big0)
} else {
stack.Push(ethutil.BigD(self.env.GetHash(num.Uint64())))
}
stack.Push(ethutil.BigD(prevHash)) self.Printf(" => 0x%x", stack.Peek().Bytes())
self.Printf(" => 0x%x", prevHash)
case COINBASE: case COINBASE:
coinbase := self.env.Coinbase() coinbase := self.env.Coinbase()

View File

@ -87,7 +87,7 @@ func (self *XEth) ExecuteObject(object *Object, data []byte, value, gas, price *
self.Vm.State = self.World().State().Copy() self.Vm.State = self.World().State().Copy()
vmenv := NewEnv(self.Vm.State, block, value.BigInt(), initiator.Address()) vmenv := NewEnv(self.chainManager, self.Vm.State, block, value.BigInt(), initiator.Address())
return vmenv.Call(initiator, object.Address(), data, gas.BigInt(), price.BigInt(), value.BigInt()) return vmenv.Call(initiator, object.Address(), data, gas.BigInt(), price.BigInt(), value.BigInt())
} }

View File

@ -10,6 +10,7 @@ import (
) )
type VMEnv struct { type VMEnv struct {
chain *core.ChainManager
state *state.StateDB state *state.StateDB
block *types.Block block *types.Block
value *big.Int value *big.Int
@ -18,7 +19,7 @@ type VMEnv struct {
depth int depth int
} }
func NewEnv(state *state.StateDB, block *types.Block, value *big.Int, sender []byte) *VMEnv { func NewEnv(chain *core.ChainManager, state *state.StateDB, block *types.Block, value *big.Int, sender []byte) *VMEnv {
return &VMEnv{ return &VMEnv{
state: state, state: state,
block: block, block: block,
@ -33,12 +34,18 @@ func (self *VMEnv) PrevHash() []byte { return self.block.ParentHash() }
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() } func (self *VMEnv) Coinbase() []byte { 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) BlockHash() []byte { return self.block.Hash() }
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() }
func (self *VMEnv) Value() *big.Int { return self.value } func (self *VMEnv) Value() *big.Int { return self.value }
func (self *VMEnv) State() *state.StateDB { return self.state } func (self *VMEnv) State() *state.StateDB { return self.state }
func (self *VMEnv) Depth() int { return self.depth } 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) GetHash(n uint64) []byte {
if block := self.chain.GetBlockByNumber(n); block != nil {
return block.Hash()
}
return nil
}
func (self *VMEnv) AddLog(log state.Log) { func (self *VMEnv) AddLog(log state.Log) {
self.state.AddLog(log) self.state.AddLog(log)
} }