Selaa lähdekoodia

Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop

Conflicts:
	accounts/account_manager.go
obscuren 10 vuotta sitten
vanhempi
commit
49ded3aa77

+ 2 - 2
.travis.yml

@@ -1,8 +1,8 @@
 language: go
 go:
-  - 1.4.1
+  - 1.4.2
 before_install:
-  - sudo add-apt-repository ppa:beineri/opt-qt54 -y
+  - sudo add-apt-repository ppa:beineri/opt-qt541 -y
   - sudo apt-get update -qq
   - sudo apt-get install -yqq libgmp3-dev libreadline6-dev qt54quickcontrols qt54webengine
 install:

+ 5 - 6
Godeps/Godeps.json

@@ -1,15 +1,10 @@
 {
 	"ImportPath": "github.com/ethereum/go-ethereum",
-	"GoVersion": "go1.4.1",
+	"GoVersion": "go1.4.2",
 	"Packages": [
 		"./..."
 	],
 	"Deps": [
-		{
-			"ImportPath": "bitbucket.org/kardianos/osext",
-			"Comment": "null-13",
-			"Rev": "5d3ddcf53a508cc2f7404eaebf546ef2cb5cdb6e"
-		},
 		{
 			"ImportPath": "code.google.com/p/go-uuid/uuid",
 			"Comment": "null-12",
@@ -37,6 +32,10 @@
 			"ImportPath": "github.com/jackpal/go-nat-pmp",
 			"Rev": "a45aa3d54aef73b504e15eb71bea0e5565b5e6e1"
 		},
+		{
+			"ImportPath": "github.com/kardianos/osext",
+			"Rev": "ccfcd0245381f0c94c68f50626665eed3c6b726a"
+		},
 		{
 			"ImportPath": "github.com/obscuren/otto",
 			"Rev": "cf13cc4228c5e5ce0fe27a7aea90bc10091c4f19"

+ 0 - 20
Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE

@@ -1,20 +0,0 @@
-Copyright (c) 2012 Daniel Theophanes
-
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any damages
-arising from the use of this software.
-
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it
-freely, subject to the following restrictions:
-
-   1. The origin of this software must not be misrepresented; you must not
-   claim that you wrote the original software. If you use this software
-   in a product, an acknowledgment in the product documentation would be
-   appreciated but is not required.
-
-   2. Altered source versions must be plainly marked as such, and must not be
-   misrepresented as being the original software.
-
-   3. This notice may not be removed or altered from any source
-   distribution.

+ 27 - 0
Godeps/_workspace/src/github.com/kardianos/osext/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2012 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 14 - 0
Godeps/_workspace/src/github.com/kardianos/osext/README.md

@@ -0,0 +1,14 @@
+### Extensions to the "os" package.
+
+## Find the current Executable and ExecutableFolder.
+
+There is sometimes utility in finding the current executable file
+that is running. This can be used for upgrading the current executable
+or finding resources located relative to the executable file.
+
+Multi-platform and supports:
+ * Linux
+ * OS X
+ * Windows
+ * Plan 9
+ * BSDs.

+ 0 - 5
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go → Godeps/_workspace/src/github.com/kardianos/osext/osext.go

@@ -25,8 +25,3 @@ func ExecutableFolder() (string, error) {
 	folder, _ := filepath.Split(p)
 	return folder, nil
 }
-
-// Depricated. Same as Executable().
-func GetExePath() (exePath string, err error) {
-	return Executable()
-}

+ 9 - 9
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go → Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go

@@ -5,16 +5,16 @@
 package osext
 
 import (
-    "syscall"
-    "os"
-    "strconv"
+	"os"
+	"strconv"
+	"syscall"
 )
 
 func executable() (string, error) {
-    f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text")
-    if err != nil {
-        return "", err
-    }
-    defer f.Close()
-    return syscall.Fd2path(int(f.Fd()))
+	f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text")
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+	return syscall.Fd2path(int(f.Fd()))
 }

+ 5 - 2
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go → Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go

@@ -2,12 +2,13 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build linux netbsd openbsd
+// +build linux netbsd openbsd solaris dragonfly
 
 package osext
 
 import (
 	"errors"
+	"fmt"
 	"os"
 	"runtime"
 )
@@ -18,8 +19,10 @@ func executable() (string, error) {
 		return os.Readlink("/proc/self/exe")
 	case "netbsd":
 		return os.Readlink("/proc/curproc/exe")
-	case "openbsd":
+	case "openbsd", "dragonfly":
 		return os.Readlink("/proc/curproc/file")
+	case "solaris":
+		return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid()))
 	}
 	return "", errors.New("ExecPath not implemented for " + runtime.GOOS)
 }

