aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/CODEOWNERS9
-rw-r--r--VERSION2
-rw-r--r--accounts/keystore/account_cache.go113
-rw-r--r--accounts/keystore/file_cache.go102
-rw-r--r--accounts/keystore/keystore_passphrase.go7
-rw-r--r--accounts/keystore/watch.go6
-rw-r--r--accounts/manager.go10
-rw-r--r--cmd/geth/accountcmd.go21
-rw-r--r--eth/api.go83
-rw-r--r--internal/web3ext/web3ext.go12
-rw-r--r--node/config.go36
-rw-r--r--params/version.go4
12 files changed, 287 insertions, 118 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 000000000..6076fe46a
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,9 @@
+# Lines starting with '#' are comments.
+# Each line is a file pattern followed by one or more owners.
+
+accounts/usbwallet @karalabe
+consensus @karalabe
+core/ @karalabe @holiman
+eth/ @karalabe
+mobile/ @karalabe
+p2p/ @fjl @zsfelfoldi
diff --git a/VERSION b/VERSION
index 661e7aead..27f9cd322 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.7.3
+1.8.0
diff --git a/accounts/keystore/account_cache.go b/accounts/keystore/account_cache.go
index 4b08cc202..71f698ece 100644
--- a/accounts/keystore/account_cache.go
+++ b/accounts/keystore/account_cache.go
@@ -20,7 +20,6 @@ import (
"bufio"
"encoding/json"
"fmt"
- "io/ioutil"
"os"
"path/filepath"
"sort"
@@ -75,13 +74,6 @@ type accountCache struct {
fileC fileCache
}
-// fileCache is a cache of files seen during scan of keystore
-type fileCache struct {
- all *set.SetNonTS // list of all files
- mtime time.Time // latest mtime seen
- mu sync.RWMutex
-}
-
func newAccountCache(keydir string) (*accountCache, chan struct{}) {
ac := &accountCache{
keydir: keydir,
@@ -236,66 +228,22 @@ func (ac *accountCache) close() {
ac.mu.Unlock()
}
-// scanFiles performs a new scan on the given directory, compares against the already
-// cached filenames, and returns file sets: new, missing , modified
-func (fc *fileCache) scanFiles(keyDir string) (set.Interface, set.Interface, set.Interface, error) {
- t0 := time.Now()
- files, err := ioutil.ReadDir(keyDir)
- t1 := time.Now()
- if err != nil {
- return nil, nil, nil, err
- }
- fc.mu.RLock()
- prevMtime := fc.mtime
- fc.mu.RUnlock()
-
- filesNow := set.NewNonTS()
- moddedFiles := set.NewNonTS()
- var newMtime time.Time
- for _, fi := range files {
- modTime := fi.ModTime()
- path := filepath.Join(keyDir, fi.Name())
- if skipKeyFile(fi) {
- log.Trace("Ignoring file on account scan", "path", path)
- continue
- }
- filesNow.Add(path)
- if modTime.After(prevMtime) {
- moddedFiles.Add(path)
- }
- if modTime.After(newMtime) {
- newMtime = modTime
- }
- }
- t2 := time.Now()
-
- fc.mu.Lock()
- // Missing = previous - current
- missing := set.Difference(fc.all, filesNow)
- // New = current - previous
- newFiles := set.Difference(filesNow, fc.all)
- // Modified = modified - new
- modified := set.Difference(moddedFiles, newFiles)
- fc.all = filesNow
- fc.mtime = newMtime
- fc.mu.Unlock()
- t3 := time.Now()
- log.Debug("FS scan times", "list", t1.Sub(t0), "set", t2.Sub(t1), "diff", t3.Sub(t2))
- return newFiles, missing, modified, nil
-}
-
// scanAccounts checks if any changes have occurred on the filesystem, and
// updates the account cache accordingly
func (ac *accountCache) scanAccounts() error {
- newFiles, missingFiles, modified, err := ac.fileC.scanFiles(ac.keydir)
- t1 := time.Now()
+ // Scan the entire folder metadata for file changes
+ creates, deletes, updates, err := ac.fileC.scan(ac.keydir)
if err != nil {
log.Debug("Failed to reload keystore contents", "err", err)
return err
}
+ if creates.Size() == 0 && deletes.Size() == 0 && updates.Size() == 0 {
+ return nil
+ }
+ // Create a helper method to scan the contents of the key files
var (
- buf = new(bufio.Reader)
- keyJSON struct {
+ buf = new(bufio.Reader)
+ key struct {
Address string `json:"address"`
}
)
@@ -308,9 +256,9 @@ func (ac *accountCache) scanAccounts() error {
defer fd.Close()
buf.Reset(fd)
// Parse the address.
- keyJSON.Address = ""
- err = json.NewDecoder(buf).Decode(&keyJSON)
- addr := common.HexToAddress(keyJSON.Address)
+ key.Address = ""
+ err = json.NewDecoder(buf).Decode(&key)
+ addr := common.HexToAddress(key.Address)
switch {
case err != nil:
log.Debug("Failed to decode keystore key", "path", path, "err", err)
@@ -321,47 +269,30 @@ func (ac *accountCache) scanAccounts() error {
}
return nil
}
+ // Process all the file diffs
+ start := time.Now()
- for _, p := range newFiles.List() {
- path, _ := p.(string)
- a := readAccount(path)
- if a != nil {
+ for _, p := range creates.List() {
+ if a := readAccount(p.(string)); a != nil {
ac.add(*a)
}
}
- for _, p := range missingFiles.List() {
- path, _ := p.(string)
- ac.deleteByFile(path)
+ for _, p := range deletes.List() {
+ ac.deleteByFile(p.(string))
}
-
- for _, p := range modified.List() {
- path, _ := p.(string)
- a := readAccount(path)
+ for _, p := range updates.List() {
+ path := p.(string)
ac.deleteByFile(path)
- if a != nil {
+ if a := readAccount(path); a != nil {
ac.add(*a)
}
}
-
- t2 := time.Now()
+ end := time.Now()
select {
case ac.notify <- struct{}{}:
default:
}
- log.Trace("Handled keystore changes", "time", t2.Sub(t1))
-
+ log.Trace("Handled keystore changes", "time", end.Sub(start))
return nil
}
-
-func skipKeyFile(fi os.FileInfo) bool {
- // Skip editor backups and UNIX-style hidden files.
- if strings.HasSuffix(fi.Name(), "~") || strings.HasPrefix(fi.Name(), ".") {
- return true
- }
- // Skip misc special files, directories (yes, symlinks too).
- if fi.IsDir() || fi.Mode()&os.ModeType != 0 {
- return true
- }
- return false
-}
diff --git a/accounts/keystore/file_cache.go b/accounts/keystore/file_cache.go
new file mode 100644
index 000000000..c91b7b7b6
--- /dev/null
+++ b/accounts/keystore/file_cache.go
@@ -0,0 +1,102 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package keystore
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/ethereum/go-ethereum/log"
+ set "gopkg.in/fatih/set.v0"
+)
+
+// fileCache is a cache of files seen during scan of keystore.
+type fileCache struct {
+ all *set.SetNonTS // Set of all files from the keystore folder
+ lastMod time.Time // Last time instance when a file was modified
+ mu sync.RWMutex
+}
+
+// scan performs a new scan on the given directory, compares against the already
+// cached filenames, and returns file sets: creates, deletes, updates.
+func (fc *fileCache) scan(keyDir string) (set.Interface, set.Interface, set.Interface, error) {
+ t0 := time.Now()
+
+ // List all the failes from the keystore folder
+ files, err := ioutil.ReadDir(keyDir)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ t1 := time.Now()
+
+ fc.mu.Lock()
+ defer fc.mu.Unlock()
+
+ // Iterate all the files and gather their metadata
+ all := set.NewNonTS()
+ mods := set.NewNonTS()
+
+ var newLastMod time.Time
+ for _, fi := range files {
+ // Skip any non-key files from the folder
+ path := filepath.Join(keyDir, fi.Name())
+ if skipKeyFile(fi) {
+ log.Trace("Ignoring file on account scan", "path", path)
+ continue
+ }
+ // Gather the set of all and fresly modified files
+ all.Add(path)
+
+ modified := fi.ModTime()
+ if modified.After(fc.lastMod) {
+ mods.Add(path)
+ }
+ if modified.After(newLastMod) {
+ newLastMod = modified
+ }
+ }
+ t2 := time.Now()
+
+ // Update the tracked files and return the three sets
+ deletes := set.Difference(fc.all, all) // Deletes = previous - current
+ creates := set.Difference(all, fc.all) // Creates = current - previous
+ updates := set.Difference(mods, creates) // Updates = modified - creates
+
+ fc.all, fc.lastMod = all, newLastMod
+ t3 := time.Now()
+
+ // Report on the scanning stats and return
+ log.Debug("FS scan times", "list", t1.Sub(t0), "set", t2.Sub(t1), "diff", t3.Sub(t2))
+ return creates, deletes, updates, nil
+}
+
+// skipKeyFile ignores editor backups, hidden files and folders/symlinks.
+func skipKeyFile(fi os.FileInfo) bool {
+ // Skip editor backups and UNIX-style hidden files.
+ if strings.HasSuffix(fi.Name(), "~") || strings.HasPrefix(fi.Name(), ".") {
+ return true
+ }
+ // Skip misc special files, directories (yes, symlinks too).
+ if fi.IsDir() || fi.Mode()&os.ModeType != 0 {
+ return true
+ }
+ return false
+}
diff --git a/accounts/keystore/keystore_passphrase.go b/accounts/keystore/keystore_passphrase.go
index 535608a60..eaec39f7d 100644
--- a/accounts/keystore/keystore_passphrase.go
+++ b/accounts/keystore/keystore_passphrase.go
@@ -28,6 +28,7 @@ package keystore
import (
"bytes"
"crypto/aes"
+ crand "crypto/rand"
"crypto/sha256"
"encoding/hex"
"encoding/json"
@@ -90,6 +91,12 @@ func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string)
return key, nil
}
+// StoreKey generates a key, encrypts with 'auth' and stores in the given directory
+func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) {
+ _, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, crand.Reader, auth)
+ return a.Address, err
+}
+
func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error {
keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP)
if err != nil {
diff --git a/accounts/keystore/watch.go b/accounts/keystore/watch.go
index 602300b10..bbcfb9925 100644
--- a/accounts/keystore/watch.go
+++ b/accounts/keystore/watch.go
@@ -81,10 +81,14 @@ func (w *watcher) loop() {
// When an event occurs, the reload call is delayed a bit so that
// multiple events arriving quickly only cause a single reload.
var (
- debounce = time.NewTimer(0)
debounceDuration = 500 * time.Millisecond
rescanTriggered = false
+ debounce = time.NewTimer(0)
)
+ // Ignore initial trigger
+ if !debounce.Stop() {
+ <-debounce.C
+ }
defer debounce.Stop()
for {
select {
diff --git a/accounts/manager.go b/accounts/manager.go
index 78ddb1368..96ca298fc 100644
--- a/accounts/manager.go
+++ b/accounts/manager.go
@@ -41,6 +41,11 @@ type Manager struct {
// NewManager creates a generic account manager to sign transaction via various
// supported backends.
func NewManager(backends ...Backend) *Manager {
+ // Retrieve the initial list of wallets from the backends and sort by URL
+ var wallets []Wallet
+ for _, backend := range backends {
+ wallets = merge(wallets, backend.Wallets()...)
+ }
// Subscribe to wallet notifications from all backends
updates := make(chan WalletEvent, 4*len(backends))
@@ -48,11 +53,6 @@ func NewManager(backends ...Backend) *Manager {
for i, backend := range backends {
subs[i] = backend.Subscribe(updates)
}
- // Retrieve the initial list of wallets from the backends and sort by URL
- var wallets []Wallet
- for _, backend := range backends {
- wallets = merge(wallets, backend.Wallets()...)
- }
// Assemble the account manager and return
am := &Manager{
backends: make(map[reflect.Type][]Backend),
diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go
index 0f53c92b0..0db5c4ce0 100644
--- a/cmd/geth/accountcmd.go
+++ b/cmd/geth/accountcmd.go
@@ -291,15 +291,28 @@ func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrErr
// accountCreate creates a new account into the keystore defined by the CLI flags.
func accountCreate(ctx *cli.Context) error {
- stack, _ := makeConfigNode(ctx)
+ cfg := gethConfig{Node: defaultNodeConfig()}
+ // Load config file.
+ if file := ctx.GlobalString(configFileFlag.Name); file != "" {
+ if err := loadConfig(file, &cfg); err != nil {
+ utils.Fatalf("%v", err)
+ }
+ }
+ utils.SetNodeConfig(ctx, &cfg.Node)
+ scryptN, scryptP, keydir, err := cfg.Node.AccountConfig()
+
+ if err != nil {
+ utils.Fatalf("Failed to read configuration: %v", err)
+ }
+
password := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
- ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
- account, err := ks.NewAccount(password)
+ address, err := keystore.StoreKey(keydir, password, scryptN, scryptP)
+
if err != nil {
utils.Fatalf("Failed to create account: %v", err)
}
- fmt.Printf("Address: {%x}\n", account.Address)
+ fmt.Printf("Address: {%x}\n", address)
return nil
}
diff --git a/eth/api.go b/eth/api.go
index e91f51bb9..12448a6a1 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -636,3 +636,86 @@ func storageRangeAt(st state.Trie, start []byte, maxResult int) StorageRangeResu
}
return result
}
+
+// GetModifiedAccountsByumber returns all accounts that have changed between the
+// two blocks specified. A change is defined as a difference in nonce, balance,
+// code hash, or storage hash.
+//
+// With one parameter, returns the list of accounts modified in the specified block.
+func (api *PrivateDebugAPI) GetModifiedAccountsByNumber(startNum uint64, endNum *uint64) ([]common.Address, error) {
+ var startBlock, endBlock *types.Block
+
+ startBlock = api.eth.blockchain.GetBlockByNumber(startNum)
+ if startBlock == nil {
+ return nil, fmt.Errorf("start block %x not found", startNum)
+ }
+
+ if endNum == nil {
+ endBlock = startBlock
+ startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash())
+ if startBlock == nil {
+ return nil, fmt.Errorf("block %x has no parent", endBlock.Number())
+ }
+ } else {
+ endBlock = api.eth.blockchain.GetBlockByNumber(*endNum)
+ if endBlock == nil {
+ return nil, fmt.Errorf("end block %d not found", *endNum)
+ }
+ }
+ return api.getModifiedAccounts(startBlock, endBlock)
+}
+
+// GetModifiedAccountsByHash returns all accounts that have changed between the
+// two blocks specified. A change is defined as a difference in nonce, balance,
+// code hash, or storage hash.
+//
+// With one parameter, returns the list of accounts modified in the specified block.
+func (api *PrivateDebugAPI) GetModifiedAccountsByHash(startHash common.Hash, endHash *common.Hash) ([]common.Address, error) {
+ var startBlock, endBlock *types.Block
+ startBlock = api.eth.blockchain.GetBlockByHash(startHash)
+ if startBlock == nil {
+ return nil, fmt.Errorf("start block %x not found", startHash)
+ }
+
+ if endHash == nil {
+ endBlock = startBlock
+ startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash())
+ if startBlock == nil {
+ return nil, fmt.Errorf("block %x has no parent", endBlock.Number())
+ }
+ } else {
+ endBlock = api.eth.blockchain.GetBlockByHash(*endHash)
+ if endBlock == nil {
+ return nil, fmt.Errorf("end block %x not found", *endHash)
+ }
+ }
+ return api.getModifiedAccounts(startBlock, endBlock)
+}
+
+func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) {
+ if startBlock.Number().Uint64() >= endBlock.Number().Uint64() {
+ return nil, fmt.Errorf("start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64())
+ }
+
+ oldTrie, err := trie.NewSecure(startBlock.Root(), api.eth.chainDb, 0)
+ if err != nil {
+ return nil, err
+ }
+ newTrie, err := trie.NewSecure(endBlock.Root(), api.eth.chainDb, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ diff, _ := trie.NewDifferenceIterator(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}))
+ iter := trie.NewIterator(diff)
+
+ var dirty []common.Address
+ for iter.Next() {
+ key := newTrie.GetKey(iter.Key)
+ if key == nil {
+ return nil, fmt.Errorf("no preimage found for hash %x", iter.Key)
+ }
+ dirty = append(dirty, common.BytesToAddress(key))
+ }
+ return dirty, nil
+}
diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go
index 1ae6e2d73..ef0d2b4e6 100644
--- a/internal/web3ext/web3ext.go
+++ b/internal/web3ext/web3ext.go
@@ -354,6 +354,18 @@ web3._extend({
call: 'debug_storageRangeAt',
params: 5,
}),
+ new web3._extend.Method({
+ name: 'getModifiedAccountsByNumber',
+ call: 'debug_getModifiedAccountsByNumber',
+ params: 2,
+ inputFormatter: [null, null],
+ }),
+ new web3._extend.Method({
+ name: 'getModifiedAccountsByHash',
+ call: 'debug_getModifiedAccountsByHash',
+ params: 2,
+ inputFormatter:[null, null],
+ }),
],
properties: []
});
diff --git a/node/config.go b/node/config.go
index be9e21b4f..1ee02d896 100644
--- a/node/config.go
+++ b/node/config.go
@@ -360,35 +360,43 @@ func (c *Config) parsePersistentNodes(path string) []*discover.Node {
return nodes
}
-func makeAccountManager(conf *Config) (*accounts.Manager, string, error) {
+// AccountConfig determines the settings for scrypt and keydirectory
+func (c *Config) AccountConfig() (int, int, string, error) {
scryptN := keystore.StandardScryptN
scryptP := keystore.StandardScryptP
- if conf.UseLightweightKDF {
+ if c.UseLightweightKDF {
scryptN = keystore.LightScryptN
scryptP = keystore.LightScryptP
}
var (
- keydir string
- ephemeral string
- err error
+ keydir string
+ err error
)
switch {
- case filepath.IsAbs(conf.KeyStoreDir):
- keydir = conf.KeyStoreDir
- case conf.DataDir != "":
- if conf.KeyStoreDir == "" {
- keydir = filepath.Join(conf.DataDir, datadirDefaultKeyStore)
+ case filepath.IsAbs(c.KeyStoreDir):
+ keydir = c.KeyStoreDir
+ case c.DataDir != "":
+ if c.KeyStoreDir == "" {
+ keydir = filepath.Join(c.DataDir, datadirDefaultKeyStore)
} else {
- keydir, err = filepath.Abs(conf.KeyStoreDir)
+ keydir, err = filepath.Abs(c.KeyStoreDir)
}
- case conf.KeyStoreDir != "":
- keydir, err = filepath.Abs(conf.KeyStoreDir)
- default:
+ case c.KeyStoreDir != "":
+ keydir, err = filepath.Abs(c.KeyStoreDir)
+ }
+ return scryptN, scryptP, keydir, err
+}
+
+func makeAccountManager(conf *Config) (*accounts.Manager, string, error) {
+ scryptN, scryptP, keydir, err := conf.AccountConfig()
+ var ephemeral string
+ if keydir == "" {
// There is no datadir.
keydir, err = ioutil.TempDir("", "go-ethereum-keystore")
ephemeral = keydir
}
+
if err != nil {
return nil, "", err
}
diff --git a/params/version.go b/params/version.go
index 40d459162..32d4a2e23 100644
--- a/params/version.go
+++ b/params/version.go
@@ -22,8 +22,8 @@ import (
const (
VersionMajor = 1 // Major version component of the current release
- VersionMinor = 7 // Minor version component of the current release
- VersionPatch = 3 // Patch version component of the current release
+ VersionMinor = 8 // Minor version component of the current release
+ VersionPatch = 0 // Patch version component of the current release
VersionMeta = "unstable" // Version metadata to append to the version string
)