github.com/murrekatt/go-ethereum@v1.5.8-0.20170123175102-fc52f2c007fb/accounts/accounts_test.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package accounts
    18  
    19  import (
    20  	"io/ioutil"
    21  	"os"
    22  	"runtime"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  )
    29  
    30  var testSigData = make([]byte, 32)
    31  
    32  func TestManager(t *testing.T) {
    33  	dir, am := tmpManager(t, true)
    34  	defer os.RemoveAll(dir)
    35  
    36  	a, err := am.NewAccount("foo")
    37  	if err != nil {
    38  		t.Fatal(err)
    39  	}
    40  	if !strings.HasPrefix(a.File, dir) {
    41  		t.Errorf("account file %s doesn't have dir prefix", a.File)
    42  	}
    43  	stat, err := os.Stat(a.File)
    44  	if err != nil {
    45  		t.Fatalf("account file %s doesn't exist (%v)", a.File, err)
    46  	}
    47  	if runtime.GOOS != "windows" && stat.Mode() != 0600 {
    48  		t.Fatalf("account file has wrong mode: got %o, want %o", stat.Mode(), 0600)
    49  	}
    50  	if !am.HasAddress(a.Address) {
    51  		t.Errorf("HasAccount(%x) should've returned true", a.Address)
    52  	}
    53  	if err := am.Update(a, "foo", "bar"); err != nil {
    54  		t.Errorf("Update error: %v", err)
    55  	}
    56  	if err := am.Delete(a, "bar"); err != nil {
    57  		t.Errorf("Delete error: %v", err)
    58  	}
    59  	if common.FileExist(a.File) {
    60  		t.Errorf("account file %s should be gone after Delete", a.File)
    61  	}
    62  	if am.HasAddress(a.Address) {
    63  		t.Errorf("HasAccount(%x) should've returned true after Delete", a.Address)
    64  	}
    65  }
    66  
    67  func TestSign(t *testing.T) {
    68  	dir, am := tmpManager(t, true)
    69  	defer os.RemoveAll(dir)
    70  
    71  	pass := "" // not used but required by API
    72  	a1, err := am.NewAccount(pass)
    73  	if err != nil {
    74  		t.Fatal(err)
    75  	}
    76  	if err := am.Unlock(a1, ""); err != nil {
    77  		t.Fatal(err)
    78  	}
    79  	if _, err := am.Sign(a1.Address, testSigData); err != nil {
    80  		t.Fatal(err)
    81  	}
    82  }
    83  
    84  func TestSignWithPassphrase(t *testing.T) {
    85  	dir, am := tmpManager(t, true)
    86  	defer os.RemoveAll(dir)
    87  
    88  	pass := "passwd"
    89  	acc, err := am.NewAccount(pass)
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  
    94  	if _, unlocked := am.unlocked[acc.Address]; unlocked {
    95  		t.Fatal("expected account to be locked")
    96  	}
    97  
    98  	_, err = am.SignWithPassphrase(acc, pass, testSigData)
    99  	if err != nil {
   100  		t.Fatal(err)
   101  	}
   102  
   103  	if _, unlocked := am.unlocked[acc.Address]; unlocked {
   104  		t.Fatal("expected account to be locked")
   105  	}
   106  
   107  	if _, err = am.SignWithPassphrase(acc, "invalid passwd", testSigData); err == nil {
   108  		t.Fatal("expected SignHash to fail with invalid password")
   109  	}
   110  }
   111  
   112  func TestTimedUnlock(t *testing.T) {
   113  	dir, am := tmpManager(t, true)
   114  	defer os.RemoveAll(dir)
   115  
   116  	pass := "foo"
   117  	a1, err := am.NewAccount(pass)
   118  	if err != nil {
   119  		t.Fatal(err)
   120  	}
   121  
   122  	// Signing without passphrase fails because account is locked
   123  	_, err = am.Sign(a1.Address, testSigData)
   124  	if err != ErrLocked {
   125  		t.Fatal("Signing should've failed with ErrLocked before unlocking, got ", err)
   126  	}
   127  
   128  	// Signing with passphrase works
   129  	if err = am.TimedUnlock(a1, pass, 100*time.Millisecond); err != nil {
   130  		t.Fatal(err)
   131  	}
   132  
   133  	// Signing without passphrase works because account is temp unlocked
   134  	_, err = am.Sign(a1.Address, testSigData)
   135  	if err != nil {
   136  		t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
   137  	}
   138  
   139  	// Signing fails again after automatic locking
   140  	time.Sleep(250 * time.Millisecond)
   141  	_, err = am.Sign(a1.Address, testSigData)
   142  	if err != ErrLocked {
   143  		t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
   144  	}
   145  }
   146  
   147  func TestOverrideUnlock(t *testing.T) {
   148  	dir, am := tmpManager(t, false)
   149  	defer os.RemoveAll(dir)
   150  
   151  	pass := "foo"
   152  	a1, err := am.NewAccount(pass)
   153  	if err != nil {
   154  		t.Fatal(err)
   155  	}
   156  
   157  	// Unlock indefinitely.
   158  	if err = am.TimedUnlock(a1, pass, 5*time.Minute); err != nil {
   159  		t.Fatal(err)
   160  	}
   161  
   162  	// Signing without passphrase works because account is temp unlocked
   163  	_, err = am.Sign(a1.Address, testSigData)
   164  	if err != nil {
   165  		t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
   166  	}
   167  
   168  	// reset unlock to a shorter period, invalidates the previous unlock
   169  	if err = am.TimedUnlock(a1, pass, 100*time.Millisecond); err != nil {
   170  		t.Fatal(err)
   171  	}
   172  
   173  	// Signing without passphrase still works because account is temp unlocked
   174  	_, err = am.Sign(a1.Address, testSigData)
   175  	if err != nil {
   176  		t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
   177  	}
   178  
   179  	// Signing fails again after automatic locking
   180  	time.Sleep(250 * time.Millisecond)
   181  	_, err = am.Sign(a1.Address, testSigData)
   182  	if err != ErrLocked {
   183  		t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
   184  	}
   185  }
   186  
   187  // This test should fail under -race if signing races the expiration goroutine.
   188  func TestSignRace(t *testing.T) {
   189  	dir, am := tmpManager(t, false)
   190  	defer os.RemoveAll(dir)
   191  
   192  	// Create a test account.
   193  	a1, err := am.NewAccount("")
   194  	if err != nil {
   195  		t.Fatal("could not create the test account", err)
   196  	}
   197  
   198  	if err := am.TimedUnlock(a1, "", 15*time.Millisecond); err != nil {
   199  		t.Fatal("could not unlock the test account", err)
   200  	}
   201  	end := time.Now().Add(500 * time.Millisecond)
   202  	for time.Now().Before(end) {
   203  		if _, err := am.Sign(a1.Address, testSigData); err == ErrLocked {
   204  			return
   205  		} else if err != nil {
   206  			t.Errorf("Sign error: %v", err)
   207  			return
   208  		}
   209  		time.Sleep(1 * time.Millisecond)
   210  	}
   211  	t.Errorf("Account did not lock within the timeout")
   212  }
   213  
   214  func tmpManager(t *testing.T, encrypted bool) (string, *Manager) {
   215  	d, err := ioutil.TempDir("", "eth-keystore-test")
   216  	if err != nil {
   217  		t.Fatal(err)
   218  	}
   219  	new := NewPlaintextManager
   220  	if encrypted {
   221  		new = func(kd string) *Manager { return NewManager(kd, veryLightScryptN, veryLightScryptP) }
   222  	}
   223  	return d, new(d)
   224  }