+ 0 - 0
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go → Godeps/_workspace/src/github.com/kardianos/osext/osext_sysctl.go


+ 0 - 0
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go → Godeps/_workspace/src/github.com/kardianos/osext/osext_test.go


+ 0 - 0
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go → Godeps/_workspace/src/github.com/kardianos/osext/osext_windows.go


+ 41 - 9
accounts/account_manager.go

@@ -35,24 +35,33 @@ package accounts
 import (
 	crand "crypto/rand"
 
+	"errors"
+	"sync"
+	"time"
+
 	"github.com/ethereum/go-ethereum/crypto"
 )
 
+var ErrLocked = errors.New("account is locked; please request passphrase")
+
 // TODO: better name for this struct?
 type Account struct {
 	Address []byte
 }
 
 type AccountManager struct {
-	keyStore crypto.KeyStore2
+	keyStore           crypto.KeyStore2
+	unlockedKeys       map[string]crypto.Key
+	unlockMilliseconds time.Duration
+	mutex              sync.RWMutex
 }
 
-// TODO: get key by addr - modify KeyStore2 GetKey to work with addr
-
-// TODO: pass through passphrase for APIs which require access to private key?
-func NewAccountManager(keyStore crypto.KeyStore2) AccountManager {
+func NewAccountManager(keyStore crypto.KeyStore2, unlockMilliseconds time.Duration) AccountManager {
+	keysMap := make(map[string]crypto.Key)
 	am := &AccountManager{
-		keyStore: keyStore,
+		keyStore:           keyStore,
+		unlockedKeys:       keysMap,
+		unlockMilliseconds: unlockMilliseconds,
 	}
 	return *am
 }
@@ -61,11 +70,26 @@ func (am AccountManager) DeleteAccount(address []byte, auth string) error {
 	return am.keyStore.DeleteKey(address, auth)
 }
 
-func (am *AccountManager) Sign(fromAccount *Account, keyAuth string, toSign []byte) (signature []byte, err error) {
+func (am *AccountManager) Sign(fromAccount *Account, toSign []byte) (signature []byte, err error) {
+	am.mutex.RLock()
+	unlockedKey := am.unlockedKeys[string(fromAccount.Address)]
+	am.mutex.RUnlock()
+	if unlockedKey.Address == nil {
+		return nil, ErrLocked
+	}
+	signature, err = crypto.Sign(toSign, unlockedKey.PrivateKey)
+	return signature, err
+}
+
+func (am *AccountManager) SignLocked(fromAccount *Account, keyAuth string, toSign []byte) (signature []byte, err error) {
 	key, err := am.keyStore.GetKey(fromAccount.Address, keyAuth)
 	if err != nil {
 		return nil, err
 	}
+	am.mutex.RLock()
+	am.unlockedKeys[string(fromAccount.Address)] = *key
+	am.mutex.RUnlock()
+	go unlockLater(am, fromAccount.Address)
 	signature, err = crypto.Sign(toSign, key.PrivateKey)
 	return signature, err
 }
@@ -81,8 +105,6 @@ func (am AccountManager) NewAccount(auth string) (*Account, error) {
 	return ua, err
 }
 
-// set of accounts == set of keys in given key store
-// TODO: do we need persistence of accounts as well?
 func (am *AccountManager) Accounts() ([]Account, error) {
 	addresses, err := am.keyStore.GetKeyAddresses()
 	if err != nil {
@@ -98,3 +120,13 @@ func (am *AccountManager) Accounts() ([]Account, error) {
 	}
 	return accounts, err
 }
+
+func unlockLater(am *AccountManager, addr []byte) {
+	select {
+	case <-time.After(time.Millisecond * am.unlockMilliseconds):
+	}
+	am.mutex.RLock()
+	// TODO: how do we know the key is actually gone from memory?
+	delete(am.unlockedKeys, string(addr))
+	am.mutex.RUnlock()
+}

+ 51 - 2
accounts/accounts_test.go

@@ -6,19 +6,68 @@ import (
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/crypto/randentropy"
 	"github.com/ethereum/go-ethereum/ethutil"
+	"time"
 )
 
 func TestAccountManager(t *testing.T) {
 	ks := crypto.NewKeyStorePlain(ethutil.DefaultDataDir() + "/testaccounts")
-	am := NewAccountManager(ks)
+	am := NewAccountManager(ks, 100)
 	pass := "" // not used but required by API
 	a1, err := am.NewAccount(pass)
 	toSign := randentropy.GetEntropyCSPRNG(32)
-	_, err = am.Sign(a1, pass, toSign)
+	_, err = am.SignLocked(a1, pass, toSign)
 	if err != nil {
 		t.Fatal(err)
 	}
 
+	// Cleanup
+	time.Sleep(time.Millisecond * 150) // wait for locking
+
+	accounts, err := am.Accounts()
+	if err != nil {
+		t.Fatal(err)
+	}
+	for _, account := range accounts {
+		err := am.DeleteAccount(account.Address, pass)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+}
+
+func TestAccountManagerLocking(t *testing.T) {
+	ks := crypto.NewKeyStorePassphrase(ethutil.DefaultDataDir() + "/testaccounts")
+	am := NewAccountManager(ks, 200)
+	pass := "foo"
+	a1, err := am.NewAccount(pass)
+	toSign := randentropy.GetEntropyCSPRNG(32)
+
+	// Signing without passphrase fails because account is locked
+	_, err = am.Sign(a1, toSign)
+	if err != ErrLocked {
+		t.Fatal(err)
+	}
+
+	// Signing with passphrase works
+	_, err = am.SignLocked(a1, pass, toSign)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Signing without passphrase works because account is temp unlocked
+	_, err = am.Sign(a1, toSign)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Signing without passphrase fails after automatic locking
+	time.Sleep(time.Millisecond * time.Duration(250))
+
+	_, err = am.Sign(a1, toSign)
+	if err != ErrLocked {
+		t.Fatal(err)
+	}
+
 	// Cleanup
 	accounts, err := am.Accounts()
 	if err != nil {

+ 1 - 30
cmd/mist/flags.go

@@ -27,10 +27,8 @@ import (
 	"log"
 	"os"
 	"path"
-	"path/filepath"
 	"runtime"
 
-	"bitbucket.org/kardianos/osext"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethutil"
 	"github.com/ethereum/go-ethereum/logger"
@@ -68,33 +66,6 @@ var (
 
 // flags specific to gui client
 var AssetPath string
-
-//TODO: If we re-use the one defined in cmd.go the binary osx image crashes. If somebody finds out why we can dry this up.
-func defaultAssetPath() string {
-	var assetPath string
-	// If the current working directory is the go-ethereum dir
-	// assume a debug build and use the source directory as
-	// asset directory.
-	pwd, _ := os.Getwd()
-	if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist") {
-		assetPath = path.Join(pwd, "assets")
-	} else {
-		switch runtime.GOOS {
-		case "darwin":
-			// Get Binary Directory
-			exedir, _ := osext.ExecutableFolder()
-			assetPath = filepath.Join(exedir, "../Resources")
-		case "linux":
-			assetPath = "/usr/share/mist"
-		case "windows":
-			assetPath = "./assets"
-		default:
-			assetPath = "."
-		}
-	}
-	return assetPath
-}
-
 var defaultConfigFile = path.Join(ethutil.DefaultDataDir(), "conf.ini")
 
 func Init() {
@@ -122,7 +93,7 @@ func Init() {
 	flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
 	flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")
 
-	flag.StringVar(&AssetPath, "asset_path", defaultAssetPath(), "absolute path to GUI assets directory")
+	flag.StringVar(&AssetPath, "asset_path", ethutil.DefaultAssetPath(), "absolute path to GUI assets directory")
 
 	// Network stuff
 	var (

+ 0 - 29
cmd/utils/cmd.go

@@ -25,12 +25,8 @@ import (
 	"fmt"
 	"os"
 	"os/signal"
-	"path"
-	"path/filepath"
 	"regexp"
-	"runtime"
 
-	"bitbucket.org/kardianos/osext"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/eth"
@@ -132,31 +128,6 @@ func StartEthereum(ethereum *eth.Ethereum) {
 	})
 }
 
-func DefaultAssetPath() string {
-	var assetPath string
-	// If the current working directory is the go-ethereum dir
-	// assume a debug build and use the source directory as
-	// asset directory.
-	pwd, _ := os.Getwd()
-	if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist") {
-		assetPath = path.Join(pwd, "assets")
-	} else {
-		switch runtime.GOOS {
-		case "darwin":
-			// Get Binary Directory
-			exedir, _ := osext.ExecutableFolder()
-			assetPath = filepath.Join(exedir, "../Resources")
-		case "linux":
-			assetPath = "/usr/share/mist"
-		case "windows":
-			assetPath = "./assets"
-		default:
-			assetPath = "."
-		}
-	}
-	return assetPath
-}
-
 func KeyTasks(keyManager *crypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
 
 	var err error

+ 6 - 1
core/block_processor.go

@@ -62,7 +62,7 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM
 
 func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
 	coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase)
-	coinbase.SetGasPool(CalcGasLimit(parent, block))
+	coinbase.SetGasPool(block.Header().GasLimit)
 
 	// Process the transactions on to parent state
 	receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess)
@@ -247,6 +247,11 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
 		return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd)
 	}
 
+	expl := CalcGasLimit(parent, block)
+	if expl.Cmp(block.Header().GasLimit) != 0 {
+		return fmt.Errorf("GasLimit check failed for block %v, %v", block.Header().GasLimit, expl)
+	}
+
 	if block.Time() < parent.Time() {
 		return ValidationError("Block timestamp not after prev block (%v - %v)", block.Header().Time, parent.Header().Time)
 	}

+ 29 - 0
ethutil/common.go

@@ -3,12 +3,41 @@ package ethutil
 import (
 	"fmt"
 	"math/big"
+	"os"
 	"os/user"
 	"path"
+	"path/filepath"
 	"runtime"
 	"time"
+
+	"github.com/kardianos/osext"
 )
 
+func DefaultAssetPath() string {
+	var assetPath string
+	// If the current working directory is the go-ethereum dir
+	// assume a debug build and use the source directory as
+	// asset directory.
+	pwd, _ := os.Getwd()
+	if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist") {
+		assetPath = path.Join(pwd, "assets")
+	} else {
+		switch runtime.GOOS {
+		case "darwin":
+			// Get Binary Directory
+			exedir, _ := osext.ExecutableFolder()
+			assetPath = filepath.Join(exedir, "../Resources")
+		case "linux":
+			assetPath = "/usr/share/mist"
+		case "windows":
+			assetPath = "./assets"
+		default:
+			assetPath = "."
+		}
+	}
+	return assetPath
+}
+
 func DefaultDataDir() string {
 	usr, _ := user.Current()
 	if runtime.GOOS == "darwin" {

+ 23 - 4
rpc/api.go

@@ -51,6 +51,8 @@ type EthereumApi struct {
 	register map[string][]*NewTxArgs
 
 	db ethutil.Database
+
+	defaultBlockAge int
 }
 
 func NewEthereumApi(eth *xeth.XEth) *EthereumApi {
@@ -80,11 +82,9 @@ done:
 		case ev := <-events.Chan():
 			switch ev.(type) {
 			case core.ChainEvent:
-				// fixme
-				const something = 1337
-				if something < 0 {
+				if self.defaultBlockAge < 0 {
 					chain := self.xeth().Backend().ChainManager()
-					block := chain.GetBlockByNumber(chain.CurrentBlock().Number().Uint64() - something)
+					block := chain.GetBlockByNumber(chain.CurrentBlock().Number().Uint64() - uint64(self.defaultBlockAge))
 					if block != nil {
 						statedb := state.New(block.Root(), self.db)
 						self.useState(statedb)
@@ -373,6 +373,17 @@ func (p *EthereumApi) SetMining(shouldmine bool, reply *interface{}) error {
 	return nil
 }
 
+func (p *EthereumApi) GetDefaultBlockAge(reply *interface{}) error {
+	*reply = p.defaultBlockAge
+	return nil
+}
+
+func (p *EthereumApi) SetDefaultBlockAge(defaultBlockAge int, reply *interface{}) error {
+	p.defaultBlockAge = defaultBlockAge
+	*reply = true
+	return nil
+}
+
 func (p *EthereumApi) BlockNumber(reply *interface{}) error {
 	*reply = p.xeth().Backend().ChainManager().CurrentBlock().Number()
 	return nil
@@ -513,6 +524,14 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 			return err
 		}
 		return p.SetMining(args, reply)
+	case "eth_defaultBlock":
+		return p.GetDefaultBlockAge(reply)
+	case "eth_setDefaultBlock":
+		args, err := req.ToIntArgs()
+		if err != nil {
+			return err
+		}
+		return p.SetDefaultBlockAge(args, reply)
 	case "eth_peerCount":
 		return p.GetPeerCount(reply)
 	case "eth_number":

+ 13 - 0
rpc/messages.go

@@ -210,6 +210,19 @@ func (req *RpcRequest) ToBoolArgs() (bool, error) {
 	return args, nil
 }
 
+func (req *RpcRequest) ToIntArgs() (int, error) {
+	if len(req.Params) < 1 {
+		return 0, errArguments
+	}
+
+	var args int
+	if err := json.Unmarshal(req.Params[0], &args); err != nil {
+		return 0, errArguments
+	}
+
+	return args, nil
+}
+
 func (req *RpcRequest) ToCompileArgs() (string, error) {
 	if len(req.Params) < 1 {
 		return "", errArguments

+ 18 - 0
ui/frontend.go

@@ -0,0 +1,18 @@
+package ui
+
+// ReturnInterface is returned by the Intercom interface when a method is called
+type ReturnInterface interface {
+	Get(i int) (interface{}, error)
+	Size() int
+}
+
+// Frontend is the basic interface for calling arbitrary methods on something that
+// implements a front end (GUI, CLI, etc)
+type Frontend interface {
+	// Checks whether a specific method is implemented
+	Supports(method string) bool
+	// Call calls the given method on interface it implements. This will return
+	// an error with errNotImplemented if the method hasn't been implemented
+	// and will return a ReturnInterface if it does.
+	Call(method string) (ReturnInterface, error)
+}

+ 33 - 0
xeth/state.go

@@ -0,0 +1,33 @@
+package xeth
+
+import "github.com/ethereum/go-ethereum/state"
+
+type State struct {
+	xeth  *XEth
+	state *state.StateDB
+}
+
+func NewState(xeth *XEth, statedb *state.StateDB) *State {
+	return &State{xeth, statedb}
+}
+
+func (self *State) State() *state.StateDB {
+	return self.state
+}
+
+func (self *State) Get(addr string) *Object {
+	return &Object{self.state.GetStateObject(fromHex(addr))}
+}
+
+func (self *State) SafeGet(addr string) *Object {
+	return &Object{self.safeGet(addr)}
+}
+
+func (self *State) safeGet(addr string) *state.StateObject {
+	object := self.state.GetStateObject(fromHex(addr))
+	if object == nil {
+		object = state.NewStateObject(fromHex(addr), self.xeth.eth.Db())
+	}
+
+	return object
+}