mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-21 23:39:26 +00:00
docs: update go account management page (#25189)
* update go accounts page * refine draft * apply suggestions from code review rewords description of key encryption and adds links to Scrypt docs. Adds warning that best practise is to use Clef.
This commit is contained in:
parent
b222b2e507
commit
8d276f51bf
1 changed files with 114 additions and 143 deletions
|
|
@ -3,70 +3,48 @@ title: Go Account Management
|
||||||
sort_key: D
|
sort_key: D
|
||||||
---
|
---
|
||||||
|
|
||||||
To provide Ethereum integration for your native applications, the very first thing you
|
Geth provides a simple, yet thorough accounts package that includes all the tools developers
|
||||||
should be interested in doing is account management.
|
need to leverage all the security of Geth's crypto implementation in a Go native application.
|
||||||
|
The account management is done client side with all sensitive data held inside the application.
|
||||||
|
This gives the user control over access permissions without relying on any third party.
|
||||||
|
|
||||||
Although all current leading Ethereum implementations provide account management built in,
|
**Note Geth's built-in account management is convenient and straightforward to use, but
|
||||||
it is ill advised to keep accounts in any location that is shared between multiple
|
best practise is to use the external tool *Clef* for key management.**
|
||||||
applications and/or multiple people. The same way you do not entrust your ISP (who is
|
|
||||||
after all your gateway into the internet) with your login credentials; you should not
|
|
||||||
entrust an Ethereum node (who is your gateway into the Ethereum network) with your
|
|
||||||
credentials either.
|
|
||||||
|
|
||||||
The proper way to handle user accounts in your native applications is to do client side
|
{:toc}
|
||||||
account management, everything self-contained within your own application. This way you
|
|
||||||
can ensure as fine grained (or as coarse) access permissions to the sensitive data as
|
|
||||||
deemed necessary, without relying on any third party application's functionality and/or
|
|
||||||
vulnerabilities.
|
|
||||||
|
|
||||||
To support this, `go-ethereum` provides a simple, yet thorough accounts package that gives
|
- this will be removed by the toc
|
||||||
you all the tools to do properly secured account management via encrypted keystores and
|
|
||||||
passphrase protected accounts. You can leverage all the security of the `go-ethereum`
|
|
||||||
crypto implementation while at the same time running everything in your own application.
|
|
||||||
|
|
||||||
## Encrypted keystores
|
## Encrypted keystores
|
||||||
|
|
||||||
Although handling accounts locally to an application does provide certain security
|
Access keys to Ethereum accounts should never be stored in plain-text. Instead, they should be
|
||||||
guarantees, access keys to Ethereum accounts should never lay around in clear-text form.
|
stored encrypted so that even if the mobile device is accessed by a malicious third party the
|
||||||
As such, we provide an encrypted keystore that provides the proper security guarantees for
|
keys are still hidden under an additional layer of security. Geth provides a keystore that enables
|
||||||
you without requiring a thorough understanding from your part of the associated
|
developers to store keys securely. The Geth keystore uses [Scrypt][scrypt-docs] to store keys that are encoded
|
||||||
cryptographic primitives.
|
using the [`secp256k1`][secp256k1] elliptic curve. Accounts are stored on disk in the
|
||||||
|
[Web3 Secret Storage][wss] format. Developers should be aware of these implementation details
|
||||||
|
but are not required to deeply understand the cryptographic primitives in order to use the keystore.
|
||||||
|
|
||||||
The important thing to know when using the encrypted keystore is that the cryptographic
|
One thing that should be understood, though, is that the cryptographic primitives underpinning the
|
||||||
primitives used within can operate either in *standard* or *light* mode. The former
|
keystore can operate in light or standard mode. Light mode is computationally cheaper, while standard
|
||||||
provides a higher level of security at the cost of increased computational burden and
|
mode has extra security. Light mode is appropriate for mobile devices, but developers should be
|
||||||
resource consumption:
|
aware that there is a security trade-off.
|
||||||
|
|
||||||
* *standard* needs 256MB memory and 1 second processing on a modern CPU to access a key
|
* standard needs 256MB memory and 1 second processing on a modern CPU to access a key
|
||||||
* *light* needs 4MB memory and 100 millisecond processing on a modern CPU to access a key
|
* light needs 4MB memory and 100 millisecond processing on a modern CPU to access a key
|
||||||
|
|
||||||
As such, *standard* is more suitable for native applications, but you should be aware of
|
|
||||||
the trade-offs nonetheless in case you you're targeting more resource constrained
|
|
||||||
environments.
|
|
||||||
|
|
||||||
*For those interested in the cryptographic and/or implementation details, the key-store
|
The encrypted keystore is implemented by the [`accounts.Manager`][accounts-manager] struct
|
||||||
uses the `secp256k1` elliptic curve as defined in the [Standards for Efficient
|
from the [`accounts`][accounts-pkg] package, which also contains the configuration constants for the
|
||||||
Cryptography](https://www.secg.org/sec2-v2.pdf), implemented by the [`libsecp256k`](https://github.com/bitcoin-core/secp256k1) library and wrapped by
|
*standard* or *light* security modes described above. Hence client side account management
|
||||||
[`github.com/ethereum/go-ethereum/accounts`](https://godoc.org/github.com/ethereum/go-ethereum/accounts). Accounts are stored on disk in
|
simply requires importing the `accounts` package into the application code.
|
||||||
the [Web3 Secret Storage](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) format.*
|
|
||||||
|
|
||||||
### Keystores from Go
|
|
||||||
|
|
||||||
The encrypted keystore is implemented by the
|
|
||||||
[`accounts.Manager`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager)
|
|
||||||
struct from the
|
|
||||||
[`github.com/ethereum/go-ethereum/accounts`](https://godoc.org/github.com/ethereum/go-ethereum/accounts)
|
|
||||||
package, which also contains the configuration constants for the *standard* or *light*
|
|
||||||
security modes described above. Hence to do client side account management from Go, you'll
|
|
||||||
need to import only the `accounts` package into your code:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/ethereum/go-ethereum/accounts"
|
import "github.com/ethereum/go-ethereum/accounts"
|
||||||
import "github.com/ethereum/go-ethereum/accounts/keystore"
|
import "github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
import "github.com/ethereum/go-ethereum/common"
|
import "github.com/ethereum/go-ethereum/common"
|
||||||
```
|
```
|
||||||
|
Afterwards a new encrypted account manager can be created via:
|
||||||
Afterwards you can create a new encrypted account manager via:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
ks := keystore.NewKeyStore("/path/to/keystore", keystore.StandardScryptN, keystore.StandardScryptP)
|
ks := keystore.NewKeyStore("/path/to/keystore", keystore.StandardScryptN, keystore.StandardScryptP)
|
||||||
|
|
@ -74,69 +52,60 @@ am := accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: false}, ks)
|
||||||
```
|
```
|
||||||
|
|
||||||
The path to the keystore folder needs to be a location that is writable by the local user
|
The path to the keystore folder needs to be a location that is writable by the local user
|
||||||
but non-readable for other system users (for security reasons obviously), so we'd
|
but non-readable for other system users, such as inside the user's home directory.
|
||||||
recommend placing it either inside your user's home directory or even more locked down for
|
|
||||||
backend applications.
|
The last two arguments of [`keystore.NewKeyStore`][keystore] are the crypto parameters defining
|
||||||
|
how resource-intensive the keystore encryption should be. The options are
|
||||||
|
[`accounts.StandardScryptN, accounts.StandardScryptP`, `accounts.LightScryptN,
|
||||||
|
accounts.LightScryptP`][pkg-constants] or custom values (requiring understanding of the underlying
|
||||||
|
cryptography). The *standard* version is recommended.
|
||||||
|
|
||||||
The last two arguments of
|
|
||||||
[`keystore.NewKeyStore`](https://godoc.org/github.com/ethereum/go-ethereum/accounts/keystore#NewKeyStore)
|
|
||||||
are the crypto parameters defining how resource-intensive the keystore encryption should
|
|
||||||
be. You can choose between [`accounts.StandardScryptN, accounts.StandardScryptP`,
|
|
||||||
`accounts.LightScryptN,
|
|
||||||
accounts.LightScryptP`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#pkg-constants)
|
|
||||||
or specify your own numbers (please make sure you understand the underlying cryptography
|
|
||||||
for this). We recommend using the *standard* version.
|
|
||||||
|
|
||||||
## Account lifecycle
|
## Account lifecycle
|
||||||
|
|
||||||
Having created an encrypted keystore for your Ethereum accounts, you can use this account
|
Once an encrypted keystore for Ethereum accounts exists it, it can be used to manage accounts for the
|
||||||
manager for the entire account lifecycle requirements of your native application. This
|
entire account lifecycle requirements of a Go native application. This includes the basic functionality
|
||||||
includes the basic functionality of creating new accounts and deleting existing ones; as
|
of creating new accounts and deleting existing ones as well as updating access credentials,
|
||||||
well as the more advanced functionality of updating access credentials, exporting existing
|
exporting existing accounts, and importing them on other devices.
|
||||||
accounts, and importing them on another device.
|
|
||||||
|
|
||||||
Although the keystore defines the encryption strength it uses to store your accounts,
|
Although the keystore defines the encryption strength it uses to store accounts, there is no global master
|
||||||
there is no global master password that can grant access to all of them. Rather each
|
password that can grant access to all of them. Rather each account is maintained individually, and stored on
|
||||||
account is maintained individually, and stored on disk in its [encrypted
|
disk in its [encrypted format][wss] individually, ensuring a much cleaner and stricter separation of
|
||||||
format](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition)
|
credentials.
|
||||||
individually, ensuring a much cleaner and stricter separation of credentials.
|
|
||||||
|
|
||||||
This individuality however means that any operation requiring access to an account will
|
This individuality means that any operation requiring access to an account will need to provide the
|
||||||
need to provide the necessary authentication credentials for that particular account in
|
necessary authentication credentials for that particular account in the form of a passphrase:
|
||||||
the form of a passphrase:
|
|
||||||
|
|
||||||
* When creating a new account, the caller must supply a passphrase to encrypt the account
|
* When creating a new account, the caller must supply a passphrase to encrypt the account
|
||||||
with. This passphrase will be required for any subsequent access, the lack of which
|
with. This passphrase will be required for any subsequent access, the lack of which
|
||||||
will forever forfeit using the newly created account.
|
will forever forfeit using the newly created account.
|
||||||
|
|
||||||
* When deleting an existing account, the caller must supply a passphrase to verify
|
* When deleting an existing account, the caller must supply a passphrase to verify
|
||||||
ownership of the account. This isn't cryptographically necessary, rather a protective
|
ownership of the account. This isn't cryptographically necessary, rather a protective
|
||||||
measure against accidental loss of accounts.
|
measure against accidental loss of accounts.
|
||||||
|
|
||||||
* When updating an existing account, the caller must supply both current and new
|
* When updating an existing account, the caller must supply both current and new
|
||||||
passphrases. After completing the operation, the account will not be accessible via the
|
passphrases. After completing the operation, the account will not be accessible via the
|
||||||
old passphrase any more.
|
old passphrase any more.
|
||||||
|
|
||||||
* When exporting an existing account, the caller must supply both the current passphrase
|
* When exporting an existing account, the caller must supply both the current passphrase
|
||||||
to decrypt the account, as well as an export passphrase to re-encrypt it with before
|
to decrypt the account, as well as an export passphrase to re-encrypt it with before
|
||||||
returning the key-file to the user. This is required to allow moving accounts between
|
returning the key-file to the user. This is required to allow moving accounts between
|
||||||
machines and applications without sharing original credentials.
|
machines and applications without sharing original credentials.
|
||||||
|
|
||||||
* When importing a new account, the caller must supply both the encryption passphrase of
|
* When importing a new account, the caller must supply both the encryption passphrase of
|
||||||
the key-file being imported, as well as a new passhprase with which to store the
|
the key-file being imported, as well as a new passhprase with which to store the
|
||||||
account. This is required to allow storing account with different credentials than used
|
account. This is required to allow storing account with different credentials than used
|
||||||
for moving them around.
|
for moving them around.
|
||||||
|
|
||||||
*Please note, there is no recovery mechanisms for losing the passphrases. The
|
***Please note, there are no recovery mechanisms for lost passphrases. The
|
||||||
cryptographic properties of the encrypted keystore (if using the provided parameters)
|
cryptographic properties of the encrypted keystore (using the provided parameters)
|
||||||
guarantee that account credentials cannot be brute forced in any meaningful time.*
|
guarantee that account credentials cannot be brute forced in any meaningful time.***
|
||||||
|
|
||||||
### Accounts from Go
|
An Ethereum account is implemented by the [`accounts.Account`][accounts-account] struct from
|
||||||
|
the Geth [accounts][accounts-pkg] package. Assuming an instance of an
|
||||||
An Ethereum account is implemented by the
|
[`accounts.Manager`][accounts-manager] called `am` exists, all of the described lifecycle
|
||||||
[`accounts.Account`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Account)
|
operations can be executed with a handful of function calls (error handling omitted).
|
||||||
struct from the
|
|
||||||
[`github.com/ethereum/go-ethereum/accounts`](https://godoc.org/github.com/ethereum/go-ethereum/accounts)
|
|
||||||
package. Assuming we already have an instance of an
|
|
||||||
[`accounts.Manager`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager)
|
|
||||||
called `am` from the previous section, we can easily execute all of the described
|
|
||||||
lifecycle operations with a handful of function calls (error handling omitted).
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Create a new account with the specified encryption passphrase.
|
// Create a new account with the specified encryption passphrase.
|
||||||
|
|
@ -158,58 +127,47 @@ _ = ks.Delete(newAcc, "Update password")
|
||||||
impAcc, _ := ks.Import(jsonAcc, "Export password", "Import password")
|
impAcc, _ := ks.Import(jsonAcc, "Export password", "Import password")
|
||||||
```
|
```
|
||||||
|
|
||||||
*Although instances of
|
*Although instances of [`accounts.Account`][accounts-account] can be used to access various information about
|
||||||
[`accounts.Account`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Account)
|
specific Ethereum accounts, they do not contain any sensitive data (such as passphrases or private keys),
|
||||||
can be used to access various information about specific Ethereum accounts, they do not
|
rather they act solely as identifiers for client code and the keystore.*
|
||||||
contain any sensitive data (such as passphrases or private keys), rather act solely as
|
|
||||||
identifiers for client code and the keystore.*
|
|
||||||
|
|
||||||
## Signing authorization
|
## Signing authorization
|
||||||
|
|
||||||
As mentioned above, account objects do not hold the sensitive private keys of the
|
Account objects do not hold the sensitive private keys of the associated Ethereum accounts.
|
||||||
associated Ethereum accounts, but are merely placeholders to identify the cryptographic
|
Account objects are placeholders that identify the cryptographic keys. All operations that
|
||||||
keys with. All operations that require authorization (e.g. transaction signing) are
|
require authorization (e.g. transaction signing) are performed by the account manager after
|
||||||
performed by the account manager after granting it access to the private keys.
|
granting it access to the private keys.
|
||||||
|
|
||||||
There are a few different ways one can authorize the account manager to execute signing
|
There are a few different ways to authorize the account manager to execute signing
|
||||||
operations, each having its advantages and drawbacks. Since the different methods have
|
operations, each having its advantages and drawbacks. Since the different methods have
|
||||||
wildly different security guarantees, it is essential to be clear on how each works:
|
wildly different security guarantees, it is essential to be clear on how each works:
|
||||||
|
|
||||||
* **Single authorization**: The simplest way to sign a transaction via the account
|
* **Single authorization**: The simplest way to sign a transaction via the account
|
||||||
manager is to provide the passphrase of the account every time something needs to be
|
manager is to provide the passphrase of the account every time something needs to be
|
||||||
signed, which will ephemerally decrypt the private key, execute the signing operation
|
signed, which will ephemerally decrypt the private key, execute the signing operation
|
||||||
and immediately throw away the decrypted key. The drawbacks are that the passphrase
|
and immediately throw away the decrypted key. The drawbacks are that the passphrase
|
||||||
needs to be queried from the user every time, which can become annoying if done
|
needs to be queried from the user every time, which can become annoying if done
|
||||||
frequently; or the application needs to keep the passphrase in memory, which can have
|
frequently or the application needs to keep the passphrase in memory, which can have
|
||||||
security consequences if not done properly; and depending on the keystore's configured
|
security consequences if not done properly. Depending on the keystore's configured
|
||||||
strength, constantly decrypting keys can result in non-negligible resource
|
strength, constantly decrypting keys can result in non-negligible resource
|
||||||
requirements.
|
requirements.
|
||||||
* **Multiple authorizations**: A more complex way of signing transactions via the account
|
|
||||||
manager is to unlock the account via its passphrase once, and allow the account manager
|
|
||||||
to cache the decrypted private key, enabling all subsequent signing requests to
|
|
||||||
complete without the passphrase. The lifetime of the cached private key may be managed
|
|
||||||
manually (by explicitly locking the account back up) or automatically (by providing a
|
|
||||||
timeout during unlock). This mechanism is useful for scenarios where the user may need
|
|
||||||
to sign many transactions or the application would need to do so without requiring user
|
|
||||||
input. The crucial aspect to remember is that **anyone with access to the account
|
|
||||||
manager can sign transactions while a particular account is unlocked** (e.g.
|
|
||||||
application running untrusted code).
|
|
||||||
|
|
||||||
*Note, creating transactions is out of scope here, so the remainder of this section will
|
* **Multiple authorizations**: A more complex way of signing transactions via the account
|
||||||
assume we already have a transaction hash to sign, and will focus only on creating a
|
manager is to unlock the account via its passphrase once, and allow the account manager
|
||||||
cryptographic signature authorizing it. Creating an actual transaction and injecting the
|
to cache the decrypted private key, enabling all subsequent signing requests to
|
||||||
authorization signature into it will be covered later.*
|
complete without the passphrase. The lifetime of the cached private key may be managed
|
||||||
|
manually (by explicitly locking the account back up) or automatically (by providing a
|
||||||
|
timeout during unlock). This mechanism is useful for scenarios where the user may need
|
||||||
|
to sign many transactions or the application would need to do so without requiring user
|
||||||
|
input. The crucial aspect to remember is that **anyone with access to the account
|
||||||
|
manager can sign transactions while a particular account is unlocked** (e.g.
|
||||||
|
application running untrusted code).
|
||||||
|
|
||||||
### Signing from Go
|
|
||||||
|
|
||||||
Assuming we already have an instance of an
|
Assuming an instance of an [`accounts.Manager`][accounts-manager] called `am` exists, a new
|
||||||
[`accounts.Manager`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager)
|
account can be created to sign transactions using [`NewAccount`][new-account]. Creating transactions
|
||||||
called `am` from the previous sections, we can create a new account to sign transactions
|
is out of scope for this page so instead a random [`common.Hash`][common-hash] will be signed instead.
|
||||||
with via it's already demonstrated
|
For information on creating transactions in Go native applications see the [Go API page](/docs/dapp/native).
|
||||||
[`NewAccount`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.NewAccount)
|
|
||||||
method; and to avoid going into transaction creation for now, we can hard-code a random
|
|
||||||
[`common.Hash`](https://godoc.org/github.com/ethereum/go-ethereum/common#Hash) to sign
|
|
||||||
instead.
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Create a new account to sign transactions with
|
// Create a new account to sign transactions with
|
||||||
|
|
@ -217,7 +175,7 @@ signer, _ := ks.NewAccount("Signer password")
|
||||||
txHash := common.HexToHash("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
txHash := common.HexToHash("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||||
```
|
```
|
||||||
|
|
||||||
With the boilerplate out of the way, we can now sign transaction using the authorization
|
With the boilerplate out of the way, the transaction can be signed using the authorization
|
||||||
mechanisms described above:
|
mechanisms described above:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
|
@ -234,19 +192,32 @@ _ = ks.TimedUnlock(signer, "Signer password", time.Second)
|
||||||
signature, _ = ks.SignHash(signer, txHash.Bytes())
|
signature, _ = ks.SignHash(signer, txHash.Bytes())
|
||||||
```
|
```
|
||||||
|
|
||||||
You may wonder why
|
Note that [`SignWithPassphrase`][sign-w-phrase] takes an [`accounts.Account`][accounts-account] as the
|
||||||
[`SignWithPassphrase`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.SignWithPassphrase)
|
signer, whereas [`Sign`][accounts-sign] takes only a [`common.Address`][common-address]. The reason
|
||||||
takes an
|
for this is that an [`accounts.Account`][accounts-account] object may also contain a custom key-path, allowing
|
||||||
[`accounts.Account`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Account)
|
[`SignWithPassphrase`][sign-w-phrase] to sign using accounts outside of the keystore; however
|
||||||
as the signer, whereas
|
[`Sign`][accounts-sign] relies on accounts already unlocked within the keystore, so it cannot specify custom paths.
|
||||||
[`Sign`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.Sign) takes
|
|
||||||
only a
|
|
||||||
[`common.Address`](https://godoc.org/github.com/ethereum/go-ethereum/common#Address). The
|
|
||||||
reason is that an
|
|
||||||
[`accounts.Account`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Account)
|
|
||||||
object may also contain a custom key-path, allowing
|
|
||||||
[`SignWithPassphrase`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.SignWithPassphrase)
|
|
||||||
to sign using accounts outside of the keystore; however
|
|
||||||
[`Sign`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.Sign) relies
|
|
||||||
on accounts already unlocked within the keystore, so it cannot specify custom paths.
|
|
||||||
|
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Account management is a fundamental pillar of Ethereum development. Geth's Go API provides the tools required
|
||||||
|
to integrate best-practise account security into Go native applications using a simple set of Go functions.
|
||||||
|
|
||||||
|
|
||||||
|
[accounts-sign]: (https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.Sign)
|
||||||
|
[common-address]: https://godoc.org/github.com/ethereum/go-ethereum/common#Address
|
||||||
|
[accounts-sign]: https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.Sign
|
||||||
|
[sign-w-phrase]: https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.SignWithPassphrase
|
||||||
|
[secp256k1]: https://www.secg.org/sec2-v2.pdf
|
||||||
|
[libsecp256k1]: https://github.com/bitcoin-core/secp256k1
|
||||||
|
[wss]:https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition
|
||||||
|
[go-accounts]:https://godoc.org/github.com/ethereum/go-ethereum/accounts
|
||||||
|
[accounts-manager]: https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager
|
||||||
|
[accounts-pkg]: https://godoc.org/github.com/ethereum/go-ethereum/accounts
|
||||||
|
[keystore]: https://godoc.org/github.com/ethereum/go-ethereum/accounts/keystore#NewKeyStore
|
||||||
|
[pkg-constants]: https://godoc.org/github.com/ethereum/go-ethereum/accounts#pkg-constants
|
||||||
|
[accounts-account]:https://godoc.org/github.com/ethereum/go-ethereum/accounts#Account
|
||||||
|
[new-account]: https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.NewAccount
|
||||||
|
[common-hash]: https://godoc.org/github.com/ethereum/go-ethereum/common#Hash
|
||||||
|
[scrypt-docs]: https://pkg.go.dev/golang.org/x/crypto/scrypt
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue