This commit is contained in:
obscuren 2014-04-11 13:29:57 -04:00
parent ca747f2688
commit 116516158d
6 changed files with 124 additions and 37 deletions

View File

@ -52,7 +52,7 @@ func (c *Closure) Get(x *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)
}
@ -69,7 +69,7 @@ func (c *Closure) Address() []byte {
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 {
c.Args = args

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@ package ethchain
import (
_ "bytes"
_ "fmt"
"fmt"
"github.com/ethereum/eth-go/ethutil"
_ "github.com/obscuren/secp256k1-go"
_ "math"
@ -33,13 +33,13 @@ type Vm struct {
}
type RuntimeVars struct {
origin []byte
blockNumber uint64
prevHash []byte
coinbase []byte
time int64
diff *big.Int
txData []string
Origin []byte
BlockNumber uint64
PrevHash []byte
Coinbase []byte
Time int64
Diff *big.Int
TxData []string
}
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
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 {
step++
@ -75,9 +77,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
val := closure.Get(pc)
// Get the opcode (it must be an opcode!)
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
gas := new(big.Int)
@ -270,7 +274,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
case oBALANCE:
stack.Push(closure.Value)
case oORIGIN:
stack.Push(ethutil.BigD(vm.vars.origin))
stack.Push(ethutil.BigD(vm.vars.Origin))
case oCALLER:
stack.Push(ethutil.BigD(closure.Callee().Address()))
case oCALLVALUE:
@ -286,15 +290,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
// 0x40 range
case oPREVHASH:
stack.Push(ethutil.BigD(vm.vars.prevHash))
stack.Push(ethutil.BigD(vm.vars.PrevHash))
case oCOINBASE:
stack.Push(ethutil.BigD(vm.vars.coinbase))
stack.Push(ethutil.BigD(vm.vars.Coinbase))
case oTIMESTAMP:
stack.Push(big.NewInt(vm.vars.time))
stack.Push(big.NewInt(vm.vars.Time))
case oNUMBER:
stack.Push(big.NewInt(int64(vm.vars.blockNumber)))
stack.Push(big.NewInt(int64(vm.vars.BlockNumber)))
case oDIFFICULTY:
stack.Push(vm.vars.diff)
stack.Push(vm.vars.Diff)
case oGASLIMIT:
// TODO
@ -406,7 +410,59 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
pc.Add(pc, ethutil.Big1)
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
}

View File

@ -130,14 +130,29 @@ func TestRun4(t *testing.T) {
callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int))
vm := NewVm(state, RuntimeVars{
origin: account.Address(),
blockNumber: 1,
prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
time: 1,
diff: big.NewInt(256),
Origin: account.Address(),
BlockNumber: 1,
PrevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
Time: 1,
Diff: big.NewInt(256),
// XXX Tx data? Could be just an argument to the closure instead
txData: nil,
TxData: 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))
}