mirror of
https://github.com/LBRYFoundation/lbcwallet.git
synced 2025-08-23 17:47:29 +00:00
Mark used addresses as such
This commit is contained in:
parent
338c711574
commit
85fe722e99
6 changed files with 180 additions and 27 deletions
|
@ -170,6 +170,9 @@ func (w *Wallet) addRedeemingTx(tx *btcutil.Tx, block *txstore.Block) error {
|
||||||
if _, err := txr.AddDebits(); err != nil {
|
if _, err := txr.AddDebits(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := w.markAddrsUsed(txr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
bs, err := w.chainSvr.BlockStamp()
|
bs, err := w.chainSvr.BlockStamp()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -51,6 +51,9 @@ type ManagedAddress interface {
|
||||||
|
|
||||||
// Compressed returns true if the backing address is compressed.
|
// Compressed returns true if the backing address is compressed.
|
||||||
Compressed() bool
|
Compressed() bool
|
||||||
|
|
||||||
|
// Used returns true if the backing address has been used in a transaction.
|
||||||
|
Used() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ManagedPubKeyAddress extends ManagedAddress and additionally provides the
|
// ManagedPubKeyAddress extends ManagedAddress and additionally provides the
|
||||||
|
@ -94,6 +97,7 @@ type managedAddress struct {
|
||||||
imported bool
|
imported bool
|
||||||
internal bool
|
internal bool
|
||||||
compressed bool
|
compressed bool
|
||||||
|
used bool
|
||||||
pubKey *btcec.PublicKey
|
pubKey *btcec.PublicKey
|
||||||
privKeyEncrypted []byte
|
privKeyEncrypted []byte
|
||||||
privKeyCT []byte // non-nil if unlocked
|
privKeyCT []byte // non-nil if unlocked
|
||||||
|
@ -184,6 +188,13 @@ func (a *managedAddress) Compressed() bool {
|
||||||
return a.compressed
|
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() bool {
|
||||||
|
return a.used
|
||||||
|
}
|
||||||
|
|
||||||
// PubKey returns the public key associated with the address.
|
// PubKey returns the public key associated with the address.
|
||||||
//
|
//
|
||||||
// This is part of the ManagedPubKeyAddress interface implementation.
|
// This is part of the ManagedPubKeyAddress interface implementation.
|
||||||
|
@ -354,6 +365,7 @@ type scriptAddress struct {
|
||||||
scriptEncrypted []byte
|
scriptEncrypted []byte
|
||||||
scriptCT []byte
|
scriptCT []byte
|
||||||
scriptMutex sync.Mutex
|
scriptMutex sync.Mutex
|
||||||
|
used bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enforce scriptAddress satisfies the ManagedScriptAddress interface.
|
// Enforce scriptAddress satisfies the ManagedScriptAddress interface.
|
||||||
|
@ -441,6 +453,13 @@ func (a *scriptAddress) Compressed() bool {
|
||||||
return false
|
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() bool {
|
||||||
|
return a.used
|
||||||
|
}
|
||||||
|
|
||||||
// Script returns the script associated with the address.
|
// Script returns the script associated with the address.
|
||||||
//
|
//
|
||||||
// This implements the ScriptAddress interface.
|
// This implements the ScriptAddress interface.
|
||||||
|
@ -465,7 +484,7 @@ func (a *scriptAddress) Script() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// newScriptAddress initializes and returns a new pay-to-script-hash address.
|
// newScriptAddress initializes and returns a new pay-to-script-hash address.
|
||||||
func newScriptAddress(m *Manager, account uint32, scriptHash, scriptEncrypted []byte) (*scriptAddress, error) {
|
func newScriptAddress(m *Manager, account uint32, scriptHash, scriptEncrypted []byte, used bool) (*scriptAddress, error) {
|
||||||
address, err := btcutil.NewAddressScriptHashFromHash(scriptHash,
|
address, err := btcutil.NewAddressScriptHashFromHash(scriptHash,
|
||||||
m.chainParams)
|
m.chainParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -477,5 +496,6 @@ func newScriptAddress(m *Manager, account uint32, scriptHash, scriptEncrypted []
|
||||||
account: account,
|
account: account,
|
||||||
address: address,
|
address: address,
|
||||||
scriptEncrypted: scriptEncrypted,
|
scriptEncrypted: scriptEncrypted,
|
||||||
|
used: used,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// LatestMgrVersion is the most recent manager version.
|
// LatestMgrVersion is the most recent manager version.
|
||||||
LatestMgrVersion = 1
|
LatestMgrVersion = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -107,6 +107,7 @@ type dbAddressRow struct {
|
||||||
account uint32
|
account uint32
|
||||||
addTime uint64
|
addTime uint64
|
||||||
syncStatus syncStatus
|
syncStatus syncStatus
|
||||||
|
used bool
|
||||||
rawData []byte // Varies based on address type field.
|
rawData []byte // Varies based on address type field.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +163,9 @@ var (
|
||||||
|
|
||||||
// Account related key names (account bucket).
|
// Account related key names (account bucket).
|
||||||
acctNumAcctsName = []byte("numaccts")
|
acctNumAcctsName = []byte("numaccts")
|
||||||
|
|
||||||
|
// Used addresses (used bucket)
|
||||||
|
usedAddrBucketName = []byte("usedaddrs")
|
||||||
)
|
)
|
||||||
|
|
||||||
// uint32ToBytes converts a 32 bit unsigned integer into a 4-byte slice in
|
// uint32ToBytes converts a 32 bit unsigned integer into a 4-byte slice in
|
||||||
|
@ -732,6 +736,17 @@ func serializeScriptAddress(encryptedHash, encryptedScript []byte) []byte {
|
||||||
return rawData
|
return rawData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fetchAddressUsed returns true if the provided address hash was flagged as used.
|
||||||
|
func fetchAddressUsed(tx walletdb.Tx, addrHash [32]byte) bool {
|
||||||
|
bucket := tx.RootBucket().Bucket(usedAddrBucketName)
|
||||||
|
|
||||||
|
val := bucket.Get(addrHash[:])
|
||||||
|
if val != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// fetchAddress loads address information for the provided address id from
|
// fetchAddress loads address information for the provided address id from
|
||||||
// the database. The returned value is one of the address rows for the specific
|
// the database. The returned value is one of the address rows for the specific
|
||||||
// address type. The caller should use type assertions to ascertain the type.
|
// address type. The caller should use type assertions to ascertain the type.
|
||||||
|
@ -749,6 +764,7 @@ func fetchAddress(tx walletdb.Tx, addressID []byte) (interface{}, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
row.used = fetchAddressUsed(tx, addrHash)
|
||||||
|
|
||||||
switch row.addrType {
|
switch row.addrType {
|
||||||
case adtChain:
|
case adtChain:
|
||||||
|
@ -763,6 +779,23 @@ func fetchAddress(tx walletdb.Tx, addressID []byte) (interface{}, error) {
|
||||||
return nil, managerError(ErrDatabase, str, nil)
|
return nil, managerError(ErrDatabase, str, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// markAddressUsed flags the provided address id as used in the database.
|
||||||
|
func markAddressUsed(tx walletdb.Tx, addressID []byte) error {
|
||||||
|
bucket := tx.RootBucket().Bucket(usedAddrBucketName)
|
||||||
|
|
||||||
|
addrHash := fastsha256.Sum256(addressID)
|
||||||
|
val := bucket.Get(addrHash[:])
|
||||||
|
if val != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := bucket.Put(addrHash[:], []byte{0})
|
||||||
|
if err != nil {
|
||||||
|
str := fmt.Sprintf("failed to mark address used %x", addressID)
|
||||||
|
return managerError(ErrDatabase, str, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// putAddress stores the provided address information to the database. This
|
// putAddress stores the provided address information to the database. This
|
||||||
// is used a common base for storing the various address types.
|
// is used a common base for storing the various address types.
|
||||||
func putAddress(tx walletdb.Tx, addressID []byte, row *dbAddressRow) error {
|
func putAddress(tx walletdb.Tx, addressID []byte, row *dbAddressRow) error {
|
||||||
|
@ -1243,6 +1276,13 @@ func createManagerNS(namespace walletdb.Namespace) error {
|
||||||
return managerError(ErrDatabase, str, err)
|
return managerError(ErrDatabase, str, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// usedAddrBucketName bucket was added after manager version 1 release
|
||||||
|
_, err = rootBucket.CreateBucket(usedAddrBucketName)
|
||||||
|
if err != nil {
|
||||||
|
str := "failed to create used addresses bucket"
|
||||||
|
return managerError(ErrDatabase, str, err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := putManagerVersion(tx, latestMgrVersion); err != nil {
|
if err := putManagerVersion(tx, latestMgrVersion); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1266,6 +1306,32 @@ func createManagerNS(namespace walletdb.Namespace) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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(namespace walletdb.Namespace) error {
|
||||||
|
err := namespace.Update(func(tx walletdb.Tx) error {
|
||||||
|
currentMgrVersion := uint32(2)
|
||||||
|
rootBucket := tx.RootBucket()
|
||||||
|
|
||||||
|
_, err := rootBucket.CreateBucket(usedAddrBucketName)
|
||||||
|
if err != nil {
|
||||||
|
str := "failed to create used addresses bucket"
|
||||||
|
return managerError(ErrDatabase, str, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := putManagerVersion(tx, currentMgrVersion); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return maybeConvertDbError(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// upgradeManager upgrades the data in the provided manager namespace to newer
|
// upgradeManager upgrades the data in the provided manager namespace to newer
|
||||||
// versions as neeeded.
|
// versions as neeeded.
|
||||||
func upgradeManager(namespace walletdb.Namespace) error {
|
func upgradeManager(namespace walletdb.Namespace) error {
|
||||||
|
@ -1312,6 +1378,16 @@ func upgradeManager(namespace walletdb.Namespace) error {
|
||||||
// version = 3
|
// version = 3
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
if version < 2 {
|
||||||
|
// Upgrade from version 1 to 2.
|
||||||
|
if err := upgradeToVersion2(namespace); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The manager is now at version 2.
|
||||||
|
version = 2
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the manager is upraded to the latest version. This check is
|
// Ensure the manager is upraded to the latest version. This check is
|
||||||
// to intentionally cause a failure if the manager version is updated
|
// to intentionally cause a failure if the manager version is updated
|
||||||
// without writing code to handle the upgrade.
|
// without writing code to handle the upgrade.
|
||||||
|
|
|
@ -349,7 +349,7 @@ func (m *Manager) Close() error {
|
||||||
// The passed derivedKey is zeroed after the new address is created.
|
// The passed derivedKey is zeroed after the new address is created.
|
||||||
//
|
//
|
||||||
// This function MUST be called with the manager lock held for writes.
|
// This function MUST be called with the manager lock held for writes.
|
||||||
func (m *Manager) keyToManaged(derivedKey *hdkeychain.ExtendedKey, account, branch, index uint32) (ManagedAddress, error) {
|
func (m *Manager) keyToManaged(derivedKey *hdkeychain.ExtendedKey, account, branch, index uint32, used bool) (ManagedAddress, error) {
|
||||||
// Create a new managed address based on the public or private key
|
// Create a new managed address based on the public or private key
|
||||||
// depending on whether the passed key is private. Also, zero the
|
// depending on whether the passed key is private. Also, zero the
|
||||||
// key after creating the managed address from it.
|
// key after creating the managed address from it.
|
||||||
|
@ -372,6 +372,7 @@ func (m *Manager) keyToManaged(derivedKey *hdkeychain.ExtendedKey, account, bran
|
||||||
if branch == internalBranch {
|
if branch == internalBranch {
|
||||||
ma.internal = true
|
ma.internal = true
|
||||||
}
|
}
|
||||||
|
ma.used = used
|
||||||
|
|
||||||
return ma, nil
|
return ma, nil
|
||||||
}
|
}
|
||||||
|
@ -486,7 +487,7 @@ func (m *Manager) loadAccountInfo(account uint32) (*accountInfo, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
lastExtAddr, err := m.keyToManaged(lastExtKey, account, branch, index)
|
lastExtAddr, err := m.keyToManaged(lastExtKey, account, branch, index, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -501,7 +502,7 @@ func (m *Manager) loadAccountInfo(account uint32) (*accountInfo, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
lastIntAddr, err := m.keyToManaged(lastIntKey, account, branch, index)
|
lastIntAddr, err := m.keyToManaged(lastIntKey, account, branch, index, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -537,7 +538,7 @@ func (m *Manager) chainAddressRowToManaged(row *dbChainAddressRow) (ManagedAddre
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.keyToManaged(addressKey, row.account, row.branch, row.index)
|
return m.keyToManaged(addressKey, row.account, row.branch, row.index, row.used)
|
||||||
}
|
}
|
||||||
|
|
||||||
// importedAddressRowToManaged returns a new managed address based on imported
|
// importedAddressRowToManaged returns a new managed address based on imported
|
||||||
|
@ -564,6 +565,7 @@ func (m *Manager) importedAddressRowToManaged(row *dbImportedAddressRow) (Manage
|
||||||
}
|
}
|
||||||
ma.privKeyEncrypted = row.encryptedPrivKey
|
ma.privKeyEncrypted = row.encryptedPrivKey
|
||||||
ma.imported = true
|
ma.imported = true
|
||||||
|
ma.used = row.used
|
||||||
|
|
||||||
return ma, nil
|
return ma, nil
|
||||||
}
|
}
|
||||||
|
@ -578,7 +580,7 @@ func (m *Manager) scriptAddressRowToManaged(row *dbScriptAddressRow) (ManagedAdd
|
||||||
return nil, managerError(ErrCrypto, str, err)
|
return nil, managerError(ErrCrypto, str, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newScriptAddress(m, row.account, scriptHash, row.encryptedScript)
|
return newScriptAddress(m, row.account, scriptHash, row.encryptedScript, row.used)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rowInterfaceToManaged returns a new managed address based on the given
|
// rowInterfaceToManaged returns a new managed address based on the given
|
||||||
|
@ -1126,7 +1128,7 @@ func (m *Manager) ImportScript(script []byte, bs *BlockStamp) (ManagedScriptAddr
|
||||||
// since it will be cleared on lock and the script the caller passed
|
// since it will be cleared on lock and the script the caller passed
|
||||||
// should not be cleared out from under the caller.
|
// should not be cleared out from under the caller.
|
||||||
scriptAddr, err := newScriptAddress(m, ImportedAddrAccount, scriptHash,
|
scriptAddr, err := newScriptAddress(m, ImportedAddrAccount, scriptHash,
|
||||||
encryptedScript)
|
encryptedScript, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1290,6 +1292,19 @@ func (m *Manager) Unlock(passphrase []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkUsed updates the used flag for the provided address id.
|
||||||
|
func (m *Manager) MarkUsed(addressID []byte) error {
|
||||||
|
err := m.namespace.Update(func(tx walletdb.Tx) error {
|
||||||
|
return markAddressUsed(tx, addressID)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return maybeConvertDbError(err)
|
||||||
|
}
|
||||||
|
// 'used' flag has become stale so remove key from cache
|
||||||
|
delete(m.addrs, addrKey(addressID))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ChainParams returns the chain parameters for this address manager.
|
// ChainParams returns the chain parameters for this address manager.
|
||||||
func (m *Manager) ChainParams() *chaincfg.Params {
|
func (m *Manager) ChainParams() *chaincfg.Params {
|
||||||
// NOTE: No need for mutex here since the net field does not change
|
// NOTE: No need for mutex here since the net field does not change
|
||||||
|
|
|
@ -67,6 +67,7 @@ type expectedAddr struct {
|
||||||
addressHash []byte
|
addressHash []byte
|
||||||
internal bool
|
internal bool
|
||||||
compressed bool
|
compressed bool
|
||||||
|
used bool
|
||||||
imported bool
|
imported bool
|
||||||
pubKey []byte
|
pubKey []byte
|
||||||
privKey []byte
|
privKey []byte
|
||||||
|
@ -1016,6 +1017,43 @@ func testImportScript(tc *testContext) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testMarkUsed ensures used addresses are flagged as such.
|
||||||
|
func testMarkUsed(tc *testContext) bool {
|
||||||
|
expectedAddr1 := expectedAddr{
|
||||||
|
addressHash: hexToBytes("2ef94abb9ee8f785d087c3ec8d6ee467e92d0d0a"),
|
||||||
|
used: true,
|
||||||
|
}
|
||||||
|
prefix := "MarkUsed"
|
||||||
|
chainParams := tc.manager.ChainParams()
|
||||||
|
addrHash := expectedAddr1.addressHash
|
||||||
|
addr, err := btcutil.NewAddressPubKeyHash(addrHash, chainParams)
|
||||||
|
|
||||||
|
if tc.create {
|
||||||
|
// Test that initially the address is not flagged as used
|
||||||
|
maddr, err := tc.manager.Address(addr)
|
||||||
|
if err != nil {
|
||||||
|
tc.t.Errorf("%s: unexpected error: %v", prefix, err)
|
||||||
|
}
|
||||||
|
if maddr.Used() != false {
|
||||||
|
tc.t.Errorf("%v: unexpected used flag -- got "+
|
||||||
|
"%v, want %v", prefix, maddr.Used(), expectedAddr1.used)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = tc.manager.MarkUsed(addrHash)
|
||||||
|
if err != nil {
|
||||||
|
tc.t.Errorf("%s: unexpected error: %v", prefix, err)
|
||||||
|
}
|
||||||
|
maddr, err := tc.manager.Address(addr)
|
||||||
|
if err != nil {
|
||||||
|
tc.t.Errorf("%s: unexpected error: %v", prefix, err)
|
||||||
|
}
|
||||||
|
if maddr.Used() != expectedAddr1.used {
|
||||||
|
tc.t.Errorf("%v: unexpected used flag -- got "+
|
||||||
|
"%v, want %v", prefix, maddr.Used(), expectedAddr1.used)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// testChangePassphrase ensures changes both the public and privte passphrases
|
// testChangePassphrase ensures changes both the public and privte passphrases
|
||||||
// works as intended.
|
// works as intended.
|
||||||
func testChangePassphrase(tc *testContext) bool {
|
func testChangePassphrase(tc *testContext) bool {
|
||||||
|
@ -1129,6 +1167,7 @@ func testManagerAPI(tc *testContext) {
|
||||||
testInternalAddresses(tc)
|
testInternalAddresses(tc)
|
||||||
testImportPrivateKey(tc)
|
testImportPrivateKey(tc)
|
||||||
testImportScript(tc)
|
testImportScript(tc)
|
||||||
|
testMarkUsed(tc)
|
||||||
testChangePassphrase(tc)
|
testChangePassphrase(tc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
38
wallet.go
38
wallet.go
|
@ -257,6 +257,24 @@ func (w *Wallet) ListenUnconfirmedBalance() (<-chan btcutil.Amount, error) {
|
||||||
return w.unconfirmedBalance, nil
|
return w.unconfirmedBalance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// markAddrsUsed marks the addresses credited by the given transaction
|
||||||
|
// record as used.
|
||||||
|
func (w *Wallet) markAddrsUsed(t *txstore.TxRecord) error {
|
||||||
|
for _, c := range t.Credits() {
|
||||||
|
// Errors don't matter here. If addrs is nil, the
|
||||||
|
// range below does nothing.
|
||||||
|
_, addrs, _, _ := c.Addresses(activeNet.Params)
|
||||||
|
for _, addr := range addrs {
|
||||||
|
addressID := addr.ScriptAddress()
|
||||||
|
if err := w.Manager.MarkUsed(addressID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Infof("Marked address used %s", addr.EncodeAddress())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (w *Wallet) notifyConnectedBlock(block waddrmgr.BlockStamp) {
|
func (w *Wallet) notifyConnectedBlock(block waddrmgr.BlockStamp) {
|
||||||
w.notificationLock.Lock()
|
w.notificationLock.Lock()
|
||||||
if w.connectedBlocks != nil {
|
if w.connectedBlocks != nil {
|
||||||
|
@ -701,25 +719,7 @@ func (w *Wallet) diskWriter() {
|
||||||
// there are any transactions with outputs to this address in the blockchain or
|
// there are any transactions with outputs to this address in the blockchain or
|
||||||
// the btcd mempool.
|
// the btcd mempool.
|
||||||
func (w *Wallet) AddressUsed(addr waddrmgr.ManagedAddress) bool {
|
func (w *Wallet) AddressUsed(addr waddrmgr.ManagedAddress) bool {
|
||||||
// This not only can be optimized by recording this data as it is
|
return addr.Used()
|
||||||
// read when opening a wallet, and keeping it up to date each time a
|
|
||||||
// new received tx arrives, but it probably should in case an address is
|
|
||||||
// used in a tx (made public) but the tx is eventually removed from the
|
|
||||||
// store (consider a chain reorg).
|
|
||||||
|
|
||||||
for _, r := range w.TxStore.Records() {
|
|
||||||
for _, c := range r.Credits() {
|
|
||||||
// Errors don't matter here. If addrs is nil, the
|
|
||||||
// range below does nothing.
|
|
||||||
_, addrs, _, _ := c.Addresses(activeNet.Params)
|
|
||||||
for _, a := range addrs {
|
|
||||||
if addr.Address().String() == a.String() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculateBalance sums the amounts of all unspent transaction
|
// CalculateBalance sums the amounts of all unspent transaction
|
||||||
|
|
Loading…
Add table
Reference in a new issue