mirror of
https://github.com/muun/recovery.git
synced 2025-11-11 06:20:16 -05:00
Release v0.1.0
This commit is contained in:
62
vendor/github.com/btcsuite/btcwallet/waddrmgr/README.md
generated
vendored
Normal file
62
vendor/github.com/btcsuite/btcwallet/waddrmgr/README.md
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
waddrmgr
|
||||
========
|
||||
|
||||
[]
|
||||
(https://travis-ci.org/btcsuite/btcwallet)
|
||||
|
||||
Package waddrmgr provides a secure hierarchical deterministic wallet address
|
||||
manager.
|
||||
|
||||
A suite of tests is provided to ensure proper functionality. See
|
||||
`test_coverage.txt` for the gocov coverage report. Alternatively, if you are
|
||||
running a POSIX OS, you can run the `cov_report.sh` script for a real-time
|
||||
report. Package waddrmgr is licensed under the liberal ISC license.
|
||||
|
||||
## Feature Overview
|
||||
|
||||
- BIP0032 hierarchical deterministic keys
|
||||
- BIP0043/BIP0044 multi-account hierarchy
|
||||
- Strong focus on security:
|
||||
- Fully encrypted database including public information such as addresses as
|
||||
well as private information such as private keys and scripts needed to
|
||||
redeem pay-to-script-hash transactions
|
||||
- Hardened against memory scraping through the use of actively clearing
|
||||
private material from memory when locked
|
||||
- Different crypto keys used for public, private, and script data
|
||||
- Ability for different passphrases for public and private data
|
||||
- Scrypt-based key derivation
|
||||
- NaCl-based secretbox cryptography (XSalsa20 and Poly1305)
|
||||
- Scalable design:
|
||||
- Multi-tier key design to allow instant password changes regardless of the
|
||||
number of addresses stored
|
||||
- Import WIF keys
|
||||
- Import pay-to-script-hash scripts for things such as multi-signature
|
||||
transactions
|
||||
- Ability to export a watching-only version which does not contain any private
|
||||
key material
|
||||
- Programmatically detectable errors, including encapsulation of errors from
|
||||
packages it relies on
|
||||
- Address synchronization capabilities
|
||||
- Comprehensive test coverage
|
||||
|
||||
## Documentation
|
||||
|
||||
[]
|
||||
(http://godoc.org/github.com/btcsuite/btcwallet/waddrmgr)
|
||||
|
||||
Full `go doc` style documentation for the project can be viewed online without
|
||||
installing this package by using the GoDoc site here:
|
||||
http://godoc.org/github.com/btcsuite/btcwallet/waddrmgr
|
||||
|
||||
You can also view the documentation locally once the package is installed with
|
||||
the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to
|
||||
http://localhost:6060/pkg/github.com/btcsuite/btcwallet/waddrmgr
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ go get github.com/btcsuite/btcwallet/waddrmgr
|
||||
```
|
||||
|
||||
Package waddrmgr is licensed under the [copyfree](http://copyfree.org) ISC
|
||||
License.
|
||||
648
vendor/github.com/btcsuite/btcwallet/waddrmgr/address.go
generated
vendored
Normal file
648
vendor/github.com/btcsuite/btcwallet/waddrmgr/address.go
generated
vendored
Normal file
@@ -0,0 +1,648 @@
|
||||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package waddrmgr
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcutil/hdkeychain"
|
||||
"github.com/btcsuite/btcwallet/internal/zero"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
)
|
||||
|
||||
// AddressType represents the various address types waddrmgr is currently able
|
||||
// to generate, and maintain.
|
||||
//
|
||||
// NOTE: These MUST be stable as they're used for scope address schema
|
||||
// recognition within the database.
|
||||
type AddressType uint8
|
||||
|
||||
const (
|
||||
// PubKeyHash is a regular p2pkh address.
|
||||
PubKeyHash AddressType = iota
|
||||
|
||||
// Script reprints a raw script address.
|
||||
Script
|
||||
|
||||
// RawPubKey is just raw public key to be used within scripts, This
|
||||
// type indicates that a scoped manager with this address type
|
||||
// shouldn't be consulted during historical rescans.
|
||||
RawPubKey
|
||||
|
||||
// NestedWitnessPubKey represents a p2wkh output nested within a p2sh
|
||||
// output. Using this address type, the wallet can receive funds from
|
||||
// other wallet's which don't yet recognize the new segwit standard
|
||||
// output types. Receiving funds to this address maintains the
|
||||
// scalability, and malleability fixes due to segwit in a backwards
|
||||
// compatible manner.
|
||||
NestedWitnessPubKey
|
||||
|
||||
// WitnessPubKey represents a p2wkh (pay-to-witness-key-hash) address
|
||||
// type.
|
||||
WitnessPubKey
|
||||
)
|
||||
|
||||
// ManagedAddress is an interface that provides acces to information regarding
|
||||
// an address managed by an address manager. Concrete implementations of this
|
||||
// type may provide further fields to provide information specific to that type
|
||||
// of address.
|
||||
type ManagedAddress interface {
|
||||
// Account returns the account the address is associated with.
|
||||
Account() uint32
|
||||
|
||||
// Address returns a btcutil.Address for the backing address.
|
||||
Address() btcutil.Address
|
||||
|
||||
// AddrHash returns the key or script hash related to the address
|
||||
AddrHash() []byte
|
||||
|
||||
// Imported returns true if the backing address was imported instead
|
||||
// of being part of an address chain.
|
||||
Imported() bool
|
||||
|
||||
// Internal returns true if the backing address was created for internal
|
||||
// use such as a change output of a transaction.
|
||||
Internal() bool
|
||||
|
||||
// Compressed returns true if the backing address is compressed.
|
||||
Compressed() bool
|
||||
|
||||
// Used returns true if the backing address has been used in a transaction.
|
||||
Used(ns walletdb.ReadBucket) bool
|
||||
|
||||
// AddrType returns the address type of the managed address. This can
|
||||
// be used to quickly discern the address type without further
|
||||
// processing
|
||||
AddrType() AddressType
|
||||
}
|
||||
|
||||
// ManagedPubKeyAddress extends ManagedAddress and additionally provides the
|
||||
// public and private keys for pubkey-based addresses.
|
||||
type ManagedPubKeyAddress interface {
|
||||
ManagedAddress
|
||||
|
||||
// PubKey returns the public key associated with the address.
|
||||
PubKey() *btcec.PublicKey
|
||||
|
||||
// ExportPubKey returns the public key associated with the address
|
||||
// serialized as a hex encoded string.
|
||||
ExportPubKey() string
|
||||
|
||||
// PrivKey returns the private key for the address. It can fail if the
|
||||
// address manager is watching-only or locked, or the address does not
|
||||
// have any keys.
|
||||
PrivKey() (*btcec.PrivateKey, error)
|
||||
|
||||
// ExportPrivKey returns the private key associated with the address
|
||||
// serialized as Wallet Import Format (WIF).
|
||||
ExportPrivKey() (*btcutil.WIF, error)
|
||||
|
||||
// DerivationInfo contains the information required to derive the key
|
||||
// that backs the address via traditional methods from the HD root. For
|
||||
// imported keys, the first value will be set to false to indicate that
|
||||
// we don't know exactly how the key was derived.
|
||||
DerivationInfo() (KeyScope, DerivationPath, bool)
|
||||
}
|
||||
|
||||
// ManagedScriptAddress extends ManagedAddress and represents a pay-to-script-hash
|
||||
// style of bitcoin addresses. It additionally provides information about the
|
||||
// script.
|
||||
type ManagedScriptAddress interface {
|
||||
ManagedAddress
|
||||
|
||||
// Script returns the script associated with the address.
|
||||
Script() ([]byte, error)
|
||||
}
|
||||
|
||||
// managedAddress represents a public key address. It also may or may not have
|
||||
// the private key associated with the public key.
|
||||
type managedAddress struct {
|
||||
manager *ScopedKeyManager
|
||||
derivationPath DerivationPath
|
||||
address btcutil.Address
|
||||
imported bool
|
||||
internal bool
|
||||
compressed bool
|
||||
used bool
|
||||
addrType AddressType
|
||||
pubKey *btcec.PublicKey
|
||||
privKeyEncrypted []byte
|
||||
privKeyCT []byte // non-nil if unlocked
|
||||
privKeyMutex sync.Mutex
|
||||
}
|
||||
|
||||
// Enforce managedAddress satisfies the ManagedPubKeyAddress interface.
|
||||
var _ ManagedPubKeyAddress = (*managedAddress)(nil)
|
||||
|
||||
// unlock decrypts and stores a pointer to the associated private key. It will
|
||||
// fail if the key is invalid or the encrypted private key is not available.
|
||||
// The returned clear text private key will always be a copy that may be safely
|
||||
// used by the caller without worrying about it being zeroed during an address
|
||||
// lock.
|
||||
func (a *managedAddress) unlock(key EncryptorDecryptor) ([]byte, error) {
|
||||
// Protect concurrent access to clear text private key.
|
||||
a.privKeyMutex.Lock()
|
||||
defer a.privKeyMutex.Unlock()
|
||||
|
||||
if len(a.privKeyCT) == 0 {
|
||||
privKey, err := key.Decrypt(a.privKeyEncrypted)
|
||||
if err != nil {
|
||||
str := fmt.Sprintf("failed to decrypt private key for "+
|
||||
"%s", a.address)
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
}
|
||||
|
||||
a.privKeyCT = privKey
|
||||
}
|
||||
|
||||
privKeyCopy := make([]byte, len(a.privKeyCT))
|
||||
copy(privKeyCopy, a.privKeyCT)
|
||||
return privKeyCopy, nil
|
||||
}
|
||||
|
||||
// lock zeroes the associated clear text private key.
|
||||
func (a *managedAddress) lock() {
|
||||
// Zero and nil the clear text private key associated with this
|
||||
// address.
|
||||
a.privKeyMutex.Lock()
|
||||
zero.Bytes(a.privKeyCT)
|
||||
a.privKeyCT = nil
|
||||
a.privKeyMutex.Unlock()
|
||||
}
|
||||
|
||||
// Account returns the account number the address is associated with.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *managedAddress) Account() uint32 {
|
||||
return a.derivationPath.Account
|
||||
}
|
||||
|
||||
// AddrType returns the address type of the managed address. This can be used
|
||||
// to quickly discern the address type without further processing
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *managedAddress) AddrType() AddressType {
|
||||
return a.addrType
|
||||
}
|
||||
|
||||
// Address returns the btcutil.Address which represents the managed address.
|
||||
// This will be a pay-to-pubkey-hash address.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *managedAddress) Address() btcutil.Address {
|
||||
return a.address
|
||||
}
|
||||
|
||||
// AddrHash returns the public key hash for the address.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *managedAddress) AddrHash() []byte {
|
||||
var hash []byte
|
||||
|
||||
switch n := a.address.(type) {
|
||||
case *btcutil.AddressPubKeyHash:
|
||||
hash = n.Hash160()[:]
|
||||
case *btcutil.AddressScriptHash:
|
||||
hash = n.Hash160()[:]
|
||||
case *btcutil.AddressWitnessPubKeyHash:
|
||||
hash = n.Hash160()[:]
|
||||
}
|
||||
|
||||
return hash
|
||||
}
|
||||
|
||||
// Imported returns true if the address was imported instead of being part of an
|
||||
// address chain.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *managedAddress) Imported() bool {
|
||||
return a.imported
|
||||
}
|
||||
|
||||
// Internal returns true if the address was created for internal use such as a
|
||||
// change output of a transaction.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *managedAddress) Internal() bool {
|
||||
return a.internal
|
||||
}
|
||||
|
||||
// Compressed returns true if the address is compressed.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *managedAddress) Compressed() bool {
|
||||
return a.compressed
|
||||
}
|
||||
|
||||
// Used returns true if the address has been used in a transaction.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *managedAddress) Used(ns walletdb.ReadBucket) bool {
|
||||
return a.manager.fetchUsed(ns, a.AddrHash())
|
||||
}
|
||||
|
||||
// PubKey returns the public key associated with the address.
|
||||
//
|
||||
// This is part of the ManagedPubKeyAddress interface implementation.
|
||||
func (a *managedAddress) PubKey() *btcec.PublicKey {
|
||||
return a.pubKey
|
||||
}
|
||||
|
||||
// pubKeyBytes returns the serialized public key bytes for the managed address
|
||||
// based on whether or not the managed address is marked as compressed.
|
||||
func (a *managedAddress) pubKeyBytes() []byte {
|
||||
if a.compressed {
|
||||
return a.pubKey.SerializeCompressed()
|
||||
}
|
||||
return a.pubKey.SerializeUncompressed()
|
||||
}
|
||||
|
||||
// ExportPubKey returns the public key associated with the address
|
||||
// serialized as a hex encoded string.
|
||||
//
|
||||
// This is part of the ManagedPubKeyAddress interface implementation.
|
||||
func (a *managedAddress) ExportPubKey() string {
|
||||
return hex.EncodeToString(a.pubKeyBytes())
|
||||
}
|
||||
|
||||
// PrivKey returns the private key for the address. It can fail if the address
|
||||
// manager is watching-only or locked, or the address does not have any keys.
|
||||
//
|
||||
// This is part of the ManagedPubKeyAddress interface implementation.
|
||||
func (a *managedAddress) PrivKey() (*btcec.PrivateKey, error) {
|
||||
// No private keys are available for a watching-only address manager.
|
||||
if a.manager.rootManager.WatchOnly() {
|
||||
return nil, managerError(ErrWatchingOnly, errWatchingOnly, nil)
|
||||
}
|
||||
|
||||
a.manager.mtx.Lock()
|
||||
defer a.manager.mtx.Unlock()
|
||||
|
||||
// Account manager must be unlocked to decrypt the private key.
|
||||
if a.manager.rootManager.IsLocked() {
|
||||
return nil, managerError(ErrLocked, errLocked, nil)
|
||||
}
|
||||
|
||||
// Decrypt the key as needed. Also, make sure it's a copy since the
|
||||
// private key stored in memory can be cleared at any time. Otherwise
|
||||
// the returned private key could be invalidated from under the caller.
|
||||
privKeyCopy, err := a.unlock(a.manager.rootManager.cryptoKeyPriv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), privKeyCopy)
|
||||
zero.Bytes(privKeyCopy)
|
||||
return privKey, nil
|
||||
}
|
||||
|
||||
// ExportPrivKey returns the private key associated with the address in Wallet
|
||||
// Import Format (WIF).
|
||||
//
|
||||
// This is part of the ManagedPubKeyAddress interface implementation.
|
||||
func (a *managedAddress) ExportPrivKey() (*btcutil.WIF, error) {
|
||||
pk, err := a.PrivKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return btcutil.NewWIF(pk, a.manager.rootManager.chainParams, a.compressed)
|
||||
}
|
||||
|
||||
// Derivationinfo contains the information required to derive the key that
|
||||
// backs the address via traditional methods from the HD root. For imported
|
||||
// keys, the first value will be set to false to indicate that we don't know
|
||||
// exactly how the key was derived.
|
||||
//
|
||||
// This is part of the ManagedPubKeyAddress interface implementation.
|
||||
func (a *managedAddress) DerivationInfo() (KeyScope, DerivationPath, bool) {
|
||||
var (
|
||||
scope KeyScope
|
||||
path DerivationPath
|
||||
)
|
||||
|
||||
// If this key is imported, then we can't return any information as we
|
||||
// don't know precisely how the key was derived.
|
||||
if a.imported {
|
||||
return scope, path, false
|
||||
}
|
||||
|
||||
return a.manager.Scope(), a.derivationPath, true
|
||||
}
|
||||
|
||||
// newManagedAddressWithoutPrivKey returns a new managed address based on the
|
||||
// passed account, public key, and whether or not the public key should be
|
||||
// compressed.
|
||||
func newManagedAddressWithoutPrivKey(m *ScopedKeyManager,
|
||||
derivationPath DerivationPath, pubKey *btcec.PublicKey, compressed bool,
|
||||
addrType AddressType) (*managedAddress, error) {
|
||||
|
||||
// Create a pay-to-pubkey-hash address from the public key.
|
||||
var pubKeyHash []byte
|
||||
if compressed {
|
||||
pubKeyHash = btcutil.Hash160(pubKey.SerializeCompressed())
|
||||
} else {
|
||||
pubKeyHash = btcutil.Hash160(pubKey.SerializeUncompressed())
|
||||
}
|
||||
|
||||
var address btcutil.Address
|
||||
var err error
|
||||
|
||||
switch addrType {
|
||||
|
||||
case NestedWitnessPubKey:
|
||||
// For this address type we'l generate an address which is
|
||||
// backwards compatible to Bitcoin nodes running 0.6.0 onwards, but
|
||||
// allows us to take advantage of segwit's scripting improvments,
|
||||
// and malleability fixes.
|
||||
|
||||
// First, we'll generate a normal p2wkh address from the pubkey hash.
|
||||
witAddr, err := btcutil.NewAddressWitnessPubKeyHash(
|
||||
pubKeyHash, m.rootManager.chainParams,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Next we'll generate the witness program which can be used as a
|
||||
// pkScript to pay to this generated address.
|
||||
witnessProgram, err := txscript.PayToAddrScript(witAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Finally, we'll use the witness program itself as the pre-image
|
||||
// to a p2sh address. In order to spend, we first use the
|
||||
// witnessProgram as the sigScript, then present the proper
|
||||
// <sig, pubkey> pair as the witness.
|
||||
address, err = btcutil.NewAddressScriptHash(
|
||||
witnessProgram, m.rootManager.chainParams,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case PubKeyHash:
|
||||
address, err = btcutil.NewAddressPubKeyHash(
|
||||
pubKeyHash, m.rootManager.chainParams,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case WitnessPubKey:
|
||||
address, err = btcutil.NewAddressWitnessPubKeyHash(
|
||||
pubKeyHash, m.rootManager.chainParams,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &managedAddress{
|
||||
manager: m,
|
||||
address: address,
|
||||
derivationPath: derivationPath,
|
||||
imported: false,
|
||||
internal: false,
|
||||
addrType: addrType,
|
||||
compressed: compressed,
|
||||
pubKey: pubKey,
|
||||
privKeyEncrypted: nil,
|
||||
privKeyCT: nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// newManagedAddress returns a new managed address based on the passed account,
|
||||
// private key, and whether or not the public key is compressed. The managed
|
||||
// address will have access to the private and public keys.
|
||||
func newManagedAddress(s *ScopedKeyManager, derivationPath DerivationPath,
|
||||
privKey *btcec.PrivateKey, compressed bool,
|
||||
addrType AddressType) (*managedAddress, error) {
|
||||
|
||||
// Encrypt the private key.
|
||||
//
|
||||
// NOTE: The privKeyBytes here are set into the managed address which
|
||||
// are cleared when locked, so they aren't cleared here.
|
||||
privKeyBytes := privKey.Serialize()
|
||||
privKeyEncrypted, err := s.rootManager.cryptoKeyPriv.Encrypt(privKeyBytes)
|
||||
if err != nil {
|
||||
str := "failed to encrypt private key"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
}
|
||||
|
||||
// Leverage the code to create a managed address without a private key
|
||||
// and then add the private key to it.
|
||||
ecPubKey := (*btcec.PublicKey)(&privKey.PublicKey)
|
||||
managedAddr, err := newManagedAddressWithoutPrivKey(
|
||||
s, derivationPath, ecPubKey, compressed, addrType,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
managedAddr.privKeyEncrypted = privKeyEncrypted
|
||||
managedAddr.privKeyCT = privKeyBytes
|
||||
|
||||
return managedAddr, nil
|
||||
}
|
||||
|
||||
// newManagedAddressFromExtKey returns a new managed address based on the passed
|
||||
// account and extended key. The managed address will have access to the
|
||||
// private and public keys if the provided extended key is private, otherwise it
|
||||
// will only have access to the public key.
|
||||
func newManagedAddressFromExtKey(s *ScopedKeyManager,
|
||||
derivationPath DerivationPath, key *hdkeychain.ExtendedKey,
|
||||
addrType AddressType) (*managedAddress, error) {
|
||||
|
||||
// Create a new managed address based on the public or private key
|
||||
// depending on whether the generated key is private.
|
||||
var managedAddr *managedAddress
|
||||
if key.IsPrivate() {
|
||||
privKey, err := key.ECPrivKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ensure the temp private key big integer is cleared after
|
||||
// use.
|
||||
managedAddr, err = newManagedAddress(
|
||||
s, derivationPath, privKey, true, addrType,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
pubKey, err := key.ECPubKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
managedAddr, err = newManagedAddressWithoutPrivKey(
|
||||
s, derivationPath, pubKey, true,
|
||||
addrType,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return managedAddr, nil
|
||||
}
|
||||
|
||||
// scriptAddress represents a pay-to-script-hash address.
|
||||
type scriptAddress struct {
|
||||
manager *ScopedKeyManager
|
||||
account uint32
|
||||
address *btcutil.AddressScriptHash
|
||||
scriptEncrypted []byte
|
||||
scriptCT []byte
|
||||
scriptMutex sync.Mutex
|
||||
used bool
|
||||
}
|
||||
|
||||
// Enforce scriptAddress satisfies the ManagedScriptAddress interface.
|
||||
var _ ManagedScriptAddress = (*scriptAddress)(nil)
|
||||
|
||||
// unlock decrypts and stores the associated script. It will fail if the key is
|
||||
// invalid or the encrypted script is not available. The returned clear text
|
||||
// script will always be a copy that may be safely used by the caller without
|
||||
// worrying about it being zeroed during an address lock.
|
||||
func (a *scriptAddress) unlock(key EncryptorDecryptor) ([]byte, error) {
|
||||
// Protect concurrent access to clear text script.
|
||||
a.scriptMutex.Lock()
|
||||
defer a.scriptMutex.Unlock()
|
||||
|
||||
if len(a.scriptCT) == 0 {
|
||||
script, err := key.Decrypt(a.scriptEncrypted)
|
||||
if err != nil {
|
||||
str := fmt.Sprintf("failed to decrypt script for %s",
|
||||
a.address)
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
}
|
||||
|
||||
a.scriptCT = script
|
||||
}
|
||||
|
||||
scriptCopy := make([]byte, len(a.scriptCT))
|
||||
copy(scriptCopy, a.scriptCT)
|
||||
return scriptCopy, nil
|
||||
}
|
||||
|
||||
// lock zeroes the associated clear text private key.
|
||||
func (a *scriptAddress) lock() {
|
||||
// Zero and nil the clear text script associated with this address.
|
||||
a.scriptMutex.Lock()
|
||||
zero.Bytes(a.scriptCT)
|
||||
a.scriptCT = nil
|
||||
a.scriptMutex.Unlock()
|
||||
}
|
||||
|
||||
// Account returns the account the address is associated with. This will always
|
||||
// be the ImportedAddrAccount constant for script addresses.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *scriptAddress) Account() uint32 {
|
||||
return a.account
|
||||
}
|
||||
|
||||
// AddrType returns the address type of the managed address. This can be used
|
||||
// to quickly discern the address type without further processing
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *scriptAddress) AddrType() AddressType {
|
||||
return Script
|
||||
}
|
||||
|
||||
// Address returns the btcutil.Address which represents the managed address.
|
||||
// This will be a pay-to-script-hash address.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *scriptAddress) Address() btcutil.Address {
|
||||
return a.address
|
||||
}
|
||||
|
||||
// AddrHash returns the script hash for the address.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *scriptAddress) AddrHash() []byte {
|
||||
return a.address.Hash160()[:]
|
||||
}
|
||||
|
||||
// Imported always returns true since script addresses are always imported
|
||||
// addresses and not part of any chain.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *scriptAddress) Imported() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Internal always returns false since script addresses are always imported
|
||||
// addresses and not part of any chain in order to be for internal use.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *scriptAddress) Internal() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Compressed returns false since script addresses are never compressed.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *scriptAddress) Compressed() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Used returns true if the address has been used in a transaction.
|
||||
//
|
||||
// This is part of the ManagedAddress interface implementation.
|
||||
func (a *scriptAddress) Used(ns walletdb.ReadBucket) bool {
|
||||
return a.manager.fetchUsed(ns, a.AddrHash())
|
||||
}
|
||||
|
||||
// Script returns the script associated with the address.
|
||||
//
|
||||
// This implements the ScriptAddress interface.
|
||||
func (a *scriptAddress) Script() ([]byte, error) {
|
||||
// No script is available for a watching-only address manager.
|
||||
if a.manager.rootManager.WatchOnly() {
|
||||
return nil, managerError(ErrWatchingOnly, errWatchingOnly, nil)
|
||||
}
|
||||
|
||||
a.manager.mtx.Lock()
|
||||
defer a.manager.mtx.Unlock()
|
||||
|
||||
// Account manager must be unlocked to decrypt the script.
|
||||
if a.manager.rootManager.IsLocked() {
|
||||
return nil, managerError(ErrLocked, errLocked, nil)
|
||||
}
|
||||
|
||||
// Decrypt the script as needed. Also, make sure it's a copy since the
|
||||
// script stored in memory can be cleared at any time. Otherwise,
|
||||
// the returned script could be invalidated from under the caller.
|
||||
return a.unlock(a.manager.rootManager.cryptoKeyScript)
|
||||
}
|
||||
|
||||
// newScriptAddress initializes and returns a new pay-to-script-hash address.
|
||||
func newScriptAddress(m *ScopedKeyManager, account uint32, scriptHash,
|
||||
scriptEncrypted []byte) (*scriptAddress, error) {
|
||||
|
||||
address, err := btcutil.NewAddressScriptHashFromHash(
|
||||
scriptHash, m.rootManager.chainParams,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &scriptAddress{
|
||||
manager: m,
|
||||
account: account,
|
||||
address: address,
|
||||
scriptEncrypted: scriptEncrypted,
|
||||
}, nil
|
||||
}
|
||||
17
vendor/github.com/btcsuite/btcwallet/waddrmgr/cov_report.sh
generated
vendored
Normal file
17
vendor/github.com/btcsuite/btcwallet/waddrmgr/cov_report.sh
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script uses gocov to generate a test coverage report.
|
||||
# The gocov tool my be obtained with the following command:
|
||||
# go get github.com/axw/gocov/gocov
|
||||
#
|
||||
# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH.
|
||||
|
||||
# Check for gocov.
|
||||
type gocov >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo >&2 "This script requires the gocov tool."
|
||||
echo >&2 "You may obtain it with the following command:"
|
||||
echo >&2 "go get github.com/axw/gocov/gocov"
|
||||
exit 1
|
||||
fi
|
||||
gocov test | gocov report
|
||||
2280
vendor/github.com/btcsuite/btcwallet/waddrmgr/db.go
generated
vendored
Normal file
2280
vendor/github.com/btcsuite/btcwallet/waddrmgr/db.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
155
vendor/github.com/btcsuite/btcwallet/waddrmgr/doc.go
generated
vendored
Normal file
155
vendor/github.com/btcsuite/btcwallet/waddrmgr/doc.go
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package waddrmgr provides a secure hierarchical deterministic wallet address
|
||||
manager.
|
||||
|
||||
Overview
|
||||
|
||||
One of the fundamental jobs of a wallet is to manage addresses, private keys,
|
||||
and script data associated with them. At a high level, this package provides
|
||||
the facilities to perform this task with a focus on security and also allows
|
||||
recovery through the use of hierarchical deterministic keys (BIP0032) generated
|
||||
from a caller provided seed. The specific structure used is as described in
|
||||
BIP0044. This setup means as long as the user writes the seed down (even better
|
||||
is to use a mnemonic for the seed), all their addresses and private keys can be
|
||||
regenerated from the seed.
|
||||
|
||||
There are two master keys which are protected by two independent passphrases.
|
||||
One is intended for public facing data, while the other is intended for private
|
||||
data. The public password can be hardcoded for callers who don't want the
|
||||
additional public data protection or the same password can be used if a single
|
||||
password is desired. These choices provide a usability versus security
|
||||
tradeoff. However, keep in mind that extended hd keys, as called out in BIP0032
|
||||
need to be handled more carefully than normal EC public keys because they can be
|
||||
used to generate all future addresses. While this is part of what makes them
|
||||
attractive, it also means an attacker getting access to your extended public key
|
||||
for an account will allow them to know all derived addresses you will use and
|
||||
hence reduces privacy. For this reason, it is highly recommended that you do
|
||||
not hard code a password which allows any attacker who gets a copy of your
|
||||
address manager database to access your effectively plain text extended public
|
||||
keys.
|
||||
|
||||
Each master key in turn protects the three real encryption keys (called crypto
|
||||
keys) for public, private, and script data. Some examples include payment
|
||||
addresses, extended hd keys, and scripts associated with pay-to-script-hash
|
||||
addresses. This scheme makes changing passphrases more efficient since only the
|
||||
crypto keys need to be re-encrypted versus every single piece of information
|
||||
(which is what is needed for *rekeying*). This results in a fully encrypted
|
||||
database where access to it does not compromise address, key, or script privacy.
|
||||
This differs from the handling by other wallets at the time of this writing in
|
||||
that they divulge your addresses, and worse, some even expose the chain code
|
||||
which can be used by the attacker to know all future addresses that will be
|
||||
used.
|
||||
|
||||
The address manager is also hardened against memory scrapers. This is
|
||||
accomplished by typically having the address manager locked meaning no private
|
||||
keys or scripts are in memory. Unlocking the address manager causes the crypto
|
||||
private and script keys to be decrypted and loaded in memory which in turn are
|
||||
used to decrypt private keys and scripts on demand. Relocking the address
|
||||
manager actively zeros all private material from memory. In addition, temp
|
||||
private key material used internally is zeroed as soon as it's used.
|
||||
|
||||
Locking and Unlocking
|
||||
|
||||
As previously mentioned, this package provide facilities for locking and
|
||||
unlocking the address manager to protect access to private material and remove
|
||||
it from memory when locked. The Lock, Unlock, and IsLocked functions are used
|
||||
for this purpose.
|
||||
|
||||
Creating a New Address Manager
|
||||
|
||||
A new address manager is created via the Create function. This function accepts
|
||||
a wallet database namespace, passphrases, network, and perhaps most importantly,
|
||||
a cryptographically random seed which is used to generate the master node of the
|
||||
hierarchical deterministic keychain which allows all addresses and private keys
|
||||
to be recovered with only the seed. The GenerateSeed function in the hdkeychain
|
||||
package can be used as a convenient way to create a random seed for use with
|
||||
this function. The address manager is locked immediately upon being created.
|
||||
|
||||
Opening an Existing Address Manager
|
||||
|
||||
An existing address manager is opened via the Open function. This function
|
||||
accepts an existing wallet database namespace, the public passphrase, and
|
||||
network. The address manager is opened locked as expected since the open
|
||||
function does not take the private passphrase to unlock it.
|
||||
|
||||
Closing the Address Manager
|
||||
|
||||
The Close method should be called on the address manager when the caller is done
|
||||
with it. While it is not required, it is recommended because it sanely shuts
|
||||
down the database and ensures all private and public key material is purged from
|
||||
memory.
|
||||
|
||||
Managed Addresses
|
||||
|
||||
Each address returned by the address manager satisifies the ManagedAddress
|
||||
interface as well as either the ManagedPubKeyAddress or ManagedScriptAddress
|
||||
interfaces. These interfaces provide the means to obtain relevant information
|
||||
about the addresses such as their private keys and scripts.
|
||||
|
||||
Chained Addresses
|
||||
|
||||
Most callers will make use of the chained addresses for normal operations.
|
||||
Internal addresses are intended for internal wallet uses such as change outputs,
|
||||
while external addresses are intended for uses such payment addresses that are
|
||||
shared. The NextInternalAddresses and NextExternalAddresses functions provide
|
||||
the means to acquire one or more of the next addresses that have not already
|
||||
been provided. In addition, the LastInternalAddress and LastExternalAddress
|
||||
functions can be used to get the most recently provided internal and external
|
||||
address, respectively.
|
||||
|
||||
Requesting Existing Addresses
|
||||
|
||||
In addition to generating new addresses, access to old addresses is often
|
||||
required. Most notably, to sign transactions in order to redeem them. The
|
||||
Address function provides this capability and returns a ManagedAddress.
|
||||
|
||||
Importing Addresses
|
||||
|
||||
While the recommended approach is to use the chained addresses discussed above
|
||||
because they can be deterministically regenerated to avoid losing funds as long
|
||||
as the user has the master seed, there are many addresses that already exist,
|
||||
and as a result, this package provides the ability to import existing private
|
||||
keys in Wallet Import Format (WIF) and hence the associated public key and
|
||||
address.
|
||||
|
||||
Importing Scripts
|
||||
|
||||
In order to support pay-to-script-hash transactions, the script must be securely
|
||||
stored as it is needed to redeem the transaction. This can be useful for a
|
||||
variety of scenarios, however the most common use is currently multi-signature
|
||||
transactions.
|
||||
|
||||
Syncing
|
||||
|
||||
The address manager also supports storing and retrieving a block hash and height
|
||||
which the manager is known to have all addresses synced through. The manager
|
||||
itself does not have any notion of which addresses are synced or not. It only
|
||||
provides the storage as a convenience for the caller.
|
||||
|
||||
Network
|
||||
|
||||
The address manager must be associated with a given network in order to provide
|
||||
appropriate addresses and reject imported addresses and scripts which don't
|
||||
apply to the associated network.
|
||||
|
||||
Errors
|
||||
|
||||
All errors returned from this package are of type ManagerError. This allows the
|
||||
caller to programmatically ascertain the specific reasons for failure by
|
||||
examining the ErrorCode field of the type asserted ManagerError. For certain
|
||||
error codes, as documented by the specific error codes, the underlying error
|
||||
will be contained in the Err field.
|
||||
|
||||
Bitcoin Improvement Proposals
|
||||
|
||||
This package includes concepts outlined by the following BIPs:
|
||||
|
||||
BIP0032 (https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
|
||||
BIP0043 (https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki)
|
||||
BIP0044 (https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)
|
||||
*/
|
||||
package waddrmgr
|
||||
219
vendor/github.com/btcsuite/btcwallet/waddrmgr/error.go
generated
vendored
Normal file
219
vendor/github.com/btcsuite/btcwallet/waddrmgr/error.go
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package waddrmgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/btcsuite/btcutil/hdkeychain"
|
||||
)
|
||||
|
||||
var (
|
||||
// errAlreadyExists is the common error description used for the
|
||||
// ErrAlreadyExists error code.
|
||||
errAlreadyExists = "the specified address manager already exists"
|
||||
|
||||
// errCoinTypeTooHigh is the common error description used for the
|
||||
// ErrCoinTypeTooHigh error code.
|
||||
errCoinTypeTooHigh = "coin type may not exceed " +
|
||||
strconv.FormatUint(hdkeychain.HardenedKeyStart-1, 10)
|
||||
|
||||
// errAcctTooHigh is the common error description used for the
|
||||
// ErrAccountNumTooHigh error code.
|
||||
errAcctTooHigh = "account number may not exceed " +
|
||||
strconv.FormatUint(hdkeychain.HardenedKeyStart-1, 10)
|
||||
|
||||
// errLocked is the common error description used for the ErrLocked
|
||||
// error code.
|
||||
errLocked = "address manager is locked"
|
||||
|
||||
// errWatchingOnly is the common error description used for the
|
||||
// ErrWatchingOnly error code.
|
||||
errWatchingOnly = "address manager is watching-only"
|
||||
)
|
||||
|
||||
// ErrorCode identifies a kind of error.
|
||||
type ErrorCode int
|
||||
|
||||
// These constants are used to identify a specific ManagerError.
|
||||
const (
|
||||
// ErrDatabase indicates an error with the underlying database. When
|
||||
// this error code is set, the Err field of the ManagerError will be
|
||||
// set to the underlying error returned from the database.
|
||||
ErrDatabase ErrorCode = iota
|
||||
|
||||
// ErrUpgrade indicates the manager needs to be upgraded. This should
|
||||
// not happen in practice unless the version number has been increased
|
||||
// and there is not yet any code written to upgrade.
|
||||
ErrUpgrade
|
||||
|
||||
// ErrKeyChain indicates an error with the key chain typically either
|
||||
// due to the inability to create an extended key or deriving a child
|
||||
// extended key. When this error code is set, the Err field of the
|
||||
// ManagerError will be set to the underlying error.
|
||||
ErrKeyChain
|
||||
|
||||
// ErrCrypto indicates an error with the cryptography related operations
|
||||
// such as decrypting or encrypting data, parsing an EC public key,
|
||||
// or deriving a secret key from a password. When this error code is
|
||||
// set, the Err field of the ManagerError will be set to the underlying
|
||||
// error.
|
||||
ErrCrypto
|
||||
|
||||
// ErrInvalidKeyType indicates an error where an invalid crypto
|
||||
// key type has been selected.
|
||||
ErrInvalidKeyType
|
||||
|
||||
// ErrNoExist indicates that the specified database does not exist.
|
||||
ErrNoExist
|
||||
|
||||
// ErrAlreadyExists indicates that the specified database already exists.
|
||||
ErrAlreadyExists
|
||||
|
||||
// ErrCoinTypeTooHigh indicates that the coin type specified in the provided
|
||||
// network parameters is higher than the max allowed value as defined
|
||||
// by the maxCoinType constant.
|
||||
ErrCoinTypeTooHigh
|
||||
|
||||
// ErrAccountNumTooHigh indicates that the specified account number is higher
|
||||
// than the max allowed value as defined by the MaxAccountNum constant.
|
||||
ErrAccountNumTooHigh
|
||||
|
||||
// ErrLocked indicates that an operation, which requires the account
|
||||
// manager to be unlocked, was requested on a locked account manager.
|
||||
ErrLocked
|
||||
|
||||
// ErrWatchingOnly indicates that an operation, which requires the
|
||||
// account manager to have access to private data, was requested on
|
||||
// a watching-only account manager.
|
||||
ErrWatchingOnly
|
||||
|
||||
// ErrInvalidAccount indicates that the requested account is not valid.
|
||||
ErrInvalidAccount
|
||||
|
||||
// ErrAddressNotFound indicates that the requested address is not known to
|
||||
// the account manager.
|
||||
ErrAddressNotFound
|
||||
|
||||
// ErrAccountNotFound indicates that the requested account is not known to
|
||||
// the account manager.
|
||||
ErrAccountNotFound
|
||||
|
||||
// ErrDuplicateAddress indicates an address already exists.
|
||||
ErrDuplicateAddress
|
||||
|
||||
// ErrDuplicateAccount indicates an account already exists.
|
||||
ErrDuplicateAccount
|
||||
|
||||
// ErrTooManyAddresses indicates that more than the maximum allowed number of
|
||||
// addresses per account have been requested.
|
||||
ErrTooManyAddresses
|
||||
|
||||
// ErrWrongPassphrase indicates that the specified passphrase is incorrect.
|
||||
// This could be for either public or private master keys.
|
||||
ErrWrongPassphrase
|
||||
|
||||
// ErrWrongNet indicates that the private key to be imported is not for the
|
||||
// the same network the account manager is configured for.
|
||||
ErrWrongNet
|
||||
|
||||
// ErrCallBackBreak is used to break from a callback function passed
|
||||
// down to the manager.
|
||||
ErrCallBackBreak
|
||||
|
||||
// ErrEmptyPassphrase indicates that the private passphrase was refused
|
||||
// due to being empty.
|
||||
ErrEmptyPassphrase
|
||||
|
||||
// ErrScopeNotFound is returned when a target scope cannot be found
|
||||
// within the database.
|
||||
ErrScopeNotFound
|
||||
|
||||
// ErrBirthdayBlockNotSet is returned when we attempt to retrieve the
|
||||
// wallet's birthday but it has not been set yet.
|
||||
ErrBirthdayBlockNotSet
|
||||
|
||||
// ErrBlockNotFound is returned when we attempt to retrieve the hash for
|
||||
// a block that we do not know of.
|
||||
ErrBlockNotFound
|
||||
)
|
||||
|
||||
// Map of ErrorCode values back to their constant names for pretty printing.
|
||||
var errorCodeStrings = map[ErrorCode]string{
|
||||
ErrDatabase: "ErrDatabase",
|
||||
ErrUpgrade: "ErrUpgrade",
|
||||
ErrKeyChain: "ErrKeyChain",
|
||||
ErrCrypto: "ErrCrypto",
|
||||
ErrInvalidKeyType: "ErrInvalidKeyType",
|
||||
ErrNoExist: "ErrNoExist",
|
||||
ErrAlreadyExists: "ErrAlreadyExists",
|
||||
ErrCoinTypeTooHigh: "ErrCoinTypeTooHigh",
|
||||
ErrAccountNumTooHigh: "ErrAccountNumTooHigh",
|
||||
ErrLocked: "ErrLocked",
|
||||
ErrWatchingOnly: "ErrWatchingOnly",
|
||||
ErrInvalidAccount: "ErrInvalidAccount",
|
||||
ErrAddressNotFound: "ErrAddressNotFound",
|
||||
ErrAccountNotFound: "ErrAccountNotFound",
|
||||
ErrDuplicateAddress: "ErrDuplicateAddress",
|
||||
ErrDuplicateAccount: "ErrDuplicateAccount",
|
||||
ErrTooManyAddresses: "ErrTooManyAddresses",
|
||||
ErrWrongPassphrase: "ErrWrongPassphrase",
|
||||
ErrWrongNet: "ErrWrongNet",
|
||||
ErrCallBackBreak: "ErrCallBackBreak",
|
||||
ErrEmptyPassphrase: "ErrEmptyPassphrase",
|
||||
ErrScopeNotFound: "ErrScopeNotFound",
|
||||
}
|
||||
|
||||
// String returns the ErrorCode as a human-readable name.
|
||||
func (e ErrorCode) String() string {
|
||||
if s := errorCodeStrings[e]; s != "" {
|
||||
return s
|
||||
}
|
||||
return fmt.Sprintf("Unknown ErrorCode (%d)", int(e))
|
||||
}
|
||||
|
||||
// ManagerError provides a single type for errors that can happen during address
|
||||
// manager operation. It is used to indicate several types of failures
|
||||
// including errors with caller requests such as invalid accounts or requesting
|
||||
// private keys against a locked address manager, errors with the database
|
||||
// (ErrDatabase), errors with key chain derivation (ErrKeyChain), and errors
|
||||
// related to crypto (ErrCrypto).
|
||||
//
|
||||
// The caller can use type assertions to determine if an error is a ManagerError
|
||||
// and access the ErrorCode field to ascertain the specific reason for the
|
||||
// failure.
|
||||
//
|
||||
// The ErrDatabase, ErrKeyChain, and ErrCrypto error codes will also have the
|
||||
// Err field set with the underlying error.
|
||||
type ManagerError struct {
|
||||
ErrorCode ErrorCode // Describes the kind of error
|
||||
Description string // Human readable description of the issue
|
||||
Err error // Underlying error
|
||||
}
|
||||
|
||||
// Error satisfies the error interface and prints human-readable errors.
|
||||
func (e ManagerError) Error() string {
|
||||
if e.Err != nil {
|
||||
return e.Description + ": " + e.Err.Error()
|
||||
}
|
||||
return e.Description
|
||||
}
|
||||
|
||||
// managerError creates a ManagerError given a set of arguments.
|
||||
func managerError(c ErrorCode, desc string, err error) ManagerError {
|
||||
return ManagerError{ErrorCode: c, Description: desc, Err: err}
|
||||
}
|
||||
|
||||
// Break is a global err used to signal a break from the callback
|
||||
// function by returning an error with the code ErrCallBackBreak
|
||||
var Break = managerError(ErrCallBackBreak, "callback break", nil)
|
||||
|
||||
// IsError returns whether the error is a ManagerError with a matching error
|
||||
// code.
|
||||
func IsError(err error, code ErrorCode) bool {
|
||||
e, ok := err.(ManagerError)
|
||||
return ok && e.ErrorCode == code
|
||||
}
|
||||
43
vendor/github.com/btcsuite/btcwallet/waddrmgr/log.go
generated
vendored
Normal file
43
vendor/github.com/btcsuite/btcwallet/waddrmgr/log.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package waddrmgr
|
||||
|
||||
import "github.com/btcsuite/btclog"
|
||||
|
||||
// log is a logger that is initialized with no output filters. This
|
||||
// means the package will not perform any logging by default until the caller
|
||||
// requests it.
|
||||
var log btclog.Logger
|
||||
|
||||
// The default amount of logging is none.
|
||||
func init() {
|
||||
DisableLog()
|
||||
}
|
||||
|
||||
// DisableLog disables all library log output. Logging output is disabled
|
||||
// by default until either UseLogger or SetLogWriter are called.
|
||||
func DisableLog() {
|
||||
UseLogger(btclog.Disabled)
|
||||
}
|
||||
|
||||
// UseLogger uses a specified Logger to output package logging info.
|
||||
// This should be used in preference to SetLogWriter if the caller is also
|
||||
// using btclog.
|
||||
func UseLogger(logger btclog.Logger) {
|
||||
log = logger
|
||||
}
|
||||
|
||||
// LogClosure is a closure that can be printed with %v to be used to
|
||||
// generate expensive-to-create data for a detailed log level and avoid doing
|
||||
// the work if the data isn't printed.
|
||||
type logClosure func() string
|
||||
|
||||
// String invokes the log closure and returns the results string.
|
||||
func (c logClosure) String() string {
|
||||
return c()
|
||||
}
|
||||
|
||||
// newLogClosure returns a new closure over the passed function which allows
|
||||
// it to be used as a parameter in a logging function that is only invoked when
|
||||
// the logging level is such that the message will actually be logged.
|
||||
func newLogClosure(c func() string) logClosure {
|
||||
return logClosure(c)
|
||||
}
|
||||
1822
vendor/github.com/btcsuite/btcwallet/waddrmgr/manager.go
generated
vendored
Normal file
1822
vendor/github.com/btcsuite/btcwallet/waddrmgr/manager.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
412
vendor/github.com/btcsuite/btcwallet/waddrmgr/migrations.go
generated
vendored
Normal file
412
vendor/github.com/btcsuite/btcwallet/waddrmgr/migrations.go
generated
vendored
Normal file
@@ -0,0 +1,412 @@
|
||||
package waddrmgr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
"github.com/btcsuite/btcwallet/walletdb/migration"
|
||||
)
|
||||
|
||||
// versions is a list of the different database versions. The last entry should
|
||||
// reflect the latest database state. If the database happens to be at a version
|
||||
// number lower than the latest, migrations will be performed in order to catch
|
||||
// it up.
|
||||
var versions = []migration.Version{
|
||||
{
|
||||
Number: 2,
|
||||
Migration: upgradeToVersion2,
|
||||
},
|
||||
{
|
||||
Number: 5,
|
||||
Migration: upgradeToVersion5,
|
||||
},
|
||||
{
|
||||
Number: 6,
|
||||
Migration: populateBirthdayBlock,
|
||||
},
|
||||
{
|
||||
Number: 7,
|
||||
Migration: resetSyncedBlockToBirthday,
|
||||
},
|
||||
{
|
||||
Number: 8,
|
||||
Migration: storeMaxReorgDepth,
|
||||
},
|
||||
}
|
||||
|
||||
// getLatestVersion returns the version number of the latest database version.
|
||||
func getLatestVersion() uint32 {
|
||||
return versions[len(versions)-1].Number
|
||||
}
|
||||
|
||||
// MigrationManager is an implementation of the migration.Manager interface that
|
||||
// will be used to handle migrations for the address manager. It exposes the
|
||||
// necessary parameters required to successfully perform migrations.
|
||||
type MigrationManager struct {
|
||||
ns walletdb.ReadWriteBucket
|
||||
}
|
||||
|
||||
// A compile-time assertion to ensure that MigrationManager implements the
|
||||
// migration.Manager interface.
|
||||
var _ migration.Manager = (*MigrationManager)(nil)
|
||||
|
||||
// NewMigrationManager creates a new migration manager for the address manager.
|
||||
// The given bucket should reflect the top-level bucket in which all of the
|
||||
// address manager's data is contained within.
|
||||
func NewMigrationManager(ns walletdb.ReadWriteBucket) *MigrationManager {
|
||||
return &MigrationManager{ns: ns}
|
||||
}
|
||||
|
||||
// Name returns the name of the service we'll be attempting to upgrade.
|
||||
//
|
||||
// NOTE: This method is part of the migration.Manager interface.
|
||||
func (m *MigrationManager) Name() string {
|
||||
return "wallet address manager"
|
||||
}
|
||||
|
||||
// Namespace returns the top-level bucket of the service.
|
||||
//
|
||||
// NOTE: This method is part of the migration.Manager interface.
|
||||
func (m *MigrationManager) Namespace() walletdb.ReadWriteBucket {
|
||||
return m.ns
|
||||
}
|
||||
|
||||
// CurrentVersion returns the current version of the service's database.
|
||||
//
|
||||
// NOTE: This method is part of the migration.Manager interface.
|
||||
func (m *MigrationManager) CurrentVersion(ns walletdb.ReadBucket) (uint32, error) {
|
||||
if ns == nil {
|
||||
ns = m.ns
|
||||
}
|
||||
return fetchManagerVersion(ns)
|
||||
}
|
||||
|
||||
// SetVersion sets the version of the service's database.
|
||||
//
|
||||
// NOTE: This method is part of the migration.Manager interface.
|
||||
func (m *MigrationManager) SetVersion(ns walletdb.ReadWriteBucket,
|
||||
version uint32) error {
|
||||
|
||||
if ns == nil {
|
||||
ns = m.ns
|
||||
}
|
||||
return putManagerVersion(m.ns, version)
|
||||
}
|
||||
|
||||
// Versions returns all of the available database versions of the service.
|
||||
//
|
||||
// NOTE: This method is part of the migration.Manager interface.
|
||||
func (m *MigrationManager) Versions() []migration.Version {
|
||||
return versions
|
||||
}
|
||||
|
||||
// upgradeToVersion2 upgrades the database from version 1 to version 2
|
||||
// 'usedAddrBucketName' a bucket for storing addrs flagged as marked is
|
||||
// initialized and it will be updated on the next rescan.
|
||||
func upgradeToVersion2(ns walletdb.ReadWriteBucket) error {
|
||||
currentMgrVersion := uint32(2)
|
||||
|
||||
_, err := ns.CreateBucketIfNotExists(usedAddrBucketName)
|
||||
if err != nil {
|
||||
str := "failed to create used addresses bucket"
|
||||
return managerError(ErrDatabase, str, err)
|
||||
}
|
||||
|
||||
return putManagerVersion(ns, currentMgrVersion)
|
||||
}
|
||||
|
||||
// upgradeToVersion5 upgrades the database from version 4 to version 5. After
|
||||
// this update, the new ScopedKeyManager features cannot be used. This is due
|
||||
// to the fact that in version 5, we now store the encrypted master private
|
||||
// keys on disk. However, using the BIP0044 key scope, users will still be able
|
||||
// to create old p2pkh addresses.
|
||||
func upgradeToVersion5(ns walletdb.ReadWriteBucket) error {
|
||||
// First, we'll check if there are any existing segwit addresses, which
|
||||
// can't be upgraded to the new version. If so, we abort and warn the
|
||||
// user.
|
||||
err := ns.NestedReadBucket(addrBucketName).ForEach(
|
||||
func(k []byte, v []byte) error {
|
||||
row, err := deserializeAddressRow(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if row.addrType > adtScript {
|
||||
return fmt.Errorf("segwit address exists in " +
|
||||
"wallet, can't upgrade from v4 to " +
|
||||
"v5: well, we tried ¯\\_(ツ)_/¯")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Next, we'll write out the new database version.
|
||||
if err := putManagerVersion(ns, 5); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// First, we'll need to create the new buckets that are used in the new
|
||||
// database version.
|
||||
scopeBucket, err := ns.CreateBucket(scopeBucketName)
|
||||
if err != nil {
|
||||
str := "failed to create scope bucket"
|
||||
return managerError(ErrDatabase, str, err)
|
||||
}
|
||||
scopeSchemas, err := ns.CreateBucket(scopeSchemaBucketName)
|
||||
if err != nil {
|
||||
str := "failed to create scope schema bucket"
|
||||
return managerError(ErrDatabase, str, err)
|
||||
}
|
||||
|
||||
// With the buckets created, we can now create the default BIP0044
|
||||
// scope which will be the only scope usable in the database after this
|
||||
// update.
|
||||
scopeKey := scopeToBytes(&KeyScopeBIP0044)
|
||||
scopeSchema := ScopeAddrMap[KeyScopeBIP0044]
|
||||
schemaBytes := scopeSchemaToBytes(&scopeSchema)
|
||||
if err := scopeSchemas.Put(scopeKey[:], schemaBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := createScopedManagerNS(scopeBucket, &KeyScopeBIP0044); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bip44Bucket := scopeBucket.NestedReadWriteBucket(scopeKey[:])
|
||||
|
||||
// With the buckets created, we now need to port over *each* item in
|
||||
// the prior main bucket, into the new default scope.
|
||||
mainBucket := ns.NestedReadWriteBucket(mainBucketName)
|
||||
|
||||
// First, we'll move over the encrypted coin type private and public
|
||||
// keys to the new sub-bucket.
|
||||
encCoinPrivKeys := mainBucket.Get(coinTypePrivKeyName)
|
||||
encCoinPubKeys := mainBucket.Get(coinTypePubKeyName)
|
||||
|
||||
err = bip44Bucket.Put(coinTypePrivKeyName, encCoinPrivKeys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = bip44Bucket.Put(coinTypePubKeyName, encCoinPubKeys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := mainBucket.Delete(coinTypePrivKeyName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mainBucket.Delete(coinTypePubKeyName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Next, we'll move over everything that was in the meta bucket to the
|
||||
// meta bucket within the new scope.
|
||||
metaBucket := ns.NestedReadWriteBucket(metaBucketName)
|
||||
lastAccount := metaBucket.Get(lastAccountName)
|
||||
if err := metaBucket.Delete(lastAccountName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scopedMetaBucket := bip44Bucket.NestedReadWriteBucket(metaBucketName)
|
||||
err = scopedMetaBucket.Put(lastAccountName, lastAccount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Finally, we'll recursively move over a set of keys which were
|
||||
// formerly under the main bucket, into the new scoped buckets. We'll
|
||||
// do so by obtaining a slice of all the keys that we need to modify
|
||||
// and then recursing through each of them, moving both nested buckets
|
||||
// and key/value pairs.
|
||||
keysToMigrate := [][]byte{
|
||||
acctBucketName, addrBucketName, usedAddrBucketName,
|
||||
addrAcctIdxBucketName, acctNameIdxBucketName, acctIDIdxBucketName,
|
||||
}
|
||||
|
||||
// Migrate each bucket recursively.
|
||||
for _, bucketKey := range keysToMigrate {
|
||||
err := migrateRecursively(ns, bip44Bucket, bucketKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// migrateRecursively moves a nested bucket from one bucket to another,
|
||||
// recursing into nested buckets as required.
|
||||
func migrateRecursively(src, dst walletdb.ReadWriteBucket,
|
||||
bucketKey []byte) error {
|
||||
// Within this bucket key, we'll migrate over, then delete each key.
|
||||
bucketToMigrate := src.NestedReadWriteBucket(bucketKey)
|
||||
newBucket, err := dst.CreateBucketIfNotExists(bucketKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = bucketToMigrate.ForEach(func(k, v []byte) error {
|
||||
if nestedBucket := bucketToMigrate.
|
||||
NestedReadBucket(k); nestedBucket != nil {
|
||||
// We have a nested bucket, so recurse into it.
|
||||
return migrateRecursively(bucketToMigrate, newBucket, k)
|
||||
}
|
||||
|
||||
if err := newBucket.Put(k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bucketToMigrate.Delete(k)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Finally, we'll delete the bucket itself.
|
||||
if err := src.DeleteNestedBucket(bucketKey); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// populateBirthdayBlock is a migration that attempts to populate the birthday
|
||||
// block of the wallet. This is needed so that in the event that we need to
|
||||
// perform a rescan of the wallet, we can do so starting from this block, rather
|
||||
// than from the genesis block.
|
||||
//
|
||||
// NOTE: This migration cannot guarantee the correctness of the birthday block
|
||||
// being set as we do not store block timestamps, so a sanity check must be done
|
||||
// upon starting the wallet to ensure we do not potentially miss any relevant
|
||||
// events when rescanning.
|
||||
func populateBirthdayBlock(ns walletdb.ReadWriteBucket) error {
|
||||
// We'll need to jump through some hoops in order to determine the
|
||||
// corresponding block height for our birthday timestamp. Since we do
|
||||
// not store block timestamps, we'll need to estimate our height by
|
||||
// looking at the genesis timestamp and assuming a block occurs every 10
|
||||
// minutes. This can be unsafe, and cause us to actually miss on-chain
|
||||
// events, so a sanity check is done before the wallet attempts to sync
|
||||
// itself.
|
||||
//
|
||||
// We'll start by fetching our birthday timestamp.
|
||||
birthdayTimestamp, err := fetchBirthday(ns)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to fetch birthday timestamp: %v", err)
|
||||
}
|
||||
|
||||
log.Infof("Setting the wallet's birthday block from timestamp=%v",
|
||||
birthdayTimestamp)
|
||||
|
||||
// Now, we'll need to determine the timestamp of the genesis block for
|
||||
// the corresponding chain.
|
||||
genesisHash, err := fetchBlockHash(ns, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to fetch genesis block hash: %v", err)
|
||||
}
|
||||
|
||||
var genesisTimestamp time.Time
|
||||
switch *genesisHash {
|
||||
case *chaincfg.MainNetParams.GenesisHash:
|
||||
genesisTimestamp =
|
||||
chaincfg.MainNetParams.GenesisBlock.Header.Timestamp
|
||||
|
||||
case *chaincfg.TestNet3Params.GenesisHash:
|
||||
genesisTimestamp =
|
||||
chaincfg.TestNet3Params.GenesisBlock.Header.Timestamp
|
||||
|
||||
case *chaincfg.RegressionNetParams.GenesisHash:
|
||||
genesisTimestamp =
|
||||
chaincfg.RegressionNetParams.GenesisBlock.Header.Timestamp
|
||||
|
||||
case *chaincfg.SimNetParams.GenesisHash:
|
||||
genesisTimestamp =
|
||||
chaincfg.SimNetParams.GenesisBlock.Header.Timestamp
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown genesis hash %v", genesisHash)
|
||||
}
|
||||
|
||||
// With the timestamps retrieved, we can estimate a block height by
|
||||
// taking the difference between them and dividing by the average block
|
||||
// time (10 minutes).
|
||||
birthdayHeight := int32((birthdayTimestamp.Sub(genesisTimestamp).Seconds() / 600))
|
||||
|
||||
// Now that we have the height estimate, we can fetch the corresponding
|
||||
// block and set it as our birthday block.
|
||||
birthdayHash, err := fetchBlockHash(ns, birthdayHeight)
|
||||
|
||||
// To ensure we record a height that is known to us from the chain,
|
||||
// we'll make sure this height estimate can be found. Otherwise, we'll
|
||||
// continue subtracting a day worth of blocks until we can find one.
|
||||
for IsError(err, ErrBlockNotFound) {
|
||||
birthdayHeight -= 144
|
||||
if birthdayHeight < 0 {
|
||||
birthdayHeight = 0
|
||||
}
|
||||
birthdayHash, err = fetchBlockHash(ns, birthdayHeight)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("Estimated birthday block from timestamp=%v: height=%d, "+
|
||||
"hash=%v", birthdayTimestamp, birthdayHeight, birthdayHash)
|
||||
|
||||
// NOTE: The timestamp of the birthday block isn't set since we do not
|
||||
// store each block's timestamp.
|
||||
return PutBirthdayBlock(ns, BlockStamp{
|
||||
Height: birthdayHeight,
|
||||
Hash: *birthdayHash,
|
||||
})
|
||||
}
|
||||
|
||||
// resetSyncedBlockToBirthday is a migration that resets the wallet's currently
|
||||
// synced block to its birthday block. This essentially serves as a migration to
|
||||
// force a rescan of the wallet.
|
||||
func resetSyncedBlockToBirthday(ns walletdb.ReadWriteBucket) error {
|
||||
syncBucket := ns.NestedReadWriteBucket(syncBucketName)
|
||||
if syncBucket == nil {
|
||||
return errors.New("sync bucket does not exist")
|
||||
}
|
||||
|
||||
birthdayBlock, err := FetchBirthdayBlock(ns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return PutSyncedTo(ns, &birthdayBlock)
|
||||
}
|
||||
|
||||
// storeMaxReorgDepth is a migration responsible for allowing the wallet to only
|
||||
// maintain MaxReorgDepth block hashes stored in order to recover from long
|
||||
// reorgs.
|
||||
func storeMaxReorgDepth(ns walletdb.ReadWriteBucket) error {
|
||||
// Retrieve the current tip of the wallet. We'll use this to determine
|
||||
// the highest stale height we currently have stored within it.
|
||||
syncedTo, err := fetchSyncedTo(ns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
maxStaleHeight := staleHeight(syncedTo.Height)
|
||||
|
||||
// It's possible for this height to be non-sensical if we have less than
|
||||
// MaxReorgDepth blocks stored, so we can end the migration now.
|
||||
if maxStaleHeight < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infof("Removing block hash entries beyond maximum reorg depth of "+
|
||||
"%v from current tip %v", MaxReorgDepth, syncedTo.Height)
|
||||
|
||||
// Otherwise, since we currently store all block hashes of the chain
|
||||
// before this migration, we'll remove all stale block hash entries
|
||||
// above the genesis block. This would leave us with only MaxReorgDepth
|
||||
// blocks stored.
|
||||
for height := maxStaleHeight; height > 0; height-- {
|
||||
if err := deleteBlockHash(ns, height); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
1762
vendor/github.com/btcsuite/btcwallet/waddrmgr/scoped_manager.go
generated
vendored
Normal file
1762
vendor/github.com/btcsuite/btcwallet/waddrmgr/scoped_manager.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
135
vendor/github.com/btcsuite/btcwallet/waddrmgr/sync.go
generated
vendored
Normal file
135
vendor/github.com/btcsuite/btcwallet/waddrmgr/sync.go
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package waddrmgr
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
)
|
||||
|
||||
// BlockStamp defines a block (by height and a unique hash) and is used to mark
|
||||
// a point in the blockchain that an address manager element is
|
||||
// synced to.
|
||||
type BlockStamp struct {
|
||||
Height int32
|
||||
Hash chainhash.Hash
|
||||
Timestamp time.Time
|
||||
}
|
||||
|
||||
// syncState houses the sync state of the manager. It consists of the recently
|
||||
// seen blocks as height, as well as the start and current sync block stamps.
|
||||
type syncState struct {
|
||||
// startBlock is the first block that can be safely used to start a
|
||||
// rescan. It is either the block the manager was created with, or the
|
||||
// earliest block provided with imported addresses or scripts.
|
||||
startBlock BlockStamp
|
||||
|
||||
// syncedTo is the current block the addresses in the manager are known
|
||||
// to be synced against.
|
||||
syncedTo BlockStamp
|
||||
}
|
||||
|
||||
// newSyncState returns a new sync state with the provided parameters.
|
||||
func newSyncState(startBlock, syncedTo *BlockStamp) *syncState {
|
||||
|
||||
return &syncState{
|
||||
startBlock: *startBlock,
|
||||
syncedTo: *syncedTo,
|
||||
}
|
||||
}
|
||||
|
||||
// SetSyncedTo marks the address manager to be in sync with the recently-seen
|
||||
// block described by the blockstamp. When the provided blockstamp is nil, the
|
||||
// oldest blockstamp of the block the manager was created at and of all
|
||||
// imported addresses will be used. This effectively allows the manager to be
|
||||
// marked as unsynced back to the oldest known point any of the addresses have
|
||||
// appeared in the block chain.
|
||||
func (m *Manager) SetSyncedTo(ns walletdb.ReadWriteBucket, bs *BlockStamp) error {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
|
||||
// Use the stored start blockstamp and reset recent hashes and height
|
||||
// when the provided blockstamp is nil.
|
||||
if bs == nil {
|
||||
bs = &m.syncState.startBlock
|
||||
}
|
||||
|
||||
// Update the database.
|
||||
err := PutSyncedTo(ns, bs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update memory now that the database is updated.
|
||||
m.syncState.syncedTo = *bs
|
||||
return nil
|
||||
}
|
||||
|
||||
// SyncedTo returns details about the block height and hash that the address
|
||||
// manager is synced through at the very least. The intention is that callers
|
||||
// can use this information for intelligently initiating rescans to sync back to
|
||||
// the best chain from the last known good block.
|
||||
func (m *Manager) SyncedTo() BlockStamp {
|
||||
m.mtx.RLock()
|
||||
defer m.mtx.RUnlock()
|
||||
|
||||
return m.syncState.syncedTo
|
||||
}
|
||||
|
||||
// BlockHash returns the block hash at a particular block height. This
|
||||
// information is useful for comparing against the chain back-end to see if a
|
||||
// reorg is taking place and how far back it goes.
|
||||
func (m *Manager) BlockHash(ns walletdb.ReadBucket, height int32) (
|
||||
*chainhash.Hash, error) {
|
||||
|
||||
return fetchBlockHash(ns, height)
|
||||
}
|
||||
|
||||
// Birthday returns the birthday, or earliest time a key could have been used,
|
||||
// for the manager.
|
||||
func (m *Manager) Birthday() time.Time {
|
||||
m.mtx.RLock()
|
||||
defer m.mtx.RUnlock()
|
||||
|
||||
return m.birthday
|
||||
}
|
||||
|
||||
// SetBirthday sets the birthday, or earliest time a key could have been used,
|
||||
// for the manager.
|
||||
func (m *Manager) SetBirthday(ns walletdb.ReadWriteBucket,
|
||||
birthday time.Time) error {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
|
||||
m.birthday = birthday
|
||||
return putBirthday(ns, birthday)
|
||||
}
|
||||
|
||||
// BirthdayBlock returns the birthday block, or earliest block a key could have
|
||||
// been used, for the manager. A boolean is also returned to indicate whether
|
||||
// the birthday block has been verified as correct.
|
||||
func (m *Manager) BirthdayBlock(ns walletdb.ReadBucket) (BlockStamp, bool, error) {
|
||||
birthdayBlock, err := FetchBirthdayBlock(ns)
|
||||
if err != nil {
|
||||
return BlockStamp{}, false, err
|
||||
}
|
||||
|
||||
return birthdayBlock, fetchBirthdayBlockVerification(ns), nil
|
||||
}
|
||||
|
||||
// SetBirthdayBlock sets the birthday block, or earliest time a key could have
|
||||
// been used, for the manager. The verified boolean can be used to specify
|
||||
// whether this birthday block should be sanity checked to determine if there
|
||||
// exists a better candidate to prevent less block fetching.
|
||||
func (m *Manager) SetBirthdayBlock(ns walletdb.ReadWriteBucket,
|
||||
block BlockStamp, verified bool) error {
|
||||
|
||||
if err := PutBirthdayBlock(ns, block); err != nil {
|
||||
return err
|
||||
}
|
||||
return putBirthdayBlockVerification(ns, verified)
|
||||
}
|
||||
126
vendor/github.com/btcsuite/btcwallet/waddrmgr/test_coverage.txt
generated
vendored
Normal file
126
vendor/github.com/btcsuite/btcwallet/waddrmgr/test_coverage.txt
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go serializeBIP0044AccountRow 100.00% (19/19)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.lock 100.00% (12/12)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go serializeScriptAddress 100.00% (10/10)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go serializeImportedAddress 100.00% (10/10)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go serializeAddressRow 100.00% (9/9)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.Address 100.00% (8/8)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.Lock 100.00% (8/8)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go scriptAddress.Script 100.00% (7/7)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go serializeAccountRow 100.00% (6/6)
|
||||
github.com/conformal/btcwallet/waddrmgr/sync.go BlockIterator.Prev 100.00% (6/6)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go zeroBigInt 100.00% (5/5)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.zeroSensitivePublicData 100.00% (5/5)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.lock 100.00% (4/4)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go scriptAddress.lock 100.00% (4/4)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go serializeChainedAddress 100.00% (4/4)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.ExportPrivKey 100.00% (4/4)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go fileExists 100.00% (4/4)
|
||||
github.com/conformal/btcwallet/waddrmgr/error.go ManagerError.Error 100.00% (3/3)
|
||||
github.com/conformal/btcwallet/waddrmgr/error.go ErrorCode.String 100.00% (3/3)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.pubKeyBytes 100.00% (3/3)
|
||||
github.com/conformal/btcwallet/waddrmgr/sync.go Manager.NewIterateRecentBlocks 100.00% (3/3)
|
||||
github.com/conformal/btcwallet/waddrmgr/sync.go BlockIterator.BlockStamp 100.00% (3/3)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go accountKey 100.00% (3/3)
|
||||
github.com/conformal/btcwallet/waddrmgr/sync.go Manager.SyncedTo 100.00% (3/3)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.PutAccountInfo 100.00% (3/3)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.IsLocked 100.00% (3/3)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.PutImportedAddress 100.00% (3/3)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.ExistsAddress 100.00% (3/3)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go zero 100.00% (2/2)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go scriptAddress.Account 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go scriptAddress.Compressed 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/sync.go newSyncState 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go scriptAddress.Internal 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go cryptoKey.CopyBytes 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go newManager 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.AddrHash 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go defaultNewSecretKey 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go scriptAddress.Imported 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go scriptAddress.AddrHash 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go scriptAddress.Address 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.Account 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.Internal 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.Net 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.ExportPubKey 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/error.go managerError 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.PubKey 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go cryptoKey.Bytes 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.Compressed 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.Address 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.Imported 100.00% (1/1)
|
||||
github.com/conformal/btcwallet/waddrmgr/sync.go Manager.SetSyncedTo 93.94% (31/33)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.PrivKey 91.67% (11/12)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go deserializeBIP0044AccountRow 90.48% (19/21)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.keyToManaged 90.00% (9/10)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.FetchCryptoKeys 88.89% (16/18)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.Close 88.89% (8/9)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go newManagedAddressWithoutPrivKey 87.50% (7/8)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.PutRecentBlocks 85.71% (12/14)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Open 85.71% (6/7)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go deserializeScriptAddress 84.62% (11/13)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go deserializeImportedAddress 84.62% (11/13)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.FetchRecentBlocks 84.62% (11/13)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.FetchMasterKeyParams 84.62% (11/13)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go deserializeAddressRow 83.33% (10/12)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.loadAndCacheAddress 83.33% (10/12)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go managedAddress.unlock 81.82% (9/11)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go scriptAddress.unlock 81.82% (9/11)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.nextAddresses 80.00% (52/65)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.PutScriptAddress 80.00% (4/5)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.ChangePassphrase 79.10% (53/67)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.PutChainedAddress 78.26% (18/23)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.FetchSyncedTo 77.78% (7/9)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.PutStartBlock 77.78% (7/9)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.FetchStartBlock 77.78% (7/9)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.PutSyncedTo 77.78% (7/9)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.existsAddress 77.78% (7/9)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go deserializeAccountRow 77.78% (7/9)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.ExportWatchingOnly 75.00% (12/16)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go newManagedAddressFromExtKey 75.00% (12/16)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go newManagedAddress 75.00% (9/12)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.PutWatchingOnly 75.00% (6/8)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.PutNumAccounts 75.00% (6/8)
|
||||
github.com/conformal/btcwallet/waddrmgr/address.go newScriptAddress 75.00% (3/4)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go defaultNewCryptoKey 75.00% (3/4)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.chainAddressRowToManaged 75.00% (3/4)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go checkBranchKeys 75.00% (3/4)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.deriveKeyFromPath 75.00% (3/4)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go loadManager 72.55% (37/51)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.putAddress 71.43% (5/7)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go deserializeChainedAddress 71.43% (5/7)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.deriveKey 69.23% (9/13)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.ImportScript 67.44% (29/43)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.Unlock 67.35% (33/49)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.FetchAddress 66.67% (10/15)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.importedAddressRowToManaged 66.67% (10/15)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.PutMasterKeyParams 66.67% (8/12)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.LastInternalAddress 66.67% (6/9)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.LastExternalAddress 66.67% (6/9)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.putAccountRow 66.67% (4/6)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.rowInterfaceToManaged 66.67% (4/6)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.NextExternalAddresses 66.67% (4/6)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.NextInternalAddresses 66.67% (4/6)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.FetchWatchingOnly 66.67% (4/6)
|
||||
github.com/conformal/btcwallet/waddrmgr/sync.go syncState.iter 66.67% (2/3)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.DeletePrivateKeys 66.04% (35/53)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go openOrCreateDB 66.04% (35/53)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.ImportPrivateKey 64.71% (33/51)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.PutCryptoKeys 64.71% (11/17)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.loadAccountInfo 62.96% (34/54)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.FetchAccountInfo 61.54% (8/13)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.scriptAddressRowToManaged 60.00% (3/5)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Create 58.59% (58/99)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go deriveAccountKey 53.85% (7/13)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerDB.Update 50.00% (4/8)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerDB.View 50.00% (4/8)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerDB.Close 50.00% (2/4)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerDB.CopyDB 45.45% (5/11)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.FetchAllAddresses 0.00% (0/20)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.AllActiveAddresses 0.00% (0/16)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerDB.WriteTo 0.00% (0/11)
|
||||
github.com/conformal/btcwallet/waddrmgr/sync.go BlockIterator.Next 0.00% (0/6)
|
||||
github.com/conformal/btcwallet/waddrmgr/db.go managerTx.FetchNumAccounts 0.00% (0/6)
|
||||
github.com/conformal/btcwallet/waddrmgr/manager.go Manager.Export 0.00% (0/3)
|
||||
github.com/conformal/btcwallet/waddrmgr ----------------------------------- 72.59% (1030/1419)
|
||||
|
||||
Reference in New Issue
Block a user