pull/150/head
obscuren 11 years ago
parent ca747f2688
commit 116516158d
  1. 4
      ethchain/closure.go
  2. 8
      ethchain/contract.go
  3. 8
      ethchain/stack.go
  4. 14
      ethchain/state_manager.go
  5. 98
      ethchain/vm.go
  6. 29
      ethchain/vm_test.go

@ -52,7 +52,7 @@ func (c *Closure) Get(x *big.Int) *ethutil.Value {
} }
func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { func (c *Closure) Gets(x, y *big.Int) *ethutil.Value {
if x.Int64() > int64(len(c.Script)) || y.Int64() > int64(len(c.Script)) { if x.Int64() >= int64(len(c.Script)) || y.Int64() >= int64(len(c.Script)) {
return ethutil.NewValue(0) return ethutil.NewValue(0)
} }
@ -69,7 +69,7 @@ func (c *Closure) Address() []byte {
return c.object.Address() return c.object.Address()
} }
type DebugHook func(op OpCode) type DebugHook func(op OpCode, mem *Memory, stack *Stack)
func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) []byte { func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) []byte {
c.Args = args c.Args = args

@ -69,6 +69,14 @@ func (c *Contract) Address() []byte {
return c.address return c.address
} }
func (c *Contract) Script() []byte {
return c.script
}
func (c *Contract) Init() []byte {
return c.initScript
}
func (c *Contract) RlpEncode() []byte { func (c *Contract) RlpEncode() []byte {
return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root, c.script, c.initScript}) return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root, c.script, c.initScript})
} }

