aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2015-06-10 03:12:25 +0800
committerobscuren <geffobscura@gmail.com>2015-06-10 03:12:25 +0800
commitbac9a94ddf20dc530966cbf6cd384aaf94aedc77 (patch)
tree0ced967e60315698cc5056a984d7678c417bc1ce /core/vm
parent0e703d92ac9df61e2ededa8c895c70ded101a607 (diff)
parent14994fa21bf6f05554ff370d41005d06b68d20a5 (diff)
downloadgo-tangerine-bac9a94ddf20dc530966cbf6cd384aaf94aedc77.tar
go-tangerine-bac9a94ddf20dc530966cbf6cd384aaf94aedc77.tar.gz
go-tangerine-bac9a94ddf20dc530966cbf6cd384aaf94aedc77.tar.bz2
go-tangerine-bac9a94ddf20dc530966cbf6cd384aaf94aedc77.tar.lz
go-tangerine-bac9a94ddf20dc530966cbf6cd384aaf94aedc77.tar.xz
go-tangerine-bac9a94ddf20dc530966cbf6cd384aaf94aedc77.tar.zst
go-tangerine-bac9a94ddf20dc530966cbf6cd384aaf94aedc77.zip
Merge branch 'release/0.9.28'v0.9.28
Diffstat (limited to 'core/vm')
-rw-r--r--core/vm/analysis.go41
-rw-r--r--core/vm/context.go11
-rw-r--r--core/vm/contracts.go (renamed from core/vm/address.go)20
-rw-r--r--core/vm/environment.go40
-rw-r--r--core/vm/main_test.go9
-rw-r--r--core/vm/opcodes.go (renamed from core/vm/types.go)0
-rw-r--r--core/vm/vm.go27
-rw-r--r--core/vm/vm_test.go3
8 files changed, 61 insertions, 90 deletions
diff --git a/core/vm/analysis.go b/core/vm/analysis.go
index 264d55cb9..a7aa8da39 100644
--- a/core/vm/analysis.go
+++ b/core/vm/analysis.go
@@ -3,34 +3,45 @@ package vm
import (
"math/big"
- "gopkg.in/fatih/set.v0"
+ "github.com/ethereum/go-ethereum/common"
)
-type destinations struct {
- set *set.Set
-}
+var bigMaxUint64 = new(big.Int).SetUint64(^uint64(0))
-func (d *destinations) Has(dest *big.Int) bool {
- return d.set.Has(string(dest.Bytes()))
-}
+// destinations stores one map per contract (keyed by hash of code).
+// The maps contain an entry for each location of a JUMPDEST
+// instruction.
+type destinations map[common.Hash]map[uint64]struct{}
-func (d *destinations) Add(dest *big.Int) {
- d.set.Add(string(dest.Bytes()))
+// has checks whether code has a JUMPDEST at dest.
+func (d destinations) has(codehash common.Hash, code []byte, dest *big.Int) bool {
+ // PC cannot go beyond len(code) and certainly can't be bigger than 64bits.
+ // Don't bother checking for JUMPDEST in that case.
+ if dest.Cmp(bigMaxUint64) > 0 {
+ return false
+ }
+ m, analysed := d[codehash]
+ if !analysed {
+ m = jumpdests(code)
+ d[codehash] = m
+ }
+ _, ok := m[dest.Uint64()]
+ return ok
}
-func analyseJumpDests(code []byte) (dests *destinations) {
- dests = &destinations{set.New()}
-
+// jumpdests creates a map that contains an entry for each
+// PC location that is a JUMPDEST instruction.
+func jumpdests(code []byte) map[uint64]struct{} {
+ m := make(map[uint64]struct{})
for pc := uint64(0); pc < uint64(len(code)); pc++ {
var op OpCode = OpCode(code[pc])
switch op {
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
a := uint64(op) - uint64(PUSH1) + 1
-
pc += a
case JUMPDEST:
- dests.Add(big.NewInt(int64(pc)))
+ m[pc] = struct{}{}
}
}
- return
+ return m
}
diff --git a/core/vm/context.go b/core/vm/context.go
index 29bb9f74e..de03f84f0 100644
--- a/core/vm/context.go
+++ b/core/vm/context.go
@@ -16,6 +16,8 @@ type Context struct {
caller ContextRef
self ContextRef
+ jumpdests destinations // result of JUMPDEST analysis.
+
Code []byte
CodeAddr *common.Address
@@ -24,10 +26,17 @@ type Context struct {
Args []byte
}
-// Create a new context for the given data items
+// Create a new context for the given data items.
func NewContext(caller ContextRef, object ContextRef, value, gas, price *big.Int) *Context {
c := &Context{caller: caller, self: object, Args: nil}
+ if parent, ok := caller.(*Context); ok {
+ // Reuse JUMPDEST analysis from parent context if available.
+ c.jumpdests = parent.jumpdests
+ } else {
+ c.jumpdests = make(destinations)
+ }
+
// Gas should be a pointer so it can safely be reduced through the run
// This pointer will be off the state transition
c.Gas = gas //new(big.Int).Set(gas)
diff --git a/core/vm/address.go b/core/vm/contracts.go
index 742017dd2..90e356b1d 100644
--- a/core/vm/address.go
+++ b/core/vm/contracts.go
@@ -67,21 +67,25 @@ func ripemd160Func(in []byte) []byte {
const ecRecoverInputLength = 128
func ecrecoverFunc(in []byte) []byte {
+ in = common.RightPadBytes(in, 128)
// "in" is (hash, v, r, s), each 32 bytes
// but for ecrecover we want (r, s, v)
- if len(in) < ecRecoverInputLength {
- return nil
- }
+ r := common.BytesToBig(in[64:96])
+ s := common.BytesToBig(in[96:128])
// Treat V as a 256bit integer
- v := new(big.Int).Sub(common.Bytes2Big(in[32:64]), big.NewInt(27))
- // Ethereum requires V to be either 0 or 1 => (27 || 28)
- if !(v.Cmp(Zero) == 0 || v.Cmp(One) == 0) {
+ vbig := common.Bytes2Big(in[32:64])
+ v := byte(vbig.Uint64())
+
+ if !crypto.ValidateSignatureValues(v, r, s) {
+ glog.V(logger.Error).Infof("EC RECOVER FAIL: v, r or s value invalid")
return nil
}
- // v needs to be moved to the end
- rsv := append(in[64:128], byte(v.Uint64()))
+ // v needs to be at the end and normalized for libsecp256k1
+ vbignormal := new(big.Int).Sub(vbig, big.NewInt(27))
+ vnormal := byte(vbignormal.Uint64())
+ rsv := append(in[64:128], vnormal)
pubKey, err := crypto.Ecrecover(in[:32], rsv)
// make sure the public key is a valid one
if err != nil {
diff --git a/core/vm/environment.go b/core/vm/environment.go
index cc9570fc8..282d19578 100644
--- a/core/vm/environment.go
+++ b/core/vm/environment.go
@@ -2,13 +2,10 @@ package vm
import (
"errors"
- "fmt"
- "io"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/rlp"
)
type Environment interface {
@@ -52,40 +49,3 @@ func Transfer(from, to Account, amount *big.Int) error {
return nil
}
-
-type Log struct {
- address common.Address
- topics []common.Hash
- data []byte
- log uint64
-}
-
-func (self *Log) Address() common.Address {
- return self.address
-}
-
-func (self *Log) Topics() []common.Hash {
- return self.topics
-}
-
-func (self *Log) Data() []byte {
- return self.data
-}
-
-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("{%x %x %x}", self.address, self.data, self.topics)
-}
diff --git a/core/vm/main_test.go b/core/vm/main_test.go
deleted file mode 100644
index 0ae03bf6a..000000000
--- a/core/vm/main_test.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package vm
-
-import (
- "testing"
-
- checker "gopkg.in/check.v1"
-)
-
-func Test(t *testing.T) { checker.TestingT(t) }
diff --git a/core/vm/types.go b/core/vm/opcodes.go
index 1ea80a212..1ea80a212 100644
--- a/core/vm/types.go
+++ b/core/vm/opcodes.go
diff --git a/core/vm/vm.go b/core/vm/vm.go
index 6db99bdcc..2bd950385 100644
--- a/core/vm/vm.go
+++ b/core/vm/vm.go
@@ -71,18 +71,22 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
}
}
- var (
- op OpCode
+ // Don't bother with the execution if there's no code.
+ if len(code) == 0 {
+ return context.Return(nil), nil
+ }
- destinations = analyseJumpDests(context.Code)
- mem = NewMemory()
- stack = newStack()
- pc = new(big.Int)
- statedb = self.env.State()
+ var (
+ op OpCode
+ codehash = crypto.Sha3Hash(code)
+ mem = NewMemory()
+ stack = newStack()
+ pc = new(big.Int)
+ statedb = self.env.State()
jump = func(from *big.Int, to *big.Int) error {
- nop := context.GetOp(to)
- if !destinations.Has(to) {
+ if !context.jumpdests.has(codehash, code, to) {
+ nop := context.GetOp(to)
return fmt.Errorf("invalid jump destination (%v) %v", nop, to)
}
@@ -95,11 +99,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
}
)
- // Don't bother with the execution if there's no code.
- if len(code) == 0 {
- return context.Return(nil), nil
- }
-
for {
// The base for all big integer arithmetic
base := new(big.Int)
diff --git a/core/vm/vm_test.go b/core/vm/vm_test.go
deleted file mode 100644
index 9bd147a72..000000000
--- a/core/vm/vm_test.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package vm
-
-// Tests have been removed in favour of general tests. If anything implementation specific needs testing, put it here