From ca1b2a1a91401255ab4e26cec7eb575b99ecb8da Mon Sep 17 00:00:00 2001
From: obscuren <geffobscura@gmail.com>
Date: Sat, 3 Jan 2015 17:18:43 +0100
Subject: 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
---
 cmd/mist/debugger.go     |  2 +-
 cmd/utils/vm_env.go      | 12 ++++++++++--
 core/block_manager.go    | 12 +++++++-----
 core/chain_manager.go    | 16 ++++++++--------
 core/state_transition.go | 41 +++++++++++++++++++++--------------------
 core/vm_env.go           | 13 ++++++++++---
 state/manifest.go        |  6 ++++++
 tests/helper/vm.go       |  7 ++++---
 vm/environment.go        |  3 +--
 vm/types.go              |  4 ++--
 vm/vm_debug.go           | 19 +++++++++++--------
 xeth/pipe.go             |  2 +-
 xeth/vm_env.go           | 11 +++++++++--
 13 files changed, 91 insertions(+), 57 deletions(-)

diff --git a/cmd/mist/debugger.go b/cmd/mist/debugger.go
index 0e97a6652..618e31f4e 100644
--- a/cmd/mist/debugger.go
+++ b/cmd/mist/debugger.go
@@ -151,7 +151,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
 
 	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))
 	go func() {
diff --git a/cmd/utils/vm_env.go b/cmd/utils/vm_env.go
index 19091bdc5..acc2ffad9 100644
--- a/cmd/utils/vm_env.go
+++ b/cmd/utils/vm_env.go
@@ -10,6 +10,7 @@ import (
 )
 
 type VMEnv struct {
+	chain *core.ChainManager
 	state *state.StateDB
 	block *types.Block
 
@@ -20,8 +21,9 @@ type VMEnv struct {
 	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{
+		chain:      chain,
 		state:      state,
 		block:      block,
 		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) Time() int64           { return self.block.Time() }
 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) Value() *big.Int       { return self.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) GetHash(n uint64) []byte {
+	if block := self.chain.GetBlockByNumber(n); block != nil {
+		return block.Hash()
+	}
+
+	return nil
+}
 func (self *VMEnv) AddLog(log state.Log) {
 	self.state.AddLog(log)
 }
diff --git a/core/block_manager.go b/core/block_manager.go
index 8a5455306..09f569d96 100644
--- a/core/block_manager.go
+++ b/core/block_manager.go
@@ -113,7 +113,7 @@ done:
 		txGas := new(big.Int).Set(tx.Gas())
 
 		cb := state.GetStateObject(coinbase.Address())
-		st := NewStateTransition(cb, tx, state, block)
+		st := NewStateTransition(NewEnv(state, self.bc, tx, block), tx, cb)
 		_, err = st.TransitionState()
 		if err != nil {
 			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
 		state.Sync()
 
+		state.Manifest().SetHash(block.Hash())
+
 		messages := state.Manifest().Messages
 		state.Manifest().Reset()
 
@@ -339,10 +341,10 @@ func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent
 	account.AddAmount(reward)
 
 	statedb.Manifest().AddMessage(&state.Message{
-		To:     block.Header().Coinbase,
-		Input:  nil,
-		Origin: nil,
-		Block:  block.Hash(), Timestamp: int64(block.Header().Time), Coinbase: block.Header().Coinbase, Number: block.Header().Number,
+		To:        block.Header().Coinbase,
+		Input:     nil,
+		Origin:    nil,
+		Timestamp: int64(block.Header().Time), Coinbase: block.Header().Coinbase, Number: block.Header().Number,
 		Value: new(big.Int).Add(reward, block.Reward),
 	})
 
diff --git a/core/chain_manager.go b/core/chain_manager.go
index ece98d783..82b17cd93 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -271,15 +271,15 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
 	self.mu.RLock()
 	defer self.mu.RUnlock()
 
-	block := self.currentBlock
-	for ; block != nil; block = self.GetBlock(block.Header().ParentHash) {
-		if block.Header().Number.Uint64() == num {
-			break
-		}
-	}
+	var block *types.Block
 
-	if block != nil && block.Header().Number.Uint64() == 0 && num != 0 {
-		return nil
+	if num <= self.currentBlock.Number().Uint64() {
+		block = self.currentBlock
+		for ; block != nil; block = self.GetBlock(block.Header().ParentHash) {
+			if block.Header().Number.Uint64() == num {
+				break
+			}
+		}
 	}
 
 	return block
diff --git a/core/state_transition.go b/core/state_transition.go
index 91cfd5fe3..b22c5bf21 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -4,7 +4,6 @@ import (
 	"fmt"
 	"math/big"
 
-	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethutil"
 	"github.com/ethereum/go-ethereum/state"
@@ -28,18 +27,17 @@ import (
  * 6) Derive new state root
  */
 type StateTransition struct {
-	coinbase, receiver []byte
-	msg                Message
-	gas, gasPrice      *big.Int
-	initialGas         *big.Int
-	value              *big.Int
-	data               []byte
-	state              *state.StateDB
-	block              *types.Block
+	coinbase      []byte
+	msg           Message
+	gas, gasPrice *big.Int
+	initialGas    *big.Int
+	value         *big.Int
+	data          []byte
+	state         *state.StateDB
 
 	cb, rec, sen *state.StateObject
 
-	Env vm.Environment
+	env vm.Environment
 }
 
 type Message interface {
@@ -69,16 +67,19 @@ func MessageGasValue(msg Message) *big.Int {
 	return new(big.Int).Mul(msg.Gas(), msg.GasPrice())
 }
 
-func NewStateTransition(coinbase *state.StateObject, msg Message, state *state.StateDB, block *types.Block) *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}
-}
-
-func (self *StateTransition) VmEnv() vm.Environment {
-	if self.Env == nil {
-		self.Env = NewEnv(self.state, self.msg, self.block)
+func NewStateTransition(env vm.Environment, msg Message, coinbase *state.StateObject) *StateTransition {
+	return &StateTransition{
+		coinbase:   coinbase.Address(),
+		env:        env,
+		msg:        msg,
+		gas:        new(big.Int),
+		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 {
@@ -183,7 +184,7 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
 		return
 	}
 
-	vmenv := self.VmEnv()
+	vmenv := self.env
 	var ref vm.ContextRef
 	if MessageCreatesContract(msg) {
 		contract := MakeContract(msg, self.state)
diff --git a/core/vm_env.go b/core/vm_env.go
index 4e0315ff3..624a63333 100644
--- a/core/vm_env.go
+++ b/core/vm_env.go
@@ -13,10 +13,12 @@ type VMEnv struct {
 	block *types.Block
 	msg   Message
 	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{
+		chain: chain,
 		state: state,
 		block: block,
 		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) 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) Time() int64           { return self.block.Time() }
 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) 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) GetHash(n uint64) []byte {
+	if block := self.chain.GetBlockByNumber(n); block != nil {
+		return block.Hash()
+	}
+
+	return nil
+}
 func (self *VMEnv) AddLog(log state.Log) {
 	self.state.AddLog(log)
 }
diff --git a/state/manifest.go b/state/manifest.go
index 21cd04a1a..994019a08 100644
--- a/state/manifest.go
+++ b/state/manifest.go
@@ -30,6 +30,12 @@ func (self *Manifest) AddMessage(msg *Message) *Message {
 	return msg
 }
 
+func (self *Manifest) SetHash(hash []byte) {
+	for _, message := range self.Messages {
+		message.Block = hash
+	}
+}
+
 type Messages []*Message
 type Message struct {
 	To, From  []byte
diff --git a/tests/helper/vm.go b/tests/helper/vm.go
index aa17313b7..123003faa 100644
--- a/tests/helper/vm.go
+++ b/tests/helper/vm.go
@@ -55,9 +55,11 @@ func (self *Env) PrevHash() []byte      { return self.parent }
 func (self *Env) Coinbase() []byte      { return self.coinbase }
 func (self *Env) Time() int64           { return self.time }
 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) GasLimit() *big.Int    { return self.gasLimit }
+func (self *Env) GetHash(n uint64) []byte {
+	return nil
+}
 func (self *Env) AddLog(log state.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)
 	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)
+	st := core.NewStateTransition(vmenv, message, coinbase)
 	vmenv.origin = keyPair.Address()
-	st.Env = vmenv
 	ret, err := st.TransitionState()
 	statedb.Update(vmenv.Gas)
 
diff --git a/vm/environment.go b/vm/environment.go
index 01bbd56ce..d8b1cef28 100644
--- a/vm/environment.go
+++ b/vm/environment.go
@@ -14,11 +14,10 @@ type Environment interface {
 
 	Origin() []byte
 	BlockNumber() *big.Int
-	PrevHash() []byte
+	GetHash(n uint64) []byte
 	Coinbase() []byte
 	Time() int64
 	Difficulty() *big.Int
-	BlockHash() []byte
 	GasLimit() *big.Int
 	Transfer(from, to Account, amount *big.Int) error
 	AddLog(state.Log)
diff --git a/vm/types.go b/vm/types.go
index ec9c7e74e..1ea80a212 100644
--- a/vm/types.go
+++ b/vm/types.go
@@ -59,7 +59,7 @@ const (
 const (
 
 	// 0x40 range - block operations
-	PREVHASH OpCode = 0x40 + iota
+	BLOCKHASH OpCode = 0x40 + iota
 	COINBASE
 	TIMESTAMP
 	NUMBER
@@ -216,7 +216,7 @@ var opCodeToString = map[OpCode]string{
 	GASPRICE:     "TXGASPRICE",
 
 	// 0x40 range - block operations
-	PREVHASH:    "PREVHASH",
+	BLOCKHASH:   "BLOCKHASH",
 	COINBASE:    "COINBASE",
 	TIMESTAMP:   "TIMESTAMP",
 	NUMBER:      "NUMBER",
diff --git a/vm/vm_debug.go b/vm/vm_debug.go
index 6ad385fd0..baacf752b 100644
--- a/vm/vm_debug.go
+++ b/vm/vm_debug.go
@@ -42,9 +42,9 @@ func (self *DebugVm) Run(me, caller ContextRef, code []byte, value, gas, price *
 
 	msg := self.env.State().Manifest().AddMessage(&state.Message{
 		To: me.Address(), From: caller.Address(),
-		Input:  callData,
-		Origin: self.env.Origin(),
-		Block:  self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(),
+		Input:     callData,
+		Origin:    self.env.Origin(),
+		Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(),
 		Value: value,
 	})
 	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)
 
 			// 0x40 range
-		case PREVHASH:
-			prevHash := self.env.PrevHash()
-
-			stack.Push(ethutil.BigD(prevHash))
+		case BLOCKHASH:
+			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())))
+			}
 
-			self.Printf(" => 0x%x", prevHash)
+			self.Printf(" => 0x%x", stack.Peek().Bytes())
 		case COINBASE:
 			coinbase := self.env.Coinbase()
 
diff --git a/xeth/pipe.go b/xeth/pipe.go
index cae6ee1de..05cefd8ad 100644
--- a/xeth/pipe.go
+++ b/xeth/pipe.go
@@ -87,7 +87,7 @@ func (self *XEth) ExecuteObject(object *Object, data []byte, value, gas, price *
 
 	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())
 }
 
diff --git a/xeth/vm_env.go b/xeth/vm_env.go
index d2a21afd5..1470b9eaa 100644
--- a/xeth/vm_env.go
+++ b/xeth/vm_env.go
@@ -10,6 +10,7 @@ import (
 )
 
 type VMEnv struct {
+	chain  *core.ChainManager
 	state  *state.StateDB
 	block  *types.Block
 	value  *big.Int
@@ -18,7 +19,7 @@ type VMEnv struct {
 	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{
 		state:  state,
 		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) Time() int64           { return self.block.Time() }
 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) Value() *big.Int       { return self.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) GetHash(n uint64) []byte {
+	if block := self.chain.GetBlockByNumber(n); block != nil {
+		return block.Hash()
+	}
+
+	return nil
+}
 func (self *VMEnv) AddLog(log state.Log) {
 	self.state.AddLog(log)
 }
-- 
cgit