@ -173,6 +173,10 @@ func NewStack() *Stack {
return &Stack{} return &Stack{}
} }
func (st *Stack) Data() []*big.Int {
return st.data
}
func (st *Stack) Pop() *big.Int { func (st *Stack) Pop() *big.Int {
str := st.data[len(st.data)-1] str := st.data[len(st.data)-1]
@ -246,6 +250,10 @@ func (m *Memory) Len() int {
return len(m.store) return len(m.store)
} }
func (m *Memory) Data() []byte {
return m.store
}
func (m *Memory) Print() { func (m *Memory) Print() {
fmt.Printf("### mem %d bytes ###\n", len(m.store)) fmt.Printf("### mem %d bytes ###\n", len(m.store))
if len(m.store) > 0 { if len(m.store) > 0 {

@ -318,14 +318,14 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo
caller := sm.procState.GetAccount(tx.Sender()) caller := sm.procState.GetAccount(tx.Sender())
closure := NewClosure(caller, contract, contract.script, sm.procState, tx.Gas, tx.Value) closure := NewClosure(caller, contract, contract.script, sm.procState, tx.Gas, tx.Value)
vm := NewVm(sm.procState, RuntimeVars{ vm := NewVm(sm.procState, RuntimeVars{
origin: caller.Address(), Origin: caller.Address(),
blockNumber: block.BlockInfo().Number, BlockNumber: block.BlockInfo().Number,
prevHash: block.PrevHash, PrevHash: block.PrevHash,
coinbase: block.Coinbase, Coinbase: block.Coinbase,
time: block.Time, Time: block.Time,
diff: block.Difficulty, Diff: block.Difficulty,
// XXX Tx data? Could be just an argument to the closure instead // XXX Tx data? Could be just an argument to the closure instead
txData: nil, TxData: nil,
}) })
closure.Call(vm, nil, nil) closure.Call(vm, nil, nil)

@ -2,7 +2,7 @@ package ethchain
import ( import (
_ "bytes" _ "bytes"
_ "fmt" "fmt"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
_ "github.com/obscuren/secp256k1-go" _ "github.com/obscuren/secp256k1-go"
_ "math" _ "math"
@ -33,13 +33,13 @@ type Vm struct {
} }
type RuntimeVars struct { type RuntimeVars struct {
origin []byte Origin []byte
blockNumber uint64 BlockNumber uint64
prevHash []byte PrevHash []byte
coinbase []byte Coinbase []byte
time int64 Time int64
diff *big.Int Diff *big.Int
txData []string TxData []string
} }
func NewVm(state *State, vars RuntimeVars) *Vm { func NewVm(state *State, vars RuntimeVars) *Vm {
@ -65,9 +65,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
// The base for all big integer arithmetic // The base for all big integer arithmetic
base := new(big.Int) base := new(big.Int)
if ethutil.Config.Debug { /*
ethutil.Config.Log.Debugf("# op\n") if ethutil.Config.Debug {
} ethutil.Config.Log.Debugf("# op\n")
}
*/
for { for {
step++ step++
@ -75,9 +77,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
val := closure.Get(pc) val := closure.Get(pc)
// Get the opcode (it must be an opcode!) // Get the opcode (it must be an opcode!)
op := OpCode(val.Uint()) op := OpCode(val.Uint())
if ethutil.Config.Debug { /*
ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) if ethutil.Config.Debug {
} ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String())
}
*/
// TODO Get each instruction cost properly // TODO Get each instruction cost properly
gas := new(big.Int) gas := new(big.Int)
@ -270,7 +274,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
case oBALANCE: case oBALANCE:
stack.Push(closure.Value) stack.Push(closure.Value)
case oORIGIN: case oORIGIN:
stack.Push(ethutil.BigD(vm.vars.origin)) stack.Push(ethutil.BigD(vm.vars.Origin))
case oCALLER: case oCALLER:
stack.Push(ethutil.BigD(closure.Callee().Address())) stack.Push(ethutil.BigD(closure.Callee().Address()))
case oCALLVALUE: case oCALLVALUE:
@ -286,15 +290,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
// 0x40 range // 0x40 range
case oPREVHASH: case oPREVHASH:
stack.Push(ethutil.BigD(vm.vars.prevHash)) stack.Push(ethutil.BigD(vm.vars.PrevHash))
case oCOINBASE: case oCOINBASE:
stack.Push(ethutil.BigD(vm.vars.coinbase)) stack.Push(ethutil.BigD(vm.vars.Coinbase))
case oTIMESTAMP: case oTIMESTAMP:
stack.Push(big.NewInt(vm.vars.time)) stack.Push(big.NewInt(vm.vars.Time))
case oNUMBER: case oNUMBER:
stack.Push(big.NewInt(int64(vm.vars.blockNumber))) stack.Push(big.NewInt(int64(vm.vars.BlockNumber)))
case oDIFFICULTY: case oDIFFICULTY:
stack.Push(vm.vars.diff) stack.Push(vm.vars.Diff)
case oGASLIMIT: case oGASLIMIT:
// TODO // TODO
@ -406,7 +410,59 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
pc.Add(pc, ethutil.Big1) pc.Add(pc, ethutil.Big1)
if hook != nil { if hook != nil {
hook(op) hook(op, mem, stack)
}
}
}
func Disassemble(script []byte) (asm []string) {
pc := new(big.Int)
for {
if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 {
return
}
// Get the memory location of pc
val := script[pc.Int64()]
// Get the opcode (it must be an opcode!)
op := OpCode(val)
asm = append(asm, fmt.Sprintf("%v", op))
switch op {
case oPUSH: // Push PC+1 on to the stack
pc.Add(pc, ethutil.Big1)
data := script[pc.Int64() : pc.Int64()+32]
val := ethutil.BigD(data)
var b []byte
if val.Int64() == 0 {
b = []byte{0}
} else {
b = val.Bytes()
}
asm = append(asm, fmt.Sprintf("0x%x", b))
pc.Add(pc, big.NewInt(31))
case oPUSH20:
pc.Add(pc, ethutil.Big1)
data := script[pc.Int64() : pc.Int64()+20]
val := ethutil.BigD(data)
var b []byte
if val.Int64() == 0 {
b = []byte{0}
} else {
b = val.Bytes()
}
asm = append(asm, fmt.Sprintf("0x%x", b))
pc.Add(pc, big.NewInt(19))
} }
pc.Add(pc, ethutil.Big1)
} }
return
} }

@ -130,14 +130,29 @@ func TestRun4(t *testing.T) {
callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int)) callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int))
vm := NewVm(state, RuntimeVars{ vm := NewVm(state, RuntimeVars{
origin: account.Address(), Origin: account.Address(),
blockNumber: 1, BlockNumber: 1,
prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), PrevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
time: 1, Time: 1,
diff: big.NewInt(256), Diff: big.NewInt(256),
// XXX Tx data? Could be just an argument to the closure instead // XXX Tx data? Could be just an argument to the closure instead
txData: nil, TxData: nil,
}) })
callerClosure.Call(vm, nil, nil) callerClosure.Call(vm, nil, nil)
} }
func TestRun5(t *testing.T) {
ethutil.ReadConfig("")
asm, _ := mutan.Compile(strings.NewReader(`
int32 a = 10
int32 b = 20
if a > b {
int32 c = this.caller()
}
exit()
`), false)
script := ethutil.Assemble(asm...)
fmt.Println(Disassemble(script))
}

Loading…
Cancel
Save