Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
38694394
Commit
38694394
authored
Apr 19, 2018
by
Péter Szilágyi
Committed by
Guillaume Ballet
Apr 08, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
accounts/scwallet: ordered wallets, tighter events, derivation logs
parent
114de0fe
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
81 additions
and
63 deletions
+81
-63
hub.go
accounts/scwallet/hub.go
+56
-45
wallet.go
accounts/scwallet/wallet.go
+25
-18
No files found.
accounts/scwallet/hub.go
View file @
38694394
...
...
@@ -36,14 +36,12 @@ import (
"encoding/json"
"io/ioutil"
"os"
"reflect"
"sync"
"time"
"github.com/ebfe/scard"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
)
...
...
@@ -71,9 +69,10 @@ type smartcardPairing struct {
type
Hub
struct
{
scheme
string
// Protocol scheme prefixing account and wallet URLs.
context
*
scard
.
Context
datadir
string
pairings
map
[
string
]
smartcardPairing
context
*
scard
.
Context
datadir
string
pairings
map
[
string
]
smartcardPairing
refreshed
time
.
Time
// Time instance when the list of wallets was last refreshed
wallets
map
[
string
]
*
Wallet
// Mapping from reader names to wallet instances
updateFeed
event
.
Feed
// Event feed to notify wallet additions/removals
...
...
@@ -82,11 +81,9 @@ type Hub struct {
quit
chan
chan
error
stateLock
sync
.
Mutex
// Protects the internals of the hub from racey access
stateLock
sync
.
RW
Mutex
// Protects the internals of the hub from racey access
}
var
HubType
=
reflect
.
TypeOf
(
&
Hub
{})
func
(
hub
*
Hub
)
readPairings
()
error
{
hub
.
pairings
=
make
(
map
[
string
]
smartcardPairing
)
pairingFile
,
err
:=
os
.
Open
(
hub
.
datadir
+
"/smartcards.json"
)
...
...
@@ -158,7 +155,6 @@ func NewHub(scheme string, datadir string) (*Hub, error) {
if
err
!=
nil
{
return
nil
,
err
}
hub
:=
&
Hub
{
scheme
:
scheme
,
context
:
context
,
...
...
@@ -166,28 +162,31 @@ func NewHub(scheme string, datadir string) (*Hub, error) {
wallets
:
make
(
map
[
string
]
*
Wallet
),
quit
:
make
(
chan
chan
error
),
}
if
err
:=
hub
.
readPairings
();
err
!=
nil
{
return
nil
,
err
}
hub
.
refreshWallets
()
return
hub
,
nil
}
// Wallets implements accounts.Backend, returning all the currently tracked
//
device
s that appear to be hardware wallets.
// Wallets implements accounts.Backend, returning all the currently tracked
smart
//
card
s that appear to be hardware wallets.
func
(
hub
*
Hub
)
Wallets
()
[]
accounts
.
Wallet
{
// Make sure the list of wallets is up to date
hub
.
stateLock
.
Lock
()
defer
hub
.
stateLock
.
Unlock
()
hub
.
refreshWallets
()
hub
.
stateLock
.
RLock
()
defer
hub
.
stateLock
.
RUnlock
()
cpy
:=
make
([]
accounts
.
Wallet
,
0
,
len
(
hub
.
wallets
))
for
_
,
wallet
:=
range
hub
.
wallets
{
if
wallet
!=
nil
{
cpy
=
append
(
cpy
,
wallet
)
cpy
=
append
(
cpy
,
wallet
)
}
for
i
:=
0
;
i
<
len
(
cpy
);
i
++
{
for
j
:=
i
+
1
;
j
<
len
(
cpy
);
j
++
{
if
cpy
[
i
]
.
URL
()
.
Cmp
(
cpy
[
j
]
.
URL
())
>
0
{
cpy
[
i
],
cpy
[
j
]
=
cpy
[
j
],
cpy
[
i
]
}
}
}
return
cpy
...
...
@@ -196,67 +195,77 @@ func (hub *Hub) Wallets() []accounts.Wallet {
// refreshWallets scans the devices attached to the machine and updates the
// list of wallets based on the found devices.
func
(
hub
*
Hub
)
refreshWallets
()
{
// Don't scan the USB like crazy it the user fetches wallets in a loop
hub
.
stateLock
.
RLock
()
elapsed
:=
time
.
Since
(
hub
.
refreshed
)
hub
.
stateLock
.
RUnlock
()
if
elapsed
<
refreshThrottling
{
return
}
// Retrieve all the smart card reader to check for cards
readers
,
err
:=
hub
.
context
.
ListReaders
()
if
err
!=
nil
{
log
.
Error
(
"Error listing readers"
,
"err"
,
err
)
// This is a perverted hack, the scard library returns an error if no card
// readers are present instead of simply returning an empty list. We don't
// want to fill the user's log with errors, so filter those out.
if
err
.
Error
()
!=
"scard: Cannot find a smart card reader."
{
log
.
Error
(
"Failed to enumerate smart card readers"
,
"err"
,
err
)
}
}
// Transform the current list of wallets into the new one
hub
.
stateLock
.
Lock
()
events
:=
[]
accounts
.
WalletEvent
{}
seen
:=
make
(
map
[
string
]
struct
{})
for
_
,
reader
:=
range
readers
{
// Mark the reader as present
seen
[
reader
]
=
struct
{}{}
// If we alreay know about this card, skip to the next reader, otherwise clean up
if
wallet
,
ok
:=
hub
.
wallets
[
reader
];
ok
{
// We already know about this card; check it's still present
if
err
:=
wallet
.
ping
();
err
!=
nil
{
log
.
Debug
(
"Got error pinging wallet"
,
"reader"
,
reader
,
"err"
,
err
)
}
else
{
seen
[
reader
]
=
struct
{}{}
if
err
:=
wallet
.
ping
();
err
==
nil
{
continue
}
continue
wallet
.
Close
()
events
=
append
(
events
,
accounts
.
WalletEvent
{
Wallet
:
wallet
,
Kind
:
accounts
.
WalletDropped
})
delete
(
hub
.
wallets
,
reader
)
}
seen
[
reader
]
=
struct
{}{}
// New card detected, try to connect to it
card
,
err
:=
hub
.
context
.
Connect
(
reader
,
scard
.
ShareShared
,
scard
.
ProtocolAny
)
if
err
!=
nil
{
log
.
Debug
(
"
Error opening
card"
,
"reader"
,
reader
,
"err"
,
err
)
log
.
Debug
(
"
Failed to open smart
card"
,
"reader"
,
reader
,
"err"
,
err
)
continue
}
wallet
:=
NewWallet
(
hub
,
card
)
err
=
wallet
.
connect
()
if
err
!=
nil
{
log
.
Debug
(
"Error connecting to wallet"
,
"reader"
,
reader
,
"err"
,
err
)
if
err
=
wallet
.
connect
();
err
!=
nil
{
log
.
Debug
(
"Failed to connect to smart card"
,
"reader"
,
reader
,
"err"
,
err
)
card
.
Disconnect
(
scard
.
LeaveCard
)
continue
}
// Card connected, start tracking in amongs the wallets
hub
.
wallets
[
reader
]
=
wallet
events
=
append
(
events
,
accounts
.
WalletEvent
{
Wallet
:
wallet
,
Kind
:
accounts
.
WalletArrived
})
log
.
Info
(
"Found new smartcard wallet"
,
"reader"
,
reader
,
"publicKey"
,
hexutil
.
Encode
(
wallet
.
PublicKey
[
:
4
]))
}
// Remove any wallets we no longer see
for
k
,
wallet
:=
range
hub
.
wallets
{
if
_
,
ok
:=
seen
[
k
];
!
ok
{
log
.
Info
(
"Wallet disconnected"
,
"pubkey"
,
hexutil
.
Encode
(
wallet
.
PublicKey
[
:
4
]),
"reader"
,
k
)
// Remove any wallets no longer present
for
reader
,
wallet
:=
range
hub
.
wallets
{
if
_
,
ok
:=
seen
[
reader
];
!
ok
{
wallet
.
Close
()
events
=
append
(
events
,
accounts
.
WalletEvent
{
Wallet
:
wallet
,
Kind
:
accounts
.
WalletDropped
})
delete
(
hub
.
wallets
,
k
)
delete
(
hub
.
wallets
,
reader
)
}
}
hub
.
refreshed
=
time
.
Now
()
hub
.
stateLock
.
Unlock
()
for
_
,
event
:=
range
events
{
hub
.
updateFeed
.
Send
(
event
)
}
hub
.
refreshed
=
time
.
Now
()
}
// Subscribe implements accounts.Backend, creating an async subscription to
// receive notifications on the addition or removal of wallets.
// receive notifications on the addition or removal of
smart card
wallets.
func
(
hub
*
Hub
)
Subscribe
(
sink
chan
<-
accounts
.
WalletEvent
)
event
.
Subscription
{
// We need the mutex to reliably start/stop the update loop
hub
.
stateLock
.
Lock
()
...
...
@@ -274,16 +283,18 @@ func (hub *Hub) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription {
}
// updater is responsible for maintaining an up-to-date list of wallets managed
// by the hub, and for firing wallet addition/removal events.
// by the
smart card
hub, and for firing wallet addition/removal events.
func
(
hub
*
Hub
)
updater
()
{
for
{
// TODO: Wait for a USB hotplug event (not supported yet) or a refresh timeout
// <-hub.changes
time
.
Sleep
(
refreshCycle
)
// Run the wallet refresher
hub
.
stateLock
.
Lock
()
hub
.
refreshWallets
()
// If all our subscribers left, stop the updater
hub
.
stateLock
.
Lock
()
if
hub
.
updateScope
.
Count
()
==
0
{
hub
.
updating
=
false
hub
.
stateLock
.
Unlock
()
...
...
accounts/scwallet/wallet.go
View file @
38694394
...
...
@@ -93,10 +93,11 @@ type Wallet struct {
Hub
*
Hub
// A handle to the Hub that instantiated this wallet.
PublicKey
[]
byte
// The wallet's public key (used for communication and identification, not signing!)
lock
sync
.
Mutex
// Lock that gates access to struct fields and communication with the card
card
*
scard
.
Card
// A handle to the smartcard interface for the wallet.
session
*
Session
// The secure communication session with the card
log
log
.
Logger
// Contextual logger to tag the base with its id
lock
sync
.
Mutex
// Lock that gates access to struct fields and communication with the card
card
*
scard
.
Card
// A handle to the smartcard interface for the wallet.
session
*
Session
// The secure communication session with the card
log
log
.
Logger
// Contextual logger to tag the base with its id
deriveNextPath
accounts
.
DerivationPath
// Next derivation path for account auto-discovery
deriveNextAddr
common
.
Address
// Next derived account address for auto-discovery
deriveChain
ethereum
.
ChainStateReader
// Blockchain state reader to discover used account with
...
...
@@ -273,7 +274,7 @@ func (w *Wallet) Unpair(pin []byte) error {
func
(
w
*
Wallet
)
URL
()
accounts
.
URL
{
return
accounts
.
URL
{
Scheme
:
w
.
Hub
.
scheme
,
Path
:
fmt
.
Sprintf
(
"%x"
,
w
.
PublicKey
[
1
:
3
]),
Path
:
fmt
.
Sprintf
(
"%x"
,
w
.
PublicKey
[
1
:
5
]),
// Byte #0 isn't unique; 1:5 covers << 64K cards, bump to 1:9 for << 4M
}
}
...
...
@@ -327,7 +328,7 @@ func (w *Wallet) Open(passphrase string) error {
if
err
:=
w
.
session
.
authenticate
(
*
pairing
);
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to authenticate card %x: %s"
,
w
.
PublicKey
[
:
4
],
err
)
}
return
nil
return
ErrPINNeeded
}
// If no passphrase was supplied, request the PUK from the user
if
passphrase
==
""
{
...
...
@@ -389,8 +390,8 @@ func (w *Wallet) Close() error {
// selfDerive is an account derivation loop that upon request attempts to find
// new non-zero accounts.
func
(
w
*
Wallet
)
selfDerive
()
{
w
.
log
.
Debug
(
"Smartcard wallet self-derivation started"
)
defer
w
.
log
.
Debug
(
"Smartcard wallet self-derivation stopped"
)
w
.
log
.
Debug
(
"Smart
card wallet self-derivation started"
)
defer
w
.
log
.
Debug
(
"Smart
card wallet self-derivation stopped"
)
// Execute self-derivations until termination or error
var
(
...
...
@@ -418,21 +419,22 @@ func (w *Wallet) selfDerive() {
// Device lock obtained, derive the next batch of accounts
var
(
paths
[]
accounts
.
DerivationPath
nextAccount
accounts
.
Account
nextAddr
=
w
.
deriveNextAddr
nextPath
=
w
.
deriveNextPath
paths
[]
accounts
.
DerivationPath
nextAcc
accounts
.
Account
nextAddr
=
w
.
deriveNextAddr
nextPath
=
w
.
deriveNextPath
context
=
context
.
Background
()
)
for
empty
:=
false
;
!
empty
;
{
// Retrieve the next derived Ethereum account
if
nextAddr
==
(
common
.
Address
{})
{
if
nextAcc
ount
,
err
=
w
.
session
.
derive
(
nextPath
);
err
!=
nil
{
if
nextAcc
,
err
=
w
.
session
.
derive
(
nextPath
);
err
!=
nil
{
w
.
log
.
Warn
(
"Smartcard wallet account derivation failed"
,
"err"
,
err
)
break
}
nextAddr
=
nextAcc
ount
.
Address
nextAddr
=
nextAcc
.
Address
}
// Check the account's status against the current chain state
var
(
...
...
@@ -459,8 +461,8 @@ func (w *Wallet) selfDerive() {
paths
=
append
(
paths
,
path
)
// Display a log message to the user for new (or previously empty accounts)
if
_
,
known
:=
pairing
.
Accounts
[
nextAddr
];
!
known
||
(
!
empty
&&
nextAddr
==
w
.
deriveNextAddr
)
{
w
.
log
.
Info
(
"Smartcard wallet discovered new account"
,
"address"
,
nextA
ccount
.
Address
,
"path"
,
path
,
"balance"
,
balance
,
"nonce"
,
nonce
)
if
_
,
known
:=
pairing
.
Accounts
[
nextAddr
];
!
known
||
!
empty
||
nextAddr
!=
w
.
deriveNextAddr
{
w
.
log
.
Info
(
"Smartcard wallet discovered new account"
,
"address"
,
nextA
ddr
,
"path"
,
path
,
"balance"
,
balance
,
"nonce"
,
nonce
)
}
pairing
.
Accounts
[
nextAddr
]
=
path
...
...
@@ -470,12 +472,10 @@ func (w *Wallet) selfDerive() {
nextPath
[
len
(
nextPath
)
-
1
]
++
}
}
// If there are new accounts, write them out
if
len
(
paths
)
>
0
{
err
=
w
.
Hub
.
setPairing
(
w
,
pairing
)
}
// Shift the self-derivation forward
w
.
deriveNextAddr
=
nextAddr
w
.
deriveNextPath
=
nextPath
...
...
@@ -524,6 +524,13 @@ func (w *Wallet) Accounts() []accounts.Account {
for
address
,
path
:=
range
pairing
.
Accounts
{
ret
=
append
(
ret
,
w
.
makeAccount
(
address
,
path
))
}
for
i
:=
0
;
i
<
len
(
ret
);
i
++
{
for
j
:=
i
+
1
;
j
<
len
(
ret
);
j
++
{
if
ret
[
i
]
.
URL
.
Cmp
(
ret
[
j
]
.
URL
)
>
0
{
ret
[
i
],
ret
[
j
]
=
ret
[
j
],
ret
[
i
]
}
}
}
return
ret
}
return
nil
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment