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()
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() {

View File

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

View File

@ -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()
@ -342,7 +344,7 @@ func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent
To: block.Header().Coinbase,
Input: 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),
})

View File

@ -271,15 +271,15 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
self.mu.RLock()
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) {
if block.Header().Number.Uint64() == num {
break
}
}
if block != nil && block.Header().Number.Uint64() == 0 && num != 0 {
return nil
}
return block

View File

@ -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
coinbase []byte
msg Message
gas, gasPrice *big.Int
initialGas *big.Int
value *big.Int
data []byte
state *state.StateDB
block *types.Block
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 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,
}
func (self *StateTransition) VmEnv() vm.Environment {
if self.Env == nil {
self.Env = NewEnv(self.state, self.msg, self.block)
}
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)

View File

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

View File

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

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

View File

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

View File

@ -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",

View File

@ -44,7 +44,7 @@ func (self *DebugVm) Run(me, caller ContextRef, code []byte, value, gas, price *
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(),
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()
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())))
}
stack.Push(ethutil.BigD(prevHash))
self.Printf(" => 0x%x", prevHash)
self.Printf(" => 0x%x", stack.Peek().Bytes())
case 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()
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())
}

View File

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