diff options
Diffstat (limited to 'vm')
-rw-r--r-- | vm/common.go | 87 | ||||
-rw-r--r-- | vm/context.go | 12 | ||||
-rw-r--r-- | vm/environment.go | 32 | ||||
-rw-r--r-- | vm/gas.go | 49 | ||||
-rw-r--r-- | vm/memory.go | 32 | ||||
-rw-r--r-- | vm/vm.go | 79 |
6 files changed, 149 insertions, 142 deletions
diff --git a/vm/common.go b/vm/common.go index 90c3361de..8d8f4253f 100644 --- a/vm/common.go +++ b/vm/common.go @@ -18,8 +18,23 @@ type Type byte const ( StdVmTy Type = iota JitVmTy - MaxVmTy + + MaxCallDepth = 1025 + + LogTyPretty byte = 0x1 + LogTyDiff byte = 0x2 +) + +var ( + Pow256 = common.BigPow(2, 256) + + U256 = common.U256 + S256 = common.S256 + + Zero = common.Big0 + + max = big.NewInt(math.MaxInt64) ) func NewVm(env Environment) VirtualMachine { @@ -34,67 +49,6 @@ func NewVm(env Environment) VirtualMachine { } } -var ( - GasQuickStep = big.NewInt(2) - GasFastestStep = big.NewInt(3) - GasFastStep = big.NewInt(5) - GasMidStep = big.NewInt(8) - GasSlowStep = big.NewInt(10) - GasExtStep = big.NewInt(20) - - GasStorageGet = big.NewInt(50) - GasStorageAdd = big.NewInt(20000) - GasStorageMod = big.NewInt(5000) - GasLogBase = big.NewInt(375) - GasLogTopic = big.NewInt(375) - GasLogByte = big.NewInt(8) - GasCreate = big.NewInt(32000) - GasCreateByte = big.NewInt(200) - GasCall = big.NewInt(40) - GasCallValueTransfer = big.NewInt(9000) - GasStipend = big.NewInt(2300) - GasCallNewAccount = big.NewInt(25000) - GasReturn = big.NewInt(0) - GasStop = big.NewInt(0) - GasJumpDest = big.NewInt(1) - - RefundStorage = big.NewInt(15000) - RefundSuicide = big.NewInt(24000) - - GasMemWord = big.NewInt(3) - GasQuadCoeffDenom = big.NewInt(512) - GasContractByte = big.NewInt(200) - GasTransaction = big.NewInt(21000) - GasTxDataNonzeroByte = big.NewInt(68) - GasTxDataZeroByte = big.NewInt(4) - GasTx = big.NewInt(21000) - GasExp = big.NewInt(10) - GasExpByte = big.NewInt(10) - - GasSha3Base = big.NewInt(30) - GasSha3Word = big.NewInt(6) - GasSha256Base = big.NewInt(60) - GasSha256Word = big.NewInt(12) - GasRipemdBase = big.NewInt(600) - GasRipemdWord = big.NewInt(12) - GasEcrecover = big.NewInt(3000) - GasIdentityBase = big.NewInt(15) - GasIdentityWord = big.NewInt(3) - GasCopyWord = big.NewInt(3) - - Pow256 = common.BigPow(2, 256) - - LogTyPretty byte = 0x1 - LogTyDiff byte = 0x2 - - U256 = common.U256 - S256 = common.S256 - - Zero = common.Big0 -) - -const MaxCallDepth = 1025 - func calcMemSize(off, l *big.Int) *big.Int { if l.Cmp(common.Big0) == 0 { return common.Big0 @@ -119,9 +73,10 @@ func toValue(val *big.Int) interface{} { return val } -func getData(data []byte, start, size uint64) []byte { - x := uint64(math.Min(float64(start), float64(len(data)))) - y := uint64(math.Min(float64(x+size), float64(len(data)))) +func getData(data []byte, start, size *big.Int) []byte { + dlen := big.NewInt(int64(len(data))) - return common.RightPadBytes(data[x:y], int(size)) + s := common.BigMin(start, dlen) + e := common.BigMin(new(big.Int).Add(s, size), dlen) + return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64())) } diff --git a/vm/context.go b/vm/context.go index 1c2f665a4..e73199b77 100644 --- a/vm/context.go +++ b/vm/context.go @@ -9,7 +9,7 @@ import ( type ContextRef interface { ReturnGas(*big.Int, *big.Int) - Address() []byte + Address() common.Address SetCode([]byte) } @@ -18,7 +18,7 @@ type Context struct { self ContextRef Code []byte - CodeAddr []byte + CodeAddr *common.Address value, Gas, UsedGas, Price *big.Int @@ -64,10 +64,6 @@ func (c *Context) GetRangeValue(x, size uint64) []byte { return common.RightPadBytes(c.Code[x:y], int(size)) } -func (c *Context) GetCode(x, size uint64) []byte { - return getData(c.Code, x, size) -} - func (c *Context) Return(ret []byte) []byte { // Return the remaining gas to the caller c.caller.ReturnGas(c.Gas, c.Price) @@ -100,7 +96,7 @@ func (c *Context) ReturnGas(gas, price *big.Int) { /* * Set / Get */ -func (c *Context) Address() []byte { +func (c *Context) Address() common.Address { return c.self.Address() } @@ -108,7 +104,7 @@ func (self *Context) SetCode(code []byte) { self.Code = code } -func (self *Context) SetCallCode(addr, code []byte) { +func (self *Context) SetCallCode(addr *common.Address, code []byte) { self.Code = code self.CodeAddr = addr } diff --git a/vm/environment.go b/vm/environment.go index 83faaa23e..5d493166c 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -3,19 +3,21 @@ package vm import ( "errors" "fmt" + "io" "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/state" ) type Environment interface { State() *state.StateDB - Origin() []byte + Origin() common.Address BlockNumber() *big.Int - GetHash(n uint64) []byte - Coinbase() []byte + GetHash(n uint64) common.Hash + Coinbase() common.Address Time() int64 Difficulty() *big.Int GasLimit() *big.Int @@ -27,16 +29,16 @@ type Environment interface { Depth() int SetDepth(i int) - Call(me ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) - CallCode(me ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) - Create(me ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, ContextRef) + Call(me ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) + CallCode(me ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) + Create(me ContextRef, addr *common.Address, data []byte, gas, price, value *big.Int) ([]byte, error, ContextRef) } type Account interface { SubBalance(amount *big.Int) AddBalance(amount *big.Int) Balance() *big.Int - Address() []byte + Address() common.Address } // generic transfer method @@ -53,17 +55,17 @@ func Transfer(from, to Account, amount *big.Int) error { } type Log struct { - address []byte - topics [][]byte + address common.Address + topics []common.Hash data []byte log uint64 } -func (self *Log) Address() []byte { +func (self *Log) Address() common.Address { return self.address } -func (self *Log) Topics() [][]byte { +func (self *Log) Topics() []common.Hash { return self.topics } @@ -75,10 +77,16 @@ func (self *Log) Number() uint64 { return self.log } +func (self *Log) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, []interface{}{self.address, self.topics, self.data}) +} + +/* func (self *Log) RlpData() interface{} { return []interface{}{self.address, common.ByteSliceToInterface(self.topics), self.data} } +*/ func (self *Log) String() string { - return fmt.Sprintf("[A=%x T=%x D=%x]", self.address, self.topics, self.data) + return fmt.Sprintf("{%x %x %x}", self.address, self.data, self.topics) } @@ -7,6 +7,55 @@ type req struct { gas *big.Int } +var ( + GasQuickStep = big.NewInt(2) + GasFastestStep = big.NewInt(3) + GasFastStep = big.NewInt(5) + GasMidStep = big.NewInt(8) + GasSlowStep = big.NewInt(10) + GasExtStep = big.NewInt(20) + + GasStorageGet = big.NewInt(50) + GasStorageAdd = big.NewInt(20000) + GasStorageMod = big.NewInt(5000) + GasLogBase = big.NewInt(375) + GasLogTopic = big.NewInt(375) + GasLogByte = big.NewInt(8) + GasCreate = big.NewInt(32000) + GasCreateByte = big.NewInt(200) + GasCall = big.NewInt(40) + GasCallValueTransfer = big.NewInt(9000) + GasStipend = big.NewInt(2300) + GasCallNewAccount = big.NewInt(25000) + GasReturn = big.NewInt(0) + GasStop = big.NewInt(0) + GasJumpDest = big.NewInt(1) + + RefundStorage = big.NewInt(15000) + RefundSuicide = big.NewInt(24000) + + GasMemWord = big.NewInt(3) + GasQuadCoeffDenom = big.NewInt(512) + GasContractByte = big.NewInt(200) + GasTransaction = big.NewInt(21000) + GasTxDataNonzeroByte = big.NewInt(68) + GasTxDataZeroByte = big.NewInt(4) + GasTx = big.NewInt(21000) + GasExp = big.NewInt(10) + GasExpByte = big.NewInt(10) + + GasSha3Base = big.NewInt(30) + GasSha3Word = big.NewInt(6) + GasSha256Base = big.NewInt(60) + GasSha256Word = big.NewInt(12) + GasRipemdBase = big.NewInt(600) + GasRipemdWord = big.NewInt(12) + GasEcrecover = big.NewInt(3000) + GasIdentityBase = big.NewInt(15) + GasIdentityWord = big.NewInt(3) + GasCopyWord = big.NewInt(3) +) + var _baseCheck = map[OpCode]req{ // Req stack Gas price ADD: {2, GasFastestStep}, diff --git a/vm/memory.go b/vm/memory.go index 2a1e6e1b9..dd47fa1b5 100644 --- a/vm/memory.go +++ b/vm/memory.go @@ -1,6 +1,10 @@ package vm -import "fmt" +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" +) type Memory struct { store []byte @@ -11,21 +15,21 @@ func NewMemory() *Memory { } func (m *Memory) Set(offset, size uint64, value []byte) { - if len(value) > 0 { - totSize := offset + size - lenSize := uint64(len(m.store) - 1) - if totSize > lenSize { - // Calculate the diff between the sizes - diff := totSize - lenSize - if diff > 0 { - // Create a new empty slice and append it - newSlice := make([]byte, diff-1) - // Resize slice - m.store = append(m.store, newSlice...) - } + value = common.RightPadBytes(value, int(size)) + + totSize := offset + size + lenSize := uint64(len(m.store) - 1) + if totSize > lenSize { + // Calculate the diff between the sizes + diff := totSize - lenSize + if diff > 0 { + // Create a new empty slice and append it + newSlice := make([]byte, diff-1) + // Resize slice + m.store = append(m.store, newSlice...) } - copy(m.store[offset:offset+size], value) } + copy(m.store[offset:offset+size], value) } func (m *Memory) Resize(size uint64) { @@ -33,10 +33,7 @@ func New(env Environment) *Vm { } func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { - //func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) { self.env.SetDepth(self.env.Depth() + 1) - - //context := NewContext(caller, me, code, gas, price) var ( caller = context.caller code = context.Code @@ -44,7 +41,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { price = context.Price ) - self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address()[:4], context.Address(), len(code), context.Gas, callData).Endl() + self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address().Bytes()[:4], context.Address(), len(code), context.Gas, callData).Endl() if self.Recoverable { // Recover from any require exception @@ -57,13 +54,14 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { ret = context.Return(nil) err = fmt.Errorf("%v", r) - } }() } - if p := Precompiled[string(context.CodeAddr)]; p != nil { - return self.RunPrecompiled(p, callData, context) + if context.CodeAddr != nil { + if p := Precompiled[context.CodeAddr.Str()]; p != nil { + return self.RunPrecompiled(p, callData, context) + } } var ( @@ -394,11 +392,11 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { self.Printf(" => (%v) %x", size, data) // 0x30 range case ADDRESS: - stack.push(common.BigD(context.Address())) + stack.push(common.Bytes2Big(context.Address().Bytes())) self.Printf(" => %x", context.Address()) case BALANCE: - addr := stack.pop().Bytes() + addr := common.BigToAddress(stack.pop()) balance := statedb.GetBalance(addr) stack.push(balance) @@ -407,12 +405,12 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { case ORIGIN: origin := self.env.Origin() - stack.push(common.BigD(origin)) + stack.push(origin.Big()) self.Printf(" => %x", origin) case CALLER: caller := context.caller.Address() - stack.push(common.BigD(caller)) + stack.push(common.Bytes2Big(caller.Bytes())) self.Printf(" => %x", caller) case CALLVALUE: @@ -447,18 +445,15 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { cOff = stack.pop() l = stack.pop() ) - var data []byte - if cOff.Cmp(big.NewInt(int64(len(callData)))) <= 0 { - data = getData(callData, cOff.Uint64(), l.Uint64()) - } + data := getData(callData, cOff, l) mem.Set(mOff.Uint64(), l.Uint64(), data) - self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, data) + self.Printf(" => [%v, %v, %v]", mOff, cOff, l) case CODESIZE, EXTCODESIZE: var code []byte if op == EXTCODESIZE { - addr := stack.pop().Bytes() + addr := common.BigToAddress(stack.pop()) code = statedb.GetCode(addr) } else { @@ -472,7 +467,8 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { case CODECOPY, EXTCODECOPY: var code []byte if op == EXTCODECOPY { - code = statedb.GetCode(stack.pop().Bytes()) + addr := common.BigToAddress(stack.pop()) + code = statedb.GetCode(addr) } else { code = context.Code } @@ -483,10 +479,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { l = stack.pop() ) - var codeCopy []byte - if cOff.Cmp(big.NewInt(int64(len(code)))) <= 0 { - codeCopy = getData(code, cOff.Uint64(), l.Uint64()) - } + codeCopy := getData(code, cOff, l) mem.Set(mOff.Uint64(), l.Uint64(), codeCopy) @@ -502,7 +495,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { n := new(big.Int).Sub(self.env.BlockNumber(), common.Big257) if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 { - stack.push(common.BigD(self.env.GetHash(num.Uint64()))) + stack.push(self.env.GetHash(num.Uint64()).Big()) } else { stack.push(common.Big0) } @@ -511,7 +504,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { case COINBASE: coinbase := self.env.Coinbase() - stack.push(common.BigD(coinbase)) + stack.push(coinbase.Big()) self.Printf(" => 0x%x", coinbase) case TIMESTAMP: @@ -562,10 +555,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { self.Printf(" => [%d]", n) case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) - topics := make([][]byte, n) + topics := make([]common.Hash, n) mStart, mSize := stack.pop(), stack.pop() for i := 0; i < n; i++ { - topics[i] = common.LeftPadBytes(stack.pop().Bytes(), 32) + topics[i] = common.BigToHash(stack.pop()) //common.LeftPadBytes(stack.pop().Bytes(), 32) } data := mem.Get(mStart.Int64(), mSize.Int64()) @@ -586,22 +579,24 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { self.Printf(" => 0x%x", val) case MSTORE8: - off, val := stack.pop(), stack.pop() + off, val := stack.pop().Int64(), stack.pop().Int64() - mem.store[off.Int64()] = byte(val.Int64() & 0xff) + mem.store[off] = byte(val & 0xff) - self.Printf(" => [%v] 0x%x", off, val) + self.Printf(" => [%v] 0x%x", off, mem.store[off]) case SLOAD: - loc := stack.pop() - val := common.BigD(statedb.GetState(context.Address(), loc.Bytes())) + loc := common.BigToHash(stack.pop()) + val := common.Bytes2Big(statedb.GetState(context.Address(), loc)) stack.push(val) - self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) + self.Printf(" {0x%x : 0x%x}", loc, val.Bytes()) case SSTORE: - loc, val := stack.pop(), stack.pop() - statedb.SetState(context.Address(), loc.Bytes(), val) + loc := common.BigToHash(stack.pop()) + val := stack.pop() + + statedb.SetState(context.Address(), loc, val) - self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) + self.Printf(" {0x%x : 0x%x}", loc, val.Bytes()) case JUMP: jump(pc, stack.pop()) @@ -634,7 +629,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { offset, size = stack.pop(), stack.pop() input = mem.Get(offset.Int64(), size.Int64()) gas = new(big.Int).Set(context.Gas) - addr []byte + addr common.Address ) self.Endl() @@ -654,7 +649,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { } addr = ref.Address() - stack.push(common.BigD(addr)) + stack.push(addr.Big()) } @@ -668,7 +663,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { // pop return size and offset retOffset, retSize := stack.pop(), stack.pop() - address := common.Address(addr.Bytes()) + address := common.BigToAddress(addr) self.Printf(" => %x", address).Endl() // Get the arguments from the memory @@ -706,10 +701,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { return context.Return(ret), nil case SUICIDE: - receiver := statedb.GetOrNewStateObject(stack.pop().Bytes()) + receiver := statedb.GetOrNewStateObject(common.BigToAddress(stack.pop())) balance := statedb.GetBalance(context.Address()) - self.Printf(" => (%x) %v", receiver.Address()[:4], balance) + self.Printf(" => (%x) %v", receiver.Address().Bytes()[:4], balance) receiver.AddBalance(balance) @@ -769,7 +764,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo var g *big.Int y, x := stack.data[stack.len()-2], stack.data[stack.len()-1] - val := statedb.GetState(context.Address(), x.Bytes()) + val := statedb.GetState(context.Address(), common.BigToHash(x)) if len(val) == 0 && len(y.Bytes()) > 0 { // 0 => non 0 g = GasStorageAdd @@ -821,7 +816,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo gas.Add(gas, stack.data[stack.len()-1]) if op == CALL { - if self.env.State().GetStateObject(stack.data[stack.len()-2].Bytes()) == nil { + if self.env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil { gas.Add(gas, GasCallNewAccount) } } |